Context Action beaTlet

Many of the things we want to do with songs we only want to do with the currently selected songs. So what's the code for manipulating those songs?

Sample ContextAction

Easy. It's pretty much a regular BaseAction that fetches the currently selected AudioSong ids, looks up the actual song objects and then does something with them. To demonstrate how it's done, we're going to show a simple action that resets the ReplayGain values for the selected songs:

# Jython

from javax.swing import Action
from com.tagtraum.core.app import AbsoluteActionLocation
from com.tagtraum.core.app import ActionLocation
from com.tagtraum.beatunes.action import BaseAction
from com.tagtraum.beatunes.action import BeaTunesUIRegion
from com.tagtraum.beatunes.songtable import SongPropertyChangeListener
# Needed for Java array creation
from jarray import array

class ResetReplayGain(BaseAction):

    def getId(self):
        return "Jython.ResetReplayGain"

    def init(self):
        self.putValue(Action.NAME, "Reset ReplayGain")

    # Install the action in both the Tools menu and the context
    # menu of the main table.
    def getActionLocations(self):
        # Java array creation via array([], type)
        return array([
        AbsoluteActionLocation(BeaTunesUIRegion.TOOL_MENU, AbsoluteActionLocation.LAST),
        AbsoluteActionLocation(BeaTunesUIRegion.SONG_CONTEXT_MENU, AbsoluteActionLocation.LAST)
        ], ActionLocation)

    def actionPerformed(self, actionEvent):
        # get ids for the selected songs
        ids = self.getSelectedSongIds()
        for id in ids:
            # obtain the AudioSong object
            # special cast to java.lang.Long necessary!!
            song = self.getApplication().getMediaLibrary().getSong(id)
            # register a SongPropertyChangeListener, so that
            # any changes are displayed right away.
            song.addPropertyChangeListener(
            SongPropertyChangeListener(self.getApplication().getMainWindow().getSongTable().getTable(), id)
            )
            # do something with the object.
            # don't forget that you are on the EDT!
            # so whatever you do here, should be quick.
            # if not, start a new thread for your work.
            song.setAlbumReplayGain(None, False)
            song.setTrackReplayGain(None, False)

// Groovy

import javax.swing.*
import java.awt.event.ActionEvent
import com.tagtraum.audiokern.*
import com.tagtraum.core.app.*
import com.tagtraum.beatunes.action.*
import com.tagtraum.beatunes.songtable.SongPropertyChangeListener

class ResetReplayGain extends BaseAction {

    def String getId() {
        "Groovy.ResetReplayGain"
    }

    def void init() {
        putValue(Action.NAME, "Reset ReplayGain")
    }

    /**
     * Install the action in both the Tools menu and the context
     * menu of the main table.
     */
    def ActionLocation[] getActionLocations() {
        [new AbsoluteActionLocation(BeaTunesUIRegion.TOOL_MENU, AbsoluteActionLocation.LAST),
        new AbsoluteActionLocation(BeaTunesUIRegion.SONG_CONTEXT_MENU, AbsoluteActionLocation.LAST)]
    }

    def void actionPerformed(ActionEvent actionEvent) {
        // get ids for the selected songs
        long[] ids = getSelectedSongIds()
        for (long id : ids) {
            // obtain the AudioSong object
            AudioSong song = getApplication().getMediaLibrary().getSong(id)
            // register a SongPropertyChangeListener, so that
            // any changes are displayed right away.
            song.addPropertyChangeListener(new SongPropertyChangeListener(getApplication().getMainWindow().getSongTable().getTable(), id))
            // do something with the object.
            // don't forget that you are on the EDT!
            // so whatever you do here, should be quick.
            // if not, start a new thread for your work.
            song.setAlbumReplayGain(null, false)
            song.setTrackReplayGain(null, false)
        }
    }
}

# JRuby

require 'java'

java_import javax.swing.Action

java_import com.tagtraum.core.app.ActionLocation
java_import com.tagtraum.core.app.AbsoluteActionLocation

java_import com.tagtraum.beatunes.action.BeaTunesUIRegion
java_import com.tagtraum.beatunes.action.BaseAction
java_import com.tagtraum.beatunes.songtable.SongPropertyChangeListener

