mainwindow.py 9.93 KB
Newer Older
Edward Hervey's avatar
Edward Hervey committed
1
# -*- coding: utf-8 -*-
2
# Pitivi video editor
Edward Hervey's avatar
Edward Hervey committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16
# Copyright (c) 2005, Edward Hervey <bilboed@bilboed.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the
Hicham HAOUARI's avatar
Hicham HAOUARI committed
17 18
# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301, USA.
19
"""Pitivi's main window."""
Edward Hervey's avatar
Edward Hervey committed
20
import os
Edward Hervey's avatar
Edward Hervey committed
21
from gettext import gettext as _
22
from urllib.parse import unquote
23

24
from gi.repository import Gio
25
from gi.repository import Gtk
26

27
from pitivi.configure import get_pixmap_dir
28 29 30
from pitivi.dialogs.about import AboutDialog
from pitivi.editorperspective import EditorPerspective
from pitivi.greeterperspective import GreeterPerspective
31 32
from pitivi.settings import GlobalSettings
from pitivi.utils.loggable import Loggable
33
from pitivi.utils.misc import show_user_manual
34

35

36
GlobalSettings.addConfigOption('mainWindowX',
37 38
                               section="main-window",
                               key="X", default=0, type_=int)
39
GlobalSettings.addConfigOption('mainWindowY',
40 41
                               section="main-window",
                               key="Y", default=0, type_=int)
42
GlobalSettings.addConfigOption('mainWindowWidth',
43 44
                               section="main-window",
                               key="width", default=-1, type_=int)
45
GlobalSettings.addConfigOption('mainWindowHeight',
46 47
                               section="main-window",
                               key="height", default=-1, type_=int)
48

49 50
GlobalSettings.addConfigSection('export')
GlobalSettings.addConfigOption('lastExportFolder',
51 52 53 54
                               section='export',
                               key="last-export-folder",
                               environment="PITIVI_EXPORT_FOLDER",
                               default=os.path.expanduser("~"))
55

Paul Lange's avatar
Paul Lange committed
56 57
GlobalSettings.addConfigSection("version")
GlobalSettings.addConfigOption('displayCounter',
58 59 60
                               section='version',
                               key='info-displayed-counter',
                               default=0)
Paul Lange's avatar
Paul Lange committed
61
GlobalSettings.addConfigOption('lastCurrentVersion',
62 63 64
                               section='version',
                               key='last-current-version',
                               default='')
65

66

67
class MainWindow(Gtk.ApplicationWindow, Loggable):
68
    """Pitivi's main window.
69

70 71 72
    It manages the UI and handles the switch between different perspectives,
    such as the default GreeterPerspective, and the EditorPerspective.

73
    Attributes:
74
        app (Pitivi): The app.
Edward Hervey's avatar
Edward Hervey committed
75
    """
76

77
    def __init__(self, app):
78
        gtksettings = Gtk.Settings.get_default()
79
        gtksettings.set_property("gtk-application-prefer-dark-theme", True)
80 81 82
        theme = gtksettings.get_property("gtk-theme-name")
        os.environ["GTK_THEME"] = theme + ":dark"

83 84
        # Pulseaudio "role"
        # (http://0pointer.de/blog/projects/tagging-audio.htm)
85 86 87
        os.environ["PULSE_PROP_media.role"] = "production"
        os.environ["PULSE_PROP_application.icon_name"] = "pitivi"

88
        Gtk.IconTheme.get_default().append_search_path(get_pixmap_dir())
89

90 91
        Gtk.ApplicationWindow.__init__(self)
        Loggable.__init__(self)
92

93
        self.log("Creating main window")
94

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
        self.app = app
        self.greeter = GreeterPerspective(app)
        self.editor = EditorPerspective(app)
        self.__perspective = None
        self.help_action = None
        self.about_action = None
        self.main_menu_action = None

        app.project_manager.connect("new-project-loading",
                                    self.__new_project_loading_cb)
        app.project_manager.connect("new-project-failed",
                                    self.__new_project_failed_cb)
        app.project_manager.connect("project-closed", self.__project_closed_cb)

    def setup_ui(self):
        """Sets up the various perspectives's UI."""
        self.log("Setting up the perspectives.")
112

113
        self.set_icon_name("pitivi")
114 115
        self.__check_screen_constraints()
        self.__set_keyboard_shortcuts()
116

117 118
        self.greeter.setup_ui()
        self.editor.setup_ui()
119

120 121
        width = self.app.settings.mainWindowWidth
        height = self.app.settings.mainWindowHeight
122

123 124
        if height == -1 and width == -1:
            self.maximize()
125 126
        else:
            self.set_default_size(width, height)
127
            self.move(self.app.settings.mainWindowX, self.app.settings.mainWindowY)
128

129 130
        self.connect("configure-event", self.__configure_cb)
        self.connect("delete-event", self.__delete_cb)
131

132
    def __check_screen_constraints(self):
