pitivi r1326 - in trunk: . pitivi pitivi/timeline pitivi/ui tests



Author: edwardrv
Date: Thu Oct 16 14:20:28 2008
New Revision: 1326
URL: http://svn.gnome.org/viewvc/pitivi?rev=1326&view=rev

Log:
        * pitivi/bin.py:
        * pitivi/discoverer.py:
        * pitivi/objectfactory.py:
        * pitivi/pitivi.py:
        * pitivi/sourcelist.py:
        * pitivi/timeline/composition.py:
        * pitivi/timeline/source.py:
        * pitivi/ui/complextimeline.py:
        * pitivi/ui/mainwindow.py:
        * pitivi/ui/sourcefactories.py:
        * pitivi/ui/viewer.py:
        * tests/common.py:
        Convert pitivi,bin,discoverer,objectfactory to gobject-less signaling
        and properties.
        Modify all code using that accordingly.

Modified:
   trunk/ChangeLog
   trunk/pitivi/bin.py
   trunk/pitivi/discoverer.py
   trunk/pitivi/objectfactory.py
   trunk/pitivi/pitivi.py
   trunk/pitivi/sourcelist.py
   trunk/pitivi/timeline/composition.py
   trunk/pitivi/timeline/source.py
   trunk/pitivi/ui/complextimeline.py
   trunk/pitivi/ui/mainwindow.py
   trunk/pitivi/ui/sourcefactories.py
   trunk/pitivi/ui/viewer.py
   trunk/tests/common.py

Modified: trunk/pitivi/bin.py
==============================================================================
--- trunk/pitivi/bin.py	(original)
+++ trunk/pitivi/bin.py	Thu Oct 16 14:20:28 2008
@@ -23,12 +23,38 @@
 High-level Pipelines with plugable back-ends
 """
 
-import gobject
 import gst
 from elements.smartscale import SmartVideoScale
 import plumber
 from threads import CallbackThread
 
+# REVIEW
+# SmartBin was mostly an idea that originated in the gst-0.8 era, and was ported
+# from that to newer gstreamer (see commit 660)
+#
+# LIMITATIONS
+# It makes MANY assumptions :
+#   * only raw data
+#   * only one audio and/or one video track
+#
+# IDEA:
+# Why not have a list of stream descriptions provided by the sources, with
+# their properties, maybe could be combined with the stream properties
+# used in filesourcefactories.
+#
+# Using the list of stream descriptions above, we could combine it in a smart
+# way with SmartSinks, like Hardware sinks (screen/audiocards), but also
+# rendering, or even streaming.
+#
+# The reason above might be why we should make SmartBin a subclass of gst.Bin
+# again.
+#
+# The recording feature could also be moved to a separate class/module too for
+# the same reaons.
+#
+# FIXME : Can we finally revert to using tee (instead of identity) ?
+
+
 class SmartBin(gst.Pipeline):
     """
     High-level pipeline with playing/encoding ready places
@@ -44,8 +70,14 @@
         @param displayname: The user-friendly name of the SmartBin
         """
         gst.log('name : %s, displayname : %s' % (name, displayname))
-        gobject.GObject.__init__(self)
+        gst.Pipeline.__init__(self)
+
+        # FIXME : Do we REALLY need to know/have the length here ???
+        #   It only seems to be overriden by the SmartTimelineBin
+        # Also... maybe we'll have infinite length sources (like live sources)
         self.length = length
+
+        # FIXME : This should be more generic.
         self.has_video = has_video
         self.has_audio = has_audio
         self.width = width
@@ -57,8 +89,10 @@
         self.atee = None
 
         self.set_name(name)
-        # Until  basetransform issues are fixed, we use an identity instead
+        # FIXME : Until basetransform issues are fixed, we use an identity instead
         # of a tee
+        # COMMENT : They have been fixed by now ! It would allow us to show
+        # visualisation while rendering for example.
         if self.has_video:
             self.vtee = gst.element_factory_make("tee", "vtee")
             self.add(self.vtee)
@@ -67,6 +101,8 @@
             self.add(self.atee)
         self._addSource()
         self._connectSource()
+
+        # FIXME : naming. thread => bin
         self.asinkthread = None
         self.vsinkthread = None
         self.encthread = None
@@ -96,7 +132,7 @@
         Returns False if there was a problem.
         """
         self.debug("asinkthread : %r" % asinkthread)
-        state  = self.get_state(0)[1]
+        state = self.get_state(0)[1]
         if state == gst.STATE_PLAYING:
             self.warning("is in PAUSED or higher : %s" % state)
             return False
@@ -166,6 +202,9 @@
         self.log("vsinkthread removed succesfully")
         return True
 
+    # FIXME : WTF IS THIS DOING HERE ! IT HAS VIRTUALLY NOTHING TO DO
+    # WITH SmartBin's concepts
+    # It should be moved into a non-ui/plumber class/module
     def getRealVideoSink(self):
         """ returns the real video sink element or None """
         if not self.vsinkthread:
