~timo-jyrinki/ubuntu/trusty/pitivi/backport_utopic_fixes

« back to all changes in this revision

Viewing changes to pitivi/application.py

  • Committer: Package Import Robot
  • Author(s): Sebastian Dröge
  • Date: 2014-04-05 15:28:16 UTC
  • mfrom: (6.1.13 sid)
  • Revision ID: package-import@ubuntu.com-20140405152816-6lijoax4cngiz5j5
Tags: 0.93-3
* debian/control:
  + Depend on python-gi (>= 3.10), older versions do not work
    with pitivi (Closes: #732813).
  + Add missing dependency on gir1.2-clutter-gst-2.0 (Closes: #743692).
  + Add suggests on gir1.2-notify-0.7 and gir1.2-gnomedesktop-3.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# PiTiVi , Non-linear video editor
 
1
# Pitivi video editor
2
2
#
3
3
#       pitivi/pitivi.py
4
4
#
23
23
 
24
24
"""
25
25
Main application
 
26
 
 
27
Hierarchy of the whole thing:
 
28
 
 
29
Pitivi
 
30
    InteractivePitivi
 
31
    GuiPitivi
 
32
        ProjectCreatorGuiPitivi
 
33
        ProjectLoaderGuiPitivi
 
34
        StartupWizardGuiPitivi
26
35
"""
27
 
import gobject
28
 
import gtk
29
 
from optparse import OptionParser
30
36
import os
31
37
import sys
32
 
import urllib
33
38
 
34
 
from pitivi.pitivigstutils import patch_gst_python
35
 
patch_gst_python()
 
39
from gi.repository import GES
 
40
from gi.repository import Gio
 
41
from gi.repository import GLib
 
42
from gi.repository import Gtk
36
43
 
37
44
from gettext import gettext as _
38
 
 
39
 
import pitivi.instance as instance
40
 
 
41
 
from pitivi.check import initial_checks
 
45
from optparse import OptionParser
 
46
 
42
47
from pitivi.effects import EffectsHandler
43
 
from pitivi.configure import APPNAME
 
48
from pitivi.configure import VERSION, RELEASES_URL
44
49
from pitivi.settings import GlobalSettings
45
 
from pitivi.threads import ThreadMaster
46
 
from pitivi.signalinterface import Signallable
47
 
from pitivi.log.loggable import Loggable
48
 
from pitivi.log import log
49
 
from pitivi.ui.mainwindow import PitiviMainWindow
50
 
from pitivi.projectmanager import ProjectManager, ProjectLogObserver
51
 
from pitivi.undo import UndoableActionLog, DebugActionLogObserver
52
 
from pitivi.timeline.timeline_undo import TimelineLogObserver
53
 
from pitivi.sourcelist_undo import SourceListLogObserver
54
 
from pitivi.ui.viewer import PitiviViewer
55
 
from pitivi.actioner import Renderer, Previewer
56
 
from pitivi.ui.startupwizard import StartUpWizard
 
50
from pitivi.utils.threads import ThreadMaster
 
51
from pitivi.mainwindow import PitiviMainWindow
 
52
from pitivi.project import ProjectManager, ProjectLogObserver
 
53
from pitivi.undo.undo import UndoableActionLog, DebugActionLogObserver
 
54
from pitivi.dialogs.startupwizard import StartUpWizard
57
55
 
58
 
# FIXME : Speedup loading time
59
 
# Currently we load everything in one go
60
 
# It would be better if a minimalistic UI could start up ASAP, without loading
61
 
# anything gst-related or that could slow down startup.
62
 
# AND THEN load up the required parts.
63
 
# This will result in a much better end-user experience
 
56
from pitivi.utils.misc import quote_uri
 
57
from pitivi.utils.signal import Signallable
 
58
from pitivi.utils.system import getSystem
 
59
from pitivi.utils.loggable import Loggable
 
60
import pitivi.utils.loggable as log
 
61
#FIXME GES port disabled it
 
62
#from pitivi.undo.timeline import TimelineLogObserver
64
63
 
65
64
 
66
65
class Pitivi(Loggable, Signallable):
73
72
     - C{new-project-loading} : Pitivi is attempting to load a new project.
74
73
     - C{new-project-loaded} : A new L{Project} has been loaded, and the UI should refresh it's view.
75
74
     - C{new-project-failed} : A new L{Project} failed to load.
76
 
     - C{closing-project} :  pitivi would like to close a project. handlers should return false
77
 
     if they do not want this project to close. by default, assumes
78
 
     true. This signal should only be used by classes that might want to abort
79
 
     the closing of a project.
80
75
     - C{project-closed} : The project is closed, it will be freed when the callback returns.
81
76
     Classes should connect to this instance when they want to know that
82
77
     data related to that project is no longer going to be used.
94
89
        "new-project-created": ["project"],
95
90
        "new-project-loaded": ["project"],
96
91
        "new-project-failed": ["uri", "exception"],
97
 
        "closing-project": ["project"],
98
92
        "project-closed": ["project"],
99
93
        "missing-uri": ["formatter", "uri"],
 
94
        "version-info-received": ["versions"],
100
95
        "shutdown": None}
101
96
 
102
97
    def __init__(self):
103
 
        """
104
 
        initialize pitivi with the command line arguments
105
 
        """
106
98
        Loggable.__init__(self)
107
99
 
108
 
        # init logging as early as possible so we can log startup code
109
 
        enable_color = os.environ.get('PITIVI_DEBUG_NO_COLOR', '0') in ('', '0')
110
 
        log.init('PITIVI_DEBUG', enable_color)
 
100
        # Init logging as early as possible so we can log startup code
 
101
        enable_color = not os.environ.get('PITIVI_DEBUG_NO_COLOR', '0') in ('', '1')
 
102
        # Let's show a human-readable pitivi debug output by default, and only
 
103
        # show a crazy unreadable mess when surrounded by gst debug statements.
 
104
        enable_crack_output = "GST_DEBUG" in os.environ
 
105
        log.init('PITIVI_DEBUG', enable_color, enable_crack_output)
111
106
 
112
107
        self.info('starting up')
113
108
 
114
 
        # store ourself in the instance global
115
 
        if instance.PiTiVi:
116
 
            raise RuntimeWarning(
117
 
                _("There is already a %s instance, please inform the developers by filing a bug at http://bugzilla.gnome.org/enter_bug.cgi?product=pitivi")
118
 
                % APPNAME)
119
 
        instance.PiTiVi = self
120
 
 
121
 
        self.current = None
122
 
 
123
 
        # get settings
124
109
        self.settings = GlobalSettings()
125
110
        self.threads = ThreadMaster()
126
 
        #self.screencast = False
127
 
 
128
111
        self.effects = EffectsHandler()
 
112
        self.system = getSystem()
129
113
 
130
 
        self.projectManager = ProjectManager(self.effects)
 
114
        self.current_project = None
 
115
        self.projectManager = ProjectManager(self)
131
116
        self._connectToProjectManager(self.projectManager)
132
117
 
133
118
        self.action_log = UndoableActionLog()
134
119
        self.debug_action_log_observer = DebugActionLogObserver()
135
120
        self.debug_action_log_observer.startObserving(self.action_log)
136
 
        self.timelineLogObserver = TimelineLogObserver(self.action_log)
 
121
        # TODO reimplement the observing after GES port
 
122
        #self.timelineLogObserver = TimelineLogObserver(self.action_log)
137
123
        self.projectLogObserver = ProjectLogObserver(self.action_log)
138
 
        self.sourcelist_log_observer = SourceListLogObserver(self.action_log)
 
124
 
 
125
        self._version_information = {}
 
126
        self._checkVersion()
139
127
 
140
128
    def shutdown(self):
141
129
        """
142
 
        Close PiTiVi.
 
130
        Close Pitivi.
143
131
 
144
 
        @return: C{True} if PiTiVi was successfully closed, else C{False}.
 
132
        @return: C{True} if Pitivi was successfully closed, else C{False}.
145
133
        @rtype: C{bool}
146
134
        """
147
135
        self.debug("shutting down")
148
136
        # we refuse to close if we're running a user interface and the user
149
137
        # doesn't want us to close the current project.
150
 
        if self.current and not self.projectManager.closeRunningProject():
 
138
        if self.current_project and not self.projectManager.closeRunningProject():
151
139
            self.warning("Not closing since running project doesn't want to close")
152
140
            return False
153
141
        self.threads.stopAllThreads()
154
142
        self.settings.storeSettings()
155
 
        self.current = None
156
 
        instance.PiTiVi = None
 
143
        self.current_project = None
157
144
        self.emit("shutdown")
158
145
        return True
159
146
 
160
147
    def _connectToProjectManager(self, projectManager):
161
 
        projectManager.connect("new-project-loading",
162
 
                self._projectManagerNewProjectLoading)
163
 
        projectManager.connect("new-project-created",
164
 
                self._projectManagerNewProjectCreated)
165
 
        projectManager.connect("new-project-loaded",
166
 
                self._projectManagerNewProjectLoaded)
167
 
        projectManager.connect("new-project-failed",
168
 
                self._projectManagerNewProjectFailed)
169
 
        projectManager.connect("closing-project",
170
 
                self._projectManagerClosingProject)
171
 
        projectManager.connect("project-closed",
172
 
                self._projectManagerProjectClosed)
 
148
        pm = projectManager
 
149
        pm.connect("new-project-loading", self._projectManagerNewProjectLoading)
 
150
        pm.connect("new-project-created", self._projectManagerNewProjectCreated)
 
151
        pm.connect("new-project-loaded", self._projectManagerNewProjectLoaded)
 
152
        pm.connect("new-project-failed", self._projectManagerNewProjectFailed)
 
153
        pm.connect("project-closed", self._projectManagerProjectClosed)
173
154
 
174
 
    def _projectManagerNewProjectLoading(self, projectManager, uri):
 
155
    def _projectManagerNewProjectLoading(self, unused_project_manager, uri):
175
156
        self.emit("new-project-loading", uri)
176
157
 
177
 
    def _projectManagerNewProjectCreated(self, projectManager, project):
178
 
        self.current = project
 
158
    def _projectManagerNewProjectCreated(self, unused_project_manager, project):
 
159
        self.current_project = project
179
160
        self.emit("new-project-created", project)
180
161
 
181
 
    def _newProjectLoaded(self, project):
 
162
    def _newProjectLoaded(self, unused_project):
182
163
        pass
183
164
 
184
 
    def _projectManagerNewProjectLoaded(self, projectManager, project):
185
 
        self.current = project
 
165
    def _projectManagerNewProjectLoaded(self, unused_project_manager, project, unused_fully_loaded):
 
166
        self.current_project = project
186
167
        self.action_log.clean()
187
 
        self.timelineLogObserver.startObserving(project.timeline)
 
168
        #self.timelineLogObserver.startObserving(project.timeline)
188
169
        self.projectLogObserver.startObserving(project)
189
 
        self.sourcelist_log_observer.startObserving(project.sources)
190
170
        self._newProjectLoaded(project)
191
171
        self.emit("new-project-loaded", project)
192
172
 
193
 
    def _projectManagerNewProjectFailed(self, projectManager, uri, exception):
 
173
    def _projectManagerNewProjectFailed(self, unused_project_manager, uri, exception):
194
174
        self.emit("new-project-failed", uri, exception)
195
175
 
196
 
    def _projectManagerClosingProject(self, projectManager, project):
197
 
        return self.emit("closing-project", project)
198
 
 
199
 
    def _projectManagerProjectClosed(self, projectManager, project):
200
 
        self.timelineLogObserver.stopObserving(project.timeline)
 
176
    def _projectManagerProjectClosed(self, unused_project_manager, project):
 
177
        #self.timelineLogObserver.stopObserving(project.timeline)
201
178
        self.projectLogObserver.stopObserving(project)
202
 
        self.current = None
 
179
        self.current_project = None
203
180
        self.emit("project-closed", project)
204
181
 
 
182
    def _checkVersion(self):
 
183
        # Check online for release versions information
 
184
        giofile = Gio.File.new_for_uri(RELEASES_URL)
 
185
        self.info("Requesting version information")
 
186
        giofile.load_contents_async(None, self._versionInfoReceivedCb, None)
 
187
 
 
188
    def _versionInfoReceivedCb(self, giofile, result, user_data):
 
189
        try:
 
190
            raw = giofile.load_contents_finish(result)[1]
 
191
            raw = raw.split("\n")
 
192
            # Split line at '=' if the line is not empty or a comment line
 
193
            data = [element.split("=") for element in raw
 
194
                    if element and not element.startswith("#")]
 
195
 
 
196
            # search newest version and status
 
197
            status = "UNSUPPORTED"
 
198
            current_version = None
 
199
            for version, version_status in data:
 
200
                if VERSION == version:
 
201
                    status = version_status
 
202
                if version_status.upper() == "CURRENT":
 
203
                    # This is the latest.
 
204
                    current_version = version
 
205
 
 
206
            self.info("Latest software version is %s", current_version)
 
207
            # Python is magical... comparing version *strings* always works,
 
208
            # even with different major.minor.nano version number schemes!
 
209
            if VERSION > current_version:
 
210
                status = "CURRENT"
 
211
                self.info("Running version %s, which is newer than the latest known version. Considering it as the latest current version.", VERSION)
 
212
            elif status is "UNSUPPORTED":
 
213
                self.warning("Using an outdated version of Pitivi (%s)", VERSION)
 
214
 
 
215
            self._version_information["current"] = current_version
 
216
            self._version_information["status"] = status
 
217
            self.emit("version-info-received", self._version_information)
 
218
        except Exception, e:
 
219
            self.warning("Version info could not be read: %s", e)
 
220
 
 
221
    def isLatest(self):
 
222
        """
 
223
        Whether the app's version is the latest as far as we know.
 
224
        """
 
225
        status = self._version_information.get("status")
 
226
        return status is None or status.upper() == "CURRENT"
 
227
 
 
228
    def getLatest(self):
 
229
        """
 
230
        Get the latest version of the app or None.
 
231
        """
 
232
        return self._version_information.get("current")
 
233
 
205
234
 
206
235
class InteractivePitivi(Pitivi):
207
236
    """
208
 
    Base class to launch interactive PiTiVi
 
237
    Base class to launch interactive Pitivi
209
238
    """
210
239
 
211
240
    def __init__(self, debug=False):
212
241
        Pitivi.__init__(self)
213
 
        self.mainloop = gobject.MainLoop()
214
 
        self.actioner = None
 
242
        self.mainloop = GLib.MainLoop()
215
243
        self.gui = None
216
 
 
217
 
        # Check the dependencies.
218
 
        missing_deps = initial_checks()
219
 
        if missing_deps:
220
 
            message, detail = missing_deps
221
 
            self._showStartupError(message, detail)
222
 
            sys.exit(2)
223
 
 
224
244
        if debug:
225
245
            sys.excepthook = self._excepthook
226
246
 
227
 
    def _showStartupError(self, message, detail):
228
 
        self.error("%s %s" % (message, detail))
229
 
 
230
 
    def _excepthook(self, exc_type, value, tback):
 
247
    def _excepthook(self, unused_exc_type, unused_value, tback):
231
248
        import traceback
232
249
        import pdb
233
250
        traceback.print_tb(tback)
234
251
        pdb.post_mortem(tback)
235
252
 
236
 
    def _setActioner(self, actioner):
237
 
        self.actioner = actioner
238
 
        if self.actioner:
239
 
            self.actioner.connect("eos", self._eosCb)
240
 
            # On error, all we need to do is shutdown which
241
 
            # is the same as we do for EOS
242
 
            self.actioner.connect("error", self._eosCb)
243
 
            # Configure the actioner and start acting!
244
 
            self.actioner.startAction()
245
 
 
246
 
    def _eosCb(self, unused_obj):
247
 
        raise NotImplementedError()
248
 
 
249
 
    def _loadProject(self, project_filename):
250
 
        project = "file://%s" % os.path.abspath(project_filename)
251
 
        self.projectManager.loadProject(project)
252
 
 
253
253
    def run(self):
254
254
        """Runs the main loop."""
255
255
        self.mainloop.run()
257
257
 
258
258
class GuiPitivi(InteractivePitivi):
259
259
    """
260
 
    Base class to launch PiTiVi with UI
 
260
    Base class to launch a Pitivi instance with a graphical user interface
 
261
 
 
262
    This is called when we start the UI with a project passed as a parameter.
 
263
    It is also called by StartupWizardGuiPitivi.
261
264
    """
262
265
 
263
266
    def __init__(self, debug=False):
265
268
        self._showGui()
266
269
 
267
270
    def _showStartupError(self, message, detail):
268
 
        dialog = gtk.MessageDialog(type=gtk.MESSAGE_ERROR,
269
 
                                   buttons=gtk.BUTTONS_OK)
270
 
        dialog.set_icon_name("pitivi")
 
271
        dialog = Gtk.MessageDialog(message_type=Gtk.MessageType.ERROR,
 
272
                                   buttons=Gtk.ButtonsType.OK)
271
273
        dialog.set_markup("<b>" + message + "</b>")
272
274
        dialog.format_secondary_text(detail)
273
275
        dialog.run()
274
276
 
275
 
    def _eosCb(self, unused_obj):
276
 
        self.shutdown()
277
 
 
278
277
    def _createGui(self):
279
 
        """Returns a gtk.Widget which represents the UI."""
280
 
        raise NotImplementedError()
 
278
        """Returns a Gtk.Widget which represents the UI."""
 
279
        return PitiviMainWindow(self)
281
280
 
282
281
    def _showGui(self):
283
282
        """Creates and shows the UI."""
292
291
        return False
293
292
 
294
293
 
295
 
class FullGuiPitivi(GuiPitivi):
296
 
    """
297
 
    Creates an instance of PiTiVi with the UI
298
 
 
299
 
    This is called when we start the UI with a project passed as a parameter,
300
 
    but not when we start with the welcome dialog.
301
 
    """
302
 
 
303
 
    def _createGui(self, **kargs):
304
 
        return PitiviMainWindow(self, **kargs)
305
 
 
306
 
 
307
 
class ProjectCreatorGuiPitivi(FullGuiPitivi):
308
 
    """
309
 
    Creates an instance of PiTiVi with the UI and loading a list
 
294
class ProjectCreatorGuiPitivi(GuiPitivi):
 
295
    """
 
296
    Creates an instance of Pitivi with the UI and loading a list
310
297
    of clips, adding them to the timeline or not
311
298
    """
312
299
 
313
300
    def __init__(self, media_filenames, add_to_timeline=False, debug=False):
314
 
        FullGuiPitivi.__init__(self, debug)
 
301
        GuiPitivi.__init__(self, debug)
315
302
        # load the passed filenames, optionally adding them to the timeline
316
303
        # (useful during development)
317
 
        self.projectManager.newBlankProject()
318
 
        uris = ["file://" + urllib.quote(os.path.abspath(media_filename))
 
304
        self.projectManager.newBlankProject(emission=False)
 
305
        uris = [quote_uri(os.path.abspath(media_filename))
319
306
                for media_filename in media_filenames]
320
 
        self.current.sources.connect("source-added",
321
 
                self._sourceAddedCb, uris, add_to_timeline)
322
 
        self.current.sources.connect("discovery-error",
323
 
                self._discoveryErrorCb, uris)
324
 
        self.current.sources.addUris(uris)
 
307
        lib = self.current_project.medialibrary
 
308
        lib.connect("source-added", self._sourceAddedCb, uris, add_to_timeline)
 
309
        lib.connect("discovery-error", self._discoveryErrorCb, uris)
 
310
        lib.addUris(uris)
325
311
 
326
 
    def _sourceAddedCb(self, sourcelist, factory,
327
 
            startup_uris, add_to_timeline):
328
 
        if self._maybePopStartupUri(startup_uris, factory.uri) \
 
312
    def _sourceAddedCb(self, unused_media_library, info, startup_uris, add_to_timeline):
 
313
        if self._maybePopStartupUri(startup_uris, info.get_uri()) \
329
314
                and add_to_timeline:
330
315
            self.action_log.begin("add clip")
331
 
            self.current.timeline.addSourceFactory(factory)
 
316
            src = GES.UriClip(uri=info.get_uri())
 
317
            src.set_property("priority", 1)
 
318
            self.current_project.timeline.get_layers()[0].add_clip(src)
332
319
            self.action_log.commit()
333
320
 
334
 
    def _discoveryErrorCb(self, sourcelist, uri, error, debug, startup_uris):
 
321
    def _discoveryErrorCb(self, unused_media_library, uri, unused_error, unused_debug, startup_uris):
335
322
        self._maybePopStartupUri(startup_uris, uri)
336
323
 
337
324
    def _maybePopStartupUri(self, startup_uris, uri):
344
331
            return False
345
332
 
346
333
        if not startup_uris:
347
 
            self.current.sources.disconnect_by_function(self._sourceAddedCb)
348
 
            self.current.sources.disconnect_by_function(self._discoveryErrorCb)
 
334
            self.current_project.medialibrary.disconnect_by_function(self._sourceAddedCb)
 
335
            self.current_project.medialibrary.disconnect_by_function(self._discoveryErrorCb)
349
336
 
350
337
        return True
351
338
 
352
339
 
353
 
class ProjectLoaderGuiPitivi(FullGuiPitivi):
 
340
class ProjectLoaderGuiPitivi(GuiPitivi):
354
341
    """
355
342
    Creates an instance of the UI and loads @project_filename
356
343
    """
357
344
 
358
345
    def __init__(self, project_filename, debug=False):
359
 
        FullGuiPitivi.__init__(self, debug)
360
 
        self._loadProject(project_filename)
361
 
 
362
 
 
363
 
class StartupWizardGuiPitivi(FullGuiPitivi):
 
346
        GuiPitivi.__init__(self, debug)
 
347
        if not os.path.exists(project_filename):
 
348
            self.error("Project file does not exist: %s" % project_filename)
 
349
            sys.exit(1)
 
350
        self.projectManager.loadProject(quote_uri(os.path.abspath(project_filename)))
 
351
 
 
352
 
 
353
class StartupWizardGuiPitivi(GuiPitivi):
364
354
    """
365
 
    Creates an instance of the PiTiVi UI with the welcome dialog
 
355
    Creates an instance of the Pitivi UI with the welcome dialog
366
356
 
367
357
    This is not called when a project is passed as a parameter.
368
358
    """
369
359
 
370
360
    def __init__(self, debug=False):
371
 
        FullGuiPitivi.__init__(self, debug)
 
361
        GuiPitivi.__init__(self, debug)
 
362
        self.projectManager.newBlankProject(emission=False)
372
363
 
373
364
    def _createGui(self):
 
365
        return PitiviMainWindow(self)
 
366
 
 
367
    def _showGui(self):
 
368
        GuiPitivi._showGui(self)
374
369
        self.wizard = StartUpWizard(self)
375
 
        # Prevent the main window to go fullscreen because at least
376
 
        # the Metacity window manager will refuse to bring
377
 
        # the startup wizard window in front of the main window.
378
 
        return FullGuiPitivi._createGui(self, allow_full_screen=False)
379
 
 
380
 
    def _showGui(self):
381
 
        FullGuiPitivi._showGui(self)
382
370
        self.wizard.show()
383
371
 
384
372
 
385
 
class PreviewGuiPitivi(GuiPitivi):
386
 
    """
387
 
    Creates an instance of PiTiVi which plays the @project_filename
388
 
    in a basic UI.
389
 
    """
390
 
 
391
 
    def __init__(self, project_filename, debug=False):
392
 
        GuiPitivi.__init__(self, debug)
393
 
        self._loadProject(project_filename)
394
 
 
395
 
    def _createGui(self):
396
 
        self.viewer = PitiviViewer(self)
397
 
        window = gtk.Window()
398
 
        window.connect("delete-event", self._deleteCb)
399
 
        window.add(self.viewer)
400
 
        return window
401
 
 
402
 
    def _deleteCb(self, unused_widget, unused_data):
403
 
        self.shutdown()
404
 
 
405
 
    def _eosCb(self, unused_obj):
406
 
        self.viewer.seek(0)
407
 
 
408
 
    def _newProjectLoaded(self, project):
409
 
        # create previewer and set ui
410
 
        previewer = Previewer(project, ui=self.viewer)
411
 
        self._setActioner(previewer)
412
 
        # hack to make the gtk.HScale seek slider UI behave properly
413
 
        self.viewer._durationChangedCb(None, project.timeline.duration)
414
 
 
415
 
 
416
 
class RenderingNoGuiPitivi(InteractivePitivi):
417
 
    """
418
 
    Creates an instance of PiTiVi with no UI which aims
419
 
    at rendering the @project_filename project in @output_filename file
420
 
    """
421
 
 
422
 
    def __init__(self, project_filename, output_filename, debug=False):
423
 
        InteractivePitivi.__init__(self, debug)
424
 
        self.outfile = "file://%s" % os.path.abspath(output_filename)
425
 
        print _("Loading project...")
426
 
        self._loadProject(project_filename)
427
 
 
428
 
    def _eosCb(self, unused_obj):
429
 
        self.shutdown()
430
 
 
431
 
    def _newProjectLoaded(self, project):
432
 
        # create renderer and set output file
433
 
        renderer = Renderer(project, outfile=self.outfile)
434
 
        print _("Project loaded.")
435
 
        print _("Rendering...")
436
 
        self._setActioner(renderer)
437
 
 
438
 
    def shutdown(self):
439
 
        if Pitivi.shutdown(self):
440
 
            self.mainloop.quit()
441
 
            return True
442
 
        return False
443
 
 
444
 
 
445
373
def _parse_options(argv):
446
374
    parser = OptionParser(
447
 
            usage=_("""
 
375
        usage=_("""
448
376
    %prog [PROJECT_FILE]               # Start the video editor.
449
 
    %prog -i [-a] [MEDIA_FILE1 ...]    # Start the editor and create a project.
450
 
    %prog PROJECT_FILE -r OUTPUT_FILE  # Render a project.
451
 
    %prog PROJECT_FILE -p              # Preview a project."""))
 
