4 from __future__ import with_statement
12 from PyQt4 import QtGui
13 from PyQt4 import QtCore
17 from util import qtpie
18 from util import misc as misc_utils
23 _moduleLogger = logging.getLogger(__name__)
29 class Dialcentral(object):
32 os.path.dirname(__file__),
33 os.path.join(os.path.dirname(__file__), "../data"),
34 os.path.join(os.path.dirname(__file__), "../lib"),
35 '/usr/share/%s' % constants.__app_name__,
36 '/usr/lib/%s' % constants.__app_name__,
39 def __init__(self, app):
42 self._hiddenCategories = set()
43 self._hiddenUnits = {}
44 self._clipboard = QtGui.QApplication.clipboard()
46 self._mainWindow = None
48 self._fullscreenAction = QtGui.QAction(None)
49 self._fullscreenAction.setText("Fullscreen")
50 self._fullscreenAction.setCheckable(True)
51 self._fullscreenAction.setShortcut(QtGui.QKeySequence("CTRL+Enter"))
52 self._fullscreenAction.toggled.connect(self._on_toggle_fullscreen)
54 self._logAction = QtGui.QAction(None)
55 self._logAction.setText("Log")
56 self._logAction.setShortcut(QtGui.QKeySequence("CTRL+l"))
57 self._logAction.triggered.connect(self._on_log)
59 self._quitAction = QtGui.QAction(None)
60 self._quitAction.setText("Quit")
61 self._quitAction.setShortcut(QtGui.QKeySequence("CTRL+q"))
62 self._quitAction.triggered.connect(self._on_quit)
64 self._app.lastWindowClosed.connect(self._on_app_quit)
67 self._mainWindow = MainWindow(None, self)
68 self._mainWindow.window.destroyed.connect(self._on_child_close)
70 def load_settings(self):
72 with open(constants._user_settings_, "r") as settingsFile:
73 settings = simplejson.load(settingsFile)
75 _moduleLogger.info("No settings")
78 _moduleLogger.info("Settings were corrupt")
81 self._fullscreenAction.setChecked(settings.get("isFullScreen", False))
83 def save_settings(self):
85 "isFullScreen": self._fullscreenAction.isChecked(),
87 with open(constants._user_settings_, "w") as settingsFile:
88 simplejson.dump(settings, settingsFile)
91 def fullscreenAction(self):
92 return self._fullscreenAction
96 return self._logAction
100 return self._quitAction
102 def _close_windows(self):
103 if self._mainWindow is not None:
104 self._mainWindow.window.destroyed.disconnect(self._on_child_close)
105 self._mainWindow.close()
106 self._mainWindow = None
108 @misc_utils.log_exception(_moduleLogger)
109 def _on_app_quit(self, checked = False):
112 @misc_utils.log_exception(_moduleLogger)
113 def _on_child_close(self, obj = None):
114 self._mainWindow = None
116 @misc_utils.log_exception(_moduleLogger)
117 def _on_toggle_fullscreen(self, checked = False):
118 for window in self._walk_children():
119 window.set_fullscreen(checked)
121 @misc_utils.log_exception(_moduleLogger)
122 def _on_log(self, checked = False):
123 with open(constants._user_logpath_, "r") as f:
124 logLines = f.xreadlines()
125 log = "".join(logLines)
126 self._clipboard.setText(log)
128 @misc_utils.log_exception(_moduleLogger)
129 def _on_quit(self, checked = False):
130 self._close_windows()
133 class QErrorLog(QtCore.QObject):
135 messagePushed = QtCore.pyqtSignal()
136 messagePopped = QtCore.pyqtSignal()
139 QtCore.QObject.__init__(self)
142 def push_message(self, message):
143 self._messages.append(message)
144 self.messagePushed.emit()
146 def push_exception(self):
147 userMessage = str(sys.exc_info()[1])
148 _moduleLogger.exception(userMessage)
149 self.push_message(userMessage)
151 def pop_message(self):
152 del self._messages[0]
153 self.messagePopped.emit()
155 def peek_message(self):
156 return self._messages[0]
159 return len(self._messages)
162 class ErrorDisplay(object):
164 def __init__(self, errorLog):
165 self._errorLog = errorLog
166 self._errorLog.messagePushed.connect(self._on_message_pushed)
167 self._errorLog.messagePopped.connect(self._on_message_popped)
169 errorIcon = maeqt.get_theme_icon(("dialog-error", "app_install_error", "gtk-dialog-error"))
170 self._severityIcon = errorIcon.pixmap(32, 32)
171 self._severityLabel = QtGui.QLabel()
172 self._severityLabel.setPixmap(self._severityIcon)
174 self._message = QtGui.QLabel()
175 self._message.setText("Boo")
177 closeIcon = maeqt.get_theme_icon(("window-close", "general_close", "gtk-close"))
178 self._closeLabel = QtGui.QPushButton(closeIcon, "")
179 self._closeLabel.clicked.connect(self._on_close)
181 self._controlLayout = QtGui.QHBoxLayout()
182 self._controlLayout.addWidget(self._severityLabel)
183 self._controlLayout.addWidget(self._message)
184 self._controlLayout.addWidget(self._closeLabel)
186 self._topLevelLayout = QtGui.QHBoxLayout()
187 self._topLevelLayout.addLayout(self._controlLayout)
188 self._widget = QtGui.QWidget()
189 self._widget.setLayout(self._topLevelLayout)
196 @misc_utils.log_exception(_moduleLogger)
197 def _on_close(self, *args):
198 self._errorLog.pop_message()
200 @misc_utils.log_exception(_moduleLogger)
201 def _on_message_pushed(self):
202 if 1 <= len(self._errorLog) and self._widget.isHidden():
203 self._message.setText(self._errorLog.peek_message())
206 @misc_utils.log_exception(_moduleLogger)
207 def _on_message_popped(self):
208 if len(self._errorLog) == 0:
209 self._message.setText("")
212 self._message.setText(self._errorLog.peek_message())
215 class CredentialsDialog(object):
218 self._usernameField = QtGui.QLineEdit()
219 self._passwordField = QtGui.QLineEdit()
220 self._passwordField.setEchoMode(QtGui.QLineEdit.PasswordEchoOnEdit)
222 self._credLayout = QtGui.QGridLayout()
223 self._credLayout.addWidget(QtGui.QLabel("Username"), 0, 0)
224 self._credLayout.addWidget(self._usernameField, 0, 1)
225 self._credLayout.addWidget(QtGui.QLabel("Password"), 1, 0)
226 self._credLayout.addWidget(self._passwordField, 1, 1)
228 self._loginButton = QtGui.QPushButton("&Login")
229 self._buttonLayout = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Cancel)
230 self._buttonLayout.addButton(self._loginButton, QtGui.QDialogButtonBox.AcceptRole)
232 self._layout = QtGui.QVBoxLayout()
233 self._layout.addLayout(self._credLayout)
234 self._layout.addLayout(self._buttonLayout)
236 centralWidget = QtGui.QWidget()
237 centralWidget.setLayout(self._layout)
239 self._dialog = QtGui.QDialog()
240 self._dialog.setWindowTitle("Login")
241 self._dialog.setCentralWidget(centralWidget)
242 maeqt.set_autorient(self._dialog, True)
243 self._buttonLayout.accepted.connect(self._dialog.accept)
244 self._buttonLayout.rejected.connect(self._dialog.reject)
246 def run(self, defaultUsername, defaultPassword, parent=None):
247 self._dialog.setParent(parent)
248 self._usernameField.setText(defaultUsername)
249 self._passwordField.setText(defaultPassword)
251 response = self._dialog.exec_()
252 if response == QtGui.QDialog.Accepted:
253 return str(self._usernameField.text()), str(self._passwordField.text())
254 elif response == QtGui.QDialog.Rejected:
255 raise RuntimeError("Login Cancelled")
258 class AccountDialog(object):
261 self._accountNumberLabel = QtGui.QLabel("NUMBER NOT SET")
262 self._clearButton = QtGui.QPushButton("Clear Account")
263 self._clearButton.clicked.connect(self._on_clear)
264 self._doClear = False
266 self._credLayout = QtGui.QGridLayout()
267 self._credLayout.addWidget(QtGui.QLabel("Account"), 0, 0)
268 self._credLayout.addWidget(self._accountNumberLabel, 0, 1)
269 self._credLayout.addWidget(QtGui.QLabel("Callback"), 1, 0)
270 self._credLayout.addWidget(self._clearButton, 2, 1)
272 self._loginButton = QtGui.QPushButton("&Login")
273 self._buttonLayout = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Cancel)
274 self._buttonLayout.addButton(self._loginButton, QtGui.QDialogButtonBox.AcceptRole)
276 self._layout = QtGui.QVBoxLayout()
277 self._layout.addLayout(self._credLayout)
278 self._layout.addLayout(self._buttonLayout)
280 centralWidget = QtGui.QWidget()
281 centralWidget.setLayout(self._layout)
283 self._dialog = QtGui.QDialog()
284 self._dialog.setWindowTitle("Login")
285 self._dialog.setCentralWidget(centralWidget)
286 maeqt.set_autorient(self._dialog, True)
287 self._buttonLayout.accepted.connect(self._dialog.accept)
288 self._buttonLayout.rejected.connect(self._dialog.reject)
294 accountNumber = property(
295 lambda self: str(self._accountNumberLabel.text()),
296 lambda self, num: self._accountNumberLabel.setText(num),
299 def run(self, defaultUsername, defaultPassword, parent=None):
300 self._doClear = False
301 self._dialog.setParent(parent)
302 self._usernameField.setText(defaultUsername)
303 self._passwordField.setText(defaultPassword)
305 response = self._dialog.exec_()
306 if response == QtGui.QDialog.Accepted:
307 return str(self._usernameField.text()), str(self._passwordField.text())
308 elif response == QtGui.QDialog.Rejected:
309 raise RuntimeError("Login Cancelled")
311 def _on_clear(self, checked = False):
313 self._dialog.accept()
316 class SMSEntryWindow(object):
318 def __init__(self, parent, app, session, errorLog):
321 self._session = session
322 self._errorLog = errorLog
324 self._history = QtGui.QListView()
325 self._smsEntry = QtGui.QTextEdit()
326 self._smsEntry.textChanged.connect(self._on_letter_count_changed)
328 self._entryLayout = QtGui.QVBoxLayout()
329 self._entryLayout.addWidget(self._history)
330 self._entryLayout.addWidget(self._smsEntry)
331 self._entryWidget = QtGui.QWidget()
332 self._entryWidget.setLayout(self._entryLayout)
333 self._scrollEntry = QtGui.QScrollArea()
334 self._scrollEntry.setWidget(self._entryWidget)
335 self._scrollEntry.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignBottom)
336 self._scrollEntry.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
337 self._scrollEntry.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
339 self._characterCountLabel = QtGui.QLabel("Letters: %s" % 0)
340 self._numberSelector = None
341 self._smsButton = QtGui.QPushButton("SMS")
342 self._dialButton = QtGui.QPushButton("Dial")
344 self._buttonLayout = QtGui.QHBoxLayout()
345 self._buttonLayout.addWidget(self._characterCountLabel)
346 self._buttonLayout.addWidget(self._smsButton)
347 self._buttonLayout.addWidget(self._dialButton)
349 self._layout = QtGui.QVBoxLayout()
350 self._layout.addLayout(self._entryLayout)
351 self._layout.addLayout(self._buttonLayout)
353 centralWidget = QtGui.QWidget()
354 centralWidget.setLayout(self._layout)
356 self._window = QtGui.QMainWindow(parent)
357 self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, False)
358 maeqt.set_autorient(self._window, True)
359 maeqt.set_stackable(self._window, True)
360 self._window.setWindowTitle("Contact")
361 self._window.setCentralWidget(centralWidget)
363 def _update_letter_count(self):
364 count = self._smsEntry.toPlainText().size()
365 self._characterCountLabel.setText("Letters: %s" % count)
367 def _update_button_state(self):
368 if len(self._contacts) == 0:
369 self._dialButton.setEnabled(False)
370 self._smsButton.setEnabled(False)
371 elif len(self._contacts) == 1:
372 count = self._smsEntry.toPlainText().size()
374 self._dialButton.setEnabled(True)
375 self._smsButton.setEnabled(False)
377 self._dialButton.setEnabled(False)
378 self._smsButton.setEnabled(True)
380 self._dialButton.setEnabled(False)
381 self._smsButton.setEnabled(True)
383 @misc_utils.log_exception(_moduleLogger)
384 def _on_letter_count_changed(self):
385 self._update_letter_count()
386 self._update_button_state()
389 class DelayedWidget(object):
391 def __init__(self, app):
392 self._layout = QtGui.QVBoxLayout()
393 self._widget = QtGui.QWidget()
394 self._widget.setLayout(self._layout)
397 self._isEnabled = True
404 return self._child is not None
406 def set_child(self, child):
407 if self._child is not None:
408 self._layout.removeWidget(self._child.toplevel)
410 if self._child is not None:
411 self._layout.addWidget(self._child.toplevel)
416 self._child.disable()
419 self._isEnabled = True
420 if self._child is not None:
424 self._isEnabled = False
425 if self._child is not None:
426 self._child.disable()
429 if self._child is not None:
433 if self._child is not None:
434 self._child.refresh()
437 class Dialpad(object):
439 def __init__(self, app, session, errorLog):
441 self._session = session
442 self._errorLog = errorLog
444 self._plus = self._generate_key_button("+", "")
445 self._entry = QtGui.QLineEdit()
447 backAction = QtGui.QAction(None)
448 backAction.setText("Back")
449 backAction.triggered.connect(self._on_backspace)
450 backPieItem = qtpie.QActionPieItem(backAction)
451 clearAction = QtGui.QAction(None)
452 clearAction.setText("Clear")
453 clearAction.triggered.connect(self._on_clear_text)
454 clearPieItem = qtpie.QActionPieItem(clearAction)
455 self._back = qtpie.QPieButton(backPieItem)
456 self._back.set_center(backPieItem)
457 self._back.insertItem(qtpie.PieFiling.NULL_CENTER)
458 self._back.insertItem(clearPieItem)
459 self._back.insertItem(qtpie.PieFiling.NULL_CENTER)
460 self._back.insertItem(qtpie.PieFiling.NULL_CENTER)
462 self._entryLayout = QtGui.QHBoxLayout()
463 self._entryLayout.addWidget(self._plus, 0, QtCore.Qt.AlignCenter)
464 self._entryLayout.addWidget(self._entry, 10)
465 self._entryLayout.addWidget(self._back, 0, QtCore.Qt.AlignCenter)
467 self._smsButton = QtGui.QPushButton("SMS")
468 self._smsButton.clicked.connect(self._on_sms_clicked)
469 self._callButton = QtGui.QPushButton("Call")
470 self._callButton.clicked.connect(self._on_call_clicked)
472 self._padLayout = QtGui.QGridLayout()
473 rows = [0, 0, 0, 1, 1, 1, 2, 2, 2]
474 columns = [0, 1, 2] * 3
486 for (num, letters), (row, column) in zip(keys, zip(rows, columns)):
487 self._padLayout.addWidget(
488 self._generate_key_button(num, letters), row, column, QtCore.Qt.AlignCenter
490 self._padLayout.addWidget(self._smsButton, 3, 0)
491 self._padLayout.addWidget(
492 self._generate_key_button("0", ""), 3, 1, QtCore.Qt.AlignCenter
494 self._padLayout.addWidget(self._callButton, 3, 2)
496 self._layout = QtGui.QVBoxLayout()
497 self._layout.addLayout(self._entryLayout)
498 self._layout.addLayout(self._padLayout)
499 self._widget = QtGui.QWidget()
500 self._widget.setLayout(self._layout)
507 self._smsButton.setEnabled(True)
508 self._callButton.setEnabled(True)
511 self._smsButton.setEnabled(False)
512 self._callButton.setEnabled(False)
520 def _generate_key_button(self, center, letters):
521 centerPieItem = self._generate_button_slice(center)
522 button = qtpie.QPieButton(centerPieItem)
523 button.set_center(centerPieItem)
525 if len(letters) == 0:
527 pieItem = qtpie.PieFiling.NULL_CENTER
528 button.insertItem(pieItem)
529 elif len(letters) in [3, 4]:
530 for i in xrange(6 - len(letters)):
531 pieItem = qtpie.PieFiling.NULL_CENTER
532 button.insertItem(pieItem)
534 for letter in letters:
535 pieItem = self._generate_button_slice(letter)
536 button.insertItem(pieItem)
539 pieItem = qtpie.PieFiling.NULL_CENTER
540 button.insertItem(pieItem)
542 raise NotImplementedError("Cannot handle %r" % letters)
545 def _generate_button_slice(self, letter):
546 action = QtGui.QAction(None)
547 action.setText(letter)
548 action.triggered.connect(lambda: self._on_keypress(letter))
549 pieItem = qtpie.QActionPieItem(action)
552 @misc_utils.log_exception(_moduleLogger)
553 def _on_keypress(self, key):
554 self._entry.insert(key)
556 @misc_utils.log_exception(_moduleLogger)
557 def _on_backspace(self, toggled = False):
558 self._entry.backspace()
560 @misc_utils.log_exception(_moduleLogger)
561 def _on_clear_text(self, toggled = False):
564 @misc_utils.log_exception(_moduleLogger)
565 def _on_sms_clicked(self, checked = False):
566 number = str(self._entry.text())
568 self._session.draft.add_contact(number, [])
570 @misc_utils.log_exception(_moduleLogger)
571 def _on_call_clicked(self, checked = False):
572 number = str(self._entry.text())
574 self._session.draft.add_contact(number, [])
578 class History(object):
586 HISTORY_ITEM_TYPES = ["All", "Received", "Missed", "Placed"]
587 HISTORY_COLUMNS = ["When", "What", "Number", "From"]
588 assert len(HISTORY_COLUMNS) == MAX_IDX
590 def __init__(self, app, session, errorLog):
591 self._selectedFilter = self.HISTORY_ITEM_TYPES[0]
593 self._session = session
594 self._session.historyUpdated.connect(self._on_history_updated)
595 self._errorLog = errorLog
597 self._typeSelection = QtGui.QComboBox()
598 self._typeSelection.addItems(self.HISTORY_ITEM_TYPES)
599 self._typeSelection.setCurrentIndex(
600 self.HISTORY_ITEM_TYPES.index(self._selectedFilter)
602 self._typeSelection.currentIndexChanged.connect(self._on_filter_changed)
604 self._itemStore = QtGui.QStandardItemModel()
605 self._itemStore.setHorizontalHeaderLabels(self.HISTORY_COLUMNS)
607 self._itemView = QtGui.QTreeView()
608 self._itemView.setModel(self._itemStore)
609 self._itemView.setUniformRowHeights(True)
610 self._itemView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
611 self._itemView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
612 self._itemView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
613 self._itemView.setHeaderHidden(True)
614 self._itemView.activated.connect(self._on_row_activated)
616 self._layout = QtGui.QVBoxLayout()
617 self._layout.addWidget(self._typeSelection)
618 self._layout.addWidget(self._itemView)
619 self._widget = QtGui.QWidget()
620 self._widget.setLayout(self._layout)
622 self._populate_items()
629 self._itemView.setEnabled(True)
632 self._itemView.setEnabled(False)
635 self._itemView.clear()
640 def _populate_items(self):
641 self._errorLog.push_message("Not supported")
643 @misc_utils.log_exception(_moduleLogger)
644 def _on_filter_changed(self, newItem):
645 self._selectedFilter = str(newItem)
647 @misc_utils.log_exception(_moduleLogger)
648 def _on_history_updated(self):
649 self._populate_items()
651 @misc_utils.log_exception(_moduleLogger)
652 def _on_row_activated(self, index):
653 rowIndex = index.row()
654 #self._session.draft.add_contact(number, details)
657 class Messages(object):
660 VOICEMAIL_MESSAGES = "Voicemail"
661 TEXT_MESSAGES = "SMS"
662 ALL_TYPES = "All Messages"
663 MESSAGE_TYPES = [NO_MESSAGES, VOICEMAIL_MESSAGES, TEXT_MESSAGES, ALL_TYPES]
665 UNREAD_STATUS = "Unread"
666 UNARCHIVED_STATUS = "Inbox"
668 MESSAGE_STATUSES = [UNREAD_STATUS, UNARCHIVED_STATUS, ALL_STATUS]
670 def __init__(self, app, session, errorLog):
671 self._selectedTypeFilter = self.ALL_TYPES
672 self._selectedStatusFilter = self.ALL_STATUS
674 self._session = session
675 self._session.messagesUpdated.connect(self._on_messages_updated)
676 self._errorLog = errorLog
678 self._typeSelection = QtGui.QComboBox()
679 self._typeSelection.addItems(self.MESSAGE_TYPES)
680 self._typeSelection.setCurrentIndex(
681 self.MESSAGE_TYPES.index(self._selectedTypeFilter)
683 self._typeSelection.currentIndexChanged.connect(self._on_type_filter_changed)
685 self._statusSelection = QtGui.QComboBox()
686 self._statusSelection.addItems(self.MESSAGE_STATUSES)
687 self._statusSelection.setCurrentIndex(
688 self.MESSAGE_STATUSES.index(self._selectedStatusFilter)
690 self._statusSelection.currentIndexChanged.connect(self._on_status_filter_changed)
692 self._selectionLayout = QtGui.QHBoxLayout()
693 self._selectionLayout.addWidget(self._typeSelection)
694 self._selectionLayout.addWidget(self._statusSelection)
696 self._itemStore = QtGui.QStandardItemModel()
697 self._itemStore.setHorizontalHeaderLabels(["Messages"])
699 self._itemView = QtGui.QTreeView()
700 self._itemView.setModel(self._itemStore)
701 self._itemView.setUniformRowHeights(True)
702 self._itemView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
703 self._itemView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
704 self._itemView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
705 self._itemView.setHeaderHidden(True)
706 self._itemView.activated.connect(self._on_row_activated)
708 self._layout = QtGui.QVBoxLayout()
709 self._layout.addLayout(self._selectionLayout)
710 self._layout.addWidget(self._itemView)
711 self._widget = QtGui.QWidget()
712 self._widget.setLayout(self._layout)
714 self._populate_items()
721 self._itemView.setEnabled(True)
724 self._itemView.setEnabled(False)
727 self._itemView.clear()
732 def _populate_items(self):
733 self._errorLog.push_message("Not supported")
735 @misc_utils.log_exception(_moduleLogger)
736 def _on_type_filter_changed(self, newItem):
737 self._selectedTypeFilter = str(newItem)
739 @misc_utils.log_exception(_moduleLogger)
740 def _on_status_filter_changed(self, newItem):
741 self._selectedStatusFilter = str(newItem)
743 @misc_utils.log_exception(_moduleLogger)
744 def _on_messages_updated(self):
745 self._populate_items()
747 @misc_utils.log_exception(_moduleLogger)
748 def _on_row_activated(self, index):
749 rowIndex = index.row()
750 #self._session.draft.add_contact(number, details)
753 class Contacts(object):
755 def __init__(self, app, session, errorLog):
756 self._selectedFilter = ""
758 self._session = session
759 self._session.contactsUpdated.connect(self._on_contacts_updated)
760 self._errorLog = errorLog
762 self._listSelection = QtGui.QComboBox()
763 self._listSelection.addItems([])
764 #self._listSelection.setCurrentIndex(self.HISTORY_ITEM_TYPES.index(self._selectedFilter))
765 self._listSelection.currentIndexChanged.connect(self._on_filter_changed)
767 self._itemStore = QtGui.QStandardItemModel()
768 self._itemStore.setHorizontalHeaderLabels(["Contacts"])
770 self._itemView = QtGui.QTreeView()
771 self._itemView.setModel(self._itemStore)
772 self._itemView.setUniformRowHeights(True)
773 self._itemView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
774 self._itemView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
775 self._itemView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
776 self._itemView.setHeaderHidden(True)
777 self._itemView.activated.connect(self._on_row_activated)
779 self._layout = QtGui.QVBoxLayout()
780 self._layout.addWidget(self._listSelection)
781 self._layout.addWidget(self._itemView)
782 self._widget = QtGui.QWidget()
783 self._widget.setLayout(self._layout)
785 self._populate_items()
792 self._itemView.setEnabled(True)
795 self._itemView.setEnabled(False)
798 self._itemView.clear()
803 def _populate_items(self):
804 self._errorLog.push_message("Not supported")
806 @misc_utils.log_exception(_moduleLogger)
807 def _on_filter_changed(self, newItem):
808 self._selectedFilter = str(newItem)
810 @misc_utils.log_exception(_moduleLogger)
811 def _on_contacts_updated(self):
812 self._populate_items()
814 @misc_utils.log_exception(_moduleLogger)
815 def _on_row_activated(self, index):
816 rowIndex = index.row()
817 #self._session.draft.add_contact(number, details)
820 class MainWindow(object):
834 assert len(_TAB_TITLES) == MAX_TABS
842 assert len(_TAB_CLASS) == MAX_TABS
844 def __init__(self, parent, app):
845 self._fsContactsPath = os.path.join(constants._data_path_, "contacts")
847 self._session = session.Session()
848 self._session.error.connect(self._on_session_error)
849 self._session.loggedIn.connect(self._on_login)
850 self._session.loggedOut.connect(self._on_logout)
852 self._errorLog = QErrorLog()
853 self._errorDisplay = ErrorDisplay(self._errorLog)
855 self._tabsContents = [
856 DelayedWidget(self._app)
857 for i in xrange(self.MAX_TABS)
859 for tab in self._tabsContents:
862 self._tabWidget = QtGui.QTabWidget()
863 if maeqt.screen_orientation() == QtCore.Qt.Vertical:
864 self._tabWidget.setTabPosition(QtGui.QTabWidget.South)
866 self._tabWidget.setTabPosition(QtGui.QTabWidget.West)
867 for tabIndex, tabTitle in enumerate(self._TAB_TITLES):
868 self._tabWidget.addTab(self._tabsContents[tabIndex].toplevel, tabTitle)
869 self._tabWidget.currentChanged.connect(self._on_tab_changed)
871 self._layout = QtGui.QVBoxLayout()
872 self._layout.addWidget(self._errorDisplay.toplevel)
873 self._layout.addWidget(self._tabWidget)
875 centralWidget = QtGui.QWidget()
876 centralWidget.setLayout(self._layout)
878 self._window = QtGui.QMainWindow(parent)
879 self._window.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
880 maeqt.set_autorient(self._window, True)
881 maeqt.set_stackable(self._window, True)
882 self._window.setWindowTitle("%s" % constants.__pretty_app_name__)
883 self._window.setCentralWidget(centralWidget)
885 self._loginTabAction = QtGui.QAction(None)
886 self._loginTabAction.setText("Login")
887 self._loginTabAction.triggered.connect(self._on_login_requested)
889 self._importTabAction = QtGui.QAction(None)
890 self._importTabAction.setText("Import")
891 self._importTabAction.triggered.connect(self._on_import)
893 self._refreshTabAction = QtGui.QAction(None)
894 self._refreshTabAction.setText("Refresh")
895 self._refreshTabAction.setShortcut(QtGui.QKeySequence("CTRL+r"))
896 self._refreshTabAction.triggered.connect(self._on_refresh)
898 self._closeWindowAction = QtGui.QAction(None)
899 self._closeWindowAction.setText("Close")
900 self._closeWindowAction.setShortcut(QtGui.QKeySequence("CTRL+w"))
901 self._closeWindowAction.triggered.connect(self._on_close_window)
904 fileMenu = self._window.menuBar().addMenu("&File")
905 fileMenu.addAction(self._loginTabAction)
906 fileMenu.addAction(self._refreshTabAction)
908 toolsMenu = self._window.menuBar().addMenu("&Tools")
909 toolsMenu.addAction(self._importTabAction)
911 self._window.addAction(self._closeWindowAction)
912 self._window.addAction(self._app.quitAction)
913 self._window.addAction(self._app.fullscreenAction)
915 fileMenu = self._window.menuBar().addMenu("&File")
916 fileMenu.addAction(self._loginTabAction)
917 fileMenu.addAction(self._refreshTabAction)
918 fileMenu.addAction(self._closeWindowAction)
919 fileMenu.addAction(self._app.quitAction)
921 viewMenu = self._window.menuBar().addMenu("&View")
922 viewMenu.addAction(self._app.fullscreenAction)
924 toolsMenu = self._window.menuBar().addMenu("&Tools")
925 toolsMenu.addAction(self._importTabAction)
927 self._window.addAction(self._app.logAction)
929 self._initialize_tab(self._tabWidget.currentIndex())
930 self.set_fullscreen(self._app.fullscreenAction.isChecked())
937 def walk_children(self):
942 for child in self.walk_children():
946 for child in self.walk_children():
951 for child in self.walk_children():
952 child.window.destroyed.disconnect(self._on_child_close)
956 def set_fullscreen(self, isFullscreen):
958 self._window.showFullScreen()
960 self._window.showNormal()
961 for child in self.walk_children():
962 child.set_fullscreen(isFullscreen)
964 def _initialize_tab(self, index):
965 assert index < self.MAX_TABS
966 if not self._tabsContents[index].has_child():
967 self._tabsContents[index].set_child(
968 self._TAB_CLASS[index](self._app, self._session, self._errorLog)
971 @misc_utils.log_exception(_moduleLogger)
972 def _on_session_error(self, message):
973 self._errorLog.push_message(message)
975 @misc_utils.log_exception(_moduleLogger)
977 for tab in self._tabsContents:
980 @misc_utils.log_exception(_moduleLogger)
981 def _on_logout(self):
982 for tab in self._tabsContents:
985 @misc_utils.log_exception(_moduleLogger)
986 def _on_login_requested(self):
989 @misc_utils.log_exception(_moduleLogger)
990 def _on_tab_changed(self, index):
991 self._initialize_tab(index)
993 @misc_utils.log_exception(_moduleLogger)
994 def _on_refresh(self, checked = True):
995 index = self._tabWidget.currentIndex()
996 self._tabsContents[index].refresh()
998 @misc_utils.log_exception(_moduleLogger)
999 def _on_import(self, checked = True):
1000 csvName = QtGui.QFileDialog.getOpenFileName(self._window, caption="Import", filter="CSV Files (*.csv)")
1003 shutil.copy2(csvName, self._fsContactsPath)
1005 @misc_utils.log_exception(_moduleLogger)
1006 def _on_close_window(self, checked = True):
1011 app = QtGui.QApplication([])
1012 handle = Dialcentral(app)
1017 if __name__ == "__main__":
1018 logFormat = '(%(asctime)s) %(levelname)-5s %(threadName)s.%(name)s: %(message)s'
1019 logging.basicConfig(level=logging.DEBUG, format=logFormat)
1021 os.makedirs(constants._data_path_)