[pitivi] Make saving working



commit 6edc7c452c15eb6e5bf645db770636f6f4a5f13b
Author: Thibault Saunier <tsaunier gnome org>
Date:   Tue Jul 27 00:14:57 2010 +0200

    Make saving working

 pitivi/application.py         |    2 +-
 pitivi/formatters/base.py     |    3 +-
 pitivi/formatters/etree.py    |   88 +++++++++++++++++++++++++++++----
 pitivi/formatters/format.py   |    4 +-
 pitivi/projectmanager.py      |   11 ++--
 pitivi/ui/clipproperties.py   |    2 +-
 pitivi/ui/effectlist.py       |    2 +-
 pitivi/ui/gstwidget.py        |   14 +++++
 pitivi/ui/timeline.py         |    2 +-
 tests/test_etree_formatter.py |  111 +++++++++++++++++++++++++++++++++-------
 tests/test_pipeline.py        |    2 +-
 11 files changed, 198 insertions(+), 43 deletions(-)
---
diff --git a/pitivi/application.py b/pitivi/application.py
index c9671a0..4611143 100644
--- a/pitivi/application.py
+++ b/pitivi/application.py
@@ -139,7 +139,7 @@ class Pitivi(Loggable, Signallable):
         self.effects = EffectsHandler()
         self.deviceprobe = get_probe()
 
-        self.projectManager = ProjectManager()
+        self.projectManager = ProjectManager(self.effects)
         self._connectToProjectManager(self.projectManager)
 
         self.action_log = UndoableActionLog()
diff --git a/pitivi/formatters/base.py b/pitivi/formatters/base.py
index 9ad93f5..d98d911 100644
--- a/pitivi/formatters/base.py
+++ b/pitivi/formatters/base.py
@@ -75,13 +75,14 @@ class Formatter(Signallable, Loggable):
     description = "Description of the format"
     ProjectClass = Project
 
-    def __init__(self):
+    def __init__(self, avalaible_effects):
         Loggable.__init__(self)
         # mapping of directory changes
         # key : old path
         # value : new path
         self.directorymapping = {}
 
+        self.avalaible_effects = avalaible_effects
         self.project = None
 
     #{ Load/Save methods
diff --git a/pitivi/formatters/etree.py b/pitivi/formatters/etree.py
index 34de3ec..0756584 100644
--- a/pitivi/formatters/etree.py
+++ b/pitivi/formatters/etree.py
@@ -29,7 +29,8 @@ from xml.etree.ElementTree import Element, SubElement, tostring, parse
 from pitivi.reflect import qual, namedAny
 from pitivi.factories.base import SourceFactory
 from pitivi.factories.file import FileSourceFactory
-from pitivi.timeline.track import Track
+from pitivi.factories.operation import EffectFactory
+from pitivi.timeline.track import Track, TrackEffect
 from pitivi.timeline.timeline import TimelineObject
 from pitivi.formatters.base import Formatter, FormatterError
 from pitivi.utils import get_filesystem_encoding
@@ -70,8 +71,8 @@ class ElementTreeFormatter(Formatter):
     _element_id = 0
     _our_properties = ["id", "type"]
 
-    def __init__(self, *args, **kwargs):
-        Formatter.__init__(self, *args, **kwargs)
+    def __init__(self, avalaible_effects, *args, **kwargs):
+        Formatter.__init__(self, avalaible_effects, *args, **kwargs)
         self.factoriesnode = None
         self.timelinenode = None
         self._settingsnode = None
@@ -327,11 +328,44 @@ class ElementTreeFormatter(Formatter):
                     str("(gint64)%s" % getattr(track_object, attribute))
 
         element.attrib["priority"] = "(int)%s" % track_object.priority
+        element.attrib["active"] = "(bool)%s" % track_object.active
 
-        factory_ref = \
-                self._saveFactoryRef(track_object.factory)
-        stream_ref = self._saveStreamRef(track_object.stream)
+        if not isinstance(track_object.factory, EffectFactory):
+            self._saveSourceTrackObject(track_object, element)
+        else:
+            self._saveTrackEffect(track_object, element)
+
+        self._context.track_objects[track_object] = element
+
+        return element
+
+    def _saveTrackEffect(self, track_object, element):
+        effect_element = Element("effect")
+        element.append(effect_element)
+
+        factory_element = Element("factory")
+        factory_element.attrib["name"] = track_object.factory.name
+        effect_element.append(factory_element)
+
+        self._saveEffectProperties(track_object, effect_element)
 
