[pitivi] Make Pitivi a GtkApplication



commit f7e23b0955525a72e9e923940d8a766aa690d87d
Author: Alexandru Băluț <alexandru balut gmail com>
Date:   Sun Mar 16 23:43:02 2014 +0100

    Make Pitivi a GtkApplication
    
    Fixes https://bugzilla.gnome.org/show_bug.cgi?id=693291

 bin/pitivi.in                   |   32 ++--
 pitivi/application.py           |  369 +++++++++------------------------------
 pitivi/clipproperties.py        |   22 ++--
 pitivi/dialogs/startupwizard.py |   35 ++--
 pitivi/effects.py               |   11 +-
 pitivi/mainwindow.py            |  106 ++++++------
 pitivi/medialibrary.py          |   30 ++--
 pitivi/project.py               |   19 ++-
 pitivi/render.py                |   12 +-
 pitivi/timeline/timeline.py     |    2 +-
 pitivi/transitions.py           |    6 +-
 pitivi/viewer.py                |   10 +-
 tests/test_application.py       |    7 +
 13 files changed, 241 insertions(+), 420 deletions(-)
---
diff --git a/bin/pitivi.in b/bin/pitivi.in
index be68e43..c347fdf 100644
--- a/bin/pitivi.in
+++ b/bin/pitivi.in
@@ -123,27 +123,19 @@ def _check_requirements():
         sys.exit(2)
 
 def _run_pitivi():
-    import pitivi.application as ptv
+    from pitivi import application
 
-    # Make it easy for developers to debug the application startup.
-    if os.environ.get('PITIVI_DEBUG_NO_UI') == '1':
-        print('Starting Pitivi with no GUI.')
-        ptv.GuiPitivi._showGui = lambda *args, **kargs : None
-
-    # Start the real Pitivi, with given arguments.
-    sys.exit(ptv.main(sys.argv))
+    app = application.Pitivi()
+    app.run(sys.argv)
 
 
 if __name__ == "__main__":
-    try:
-        _add_pitivi_path()
-        _initialize_modules()
-        # Dep checks really have to happen here, not in application.py. Otherwise,
-        # as soon as application.py starts, it will try importing all the code and
-        # the classes in application.py will not even have the opportunity to run.
-        # We do these checks on every startup (even outside the dev environment, for
-        # soft deps); doing imports and gst registry checks has near-zero cost.
-        _check_requirements()
-        _run_pitivi()
-    except KeyboardInterrupt:
-        print("\tPitivi stopped by user with KeyboardInterrupt!")
+    _add_pitivi_path()
+    _initialize_modules()
+    # Dep checks really have to happen here, not in application.py. Otherwise,
+    # as soon as application.py starts, it will try importing all the code and
+    # the classes in application.py will not even have the opportunity to run.
+    # We do these checks on every startup (even outside the dev environment, for
+    # soft deps); doing imports and gst registry checks has near-zero cost.
+    _check_requirements()
+    _run_pitivi()
diff --git a/pitivi/application.py b/pitivi/application.py
index 1c87e38..c2095d8 100644
--- a/pitivi/application.py
+++ b/pitivi/application.py
@@ -1,10 +1,8 @@
 # Pitivi video editor
 #
-#       pitivi/pitivi.py
+#       pitivi/application.py
 #
-# Copyright (c) 2005-2009 Edward Hervey <bilboed bilboed com>
-# Copyright (c) 2008-2009 Alessandro Decina <alessandro d gmail com>
-# Copyright (c) 2010      Google <aleb google com>
+# Copyright (c) 2014 <alexandru balut gmail com>
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU Lesser General Public
@@ -21,29 +19,13 @@
 # Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 # Boston, MA 02110-1301, USA.
 
-"""
-Main application
-
-Hierarchy of the whole thing:
-
-Pitivi
-    InteractivePitivi
-    GuiPitivi
-        ProjectCreatorGuiPitivi
-        ProjectLoaderGuiPitivi
-        StartupWizardGuiPitivi
-"""
 import os
-import sys
 
-from gi.repository import GES
+from gi.repository import GObject
+from gi.repository import GdkX11
 from gi.repository import Gio
-from gi.repository import GLib
 from gi.repository import Gtk
 
-from gettext import gettext as _
-from optparse import OptionParser
-
 from pitivi.effects import EffectsHandler
 from pitivi.configure import VERSION, RELEASES_URL
 from pitivi.settings import GlobalSettings
@@ -54,77 +36,105 @@ from pitivi.undo.undo import UndoableActionLog, DebugActionLogObserver
 from pitivi.dialogs.startupwizard import StartUpWizard
 
 from pitivi.utils.misc import quote_uri
-from pitivi.utils.signal import Signallable
 from pitivi.utils.system import getSystem
 from pitivi.utils.loggable import Loggable
 import pitivi.utils.loggable as log
-#FIXME GES port disabled it
-#from pitivi.undo.timeline import TimelineLogObserver
 
 
-class Pitivi(Loggable, Signallable):
+class Pitivi(Gtk.Application, Loggable):
     """
-    Pitivi's main application class.
-
-    Signals:
-     - C{new-project} : A new C{Project} is loaded and ready to use.
-
-     - C{new-project-loading} : Pitivi is attempting to load a new project.
-     - C{new-project-loaded} : A new L{Project} has been loaded, and the UI should refresh it's view.
-     - C{new-project-failed} : A new L{Project} failed to load.
-     - C{project-closed} : The project is closed, it will be freed when the callback returns.
-     Classes should connect to this instance when they want to know that
-     data related to that project is no longer going to be used.
-     - C{shutdown} : Used internally, do not use this signal.`
+    Pitivi's application.
 
+    @ivar gui: The main window of the app.
+    @type gui: L{PitiviMainWindow}
+    @type project_manager: L{ProjectManager}
     @ivar settings: Application-wide settings.
     @type settings: L{GlobalSettings}.
-    @ivar current: Currently used project.
-    @type current: L{Project}.
     """
 
-    __signals__ = {
-        "new-project": ["project"],
-        "new-project-loading": ["uri"],
-        "new-project-created": ["project"],
-        "new-project-loaded": ["project"],
-        "new-project-failed": ["uri", "exception"],
-        "project-closed": ["project"],
-        "missing-uri": ["formatter", "uri"],
-        "version-info-received": ["versions"],
-        "shutdown": None}
+    __gsignals__ = {
+        'version-info-received': (GObject.SIGNAL_RUN_LAST, None, (object,))
+    }
 
     def __init__(self):
+        Gtk.Application.__init__(self,
+                                 application_id="org.pitivi",
+                                 flags=Gio.ApplicationFlags.HANDLES_OPEN)
         Loggable.__init__(self)
 
+        self.settings = None
+        self.threads = None
+        self.effects = None
+        self.system = None
+        self.project_manager = ProjectManager(self)
+        self.action_log = None
+        self.debug_action_log_observer = None
+        self.project_log_observer = None
+
+        self.gui = None
+        self.welcome_wizard = None
+
+        self._version_information = {}
+
+        self.connect("startup", self.startupCb)
+        self.connect("activate", self.activateCb)
+        self.connect("open", self.openCb)
+
+    def startupCb(self, unused_app):
         # Init logging as early as possible so we can log startup code
         enable_color = not os.environ.get('PITIVI_DEBUG_NO_COLOR', '0') in ('', '1')