@@ -256,22 +295,9 @@
         """ Return the ExportSettings for the bin """
         return None
 
-    def _debugProbe(self, unused_pad, data, categoryname):
-        if isinstance(data, gst.Buffer):
-            self.log("%s\tBUFFER timestamp:%s duration:%s size:%d" % (categoryname,
-                                                                      gst.TIME_ARGS(data.timestamp),
-                                                                      gst.TIME_ARGS(data.duration),
-                                                                      data.size))
-            if not data.flag_is_set(gst.BUFFER_FLAG_DELTA_UNIT):
-                self.log("%s\tKEYFRAME" % categoryname)
-        else:
-            self.log("%s\tEVENT %s" % (categoryname, data))
-        return True
-
     def _makeEncThread(self, uri, settings=None):
         """ Construct the encoding bin according to the given setting. """
         # TODO : verify if encoders take video/x-raw-yuv and audio/x-raw-int
-        # TODO : use video/audio settings !
         # TODO : Check if we really do both audio and video !
         self.debug("Creating encoding thread")
         if not settings:
@@ -303,6 +329,7 @@
         ainq.props.max_size_buffers = 0
         ainq.props.max_size_bytes = 0
         aident = gst.element_factory_make("identity", "aident")
+        aident.props.silent = True
         aident.props.single_segment = True
         aconv = gst.element_factory_make("audioconvert", "aconv")
         ares = gst.element_factory_make("audioresample", "ares")
@@ -343,6 +370,7 @@
         vinq.props.max_size_bytes = 0
         vident = gst.element_factory_make("identity", "vident")
         vident.props.single_segment = True
+        vident.props.silent = True
         csp = gst.element_factory_make("ffmpegcolorspace", "csp")
         vrate = gst.element_factory_make("videorate", "vrate")
         vscale = SmartVideoScale()
@@ -400,8 +428,7 @@
                           has_video = factory.is_video,
                           has_audio = factory.is_audio,
                           width = width, height = height,
-                          length = factory.getDuration(),
-                          is_seekable = True)
+                          length = factory.duration)
 
     def _addSource(self):
         self.add(self.source)

Modified: trunk/pitivi/discoverer.py
==============================================================================
--- trunk/pitivi/discoverer.py	(original)
+++ trunk/pitivi/discoverer.py	Thu Oct 16 14:20:28 2008
@@ -24,14 +24,15 @@
 Discover file multimedia information.
 """
 
+from gettext import gettext as _
+import os.path
 import gobject
 import gst
-import objectfactory
 
-from gettext import gettext as _
-import os.path
+from objectfactory import FileSourceFactory
+from signalinterface import Signallable
 
-class Discoverer(gobject.GObject):
+class Discoverer(object, Signallable):
     """
     Queues requests to discover information about given files.
     The discovery is done in a very fragmented way, so that it appears to be
@@ -44,34 +45,23 @@
 
     The "finished-analyzing" signal is emitted a file is finished being analyzed
 