+    def _saveEffectProperties(self, track_object, effect_element):
+        effect_properties = Element("gst-element-properties")
+        effect = track_object.getElement()
+        properties = gobject.list_properties(effect)
+        for prop in properties:
+            type_name = str(gobject.type_name(prop.value_type.fundamental))
+            if type_name == "GEnum":
+                value = str(effect.get_property(prop.name).value_name)
+            else:
+                value = str(effect.get_property(prop.name))
+            effect_properties.attrib[prop.name] = '(' + type_name + ')' + value
+        effect_element.append(effect_properties)
+
+
+    def _saveSourceTrackObject(self, track_object, element):
+        factory_ref = self._saveFactoryRef(track_object.factory)
+        stream_ref = self._saveStreamRef(track_object.stream)
         element.append(factory_ref)
         element.append(stream_ref)
         interpolators = track_object.getInterpolators()
@@ -340,14 +374,48 @@ class ElementTreeFormatter(Formatter):
             curves.append(self._saveInterpolator(interpolator, property))
         element.append(curves)
 
-        self._context.track_objects[track_object] = element
-
-        return element
-
     def _loadTrackObject(self, track, element):
         self.debug("%r", element)
         klass = namedAny(element.attrib["type"])
+        if klass is TrackEffect:
+            track_object = self._loadEffectTrackObject(element, klass, track)
+        else:
+            track_object = self._loadSourceTrackObject(element, klass, track)
+        return track_object
+
+    def _loadEffectTrackObject(self, element, klass, track):
+        effect_element = element.find('effect')
+        factory_name = effect_element.find('factory').attrib['name']
+        properties_elem = effect_element.find('gst-element-properties')
+        try:
+            factory = self.avalaible_effects.getFactoryFromName(factory_name)
+        except KeyError:
+            #Find a way to figure out how we could install the missing effect...
+            raise FormatterError(_("The project contains effects that are not\
+                                   avalaibe on the system. It can't be loaded"))
+
+        input_stream = factory.getInputStreams()
+        if not input_stream:
+            raise FormatterError("cant find effect factory input stream")
+        input_stream = input_stream[0]
+
+        track_object = klass(factory, input_stream)
+
+        track.addTrackObject(track_object)
+
+        for name, value_string in self._filterElementProperties(element):
+            value = self._parsePropertyValue(value_string)
+            setattr(track_object, name, value)
+
+        effect_gst_element = track_object.getElement()
+        for name, value in properties_elem.attrib.iteritems():
+            value = self._parsePropertyValue(value)
+            effect_gst_element.set_property(name, value)
+
+        self._context.track_objects[element.attrib["id"]] = track_object
+        return track_object
 
+    def _loadSourceTrackObject(self, element, klass, track):
         factory_ref = element.find("factory-ref")
         factory = self._loadFactoryRef(factory_ref)
 
diff --git a/pitivi/formatters/format.py b/pitivi/formatters/format.py
index fc63ed5..5bf591d 100644
--- a/pitivi/formatters/format.py
+++ b/pitivi/formatters/format.py
@@ -54,7 +54,7 @@ def list_formats():
     """
     return _formatters
 
-def get_formatter_for_uri(uri):
+def get_formatter_for_uri(uri, avalaible_effects):
     """
     Returns an Formatter object that can parse the given project file
 