-        # Let's show a human-readable pitivi debug output by default, and only
+        # Let's show a human-readable Pitivi debug output by default, and only
         # show a crazy unreadable mess when surrounded by gst debug statements.
         enable_crack_output = "GST_DEBUG" in os.environ
         log.init('PITIVI_DEBUG', enable_color, enable_crack_output)
 
         self.info('starting up')
-
         self.settings = GlobalSettings()
         self.threads = ThreadMaster()
         self.effects = EffectsHandler()
         self.system = getSystem()
 
-        self.current_project = None
-        self.projectManager = ProjectManager(self)
-        self._connectToProjectManager(self.projectManager)
-
         self.action_log = UndoableActionLog()
         self.debug_action_log_observer = DebugActionLogObserver()
         self.debug_action_log_observer.startObserving(self.action_log)
-        # TODO reimplement the observing after GES port
-        #self.timelineLogObserver = TimelineLogObserver(self.action_log)
-        self.projectLogObserver = ProjectLogObserver(self.action_log)
+        self.project_log_observer = ProjectLogObserver(self.action_log)
+
+        self.project_manager.connect("new-project-loaded", self._newProjectLoaded)
+        self.project_manager.connect("project-closed", self._projectClosed)
 
-        self._version_information = {}
         self._checkVersion()
 
+    def activateCb(self, unused_app):
+        if self.gui:
+            # The app is already started and the window already created.
+            # Present the already existing window.
+            # TODO: Use present() instead of present_with_time() when
+            # https://bugzilla.gnome.org/show_bug.cgi?id=688830 is fixed.
+            x11_server_time = GdkX11.x11_get_server_time(self.gui.get_window())
+            self.gui.present_with_time(x11_server_time)
+            # No need to show the welcome wizard.
+            return
+        self.createMainWindow()
+        self.welcome_wizard = StartUpWizard(self)
+        self.welcome_wizard.show()
+
+    def createMainWindow(self):
+        if self.gui:
+            return
+        self.gui = PitiviMainWindow(self)
+        self.add_window(self.gui)
+        # We might as well show it.
+        self.gui.show()
+
+    def openCb(self, unused_app, giofiles, unused_count, unused_hint):
+        assert giofiles
+        self.createMainWindow()
+        if len(giofiles) > 1:
+            self.warning("Can open only one project file at a time. Ignoring the rest!")
+        project_file = giofiles[0]
+        self.project_manager.loadProject(quote_uri(project_file.get_uri()))
+        return True
+
     def shutdown(self):
         """
         Close Pitivi.
@@ -133,56 +143,32 @@ class Pitivi(Loggable, Signallable):
         @rtype: C{bool}
         """
         self.debug("shutting down")
-        # we refuse to close if we're running a user interface and the user
-        # doesn't want us to close the current project.
-        if self.current_project and not self.projectManager.closeRunningProject():
+        # Refuse to close if we are not done with the current project.
+        if not self.project_manager.closeRunningProject():
             self.warning("Not closing since running project doesn't want to close")
             return False
+        if self.welcome_wizard:
+            self.welcome_wizard.hide()
+        if self.gui:
+            self.gui.destroy()
         self.threads.stopAllThreads()
         self.settings.storeSettings()
-        self.current_project = None
-        self.emit("shutdown")
+        self.quit()
         return True
 
-    def _connectToProjectManager(self, projectManager):
-        pm = projectManager
-        pm.connect("new-project-loading", self._projectManagerNewProjectLoading)
-        pm.connect("new-project-created", self._projectManagerNewProjectCreated)
-        pm.connect("new-project-loaded", self._projectManagerNewProjectLoaded)
-        pm.connect("new-project-failed", self._projectManagerNewProjectFailed)
-        pm.connect("project-closed", self._projectManagerProjectClosed)
-
-    def _projectManagerNewProjectLoading(self, unused_project_manager, uri):
-        self.emit("new-project-loading", uri)
-
-    def _projectManagerNewProjectCreated(self, unused_project_manager, project):
-        self.current_project = project
-        self.emit("new-project-created", project)
-
-    def _newProjectLoaded(self, unused_project):
-        pass
-
-    def _projectManagerNewProjectLoaded(self, unused_project_manager, project, unused_fully_loaded):
-        self.current_project = project
+    def _newProjectLoaded(self, unused_project_manager, project, unused_fully_loaded):
         self.action_log.clean()
-        #self.timelineLogObserver.startObserving(project.timeline)
-        self.projectLogObserver.startObserving(project)
-        self._newProjectLoaded(project)
-        self.emit("new-project-loaded", project)
-
-    def _projectManagerNewProjectFailed(self, unused_project_manager, uri, exception):
-        self.emit("new-project-failed", uri, exception)
+        self.project_log_observer.startObserving(project)
 
-    def _projectManagerProjectClosed(self, unused_project_manager, project):
-        #self.timelineLogObserver.stopObserving(project.timeline)
-        self.projectLogObserver.stopObserving(project)
-        self.current_project = None
-        self.emit("project-closed", project)
+    def _projectClosed(self, unused_project_manager, project):
+        self.project_log_observer.stopObserving(project)
 
     def _checkVersion(self):
-        # Check online for release versions information
+        """
+        Check online for release versions information.
+        """
+        self.info("Requesting version information async")
         giofile = Gio.File.new_for_uri(RELEASES_URL)
-        self.info("Requesting version information")
         giofile.load_contents_async(None, self._versionInfoReceivedCb, None)
 
     def _versionInfoReceivedCb(self, giofile, result, user_data):