-    The "starting" signal isemitted when the discoverer starts analyzing some
+    The "starting" signal is emitted when the discoverer starts analyzing some
     files.
 
     The "ready" signal is emitted when the discoverer has no more files to
     analyze.
     """
 
-    __gsignals__ = {
-        "new_sourcefilefactory" : (gobject.SIGNAL_RUN_LAST,
-                                   gobject.TYPE_NONE,
-                                   (gobject.TYPE_PYOBJECT, )),
-        "not_media_file" : (gobject.SIGNAL_RUN_LAST,
-                            gobject.TYPE_NONE,
-                            (gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)),
-        "finished_analyzing" : ( gobject.SIGNAL_RUN_LAST,
-                                 gobject.TYPE_NONE,
-                                 (gobject.TYPE_PYOBJECT, )),
-        "ready" : ( gobject.SIGNAL_RUN_LAST,
-                    gobject.TYPE_NONE,
-                    ( )),
-        "starting" : ( gobject.SIGNAL_RUN_LAST,
-                       gobject.TYPE_NONE,
-                       ( ))
+    __signals__ = {
+        "new_sourcefilefactory" : ["factory"],
+        "not_media_file" : ["a", "b", "c" ],
+        "finished_analyzing" : ["factory"],
+        "ready" : None,
+        "starting" : None,
         }
 
     def __init__(self, project):
         gst.log("new discoverer for project %s" % project)
-        gobject.GObject.__init__(self)
         self.project = project
         self.queue = []
         self.working = False
@@ -154,13 +144,13 @@
         elif self.currentfactory:
             self.currentfactory.addMediaTags(self.currentTags)
             if self.isimage:
-                self.currentfactory.setThumbnail(gst.uri_get_location(self.current))
-            if not self.currentfactory.getDuration() and not self.isimage:
+                self.currentfactory.thumbnail = gst.uri_get_location(self.current)
+            if not self.currentfactory.duration and not self.isimage:
                 self.emit('not_media_file', self.current,
                           _("Could not establish the duration of the file."),
                           _("This clip seems to be in a format which cannot be accessed in a random fashion."))
             else:
-                self.emit('finished-analyzing', self.currentfactory)
+                self.emit('finished_analyzing', self.currentfactory)
         self.currentTags = []
         self.analyzing = False
         self.current = None
@@ -276,7 +266,7 @@
             self.thisdone = True
             filename = "/tmp/" + self.currentfactory.name.encode('base64').replace('\n','') + ".png"
             if os.path.isfile(filename):
-                self.currentfactory.setThumbnail(filename)
+                self.currentfactory.thumbnail = filename
             gobject.idle_add(self._finishAnalysis)
         elif message.type == gst.MESSAGE_ERROR:
             error, detail = message.parse_error()
@@ -322,34 +312,34 @@
 
             if caps and caps.is_fixed():
                 if not self.currentfactory:
-                    self.currentfactory = objectfactory.FileSourceFactory(self.current, self.project)
+                    self.currentfactory = FileSourceFactory(self.current, self.project)
                     self.emit("new_sourcefilefactory", self.currentfactory)
                 if caps.to_string().startswith("audio/x-raw") and not self.currentfactory.audio_info:
-                    self.currentfactory.setAudioInfo(caps)
+                    self.currentfactory.audio_info = caps
                 elif caps.to_string().startswith("video/x-raw") and not self.currentfactory.video_info:
-                    self.currentfactory.setVideoInfo(caps)
-            if not self.currentfactory.getDuration():
+                    self.currentfactory.video_info = caps
+            if not self.currentfactory.duration:
                 try:
                     length, format = pad.query_duration(gst.FORMAT_TIME)
                 except:
                     pad.warning("duration query failed")
                 else:
                     if format == gst.FORMAT_TIME:
-                        self.currentfactory.set_property("length", length)
+                        self.currentfactory.length = length
 
     def _vcapsNotifyCb(self, pad, unused_property):
         gst.info("pad:%s , caps:%s" % (pad, pad.get_caps().to_string()))
         if pad.get_caps().is_fixed() and (not self.currentfactory.video_info_stream or not self.currentfactory.video_info_stream.fixed):
-            self.currentfactory.setVideoInfo(pad.get_caps())
+            self.currentfactory.video_info = pad.get_caps()
 
     def _newVideoPadCb(self, element, pad):
         """ a new video pad was found """
         gst.debug("pad %s" % pad)
 
-        self.currentfactory.setVideo(True)
+        self.currentfactory.is_video = True
 
         if pad.get_caps().is_fixed():
-            self.currentfactory.setVideoInfo(pad.get_caps())
+            self.currentfactory.video_info = pad.get_caps()
 
         q = gst.element_factory_make("queue")
         q.props.max_size_bytes = 5 * 1024 * 1024
@@ -377,7 +367,7 @@
         """ a new audio pad was found """
         gst.debug("pad %s" % pad)
 
-        self.currentfactory.setAudio(True)
+        self.currentfactory.is_audio = True
 
         # if we already saw another pad, remove no-more-pads hack
         if self.currentfactory.is_video:
@@ -386,7 +376,7 @@
 
         if pad.get_caps().is_fixed():
             gst.debug("fixed caps, setting info on factory")
-            self.currentfactory.setAudioInfo(pad.get_caps())
+            self.currentfactory.audio_info = pad.get_caps()
             # if we already have fixed caps, we don't need to take this stream.
         else:
             gst.debug("non-fixed caps, adding queue and fakesink")
@@ -417,12 +407,12 @@
         gst.info("pad:%s caps:%s is_last:%s" % (pad, capsstr, is_last))
         if capsstr.startswith("video/x-raw"):
             if not self.currentfactory:
-                self.currentfactory = objectfactory.FileSourceFactory(self.current, self.project)
+                self.currentfactory = FileSourceFactory(self.current, self.project)
                 self.emit("new_sourcefilefactory", self.currentfactory)
             self._newVideoPadCb(element, pad)
         elif capsstr.startswith("audio/x-raw"):
             if not self.currentfactory:
-                self.currentfactory = objectfactory.FileSourceFactory(self.current, self.project)
+                self.currentfactory = FileSourceFactory(self.current, self.project)
                 self.emit("new_sourcefilefactory", self.currentfactory)
             self._newAudioPadCb(element, pad)
         else:

Modified: trunk/pitivi/objectfactory.py
==============================================================================
--- trunk/pitivi/objectfactory.py	(original)
+++ trunk/pitivi/objectfactory.py	Thu Oct 16 14:20:28 2008
@@ -37,30 +37,11 @@
 
 from gettext import gettext as _
 
-class ObjectFactory(gobject.GObject, Serializable):
+class ObjectFactory(Serializable):
     """
     base class for object factories which provide elements to use
     in the timeline
     """
-    __gproperties__ = {
-        "is-audio" : ( gobject.TYPE_BOOLEAN,
-                       "Contains audio stream",
-                       "Does the element contain audio",
-                       False, gobject.PARAM_READWRITE),
-
-        "is-video" : ( gobject.TYPE_BOOLEAN,
-                       "Contains video stream",
-                       "Does the element contain video",
-                       False, gobject.PARAM_READWRITE),
-        "audio-info" : ( gobject.TYPE_PYOBJECT,
-                         "Audio Information",
-                         "GstCaps of the audio stream",
-                         gobject.PARAM_READWRITE ),
-        "video-info" : ( gobject.TYPE_PYOBJECT,
-                         "Video Information",
-                         "GstCaps of the video stream",
-                         gobject.PARAM_READWRITE )
-        }
 
     __data_type__ = "object-factory"
 
@@ -71,56 +52,70 @@
     # pending UID (int) => objects (list of BrotherObjects and extra field)
     __waiting_for_pending_objects__ = {}
 
-    def __init__(self, name="", displayname="", **unused_kw):
-        gobject.GObject.__init__(self)
+    # FIXME : Use Setter/Getter for internal values !
+
+    def __init__(self, name="", displayname="",
+                 **unused_kw):
         self.name = name
         self.displayname = displayname
-        self.is_audio = False
-        self.is_video = False
+        self._is_audio = False
+        self._is_video = False
         self.is_effect = False
         self.instances = []
-        self.audio_info = None
-        self.audio_info_stream = None
-        self.video_info = None
-        self.video_info_stream = None
-        self.mediaTags = {}
+        self._audio_info = None
+        self._audio_info_stream = None
+        self._video_info = None
+        self._video_info_stream = None
+        self._mediaTags = {}
         self.title = None
         self.artist = None
         self.uid = -1
 
-    def do_set_property(self, property, value):
-        """
-        override for the "set_property" gobject virtual method
-        """
-        gst.info(property.name)
-        if property.name == "is-audio":
-            self.is_audio = value
-        elif property.name == "is-video":
-            self.is_video = value
-        elif property.name == "video-info":
-            self.video_info = value
-            self.video_info_stream = get_stream_for_caps(value)
-        elif property.name == "audio-info":
-            self.audio_info = value
-            self.audio_info_stream = get_stream_for_caps(value)
-        else:
-            raise AttributeError, 'unknown property %s' % property.name
+    ## properties
+
+    def _get_is_audio(self):
+        return self._is_audio
+
+    def _set_is_audio(self, isaudio):
+        self._is_audio = isaudio
+    is_audio = property(_get_is_audio, _set_is_audio,
+                        doc="True if the factory provides audio")
+
+    def _get_is_video(self):
+        return self._is_video
+
+    def _set_is_video(self, isvideo):
+        self._is_video = isvideo
+    is_video = property(_get_is_video, _set_is_video,
+                        doc="True if the factory provides video")
+
+    def _get_audio_info(self):
+        return self._audio_info
+
+    def _set_audio_info(self, inf):
+        self._audio_info = inf
+        self._audio_info_stream = get_stream_for_caps(inf)
+    audio_info = property(_get_audio_info, _set_audio_info,
+                          doc="Audio information as gst.Caps")
+
+    def _get_video_info(self):
+        return self._video_info
+    def _set_video_info(self, inf):
+        self._video_info = inf
+        self._video_info_stream = get_stream_for_caps(inf)
+    video_info = property(_get_video_info, _set_video_info,
+                          doc="Video information as gst.Caps")
+
+    def _get_audio_info_stream(self):
+        return self._audio_info_stream
+    audio_info_stream = property(_get_audio_info_stream,
+                                 doc="Audio information as a Stream")
+
+    def _get_video_info_stream(self):
+        return self._video_info_stream
+    video_info_stream = property(_get_video_info_stream,
+                                 doc="Video information as a Stream")
 
-    def setAudioInfo(self, caps):
-        """ sets the audio caps of the element """
-        self.set_property("audio-info", caps)
-
-    def setVideoInfo(self, caps):
-        """ set the video caps of the element """
-        self.set_property("video-info", caps)
-
-    def setAudio(self, is_audio):
-        """ sets whether the element has audio stream """
-        self.set_property("is-audio", is_audio)
-
-    def setVideo(self, is_video):
-        """ sets whether the element has video stream """
-        self.set_property("is-video", is_video)
 
     def __repr__(self):
         return "<%s: %s>" % (self.__class__.__name__, self.displayname or self.name)
@@ -129,22 +124,22 @@
         """ Add the given gst.Tag or gst.TagList to the factory """
         gst.debug("tags:%s" % tags)
         for tag in tags:
-            self.mediaTags.update(tag)
-        for tag in self.mediaTags.keys():
-            if isinstance(self.mediaTags[tag], str):
-                self.mediaTags[tag] = self.mediaTags[tag].replace('&', '&amp;').strip()
-            if isinstance(self.mediaTags[tag], gst.Date):
-                d = self.mediaTags[tag]
-                self.mediaTags[tag] = "%s/%s/%s" % (d.day, d.month, d.year)
-        gst.debug("tags:%s" % self.mediaTags)
+            self._mediaTags.update(tag)
+        for tag in self._mediaTags.keys():
+            if isinstance(self._mediaTags[tag], str):
+                self._mediaTags[tag] = self._mediaTags[tag].replace('&', '&amp;').strip()
+            if isinstance(self._mediaTags[tag], gst.Date):
+                d = self._mediaTags[tag]
+                self._mediaTags[tag] = "%s/%s/%s" % (d.day, d.month, d.year)
+        gst.debug("tags:%s" % self._mediaTags)
         if self.video_info_stream:
-            self.video_info_stream.set_codec(self.mediaTags.get(gst.TAG_VIDEO_CODEC))
+            self.video_info_stream.set_codec(self._mediaTags.get(gst.TAG_VIDEO_CODEC))
         if self.audio_info_stream:
-            self.audio_info_stream.set_codec(self.mediaTags.get(gst.TAG_AUDIO_CODEC))
-        self.artist = self.mediaTags.get(gst.TAG_ARTIST)
+            self.audio_info_stream.set_codec(self._mediaTags.get(gst.TAG_AUDIO_CODEC))
+        self.artist = self._mediaTags.get(gst.TAG_ARTIST)
         if self.artist:
             self.artist.strip()
-        self.title = self.mediaTags.get(gst.TAG_TITLE)
+        self.title = self._mediaTags.get(gst.TAG_TITLE)
         if self.title:
             self.title.strip()
 
@@ -271,7 +266,12 @@
             cls.__waiting_for_pending_objects__[uid] = []
         cls.__waiting_for_pending_objects__[uid].append((weakref.proxy(obj), extra))
 
-gobject.type_register(ObjectFactory)
+
+
+
+# FIXME : Figure out everything which is Source specific and put it here
+# FIXME : It might not just be files (network sources ?) !
+# FIMXE : It might not even had a URI ! (audio/video generators for ex)
 
 class SourceFactory(ObjectFactory):
     """