@@ -64,7 +64,7 @@ def get_formatter_for_uri(uri):
     """
     for klass, name, exts in _formatters:
         if klass.canHandle(uri):
-            return klass()
+            return klass(avalaible_effects)
 
 def register_formatter(klass, name, extensions):
     _formatters.append((klass, name, extensions))
diff --git a/pitivi/projectmanager.py b/pitivi/projectmanager.py
index b6d0ac9..463454e 100644
--- a/pitivi/projectmanager.py
+++ b/pitivi/projectmanager.py
@@ -82,12 +82,13 @@ class ProjectManager(Signallable, Loggable):
         "reverting-to-saved":["project"],
     }
 
-    def __init__(self):
+    def __init__(self, avalaible_effects={}):
         Signallable.__init__(self)
         Loggable.__init__(self)
 
         self.current = None
         self.backup_lock = 0
+        self.avalaible_effects = avalaible_effects
 
     def loadProject(self, uri):
         """ Load the given project file"""
@@ -133,7 +134,7 @@ class ProjectManager(Signallable, Loggable):
                 formatter == project.format
             else:
                 from pitivi.formatters.etree import ElementTreeFormatter
-                formatter = ElementTreeFormatter()
+                formatter = ElementTreeFormatter(self.avalaible_effects)
 
         if uri is None:
             if project.uri is None:
@@ -195,12 +196,12 @@ class ProjectManager(Signallable, Loggable):
         #no running project or
         #project has not been modified
         if self.current.uri is None \
-           or not self.current.hasUnsavedModifications(): 
+           or not self.current.hasUnsavedModifications():
             return True
 
         if not self.emit("reverting-to-saved", self.current):
             return False
-        uri = self.current.uri 
+        uri = self.current.uri
         self.current.setModificationState(False)
         self.closeRunningProject()
         self.loadProject(uri)
@@ -249,7 +250,7 @@ class ProjectManager(Signallable, Loggable):
         return None
 
     def _getFormatterForUri(self, uri):
-        return get_formatter_for_uri(uri)
+        return get_formatter_for_uri(uri, self.avalaible_effects)
 
     def _connectToFormatter(self, formatter):
         formatter.connect("missing-uri", self._formatterMissingURICb)
diff --git a/pitivi/ui/clipproperties.py b/pitivi/ui/clipproperties.py
index c835d86..5c69167 100644
--- a/pitivi/ui/clipproperties.py
+++ b/pitivi/ui/clipproperties.py
@@ -242,7 +242,7 @@ class EffectProperties(gtk.Expander):
 
     def _dragDataReceivedCb(self, unused_layout, context, x, y,
         selection, targetType, timestamp):
-        self._factory = self.app.effects.getEffect(selection.data)
+        self._factory = self.app.effects.getFactoryFromName(selection.data)
 
     def _dragDropCb(self, unused, context, x, y, timestamp):
         if self._factory:
diff --git a/pitivi/ui/effectlist.py b/pitivi/ui/effectlist.py
index 7234c3d..f57cdce 100644
--- a/pitivi/ui/effectlist.py
+++ b/pitivi/ui/effectlist.py
@@ -165,7 +165,7 @@ class EffectList(gtk.VBox, Loggable):
 
     def _addFactories(self, elements, effectType):
         for element in elements:
-            effect = self.app.effects.getEffect(element.get_name())
+            effect = self.app.effects.getFactoryFromName(element.get_name())
             self.storemodel.append ([effect.icon, effect.getHumanName(),\
                                     effect.getDescription(), effectType, effect.getCategories(),\
                                     effect, element.get_name()])
diff --git a/pitivi/ui/gstwidget.py b/pitivi/ui/gstwidget.py
index 01f69d2..a06bb00 100644
--- a/pitivi/ui/gstwidget.py
+++ b/pitivi/ui/gstwidget.py
@@ -106,6 +106,20 @@ def make_property_widget(unused_element, prop, value=None):
                 selected = idx
             idx = idx + 1
         widget.set_active(selected)
+    elif type_name == 'GstFraction':
+        widget = gtk.HBox()
+        widget1 = gtk.SpinButton()
+        widget1.set_range(0,100)
+        widget1.set_increments(1.0, 10.0)
+        #widget1.set_value(float(value))
+        widget2 = gtk.SpinButton()
+        widget2.set_range(0,100)
+        widget2.set_increments(1.0, 10.0)
+        #widget2.set_value(float(value))
+        widget.pack_start(widget1)
+        widget.pack_start(gtk.Label("/"))
+        widget.pack_start(widget2)
+        print "%s, %s" %(value, type(value))
     else:
         widget = gtk.Label(type_name)
         widget.set_alignment(1.0, 0.5)
diff --git a/pitivi/ui/timeline.py b/pitivi/ui/timeline.py
index 2cf7b8c..2670930 100644
--- a/pitivi/ui/timeline.py
+++ b/pitivi/ui/timeline.py
@@ -530,7 +530,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
             uris = selection.data.split("\n")
             self._factories = [self.project.sources.getUri(uri) for uri in uris]
         else:
-            self._factories = [self.app.effects.getEffect(selection.data)]
+            self._factories = [self.app.effects.getFactoryFromName(selection.data)]
 
         context.drag_status(gtk.gdk.ACTION_COPY, timestamp)
         return True
diff --git a/tests/test_etree_formatter.py b/tests/test_etree_formatter.py
index 25267d3..c8632cf 100644
--- a/tests/test_etree_formatter.py
+++ b/tests/test_etree_formatter.py
@@ -30,10 +30,13 @@ from pitivi.stream import VideoStream, AudioStream
 from pitivi.factories.file import FileSourceFactory
 from pitivi.factories.test import VideoTestSourceFactory, \
     AudioTestSourceFactory
-from pitivi.timeline.track import Track, SourceTrackObject, Interpolator
+from pitivi.factories.operation import EffectFactory
+from pitivi.timeline.track import Track, SourceTrackObject, Interpolator,\
+                                  TrackEffect
 from pitivi.timeline.timeline import Timeline, TimelineObject
 from pitivi.project import Project
 from pitivi.utils import get_controllable_properties
+from pitivi.effects import EffectsHandler
 
 class FakeElementTreeFormatter(ElementTreeFormatter):
     pass
@@ -43,7 +46,7 @@ def ts(time):
 
 class TestFormatterSave(TestCase):
     def setUp(self):
-        self.formatter = FakeElementTreeFormatter()
+        self.formatter = FakeElementTreeFormatter(EffectsHandler())
 
     def testSaveStream(self):
         stream = VideoStream(gst.Caps("video/x-raw-rgb, blah=meh"))
@@ -87,13 +90,13 @@ class TestFormatterSave(TestCase):
         source2.addOutputStream(video_stream)
         source2.addOutputStream(audio_stream)
 
-        factories = [source1, source2]
-        element = self.formatter._saveFactories(factories)
+        source_factories = [source1, source2]
+        element = self.formatter._saveFactories(source_factories)
         self.failUnlessEqual(element.tag, "factories")
 
         sources = element.find("sources")
         self.failUnlessEqual(len(sources), 2)
-        # source tags are tested in testSaveSource
+        #source tags are tested in testSaveSource
 
     def testSaveFactoryRef(self):
         video_stream = VideoStream(gst.Caps("video/x-raw-yuv"))
@@ -107,7 +110,43 @@ class TestFormatterSave(TestCase):
         self.failUnlessEqual(element_ref.tag, "factory-ref")
         self.failUnlessEqual(element_ref.attrib["id"], element.attrib["id"])
 
-    def testSaveTrackObject(self):
+    def testSaveTrackEffect(self):
+        video_stream = VideoStream(gst.Caps("video/x-raw-yuv"))
+        audio_stream = AudioStream(gst.Caps("audio/x-raw-int"))
+
+        effect1 = EffectFactory ('identity', 'identity')
+        effect1.addOutputStream(video_stream)
+        effect1.addInputStream(video_stream)
+
+        #It is necessary to had the identity factory to the 
+        #effect_factories_dictionnary
+        self.formatter.avalaible_effects._effect_factories_dict['identity'] =\
+                                                                     effect1
+        track_effect = TrackEffect(effect1, video_stream,
+                start=10 * gst.SECOND, duration=20 * gst.SECOND,
+                in_point=5 * gst.SECOND, media_duration=15 * gst.SECOND,
+                priority=10)
+
+        track = Track(video_stream)
+        track.addTrackObject(track_effect)
+
+        element = self.formatter._saveTrackObject(track_effect)
+        self.failUnlessEqual(element.tag, "track-object")
+        self.failUnlessEqual(element.attrib["type"],
+                qual(track_effect.__class__))
+        self.failUnlessEqual(element.attrib["start"], ts(10 * gst.SECOND))
+        self.failUnlessEqual(element.attrib["duration"], ts(20 * gst.SECOND))
+        self.failUnlessEqual(element.attrib["in_point"], ts(5 * gst.SECOND))
+        self.failUnlessEqual(element.attrib["media_duration"],
+                ts(15 * gst.SECOND))
+        self.failUnlessEqual(element.attrib["priority"], "(int)10")
+
+        effect_element = element.find('effect')
+        self.failIfEqual(effect_element, None)
+        self.failIfEqual(effect_element.find("factory"), None)
+        self.failIfEqual(effect_element.find("properties"), None)
+
+    def testSaveTrackSource(self):
         video_stream = VideoStream(gst.Caps("video/x-raw-yuv"))
         audio_stream = AudioStream(gst.Caps("audio/x-raw-int"))
         source1 = FileSourceFactory("file1.ogg")
@@ -118,20 +157,22 @@ class TestFormatterSave(TestCase):
         self.formatter._saveSource(source1)
         self.formatter._saveStream(video_stream)
 
-        track_object = SourceTrackObject(source1, video_stream,
+
+        track_source = SourceTrackObject(source1, video_stream,
                 start=10 * gst.SECOND, duration=20 * gst.SECOND,
                 in_point=5 * gst.SECOND, media_duration=15 * gst.SECOND,
                 priority=10)
+
         track = Track(video_stream)
-        track.addTrackObject(track_object)
+        track.addTrackObject(track_source)
 
         # create an interpolator and insert it into the track object
         fakevol = gst.element_factory_make("volume")
         prop = get_controllable_properties(fakevol)[1][1]
-        volcurve = Interpolator(track_object, fakevol, prop)
-        track_object.interpolators[prop.name] = (prop, volcurve)
+        volcurve = Interpolator(track_source, fakevol, prop)
+        track_source.interpolators[prop.name] = (prop, volcurve)
 
-        # add some points to the interpolator 
+        # add some points to the interpolator
         value = float(0)
         volcurve.start.setObjectTime(0)
         volcurve.start.value = 0
@@ -141,10 +182,10 @@ class TestFormatterSave(TestCase):
         volcurve.end.setObjectTime(15 * gst.SECOND)
         volcurve.end.value = 15 % 2
 
-        element = self.formatter._saveTrackObject(track_object)
+        element = self.formatter._saveTrackObject(track_source)
         self.failUnlessEqual(element.tag, "track-object")
         self.failUnlessEqual(element.attrib["type"],
-                qual(track_object.__class__))
+                qual(track_source.__class__))
         self.failUnlessEqual(element.attrib["start"], ts(10 * gst.SECOND))
         self.failUnlessEqual(element.attrib["duration"], ts(20 * gst.SECOND))
         self.failUnlessEqual(element.attrib["in_point"], ts(5 * gst.SECOND))
@@ -161,7 +202,7 @@ class TestFormatterSave(TestCase):
         curve = curves.find("curve")
         self.failIfEqual(curve, None)
         self.failUnlessEqual(curve.attrib["property"], "volume")
-        
+
         # compute a dictionary of keyframes
         saved_points = dict(((obj.attrib["time"], (obj.attrib["value"],
             obj.attrib["mode"])) for obj in curve.getiterator("keyframe")))
@@ -350,7 +391,7 @@ class TestFormatterSave(TestCase):
 
 class TestFormatterLoad(TestCase):
     def setUp(self):
-        self.formatter = FakeElementTreeFormatter()
+        self.formatter = FakeElementTreeFormatter(EffectsHandler())
 
     def testLoadStream(self):
         caps = gst.Caps("video/x-raw-yuv")
@@ -364,6 +405,36 @@ class TestFormatterLoad(TestCase):
         self.failUnlessEqual(str(stream.caps), str(caps))
         self.failUnlessEqual(stream, self.formatter._context.streams["1"])
 
+    def testLoadTrackEffect(self):
+        # create fake document tree
+        element = Element("track-object",\
+                type="pitivi.timeline.track.TrackEffect",
+                start=ts(1 * gst.SECOND), duration=ts(10 * gst.SECOND),
+                in_point=ts(5 * gst.SECOND),
+                media_duration=ts(15 * gst.SECOND), priority=ts(5), id="1")
+        effect_elem = SubElement(element, "effect")
+        factory_elem = SubElement(effect_elem, "factory", name="identity")
+        properties_elem = SubElement(effect_elem, "gst-element-properties", async_handling="(bool)True")
+
+        # insert our fake factory into the context
+        stream = AudioStream(gst.Caps("audio/x-raw-int"))
+        factory = EffectFactory('identity')
+        factory.addInputStream(stream)
+        factory.addOutputStream(stream)
+        self.formatter.avalaible_effects._effect_factories_dict['identity'] = factory
+
+        track = Track(stream)
+        track_object = self.formatter._loadTrackObject(track, element)
+        self.failUnless(isinstance(track_object, TrackEffect))
+        self.failUnlessEqual(track_object.factory, factory)
+        self.failUnlessEqual(track_object.stream, stream)
+
+        self.failUnlessEqual(track_object.start, 1 * gst.SECOND)
+        self.failUnlessEqual(track_object.duration, 10 * gst.SECOND)
+        self.failUnlessEqual(track_object.in_point, 5 * gst.SECOND)
+        self.failUnlessEqual(track_object.media_duration, 15 * gst.SECOND)
+        self.failUnlessEqual(track_object.priority, 5)
+
     def testLoadStreamRef(self):
         stream = VideoStream(gst.Caps("meh"))
         self.formatter._context.streams["1"] = stream
@@ -401,7 +472,7 @@ class TestFormatterLoad(TestCase):
         ret = self.formatter._loadFactoryRef(element)
         self.failUnless(ret is tag)
 
-    def testLoadTrackObject(self):
+    def testLoadTrackSource(self):
         # create fake document tree
         element = Element("track-object",
                 type="pitivi.timeline.track.SourceTrackObject",
@@ -424,11 +495,11 @@ class TestFormatterLoad(TestCase):
         curves = SubElement(element, "curves")
         curve = SubElement(curves, "curve", property="volume",
             version="1")
-        expected = dict((long(t * gst.SECOND), (float(t % 2), gst.INTERPOLATE_LINEAR)) 
+        expected = dict((long(t * gst.SECOND), (float(t % 2), gst.INTERPOLATE_LINEAR))
             for t in xrange(1, 10))
         start = SubElement(curve, "start", value="0.0", mode="2")
         for time, (value, mode) in expected.iteritems():
-            SubElement(curve, "keyframe", time=str(time), value=str(value), 
+            SubElement(curve, "keyframe", time=str(time), value=str(value),
                 mode=str(mode))
         end = SubElement(curve, "end", value=str(10 % 2), mode="2")
 
@@ -479,11 +550,11 @@ class TestFormatterLoad(TestCase):
         # add a volume curve
         curves = SubElement(element, "curves")
         curve = SubElement(curves, "curve", property="volume")
-        expected = dict((long(t * gst.SECOND), (float(t % 2), gst.INTERPOLATE_LINEAR)) 
+        expected = dict((long(t * gst.SECOND), (float(t % 2), gst.INTERPOLATE_LINEAR))
             for t in xrange(6, 15))
         start = SubElement(curve, "start", value="1.0", mode="2")
         for time, (value, mode) in expected.iteritems():
-            SubElement(curve, "keyframe", time=str(time), value=str(value), 
+            SubElement(curve, "keyframe", time=str(time), value=str(value),
                 mode=str(mode))
         end = SubElement(curve, "end", value="1.0", mode="2")
 
diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py
index 2a8d5a9..3d0ab1c 100644
--- a/tests/test_pipeline.py
+++ b/tests/test_pipeline.py
@@ -26,7 +26,7 @@ from unittest import main
 from pitivi.pipeline import Pipeline, STATE_NULL, STATE_READY, STATE_PAUSED, STATE_PLAYING, PipelineError
 from pitivi.action import Action, STATE_ACTIVE, STATE_NOT_ACTIVE
 from pitivi.stream import AudioStream, VideoStream
-from common import TestCase, SignalMonitor, FakeSourceFactory, FakeSinkFactory
+from common import TestCase, SignalMonitor, FakeSourceFactory, FakeSinkFactory, FakeEffectFactory
 
 class BogusAction(Action):
     pass



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