@@ -230,188 +216,3 @@ class Pitivi(Loggable, Signallable):
         Get the latest version of the app or None.
         """
         return self._version_information.get("current")
-
-
-class InteractivePitivi(Pitivi):
-    """
-    Base class to launch interactive Pitivi
-    """
-
-    def __init__(self, debug=False):
-        Pitivi.__init__(self)
-        self.mainloop = GLib.MainLoop()
-        self.gui = None
-        if debug:
-            sys.excepthook = self._excepthook
-
-    def _excepthook(self, unused_exc_type, unused_value, tback):
-        import traceback
-        import pdb
-        traceback.print_tb(tback)
-        pdb.post_mortem(tback)
-
-    def run(self):
-        """Runs the main loop."""
-        self.mainloop.run()
-
-
-class GuiPitivi(InteractivePitivi):
-    """
-    Base class to launch a Pitivi instance with a graphical user interface
-
-    This is called when we start the UI with a project passed as a parameter.
-    It is also called by StartupWizardGuiPitivi.
-    """
-
-    def __init__(self, debug=False):
-        InteractivePitivi.__init__(self, debug)
-        self._showGui()
-
-    def _showStartupError(self, message, detail):
-        dialog = Gtk.MessageDialog(message_type=Gtk.MessageType.ERROR,
-                                   buttons=Gtk.ButtonsType.OK)
-        dialog.set_markup("<b>" + message + "</b>")
-        dialog.format_secondary_text(detail)
-        dialog.run()
-
-    def _createGui(self):
-        """Returns a Gtk.Widget which represents the UI."""
-        return PitiviMainWindow(self)
-
-    def _showGui(self):
-        """Creates and shows the UI."""
-        self.gui = self._createGui()
-        self.gui.show()
-
-    def shutdown(self):
-        if Pitivi.shutdown(self):
-            self.gui.destroy()
-            self.mainloop.quit()
-            return True
-        return False
-
-
-class ProjectCreatorGuiPitivi(GuiPitivi):
-    """
-    Creates an instance of Pitivi with the UI and loading a list
-    of clips, adding them to the timeline or not
-    """
-
-    def __init__(self, media_filenames, add_to_timeline=False, debug=False):
-        GuiPitivi.__init__(self, debug)
-        # load the passed filenames, optionally adding them to the timeline
-        # (useful during development)
-        self.projectManager.newBlankProject(emission=False)
-        uris = [quote_uri(os.path.abspath(media_filename))
-                for media_filename in media_filenames]
-        lib = self.current_project.medialibrary
-        lib.connect("source-added", self._sourceAddedCb, uris, add_to_timeline)
-        lib.connect("discovery-error", self._discoveryErrorCb, uris)
-        lib.addUris(uris)
-
-    def _sourceAddedCb(self, unused_media_library, info, startup_uris, add_to_timeline):
-        if self._maybePopStartupUri(startup_uris, info.get_uri()) \
-                and add_to_timeline:
-            self.action_log.begin("add clip")
-            src = GES.UriClip(uri=info.get_uri())
-            src.set_property("priority", 1)
-            self.current_project.timeline.get_layers()[0].add_clip(src)
-            self.action_log.commit()
-
-    def _discoveryErrorCb(self, unused_media_library, uri, unused_error, unused_debug, startup_uris):
-        self._maybePopStartupUri(startup_uris, uri)
-
-    def _maybePopStartupUri(self, startup_uris, uri):
-        try:
-            startup_uris.remove(uri)
-        except ValueError:
-            # uri is not a startup uri. This can happen if the user starts
-            # importing sources while sources specified at startup are still
-            # being processed. In practice this will never happen.
-            return False
-
-        if not startup_uris:
-            self.current_project.medialibrary.disconnect_by_function(self._sourceAddedCb)
-            self.current_project.medialibrary.disconnect_by_function(self._discoveryErrorCb)
-
-        return True
-
-
-class ProjectLoaderGuiPitivi(GuiPitivi):
-    """
-    Creates an instance of the UI and loads @project_filename
-    """
-
-    def __init__(self, project_filename, debug=False):
-        GuiPitivi.__init__(self, debug)
-        if not os.path.exists(project_filename):
-            self.error("Project file does not exist: %s" % project_filename)
-            sys.exit(1)
-        self.projectManager.loadProject(quote_uri(os.path.abspath(project_filename)))
-
-
-class StartupWizardGuiPitivi(GuiPitivi):
-    """
-    Creates an instance of the Pitivi UI with the welcome dialog
-
-    This is not called when a project is passed as a parameter.
-    """
-
-    def __init__(self, debug=False):
-        GuiPitivi.__init__(self, debug)
-        self.projectManager.newBlankProject(emission=False)
-
-    def _createGui(self):
-        return PitiviMainWindow(self)
-
-    def _showGui(self):
-        GuiPitivi._showGui(self)
-        self.wizard = StartUpWizard(self)
-        self.wizard.show()
-
-
-def _parse_options(argv):
-    parser = OptionParser(
-        usage=_("""
-    %prog [PROJECT_FILE]               # Start the video editor.
-    %prog -i [-a] [MEDIA_FILE1 ...]    # Start the editor and create a project."""))
-
-    parser.add_option("-i", "--import", dest="import_sources",
-            action="store_true", default=False,
-            help=_("Import each MEDIA_FILE into a new project."))
-    parser.add_option("-a", "--add-to-timeline",
-            action="store_true", default=False,
-            help=_("Add each imported MEDIA_FILE to the timeline."))
-    parser.add_option("-d", "--debug",
-            action="store_true", default=False,
-            help=_("Run Pitivi in the Python Debugger."))
-    options, args = parser.parse_args(argv[1:])
-
-    # Validate options.
-    if options.add_to_timeline and not options.import_sources:
-        parser.error(_("-a requires -i"))
-
-    # Validate args.
-    if options.import_sources:
-        # When no MEDIA_FILE is specified, we just create a new project.
-        pass
-    else:
-        if len(args) > 1:
-            parser.error(_("Cannot open more than one PROJECT_FILE"))
-
-    return options, args
-
-
-def main(argv):
-    options, args = _parse_options(argv)
-    if options.import_sources:
-        ptv = ProjectCreatorGuiPitivi(media_filenames=args,
-                                      add_to_timeline=options.add_to_timeline,
-                                      debug=options.debug)
-    else:
-        if args:
-            ptv = ProjectLoaderGuiPitivi(project_filename=args[0],
-                                         debug=options.debug)
-        else:
-            ptv = StartupWizardGuiPitivi(debug=options.debug)
-    ptv.run()
diff --git a/pitivi/clipproperties.py b/pitivi/clipproperties.py
index 8d90c8f..f234363 100644
--- a/pitivi/clipproperties.py
+++ b/pitivi/clipproperties.py
@@ -144,7 +144,7 @@ class EffectProperties(Gtk.Expander, Loggable):
     # Note: This should be inherited from Gtk.Expander when we get other things
     # to put in ClipProperties, that is why this is done this way
 
-    def __init__(self, instance, effects_properties_manager, clip_properties):
+    def __init__(self, app, effects_properties_manager, clip_properties):
         # Set up the expander widget that will contain everything:
         Gtk.Expander.__init__(self)
         self.set_expanded(True)
@@ -152,8 +152,8 @@ class EffectProperties(Gtk.Expander, Loggable):
         Loggable.__init__(self)
 
         # Global variables related to effects
-        self.app = instance
-        self.settings = instance.settings
+        self.app = app
+        self.settings = app.settings
 
         self.selected_effects = []
         self.clips = []
@@ -244,11 +244,11 @@ class EffectProperties(Gtk.Expander, Loggable):
         self.treeview.connect("query-tooltip", self._treeViewQueryTooltipCb)
         self._vcontent.connect("notify", self._vcontentNotifyCb)
         removeEffectButton.connect("clicked", self._removeEffectCb)
-        self.app.connect("new-project-loaded", self._newProjectLoadedCb)
+        self.app.project_manager.connect("new-project-loaded", self._newProjectLoadedCb)
         self.connect('notify::expanded', self._expandedCb)
         self.connected = False
 
-    def _newProjectLoadedCb(self, app, project):
+    def _newProjectLoadedCb(self, app, project, unused_fully_loaded):
         self.clip_properties.project = project
         self.selected_effects = self.timeline.selection.getSelectedEffects()
         self.updateAll()
@@ -337,9 +337,9 @@ class EffectProperties(Gtk.Expander, Loggable):
                     effect = GES.Effect.new(bin_description=bin_desc)
                     clip.add(effect)
                     self.updateAll()
-                    self.app.current_project.timeline.commit()
+                    self.app.project_manager.current_project.timeline.commit()
                     self.app.action_log.commit()
-                    self.app.current_project.pipeline.flushSeek()
+                    self.app.project_manager.current_project.pipeline.flushSeek()
 
                     break
 