133 134 135
        """Measures the approximate minimum size required by the main window.

        Shrinks some widgets to fit better on smaller screen resolutions.
136 137 138 139 140
        """
        # This code works, but keep in mind get_preferred_size's output
        # is only an approximation. As of 2015, GTK still does not have
        # a way, even with client-side decorations, to tell us the exact
        # minimum required dimensions of a window.
141
        min_size, _ = self.get_preferred_size()
142 143
        screen_width = self.get_screen().get_width()
        screen_height = self.get_screen().get_height()
144 145
        self.debug("Minimum UI size is %sx%s", min_size.width, min_size.height)
        self.debug("Screen size is %sx%s", screen_width, screen_height)
146 147 148
        if min_size.width >= 0.9 * screen_width:
            self.medialibrary.activateCompactMode()
            self.viewer.activateCompactMode()
149
            min_size, _ = self.get_preferred_size()
150 151
            self.info("Minimum UI size has been reduced to %sx%s",
                      min_size.width, min_size.height)
152

153
    def __set_keyboard_shortcuts(self):
154
        self.app.shortcuts.register_group("win", _("Project"), position=20)
155 156

        self.help_action = Gio.SimpleAction.new("help", None)
157
        self.help_action.connect("activate", self.__user_manual_cb)
158
        self.add_action(self.help_action)
159
        self.app.shortcuts.add("win.help", ["F1"], _("Help"), group="app")
160

161 162 163 164 165
        self.about_action = Gio.SimpleAction.new("about", None)
        self.about_action.connect("activate", self.__about_cb)
        self.add_action(self.about_action)
        self.app.shortcuts.add("win.about", ["<Primary><Shift>a"],
                               _("About"), group="app")
166

167 168 169 170 171
        self.main_menu_action = Gio.SimpleAction.new("menu-button", None)
        self.main_menu_action.connect("activate", self.__menu_cb)
        self.add_action(self.main_menu_action)
        self.app.shortcuts.add("win.menu-button", ["F10"],
                               _("Show the menu button content"), group="app")
172

173 174 175
    @staticmethod
    def __user_manual_cb(unused_action, unused_param):
        show_user_manual()
176

177 178 179
    def __about_cb(self, unused_action, unused_param):
        about_dialog = AboutDialog(self.app)
        about_dialog.show()
180

181 182 183
    def __menu_cb(self, unused_action, unused_param):
        self.__perspective.menu_button.set_active(
            not self.__perspective.menu_button.get_active())
Edward Hervey's avatar
Edward Hervey committed
184

185
    def __configure_cb(self, unused_widget, unused_event):
186 187
        """Saves the main window position and size."""
        # Takes window manager decorations into account.
188
        position = self.get_position()
189 190
        self.app.settings.mainWindowX = position.root_x
        self.app.settings.mainWindowY = position.root_y
191 192 193

        # Does not include the size of the window manager decorations.
        size = self.get_size()
194 195
        self.app.settings.mainWindowWidth = size.width
        self.app.settings.mainWindowHeight = size.height
196

197 198 199 200
    def __delete_cb(self, unused_widget, unused_data=None):
        self.app.settings.mainWindowHPanePosition = self.editor.secondhpaned.get_position()
        self.app.settings.mainWindowMainHPanePosition = self.editor.mainhpaned.get_position()
        self.app.settings.mainWindowVPanePosition = self.editor.toplevel_widget.get_position()
201

202
        if not self.app.shutdown():
203
            return True
204 205
        return False

206 207
    def __new_project_loading_cb(self, unused_project_manager, unused_project):
        self.show_perspective(self.editor)
208

209
    def __new_project_failed_cb(self, unused_project_manager, uri, reason):
210
        project_filename = unquote(uri.split("/")[-1])
211 212 213 214 215
        dialog = Gtk.MessageDialog(transient_for=self,
                                   modal=True,
                                   message_type=Gtk.MessageType.ERROR,
                                   buttons=Gtk.ButtonsType.OK,
                                   text=_('Unable to load project "%s"') % project_filename)
216
        dialog.set_property("secondary-use-markup", True)
217
        dialog.set_property("secondary-text", unquote(str(reason)))
218
        dialog.set_transient_for(self)
219
        dialog.run()
Edward Hervey's avatar
Edward Hervey committed
220
        dialog.destroy()
221
        self.show_perspective(self.greeter)
222

223 224
    def __project_closed_cb(self, unused_project_manager, unused_project):
        self.show_perspective(self.greeter)
225

226 227 228
    def show_perspective(self, perspective):
        """Displays the specified perspective."""
        if self.__perspective is perspective:
229
            return
230 231 232 233 234 235 236 237 238 239
        if self.__perspective:
            # Remove the current perspective before adding the
            # specified perspective because we can only add one
            # toplevel widget to the main window at a time.
            self.remove(self.__perspective.toplevel_widget)
        self.log("Displaying perspective: %s", type(perspective).__name__)
        self.__perspective = perspective
        self.set_titlebar(perspective.headerbar)
        self.add(perspective.toplevel_widget)
        perspective.refresh()