#
# THIS FILE IS PART OF THE JOKOSHER PROJECT AND LICENSED UNDER THE GPL. SEE
# THE 'COPYING' FILE FOR DETAILS
#
# This module is used to present a dialog which allows the user to create, modify and
# remove mixdown profiles.
#
#-------------------------------------------------------------------------------
import gtk.glade
import gobject
import Globals
import MixdownProfileManager
import MixdownActions
import gettext
_ = gettext.gettext
#=========================================================================
class MixdownProfileDialog:
"""
This class allows the user to create, modify and remove mixdown profiles.
"""
#_____________________________________________________________________
def __init__(self, mainapp, project, profile=None):
"""
Creates a new instance of MixdownProfileDialog.
Parameters:
project -- the currently active Project.
mainapp -- reference to the MainApp Jokosher window.
"""
if profile:
self.profile = profile
else:
self.profile = None
self.mainapp = mainapp
self.project = project
self.res = gtk.glade.XML(Globals.GLADE_PATH, "MixdownProfileDialog")
self.signals = {
"on_add_profile_button_clicked" : self.OnAddProfile,
"on_remove_profile_button_clicked" : self.OnRemoveProfile,
"on_configure_action_button_clicked" : self.OnConfigureAction,
"on_add_action_button_clicked" : self.OnAddAction,
"on_remove_action_button_clicked" : self.OnRemoveAction,
"on_cancel_button_clicked" : self.OnDestroy,
"on_mixdown_button_clicked" : self.OnMixdown
}
self.res.signal_autoconnect(self.signals)
self.window = self.res.get_widget("MixdownProfileDialog")
self.window.set_default_size(450, 400)
self.window.set_icon(self.mainapp.icon)
self.profileCombo = self.res.get_widget("profile_combo")
self.treeView = self.res.get_widget("actions_treeview")
self.mixdownButton = self.res.get_widget("mixdown_button")
self.configureLabel = self.res.get_widget("action_configured_label")
self.manager = MixdownProfileManager.MixdownProfileManager(self)
self.treeViewModel = gtk.ListStore(gtk.gdk.Pixbuf, str, object) # pixbuf, details, class instance
self.profileComboModel = gtk.ListStore(str)
self.treeView.set_model(self.treeViewModel)
self.profileCombo.set_model(self.profileComboModel)
iconCell = gtk.CellRendererPixbuf()
iconColumn = gtk.TreeViewColumn()
iconColumn.pack_start(iconCell, False)
iconColumn.add_attribute(iconCell, "pixbuf", 0)
detailsCell = gtk.CellRendererText()
detailsColumn = gtk.TreeViewColumn()
detailsColumn.pack_start(detailsCell, False)
detailsColumn.add_attribute(detailsCell, "markup", 1)
self.treeView.append_column(iconColumn)
self.treeView.append_column(detailsColumn)
self.profileCombo.clear()
textrend = gtk.CellRendererText()
self.profileCombo.pack_start(textrend)
self.profileCombo.add_attribute(textrend, "text", 0)
self.profileCombo.connect("changed", self.OnProfileComboBoxChanged)
self.treeViewSelection = self.treeView.get_selection()
self.treeViewSelection.connect("changed", self.OnSelectionChanged)
self.treeViewSelection.set_mode(gtk.SELECTION_SINGLE)
self.PopulateProfileComboBoxModel()
# the previously selected item in the treeview
self.lastSelected = None
# the previously selected action instance in the treeview
self.lastAction = None
if self.profile:
self.SetActiveProfileItem(self.profile)
elif self.CountRowsInTreeModel(self.profileComboModel) > 0:
self.profileCombo.set_active(0)
self.window.show_all()
#_____________________________________________________________________
def SetActiveProfileItem(self, profileName):
"""
Called when an item in the profile combo (self.profileCombo) should be made
the active item.
Sets the active item in profile combo by the profile name specified
Parameters:
profileName -- name of the profile which should be active.
"""
active = -1
for item in self.profileComboModel:
active += 1
if item[0] == self.profile:
self.profileCombo.set_active(active)
break
#_____________________________________________________________________
def OnSelectionChanged(self, widget):
"""
Called when a treeview (self.treeView) selection has been made.
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
if self.treeViewSelection.count_selected_rows() > 0:
self.OnCheckActionConfigured()
self.UpdateSelectedActionAppearence()
else:
return
#_____________________________________________________________________
def UpdateSelectedActionAppearence(self):
"""
Called when a MixdownAction is selected in the action treeview (self.treeView).
Changes the appearence of the selected action.
"""
selected = self.treeViewSelection.get_selected()
action = self.treeViewModel [selected[1]] [2]
# set the foreground colour of the text to white
newText = "%s\n" % action.name \
+ "%s" % action.description
self.treeViewModel [selected[1]] [1] = newText
# modify the last selected item in the model to use the default colour grey
if self.lastSelected:
oldText = "%s\n" % self.lastAction.name \
+ "%s" % self.lastAction.description
self.treeViewModel [self.lastSelected[1]] [1] = oldText
self.lastAction = action
self.lastSelected = selected
#_____________________________________________________________________
def OnCheckActionConfigured(self):
"""
Called to check if a MixdownAction has been configured.
Checks to see if the selected action is configured and updates
the configure label accordingly.
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
if self.treeViewSelection.count_selected_rows() > 0:
profileName = self.profileComboModel[self.profileCombo.get_active()][0]
selected = self.treeViewSelection.get_selected()
action = self.treeViewModel [selected[1]] [2]
if action.isConfigured:
self.configureLabel.set_markup(_("%s is configured" % action.name))
else:
self.configureLabel.set_markup(_("%s is not configured" % action.name))
else:
self.configureLabel.set_text("")
#_____________________________________________________________________
def AddActionToActionModel(self, profileName, action):
"""
Called when a MixdownAction needs to be added to the action model (self.treeViewModel).
Adds the information associated with the MixdownAction to the action model.
Parameters:
profileName -- name of the mixdown profile to add the action to.
action -- the MixdownAction instance which will be added to the action model.
"""
self.treeViewModel.append( self.ReturnActionDisplayDetails(action) )
self.SaveProfileActions(profileName)
#_____________________________________________________________________
def ReturnActionDisplayDetails(self, action):
"""
Called when action details need to be displayed in the action model (self.treeViewModel).
Returns the details needed for the action to be added to the treeview (self.treeView).
Parameters:
action -- the MixdownAction instance which will be added to the action model.
"""
pixbuf = self.ReturnActionPixbuf(action)
detailsText = "%s\n" % action.name \
+ "%s" % action.description
return (pixbuf, detailsText, action)
#_____________________________________________________________________
def UpdateProfileModel(self, signalDetails):
"""
Called when the profile combo model (self.profileComboModel) needs updating.
Updates the combo box model with the files that reside in the mixdownprofiles directory
(JOKOSHER_DATA_HOME/mixdownprofiles/).
Parameters:
signalName -- the signal details which are passed to this method.
"""
profileName = None
active = self.profileCombo.get_active()
if signalDetails == "deleteProfile":
if active:
active -= 1
self.profileComboModel.clear()
for item in self.manager.GetMixdownProfileList():
self.profileComboModel.append((item,))
self.profileCombo.show_all()
if active > 0:
self.profileCombo.set_active(active)
else:
self.profileCombo.set_active(0)
if self.CountRowsInTreeModel(self.profileComboModel) > 0:
profileName = self.profileComboModel[self.profileCombo.get_active()][0]
self.UpdateActionTreeViewModel(profileName)
#_____________________________________________________________________
def UpdateActionTreeViewModel(self, profileName):
"""
Called when the action treeview (self.treeView) needs updating.
Updates the MixdownActions in the treeview.
Parameters:
profileName -- the name of the profile to use to retrieve MixdownActions from.
"""
self.treeViewModel.clear()
if profileName:
actions = self.manager.ReturnAllActionsFromMixdownProfile(profileName)
if actions:
for action in actions:
action.connect("action-configured", self.ActionIsConfigured)
self.treeViewModel.append( self.ReturnActionDisplayDetails(action) )
self.OnCheckActionConfigured()
#_____________________________________________________________________
def ActionIsConfigured(self, action):
"""
Called when a MixdownAction has been configured.
Saves the MixdownActions present in the action treeview (self.treeView)
to the currently selected profile (self.profileCombo).
Parameters:
action -- the MixdownAction instance which has just been configured.
"""
profileName = self.profileComboModel[self.profileCombo.get_active()][0]
self.SaveProfileActions(profileName)
#_____________________________________________________________________
def ReturnActionPixbuf(self, action):
"""
Called when the action treeview (self.treeView) needs to insert a
pixbuf associated with a MixdownAction.
Returns a pixbuf from the icon path specified by the MixdownAction.
Parameters:
action -- the MixdownAction instance from which a pixbuf will be returned.
Returns:
pixbuf -- A gtk.gdk.Pixbuf associated with the MixdownAction.
"""
if action.iconPath.startswith("gtk"):
pixbuf = self.treeView.render_icon(action.iconPath, gtk.ICON_SIZE_DIALOG)
else:
pixbuf = gtk.gdk.pixbuf_new_from_file(action.iconPath)
if pixbuf.get_property("width") and pixbuf.get_property("height") != 48:
scaled = pixbuf.scale_simple(48, 48, gtk.gdk.INTERP_BILINEAR)
return scaled
else:
return pixbuf
#_____________________________________________________________________
def PopulateProfileComboBoxModel(self):
"""
Populates the profile combo model (self.profileComboModel) with profiles
in JOKOSHER_DATA_HOME/mixdownprofiles/
"""
for profile in self.manager.GetMixdownProfileList():
self.profileComboModel.append((profile,))
#_____________________________________________________________________
def OnProfileComboBoxChanged(self, widget):
"""
Called when the profile combo box (self.profileCombo) contents change.
Updates the action treeview (self.treeView) with the MixdownActions in
the newly selected profile.
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
if self.CountRowsInTreeModel(self.profileComboModel) > 0:
profileName = self.profileComboModel[self.profileCombo.get_active()][0]
self.UpdateActionTreeViewModel(profileName)
else:
# if there is nothing in the combo model, then clear any actions that may be
# remaining in the action treeview
self.treeViewModel.clear()
#_____________________________________________________________________
def OnAddProfile(self, widget):
"""
Called when the Add Mixdown Profile button is clicked.
Shows a dialog allowing the user to add MixdownActions
to the currently selected profile (self.profileCombo).
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
self.ShowAddProfileDialog()
#_____________________________________________________________________
def ShowAddProfileDialog(self):
"""
Shows the Add Mixdown Profile dialog, allowing the user to create a MixdownProfile.
"""
buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)
iconBox = gtk.HBox()
iconBox.set_border_width(12)
iconBox.set_spacing(12)
iconImage = gtk.Image()
iconImage.set_from_stock(gtk.STOCK_DIALOG_QUESTION, gtk.ICON_SIZE_DIALOG)
iconLabel = gtk.Label(_("Please enter the name of the mixdown profile you wish to create."))
iconLabel.set_line_wrap(True)
iconBox.pack_start(iconImage, False, False)
iconBox.pack_start(iconLabel, False, False)
entryBox = gtk.HBox()
entryBox.set_spacing(12)
entryBox.set_border_width(6)
profileEntry = gtk.Entry()
entryBox.pack_start(gtk.Label(_("Profile name:")), False, False)
entryBox.pack_start(profileEntry, True, True)
dlg = gtk.Dialog(_("Create Mixdown Profile"), self.window, gtk.DIALOG_DESTROY_WITH_PARENT, buttons)
dlg.set_default_size(375, 200)
dlg.set_has_separator(False)
dlg.set_default_response(gtk.RESPONSE_OK)
dlg.vbox.set_spacing(6)
dlg.vbox.pack_start(iconBox, False, False)
dlg.vbox.pack_start(entryBox, False, False)
dlg.vbox.show_all()
response = dlg.run()
if response == gtk.RESPONSE_OK:
msgdlg = gtk.MessageDialog(self.window,
gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_INFO,
gtk.BUTTONS_CLOSE)
if profileEntry.get_text():
self.manager.SaveMixdownProfile(profileEntry.get_text())
msgdlg.set_markup(_("Successfully created mixdown profile %s.profile.") % profileEntry.get_text())
msgdlg.run()
msgdlg.destroy()
else:
msgdlg.set_markup(_("Cannot create mixdown profile. Please make sure you have specified a profile name."))
msgdlg.set_property("message-type", gtk.MESSAGE_ERROR)
msgdlg.run()
msgdlg.destroy()
dlg.destroy()
#_____________________________________________________________________
def ShowActionErrorDialog(self, actionName, extensionName):
"""
Called when an error has occured while loading MixdownActions.
Shows a dialog informing the user that a MixdownAction has failed to load.
Parameters:
actionName -- the name of the MixdownAction which cannot be loaded.
extensionName -- the name of the extension that the MixdownAction can't be loaded from.
"""
msgdlg = gtk.MessageDialog(self.window,
gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_ERROR,
gtk.BUTTONS_CLOSE)
message = _("Please make sure the extension %s is enabled." % extensionName)
msgdlg.set_markup(_("Cannot load mixdown action %s.\n\n%s" % (actionName, message)))
msgdlg.run()
msgdlg.destroy()
#_____________________________________________________________________
def OnRemoveProfile(self, widget):
"""
Called when the Remove Mixdown Profile button is clicked.
Removes the currently selected profile in the profile
combo box (self.profileCombo).
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
if self.CountRowsInTreeModel(self.profileComboModel) > 0:
profileName = self.profileComboModel[self.profileCombo.get_active()][0]
self.manager.DeleteMixdownProfile(profileName)
else:
return
#_____________________________________________________________________
def OnConfigureAction(self, widget):
"""
Called when the Configure Mixdown Action button is clicked.
Calls the selected MixdownAction's ConfigureAction method.
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
if self.treeViewSelection.count_selected_rows() > 0:
selected = self.treeViewSelection.get_selected()
action = self.treeView.get_model() [selected[1]] [2]
action.ConfigureAction()
else:
return
#_____________________________________________________________________
def OnAddAction(self, widget):
"""
Called when the Add Mixdown Action button is clicked.
Shows the Add Mixdown Action dialog, allowing the user to add a MixdownAction
to the currently selected profile (self.profileCombo).
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
if self.CountRowsInTreeModel(self.profileComboModel) > 0:
if self.profileComboModel[self.profileCombo.get_active()][0]:
self.ShowAddActionDialog()
else:
return
#_____________________________________________________________________
def OnRemoveAction(self, widget):
"""
Called when the Remove Action button is clicked.
Removes the currently selected action from the action
treeview (self.treeView)
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
if self.treeViewSelection.count_selected_rows() > 0:
profileName = self.profileComboModel[self.profileCombo.get_active()][0]
iterpos = self.treeViewSelection.get_selected()[1]
self.treeView.get_model().remove(iterpos)
self.SaveProfileActions(profileName)
else:
return
#_____________________________________________________________________
def ShowAddActionDialog(self):
"""
Called when the Add Mixdown Action button is clicked.
Shows a dialog which allows the user to add a MixdownAction
to the currently selected profile (self.profileCombo)
"""
AddMixdownActionDialog(self)
#_____________________________________________________________________
def SaveProfileActions(self, name):
"""
Called when MixdownActions in a profile need to be saved.
Saves MixdownActions to the profile specified.
Parameters:
name -- name of the profile which the mixdown actions will be saved to.
"""
actions = []
for row in self.treeView.get_model():
actions.append(row[2])
self.manager.SaveMixdownProfile(name, actions)
#_____________________________________________________________________
def OnDestroy(self, widget):
"""
Called when the window is closed. Destroys the window.
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
self.window.destroy()
#_____________________________________________________________________
def OnMixdown(self, widget):
"""
Called when the user clicks the Mixdown button.
Calls the RunAction method on the MixdownActions
in the action treeview (self.treeView). See RunAction in MixdownActions.py
for more details.
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
for row in self.treeViewModel:
action = row[2]
try:
action.RunAction()
except MixdownActions.MixdownActionException, e:
text = _("An error occured while running the mixdown action: %s") % action.name
text = "%s\n\n%s" % (text, e.message)
dlg = gtk.MessageDialog(self.window,
gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_ERROR,
gtk.BUTTONS_CLOSE,
text)
dlg.connect('response', lambda dlg, response: dlg.destroy())
dlg.show()
return
#_____________________________________________________________________
def CountRowsInTreeModel(self, treeModel):
"""
Called when the number of rows in the action treeview (self.treeView) is needed.
Parameters:
treeModel -- the model to use when counting the number of rows.
Returns:
rows -- number of rows in the action treeview.
"""
rows = treeModel.iter_n_children(None)
return rows
#_____________________________________________________________________
#=========================================================================
class AddMixdownActionDialog:
"""
This class allows the user to add a MixdownAction to the list of MixdownActions in
the MixdownProfileDialog.
"""
#_____________________________________________________________________
def __init__(self, profileDialog):
"""
Creates a new instance of MixdownProfileDialog.
Parameters:
profileDialog -- reference to the MixdownProfileDialog object which calls this class.
"""
self.profileDialog = profileDialog
self.addActionDialogTree = gtk.glade.XML(Globals.GLADE_PATH, "AddMixdownActionDialog")
signals = {
"on_cancel_button_clicked" : self.OnCancelAction,
"on_add_action_button_clicked" : self.OnAddAction,
}
self.addActionDialogTree.signal_autoconnect(signals)
self.addActionDialog = self.addActionDialogTree.get_widget("AddMixdownActionDialog")
self.treeView = self.addActionDialogTree.get_widget("treeview")
self.actionLabel = self.addActionDialogTree.get_widget("action_label")
self.addActionButton = self.addActionDialogTree.get_widget("add_action_button")
self.treeModel = gtk.ListStore(gtk.gdk.Pixbuf, str, object) # pixbuf, details, class instance
self.treeView.set_model(self.treeModel)
self.treeView.append_column(gtk.TreeViewColumn(_("Icon"), gtk.CellRendererPixbuf(), pixbuf=0))
self.treeView.append_column(gtk.TreeViewColumn(_("Name"), gtk.CellRendererText(), markup=1))
self.treeViewSelection = self.treeView.get_selection()
self.treeViewSelection.connect("changed", self.UpdateSelectedActionAppearence)
self.treeViewSelection.set_mode(gtk.SELECTION_SINGLE)
self.profileName = self.profileDialog.profileComboModel[self.profileDialog.profileCombo.get_active()][0]
self.lastAction = None
self.lastSelected = None
# set some properties for the widgets
self.addActionDialog.set_transient_for(self.profileDialog.window)
self.addActionDialog.set_icon(self.profileDialog.window.get_icon())
self.actionLabel.set_markup(_("Please select the mixdown actions you would like to add to mixdown profile %s.") % self.profileName)
self.PopulateActionModel()
#_____________________________________________________________________
def UpdateSelectedActionAppearence(self, widget):
"""
Called when a MixdownAction is selected in the add action treeview (self.treeView).
Changes the appearence of the selected action.
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
selected = self.treeViewSelection.get_selected()
action = self.treeModel [selected[1]] [2]
# set the foreground colour of the text to white
newText = "%s\n" % action.name \
+ "%s" % action.description
self.treeModel [selected[1]] [1] = newText
# modify the last selected item in the model to use the default colour grey
if self.lastSelected:
oldText = "%s\n" % self.lastAction.name \
+ "%s" % self.lastAction.description
self.treeModel [self.lastSelected[1]] [1] = oldText
self.lastAction = action
self.lastSelected = selected
#_____________________________________________________________________
def ReturnAllActions(self):
"""
Returns all actions in MixdownActions.py, excluding the MixdownAction class.
Returns:
actionList -- list of MixdownAction instances
"""
actionList = []
for action in self.profileDialog.mainapp.registerMixdownActionAPI.ReturnAllActions():
# we have to pass Project to ExportAsFileType for it to work
if action.__name__ == "ExportAsFileType":
actionList.append( action(self.profileDialog.project) )
else:
actionList.append( action() )
# a list of MixdownAction instances should be returned
return actionList
#_____________________________________________________________________
def PopulateActionModel(self):
"""
Called when the action model (self.treeModel) needs to be populated.
"""
for action in self.ReturnAllActions():
self.treeModel.append( self.profileDialog.ReturnActionDisplayDetails(action) )
#_____________________________________________________________________
def OnAddAction(self, widget):
"""
Called when the Add Action button is clicked.
Adds the selected MixdownAction to the profile dialog's action
model (self.profileDialog.treeViewModel).
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
if self.treeViewSelection.count_selected_rows() > 0:
selected = self.treeViewSelection.get_selected()
action = self.treeModel [selected[1]] [2]
self.profileDialog.AddActionToActionModel(self.profileName, action)
else:
return
self.addActionDialog.destroy()
#_____________________________________________________________________
def OnCancelAction(self, widget):
"""
Called when the Cancel button is clicked.
Destroys the Add Mixdown Action dialog
Parameters:
widget -- reserved for GTK callbacks, don't use it explicitly.
"""
self.addActionDialog.destroy()
#_____________________________________________________________________
#=========================================================================