34
44
from gettext import gettext as _
35
45
from optparse import OptionParser
37
import pitivi.instance as instance
39
47
from pitivi.effects import EffectsHandler
40
from pitivi.configure import APPNAME, pitivi_version, RELEASES_URL
48
from pitivi.configure import VERSION, RELEASES_URL
41
49
from pitivi.settings import GlobalSettings
42
50
from pitivi.utils.threads import ThreadMaster
43
51
from pitivi.mainwindow import PitiviMainWindow
54
62
#from pitivi.undo.timeline import TimelineLogObserver
58
Hierarchy of the whole thing:
63
ProjectCreatorGuiPitivi
64
ProjectLoaderGuiPitivi
65
StartupWizardGuiPitivi
69
65
class Pitivi(Loggable, Signallable):
71
67
Pitivi's main application class.
76
72
- C{new-project-loading} : Pitivi is attempting to load a new project.
77
73
- C{new-project-loaded} : A new L{Project} has been loaded, and the UI should refresh it's view.
78
74
- C{new-project-failed} : A new L{Project} failed to load.
79
- C{closing-project} : pitivi would like to close a project. handlers should return false
80
if they do not want this project to close. by default, assumes
81
true. This signal should only be used by classes that might want to abort
82
the closing of a project.
83
75
- C{project-closed} : The project is closed, it will be freed when the callback returns.
84
76
Classes should connect to this instance when they want to know that
85
77
data related to that project is no longer going to be used.
97
89
"new-project-created": ["project"],
98
90
"new-project-loaded": ["project"],
99
91
"new-project-failed": ["uri", "exception"],
100
"closing-project": ["project"],
101
92
"project-closed": ["project"],
102
93
"missing-uri": ["formatter", "uri"],
103
94
"version-info-received": ["versions"],
106
97
def __init__(self):
108
initialize pitivi with the command line arguments
110
98
Loggable.__init__(self)
112
# init logging as early as possible so we can log startup code
113
enable_color = os.environ.get('PITIVI_DEBUG_NO_COLOR', '0') in ('', '0')
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')
114
102
# Let's show a human-readable pitivi debug output by default, and only
115
103
# show a crazy unreadable mess when surrounded by gst debug statements.
116
104
enable_crack_output = "GST_DEBUG" in os.environ
119
107
self.info('starting up')
121
# store ourself in the instance global
123
raise RuntimeWarning(_("There is already a %s instance, please inform "
124
"the developers by filing a bug at "
125
"http://bugzilla.gnome.org/enter_bug.cgi?product=pitivi")
127
instance.Pitivi = self
129
self.current_project = None
132
109
self.settings = GlobalSettings()
133
110
self.threads = ThreadMaster()
134
#self.screencast = False
136
111
self.effects = EffectsHandler()
137
112
self.system = getSystem()
114
self.current_project = None
139
115
self.projectManager = ProjectManager(self)
140
116
self._connectToProjectManager(self.projectManager)
175
150
pm.connect("new-project-created", self._projectManagerNewProjectCreated)
176
151
pm.connect("new-project-loaded", self._projectManagerNewProjectLoaded)
177
152
pm.connect("new-project-failed", self._projectManagerNewProjectFailed)
178
pm.connect("closing-project", self._projectManagerClosingProject)
179
153
pm.connect("project-closed", self._projectManagerProjectClosed)
181
def _projectManagerNewProjectLoading(self, projectManager, uri):
155
def _projectManagerNewProjectLoading(self, unused_project_manager, uri):
182
156
self.emit("new-project-loading", uri)
184
def _projectManagerNewProjectCreated(self, projectManager, project):
158
def _projectManagerNewProjectCreated(self, unused_project_manager, project):
185
159
self.current_project = project
186
160
self.emit("new-project-created", project)
188
def _newProjectLoaded(self, project):
162
def _newProjectLoaded(self, unused_project):
191
def _projectManagerNewProjectLoaded(self, projectManager, project, unused_fully_loaded):
165
def _projectManagerNewProjectLoaded(self, unused_project_manager, project, unused_fully_loaded):
192
166
self.current_project = project
193
167
self.action_log.clean()
194
168
#self.timelineLogObserver.startObserving(project.timeline)
196
170
self._newProjectLoaded(project)
197
171
self.emit("new-project-loaded", project)
199
def _projectManagerNewProjectFailed(self, projectManager, uri, exception):
173
def _projectManagerNewProjectFailed(self, unused_project_manager, uri, exception):
200
174
self.emit("new-project-failed", uri, exception)
202
def _projectManagerClosingProject(self, projectManager, project):
203
return self.emit("closing-project", project)
205
def _projectManagerProjectClosed(self, projectManager, project):
176
def _projectManagerProjectClosed(self, unused_project_manager, project):
206
177
#self.timelineLogObserver.stopObserving(project.timeline)
207
178
self.projectLogObserver.stopObserving(project)
208
179
self.current_project = None
214
185
self.info("Requesting version information")
215
186
giofile.load_contents_async(None, self._versionInfoReceivedCb, None)
217
def _versionInfoReceivedCb(self, giofile, result, data):
188
def _versionInfoReceivedCb(self, giofile, result, user_data):
219
190
raw = giofile.load_contents_finish(result)[1]
220
191
raw = raw.split("\n")
225
196
# search newest version and status
226
197
status = "UNSUPPORTED"
198
current_version = None
227
199
for version, version_status in data:
228
if pitivi_version == version:
200
if VERSION == version:
229
201
status = version_status
230
202
if version_status.upper() == "CURRENT":
203
# This is the latest.
231
204
current_version = version
233
206
self.info("Latest software version is %s", current_version)
234
if status is "UNSUPPORTED":
235
self.warning("Using an outdated version of Pitivi (%s)" % pitivi_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:
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)
237
self.version_information["current"] = current_version
238
self.version_information["status"] = status
239
self.emit("version-info-received", self.version_information)
215
self._version_information["current"] = current_version
216
self._version_information["status"] = status
217
self.emit("version-info-received", self._version_information)
240
218
except Exception, e:
241
self.warning("Version info could not be read: %s" % e)
219
self.warning("Version info could not be read: %s", e)
223
Whether the app's version is the latest as far as we know.
225
status = self._version_information.get("status")
226
return status is None or status.upper() == "CURRENT"
230
Get the latest version of the app or None.
232
return self._version_information.get("current")
244
235
class InteractivePitivi(Pitivi):
249
240
def __init__(self, debug=False):
250
241
Pitivi.__init__(self)
251
242
self.mainloop = GLib.MainLoop()
255
245
sys.excepthook = self._excepthook
257
def _excepthook(self, exc_type, value, tback):
247
def _excepthook(self, unused_exc_type, unused_value, tback):
260
250
traceback.print_tb(tback)
261
251
pdb.post_mortem(tback)
263
def _setActioner(self, actioner):
264
self.actioner = actioner
266
self.actioner.connect("eos", self._eosCb)
267
# On error, all we need to do is shutdown which
268
# is the same as we do for EOS
269
self.actioner.connect("error", self._eosCb)
270
# Configure the actioner and start acting!
271
self.actioner.startAction()
273
def _eosCb(self, unused_obj):
274
raise NotImplementedError()
276
def _loadProject(self, project_filename):
277
self.projectManager.loadProject(quote_uri(os.path.abspath(project_filename)))
280
254
"""Runs the main loop."""
281
255
self.mainloop.run()
296
270
def _showStartupError(self, message, detail):
297
dialog = Gtk.MessageDialog(type=Gtk.MessageType.ERROR,
271
dialog = Gtk.MessageDialog(message_type=Gtk.MessageType.ERROR,
298
272
buttons=Gtk.ButtonsType.OK)
299
273
dialog.set_markup("<b>" + message + "</b>")
300
274
dialog.format_secondary_text(detail)
303
def _eosCb(self, unused_obj):
306
277
def _createGui(self):
307
278
"""Returns a Gtk.Widget which represents the UI."""
308
279
return PitiviMainWindow(self)
338
309
lib.connect("discovery-error", self._discoveryErrorCb, uris)
339
310
lib.addUris(uris)
341
def _sourceAddedCb(self, medialibrary, info, startup_uris, add_to_timeline):
312
def _sourceAddedCb(self, unused_media_library, info, startup_uris, add_to_timeline):
342
313
if self._maybePopStartupUri(startup_uris, info.get_uri()) \
343
314
and add_to_timeline:
344
315
self.action_log.begin("add clip")
347
318
self.current_project.timeline.get_layers()[0].add_clip(src)
348
319
self.action_log.commit()
350
def _discoveryErrorCb(self, medialibrary, uri, error, debug, startup_uris):
321
def _discoveryErrorCb(self, unused_media_library, uri, unused_error, unused_debug, startup_uris):
351
322
self._maybePopStartupUri(startup_uris, uri)
353
324
def _maybePopStartupUri(self, startup_uris, uri):
376
347
if not os.path.exists(project_filename):
377
348
self.error("Project file does not exist: %s" % project_filename)
380
self._loadProject(project_filename)
350
self.projectManager.loadProject(quote_uri(os.path.abspath(project_filename)))
383
353
class StartupWizardGuiPitivi(GuiPitivi):
392
362
self.projectManager.newBlankProject(emission=False)
394
364
def _createGui(self):
395
# Prevent the main window to go fullscreen because at least
396
# the Metacity window manager will refuse to bring
397
# the startup wizard window in front of the main window.
398
return PitiviMainWindow(self, allow_full_screen=False)
365
return PitiviMainWindow(self)
400
367
def _showGui(self):
401
368
GuiPitivi._showGui(self)