OpenShot Video Editor  2.0.0
preferences.py
Go to the documentation of this file.
1 ##
2 #
3 # @file
4 # @brief This file loads the Preferences dialog (i.e where is all preferences)
5 # @author Jonathan Thomas <jonathan@openshot.org>
6 # @author Olivier Girard <olivier@openshot.org>
7 #
8 # @section LICENSE
9 #
10 # Copyright (c) 2008-2018 OpenShot Studios, LLC
11 # (http://www.openshotstudios.com). This file is part of
12 # OpenShot Video Editor (http://www.openshot.org), an open-source project
13 # dedicated to delivering high quality video editing and animation solutions
14 # to the world.
15 #
16 # OpenShot Video Editor is free software: you can redistribute it and/or modify
17 # it under the terms of the GNU General Public License as published by
18 # the Free Software Foundation, either version 3 of the License, or
19 # (at your option) any later version.
20 #
21 # OpenShot Video Editor is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 # GNU General Public License for more details.
25 #
26 # You should have received a copy of the GNU General Public License
27 # along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
28 #
29 
30 import os
31 import operator
32 import functools
33 
34 from PyQt5.QtCore import *
35 from PyQt5.QtWidgets import *
36 from PyQt5.QtGui import QKeySequence
37 from PyQt5 import uic
38 
39 from classes import info, ui_util, settings, qt_types, updates
40 from classes.app import get_app
41 from classes.language import get_all_languages
42 from classes.logger import log
43 from classes.metrics import *
44 import openshot
45 
46 
47 ##
48 # Preferences Dialog
49 class Preferences(QDialog):
50 
51  # Path to ui file
52  ui_path = os.path.join(info.PATH, 'windows', 'ui', 'preferences.ui')
53 
54  def __init__(self):
55 
56  # Create dialog class
57  QDialog.__init__(self)
58 
59  # Load UI from designer
60  ui_util.load_ui(self, self.ui_path)
61 
62  # Init UI
63  ui_util.init_ui(self)
64 
65  # get translations
66  app = get_app()
67  _ = app._tr
68 
69  # Get settings
71 
72  # Dynamically load tabs from settings data
73  self.settings_data = settings.get_settings().get_all_settings()
74 
75  # Track metrics
76  track_metric_screen("preferences-screen")
77 
78  # Load all user values
79  self.params = {}
80  for item in self.settings_data:
81  if "setting" in item and "value" in item:
82  self.params[item["setting"]] = item
83 
84  self.requires_restart = False
85  self.category_names = {}
86  self.category_tabs = {}
87  self.category_sort = {}
88 
89  # Loop through settings and find all unique categories
90  for item in self.settings_data:
91  category = item.get("category")
92  setting_type = item.get("type")
93  sort_category = item.get("sort")
94 
95  # Indicate sorted category
96  if sort_category:
97  self.category_sort[category] = sort_category
98 
99  if not setting_type == "hidden":
100  # Load setting
101  if not category in self.category_names:
102  self.category_names[category] = []
103 
104  # Create scrollarea
105  scroll_area = QScrollArea(self)
106  scroll_area.setWidgetResizable(True)
107  scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
108  scroll_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
109 
110  # Create tab widget and layout
111  layout = QVBoxLayout()
112  tabWidget = QWidget(self)
113  tabWidget.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
114  tabWidget.setLayout(layout)
115  scroll_area.setWidget(tabWidget)
116 
117  # Add tab
118  self.tabCategories.addTab(scroll_area, _(category))
119  self.category_tabs[category] = tabWidget
120 
121  # Append translated title
122  item["title_tr"] = _(item.get("title"))
123 
124  # Append settings into correct category
125  self.category_names[category].append(item)
126 
127  # Loop through each category setting, and add them to the tabs
128  for category in self.category_tabs.keys():
129  tabWidget = self.category_tabs[category]
130 
131  # Get list of items in category
132  params = self.category_names[category]
133  if self.category_sort.get(category):
134  # Sort this category by translated title
135  params.sort(key=operator.itemgetter("title_tr"))
136 
137  # Loop through settings for each category
138  for param in params:
139 
140  # Create Label
141  widget = None
142  label = QLabel()
143  label.setText(_(param["title"]))
144  label.setToolTip(_(param["title"]))
145 
146  if param["type"] == "spinner":
147  # create QDoubleSpinBox
148  widget = QDoubleSpinBox()
149  widget.setMinimum(float(param["min"]))
150  widget.setMaximum(float(param["max"]))
151  widget.setValue(float(param["value"]))
152  widget.setSingleStep(1.0)
153  widget.setToolTip(param["title"])
154  widget.valueChanged.connect(functools.partial(self.spinner_value_changed, param))
155 
156  if param["type"] == "spinner-int":
157  # create QDoubleSpinBox
158  widget = QSpinBox()
159  widget.setMinimum(int(param["min"]))
160  widget.setMaximum(int(param["max"]))
161  widget.setValue(int(param["value"]))
162  widget.setSingleStep(1.0)
163  widget.setToolTip(param["title"])
164  widget.valueChanged.connect(functools.partial(self.spinner_value_changed, param))
165 
166  elif param["type"] == "text":
167  # create QLineEdit
168  widget = QLineEdit()
169  widget.setText(_(param["value"]))
170  widget.textChanged.connect(functools.partial(self.text_value_changed, widget, param))
171 
172  elif param["type"] == "bool":
173  # create spinner
174  widget = QCheckBox()
175  if param["value"] == True:
176  widget.setCheckState(Qt.Checked)
177  else:
178  widget.setCheckState(Qt.Unchecked)
179  widget.stateChanged.connect(functools.partial(self.bool_value_changed, widget, param))
180 
181  elif param["type"] == "dropdown":
182 
183  # create spinner
184  widget = QComboBox()
185 
186  # Get values
187  value_list = param["values"]
188  # Overwrite value list (for profile dropdown)
189  if param["setting"] == "default-profile":
190  value_list = []
191  # Loop through profiles
192  for profile_folder in [info.USER_PROFILES_PATH, info.PROFILES_PATH]:
193  for file in os.listdir(profile_folder):
194  # Load Profile and append description
195  profile_path = os.path.join(profile_folder, file)
196  profile = openshot.Profile(profile_path)
197  value_list.append({"name":profile.info.description, "value":profile.info.description})
198  # Sort profile list
199  value_list.sort(key=operator.itemgetter("name"))
200 
201  # Overwrite value list (for language dropdown)
202  if param["setting"] == "default-language":
203  value_list = []
204  # Loop through languages
205  for locale, language, country in get_all_languages():
206  # Load Profile and append description
207  if language:
208  lang_name = "%s (%s)" % (language, locale)
209  value_list.append({"name":lang_name, "value":locale})
210  # Sort profile list
211  value_list.sort(key=operator.itemgetter("name"))
212  # Add Default to top of list
213  value_list.insert(0, {"name":_("Default"), "value":"Default"})
214 
215 
216  # Add normal values
217  box_index = 0
218  for value_item in value_list:
219  k = value_item["name"]
220  v = value_item["value"]
221  # add dropdown item
222  widget.addItem(_(k), v)
223 
224  # select dropdown (if default)
225  if v == param["value"]:
226  widget.setCurrentIndex(box_index)
227  box_index = box_index + 1
228 
229  widget.currentIndexChanged.connect(functools.partial(self.dropdown_index_changed, widget, param))
230 
231 
232  # Add Label and Widget to the form
233  if (widget and label):
234  # Add minimum size
235  label.setMinimumWidth(180);
236  label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
237  widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
238 
239  # Create HBox layout
240  layout_hbox = QHBoxLayout()
241  layout_hbox.addWidget(label)
242  layout_hbox.addWidget(widget)
243 
244  # Add widget to layout
245  tabWidget.layout().addLayout(layout_hbox)
246  elif (label):
247  # Add widget to layout
248  tabWidget.layout().addWidget(label)
249 
250  # Add stretch to bottom of layout
251  tabWidget.layout().addStretch()
252 
253  ##
254  # Check if the app needs to restart
255  def check_for_restart(self, param):
256  if "restart" in param and param["restart"]:
257  self.requires_restart = True
258 
259  def bool_value_changed(self, widget, param, state):
260  # Save setting
261  if state == Qt.Checked:
262  self.s.set(param["setting"], True)
263  else:
264  self.s.set(param["setting"], False)
265 
266  # Trigger specific actions
267  if param["setting"] == "debug-mode":
268  # Update debug setting of timeline
269  log.info("Setting debug-mode to %s" % (state == Qt.Checked))
270  debug_enabled = (state == Qt.Checked)
271 
272  # Enable / Disable logger
273  openshot.ZmqLogger.Instance().Enable(debug_enabled)
274 
275  elif param["setting"] == "enable-auto-save":
276  # Toggle autosave
277  if (state == Qt.Checked):
278  # Start/Restart autosave timer
279  get_app().window.auto_save_timer.start()
280  else:
281  # Stop autosave timer
282  get_app().window.auto_save_timer.stop()
283 
284  elif param["setting"] == "hardware_decode":
285  if (state == Qt.Checked):
286  # Enable hardware decode environment variable
287  os.environ['OS2_DECODE_HW'] = "1"
288  else:
289  # Disable hardware decode environment variable
290  os.environ['OS2_DECODE_HW'] = "0"
291 
292  # Check for restart
293  self.check_for_restart(param)
294 
295  def spinner_value_changed(self, param, value):
296  # Save setting
297  self.s.set(param["setting"], value)
298  log.info(value)
299 
300  if param["setting"] == "autosave-interval":
301  # Update autosave interval (# of minutes)
302  get_app().window.auto_save_timer.setInterval(value * 1000 * 60)
303 
304  # Apply cache settings (if needed)
305  if param["setting"] in ["cache-limit-mb", "cache-scale", "cache-quality"]:
306  get_app().window.InitCacheSettings()
307 
308  # Check for restart
309  self.check_for_restart(param)
310 
311  def text_value_changed(self, widget, param, value=None):
312  try:
313  # Attempt to load value from QTextEdit (i.e. multi-line)
314  if not value:
315  value = widget.toPlainText()
316  except:
317  pass
318 
319  # If this setting is a keyboard mapping, parse it first
320  if param.get("category") == "Keyboard":
321  previous_value = value
322  value = QKeySequence(value).toString()
323  log.info("Parsing keyboard mapping via QKeySequence from %s to %s" % (previous_value, value))
324 
325  # Save setting
326  self.s.set(param["setting"], value)
327  log.info(value)
328 
329  # Check for restart
330  self.check_for_restart(param)
331 
332  def dropdown_index_changed(self, widget, param, index):
333  # Save setting
334  value = widget.itemData(index)
335  self.s.set(param["setting"], value)
336  log.info(value)
337 
338  # Apply cache settings (if needed)
339  if param["setting"] in ["cache-mode", "cache-image-format"]:
340  get_app().window.InitCacheSettings()
341 
342  # Check for restart
343  self.check_for_restart(param)
344 
345  ##
346  # Signal for closing Preferences window
347  def closeEvent(self, event):
348  # Invoke the close button
349  self.reject()
350 
351  def reject(self):
352  # Prompt user to restart openshot (if needed)
353  if self.requires_restart:
354  msg = QMessageBox()
355  _ = get_app()._tr
356  msg.setWindowTitle(_("Restart Required"))
357  msg.setText(_("Please restart OpenShot for all preferences to take effect."))
358  msg.exec_()
359 
360  # Close dialog
361  super(Preferences, self).reject()
def track_metric_screen
Track a GUI screen being shown.
Definition: metrics.py:96
def get_app
Returns the current QApplication instance of OpenShot.
Definition: app.py:55
def check_for_restart
Check if the app needs to restart.
Definition: preferences.py:255
def load_ui
Load a Qt *.ui file, and also load an XML parsed version.
Definition: ui_util.py:66
def closeEvent
Signal for closing Preferences window.
Definition: preferences.py:347
def init_ui
Initialize all child widgets and action of a window or dialog.
Definition: ui_util.py:220
Preferences Dialog.
Definition: preferences.py:49
def get_all_languages
Get all language names and countries packaged with OpenShot.
Definition: language.py:177
def get_settings
Get the current QApplication's settings instance.
Definition: settings.py:44