Example #1
0
    def actionThumbnailView_trigger(self, event):
        log.info("Switch to Thumbnail View")

        # Get settings
        app = get_app()
        s = settings.get_settings()

        # Files
        if app.context_menu_object == "files":
            s.set("file_view", "thumbnail")
            self.tabFiles.layout().removeWidget(self.filesTreeView)
            self.filesTreeView.deleteLater()
            self.filesTreeView = None
            self.filesTreeView = FilesListView(self)
            self.tabFiles.layout().addWidget(self.filesTreeView)

        # Transitions
        elif app.context_menu_object == "transitions":
            s.set("transitions_view", "thumbnail")
            self.tabTransitions.layout().removeWidget(self.transitionsTreeView)
            self.transitionsTreeView.deleteLater()
            self.transitionsTreeView = None
            self.transitionsTreeView = TransitionsListView(self)
            self.tabTransitions.layout().addWidget(self.transitionsTreeView)

        # Effects
        elif app.context_menu_object == "effects":
            s.set("effects_view", "thumbnail")
            self.tabEffects.layout().removeWidget(self.effectsTreeView)
            self.effectsTreeView.deleteLater()
            self.effectsTreeView = None
            self.effectsTreeView = EffectsListView(self)
            self.tabEffects.layout().addWidget(self.effectsTreeView)
