def _createUi(self, instance): """ Create the graphical interface """ self.set_title("%s" % (APPNAME)) self.connect("delete-event", self._deleteCb) self.connect("configure-event", self._configureCb) # main menu & toolbar vbox = gtk.VBox(False) self.add(vbox) vbox.show() self.menu = self.uimanager.get_widget("/MainMenuBar") vbox.pack_start(self.menu, expand=False) self.menu.show() self.toolbar = self.uimanager.get_widget("/MainToolBar") vbox.pack_start(self.toolbar, expand=False) self.toolbar.show() # timeline and project tabs vpaned = gtk.VPaned() vbox.pack_start(vpaned) vpaned.show() self.timeline = Timeline(instance, self.uimanager) self.timeline.project = self.project vpaned.pack2(self.timeline, resize=True, shrink=False) self.timeline.show() self.mainhpaned = gtk.HPaned() vpaned.pack1(self.mainhpaned, resize=True, shrink=False) self.secondhpaned = gtk.HPaned() self.mainhpaned.pack1(self.secondhpaned, resize=True, shrink=False) self.secondhpaned.show() self.mainhpaned.show() self.projecttabs = BaseTabs(instance) self.sourcelist = SourceList(instance, self.uimanager) self.projecttabs.append_page(self.sourcelist, gtk.Label(_("Media Library"))) self._connectToSourceList() self.sourcelist.show() self.effectlist = EffectList(instance, self.uimanager) self.projecttabs.append_page(self.effectlist, gtk.Label(_("Effect Library"))) self.effectlist.show() self.secondhpaned.pack1(self.projecttabs, resize=True, shrink=False) self.projecttabs.show() # Actions with key accelerators that will be made unsensitive while # a gtk entry box is used to avoid conflicts. self.sensitive_actions = [] for action in self.timeline.playhead_actions: self.sensitive_actions.append(action[0]) for action in self.toggleactions: self.sensitive_actions.append(action[0]) #Clips properties self.propertiestabs = BaseTabs(instance, True) self.clipconfig = ClipProperties(instance, self.uimanager) self.clipconfig.project = self.project self.propertiestabs.append_page(self.clipconfig, gtk.Label(_("Effects configurations"))) self.clipconfig.show() self.secondhpaned.pack2(self.propertiestabs, resize= True, shrink=False) self.propertiestabs.show() # Viewer self.viewer = PitiviViewer(instance, undock_action=self.undock_action) # drag and drop self.viewer.drag_dest_set(gtk.DEST_DEFAULT_DROP | gtk.DEST_DEFAULT_MOTION, [dnd.FILESOURCE_TUPLE, dnd.URI_TUPLE], gtk.gdk.ACTION_COPY) self.viewer.connect("drag_data_received", self._viewerDndDataReceivedCb) self.mainhpaned.pack2(self.viewer, resize=False, shrink=False) self.viewer.connect("expose-event", self._exposeEventCb) # window and pane position defaults self.mainhpaned = self.mainhpaned self.hpaned = self.secondhpaned self.vpaned = vpaned height = -1 width = -1 if self.settings.mainWindowHPanePosition: self.hpaned.set_position(self.settings.mainWindowHPanePosition) if self.settings.mainWindowMainHPanePosition: self.mainhpaned.set_position(self.settings.mainWindowMainHPanePosition) if self.settings.mainWindowVPanePosition: self.vpaned.set_position(self.settings.mainWindowVPanePosition) if self.settings.mainWindowWidth: width = self.settings.mainWindowWidth if self.settings.mainWindowHeight: height = self.settings.mainWindowHeight self.set_default_size(width, height) if height == -1 and width == -1: self.maximize() self._do_pending_fullscreen = False # FIXME: don't know why this doesn't work #if self.settings.mainWindowFullScreen: # self._do_pending_fullscreen = True # timeline toolbar # FIXME: remove toolbar padding and shadow. In fullscreen mode, the # toolbar buttons should be clickable with the mouse cursor at the # very bottom of the screen. ttb = self.uimanager.get_widget("/TimelineToolBar") vbox.pack_start(ttb, expand=False) ttb.show() self.show() if not self.settings.mainWindowShowMainToolbar: self.toolbar.props.visible = False if not self.settings.mainWindowShowTimelineToolbar: ttb.props.visible = False #application icon self.set_icon_name("pitivi") #pulseaudio 'role' (http://0pointer.de/blog/projects/tagging-audio.htm os.environ["PULSE_PROP_media.role"] = "production" os.environ["PULSE_PROP_application.icon_name"] = "pitivi"
def _createUi(self, instance): """ Create the graphical interface """ self.set_title("%s" % (APPNAME)) self.connect("delete-event", self._deleteCb) self.connect("configure-event", self._configureCb) # main menu & toolbar vbox = gtk.VBox(False) self.add(vbox) vbox.show() self.menu = self.uimanager.get_widget("/MainMenuBar") vbox.pack_start(self.menu, expand=False) self.menu.show() self.toolbar = self.uimanager.get_widget("/MainToolBar") vbox.pack_start(self.toolbar, expand=False) self.toolbar.show() # timeline and project tabs vpaned = gtk.VPaned() vbox.pack_start(vpaned) vpaned.show() self.timeline = Timeline(instance, self.uimanager) self.timeline.project = self.project vpaned.pack2(self.timeline, resize=True, shrink=False) self.timeline.show() self.mainhpaned = gtk.HPaned() vpaned.pack1(self.mainhpaned, resize=True, shrink=False) self.secondhpaned = gtk.HPaned() self.mainhpaned.pack1(self.secondhpaned, resize=True, shrink=False) self.secondhpaned.show() self.mainhpaned.show() self.projecttabs = BaseTabs(instance) self.sourcelist = SourceList(instance, self.uimanager) self.projecttabs.append_page(self.sourcelist, gtk.Label(_("Media Library"))) self._connectToSourceList() self.sourcelist.show() self.effectlist = EffectList(instance, self.uimanager) self.projecttabs.append_page(self.effectlist, gtk.Label(_("Effect Library"))) self.effectlist.show() self.secondhpaned.pack1(self.projecttabs, resize=True, shrink=False) self.projecttabs.show() #Clips properties self.propertiestabs = BaseTabs(instance, True) self.clipconfig = ClipProperties(instance, self.uimanager) self.clipconfig.project = self.project self.propertiestabs.append_page(self.clipconfig, gtk.Label(_("Effects configurations"))) self.clipconfig.show() self.secondhpaned.pack2(self.propertiestabs, resize= True, shrink=False) self.propertiestabs.show() # Viewer self.viewer = PitiviViewer() # drag and drop self.viewer.drag_dest_set(gtk.DEST_DEFAULT_DROP | gtk.DEST_DEFAULT_MOTION, [dnd.FILESOURCE_TUPLE, dnd.URI_TUPLE], gtk.gdk.ACTION_COPY) self.viewer.connect("drag_data_received", self._viewerDndDataReceivedCb) self.mainhpaned.pack2(self.viewer, resize=False, shrink=False) self.viewer.show() self.viewer.connect("expose-event", self._exposeEventCb) # window and pane position defaults self.mainhpaned = self.mainhpaned self.hpaned = self.secondhpaned self.vpaned = vpaned height = -1 width = -1 if self.settings.mainWindowHPanePosition: self.hpaned.set_position(self.settings.mainWindowHPanePosition) if self.settings.mainWindowMainHPanePosition: self.mainhpaned.set_position(self.settings.mainWindowMainHPanePosition) if self.settings.mainWindowVPanePosition: self.vpaned.set_position(self.settings.mainWindowVPanePosition) if self.settings.mainWindowWidth: width = self.settings.mainWindowWidth if self.settings.mainWindowHeight: height = self.settings.mainWindowHeight self.set_default_size(width, height) if height == -1 and width == -1: self.maximize() self._do_pending_fullscreen = False # FIXME: don't know why this doesn't work #if self.settings.mainWindowFullScreen: # self._do_pending_fullscreen = True # timeline toolbar # FIXME: remove toolbar padding and shadow. In fullscreen mode, the # toolbar buttons should be clickable with the mouse cursor at the # very bottom of the screen. ttb = self.uimanager.get_widget("/TimelineToolBar") vbox.pack_start(ttb, expand=False) ttb.show() self.show() if not self.settings.mainWindowShowMainToolbar: self.toolbar.props.visible = False if not self.settings.mainWindowShowTimelineToolbar: ttb.props.visible = False #application icon self.set_icon_name("pitivi") #pulseaudio 'role' (http://0pointer.de/blog/projects/tagging-audio.htm os.environ["PULSE_PROP_media.role"] = "production" os.environ["PULSE_PROP_application.icon_name"] = "pitivi"
class PitiviMainWindow(gtk.Window, Loggable): """ Pitivi's main window. @cvar app: The application object @type app: L{Application} @cvar project: The current project @type project: L{Project} """ def __init__(self, instance): """ initialize with the Pitivi object """ gtk.Window.__init__(self) Loggable.__init__(self) self.log("Creating MainWindow") self.actions = None self.toggleactions = None self.actiongroup = None self.settings = instance.settings self.is_fullscreen = self.settings.mainWindowFullScreen self.timelinepos = 0 self.prefsdialog = None create_stock_icons() self._setActions(instance) self._createUi(instance) self.app = instance self._launchWizard() self.manager = RecentManager() self._zoom_duration_changed = False self._missingUriOnLoading = False self.app.projectManager.connect("new-project-loading", self._projectManagerNewProjectLoadingCb) self.app.projectManager.connect("new-project-loaded", self._projectManagerNewProjectLoadedCb) self.app.projectManager.connect("new-project-loaded", self._quitWizardCb) self.app.projectManager.connect("new-project-failed", self._projectManagerNewProjectFailedCb) self.app.projectManager.connect("save-project-failed", self._projectManagerSaveProjectFailedCb) self.app.projectManager.connect("project-saved", self._projectManagerProjectSavedCb) self.app.projectManager.connect("closing-project", self._projectManagerClosingProjectCb) self.app.projectManager.connect("reverting-to-saved", self._projectManagerRevertingToSavedCb) self.app.projectManager.connect("project-closed", self._projectManagerProjectClosedCb) self.app.projectManager.connect("missing-uri", self._projectManagerMissingUriCb) self.app.action_log.connect("commit", self._actionLogCommit) self.app.action_log.connect("undo", self._actionLogUndo) self.app.action_log.connect("redo", self._actionLogRedo) self.app.action_log.connect("cleaned", self._actionLogCleaned) # if no webcams available, hide the webcam action if self.app.deviceprobe is not None: # On Windows disable device probe if platform.system() != 'Windows': self.app.deviceprobe.connect("device-added", self._deviceChangeCb) self.app.deviceprobe.connect("device-removed", self._deviceChangeCb) if len(self.app.deviceprobe.getVideoSourceDevices()) < 1: self.webcam_button.set_sensitive(False) else: self.webcam_button.set_sensitive(False) self.show() def showEncodingDialog(self, project, pause=True): """ Shows the L{EncodingDialog} for the given project Timeline. @param project: The project @type project: L{Project} @param pause: If C{True}, pause the timeline before displaying the dialog. @type pause: C{bool} """ from encodingdialog import EncodingDialog if pause: project.pipeline.pause() win = EncodingDialog(self, project) win.window.connect("destroy", self._encodingDialogDestroyCb) self.set_sensitive(False) win.show() def _encodingDialogDestroyCb(self, unused_dialog): self.set_sensitive(True) def _recordCb(self, unused_button): self.showEncodingDialog(self.project) def _setActions(self, instance): PLAY = _("Start Playback") PAUSE = _("Stop Playback") LOOP = _("Loop over selected area") """ sets up the GtkActions """ self.actions = [ ("NewProject", gtk.STOCK_NEW, None, None, _("Create a new project"), self._newProjectMenuCb), ("OpenProject", gtk.STOCK_OPEN, _("_Open..."), None, _("Open an existing project"), self._openProjectCb), ("SaveProject", gtk.STOCK_SAVE, None, None, _("Save the current project"), self._saveProjectCb), ("SaveProjectAs", gtk.STOCK_SAVE_AS, _("Save _As..."), None, _("Save the current project"), self._saveProjectAsCb), ("RevertToSavedProject", gtk.STOCK_REVERT_TO_SAVED, None, None, _("Reload the current project"), self._revertToSavedProjectCb), ("ProjectSettings", gtk.STOCK_PROPERTIES, _("Project Settings"), None, _("Edit the project settings"), self._projectSettingsCb), ("RenderProject", 'pitivi-render' , _("_Render project"), None, _("Render project..."), self._recordCb), ("Undo", gtk.STOCK_UNDO, _("_Undo"), "<Ctrl>Z", _("Undo the last operation"), self._undoCb), ("Redo", gtk.STOCK_REDO, _("_Redo"), "<Ctrl>Y", _("Redo the last operation that was undone"), self._redoCb), ("PluginManager", gtk.STOCK_PREFERENCES , _("_Plugins..."), None, _("Manage plugins"), self._pluginManagerCb), ("Preferences", gtk.STOCK_PREFERENCES, _("_Preferences"), None, None, self._prefsCb), ("ImportfromCam", gtk.STOCK_ADD , _("Import from _Webcam..."), None, _("Import Camera stream"), self._ImportWebcam), ("Screencast", gtk.STOCK_ADD , _("_Make screencast..."), None, _("Capture the desktop"), self._Screencast), ("NetstreamCapture", gtk.STOCK_ADD , _("_Capture Network Stream..."), None, _("Capture Network Stream"), self._ImportNetstream), ("Quit", gtk.STOCK_QUIT, None, None, None, self._quitCb), ("About", gtk.STOCK_ABOUT, None, None, _("Information about %s") % APPNAME, self._aboutCb), ("UserManual", gtk.STOCK_HELP, _("User manual"), None, None, self._userManualCb), ("File", None, _("_File")), ("Edit", None, _("_Edit")), ("View", None, _("_View")), ("Library", None, _("_Project")), ("Timeline", None, _("_Timeline")), ("Viewer", None, _("Previe_w")), ("PlayPause", gtk.STOCK_MEDIA_PLAY, None, "space", PLAY, self.playPause), ("Loop", gtk.STOCK_REFRESH, _("Loop"), None, LOOP, self.loop), ("Help", None, _("_Help")), ] self.toggleactions = [ ("FullScreen", gtk.STOCK_FULLSCREEN, None, "f", _("View the main window on the whole screen"), self._fullScreenCb), ("FullScreenAlternate", gtk.STOCK_FULLSCREEN, None, "F11", None, self._fullScreenAlternateCb), ("ShowHideMainToolbar", None, _("Main Toolbar"), None, None, self._showHideMainToolBar, self.settings.mainWindowShowMainToolbar), ("ShowHideTimelineToolbar", None, _("Timeline Toolbar"), None, None, self._showHideTimelineToolbar, self.settings.mainWindowShowTimelineToolbar), ] self.actiongroup = gtk.ActionGroup("mainwindow") self.actiongroup.add_actions(self.actions) self.actiongroup.add_toggle_actions(self.toggleactions) self.undock_action = gtk.Action("WindowizeViewer", _("Undock Viewer"), _("Put the viewer in a serparate window"), None) self.actiongroup.add_action(self.undock_action) # deactivating non-functional actions # FIXME : reactivate them save_action = self.actiongroup.get_action("SaveProject") save_action.set_sensitive(False) for action in self.actiongroup.list_actions(): action_name = action.get_name() if action_name == "RenderProject": self.render_button = action # this will be set sensitive when the timeline duration changes action.set_sensitive(False) action.props.is_important = True elif action_name == "ImportfromCam": self.webcam_button = action action.set_sensitive(False) elif action_name == "Screencast": # FIXME : re-enable this action once istanbul integration is complete # and upstream istanbul has applied packages for proper interaction. action.set_sensitive(False) action.set_visible(False) elif action_name in [ "ProjectSettings", "Quit", "File", "Edit", "Help", "About", "View", "FullScreen", "FullScreenAlternate", "UserManual", "ImportSourcesFolder", "PluginManager", "PlayPause", "Project", "FrameForward", "FrameBackward", "ShowHideMainToolbar", "ShowHideTimelineToolbar", "Library", "Timeline", "Viewer", "FrameForward", "FrameBackward", "SecondForward", "SecondBackward", "EdgeForward", "EdgeBackward", "Preferences", "WindowizeViewer"]: action.set_sensitive(True) elif action_name in ["NewProject", "SaveProjectAs", "OpenProject"]: if instance.settings.fileSupportEnabled: action.set_sensitive(True) elif action_name == "SaveProject": if instance.settings.fileSupportEnabled: action.set_sensitive(True) action.props.is_important = True elif action_name == "Undo": action.set_sensitive(True) action.props.is_important = True else: action.set_sensitive(False) self.uimanager = gtk.UIManager() self.add_accel_group(self.uimanager.get_accel_group()) self.uimanager.insert_action_group(self.actiongroup, 0) if 'pitivi.exe' in __file__.lower(): xml = LIBDIR + '\\pitivi.exe' else: xml = __file__ self.uimanager.add_ui_from_file(os.path.join(os.path.dirname( os.path.abspath(xml)), "mainwindow.xml")) def _createUi(self, instance): """ Create the graphical interface """ self.set_title("%s" % (APPNAME)) self.connect("delete-event", self._deleteCb) self.connect("configure-event", self._configureCb) # main menu & toolbar vbox = gtk.VBox(False) self.add(vbox) vbox.show() self.menu = self.uimanager.get_widget("/MainMenuBar") vbox.pack_start(self.menu, expand=False) self.menu.show() self.toolbar = self.uimanager.get_widget("/MainToolBar") vbox.pack_start(self.toolbar, expand=False) self.toolbar.show() # timeline and project tabs vpaned = gtk.VPaned() vbox.pack_start(vpaned) vpaned.show() self.timeline = Timeline(instance, self.uimanager) self.timeline.project = self.project vpaned.pack2(self.timeline, resize=True, shrink=False) self.timeline.show() self.mainhpaned = gtk.HPaned() vpaned.pack1(self.mainhpaned, resize=True, shrink=False) self.secondhpaned = gtk.HPaned() self.mainhpaned.pack1(self.secondhpaned, resize=True, shrink=False) self.secondhpaned.show() self.mainhpaned.show() self.projecttabs = BaseTabs(instance) self.sourcelist = SourceList(instance, self.uimanager) self.projecttabs.append_page(self.sourcelist, gtk.Label(_("Media Library"))) self._connectToSourceList() self.sourcelist.show() self.effectlist = EffectList(instance, self.uimanager) self.projecttabs.append_page(self.effectlist, gtk.Label(_("Effect Library"))) self.effectlist.show() self.secondhpaned.pack1(self.projecttabs, resize=True, shrink=False) self.projecttabs.show() # Actions with key accelerators that will be made unsensitive while # a gtk entry box is used to avoid conflicts. self.sensitive_actions = [] for action in self.timeline.playhead_actions: self.sensitive_actions.append(action[0]) for action in self.toggleactions: self.sensitive_actions.append(action[0]) #Clips properties self.propertiestabs = BaseTabs(instance, True) self.clipconfig = ClipProperties(instance, self.uimanager) self.clipconfig.project = self.project self.propertiestabs.append_page(self.clipconfig, gtk.Label(_("Effects configurations"))) self.clipconfig.show() self.secondhpaned.pack2(self.propertiestabs, resize= True, shrink=False) self.propertiestabs.show() # Viewer self.viewer = PitiviViewer(instance, undock_action=self.undock_action) # drag and drop self.viewer.drag_dest_set(gtk.DEST_DEFAULT_DROP | gtk.DEST_DEFAULT_MOTION, [dnd.FILESOURCE_TUPLE, dnd.URI_TUPLE], gtk.gdk.ACTION_COPY) self.viewer.connect("drag_data_received", self._viewerDndDataReceivedCb) self.mainhpaned.pack2(self.viewer, resize=False, shrink=False) self.viewer.connect("expose-event", self._exposeEventCb) # window and pane position defaults self.mainhpaned = self.mainhpaned self.hpaned = self.secondhpaned self.vpaned = vpaned height = -1 width = -1 if self.settings.mainWindowHPanePosition: self.hpaned.set_position(self.settings.mainWindowHPanePosition) if self.settings.mainWindowMainHPanePosition: self.mainhpaned.set_position(self.settings.mainWindowMainHPanePosition) if self.settings.mainWindowVPanePosition: self.vpaned.set_position(self.settings.mainWindowVPanePosition) if self.settings.mainWindowWidth: width = self.settings.mainWindowWidth if self.settings.mainWindowHeight: height = self.settings.mainWindowHeight self.set_default_size(width, height) if height == -1 and width == -1: self.maximize() self._do_pending_fullscreen = False # FIXME: don't know why this doesn't work #if self.settings.mainWindowFullScreen: # self._do_pending_fullscreen = True # timeline toolbar # FIXME: remove toolbar padding and shadow. In fullscreen mode, the # toolbar buttons should be clickable with the mouse cursor at the # very bottom of the screen. ttb = self.uimanager.get_widget("/TimelineToolBar") vbox.pack_start(ttb, expand=False) ttb.show() self.show() if not self.settings.mainWindowShowMainToolbar: self.toolbar.props.visible = False if not self.settings.mainWindowShowTimelineToolbar: ttb.props.visible = False #application icon self.set_icon_name("pitivi") #pulseaudio 'role' (http://0pointer.de/blog/projects/tagging-audio.htm os.environ["PULSE_PROP_media.role"] = "production" os.environ["PULSE_PROP_application.icon_name"] = "pitivi" def _connectToSourceList(self): self.sourcelist.connect('play', self._sourceListPlayCb) def _launchWizard(self): self._wizard = StartUpWizard(self.app) def _quitWizardCb(self, projectManager, uri = None): if uri.uri != None: self._wizard.quit() def toggleFullScreen(self): """ Toggle the fullscreen mode of the application """ if not self.is_fullscreen: self.viewer.window.fullscreen() self.is_fullscreen = True else: self.viewer.window.unfullscreen() self.is_fullscreen = False #TODO check if it is the way to go def setActionsSensitive(self, action_names, sensitive): """ Permit to get the focus for the keyboard letter keys for other operation as typing text in an entry, or loose it @param action_names: The name of actions we want to set to sensitive or not @type action_names: A {list} of action names @param sensitiive: %True if actions must be sensitive False otherwise @type action_names: C{Bool} """ for action in self.actiongroup.list_actions(): if action.get_name() in action_names: action.set_sensitive(sensitive) if self.timeline: for action_group in self.timeline.ui_manager.get_action_groups(): for action in action_group.list_actions(): if action.get_name() in action_names: action.set_sensitive(sensitive) ## Missing Plugin Support def _installPlugins(self, details, missingPluginsCallback): context = gst.pbutils.InstallPluginsContext() context.set_xid(self.window.xid) res = gst.pbutils.install_plugins_async(details, context, missingPluginsCallback) return res ## UI Callbacks def _configureCb(self, unused_widget, event): if not self.is_fullscreen: self.settings.mainWindowWidth = event.width self.settings.mainWindowHeight = event.height def _deleteCb(self, unused_widget, unused_data=None): self._saveWindowSettings() if not self.app.shutdown(): return True return False def _exposeEventCb(self, unused_widget, event): if self._do_pending_fullscreen: self._fullScreenAlternateCb(None) self._do_pending_fullscreen = False def _saveWindowSettings(self): self.settings.mainWindowFullScreen = self.is_fullscreen self.settings.mainWindowHPanePosition = self.hpaned.get_position() self.settings.mainWindowMainHPanePosition = self.mainhpaned.get_position() self.settings.mainWindowVPanePosition = self.vpaned.get_position() mtb = self.actiongroup.get_action("ShowHideMainToolbar") ttb = self.actiongroup.get_action("ShowHideTimelineToolbar") self.settings.mainWindowShowMainToolbar = mtb.props.active self.settings.mainWindowShowTimelineToolbar = ttb.props.active def _sourceListPlayCb(self, sourcelist, factory): self._viewFactory(factory) ## Toolbar/Menu actions callback def _newProjectMenuCb(self, unused_action): self.app.projectManager.newBlankProject() def _openProjectCb(self, unused_action): self.openProject() def _saveProjectCb(self, unused_action): if not self.project.uri: self._saveProjectAsCb(unused_action) else: self.app.projectManager.saveProject(self.project, overwrite=True) def _saveProjectAsCb(self, unused_action): uri = self._showSaveAsDialog(self.app.current) if uri is not None: return self.app.projectManager.saveProject(self.project, uri, overwrite=True) return False def _revertToSavedProjectCb(self, unused_action): return self.app.projectManager.revertToSavedProject() def _projectSettingsCb(self, unused_action): self.showProjectSettingsDialog() def showProjectSettingsDialog(self): from projectsettings import ProjectSettingsDialog ProjectSettingsDialog(self, self.app.current).show() def _quitCb(self, unused_action): self._saveWindowSettings() self.app.shutdown() def _fullScreenCb(self, unused_action): self.toggleFullScreen() def _fullScreenAlternateCb(self, unused_action): self.actiongroup.get_action("FullScreen").activate() def _showHideMainToolBar(self, action): self.uimanager.get_widget("/MainToolBar").props.visible = \ action.props.active def _showHideTimelineToolbar(self, action): self.uimanager.get_widget("/TimelineToolBar").props.visible = \ action.props.active def _userManualCb(self, unused_action): webbrowser.open_new (APPMANUALURL) def _aboutResponseCb(self, dialog, unused_response): dialog.destroy() def _showWebsiteCb(self, dialog, uri): webbrowser.open_new(uri) def _aboutCb(self, unused_action): abt = gtk.AboutDialog() abt.set_name(APPNAME) abt.set_version("v%s" % pitivi_version) gtk.about_dialog_set_url_hook(self._showWebsiteCb) abt.set_website(APPURL) authors = ["Edward Hervey <*****@*****.**>", "Alessandro Decina <*****@*****.**>", "Brandon Lewis <*****@*****.**> (UI)", "", _("Contributors:"), "Christophe Sauthier <*****@*****.**> (i18n)", "Laszlo Pandy <*****@*****.**> (UI)", "Ernst Persson <*****@*****.**>", "Richard Boulton <*****@*****.**>", "Thibaut Girka <*****@*****.**> (UI)", "Jean-François Fortin Tam <*****@*****.**> (UI)", "Johan Dahlin <*****@*****.**> (UI)", "Luca Della Santina <*****@*****.**>", "Thijs Vermeir <*****@*****.**>", "Sarath Lakshman <*****@*****.**>"] abt.set_authors(authors) abt.set_license(_("GNU Lesser General Public License\n" "See http://www.gnu.org/copyleft/lesser.html for more details")) abt.set_icon_name("pitivi") abt.set_logo_icon_name("pitivi") abt.connect("response", self._aboutResponseCb) abt.show() def openProject(self): chooser = gtk.FileChooserDialog(_("Open File..."), self, action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) chooser.set_icon_name("pitivi") chooser.set_select_multiple(False) chooser.set_current_folder(self.settings.lastProjectFolder) formats = formatter.list_formats() for format in formats: filt = gtk.FileFilter() filt.set_name(format[1]) for ext in format[2]: filt.add_pattern("*%s" % ext) chooser.add_filter(filt) default = gtk.FileFilter() default.set_name(_("All Supported Formats")) default.add_custom(gtk.FILE_FILTER_URI, supported) chooser.add_filter(default) response = chooser.run() self.settings.lastProjectFolder = chooser.get_current_folder() if response == gtk.RESPONSE_OK: uri = chooser.get_uri() uri = unquote(uri) self.app.projectManager.loadProject(uri) chooser.destroy() return True def _undoCb(self, action): self.app.action_log.undo() def _redoCb(self, action): self.app.action_log.redo() def _pluginManagerCb(self, unused_action): from pluginmanagerdialog import PluginManagerDialog PluginManagerDialog(self.app.plugin_manager) # Import from Webcam callback def _ImportWebcam(self,unused_action): from webcam_managerdialog import WebcamManagerDialog w = WebcamManagerDialog(self.app) w.show() # Capture network stream callback def _ImportNetstream(self,unused_action): from netstream_managerdialog import NetstreamManagerDialog NetstreamManagerDialog() # screencast callback def _Screencast(self,unused_action): from screencast_managerdialog import ScreencastManagerDialog ScreencastManagerDialog(self.app) ## Devices changed def _deviceChangeCb(self, probe, unused_device): if len(probe.getVideoSourceDevices()) < 1: self.webcam_button.set_sensitive(False) else: self.webcam_button.set_sensitive(True) def _hideChildWindow(self, window, event): window.hide() return True def _prefsCb(self, unused_action): if not self.prefsdialog: from pitivi.ui.prefs import PreferencesDialog self.prefsdialog = PreferencesDialog(self.app) self.prefsdialog.set_transient_for(self) self.prefsdialog.connect("delete-event", self._hideChildWindow) self.prefsdialog.show() def rewind(self, unused_action): pass def playPause(self, unused_action): self.viewer.togglePlayback() def pause(self, unused_action): self.viewer.pause() def fastForward(self, unused_action): pass def loop(self, unused_action): pass def _projectManagerNewProjectLoadedCb(self, projectManager, project): self.log("A NEW project is loaded, update the UI!") self.project = project self._connectToProjectSources(project.sources) can_render = project.timeline.duration > 0 self.render_button.set_sensitive(can_render) self._syncDoUndo(self.app.action_log) if self._missingUriOnLoading: self.app.current.setModificationState(True) self.actiongroup.get_action("SaveProject").set_sensitive(True) self._missingUriOnLoading = False if project.timeline.duration != 0: self._setBestZoomRatio() else: self._zoom_duration_changed = True self.project.seeker.connect("seek", self._timelineSeekCb) # preliminary seek to ensure the project pipeline is configured self.project.seeker.seek(0) def _setBestZoomRatio(self): ruler_width = self.timeline.ruler.get_allocation()[2] timeline_duration = self.project.timeline.duration ideal_zoom_ratio = ruler_width / float(timeline_duration / gst.SECOND) nearest_zoom_level = Zoomable.computeZoomLevel(ideal_zoom_ratio) Zoomable.setZoomLevel(nearest_zoom_level) def _projectManagerNewProjectLoadingCb(self, projectManager, uri): if uri != None : self.manager.add_item(uri) self.log("A NEW project is being loaded, deactivate UI") def _projectManagerSaveProjectFailedCb(self, projectManager, project, uri, exception): # FIXME: do something here self.error("failed to save project") def _projectManagerProjectSavedCb(self, projectManager, project, uri): self.app.action_log.checkpoint() self._syncDoUndo(self.app.action_log) if project.uri is None: project.uri = uri def _projectManagerClosingProjectCb(self, projectManager, project): if not project.hasUnsavedModifications(): return True if project.uri: save = gtk.STOCK_SAVE else: save = gtk.STOCK_SAVE_AS dialog = gtk.Dialog("", self, gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR, (_("Close without saving"), gtk.RESPONSE_REJECT, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, save, gtk.RESPONSE_YES)) dialog.set_icon_name("pitivi") dialog.set_resizable(False) dialog.set_has_separator(False) dialog.set_default_response(gtk.RESPONSE_YES) primary = gtk.Label() primary.set_line_wrap(True) primary.set_use_markup(True) primary.set_alignment(0, 0.5) message = _("Save changes to the current project before closing?") primary.set_markup("<span weight=\"bold\">" + message + "</span>") secondary = gtk.Label() secondary.set_line_wrap(True) secondary.set_use_markup(True) secondary.set_alignment(0, 0.5) secondary.props.label = _("If you don't save some of your " "changes will be lost") # put the text in a vbox vbox = gtk.VBox(False, 12) vbox.pack_start(primary, expand=True, fill=True) vbox.pack_start(secondary, expand=True, fill=True) # make the [[image] text] hbox image = gtk.image_new_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG) hbox = gtk.HBox(False, 12) hbox.pack_start(image, expand=False) hbox.pack_start(vbox, expand=True, fill=True) action_area = dialog.get_action_area() # FIXME: find out where this "6" comes from. It's needed to align our # hbox with the action area button box hbox.set_border_width(6) # stuff the hbox in the dialog content_area = dialog.get_content_area() content_area.pack_start(hbox, expand=True, fill=True) content_area.set_spacing(14) hbox.show_all() response = dialog.run() dialog.destroy() if response == gtk.RESPONSE_YES: if project.uri is not None: res = self.app.projectManager.saveProject(project, overwrite=True) else: res = self._saveProjectAsCb(None) elif response == gtk.RESPONSE_REJECT: res = True else: res = False return res def _projectManagerProjectClosedCb(self, projectManager, project): # we must disconnect from the project pipeline before it is released self._disconnectFromProjectSources(project.sources) self.viewer.setAction(None) self.viewer.setPipeline(None) project.seeker.disconnect_by_func(self._timelineSeekCb) return False def _projectManagerRevertingToSavedCb(self, projectManager, project): if project.hasUnsavedModifications(): dialog = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_NONE, _("Do you want to reload current project?") ) dialog.set_icon_name("pitivi") dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_NO, gtk.STOCK_REVERT_TO_SAVED, gtk.RESPONSE_YES) dialog.set_title(_("Revert to saved project")) dialog.set_resizable(False) dialog.set_property("secondary-text", _("All unsaved changes will be lost.") ) dialog.set_default_response(gtk.RESPONSE_NO) response = dialog.run() dialog.destroy() if response <> gtk.RESPONSE_YES: return False return True def _projectManagerNewProjectFailedCb(self, projectManager, uri, exception): # ungrey UI dialog = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("PiTiVi is unable to load file \"%s\"") % uri) dialog.set_icon_name("pitivi") dialog.set_title(_("Error Loading File")) dialog.set_property("secondary-text", str(exception)) dialog.run() dialog.destroy() self.set_sensitive(True) def _projectManagerMissingUriCb(self, instance, formatter, uri, factory): dialog = gtk.Dialog(_("Locate missing file..."), self, gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_icon_name("pitivi") dialog.set_border_width(12) dialog.get_content_area().set_spacing(6) text = _("The following file has moved, please tell PiTiVi where to find it.") + \ "\n\n" + beautify_factory(factory) + "\n" + \ "<b>%s</b>" % _("Duration:") + beautify_length(factory.duration) label = gtk.Label() label.set_markup(text) label.set_justify(gtk.JUSTIFY_CENTER) dialog.get_content_area().pack_start(label, False, False) label.show() chooser = gtk.FileChooserWidget(action=gtk.FILE_CHOOSER_ACTION_OPEN) chooser.set_select_multiple(False) chooser.set_current_folder(self.settings.lastProjectFolder) dialog.get_content_area().pack_start(chooser, True, True) chooser.show() dialog.set_size_request(640, 480) response = dialog.run() if response == gtk.RESPONSE_OK: self.log("User chose a URI to save project to") new = chooser.get_uri() if new: formatter.addMapping(uri, unquote(new)) self._missingUriOnLoading = True else: self.log("User didn't choose a URI to save project to") # FIXME: not calling addMapping doesn't keep the formatter from # re-emitting the same signal. How do we get out of this # situation? pass dialog.destroy() def _connectToProjectSources(self, sourcelist): sourcelist.connect("missing-plugins", self._sourceListMissingPluginsCb) def _disconnectFromProjectSources(self, sourcelist): sourcelist.disconnect_by_func(self._sourceListMissingPluginsCb) def _actionLogCommit(self, action_log, stack, nested): if nested: return self._syncDoUndo(action_log) def _actionLogCleaned(self, action_log): self._syncDoUndo(action_log) def _actionLogUndo(self, action_log, stack): self._syncDoUndo(action_log) def _actionLogRedo(self, action_log, stack): self._syncDoUndo(action_log) def _syncDoUndo(self, action_log): undo_action = self.actiongroup.get_action("Undo") can_undo = bool(action_log.undo_stacks) undo_action.set_sensitive(can_undo) dirty = action_log.dirty() save_action = self.actiongroup.get_action("SaveProject") save_action.set_sensitive(dirty) if self.app.current.uri is not None: revert_action = self.actiongroup.get_action("RevertToSavedProject") revert_action.set_sensitive(dirty) self.app.current.setModificationState(dirty) redo_action = self.actiongroup.get_action("Redo") can_redo = bool(action_log.redo_stacks) redo_action.set_sensitive(can_redo) if self.project is not None: app_name = "%s" % (APPNAME) title = u"%s \u2014 %s" % (self.project.name, app_name) if dirty: title = "*" + title title = title.encode("utf8") self.set_title(title) ## PiTiVi current project callbacks def _setProject(self): if self.project: self.project_pipeline = self.project.pipeline self.project_timeline = self.project.timeline if self.timeline: self.timeline.project = self.project self.clipconfig.project = self.project self.app.timelineLogObserver.effect_properties_tracker.pipeline\ = self.project.pipeline project = receiver(_setProject) @handler(project, "settings-changed") def _settingsChangedCb(self, project, old, new): if self.viewer.action == self.project.view_action: self.viewer.setDisplayAspectRatio(float(new.videopar * new.videowidth) / float(new.videoheight)) def _sourceListMissingPluginsCb(self, project, uri, factory, details, descriptions, missingPluginsCallback): res = self._installPlugins(details, missingPluginsCallback) return res ## 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): pass @handler(project_pipeline, "position") def _timelinePipelinePositionChangedCb(self, pipeline, position): self.timeline.timelinePositionChanged(position) self.timelinepos = position @handler(project_pipeline, "state-changed") def _timelinePipelineStateChangedCb(self, pipeline, state): self.timeline.stateChanged(state) ## 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 if self._zoom_duration_changed: self._setBestZoomRatio() self._zoom_duration_changed = False else: sensitive = False self.render_button.set_sensitive(sensitive) ## other def _showSaveAsDialog(self, project): self.log("Save URI requested") chooser = gtk.FileChooserDialog(_("Save As..."), self, action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) chooser.set_icon_name("pitivi") chooser.set_select_multiple(False) chooser.set_current_name(_("Untitled.xptv")) chooser.set_current_folder(self.settings.lastProjectFolder) chooser.props.do_overwrite_confirmation = True formats = formatter.list_formats() for format in formats: filt = gtk.FileFilter() filt.set_name(format[1]) for ext in format[2]: filt.add_pattern("*.%s" % ext) chooser.add_filter(filt) default = gtk.FileFilter() default.set_name(_("Detect Automatically")) default.add_pattern("*") chooser.add_filter(default) response = chooser.run() self.settings.lastProjectFolder = chooser.get_current_folder() if response == gtk.RESPONSE_OK: self.log("User chose a URI to save project to") # need to do this to work around bug in gst.uri_construct # which escapes all /'s in path! uri = "file://" + chooser.get_filename() format = chooser.get_filter().get_name() if format == _("Detect Automatically"): format = None self.log("uri:%s , format:%s", uri, format) ret = uri else: self.log("User didn't choose a URI to save project to") ret = None chooser.destroy() return ret def _viewerDndDataReceivedCb(self, unused_widget, context, unused_x, unused_y, selection, targetType, ctime): # FIXME : This should be handled by the main application who knows how # to switch between pipelines. self.info("context:%s, targetType:%s", context, targetType) if targetType == dnd.TYPE_URI_LIST: uri = selection.data.strip().split("\n")[0].strip() elif targetType == dnd.TYPE_PITIVI_FILESOURCE: uri = selection.data else: context.finish(False, False, ctime) return # Use factory from our source list if we have the given uri try: fact = self.project.sources.getUri(uri) except SourceListError: from pitivi.factories.file import FileSourceFactory fact = FileSourceFactory(uri) self._viewFactory(fact) context.finish(True, False, ctime) def _viewFactory(self, factory): # FIXME: we change the viewer pipeline unconditionally for now # we need a pipeline for playback pipeline = Pipeline() action = ViewAction() action.addProducers(factory) self.viewer.setPipeline(None) self.viewer.showSlider() # FIXME: why do I have to call viewer.setAction ? self.viewer.setAction(action) self.viewer.setPipeline(pipeline) self.viewer.play() def _timelineSeekCb(self, ruler, position, format): self.debug("position:%s", gst.TIME_ARGS (position)) if self.viewer.action != self.project.view_action: self.viewer.setPipeline(None) self.viewer.hideSlider() self.viewer.setAction(self.project.view_action) self.viewer.setPipeline(self.project.pipeline) # get the pipeline settings and set the DAR of the viewer sett = self.project.getSettings() self.viewer.setDisplayAspectRatio(float(sett.videopar * sett.videowidth) / float(sett.videoheight)) # everything above only needs to be done if the viewer isn't already # set to the pipeline. self.project.pipeline.pause() try: self.project.pipeline.seek(position, format) except: self.debug("Seeking failed")
class PitiviMainWindow(gtk.Window, Loggable): """ Pitivi's main window. @cvar app: The application object @type app: L{Application} @cvar project: The current project @type project: L{Project} """ def __init__(self, instance): """ initialize with the Pitivi object """ gtk.Window.__init__(self) Loggable.__init__(self) self.log("Creating MainWindow") self.actions = None self.toggleactions = None self.actiongroup = None self.settings = instance.settings self.is_fullscreen = self.settings.mainWindowFullScreen self.timelinepos = 0 self.prefsdialog = None create_stock_icons() self._setActions(instance) self._createUi(instance) self.app = instance self._zoom_duration_changed = False self.app.projectManager.connect("new-project-loading", self._projectManagerNewProjectLoadingCb) self.app.projectManager.connect("new-project-loaded", self._projectManagerNewProjectLoadedCb) self.app.projectManager.connect("new-project-failed", self._projectManagerNewProjectFailedCb) self.app.projectManager.connect("save-project-failed", self._projectManagerSaveProjectFailedCb) self.app.projectManager.connect("project-saved", self._projectManagerProjectSavedCb) self.app.projectManager.connect("closing-project", self._projectManagerClosingProjectCb) self.app.projectManager.connect("reverting-to-saved", self._projectManagerRevertingToSavedCb) self.app.projectManager.connect("project-closed", self._projectManagerProjectClosedCb) self.app.projectManager.connect("missing-uri", self._projectManagerMissingUriCb) self.app.action_log.connect("commit", self._actionLogCommit) self.app.action_log.connect("undo", self._actionLogUndo) self.app.action_log.connect("redo", self._actionLogRedo) self.app.action_log.connect("cleaned", self._actionLogCleaned) # if no webcams available, hide the webcam action if self.app.deviceprobe is not None: # On Windows disable device probe if platform.system() != 'Windows': self.app.deviceprobe.connect("device-added", self._deviceChangeCb) self.app.deviceprobe.connect("device-removed", self._deviceChangeCb) if len(self.app.deviceprobe.getVideoSourceDevices()) < 1: self.webcam_button.set_sensitive(False) else: self.webcam_button.set_sensitive(False) self.show() def showEncodingDialog(self, project, pause=True): """ Shows the L{EncodingDialog} for the given project Timeline. @param project: The project @type project: L{Project} @param pause: If C{True}, pause the timeline before displaying the dialog. @type pause: C{bool} """ from encodingdialog import EncodingDialog if pause: project.pipeline.pause() win = EncodingDialog(self, project) win.window.connect("destroy", self._encodingDialogDestroyCb) self.set_sensitive(False) win.show() def _encodingDialogDestroyCb(self, unused_dialog): self.set_sensitive(True) def _recordCb(self, unused_button): self.showEncodingDialog(self.project) def _setActions(self, instance): PLAY = _("Start Playback") PAUSE = _("Stop Playback") LOOP = _("Loop over selected area") """ sets up the GtkActions """ self.actions = [ ("NewProject", gtk.STOCK_NEW, None, None, _("Create a new project"), self._newProjectMenuCb), ("OpenProject", gtk.STOCK_OPEN, None, None, _("Open an existing project"), self._openProjectCb), ("SaveProject", gtk.STOCK_SAVE, None, None, _("Save the current project"), self._saveProjectCb), ("SaveProjectAs", gtk.STOCK_SAVE_AS, None, None, _("Save the current project"), self._saveProjectAsCb), ("RevertToSavedProject", gtk.STOCK_REVERT_TO_SAVED, None, None, _("Reload the current project"), self._revertToSavedProjectCb), ("ProjectSettings", gtk.STOCK_PROPERTIES, _("Project Settings"), None, _("Edit the project settings"), self._projectSettingsCb), ("RenderProject", 'pitivi-render' , _("_Render project"), None, _("Render project"), self._recordCb), ("Undo", gtk.STOCK_UNDO, _("_Undo"), "<Ctrl>Z", _("Undo the last operation"), self._undoCb), ("Redo", gtk.STOCK_REDO, _("_Redo"), "<Ctrl>Y", _("Redo the last operation that was undone"), self._redoCb), ("PluginManager", gtk.STOCK_PREFERENCES , _("_Plugins..."), None, _("Manage plugins"), self._pluginManagerCb), ("Preferences", gtk.STOCK_PREFERENCES, _("_Preferences"), None, None, self._prefsCb), ("ImportfromCam", gtk.STOCK_ADD , _("Import from _Webcam..."), None, _("Import Camera stream"), self._ImportWebcam), ("Screencast", gtk.STOCK_ADD , _("_Make screencast..."), None, _("Capture the desktop"), self._Screencast), ("NetstreamCapture", gtk.STOCK_ADD , _("_Capture Network Stream..."), None, _("Capture Network Stream"), self._ImportNetstream), ("Quit", gtk.STOCK_QUIT, None, None, None, self._quitCb), ("About", gtk.STOCK_ABOUT, None, None, _("Information about %s") % APPNAME, self._aboutCb), ("File", None, _("_File")), ("Edit", None, _("_Edit")), ("View", None, _("_View")), ("Library", None, _("_Project")), ("Timeline", None, _("_Timeline")), ("Viewer", None, _("Previe_w")), ("PlayPause", gtk.STOCK_MEDIA_PLAY, None, "space", PLAY, self.playPause), ("Loop", gtk.STOCK_REFRESH, _("Loop"), None, LOOP, self.loop), ("Help", None, _("_Help")), ] self.toggleactions = [ ("FullScreen", gtk.STOCK_FULLSCREEN, None, "f", _("View the main window on the whole screen"), self._fullScreenCb), ("FullScreenAlternate", gtk.STOCK_FULLSCREEN, None, "F11", None, self._fullScreenAlternateCb), ("ShowHideMainToolbar", None, _("Main Toolbar"), None, None, self._showHideMainToolBar, self.settings.mainWindowShowMainToolbar), ("ShowHideTimelineToolbar", None, _("Timeline Toolbar"), None, None, self._showHideTimelineToolbar, self.settings.mainWindowShowTimelineToolbar), ] self.actiongroup = gtk.ActionGroup("mainwindow") self.actiongroup.add_actions(self.actions) self.actiongroup.add_toggle_actions(self.toggleactions) # deactivating non-functional actions # FIXME : reactivate them save_action = self.actiongroup.get_action("SaveProject") save_action.set_sensitive(False) for action in self.actiongroup.list_actions(): action_name = action.get_name() if action_name == "RenderProject": self.render_button = action # this will be set sensitive when the timeline duration changes action.set_sensitive(False) action.props.is_important = True elif action_name == "ImportfromCam": self.webcam_button = action action.set_sensitive(False) elif action_name == "Screencast": # FIXME : re-enable this action once istanbul integration is complete # and upstream istanbul has applied packages for proper interaction. action.set_sensitive(False) action.set_visible(False) elif action_name in [ "ProjectSettings", "Quit", "File", "Edit", "Help", "About", "View", "FullScreen", "FullScreenAlternate", "ImportSourcesFolder", "PluginManager", "PlayPause", "Project", "FrameForward", "FrameBackward", "ShowHideMainToolbar", "ShowHideTimelineToolbar", "Library", "Timeline", "Viewer", "FrameForward", "FrameBackward", "SecondForward", "SecondBackward", "EdgeForward", "EdgeBackward", "Preferences"]: action.set_sensitive(True) elif action_name in ["NewProject", "SaveProjectAs", "OpenProject"]: if instance.settings.fileSupportEnabled: action.set_sensitive(True) elif action_name == "SaveProject": if instance.settings.fileSupportEnabled: action.set_sensitive(True) action.props.is_important = True elif action_name == "Undo": action.set_sensitive(True) action.props.is_important = True else: action.set_sensitive(False) self.uimanager = gtk.UIManager() self.add_accel_group(self.uimanager.get_accel_group()) self.uimanager.insert_action_group(self.actiongroup, 0) if 'pitivi.exe' in __file__.lower(): xml = LIBDIR + '\\pitivi.exe' else: xml = __file__ self.uimanager.add_ui_from_file(os.path.join(os.path.dirname( os.path.abspath(xml)), "mainwindow.xml")) def _createUi(self, instance): """ Create the graphical interface """ self.set_title("%s" % (APPNAME)) self.connect("delete-event", self._deleteCb) self.connect("configure-event", self._configureCb) # main menu & toolbar vbox = gtk.VBox(False) self.add(vbox) vbox.show() self.menu = self.uimanager.get_widget("/MainMenuBar") vbox.pack_start(self.menu, expand=False) self.menu.show() self.toolbar = self.uimanager.get_widget("/MainToolBar") vbox.pack_start(self.toolbar, expand=False) self.toolbar.show() # timeline and project tabs vpaned = gtk.VPaned() vbox.pack_start(vpaned) vpaned.show() self.timeline = Timeline(instance, self.uimanager) self.timeline.project = self.project vpaned.pack2(self.timeline, resize=True, shrink=False) self.timeline.show() self.mainhpaned = gtk.HPaned() vpaned.pack1(self.mainhpaned, resize=True, shrink=False) self.secondhpaned = gtk.HPaned() self.mainhpaned.pack1(self.secondhpaned, resize=True, shrink=False) self.secondhpaned.show() self.mainhpaned.show() self.projecttabs = BaseTabs(instance) self.sourcelist = SourceList(instance, self.uimanager) self.projecttabs.append_page(self.sourcelist, gtk.Label(_("Media Library"))) self._connectToSourceList() self.sourcelist.show() self.effectlist = EffectList(instance, self.uimanager) self.projecttabs.append_page(self.effectlist, gtk.Label(_("Effect Library"))) self.effectlist.show() self.secondhpaned.pack1(self.projecttabs, resize=True, shrink=False) self.projecttabs.show() #Clips properties self.propertiestabs = BaseTabs(instance, True) self.clipconfig = ClipProperties(instance, self.uimanager) self.clipconfig.project = self.project self.propertiestabs.append_page(self.clipconfig, gtk.Label(_("Effects configurations"))) self.clipconfig.show() self.secondhpaned.pack2(self.propertiestabs, resize= True, shrink=False) self.propertiestabs.show() # Viewer self.viewer = PitiviViewer() # drag and drop self.viewer.drag_dest_set(gtk.DEST_DEFAULT_DROP | gtk.DEST_DEFAULT_MOTION, [dnd.FILESOURCE_TUPLE, dnd.URI_TUPLE], gtk.gdk.ACTION_COPY) self.viewer.connect("drag_data_received", self._viewerDndDataReceivedCb) self.mainhpaned.pack2(self.viewer, resize=False, shrink=False) self.viewer.show() self.viewer.connect("expose-event", self._exposeEventCb) # window and pane position defaults self.mainhpaned = self.mainhpaned self.hpaned = self.secondhpaned self.vpaned = vpaned height = -1 width = -1 if self.settings.mainWindowHPanePosition: self.hpaned.set_position(self.settings.mainWindowHPanePosition) if self.settings.mainWindowMainHPanePosition: self.mainhpaned.set_position(self.settings.mainWindowMainHPanePosition) if self.settings.mainWindowVPanePosition: self.vpaned.set_position(self.settings.mainWindowVPanePosition) if self.settings.mainWindowWidth: width = self.settings.mainWindowWidth if self.settings.mainWindowHeight: height = self.settings.mainWindowHeight self.set_default_size(width, height) if height == -1 and width == -1: self.maximize() self._do_pending_fullscreen = False # FIXME: don't know why this doesn't work #if self.settings.mainWindowFullScreen: # self._do_pending_fullscreen = True # timeline toolbar # FIXME: remove toolbar padding and shadow. In fullscreen mode, the # toolbar buttons should be clickable with the mouse cursor at the # very bottom of the screen. ttb = self.uimanager.get_widget("/TimelineToolBar") vbox.pack_start(ttb, expand=False) ttb.show() self.show() if not self.settings.mainWindowShowMainToolbar: self.toolbar.props.visible = False if not self.settings.mainWindowShowTimelineToolbar: ttb.props.visible = False #application icon self.set_icon_name("pitivi") #pulseaudio 'role' (http://0pointer.de/blog/projects/tagging-audio.htm os.environ["PULSE_PROP_media.role"] = "production" os.environ["PULSE_PROP_application.icon_name"] = "pitivi" def _connectToSourceList(self): self.sourcelist.connect('play', self._sourceListPlayCb) def toggleFullScreen(self): """ Toggle the fullscreen mode of the application """ if not self.is_fullscreen: self.viewer.window.fullscreen() self.is_fullscreen = True else: self.viewer.window.unfullscreen() self.is_fullscreen = False #TODO check if it is the way to go def setActionsSensitive(self, action_names, sensitive): """ Permit to get the focus for the keyboard letter keys for other operation as typing text in an entry, or loose it @param action_names: The name of actions we want to set to sensitive or not @type action_names: A {list} of action names @param sensitiive: %True if actions must be sensitive False otherwise @type action_names: C{Bool} """ for action in self.actiongroup.list_actions(): if action.get_name() in action_names: action.set_sensitive(sensitive) if self.timeline: for action_group in self.timeline.ui_manager.get_action_groups(): for action in action_group.list_actions(): if action.get_name() in action_names: action.set_sensitive(sensitive) ## PlayGround callback def _windowizeViewer(self, button, pane): # FIXME: the viewer can't seem to handle being unparented/reparented pane.remove(self.viewer) window = gtk.Window() window.add(self.viewer) window.connect("destroy", self._reparentViewer, pane) window.resize(200, 200) window.show_all() def _reparentViewer(self, window, pane): window.remove(self.viewer) pane.pack2(self.viewer, resize=False, shrink=False) self.viewer.show() ## Missing Plugin Support def _installPlugins(self, details, missingPluginsCallback): context = gst.pbutils.InstallPluginsContext() context.set_xid(self.window.xid) res = gst.pbutils.install_plugins_async(details, context, missingPluginsCallback) return res ## UI Callbacks def _configureCb(self, unused_widget, event): if not self.is_fullscreen: self.settings.mainWindowWidth = event.width self.settings.mainWindowHeight = event.height def _deleteCb(self, unused_widget, unused_data=None): self._saveWindowSettings() if not self.app.shutdown(): return True return False def _exposeEventCb(self, unused_widget, event): if self._do_pending_fullscreen: self._fullScreenAlternateCb(None) self._do_pending_fullscreen = False def _saveWindowSettings(self): self.settings.mainWindowFullScreen = self.is_fullscreen self.settings.mainWindowHPanePosition = self.hpaned.get_position() self.settings.mainWindowMainHPanePosition = self.mainhpaned.get_position() self.settings.mainWindowVPanePosition = self.vpaned.get_position() mtb = self.actiongroup.get_action("ShowHideMainToolbar") ttb = self.actiongroup.get_action("ShowHideTimelineToolbar") self.settings.mainWindowShowMainToolbar = mtb.props.active self.settings.mainWindowShowTimelineToolbar = ttb.props.active def _sourceListPlayCb(self, sourcelist, factory): self._viewFactory(factory) ## Toolbar/Menu actions callback def _newProjectMenuCb(self, unused_action): self.app.projectManager.newBlankProject() def _openProjectCb(self, unused_action): chooser = gtk.FileChooserDialog(_("Open File..."), self, action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) chooser.set_icon_name("pitivi") chooser.set_select_multiple(False) chooser.set_current_folder(self.settings.lastProjectFolder) formats = formatter.list_formats() for format in formats: filt = gtk.FileFilter() filt.set_name(format[1]) for ext in format[2]: filt.add_pattern("*%s" % ext) chooser.add_filter(filt) default = gtk.FileFilter() default.set_name(_("All Supported Formats")) default.add_custom(gtk.FILE_FILTER_URI, supported) chooser.add_filter(default) response = chooser.run() self.settings.lastProjectFolder = chooser.get_current_folder() if response == gtk.RESPONSE_OK: uri = chooser.get_uri() uri = unquote(uri) self.app.projectManager.loadProject(uri) chooser.destroy() return True def _saveProjectCb(self, unused_action): if not self.project.uri: self._saveProjectAsCb(unused_action) else: self.app.projectManager.saveProject(self.project, overwrite=True) def _saveProjectAsCb(self, unused_action): uri = self._showSaveAsDialog(self.app.current) if uri is not None: return self.app.projectManager.saveProject(self.project, uri, overwrite=True) return False def _revertToSavedProjectCb(self, unused_action): return self.app.projectManager.revertToSavedProject() def _projectSettingsCb(self, unused_action): from projectsettings import ProjectSettingsDialog ProjectSettingsDialog(self, self.app.current).show() def _quitCb(self, unused_action): self._saveWindowSettings() self.app.shutdown() def _fullScreenCb(self, unused_action): self.toggleFullScreen() def _fullScreenAlternateCb(self, unused_action): self.actiongroup.get_action("FullScreen").activate() def _showHideMainToolBar(self, action): self.uimanager.get_widget("/MainToolBar").props.visible = \ action.props.active def _showHideTimelineToolbar(self, action): self.uimanager.get_widget("/TimelineToolBar").props.visible = \ action.props.active def _aboutResponseCb(self, dialog, unused_response): dialog.destroy() def _showWebsiteCb(self, dialog, uri): import webbrowser webbrowser.open_new(uri) def _aboutCb(self, unused_action): abt = gtk.AboutDialog() abt.set_name(APPNAME) abt.set_version("v%s" % pitivi_version) gtk.about_dialog_set_url_hook(self._showWebsiteCb) abt.set_website("http://www.pitivi.org/") authors = ["Edward Hervey <*****@*****.**>", "Alessandro Decina <*****@*****.**>", "Brandon Lewis <*****@*****.**> (UI)", "", _("Contributors:"), "Christophe Sauthier <*****@*****.**> (i18n)", "Laszlo Pandy <*****@*****.**> (UI)", "Ernst Persson <*****@*****.**>", "Richard Boulton <*****@*****.**>", "Thibaut Girka <*****@*****.**> (UI)", "Jeff Fortin <*****@*****.**> (UI)", "Johan Dahlin <*****@*****.**> (UI)", "Luca Della Santina <*****@*****.**>", "Thijs Vermeir <*****@*****.**>", "Sarath Lakshman <*****@*****.**>"] abt.set_authors(authors) abt.set_license(_("GNU Lesser General Public License\n" "See http://www.gnu.org/copyleft/lesser.html for more details")) abt.set_icon_name("pitivi") abt.set_logo_icon_name("pitivi") abt.connect("response", self._aboutResponseCb) abt.show() def _undoCb(self, action): self.app.action_log.undo() def _redoCb(self, action): self.app.action_log.redo() def _pluginManagerCb(self, unused_action): from pluginmanagerdialog import PluginManagerDialog PluginManagerDialog(self.app.plugin_manager) # Import from Webcam callback def _ImportWebcam(self,unused_action): from webcam_managerdialog import WebcamManagerDialog w = WebcamManagerDialog(self.app) w.show() # Capture network stream callback def _ImportNetstream(self,unused_action): from netstream_managerdialog import NetstreamManagerDialog NetstreamManagerDialog() # screencast callback def _Screencast(self,unused_action): from screencast_managerdialog import ScreencastManagerDialog ScreencastManagerDialog(self.app) ## Devices changed def _deviceChangeCb(self, probe, unused_device): if len(probe.getVideoSourceDevices()) < 1: self.webcam_button.set_sensitive(False) else: self.webcam_button.set_sensitive(True) def _hideChildWindow(self, window, event): window.hide() return True def _prefsCb(self, unused_action): if not self.prefsdialog: from pitivi.ui.prefs import PreferencesDialog self.prefsdialog = PreferencesDialog(self.app) self.prefsdialog.set_transient_for(self) self.prefsdialog.connect("delete-event", self._hideChildWindow) self.prefsdialog.show() def rewind(self, unused_action): pass def playPause(self, unused_action): self.viewer.togglePlayback() def pause(self, unused_action): self.viewer.pause() def fastForward(self, unused_action): pass def loop(self, unused_action): pass def _projectManagerNewProjectLoadedCb(self, projectManager, project): self.log("A NEW project is loaded, update the UI!") self.project = project self._connectToProjectSources(project.sources) can_render = project.timeline.duration > 0 self.render_button.set_sensitive(can_render) self._syncDoUndo(self.app.action_log) if project.timeline.duration != 0: self._setBestZoomRatio() else: self._zoom_duration_changed = True self.project.seeker.connect("seek", self._timelineSeekCb) # preliminary seek to ensure the project pipeline is configured self.project.seeker.seek(0) def _setBestZoomRatio(self): ruler_width = self.timeline.ruler.get_allocation()[2] timeline_duration = self.project.timeline.duration ideal_zoom_ratio = ruler_width / float(timeline_duration / gst.SECOND) nearest_zoom_level = Zoomable.computeZoomLevel(ideal_zoom_ratio) Zoomable.setZoomLevel(nearest_zoom_level) def _projectManagerNewProjectLoadingCb(self, projectManager, uri): self.log("A NEW project is being loaded, deactivate UI") def _projectManagerSaveProjectFailedCb(self, projectManager, project, uri, exception): # FIXME: do something here self.error("failed to save project") def _projectManagerProjectSavedCb(self, projectManager, project, uri): self.app.action_log.checkpoint() self._syncDoUndo(self.app.action_log) if project.uri is None: project.uri = uri def _projectManagerClosingProjectCb(self, projectManager, project): if not project.hasUnsavedModifications(): return True if project.uri: save = gtk.STOCK_SAVE else: save = gtk.STOCK_SAVE_AS dialog = gtk.Dialog("", self, gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR, (_("Close without saving"), gtk.RESPONSE_REJECT, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, save, gtk.RESPONSE_YES)) dialog.set_icon_name("pitivi") dialog.set_resizable(False) dialog.set_has_separator(False) dialog.set_default_response(gtk.RESPONSE_YES) primary = gtk.Label() primary.set_line_wrap(True) primary.set_use_markup(True) primary.set_alignment(0, 0.5) message = _("Save changes to the current project before closing?") primary.set_markup("<span weight=\"bold\">" + message + "</span>") secondary = gtk.Label() secondary.set_line_wrap(True) secondary.set_use_markup(True) secondary.set_alignment(0, 0.5) secondary.props.label = _("If you don't save some of your " "changes will be lost") # put the text in a vbox vbox = gtk.VBox(False, 12) vbox.pack_start(primary, expand=True, fill=True) vbox.pack_start(secondary, expand=True, fill=True) # make the [[image] text] hbox image = gtk.image_new_from_stock(gtk.STOCK_DIALOG_WARNING, gtk.ICON_SIZE_DIALOG) hbox = gtk.HBox(False, 12) hbox.pack_start(image, expand=False) hbox.pack_start(vbox, expand=True, fill=True) action_area = dialog.get_action_area() # FIXME: find out where this "6" comes from. It's needed to align our # hbox with the action area button box hbox.set_border_width(6) # stuff the hbox in the dialog content_area = dialog.get_content_area() content_area.pack_start(hbox, expand=True, fill=True) content_area.set_spacing(14) hbox.show_all() response = dialog.run() dialog.destroy() if response == gtk.RESPONSE_YES: if project.uri is not None: res = self.app.projectManager.saveProject(project, overwrite=True) else: res = self._saveProjectAsCb(None) elif response == gtk.RESPONSE_REJECT: res = True else: res = False return res def _projectManagerProjectClosedCb(self, projectManager, project): # we must disconnect from the project pipeline before it is released self._disconnectFromProjectSources(project.sources) self.viewer.setAction(None) self.viewer.setPipeline(None) project.seeker.disconnect_by_func(self._timelineSeekCb) return False def _projectManagerRevertingToSavedCb(self, projectManager, project): if project.hasUnsavedModifications(): dialog = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_WARNING, gtk.BUTTONS_NONE, _("Do you want to reload current project?") ) dialog.set_icon_name("pitivi") dialog.add_buttons(gtk.STOCK_CANCEL, gtk.RESPONSE_NO, gtk.STOCK_REVERT_TO_SAVED, gtk.RESPONSE_YES) dialog.set_title(_("Revert to saved project")) dialog.set_resizable(False) dialog.set_property("secondary-text", _("All unsaved changes will be lost.") ) dialog.set_default_response(gtk.RESPONSE_NO) response = dialog.run() dialog.destroy() if response <> gtk.RESPONSE_YES: return False return True def _projectManagerNewProjectFailedCb(self, projectManager, uri, exception): # ungrey UI dialog = gtk.MessageDialog(self, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, _("PiTiVi is unable to load file \"%s\"") % uri) dialog.set_icon_name("pitivi") dialog.set_title(_("Error Loading File")) dialog.set_property("secondary-text", str(exception)) dialog.run() dialog.destroy() self.set_sensitive(True) def _projectManagerMissingUriCb(self, instance, formatter, uri, factory): dialog = gtk.Dialog(_("Locate missing file..."), self, gtk.DIALOG_MODAL, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) dialog.set_icon_name("pitivi") dialog.set_border_width(12) dialog.get_content_area().set_spacing(6) text = _("The following file has moved, please tell PiTiVi where to find it.") + \ "\n\n" + beautify_factory(factory) + "\n" + \ "<b>%s</b>" % _("Duration:") + beautify_length(factory.duration) label = gtk.Label() label.set_markup(text) label.set_justify(gtk.JUSTIFY_CENTER) dialog.get_content_area().pack_start(label, False, False) label.show() chooser = gtk.FileChooserWidget(action=gtk.FILE_CHOOSER_ACTION_OPEN) chooser.set_select_multiple(False) chooser.set_current_folder(self.settings.lastProjectFolder) dialog.get_content_area().pack_start(chooser, True, True) chooser.show() dialog.set_size_request(640, 480) response = dialog.run() if response == gtk.RESPONSE_OK: self.log("User chose a URI to save project to") new = chooser.get_uri() if new: formatter.addMapping(uri, unquote(new)) else: self.log("User didn't choose a URI to save project to") # FIXME: not calling addMapping doesn't keep the formatter from # re-emitting the same signal. How do we get out of this # situation? pass dialog.destroy() def _connectToProjectSources(self, sourcelist): sourcelist.connect("missing-plugins", self._sourceListMissingPluginsCb) def _disconnectFromProjectSources(self, sourcelist): sourcelist.disconnect_by_func(self._sourceListMissingPluginsCb) def _actionLogCommit(self, action_log, stack, nested): if nested: return self._syncDoUndo(action_log) def _actionLogCleaned(self, action_log): self._syncDoUndo(action_log) def _actionLogUndo(self, action_log, stack): self._syncDoUndo(action_log) def _actionLogRedo(self, action_log, stack): self._syncDoUndo(action_log) def _syncDoUndo(self, action_log): undo_action = self.actiongroup.get_action("Undo") can_undo = bool(action_log.undo_stacks) undo_action.set_sensitive(can_undo) dirty = action_log.dirty() save_action = self.actiongroup.get_action("SaveProject") save_action.set_sensitive(dirty) if self.app.current.uri is not None: revert_action = self.actiongroup.get_action("RevertToSavedProject") revert_action.set_sensitive(dirty) self.app.current.setModificationState(dirty) redo_action = self.actiongroup.get_action("Redo") can_redo = bool(action_log.redo_stacks) redo_action.set_sensitive(can_redo) if self.project is not None: app_name = "%s" % (APPNAME) title = u"%s \u2014 %s" % (self.project.name, app_name) if dirty: title = "*" + title title = title.encode("utf8") self.set_title(title) ## PiTiVi current project callbacks def _setProject(self): if self.project: self.project_pipeline = self.project.pipeline self.project_timeline = self.project.timeline if self.timeline: self.timeline.project = self.project self.clipconfig.project = self.project self.app.timelineLogObserver.effect_properties_tracker.pipeline\ = self.project.pipeline project = receiver(_setProject) @handler(project, "settings-changed") def _settingsChangedCb(self, project, old, new): if self.viewer.action == self.project.view_action: self.viewer.setDisplayAspectRatio(float(new.videopar * new.videowidth) / float(new.videoheight)) def _sourceListMissingPluginsCb(self, project, uri, factory, details, descriptions, missingPluginsCallback): res = self._installPlugins(details, missingPluginsCallback) return res ## 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): pass @handler(project_pipeline, "position") def _timelinePipelinePositionChangedCb(self, pipeline, position): self.timeline.timelinePositionChanged(position) self.timelinepos = position @handler(project_pipeline, "state-changed") def _timelinePipelineStateChangedCb(self, pipeline, state): self.timeline.stateChanged(state) ## 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 if self._zoom_duration_changed: self._setBestZoomRatio() self._zoom_duration_changed = False else: sensitive = False self.render_button.set_sensitive(sensitive) ## other def _showSaveAsDialog(self, project): self.log("Save URI requested") chooser = gtk.FileChooserDialog(_("Save As..."), self, action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) chooser.set_icon_name("pitivi") chooser.set_select_multiple(False) chooser.set_current_name(_("Untitled.xptv")) chooser.set_current_folder(self.settings.lastProjectFolder) chooser.props.do_overwrite_confirmation = True formats = formatter.list_formats() for format in formats: filt = gtk.FileFilter() filt.set_name(format[1]) for ext in format[2]: filt.add_pattern("*.%s" % ext) chooser.add_filter(filt) default = gtk.FileFilter() default.set_name(_("Detect Automatically")) default.add_pattern("*") chooser.add_filter(default) response = chooser.run() self.settings.lastProjectFolder = chooser.get_current_folder() if response == gtk.RESPONSE_OK: self.log("User chose a URI to save project to") # need to do this to work around bug in gst.uri_construct # which escapes all /'s in path! uri = "file://" + chooser.get_filename() format = chooser.get_filter().get_name() if format == _("Detect Automatically"): format = None self.log("uri:%s , format:%s", uri, format) ret = uri else: self.log("User didn't choose a URI to save project to") ret = None chooser.destroy() return ret def _viewerDndDataReceivedCb(self, unused_widget, context, unused_x, unused_y, selection, targetType, ctime): # FIXME : This should be handled by the main application who knows how # to switch between pipelines. self.info("context:%s, targetType:%s", context, targetType) if targetType == dnd.TYPE_URI_LIST: uri = selection.data.strip().split("\n")[0].strip() elif targetType == dnd.TYPE_PITIVI_FILESOURCE: uri = selection.data else: context.finish(False, False, ctime) return # Use factory from our source list if we have the given uri try: fact = self.project.sources.getUri(uri) except SourceListError: from pitivi.factories.file import FileSourceFactory fact = FileSourceFactory(uri) self._viewFactory(fact) context.finish(True, False, ctime) def _viewFactory(self, factory): # FIXME: we change the viewer pipeline unconditionally for now # we need a pipeline for playback pipeline = Pipeline() action = ViewAction() action.addProducers(factory) self.viewer.setPipeline(None) self.viewer.showSlider() # FIXME: why do I have to call viewer.setAction ? self.viewer.setAction(action) self.viewer.setPipeline(pipeline) self.viewer.play() def _timelineSeekCb(self, ruler, position, format): self.debug("position:%s", gst.TIME_ARGS (position)) if self.viewer.action != self.project.view_action: self.viewer.setPipeline(None) self.viewer.hideSlider() self.viewer.setAction(self.project.view_action) self.viewer.setPipeline(self.project.pipeline) # get the pipeline settings and set the DAR of the viewer sett = self.project.getSettings() self.viewer.setDisplayAspectRatio(float(sett.videopar * sett.videowidth) / float(sett.videoheight)) # everything above only needs to be done if the viewer isn't already # set to the pipeline. self.project.pipeline.pause() try: self.project.pipeline.seek(position, format) except: self.debug("Seeking failed")