377
    %prog -i [-a] [MEDIA_FILE1 ...]    # Start the editor and create a project."""))
452
378
 
453
379
    parser.add_option("-i", "--import", dest="import_sources",
454
380
            action="store_true", default=False,
459
385
    parser.add_option("-d", "--debug",
460
386
            action="store_true", default=False,
461
387
            help=_("Run Pitivi in the Python Debugger."))
462
 
    parser.add_option("-r", "--render", dest="render_output",
463
 
            action="store", default=None,
464
 
            help=_("Render the specified project to OUTPUT_FILE with no GUI."))
465
 
    parser.add_option("-p", "--preview",
466
 
            action="store_true", default=False,
467
 
            help=_("Preview the specified project file without the full UI."))
468
388
    options, args = parser.parse_args(argv[1:])
469
389
 
470
390
    # Validate options.
471
 
    if options.render_output and options.preview:
472
 
        parser.error(_("-p and -r cannot be used simultaneously"))
473
 
 
474
 
    if options.import_sources and (options.render_output or options.preview):
475
 
        parser.error(_("-r or -p and -i are incompatible"))
476
 
 
477
391
    if options.add_to_timeline and not options.import_sources:
478
392
        parser.error(_("-a requires -i"))
479
393
 
481
395
    if options.import_sources:
482
396
        # When no MEDIA_FILE is specified, we just create a new project.
483
397
        pass
484
 
    elif options.render_output:
485
 
        if len(args) != 1:
486
 
            parser.error(_("-r requires exactly one PROJECT_FILE"))
487
 
    elif options.preview:
488
 
        if len(args) != 1:
489
 
            parser.error(_("-p requires exactly one PROJECT_FILE"))
490
398
    else:
491
399
        if len(args) > 1:
492
400
            parser.error(_("Cannot open more than one PROJECT_FILE"))
500
408
        ptv = ProjectCreatorGuiPitivi(media_filenames=args,
501
409
                                      add_to_timeline=options.add_to_timeline,
502
410
                                      debug=options.debug)
503
 
    elif options.render_output:
504
 
        ptv = RenderingNoGuiPitivi(project_filename=args[0],
505
 
                                   output_filename=options.render_output,
506
 
                                   debug=options.debug)
507
 
    elif options.preview:
508
 
        ptv = PreviewGuiPitivi(project_filename=args[0], debug=options.debug)
509
411
    else:
510
412
        if args:
511
413
            ptv = ProjectLoaderGuiPitivi(project_filename=args[0],