@@ -371,7 +371,7 @@ class EffectProperties(Gtk.Expander, Loggable):
         tck_effect.set_active(not tck_effect.is_active())
         cellrenderertoggle.set_active(tck_effect.is_active())
         self._updateTreeview()
-        self.app.current_project.timeline.commit()
+        self.app.project_manager.current_project.timeline.commit()
         self.app.action_log.commit()
 
     def _expandedCb(self, expander, params):
@@ -579,7 +579,7 @@ class TransformationProperties(Gtk.Expander):
             box.update_from_effect(self.effect)
 
     def _flushPipeLineCb(self, widget):
-        self.app.current_project.pipeline.flushSeek()
+        self.app.project_manager.current_project.pipeline.flushSeek()
 
     def _findEffect(self, name):
         for effect in self._selected_clip.get_children(False):
@@ -593,7 +593,7 @@ class TransformationProperties(Gtk.Expander):
         if not effect:
             effect = GES.Effect.new(bin_description=name)
             self._selected_clip.add(effect)
-            tracks = self.app.projectManager.current_project.timeline.get_tracks()
+            tracks = self.app.project_manager.current_project.timeline.get_tracks()
             effect = self._findEffect(name)
             # disable the effect on default
             a = self.effect.get_gnlobject()
@@ -620,7 +620,7 @@ class TransformationProperties(Gtk.Expander):
             if self._selected_clip:
                 self._selected_clip = None
                 self.zoom_scale.set_value(1.0)
-                self.app.current_project.pipeline.flushSeek()
+                self.app.project_manager.current_project.pipeline.flushSeek()
             self.effect = None
             self.hide()
         self._updateBoxVisibility()
diff --git a/pitivi/dialogs/startupwizard.py b/pitivi/dialogs/startupwizard.py
index 2691f34..8ed3828 100644
--- a/pitivi/dialogs/startupwizard.py
+++ b/pitivi/dialogs/startupwizard.py
@@ -1,4 +1,3 @@
-""" This module implements a startup wizard"""
 # Pitivi video editor
 #
 #       pitivi/dialogs/startupwizard.py
@@ -28,9 +27,9 @@ from gi.repository import GES
 
 from gettext import gettext as _
 
+from pitivi.check import missing_soft_deps
 from pitivi.configure import get_ui_dir
 from pitivi.dialogs.depsmanager import DepsManager
-from pitivi.check import missing_soft_deps
 from pitivi.utils.misc import show_user_manual
 
 
@@ -79,9 +78,10 @@ class StartUpWizard(object):
         if not missing_soft_deps:
             missing_button.hide()
 
-        self.app.projectManager.connect("new-project-failed", self._projectFailedCb)
-        self.app.projectManager.connect("new-project-loaded", self._projectLoadedCb)
-        self.app.projectManager.connect("new-project-loading", self._projectLoadingCb)
+        project_manager = self.app.project_manager
+        project_manager.connect("new-project-failed", self._projectFailedCb)
+        project_manager.connect("new-project-loaded", self._projectLoadedCb)
+        project_manager.connect("new-project-loading", self._projectLoadingCb)
 
         vbox = self.builder.get_object("topvbox")
         self.infobar = Gtk.InfoBar()
@@ -93,7 +93,8 @@ class StartUpWizard(object):
 
     def _newProjectCb(self, unused_button):
         """Handle a click on the New (Project) button."""
-        self.app.projectManager.newBlankProject()
+        self.app.project_manager.newBlankProject()
+        self.hide()
         self.app.gui.showProjectSettingsDialog()
 
     def _loadCb(self, unused_recent_chooser):
@@ -102,13 +103,14 @@ class StartUpWizard(object):
         This calls the project manager to load the associated URI.
         """
         uri = self.recent_chooser.get_current_uri()
-        self.app.projectManager.loadProject(uri)
+        self.app.project_manager.loadProject(uri)
 
     def _keyPressCb(self, unused_widget, event):
         """Handle a key press event on the dialog."""
         if event.keyval == Gdk.KEY_Escape:
             # The user pressed "Esc".
-            self.app.projectManager.newBlankProject()
+            self.app.project_manager.newBlankProject()
+            self.hide()
 
     def _onBrowseButtonClickedCb(self, unused_button6):
         """Handle a click on the Browse button."""
@@ -120,7 +122,8 @@ class StartUpWizard(object):
 
     def _deleteCb(self, unused_widget, unused_event):
         """Handle a click on the X button of the dialog."""
-        self.app.projectManager.newBlankProject()
+        self.app.project_manager.newBlankProject()
+        self.hide()
 
     def show(self):
         """Will show the interal window and position the wizard"""
@@ -137,16 +140,16 @@ class StartUpWizard(object):
         """Handle the failure of a project open operation."""
         self.show()
 
-    def _projectLoadedCb(self, unused_project_manager, unused_project, fully_loaded):
-        """Handle the success of a project load operation.
+    def _projectLoadedCb(self, project_manager, unused_project, fully_loaded):
+        """
+        Handle the success of a project load operation.
 
-        All the create or load project usage scenarios must generate
-        a new-project-loaded signal from self.app.projectManager!
+        @type project_manager: L{ProjectManager}
         """
         if fully_loaded:
-            self.app.projectManager.disconnect_by_function(self._projectFailedCb)
-            self.app.projectManager.disconnect_by_function(self._projectLoadedCb)
-            self.app.projectManager.disconnect_by_function(self._projectLoadingCb)
+            project_manager.disconnect_by_function(self._projectFailedCb)
+            project_manager.disconnect_by_function(self._projectLoadedCb)
+            project_manager.disconnect_by_function(self._projectLoadingCb)
 
     def _projectLoadingCb(self, unused_project_manager, unused_project):
         """Handle the start of a project load operation."""
diff --git a/pitivi/effects.py b/pitivi/effects.py
index 89336fd..ebc49b4 100644
--- a/pitivi/effects.py
+++ b/pitivi/effects.py
@@ -609,12 +609,15 @@ PROPS_TO_IGNORE = ['name', 'qos', 'silent', 'message']
 
 
 class EffectsPropertiesManager:
-    def __init__(self, instance):
+    """
+    @type app: L{Pitivi}
+    """
+    def __init__(self, app):
         self.cache_dict = {}
         self._current_effect_setting_ui = None
         self._current_element_values = {}
-        self.action_log = instance.action_log
-        self.app = instance
+        self.action_log = app.action_log
+        self.app = app
 
     def getEffectConfigurationUI(self, effect):
         """Permit to get a configuration GUI for the effect
@@ -681,5 +684,5 @@ class EffectsPropertiesManager:
             self._current_effect_setting_ui.element.set_child_property(prop.name, value)
             self.action_log.commit()
 
-            self.app.current_project.pipeline.flushSeek()
+            self.app.project_manager.current_project.pipeline.flushSeek()
             self._current_element_values[prop.name] = value
diff --git a/pitivi/mainwindow.py b/pitivi/mainwindow.py
index d70ad64..23d2a26 100644
--- a/pitivi/mainwindow.py
+++ b/pitivi/mainwindow.py
@@ -176,7 +176,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         self.recent_manager = Gtk.RecentManager()
         self._missingUriOnLoading = False
 
-        pm = self.app.projectManager
+        pm = self.app.project_manager
         pm.connect("new-project-loading", self._projectManagerNewProjectLoadingCb)
         pm.connect("new-project-loaded", self._projectManagerNewProjectLoadedCb)
         pm.connect("new-project-failed", self._projectManagerNewProjectFailedCb)
@@ -212,7 +212,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         self.timeline_ui.enableKeyboardAndMouseEvents()
 
     def _renderCb(self, unused_button):
-        self.showRenderDialog(self.app.current_project)
+        self.showRenderDialog(self.app.project_manager.current_project)
 
     def _createUi(self):
         """
