4 from __future__ import with_statement
12 from PyQt4 import QtGui
13 from PyQt4 import QtCore
17 from util import misc as misc_utils
20 _moduleLogger = logging.getLogger(__name__)
26 class Dialcentral(object):
29 os.path.dirname(__file__),
30 os.path.join(os.path.dirname(__file__), "../data"),
31 os.path.join(os.path.dirname(__file__), "../lib"),
32 '/usr/share/%s' % constants.__app_name__,
33 '/usr/lib/%s' % constants.__app_name__,
36 def __init__(self, app):
39 self._hiddenCategories = set()
40 self._hiddenUnits = {}
41 self._clipboard = QtGui.QApplication.clipboard()
43 self._mainWindow = None
45 self._fullscreenAction = QtGui.QAction(None)
46 self._fullscreenAction.setText("Fullscreen")
47 self._fullscreenAction.setCheckable(True)
48 self._fullscreenAction.setShortcut(QtGui.QKeySequence("CTRL+Enter"))
49 self._fullscreenAction.toggled.connect(self._on_toggle_fullscreen)
51 self._logAction = QtGui.QAction(None)
52 self._logAction.setText("Log")
53 self._logAction.setShortcut(QtGui.QKeySequence("CTRL+l"))
54 self._logAction.triggered.connect(self._on_log)
56 self._quitAction = QtGui.QAction(None)
57 self._quitAction.setText("Quit")
58 self._quitAction.setShortcut(QtGui.QKeySequence("CTRL+q"))
59 self._quitAction.triggered.connect(self._on_quit)
61 self._app.lastWindowClosed.connect(self._on_app_quit)
64 self._mainWindow = MainWindow(None, self)
65 self._mainWindow.window.destroyed.connect(self._on_child_close)
67 def load_settings(self):
69 with open(constants._user_settings_, "r") as settingsFile:
70 settings = simplejson.load(settingsFile)
72 _moduleLogger.info("No settings")
75 _moduleLogger.info("Settings were corrupt")
78 self._fullscreenAction.setChecked(settings.get("isFullScreen", False))
80 def save_settings(self):
82 "isFullScreen": self._fullscreenAction.isChecked(),
84 with open(constants._user_settings_, "w") as settingsFile:
85 simplejson.dump(settings, settingsFile)
88 def fullscreenAction(self):
89 return self._fullscreenAction
93 return self._logAction
97 return self._quitAction
99 def _close_windows(self):
100 if self._mainWindow is not None:
101 self._mainWindow.window.destroyed.disconnect(self._on_child_close)
102 self._mainWindow.close()
103 self._mainWindow = None
105 @misc_utils.log_exception(_moduleLogger)
106 def _on_app_quit(self, checked = False):
109 @misc_utils.log_exception(_moduleLogger)
110 def _on_child_close(self, obj = None):
111 self._mainWindow = None
113 @misc_utils.log_exception(_moduleLogger)
114 def _on_toggle_fullscreen(self, checked = False):
115 for window in self._walk_children():
116 window.set_fullscreen(checked)
118 @misc_utils.log_exception(_moduleLogger)
119 def _on_log(self, checked = False):
120 with open(constants._user_logpath_, "r") as f:
121 logLines = f.xreadlines()
122 log = "".join(logLines)
123 self._clipboard.setText(log)
125 @misc_utils.log_exception(_moduleLogger)
126 def _on_quit(self, checked = False):
127 self._close_windows()
130 class QErrorDisplay(object):
135 errorIcon = maeqt.get_theme_icon(("dialog-error", "app_install_error", "gtk-dialog-error"))
136 self._severityIcon = errorIcon.pixmap(32, 32)
137 self._severityLabel = QtGui.QLabel()
138 self._severityLabel.setPixmap(self._severityIcon)
140 self._message = QtGui.QLabel()
141 self._message.setText("Boo")
143 closeIcon = maeqt.get_theme_icon(("window-close", "general_close", "gtk-close"))
144 self._closeLabel = QtGui.QPushButton(closeIcon, "")
145 self._closeLabel.clicked.connect(self._on_close)
147 self._controlLayout = QtGui.QHBoxLayout()
148 self._controlLayout.addWidget(self._severityLabel)
149 self._controlLayout.addWidget(self._message)
150 self._controlLayout.addWidget(self._closeLabel)
152 self._topLevelLayout = QtGui.QHBoxLayout()
153 self._topLevelLayout.addLayout(self._controlLayout)
154 self._widget = QtGui.QWidget()
155 self._widget.setLayout(self._topLevelLayout)
162 def push_message(self, message):
163 self._messages.append(message)
164 if 1 == len(self._messages):
165 self._show_message(message)
167 def push_exception(self):
168 userMessage = str(sys.exc_info()[1])
169 _moduleLogger.exception(userMessage)
170 self.push_message(userMessage)
172 def pop_message(self):
173 del self._messages[0]
174 if 0 == len(self._messages):
177 self._message.setText(self._messages[0])
179 def _on_close(self, *args):
182 def _show_message(self, message):
183 self._message.setText(message)
186 def _hide_message(self):
187 self._message.setText("")
191 class CredentialsDialog(object):
194 self._usernameField = QtGui.QLineEdit()
195 self._passwordField = QtGui.QLineEdit()
196 self._passwordField.setEchoMode(QtGui.QLineEdit.PasswordEchoOnEdit)
198 self._credLayout = QtGui.QGridLayout()
199 self._credLayout.addWidget(QtGui.QLabel("Username"), 0, 0)
200 self._credLayout.addWidget(self._usernameField, 0, 1)
201 self._credLayout.addWidget(QtGui.QLabel("Password"), 1, 0)
202 self._credLayout.addWidget(self._passwordField, 1, 1)
204 self._loginButton = QtGui.QPushButton("&Login")
205 self._buttonLayout = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Cancel)
206 self._buttonLayout.addButton(self._loginButton, QtGui.QDialogButtonBox.AcceptRole)
208 self._layout = QtGui.QVBoxLayout()
209 self._layout.addLayout(self._credLayout)
210 self._layout.addLayout(self._buttonLayout)
212 centralWidget = QtGui.QWidget()
213 centralWidget.setLayout(self._layout)
215 self._dialog = QtGui.QDialog()
216 self._dialog.setWindowTitle("Login")
217 self._dialog.setCentralWidget(centralWidget)
218 maeqt.set_autorient(self._dialog, True)
219 self._buttonLayout.accepted.connect(self._dialog.accept)
220 self._buttonLayout.rejected.connect(self._dialog.reject)
222 def run(self, defaultUsername, defaultPassword, parent=None):
223 self._dialog.setParent(parent)
224 self._usernameField.setText(defaultUsername)
225 self._passwordField.setText(defaultPassword)
227 response = self._dialog.exec_()
228 if response == QtGui.QDialog.Accepted:
229 return str(self._usernameField.text()), str(self._passwordField.text())
230 elif response == QtGui.QDialog.Rejected:
231 raise RuntimeError("Login Cancelled")
234 class AccountDialog(object):
237 self._accountNumberLabel = QtGui.QLabel("NUMBER NOT SET")
238 self._clearButton = QtGui.QPushButton("Clear Account")
239 self._clearButton.clicked.connect(self._on_clear)
240 self._doClear = False
242 self._credLayout = QtGui.QGridLayout()
243 self._credLayout.addWidget(QtGui.QLabel("Account"), 0, 0)
244 self._credLayout.addWidget(self._accountNumberLabel, 0, 1)
245 self._credLayout.addWidget(QtGui.QLabel("Callback"), 1, 0)
246 self._credLayout.addWidget(self._clearButton, 2, 1)
248 self._loginButton = QtGui.QPushButton("&Login")
249 self._buttonLayout = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Cancel)
250 self._buttonLayout.addButton(self._loginButton, QtGui.QDialogButtonBox.AcceptRole)
252 self._layout = QtGui.QVBoxLayout()
253 self._layout.addLayout(self._credLayout)
254 self._layout.addLayout(self._buttonLayout)
256 centralWidget = QtGui.QWidget()
257 centralWidget.setLayout(self._layout)
259 self._dialog = QtGui.QDialog()
260 self._dialog.setWindowTitle("Login")
261 self._dialog.setCentralWidget(centralWidget)
262 maeqt.set_autorient(self._dialog, True)
263 self._buttonLayout.accepted.connect(self._dialog.accept)
264 self._buttonLayout.rejected.connect(self._dialog.reject)
270 accountNumber = property(
271 lambda self: str(self._accountNumberLabel.text()),
272 lambda self, num: self._accountNumberLabel.setText(num),
275 def run(self, defaultUsername, defaultPassword, parent=None):
276 self._doClear = False
277 self._dialog.setParent(parent)
278 self._usernameField.setText(defaultUsername)
279 self._passwordField.setText(defaultPassword)
281 response = self._dialog.exec_()
282 if response == QtGui.QDialog.Accepted:
283 return str(self._usernameField.text()), str(self._passwordField.text())
284 elif response == QtGui.QDialog.Rejected:
285 raise RuntimeError("Login Cancelled")
287 def _on_clear(self, checked = False):
289 self._dialog.accept()
292 class MainWindow(object):
300 def __init__(self, parent, app):
301 self._fsContactsPath = os.path.join(constants._data_path_, "contacts")
304 self._errorDisplay = QErrorDisplay()
306 self._tabs = QtGui.QTabWidget()
307 if maeqt.screen_orientation() == QtCore.Qt.Vertical:
308 self._tabs.setTabPosition(QtGui.QTabWidget.South)
310 self._tabs.setTabPosition(QtGui.QTabWidget.West)
312 self._layout = QtGui.QVBoxLayout()
313 self._layout.addWidget(self._errorDisplay.toplevel)
314 self._layout.addWidget(self._tabs)
316 centralWidget = QtGui.QWidget()
317 centralWidget.setLayout(self._layout)
319 self._window = QtGui.QMainWindow(parent)
320 self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
321 maeqt.set_autorient(self._window, True)
322 maeqt.set_stackable(self._window, True)
323 self._window.setWindowTitle("%s" % constants.__pretty_app_name__)
324 self._window.setCentralWidget(centralWidget)
326 self._loginTabAction = QtGui.QAction(None)
327 self._loginTabAction.setText("Login")
328 self._loginTabAction.triggered.connect(self._on_login)
330 self._importTabAction = QtGui.QAction(None)
331 self._importTabAction.setText("Import")
332 self._importTabAction.triggered.connect(self._on_import)
334 self._refreshTabAction = QtGui.QAction(None)
335 self._refreshTabAction.setText("Refresh")
336 self._refreshTabAction.setShortcut(QtGui.QKeySequence("CTRL+r"))
337 self._refreshTabAction.triggered.connect(self._on_refresh)
339 self._closeWindowAction = QtGui.QAction(None)
340 self._closeWindowAction.setText("Close")
341 self._closeWindowAction.setShortcut(QtGui.QKeySequence("CTRL+w"))
342 self._closeWindowAction.triggered.connect(self._on_close_window)
345 fileMenu = self._window.menuBar().addMenu("&File")
346 fileMenu.addAction(self._loginTabAction)
347 fileMenu.addAction(self._refreshTabAction)
349 toolsMenu = self._window.menuBar().addMenu("&Tools")
350 toolsMenu.addAction(self._importTabAction)
352 self._window.addAction(self._closeWindowAction)
353 self._window.addAction(self._app.quitAction)
354 self._window.addAction(self._app.fullscreenAction)
356 fileMenu = self._window.menuBar().addMenu("&File")
357 fileMenu.addAction(self._loginTabAction)
358 fileMenu.addAction(self._refreshTabAction)
359 fileMenu.addAction(self._closeWindowAction)
360 fileMenu.addAction(self._app.quitAction)
362 viewMenu = self._window.menuBar().addMenu("&View")
363 viewMenu.addAction(self._app.fullscreenAction)
365 toolsMenu = self._window.menuBar().addMenu("&Tools")
366 toolsMenu.addAction(self._importTabAction)
368 self._window.addAction(self._app.logAction)
370 self.set_fullscreen(self._app.fullscreenAction.isChecked())
377 def walk_children(self):
382 for child in self.walk_children():
386 for child in self.walk_children():
391 for child in self.walk_children():
392 child.window.destroyed.disconnect(self._on_child_close)
396 def set_fullscreen(self, isFullscreen):
398 self._window.showFullScreen()
400 self._window.showNormal()
401 for child in self.walk_children():
402 child.set_fullscreen(isFullscreen)
404 def _populate_tab(self, index):
407 @misc_utils.log_exception(_moduleLogger)
408 def _on_login(self, checked = True):
411 @misc_utils.log_exception(_moduleLogger)
412 def _on_tab_changed(self, index):
413 self._populate_tab(index)
415 @misc_utils.log_exception(_moduleLogger)
416 def _on_refresh(self, checked = True):
417 index = self._tabs.currentIndex()
418 self._populate_tab(index)
420 @misc_utils.log_exception(_moduleLogger)
421 def _on_import(self, checked = True):
422 csvName = QtGui.QFileDialog.getOpenFileName(self._window, caption="Import", filter="CSV Files (*.csv)")
425 shutil.copy2(csvName, self._fsContactsPath)
427 @misc_utils.log_exception(_moduleLogger)
428 def _on_close_window(self, checked = True):
433 app = QtGui.QApplication([])
434 handle = Dialcentral(app)
438 if __name__ == "__main__":
439 logging.basicConfig(level = logging.DEBUG)
441 os.makedirs(constants._data_path_)