=== added file 'serpentine/compatxml.py' --- serpentine/compatxml.py 1970-01-01 00:00:00 +0000 +++ serpentine/compatxml.py 2008-03-07 16:02:11 +0000 @@ -0,0 +1,29 @@ +""" +Compability layer of XML. +""" +try: + from Ft.Xml.Domlette import NonvalidatingReader + parseUri = NonvalidatingReader.parseUri + parseString = NonvalidatingReader.parseString + del NonvalidatingReader + from Ft.Xml.XPath import Evaluate +except ImportError: + from xml.dom.minidom import parse as parseUri + from xml.dom.minidom import parseString + from xml.xpath import Evaluate + +def get_node_attr(node, attr): + """ + Tries to uniform the way to get the *value* of an attribute in + both minidom and in 4Suite. + """ + try: + return node.attributes[attr].value + except KeyError: + return node.attributes[(None, attr)].value + +def node_contains_attr(node, attr): + """ + Uniforms the attributes in both minidom and in 4Suite. + """ + return attr in node.attributes or (None, attr) in node.attributes === modified file '.bzrignore' --- .bzrignore 2007-08-02 16:40:45 +0000 +++ .bzrignore 2007-08-22 19:44:07 +0000 @@ -30,3 +30,4 @@ ./dist ./muine-plugin/Makefile ./muine-plugin/Makefile.in +*.mo === modified file 'Makefile.am' --- Makefile.am 2007-08-13 15:30:11 +0000 +++ Makefile.am 2008-03-07 13:00:31 +0000 @@ -34,6 +34,7 @@ serpentine/common.py \ serpentine/urlutil.py \ serpentine/errors.py \ + serpentine/compatxml.py \ serpentine/release.py serpentine_pluginsdir = $(pythondir)/serpentine/plugins === modified file 'NEWS' --- NEWS 2006-06-12 23:43:15 +0000 +++ NEWS 2007-09-01 16:58:04 +0000 @@ -1,11 +1,36 @@ -Changes from 0.6.4: +serpentine 0.9.1: + - Dutch (nl) translation by Frederik Himpe . + +serpentine 0.9: + - Support for totem-plparser 2.19 (#463180). + - Set the device from the command line and make it persistent (#333281). + - Able to write the same file more than once in the same playlist (#465352). + - Files can now be removed from the list while recording (#345270). + - When cache location is unavailable allow the user to select another + (#382145). + - Serpentine now inhibits suspension while recording, via GNOME Power Manager. + Contribution from Matthew Martin (#344948). + - Mastering widget is now aware of the two seconds gap between + tracks (#344689). + +serpentine 0.7: + - Added keybindings. + - Made the UI more persistent. + - Finnish (fi) translation by Timo Jyrinki . + - Portuguese (pt) translation by Tiago Cogumbreiro + - Spanish (es) translation by Rafael Bermúdez . + - Improved audio decoding algorithm. + - More checks before writing the CD. + - Improved the detection of temporary directory (#342342). + +serpentine 0.6.9: - Support for GStreamer 0.10 - Ability to open files through the command line. - Uses Cairo to draw the usage gauge. - Ability to not use GnomeVfs - More robust metadata parsing and not media files handling -Changes from 0.6.3: +serpentine 0.6.4: - Added the possibility to add Rhythmbox playlists. - Spanish (es) translation by Rafael Bermúdez - German (de) translation by Julian Turner @@ -18,33 +43,33 @@ Rafael Peregrino - Bug fixes -Changes from 0.6.2: +serpentine 0.6.3: - Bug fixes release. -Changes from 0.6.1: +serpentine 0.6.2: - Support for K3B audio projects - Possibility to choose to add 2 seconds silence gap between tracks - i18n enabled and Portuguese translation - Lots of bugfixes -Changes from 0.6: - - HIG compliance fixes: toolbar buttons now have tooltips and react to system preferences - on toolbar style and detachable state. - - Fixed a bug that made new installations of serpentine not work (regretion introduced in 0.6). - - Removed cache location widgets, you can still set it in gconf key: "/apps/serpentine/temporary_dir" +serpentine 0.6.1: + - HIG compliance fixes: toolbar buttons now have tooltips and react to system + preferences on toolbar style and detachable state. + - Fixed a bug that made new installations of serpentine not work (regretion + introduced in 0.6). + - Removed cache location widgets, you can still set it in gconf key: + "/apps/serpentine/temporary_dir" - Muine plugin is now bundled in tarball - Added a button in the preferences to refresh maximum speed -Changes from 0.5: - - New usage widget: progressbar should be used for progress. The new usage disc widget - improves the user experience by reflecting the disc contents in a disc like display. - - - Integration friendly: special command line arguments make integration with other - applications easier. - +serpentine 0.6: + - New usage widget: progressbar should be used for progress. The new usage + disc widget improves the user experience by reflecting the disc contents in + a disc like display. + - Integration friendly: special command line arguments make integration with + other applications easier. - New Muine plugin: you can write your playlist to a CD directly from Muine. - - - Save and load playlist: you can now open and save playlists inside Serpentine. - - - User interface polish: the user interface was improved and made more similar to - nautilus-cd-burner. + - Save and load playlist: you can now open and save playlists inside + Serpentine. + - User interface polish: the user interface was improved and made more similar + to nautilus-cd-burner. === modified file 'po/nl.po' Binary files po/nl.po 2007-08-22 19:38:48 +0000 and po/nl.po 2007-09-01 16:40:18 +0000 differ === modified file 'po/serpentine.pot' --- po/serpentine.pot 2006-06-11 23:09:13 +0000 +++ po/serpentine.pot 2007-08-22 19:30:37 +0000 @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2006-06-11 22:52+0000\n" +"POT-Creation-Date: 2007-08-22 19:30+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -96,8 +96,8 @@ msgid "Serpentine Audio Mastering" msgstr "" -#: ../data/serpentine.glade.h:21 ../serpentine/preferences.py:71 -#: ../serpentine/preferences.py:197 +#: ../data/serpentine.glade.h:21 ../serpentine/preferences.py:69 +#: ../serpentine/preferences.py:265 msgid "Serpentine Preferences" msgstr "" @@ -109,7 +109,7 @@ msgid "Write playlist to disc" msgstr "" -#: ../data/serpentine.glade.h:24 ../serpentine/mainwindow.py:569 +#: ../data/serpentine.glade.h:24 ../serpentine/mainwindow.py:718 msgid "Write to Disc" msgstr "" @@ -137,403 +137,415 @@ msgid "Recording operations will be done in simulation mode." msgstr "" -#: ../scripts/serpentine:60 +#: ../scripts/serpentine:62 msgid "Shows debugging information from recording backend." msgstr "" -#: ../scripts/serpentine:63 +#: ../scripts/serpentine:67 msgid "Shows preferences dialog." msgstr "" -#: ../scripts/serpentine:66 +#: ../scripts/serpentine:70 +msgid "Sets the default device to be used." +msgstr "" + +#: ../scripts/serpentine:75 msgid "" "Writes the filenames after this option to a CD. This will show a dialog " "suitable for embedding in other applications." msgstr "" -#: ../scripts/serpentine:71 +#: ../scripts/serpentine:80 msgid "Uses filenames after this option as the playlist contents." msgstr "" -#: ../scripts/serpentine:75 +#: ../scripts/serpentine:84 msgid "Do not use GnomeVfs module." msgstr "" -#: ../scripts/serpentine:132 +#: ../scripts/serpentine:145 msgid "Simulation mode" msgstr "" -#: ../scripts/serpentine:133 +#: ../scripts/serpentine:146 msgid "" "Serpentine is on simulation mode, no actual writing will be done on inserted " "media." msgstr "" -#: ../serpentine/__init__.py:63 +#: ../serpentine/__init__.py:66 msgid "The following musics have missing files:" msgstr "" -#: ../serpentine/__init__.py:90 +#: ../serpentine/__init__.py:92 msgid "Please check if the cache location exists and has writable permissions." msgstr "" -#: ../serpentine/__init__.py:100 ../serpentine/__init__.py:239 +#: ../serpentine/__init__.py:107 ../serpentine/__init__.py:306 msgid "All files" msgstr "" -#: ../serpentine/__init__.py:104 ../serpentine/__init__.py:290 +#: ../serpentine/__init__.py:111 ../serpentine/__init__.py:357 msgid "Supported playlists" msgstr "" -#: ../serpentine/__init__.py:282 +#: ../serpentine/__init__.py:349 msgid "Common media files" msgstr "" -#: ../serpentine/common.py:71 +#: ../serpentine/common.py:72 msgid "GByte" msgstr "" -#: ../serpentine/common.py:71 +#: ../serpentine/common.py:72 msgid "GBytes" msgstr "" -#: ../serpentine/common.py:72 +#: ../serpentine/common.py:73 msgid "MByte" msgstr "" -#: ../serpentine/common.py:72 +#: ../serpentine/common.py:73 msgid "MBytes" msgstr "" -#: ../serpentine/common.py:73 +#: ../serpentine/common.py:74 msgid "KByte" msgstr "" -#: ../serpentine/common.py:74 +#: ../serpentine/common.py:75 msgid "byte" msgstr "" -#: ../serpentine/common.py:74 +#: ../serpentine/common.py:75 msgid "bytes" msgstr "" -#: ../serpentine/mainwindow.py:152 +#: ../serpentine/mainwindow.py:156 msgid "Save playlist in format:" msgstr "" -#: ../serpentine/mainwindow.py:166 +#: ../serpentine/mainwindow.py:170 msgid "Detect by extension" msgstr "" -#: ../serpentine/mainwindow.py:183 +#: ../serpentine/mainwindow.py:187 msgid "Playlist Not Saved" msgstr "" -#: ../serpentine/mainwindow.py:184 +#: ../serpentine/mainwindow.py:188 msgid "There was an error while saving the playlist." msgstr "" -#: ../serpentine/mainwindow.py:221 +#: ../serpentine/mainwindow.py:225 msgid "Replace existing file" msgstr "" -#: ../serpentine/mainwindow.py:222 +#: ../serpentine/mainwindow.py:226 #, python-format msgid "" "A file named %s already exists. Do you want to replace it with the " "one you are saving?" msgstr "" -#: ../serpentine/mainwindow.py:249 +#: ../serpentine/mainwindow.py:253 msgid "Select one playlist format" msgstr "" -#: ../serpentine/mainwindow.py:250 +#: ../serpentine/mainwindow.py:254 msgid "" "Serpentine will open any of these formats so the one you choose only matters " "if you are going to open with other applications." msgstr "" -#: ../serpentine/mainwindow.py:253 +#: ../serpentine/mainwindow.py:257 #, python-format msgid "Do you want to save as the %s format?" msgstr "" -#: ../serpentine/mainwindow.py:281 +#: ../serpentine/mainwindow.py:285 msgid "Unsupported Format" msgstr "" -#: ../serpentine/mainwindow.py:282 +#: ../serpentine/mainwindow.py:286 msgid "" "The playlist format you used (by the file extension) is currently not " "supported." msgstr "" -#: ../serpentine/mainwindow.py:464 +#: ../serpentine/mainwindow.py:474 +msgid "Cache location:" +msgstr "" + +#: ../serpentine/mainwindow.py:586 msgid "No recording drive found" msgstr "" -#: ../serpentine/mainwindow.py:465 +#: ../serpentine/mainwindow.py:587 msgid "" "No recording drive found on your system, therefore some of Serpentine's " "functionalities will be disabled." msgstr "" -#: ../serpentine/mainwindow.py:532 +#: ../serpentine/mainwindow.py:672 msgid "translator-credits" msgstr "" -#: ../serpentine/mainwindow.py:533 +#: ../serpentine/mainwindow.py:673 msgid "Audio CD Creator" msgstr "" -#: ../serpentine/mainwindow.py:546 +#: ../serpentine/mainwindow.py:689 msgid "Cache directory location unavailable" msgstr "" -#: ../serpentine/mainwindow.py:550 +#: ../serpentine/mainwindow.py:693 msgid "Not enough space on cache directory" msgstr "" -#: ../serpentine/mainwindow.py:557 +#: ../serpentine/mainwindow.py:706 msgid "Do you want to overburn your disc?" msgstr "" -#: ../serpentine/mainwindow.py:558 +#: ../serpentine/mainwindow.py:707 msgid "" "You are about to record a media disc in overburn mode. This may not work on " "all drives and shouldn't give you more then a couple of minutes." msgstr "" -#: ../serpentine/mainwindow.py:561 +#: ../serpentine/mainwindow.py:710 msgid "Write to Disc (Overburning)" msgstr "" -#: ../serpentine/mainwindow.py:564 +#: ../serpentine/mainwindow.py:713 msgid "Do you want to record your music?" msgstr "" -#: ../serpentine/mainwindow.py:565 +#: ../serpentine/mainwindow.py:714 msgid "" "You are about to record a media disc. Canceling a writing operation will " "make your disc unusable." msgstr "" -#: ../serpentine/mastering.py:73 +#: ../serpentine/mastering.py:83 msgid "Unsupported file type" msgstr "" -#: ../serpentine/mastering.py:79 +#: ../serpentine/mastering.py:89 msgid "The following file was not added:" msgstr "" -#: ../serpentine/mastering.py:86 +#: ../serpentine/mastering.py:96 msgid "" "If you're having problems opening certain files make sure you have the " "GStreamer plugins needed to decode them." msgstr "" -#: ../serpentine/mastering.py:145 +#: ../serpentine/mastering.py:152 msgid "Unknown" msgstr "" -#: ../serpentine/mastering.py:146 +#: ../serpentine/mastering.py:153 msgid "Unknown Artist" msgstr "" -#: ../serpentine/mastering.py:609 +#: ../serpentine/mastering.py:740 msgid "Track" msgstr "" -#: ../serpentine/mastering.py:622 +#: ../serpentine/mastering.py:747 +msgid "Title" +msgstr "" + +#: ../serpentine/mastering.py:753 msgid "Artist" msgstr "" -#: ../serpentine/mastering.py:625 +#: ../serpentine/mastering.py:756 msgid "Duration" msgstr "" #. To translators: I know this is ugly for you -#: ../serpentine/mastering.py:726 +#: ../serpentine/mastering.py:859 msgid "minute" msgstr "" -#: ../serpentine/mastering.py:726 +#: ../serpentine/mastering.py:859 msgid "minutes" msgstr "" #. To translators: I know this is ugly for you -#: ../serpentine/mastering.py:730 +#: ../serpentine/mastering.py:863 msgid "second" msgstr "" -#: ../serpentine/mastering.py:730 +#: ../serpentine/mastering.py:863 msgid "seconds" msgstr "" -#: ../serpentine/mastering.py:732 +#: ../serpentine/mastering.py:865 msgid " and " msgstr "" -#: ../serpentine/mastering.py:766 +#: ../serpentine/mastering.py:895 #, python-format msgid "%s remaining" msgstr "" -#: ../serpentine/mastering.py:768 +#: ../serpentine/mastering.py:897 #, python-format msgid "%s overlaping" msgstr "" -#: ../serpentine/mastering.py:770 +#: ../serpentine/mastering.py:899 msgid "Empty" msgstr "" -#: ../serpentine/plugins/plugrhythmbox.py:41 +#: ../serpentine/plugins/plugrhythmbox.py:54 msgid "No Rhythmbox playlist found" msgstr "" -#: ../serpentine/plugins/plugrhythmbox.py:42 +#: ../serpentine/plugins/plugrhythmbox.py:55 msgid "" "Please create a playlist using Music→Playlist→New Playlist..." "" msgstr "" -#: ../serpentine/plugins/plugrhythmbox.py:48 +#: ../serpentine/plugins/plugrhythmbox.py:62 msgid "Which playlist do you choose to open?" msgstr "" -#: ../serpentine/plugins/plugrhythmbox.py:49 +#: ../serpentine/plugins/plugrhythmbox.py:63 msgid "These are the playlists created on Rhythmbox." msgstr "" -#: ../serpentine/plugins/plugrhythmbox.py:50 +#: ../serpentine/plugins/plugrhythmbox.py:64 #, python-format msgid "Do you want to open the playlist %s?" msgstr "" -#: ../serpentine/plugins/plugrhythmbox.py:51 +#: ../serpentine/plugins/plugrhythmbox.py:65 msgid "Rhythmbox playlists:" msgstr "" -#: ../serpentine/plugins/plugrhythmbox.py:70 +#: ../serpentine/plugins/plugrhythmbox.py:85 msgid "Open Rhythmbox Playlist..." msgstr "" -#: ../serpentine/preferences.py:361 ../serpentine/preferences.py:379 +#: ../serpentine/preferences.py:464 ../serpentine/preferences.py:482 msgid "Serpentine's playlist" msgstr "" -#: ../serpentine/recording.py:43 ../serpentine/recording.py:50 +#: ../serpentine/recording.py:45 ../serpentine/recording.py:52 msgid "Converting files failed" msgstr "" -#: ../serpentine/recording.py:44 +#: ../serpentine/recording.py:46 msgid "Some of the files were missing. The disc is still usable." msgstr "" -#: ../serpentine/recording.py:51 +#: ../serpentine/recording.py:53 msgid "Writing to disc didn't start so it is still usable." msgstr "" -#: ../serpentine/recording.py:64 +#: ../serpentine/recording.py:66 msgid "Writing to disc failed" msgstr "" -#: ../serpentine/recording.py:66 +#: ../serpentine/recording.py:68 msgid "Writing to disc canceled" msgstr "" -#: ../serpentine/recording.py:69 +#: ../serpentine/recording.py:71 msgid "The writing operation has started. The disc may be unusable." msgstr "" -#: ../serpentine/recording.py:90 +#: ../serpentine/recording.py:92 msgid "Writing Audio Disc" msgstr "" -#: ../serpentine/recording.py:91 +#: ../serpentine/recording.py:93 msgid "" "The audio tracks are going to be written to a disc. This operation may take " "a long time, depending on data size and write speed." msgstr "" -#: ../serpentine/recording.py:124 +#: ../serpentine/recording.py:127 msgid "CD-RW disc will be erased" msgstr "" -#: ../serpentine/recording.py:125 -msgid "Please remove your disc if you want to preserve it's contents." +#: ../serpentine/recording.py:128 +msgid "Please remove your disc if you want to preserve its contents." msgstr "" -#: ../serpentine/recording.py:172 +#: ../serpentine/recording.py:177 msgid "Preparing recorder" msgstr "" -#: ../serpentine/recording.py:174 +#: ../serpentine/recording.py:179 msgid "Writing media files to disc" msgstr "" -#: ../serpentine/recording.py:176 +#: ../serpentine/recording.py:181 msgid "Fixating disc" msgstr "" -#: ../serpentine/recording.py:184 +#: ../serpentine/recording.py:189 msgid "Preparing media files" msgstr "" -#: ../serpentine/recording.py:199 +#: ../serpentine/recording.py:202 msgid "Writing to disc finished" msgstr "" -#: ../serpentine/recording.py:200 +#: ../serpentine/recording.py:203 msgid "Disc writing was successful." msgstr "" -#: ../serpentine/recording.py:231 +#: ../serpentine/recording.py:235 msgid "Writing Files to Disc" msgstr "" -#: ../serpentine/recording.py:250 +#: ../serpentine/recording.py:254 msgid "There were no valid files for writing. Please select at least one." msgstr "" -#: ../serpentine/recording.py:302 +#: ../serpentine/recording.py:306 msgid "Please make sure another application is not using the drive." msgstr "" -#: ../serpentine/recording.py:303 +#: ../serpentine/recording.py:307 msgid "Drive is busy" msgstr "" -#: ../serpentine/recording.py:305 +#: ../serpentine/recording.py:309 msgid "Please put a rewritable or blank disc into the drive." msgstr "" -#: ../serpentine/recording.py:306 +#: ../serpentine/recording.py:310 msgid "Insert rewritable or blank disc" msgstr "" -#: ../serpentine/recording.py:308 +#: ../serpentine/recording.py:312 msgid "Please put a blank disc into the drive." msgstr "" -#: ../serpentine/recording.py:309 +#: ../serpentine/recording.py:313 msgid "Insert blank disc" msgstr "" -#: ../serpentine/recording.py:311 +#: ../serpentine/recording.py:315 msgid "Please replace the disc in the drive with a rewritable or blank disc." msgstr "" -#: ../serpentine/recording.py:314 +#: ../serpentine/recording.py:318 msgid "Reload rewritable or blank disc" msgstr "" -#: ../serpentine/recording.py:316 +#: ../serpentine/recording.py:320 msgid "Please replace the disc in the drive a blank disc." msgstr "" -#: ../serpentine/recording.py:317 +#: ../serpentine/recording.py:321 msgid "Reload blank disc" msgstr "" === modified file 'serpentine/__init__.py' --- serpentine/__init__.py 2007-08-13 21:44:01 +0000 +++ serpentine/__init__.py 2008-03-07 13:02:42 +0000 @@ -29,21 +29,24 @@ import statvfs from gettext import gettext as _ +from gettext import ngettext as N_ # Private modules from serpentine import operations from serpentine import urlutil -from serpentine.operations import (CallbackListener, SuccessfulOperation, - OperationsQueue, Listenable, - CallableOperation) + +from serpentine.operations import CallbackListener, SuccessfulOperation +from serpentine.operations import OperationsQueue, Listenable +from serpentine.operations import CallableOperation from serpentine.mastering import GtkMusicList, MusicListGateway from serpentine.mastering import ErrorTrapper from serpentine.recording import ConvertAndWrite from serpentine.preferences import RecordingPreferences from serpentine.components import Component from serpentine.mainwindow import SerpentineWindow -from serpentine.common import SerpentineNotSupportedError, SerpentineCacheError +from serpentine.common import SerpentineNotSupportedError +from serpentine.common import SerpentineCacheError, MissingFilesCacheError from serpentine.plugins import plugins PATTERN_SEPARATOR = ";" @@ -61,11 +64,10 @@ secs += music["duration"] if len(missing_musics) > 0: - raise SerpentineCacheError(SerpentineCacheError.INVALID, - "%s\n%s" % ( - _("The following musics have missing files:"), - "\n".join(missing_musics) - )) + raise MissingFilesCacheError(N_("The following file is missing:", + "The following files are missing:", + len(missing_musics)), + missing_musics) # 44100hz * 16bit * 2channels / 8bits = 176400 bytes per sec size_needed = secs * 176400L @@ -89,9 +91,8 @@ # Yay we have the needed space return - raise SerpentineCacheError(SerpentineCacheError.INVALID, _("Please " - "check if the cache location exists and " - "has writable permissions.")) + raise InvalidCacheError(_("Please check if the cache location exists and " + "has writable permissions.")) @@ -457,7 +458,7 @@ """ # Clean window object Application.stop(self) - self.__window.destroy() +# self.__window.destroy() del self.__window === modified file 'serpentine/common.py' --- serpentine/common.py 2007-08-13 21:42:36 +0000 +++ serpentine/common.py 2007-10-15 10:46:47 +0000 @@ -53,18 +53,23 @@ class SerpentineError (StandardError): pass + class SerpentineCacheError (SerpentineError): - INVALID = 1 - NO_SPACE = 2 - def __init__ (self, error_id, error_message): - self.__error_id = error_id - self.__error_message = error_message - - error_id = property (lambda self: self.__error_id) - error_message = property (lambda self: self.__error_message) - - def __str__ (self): - return "[Error %d] %s" % (self.error_id, self.error_message) + """The class of errors related to cache errors.""" + +class InvalidCacheError(SerpentineCacheError): + """Raised when the permissions are wrong.""" + +class NoSpaceCacheError(SerpentineCacheError): + """Raised when there is no space left on the cache.""" + +class MissingFilesCacheError(SerpentineCacheError): + """ + Raised when some files from the cache are missing. + """ + def __init__(self, message, files): + super(MissingFilesCacheError, self).__init__(message) + self.files = files class SerpentineNotSupportedError (SerpentineError): pass === modified file 'serpentine/gtkutil.py' --- serpentine/gtkutil.py 2007-08-10 18:09:15 +0000 +++ serpentine/gtkutil.py 2007-10-15 10:53:35 +0000 @@ -300,7 +300,11 @@ lbl.set_alignment(0, 0) if len(self._args) == 1: - lbl.set_markup(self._args[0]) + txt = self._args[0] + if txt is None or txt == "": + lbl.hide() + else: + lbl.set_markup(self._args[0]) lbl.set_selectable(True) lbl.set_line_wrap(True) === modified file 'serpentine/mainwindow.py' --- serpentine/mainwindow.py 2007-08-13 21:47:17 +0000 +++ serpentine/mainwindow.py 2007-10-15 10:52:26 +0000 @@ -25,14 +25,16 @@ # Local imports from serpentine import (operations, gaw, gtkutil) + from serpentine.preferences import KEY_TEMP_ISO_DIR from serpentine.components import Component from serpentine.operations import MapProxy, OperationListener from serpentine.mastering import AudioMastering from serpentine.gtkutil import SetupAlert -from serpentine.common import (SerpentineNotSupportedError, parse_key_event, - SerpentineCacheError) +from serpentine.common import SerpentineNotSupportedError, parse_key_event +from serpentine.common import SerpentineCacheError, MissingFilesCacheError from gettext import gettext as _ +from gettext import ngettext as N_ D_G_INTERFACE = "/desktop/gnome/interface" @@ -683,21 +685,27 @@ self.__application.validate_files() except SerpentineCacheError, err: - show_prefs = False - - if err.error_id == SerpentineCacheError.INVALID: - title = _("Cache directory location unavailable") - show_prefs = True + if isinstance(err, MissingFilesCacheError): + gtkutil.list_dialog(_("Cannot write the CD"), + None, + list_title=err.message, + parent=self, + items=err.files, + stock=gtk.STOCK_DIALOG_ERROR, + buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_OK), + ) + else: + if isinstance(err, InvalidCacheError): + title = _("Cache directory location unavailable") - elif err.error_id == SerpentineCacheError.NO_SPACE: - title = _("Not enough space on cache directory") - # TODO: see bug #344688 - gtkutil.dialog_warn( - title, - gobject.markup_escape_text(err.error_message), - _setup_alert=SetupCacheAlert, - parent=self - ) + elif isinstance(err, NoSpaceCacheError): + title = _("Not enough space on cache directory") + + gtkutil.dialog_warn( + title, + gobject.markup_escape_text(err.message), + _setup_alert=SetupCacheAlert, + parent=self) return === modified file 'serpentine/operations.py' --- serpentine/operations.py 2007-08-18 13:13:37 +0000 +++ serpentine/operations.py 2007-09-01 17:46:23 +0000 @@ -232,6 +232,46 @@ running = property(lambda self: False) +class StartableOperation(Operation): + """ + This operation wraps an operation and adds an event named + `on_start`, which is triggered before starting the wrapped + operation. + + on_start(decorator, decorated) + - decorator, an instance of the `StartableOperation` + - decorated, the operation being decorated with the + `on_start` event. + + Note that ownership of the event is changed to + `StartableOperation`. + """ + def __init__(self, oper): + super(StartableOperation, self).__init__() + self.oper = oper + self.oper.add_listener(self) + + def on_finished(self, event): + self._propagate(event, self) + + can_start = property(lambda x: x.oper.can_start) + can_stop = property(lambda x: x.oper.can_stop) + running = property(lambda x: x.oper.running) + + def start(self): + self._notify('on_start', self, self.oper) + self.oper.start() + + def __getattr__(self, attr): + if attr == 'progress': + return getattr(self.oper, attr) + raise AttributeError(attr) + + def __hasattr__(self, attr): + if attr == 'progress': + return hasattr(self.oper, attr) + return False + def operation_factory(func): """ === modified file 'serpentine/plugins/plugfilter_k3b.py' --- serpentine/plugins/plugfilter_k3b.py 2007-08-02 17:26:16 +0000 +++ serpentine/plugins/plugfilter_k3b.py 2008-03-07 16:00:09 +0000 @@ -21,8 +21,8 @@ import zipfile, gnomevfs -from xml.dom import minidom -from xml.xpath import Evaluate +from serpentine.compatxml import parseString, Evaluate, get_node_attr + from xml.parsers.expat import ExpatError from serpentine.mastering import HintsFilter @@ -70,7 +70,7 @@ try: zfile = zipfile.ZipFile(fd) buff = zfile.read("maindata.xml") - root = minidom.parseString(buff) + root = parseString(buff) except (zipfile.BadZipfile, IOError, KeyError, ExpatError): raise UnsupportedLocationError() @@ -81,7 +81,7 @@ hints_list = [] for node in Evaluate ("/k3b_audio_project/contents/track", root): try: - hints_list.append ({"location": node.attributes["url"].value}) + hints_list.append ({"location": get_node_attr(node, "url")}) except KeyError: # skip elements without the 'url' attribute set pass @@ -92,9 +92,8 @@ for node in Evaluate ("/k3b_audio_project/contents/track/sources/file", root): try: - hints_list.append ({"location": node.attributes["url"].value}) + hints_list.append ({"location": get_node_attr(node, "url")}) except KeyError: - # skip elements with not 'url' attribute set pass return hints_list === modified file 'serpentine/plugins/plugrhythmbox.py' --- serpentine/plugins/plugrhythmbox.py 2007-08-14 08:43:07 +0000 +++ serpentine/plugins/plugrhythmbox.py 2008-03-07 16:02:39 +0000 @@ -3,8 +3,8 @@ import os.path import weakref -from xml.xpath import Evaluate -from xml.dom import minidom +from serpentine.compatxml import Evaluate, parseUri, get_node_attr, node_contains_attr + from gettext import gettext as _ if __name__ == '__main__': @@ -20,17 +20,17 @@ def rhythmbox_list_names(): try: - root = minidom.parse(PLAYLISTS) + root = parseUri(PLAYLISTS) except IOError: return () nodes = Evaluate("/rhythmdb-playlists/playlist", root) - return [node.attributes["name"].value for node in nodes] + return [get_node_attr(node, "name") for node in nodes if node_contains_attr(node, "name")] def rhythmbox_get_playlist(playlist_name): try: - root = minidom.parse(PLAYLISTS) + root = parseUri(PLAYLISTS) except IOError: return () === modified file 'serpentine/plugins/plugsuspend.py' --- serpentine/plugins/plugsuspend.py 2007-08-14 08:41:57 +0000 +++ serpentine/plugins/plugsuspend.py 2007-09-17 10:04:58 +0000 @@ -22,21 +22,41 @@ from gettext import gettext as _ +GNOME = dict(object_name='org.gnome.PowerManager', + object_path='/org/gnome/PowerManager', + interface='org.gnome.PowerManager') + +FDO = dict(object_name='org.freedesktop.PowerManagement', + object_path='/org/freedesktop/PowerManagement/Inhibit', + interface='org.freedesktop.PowerManagement.Inhibit') + +SPECS = (GNOME, FDO) + class InhibitSuspend(object): """ Plugin to enable power inhibiting while writing an audio disc. """ def __init__(self): - self.bus = dbus.Bus(dbus.Bus.TYPE_SESSION) - self.devobj = self.bus.get_object('org.gnome.PowerManager', - '/org/gnome/PowerManager') - self.dev = dbus.Interface(self.devobj, "org.gnome.PowerManager") + bus = dbus.Bus(dbus.Bus.TYPE_SESSION) + for spec in SPECS: + try: + obj = bus.get_object(spec['object_name'], + spec['object_path']) + iface = dbus.Interface(obj, spec['interface']) + self.inhibit = iface.Inhibit + self.uninhibit = iface.UnInhibit + break + except dbus.DBusException: + pass + else: + self.inhibit = lambda *args: None + self.uninhibit = self.inhibit def on_writing_started(self, app): - self.cookie = self.dev.Inhibit('Serpentine', _('Writing audio disc')) + self.cookie = self.inhibit('Serpentine', _('Writing audio disc')) def on_writing_finished(self, app): - self.dev.UnInhibit(self.cookie) + self.uninhibit(self.cookie) def create_plugin(app): === modified file 'serpentine/preferences.py' --- serpentine/preferences.py 2007-08-15 19:59:12 +0000 +++ serpentine/preferences.py 2008-03-03 18:29:55 +0000 @@ -452,7 +452,9 @@ def _on_gconf_device_changed(self, *args): self.__drive_selection.set_device(self._device.data) - self._device.data = self.__drive_selection.get_device() + dev = self.__drive_selection.get_device() + if dev is not None: + self._device.data = dev def __on_destroy (self, *args): self.dialog.hide () === modified file 'serpentine/recording.py' --- serpentine/recording.py 2007-08-18 13:14:08 +0000 +++ serpentine/recording.py 2007-08-22 19:29:02 +0000 @@ -126,7 +126,7 @@ if self.preferences.drive.get_media_type () == nautilusburn.MEDIA_TYPE_CDRW: gtkutil.dialog_warn (_("CD-RW disc will be erased"), _("Please remove your disc if you want to " - "preserve it's contents."), + "preserve its contents."), parent = self.__prog) self.__blocked = False self.pool.temporary_dir = self.preferences.temporary_dir === modified file 'serpentine/xspf.py' --- serpentine/xspf.py 2007-08-02 17:20:48 +0000 +++ serpentine/xspf.py 2008-03-07 13:01:11 +0000 @@ -23,8 +23,8 @@ This is a very simple utility module for retrieving basic XSPF playlist data. Basically it retrieves the playlist tracks' title, artist, location and duration. """ -from xml.dom import minidom -from xml.xpath import Evaluate + +from serpentine.compatxml import parseUri, Evaluate from xml.dom.minidom import getDOMImplementation class _Field(object): @@ -121,7 +121,8 @@ return doc def parse (self, file_or_filename): - root = minidom.parse (file_or_filename) + #root = minidom.parse (file_or_filename) + root = parseUri(file_or_filename) # Iterate over tracks for track_node in Evaluate ("/playlist/trackList/track", root): t = Track()