@@ -280,16 +280,16 @@
 
     __data_type__ = "source-factory"
 
-    def getDuration(self):
+    def _getDuration(self):
         """
         Returns the maximum duration of the source in nanoseconds
 
         If the source doesn't have a maximum duration (like an image), subclasses
         should implement this by returning 2**63 - 1 (MAX_LONG).
         """
-        pass
+        raise NotImplementedError
 
-    def getDefaultDuration(self):
+    def _getDefaultDuration(self):
         """
         Returns the default duration of a file in nanoseconds,
         this should be used when using sources initially.
@@ -297,30 +297,29 @@
         Most sources will return the same as getDuration(), but can be overriden
         for sources that have an infinite duration.
         """
-        return self.getDuration()
+        return self.duration
+
+    ## properties
+
+    def __getDefaultDuration(self):
+        return self._getDefaultDuration()
+    default_duration = property(__getDefaultDuration,
+                                doc = "Default duration of a source in nanoseconds")
+
+    def __getDuration(self):
+        return self._getDuration()
+    duration = property(__getDuration,
+                        doc = "Maximum duration of the source in nanoseconds")
 
-gobject.type_register(SourceFactory)
+
+
+# FIXME : What about non-file sources ???
 
 class FileSourceFactory(SourceFactory):
     """
     Provides File sources useable in a timeline
     """
 
