~ubuntu-branches/ubuntu/trusty/jokosher/trusty

« back to all changes in this revision

Viewing changes to Jokosher/MixdownProfileDialog.py

  • Committer: Bazaar Package Importer
  • Author(s): Luca Falavigna, Luca Falavigna, Piotr Ożarowski
  • Date: 2009-05-12 00:37:15 UTC
  • mfrom: (1.3.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090512003715-3hp2ycoqjlzwfnlv
Tags: 0.11.2-1
[ Luca Falavigna ]
* New upstream release (Closes: #517234).
  - Jokosher now appears under Sound & Video (Closes: #443788).
* New Maintainer (Closes: #523167).
* Add Python Applications Packaging Team to Uploaders.
* Add Vcs-* fields in source stanza.
* Adjust copyright informations:
  - Refresh upstream authors and copyright holders.
  - Link to /usr/share/common-licenses/GPL-2.
  - Adjust copyright holders for Debian packaging.
  - Replace (c) with ©.
* Apply changes from Ubuntu by Daniel Holbach (thanks!):
  - Drop scrollkeeper from Build-Depends.
  - Drop useless dependencies: python-alsaaudio, gstreamer0.10-gnomevfs,
    librsvg2-common, python-gnome2.
  - Bump gstreamer0.10-plugins-good requirement to >= 0.10.9.
  - Drop debian/jokosher.sh, useless.
  - Provide debian/watch file.
* Switch to debhelper 7.
* Install Jokosher module in private directory.
* Unpack egg files to let python-support handle them.
* Drop python-dev from Build-Depends, use python (>= 2.4) instead.
* Depend on python-gobject.
* Switch dependency from python-setuptools to python-pkg-resources
  because of package rename (Closes: #468728).
* debian/patches/10_update_mime_database.dpatch:
  - Refresh for new upstream release.
* debian/patches/20_LevelList_IOError.dpatch:
  - Fix IOError exception trying to add an audio file to a project.
* debian/patches/30_desktop_file.dpatch:
  - Adhere to Freedesktop.org standards by removing deprecated entries.
* debian/patches/50_CreateNewProject_return.dpatch:
  - Return class while creating a new project.
* Provide a simple man page for jokosher.
* Bump Standards-Version to 3.8.1:
  - Provide Homepage field in source stanza.
  - Provide debian/README.source to document dpatch usage.

[ Piotr Ożarowski ]
* Add 40_load_extensions_from_unpacked_eggs patch so that extensions in
  unzipped Eggs are recognized as well

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
#       THIS FILE IS PART OF THE JOKOSHER PROJECT AND LICENSED UNDER THE GPL. SEE
3
3
#       THE 'COPYING' FILE FOR DETAILS
4
4
#
5
 
#       This class handles all of the processing associated with the
6
 
#       Mixdown Profile dialog.
 
5
#       This module is used to present a dialog which allows the user to create, modify and
 
6
#       remove mixdown profiles.
7
7
#
8
8
#-------------------------------------------------------------------------------
9
9
 
10
10
import gtk.glade
11
11
import gobject
 
12
 
12
13
import Globals
13
 
import os
14
 
import MixdownProfiles
 
14
import MixdownProfileManager
 
15
import MixdownActions
15
16
 
16
17
import gettext
17
18
_ = gettext.gettext
20
21
 
21
22
class MixdownProfileDialog:
22
23
        """
23
 
        Handles all of the processing associated with the Mixdown Profile dialog.
 
24
        This class allows the user to create, modify and remove mixdown profiles.
24
25
        """
25
26
        
26
27
        #_____________________________________________________________________
27
28
 
28
 
        def __init__(self, project, parent, profile=None):
 
29
        def __init__(self, mainapp, project, profile=None):
29
30
                """
30
31
                Creates a new instance of MixdownProfileDialog.
31
32
                
32
33
                Parameters:
33
34
                        project -- the currently active Project.
34
 
                        parent -- reference to the MainApp Jokosher window.
35
 
                        profile -- a profile name, as saved by SaveSettings.
 
35
                        mainapp -- reference to the MainApp Jokosher window.
36
36
                """
37
 
                if project:
38
 
                        self.project = project
 
37
                if profile:
 
38
                        self.profile = profile
39
39
                else:
40
 
                        return
 
40
                        self.profile = None
 
41
                        
 
42
                self.mainapp = mainapp
 
43
                self.project = project
41
44
                
42
45
                self.res = gtk.glade.XML(Globals.GLADE_PATH, "MixdownProfileDialog")
43
46
 
44
47
                self.signals = {
45
 
                        "on_mixdownbutton_clicked" : self.OnMixdown,
46
 
                        "on_savesettingsbutton_clicked" : self.OnSaveSettings,
47
 
                        "on_addstepbutton_clicked" : self.OnAddStep,
48
 
                        "on_cancelbutton_clicked" : self.OnClose
 
48
                        "on_add_profile_button_clicked" : self.OnAddProfile,
 
49
                        "on_remove_profile_button_clicked" : self.OnRemoveProfile,
 
50
                        "on_configure_action_button_clicked" : self.OnConfigureAction,
 
51
                        "on_add_action_button_clicked" : self.OnAddAction,
 
52
                        "on_remove_action_button_clicked" : self.OnRemoveAction,
 
53
                        "on_cancel_button_clicked" : self.OnDestroy,
 
54
                        "on_mixdown_button_clicked" : self.OnMixdown
49
55
                }
50
 
                
 
56
 
51
57
                self.res.signal_autoconnect(self.signals)
52
58
 
53
59
                self.window = self.res.get_widget("MixdownProfileDialog")
54
 
                self.scrolledSteps = self.res.get_widget("scrolledwindow")
55
 
 
56
 
                self.parent = parent
57
 
                self.window.set_icon(self.parent.icon)
58
 
                self.actionstable = gtk.Table(rows=1, columns=2)
59
 
                
60
 
                # set up the table for displaying the results
61
 
                self.actionstable.set_row_spacings(6)
62
 
                self.actionstable.set_col_spacings(6)
63
 
                self.actionstable.set_border_width(6)
64
 
                self.scrolledSteps.add_with_viewport(self.actionstable)
65
 
                
66
 
                # centre the MixdownProfileDialog on the main jokosher window
67
 
                self.window.set_transient_for(self.parent.window)
68
 
                
69
 
                # replace $PROJECTNAME with the project name in the window label
70
 
                projectnamelabel = self.res.get_widget("lbl_projectname")
71
 
                txt = _("<b>Steps to mixdown %(projectname)s</b>") % {"projectname":self.project.name}
72
 
                projectnamelabel.set_markup(txt)
73
 
 
74
 
                # populate actions list
75
 
                self.possible_action_classes = [
76
 
                        MixdownProfiles.ExportAsFileType,
77
 
                        MixdownProfiles.RunAScript
78
 
                ] # eventually allow extensions to add to this, but not yet
79
 
 
80
 
                self.combo_newstep = self.res.get_widget("newstep")
81
 
                self.combo_newstep_model = self.combo_newstep.get_model()
82
 
                for action in self.possible_action_classes:
83
 
                        self.combo_newstep_model.append([action.create_name()])
84
 
                self.combo_newstep.set_active(0)
85
 
 
86
 
                self.actions = []
87
 
                if profile:
88
 
                        self.RestoreProfile(profile)
89
 
                else:           
90
 
                        # create a "export as Ogg" button by default
91
 
                        # specialcase ExportAsFileType
92
 
                        export_action = MixdownProfiles.ExportAsFileType(self.project)
93
 
                        self.AddAction(export_action)
 
60
                self.window.set_default_size(450, 400)
 
61
                self.window.set_icon(self.mainapp.icon)
 
62
 
 
63
                self.profileCombo = self.res.get_widget("profile_combo")
 
64
                self.treeView = self.res.get_widget("actions_treeview")
 
65
                self.mixdownButton = self.res.get_widget("mixdown_button")
 
66
                self.configureLabel = self.res.get_widget("action_configured_label")
 
67
                
 
68
                self.manager = MixdownProfileManager.MixdownProfileManager(self)
 
69
                
 
70
                self.treeViewModel = gtk.ListStore(gtk.gdk.Pixbuf, str, object) # pixbuf, details, class instance
 
71
                self.profileComboModel = gtk.ListStore(str)
 
72
                
 
73
                self.treeView.set_model(self.treeViewModel)
 
74
                self.profileCombo.set_model(self.profileComboModel)
 
75
                
 
76
                iconCell = gtk.CellRendererPixbuf()
 
77
                iconColumn = gtk.TreeViewColumn()
 
78
                iconColumn.pack_start(iconCell, False)
 
79
                iconColumn.add_attribute(iconCell, "pixbuf", 0)
 
80
                
 
81
                detailsCell = gtk.CellRendererText()
 
82
                detailsColumn = gtk.TreeViewColumn()
 
83
                detailsColumn.pack_start(detailsCell, False)
 
84
                detailsColumn.add_attribute(detailsCell, "markup", 1)
 
85
                
 
86
                self.treeView.append_column(iconColumn)
 
87
                self.treeView.append_column(detailsColumn)
 
88
                
 
89
                self.profileCombo.clear()
 
90
                textrend = gtk.CellRendererText()
 
91
                self.profileCombo.pack_start(textrend)
 
92
                self.profileCombo.add_attribute(textrend, "text", 0)
 
93
                self.profileCombo.connect("changed", self.OnProfileComboBoxChanged)
 
94
                
 
95
                self.treeViewSelection = self.treeView.get_selection()
 
96
                self.treeViewSelection.connect("changed", self.OnSelectionChanged)
 
97
                self.treeViewSelection.set_mode(gtk.SELECTION_SINGLE)
 
98
                
 
99
                self.PopulateProfileComboBoxModel()
 
100
                
 
101
                # the previously selected item in the treeview
 
102
                self.lastSelected = None
 
103
                # the previously selected action instance in the treeview
 
104
                self.lastAction = None
 
105
                
 
106
                if self.profile:
 
107
                        self.SetActiveProfileItem(self.profile)
 
108
                elif self.CountRowsInTreeModel(self.profileComboModel) > 0:
 
109
                        self.profileCombo.set_active(0)
94
110
                        
95
 
                # TODO: if a profile was supplied, show a delete button for it
96
 
                
97
111
                self.window.show_all()
98
 
 
99
 
        #_____________________________________________________________________
100
 
 
101
 
        def AddAction(self, action):
102
 
                """
103
 
                Adds a MixdownAction to this mixdown profile.
104
 
                
105
 
                Parameters:
106
 
                        action -- a MixdownProfiles.MixdownAction subclass.
107
 
                """
108
 
                rows = self.actionstable.get_property("n-rows")
109
 
                cols = self.actionstable.get_property("n-columns")
110
 
                
111
 
                if rows == 1 and len(self.actions) == 0:
112
 
                        pass
113
 
                else:
114
 
                        rows += 1
115
 
                        self.actionstable.resize(rows, cols)
116
 
                
117
 
                tooltips = gtk.Tooltips()
118
 
                button = gtk.Button()
119
 
                button.mixdownaction = action
120
 
                action.button = button
121
 
                action.update_button()
122
 
                tooltips.set_tip(button, _("Edit this mixdown step settings"))
123
 
                button.connect("clicked", self.ConfigureButton)
124
 
                self.actionstable.attach(button, 0, 1, rows-1, rows, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL|gtk.SHRINK)
125
 
                
126
 
                buttondel = gtk.Button(stock=gtk.STOCK_DELETE)
127
 
                buttondel.mixdownaction = action
128
 
                tooltips.set_tip(buttondel, _("Remove this mixdown step"))
129
 
                buttondel.connect("clicked", self.DeleteButton)
130
 
                buttondel.actionbutton = button
131
 
                if rows == 1:
132
 
                        buttondel.set_sensitive(False) # you can't delete the first export      
133
 
                self.actionstable.attach(buttondel, 1, 2, rows-1, rows, xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL|gtk.SHRINK)
134
 
                
135
 
                self.actionstable.show_all()
136
 
                self.actions.append(action)
137
 
        
138
 
        #_____________________________________________________________________
139
 
 
140
 
        def ConfigureButton(self, button):
141
 
                """
142
 
                Called when the user clicks the button for an action, which
143
 
                pops its config window.
144
 
                
145
 
                Parameters:
146
 
                        button -- reserved for GTK callbacks, don't use it explicitly.
147
 
                """
148
 
                button.mixdownaction.configure()
149
 
 
150
 
        #_____________________________________________________________________
151
 
 
152
 
        def DeleteButton(self, button):
153
 
                """
154
 
                Called when the user clicks the delete button for an action, which
155
 
                removes that action.
156
 
                
157
 
                Parameters:
158
 
                        button -- reserved for GTK callbacks, don't use it explicitly.
159
 
                """
160
 
                # remove the action from the list
161
 
                self.actions.remove(button.mixdownaction)
162
 
                
163
 
                # delete the action
164
 
                del(button.mixdownaction)
165
 
                
166
 
                # delete the buttons
167
 
                table = button.get_parent()
168
 
                actionbutton = button.actionbutton
169
 
                
170
 
                # walk through the table; when we find our button, delete it and
171
 
                # its associated action button, and then move everything up a row;
172
 
                # finally, resize the table to be one row smaller
173
 
                our_row = table.child_get_property(button, "top-attach")
174
 
                
175
 
                table.remove(button)
176
 
                table.remove(actionbutton)
177
 
                
178
 
                # move everything up a row
179
 
                # we do this by finding all the table's children which are in a row greater
180
 
                # than the buttons we've removed, and removing them too while stashing them
181
 
                # in a list. Then sort the list into incrementing row order, and finally
182
 
                # walk through the list readding them. We have to do this stupid dance
183
 
                # so that we read them all in increasing row order, otherwise it'll 
184
 
                # possibly break by putting two things in a table cell, etc.
185
 
                removed_buttons_to_readd = []
186
 
                for child in table.get_children():
187
 
                        this_child_row = table.child_get_property(child, "top-attach")
188
 
                        this_child_col = table.child_get_property(child, "left-attach")
189
 
                        if this_child_row > our_row:
190
 
                                removed_buttons_to_readd.append((this_child_row - 1, this_child_col, child))
191
 
                                table.remove(child)
192
 
                
193
 
                removed_buttons_to_readd.sort(cmp=lambda a,b: cmp(a[0], b[0]))
194
 
                
195
 
                for row_to_readd_to, col_to_readd_to, widget in removed_buttons_to_readd:
196
 
                        table.attach(widget, col_to_readd_to, col_to_readd_to + 1,
197
 
                                                                                                         row_to_readd_to, row_to_readd_to + 1,
198
 
                                                                                                         xoptions=gtk.FILL|gtk.EXPAND, yoptions=gtk.FILL|gtk.SHRINK)
199
 
                
200
 
                # finally resize the table down by one row
201
 
                rows = self.actionstable.get_property("n-rows")
202
 
                cols = self.actionstable.get_property("n-columns")
203
 
                rows -= 1
204
 
                self.actionstable.resize(rows, cols)
205
 
 
206
 
        #_____________________________________________________________________
207
 
 
208
 
        def OnAddStep(self, button):
209
 
                """
210
 
                Called when the user clicks the "Add step" button to add a step.
211
 
                
212
 
                Parameters:
213
 
                        button -- reserved for GTK callbacks, don't use it explicitly.
214
 
                """
215
 
                active = self.combo_newstep.get_active()
216
 
                
217
 
                if active == -1:
218
 
                        return
219
 
                
220
 
                action_class = self.possible_action_classes[active]
221
 
                
222
 
                # specialcase ExportAsFileType
223
 
                if action_class == MixdownProfiles.ExportAsFileType: 
224
 
                        new_action = action_class(self.project)
225
 
                else:
226
 
                        new_action = action_class()
227
 
                self.AddAction(new_action)
228
 
                
229
 
        #_____________________________________________________________________
230
 
 
231
 
        def OnClose(self, button):
232
 
                """
233
 
                Called when the dialog gets closed.
234
 
                
235
 
                Parameters:
236
 
                        button -- reserved for GTK callbacks, don't use it explicitly.
 
112
                
 
113
        #_____________________________________________________________________
 
114
        
 
115
        def SetActiveProfileItem(self, profileName):
 
116
                """
 
117
                Called when an item in the profile combo (self.profileCombo) should be made
 
118
                the active item.
 
119
                Sets the active item in profile combo by the profile name specified
 
120
                
 
121
                Parameters:
 
122
                        profileName -- name of the profile which should be active.
 
123
                """
 
124
                active = -1
 
125
                for item in self.profileComboModel:
 
126
                        active += 1
 
127
                        if item[0] == self.profile:
 
128
                                self.profileCombo.set_active(active)
 
129
                                break
 
130
                        
 
131
        #_____________________________________________________________________
 
132
        
 
133
        def OnSelectionChanged(self, widget):
 
134
                """
 
135
                Called when a treeview (self.treeView) selection has been made.
 
136
                
 
137
                Parameters:
 
138
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
139
                """
 
140
                if self.treeViewSelection.count_selected_rows() > 0:
 
141
                        self.OnCheckActionConfigured()
 
142
                        self.UpdateSelectedActionAppearence()
 
143
                else:
 
144
                        return
 
145
                
 
146
        #_____________________________________________________________________
 
147
        
 
148
        def UpdateSelectedActionAppearence(self):
 
149
                """
 
150
                Called when a MixdownAction is selected in the action treeview (self.treeView).
 
151
                Changes the appearence of the selected action.
 
152
                """
 
153
                selected = self.treeViewSelection.get_selected()
 
154
                action = self.treeViewModel [selected[1]] [2]
 
155
                
 
156
                # set the foreground colour of the text to white
 
157
                newText = "<span size='larger' weight='bold'>%s</span>\n" % action.name  \
 
158
                + "<span size='smaller' foreground='white'>%s</span>" % action.description
 
159
                self.treeViewModel [selected[1]] [1] = newText
 
160
                
 
161
                # modify the last selected item in the model to use the default colour grey
 
162
                if self.lastSelected:
 
163
                        oldText = "<span size='larger' weight='bold'>%s</span>\n" % self.lastAction.name  \
 
164
                        + "<span size='smaller' foreground='dim grey'>%s</span>" % self.lastAction.description
 
165
                        self.treeViewModel [self.lastSelected[1]] [1] = oldText
 
166
                
 
167
                self.lastAction = action
 
168
                self.lastSelected = selected
 
169
                
 
170
        #_____________________________________________________________________
 
171
        
 
172
        def OnCheckActionConfigured(self):
 
173
                """
 
174
                Called to check if a MixdownAction has been configured.
 
175
                Checks to see if the selected action is configured and updates
 
176
                the configure label accordingly.
 
177
                
 
178
                Parameters:
 
179
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
180
                """
 
181
                if self.treeViewSelection.count_selected_rows() > 0:
 
182
                        profileName = self.profileComboModel[self.profileCombo.get_active()][0]
 
183
                        selected = self.treeViewSelection.get_selected()
 
184
                        action = self.treeViewModel [selected[1]] [2]
 
185
                        if action.isConfigured:
 
186
                                self.configureLabel.set_markup(_("<b>%s is configured</b>" % action.name))
 
187
                        else:
 
188
                                self.configureLabel.set_markup(_("<b>%s is not configured</b>" % action.name))
 
189
                else:
 
190
                        self.configureLabel.set_text("")
 
191
                        
 
192
        #_____________________________________________________________________
 
193
        
 
194
        def AddActionToActionModel(self, profileName, action):
 
195
                """
 
196
                Called when a MixdownAction needs to be added to the action model (self.treeViewModel).
 
197
                Adds the information associated with the MixdownAction to the action model.
 
198
                
 
199
                Parameters:
 
200
                        profileName -- name of the mixdown profile to add the action to.
 
201
                        action -- the MixdownAction instance which will be added to the action model.
 
202
                """
 
203
                self.treeViewModel.append( self.ReturnActionDisplayDetails(action) )
 
204
                self.SaveProfileActions(profileName)
 
205
                
 
206
        #_____________________________________________________________________
 
207
        
 
208
        def ReturnActionDisplayDetails(self, action):
 
209
                """
 
210
                Called when action details need to be displayed in the action model (self.treeViewModel).
 
211
                Returns the details needed for the action to be added to the treeview (self.treeView).
 
212
                
 
213
                Parameters:
 
214
                        action -- the MixdownAction instance which will be added to the action model.
 
215
                """
 
216
                pixbuf = self.ReturnActionPixbuf(action)
 
217
                
 
218
                detailsText = "<span size='larger' weight='bold'>%s</span>\n" % action.name  \
 
219
                + "<span size='smaller' foreground='dim grey'>%s</span>" % action.description
 
220
                
 
221
                return (pixbuf, detailsText, action)
 
222
                
 
223
        #_____________________________________________________________________
 
224
        
 
225
        def UpdateProfileModel(self, signalDetails):
 
226
                """
 
227
                Called when the profile combo model (self.profileComboModel) needs updating.
 
228
                Updates the combo box model with the files that reside in the mixdownprofiles directory
 
229
                (JOKOSHER_DATA_HOME/mixdownprofiles/).
 
230
                
 
231
                Parameters:
 
232
                        signalName -- the signal details which are passed to this method.
 
233
                """
 
234
                profileName = None
 
235
                active = self.profileCombo.get_active()
 
236
 
 
237
                if signalDetails == "deleteProfile":
 
238
                        if active:
 
239
                                active -= 1
 
240
                
 
241
                self.profileComboModel.clear()
 
242
                for item in self.manager.GetMixdownProfileList():
 
243
                        self.profileComboModel.append((item,))
 
244
                        self.profileCombo.show_all()
 
245
                        if active > 0:
 
246
                                self.profileCombo.set_active(active)
 
247
                        else:
 
248
                                self.profileCombo.set_active(0)
 
249
                
 
250
                if self.CountRowsInTreeModel(self.profileComboModel) > 0:
 
251
                        profileName = self.profileComboModel[self.profileCombo.get_active()][0]
 
252
                self.UpdateActionTreeViewModel(profileName)
 
253
                        
 
254
        #_____________________________________________________________________
 
255
                
 
256
        def UpdateActionTreeViewModel(self, profileName):
 
257
                """
 
258
                Called when the action treeview (self.treeView) needs updating.
 
259
                Updates the MixdownActions in the treeview.
 
260
                
 
261
                Parameters:
 
262
                        profileName -- the name of the profile to use to retrieve MixdownActions from.
 
263
                """
 
264
                self.treeViewModel.clear()
 
265
                if profileName:
 
266
                        actions = self.manager.ReturnAllActionsFromMixdownProfile(profileName)
 
267
                        if actions:
 
268
                                for action in actions:
 
269
                                        action.connect("action-configured", self.ActionIsConfigured)
 
270
                                        self.treeViewModel.append( self.ReturnActionDisplayDetails(action) )
 
271
                self.OnCheckActionConfigured()
 
272
 
 
273
        #_____________________________________________________________________
 
274
        
 
275
        def ActionIsConfigured(self, action):
 
276
                """
 
277
                Called when a MixdownAction has been configured.
 
278
                Saves the MixdownActions present in the action treeview (self.treeView)
 
279
                to the currently selected profile (self.profileCombo).
 
280
                
 
281
                Parameters:
 
282
                        action -- the MixdownAction instance which has just been configured.
 
283
                """
 
284
                profileName = self.profileComboModel[self.profileCombo.get_active()][0]
 
285
                self.SaveProfileActions(profileName)
 
286
                
 
287
        #_____________________________________________________________________
 
288
        
 
289
        def ReturnActionPixbuf(self, action):
 
290
                """
 
291
                Called when the action treeview (self.treeView) needs to insert a
 
292
                pixbuf associated with a MixdownAction.
 
293
                Returns a pixbuf from the icon path specified by the MixdownAction.
 
294
                
 
295
                Parameters:
 
296
                        action -- the MixdownAction instance from which a pixbuf will be returned.
 
297
                        
 
298
                Returns:
 
299
                        pixbuf -- A gtk.gdk.Pixbuf associated with the MixdownAction.
 
300
                """
 
301
                if action.iconPath.startswith("gtk"):
 
302
                        pixbuf = self.treeView.render_icon(action.iconPath, gtk.ICON_SIZE_DIALOG)
 
303
                else:
 
304
                        pixbuf = gtk.gdk.pixbuf_new_from_file(action.iconPath)
 
305
        
 
306
                if pixbuf.get_property("width") and pixbuf.get_property("height") != 48:
 
307
                        scaled = pixbuf.scale_simple(48, 48, gtk.gdk.INTERP_BILINEAR)
 
308
                        return scaled
 
309
                else:
 
310
                        return pixbuf
 
311
        
 
312
        #_____________________________________________________________________
 
313
 
 
314
        def PopulateProfileComboBoxModel(self):
 
315
                """
 
316
                Populates the profile combo model (self.profileComboModel) with profiles
 
317
                in JOKOSHER_DATA_HOME/mixdownprofiles/
 
318
                """
 
319
                for profile in self.manager.GetMixdownProfileList():
 
320
                        self.profileComboModel.append((profile,))
 
321
                        
 
322
        #_____________________________________________________________________
 
323
        
 
324
        def OnProfileComboBoxChanged(self, widget):
 
325
                """
 
326
                Called when the profile combo box (self.profileCombo) contents change.
 
327
                Updates the action treeview (self.treeView) with the MixdownActions in
 
328
                the newly selected profile.
 
329
                
 
330
                Parameters:
 
331
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
332
                """
 
333
                if self.CountRowsInTreeModel(self.profileComboModel) > 0:
 
334
                        profileName = self.profileComboModel[self.profileCombo.get_active()][0]
 
335
                        self.UpdateActionTreeViewModel(profileName)
 
336
                else:
 
337
                        # if there is nothing in the combo model, then clear any actions that may be
 
338
                        # remaining in the action treeview
 
339
                        self.treeViewModel.clear()
 
340
                        
 
341
        #_____________________________________________________________________
 
342
 
 
343
        def OnAddProfile(self, widget):
 
344
                """
 
345
                Called when the Add Mixdown Profile button is clicked.
 
346
                Shows a dialog allowing the user to add MixdownActions
 
347
                to the currently selected profile (self.profileCombo).
 
348
                
 
349
                Parameters:
 
350
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
351
                """
 
352
                self.ShowAddProfileDialog()
 
353
                
 
354
        #_____________________________________________________________________
 
355
        
 
356
        def ShowAddProfileDialog(self):
 
357
                """
 
358
                Shows the Add Mixdown Profile dialog, allowing the user to create a MixdownProfile.
 
359
                """
 
360
                buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK)
 
361
                
 
362
                iconBox = gtk.HBox()
 
363
                iconBox.set_border_width(12)
 
364
                iconBox.set_spacing(12)
 
365
                iconImage = gtk.Image()
 
366
                iconImage.set_from_stock(gtk.STOCK_DIALOG_QUESTION, gtk.ICON_SIZE_DIALOG)
 
367
                iconLabel = gtk.Label(_("Please enter the name of the mixdown profile you wish to create."))
 
368
                iconLabel.set_line_wrap(True)
 
369
                
 
370
                iconBox.pack_start(iconImage, False, False)
 
371
                iconBox.pack_start(iconLabel, False, False)
 
372
                
 
373
                entryBox = gtk.HBox()
 
374
                entryBox.set_spacing(12)
 
375
                entryBox.set_border_width(6)
 
376
                profileEntry = gtk.Entry()
 
377
                entryBox.pack_start(gtk.Label(_("Profile name:")), False, False)
 
378
                entryBox.pack_start(profileEntry, True, True)
 
379
                
 
380
                dlg = gtk.Dialog(_("Create Mixdown Profile"), self.window, gtk.DIALOG_DESTROY_WITH_PARENT, buttons)
 
381
                dlg.set_default_size(375, 200)
 
382
                dlg.set_has_separator(False)
 
383
                dlg.set_default_response(gtk.RESPONSE_OK)
 
384
                
 
385
                dlg.vbox.set_spacing(6)
 
386
                dlg.vbox.pack_start(iconBox, False, False)
 
387
                dlg.vbox.pack_start(entryBox, False, False)
 
388
                dlg.vbox.show_all()
 
389
                response = dlg.run()
 
390
                
 
391
                if response == gtk.RESPONSE_OK:
 
392
                        msgdlg = gtk.MessageDialog(self.window,
 
393
                                        gtk.DIALOG_DESTROY_WITH_PARENT,
 
394
                                        gtk.MESSAGE_INFO,
 
395
                                        gtk.BUTTONS_CLOSE)
 
396
                        if profileEntry.get_text():
 
397
                                self.manager.SaveMixdownProfile(profileEntry.get_text())
 
398
                                msgdlg.set_markup(_("Successfully created mixdown profile <b>%s.profile</b>.") % profileEntry.get_text())
 
399
                                msgdlg.run()
 
400
                                msgdlg.destroy()
 
401
                        else:
 
402
                                msgdlg.set_markup(_("Cannot create mixdown profile. Please make sure you have specified a profile name."))
 
403
                                msgdlg.set_property("message-type", gtk.MESSAGE_ERROR)
 
404
                                msgdlg.run()
 
405
                                msgdlg.destroy()
 
406
                dlg.destroy()
 
407
                
 
408
        #_____________________________________________________________________
 
409
        
 
410
        def ShowActionErrorDialog(self, actionName, extensionName):
 
411
                """
 
412
                Called when an error has occured while loading MixdownActions.
 
413
                Shows a dialog informing the user that a MixdownAction has failed to load.
 
414
                
 
415
                Parameters:
 
416
                        actionName -- the name of the MixdownAction which cannot be loaded.
 
417
                        extensionName -- the name of the extension that the MixdownAction can't be loaded from.
 
418
                """
 
419
                msgdlg = gtk.MessageDialog(self.window,
 
420
                                gtk.DIALOG_DESTROY_WITH_PARENT,
 
421
                                gtk.MESSAGE_ERROR,
 
422
                                gtk.BUTTONS_CLOSE)
 
423
                message = _("Please make sure the extension <b>%s</b> is enabled." % extensionName)
 
424
                msgdlg.set_markup(_("<big><b>Cannot load mixdown action %s.</b></big>\n\n%s" % (actionName, message)))
 
425
                msgdlg.run()
 
426
                msgdlg.destroy()
 
427
                
 
428
        #_____________________________________________________________________
 
429
 
 
430
        def OnRemoveProfile(self, widget):
 
431
                """
 
432
                Called when the Remove Mixdown Profile button is clicked.
 
433
                Removes the currently selected profile in the profile
 
434
                combo box (self.profileCombo).
 
435
                
 
436
                Parameters:
 
437
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
438
                """
 
439
                if self.CountRowsInTreeModel(self.profileComboModel) > 0:
 
440
                        profileName = self.profileComboModel[self.profileCombo.get_active()][0]
 
441
                        self.manager.DeleteMixdownProfile(profileName)
 
442
                else:
 
443
                        return
 
444
        
 
445
        #_____________________________________________________________________
 
446
 
 
447
        def OnConfigureAction(self, widget):
 
448
                """
 
449
                Called when the Configure Mixdown Action button is clicked.
 
450
                Calls the selected MixdownAction's ConfigureAction method.
 
451
                
 
452
                Parameters:
 
453
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
454
                """
 
455
                if self.treeViewSelection.count_selected_rows() > 0:
 
456
                        selected = self.treeViewSelection.get_selected()
 
457
                        action = self.treeView.get_model() [selected[1]] [2]
 
458
                        action.ConfigureAction()
 
459
                else:
 
460
                        return
 
461
                
 
462
        #_____________________________________________________________________
 
463
 
 
464
        def OnAddAction(self, widget):
 
465
                """
 
466
                Called when the Add Mixdown Action button is clicked.
 
467
                Shows the Add Mixdown Action dialog, allowing the user to add a MixdownAction
 
468
                to the currently selected profile (self.profileCombo).
 
469
                
 
470
                Parameters:
 
471
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
472
                """
 
473
                if self.CountRowsInTreeModel(self.profileComboModel) > 0:
 
474
                        if self.profileComboModel[self.profileCombo.get_active()][0]:
 
475
                                self.ShowAddActionDialog()
 
476
                else:
 
477
                        return
 
478
 
 
479
        #_____________________________________________________________________
 
480
 
 
481
        def OnRemoveAction(self, widget):
 
482
                """
 
483
                Called when the Remove Action button is clicked.
 
484
                Removes the currently selected action from the action
 
485
                treeview (self.treeView)
 
486
                
 
487
                Parameters:
 
488
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
489
                """
 
490
                if self.treeViewSelection.count_selected_rows() > 0:
 
491
                        profileName = self.profileComboModel[self.profileCombo.get_active()][0]
 
492
                        iterpos = self.treeViewSelection.get_selected()[1]
 
493
                        self.treeView.get_model().remove(iterpos)
 
494
                        self.SaveProfileActions(profileName)
 
495
                else:
 
496
                        return
 
497
        
 
498
        #_____________________________________________________________________
 
499
        
 
500
        def ShowAddActionDialog(self):
 
501
                """
 
502
                Called when the Add Mixdown Action button is clicked.
 
503
                Shows a dialog which allows the user to add a MixdownAction
 
504
                to the currently selected profile (self.profileCombo)
 
505
                """
 
506
                AddMixdownActionDialog(self)
 
507
        
 
508
        #_____________________________________________________________________
 
509
 
 
510
        def SaveProfileActions(self, name):
 
511
                """
 
512
                Called when MixdownActions in a profile need to be saved.
 
513
                Saves MixdownActions to the profile specified.
 
514
                
 
515
                Parameters:
 
516
                        name -- name of the profile which the mixdown actions will be saved to.
 
517
                """
 
518
                actions = []
 
519
                for row in self.treeView.get_model():
 
520
                        actions.append(row[2])
 
521
                self.manager.SaveMixdownProfile(name, actions)
 
522
                
 
523
        #_____________________________________________________________________
 
524
 
 
525
        def OnDestroy(self, widget):
 
526
                """
 
527
                Called when the window is closed. Destroys the window.
 
528
                
 
529
                Parameters:
 
530
                        widget -- reserved for GTK callbacks, don't use it explicitly.
237
531
                """
238
532
                self.window.destroy()
239
533
        
240
534
        #_____________________________________________________________________
241
535
        
242
 
        def OnMixdown(self, button):
243
 
                """
244
 
                Called when the user clicks the Mix down button.
245
 
                
246
 
                Parameters:
247
 
                        button -- reserved for GTK callbacks, don't use it explicitly.
248
 
                """
249
 
                # TODO: show a progress bar in a window for these steps
250
 
                data = {}
251
 
                for action in self.actions:
252
 
                        # TODO: trap errors and abort if you find any
253
 
                        action.run(data)
254
 
                        
255
 
        #_____________________________________________________________________
256
 
        
257
 
        def OnSaveSettings(self, button):
258
 
                """
259
 
                Called when the user clicks the Save these settings button.
260
 
                
261
 
                Parameters:
262
 
                        button -- reserved for GTK callbacks, don't use it explicitly.
263
 
                """
264
 
                # create a window to ask for a title to save it as
265
 
                window = gtk.Window()
266
 
                vb = gtk.VBox()
267
 
                entry = gtk.Entry()
268
 
                buttonBox = gtk.HButtonBox()
269
 
                saveButton = gtk.Button(stock=gtk.STOCK_SAVE)
270
 
                cancelButton = gtk.Button(stock=gtk.STOCK_CANCEL)
271
 
                tooltips = gtk.Tooltips()
272
 
                
273
 
                window.set_transient_for(self.window)
274
 
                window.set_property("window-position", gtk.WIN_POS_CENTER)
275
 
                window.set_border_width(12)
276
 
                vb.set_spacing(6)
277
 
                buttonBox.set_layout(gtk.BUTTONBOX_END)
278
 
                buttonBox.set_spacing(6)
279
 
                tooltips.set_tip(saveButton, _("Save these mixdown settings"))
280
 
                tooltips.set_tip(cancelButton, _("Don't save these mixdown settings"))
281
 
                
282
 
                window.add(vb)
283
 
                vb.add(gtk.Label(_("Choose a name for this profile")))
284
 
                vb.add(entry)
285
 
                
286
 
                saveButton.connect("clicked", self.SaveProfile, entry, window)
287
 
                cancelButton.connect("clicked", lambda x:window.destroy())
288
 
                buttonBox.add(saveButton)
289
 
                buttonBox.add(cancelButton)
290
 
                vb.add(buttonBox)
291
 
                
292
 
                window.connect("delete_event", window.destroy)
293
 
                window.show_all()
294
 
                
295
 
        #_____________________________________________________________________
296
 
        
297
 
        def SaveProfile(self, button, entry, window):
298
 
                """
299
 
                Called when the user clicks the Save button when naming the profile.
300
 
                
301
 
                Parameters:
302
 
                        button -- reserved for GTK callbacks, don't use it explicitly.
303
 
                        entry -- the entry in the save window.
304
 
                        window -- the save window
305
 
                """
306
 
                
307
 
                profile_title = entry.get_text()
308
 
                outputxmlitems = [a.serialise() for a in self.actions]
309
 
                outputxml = "<mixdownprofile>\n%s\n</mixdownprofile>" % '\n'.join(outputxmlitems)
310
 
                
311
 
                savefolder = os.path.expanduser('~/.jokosher/mixdownprofiles') # created by Globals
312
 
                profile_file = os.path.join(savefolder, profile_title)
313
 
                fp = open(profile_file, "w")
314
 
                fp.write(outputxml)
315
 
                fp.close()
316
 
                
317
 
                window.destroy()
318
 
        
319
 
        #_____________________________________________________________________
320
 
 
321
 
        def RestoreProfile(self, profile_title):
322
 
                """
323
 
                Loads a previously saved profile.
324
 
                
325
 
                Parameters:
326
 
                        profile_title -- a profile name
327
 
                """
328
 
                savefolder = os.path.expanduser('~/.jokosher/mixdownprofiles') # created by Globals
329
 
                profile_file = os.path.join(savefolder, profile_title)
330
 
                
331
 
                from xml.dom import minidom
332
 
                dom = minidom.parse(profile_file)
333
 
                
334
 
                for element in dom.documentElement.childNodes:
335
 
                        if element.nodeType == 1: # an element, not a text node
336
 
                                action_name = element.nodeName
337
 
                                action_obj = getattr(MixdownProfiles,action_name)
338
 
                                
339
 
                                # specialcase ExportAsFileType
340
 
                                if action_obj == MixdownProfiles.ExportAsFileType:
341
 
                                        action = action_obj(self.project)
342
 
                                else:
343
 
                                        action = action_obj()
344
 
                                        
345
 
                                # now get all its saved properties
346
 
                                for subel in element.childNodes:
347
 
                                        if subel.nodeType == 1:
348
 
                                                name = subel.nodeName
349
 
                                                if subel.childNodes:
350
 
                                                        value = subel.firstChild.nodeValue
351
 
                                                else:
352
 
                                                        value = ""
353
 
                                                action.config[name] = value
354
 
                                # and add the action to this profile
355
 
                                self.AddAction(action)
356
 
                                
357
 
        #_____________________________________________________________________
358
 
        
 
536
        def OnMixdown(self, widget):
 
537
                """
 
538
                Called when the user clicks the Mixdown button.
 
539
                Calls the RunAction method on the MixdownActions
 
540
                in the action treeview (self.treeView). See RunAction in MixdownActions.py
 
541
                for more details.
 
542
                
 
543
                Parameters:
 
544
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
545
                """
 
546
 
 
547
                for row in self.treeViewModel:
 
548
                        action = row[2]
 
549
                        try:
 
550
                                action.RunAction()
 
551
                        except MixdownActions.MixdownActionException, e:
 
552
                                text = _("An error occured while running the mixdown action: %s") % action.name
 
553
                                text = "%s\n\n%s" % (text, e.message)
 
554
                                dlg = gtk.MessageDialog(self.window,
 
555
                                          gtk.DIALOG_DESTROY_WITH_PARENT,
 
556
                                          gtk.MESSAGE_ERROR,
 
557
                                          gtk.BUTTONS_CLOSE,
 
558
                                          text)
 
559
                                dlg.connect('response', lambda dlg, response: dlg.destroy())
 
560
                                dlg.show()
 
561
                                return
 
562
                        
 
563
        
 
564
        #_____________________________________________________________________
 
565
        
 
566
        def CountRowsInTreeModel(self, treeModel):
 
567
                """
 
568
                Called when the number of rows in the action treeview (self.treeView) is needed.
 
569
 
 
570
                Parameters:
 
571
                        treeModel -- the model to use when counting the number of rows.
 
572
 
 
573
                Returns:
 
574
                        rows -- number of rows in the action treeview.
 
575
                """
 
576
                rows = treeModel.iter_n_children(None)
 
577
                return rows
 
578
        
 
579
        #_____________________________________________________________________
 
580
 
 
581
 
 
582
#=========================================================================
 
583
 
 
584
class AddMixdownActionDialog:
 
585
        """
 
586
        This class allows the user to add a MixdownAction to the list of MixdownActions in
 
587
        the MixdownProfileDialog.
 
588
        """
 
589
        
 
590
        #_____________________________________________________________________
 
591
        
 
592
        def __init__(self, profileDialog):
 
593
                """
 
594
                Creates a new instance of MixdownProfileDialog.
 
595
                
 
596
                Parameters:
 
597
                        profileDialog -- reference to the MixdownProfileDialog object which calls this class.
 
598
                """
 
599
                self.profileDialog = profileDialog
 
600
                self.addActionDialogTree = gtk.glade.XML(Globals.GLADE_PATH, "AddMixdownActionDialog")
 
601
                
 
602
                signals = {
 
603
                        "on_cancel_button_clicked" : self.OnCancelAction,
 
604
                        "on_add_action_button_clicked" : self.OnAddAction,
 
605
                }
 
606
                        
 
607
                self.addActionDialogTree.signal_autoconnect(signals)
 
608
        
 
609
                self.addActionDialog = self.addActionDialogTree.get_widget("AddMixdownActionDialog")
 
610
                self.treeView = self.addActionDialogTree.get_widget("treeview")
 
611
                self.actionLabel = self.addActionDialogTree.get_widget("action_label")
 
612
                self.addActionButton = self.addActionDialogTree.get_widget("add_action_button")
 
613
                
 
614
                self.treeModel = gtk.ListStore(gtk.gdk.Pixbuf, str, object) # pixbuf, details, class instance
 
615
                self.treeView.set_model(self.treeModel)
 
616
                
 
617
                self.treeView.append_column(gtk.TreeViewColumn(_("Icon"), gtk.CellRendererPixbuf(), pixbuf=0))
 
618
                self.treeView.append_column(gtk.TreeViewColumn(_("Name"), gtk.CellRendererText(), markup=1))
 
619
                
 
620
                self.treeViewSelection = self.treeView.get_selection()
 
621
                self.treeViewSelection.connect("changed", self.UpdateSelectedActionAppearence)
 
622
                self.treeViewSelection.set_mode(gtk.SELECTION_SINGLE)
 
623
                
 
624
                self.profileName = self.profileDialog.profileComboModel[self.profileDialog.profileCombo.get_active()][0]
 
625
                
 
626
                self.lastAction = None
 
627
                self.lastSelected = None
 
628
                
 
629
                # set some properties for the widgets
 
630
                self.addActionDialog.set_transient_for(self.profileDialog.window)
 
631
                self.addActionDialog.set_icon(self.profileDialog.window.get_icon())
 
632
                self.actionLabel.set_markup(_("Please select the mixdown actions you would like to add to mixdown profile <b>%s.</b>") % self.profileName)
 
633
        
 
634
                self.PopulateActionModel()
 
635
        
 
636
        #_____________________________________________________________________
 
637
        
 
638
        def UpdateSelectedActionAppearence(self, widget):
 
639
                """
 
640
                Called when a MixdownAction is selected in the add action treeview (self.treeView).
 
641
                Changes the appearence of the selected action.
 
642
                
 
643
                Parameters:
 
644
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
645
                """
 
646
                selected = self.treeViewSelection.get_selected()
 
647
                action = self.treeModel [selected[1]] [2]
 
648
                
 
649
                # set the foreground colour of the text to white
 
650
                newText = "<span size='larger' weight='bold'>%s</span>\n" % action.name  \
 
651
                + "<span size='smaller' foreground='white'>%s</span>" % action.description
 
652
                self.treeModel [selected[1]] [1] = newText
 
653
                
 
654
                # modify the last selected item in the model to use the default colour grey
 
655
                if self.lastSelected:
 
656
                        oldText = "<span size='larger' weight='bold'>%s</span>\n" % self.lastAction.name  \
 
657
                        + "<span size='smaller' foreground='dim grey'>%s</span>" % self.lastAction.description
 
658
                        self.treeModel [self.lastSelected[1]] [1] = oldText
 
659
                
 
660
                self.lastAction = action
 
661
                self.lastSelected = selected
 
662
        
 
663
        #_____________________________________________________________________
 
664
 
 
665
        def ReturnAllActions(self):
 
666
                """
 
667
                Returns all actions in MixdownActions.py, excluding the MixdownAction class.
 
668
                
 
669
                Returns:
 
670
                        actionList -- list of MixdownAction instances
 
671
                """
 
672
                actionList = []
 
673
                for action in self.profileDialog.mainapp.registerMixdownActionAPI.ReturnAllActions():
 
674
                        # we have to pass Project to ExportAsFileType for it to work
 
675
                        if action.__name__ == "ExportAsFileType":
 
676
                                actionList.append( action(self.profileDialog.project) )
 
677
                        else:
 
678
                                actionList.append( action() )
 
679
                # a list of MixdownAction instances should be returned
 
680
                return actionList
 
681
 
 
682
        #_____________________________________________________________________
 
683
 
 
684
        def PopulateActionModel(self):
 
685
                """
 
686
                Called when the action model (self.treeModel) needs to be populated.
 
687
                """
 
688
                for action in self.ReturnAllActions():
 
689
                        self.treeModel.append( self.profileDialog.ReturnActionDisplayDetails(action) )
 
690
                
 
691
        #_____________________________________________________________________
 
692
 
 
693
        def OnAddAction(self, widget):
 
694
                """
 
695
                Called when the Add Action button is clicked.
 
696
                Adds the selected MixdownAction to the profile dialog's action
 
697
                model (self.profileDialog.treeViewModel).
 
698
                
 
699
                Parameters:
 
700
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
701
                """
 
702
                if self.treeViewSelection.count_selected_rows() > 0:
 
703
                        selected = self.treeViewSelection.get_selected()
 
704
                        action = self.treeModel [selected[1]] [2]
 
705
                        self.profileDialog.AddActionToActionModel(self.profileName, action)
 
706
                else:
 
707
                        return
 
708
                self.addActionDialog.destroy()
 
709
                        
 
710
        #_____________________________________________________________________
 
711
        
 
712
        def OnCancelAction(self, widget):
 
713
                """
 
714
                Called when the Cancel button is clicked.
 
715
                Destroys the Add Mixdown Action dialog
 
716
                
 
717
                Parameters:
 
718
                        widget -- reserved for GTK callbacks, don't use it explicitly.
 
719
                """
 
720
                self.addActionDialog.destroy()
 
721
        
 
722
        #_____________________________________________________________________
 
723
 
359
724
#=========================================================================