[pitivi] UI: refactor UI to ensure that UI properly connects to new projects when they are created
- From: Edward Hervey <edwardrv src gnome org>
- To: svn-commits-list gnome org
- Subject: [pitivi] UI: refactor UI to ensure that UI properly connects to new projects when they are created
- Date: Fri, 17 Apr 2009 09:36:30 -0400 (EDT)
commit 4a3150dce3c261b891f5290435b5eb73c7997c5a
Author: Brandon Lewis <brandon_lewis berkeley edu>
Date: Tue Apr 7 13:37:31 2009 -0700
UI: refactor UI to ensure that UI properly connects to new projects when they are created
---
pitivi/application.py | 1 -
pitivi/ui/mainwindow.py | 218 ++++++++++++++++++-----------------------
pitivi/ui/projecttabs.py | 5 +-
pitivi/ui/sourcelist.py | 4 +-
pitivi/ui/timeline.py | 30 ++++---
pitivi/ui/timelinecanvas.py | 2 +-
pitivi/ui/timelinecontrols.py | 3 +-
7 files changed, 118 insertions(+), 145 deletions(-)
diff --git a/pitivi/application.py b/pitivi/application.py
index 05331e5..8987a01 100644
--- a/pitivi/application.py
+++ b/pitivi/application.py
@@ -255,7 +255,6 @@ class InteractivePitivi(Pitivi):
self.mainloop = mainloop
self._gui = PitiviMainWindow(self)
- self._gui.load()
self._gui.show()
if project:
diff --git a/pitivi/ui/mainwindow.py b/pitivi/ui/mainwindow.py
index 73263cd..48906f0 100644
--- a/pitivi/ui/mainwindow.py
+++ b/pitivi/ui/mainwindow.py
@@ -49,6 +49,7 @@ from pitivi.ui import dnd
from pitivi.pipeline import Pipeline
from pitivi.action import ViewAction
from pitivi.settings import GlobalSettings
+from pitivi.receiver import receiver, handler
import pitivi.formatters.format as formatter
if HAVE_GCONF:
@@ -142,8 +143,6 @@ class PitiviMainWindow(gtk.Window, Loggable):
gtk.Window.__init__(self)
Loggable.__init__(self)
self.log("Creating MainWindow")
- self.app = instance
- self.project = self.app.current
self.actions = None
self.toggleactions = None
self.actiongroup = None
@@ -152,22 +151,10 @@ class PitiviMainWindow(gtk.Window, Loggable):
self.is_fullscreen = self.settings.mainWindowFullScreen
self.missing_plugins = []
self.timelinepos = 0
-
- def load(self):
- """ load the user interface """
create_stock_icons()
- self._setActions()
- self._createUi()
- self.app.connect("new-project-loaded", self._newProjectLoadedCb)
- self.app.connect("new-project-loading", self._newProjectLoadingCb)
- self.app.connect("closing-project", self._closingProjectCb)
- self.app.connect("new-project-failed", self._notProjectCb)
- self.project.pipeline.connect("error", self._pipelineErrorCb)
- self.app.current.sources.connect("file_added", self._sourcesFileAddedCb)
- self.app.current.connect("settings-changed", self._settingsChangedCb)
-
- self.app.current.connect('missing-plugins',
- self._projectMissingPluginsCb)
+ self._setActions(instance)
+ self._createUi(instance)
+ self.app = instance
# if no webcams available, hide the webcam action
self.app.deviceprobe.connect("device-added", self._deviceChangeCb)
@@ -178,11 +165,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
# connect to timeline
self.app.current.pipeline.activatePositionListener()
self.app.current.pipeline.connect('position', self._timelinePipelinePositionChangedCb)
-
- self.app.current.timeline.connect('duration-changed',
- self._timelineDurationChangedCb)
-
- self.rate = float(1 / self.project.getSettings().videorate)
+ self.show_all()
def showEncodingDialog(self, project, pause=True):
"""
@@ -208,14 +191,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
def _recordCb(self, unused_button):
self.showEncodingDialog(self.project)
- def _timelineDurationChangedCb(self, timeline, duration):
- if duration > 0:
- sensitive = True
- else:
- sensitive = False
- self.render_button.set_sensitive(sensitive)
-
- def _setActions(self):
+ def _setActions(self, instance):
PLAY = _("Start Playback")
PAUSE = _("Stop Playback")
FRAME_FORWARD = _("Forward one frame")
@@ -327,7 +303,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
action.set_sensitive(True)
elif action_name in ["SaveProject", "SaveProjectAs",
"NewProject", "OpenProject"]:
- if self.app.settings.fileSupportEnabled:
+ if instance.settings.fileSupportEnabled:
action.set_sensitive(True)
else:
action.set_sensitive(False)
@@ -338,7 +314,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
self.uimanager.add_ui_from_file(os.path.join(os.path.dirname(
os.path.abspath(__file__)), "mainwindow.xml"))
- def _createUi(self):
+ def _createUi(self, instance):
""" Create the graphical interface """
self.set_title("%s v%s" % (APPNAME, pitivi_version))
self.set_geometry_hints(min_width=800, min_height=480)
@@ -359,12 +335,12 @@ class PitiviMainWindow(gtk.Window, Loggable):
vbox.pack_start(vpaned)
self.timeline = Timeline(self.uimanager)
- self.timeline.setProject(self.app.current)
+ self.timeline.project = self.project
vpaned.pack2(self.timeline, resize=True, shrink=False)
hpaned = gtk.HPaned()
vpaned.pack1(hpaned, resize=False, shrink=True)
- self.projecttabs = ProjectTabs(self.app)
+ self.projecttabs = ProjectTabs(instance, self.uimanager)
self._connectToSourceList()
hpaned.pack1(self.projecttabs, resize=True, shrink=False)
@@ -455,37 +431,7 @@ class PitiviMainWindow(gtk.Window, Loggable):
dialogbox.destroy()
self.error_dialogbox = None
- def _pipelineErrorCb(self, unused_pipeline, error, detail):
- # FIXME FIXME FIXME:
- # _need_ an onobtrusive way to present gstreamer errors,
- # one that doesn't steel mouse/keyboard focus, one that
- # makes some kind of sense to the user, and one that presents
- # some ways of actually _dealing_ with the underlying problem:
- # install a plugin, re-conform source to some other format, or
- # maybe even disable playback of a problematic file.
- if self.error_dialogbox:
- return
- self.error_dialogbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL,
- gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, None)
- self.error_dialogbox.set_markup("<b>%s</b>" % error)
- self.error_dialogbox.connect("response", self._errorMessageResponseCb)
- if detail:
- self.error_dialogbox.format_secondary_text(detail)
- self.error_dialogbox.show()
-
-## Project source list callbacks
-
- def _sourcesFileAddedCb(self, unused_sources, unused_factory):
- #if (len(self.sourcefactories.sourcelist.storemodel) == 1
- # and not len(self.app.current.timeline.videocomp):
- pass
-
- def _settingsChangedCb(self, project, settings):
- self.rate = float(1 / self.project.getSettings().videorate)
-
- def _projectMissingPluginsCb(self, project, uri, detail, message):
- self.missing_plugins.append(uri)
- return self._installPlugins(detail)
+## Missing Plugin Support
def _installPlugins(self, details):
context = gst.pbutils.InstallPluginsContext()
@@ -714,19 +660,28 @@ class PitiviMainWindow(gtk.Window, Loggable):
def loop(self, unused_action):
pass
- ## PiTiVi main object callbacks
+## PiTiVi main object callbacks
+
+ def _setApplication(self):
+ if self.app:
+ self.project = self.app.current
+ app = receiver(_setApplication)
+
+ @handler(app, "new-project-loaded")
def _newProjectLoadedCb(self, unused_pitivi, project):
self.log("A NEW project is loaded, update the UI!")
- self.timeline.setProject(project)
+ self.project = project
# ungrey UI
self.set_sensitive(True)
+ @handler(app, "new-project-loading")
def _newProjectLoadingCb(self, unused_pitivi, unused_project):
self.log("A NEW project is being loaded, deactivate UI")
# grey UI
self.set_sensitive(False)
+ @handler(app, "closing-project")
def _closingProjectCb(self, unused_pitivi, project):
if not project.hasUnsavedModifications():
return True
@@ -743,6 +698,14 @@ class PitiviMainWindow(gtk.Window, Loggable):
return True
return False
+ @handler(app, "project-closed")
+ def _projectClosedCb(self, unused_pitivi, project):
+ # we must disconnect from the project pipeline before it is released
+ self.viewer.setAction(None)
+ self.viewer.setPipeline(None)
+ return False
+
+ @handler(app, "new-project-failed")
def _notProjectCb(self, unused_pitivi, reason, uri):
# ungrey UI
dialog = gtk.MessageDialog(self,
@@ -759,22 +722,72 @@ class PitiviMainWindow(gtk.Window, Loggable):
## PiTiVi current project callbacks
- def _confirmOverwriteCb(self, unused_project, uri):
- message = _("Do you wish to overwrite existing file \"%s\"?") %\
- gst.uri_get_location(uri)
+ def _setProject(self):
+ if self.project:
+ self.rate = float(1 / self.project.getSettings().videorate)
+ self.project_pipeline = self.project.pipeline
+ self.project_timeline = self.project.timeline
+ if self.timeline:
+ self.timeline.project = self.project
- dialog = gtk.MessageDialog(self,
- gtk.DIALOG_MODAL,
- gtk.MESSAGE_WARNING,
- gtk.BUTTONS_YES_NO,
- message)
+ project = receiver(_setProject)
- dialog.set_title(_("Overwrite Existing File?"))
- response = dialog.run()
- dialog.destroy()
- if response == gtk.RESPONSE_YES:
- return True
- return False
+ @handler(project, "settings-changed")
+ def _settingsChangedCb(self, project, settings):
+ self.rate = float(1 / self.project.getSettings().videorate)
+
+ @handler(project, "missing-plugins")
+ def _projectMissingPluginsCb(self, project, uri, detail, message):
+ self.missing_plugins.append(uri)
+ return self._installPlugins(detail)
+
+## Current Project Pipeline
+
+ def _setProjectPipeline(self):
+ if self.project_pipeline:
+ # connect to timeline
+ self.project_pipeline.activatePositionListener()
+ self._timelinePipelinePositionChangedCb(self.project_pipeline, 0)
+
+ project_pipeline = receiver()
+
+ @handler(project_pipeline, "error")
+ def _pipelineErrorCb(self, unused_pipeline, error, detail):
+ # FIXME FIXME FIXME:
+ # _need_ an onobtrusive way to present gstreamer errors,
+ # one that doesn't steel mouse/keyboard focus, one that
+ # makes some kind of sense to the user, and one that presents
+ # some ways of actually _dealing_ with the underlying problem:
+ # install a plugin, re-conform source to some other format, or
+ # maybe even disable playback of a problematic file.
+ if self.error_dialogbox:
+ return
+ self.error_dialogbox = gtk.MessageDialog(None, gtk.DIALOG_MODAL,
+ gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, None)
+ self.error_dialogbox.set_markup("<b>%s</b>" % error)
+ self.error_dialogbox.connect("response", self._errorMessageResponseCb)
+ if detail:
+ self.error_dialogbox.format_secondary_text(detail)
+ self.error_dialogbox.show()
+
+ @handler(project_pipeline, "position")
+ def _timelinePipelinePositionChangedCb(self, pipeline, position):
+ self.timeline.timelinePositionChanged(position)
+ self.timelinepos = position
+
+## Project Timeline (not to be confused with UI timeline)
+
+ project_timeline = receiver()
+
+ @handler(project_timeline, "duration-changed")
+ def _timelineDurationChangedCb(self, timeline, duration):
+ if duration > 0:
+ sensitive = True
+ else:
+ sensitive = False
+ self.render_button.set_sensitive(sensitive)
+
+## other
def _showSaveAsDialog(self, project):
self.log("Save URI requested")
@@ -848,46 +861,6 @@ class PitiviMainWindow(gtk.Window, Loggable):
self.viewer.setPipeline(pipeline)
self.viewer.play()
- def _timelineDragMotionCb(self, unused_layout, unused_context, x, y, timestamp):
- # FIXME: temporarily add source to timeline, and put it in drag mode
- # so user can see where it will go
- self.info("SimpleTimeline x:%d , source would go at %d", x, 0)
-
- def _timelineDragDataReceivedCb(self, unused_layout, context, x, y,
- selection, targetType, timestamp):
- self.log("SimpleTimeline, targetType:%d, selection.data:%s" %
- (targetType, selection.data))
- if targetType == dnd.TYPE_PITIVI_FILESOURCE:
- uri = selection.data
- else:
- context.finish(False, False, timestamp)
- factory = self.app.current.sources[uri]
-
- # FIXME: the UI should be smart here and figure out which track the
- # source was dragged onto
- self.app.current.timeline.addSourceFactory(factory)
- context.finish(True, False, timestamp)
-
- def _getTimelinePipeline(self):
- # FIXME: the timeline pipeline should probably be moved in project
- try:
- return self._timeline_pipeline, self._timeline_view_action
- except AttributeError:
- pass
-
- timeline = self.pitivi.current.timeline
- factory = TimelineSourceFactory(timeline)
- pipeline = Pipeline()
- pipeline.activatePositionListener()
- pipeline.connect('position', self._timelinePipelinePositionChangedCb)
- action = ViewAction()
- action.addProducers(factory)
-
- self._timeline_pipeline = pipeline
- self._timeline_view_action = action
-
- return self._timeline_pipeline, self._timeline_view_action
-
def _timelineRulerSeekCb(self, ruler, position):
self.debug("position:%s", gst.TIME_ARGS (position))
self.viewer.setAction(self.project.view_action)
@@ -900,6 +873,3 @@ class PitiviMainWindow(gtk.Window, Loggable):
except:
self.debug("Seeking failed")
- def _timelinePipelinePositionChangedCb(self, pipeline, position):
- self.timeline.timelinePositionChanged(position)
- self.timelinepos = position
diff --git a/pitivi/ui/projecttabs.py b/pitivi/ui/projecttabs.py
index 81130e5..93a1a31 100644
--- a/pitivi/ui/projecttabs.py
+++ b/pitivi/ui/projecttabs.py
@@ -69,10 +69,11 @@ class ProjectTabs(gtk.Notebook):
# (PropertyEditor, _("Properties")),
)
- def __init__(self, instance):
+ def __init__(self, instance, uiman):
""" initialize """
gtk.Notebook.__init__(self)
self.app = instance
+ self.uiman = uiman
self._full_list = []
self.connect("switch-page", self._switchPage)
self._createUi()
@@ -81,7 +82,7 @@ class ProjectTabs(gtk.Notebook):
""" set up the gui """
self.set_tab_pos(gtk.POS_TOP)
for component, label in self.__DEFAULT_COMPONENTS__:
- self.addComponent(component(self.app), label)
+ self.addComponent(component(self.app, self.uiman), label)
def addComponent(self, component, label):
self.append_page(component, DetachLabel(self, component, label))
diff --git a/pitivi/ui/sourcelist.py b/pitivi/ui/sourcelist.py
index ef7d272..2ebd576 100644
--- a/pitivi/ui/sourcelist.py
+++ b/pitivi/ui/sourcelist.py
@@ -131,7 +131,7 @@ class SourceList(gtk.VBox, Loggable):
(gobject.TYPE_PYOBJECT,))
}
- def __init__(self, instance):
+ def __init__(self, instance, uiman):
gtk.VBox.__init__(self)
Loggable.__init__(self)
@@ -296,7 +296,6 @@ class SourceList(gtk.VBox, Loggable):
self._insertEndCb),
)
- uiman = self.app.gui.uimanager
actiongroup = gtk.ActionGroup("sourcelistpermanent")
actiongroup.add_actions(actions)
uiman.insert_action_group(actiongroup, 0)
@@ -305,7 +304,6 @@ class SourceList(gtk.VBox, Loggable):
self.selection_actions.add_actions(selection_actions)
self.selection_actions.set_sensitive(False)
uiman.insert_action_group(self.selection_actions, 0)
-
uiman.add_ui_from_string(ui)
def _importSourcesCb(self, unused_action):
diff --git a/pitivi/ui/timeline.py b/pitivi/ui/timeline.py
index f6ba65a..53904aa 100644
--- a/pitivi/ui/timeline.py
+++ b/pitivi/ui/timeline.py
@@ -118,13 +118,11 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self.log("Creating Timeline")
self.project = None
- self.timeline = None
self.ui_manager = ui_manager
self._temp_objects = None
self._factories = None
self._finish_drag = False
self._position = 0
-
self._createUI()
def _createUI(self):
@@ -133,7 +131,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self.vadj = gtk.Adjustment()
# controls for tracks and layers
- self._controls = TimelineControls(self.timeline)
+ self._controls = TimelineControls()
self._controls.connect('track-expanded',
self._timelineControlsTrackExpandedCb)
controlwindow = gtk.ScrolledWindow(None, self.vadj)
@@ -148,7 +146,7 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self.attach(self.ruler, 1, 2, 0, 1, yoptions=0)
# proportional timeline
- self._canvas = TimelineCanvas(self.timeline)
+ self._canvas = TimelineCanvas()
timelinewindow = gtk.ScrolledWindow(self.hadj, self.vadj)
timelinewindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
timelinewindow.add(self._canvas)
@@ -282,12 +280,6 @@ class Timeline(gtk.Table, Loggable, Zoomable):
obj.setStart(max(0, delta), snap=True)
delta += obj.duration
- def setProject(self, project):
- self.project = project
- self.timeline = project.timeline
- self._controls.timeline = self.timeline
- self._canvas.timeline = self.timeline
- self._canvas.zoomChanged()
## Zooming and Scrolling
@@ -322,13 +314,27 @@ class Timeline(gtk.Table, Loggable, Zoomable):
self.hadj.set_value(position)
return False
+## Project callbacks
+
+ def _setProject(self):
+ if self.project:
+ self.timeline = self.project.timeline
+ self._controls.timeline = self.timeline
+ self._canvas.timeline = self.timeline
+ self._canvas.zoomChanged()
+ self.ruler.zoomChanged()
+
+ project = receiver(_setProject)
+
## Timeline callbacks
- def _set_timeline(self):
+ def _setTimeline(self):
if self.timeline:
self._timelineSelectionChanged(self.timeline)
- timeline = receiver(_set_timeline)
+ self._controls.timeline = self.timeline
+
+ timeline = receiver(_setTimeline)
@handler(timeline, "duration-changed")
def _timelineStartDurationChanged(self, unused_timeline, duration):
diff --git a/pitivi/ui/timelinecanvas.py b/pitivi/ui/timelinecanvas.py
index e09eb27..8383013 100644
--- a/pitivi/ui/timelinecanvas.py
+++ b/pitivi/ui/timelinecanvas.py
@@ -42,7 +42,7 @@ class TimelineCanvas(goocanvas.Canvas, Zoomable):
_tracks = None
- def __init__(self, timeline):
+ def __init__(self, timeline=None):
goocanvas.Canvas.__init__(self)
Zoomable.__init__(self)
self._selected_sources = []
diff --git a/pitivi/ui/timelinecontrols.py b/pitivi/ui/timelinecontrols.py
index 79ccf7a..7105f24 100644
--- a/pitivi/ui/timelinecontrols.py
+++ b/pitivi/ui/timelinecontrols.py
@@ -58,11 +58,10 @@ class TimelineControls(gtk.VBox):
(gobject.TYPE_PYOBJECT, gobject.TYPE_BOOLEAN))
}
- def __init__(self, timeline):
+ def __init__(self):
gtk.VBox.__init__(self)
self._tracks = []
self.set_spacing(LAYER_SPACING)
- self.timeline = timeline
self.set_size_request(TRACK_CONTROL_WIDTH, -1)
## Timeline callbacks
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]