-    __gproperties__ = {
-        "length" : ( gobject.TYPE_UINT64,
-                     "Length",
-                     "Length of element",
-                     0,
-                     (2**63) - 1, # should be (1<<64)-1 but #335854
-                     0,
-                     gobject.PARAM_READWRITE ),
-        "thumbnail" :  ( gobject.TYPE_STRING,
-                         "Thumbnail filename",
-                         "Filename for the element's thumbnail",
-                         "",
-                         gobject.PARAM_READWRITE )
-        }
-
     __data_type__ = "file-source-factory"
 
     def __init__(self, filename="", project=None, **kwargs):
@@ -335,25 +334,27 @@
         self._thumbnails = []
         self.settings = None
 
+    def _get_length(self):
+        return self._length
+
+    def _set_length(self, length):
+        gst.debug("length:%r" % length)
+        self._length = length
+    length = property(_get_length, _set_length,
+                      doc="Length in nanoseconds")
+
+    def _get_thumbnail(self):
+        return self._thumbnail
+
+    def _set_thumbnail(self, thumbnail):
+        self._thumbnail = thumbnail
+    thumbnail = property(_get_thumbnail, _set_thumbnail,
+                         doc="Thumbnail file location")
+
     ## SourceFactory implementation
-    def getDuration(self):
+    def _getDuration(self):
         return self._length
 