Example #2
0
class MainWindow(QMainWindow, updates.UpdateWatcher, updates.UpdateInterface):
    """ This class contains the logic for the main window widget """

    # Path to ui file
    ui_path = os.path.join(info.PATH, 'windows', 'ui', 'main-window.ui')

    # Save window settings on close
    def closeEvent(self, event):
        # Save settings
        self.save_settings()

        # Stop threads
        self.preview_thread.kill()

    def actionNew_trigger(self, event):
        # clear data and start new project
        get_app().project.load("")
        get_app().updates.reset()
        self.filesTreeView.refresh_view()
        log.info("New Project created.")

        # Set Window title
        self.SetWindowTitle()

    def actionAnimatedTitle_trigger(self, event):
        # show dialog
        from windows.animated_title import AnimatedTitle
        win = AnimatedTitle()
        # Run the dialog event loop - blocking interaction on this window during that time
        result = win.exec_()
        if result == QDialog.Accepted:
            log.info('animated title add confirmed')
        else:
            log.info('animated title add cancelled')

    def actionTitle_trigger(self, event):
        # show dialog
        from windows.title_editor import TitleEditor
        win = TitleEditor()
        # Run the dialog event loop - blocking interaction on this window during that time
        result = win.exec_()
        if result == QDialog.Accepted:
            log.info('title editor add confirmed')
        else:
            log.info('title editor add cancelled')

    def actionImportImageSequence_trigger(self, event):
        # show dialog
        from windows.Import_image_seq import ImportImageSeq
        win = ImportImageSeq()
        # Run the dialog event loop - blocking interaction on this window during that time
        result = win.exec_()
        if result == QDialog.Accepted:
            log.info('Import image sequence add confirmed')
        else:
            log.info('Import image sequence add cancelled')

    def actionImportTransition_trigger(self, event):
        # show dialog
        from windows.Import_transitions import ImportTransition
        win = ImportTransition()
        # Run the dialog event loop -blocking interaction on this window during that time
        result = win.exec_()
        if result == QDialog.Accepted:
            log.info('Import transition add confirmed')
        else:
            log.info('Import transition add cancelled')

    def actionImportTitle_trigger(self, event):
        # show dialog
        from windows.Import_titles import ImportTitles
        win = ImportTitles()
        # Run the dialog event loop - blocking interaction on this window during that time
        result = win.exec_()
        if result == QDialog.Accepted:
            log.info('Import title add confirmed')
        else:
            log.info('Import title add cancelled')

    def save_project(self, file_path):
        """ Save a project to a file path, and refresh the screen """
        app = get_app()

        try:
            # Save project to file
            app.project.save(file_path)

            # Set Window title
            self.SetWindowTitle()

            # Load recent projects again
            self.load_recent_menu()

            log.info("Saved project {}".format(file_path))

        except Exception as ex:
            log.error("Couldn't save project {}".format(file_path))

    def open_project(self, file_path):
        """ Open a project from a file path, and refresh the screen """

        app = get_app()

        try:
            if os.path.exists(file_path.encode('UTF-8')):
                # Load project file
                app.project.load(file_path)

                # Set Window title
                self.SetWindowTitle()

                # Reset undo/redo history
                app.updates.reset()

                # Refresh file tree
                self.filesTreeView.refresh_view()

                # Load recent projects again
                self.load_recent_menu()

                log.info("Loaded project {}".format(file_path))

        except Exception as ex:
            log.error("Couldn't save project {}".format(file_path))

    def actionOpen_trigger(self, event):
        app = get_app()
        _ = app._tr
        file_path, file_type = QFileDialog.getOpenFileName(self, _("Open Project..."))

        # Load project file
        self.open_project(file_path)

    def actionSave_trigger(self, event):
        app = get_app()
        _ = app._tr
        # Get current filepath if any, otherwise ask user
        file_path = app.project.current_filepath
        if not file_path:
            file_path, file_type = QFileDialog.getSaveFileName(self, _("Save Project..."))

        if file_path:
            # Save project
            self.save_project(file_path)

    def actionSaveAs_trigger(self, event):
        app = get_app()
        _ = app._tr
        file_path, file_type = QFileDialog.getSaveFileName(self, _("Save Project As..."))
        if file_path:
            # Save project
            self.save_project(file_path)

    def actionImportFiles_trigger(self, event):
        app = get_app()
        _ = app._tr
        files = QFileDialog.getOpenFileNames(self, _("Import File..."))[0]
        for file_path in files:
            self.filesTreeView.add_file(file_path)
            self.filesTreeView.refresh_view()
            log.info("Loaded project {}".format(file_path))

    def actionUploadVideo_trigger(self, event):
        # show window
        from windows.upload_video import UploadVideo
        win = UploadVideo()
        # Run the dialog event loop - blocking interaction on this window during this time
        result = win.exec_()
        if result == QDialog.Accepted:
            log.info('Upload Video add confirmed')
        else:
            log.info('Upload Video add cancelled')

    def actionExportVideo_trigger(self, event):
        # show window
        from windows.export import Export
        win = Export()
        # Run the dialog event loop - blocking interaction on this window during this time
        result = win.exec_()
        if result == QDialog.Accepted:
            log.info('Export Video add confirmed')
        else:
            log.info('Export Video add cancelled')

    def actionUndo_trigger(self, event):
        app = get_app()
        app.updates.undo()

    # log.info(app.project._data)

    def actionRedo_trigger(self, event):
        app = get_app()
        app.updates.redo()

    # log.info(app.project._data)

    def actionPreferences_trigger(self, event):
        # Show dialog
        from windows.preferences import Preferences
        win = Preferences()
        # Run the dialog event loop - blocking interaction on this window during this time
        result = win.exec_()
        if result == QDialog.Accepted:
            log.info('Preferences add confirmed')
        else:
            log.info('Preferences add cancelled')

    def actionFilesShowAll_trigger(self, event):
        self.filesTreeView.refresh_view()

    def actionFilesShowVideo_trigger(self, event):
        self.filesTreeView.refresh_view()

    def actionFilesShowAudio_trigger(self, event):
        self.filesTreeView.refresh_view()

    def actionFilesShowImage_trigger(self, event):
        self.filesTreeView.refresh_view()

    def actionTransitionsShowAll_trigger(self, event):
        self.transitionsTreeView.refresh_view()

    def actionTransitionsShowCommon_trigger(self, event):
        self.transitionsTreeView.refresh_view()

    def actionEffectsShowAll_trigger(self, event):
        self.effectsTreeView.refresh_view()

    def actionEffectsShowVideo_trigger(self, event):
        self.effectsTreeView.refresh_view()

    def actionEffectsShowAudio_trigger(self, event):
        self.effectsTreeView.refresh_view()

    def actionHelpContents_trigger(self, event):
        try:
            webbrowser.open("http://openshotusers.com/")
            log.info("Help Contents is open")
        except:
            QMessageBox.information(self, "Error !",
                                    "Unable to open the Help Contents. Please ensure the openshot-doc package is installed.")
            log.info("Unable to open the Help Contents")

    def actionAbout_trigger(self, event):
        """Show about dialog"""
        from windows.about import About
        win = About()
        # Run the dialog event loop - blocking interaction on this window during this time
        result = win.exec_()
        if result == QDialog.Accepted:
            log.info('About Openshot add confirmed')
        else:
            log.info('About Openshot add cancelled')

    def actionReportBug_trigger(self, event):
        try:
            webbrowser.open("https://bugs.launchpad.net/openshot/+filebug")
            log.info("Open the Report Bug Launchpad web page with success")
        except:
            QMessageBox.information(self, "Error !", "Unable to open the launchpad web page")
            log.info("Unable to open the Report Bug launchpad web page")

    def actionAskQuestion_trigger(self, event):
        try:
            webbrowser.open("https://answers.launchpad.net/openshot/+addquestion")
            log.info("Open the Question launchpad web page with success")
        except:
            QMessageBox.information(self, "Error !", "Unable to open the Question web page")
            log.info("Unable to open the Question web page")

    def actionTranslate_trigger(self, event):
        try:
            webbrowser.open("https://translations.launchpad.net/openshot")
            log.info("Open the Translate launchpad web page with success")
        except:
            QMessageBox.information(self, "Error !", "Unable to open the Translation web page")
            log.info("Unable to open the Translation web page")

    def actionDonate_trigger(self, event):
        try:
            webbrowser.open("http://openshot.org/donate/")
            log.info("Open the Donate web page with success")
        except:
            QMessageBox.information(self, "Error !", "Unable to open the Donate web page")
            log.info("Unable to open the Donate web page")

    def actionPlay_trigger(self, event, force=None):

        if force == "pause":
            self.actionPlay.setChecked(False)
        elif force == "play":
            self.actionPlay.setChecked(True)

        if self.actionPlay.isChecked():
            ui_util.setup_icon(self, self.actionPlay, "actionPlay", "media-playback-pause")
            self.preview_thread.Play()

        else:
            ui_util.setup_icon(self, self.actionPlay, "actionPlay")  # to default
            self.preview_thread.Pause()

    def actionPreview_File_trigger(self, event):
        """ Preview the selected media file """
        log.info('actionPreview_File_trigger')

        if self.selected_files:
            # Find matching file
            f = File.get(id=self.selected_files[0])
            if f:
                # Get file path
                previewPath = f.data["path"]

                # Load file into player
                self.preview_thread.LoadFile(previewPath)

                # Trigger play button
                self.actionPlay.setChecked(False)
                self.actionPlay.trigger()

    def previewFrame(self, position_seconds, position_frames, time_code):
        """Preview a specific frame"""
        log.info("previewFrame - position_seconds: %s, position_frames: %s, time_code: %s" % (
        position_seconds, position_frames, time_code))

        # Notify preview thread
        self.preview_thread.previewFrame(position_frames)

        # Notify properties dialog
        self.propertyTableView.select_frame(position_frames)

    def movePlayhead(self, position_frames):
        """Update playhead position"""
        log.info(position_frames)

        # Notify preview thread
        self.timeline.movePlayhead(position_frames)

    def actionFastForward_trigger(self, event):

        # Get the video player object
        player = self.preview_thread.player

        if player.Speed() + 1 != 0:
            player.Speed(player.Speed() + 1)
        else:
            player.Speed(player.Speed() + 2)

        if player.Mode() == openshot.PLAYBACK_PAUSED:
            self.actionPlay.trigger()

    def actionRewind_trigger(self, event):

        # Get the video player object
        player = self.preview_thread.player

        if player.Speed() - 1 != 0:
            player.Speed(player.Speed() - 1)
        else:
            player.Speed(player.Speed() - 2)

        if player.Mode() == openshot.PLAYBACK_PAUSED:
            self.actionPlay.trigger()

    def actionJumpStart_trigger(self, event):
        log.info("actionJumpStart_trigger")

        # Seek to the 1st frame
        self.preview_thread.player.Seek(1)

    def actionJumpEnd_trigger(self, event):
        log.info("actionJumpEnd_trigger")

        # Determine max frame (based on clips)
        timeline_length = 0.0
        fps = get_app().window.timeline_sync.timeline.info.fps.ToFloat()
        clips = get_app().window.timeline_sync.timeline.Clips()
        for clip in clips:
            clip_last_frame = clip.Position() + clip.Duration()
            if clip_last_frame > timeline_length:
                # Set max length of timeline
                timeline_length = clip_last_frame

        # Convert to int and round
        timeline_length_int = round(timeline_length * fps) + 1

        # Seek to the 1st frame
        self.preview_thread.player.Seek(timeline_length_int)

    def actionAddTrack_trigger(self, event):
        log.info("actionAddTrack_trigger")

        # Get # of tracks
        track_number = len(get_app().project.get(["layers"]))

        # Look for existing Marker
        track = Track()
        track.data = {"number": track_number, "y": 0}
        track.save()

    def actionAddTrackAbove_trigger(self, event):
        log.info("actionAddTrackAbove_trigger")

        # Get # of tracks
        track_number = len(get_app().project.get(["layers"]))

        # Look for existing Marker
        track = Track()
        track.data = {"number": track_number, "y": 0}
        track.save()

    def actionAddTrackBelow_trigger(self, event):
        log.info("actionAddTrackAbove_trigger")

        # Get # of tracks
        track_number = len(get_app().project.get(["layers"]))

        # Look for existing Marker
        track = Track()
        track.data = {"number": track_number, "y": 0}
        track.save()

    def actionArrowTool_trigger(self, event):
        log.info("actionArrowTool_trigger")

    def actionSnappingTool_trigger(self, event):
        log.info("actionSnappingTool_trigger")
        log.info(self.actionSnappingTool.isChecked())

        # Enable / Disable snapping mode
        self.timeline.SetSnappingMode(self.actionSnappingTool.isChecked())

    def actionAddMarker_trigger(self, event):
        log.info("actionAddMarker_trigger")

        # Get player object
        player = self.preview_thread.player

        # Calculate frames per second
        fps = get_app().project.get(["fps"])
        fps_float = float(fps["num"]) / float(fps["den"])

        # Calculate position in seconds
        position = player.Position() / fps_float

        # Look for existing Marker
        marker = Marker()
        marker.data = {"position": position, "icon": "blue.png"}
        marker.save()

    def actionPreviousMarker_trigger(self, event):
        log.info("actionPreviousMarker_trigger")

        # Calculate current position (in seconds)
        fps = get_app().project.get(["fps"])
        fps_float = float(fps["num"]) / float(fps["den"])
        current_position = self.preview_thread.current_frame / fps_float

        # Loop through all markers, and find the closest one to the left
        closest_position = None
        for marker in Marker.filter():
            marker_position = marker.data["position"]

            # Is marker smaller than position?
            if marker_position < current_position:
                # Is marker larger than previous marker
                if closest_position and marker_position > closest_position:
                    # Set a new closest marker
                    closest_position = marker_position
                elif not closest_position:
                    # First one found
                    closest_position = marker_position

        # Seek to marker position (if any)
        if closest_position:
            # Seek
            frame_to_seek = int(closest_position * fps_float)
            self.preview_thread.player.Seek(frame_to_seek)

    def actionNextMarker_trigger(self, event):
        log.info("actionNextMarker_trigger")
        log.info(self.preview_thread.current_frame)

        # Calculate current position (in seconds)
        fps = get_app().project.get(["fps"])
        fps_float = float(fps["num"]) / float(fps["den"])
        current_position = self.preview_thread.current_frame / fps_float

        # Loop through all markers, and find the closest one to the right
        closest_position = None
        for marker in Marker.filter():
            marker_position = marker.data["position"]

            # Is marker smaller than position?
            if marker_position > current_position:
                # Is marker larger than previous marker
                if closest_position and marker_position < closest_position:
                    # Set a new closest marker
                    closest_position = marker_position
                elif not closest_position:
                    # First one found
                    closest_position = marker_position

        # Seek to marker position (if any)
        if closest_position:
            # Seek
            frame_to_seek = int(closest_position * fps_float)
            self.preview_thread.player.Seek(frame_to_seek)

    def keyPressEvent(self, event):
        """ Add some shortkey for Player """
        self.key = ""

        # Get the video player object
        player = self.preview_thread.player

        log.info("keyPressEvent: player.Position(): %s" % player.Position())

        # Basic shortcuts i.e just a letter
        if event.key() == Qt.Key_Left:
            # Pause video
            self.actionPlay_trigger(event, force="pause")
            # Set speed to 0
            if player.Speed() != 0:
                player.Speed(0)
            # Seek to previous frame
            player.Seek(player.Position() - 1)

            # Notify properties dialog
            self.propertyTableView.select_frame(player.Position())

        elif event.key() == Qt.Key_Right:
            # Pause video
            self.actionPlay_trigger(event, force="pause")
            # Set speed to 0
            if player.Speed() != 0:
                player.Speed(0)
            # Seek to next frame
            player.Seek(player.Position() + 1)

            # Notify properties dialog
            self.propertyTableView.select_frame(player.Position())

        elif event.key() == Qt.Key_Up:
            self.actionPlay.trigger()

        elif event.key() == Qt.Key_Down:
            self.actionPlay.trigger()

        elif event.key() == Qt.Key_C:
            self.actionPlay.trigger()

        elif event.key() == Qt.Key_J:
            self.actionRewind.trigger()
            ui_util.setup_icon(self, self.actionPlay, "actionPlay", "media-playback-pause")
            self.actionPlay.setChecked(True)

        elif event.key() == Qt.Key_K or event.key() == Qt.Key_Space:
            self.actionPlay.trigger()

            # Notify properties dialog
            self.propertyTableView.select_frame(player.Position())

        elif event.key() == Qt.Key_L:
            self.actionFastForward.trigger()
            ui_util.setup_icon(self, self.actionPlay, "actionPlay", "media-playback-pause")
            self.actionPlay.setChecked(True)

        elif event.key() == Qt.Key_M:
            self.actionPlay.trigger()

        elif event.key() == Qt.Key_D:
            # Add the Ctrl key
            if event.modifiers() & Qt.ControlModifier:
                self.actionFastForward.trigger()

        elif event.key() == Qt.Key_End:
            # Add the Ctrl key
            if event.modifiers() & Qt.ControlModifier:
                self.actionFastForward.trigger()

        elif event.key() == Qt.Key_Home:
            # Add the Ctrl key
            if event.modifiers() & Qt.ControlModifier:
                self.actionFastForward.trigger()

        # Bubble event on
        event.ignore()

    def actionProfile_trigger(self, event):
        # Show dialog
        from windows.profile import Profile
        win = Profile()
        # Run the dialog event loop - blocking interaction on this window during this time
        result = win.exec_()
        if result == QDialog.Accepted:
            log.info('Profile add confirmed')

    def actionRemove_from_Project_trigger(self, event):
        log.info("actionRemove_from_Project_trigger")

        # Loop through selected files
        for file_id in self.selected_files:
            # Find matching file
            f = File.get(id=file_id)
            if f:
                # Remove file
                f.delete()

                # Find matching clips (if any)
                clips = Clip.filter(file_id=file_id)
                for c in clips:
                    # Remove clip
                    c.delete()

        # Clear selected files
        self.selected_files = []

    def actionRemoveClip_trigger(self, event):
        log.info('actionRemoveClip_trigger')

        # Loop through selected clips
        for clip_id in self.selected_clips:
            # Find matching file
            clips = Clip.filter(id=clip_id)
            for c in clips:
                # Clear selected clips
                self.removeSelection(clip_id, "clip")

                # Remove clip
                c.delete()

    def actionRemoveEffect_trigger(self, event):
        log.info('actionRemoveEffect_trigger')

        # Loop through selected clips
        for effect_id in self.selected_effects:
            log.info("effect id: %s" % effect_id)

            # Find matching file
            clips = Clip.filter()
            found_effect = None
            for c in clips:
                found_effect = False
                log.info("c.data[effects]: %s" % c.data["effects"])

                for effect in c.data["effects"]:
                    if effect["id"] == effect_id:
                        found_effect = effect
                        break

                if found_effect:
                    # Remove found effect from clip data and save clip
                    c.data["effects"].remove(found_effect)
                    c.save()

                    # Clear selected effects
                    self.removeSelection(effect_id, "effect")

    def actionRemoveTransition_trigger(self, event):
        log.info('actionRemoveTransition_trigger')

        # Loop through selected clips
        for tran_id in self.selected_transitions:
            # Find matching file
            transitions = Transition.filter(id=tran_id)
            for t in transitions:
                # Clear selected clips
                self.removeSelection(tran_id, "transition")

                # Remove transition
                t.delete()

    def actionRemoveTrack_trigger(self, event):
        log.info('actionRemoveTrack_trigger')

        for track_id in self.selected_tracks:
            tracks = Track.filter(id=track_id)
            for t in tracks:
                # Remove track
                t.delete()

    def actionRemoveMarker_trigger(self, event):
        log.info('actionRemoveMarker_trigger')

        for marker_id in self.selected_markers:
            marker = Marker.filter(id=marker_id)
            for m in marker:
                # Remove track
                m.delete()

    def actionTimelineZoomIn_trigger(self, event):
        self.sliderZoom.setValue(self.sliderZoom.value() - self.sliderZoom.singleStep())

    def actionTimelineZoomOut_trigger(self, event):
        self.sliderZoom.setValue(self.sliderZoom.value() + self.sliderZoom.singleStep())

    def actionFullscreen_trigger(self, event):
        # Hide fullscreen button, and display exit fullscreen button
        self.actionFullscreen.setVisible(False)
        self.actionExit_Fullscreen.setVisible(True)

    def actionExit_Fullscreen_trigger(self, event):
        # Hide exit fullscreen button, and display fullscreen button
        self.actionExit_Fullscreen.setVisible(False)
        self.actionFullscreen.setVisible(True)

    def actionDetailsView_trigger(self, event):
        log.info("Switch to Details View")

        # Get settings
        app = get_app()
        s = settings.get_settings()

        # Files
        if app.context_menu_object == "files":
            s.set("file_view", "details")
            self.tabFiles.layout().removeWidget(self.filesTreeView)
            self.filesTreeView.deleteLater()
            self.filesTreeView = None
            self.filesTreeView = FilesTreeView(self)
            self.tabFiles.layout().addWidget(self.filesTreeView)

        # Transitions
        elif app.context_menu_object == "transitions":
            s.set("transitions_view", "details")
            self.tabTransitions.layout().removeWidget(self.transitionsTreeView)
            self.transitionsTreeView.deleteLater()
            self.transitionsTreeView = None
            self.transitionsTreeView = TransitionsTreeView(self)
            self.tabTransitions.layout().addWidget(self.transitionsTreeView)

        # Effects
        elif app.context_menu_object == "effects":
            s.set("effects_view", "details")
            self.tabEffects.layout().removeWidget(self.effectsTreeView)
            self.effectsTreeView.deleteLater()
            self.effectsTreeView = None
            self.effectsTreeView = EffectsTreeView(self)
            self.tabEffects.layout().addWidget(self.effectsTreeView)

    def actionThumbnailView_trigger(self, event):
        log.info("Switch to Thumbnail View")

        # Get settings
        app = get_app()
        s = settings.get_settings()

        # Files
        if app.context_menu_object == "files":
            s.set("file_view", "thumbnail")
            self.tabFiles.layout().removeWidget(self.filesTreeView)
            self.filesTreeView.deleteLater()
            self.filesTreeView = None
            self.filesTreeView = FilesListView(self)
            self.tabFiles.layout().addWidget(self.filesTreeView)

        # Transitions
        elif app.context_menu_object == "transitions":
            s.set("transitions_view", "thumbnail")
            self.tabTransitions.layout().removeWidget(self.transitionsTreeView)
            self.transitionsTreeView.deleteLater()
            self.transitionsTreeView = None
            self.transitionsTreeView = TransitionsListView(self)
            self.tabTransitions.layout().addWidget(self.transitionsTreeView)

        # Effects
        elif app.context_menu_object == "effects":
            s.set("effects_view", "thumbnail")
            self.tabEffects.layout().removeWidget(self.effectsTreeView)
            self.effectsTreeView.deleteLater()
            self.effectsTreeView = None
            self.effectsTreeView = EffectsListView(self)
            self.tabEffects.layout().addWidget(self.effectsTreeView)

    def resize_contents(self):
        if self.filesTreeView:
            self.filesTreeView.resize_contents()

    def getDocks(self):
        """ Get a list of all dockable widgets """
        return [self.dockFiles,
                self.dockTransitions,
                self.dockEffects,
                self.dockVideo,
                self.dockProperties,
                self.dockKeyframe]

    def removeDocks(self):
        """ Remove all dockable widgets on main screen """
        for dock in self.getDocks():
            self.removeDockWidget(dock)

    def addDocks(self, docks, area):
        """ Add all dockable widgets to the same dock area on the main screen """
        for dock in docks:
            self.addDockWidget(area, dock)

    def floatDocks(self, is_floating):
        """ Float or Un-Float all dockable widgets above main screen """
        for dock in self.getDocks():
            dock.setFloating(is_floating)

    def showDocks(self, docks):
        """ Show all dockable widgets on the main screen """
        for dock in docks:
            if get_app().window.dockWidgetArea(dock) != Qt.NoDockWidgetArea:
                # Only show correctly docked widgets
                dock.show()

    def freezeDocks(self):
        """ Freeze all dockable widgets on the main screen (no float, moving, or closing) """
        for dock in self.getDocks():
            dock.setFeatures(QDockWidget.NoDockWidgetFeatures)

    def unFreezeDocks(self):
        """ Un-freeze all dockable widgets on the main screen (allow them to be moved, closed, and floated) """
        for dock in self.getDocks():
            dock.setFeatures(QDockWidget.AllDockWidgetFeatures)

    def hideDocks(self):
        """ Hide all dockable widgets on the main screen """
        for dock in self.getDocks():
            dock.hide()

    def actionSimple_View_trigger(self, event):
        """ Switch to the default / simple view  """
        self.removeDocks()
        self.addDocks([self.dockFiles, self.dockTransitions, self.dockEffects, self.dockVideo], Qt.TopDockWidgetArea)
        self.floatDocks(False)
        self.tabifyDockWidget(self.dockFiles, self.dockTransitions)
        self.tabifyDockWidget(self.dockTransitions, self.dockEffects)
        self.showDocks([self.dockFiles, self.dockTransitions, self.dockEffects, self.dockVideo])

    def actionAdvanced_View_trigger(self, event):
        """ Switch to an alternative view """
        self.removeDocks()

        # Add Docks
        self.addDocks([self.dockFiles, self.dockTransitions, self.dockVideo], Qt.TopDockWidgetArea)
        self.addDocks([self.dockEffects], Qt.RightDockWidgetArea)
        self.addDocks([self.dockProperties, self.dockKeyframe], Qt.LeftDockWidgetArea)
        self.tabifyDockWidget(self.dockProperties, self.dockKeyframe)

        self.floatDocks(False)
        self.showDocks([self.dockFiles, self.dockTransitions, self.dockVideo, self.dockEffects, self.dockProperties,
                        self.dockKeyframe])

    def actionFreeze_View_trigger(self, event):
        """ Freeze all dockable widgets on the main screen """
        self.freezeDocks()
        self.actionFreeze_View.setVisible(False)
        self.actionUn_Freeze_View.setVisible(True)

    def actionUn_Freeze_View_trigger(self, event):
        """ Un-Freeze all dockable widgets on the main screen """
        self.unFreezeDocks()
        self.actionFreeze_View.setVisible(True)
        self.actionUn_Freeze_View.setVisible(False)

    def actionShow_All_trigger(self, event):
        """ Show all dockable widgets """
        self.showDocks(self.getDocks())

    # Init fullscreen menu visibility
    def init_fullscreen_menu(self):
        if self.isFullScreen():
            self.actionFullscreen_trigger(None)
        else:
            self.actionExit_Fullscreen_trigger(None)

    def SetWindowTitle(self, profile=None):
        """ Set the window title based on a variety of factors """

        # Get translation function
        _ = get_app()._tr

        if not profile:
            profile = get_app().project.get(["profile"])

        # Is this a saved project?
        if not get_app().project.current_filepath:
            # Not saved yet
            self.setWindowTitle("%s [%s] - %s" % (_("Untitled Project"), profile, "OpenShot Video Editor"))
        else:
            # Yes, project is saved
            # Get just the filename
            parent_path, filename = os.path.split(get_app().project.current_filepath)
            filename, ext = os.path.splitext(filename)
            filename = filename.replace("_", " ").replace("-", " ").capitalize()
            self.setWindowTitle("%s [%s] - %s" % (filename, profile, "OpenShot Video Editor"))

    # Update undo and redo buttons enabled/disabled to available changes
    def updateStatusChanged(self, undo_status, redo_status):
        self.actionUndo.setEnabled(undo_status)
        self.actionRedo.setEnabled(redo_status)

    # Add to the selected items
    def addSelection(self, item_id, item_type):
        if item_type == "clip" and item_id not in self.selected_clips:
            self.selected_clips.append(item_id)
        elif item_type == "transition" and item_id not in self.selected_transitions:
            self.selected_transitions.append(item_id)
        elif item_type == "effect" and item_id not in self.selected_effects:
            self.selected_effects.append(item_id)

        # Change selected item in properties view
        self.propertyTableView.select_item(item_id, item_type)

    # Remove from the selected items
    def removeSelection(self, item_id, item_type):
        if item_type == "clip" and item_id in self.selected_clips:
            self.selected_clips.remove(item_id)
        elif item_type == "transition" and item_id in self.selected_transitions:
            self.selected_transitions.remove(item_id)
        elif item_type == "effect" and item_id in self.selected_effects:
            self.selected_effects.remove(item_id)

        # Move selection to next selected clip (if any)
        if item_type == "clip" and self.selected_clips:
            self.propertyTableView.select_item(self.selected_clips[0], item_type)
        elif item_type == "transition" and self.selected_transitions:
            self.propertyTableView.select_item(self.selected_transitions[0], item_type)
        elif item_type == "effect" and self.selected_effects:
            self.propertyTableView.select_item(self.selected_effects[0], item_type)
        else:
            # Clear selection in properties view
            self.propertyTableView.select_item("", "")

    # Update window settings in setting store
    def save_settings(self):
        s = settings.get_settings()

        # Save window state and geometry (saves toolbar and dock locations)
        s.set('window_state', qt_types.bytes_to_str(self.saveState()))
        s.set('window_geometry', qt_types.bytes_to_str(self.saveGeometry()))

    # Get window settings from setting store
    def load_settings(self):
        s = settings.get_settings()

        # Window state and geometry (also toolbar and dock locations)
        if s.get('window_geometry'): self.restoreGeometry(qt_types.str_to_bytes(s.get('window_geometry')))
        if s.get('window_state'): self.restoreState(qt_types.str_to_bytes(s.get('window_state')))

        # Load Recent Projects
        self.load_recent_menu()

    def load_recent_menu(self):
        """ Clear and load the list of recent menu items """
        s = settings.get_settings()
        _ = get_app()._tr  # Get translation function

        # Get list of recent projects
        recent_projects = s.get("recent_projects")

        # Add Recent Projects menu (after Open File)
        import functools
        if not self.recent_menu:
            # Create a new recent menu
            self.recent_menu = self.menuFile.addMenu(QIcon.fromTheme("document-open-recent"), _("Recent Projects"))
            self.menuFile.insertMenu(self.actionRecent_Placeholder, self.recent_menu)
        else:
            # Clear the existing children
            self.recent_menu.clear()

        # Add recent projects to menu
        for file_path in reversed(recent_projects):
            new_action = self.recent_menu.addAction(file_path)
            new_action.triggered.connect(functools.partial(self.recent_project_clicked, file_path))

    def recent_project_clicked(self, file_path):
        """ Load a recent project when clicked """

        # Load project file
        self.open_project(file_path)

    def setup_toolbars(self):
        _ = get_app()._tr  # Get translation function

        # Start undo and redo actions disabled
        self.actionUndo.setEnabled(False)
        self.actionRedo.setEnabled(False)

        # Add files toolbar =================================================================================
        self.filesToolbar = QToolBar("Files Toolbar")
        self.filesActionGroup = QActionGroup(self)
        self.filesActionGroup.setExclusive(True)
        self.filesActionGroup.addAction(self.actionFilesShowAll)
        self.filesActionGroup.addAction(self.actionFilesShowVideo)
        self.filesActionGroup.addAction(self.actionFilesShowAudio)
        self.filesActionGroup.addAction(self.actionFilesShowImage)
        self.actionFilesShowAll.setChecked(True)
        self.filesToolbar.addAction(self.actionFilesShowAll)
        self.filesToolbar.addAction(self.actionFilesShowVideo)
        self.filesToolbar.addAction(self.actionFilesShowAudio)
        self.filesToolbar.addAction(self.actionFilesShowImage)
        self.filesFilter = QLineEdit()
        self.filesFilter.setObjectName("filesFilter")
        self.filesFilter.setPlaceholderText(_("Filter"))
        self.filesToolbar.addWidget(self.filesFilter)
        self.actionFilesClear.setEnabled(False)
        self.filesToolbar.addAction(self.actionFilesClear)
        self.tabFiles.layout().addWidget(self.filesToolbar)

        # Add transitions toolbar =================================================================================
        self.transitionsToolbar = QToolBar("Transitions Toolbar")
        self.transitionsActionGroup = QActionGroup(self)
        self.transitionsActionGroup.setExclusive(True)
        self.transitionsActionGroup.addAction(self.actionTransitionsShowAll)
        self.transitionsActionGroup.addAction(self.actionTransitionsShowCommon)
        self.actionTransitionsShowAll.setChecked(True)
        self.transitionsToolbar.addAction(self.actionTransitionsShowAll)
        self.transitionsToolbar.addAction(self.actionTransitionsShowCommon)
        self.transitionsFilter = QLineEdit()
        self.transitionsFilter.setObjectName("transitionsFilter")
        self.transitionsFilter.setPlaceholderText(_("Filter"))
        self.transitionsToolbar.addWidget(self.transitionsFilter)
        self.actionTransitionsClear.setEnabled(False)
        self.transitionsToolbar.addAction(self.actionTransitionsClear)
        self.tabTransitions.layout().addWidget(self.transitionsToolbar)

        # Add effects toolbar =================================================================================
        self.effectsToolbar = QToolBar("Effects Toolbar")
        self.effectsActionGroup = QActionGroup(self)
        self.effectsActionGroup.setExclusive(True)
        self.effectsActionGroup.addAction(self.actionEffectsShowAll)
        self.effectsActionGroup.addAction(self.actionEffectsShowVideo)
        self.effectsActionGroup.addAction(self.actionEffectsShowAudio)
        self.actionEffectsShowAll.setChecked(True)
        self.effectsToolbar.addAction(self.actionEffectsShowAll)
        self.effectsToolbar.addAction(self.actionEffectsShowVideo)
        self.effectsToolbar.addAction(self.actionEffectsShowAudio)
        self.effectsFilter = QLineEdit()
        self.effectsFilter.setObjectName("effectsFilter")
        self.effectsFilter.setPlaceholderText(_("Filter"))
        self.effectsToolbar.addWidget(self.effectsFilter)
        self.actionEffectsClear.setEnabled(False)
        self.effectsToolbar.addAction(self.actionEffectsClear)
        self.tabEffects.layout().addWidget(self.effectsToolbar)

        # Add Video Preview toolbar ==========================================================================
        self.videoToolbar = QToolBar("Video Toolbar")

        # Add left spacer
        spacer = QWidget(self)
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.videoToolbar.addWidget(spacer)

        # Playback controls
        self.videoToolbar.addAction(self.actionJumpStart)
        self.videoToolbar.addAction(self.actionRewind)
        self.videoToolbar.addAction(self.actionPlay)
        self.videoToolbar.addAction(self.actionFastForward)
        self.videoToolbar.addAction(self.actionJumpEnd)
        self.actionPlay.setCheckable(True)

        # Add right spacer
        spacer = QWidget(self)
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.videoToolbar.addWidget(spacer)

        self.tabVideo.layout().addWidget(self.videoToolbar)

        # Add Timeline toolbar ================================================================================
        self.timelineToolbar = QToolBar("Timeline Toolbar", self)

        self.timelineToolbar.addAction(self.actionAddTrack)
        self.timelineToolbar.addSeparator()

        # rest of options
        self.timelineToolbar.addAction(self.actionSnappingTool)
        self.timelineToolbar.addSeparator()
        self.timelineToolbar.addAction(self.actionAddMarker)
        self.timelineToolbar.addAction(self.actionPreviousMarker)
        self.timelineToolbar.addAction(self.actionNextMarker)
        self.timelineToolbar.addSeparator()

        # Setup Zoom slider
        self.sliderZoom = QSlider(Qt.Horizontal, self)
        self.sliderZoom.setPageStep(6)
        self.sliderZoom.setRange(8, 200)
        self.sliderZoom.setValue(20)
        self.sliderZoom.setInvertedControls(True)
        # self.sliderZoom.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
        self.sliderZoom.resize(100, 16)

        self.zoomScaleLabel = QLabel(_("{} seconds").format(self.sliderZoom.value()))

        # add zoom widgets
        self.timelineToolbar.addAction(self.actionTimelineZoomIn)
        self.timelineToolbar.addWidget(self.sliderZoom)
        self.timelineToolbar.addAction(self.actionTimelineZoomOut)
        self.timelineToolbar.addWidget(self.zoomScaleLabel)

        # Add timeline toolbar to web frame
        self.frameWeb.addWidget(self.timelineToolbar)

    def __init__(self):

        # Create main window base class
        QMainWindow.__init__(self)

        # set window on app for reference during initialization of children
        get_app().window = self

        # Load UI from designer
        ui_util.load_ui(self, self.ui_path)

        # Load user settings for window
        s = settings.get_settings()
        self.recent_menu = None

        # Init UI
        ui_util.init_ui(self)

        # Setup toolbars that aren't on main window, set initial state of items, etc
        self.setup_toolbars()

        # Add window as watcher to receive undo/redo status updates
        get_app().updates.add_watcher(self)

        # Track the selected file(s)
        self.selected_files = []
        self.selected_clips = []
        self.selected_transitions = []
        self.selected_markers = []
        self.selected_tracks = []
        self.selected_effects = []

        # Init fullscreen menu visibility
        self.init_fullscreen_menu()

        # Setup timeline
        self.timeline = TimelineWebView(self)
        self.frameWeb.layout().addWidget(self.timeline)

        # Set Window title
        self.SetWindowTitle()

        # Setup files tree
        if s.get("file_view") == "details":
            self.filesTreeView = FilesTreeView(self)
        else:
            self.filesTreeView = FilesListView(self)
        self.tabFiles.layout().addWidget(self.filesTreeView)

        # Setup transitions tree
        if s.get("transitions_view") == "details":
            self.transitionsTreeView = TransitionsTreeView(self)
        else:
            self.transitionsTreeView = TransitionsListView(self)
        self.tabTransitions.layout().addWidget(self.transitionsTreeView)

        # Setup effects tree
        if s.get("effects_view") == "details":
            self.effectsTreeView = EffectsTreeView(self)
        else:
            self.effectsTreeView = EffectsListView(self)
        self.tabEffects.layout().addWidget(self.effectsTreeView)

        # Setup properties table
        self.propertyTableView = PropertiesTableView(self)
        self.dockPropertiesContent.layout().addWidget(self.propertyTableView, 3, 1)

        # Setup video preview QWidget
        self.videoPreview = VideoWidget()
        self.tabVideo.layout().insertWidget(0, self.videoPreview)

        # Load window state and geometry
        self.load_settings()

        # Create the timeline sync object (used for previewing timeline)
        self.timeline_sync = TimelineSync()

        # Start the preview thread
        self.preview_parent = PreviewParent()
        self.preview_parent.Init(self, self.timeline_sync.timeline)
        self.preview_thread = self.preview_parent.worker