@@ -297,7 +297,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
 
         # Now, the lower part: the timeline
         self.timeline_ui = TimelineContainer(self, self.app, self.uimanager)
-        self.timeline_ui.setProjectManager(self.app.projectManager)
+        self.timeline_ui.setProjectManager(self.app.project_manager)
         self.vpaned.pack2(self.timeline_ui, resize=True, shrink=False)
 
         # Enable our shortcuts for HeaderBar buttons and menu items:
@@ -502,33 +502,33 @@ class PitiviMainWindow(Gtk.Window, Loggable):
 ## Toolbar/Menu actions callback
 
     def _newProjectMenuCb(self, unused_action):
-        if self.app.projectManager.newBlankProject() is not False:
+        if self.app.project_manager.newBlankProject() is not False:
             self.showProjectSettingsDialog()
 
     def _openProjectCb(self, unused_action):
         self.openProject()
 
     def _saveProjectCb(self, unused_action):
-        if not self.app.current_project.uri or self.app.projectManager.disable_save is True:
+        if not self.app.project_manager.current_project.uri or self.app.project_manager.disable_save:
             self._saveProjectAsCb(unused_action)
         else:
-            self.app.projectManager.saveProject()
+            self.app.project_manager.saveProject()
 
     def _saveProjectAsCb(self, unused_action):
-        uri = self._showSaveAsDialog(self.app.current_project)
+        uri = self._showSaveAsDialog(self.app.project_manager.current_project)
         if uri is not None:
-            return self.app.projectManager.saveProject(uri)
+            return self.app.project_manager.saveProject(uri)
 
         return False
 
     def _revertToSavedProjectCb(self, unused_action):
-        return self.app.projectManager.revertToSavedProject()
+        return self.app.project_manager.revertToSavedProject()
 
     def _exportProjectAsTarCb(self, unused_action):
-        uri = self._showExportDialog(self.app.current_project)
+        uri = self._showExportDialog(self.app.project_manager.current_project)
         result = None
         if uri:
-            result = self.app.projectManager.exportProject(self.app.current_project, uri)
+            result = self.app.project_manager.exportProject(self.app.project_manager.current_project, uri)
 
         if not result:
             self.log("Project couldn't be exported")
@@ -539,7 +539,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
 
     def showProjectSettingsDialog(self):
         from pitivi.project import ProjectSettingsDialog
-        ProjectSettingsDialog(self, self.app.current_project).window.run()
+        ProjectSettingsDialog(self, self.app.project_manager.current_project).window.run()
         self.updateTitle()
 
     def _userManualCb(self, unused_action):
@@ -605,7 +605,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         # Requesting project closure at this point in time prompts users about
         # unsaved changes (if any); much better than having ProjectManager
         # trigger this *after* the user already chose a new project to load...