-    def do_set_property(self, property, value):
-        if property.name == "length":
-            if self._length and self._length != value:
-                gst.warning("%s : Trying to set a new length (%s) different from previous one (%s)" % (self.name,
-                                                                                                       gst.TIME_ARGS(self._length),
-                                                                                                       gst.TIME_ARGS(value)))
-            self._length = value
-        elif property.name == "thumbnail":
-            gst.debug("thumbnail : %s" % value)
-            if os.path.isfile(value):
-                self._thumbnail = value
-            else:
-                gst.warning("Thumbnail path is invalid !")
-        else:
-            ObjectFactory.do_set_property(self, property, value)
 
     def makeBin(self):
         """ returns a source bin with all pads """
@@ -410,16 +411,6 @@
         if bin in self.instances:
             self.instances.remove(bin)
 
-    def setLength(self, length):
-        """ sets the length of the element """
-        self.set_property("length", length)
-
-    def setThumbnail(self, thumbnail):
-        """ Sets the thumbnail filename of the element """
-        self.set_property("thumbnail", thumbnail)
-
-    def getThumbnail(self):
-        return self._thumbnail
 
     def getExportSettings(self):
         """ Returns the ExportSettings corresponding to this source """

Modified: trunk/pitivi/pitivi.py
==============================================================================
--- trunk/pitivi/pitivi.py	(original)
+++ trunk/pitivi/pitivi.py	Thu Oct 16 14:20:28 2008
@@ -23,7 +23,6 @@
 Main application
 """
 import os
-import gobject
 import gtk
 import gst
 import check
@@ -38,10 +37,19 @@
 from settings import GlobalSettings
 from threads import ThreadMaster
 from pluginmanager import PluginManager
+from signalinterface import Signallable
+import instance
 
 from gettext import gettext as _
 
-class Pitivi(gobject.GObject):
+# FIXME : Speedup loading time
+# Currently we load everything in one go
+# It would be better if a minimalistic UI could start up ASAP, without loading
+# anything gst-related or that could slow down startup.
+# AND THEN load up the required parts.
+# This will result in a much better end-user experience
+
+class Pitivi(object, Signallable):
     """
     Pitivi's main class
 
@@ -70,25 +78,13 @@
         shutdown
             used internally, do not catch this signals"""
 
-    __gsignals__ = {
-        "new-project-loading" : (gobject.SIGNAL_RUN_LAST,
-                          gobject.TYPE_NONE,
-                          (gobject.TYPE_PYOBJECT, )),
-        "new-project-loaded" : ( gobject.SIGNAL_RUN_LAST,
-                          gobject.TYPE_NONE,
-                          (gobject.TYPE_PYOBJECT, )),
-        "closing-project" : ( gobject.SIGNAL_RUN_LAST,
-                              gobject.TYPE_BOOLEAN,
-                              (gobject.TYPE_PYOBJECT, )),
-        "project-closed" : ( gobject.SIGNAL_RUN_LAST,
-                             gobject.TYPE_NONE,
-                             ( gobject.TYPE_PYOBJECT, )),
-        "new-project-failed" : ( gobject.SIGNAL_RUN_LAST,
-                          gobject.TYPE_NONE,
-                          (gobject.TYPE_STRING, gobject.TYPE_STRING)),
-        "shutdown" : ( gobject.SIGNAL_RUN_LAST,
-                       gobject.TYPE_NONE,
-                       ( ))
+    __signals__ = {
+        "new-project-loading" : ["project"],
+        "new-project-loaded" : ["project"],
+        "closing-project" : ["project"],
+        "project-closed" : ["project"],
+        "new-project-failed" : ["reason", "uri"],
+        "shutdown" : None
         }
 
     def __init__(self, args=[], use_ui=True):
@@ -96,7 +92,6 @@
         initialize pitivi with the command line arguments
         """
         gst.log("starting up pitivi...")
-        gobject.GObject.__init__(self)
         self.project = None
         self._use_ui = use_ui
 

Modified: trunk/pitivi/sourcelist.py
==============================================================================
--- trunk/pitivi/sourcelist.py	(original)
+++ trunk/pitivi/sourcelist.py	Thu Oct 16 14:20:28 2008
@@ -23,23 +23,23 @@
 Handles the list of source for a project
 """
 
-import gobject
 import gst
 from discoverer import Discoverer
 from serializable import Serializable, to_object_from_data_type
+from signalinterface import Signallable
 
-class SourceList(gobject.GObject, Serializable):
+class SourceList(Serializable, Signallable):
     """
     Contains the sources for a project, stored as FileSourceFactory
 
     Signals:
