1f5b8ead586e3decebf956aa6223f6057d452cf8
[gc-dialer] / src / util / qwrappers.py
1 #!/usr/bin/env python
2
3 from __future__ import with_statement
4 from __future__ import division
5
6 import logging
7
8 import qt_compat
9 QtCore = qt_compat.QtCore
10 QtGui = qt_compat.import_module("QtGui")
11
12 from util import qui_utils
13 from util import misc as misc_utils
14
15
16 _moduleLogger = logging.getLogger(__name__)
17
18
19 class ApplicationWrapper(object):
20
21         DEFAULT_ORIENTATION = "Default"
22         AUTO_ORIENTATION = "Auto"
23         LANDSCAPE_ORIENTATION = "Landscape"
24         PORTRAIT_ORIENTATION = "Portrait"
25
26         def __init__(self, qapp, constants):
27                 self._constants = constants
28                 self._qapp = qapp
29                 self._clipboard = QtGui.QApplication.clipboard()
30
31                 self._errorLog = qui_utils.QErrorLog()
32                 self._mainWindow = None
33
34                 self._fullscreenAction = QtGui.QAction(None)
35                 self._fullscreenAction.setText("Fullscreen")
36                 self._fullscreenAction.setCheckable(True)
37                 self._fullscreenAction.setShortcut(QtGui.QKeySequence("CTRL+Enter"))
38                 self._fullscreenAction.toggled.connect(self._on_toggle_fullscreen)
39
40                 self._orientation = self.DEFAULT_ORIENTATION
41                 self._orientationAction = QtGui.QAction(None)
42                 self._orientationAction.setText("Next Orientation")
43                 self._orientationAction.setCheckable(True)
44                 self._orientationAction.setShortcut(QtGui.QKeySequence("CTRL+o"))
45                 self._orientationAction.triggered.connect(self._on_next_orientation)
46
47                 self._logAction = QtGui.QAction(None)
48                 self._logAction.setText("Log")
49                 self._logAction.setShortcut(QtGui.QKeySequence("CTRL+l"))
50                 self._logAction.triggered.connect(self._on_log)
51
52                 self._quitAction = QtGui.QAction(None)
53                 self._quitAction.setText("Quit")
54                 self._quitAction.setShortcut(QtGui.QKeySequence("CTRL+q"))
55                 self._quitAction.triggered.connect(self._on_quit)
56
57                 self._aboutAction = QtGui.QAction(None)
58                 self._aboutAction.setText("About")
59                 self._aboutAction.triggered.connect(self._on_about)
60
61                 self._qapp.lastWindowClosed.connect(self._on_app_quit)
62                 self._mainWindow = self._new_main_window()
63                 self._mainWindow.window.destroyed.connect(self._on_child_close)
64
65                 self.load_settings()
66
67                 self._mainWindow.show()
68                 self._idleDelay = QtCore.QTimer()
69                 self._idleDelay.setSingleShot(True)
70                 self._idleDelay.setInterval(0)
71                 self._idleDelay.timeout.connect(self._on_delayed_start)
72                 self._idleDelay.start()
73
74         def load_settings(self):
75                 raise NotImplementedError("Booh")
76
77         def save_settings(self):
78                 raise NotImplementedError("Booh")
79
80         def _new_main_window(self):
81                 raise NotImplementedError("Booh")
82
83         @property
84         def qapp(self):
85                 return self._qapp
86
87         @property
88         def constants(self):
89                 return self._constants
90
91         @property
92         def errorLog(self):
93                 return self._errorLog
94
95         @property
96         def fullscreenAction(self):
97                 return self._fullscreenAction
98
99         @property
100         def orientationAction(self):
101                 return self._orientationAction
102
103         @property
104         def orientation(self):
105                 return self._orientation
106
107         @property
108         def logAction(self):
109                 return self._logAction
110
111         @property
112         def aboutAction(self):
113                 return self._aboutAction
114
115         @property
116         def quitAction(self):
117                 return self._quitAction
118
119         @classmethod
120         def _next_orientation(cls, current):
121                 return {
122                         cls.DEFAULT_ORIENTATION: cls.AUTO_ORIENTATION,
123                         cls.AUTO_ORIENTATION: cls.LANDSCAPE_ORIENTATION,
124                         cls.LANDSCAPE_ORIENTATION: cls.PORTRAIT_ORIENTATION,
125                         cls.PORTRAIT_ORIENTATION: cls.DEFAULT_ORIENTATION,
126                 }[current]
127
128         def _close_windows(self):
129                 if self._mainWindow is not None:
130                         self.save_settings()
131                         self._mainWindow.window.destroyed.disconnect(self._on_child_close)
132                         self._mainWindow.close()
133                         self._mainWindow = None
134
135         @misc_utils.log_exception(_moduleLogger)
136         def _on_delayed_start(self):
137                 self._mainWindow.start()
138
139         @misc_utils.log_exception(_moduleLogger)
140         def _on_app_quit(self, checked = False):
141                 if self._mainWindow is not None:
142                         self.save_settings()
143                         self._mainWindow.destroy()
144
145         @misc_utils.log_exception(_moduleLogger)
146         def _on_child_close(self, obj = None):
147                 if self._mainWindow is not None:
148                         self.save_settings()
149                         self._mainWindow = None
150
151         @misc_utils.log_exception(_moduleLogger)
152         def _on_toggle_fullscreen(self, checked = False):
153                 with qui_utils.notify_error(self._errorLog):
154                         self._mainWindow.set_fullscreen(checked)
155
156         @misc_utils.log_exception(_moduleLogger)
157         def _on_next_orientation(self, checked = False):
158                 with qui_utils.notify_error(self._errorLog):
159                         self._orientation = self._next_orientation(self._orientation)
160                         self._mainWindow.update_orientation(self._orientation)
161
162         @misc_utils.log_exception(_moduleLogger)
163         def _on_about(self, checked = True):
164                 raise NotImplementedError("Booh")
165
166         @misc_utils.log_exception(_moduleLogger)
167         def _on_log(self, checked = False):
168                 with qui_utils.notify_error(self._errorLog):
169                         with open(self._constants._user_logpath_, "r") as f:
170                                 logLines = f.xreadlines()
171                                 log = "".join(logLines)
172                                 self._clipboard.setText(log)
173
174         @misc_utils.log_exception(_moduleLogger)
175         def _on_quit(self, checked = False):
176                 with qui_utils.notify_error(self._errorLog):
177                         self._close_windows()
178
179
180 class WindowWrapper(object):
181
182         def __init__(self, parent, app):
183                 self._app = app
184
185                 self._errorDisplay = qui_utils.ErrorDisplay(self._app.errorLog)
186
187                 self._layout = QtGui.QBoxLayout(QtGui.QBoxLayout.LeftToRight)
188                 self._layout.setContentsMargins(0, 0, 0, 0)
189
190                 self._superLayout = QtGui.QVBoxLayout()
191                 self._superLayout.addWidget(self._errorDisplay.toplevel)
192                 self._superLayout.setContentsMargins(0, 0, 0, 0)
193                 self._superLayout.addLayout(self._layout)
194
195                 centralWidget = QtGui.QWidget()
196                 centralWidget.setLayout(self._superLayout)
197                 centralWidget.setContentsMargins(0, 0, 0, 0)
198
199                 self._window = qui_utils.QSignalingMainWindow(parent)
200                 self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
201                 qui_utils.set_stackable(self._window, True)
202                 self._window.setCentralWidget(centralWidget)
203
204                 self._closeWindowAction = QtGui.QAction(None)
205                 self._closeWindowAction.setText("Close")
206                 self._closeWindowAction.setShortcut(QtGui.QKeySequence("CTRL+w"))
207                 self._closeWindowAction.triggered.connect(self._on_close_window)
208
209                 self._window.addAction(self._closeWindowAction)
210                 self._window.addAction(self._app.quitAction)
211                 self._window.addAction(self._app.fullscreenAction)
212                 self._window.addAction(self._app.orientationAction)
213                 self._window.addAction(self._app.logAction)
214
215         @property
216         def window(self):
217                 return self._window
218
219         @property
220         def windowOrientation(self):
221                 geom = self._window.size()
222                 if geom.width() <= geom.height():
223                         return QtCore.Qt.Vertical
224                 else:
225                         return QtCore.Qt.Horizontal
226
227         @property
228         def idealWindowOrientation(self):
229                 if self._app.orientation ==  self._app.LANDSCAPE_ORIENTATION:
230                         windowOrientation = QtCore.Qt.Horizontal
231                 elif self._app.orientation ==  self._app.PORTRAIT_ORIENTATION:
232                         windowOrientation = QtCore.Qt.Vertical
233                 else:
234                         windowOrientation = self.windowOrientation
235                 return windowOrientation
236
237         def walk_children(self):
238                 return ()
239
240         def start(self):
241                 pass
242
243         def close(self):
244                 for child in self.walk_children():
245                         child.window.destroyed.disconnect(self._on_child_close)
246                         child.close()
247                 self._window.close()
248
249         def destroy(self):
250                 pass
251
252         def show(self):
253                 self._window.show()
254                 for child in self.walk_children():
255                         child.show()
256                 self.set_fullscreen(self._app.fullscreenAction.isChecked())
257
258         def hide(self):
259                 for child in self.walk_children():
260                         child.hide()
261                 self._window.hide()
262
263         def set_fullscreen(self, isFullscreen):
264                 if self._window.isVisible():
265                         if isFullscreen:
266                                 self._window.showFullScreen()
267                         else:
268                                 self._window.showNormal()
269                 for child in self.walk_children():
270                         child.set_fullscreen(isFullscreen)
271
272         def update_orientation(self, orientation):
273                 if orientation == self._app.DEFAULT_ORIENTATION:
274                         qui_utils.set_autorient(self.window, False)
275                         qui_utils.set_window_orientation(self.window, None)
276                 elif orientation == self._app.AUTO_ORIENTATION:
277                         qui_utils.set_autorient(self.window, True)
278                         qui_utils.set_window_orientation(self.window, None)
279                 elif orientation == self._app.LANDSCAPE_ORIENTATION:
280                         qui_utils.set_autorient(self.window, False)
281                         qui_utils.set_window_orientation(self.window, QtCore.Qt.Horizontal)
282                 elif orientation == self._app.PORTRAIT_ORIENTATION:
283                         qui_utils.set_autorient(self.window, False)
284                         qui_utils.set_window_orientation(self.window, QtCore.Qt.Vertical)
285                 else:
286                         raise RuntimeError("Unknown orientation: %r" % orientation)
287                 for child in self.walk_children():
288                         child.update_orientation(orientation)
289
290         @misc_utils.log_exception(_moduleLogger)
291         def _on_child_close(self, obj = None):
292                 raise NotImplementedError("Booh")
293
294         @misc_utils.log_exception(_moduleLogger)
295         def _on_close_window(self, checked = True):
296                 with qui_utils.notify_error(self._errorLog):
297                         self.close()
298
299
300 class AutoFreezeWindowFeature(object):
301
302         def __init__(self, app, window):
303                 self._app = app
304                 self._window = window
305                 self._app.qapp.focusChanged.connect(self._on_focus_changed)
306                 if self._app.qapp.focusWidget() is not None:
307                         self._window.setUpdatesEnabled(True)
308                 else:
309                         self._window.setUpdatesEnabled(False)
310
311         def close(self):
312                 self._app.qapp.focusChanged.disconnect(self._on_focus_changed)
313                 self._window.setUpdatesEnabled(True)
314
315         @misc_utils.log_exception(_moduleLogger)
316         def _on_focus_changed(self, oldWindow, newWindow):
317                 with qui_utils.notify_error(self._app.errorLog):
318                         if oldWindow is None and newWindow is not None:
319                                 self._window.setUpdatesEnabled(True)
320                         elif oldWindow is not None and newWindow is None:
321                                 self._window.setUpdatesEnabled(False)