OpenShot Video Editor  2.0.0
ui_util.py
Go to the documentation of this file.
1 ##
2 #
3 # @file
4 # @brief This file contains PyQt help functions, to translate the interface, load icons, and connect signals
5 # @author Noah Figg <eggmunkee@hotmail.com>
6 # @author Jonathan Thomas <jonathan@openshot.org>
7 # @author Olivier Girard <eolinwen@gmail.com>
8 #
9 # @section LICENSE
10 #
11 # Copyright (c) 2008-2018 OpenShot Studios, LLC
12 # (http://www.openshotstudios.com). This file is part of
13 # OpenShot Video Editor (http://www.openshot.org), an open-source project
14 # dedicated to delivering high quality video editing and animation solutions
15 # to the world.
16 #
17 # OpenShot Video Editor is free software: you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation, either version 3 of the License, or
20 # (at your option) any later version.
21 #
22 # OpenShot Video Editor is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 # GNU General Public License for more details.
26 #
27 # You should have received a copy of the GNU General Public License
28 # along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
29 #
30 
31 import os
32 import xml.etree.ElementTree
33 import time
34 
35 from PyQt5.QtCore import QDir, QLocale
36 from PyQt5.QtGui import QIcon
37 from PyQt5.QtWidgets import *
38 from PyQt5 import uic
39 
40 from classes.logger import log
41 from classes import settings
42 
43 DEFAULT_THEME_NAME = "Humanity"
44 
45 
46 ##
47 # Load the current OS theme, or fallback to a default one
48 def load_theme():
49 
51 
52  # If theme not reported by OS
53  if QIcon.themeName() == '' and not s.get("theme") == "No Theme":
54 
55  # Address known Ubuntu bug of not reporting configured theme name, use default ubuntu theme
56  if os.getenv('DESKTOP_SESSION') == 'ubuntu':
57  QIcon.setThemeName('unity-icon-theme')
58 
59  # Windows/Mac use packaged theme
60  else:
61  QIcon.setThemeName(DEFAULT_THEME_NAME)
62 
63 
64 ##
65 # Load a Qt *.ui file, and also load an XML parsed version
66 def load_ui(window, path):
67  # Attempt to load the UI file 5 times
68  # This is a hack, and I'm trying to avoid a really common error which might be a
69  # race condition. [zipimport.ZipImportError: can't decompress data; zlib not available]
70  # This error only happens when cx_Freeze is used, and the app is launched.
71  error = None
72  for attempt in range(1,6):
73  try:
74  # Load ui from configured path
75  uic.loadUi(path, window)
76 
77  # Successfully loaded UI file, so clear any previously encountered errors
78  error = None
79  break
80 
81  except Exception as ex:
82  # Keep track of this error
83  error = ex
84  time.sleep(0.1)
85 
86  # Raise error (if any)
87  if error:
88  raise error
89 
90  # Save xml tree for ui
91  window.uiTree = xml.etree.ElementTree.parse(path)
92 
93 
94 ##
95 # Get a QIcon, and fallback to default theme if OS does not support themes.
96 def get_default_icon(theme_name):
97 
98  # Default path to backup icons
99  start_path = ":/icons/" + DEFAULT_THEME_NAME + "/"
100  icon_path = search_dir(start_path, theme_name)
101  return QIcon(icon_path), icon_path
102 
103 
104 ##
105 # Search for theme name
106 def search_dir(base_path, theme_name):
107 
108  # Search each entry in this directory
109  base_dir = QDir(base_path)
110  for e in base_dir.entryList():
111  # Path to current item
112  path = base_dir.path() + "/" + e
113  base_filename = e.split('.')[0]
114 
115  # If file matches theme name, return
116  if base_filename == theme_name:
117  return path
118 
119  # If this is a directory, search within it
120  dir = QDir(path)
121  if dir.exists():
122  # If found below, return it
123  res = search_dir(path, theme_name)
124  if res:
125  return res
126 
127  # If no match found in dir, return None
128  return None
129 
130 
131 ##
132 # Get either the current theme icon or fallback to default theme (for custom icons). Returns None if none
133 # found or empty name.
134 def get_icon(theme_name):
135 
136  if theme_name:
137  has_icon = QIcon.hasThemeIcon(theme_name)
138  fallback_icon, fallback_path = get_default_icon(theme_name)
139  if has_icon or fallback_icon:
140  return QIcon.fromTheme(theme_name, fallback_icon)
141  return None
142 
143 
144 ##
145 # Using the window xml, set the icon on the given element, or if theme_name passed load that icon.
146 def setup_icon(window, elem, name, theme_name=None):
147 
148  type_filter = 'action'
149  if isinstance(elem, QWidget): # Search for widget with name instead
150  type_filter = 'widget'
151  # Find iconset in tree (if any)
152  iconset = window.uiTree.find('.//' + type_filter + '[@name="' + name + '"]/property[@name="icon"]/iconset')
153  if iconset != None or theme_name: # For some reason "if iconset:" doesn't work the same as "!= None"
154  if not theme_name:
155  theme_name = iconset.get('theme', '')
156  # Get Icon (either current theme or fallback)
157  icon = get_icon(theme_name)
158  if icon:
159  elem.setIcon(icon)
160 
161 
162 ##
163 # Initialize language and icons of the given element
164 def init_element(window, elem):
165 
166  _translate = QApplication.instance().translate
167 
168  name = ''
169  if hasattr(elem, 'objectName'):
170  name = elem.objectName()
171  connect_auto_events(window, elem, name)
172 
173  # Handle generic translatable properties
174  if hasattr(elem, 'setText') and hasattr(elem, 'text') and elem.text() != "":
175  elem.setText(_translate("", elem.text()))
176  if hasattr(elem, 'setToolTip') and hasattr(elem, 'toolTip') and elem.toolTip() != "":
177  elem.setToolTip(_translate("", elem.toolTip()))
178  if hasattr(elem, 'setWindowTitle') and hasattr(elem, 'windowTitle') and elem.windowTitle() != "":
179  elem.setWindowTitle(_translate("", elem.windowTitle()))
180  if hasattr(elem, 'setTitle') and hasattr(elem, 'title') and elem.title() != "":
181  elem.setTitle(_translate("", elem.title()))
182  if hasattr(elem, 'setPlaceholderText') and hasattr(elem, 'placeholderText') and elem.placeholderText() != "":
183  elem.setPlaceholderText(_translate("", elem.placeholderText()))
184  if hasattr(elem, 'setLocale'):
185  elem.setLocale(QLocale().system())
186  # Handle tabs differently
187  if isinstance(elem, QTabWidget):
188  for i in range(elem.count()):
189  elem.setTabText(i, _translate("", elem.tabText(i)))
190  elem.setTabToolTip(i, _translate("", elem.tabToolTip(i)))
191  # Set icon if possible
192  if hasattr(elem, 'setIcon') and name != '': # Has ability to set its icon
193  setup_icon(window, elem, name)
194 
195 
196 ##
197 # Connect any events in a *.ui file with matching Python method names
198 def connect_auto_events(window, elem, name):
199 
200  # If trigger slot available check it
201  if hasattr(elem, 'trigger'):
202  func_name = name + "_trigger"
203  if hasattr(window, func_name) and callable(getattr(window, func_name)):
204  func = getattr(window, func_name)
205  elem.triggered.connect(getattr(window, func_name))
206  if hasattr(elem, 'click'):
207  func_name = name + "_click"
208  if hasattr(window, func_name) and callable(getattr(window, func_name)):
209  func = getattr(window, func_name)
210  elem.clicked.connect(getattr(window, func_name))
211 
212 
213 ##
214 # Initialize all child widgets and action of a window or dialog
215 def init_ui(window):
216  log.info('Initializing UI for {}'.format(window.objectName()))
217 
218  try:
219  # Set locale & window title on the window object
220  if hasattr(window, 'setWindowTitle') and window.windowTitle() != "":
221  _translate = QApplication.instance().translate
222  window.setWindowTitle(_translate("", window.windowTitle()))
223 
224  # Center window
225  center(window)
226 
227  # Loop through all widgets
228  for widget in window.findChildren(QWidget):
229  init_element(window, widget)
230 
231  # Loop through all actions
232  for action in window.findChildren(QAction):
233  init_element(window, action)
234  except:
235  log.info('Failed to initialize an element on {}'.format(window.objectName()))
236 
237 ##
238 # Center a window on the main window
239 def center(window):
240  from classes.app import get_app
241 
242  frameGm = window.frameGeometry()
243  centerPoint = get_app().window.frameGeometry().center()
244  frameGm.moveCenter(centerPoint)
245  window.move(frameGm.topLeft())
246 
247 def transfer_children(from_widget, to_widget):
248  log.info("Transferring children from '{}' to '{}'".format(from_widget.objectName(), to_widget.objectName()))
def get_app
Returns the current QApplication instance of OpenShot.
Definition: app.py:55
def setup_icon
Using the window xml, set the icon on the given element, or if theme_name passed load that icon...
Definition: ui_util.py:146
def connect_auto_events
Connect any events in a *.ui file with matching Python method names.
Definition: ui_util.py:198
def load_theme
Load the current OS theme, or fallback to a default one.
Definition: ui_util.py:48
def init_element
Initialize language and icons of the given element.
Definition: ui_util.py:164
def load_ui
Load a Qt *.ui file, and also load an XML parsed version.
Definition: ui_util.py:66
def search_dir
Search for theme name.
Definition: ui_util.py:106
def transfer_children
Definition: ui_util.py:247
def init_ui
Initialize all child widgets and action of a window or dialog.
Definition: ui_util.py:215
def get_default_icon
Get a QIcon, and fallback to default theme if OS does not support themes.
Definition: ui_util.py:96
def get_icon
Get either the current theme icon or fallback to default theme (for custom icons).
Definition: ui_util.py:134
def center
Center a window on the main window.
Definition: ui_util.py:239
def get_settings
Get the current QApplication's settings instance.
Definition: settings.py:44