-        if not self.app.projectManager.closeRunningProject():
+        if not self.app.project_manager.closeRunningProject():
             return  # The user has not made a decision, don't do anything
 
         chooser = Gtk.FileChooserDialog(title=_("Open File..."),
@@ -630,10 +630,10 @@ class PitiviMainWindow(Gtk.Window, Loggable):
 
         response = chooser.run()
         if response == Gtk.ResponseType.OK:
-            self.app.projectManager.loadProject(chooser.get_uri())
+            self.app.project_manager.loadProject(chooser.get_uri())
         else:
             self.info("User cancelled loading a new project, but no other project is currently active. 
Resetting")
-            self.app.projectManager.newBlankProject()
+            self.app.project_manager.newBlankProject()
         chooser.destroy()
         return True
 
@@ -656,16 +656,16 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         self.prefsdialog.run()
 
 ## Project management callbacks
-    def _projectManagerNewProjectLoadedCb(self, projectManager, unused_project, unused_fully_loaded):
+
+    def _projectManagerNewProjectLoadedCb(self, project_manager, unused_project, unused_fully_loaded):
         """
-        Once a new project has been loaded, wait for media library's
-        "ready" signal to populate the timeline.
+        @type project_manager: L{ProjectManager}
         """
         self.log("A new project is loaded")
-        self._connectToProject(self.app.current_project)
-        self.app.current_project.timeline.connect("notify::duration",
+        self._connectToProject(self.app.project_manager.current_project)
+        self.app.project_manager.current_project.timeline.connect("notify::duration",
                 self._timelineDurationChangedCb)
-        self.app.current_project.pipeline.activatePositionListener()
+        self.app.project_manager.current_project.pipeline.activatePositionListener()
         self._setProject()
 
         #FIXME GES we should re-enable this when possible
@@ -673,16 +673,16 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         self.updateTitle()
 
         if self._missingUriOnLoading:
-            self.app.current_project.setModificationState(True)
+            self.app.project_manager.current_project.setModificationState(True)
             self.save_button.set_sensitive(True)
             self._missingUriOnLoading = False
 
-        if projectManager.disable_save is True:
+        if project_manager.disable_save is True:
             # Special case: we enforce "Save as", but the normal "Save" button
             # redirects to it if needed, so we still want it to be enabled:
             self.save_button.set_sensitive(True)
 
-        if self.app.current_project.timeline.props.duration != 0:
+        if self.app.project_manager.current_project.timeline.props.duration != 0:
             self.render_button.set_sensitive(True)
 
     def _projectManagerNewProjectLoadingCb(self, unused_project_manager, uri):
@@ -718,11 +718,15 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         if project.uri is None:
             project.uri = uri
 
-    def _projectManagerClosingProjectCb(self, projectManager, project):
+    def _projectManagerClosingProjectCb(self, project_manager, project):
+        """
+        @type project_manager: L{ProjectManager}
+        @type project: L{Project}
+        """
         if not project.hasUnsavedModifications():
             return True
 
-        if project.uri and projectManager.disable_save is False:
+        if project.uri and not project_manager.disable_save:
             save = Gtk.STOCK_SAVE
         else:
             save = Gtk.STOCK_SAVE_AS
@@ -755,7 +759,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
 
         if project.uri:
             path = unquote(project.uri).split("file://")[1]
-            last_saved = max(os.path.getmtime(path), projectManager.time_loaded)
+            last_saved = max(os.path.getmtime(path), project_manager.time_loaded)
             time_delta = time() - last_saved
             secondary.props.label = _("If you don't save, "
                 "the changes from the last %s will be lost."
@@ -785,8 +789,8 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         response = dialog.run()
         dialog.destroy()
         if response == Gtk.ResponseType.YES:
-            if project.uri is not None and projectManager.disable_save is False:
-                res = self.app.projectManager.saveProject()
+            if project.uri is not None and project_manager.disable_save is False:
+                res = self.app.project_manager.saveProject()
             else:
                 res = self._saveProjectAsCb(None)
         elif response == Gtk.ResponseType.REJECT:
@@ -815,7 +819,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         return False
 
     def _projectManagerRevertingToSavedCb(self, unused_project_manager, unused_project):
-        if self.app.current_project.hasUnsavedModifications():
+        if self.app.project_manager.current_project.hasUnsavedModifications():
             dialog = Gtk.MessageDialog(transient_for=self,
                     modal=True,
                     message_type=Gtk.MessageType.WARNING,
@@ -929,7 +933,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         if response == Gtk.ResponseType.OK:
             self.log("User chose a new URI for the missing file")
             new_uri = chooser.get_uri()
-            self.app.current_project.setModificationState(False)
+            self.app.project_manager.current_project.setModificationState(False)
         else:
             # Even if the user clicks Cancel, the discoverer keeps trying to
             # import the rest of the clips...
@@ -937,22 +941,22 @@ class PitiviMainWindow(Gtk.Window, Loggable):
             # this async operation, or the filechooser will keep showing up
             # and all sorts of weird things will happen.
             # TODO: bugs #661059, 609136
-            attempted_uri = self.app.current_project.uri
+            attempted_uri = self.app.project_manager.current_project.uri
             reason = _('No replacement file was provided for "<i>%s</i>".\n\n'
                     'Pitivi does not currently support partial projects.'
                     % info_name(asset))
             # Put an end to the async signals spamming us with dialogs:
-            self.app.projectManager.disconnect_by_func(self._projectManagerMissingUriCb)
+            self.app.project_manager.disconnect_by_func(self._projectManagerMissingUriCb)
             # Don't overlap the file chooser with our error dialog
             # The chooser will be destroyed further below, so let's hide it now.
             dialog.hide()
             # Reset projectManager and disconnect all the signals:
-            self.app.projectManager.newBlankProject(ignore_unsaved_changes=True)
+            self.app.project_manager.newBlankProject(ignore_unsaved_changes=True)
             # Force the project load to fail:
             # This will show an error using _projectManagerNewProjectFailedCb
             # You have to do this *after* successfully creating a blank project,
             # or the startupwizard will still be connected to that signal too.
-            self.app.projectManager.emit("new-project-failed", attempted_uri, reason)
+            self.app.project_manager.emit("new-project-failed", attempted_uri, reason)
 
         dialog.destroy()
         return new_uri
@@ -986,9 +990,9 @@ class PitiviMainWindow(Gtk.Window, Loggable):
 
         dirty = action_log.dirty()
         self.save_button.set_sensitive(dirty)
-        if self.app.current_project.uri is not None:
+        if self.app.project_manager.current_project.uri is not None:
             self._menubutton_items["menu_revert_to_saved"].set_sensitive(dirty)
-        self.app.current_project.setModificationState(dirty)
+        self.app.project_manager.current_project.setModificationState(dirty)
 
         can_redo = bool(action_log.redo_stacks)
         self.redo_button.set_sensitive(can_redo)
@@ -1000,28 +1004,28 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         """
         Disconnect and reconnect callbacks to the new current project
         """
-        if not self.app.current_project:
+        if not self.app.project_manager.current_project:
             self.warning("Current project instance does not exist")
             return False
         try:
-            self.app.current_project.disconnect_by_func(self._renderingSettingsChangedCb)
+            self.app.project_manager.current_project.disconnect_by_func(self._renderingSettingsChangedCb)
         except TypeError:
             # When loading the first project, the signal has never been
             # connected before.
             pass
-        self.app.current_project.connect("rendering-settings-changed", self._renderingSettingsChangedCb)
+        self.app.project_manager.current_project.connect("rendering-settings-changed", 
self._renderingSettingsChangedCb)
 
-        self.viewer.setPipeline(self.app.current_project.pipeline)
-        self._renderingSettingsChangedCb(self.app.current_project)
+        self.viewer.setPipeline(self.app.project_manager.current_project.pipeline)
+        self._renderingSettingsChangedCb(self.app.project_manager.current_project)
         if self.timeline_ui:
-            self.clipconfig.project = self.app.current_project
+            self.clipconfig.project = self.app.project_manager.current_project
             #FIXME GES port undo/redo
-            #self.app.timelineLogObserver.pipeline = self.app.current_project.pipeline
+            #self.app.timelineLogObserver.pipeline = self.app.project_manager.current_project.pipeline
 
         # When creating a blank project, medialibrary will eventually trigger
         # this _setProject method, but there's no project URI yet.
-        if self.app.current_project.uri:
-            folder_path = os.path.dirname(path_from_uri(self.app.current_project.uri))
+        if self.app.project_manager.current_project.uri:
+            folder_path = os.path.dirname(path_from_uri(self.app.project_manager.current_project.uri))
             self.settings.lastProjectFolder = folder_path
 
     def _renderingSettingsChangedCb(self, project, unused_item=None, unused_value=None):
@@ -1139,7 +1143,7 @@ class PitiviMainWindow(Gtk.Window, Loggable):
         foo = self._showSaveScreenshotDialog()
         if foo:
             path, mime = foo[0], foo[1]
-            self.app.current_project.pipeline.save_thumbnail(-1, -1, mime, path)
+            self.app.project_manager.current_project.pipeline.save_thumbnail(-1, -1, mime, path)
 
     def _showSaveScreenshotDialog(self):
         """
@@ -1178,12 +1182,12 @@ class PitiviMainWindow(Gtk.Window, Loggable):
 
     def updateTitle(self):
         name = touched = ""
-        if self.app.current_project:
-            if self.app.current_project.name:
-                name = self.app.current_project.name
+        if self.app.project_manager.current_project:
+            if self.app.project_manager.current_project.name:
+                name = self.app.project_manager.current_project.name
             else:
                 name = _("Untitled")
-            if self.app.current_project.hasUnsavedModifications():
+            if self.app.project_manager.current_project.hasUnsavedModifications():
                 touched = "*"
         title = "%s%s — %s" % (touched, name, APPNAME)
         self._headerbar.set_title(title)
diff --git a/pitivi/medialibrary.py b/pitivi/medialibrary.py
index e48b856..9e06637 100644
--- a/pitivi/medialibrary.py
+++ b/pitivi/medialibrary.py
@@ -137,6 +137,7 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
         builder.connect_signals(self)
         self._welcome_infobar = builder.get_object("welcome_infobar")
         self._import_warning_infobar = builder.get_object("warning_infobar")
+        self._import_warning_infobar.hide()
         self._warning_label = builder.get_object("warning_label")
         self._view_error_button = builder.get_object("view_error_button")
         toolbar = builder.get_object("medialibrary_toolbar")
@@ -252,9 +253,10 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
         # Connect to project.  We must remove and reset the callbacks when
         # changing project.
         self.project_signals = SignalGroup()
-        self.app.connect("new-project-created", self._newProjectCreatedCb)
-        self.app.connect("new-project-loaded", self._newProjectLoadedCb)
-        self.app.connect("new-project-failed", self._newProjectFailedCb)
+        project_manager = self.app.project_manager
+        project_manager.connect("new-project-created", self._newProjectCreatedCb)
+        project_manager.connect("new-project-loaded", self._newProjectLoadedCb)
+        project_manager.connect("new-project-failed", self._newProjectFailedCb)
 
         # Drag and Drop
         self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION,
@@ -499,8 +501,8 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
         # The clip iter has a +1 offset in the progressbar label (to refer to
         # the actual # of the clip we're processing), but there is no offset
         # in the progressbar itself (to reflect the process being incomplete).
-        current_clip_iter = self.app.current_project.nb_imported_files
-        total_clips = self.app.current_project.nb_remaining_file_to_import + current_clip_iter
+        current_clip_iter = self.app.project_manager.current_project.nb_imported_files
+        total_clips = self.app.project_manager.current_project.nb_remaining_file_to_import + 
current_clip_iter
 
         progressbar_text = _("Importing clip %(current_clip)d of %(total)d" %
             {"current_clip": current_clip_iter + 1,
@@ -727,7 +729,7 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
             self.app.settings.closeImportDialog = \
                 dialogbox.props.extra_widget.get_active()
             filenames = dialogbox.get_uris()
-            self.app.current_project.addUris(filenames)
+            self.app.project_manager.current_project.addUris(filenames)
             if self.app.settings.closeImportDialog:
                 dialogbox.destroy()
                 self._importDialog = None
@@ -757,12 +759,12 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
         self.app.action_log.begin("remove clip from source list")
         for row in rows:
             asset = model[row.get_path()][COL_ASSET]
-            self.app.current_project.remove_asset(asset)
+            self.app.project_manager.current_project.remove_asset(asset)
         self.app.action_log.commit()
 
     def _sourceIsUsed(self, asset):
         """Check if a given URI is present in the timeline"""
-        layers = self.app.current_project.timeline.get_layers()
+        layers = self.app.project_manager.current_project.timeline.get_layers()
         for layer in layers:
             for clip in layer.get_clips():
                 if clip.get_asset() == asset:
@@ -773,7 +775,7 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
         """
         Select, in the media library, unused sources in the project.
         """
-        assets = self.app.current_project.list_assets(GES.UriClip)
+        assets = self.app.project_manager.current_project.list_assets(GES.UriClip)
         unused_sources_uris = []
 
         model = self.treeview.get_model()
@@ -814,7 +816,7 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
         # Only use the first item.
         path = paths[0]
         asset = self.storemodel[path][COL_ASSET]
-        dialog = ClipMediaPropsDialog(self.app.current_project, asset)
+        dialog = ClipMediaPropsDialog(self.app.project_manager.current_project, asset)
         dialog.run()
 
     def _warningInfoBarDismissedCb(self, unused_button):
@@ -998,7 +1000,7 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
             self._welcome_infobar.show_all()
             self._connectToProject(project)
 
-    def _newProjectLoadedCb(self, unused_pitivi, project):
+    def _newProjectLoadedCb(self, unused_app, project, unused_fully_ready):
         if not self._project is project:
             self._project = project
             self.storemodel.clear()
@@ -1013,8 +1015,8 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
         self._project = None
 
     def _addUris(self, uris):
-        if self.app.current_project:
-            self.app.current_project.addUris(uris)
+        if self.app.project_manager.current_project:
+            self.app.project_manager.current_project.addUris(uris)
         else:
             self.warning("Adding uris to project, but the project has changed in the meantime")
         return False
@@ -1049,7 +1051,7 @@ class MediaLibraryWidget(Gtk.VBox, Loggable):
             # Recursively import from folders that were dragged into the library
             self.app.threads.addThread(PathWalker, directories, self._addUris)
         if filenames:
-            self.app.current_project.addUris(filenames)
+            self.app.project_manager.current_project.addUris(filenames)
 
     #used with TreeView and IconView
     def _dndDragDataGetCb(self, unused_view, unused_context, data, unused_info, unused_timestamp):
diff --git a/pitivi/project.py b/pitivi/project.py
index 7ebfe8c..a5b6461 100644
--- a/pitivi/project.py
+++ b/pitivi/project.py
@@ -106,6 +106,12 @@ class ProjectLogObserver(UndoableAction):
 
 
 class ProjectManager(Signallable, Loggable):
+    """
+    @type app: L{Pitivi}
+    @type current_project: L{Project}
+    @param disable_save: Whether saving is disabled to enforce using save-as.
+    """
+
     __signals__ = {
         "new-project-loading": ["uri"],
         "new-project-created": ["project"],
@@ -119,12 +125,14 @@ class ProjectManager(Signallable, Loggable):
         "reverting-to-saved": ["project"],
     }
 
-    def __init__(self, app_instance):
+    _instance = None
+
+    def __init__(self, app):
         Signallable.__init__(self)
         Loggable.__init__(self)
-        self.app = app_instance
+        self.app = app
         self.current_project = None
-        self.disable_save = False  # Enforce "Save as" for backup and xptv files
+        self.disable_save = False
         self._backup_lock = 0
 
     def loadProject(self, uri):
@@ -176,7 +184,6 @@ class ProjectManager(Signallable, Loggable):
                       _('This might be due to a bug or an unsupported project file format. '
                       'If you were trying to add a media file to your project, '
                       'use the "Import" button instead.'))
-            # Reset projectManager and disconnect all the signals:
             self.newBlankProject(ignore_unsaved_changes=True)
             return False
 
@@ -426,6 +433,7 @@ class ProjectManager(Signallable, Loggable):
         self.emit("new-project-created", project)
 
         project.connect("project-changed", self._projectChangedCb)
+        project.setModificationState(False)
         self.emit("new-project-loaded", self.current_project, emission)
         self.time_loaded = time()
 
@@ -499,7 +507,8 @@ class ProjectManager(Signallable, Loggable):
 
 
 class Project(Loggable, GES.Project):
-    """The base class for Pitivi projects
+    """
+    The base class for Pitivi projects
 
     @ivar name: The name of the project
     @type name: C{str}
diff --git a/pitivi/render.py b/pitivi/render.py
index dd19f69..4b76b39 100644
--- a/pitivi/render.py
+++ b/pitivi/render.py
@@ -726,7 +726,7 @@ class RenderDialog(Loggable):
             return None
 
         current_filesize = os.stat(path_from_uri(self.outfile)).st_size
-        length = self.app.current_project.timeline.props.duration
+        length = self.app.project_manager.current_project.timeline.props.duration
         estimated_size = float(current_filesize * float(length) / self.current_position)
         # Now let's make it human-readable (instead of octets).
         # If it's in the giga range (10⁹) instead of mega (10⁶), use 2 decimals
@@ -842,7 +842,7 @@ class RenderDialog(Loggable):
         else:
             self._time_spent_paused += time.time() - self._last_timestamp_when_pausing
             self.debug("Resuming render after %d seconds in pause", self._time_spent_paused)
-        self.app.current_project.pipeline.togglePlayback()
+        self.app.project_manager.current_project.pipeline.togglePlayback()
 
     def _destroyProgressWindow(self):
         """ Handle the completion or the cancellation of the render process. """
@@ -855,7 +855,7 @@ class RenderDialog(Loggable):
             obj.disconnect(id)
         self._gstSigId = {}
         try:
-            self.app.current_project.pipeline.disconnect_by_func(self._updatePositionCb)
+            self.app.project_manager.current_project.pipeline.disconnect_by_func(self._updatePositionCb)
         except TypeError:
             # The render was successful, so this was already disconnected
             pass
@@ -914,7 +914,7 @@ class RenderDialog(Loggable):
         bus = self._pipeline.get_bus()
         bus.add_signal_watch()
         self._gstSigId[bus] = bus.connect('message', self._busMessageCb)
-        self.app.current_project.pipeline.connect("position", self._updatePositionCb)
+        self.app.project_manager.current_project.pipeline.connect("position", self._updatePositionCb)
         # Force writing the config now, or the path will be reset
         # if the user opens the rendering dialog again
         self.app.settings.lastExportFolder = self.filebutton.get_current_folder()
@@ -937,7 +937,7 @@ class RenderDialog(Loggable):
             return True  # Do nothing until we resume rendering
         elif self._is_rendering:
             timediff = time.time() - self._time_started - self._time_spent_paused
-            length = self.app.current_project.timeline.props.duration
+            length = self.app.project_manager.current_project.timeline.props.duration
             totaltime = (timediff * float(length) / float(self.current_position)) - timediff
             time_estimate = beautify_ETA(int(totaltime * Gst.SECOND))
             if time_estimate:
@@ -1006,7 +1006,7 @@ class RenderDialog(Loggable):
         if not self.progress or not position:
             return
 
-        length = self.app.current_project.timeline.props.duration
+        length = self.app.project_manager.current_project.timeline.props.duration
         fraction = float(min(position, length)) / float(length)
         self.progress.updatePosition(fraction)
 
diff --git a/pitivi/timeline/timeline.py b/pitivi/timeline/timeline.py
index 1d45786..b7d8b31 100644
--- a/pitivi/timeline/timeline.py
+++ b/pitivi/timeline/timeline.py
@@ -603,7 +603,7 @@ class TimelineStage(Clutter.ScrollActor, Zoomable, Loggable):
 
     def _trackAddedCb(self, unused_timeline, track):
         self._connectTrack(track)
-        self._container.app.current_project.update_restriction_caps()
+        self._container.app.project_manager.current_project.update_restriction_caps()
 
     def _trackRemovedCb(self, unused_timeline, track):
         self._disconnectTrack(track)
diff --git a/pitivi/transitions.py b/pitivi/transitions.py
index 1d7cecc..8c7f9d6 100644
--- a/pitivi/transitions.py
+++ b/pitivi/transitions.py
@@ -161,7 +161,7 @@ class TransitionsListWidget(Signallable, Gtk.VBox, Loggable):
             self.props_widgets.set_sensitive(True)
 
         self.element.get_parent().set_asset(transition_asset)
-        self.app.current_project.seeker.flush(True)
+        self.app.project_manager.current_project.seeker.flush(True)
 
         return True
 
@@ -169,13 +169,13 @@ class TransitionsListWidget(Signallable, Gtk.VBox, Loggable):
         value = range_changed.get_value()
         self.debug("User changed the border property to %s", value)
         self.element.set_border(int(value))
-        self.app.current_project.seeker.flush(True)
+        self.app.project_manager.current_project.seeker.flush(True)
 
     def _invertCheckboxCb(self, widget):
         value = widget.get_active()
         self.debug("User changed the invert property to %s", value)
         self.element.set_inverted(value)
-        self.app.current_project.seeker.flush()
+        self.app.project_manager.current_project.seeker.flush()
 
     def _borderTypeChangedCb(self, widget=None):
         """
diff --git a/pitivi/viewer.py b/pitivi/viewer.py
index c994dc2..cf50299 100644
--- a/pitivi/viewer.py
+++ b/pitivi/viewer.py
@@ -309,7 +309,7 @@ class ViewerContainer(Gtk.VBox, Loggable):
             self.target.renderbox()
 
     def _playButtonCb(self, unused_button, unused_playing):
-        self.app.current_project.pipeline.togglePlayback()
+        self.app.project_manager.current_project.pipeline.togglePlayback()
         self.app.gui.focusTimeline()
 
     def _goToStartCb(self, unused_button):
@@ -327,7 +327,7 @@ class ViewerContainer(Gtk.VBox, Loggable):
         self.app.gui.focusTimeline()
 
     def _goToEndCb(self, unused_button):
-        end = self.app.current_project.pipeline.getDuration()
+        end = self.app.project_manager.current_project.pipeline.getDuration()
         self.seeker.seek(end)
         self.app.gui.focusTimeline()
 
@@ -412,7 +412,7 @@ class ViewerContainer(Gtk.VBox, Loggable):
 
         clip_uri = tl_obj.props.uri
         cur_time = time()
-        if self.pipeline == self.app.current_project.pipeline:
+        if self.pipeline == self.app.project_manager.current_project.pipeline:
             self.debug("Creating temporary pipeline for clip %s, position %s",
                 clip_uri, format_ns(position))
             self._oldTimelinePos = self.pipeline.getPosition()
@@ -428,11 +428,11 @@ class ViewerContainer(Gtk.VBox, Loggable):
         """
         After trimming a clip, reset the project pipeline into the viewer.
         """
-        if self.pipeline is not self.app.current_project.pipeline:
+        if self.pipeline is not self.app.project_manager.current_project.pipeline:
             self.pipeline.setState(Gst.State.NULL)
             # Using pipeline.getPosition() here does not work because for some
             # reason it's a bit off, that's why we need self._oldTimelinePos.
-            self.setPipeline(self.app.current_project.pipeline, self._oldTimelinePos)
+            self.setPipeline(self.app.project_manager.current_project.pipeline, self._oldTimelinePos)
             self.debug("Back to the project's pipeline")
 
     def _pipelineStateChangedCb(self, unused_pipeline, state):
diff --git a/tests/test_application.py b/tests/test_application.py
index 8ea2509..064c040 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -35,32 +35,39 @@ class TestPitivi(TestCase):
 
     def testBasic(self):
         app = application.Pitivi()
+        app.emit("startup")
         self.assertTrue(app.shutdown())
 
     def testVersionInfo(self):
         app = application.Pitivi()
+        app.emit("startup")
         self.assertTrue(app.isLatest())
 
         app = application.Pitivi()
+        app.emit("startup")
         app._versionInfoReceivedCb(MockGioFile(), "invalid", None)
         self.assertTrue(app.isLatest())
 
         app = application.Pitivi()
+        app.emit("startup")
         app._versionInfoReceivedCb(MockGioFile(), "%s=CURRENT" % configure.VERSION, None)
         self.assertTrue(app.isLatest())
         self.assertEqual(configure.VERSION, app.getLatest())
 
         app = application.Pitivi()
+        app.emit("startup")
         app._versionInfoReceivedCb(MockGioFile(), "%s=current\n0=supported" % configure.VERSION, None)
         self.assertTrue(app.isLatest())
         self.assertEqual(configure.VERSION, app.getLatest())
 
         app = application.Pitivi()
+        app.emit("startup")
         app._versionInfoReceivedCb(MockGioFile(), "999.0=CURRENT", None)
         self.assertFalse(app.isLatest())
         self.assertEqual("999.0", app.getLatest())
 
         app = application.Pitivi()
+        app.emit("startup")
         app._versionInfoReceivedCb(MockGioFile(), "999.0=CURRENT\n%s=SUPPORTED" % configure.VERSION, None)
         self.assertFalse(app.isLatest())
         self.assertEqual("999.0", app.getLatest())


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