[pitivi: 10/14] Refactor pitivi.sourcelist. Tweak missing-plugin handling.
- From: Edward Hervey <edwardrv src gnome org>
- To: svn-commits-list gnome org
- Subject: [pitivi: 10/14] Refactor pitivi.sourcelist. Tweak missing-plugin handling.
- Date: Wed, 24 Jun 2009 13:11:05 +0000 (UTC)
commit 2ebbd62fd98a67425f35f2751d1b86e5ce5ce270
Author: Alessandro Decina <alessandro d gmail com>
Date: Fri Jun 19 20:19:14 2009 +0200
Refactor pitivi.sourcelist. Tweak missing-plugin handling.
Refactor pitivi.sourcelist so that it removes the (broken) mapping methods and
emits saner signals (source-added, source-removed rather than file_added and
file_removed).
Also tweak missing-plugin handling in discoverer so that we can rediscover a
source more quickly after installing missing plugins.
pitivi/application.py | 15 ++-
pitivi/discoverer.py | 157 ++++++++++++++++++++----------
pitivi/formatters/etree.py | 2 +-
pitivi/project.py | 9 +--
pitivi/sourcelist.py | 214 +++++++++++++++++++----------------------
pitivi/ui/mainwindow.py | 30 +++---
pitivi/ui/sourcelist.py | 12 +-
pitivi/ui/timeline.py | 4 +-
tests/test_discoverer.py | 31 ++++++-
tests/test_etree_formatter.py | 4 +-
tests/test_sourcelist.py | 104 ++++++++++++++++++++
11 files changed, 370 insertions(+), 212 deletions(-)
---
diff --git a/pitivi/application.py b/pitivi/application.py
index 57b01c6..1a9a512 100644
--- a/pitivi/application.py
+++ b/pitivi/application.py
@@ -50,6 +50,7 @@ from pitivi.ui.mainwindow import PitiviMainWindow
from pitivi.projectmanager import ProjectManager
from pitivi.undo import UndoableActionLog, DebugActionLogObserver
from pitivi.timeline.timeline_undo import TimelineLogObserver
+from pitivi.sourcelist_undo import SourceListLogObserver
# FIXME : Speedup loading time
# Currently we load everything in one go
@@ -140,6 +141,7 @@ class Pitivi(Loggable, Signallable):
self.debug_action_log_observer = DebugActionLogObserver()
self.debug_action_log_observer.startObserving(self.action_log)
self.timelineLogObserver = TimelineLogObserver(self.action_log)
+ self.sourcelist_log_observer = SourceListLogObserver(self.action_log)
#{ Shutdown methods
@@ -190,7 +192,9 @@ class Pitivi(Loggable, Signallable):
def _projectManagerNewProjectLoaded(self, projectManager, project):
self.current = project
+ self.action_log.clean()
self.timelineLogObserver.startObserving(project.timeline)
+ self.sourcelist_log_observer.startObserving(project.sources)
self.emit("new-project-loaded", project)
def _projectManagerNewProjectFailed(self, projectManager, uri, exception):
@@ -200,7 +204,6 @@ class Pitivi(Loggable, Signallable):
return self.emit("closing-project", project)
def _projectManagerProjectClosed(self, projectManager, project):
- self.action_log.clean()
self.timelineLogObserver.stopObserving(project.timeline)
self.current = None
self.emit("project-closed", project)
@@ -254,11 +257,11 @@ class InteractivePitivi(Pitivi):
self.projectManager.newBlankProject()
uris = ["file://" + os.path.abspath(path) for path in args]
if options.add_to_timeline:
- self.current.sources.connect("file_added",
- self._addSourceCb, uris)
+ self.current.sources.connect("source-added",
+ self._sourceAddedCb, uris)
self.current.sources.connect("discovery-error",
self._discoveryErrorCb, uris)
- self.current.sources.addUris(uris)
+ self.current.sources.addUris(uris)
# run the mainloop
self.mainloop.run()
@@ -294,7 +297,7 @@ class InteractivePitivi(Pitivi):
return True
- def _addSourceCb(self, unused_sourcelist, factory, startup_uris):
+ def _sourceAddedCb(self, unused_sourcelist, factory, startup_uris):
if self._maybePopStartupUri(startup_uris, factory.uri):
self.current.timeline.addSourceFactory(factory)
@@ -311,7 +314,7 @@ class InteractivePitivi(Pitivi):
return False
if not startup_uris:
- self.current.sources.disconnect_by_function(self._addSourceCb)
+ self.current.sources.disconnect_by_function(self._sourceAddedCb)
self.current.sources.disconnect_by_function(self._discoveryErrorCb)
return True
diff --git a/pitivi/discoverer.py b/pitivi/discoverer.py
index e02be4b..3b07b80 100644
--- a/pitivi/discoverer.py
+++ b/pitivi/discoverer.py
@@ -31,6 +31,9 @@ import gobject
gobject.threads_init()
import gst
import gst.pbutils
+from gst.pbutils import INSTALL_PLUGINS_SUCCESS, \
+ INSTALL_PLUGINS_PARTIAL_SUCCESS, INSTALL_PLUGINS_USER_ABORT, \
+ INSTALL_PLUGINS_STARTED_OK
import tempfile
from base64 import urlsafe_b64encode
@@ -90,6 +93,8 @@ class Discoverer(Signallable, Loggable):
self.missing_plugin_messages = []
self.dynamic_elements = []
self.thumbnails = {}
+ self.missing_plugin_details = []
+ self.missing_plugin_descriptions = []
def _resetPipeline(self):
# finish current, cleanup
@@ -152,33 +157,105 @@ class Discoverer(Signallable, Loggable):
if not self.missing_plugin_messages:
return False
- missing_plugin_details = []
- missing_plugin_descriptions = []
for message in self.missing_plugin_messages:
detail = \
gst.pbutils.missing_plugin_message_get_installer_detail(message)
description = \
gst.pbutils.missing_plugin_message_get_description(message)
- missing_plugin_details.append(detail)
- missing_plugin_descriptions.append(description)
+ self.missing_plugin_details.append(detail)
+ self.missing_plugin_descriptions.append(description)
- result = self.emit('missing-plugins', self.current_uri,
- missing_plugin_details, missing_plugin_descriptions)
+ return True
- if result == gst.pbutils.INSTALL_PLUGINS_STARTED_OK:
- # don't emit an error yet
- self.error = None
- self.error_detail = None
- res = True
+ def _installMissingPluginsCallback(self, result, factory):
+ rescan = False
+
+ if result in (INSTALL_PLUGINS_SUCCESS,
+ INSTALL_PLUGINS_PARTIAL_SUCCESS):
+ gst.update_registry()
+ rescan = True
+ elif result == INSTALL_PLUGINS_USER_ABORT \
+ and factory.getOutputStreams():
+ self._emitDone(factory)
else:
- if self.error is None:
- self.error = _('Missing plugins:\n%s') % \
- '\n'.join(missing_plugin_descriptions)
- self.error_detail = ''
- res = False
+ self._emitErrorMissingPlugins()
+
+ self._finishAnalysisAfterResult(rescan=rescan)
+
+ def _emitError(self):
+ self.emit("discovery-error", self.current_uri, self.error, self.error_detail)
+
+ def _emitErrorMissingPlugins(self):
+ self.error = _("Missing plugins:\n%s") % \
+ "\n".join(self.missing_plugin_descriptions)
+ self.error_detail = ""
+ self._emitError()
+
+ def _emitDone(self, factory):
+ self.emit("discovery-done", self.current_uri, factory)
+
+ def _emitResult(self):
+ # we got a gst error, error out ASAP
+ if self.error:
+ self._emitError()
+ return True
+
+ have_video, have_audio, have_image = self._getCurrentStreamTypes()
+ missing_plugins = bool(self.missing_plugin_details)
+
+ if not self.current_streams and not missing_plugins:
+ # woot, nothing decodable
+ self.error = _('Can not decode file.')
+ self.error_detail = _("The given file does not contain audio, "
+ "video or picture streams.")
+ self._emitError()
+ return True
+
+ # construct the factory with the streams we found
+ if have_image:
+ factory = PictureFileSourceFactory(self.current_uri)
+ else:
+ factory = FileSourceFactory(self.current_uri)
+
+ factory.duration = self.current_duration
+ for stream in self.current_streams:
+ factory.addOutputStream(stream)
+
+ if not missing_plugins:
+ # make sure that we could query the duration (if it's an image, we
+ # assume it's got infinite duration)
+ is_image = have_image and len(self.current_streams) == 1
+ if self.current_duration == gst.CLOCK_TIME_NONE and not is_image:
+ self.error =_("Could not establish the duration of the file.")
+ self.error_detail = _("This clip seems to be in a format "
+ "which cannot be accessed in a random fashion.")
+ self._emitError()
+ return True
+
+ self._emitDone(factory)
+ return True
+
+ def callback(result):
+ self._installMissingPluginsCallback(result, factory)
+
+ res = self.emit("missing-plugins", self.current_uri, factory,
+ self.missing_plugin_details,
+ self.missing_plugin_descriptions,
+ callback)
+ if res is None or res != INSTALL_PLUGINS_STARTED_OK:
+ # no missing-plugins handlers
+ if factory.getOutputStreams():
+ self._emitDone(factory)
+ else:
+ self._emitErrorMissingPlugins()
- return res
+ return True
+
+
+ # plugins are being installed, processing will continue when
+ # self._installMissingPluginsCallback is called by the application
+ return False
def _finishAnalysis(self):
"""
@@ -188,49 +265,21 @@ class Discoverer(Signallable, Loggable):
if self.timeout_id:
self._removeTimeout()
- missing_plugins = self._checkMissingPlugins()
+ # check if there are missing plugins before calling _resetPipeline as we
+ # are going to pop messagess off the bus
+ self._checkMissingPlugins()
self._resetPipeline()
- if not self.current_streams and self.error is None:
- # EOS and no decodable streams?
- self.error = _('No streams found')
- self.error_detail = ""
-
- if len(self.current_streams) == 1:
- stream = self.current_streams[0]
- is_image = isinstance(stream, VideoStream) and stream.is_image
- else:
- is_image = False
-
- if self.error:
- self.emit('discovery-error', self.current_uri, self.error, self.error_detail)
- elif self.current_duration == gst.CLOCK_TIME_NONE and not is_image:
- self.emit('discovery-error', self.current_uri,
- _("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:
- have_video, have_audio, have_image = self._getCurrentStreamTypes()
- if have_video or have_audio:
- factory = FileSourceFactory(self.current_uri)
- elif have_image:
- factory = PictureFileSourceFactory(self.current_uri)
- else:
- # woot, nothing decodable
- self.error = _('Can not decode file.')
- self.error_detail = _('The given file does not contain audio, video or picture streams.')
- factory = None
-
- if factory is not None:
- factory.duration = self.current_duration
-
- for stream in self.current_streams:
- factory.addOutputStream(stream)
- self.emit('discovery-done', self.current_uri, factory)
+ # emit discovery-done, discovery-error or missing-plugins
+ if self._emitResult():
+ self._finishAnalysisAfterResult()
+ def _finishAnalysisAfterResult(self, rescan=False):
self.info("Cleaning up after finished analyzing %s", self.current_uri)
self._resetState()
- self.queue.pop(0)
+ if not rescan:
+ self.queue.pop(0)
# restart an analysis if there's more...
if self.queue:
self._scheduleAnalysis()
diff --git a/pitivi/formatters/etree.py b/pitivi/formatters/etree.py
index ed238a2..b82ad46 100644
--- a/pitivi/formatters/etree.py
+++ b/pitivi/formatters/etree.py
@@ -639,7 +639,7 @@ class ElementTreeFormatter(Formatter):
return
self._replaceMatchingOldFactory(factory, old_factories)
- project.sources.addFactory(factory=factory)
+ project.sources.addFactory(factory)
closure["rediscovered"] += 1
if closure["rediscovered"] == len(old_factories):
diff --git a/pitivi/project.py b/pitivi/project.py
index 52f93ae..1c90144 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -59,13 +59,11 @@ class Project(Signallable, Loggable):
@type loaded: C{bool}
Signals:
- - C{missing-plugins} : A plugin is missing for the given uri
- C{loaded} : The project is now fully loaded.
"""
__signals__ = {
"settings-changed" : None,
- "missing-plugins": ["uri", "detail", "description"],
}
def __init__(self, name="", uri=None, **kwargs):
@@ -81,13 +79,11 @@ class Project(Signallable, Loggable):
self.uri = uri
self.urichanged = False
self.format = None
- self.sources = SourceList(self)
+ self.sources = SourceList()
self.settingssigid = 0
self._dirty = False
- self.sources.connect('missing-plugins', self._sourceListMissingPluginsCb)
-
self.timeline = Timeline()
self.factory = TimelineSourceFactory(self.timeline)
@@ -161,9 +157,6 @@ class Project(Signallable, Loggable):
#}
- def _sourceListMissingPluginsCb(self, source_list, uri, detail, description):
- return self.emit('missing-plugins', uri, detail, description)
-
#{ Save and Load features
def save(self, location=None, overwrite=False):
diff --git a/pitivi/sourcelist.py b/pitivi/sourcelist.py
index 37702b3..bc64d99 100644
--- a/pitivi/sourcelist.py
+++ b/pitivi/sourcelist.py
@@ -3,6 +3,7 @@
# pitivi/sourcelist.py
#
# Copyright (c) 2005, Edward Hervey <bilboed bilboed com>
+# Copyright (c) 2009, Alessandro Decina <alessandro d gmail com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -22,167 +23,143 @@
"""
Handles the list of source for a project
"""
+
import urllib
from pitivi.discoverer import Discoverer
from pitivi.signalinterface import Signallable
from pitivi.log.loggable import Loggable
+class SourceListError(Exception):
+ pass
+
class SourceList(Signallable, Loggable):
+ discovererClass = Discoverer
+
"""
- Contains the sources for a project, stored as FileSourceFactory
+ Contains the sources for a project, stored as SourceFactory objects.
- @ivar project: The owner project
- @type project: L{Project}
- @ivar discoverer: The discoverer used
+ @ivar discoverer: The discoverer object used internally
@type discoverer: L{Discoverer}
- @ivar sources: The sources
- @type sources: Dictionnary of uri => factory
Signals:
- - C{file_added} : A file has been completely discovered and is valid.
- - C{file_removed} : A file was removed from the SourceList.
+ - C{source-added} : A source has been discovered and added to the SourceList.
+ - C{source-removed} : A source was removed from the SourceList.
+ - C{missing-plugins} : A source has been discovered but some plugins are
+ missing in order to decode all of its streams.
- C{discovery-error} : The given uri is not a media file.
- - C{tmp_is_ready} : The temporary uri given to the SourceList is ready to use.
- C{ready} : No more files are being discovered/added.
- C{starting} : Some files are being discovered/added.
"""
__signals__ = {
- "file_added" : ["factory"],
- "file_removed" : ["uri"],
+ "ready" : [],
+ "starting" : [],
+ "missing-plugins": ["uri", "factory", "details", "descriptions"],
+ "source-added" : ["factory"],
+ "source-removed" : ["uri"],
"discovery-error" : ["uri", "reason"],
- "tmp_is_ready": ["factory"],
- "ready" : None,
- "starting" : None,
- "missing-plugins": ["uri", "detail", "description"]
}
- def __init__(self, project=None):
+ def __init__(self):
Loggable.__init__(self)
- self.log("new sourcelist for project %s", project)
- self.project = project
- self.sources = {}
- self._sourceindex = []
- self.tempsources = {}
- self.discoverer = Discoverer()
+ Signallable.__init__(self)
+ self._sources = {}
+ self._ordered_sources = []
+
+ self.discoverer = self.discovererClass()
self.discoverer.connect("discovery-error", self._discoveryErrorCb)
self.discoverer.connect("discovery-done", self._discoveryDoneCb)
self.discoverer.connect("starting", self._discovererStartingCb)
self.discoverer.connect("ready", self._discovererReadyCb)
self.discoverer.connect("missing-plugins",
self._discovererMissingPluginsCb)
- self.missing_plugins = {}
- def __contains__(self, uri):
- return self.sources.__contains__(uri)
- def __delitem__(self, uri):
- try:
- self.sources.__delitem__(uri)
- self._sourceindex.remove(uri)
- except KeyError:
- pass
- else:
- # emit deleted item signal
- self.emit("file_removed", uri)
+ def addUri(self, uri):
+ """
+ Add c{uri} to the source list.
- def __getitem__(self, uri):
- try:
- res = self.sources.__getitem__(uri)
- except KeyError:
- res = None
- return res
+ The uri will be analyzed before being added.
+ """
+ if uri in self._sources:
+ raise SourceListError("URI already present in the source list", uri)
- def __iter__(self):
- """ returns an (uri, factory) iterator over the sources """
- return self.sources.iteritems()
+ uri = urllib.unquote(uri)
+ self._sources[uri] = None
- def addUri(self, uri):
- """ Add the uri to the list of sources, will be discovered """
- # here we add the uri and emit a signal
- # later on the existence of the file will be confirmed or not
- # Until it's confirmed, the uri stays in the temporary list
- # for the moment, we pass it on to the Discoverer
- if uri in self.sources.keys():
- return
- self.sources[uri] = None
self.discoverer.addUri(uri)
def addUris(self, uris):
- """ Add the list of uris to the list of sources, they will be discovered """
- # same as above but for a list
- rlist = []
+ """
+ Add c{uris} to the source list.
+
+ The uris will be analyzed before being added.
+ """
for uri in uris:
- uri = urllib.unquote(uri)
- if not uri in self.sources.keys():
- self.sources[uri] = None
- rlist.append(uri)
+ self.addUri(uri)
- self.discoverer.addUris(rlist)
+ def removeUri(self, uri):
+ """
+ Remove the factory for c{uri} from the source list.
+ """
+ try:
+ factory = self._sources.pop(uri)
+ except KeyError:
+ raise SourceListError("URI not in the sourcelist", uri)
- def addTmpUri(self, uri):
- """ Adds a temporary uri, will not be saved """
- uri = urllib.unquote(uri)
- if uri in self.sources.keys():
- return
- self.tempsources[uri] = None
- self.discoverer.addUri(uri)
+ try:
+ self._ordered_sources.remove(factory)
+ except ValueError:
+ # this can only happen if discoverer hasn't finished scanning the
+ # source, so factory must be None
+ assert factory is None
+
+ self.emit("source-removed", uri, factory)
+
+ def getUri(self, uri):
+ """
+ Get the source corresponding to C{uri}.
+ """
+ factory = self._sources.get(uri, None)
+ if factory is None:
+ raise SourceListError("URI not in the sourcelist", uri)
+
+ return factory
- def removeFactory(self, factory):
- """ Remove a file using it's objectfactory """
- # TODO
- # remove an item using the factory as a key
- # otherwise just use the __delitem__
- # del self[uri]
- rmuri = []
- for uri, fact in self.sources.iteritems():
- if fact == factory:
- rmuri.append(uri)
- for uri in rmuri:
- del self[uri]
-
- # FIXME : Invert the order of the arguments so we can just have:
- # addFactory(self, factory, uri=None)
- def addFactory(self, uri=None, factory=None):
+ def addFactory(self, factory):
"""
Add an objectfactory for the given uri.
"""
- if uri==None:
- uri = factory.uri
- if uri in self and self[uri]:
- raise Exception("We already have an objectfactory for uri %s", uri)
- self.sources[uri] = factory
- self._sourceindex.append(uri)
- self.emit("file_added", factory)
+ if self._sources.get(factory.uri, None) is not None:
+ raise SourceListError("We already have a factory for this uri",
+ factory.uri)
+
+ self._sources[factory.uri] = factory
+ self._ordered_sources.append(factory)
+ self.emit("source-added", factory)
def getSources(self):
""" Returns the list of sources used.
The list will be ordered by the order in which they were added
"""
- res = []
- for i in self._sourceindex:
- res.append(self[i])
- return res
-
- def _discoveryDoneCb(self, unused_discoverer, uri, factory):
- # callback from finishing analyzing factory
- if uri in self.tempsources:
- self.tempsources[uri] = factory
- self.emit("tmp_is_ready", factory)
- elif uri in self.sources:
- self.addFactory(uri, factory)
-
- def _discoveryErrorCb(self, unused_discoverer, uri, reason, extra):
- if self.missing_plugins.pop(uri, None) is None:
- # callback from the discoverer's 'discovery-error' signal
- # remove it from the list
- self.emit("discovery-error", uri, reason, extra)
-
- if uri in self.sources and not self.sources[uri]:
- del self.sources[uri]
- elif uri in self.tempsources:
- del self.tempsources[uri]
+ return self._ordered_sources
+
+ def _discoveryDoneCb(self, discoverer, uri, factory):
+ if factory.uri not in self._sources:
+ # the source was removed while it was being scanned
+ return
+
+ self.addFactory(factory)
+
+ def _discoveryErrorCb(self, discoverer, uri, reason, extra):
+ try:
+ del self._sources[uri]
+ except KeyError:
+ # the source was removed while it was being scanned
+ pass
+
+ self.emit("discovery-error", uri, reason, extra)
def _discovererStartingCb(self, unused_discoverer):
self.emit("starting")
@@ -190,6 +167,11 @@ class SourceList(Signallable, Loggable):
def _discovererReadyCb(self, unused_discoverer):
self.emit("ready")
- def _discovererMissingPluginsCb(self, discoverer, uri, detail, description):
- self.missing_plugins[uri] = True
- return self.emit('missing-plugins', uri, detail, description)
+ def _discovererMissingPluginsCb(self, discoverer, uri, factory,
+ details, descriptions, missingPluginsCallback):
+ if factory.uri not in self._sources:
+ # the source was removed while it was being scanned
+ return None
+
+ return self.emit('missing-plugins', uri, factory,
+ details, descriptions, missingPluginsCallback)
diff --git a/pitivi/ui/mainwindow.py b/pitivi/ui/mainwindow.py
index 09f3454..5e42282 100644
--- a/pitivi/ui/mainwindow.py
+++ b/pitivi/ui/mainwindow.py
@@ -159,7 +159,6 @@ class PitiviMainWindow(gtk.Window, Loggable):
self.error_dialogbox = None
self.settings = instance.settings
self.is_fullscreen = self.settings.mainWindowFullScreen
- self.missing_plugins = []
self.timelinepos = 0
self.prefsdialog = None
create_stock_icons()
@@ -453,23 +452,14 @@ class PitiviMainWindow(gtk.Window, Loggable):
## Missing Plugin Support
- def _installPlugins(self, details):
+ def _installPlugins(self, details, missingPluginsCallback):
context = gst.pbutils.InstallPluginsContext()
context.set_xid(self.window.xid)
res = gst.pbutils.install_plugins_async(details, context,
- self._installPluginsAsyncCb)
+ missingPluginsCallback)
return res
- def _installPluginsAsyncCb(self, result):
- missing_plugins, self.missing_plugins = self.missing_plugins, []
-
- if result != gst.pbutils.INSTALL_PLUGINS_SUCCESS:
- return
-
- gst.update_registry()
- self.app.current.sources.addUris(missing_plugins)
-
## UI Callbacks
def _configureCb(self, unused_widget, event):
@@ -669,6 +659,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
def _projectManagerNewProjectLoadedCb(self, projectManager, project):
self.log("A NEW project is loaded, update the UI!")
self.project = project
+ self._connectToProjectSources(project.sources)
if project.timeline.duration > 0:
self.render_button.set_sensitive(True)
@@ -749,6 +740,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
def _projectManagerProjectClosedCb(self, projectManager, project):
# we must disconnect from the project pipeline before it is released
+ self._disconnectFromProjectSources(project.sources)
self.viewer.setAction(None)
self.viewer.setPipeline(None)
return False
@@ -802,6 +794,12 @@ class PitiviMainWindow(gtk.Window, Loggable):
dialog.destroy()
+ def _connectToProjectSources(self, sourcelist):
+ sourcelist.connect("missing-plugins", self._sourceListMissingPluginsCb)
+
+ def _disconnectFromProjectSources(self, sourcelist):
+ sourcelist.disconnect_by_func(self._sourceListMissingPluginsCb)
+
def _actionLogCommit(self, action_log, stack, nested):
if nested:
return
@@ -858,10 +856,10 @@ class PitiviMainWindow(gtk.Window, Loggable):
sett = self.project.getSettings()
self.viewer.setDisplayAspectRatio(float(sett.videopar * sett.videowidth) / float(sett.videoheight))
- @handler(project, "missing-plugins")
- def _projectMissingPluginsCb(self, project, uri, detail, message):
- self.missing_plugins.append(uri)
- return self._installPlugins(detail)
+ def _sourceListMissingPluginsCb(self, project, uri, factory,
+ details, descriptions, missingPluginsCallback):
+ res = self._installPlugins(details, missingPluginsCallback)
+ return res
## Current Project Pipeline
diff --git a/pitivi/ui/sourcelist.py b/pitivi/ui/sourcelist.py
index 8621db5..d4c1d47 100644
--- a/pitivi/ui/sourcelist.py
+++ b/pitivi/ui/sourcelist.py
@@ -348,13 +348,13 @@ class SourceList(gtk.VBox, Loggable):
"""
self.project_signals.connect(
- project.sources, "file_added", None, self._fileAddedCb)
+ project.sources, "source-added", None, self._sourceAddedCb)
self.project_signals.connect(
- project.sources, "file_removed", None, self._fileRemovedCb)
+ project.sources, "source-removed", None, self._sourceRemovedCb)
self.project_signals.connect(
project.sources, "discovery-error", None, self._discoveryErrorCb)
- self.project_signals.connect(
- project.sources, "missing-plugins", None, self._missingPluginsCb)
+ #self.project_signals.connect(
+ # project.sources, "missing-plugins", None, self._missingPluginsCb)
self.project_signals.connect(
project.sources, "ready", None, self._sourcesStoppedImportingCb)
self.project_signals.connect(
@@ -472,11 +472,11 @@ class SourceList(gtk.VBox, Loggable):
# sourcelist callbacks
- def _fileAddedCb(self, unused_sourcelist, factory):
+ def _sourceAddedCb(self, unused_sourcelist, factory):
""" a file was added to the sourcelist """
self._addFactory(factory)
- def _fileRemovedCb(self, unused_sourcelist, uri):
+ def _sourceRemovedCb(self, sourcelist, uri, factory):
""" the given uri was removed from the sourcelist """
# find the good line in the storemodel and remove it
model = self.storemodel
diff --git a/pitivi/ui/timeline.py b/pitivi/ui/timeline.py
index a3e1c2e..0eb7ee1 100644
--- a/pitivi/ui/timeline.py
+++ b/pitivi/ui/timeline.py
@@ -277,7 +277,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self.warning("self._factories:%r, self._temp_objects:%r",
not not self._factories,
not not self._temp_objects)
- if not self._factories:
+ if self._factories is None:
atom = gtk.gdk.atom_intern(dnd.FILESOURCE_TUPLE[0])
self.drag_get_data(context, atom, timestamp)
self.drag_highlight()
@@ -324,7 +324,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
uris = selection.data.split("\n")
else:
context.finish(False, False, timestamp)
- self._factories = [self.project.sources[uri] for uri in uris]
+ self._factories = [self.project.sources.getUri(uri) for uri in uris]
context.drag_status(gtk.gdk.ACTION_COPY, timestamp)
return True
diff --git a/tests/test_discoverer.py b/tests/test_discoverer.py
index 4451c47..36ef727 100644
--- a/tests/test_discoverer.py
+++ b/tests/test_discoverer.py
@@ -365,7 +365,6 @@ class TestStateChange(TestCase):
self.error_detail = debug
def discoveryDoneCb(self, disc, uri, factory):
- self.failUnlessEqual(factory.duration, 10 * gst.SECOND)
self.factories.append(factory)
def testBusStateChangedIgnored(self):
@@ -457,3 +456,33 @@ class TestStateChange(TestCase):
self.failUnless(isinstance(factory, PictureFileSourceFactory))
self.failUnlessEqual(len(factory.output_streams), 1)
+ def testDurationCheckImage(self):
+ self.discoverer.current_duration = gst.CLOCK_TIME_NONE
+ pngdec = gst.element_factory_make('pngdec')
+ self.discoverer.pipeline.add(pngdec)
+ pad = pngdec.get_pad('src')
+ caps = gst.Caps(pad.get_caps()[0])
+ caps[0]['width'] = 320
+ caps[0]['height'] = 240
+ caps[0]['framerate'] = gst.Fraction(0, 1)
+ pad.set_caps(caps)
+ self.discoverer._newDecodedPadCb(None, pad, False)
+ self.discoverer.addUri('illbepopped')
+ self.discoverer._finishAnalysis()
+
+ self.failUnlessEqual(self.error, None)
+ self.failUnlessEqual(self.discoverer.current_duration,
+ gst.CLOCK_TIME_NONE)
+
+ def testDurationCheckNonImage(self):
+ self.discoverer.current_duration = gst.CLOCK_TIME_NONE
+ pad = gst.Pad('src', gst.PAD_SRC)
+ pad.set_caps(gst.Caps('audio/x-raw-int'))
+ self.discoverer._newDecodedPadCb(None, pad, False)
+ self.discoverer.addUri('illbepopped')
+ self.discoverer._finishAnalysis()
+
+ self.failUnlessEqual(self.error,
+ "Could not establish the duration of the file.")
+ self.failUnlessEqual(self.discoverer.current_duration,
+ gst.CLOCK_TIME_NONE)
diff --git a/tests/test_etree_formatter.py b/tests/test_etree_formatter.py
index 166dad0..611d041 100644
--- a/tests/test_etree_formatter.py
+++ b/tests/test_etree_formatter.py
@@ -294,7 +294,7 @@ class TestFormatterSave(TestCase):
project = Project()
project.timeline = timeline
- project.sources.addFactory("meh", source1)
+ project.sources.addFactory(source1)
element = self.formatter._serializeProject(project)
@@ -516,7 +516,7 @@ class TestFormatterLoad(TestCase):
project = Project()
project.timeline = timeline
- project.sources.addFactory("meh", source1)
+ project.sources.addFactory(source1)
element = self.formatter._serializeProject(project)
diff --git a/tests/test_sourcelist.py b/tests/test_sourcelist.py
new file mode 100644
index 0000000..b128047
--- /dev/null
+++ b/tests/test_sourcelist.py
@@ -0,0 +1,104 @@
+# PiTiVi , Non-linear video editor
+#
+# pitivi/sourcelist.py
+#
+# Copyright (c) 2009, Alessandro Decina <alessandro d gmail com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+from unittest import TestCase
+from pitivi.sourcelist import SourceList, SourceListError
+from pitivi.discoverer import Discoverer
+from pitivi.factories.file import FileSourceFactory
+
+class FakeDiscoverer(Discoverer):
+ def _scheduleAnalysis(self):
+ pass
+
+
+class FakeSourceList(SourceList):
+ discovererClass = FakeDiscoverer
+
+
+class TestSourceList(TestCase):
+ def setUp(self):
+ self.sourcelist = SourceList()
+
+ def testAddUriDiscoveryOk(self):
+ """
+ Test the simple case of adding an uri.
+ """
+ uri = "file:///ciao"
+ factory = FileSourceFactory(uri)
+ self.sourcelist.addUri(uri)
+ self.failUnlessEqual(len(self.sourcelist.getSources()), 0)
+ self.failUnlessRaises(SourceListError, self.sourcelist.addUri, uri)
+
+ # mock discovery-done
+ self.sourcelist.discoverer.emit("discovery-done", uri, factory)
+ self.failUnlessEqual(len(self.sourcelist.getSources()), 1)
+
+ # can't add again
+ self.failUnlessRaises(SourceListError, self.sourcelist.addUri, uri)
+
+ def testAddUriDiscoveryOkSourceGone(self):
+ """
+ Test that we don't explode if discoverer finishes analyzing a source
+ that in the meantime was removed.
+ """
+ uri = "file:///ciao"
+ factory = FileSourceFactory(uri)
+ self.sourcelist.addUri(uri)
+ self.sourcelist.removeUri(uri)
+
+ self.sourcelist.discoverer.emit("discovery-done", uri, factory)
+ self.failUnlessEqual(len(self.sourcelist.getSources()), 0)
+
+ # this shouldn't fail since we removed the factory before the discovery
+ # was complete
+ self.sourcelist.addUri(uri)
+
+ def testAddUriDiscoveryErrorSourceGone(self):
+ """
+ Same as the test above, but testing the discovery-error handler.
+ """
+ uri = "file:///ciao"
+ factory = FileSourceFactory(uri)
+ self.sourcelist.addUri(uri)
+ self.sourcelist.removeUri(uri)
+
+ self.sourcelist.discoverer.emit("discovery-error", uri,
+ "error", "verbose debug")
+ self.failUnlessEqual(len(self.sourcelist.getSources()), 0)
+
+ # this shouldn't fail since we removed the factory before the discovery
+ # was complete
+ self.sourcelist.addUri(uri)
+
+ def testAddUriDiscoveryError(self):
+ uri = "file:///ciao"
+ factory = FileSourceFactory(uri)
+ self.sourcelist.addUri(uri)
+ self.failUnlessEqual(len(self.sourcelist.getSources()), 0)
+ self.failUnlessRaises(SourceListError, self.sourcelist.addUri, uri)
+
+ # mock discovery-done
+ self.sourcelist.discoverer.emit("discovery-error", uri,
+ "error", "verbose debug")
+ self.failUnlessEqual(len(self.sourcelist.getSources()), 0)
+
+ # there was an error, the factory wasn't added so this shouldn't raise
+ self.sourcelist.addUri(uri)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]