class ResetReplayGain < BaseAction

    def getId
        "JRuby.ResetReplayGain"
    end

    def init()
        putValue(Action.NAME, "Reset ReplayGain")
    end

    # Install the action in both the Tools menu and the context
    # menu of the main table.
    def getActionLocations()
        # "to_java()" converts the Ruby array into a Java array of the given type
        [
            AbsoluteActionLocation.new(BeaTunesUIRegion::TOOL_MENU, AbsoluteActionLocation::LAST),
            AbsoluteActionLocation.new(BeaTunesUIRegion::SONG_CONTEXT_MENU, AbsoluteActionLocation::LAST)
        ].to_java(ActionLocation)
    end

    def actionPerformed(actionEvent)
        # get ids for the selected songs
        ids = getSelectedSongIds()
        for id in ids
            # obtain the AudioSong object
            # special cast to java.lang.Long necessary!!
            song = getApplication().getMediaLibrary().getSong(id.to_java(java.lang.Long))
            # register a SongPropertyChangeListener, so that
            # any changes are displayed right away.
            song.addPropertyChangeListener(
                SongPropertyChangeListener.new(getApplication().getMainWindow().getSongTable().getTable(), id)
            )
            # do something with the object.
            # don't forget that you are on the EDT!
            # so whatever you do here, should be quick.
            # if not, start a new thread for your work.
            song.setAlbumReplayGain(nil, false)
            song.setTrackReplayGain(nil, false)
        end
    end
end

// JavaScript

/*
 * These type vars basically act as imports for Java classes.
 */
var Action = Java.type("javax.swing.Action");
var ActionLocations = Java.type("com.tagtraum.core.app.ActionLocation[]");
var AbsoluteActionLocation = Java.type("com.tagtraum.core.app.AbsoluteActionLocation");
var BeaTunesUIRegion = Java.type("com.tagtraum.beatunes.action.BeaTunesUIRegion");
var BaseAction = Java.type("com.tagtraum.beatunes.action.BaseAction");
var SongPropertyChangeListener = Java.type("com.tagtraum.beatunes.songtable.SongPropertyChangeListener");

// BaseAction is an abstract class.
// This allows us to subclass it with "new".
// The resulting subclass instance is stored in the "beatlet" variable.
var beatlet = new BaseAction() {

    /*
     * Unique id.
     */
    getId: function() {
        return "Javascript.ResetReplayGain";
    },

    /*
     * Is called by beaTunes as part of the lifecycle after instantiation.
     * At this point all other plugins are instantiated and registered.
     * We use this to set the menu item's (i.e. the action's) name.
     */
    init: function() {
        beatletSuper.putValue(Action.NAME, "Reset ReplayGain");
    },

    /*
     * Define, where in the UI the Action should appear.
     * You can define multiple locations in an array. Here, we
     * request to be the last item in the Tool and the Context menu.
     * Note, that we use the Nashorn extension "Java.to", to
     * create a Java array.
     */
    getActionLocations: function() {
        return Java.to(
            [
                new AbsoluteActionLocation(BeaTunesUIRegion.TOOL_MENU, AbsoluteActionLocation.LAST),
                new AbsoluteActionLocation(BeaTunesUIRegion.SONG_CONTEXT_MENU, AbsoluteActionLocation.LAST),
            ], ActionLocations
        );
    },

    /*
     * React to a click on the menu item.
     */
    actionPerformed: function(actionEvent) {
        // get ids for the selected songs (this is an array of type long)
        var ids = beatletSuper.getSelectedSongIds()
        for (var i=0; i<ids.length; i++) {
            // obtain the AudioSong object
            var song = beatletSuper.getApplication().getMediaLibrary().getSong(ids[i]);
            // register a SongPropertyChangeListener, so that
            // any changes are displayed right away.
            song.addPropertyChangeListener(new SongPropertyChangeListener(beatletSuper.getApplication().getMainWindow().getSongTable().getTable(), ids[i]));
            // do something with the object.
            // don't forget that you are on the EDT!
            // so whatever you do here, should be quick.
            // if not, start a new thread for your work.
            song.setAlbumReplayGain(null, false);
            song.setTrackReplayGain(null, false);
        }
    }
}

// Find super class of beatlet, so that we can call methods on it
// in the "actionPerformed" function.
var beatletSuper = Java.super(beatlet);

// Put "beatlet" into the last line, so that it is returned
// to beaTunes when this script is eval'd.
beatlet;

Other beaTlet samples:

All sample beaTlets are also on GitHub .