-    _ file-added (FileSourceFactory) :
+    _ file_added (FileSourceFactory) :
                 A file has been completely discovered and is valid.
-    _ file-removed (string : uri) :
+    _ file_removed (string : uri) :
                 A file was removed from the SourceList
-    _ not-media-file (string : uri, string : reason)
+    _ not_media_file (string : uri, string : reason)
                 The given uri is not a media file
-    _ tmp-is-ready (FileSourceFactory) :
+    _ tmp_is_ready (FileSourceFactory) :
                 The temporary uri given to the SourceList is ready to use.
     _ ready :
                 No more files are being discovered/added
@@ -47,33 +47,19 @@
                 Some files are being discovered/added
     """
 
-    __gsignals__ = {
-        "file_added" : (gobject.SIGNAL_RUN_LAST,
-                        gobject.TYPE_NONE,
-                        (gobject.TYPE_PYOBJECT, )),
-        "file_removed" : (gobject.SIGNAL_RUN_LAST,
-                          gobject.TYPE_NONE,
-                          (gobject.TYPE_STRING, )),
-        "not_media_file" : (gobject.SIGNAL_RUN_LAST,
-                            gobject.TYPE_NONE,
-                            (gobject.TYPE_STRING, gobject.TYPE_STRING,
-                             gobject.TYPE_STRING)),
-        "tmp_is_ready": (gobject.SIGNAL_RUN_LAST,
-                         gobject.TYPE_NONE,
-                         (gobject.TYPE_PYOBJECT, )),
-        "ready" : ( gobject.SIGNAL_RUN_LAST,
-                    gobject.TYPE_NONE,
-                    ( )),
-        "starting" : ( gobject.SIGNAL_RUN_LAST,
-                       gobject.TYPE_NONE,
-                       ( ))
+    __signals__ = {
+        "file_added" : ["factory"],
+        "file_removed" : ["uri"],
+        "not_media_file" : ["uri", "reason"],
+        "tmp_is_ready": ["factory"],
+        "ready" : None,
+        "starting" : None
         }
 
     __data_type__ = "source-list"
 
-    def __init__(self, project=None, **kwargs):
+    def __init__(self, project=None):
         gst.log("new sourcelist for project %s" % project)
-        gobject.GObject.__init__(self)
         self.project = project
         self.sources = {}
         self.tempsources = {}
@@ -154,13 +140,13 @@
         if uri in self and self[uri]:
             raise Exception("We already have an objectfactory for uri %s" % uri)
         self.sources[uri] = factory
-        self.emit("file-added", factory)
+        self.emit("file_added", factory)
 
     def _finishedAnalyzingCb(self, unused_discoverer, factory):
         # callback from finishing analyzing factory
         if factory.name in self.tempsources:
             self.tempsources[factory.name] = factory
-            self.emit("tmp-is-ready", factory)
+            self.emit("tmp_is_ready", factory)
         elif factory.name in self.sources:
             self.addFactory(factory.name, factory)
 

Modified: trunk/pitivi/timeline/composition.py
==============================================================================
--- trunk/pitivi/timeline/composition.py	(original)
+++ trunk/pitivi/timeline/composition.py	Thu Oct 16 14:20:28 2008
@@ -485,15 +485,15 @@
         gst.info("start=%s, position=%d, existorder=%d, sourcelength=%s" % (gst.TIME_ARGS(start),
                                                                             position,
                                                                             existorder,
-                                                                            gst.TIME_ARGS(source.factory.getDuration())))
+                                                                            gst.TIME_ARGS(source.factory.duration)))
         # set the correct start/duration time
-        duration = source.factory.getDuration()
+        duration = source.factory.duration
         source.setStartDurationTime(start, duration)
 
         # pushing following
         if push_following and not position in [-1, 0]:
             #print self.gnlobject, "pushing following", existorder, len(self.sources[position - 1][2])
-            self.shiftSources(source.factory.getDuration(), existorder, len(self.sources[position - 1][2]))
+            self.shiftSources(source.factory.duration, existorder, len(self.sources[position - 1][2]))
 
         self.addSource(source, position, auto_linked=auto_linked)
 

Modified: trunk/pitivi/timeline/source.py
==============================================================================
--- trunk/pitivi/timeline/source.py	(original)
+++ trunk/pitivi/timeline/source.py	Thu Oct 16 14:20:28 2008
@@ -194,14 +194,14 @@
         if self.media_start == gst.CLOCK_TIME_NONE:
             self.media_start = 0
         if self.media_duration == 0:
-            self.media_duration = self.factory.getDuration()
+            self.media_duration = self.factory.duration
 
         gnlobject = TimelineSource._makeGnlObject(self)
         if gnlobject == None:
             return None
 
         # we override start/duration
-        gnlobject.set_property("duration", long(self.factory.getDuration()))
+        gnlobject.set_property("duration", long(self.factory.duration))
         gnlobject.set_property("start", long(0))
 
         return gnlobject

Modified: trunk/pitivi/ui/complextimeline.py
==============================================================================
--- trunk/pitivi/ui/complextimeline.py	(original)
+++ trunk/pitivi/ui/complextimeline.py	Thu Oct 16 14:20:28 2008
@@ -241,12 +241,12 @@
         element = item.element
         cur_end = element.start + element.duration
         # Invariant:
-        #  max(duration) = element.factory.getDuration()
+        #  max(duration) = element.factory.duration
         #  start = end - duration
         # Therefore
-        #  min(start) = end - element.factory.getDuration()
+        #  min(start) = end - element.factory.duration
         new_start =  max(0,
-            cur_end - element.factory.getDuration(), 
+            cur_end - element.factory.duration,
             self.canvas.snap_time_to_edit(self.pixelToNs(pos[0])))
         new_duration = cur_end - new_start
         new_media_start = element.media_start + (new_start - element.media_start)
@@ -257,8 +257,8 @@
     def _trim_source_end_cb(self, item, pos):
         element = item.element
         cur_start = element.start
-        new_end = min(cur_start + element.factory.getDuration(),
-            max(cur_start, 
+        new_end = min(cur_start + element.factory.duration,
+            max(cur_start,
                 self.canvas.snap_time_to_edit(
                     self.pixelToNs(pos[0] + width(item)))))
         new_duration = new_end - element.start

Modified: trunk/pitivi/ui/mainwindow.py
==============================================================================
--- trunk/pitivi/ui/mainwindow.py	(original)
+++ trunk/pitivi/ui/mainwindow.py	Thu Oct 16 14:20:28 2008
@@ -94,7 +94,7 @@
         instance.PiTiVi.current.connect("save-uri-requested", self._saveAsDialogCb)
         instance.PiTiVi.current.connect("confirm-overwrite", self._confirmOverwriteCb)
         instance.PiTiVi.playground.connect("error", self._playGroundErrorCb)
-        instance.PiTiVi.current.sources.connect_after("file_added", self._sourcesFileAddedCb)
+        instance.PiTiVi.current.sources.connect("file_added", self._sourcesFileAddedCb)
 
         # Start dbus service
         session_bus = dbus.SessionBus()

Modified: trunk/pitivi/ui/sourcefactories.py
==============================================================================
--- trunk/pitivi/ui/sourcefactories.py	(original)
+++ trunk/pitivi/ui/sourcefactories.py	Thu Oct 16 14:20:28 2008
@@ -337,9 +337,10 @@
 
     def _addFactory(self, factory):
         try:
-            pixbuf = gtk.gdk.pixbuf_new_from_file(factory.getThumbnail())
+            gst.debug("attempting to open thumbnail %s" % factory.thumbnail)
+            pixbuf = gtk.gdk.pixbuf_new_from_file(factory.thumbnail)
         except:
-            gst.error("Failure to create thumbnail from file %s" % factory.getThumbnail())
+            gst.error("Failure to create thumbnail from file %s" % factory.thumbnail)
             if factory.is_video:
                 thumbnail = self.videofilepixbuf
             elif factory.is_audio:
@@ -356,7 +357,7 @@
                                 factory.getPrettyInfo(),
                                 factory,
                                 factory.name,
-                                factory.getDuration() and "<b>%s</b>" % beautify_length(factory.getDuration()) or ""])
+                                factory.duration and "<b>%s</b>" % beautify_length(factory.duration) or ""])
         self._displayTreeView()
 
     # sourcelist callbacks

Modified: trunk/pitivi/ui/viewer.py
==============================================================================
--- trunk/pitivi/ui/viewer.py	(original)
+++ trunk/pitivi/ui/viewer.py	Thu Oct 16 14:20:28 2008
@@ -415,7 +415,7 @@
                 self._timelineDurationChangedSigId = (smartbin.project.timeline.videocomp,
                                                       sigid)
             else:
-                self.posadjust.upper = float(smartbin.factory.getDuration())
+                self.posadjust.upper = float(smartbin.factory.duration)
                 if not self._timelineDurationChangedSigId == (None, None):
                     obj, sigid = self._timelineDurationChangedSigId
                     obj.disconnect(sigid)

Modified: trunk/tests/common.py
==============================================================================
--- trunk/tests/common.py	(original)
+++ trunk/tests/common.py	Thu Oct 16 14:20:28 2008
@@ -123,5 +123,6 @@
         TestObjectFactory.__init__(self, *args, **kwargs)
         self.length = duration
 
-    def getDuration(self):
+    def _getDuration(self):
         return self.length
+    duration = property(_getDuration)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]