Example #3
0
    def __init__(self):

        # Create main window base class
        QMainWindow.__init__(self)

        # set window on app for reference during initialization of children
        get_app().window = self

        # Load UI from designer
        ui_util.load_ui(self, self.ui_path)

        # Load user settings for window
        s = settings.get_settings()
        self.recent_menu = None

        # Init UI
        ui_util.init_ui(self)

        # Setup toolbars that aren't on main window, set initial state of items, etc
        self.setup_toolbars()

        # Add window as watcher to receive undo/redo status updates
        get_app().updates.add_watcher(self)

        # Track the selected file(s)
        self.selected_files = []
        self.selected_clips = []
        self.selected_transitions = []
        self.selected_markers = []
        self.selected_tracks = []
        self.selected_effects = []

        # Init fullscreen menu visibility
        self.init_fullscreen_menu()

        # Setup timeline
        self.timeline = TimelineWebView(self)
        self.frameWeb.layout().addWidget(self.timeline)

        # Set Window title
        self.SetWindowTitle()

        # Setup files tree
        if s.get("file_view") == "details":
            self.filesTreeView = FilesTreeView(self)
        else:
            self.filesTreeView = FilesListView(self)
        self.tabFiles.layout().addWidget(self.filesTreeView)

        # Setup transitions tree
        if s.get("transitions_view") == "details":
            self.transitionsTreeView = TransitionsTreeView(self)
        else:
            self.transitionsTreeView = TransitionsListView(self)
        self.tabTransitions.layout().addWidget(self.transitionsTreeView)

        # Setup effects tree
        if s.get("effects_view") == "details":
            self.effectsTreeView = EffectsTreeView(self)
        else:
            self.effectsTreeView = EffectsListView(self)
        self.tabEffects.layout().addWidget(self.effectsTreeView)

        # Setup properties table
        self.propertyTableView = PropertiesTableView(self)
        self.dockPropertiesContent.layout().addWidget(self.propertyTableView, 3, 1)

        # Setup video preview QWidget
        self.videoPreview = VideoWidget()
        self.tabVideo.layout().insertWidget(0, self.videoPreview)

        # Load window state and geometry
        self.load_settings()

        # Create the timeline sync object (used for previewing timeline)
        self.timeline_sync = TimelineSync()

        # Start the preview thread
        self.preview_parent = PreviewParent()
        self.preview_parent.Init(self, self.timeline_sync.timeline)
        self.preview_thread = self.preview_parent.worker