def _onTvFilesCustomContextMenuRequested(self, pos ): """Connected automatically by uic """ menu = QMenu() menu.addAction( core.actionManager().action( "mFile/mClose/aCurrent" ) ) menu.addAction( core.actionManager().action( "mFile/mSave/aCurrent" ) ) menu.addAction( core.actionManager().action( "mFile/mReload/aCurrent" ) ) menu.addSeparator() # sort menu sortMenu = QMenu( self ) group = QActionGroup( sortMenu ) group.addAction( self.tr( "Opening order" ) ) group.addAction( self.tr( "File name" ) ) group.addAction( self.tr( "URL" ) ) group.addAction( self.tr( "Suffixes" ) ) group.triggered.connect(self._onSortTriggered) sortMenu.addActions( group.actions() ) for i, sortMode in enumerate(["OpeningOrder", "FileName", "URL", "Suffixes"]): action = group.actions()[i] action.setData( sortMode ) action.setCheckable( True ) if sortMode == self.model.sortMode(): action.setChecked( True ) aSortMenu = QAction( self.tr( "Sorting" ), self ) aSortMenu.setMenu( sortMenu ) aSortMenu.setIcon( QIcon( ":/enkiicons/sort.png" )) aSortMenu.setToolTip( aSortMenu.text() ) menu.addAction( sortMenu.menuAction() ) menu.exec_( self.tvFiles.mapToGlobal( pos ) )
class FilterSetWidget(QWidget, Ui_FilterSetWidget): def __init__(self, parent=None): super(FilterSetWidget, self).__init__(parent) self.setupUi(self) self._filterSetActionGroup = QActionGroup(self) self._filterSetActionGroup.addAction(self.saveFilterSetAction) self._filterSetActionGroup.addAction(self.reloadFilterSetAction) self._filterSetActionGroup.addAction(self.deleteFilterSetAction) self._filterSetActionGroup.addAction(self.exportFilterSetAction) self._filterSetMenu = QMenu(self) self._filterSetMenu.addActions(self._filterSetActionGroup.actions()) self.filterSetTool.setMenu(self._filterSetMenu) self.filterSetTool.setDefaultAction(self.saveFilterSetAction) def setFilterSet(self, filterSet): self.setFilterSetKey(filterSet.key) if filterSet.source == 'ark': self.saveFilterSetAction.setEnabled(False) self.deleteFilterSetAction.setEnabled(False) self.filterSetTool.setDefaultAction(self.reloadFilterSetAction) else: self.saveFilterSetAction.setEnabled(True) self.deleteFilterSetAction.setEnabled(True) self.filterSetTool.setDefaultAction(self.saveFilterSetAction) def setFilterSetKey(self, key): self.filterSetCombo.setCurrentIndex(self.filterSetCombo.findData(key)) def currentFilterSetKey(self): return self.filterSetCombo.itemData(self.filterSetCombo.currentIndex()) def currentFilterSetName(self): return self.filterSetCombo.currentText()
class TrayContextMenu(QtGui.QMenu): instances = set() def __init__(self, trayIcon): """ trayIcon = the object with the methods to call """ QtGui.QMenu.__init__(self) TrayContextMenu.instances.add(self) self.trayIcon = trayIcon self._buildMenu() def _buildMenu(self): self.framelessCheck = QtGui.QAction("Frameless Window", self, checkable=True) self.connect(self.framelessCheck, SIGNAL("triggered()"), self.trayIcon.changeFrameless) self.addAction(self.framelessCheck) self.addSeparator() self.requestCheck = QtGui.QAction("Show status request notifications", self, checkable=True) self.requestCheck.setChecked(True) self.addAction(self.requestCheck) self.connect(self.requestCheck, SIGNAL("triggered()"), self.trayIcon.switchRequest) self.alarmCheck = QtGui.QAction("Show alarm notifications", self, checkable=True) self.alarmCheck.setChecked(True) self.connect(self.alarmCheck, SIGNAL("triggered()"), self.trayIcon.switchAlarm) self.addAction(self.alarmCheck) distanceMenu = self.addMenu("Alarm Distance") self.distanceGroup = QActionGroup(self) for i in range(0, 6): action = QAction("{0} Jumps".format(i), None, checkable=True) if i == 0: action.setChecked(True) action.alarmDistance = i self.connect(action, SIGNAL("triggered()"), self.changeAlarmDistance) self.distanceGroup.addAction(action) distanceMenu.addAction(action) self.addMenu(distanceMenu) self.addSeparator() self.quitAction = QAction("Quit", self) self.connect(self.quitAction, SIGNAL("triggered()"), self.trayIcon.quit) self.addAction(self.quitAction) def changeAlarmDistance(self): for action in self.distanceGroup.actions(): if action.isChecked(): self.trayIcon.alarmDistance = action.alarmDistance self.trayIcon.changeAlarmDistance()
def _onTvFilesCustomContextMenuRequested(self, pos): """Connected automatically by uic """ menu = QMenu() menu.addAction(core.actionManager().action("mFile/mClose/aCurrent")) menu.addAction(core.actionManager().action("mFile/mSave/aCurrent")) menu.addAction(core.actionManager().action("mFile/mReload/aCurrent")) menu.addSeparator() # sort menu sortMenu = QMenu(self) group = QActionGroup(sortMenu) group.addAction(self.tr("Opening order")) group.addAction(self.tr("File name")) group.addAction(self.tr("URL")) group.addAction(self.tr("Suffixes")) group.triggered.connect(self._onSortTriggered) sortMenu.addActions(group.actions()) for i, sortMode in enumerate( ["OpeningOrder", "FileName", "URL", "Suffixes"]): action = group.actions()[i] action.setData(sortMode) action.setCheckable(True) if sortMode == self.model.sortMode(): action.setChecked(True) aSortMenu = QAction(self.tr("Sorting"), self) aSortMenu.setMenu(sortMenu) aSortMenu.setIcon(QIcon(":/enkiicons/sort.png")) aSortMenu.setToolTip(aSortMenu.text()) menu.addAction(sortMenu.menuAction()) menu.exec_(self.tvFiles.mapToGlobal(pos))
class MainWindow(base_class, ui_class): implements(IObserver) def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.idle_status_index = 0 notification_center = NotificationCenter() notification_center.add_observer(self, name='SIPApplicationWillStart') notification_center.add_observer(self, name='SIPApplicationDidStart') notification_center.add_observer(self, name='SIPAccountMWIDidGetSummary') notification_center.add_observer(self, sender=AccountManager()) self.mwi_icons = [QIcon(Resources.get('icons/mwi-%d.png' % i)) for i in xrange(0, 11)] self.mwi_icons.append(QIcon(Resources.get('icons/mwi-many.png'))) with Resources.directory: self.setupUi() self.setWindowTitle('Blink') self.setWindowIconText('Blink') self.set_user_icon(Resources.get("icons/default-avatar.png")) # ":/resources/icons/default-avatar.png" self.active_sessions_label.hide() self.enable_call_buttons(False) self.conference_button.setEnabled(False) self.hangup_all_button.setEnabled(False) self.sip_server_settings_action.setEnabled(False) self.search_for_people_action.setEnabled(False) self.history_on_server_action.setEnabled(False) self.buy_pstn_access_action.setEnabled(False) self.main_view.setCurrentWidget(self.contacts_panel) self.contacts_view.setCurrentWidget(self.contact_list_panel) self.search_view.setCurrentWidget(self.search_list_panel) # Accounts self.account_model = AccountModel(self) self.enabled_account_model = ActiveAccountModel(self.account_model, self) self.server_tools_account_model = ServerToolsAccountModel(self.account_model, self) self.identity.setModel(self.enabled_account_model) # Contacts self.contact_model = ContactModel(self) self.contact_search_model = ContactSearchModel(self.contact_model, self) self.contact_list.setModel(self.contact_model) self.search_list.setModel(self.contact_search_model) # Sessions self.session_model = SessionModel(self) self.session_list.setModel(self.session_model) self.session_list.selectionModel().selectionChanged.connect(self._SH_SessionListSelectionChanged) # Windows, dialogs and panels self.about_panel = AboutPanel(self) self.contact_editor_dialog = ContactEditorDialog(self.contact_model, self) self.google_contacts_dialog = GoogleContactsDialog(self) self.preferences_window = PreferencesWindow(self.account_model, None) self.server_tools_window = ServerToolsWindow(self.server_tools_account_model, None) # Signals self.add_contact_button.clicked.connect(self._SH_AddContactButtonClicked) self.add_search_contact_button.clicked.connect(self._SH_AddContactButtonClicked) self.audio_call_button.clicked.connect(self._SH_AudioCallButtonClicked) self.back_to_contacts_button.clicked.connect(self.search_box.clear) # this can be set in designer -Dan self.conference_button.makeConference.connect(self._SH_MakeConference) self.conference_button.breakConference.connect(self._SH_BreakConference) self.contact_list.doubleClicked.connect(self._SH_ContactDoubleClicked) # activated is emitted on single click self.contact_list.selectionModel().selectionChanged.connect(self._SH_ContactListSelectionChanged) self.contact_model.itemsAdded.connect(self._SH_ContactModelAddedItems) self.contact_model.itemsRemoved.connect(self._SH_ContactModelRemovedItems) self.display_name.editingFinished.connect(self._SH_DisplayNameEditingFinished) self.hangup_all_button.clicked.connect(self._SH_HangupAllButtonClicked) self.identity.activated[int].connect(self._SH_IdentityChanged) self.identity.currentIndexChanged[int].connect(self._SH_IdentityCurrentIndexChanged) self.mute_button.clicked.connect(self._SH_MuteButtonClicked) self.search_box.textChanged.connect(self._SH_SearchBoxTextChanged) self.search_box.textChanged.connect(self.contact_search_model.setFilterFixedString) self.search_box.returnPressed.connect(self._SH_SearchBoxReturnPressed) self.search_box.shortcut.activated.connect(self.search_box.setFocus) self.search_list.selectionModel().selectionChanged.connect(self._SH_SearchListSelectionChanged) self.search_list.doubleClicked.connect(self._SH_ContactDoubleClicked) # activated is emitted on single click self.server_tools_account_model.rowsInserted.connect(self._SH_ServerToolsAccountModelChanged) self.server_tools_account_model.rowsRemoved.connect(self._SH_ServerToolsAccountModelChanged) self.session_model.sessionAdded.connect(self._SH_SessionModelAddedSession) self.session_model.structureChanged.connect(self._SH_SessionModelChangedStructure) self.silent_button.clicked.connect(self._SH_SilentButtonClicked) self.status.activated[int].connect(self._SH_StatusChanged) self.switch_view_button.viewChanged.connect(self._SH_SwitchViewButtonChangedView) # Blink menu actions self.about_action.triggered.connect(self.about_panel.show) self.donate_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/payments.phtml'))) self.add_account_action.triggered.connect(self.preferences_window.show_add_account_dialog) self.manage_accounts_action.triggered.connect(self.preferences_window.show_for_accounts) self.help_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/help-qt.phtml'))) self.preferences_action.triggered.connect(self.preferences_window.show) self.auto_accept_chat_action.triggered.connect(self._AH_AutoAcceptChatTriggered) self.auto_accept_files_action.triggered.connect(self._AH_AutoAcceptFilesTriggered) self.release_notes_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/changelog-qt.phtml'))) self.quit_action.triggered.connect(self.close) # Audio menu actions self.mute_action.triggered.connect(self._SH_MuteButtonClicked) self.silent_action.triggered.connect(self._SH_SilentButtonClicked) self.output_devices_group.triggered.connect(self._AH_AudioOutputDeviceChanged) self.input_devices_group.triggered.connect(self._AH_AudioInputDeviceChanged) self.alert_devices_group.triggered.connect(self._AH_AudioAlertDeviceChanged) # History menu actions self.redial_action.triggered.connect(self._AH_RedialActionTriggered) # Tools menu actions self.answering_machine_action.triggered.connect(self._AH_EnableAnsweringMachineTriggered) self.sip_server_settings_action.triggered.connect(self._AH_SIPServerSettings) self.search_for_people_action.triggered.connect(self._AH_SearchForPeople) self.history_on_server_action.triggered.connect(self._AH_HistoryOnServer) self.buy_pstn_access_action.triggered.connect(self._AH_PurchasePstnAccess) self.contact_model.load() def setupUi(self): super(MainWindow, self).setupUi(self) self.search_box.shortcut = QShortcut(self.search_box) self.search_box.shortcut.setKey('CTRL+F') self.output_devices_group = QActionGroup(self) self.input_devices_group = QActionGroup(self) self.alert_devices_group = QActionGroup(self) # adjust search box height depending on theme as the value set in designer isn't suited for all themes search_box = self.search_box option = QStyleOptionFrameV2() search_box.initStyleOption(option) frame_width = search_box.style().pixelMetric(QStyle.PM_DefaultFrameWidth, option, search_box) if frame_width < 4: search_box.setMinimumHeight(20 + 2*frame_width) # adjust status combo-box font size to fit the combo-box option = QStyleOptionComboBox() self.status.initStyleOption(option) frame_width = self.status.style().pixelMetric(QStyle.PM_DefaultFrameWidth, option, self.status) font = self.status.font() font.setFamily('Sans Serif') font.setPointSize(font.pointSize() - 1) # make it 1 point smaller then the default font size font_metrics = QFontMetrics(font) if font_metrics.height() > self.status.maximumHeight() - 2*frame_width: pixel_size = 11 - (frame_width - 2) # subtract 1 pixel for every frame pixel over 2 pixels font.setPixelSize(pixel_size) self.status.setFont(font) # adjust the combo boxes for themes with too much padding (like the default theme on Ubuntu 10.04) option = QStyleOptionComboBox() self.status.initStyleOption(option) font_metrics = self.status.fontMetrics() text_width = max(font_metrics.width(self.status.itemText(index)) for index in xrange(self.status.count())) frame_width = self.status.style().pixelMetric(QStyle.PM_ComboBoxFrameWidth, option, self.status) arrow_width = self.status.style().subControlRect(QStyle.CC_ComboBox, option, QStyle.SC_ComboBoxArrow, self.status).width() wide_padding = self.status.style().subControlRect(QStyle.CC_ComboBox, option, QStyle.SC_ComboBoxEditField, self.status).height() < 10 self.status.setFixedWidth(text_width + arrow_width + 2*frame_width + 30) # 30? Don't ask. self.status.setStyleSheet("""QComboBox { padding: 0px 3px 0px 3px; }""" if wide_padding else "") self.identity.setStyleSheet("""QComboBox { padding: 0px 4px 0px 4px; }""" if wide_padding else "") def closeEvent(self, event): super(MainWindow, self).closeEvent(event) self.about_panel.close() self.contact_editor_dialog.close() self.google_contacts_dialog.close() self.preferences_window.close() self.server_tools_window.close() def set_user_icon(self, image_file_name): pixmap = QPixmap(32, 32) pixmap.fill(QColor(Qt.transparent)) painter = QPainter(pixmap) painter.setRenderHint(QPainter.Antialiasing, True) painter.setBrush(QBrush(Qt.white)) painter.setPen(QPen(painter.brush(), 0, Qt.NoPen)) #painter.drawRoundedRect(0, 0, 32, 32, 6, 6) painter.drawRoundedRect(0, 0, 32, 32, 0, 0) icon = QPixmap() if icon.load(image_file_name): icon = icon.scaled(32, 32, Qt.KeepAspectRatio, Qt.SmoothTransformation) painter.setCompositionMode(QPainter.CompositionMode_SourceOver) painter.drawPixmap(0, 0, icon) painter.end() self.image.setPixmap(pixmap) def enable_call_buttons(self, enabled): self.audio_call_button.setEnabled(enabled) self.im_session_button.setEnabled(False) self.ds_session_button.setEnabled(False) def load_audio_devices(self): settings = SIPSimpleSettings() action = QAction(u'System default', self.output_devices_group) action.setData(QVariant(u'system_default')) self.output_device_menu.addAction(action) self.output_device_menu.addSeparator() for device in SIPApplication.engine.output_devices: action = QAction(device, self.output_devices_group) action.setData(QVariant(device)) self.output_device_menu.addAction(action) action = QAction(u'None', self.output_devices_group) action.setData(QVariant(None)) self.output_device_menu.addAction(action) for action in self.output_devices_group.actions(): action.setCheckable(True) if settings.audio.output_device == action.data().toPyObject(): action.setChecked(True) action = QAction(u'System default', self.input_devices_group) action.setData(QVariant(u'system_default')) self.input_device_menu.addAction(action) self.input_device_menu.addSeparator() for device in SIPApplication.engine.input_devices: action = QAction(device, self.input_devices_group) action.setData(QVariant(device)) self.input_device_menu.addAction(action) action = QAction(u'None', self.input_devices_group) action.setData(QVariant(None)) self.input_device_menu.addAction(action) for action in self.input_devices_group.actions(): action.setCheckable(True) if settings.audio.input_device == action.data().toPyObject(): action.setChecked(True) action = QAction(u'System default', self.alert_devices_group) action.setData(QVariant(u'system_default')) self.alert_device_menu.addAction(action) self.alert_device_menu.addSeparator() for device in SIPApplication.engine.output_devices: action = QAction(device, self.alert_devices_group) action.setData(QVariant(device)) self.alert_device_menu.addAction(action) action = QAction(u'None', self.alert_devices_group) action.setData(QVariant(None)) self.alert_device_menu.addAction(action) for action in self.alert_devices_group.actions(): action.setCheckable(True) if settings.audio.alert_device == action.data().toPyObject(): action.setChecked(True) def _AH_AccountActionTriggered(self, action, enabled): account = action.data().toPyObject() account.enabled = enabled account.save() def _AH_AudioAlertDeviceChanged(self, action): settings = SIPSimpleSettings() settings.audio.alert_device = action.data().toPyObject() call_in_auxiliary_thread(settings.save) def _AH_AudioInputDeviceChanged(self, action): settings = SIPSimpleSettings() settings.audio.input_device = action.data().toPyObject() call_in_auxiliary_thread(settings.save) def _AH_AudioOutputDeviceChanged(self, action): settings = SIPSimpleSettings() settings.audio.output_device = action.data().toPyObject() call_in_auxiliary_thread(settings.save) def _AH_AutoAcceptChatTriggered(self, checked): settings = SIPSimpleSettings() settings.chat.auto_accept = checked settings.save() def _AH_AutoAcceptFilesTriggered(self, checked): settings = SIPSimpleSettings() settings.file_transfer.auto_accept = checked settings.save() def _AH_EnableAnsweringMachineTriggered(self, checked): settings = SIPSimpleSettings() settings.answering_machine.enabled = checked settings.save() def _AH_GoogleContactsActionTriggered(self): settings = SIPSimpleSettings() if settings.google_contacts.authorization_token is not None: settings.google_contacts.authorization_token = None settings.save() self.google_contacts_dialog.hide() else: self.google_contacts_dialog.open() def _AH_RedialActionTriggered(self): session_manager = SessionManager() if session_manager.last_dialed_uri is not None: session_manager.start_call(None, unicode(session_manager.last_dialed_uri)) def _AH_SIPServerSettings(self, checked): account = self.identity.itemData(self.identity.currentIndex()).toPyObject().account account = account if account is not BonjourAccount() and account.server.settings_url else None self.server_tools_window.open_settings_page(account) def _AH_SearchForPeople(self, checked): account = self.identity.itemData(self.identity.currentIndex()).toPyObject().account account = account if account is not BonjourAccount() and account.server.settings_url else None self.server_tools_window.open_search_for_people_page(account) def _AH_HistoryOnServer(self, checked): account = self.identity.itemData(self.identity.currentIndex()).toPyObject().account account = account if account is not BonjourAccount() and account.server.settings_url else None self.server_tools_window.open_history_page(account) def _AH_PurchasePstnAccess(self, checked): account = self.identity.itemData(self.identity.currentIndex()).toPyObject().account account = account if account is not BonjourAccount() and account.server.settings_url else None self.server_tools_window.open_buy_pstn_access_page(account) def _AH_VoicemailActionTriggered(self, action, checked): account = action.data().toPyObject() SessionManager().start_call("Voicemail", account.voicemail_uri, account=account) def _SH_AddContactButtonClicked(self, clicked): model = self.contact_model selected_items = ((index.row(), model.data(index)) for index in self.contact_list.selectionModel().selectedIndexes()) try: item = (item for row, item in sorted(selected_items) if type(item) in (Contact, ContactGroup)).next() preferred_group = item if type(item) is ContactGroup else item.group except StopIteration: try: preferred_group = (group for group in model.contact_groups if type(group) is ContactGroup).next() except StopIteration: preferred_group = None self.contact_editor_dialog.open_for_add(self.search_box.text(), preferred_group) def _SH_AudioCallButtonClicked(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list selected_indexes = list_view.selectionModel().selectedIndexes() contact = list_view.model().data(selected_indexes[0]) if selected_indexes else Null address = contact.uri or unicode(self.search_box.text()) name = contact.name or None session_manager = SessionManager() session_manager.start_call(name, address, contact=contact, account=BonjourAccount() if isinstance(contact, BonjourNeighbour) else None) def _SH_BreakConference(self): active_session = self.session_model.data(self.session_list.selectionModel().selectedIndexes()[0]) self.session_model.breakConference(active_session.conference) def _SH_ContactDoubleClicked(self, index): contact = index.model().data(index) if not isinstance(contact, Contact): return session_manager = SessionManager() session_manager.start_call(contact.name, contact.uri, contact=contact, account=BonjourAccount() if isinstance(contact, BonjourNeighbour) else None) def _SH_ContactListSelectionChanged(self, selected, deselected): account_manager = AccountManager() selected_items = self.contact_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)==1 and isinstance(self.contact_model.data(selected_items[0]), Contact)) def _SH_ContactModelAddedItems(self, items): if self.search_box.text().isEmpty(): return active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel self.search_view.setCurrentWidget(active_widget) def _SH_ContactModelRemovedItems(self, items): if self.search_box.text().isEmpty(): return if any(type(item) is Contact for item in items) and self.contact_search_model.rowCount() == 0: self.search_box.clear() else: active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel self.search_view.setCurrentWidget(active_widget) def _SH_DisplayNameEditingFinished(self): self.display_name.clearFocus() index = self.identity.currentIndex() if index != -1: name = unicode(self.display_name.text()) account = self.identity.itemData(index).toPyObject().account account.display_name = name if name else None account.save() def _SH_HangupAllButtonClicked(self): for session in self.session_model.sessions: session.end() def _SH_IdentityChanged(self, index): account_manager = AccountManager() account_manager.default_account = self.identity.itemData(index).toPyObject().account def _SH_IdentityCurrentIndexChanged(self, index): if index != -1: account = self.identity.itemData(index).toPyObject().account self.display_name.setText(account.display_name or u'') self.display_name.setEnabled(True) self.activity_note.setEnabled(True) self.status.setEnabled(True) if not self.session_model.active_sessions: self.status.setCurrentIndex(self.idle_status_index) else: self.display_name.clear() self.display_name.setEnabled(False) self.activity_note.setEnabled(False) self.status.setEnabled(False) self.status.setCurrentIndex(self.status.findText(u'Offline')) def _SH_MakeConference(self): self.session_model.conferenceSessions([session for session in self.session_model.active_sessions if session.conference is None]) def _SH_MuteButtonClicked(self, muted): self.mute_action.setChecked(muted) self.mute_button.setChecked(muted) SIPApplication.voice_audio_bridge.mixer.muted = muted def _SH_SearchBoxReturnPressed(self): address = unicode(self.search_box.text()) if address: session_manager = SessionManager() session_manager.start_call(None, address) def _SH_SearchBoxTextChanged(self, text): account_manager = AccountManager() if text: self.switch_view_button.view = SwitchViewButton.ContactView selected_items = self.search_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1) else: selected_items = self.contact_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)==1 and type(self.contact_model.data(selected_items[0])) is Contact) active_widget = self.contact_list_panel if text.isEmpty() else self.search_panel if active_widget is self.search_panel and self.contacts_view.currentWidget() is not self.search_panel: self.search_list.selectionModel().clearSelection() self.contacts_view.setCurrentWidget(active_widget) active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel self.search_view.setCurrentWidget(active_widget) def _SH_SearchListSelectionChanged(self, selected, deselected): account_manager = AccountManager() selected_items = self.search_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1) def _SH_ServerToolsAccountModelChanged(self, parent_index, start, end): server_tools_enabled = self.server_tools_account_model.rowCount() > 0 self.sip_server_settings_action.setEnabled(server_tools_enabled) self.search_for_people_action.setEnabled(server_tools_enabled) self.history_on_server_action.setEnabled(server_tools_enabled) self.buy_pstn_access_action.setEnabled(server_tools_enabled) def _SH_SessionListSelectionChanged(self, selected, deselected): selected_indexes = selected.indexes() active_session = self.session_model.data(selected_indexes[0]) if selected_indexes else Null if active_session.conference: self.conference_button.setEnabled(True) self.conference_button.setChecked(True) else: self.conference_button.setEnabled(len([session for session in self.session_model.active_sessions if session.conference is None]) > 1) self.conference_button.setChecked(False) def _SH_SessionModelAddedSession(self, session_item): if session_item.session.state is None: self.search_box.clear() def _SH_SessionModelChangedStructure(self): active_sessions = self.session_model.active_sessions self.active_sessions_label.setText(u'There is 1 active call' if len(active_sessions)==1 else u'There are %d active calls' % len(active_sessions)) self.active_sessions_label.setVisible(any(active_sessions)) self.hangup_all_button.setEnabled(any(active_sessions)) selected_indexes = self.session_list.selectionModel().selectedIndexes() active_session = self.session_model.data(selected_indexes[0]) if selected_indexes else Null if active_session.conference: self.conference_button.setEnabled(True) self.conference_button.setChecked(True) else: self.conference_button.setEnabled(len([session for session in active_sessions if session.conference is None]) > 1) self.conference_button.setChecked(False) if active_sessions and self.status.currentText() != u'Offline': self.status.setCurrentIndex(self.status.findText(u'On the phone')) else: self.status.setCurrentIndex(self.idle_status_index) def _SH_SilentButtonClicked(self, silent): settings = SIPSimpleSettings() settings.audio.silent = silent settings.save() def _SH_StatusChanged(self, index): self.idle_status_index = index def _SH_SwitchViewButtonChangedView(self, view): self.main_view.setCurrentWidget(self.contacts_panel if view is SwitchViewButton.ContactView else self.sessions_panel) @run_in_gui_thread def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) def _NH_SIPApplicationWillStart(self, notification): account_manager = AccountManager() settings = SIPSimpleSettings() self.silent_action.setChecked(settings.audio.silent) self.silent_button.setChecked(settings.audio.silent) self.answering_machine_action.setChecked(settings.answering_machine.enabled) self.auto_accept_chat_action.setChecked(settings.chat.auto_accept) self.auto_accept_files_action.setChecked(settings.file_transfer.auto_accept) if settings.google_contacts.authorization_token is None: self.google_contacts_action.setText(u'Enable Google Contacts') else: self.google_contacts_action.setText(u'Disable Google Contacts') self.google_contacts_action.triggered.connect(self._AH_GoogleContactsActionTriggered) if not any(account.enabled for account in account_manager.iter_accounts()): self.display_name.setEnabled(False) self.activity_note.setEnabled(False) self.status.setEnabled(False) self.status.setCurrentIndex(self.status.findText(u'Offline')) def _NH_SIPApplicationDidStart(self, notification): self.load_audio_devices() notification_center = NotificationCenter() notification_center.add_observer(self, name='CFGSettingsObjectDidChange') notification_center.add_observer(self, name='AudioDevicesDidChange') def _NH_AudioDevicesDidChange(self, notification): for action in self.output_device_menu.actions(): self.output_devices_group.removeAction(action) self.output_device_menu.removeAction(action) for action in self.input_device_menu.actions(): self.input_devices_group.removeAction(action) self.input_device_menu.removeAction(action) for action in self.alert_device_menu.actions(): self.alert_devices_group.removeAction(action) self.alert_device_menu.removeAction(action) if self.session_model.active_sessions: old_devices = set(notification.data.old_devices) new_devices = set(notification.data.new_devices) added_devices = new_devices - old_devices if added_devices: new_device = added_devices.pop() settings = SIPSimpleSettings() settings.audio.input_device = new_device settings.audio.output_device = new_device settings.save() self.load_audio_devices() def _NH_CFGSettingsObjectDidChange(self, notification): settings = SIPSimpleSettings() if notification.sender is settings: if 'audio.silent' in notification.data.modified: self.silent_action.setChecked(settings.audio.silent) self.silent_button.setChecked(settings.audio.silent) if 'audio.output_device' in notification.data.modified: action = (action for action in self.output_devices_group.actions() if action.data().toPyObject() == settings.audio.output_device).next() action.setChecked(True) if 'audio.input_device' in notification.data.modified: action = (action for action in self.input_devices_group.actions() if action.data().toPyObject() == settings.audio.input_device).next() action.setChecked(True) if 'audio.alert_device' in notification.data.modified: action = (action for action in self.alert_devices_group.actions() if action.data().toPyObject() == settings.audio.alert_device).next() action.setChecked(True) if 'answering_machine.enabled' in notification.data.modified: self.answering_machine_action.setChecked(settings.answering_machine.enabled) if 'chat.auto_accept' in notification.data.modified: self.auto_accept_chat_action.setChecked(settings.chat.auto_accept) if 'file_transfer.auto_accept' in notification.data.modified: self.auto_accept_files_action.setChecked(settings.file_transfer.auto_accept) if 'google_contacts.authorization_token' in notification.data.modified: authorization_token = notification.sender.google_contacts.authorization_token if authorization_token is None: self.google_contacts_action.setText(u'Enable Google Contacts') else: self.google_contacts_action.setText(u'Disable Google Contacts') if authorization_token is InvalidToken: self.google_contacts_dialog.open_for_incorrect_password() elif isinstance(notification.sender, (Account, BonjourAccount)): account_manager = AccountManager() account = notification.sender if 'enabled' in notification.data.modified: action = (action for action in self.accounts_menu.actions() if action.data().toPyObject() is account).next() action.setChecked(account.enabled) if 'display_name' in notification.data.modified and account is account_manager.default_account: self.display_name.setText(account.display_name or u'') if set(['enabled', 'message_summary.enabled', 'message_summary.voicemail_uri']).intersection(notification.data.modified): action = (action for action in self.voicemail_menu.actions() if action.data().toPyObject() is account).next() action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled) action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None) def _NH_SIPAccountManagerDidAddAccount(self, notification): account = notification.data.account action = QAction(account.id if account is not BonjourAccount() else u'Bonjour', None) action.setEnabled(True if account is not BonjourAccount() else BonjourAccount.mdns_available) action.setCheckable(True) action.setChecked(account.enabled) action.setData(QVariant(account)) action.triggered.connect(partial(self._AH_AccountActionTriggered, action)) self.accounts_menu.addAction(action) action = QAction(self.mwi_icons[0], account.id, None) action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled) action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None) action.setData(QVariant(account)) action.triggered.connect(partial(self._AH_VoicemailActionTriggered, action)) self.voicemail_menu.addAction(action) def _NH_SIPAccountManagerDidRemoveAccount(self, notification): account = notification.data.account action = (action for action in self.accounts_menu.actions() if action.data().toPyObject() is account).next() self.accounts_menu.removeAction(action) action = (action for action in self.voicemail_menu.actions() if action.data().toPyObject() is account).next() self.voicemail_menu.removeAction(action) def _NH_SIPAccountManagerDidChangeDefaultAccount(self, notification): if notification.data.account is None: self.enable_call_buttons(False) else: selected_items = self.contact_list.selectionModel().selectedIndexes() self.enable_call_buttons(len(selected_items)==1 and isinstance(self.contact_model.data(selected_items[0]), Contact)) def _NH_SIPAccountMWIDidGetSummary(self, notification): account = notification.sender summary = notification.data.message_summary action = (action for action in self.voicemail_menu.actions() if action.data().toPyObject() is account).next() action.setEnabled(account.voicemail_uri is not None) if summary.messages_waiting: try: new_messages = limit(int(summary.summaries['voice-message']['new_messages']), min=0, max=11) except (KeyError, ValueError): new_messages = 0 else: new_messages = 0 action.setIcon(self.mwi_icons[new_messages])
class XSplitButton(QWidget): """ ~~>[img:widgets/xsplitbutton.png] The XSplitButton class provides a simple class for creating a multi-checkable tool button based on QActions and QActionGroups. === Example Usage === |>>> from projexui.widgets.xsplitbutton import XSplitButton |>>> import projexui | |>>> # create the widget |>>> widget = projexui.testWidget(XSplitButton) | |>>> # add some actions (can be text or a QAction) |>>> widget.addAction('Day') |>>> widget.addAction('Month') |>>> widget.addAction('Year') | |>>> # create connections |>>> def printAction(act): print act.text() |>>> widget.actionGroup().triggered.connect(printAction) """ __designer_icon__ = projexui.resources.find('img/ui/multicheckbox.png') clicked = Signal() currentActionChanged = Signal(object) hovered = Signal(object) triggered = Signal(object) def __init__( self, parent = None ): super(XSplitButton, self).__init__( parent ) # define custom properties self._actionGroup = QActionGroup(self) self._padding = 5 self._cornerRadius = 10 #self._currentAction = None self._checkable = True # set default properties layout = QBoxLayout(QBoxLayout.LeftToRight) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.setLayout(layout) self.clear() # create connections self._actionGroup.hovered.connect(self.emitHovered) self._actionGroup.triggered.connect(self.emitTriggered) def actions(self): """ Returns a list of the actions linked with this widget. :return [<QAction>, ..] """ return self._actionGroup.actions() def actionTexts(self): """ Returns a list of the action texts for this widget. :return [<str>, ..] """ return map(lambda x: x.text(), self._actionGroup.actions()) def actionGroup( self ): """ Returns the action group linked with this widget. :return <QActionGroup> """ return self._actionGroup def addAction(self, action, checked=None, autoBuild=True): """ Adds the inputed action to this widget's action group. This will auto-\ create a new group if no group is already defined. :param action | <QAction> || <str> :return <QAction> """ # clear the holder actions = self._actionGroup.actions() if actions and actions[0].objectName() == 'place_holder': self._actionGroup.removeAction(actions[0]) actions[0].deleteLater() # create an action from the name if not isinstance(action, QAction): action_name = str(action) action = QAction(action_name, self) action.setObjectName(action_name) action.setCheckable(self.isCheckable()) # auto-check the first option if checked or (not self._actionGroup.actions() and checked is None): action.setChecked(True) self._actionGroup.addAction(action) if autoBuild: self.rebuild() return action def clear(self, autoBuild=True): """ Clears the actions for this widget. """ for action in self._actionGroup.actions(): self._actionGroup.removeAction(action) action = QAction('', self) action.setObjectName('place_holder') # self._currentAction = None self._actionGroup.addAction(action) if autoBuild: self.rebuild() def cornerRadius( self ): """ Returns the corner radius for this widget. :return <int> """ return self._cornerRadius def count(self): """ Returns the number of actions associated with this button. :return <int> """ actions = self._actionGroup.actions() if len(actions) == 1 and actions[0].objectName() == 'place_holder': return 0 return len(actions) def currentAction( self ): """ Returns the action that is currently checked in the system. :return <QAction> || None """ return self._actionGroup.checkedAction() def direction( self ): """ Returns the direction for this widget. :return <QBoxLayout::Direction> """ return self.layout().direction() def emitClicked(self): """ Emits the clicked signal whenever any of the actions are clicked. """ if not self.signalsBlocked(): self.clicked.emit() def emitHovered(self, action): """ Emits the hovered action for this widget. :param action | <QAction> """ if not self.signalsBlocked(): self.hovered.emit(action) def emitTriggered(self, action): """ Emits the triggered action for this widget. :param action | <QAction> """ # if action != self._currentAction: # self._currentAction = action # self.currentActionChanged.emit(action) # self._currentAction = action if not self.signalsBlocked(): self.triggered.emit(action) def findAction( self, text ): """ Looks up the action based on the inputed text. :return <QAction> || None """ for action in self.actionGroup().actions(): if ( text in (action.objectName(), action.text()) ): return action return None def isCheckable(self): """ Returns whether or not the actions within this button should be checkable. :return <bool> """ return self._checkable def padding( self ): """ Returns the button padding amount for this widget. :return <int> """ return self._padding def rebuild( self ): """ Rebuilds the user interface buttons for this widget. """ self.setUpdatesEnabled(False) # sync up the toolbuttons with our actions actions = self._actionGroup.actions() btns = self.findChildren(QToolButton) horiz = self.direction() in (QBoxLayout.LeftToRight, QBoxLayout.RightToLeft) # remove unnecessary buttons if len(actions) < len(btns): rem_btns = btns[len(actions)-1:] btns = btns[:len(actions)] for btn in rem_btns: btn.close() btn.setParent(None) btn.deleteLater() # create new buttons elif len(btns) < len(actions): for i in range(len(btns), len(actions)): btn = QToolButton(self) btn.setAutoFillBackground(True) btns.append(btn) self.layout().addWidget(btn) btn.clicked.connect(self.emitClicked) # determine coloring options palette = self.palette() checked = palette.color(palette.Highlight) checked_fg = palette.color(palette.HighlightedText) unchecked = palette.color(palette.Button) unchecked_fg = palette.color(palette.ButtonText) border = palette.color(palette.Mid) # define the stylesheet options options = {} options['top_left_radius'] = 0 options['top_right_radius'] = 0 options['bot_left_radius'] = 0 options['bot_right_radius'] = 0 options['border_color'] = border.name() options['checked_fg'] = checked_fg.name() options['checked_bg'] = checked.name() options['checked_bg_alt'] = checked.darker(120).name() options['unchecked_fg'] = unchecked_fg.name() options['unchecked_bg'] = unchecked.name() options['unchecked_bg_alt'] = unchecked.darker(120).name() options['padding_top'] = 1 options['padding_bottom'] = 1 options['padding_left'] = 1 options['padding_right'] = 1 if horiz: options['x1'] = 0 options['y1'] = 0 options['x2'] = 0 options['y2'] = 1 else: options['x1'] = 0 options['y1'] = 0 options['x2'] = 1 options['y2'] = 1 # sync up the actions and buttons count = len(actions) palette = self.palette() font = self.font() for i, action in enumerate(actions): btn = btns[i] # assign the action for this button if btn.defaultAction() != action: # clear out any existing actions for act in btn.actions(): btn.removeAction(act) # assign the given action btn.setDefaultAction(action) options['top_left_radius'] = 1 options['bot_left_radius'] = 1 options['top_right_radius'] = 1 options['bot_right_radius'] = 1 if horiz: options['padding_left'] = self._padding options['padding_right'] = self._padding else: options['padding_top'] = self._padding options['padding_bottom'] = self._padding if not i: if horiz: options['top_left_radius'] = self.cornerRadius() options['bot_left_radius'] = self.cornerRadius() options['padding_left'] += self.cornerRadius() / 3.0 else: options['top_left_radius'] = self.cornerRadius() options['top_right_radius'] = self.cornerRadius() options['padding_top'] += self.cornerRadius() / 3.0 if i == count - 1: if horiz: options['top_right_radius'] = self.cornerRadius() options['bot_right_radius'] = self.cornerRadius() options['padding_right'] += self.cornerRadius() / 3.0 else: options['bot_left_radius'] = self.cornerRadius() options['bot_right_radius'] = self.cornerRadius() options['padding_bottom'] += self.cornerRadius() / 3.0 btn.setFont(font) btn.setPalette(palette) btn.setStyleSheet(TOOLBUTTON_STYLE % options) if horiz: btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) else: btn.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self.setUpdatesEnabled(True) def setActions(self, actions): """ Sets the actions for this widget to th inputed list of actions. :param [<QAction>, ..] """ self.clear(autoBuild=False) for action in actions: self.addAction(action, autoBuild=False) self.rebuild() def setActionTexts(self, names): """ Convenience method for auto-generating actions based on text names, sets the list of actions for this widget to the inputed list of names. :param names | [<str>, ..] """ self.setActions(names) def setActionGroup( self, actionGroup ): """ Sets the action group for this widget to the inputed action group. :param actionGroup | <QActionGroup> """ self._actionGroup = actionGroup self.rebuild() def setCheckable(self, state): """ Sets whether or not the actions within this button should be checkable. :param state | <bool> """ self._checkable = state for act in self._actionGroup.actions(): act.setCheckable(state) def setCornerRadius( self, radius ): """ Sets the corner radius value for this widget to the inputed radius. :param radius | <int> """ self._cornerRadius = radius def setCurrentAction(self, action): """ Sets the current action for this button to the inputed action. :param action | <QAction> || <str> """ self._actionGroup.blockSignals(True) for act in self._actionGroup.actions(): act.setChecked(act == action or act.text() == action) self._actionGroup.blockSignals(False) def setDirection( self, direction ): """ Sets the direction that this group widget will face. :param direction | <QBoxLayout::Direction> """ self.layout().setDirection(direction) self.rebuild() def setFont(self, font): """ Sets the font for this widget and propogates down to the buttons. :param font | <QFont> """ super(XSplitButton, self).setFont(font) self.rebuild() def setPadding( self, padding ): """ Sets the padding amount for this widget's button set. :param padding | <int> """ self._padding = padding self.rebuild() def setPalette(self, palette): """ Rebuilds the buttons for this widget since they use specific palette options. :param palette | <QPalette> """ super(XSplitButton, self).setPalette(palette) self.rebuild() def sizeHint(self): """ Returns the base size hint for this widget. :return <QSize> """ return QSize(35, 22) x_actionTexts = Property(QStringList, actionTexts, setActionTexts) x_checkable = Property(bool, isCheckable, setCheckable)
class FilterClauseWidget(QWidget, Ui_FilterClauseWidget): clauseAdded = pyqtSignal() clauseRemoved = pyqtSignal(int) clauseChanged = pyqtSignal(int) def __init__(self, parent=None): super(FilterClauseWidget, self).__init__(parent) self.setupUi(self) self._filterIndex = -1 self._filterType = FilterType.Include self._filterActionStatus = -1 self._siteCode = '' self._addIcon = QIcon(':/plugins/ark/filter/addFilter.svg') self._addAction = QAction(self._addIcon, 'Add filter', self) self._addAction.setStatusTip('Add filter') self._addAction.triggered.connect(self._addFilterClicked) self._removeIcon = QIcon(':/plugins/ark/filter/removeFilter.svg') self._removeAction = QAction(self._removeIcon, 'Remove filter', self) self._removeAction.setStatusTip('Remove filter') self._removeAction.triggered.connect(self._removeFilterClicked) self.setFilterAction(FilterWidgetAction.AddFilter) self._includeIcon = QIcon(':/plugins/ark/filter/includeFilter.png') self._includeAction = QAction(self._includeIcon, 'Include', self) self._includeAction.setStatusTip('Include items in selection') self._includeAction.setCheckable(True) self._includeAction.triggered.connect(self._includeFilterChecked) self._excludeIcon = QIcon(':/plugins/ark/filter/excludeFilter.png') self._excludeAction = QAction(self._excludeIcon, 'Exclude', self) self._excludeAction.setStatusTip('Exclude items from selection') self._excludeAction.setCheckable(True) self._excludeAction.triggered.connect(self._excludeFilterChecked) self._selectIcon = QIcon(':/plugins/ark/filter/selectFilter.svg') self._selectAction = QAction(self._selectIcon, 'Select', self) self._selectAction.setStatusTip('Select items') self._selectAction.setCheckable(True) self._selectAction.triggered.connect(self._selectFilterChecked) self._highlightIcon = QIcon(':/plugins/ark/filter/highlightFilter.svg') self._highlightAction = QAction(self._highlightIcon, 'Highlight', self) self._highlightAction.setStatusTip('Highlight items') self._highlightAction.setCheckable(True) self._highlightAction.triggered.connect(self._highlightFilterChecked) self._typeActionGroup = QActionGroup(self) self._typeActionGroup.addAction(self._includeAction) self._typeActionGroup.addAction(self._excludeAction) self._typeActionGroup.addAction(self._selectAction) self._typeActionGroup.addAction(self._highlightAction) self._colorTool = QgsColorButtonV2(self) self._colorTool.setAllowAlpha(True) self._colorTool.setColorDialogTitle('Choose Highlight Color') self._colorTool.setContext('Choose Highlight Color') self._colorTool.setDefaultColor(Application.highlightFillColor()) self._colorTool.setToDefaultColor() self._colorTool.colorChanged.connect(self._colorChanged) self._colorAction = QWidgetAction(self) self._colorAction.setDefaultWidget(self._colorTool) self._typeMenu = QMenu(self) self._typeMenu.addActions(self._typeActionGroup.actions()) self._typeMenu.addSeparator() self._typeMenu.addAction(self._colorAction) self.filterTypeTool.setMenu(self._typeMenu) self._setFilterType(FilterType.Include) def index(self): return self._filterIndex def setIndex(self, index): self._filterIndex = index def clause(self): cl = FilterClause() cl.item = Item(self.siteCode(), self.classCode(), self.filterRange()) cl.action = self.filterType() cl.color = self.color() return cl def setClause(self, clause): self.blockSignals(True) self._colorTool.blockSignals(True) self._siteCode = clause.item.siteCode() self.filterClassCombo.setCurrentIndex(self.filterClassCombo.findData(clause.item.classCode())) self.filterRangeCombo.setEditText(clause.item.itemId()) self._setFilterType(clause.action) # self._colorTool.setColor(clause.color) self._colorTool.blockSignals(False) self.blockSignals(False) def _setFilterType(self, filterType): self._filterType = filterType if filterType == FilterType.Exclude: self._excludeAction.setChecked(True) self.filterTypeTool.setDefaultAction(self._excludeAction) elif filterType == FilterType.Select: self._selectAction.setChecked(True) self.filterTypeTool.setDefaultAction(self._selectAction) elif filterType == FilterType.Highlight: self._highlightAction.setChecked(True) self.filterTypeTool.setDefaultAction(self._highlightAction) else: self._includeAction.setChecked(True) self.filterTypeTool.setDefaultAction(self._includeAction) def filterType(self): return self._filterType def siteCode(self): return self._siteCode def setSiteCode(self, siteCode): self._siteCode = siteCode def classCode(self): return self.filterClassCombo.itemData(self.filterClassCombo.currentIndex()) def filterRange(self): return self._normaliseRange(self.filterRangeCombo.currentText()) def color(self): return self._colorTool.color() def setClassCodes(self, codes): self.filterClassCombo.clear() keys = codes.keys() keys.sort() for key in keys: self.filterClassCombo.addItem(codes[key], key) def setHistory(self, history): self.filterRangeCombo.addItems(history) self.filterRangeCombo.clearEditText() def history(self): history = [] for idx in range(0, self.filterRangeCombo.count()): history.append(self.filterRangeCombo.itemText(idx)) return history def clearFilterRange(self): self.filterRangeCombo.clearEditText() def setFilterAction(self, action): if self._filterActionStatus == FilterWidgetAction.AddFilter: self.filterRangeCombo.lineEdit().returnPressed.disconnect(self._addFilterClicked) elif self._filterActionStatus == FilterWidgetAction.RemoveFilter: self.filterRangeCombo.lineEdit().editingFinished.disconnect(self._filterRangeChanged) self._filterActionStatus = action if action == FilterWidgetAction.LockFilter: self.filterActionTool.removeAction(self._addAction) self.filterActionTool.setDefaultAction(self._removeAction) self.setEnabled(False) elif action == FilterWidgetAction.RemoveFilter: self.filterActionTool.removeAction(self._addAction) self.filterActionTool.setDefaultAction(self._removeAction) self.filterRangeCombo.lineEdit().editingFinished.connect(self._filterRangeChanged) self.setEnabled(True) else: self.filterActionTool.removeAction(self._removeAction) self.filterActionTool.setDefaultAction(self._addAction) self.filterRangeCombo.lineEdit().returnPressed.connect(self._addFilterClicked) self.setEnabled(True) def _normaliseRange(self, text): return text.replace(' - ', '-').replace(',', ' ').strip() def _addFilterClicked(self): self.setFilterAction(FilterWidgetAction.RemoveFilter) self.clauseAdded.emit() def _removeFilterClicked(self): self.clauseRemoved.emit(self._filterIndex) def _includeFilterChecked(self): self._setFilterType(FilterType.Include) self.clauseChanged.emit(self._filterIndex) def _excludeFilterChecked(self): self._setFilterType(FilterType.Exclude) self.clauseChanged.emit(self._filterIndex) def _highlightFilterChecked(self): self._setFilterType(FilterType.Highlight) self.clauseChanged.emit(self._filterIndex) def _selectFilterChecked(self): self._setFilterType(FilterType.Select) self.clauseChanged.emit(self._filterIndex) def _filterRangeChanged(self): self.clauseChanged.emit(self._filterIndex) def _colorChanged(self, color): pix = QPixmap(22, 22) pix.fill(color) self._highlightIcon = QIcon(pix) self._highlightAction.setIcon(self._highlightIcon) self._setFilterType(FilterType.Highlight) self.clauseChanged.emit(self._filterIndex)
class EjdexplInt: def __init__(self, iface): self.iface = iface self.plugin_dir = os.path.dirname(__file__) self.searchobj = None self.readconfig() self.updateconfig() self.srsitem = CanvasItems(self.iface.mapCanvas(),self.config['search_color'],self.config['search_style'],self.config['search_width'],self.config['search_icon'],self.config['search_size']) self.db = QSqlDatabase.addDatabase('QODBC') self.db.setDatabaseName(self.config['connection']) locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir,'i18n','EjdexplInt_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) def tr(self, message): return QCoreApplication.translate('EjdexplInt', message) def initGui(self): self.action = QAction(QIcon(":/plugins/EjdexplInt/icons/icon.png"),self.tr(u'Activate EjdExplorer tool'),self.iface.mainWindow()) self.action.setWhatsThis(u"Activate EjdExplorer tool") self.action.triggered.connect(self.run) self.tbmenu = QMenu() self.ag1 = QActionGroup(self.tbmenu,exclusive=True) self.acPol = self.ag1.addAction(QAction(QIcon(':/plugins/EjdexplInt/icons/Icons8-Ios7-Maps-Polygon.ico'),self.tr(u'Draw polygon'),self.tbmenu,checkable=True)) self.acLin = self.ag1.addAction(QAction(QIcon(':/plugins/EjdexplInt/icons/Icons8-Ios7-Maps-Polyline.ico'),self.tr(u'Draw line'),self.tbmenu,checkable=True)) self.acPnt = self.ag1.addAction(QAction(QIcon(':/plugins/EjdexplInt/icons/Icons8-Ios7-Maps-Geo-Fence.ico'),self.tr(u'Draw point'),self.tbmenu,checkable=True)) self.acAlay = self.ag1.addAction(QAction(QIcon(':/plugins/EjdexplInt/icons/Icons8-Ios7-Maps-Layers.ico'),self.tr(u'Active selection'),self.tbmenu,checkable=True)) self.acPobj = self.ag1.addAction(QAction(QIcon(':/plugins/EjdexplInt/icons/Icons8-Ios7-Maps-Quest.ico'),self.tr(u'Previous object'),self.tbmenu,checkable=True)) self.tbmenu.addActions(self.ag1.actions()); self.acPol.setChecked(self.config['searchtool']==u'polygon') self.acLin.setChecked(self.config['searchtool']==u'line') self.acPnt.setChecked(self.config['searchtool']==u'point') self.acAlay.setChecked(self.config['searchtool']==u'selection') self.acPobj.setChecked(self.config['searchtool']==u'search') self.tbmenu.addSeparator() self.ag2 = QActionGroup(self.tbmenu,exclusive=True) self.acSingle = self.ag2.addAction(QAction(self.tr(u'Use single mode'),self.tbmenu,checkable=True)) self.acBulk = self.ag2.addAction(QAction(self.tr(u'Use bulk mode'),self.tbmenu,checkable=True)) self.acMerge = self.ag2.addAction(QAction(self.tr(u'Use merge mode'),self.tbmenu,checkable=True)) self.tbmenu.addActions(self.ag2.actions()); self.acSingle.setChecked(self.config['tabchoice']==u'single') self.acBulk.setChecked(self.config['tabchoice']==u'bulk') self.acMerge.setChecked(self.config['tabchoice']==u'merge') if self.config['old_behavior'] == 0: self.tbmenu.addSeparator() self.acClear = QAction(self.tr(u'Clear'),self.tbmenu,checkable=False) self.acClear.triggered.connect(self.clearSearch) self.tbmenu.addAction(self.acClear) self.toolButton = QToolButton() self.toolButton.addAction(self.action) self.toolButton.setDefaultAction(self.action) self.toolButton.setMenu(self.tbmenu) self.toolButton.setPopupMode(QToolButton.MenuButtonPopup) self.iface.addToolBarWidget(self.toolButton) self.iface.addPluginToMenu(self.tr(u'Activate EjdExplorer tool'), self.action) self.ag1.triggered.connect(self.drawChanged) def drawChanged(self, action): if action.isChecked(): self.run() def clearSearch(self): if self.config['old_behavior'] == 0: self.srsitem.clearMarkerGeom() def unload(self): self.iface.removePluginMenu(self.tr(u'Activate EjdExplorer tool'), self.action) self.iface.removeToolBarIcon(self.action) del self.tbmenu # No parent del self.toolButton # No parent def run(self): geoms = None canvas = self.iface.mapCanvas() if self.config['old_behavior'] == 0: self.srsitem.clearMarkerGeom() if self.acPol.isChecked(): # polygon tool = CaptureTool(canvas, self.geometryAdded, CaptureTool.CAPTURE_POLYGON) canvas.setMapTool(tool) elif self.acLin.isChecked(): # line tool = CaptureTool(canvas, self.geometryAdded, CaptureTool.CAPTURE_LINE) canvas.setMapTool(tool) elif self.acPnt.isChecked(): # point tool = AddPointTool(canvas, self.geometryAdded) canvas.setMapTool(tool) elif self.acAlay.isChecked(): # active layer selection layer = self.iface.activeLayer() if (layer) and (layer.type() == QgsMapLayer.VectorLayer): selection = layer.selectedFeatures() if (selection): for f in selection: if geoms == None: geoms = f.geometry() else: geoms = geoms.combine( f.geometry() ) if (geoms != None): self.geometryAdded(geoms) else: self.iface.messageBar().pushMessage(self.tr(u'EjdExplorer - Object definition'), self.tr(u'No object found'), QgsMessageBar.CRITICAL, 6) elif self.acPobj.isChecked(): # existing object geoms = self.searchobj if (geoms != None): self.geometryAdded(geoms) else: self.iface.messageBar().pushMessage(self.tr(u'EjdExplorer - Object definition'), self.tr(u'No existing object found'), QgsMessageBar.CRITICAL, 6) self.acPol.setChecked(True) else: self.iface.messageBar().pushMessage(self.tr(u'EjdExplorer - Object definition'), self.tr(u'Uknown search tool'), QgsMessageBar.CRITICAL, 6) def cnvobj2wkt (self,gobj,epsg_in,epsg_out, buffer_pol, buffer_lin): # Buffer around search object; negative for polygon or positive for points and lines if gobj.type() == 2: # Polygon gobj = gobj.buffer(buffer_pol,8) else: # Line or Point gobj = gobj.buffer(buffer_lin,8) crsSrc = QgsCoordinateReferenceSystem(int(epsg_in)) crsDest = QgsCoordinateReferenceSystem(int(epsg_out)) xform = QgsCoordinateTransform(crsSrc, crsDest) i = gobj.transform(xform) return gobj.exportToWkt() def geometryAdded(self, geom): self.iface.messageBar().pushMessage(self.tr(u'EjdExplorer - Start EjdExplorer'), self.tr(u'Starting EjdExplorer program, takes a few seconds..'), QgsMessageBar.INFO, 6) self.searchobj = geom if self.config['old_behavior'] == 0: self.srsitem.setMarkerGeom(geom) epsg_in = self.iface.mapCanvas().mapRenderer().destinationCrs().authid().replace('EPSG:','') geom_txt = self.cnvobj2wkt (geom,epsg_in,self.config['epsg'],self.config['buffer_pol'],self.config['buffer_lin']) txt1, txt2 = self.getlists (geom_txt) mode = u'single' if self.acBulk.isChecked(): mode = u'bulk' if self.acMerge.isChecked(): mode = u'merge' # NB! parameters dosn't work as expected, LIFA contacted (and admit to an error in their program) txt = u'start ' + self.config['command'] + u' "' + self.config['parameter'].format(mode, txt1,txt2) + u'"' txt = txt.encode('latin-1') if len(txt) <= 8190: # max length of command-line parameter os.system ( txt) else: self.iface.messageBar().pushMessage(self.tr(u'EjdExplorer - Start EjdExplorer'), self.tr(u'To many entities selected; try with a smaller search object'), QgsMessageBar.CRITICAL, 6) self.iface.actionPan().trigger() def msgbox (self,txt1): cb = QApplication.clipboard() cb.setText(txt1) msgBox = QMessageBox() msgBox.setText(txt1) msgBox.exec_() def getlists(self, wkt): ejrlrv = [] matrnr = [] if (self.db.open()==True): query = QSqlQuery (self.config['sqlquery'].format(wkt,self.config['epsg'])) while (query.next()): ejrlrv.append(query.value(0)) matrnr.append(query.value(1)) else: self.iface.messageBar().pushMessage(self.tr(u'EjdExplorer - Database Error'), db.lastError().text(), QgsMessageBar.INFO, 6) return u','.join(ejrlrv), u','.join(matrnr) def readconfig(self): s = QSettings() k = __package__ self.config = { 'epsg': unicode(s.value(k + "/epsg" , "25832", type=str)), 'buffer_pol': s.value(k + "/buffer_pol" , -0.1, type=float), 'buffer_lin': s.value(k + "/buffer_lin" , 0.1, type=float), 'searchtool': unicode(s.value(k + "/searchtool" , "point", type=str)).lower(), 'tabchoice': unicode(s.value(k + "/tabchoice" , "single", type=str)).lower(), 'sqlquery': unicode(s.value(k + "/sqlquery" , "select LTRIM(RTRIM(CONVERT(varchar(10), [landsejerlavskode]))) as ejrlvnr, LTRIM(RTRIM([matrikelnummer])) as matrnr from [dbo].[Jordstykke] where geometry::STGeomFromText('{0}',{1}).STIntersects([geometri])=1", type=str)), 'connection': unicode(s.value(k + "/connection" , "Driver={SQL Server};Server=f-sql12;Database=LOIS;Trusted_Connection=Yes;", type=str)), 'command': unicode(s.value(k + "/command" , 'C:/"Program Files (x86)"/LIFA/EjdExplorer/LIFA.EjdExplorer.GUI.exe', type=str)), 'parameter': unicode(s.value(k + "/parameter" , 'ejdexpl://?mode={0}&CadastralDistrictIdentifier={1}&RealPropertyKey={2}', type=str)), 'search_color': str(s.value(k + "/search_color", "#FF0000", type=str)), 'search_width': s.value(k + "/search_width", 4, type=int), 'search_style': s.value(k + "/search_style", 1, type=int), 'search_icon': s.value(k + "/search_icon", QgsVertexMarker.ICON_CROSS, type=int), 'search_size': s.value(k + "/search_size", 30, type=int), 'old_behavior': s.value(k + "/old_behavior", 0, type=int) } self.srsitem = CanvasItems(self.iface.mapCanvas(),self.config['search_color'],self.config['search_style'],self.config['search_width'],self.config['search_icon'],self.config['search_size']) def updateconfig(self): s = QSettings() k = __package__ s.setValue(k + "/epsg", self.config['epsg']) s.setValue(k + "/buffer_pol", self.config['buffer_pol']) s.setValue(k + "/buffer_lin", self.config['buffer_lin']) s.setValue(k + "/searchtool", self.config['searchtool']) s.setValue(k + "/tabchoice", self.config['tabchoice']) s.setValue(k + "/sqlquery", self.config['sqlquery']) s.setValue(k + "/connection", self.config['connection']) s.setValue(k + "/command", self.config['command']) s.setValue(k + "/parameter", self.config['parameter']) s.setValue(k + "/search_color", self.config['search_color']) s.setValue(k + "/search_style", self.config['search_style']) s.setValue(k + "/search_width", self.config['search_width']) s.setValue(k + "/search_icon", self.config['search_icon']) s.setValue(k + "/search_size", self.config['search_size']) s.setValue(k + "/old_behavior", self.config['old_behavior']) s.sync
class LayerSnappingAction(LayerSnappingEnabledAction): """Action to change snapping settings for a QGIS vector layer.""" snapSettingsChanged = pyqtSignal(str) def __init__(self, snapLayer, parent=None): super(LayerSnappingAction, self).__init__(snapLayer, parent) self._toleranceAction = None # LayerSnappingToleranceAction() self._avoidAction = None # LayerSnappingAvoidIntersectionsAction() self._vertexAction = LayerSnappingTypeAction(snapLayer, Snapping.Vertex, self) self._segmentAction = LayerSnappingTypeAction(snapLayer, Snapping.Segment, self) self._vertexSegmentAction = LayerSnappingTypeAction( snapLayer, Snapping.VertexAndSegment, self) self._snappingTypeActionGroup = QActionGroup(self) self._snappingTypeActionGroup.addAction(self._vertexAction) self._snappingTypeActionGroup.addAction(self._segmentAction) self._snappingTypeActionGroup.addAction(self._vertexSegmentAction) self._toleranceAction = LayerSnappingToleranceAction(snapLayer, parent) self._pixelUnitsAction = LayerSnappingUnitAction( snapLayer, Snapping.Pixels, self) self._layerUnitsAction = LayerSnappingUnitAction( snapLayer, Snapping.LayerUnits, self) self._projectUnitsAction = LayerSnappingUnitAction( snapLayer, Snapping.ProjectUnits, self) self._unitTypeActionGroup = QActionGroup(self) self._unitTypeActionGroup.addAction(self._pixelUnitsAction) self._unitTypeActionGroup.addAction(self._layerUnitsAction) self._unitTypeActionGroup.addAction(self._projectUnitsAction) menu = ControlMenu(parent) menu.addActions(self._snappingTypeActionGroup.actions()) menu.addSeparator() menu.addAction(self._toleranceAction) menu.addActions(self._unitTypeActionGroup.actions()) if (isinstance(snapLayer, QgisInterface) or (isinstance(snapLayer, QgsVectorLayer) and snapLayer.geometryType() == QGis.Polygon)): self._avoidAction = LayerSnappingAvoidIntersectionsAction( snapLayer, self) menu.addSeparator() menu.addAction(self._avoidAction) self.setMenu(menu) self._refreshAction() # Make sure we catch changes in the main snapping dialog QgsProject.instance().snapSettingsChanged.connect(self._refreshAction) # If using current layer, make sure we update when it changes if self._iface: self._iface.legendInterface().currentLayerChanged.connect( self._refreshAction) # If any of the settings change then signal, but don't tell project as actions already have self.snappingEnabledChanged.connect(self.snapSettingsChanged) self._vertexAction.snappingTypeChanged.connect( self.snapSettingsChanged) self._segmentAction.snappingTypeChanged.connect( self.snapSettingsChanged) self._vertexSegmentAction.snappingTypeChanged.connect( self.snapSettingsChanged) self._toleranceAction.snappingToleranceChanged.connect( self.snapSettingsChanged) self._pixelUnitsAction.snappingUnitChanged.connect( self.snapSettingsChanged) self._layerUnitsAction.snappingUnitChanged.connect( self.snapSettingsChanged) self._projectUnitsAction.snappingUnitChanged.connect( self.snapSettingsChanged) if self._avoidAction: self._avoidAction.avoidIntersectionsChanged.connect( self.snapSettingsChanged) def setInterface(self, iface): self._toleranceAction.setInterface(iface) def unload(self): if not self._layerId: return super(LayerSnappingAction, self).unload() QgsProject.instance().snapSettingsChanged.disconnect( self._refreshAction) self.snappingEnabledChanged.disconnect(self.snapSettingsChanged) self._vertexAction.snappingTypeChanged.disconnect( self.snapSettingsChanged) self._segmentAction.snappingTypeChanged.disconnect( self.snapSettingsChanged) self._vertexSegmentAction.snappingTypeChanged.disconnect( self.snapSettingsChanged) self._toleranceAction.snappingToleranceChanged.disconnect( self.snapSettingsChanged) self._pixelUnitsAction.snappingUnitChanged.disconnect( self.snapSettingsChanged) self._layerUnitsAction.snappingUnitChanged.disconnect( self.snapSettingsChanged) self._projectUnitsAction.snappingUnitChanged.disconnect( self.snapSettingsChanged) if self._avoidAction: self._avoidAction.avoidIntersectionsChanged.disconnect( self.snapSettingsChanged) self._vertexAction.unload() self._segmentAction.unload() self._vertexSegmentAction.unload() self._toleranceAction.unload() self._pixelUnitsAction.unload() self._layerUnitsAction.unload() self._projectUnitsAction.unload() # Private API def _refreshAction(self): if (self._segmentAction.isChecked()): self.setIcon(self._segmentAction.icon()) elif (self._vertexSegmentAction.isChecked()): self.setIcon(self._vertexSegmentAction.icon()) else: # Snapping.Vertex or undefined self.setIcon(self._vertexAction.icon()) if self._iface and self._avoidAction: layer = QgsMapLayerRegistry.instance().mapLayer(self.layerId()) isPolygon = (layer is not None and layer.type() == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Polygon) self._avoidAction.setEnabled(isPolygon)
class ActionSettingsTool(QToolButton): settingsChanged = pyqtSignal() mapActionChanged = pyqtSignal(int) filterActionChanged = pyqtSignal(int) drawingActionChanged = pyqtSignal(int) def __init__(self, parent=None): super(ActionSettingsTool, self).__init__(parent) self._mapActionGroup = QActionGroup(self) self._noMapAction = self._addMapAction(MapAction.NoMapAction, 'No map action') self._zoomMapAction = self._addMapAction(MapAction.ZoomMap, 'Zoom map view') self._panMapAction = self._addMapAction(MapAction.PanMap, 'Pan map view') self._moveMapAction = self._addMapAction(MapAction.MoveMap, 'Move map view') self._moveMapAction.setChecked(True) self._filterActionGroup = QActionGroup(self) self._noFilterAction = self._addFilterAction(FilterAction.NoFilterAction, 'No filter action') self._includeFilterAction = self._addFilterAction(FilterAction.IncludeFilter, 'Add to filter') self._exclusiveFilterAction = self._addFilterAction(FilterAction.ExclusiveFilter, 'Exclusive filter') self._selectFilterAction = self._addFilterAction(FilterAction.SelectFilter, 'Add to selection') self._exclusiveSelectFilterAction = self._addFilterAction( FilterAction.ExclusiveSelectFilter, 'Exclusive selection') self._highlightFilterAction = self._addFilterAction(FilterAction.HighlightFilter, 'Add to highlight') self._exclusiveHighlightFilterAction = self._addFilterAction( FilterAction.ExclusiveHighlightFilter, 'Exclusive highlight') self._exclusiveHighlightFilterAction.setChecked(True) self._drawingActionGroup = QActionGroup(self) self._noDrawingAction = self._addDrawingAction(DrawingAction.NoDrawingAction, 'No drawing action') self._noDrawingAction.setChecked(True) self._loadDrawingsAction = self._addDrawingAction(DrawingAction.LoadDrawings, 'Load drawings') self._addDrawingsAction = self._addDrawingAction(DrawingAction.AddDrawings, 'Add drawings') self._settingsMenu = QMenu(self) self._settingsMenu.addActions(self._mapActionGroup.actions()) self._settingsMenu.addSeparator() self._settingsMenu.addActions(self._filterActionGroup.actions()) self._settingsMenu.addSeparator() self._settingsMenu.addActions(self._drawingActionGroup.actions()) self._settingsAction = QAction(QIcon(':/plugins/ark/settings.svg'), "Action Settings", self) self._settingsAction.setMenu(self._settingsMenu) self.setDefaultAction(self._settingsAction) self.setPopupMode(QToolButton.InstantPopup) def setMapAction(self, mapAction): if mapAction == MapAction.NoMapAction: self._noMapAction.setChecked(True) elif mapAction == MapAction.ZoomMap: self._zoomMapAction.setChecked(True) elif mapAction == MapAction.PanMap: self._panMapAction.setChecked(True) elif mapAction == MapAction.MoveMap: self._moveMapAction.setChecked(True) def setFilterAction(self, filterAction): if filterAction == FilterAction.NoFilterAction: self._noFilterAction.setChecked(True) elif filterAction == FilterAction.IncludeFilter: self._includeFilterAction.setChecked(True) elif filterAction == FilterAction.ExclusiveFilter: self._exclusiveFilterAction.setChecked(True) elif filterAction == FilterAction.SelectFilter: self._selectFilterAction.setChecked(True) elif filterAction == FilterAction.ExclusiveSelectFilter: self._exclusiveSelectFilterAction.setChecked(True) elif filterAction == FilterAction.HighlightFilter: self._highlightFilterAction.setChecked(True) elif filterAction == FilterAction.ExclusiveHighlightFilter: self._exclusiveHighlightFilterAction.setChecked(True) def setDrawingAction(self, drawingAction): if drawingAction == DrawingAction.NoDrawingAction: self._noDrawingAction.setChecked(True) elif drawingAction == DrawingAction.LoadDrawings: self._loadDrawingsAction.setChecked(True) elif drawingAction == DrawingAction.AddDrawings: self._addDrawingsAction.setChecked(True) def _addMapAction(self, mapAction, text): action = QAction(text, self) action.setCheckable(True) action.setData(mapAction) action.triggered.connect(self._mapActionSelected) self._mapActionGroup.addAction(action) return action def _mapActionSelected(self): self.mapActionChanged.emit(self._mapActionGroup.checkedAction().data()) self.settingsChanged.emit() def _addFilterAction(self, filterAction, text): action = QAction(text, self) action.setCheckable(True) action.setData(filterAction) action.triggered.connect(self._filterActionSelected) self._filterActionGroup.addAction(action) return action def _filterActionSelected(self): self.filterActionChanged.emit(self._filterActionGroup.checkedAction().data()) self.settingsChanged.emit() def _addDrawingAction(self, drawingAction, text): action = QAction(text, self) action.setCheckable(True) action.setData(drawingAction) action.triggered.connect(self._drawingActionSelected) self._drawingActionGroup.addAction(action) return action def _drawingActionSelected(self): self.drawingActionChanged.emit(self._drawingActionGroup.checkedAction().data()) self.settingsChanged.emit()
class XViewPanelMenu(XMenu): _instance = None def __init__(self, viewWidget, interfaceMode = False): # initialize the super class super(XViewPanelMenu, self).__init__( viewWidget ) # define custom properties self._viewWidget = viewWidget self._currentPanel = None self._interfaceMenu = None self._groupingMenu = None self._panelGroup = QActionGroup(self) self._groupingGroup = QActionGroup(self) # initialize the menu if not interfaceMode: self.setTitle('Panel Options') self.addSection('Panels') act = self.addAction('Split Panel Left/Right') act.setIcon(QIcon(resources.find('img/view/split_horizontal.png'))) act.triggered.connect(self.splitHorizontal) act = self.addAction('Split Panel Top/Bottom') act.setIcon(QIcon(resources.find('img/view/split_vertical.png'))) act.triggered.connect(self.splitVertical) self.addSeparator() act = self.addAction('Add Panel') act.setIcon(QIcon(resources.find('img/view/add.png'))) act.triggered.connect(self.addPanel) # create pane options menu self._interfaceMenu = XViewPanelMenu(viewWidget, True) self.addMenu(self._interfaceMenu) menu = self.addMenu('Switch Panels') menu.setIcon(QIcon(resources.find('img/view/switch.png'))) act = menu.addAction('Move Up') act.setIcon(QIcon(resources.find('img/view/up.png'))) act = menu.addAction('Move Down') act.setIcon(QIcon(resources.find('img/view/down.png'))) menu.addSeparator() act = menu.addAction('Move Left') act.setIcon(QIcon(resources.find('img/view/left.png'))) act = menu.addAction('Move Right') act.setIcon(QIcon(resources.find('img/view/right.png'))) menu.triggered.connect(self.switchPanels) set_tab_menu = self.addMenu('Switch View') for viewType in viewWidget.viewTypes(): act = set_tab_menu.addAction(viewType.viewName()) act.setIcon(QIcon(viewType.viewIcon())) act.setCheckable(True) self._panelGroup.addAction(act) set_tab_menu.triggered.connect( self.swapTabType ) self.addSeparator() act = self.addAction('Close Panel (Closes All Tabs)') act.setIcon(QIcon(resources.find('img/view/close.png'))) act.triggered.connect( self.closePanel ) act = self.addAction('Close All Panels (Clears Dashboard)') act.setIcon(QIcon(resources.find('img/view/reset.png'))) act.triggered.connect( self.reset ) self.addSection('Tabs') act = self.addAction('Rename Tab') act.setIcon(QIcon(resources.find('img/edit.png'))) act.triggered.connect( self.renamePanel ) act = self.addAction('Detach Tab') act.setIcon(QIcon(resources.find('img/view/detach.png'))) act.triggered.connect( self.detachPanel ) act = self.addAction('Detach Tab (as a Copy)') act.setIcon(QIcon(resources.find('img/view/detach_copy.png'))) act.triggered.connect( self.detachPanelCopy ) act = self.addAction('Close Tab') act.setIcon(QIcon(resources.find('img/view/tab_remove.png'))) act.triggered.connect( self.closeView ) self.addSection('Views') # create view grouping options self._groupingMenu = self.addMenu('Set Group') icon = QIcon(resources.find('img/view/group.png')) self._groupingMenu.setIcon(icon) act = self._groupingMenu.addAction('No Grouping') act.setData(qt.wrapVariant(0)) act.setCheckable(True) self._groupingMenu.addSeparator() self._groupingGroup.addAction(act) for i in range(1, 6): act = self._groupingMenu.addAction('Group %i' % i) act.setData(qt.wrapVariant(i)) act.setCheckable(True) self._groupingGroup.addAction(act) self._groupingMenu.triggered.connect(self.assignGroup) else: self.setTitle( 'Add View' ) for viewType in viewWidget.viewTypes(): act = self.addAction(viewType.viewName()) act.setIcon(QIcon(viewType.viewIcon())) self.triggered.connect( self.addView ) self.addSeparator() def addPanel( self ): panel = self.currentPanel() if panel is not None: return panel.addPanel() return None def addView( self, action ): panel = self.currentPanel() if ( panel is None ): return False viewType = self._viewWidget.viewType(action.text()) return panel.addView(viewType) def assignGroup( self, action ): """ Assigns the group for the given action to the current view. :param action | <QAction> """ grp = qt.unwrapVariant(action.data()) view = self._currentPanel.currentView() view.setViewingGroup(grp) def closePanel( self ): """ Closes the current panel within the view widget. """ panel = self.currentPanel() if panel is not None: return panel.closePanel() return False def closeView( self ): """ Closes the current view within the panel. """ panel = self.currentPanel() if ( panel is not None ): return panel.closeView() return False def currentPanel( self ): """ Returns the current panel widget. :return <XViewPanel> """ return self._currentPanel def detachPanel( self ): """ Detaches the current panel as a floating window. """ #from projexui.widgets.xviewwidget import XViewDialog dlg = XViewDialog(self._viewWidget, self._viewWidget.viewTypes()) size = self._currentPanel.size() dlg.viewWidget().currentPanel().snagViewFromPanel(self._currentPanel) dlg.resize(size) dlg.show() def detachPanelCopy( self ): """ Detaches the current panel as a floating window. """ #from projexui.widgets.xviewwidget import XViewDialog dlg = XViewDialog(self._viewWidget, self._viewWidget.viewTypes()) size = self._currentPanel.size() view = self._currentPanel.currentView() # duplicate the current view if ( view ): new_view = view.duplicate(dlg.viewWidget().currentPanel()) view_widget = dlg.viewWidget() view_panel = view_widget.currentPanel() view_panel.addTab(new_view, new_view.windowTitle()) dlg.resize(size) dlg.show() def gotoNext( self ): """ Goes to the next panel tab. """ index = self._currentPanel.currentIndex() + 1 if ( self._currentPanel.count() == index ): index = 0 self._currentPanel.setCurrentIndex(index) def gotoPrevious( self ): """ Goes to the previous panel tab. """ index = self._currentPanel.currentIndex() - 1 if ( index < 0 ): index = self._currentPanel.count() - 1 self._currentPanel.setCurrentIndex(index) def newPanelTab( self ): """ Creates a new panel with a copy of the current widget. """ view = self._currentPanel.currentView() # duplicate the current view if ( view ): new_view = view.duplicate(self._currentPanel) self._currentPanel.addTab(new_view, new_view.windowTitle()) def renamePanel( self ): """ Prompts the user for a custom name for the current panel tab. """ index = self._currentPanel.currentIndex() title = self._currentPanel.tabText(index) new_title, accepted = QInputDialog.getText( self, 'Rename Tab', 'Name:', QLineEdit.Normal, title ) if ( accepted ): widget = self._currentPanel.currentView() widget.setWindowTitle(new_title) self._currentPanel.setTabText(index, new_title) def reset( self ): """ Clears the current views from the system """ self._viewWidget.reset() def setCurrentPanel( self, panel ): self._currentPanel = panel # update the current tab based on what view type it is viewType = '' grp = -1 if ( panel is not None and panel.currentView() ): viewType = panel.currentView().viewName() grp = panel.currentView().viewingGroup() self._panelGroup.blockSignals(True) for act in self._panelGroup.actions(): act.setChecked(viewType == act.text()) self._panelGroup.blockSignals(False) self._groupingGroup.blockSignals(True) for act in self._groupingGroup.actions(): act.setChecked(grp == qt.unwrapVariant(act.data())) self._groupingGroup.blockSignals(False) if ( self._groupingMenu ): self._groupingMenu.setEnabled(grp != -1) if ( self._interfaceMenu ): self._interfaceMenu.setCurrentPanel(panel) def splitVertical( self ): panel = self.currentPanel() if ( panel is not None ): return panel.splitVertical() return None def splitHorizontal( self ): panel = self.currentPanel() if ( panel is not None ): return panel.splitHorizontal() return None def switchPanels(self, action): direction = action.text() if direction in ('Move Up', 'Move Down'): orientation = Qt.Vertical else: orientation = Qt.Horizontal widget = self.currentPanel() if not widget: return # look up the splitter for the widget splitter = widget.parent() while widget and isinstance(splitter, QSplitter): if splitter.orientation() == orientation: break widget = splitter splitter = splitter.parent() if not isinstance(splitter, QSplitter): return # determine the new location for the panel index = splitter.indexOf(widget) if direction in ('Move Down', 'Move Right'): new_index = index widget = splitter.widget(index + 1) else: new_index = index - 1 if widget and 0 <= new_index and new_index < splitter.count(): splitter.insertWidget(new_index, widget) def swapTabType( self, action ): """ Swaps the current tab view for the inputed action's type. :param action | <QAction> """ # for a new tab, use the add tab slot if not self._currentPanel.count(): self.addView(action) return # make sure we're not trying to switch to the same type viewType = self._viewWidget.viewType(action.text()) view = self._currentPanel.currentView() if ( type(view) == viewType ): return # create a new view and close the old one self._currentPanel.setUpdatesEnabled(False) # create the new view new_view = viewType.createInstance(self._currentPanel) index = self._currentPanel.currentIndex() # cleanup the view view.destroyInstance(view) # add the new view self._currentPanel.insertTab(index - 1, new_view, new_view.windowTitle()) self._currentPanel.setUpdatesEnabled(True)
class LayerSnappingAction(LayerSnappingEnabledAction): """Action to change snapping settings for a QGIS vector layer.""" snapSettingsChanged = pyqtSignal(str) def __init__(self, snapLayer, parent=None): super(LayerSnappingAction, self).__init__(snapLayer, parent) self._toleranceAction = None # LayerSnappingToleranceAction() self._avoidAction = None # LayerSnappingAvoidIntersectionsAction() self._vertexAction = LayerSnappingTypeAction(snapLayer, Snapping.Vertex, self) self._segmentAction = LayerSnappingTypeAction(snapLayer, Snapping.Segment, self) self._vertexSegmentAction = LayerSnappingTypeAction(snapLayer, Snapping.VertexAndSegment, self) self._snappingTypeActionGroup = QActionGroup(self) self._snappingTypeActionGroup.addAction(self._vertexAction) self._snappingTypeActionGroup.addAction(self._segmentAction) self._snappingTypeActionGroup.addAction(self._vertexSegmentAction) self._toleranceAction = LayerSnappingToleranceAction(snapLayer, parent) self._pixelUnitsAction = LayerSnappingUnitAction(snapLayer, Snapping.Pixels, self) self._layerUnitsAction = LayerSnappingUnitAction(snapLayer, Snapping.LayerUnits, self) self._projectUnitsAction = LayerSnappingUnitAction(snapLayer, Snapping.ProjectUnits, self) self._unitTypeActionGroup = QActionGroup(self) self._unitTypeActionGroup.addAction(self._pixelUnitsAction) self._unitTypeActionGroup.addAction(self._layerUnitsAction) self._unitTypeActionGroup.addAction(self._projectUnitsAction) menu = ControlMenu(parent) menu.addActions(self._snappingTypeActionGroup.actions()) menu.addSeparator() menu.addAction(self._toleranceAction) menu.addActions(self._unitTypeActionGroup.actions()) if (isinstance(snapLayer, QgisInterface) or (isinstance(snapLayer, QgsVectorLayer) and snapLayer.geometryType() == QGis.Polygon)): self._avoidAction = LayerSnappingAvoidIntersectionsAction(snapLayer, self) menu.addSeparator() menu.addAction(self._avoidAction) self.setMenu(menu) self._refreshAction() # Make sure we catch changes in the main snapping dialog QgsProject.instance().snapSettingsChanged.connect(self._refreshAction) # If using current layer, make sure we update when it changes if self._iface: self._iface.legendInterface().currentLayerChanged.connect(self._refreshAction) # If any of the settings change then signal, but don't tell project as actions already have self.snappingEnabledChanged.connect(self.snapSettingsChanged) self._vertexAction.snappingTypeChanged.connect(self.snapSettingsChanged) self._segmentAction.snappingTypeChanged.connect(self.snapSettingsChanged) self._vertexSegmentAction.snappingTypeChanged.connect(self.snapSettingsChanged) self._toleranceAction.snappingToleranceChanged.connect(self.snapSettingsChanged) self._pixelUnitsAction.snappingUnitChanged.connect(self.snapSettingsChanged) self._layerUnitsAction.snappingUnitChanged.connect(self.snapSettingsChanged) self._projectUnitsAction.snappingUnitChanged.connect(self.snapSettingsChanged) if self._avoidAction: self._avoidAction.avoidIntersectionsChanged.connect(self.snapSettingsChanged) def setInterface(self, iface): self._toleranceAction.setInterface(iface) def unload(self): if not self._layerId: return super(LayerSnappingAction, self).unload() QgsProject.instance().snapSettingsChanged.disconnect(self._refreshAction) self.snappingEnabledChanged.disconnect(self.snapSettingsChanged) self._vertexAction.snappingTypeChanged.disconnect(self.snapSettingsChanged) self._segmentAction.snappingTypeChanged.disconnect(self.snapSettingsChanged) self._vertexSegmentAction.snappingTypeChanged.disconnect(self.snapSettingsChanged) self._toleranceAction.snappingToleranceChanged.disconnect(self.snapSettingsChanged) self._pixelUnitsAction.snappingUnitChanged.disconnect(self.snapSettingsChanged) self._layerUnitsAction.snappingUnitChanged.disconnect(self.snapSettingsChanged) self._projectUnitsAction.snappingUnitChanged.disconnect(self.snapSettingsChanged) if self._avoidAction: self._avoidAction.avoidIntersectionsChanged.disconnect(self.snapSettingsChanged) self._vertexAction.unload() self._segmentAction.unload() self._vertexSegmentAction.unload() self._toleranceAction.unload() self._pixelUnitsAction.unload() self._layerUnitsAction.unload() self._projectUnitsAction.unload() # Private API def _refreshAction(self): if (self._segmentAction.isChecked()): self.setIcon(self._segmentAction.icon()) elif (self._vertexSegmentAction.isChecked()): self.setIcon(self._vertexSegmentAction.icon()) else: # Snapping.Vertex or undefined self.setIcon(self._vertexAction.icon()) if self._iface and self._avoidAction: layer = QgsMapLayerRegistry.instance().mapLayer(self.layerId()) isPolygon = (layer is not None and layer.type() == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Polygon) self._avoidAction.setEnabled(isPolygon)
def initOptionsMenu(self): men = QMenu() #Threshold Slider self.threshSlider = QSlider() self.threshSlider.setTickPosition(QSlider.TicksLeft) self.threshSlider.setOrientation(Qt.Horizontal) self.threshSlider.setValue(config.thresh()) self.threshSlider.setMinimum(0) self.threshSlider.setMaximum(5) self.threshSlider.valueChanged.connect(self.parent.setThreshold) self.threshSliderAction = QWidgetAction(men) self.threshSliderAction.setDefaultWidget(self.threshSlider) #TabsWidth Slider self.tabsSlider = QSlider() self.tabsSlider.setTickPosition(QSlider.TicksLeft) self.tabsSlider.setOrientation(Qt.Horizontal) self.tabsSlider.setValue(config.tabwidth()) self.tabsSlider.setMinimum(0) self.tabsSlider.setMaximum(8) self.tabsSlider.valueChanged.connect(self.parent.setTabWidth) self.tabsSliderAction = QWidgetAction(men) self.tabsSliderAction.setDefaultWidget(self.tabsSlider) #iconSize Slider self.iconSlider = QSlider() self.iconSlider.setTickPosition(QSlider.TicksLeft) self.iconSlider.setOrientation(Qt.Horizontal) self.iconSlider.setValue(config.iconSize()) self.iconSlider.setMinimum(16) self.iconSlider.setMaximum(32) self.iconSlider.setSingleStep(2) self.iconSlider.valueChanged.connect(self.setIcon) self.iconSliderAction = QWidgetAction(men) self.iconSliderAction.setDefaultWidget(self.iconSlider) '''Font Button''' self.fontCombo = QFontComboBox() self.fontCombo.currentFontChanged.connect(self.parent.setFont) self.fontCombo.setCurrentFont(QFont(config.fontName())) self.fontComboMenu = QWidgetAction(men) self.fontComboMenu.setDefaultWidget(self.fontCombo) '''Font Size''' self.fontSizeCombo = QComboBox() for size in range(1,40): self.fontSizeCombo.addItem(str(size)) self.fontSizeCombo.setCurrentIndex(config.fontSize()) self.fontSizeCombo.currentIndexChanged.connect(self.parent.setFontSize) self.fontSizeComboMenu = QWidgetAction(men) self.fontSizeComboMenu.setDefaultWidget(self.fontSizeCombo) action_Android = QAction(Icons.android,'Android', self) action_Android.triggered.connect(self.parent.android) action_Ant = QAction(Icons.ant_view,'Ant', self) action_Ant.triggered.connect(self.parent.antt) action_Squirrel = QAction(Icons.nut,'Squirrel', self) action_Squirrel.triggered.connect(self.parent.squirrel) action_Ios1 = QAction(Icons.ios,'iOS', self) action_Update = QAction(Icons.update,"Update",self) action_Update.triggered.connect(self.parent.update) action_explorer = QAction("Explorer",self) action_explorer.triggered.connect(self.parent.exp) action_explorer.setCheckable(True) action_explorer.setChecked(True) action_console = QAction("Console",self) action_console.triggered.connect(self.parent.cmd) action_console.setCheckable(True) action_console.setChecked(False) #action_designer = QAction("Designer",self) #action_designer.triggered.connect(self.parent.design) action_Indentation = QAction("Indentation Guides",self) action_Indentation.triggered.connect(self.parent.setIndent) action_Indentation.setCheckable(True) action_Indentation.setChecked(config.indent()) action_WhiteSpace = QAction("WhiteSpace",self) action_WhiteSpace.triggered.connect(self.parent.setWhiteSpace) action_WhiteSpace.setCheckable(True) action_WhiteSpace.setChecked(config.whiteSpace()) action_EndLine = QAction("End of Lines",self) action_EndLine.triggered.connect(self.parent.setEndLine) action_EndLine.setCheckable(True) action_Margin = QAction("Line Numbers",self) action_Margin.triggered.connect(self.parent.setMargin) action_Margin.setCheckable(True) action_Margin.setChecked(config.margin()) action_ToolLabel = QAction("Tool Labels",self) action_ToolLabel.triggered.connect(self.setToolLabel) action_ToolLabel.setCheckable(True) #action_ToolLabel.setChecked(config.toolLabel()) '''Encoding''' encodingGroup = QActionGroup(self) encodingGroup.setExclusive(True) action_Ascii = QAction("Ascii",encodingGroup) action_Ascii.setCheckable(True) action_Unicode = QAction("Unicode",encodingGroup) action_Unicode.setCheckable(False) encodingGroup.addAction(action_Ascii) encodingGroup.addAction(action_Unicode) encodingGroup.selected.connect(self.parent.setEncoding) if(config.encoding() == Encoding.ASCII): action_Ascii.setChecked(True) else: action_Unicode.setChecked(True) men.addAction(action_Update) men.addAction(self.action_Help) men.addAction(self.action_Full) men.addSeparator() men.addAction(action_Android) men.addAction(action_Ant) men.addAction(action_Squirrel) men.addAction(action_Ios1) men.addSeparator() men.addAction(action_explorer) men.addAction(action_console) #men.addAction(action_designer) men.addSeparator() men.addAction(action_Indentation) men.addAction(action_WhiteSpace) men.addAction(action_EndLine) men.addAction(action_Margin) men.addAction(action_ToolLabel) men.addSeparator() men.addActions(encodingGroup.actions()) men.addSeparator() head_font = QLabel("Font---------------------") fnt = head_font.font() fnt.setBold(True) head_font.setFont(fnt) head_fontWidgetAction = QWidgetAction(men) head_fontWidgetAction.setDefaultWidget(head_font) men.addAction(head_fontWidgetAction) men.addAction(self.fontComboMenu) men.addAction(self.fontSizeComboMenu) men.addSeparator() men.addAction(QAction("TabWidth",self)) men.addAction(self.tabsSliderAction) men.addSeparator() men.addAction(QAction("Threshold",self)) men.addAction(self.threshSliderAction) #men.addAction(QAction("Icon Size",self)) #men.addAction(self.iconSliderAction) self.action_Options = QAction(Icons.emblem_system, 'Options', self) self.action_Options.setMenu(men) self.addAction(self.action_Options)
class XActionGroupWidget(QWidget): """ ~~>[img:widgets/xactiongroupwidget.png] The XActionGroupWidget class provides a simple class for creating a multi-checkable tool button based on QActions and QActionGroups. === Example Usage === |>>> from projexui.widgets.xactiongroupwidget import XActionGroupWidget |>>> import projexui | |>>> # create the widget |>>> widget = projexui.testWidget(XActionGroupWidget) | |>>> # add some actions (can be text or a QAction) |>>> widget.addAction('Day') |>>> widget.addAction('Month') |>>> widget.addAction('Year') | |>>> # create connections |>>> def printAction(act): print act.text() |>>> widget.actionGroup().triggered.connect(printAction) """ __designer_icon__ = projexui.resources.find('img/ui/multicheckbox.png') def __init__(self, parent=None): super(XActionGroupWidget, self).__init__(parent) # define custom properties self._actionGroup = None self._padding = 5 self._cornerRadius = 10 # set default properties layout = QBoxLayout(QBoxLayout.LeftToRight) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.setLayout(layout) # create connections def actionGroup(self): """ Returns the action group linked with this widget. :return <QActionGroup> """ return self._actionGroup def addAction(self, action): """ Adds the inputed action to this widget's action group. This will auto-\ create a new group if no group is already defined. :param action | <QAction> || <str> :return <QAction> """ if (not isinstance(action, QAction)): action_name = str(action) action = QAction(action_name, self) action.setObjectName(action_name) action.setCheckable(True) if (not self._actionGroup): self._actionGroup = QActionGroup(self) action.setChecked(True) self._actionGroup.addAction(action) self.reset() return action def colorString(self, clr): """ Renders the inputed color to an RGB string value. :return <str> """ return 'rgb(%s, %s, %s)' % (clr.red(), clr.green(), clr.blue()) def cornerRadius(self): """ Returns the corner radius for this widget. :return <int> """ return self._cornerRadius def currentAction(self): """ Returns the action that is currently checked in the system. :return <QAction> || None """ if (not self._actionGroup): return None for act in self._actionGroup.actions(): if (act.isChecked()): return act return None def direction(self): """ Returns the direction for this widget. :return <QBoxLayout::Direction> """ return self.layout().direction() def findAction(self, text): """ Looks up the action based on the inputed text. :return <QAction> || None """ for action in self.actionGroup().actions(): if (text in (action.objectName(), action.text())): return action return None def padding(self): """ Returns the button padding amount for this widget. :return <int> """ return self._padding def reset(self): """ Resets the user interface buttons for this widget. """ # clear previous widgets for btn in self.findChildren(QToolButton): btn.close() btn.setParent(None) btn.deleteLater() # determine coloring options palette = self.palette() unchecked = palette.color(palette.Button) # determine if this is a dark or light scheme avg = (unchecked.red() + unchecked.green() + unchecked.blue()) / 3.0 if (avg < 140): checked = unchecked.lighter(115) checked_clr = self.colorString(unchecked.lighter(120)) border_clr = self.colorString(unchecked.darker(140)) unchecked_clr = self.colorString(checked.lighter(140)) unchecked_clr_alt = self.colorString(checked.lighter(120)) checked_clr_alt = self.colorString(unchecked) else: checked = unchecked.lighter(120) checked_clr = self.colorString(unchecked) border_clr = self.colorString(unchecked.darker(160)) unchecked_clr = self.colorString(checked) unchecked_clr_alt = self.colorString(checked.darker(130)) checked_clr_alt = self.colorString(unchecked.darker(120)) # define the stylesheet options options = {} options['top_left_radius'] = 0 options['top_right_radius'] = 0 options['bot_left_radius'] = 0 options['bot_right_radius'] = 0 options['border_color'] = border_clr options['checked_clr'] = checked_clr options['checked_clr_alt'] = checked_clr_alt options['unchecked_clr'] = unchecked_clr options['unchecked_clr_alt'] = unchecked_clr_alt options['padding_top'] = 1 options['padding_bottom'] = 1 options['padding_left'] = 1 options['padding_right'] = 1 horiz = self.direction() in (QBoxLayout.LeftToRight, QBoxLayout.RightToLeft) if (horiz): options['x1'] = 0 options['y1'] = 0 options['x2'] = 0 options['y2'] = 1 else: options['x1'] = 0 options['y1'] = 0 options['x2'] = 1 options['y2'] = 1 actions = self.actionGroup().actions() count = len(actions) for i, action in enumerate(actions): btn = QToolButton(self) btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) btn.setDefaultAction(action) self.layout().insertWidget(i, btn) options['top_left_radius'] = 1 options['bot_left_radius'] = 1 options['top_right_radius'] = 1 options['bot_right_radius'] = 1 if (horiz): options['padding_left'] = self._padding options['padding_right'] = self._padding else: options['padding_top'] = self._padding options['padding_bottom'] = self._padding if (not i): if (horiz): options['top_left_radius'] = self.cornerRadius() options['bot_left_radius'] = self.cornerRadius() options['padding_left'] += self.cornerRadius() / 3.0 else: options['top_left_radius'] = self.cornerRadius() options['top_right_radius'] = self.cornerRadius() options['padding_top'] += self.cornerRadius() / 3.0 elif (i == count - 1): if (horiz): options['top_right_radius'] = self.cornerRadius() options['bot_right_radius'] = self.cornerRadius() options['padding_right'] += self.cornerRadius() / 3.0 else: options['bot_left_radius'] = self.cornerRadius() options['bot_right_radius'] = self.cornerRadius() options['padding_bottom'] += self.cornerRadius() / 3.0 btn.setStyleSheet(TOOLBUTTON_STYLE % options) btn.setAutoFillBackground(True) def setActionGroup(self, actionGroup): """ Sets the action group for this widget to the inputed action group. :param actionGroup | <QActionGroup> """ self._actionGroup = actionGroup self.reset() def setCornerRadius(self, radius): """ Sets the corner radius value for this widget to the inputed radius. :param radius | <int> """ self._cornerRadius = radius def setDirection(self, direction): """ Sets the direction that this group widget will face. :param direction | <QBoxLayout::Direction> """ self.layout().setDirection(direction) self.reset() def setPadding(self, padding): """ Sets the padding amount for this widget's button set. :param padding | <int> """ self._padding = padding self.reset()
class XActionGroupWidget(QWidget): """ ~~>[img:widgets/xactiongroupwidget.png] The XActionGroupWidget class provides a simple class for creating a multi-checkable tool button based on QActions and QActionGroups. === Example Usage === |>>> from projexui.widgets.xactiongroupwidget import XActionGroupWidget |>>> import projexui | |>>> # create the widget |>>> widget = projexui.testWidget(XActionGroupWidget) | |>>> # add some actions (can be text or a QAction) |>>> widget.addAction('Day') |>>> widget.addAction('Month') |>>> widget.addAction('Year') | |>>> # create connections |>>> def printAction(act): print act.text() |>>> widget.actionGroup().triggered.connect(printAction) """ __designer_icon__ = projexui.resources.find('img/ui/multicheckbox.png') def __init__( self, parent = None ): super(XActionGroupWidget, self).__init__( parent ) # define custom properties self._actionGroup = None self._padding = 5 self._cornerRadius = 10 # set default properties layout = QBoxLayout(QBoxLayout.LeftToRight) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Preferred ) self.setLayout(layout) # create connections def actionGroup( self ): """ Returns the action group linked with this widget. :return <QActionGroup> """ return self._actionGroup def addAction( self, action ): """ Adds the inputed action to this widget's action group. This will auto-\ create a new group if no group is already defined. :param action | <QAction> || <str> :return <QAction> """ if ( not isinstance(action, QAction) ): action_name = str(action) action = QAction(action_name, self) action.setObjectName(action_name) action.setCheckable(True) if ( not self._actionGroup ): self._actionGroup = QActionGroup(self) action.setChecked(True) self._actionGroup.addAction(action) self.reset() return action def colorString( self, clr ): """ Renders the inputed color to an RGB string value. :return <str> """ return 'rgb(%s, %s, %s)' % (clr.red(), clr.green(), clr.blue()) def cornerRadius( self ): """ Returns the corner radius for this widget. :return <int> """ return self._cornerRadius def currentAction( self ): """ Returns the action that is currently checked in the system. :return <QAction> || None """ if ( not self._actionGroup ): return None for act in self._actionGroup.actions(): if ( act.isChecked() ): return act return None def direction( self ): """ Returns the direction for this widget. :return <QBoxLayout::Direction> """ return self.layout().direction() def findAction( self, text ): """ Looks up the action based on the inputed text. :return <QAction> || None """ for action in self.actionGroup().actions(): if ( text in (action.objectName(), action.text()) ): return action return None def padding( self ): """ Returns the button padding amount for this widget. :return <int> """ return self._padding def reset( self ): """ Resets the user interface buttons for this widget. """ # clear previous widgets for btn in self.findChildren(QToolButton): btn.close() btn.setParent(None) btn.deleteLater() # determine coloring options palette = self.palette() unchecked = palette.color(palette.Button) # determine if this is a dark or light scheme avg = (unchecked.red() + unchecked.green() + unchecked.blue()) / 3.0 if ( avg < 140 ): checked = unchecked.lighter(115) checked_clr = self.colorString(unchecked.lighter(120)) border_clr = self.colorString(unchecked.darker(140)) unchecked_clr = self.colorString(checked.lighter(140)) unchecked_clr_alt = self.colorString(checked.lighter(120)) checked_clr_alt = self.colorString(unchecked) else: checked = unchecked.lighter(120) checked_clr = self.colorString(unchecked) border_clr = self.colorString(unchecked.darker(160)) unchecked_clr = self.colorString(checked) unchecked_clr_alt = self.colorString(checked.darker(130)) checked_clr_alt = self.colorString(unchecked.darker(120)) # define the stylesheet options options = {} options['top_left_radius'] = 0 options['top_right_radius'] = 0 options['bot_left_radius'] = 0 options['bot_right_radius'] = 0 options['border_color'] = border_clr options['checked_clr'] = checked_clr options['checked_clr_alt'] = checked_clr_alt options['unchecked_clr'] = unchecked_clr options['unchecked_clr_alt'] = unchecked_clr_alt options['padding_top'] = 1 options['padding_bottom'] = 1 options['padding_left'] = 1 options['padding_right'] = 1 horiz = self.direction() in (QBoxLayout.LeftToRight, QBoxLayout.RightToLeft) if ( horiz ): options['x1'] = 0 options['y1'] = 0 options['x2'] = 0 options['y2'] = 1 else: options['x1'] = 0 options['y1'] = 0 options['x2'] = 1 options['y2'] = 1 actions = self.actionGroup().actions() count = len(actions) for i, action in enumerate(actions): btn = QToolButton(self) btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) btn.setDefaultAction(action) self.layout().insertWidget(i, btn) options['top_left_radius'] = 1 options['bot_left_radius'] = 1 options['top_right_radius'] = 1 options['bot_right_radius'] = 1 if ( horiz ): options['padding_left'] = self._padding options['padding_right'] = self._padding else: options['padding_top'] = self._padding options['padding_bottom'] = self._padding if ( not i ): if ( horiz ): options['top_left_radius'] = self.cornerRadius() options['bot_left_radius'] = self.cornerRadius() options['padding_left'] += self.cornerRadius() / 3.0 else: options['top_left_radius'] = self.cornerRadius() options['top_right_radius'] = self.cornerRadius() options['padding_top'] += self.cornerRadius() / 3.0 elif ( i == count - 1 ): if ( horiz ): options['top_right_radius'] = self.cornerRadius() options['bot_right_radius'] = self.cornerRadius() options['padding_right'] += self.cornerRadius() / 3.0 else: options['bot_left_radius'] = self.cornerRadius() options['bot_right_radius'] = self.cornerRadius() options['padding_bottom'] += self.cornerRadius() / 3.0 btn.setStyleSheet(TOOLBUTTON_STYLE % options) btn.setAutoFillBackground(True) def setActionGroup( self, actionGroup ): """ Sets the action group for this widget to the inputed action group. :param actionGroup | <QActionGroup> """ self._actionGroup = actionGroup self.reset() def setCornerRadius( self, radius ): """ Sets the corner radius value for this widget to the inputed radius. :param radius | <int> """ self._cornerRadius = radius def setDirection( self, direction ): """ Sets the direction that this group widget will face. :param direction | <QBoxLayout::Direction> """ self.layout().setDirection(direction) self.reset() def setPadding( self, padding ): """ Sets the padding amount for this widget's button set. :param padding | <int> """ self._padding = padding self.reset()
def __init__(self,parent): QToolBar.__init__(self,parent) self.parent = parent self.action_NewProject = QAction(Icons.newprj, 'Project', self) self.action_NewProject.triggered.connect(self.parent.treeWidget.newProject) self.action_NewProject.setToolTip("Create a New Project") self.action_Open = QAction(Icons.open, 'Open', self) self.action_Open.triggered.connect(self.parent.fileOpen) self.action_Open.setToolTip("Open File") self.action_Save = QAction(Icons.save, 'Save', self) self.action_Save.setShortcut('Ctrl+S') self.action_Save.triggered.connect(self.parent.fileSave) self.action_Save.setToolTip("Save Current File") self.action_SaveAll = QAction(Icons.saveall, 'SaveAll', self) self.action_SaveAll.setShortcut('Ctrl+A') self.action_SaveAll.triggered.connect(self.parent.fileSaveAll) self.action_SaveAll.setToolTip("Save All Files") self.action_Build = QAction(Icons.thread_view, 'Build', self) self.action_Build.setShortcut('Ctrl+B') self.action_Build.triggered.connect(self.parent.build_project) self.action_Debug = QAction(Icons.debug_exec, 'Debug', self) self.action_Refresh = QAction(Icons.refresh_tab, 'Refresh', self) self.action_Refresh.triggered.connect(self.parent.treeWidget.refreshCurrentProject) self.action_Run = QAction(Icons.run, 'Run', self) self.action_Run.setShortcut('Ctrl+R') self.action_Run.triggered.connect(self.parent.adb.run) self.action_RunFile = QAction(Icons.go, 'Cmd', self) self.action_RunFile.triggered.connect(self.parent.openCommand) self.parent.runButton.clicked.connect(self.parent.command.setCmdLine) self.action_Stop = QAction(Icons.stop, 'Stop', self) self.action_Stop.setShortcut('Ctrl+Q') self.action_Stop.triggered.connect(self.parent.adb.stop) self.action_Design = QAction(Icons.color_palette, 'Design', self) self.action_Design.triggered.connect(self.parent.design) self.action_Level = QAction(Icons.cmpC_pal, 'Level', self) self.action_Level.triggered.connect(self.parent.level) self.action_Todo = QAction(Icons.task_set, 'Todo', self) self.action_Todo.triggered.connect(self.parent.todo) self.action_Help = QAction(Icons.toc_open, 'Help', self) self.action_Help.triggered.connect(self.parent.help) men = QMenu() #Threshold Slider self.threshSlider = QSlider() self.threshSlider.setTickPosition(QSlider.TicksLeft) self.threshSlider.setOrientation(Qt.Horizontal) self.threshSlider.setValue(config.thresh()) self.threshSlider.setMinimum(0) self.threshSlider.setMaximum(5) self.threshSlider.valueChanged.connect(self.parent.setThreshold) self.threshSliderAction = QWidgetAction(men) self.threshSliderAction.setDefaultWidget(self.threshSlider) #TabsWidth Slider self.tabsSlider = QSlider() self.tabsSlider.setTickPosition(QSlider.TicksLeft) self.tabsSlider.setOrientation(Qt.Horizontal) self.tabsSlider.setValue(config.tabwidth()) self.tabsSlider.setMinimum(0) self.tabsSlider.setMaximum(8) self.tabsSlider.valueChanged.connect(self.parent.setTabWidth) self.tabsSliderAction = QWidgetAction(men) self.tabsSliderAction.setDefaultWidget(self.tabsSlider) #iconSize Slider self.iconSlider = QSlider() self.iconSlider.setTickPosition(QSlider.TicksLeft) self.iconSlider.setOrientation(Qt.Horizontal) self.iconSlider.setValue(config.iconSize()) self.iconSlider.setMinimum(16) self.iconSlider.setMaximum(32) self.iconSlider.setSingleStep(2) self.iconSlider.valueChanged.connect(self.setIcon) self.iconSliderAction = QWidgetAction(men) self.iconSliderAction.setDefaultWidget(self.iconSlider) '''Font Button''' self.fontCombo = QFontComboBox() self.fontCombo.currentFontChanged.connect(self.parent.setFont) self.fontCombo.setCurrentFont(QFont(config.fontName())) self.fontComboMenu = QWidgetAction(men) self.fontComboMenu.setDefaultWidget(self.fontCombo) '''Font Size''' self.fontSizeCombo = QComboBox() for size in range(1,40): self.fontSizeCombo.addItem(str(size)) self.fontSizeCombo.setCurrentIndex(config.fontSize()) self.fontSizeCombo.currentIndexChanged.connect(self.parent.setFontSize) self.fontSizeComboMenu = QWidgetAction(men) self.fontSizeComboMenu.setDefaultWidget(self.fontSizeCombo) action_explorer = QAction("Show Explorer",self) action_explorer.triggered.connect(self.parent.exp) action_console = QAction("Show Console",self) action_console.triggered.connect(self.parent.cmd) action_designer = QAction("Show Designer",self) action_designer.triggered.connect(self.parent.design) action_Indentation = QAction("Indentation Guides",self) action_Indentation.triggered.connect(self.parent.setIndent) action_WhiteSpace = QAction("Show WhiteSpace",self) action_WhiteSpace.triggered.connect(self.parent.setWhiteSpace) action_EndLine = QAction("Show End of Lines",self) action_EndLine.triggered.connect(self.parent.setEndLine) action_Margin = QAction("Line Numbers",self) action_Margin.triggered.connect(self.parent.setMargin) action_ToolLabel = QAction("Tool Labels",self) action_ToolLabel.triggered.connect(self.setToolLabel) action_Android = QAction(Icons.android,'Android', self) action_Android.triggered.connect(self.parent.android) action_Ant = QAction(Icons.ant_view,'Ant', self) action_Ant.triggered.connect(self.parent.antt) action_Squirrel = QAction(Icons.nut,'Squirrel', self) action_Squirrel.triggered.connect(self.parent.squirrel) action_Ios1 = QAction(Icons.ios,'iOS', self) action_Update = QAction("Update",self) action_Update.triggered.connect(self.parent.update) '''Encoding''' encodingGroup = QActionGroup(self) encodingGroup.setExclusive(True) action_Ascii = QAction("Ascii",encodingGroup) action_Ascii.setCheckable(True) action_Unicode = QAction("Unicode",encodingGroup) action_Unicode.setCheckable(True) encodingGroup.addAction(action_Ascii) encodingGroup.addAction(action_Unicode) encodingGroup.selected.connect(self.parent.setEncoding) if(config.encoding() == Encoding.ASCII): action_Ascii.setChecked(True) else: action_Unicode.setChecked(True) men.addAction(action_Android) men.addAction(action_Ant) men.addAction(action_Squirrel) men.addAction(action_Ios1) men.addAction(action_Update) men.addSeparator() men.addAction(action_explorer) men.addAction(action_console) men.addAction(action_designer) men.addAction(action_Indentation) men.addAction(action_WhiteSpace) men.addAction(action_EndLine) men.addAction(action_Margin) men.addAction(action_ToolLabel) men.addSeparator() men.addActions(encodingGroup.actions()) men.addSeparator() head_font = QLabel("Font---------------------") fnt = head_font.font() fnt.setBold(True) head_font.setFont(fnt) head_fontWidgetAction = QWidgetAction(men) head_fontWidgetAction.setDefaultWidget(head_font) men.addAction(head_fontWidgetAction) men.addAction(self.fontComboMenu) men.addAction(self.fontSizeComboMenu) men.addSeparator() men.addAction(QAction("TabWidth",self)) men.addAction(self.tabsSliderAction) men.addSeparator() men.addAction(QAction("Threshold",self)) men.addAction(self.threshSliderAction) #men.addAction(QAction("Icon Size",self)) #men.addAction(self.iconSliderAction) self.action_Options = QAction(Icons.emblem_system, 'Options', self) self.action_Options.setMenu(men) self.action_Full = QAction(Icons.fullscreen, 'Full', self) self.action_Full.setShortcut('Shift+Enter') self.action_Full.triggered.connect(self.parent.full) self.modeGroup = QActionGroup(self) self.modeGroup.setExclusive(True) self.modeGroup.selected.connect(self.parent.setMode) self.action_Squirrel = QAction(Icons.nut, 'Squ', self.modeGroup) self.action_Squirrel.setCheckable(True) self.action_Emo = QAction(Icons.emo, 'Emo', self.modeGroup) self.action_Emo.setCheckable(True) self.action_And = QAction(Icons.android, 'Android', self.modeGroup) self.action_And.setCheckable(True) self.action_Ios = QAction(Icons.ios, 'ios', self.modeGroup) self.action_Ios.setCheckable(True) self.modeGroup.addAction(self.action_Squirrel) self.modeGroup.addAction(self.action_Emo) self.modeGroup.addAction(self.action_And) self.modeGroup.addAction(self.action_Ios) self.action_Style = QAction(Icons.style, 'Style', self) men1 = QMenu() self.styleslist = [] self.style1 = QAction("All Hallow's Eve",self) self.style1.triggered.connect(lambda:self.parent.style_clicked(1)) self.style1.setCheckable(True) self.style2 = QAction("Amy",self) self.style2.triggered.connect(lambda:self.parent.style_clicked(2)) self.style2.setCheckable(True) self.style3 = QAction("Aptana Studio",self) self.style3.triggered.connect(lambda:self.parent.style_clicked(3)) self.style3.setCheckable(True) self.style4 = QAction("Bespin",self) self.style4.triggered.connect(lambda:self.parent.style_clicked(4)) self.style4.setCheckable(True) self.style5 = QAction("Blackboard",self) self.style5.triggered.connect(lambda:self.parent.style_clicked(5)) self.style5.setCheckable(True) self.style6 = QAction("Choco",self) self.style6.triggered.connect(lambda:self.parent.style_clicked(6)) self.style6.setCheckable(True) self.style7 = QAction("Cobalt",self) self.style7.triggered.connect(lambda:self.parent.style_clicked(7)) self.style7.setCheckable(True) self.style8 = QAction("Dawn",self) self.style8.triggered.connect(lambda:self.parent.style_clicked(8)) self.style8.setCheckable(True) self.style9 = QAction("Eclipse",self) self.style9.triggered.connect(lambda:self.parent.style_clicked(9)) self.style9.setCheckable(True) self.styleslist.append(self.style1) self.styleslist.append(self.style2) self.styleslist.append(self.style3) self.styleslist.append(self.style4) self.styleslist.append(self.style5) self.styleslist.append(self.style6) self.styleslist.append(self.style7) self.styleslist.append(self.style8) self.styleslist.append(self.style9) men1.addActions(self.styleslist) self.action_Style.setMenu(men1) self.styleslist[self.parent.styleIndex].setChecked(True) self.action_Stop.setDisabled(True) self.setToolLabel() self.setAllowedAreas(Qt.AllToolBarAreas) #self.setFixedHeight(40) #self.setIconSize(QSize(config.iconSize(),config.iconSize())) self.addAction(self.action_NewProject) self.addAction(self.action_Open) self.addAction(self.action_Save) self.addAction(self.action_SaveAll) #self.addAction(self.action_Refresh) self.addSeparator() self.addAction(self.action_Build) self.addAction(self.action_Run) self.addAction(self.action_RunFile) self.addAction(self.action_Stop) self.addAction(self.action_Debug) self.addSeparator() self.addAction(self.action_Design) self.addAction(self.action_Level) self.addAction(self.action_Todo) self.addAction(self.action_Options) self.addAction(self.action_Style) self.addSeparator() self.addAction(self.action_Help) self.addAction(self.action_Full) self.addSeparator() self.addActions(self.modeGroup.actions()) if(config.mode() == 0): self.action_Squirrel.setChecked(True) elif(config.mode() == 1): self.action_Emo.setChecked(True) elif(config.mode() == 2): self.action_And.setChecked(True) elif(config.mode() == 3): self.action_Ios.setChecked(True)
class XViewProfileToolBar(XToolBar): profileCreated = qt.Signal(qt.PyObject) profileChanged = qt.Signal(qt.PyObject) profileRemoved = qt.Signal(qt.PyObject) currentProfileChanged = qt.Signal(qt.PyObject) def __init__(self, parent): super(XViewProfileToolBar, self).__init__(parent) # create custom properties self._editingEnabled = True self._viewWidget = None self._profileGroup = QActionGroup(self) # set the default options self.setIconSize(QSize(48, 48)) self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.setContextMenuPolicy(Qt.CustomContextMenu) # create connections self.actionTriggered.connect(self.handleActionTrigger) self.customContextMenuRequested.connect(self.showProfileMenu) def addProfile(self, profile): """ Adds the inputed profile as an action to the toolbar. :param profile | <projexui.widgets.xviewwidget.XViewProfile> """ act = XViewProfileAction(profile, self) self._profileGroup.addAction(act) self.addAction(act) return act def currentProfile(self): """ Returns the current profile for this toolbar. :return <projexui.widgets.xviewwidget.XViewProfile> || None """ act = self._profileGroup.checkedAction() if (act): return act.profile() return None def createProfile(self, profile=None, clearLayout=True): """ Prompts the user to create a new profile. """ if (profile): prof = profile elif (not self.viewWidget() or clearLayout): prof = XViewProfile() else: prof = self.viewWidget().saveProfile() blocked = self.signalsBlocked() self.blockSignals(False) changed = self.editProfile(prof) self.blockSignals(blocked) if (not changed): return act = self.addProfile(prof) act.setChecked(True) # update the interface if (self.viewWidget() and (profile or clearLayout)): self.viewWidget().restoreProfile(prof) if (not self.signalsBlocked()): self.profileCreated.emit(prof) @qt.Slot(qt.PyObject) def editProfile(self, profile): """ Prompts the user to edit the given profile. :param profile | <projexui.widgets.xviewwidget.XViewProfile> """ mod = XViewProfileDialog.edit(self, profile) if (not mod): return False # update the action interface for act in self._profileGroup.actions(): if (act.profile() == profile): act.setProfile(profile) break # signal the change if (not self.signalsBlocked()): self.profileChanged.emit(profile) return True def exportProfiles(self, filename=None): """ Exports this toolbar to the given filename. :param filename | <str> || None """ if (not filename): filename = QFileDialog.getSaveFileName(self, 'Export Toolbar', '', 'Toolbar Files (*.xtool)') if (not filename): return False profile_xml = self.toXml() projex.text.xmlindent(profile_xml) profile_string = ElementTree.tostring(profile_xml) f = open(str(filename), 'w') f.write(profile_string) f.close() return True def handleActionTrigger(self, action): """ Handles when an action has been triggered. If the inputed action is a XViewProfileAction, then the currentProfileChanged signal will emit. :param action | <QAction> """ # trigger a particular profile if (isinstance(action, XViewProfileAction)): if (not self.signalsBlocked()): self.currentProfileChanged.emit(action.profile()) if (self._viewWidget): self._viewWidget.restoreProfile(action.profile()) def importProfiles(self, filename=None): """ Imports the profiles from the given filename. :param filename | <str> || None """ if (not filename): filename = QFileDialog.getOpenFileName(self, 'Import Toolbar', '', 'Toolbar Files (*.xtool)') if type(filename) == tuple: filename = str(filename[0]) if (not (filename and os.path.exists(filename))): return False f = open(str(filename), 'r') profile_string = f.read() f.close() self.loadString(profile_string) # load the default toolbar action = self._profileGroup.checkedAction() if (action): self.handleActionTrigger(action) def isEditingEnabled(self): """ Sets whether or not the create is enabled for this toolbar. :return <bool> """ return self._editingEnabled def isEmpty(self): """ Returns whether or not this toolbar is empty. :return <bool> """ return len(self._profileGroup.actions()) == 0 def loadString(self, profilestr): """ Loads the information for this toolbar from the inputed string. :param profilestr | <str> """ try: xtoolbar = ElementTree.fromstring(str(profilestr)) except ExpatError, e: return self.clear() curr = xtoolbar.get('current') for xprofile in xtoolbar: prof = XViewProfile.fromXml(xprofile) act = self.addProfile(prof) if (prof.name() == curr): act.setChecked(True)
class MainWindow(base_class, ui_class): implements(IObserver) def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.saved_account_state = None notification_center = NotificationCenter() notification_center.add_observer(self, name='SIPApplicationWillStart') notification_center.add_observer(self, name='SIPApplicationDidStart') notification_center.add_observer(self, name='SIPAccountGotMessageSummary') notification_center.add_observer(self, name='SIPAccountGotPendingWatcher') notification_center.add_observer(self, name='BlinkSessionNewOutgoing') notification_center.add_observer(self, name='BlinkSessionDidReinitializeForOutgoing') notification_center.add_observer(self, name='FileTransferNewIncoming') notification_center.add_observer(self, name='FileTransferNewOutgoing') notification_center.add_observer(self, sender=AccountManager()) icon_manager = IconManager() self.pending_watcher_dialogs = [] self.mwi_icons = [QIcon(Resources.get('icons/mwi-%d.png' % i)) for i in xrange(0, 11)] self.mwi_icons.append(QIcon(Resources.get('icons/mwi-many.png'))) with Resources.directory: self.setupUi() self.setWindowTitle('Blink') self.setWindowIconText('Blink') geometry = QSettings().value("main_window/geometry") if geometry: self.restoreGeometry(geometry) self.default_icon_path = Resources.get('icons/default-avatar.png') self.default_icon = QIcon(self.default_icon_path) self.last_icon_directory = Path('~').normalized self.set_user_icon(icon_manager.get('avatar')) self.active_sessions_label.hide() self.enable_call_buttons(False) self.conference_button.setEnabled(False) self.hangup_all_button.setEnabled(False) self.sip_server_settings_action.setEnabled(False) self.search_for_people_action.setEnabled(False) self.history_on_server_action.setEnabled(False) self.main_view.setCurrentWidget(self.contacts_panel) self.contacts_view.setCurrentWidget(self.contact_list_panel) self.search_view.setCurrentWidget(self.search_list_panel) # System tray if QSystemTrayIcon.isSystemTrayAvailable() and not os.getenv('XDG_CURRENT_DESKTOP', '').lower().startswith('unity'): self.system_tray_icon = QSystemTrayIcon(QIcon(Resources.get('icons/blink.png')), self) self.system_tray_icon.activated.connect(self._SH_SystemTrayIconActivated) menu = QMenu(self) menu.addAction(QAction("Show", self, triggered=self._AH_SystemTrayShowWindow)) menu.addAction(QAction(QIcon(Resources.get('icons/application-exit.png')), "Quit", self, triggered=self._AH_QuitActionTriggered)) self.system_tray_icon.setContextMenu(menu) self.system_tray_icon.show() else: self.system_tray_icon = None # Accounts self.account_model = AccountModel(self) self.enabled_account_model = ActiveAccountModel(self.account_model, self) self.server_tools_account_model = ServerToolsAccountModel(self.account_model, self) self.identity.setModel(self.enabled_account_model) # Contacts self.contact_model = ContactModel(self) self.contact_search_model = ContactSearchModel(self.contact_model, self) self.contact_list.setModel(self.contact_model) self.search_list.setModel(self.contact_search_model) # Sessions (audio) self.session_model = AudioSessionModel(self) self.session_list.setModel(self.session_model) self.session_list.selectionModel().selectionChanged.connect(self._SH_SessionListSelectionChanged) # History self.history_manager = HistoryManager() # Windows, dialogs and panels self.about_panel = AboutPanel(self) self.conference_dialog = ConferenceDialog(self) self.contact_editor_dialog = ContactEditorDialog(self) self.google_contacts_dialog = GoogleContactsDialog(self) self.filetransfer_window = FileTransferWindow() self.preferences_window = PreferencesWindow(self.account_model, None) self.server_tools_window = ServerToolsWindow(self.server_tools_account_model, None) # Signals self.account_state.stateChanged.connect(self._SH_AccountStateChanged) self.account_state.clicked.connect(self._SH_AccountStateClicked) self.activity_note.editingFinished.connect(self._SH_ActivityNoteEditingFinished) self.add_contact_button.clicked.connect(self._SH_AddContactButtonClicked) self.add_search_contact_button.clicked.connect(self._SH_AddContactButtonClicked) self.audio_call_button.clicked.connect(self._SH_AudioCallButtonClicked) self.video_call_button.clicked.connect(self._SH_VideoCallButtonClicked) self.chat_session_button.clicked.connect(self._SH_ChatSessionButtonClicked) self.back_to_contacts_button.clicked.connect(self.search_box.clear) # this can be set in designer -Dan self.conference_button.makeConference.connect(self._SH_MakeConference) self.conference_button.breakConference.connect(self._SH_BreakConference) self.contact_list.selectionModel().selectionChanged.connect(self._SH_ContactListSelectionChanged) self.contact_model.itemsAdded.connect(self._SH_ContactModelAddedItems) self.contact_model.itemsRemoved.connect(self._SH_ContactModelRemovedItems) self.display_name.editingFinished.connect(self._SH_DisplayNameEditingFinished) self.hangup_all_button.clicked.connect(self._SH_HangupAllButtonClicked) self.identity.activated[int].connect(self._SH_IdentityChanged) self.identity.currentIndexChanged[int].connect(self._SH_IdentityCurrentIndexChanged) self.mute_button.clicked.connect(self._SH_MuteButtonClicked) self.search_box.textChanged.connect(self._SH_SearchBoxTextChanged) self.search_box.returnPressed.connect(self._SH_SearchBoxReturnPressed) self.search_box.shortcut.activated.connect(self.search_box.setFocus) self.search_list.selectionModel().selectionChanged.connect(self._SH_SearchListSelectionChanged) self.server_tools_account_model.rowsInserted.connect(self._SH_ServerToolsAccountModelChanged) self.server_tools_account_model.rowsRemoved.connect(self._SH_ServerToolsAccountModelChanged) self.session_model.sessionAdded.connect(self._SH_AudioSessionModelAddedSession) self.session_model.sessionRemoved.connect(self._SH_AudioSessionModelRemovedSession) self.session_model.structureChanged.connect(self._SH_AudioSessionModelChangedStructure) self.silent_button.clicked.connect(self._SH_SilentButtonClicked) self.switch_view_button.viewChanged.connect(self._SH_SwitchViewButtonChangedView) # Blink menu actions self.about_action.triggered.connect(self.about_panel.show) self.add_account_action.triggered.connect(self.preferences_window.show_add_account_dialog) self.manage_accounts_action.triggered.connect(self.preferences_window.show_for_accounts) self.help_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/help-qt.phtml'))) self.preferences_action.triggered.connect(self.preferences_window.show) self.auto_accept_chat_action.triggered.connect(self._AH_AutoAcceptChatActionTriggered) self.received_messages_sound_action.triggered.connect(self._AH_ReceivedMessagesSoundActionTriggered) self.answering_machine_action.triggered.connect(self._AH_EnableAnsweringMachineActionTriggered) self.release_notes_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/changelog-qt.phtml'))) self.quit_action.triggered.connect(self._AH_QuitActionTriggered) # Call menu actions self.redial_action.triggered.connect(self._AH_RedialActionTriggered) self.join_conference_action.triggered.connect(self.conference_dialog.show) self.history_menu.aboutToShow.connect(self._SH_HistoryMenuAboutToShow) self.history_menu.triggered.connect(self._AH_HistoryMenuTriggered) self.output_devices_group.triggered.connect(self._AH_AudioOutputDeviceChanged) self.input_devices_group.triggered.connect(self._AH_AudioInputDeviceChanged) self.alert_devices_group.triggered.connect(self._AH_AudioAlertDeviceChanged) self.video_devices_group.triggered.connect(self._AH_VideoDeviceChanged) self.mute_action.triggered.connect(self._SH_MuteButtonClicked) self.silent_action.triggered.connect(self._SH_SilentButtonClicked) # Tools menu actions self.sip_server_settings_action.triggered.connect(self._AH_SIPServerSettings) self.search_for_people_action.triggered.connect(self._AH_SearchForPeople) self.history_on_server_action.triggered.connect(self._AH_HistoryOnServer) # Window menu actions self.chat_window_action.triggered.connect(self._AH_ChatWindowActionTriggered) self.transfers_window_action.triggered.connect(self._AH_TransfersWindowActionTriggered) self.logs_window_action.triggered.connect(self._AH_LogsWindowActionTriggered) self.received_files_window_action.triggered.connect(self._AH_ReceivedFilesWindowActionTriggered) self.screenshots_window_action.triggered.connect(self._AH_ScreenshotsWindowActionTriggered) def setupUi(self): super(MainWindow, self).setupUi(self) self.search_box.shortcut = QShortcut(self.search_box) self.search_box.shortcut.setKey('Ctrl+F') self.output_devices_group = QActionGroup(self) self.input_devices_group = QActionGroup(self) self.alert_devices_group = QActionGroup(self) self.video_devices_group = QActionGroup(self) self.request_screen_action = QAction('Request screen', self, triggered=self._AH_RequestScreenActionTriggered) self.share_my_screen_action = QAction('Share my screen', self, triggered=self._AH_ShareMyScreenActionTriggered) self.screen_sharing_button.addAction(self.request_screen_action) self.screen_sharing_button.addAction(self.share_my_screen_action) # adjust search box height depending on theme as the value set in designer isn't suited for all themes search_box = self.search_box option = QStyleOptionFrameV2() search_box.initStyleOption(option) frame_width = search_box.style().pixelMetric(QStyle.PM_DefaultFrameWidth, option, search_box) if frame_width < 4: search_box.setMinimumHeight(20 + 2*frame_width) # adjust the combo boxes for themes with too much padding (like the default theme on Ubuntu 10.04) option = QStyleOptionComboBox() self.identity.initStyleOption(option) wide_padding = self.identity.style().subControlRect(QStyle.CC_ComboBox, option, QStyle.SC_ComboBoxEditField, self.identity).height() < 10 self.identity.setStyleSheet("""QComboBox { padding: 0px 4px 0px 4px; }""" if wide_padding else "") def closeEvent(self, event): QSettings().setValue("main_window/geometry", self.saveGeometry()) super(MainWindow, self).closeEvent(event) self.about_panel.close() self.contact_editor_dialog.close() self.google_contacts_dialog.close() self.server_tools_window.close() for dialog in self.pending_watcher_dialogs[:]: dialog.close() def show(self): super(MainWindow, self).show() self.raise_() self.activateWindow() def set_user_icon(self, icon): self.account_state.setIcon(icon or self.default_icon) def enable_call_buttons(self, enabled): self.audio_call_button.setEnabled(enabled) self.video_call_button.setEnabled(enabled) self.chat_session_button.setEnabled(enabled) self.screen_sharing_button.setEnabled(enabled) def load_audio_devices(self): settings = SIPSimpleSettings() action = QAction(u'System default', self.output_devices_group) action.setData(u'system_default') self.output_device_menu.addAction(action) self.output_device_menu.addSeparator() for device in SIPApplication.engine.output_devices: action = QAction(device, self.output_devices_group) action.setData(device) self.output_device_menu.addAction(action) action = QAction(u'None', self.output_devices_group) action.setData(None) self.output_device_menu.addAction(action) for action in self.output_devices_group.actions(): action.setCheckable(True) if settings.audio.output_device == action.data(): action.setChecked(True) action = QAction(u'System default', self.input_devices_group) action.setData(u'system_default') self.input_device_menu.addAction(action) self.input_device_menu.addSeparator() for device in SIPApplication.engine.input_devices: action = QAction(device, self.input_devices_group) action.setData(device) self.input_device_menu.addAction(action) action = QAction(u'None', self.input_devices_group) action.setData(None) self.input_device_menu.addAction(action) for action in self.input_devices_group.actions(): action.setCheckable(True) if settings.audio.input_device == action.data(): action.setChecked(True) action = QAction(u'System default', self.alert_devices_group) action.setData(u'system_default') self.alert_device_menu.addAction(action) self.alert_device_menu.addSeparator() for device in SIPApplication.engine.output_devices: action = QAction(device, self.alert_devices_group) action.setData(device) self.alert_device_menu.addAction(action) action = QAction(u'None', self.alert_devices_group) action.setData(None) self.alert_device_menu.addAction(action) for action in self.alert_devices_group.actions(): action.setCheckable(True) if settings.audio.alert_device == action.data(): action.setChecked(True) def load_video_devices(self): settings = SIPSimpleSettings() action = QAction(u'System default', self.video_devices_group) action.setData(u'system_default') self.video_camera_menu.addAction(action) self.video_camera_menu.addSeparator() for device in SIPApplication.engine.video_devices: action = QAction(device, self.video_devices_group) action.setData(device) self.video_camera_menu.addAction(action) action = QAction(u'None', self.video_devices_group) action.setData(None) self.video_camera_menu.addAction(action) for action in self.video_devices_group.actions(): action.setCheckable(True) if settings.video.device == action.data(): action.setChecked(True) def _AH_AccountActionTriggered(self, action, enabled): account = action.data() account.enabled = enabled account.save() def _AH_AudioAlertDeviceChanged(self, action): settings = SIPSimpleSettings() settings.audio.alert_device = action.data() settings.save() def _AH_AudioInputDeviceChanged(self, action): settings = SIPSimpleSettings() settings.audio.input_device = action.data() settings.save() def _AH_AudioOutputDeviceChanged(self, action): settings = SIPSimpleSettings() settings.audio.output_device = action.data() settings.save() def _AH_VideoDeviceChanged(self, action): settings = SIPSimpleSettings() settings.video.device = action.data() settings.save() def _AH_AutoAcceptChatActionTriggered(self, checked): settings = SIPSimpleSettings() settings.chat.auto_accept = checked settings.save() def _AH_ReceivedMessagesSoundActionTriggered(self, checked): settings = SIPSimpleSettings() settings.sounds.play_message_alerts = checked settings.save() def _AH_EnableAnsweringMachineActionTriggered(self, checked): settings = SIPSimpleSettings() settings.answering_machine.enabled = checked settings.save() def _AH_GoogleContactsActionTriggered(self): settings = SIPSimpleSettings() if settings.google_contacts.authorization_token is not None: settings.google_contacts.authorization_token = None settings.save() self.google_contacts_dialog.hide() else: self.google_contacts_dialog.open() def _AH_RedialActionTriggered(self): session_manager = SessionManager() if session_manager.last_dialed_uri is not None: contact, contact_uri = URIUtils.find_contact(session_manager.last_dialed_uri) session_manager.create_session(contact, contact_uri, [StreamDescription('audio')]) # TODO: remember used media types and redial with them. -Saul def _AH_SIPServerSettings(self, checked): account = self.identity.itemData(self.identity.currentIndex()).account account = account if account is not BonjourAccount() and account.server.settings_url else None self.server_tools_window.open_settings_page(account) def _AH_SearchForPeople(self, checked): account = self.identity.itemData(self.identity.currentIndex()).account account = account if account is not BonjourAccount() and account.server.settings_url else None self.server_tools_window.open_search_for_people_page(account) def _AH_HistoryOnServer(self, checked): account = self.identity.itemData(self.identity.currentIndex()).account account = account if account is not BonjourAccount() and account.server.settings_url else None self.server_tools_window.open_history_page(account) def _AH_ChatWindowActionTriggered(self, checked): blink = QApplication.instance() blink.chat_window.show() def _AH_TransfersWindowActionTriggered(self, checked): self.filetransfer_window.show() def _AH_LogsWindowActionTriggered(self, checked): directory = ApplicationData.get('logs') makedirs(directory) QDesktopServices.openUrl(QUrl.fromLocalFile(directory)) def _AH_ReceivedFilesWindowActionTriggered(self, checked): settings = SIPSimpleSettings() directory = settings.file_transfer.directory.normalized makedirs(directory) QDesktopServices.openUrl(QUrl.fromLocalFile(directory)) def _AH_ScreenshotsWindowActionTriggered(self, checked): settings = BlinkSettings() directory = settings.screen_sharing.screenshots_directory.normalized makedirs(directory) QDesktopServices.openUrl(QUrl.fromLocalFile(directory)) def _AH_VoicemailActionTriggered(self, action, checked): account = action.data() contact, contact_uri = URIUtils.find_contact(account.voicemail_uri, display_name='Voicemail') session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('audio')], account=account) def _SH_HistoryMenuAboutToShow(self): self.history_menu.clear() if self.history_manager.calls: for entry in reversed(self.history_manager.calls): action = self.history_menu.addAction(entry.icon, entry.text) action.entry = entry action.setToolTip(entry.uri) else: action = self.history_menu.addAction("Call history is empty") action.setEnabled(False) def _AH_HistoryMenuTriggered(self, action): account_manager = AccountManager() session_manager = SessionManager() try: account = account_manager.get_account(action.entry.account_id) except KeyError: account = None contact, contact_uri = URIUtils.find_contact(action.entry.uri) session_manager.create_session(contact, contact_uri, [StreamDescription('audio')], account=account) # TODO: memorize media type and use it? -Saul (not sure about history in/out -Dan) def _AH_SystemTrayShowWindow(self, checked): self.show() self.raise_() self.activateWindow() def _AH_QuitActionTriggered(self, checked): if self.system_tray_icon is not None: self.system_tray_icon.hide() QApplication.instance().quit() def _SH_AccountStateChanged(self): self.activity_note.setText(self.account_state.note) if self.account_state.state is AccountState.Invisible: self.activity_note.inactiveText = u'(invisible)' self.activity_note.setEnabled(False) else: if not self.activity_note.isEnabled(): self.activity_note.inactiveText = u'Add an activity note here' self.activity_note.setEnabled(True) if not self.account_state.state.internal: self.saved_account_state = None blink_settings = BlinkSettings() blink_settings.presence.current_state = PresenceState(self.account_state.state, self.account_state.note) blink_settings.presence.state_history = [PresenceState(state, note) for state, note in self.account_state.history] blink_settings.save() def _SH_AccountStateClicked(self, checked): filename = QFileDialog.getOpenFileName(self, u'Select Icon', self.last_icon_directory, u"Images (*.png *.tiff *.jpg *.xmp *.svg)") if filename: self.last_icon_directory = os.path.dirname(filename) filename = filename if os.path.realpath(filename) != os.path.realpath(self.default_icon_path) else None blink_settings = BlinkSettings() icon_manager = IconManager() if filename is not None: icon = icon_manager.store_file('avatar', filename) if icon is not None: blink_settings.presence.icon = IconDescriptor(FileURL(icon.filename), hashlib.sha1(icon.content).hexdigest()) else: icon_manager.remove('avatar') blink_settings.presence.icon = None else: icon_manager.remove('avatar') blink_settings.presence.icon = None blink_settings.save() def _SH_ActivityNoteEditingFinished(self): self.activity_note.clearFocus() note = self.activity_note.text() if note != self.account_state.note: self.account_state.state.internal = False self.account_state.setState(self.account_state.state, note) def _SH_AddContactButtonClicked(self, clicked): self.contact_editor_dialog.open_for_add(self.search_box.text(), None) def _SH_AudioCallButtonClicked(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list if list_view.detail_view.isVisible(): list_view.detail_view._AH_StartAudioCall() else: selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('audio')]) def _SH_VideoCallButtonClicked(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list if list_view.detail_view.isVisible(): list_view.detail_view._AH_StartVideoCall() else: selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('audio'), StreamDescription('video')]) def _SH_ChatSessionButtonClicked(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list if list_view.detail_view.isVisible(): list_view.detail_view._AH_StartChatSession() else: selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('chat')], connect=False) def _AH_RequestScreenActionTriggered(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list if list_view.detail_view.isVisible(): list_view.detail_view._AH_RequestScreen() else: selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('screen-sharing', mode='viewer'), StreamDescription('audio')]) def _AH_ShareMyScreenActionTriggered(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list if list_view.detail_view.isVisible(): list_view.detail_view._AH_ShareMyScreen() else: selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('screen-sharing', mode='server'), StreamDescription('audio')]) def _SH_BreakConference(self): active_session = self.session_list.selectionModel().selectedIndexes()[0].data(Qt.UserRole) self.session_model.breakConference(active_session.client_conference) def _SH_ContactListSelectionChanged(self, selected, deselected): account_manager = AccountManager() selected_items = self.contact_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)==1 and isinstance(selected_items[0].data(Qt.UserRole), Contact)) def _SH_ContactModelAddedItems(self, items): if not self.search_box.text(): return active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel self.search_view.setCurrentWidget(active_widget) def _SH_ContactModelRemovedItems(self, items): if not self.search_box.text(): return if any(type(item) is Contact for item in items) and self.contact_search_model.rowCount() == 0: self.search_box.clear() # check this. it is no longer be the correct behaviour as now contacts can be deleted from remote -Dan else: active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel self.search_view.setCurrentWidget(active_widget) def _SH_DisplayNameEditingFinished(self): self.display_name.clearFocus() index = self.identity.currentIndex() if index != -1: name = self.display_name.text() account = self.identity.itemData(index).account account.display_name = name if name else None account.save() def _SH_HangupAllButtonClicked(self): for session in self.session_model.sessions: session.end() def _SH_IdentityChanged(self, index): account_manager = AccountManager() account_manager.default_account = self.identity.itemData(index).account def _SH_IdentityCurrentIndexChanged(self, index): if index != -1: account = self.identity.itemData(index).account self.display_name.setText(account.display_name or u'') self.display_name.setEnabled(True) self.activity_note.setEnabled(True) self.account_state.setEnabled(True) else: self.display_name.clear() self.display_name.setEnabled(False) self.activity_note.setEnabled(False) self.account_state.setEnabled(False) self.account_state.setState(AccountState.Invisible) self.saved_account_state = None def _SH_MakeConference(self): self.session_model.conferenceSessions([session for session in self.session_model.active_sessions if session.client_conference is None]) def _SH_MuteButtonClicked(self, muted): settings = SIPSimpleSettings() settings.audio.muted = muted settings.save() def _SH_SearchBoxReturnPressed(self): address = self.search_box.text() if address: contact, contact_uri = URIUtils.find_contact(address) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('audio')]) def _SH_SearchBoxTextChanged(self, text): self.contact_search_model.setFilterFixedString(text) account_manager = AccountManager() if text: self.switch_view_button.view = SwitchViewButton.ContactView if self.contacts_view.currentWidget() is not self.search_panel: self.search_list.selectionModel().clearSelection() self.contacts_view.setCurrentWidget(self.search_panel) self.search_view.setCurrentWidget(self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel) selected_items = self.search_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1) else: self.contacts_view.setCurrentWidget(self.contact_list_panel) selected_items = self.contact_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)==1 and type(selected_items[0].data(Qt.UserRole)) is Contact) self.search_list.detail_model.contact = None self.search_list.detail_view.hide() def _SH_SearchListSelectionChanged(self, selected, deselected): account_manager = AccountManager() selected_items = self.search_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1) def _SH_ServerToolsAccountModelChanged(self, parent_index, start, end): server_tools_enabled = self.server_tools_account_model.rowCount() > 0 self.sip_server_settings_action.setEnabled(server_tools_enabled) self.search_for_people_action.setEnabled(server_tools_enabled) self.history_on_server_action.setEnabled(server_tools_enabled) def _SH_SessionListSelectionChanged(self, selected, deselected): selected_indexes = selected.indexes() active_session = selected_indexes[0].data(Qt.UserRole) if selected_indexes else Null if active_session.client_conference: self.conference_button.setEnabled(True) self.conference_button.setChecked(True) else: self.conference_button.setEnabled(len([session for session in self.session_model.active_sessions if session.client_conference is None]) > 1) self.conference_button.setChecked(False) def _SH_AudioSessionModelAddedSession(self, session_item): if len(session_item.blink_session.streams) == 1: self.switch_view_button.view = SwitchViewButton.SessionView def _SH_AudioSessionModelRemovedSession(self, session_item): if self.session_model.rowCount() == 0: self.switch_view_button.view = SwitchViewButton.ContactView def _SH_AudioSessionModelChangedStructure(self): active_sessions = self.session_model.active_sessions self.active_sessions_label.setText(u'There is 1 active call' if len(active_sessions)==1 else u'There are %d active calls' % len(active_sessions)) self.active_sessions_label.setVisible(any(active_sessions)) self.hangup_all_button.setEnabled(any(active_sessions)) selected_indexes = self.session_list.selectionModel().selectedIndexes() active_session = selected_indexes[0].data(Qt.UserRole) if selected_indexes else Null if active_session.client_conference: self.conference_button.setEnabled(True) self.conference_button.setChecked(True) else: self.conference_button.setEnabled(len([session for session in active_sessions if session.client_conference is None]) > 1) self.conference_button.setChecked(False) if active_sessions: if self.account_state.state is not AccountState.Invisible: if self.saved_account_state is None: self.saved_account_state = self.account_state.state, self.activity_note.text() self.account_state.setState(AccountState.Busy.Internal, note=u'On the phone') elif self.saved_account_state is not None: state, note = self.saved_account_state self.saved_account_state = None self.account_state.setState(state, note) def _SH_SilentButtonClicked(self, silent): settings = SIPSimpleSettings() settings.audio.silent = silent settings.save() def _SH_SwitchViewButtonChangedView(self, view): self.main_view.setCurrentWidget(self.contacts_panel if view is SwitchViewButton.ContactView else self.sessions_panel) def _SH_PendingWatcherDialogFinished(self, result): self.pending_watcher_dialogs.remove(self.sender()) def _SH_SystemTrayIconActivated(self, reason): if reason == QSystemTrayIcon.Trigger: self.show() self.raise_() self.activateWindow() @run_in_gui_thread def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) def _NH_SIPApplicationWillStart(self, notification): account_manager = AccountManager() settings = SIPSimpleSettings() self.silent_action.setChecked(settings.audio.silent) self.silent_button.setChecked(settings.audio.silent) self.answering_machine_action.setChecked(settings.answering_machine.enabled) self.auto_accept_chat_action.setChecked(settings.chat.auto_accept) self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts) if settings.google_contacts.authorization_token is None: self.google_contacts_action.setText(u'Enable &Google Contacts...') else: self.google_contacts_action.setText(u'Disable &Google Contacts') self.google_contacts_action.triggered.connect(self._AH_GoogleContactsActionTriggered) if not any(account.enabled for account in account_manager.iter_accounts()): self.display_name.setEnabled(False) self.activity_note.setEnabled(False) self.account_state.setEnabled(False) def _NH_SIPApplicationDidStart(self, notification): self.load_audio_devices() self.load_video_devices() notification.center.add_observer(self, name='CFGSettingsObjectDidChange') notification.center.add_observer(self, name='AudioDevicesDidChange') blink_settings = BlinkSettings() self.account_state.history = [(item.state, item.note) for item in blink_settings.presence.state_history] state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available) self.account_state.setState(state, blink_settings.presence.current_state.note) def _NH_AudioDevicesDidChange(self, notification): for action in self.output_device_menu.actions(): self.output_devices_group.removeAction(action) self.output_device_menu.removeAction(action) for action in self.input_device_menu.actions(): self.input_devices_group.removeAction(action) self.input_device_menu.removeAction(action) for action in self.alert_device_menu.actions(): self.alert_devices_group.removeAction(action) self.alert_device_menu.removeAction(action) if self.session_model.active_sessions: old_devices = set(notification.data.old_devices) new_devices = set(notification.data.new_devices) added_devices = new_devices - old_devices if added_devices: new_device = added_devices.pop() settings = SIPSimpleSettings() settings.audio.input_device = new_device settings.audio.output_device = new_device settings.save() self.load_audio_devices() def _NH_CFGSettingsObjectDidChange(self, notification): settings = SIPSimpleSettings() blink_settings = BlinkSettings() icon_manager = IconManager() if notification.sender is settings: if 'audio.muted' in notification.data.modified: self.mute_action.setChecked(settings.audio.muted) self.mute_button.setChecked(settings.audio.muted) if 'audio.silent' in notification.data.modified: self.silent_action.setChecked(settings.audio.silent) self.silent_button.setChecked(settings.audio.silent) if 'audio.output_device' in notification.data.modified: action = (action for action in self.output_devices_group.actions() if action.data() == settings.audio.output_device).next() action.setChecked(True) if 'audio.input_device' in notification.data.modified: action = (action for action in self.input_devices_group.actions() if action.data() == settings.audio.input_device).next() action.setChecked(True) if 'audio.alert_device' in notification.data.modified: action = (action for action in self.alert_devices_group.actions() if action.data() == settings.audio.alert_device).next() action.setChecked(True) if 'video.device' in notification.data.modified: action = (action for action in self.video_devices_group.actions() if action.data() == settings.video.device).next() action.setChecked(True) if 'answering_machine.enabled' in notification.data.modified: self.answering_machine_action.setChecked(settings.answering_machine.enabled) if 'chat.auto_accept' in notification.data.modified: self.auto_accept_chat_action.setChecked(settings.chat.auto_accept) if 'sounds.play_message_alerts' in notification.data.modified: self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts) if 'google_contacts.authorization_token' in notification.data.modified: authorization_token = notification.sender.google_contacts.authorization_token if authorization_token is None: self.google_contacts_action.setText(u'Enable &Google Contacts...') else: self.google_contacts_action.setText(u'Disable &Google Contacts') if authorization_token is InvalidToken: self.google_contacts_dialog.open_for_incorrect_password() elif notification.sender is blink_settings: if 'presence.current_state' in notification.data.modified: state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available) self.account_state.setState(state, blink_settings.presence.current_state.note) if 'presence.icon' in notification.data.modified: self.set_user_icon(icon_manager.get('avatar')) if 'presence.offline_note' in notification.data.modified: # TODO: set offline note -Saul pass elif isinstance(notification.sender, (Account, BonjourAccount)): account_manager = AccountManager() account = notification.sender if 'enabled' in notification.data.modified: action = (action for action in self.accounts_menu.actions() if action.data() is account).next() action.setChecked(account.enabled) if 'display_name' in notification.data.modified and account is account_manager.default_account: self.display_name.setText(account.display_name or u'') if set(['enabled', 'message_summary.enabled', 'message_summary.voicemail_uri']).intersection(notification.data.modified): action = (action for action in self.voicemail_menu.actions() if action.data() is account).next() action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled) action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None) def _NH_SIPAccountManagerDidAddAccount(self, notification): account = notification.data.account action = QAction(account.id if account is not BonjourAccount() else u'Bonjour', None) action.setEnabled(True if account is not BonjourAccount() else BonjourAccount.mdns_available) action.setCheckable(True) action.setChecked(account.enabled) action.setData(account) action.triggered.connect(partial(self._AH_AccountActionTriggered, action)) self.accounts_menu.addAction(action) action = QAction(self.mwi_icons[0], account.id, None) action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled) action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None) action.setData(account) action.triggered.connect(partial(self._AH_VoicemailActionTriggered, action)) self.voicemail_menu.addAction(action) def _NH_SIPAccountManagerDidRemoveAccount(self, notification): account = notification.data.account action = (action for action in self.accounts_menu.actions() if action.data() is account).next() self.accounts_menu.removeAction(action) action = (action for action in self.voicemail_menu.actions() if action.data() is account).next() self.voicemail_menu.removeAction(action) def _NH_SIPAccountManagerDidChangeDefaultAccount(self, notification): if notification.data.account is None: self.enable_call_buttons(False) else: selected_items = self.contact_list.selectionModel().selectedIndexes() self.enable_call_buttons(len(selected_items)==1 and isinstance(selected_items[0].data(Qt.UserRole), Contact)) def _NH_SIPAccountGotMessageSummary(self, notification): account = notification.sender summary = notification.data.message_summary action = (action for action in self.voicemail_menu.actions() if action.data() is account).next() action.setEnabled(account.voicemail_uri is not None) if summary.messages_waiting: try: new_messages = limit(int(summary.summaries['voice-message']['new_messages']), min=0, max=11) except (KeyError, ValueError): new_messages = 0 else: new_messages = 0 action.setIcon(self.mwi_icons[new_messages]) def _NH_SIPAccountGotPendingWatcher(self, notification): dialog = PendingWatcherDialog(notification.sender, notification.data.uri, notification.data.display_name) dialog.finished.connect(self._SH_PendingWatcherDialogFinished) self.pending_watcher_dialogs.append(dialog) dialog.show() def _NH_BlinkSessionNewOutgoing(self, notification): self.search_box.clear() def _NH_BlinkSessionDidReinitializeForOutgoing(self, notification): self.search_box.clear() def _NH_FileTransferNewIncoming(self, notification): self.filetransfer_window.show(activate=QApplication.activeWindow() is not None) def _NH_FileTransferNewOutgoing(self, notification): self.filetransfer_window.show(activate=QApplication.activeWindow() is not None)
class ProjectSnappingAction(ProjectSnappingEnabledAction): """Action to configure snapping.""" snapSettingsChanged = pyqtSignal() def __init__(self, parent=None): super(ProjectSnappingAction, self).__init__(parent) self.setCheckable(True) self._currentAction = SnappingModeAction(Snapping.CurrentLayer, self) self._allAction = SnappingModeAction(Snapping.AllLayers, self) self._selectedAction = SnappingModeAction(Snapping.SelectedLayers, self) self._snappingModeActionGroup = QActionGroup(self) self._snappingModeActionGroup.addAction(self._currentAction) self._snappingModeActionGroup.addAction(self._allAction) self._snappingModeActionGroup.addAction(self._selectedAction) self._vertexAction = ProjectSnappingTypeAction(Snapping.Vertex, self) self._segmentAction = ProjectSnappingTypeAction(Snapping.Segment, self) self._vertexSegmentAction = ProjectSnappingTypeAction(Snapping.VertexAndSegment, self) self._snappingTypeActionGroup = QActionGroup(self) self._snappingTypeActionGroup.addAction(self._vertexAction) self._snappingTypeActionGroup.addAction(self._segmentAction) self._snappingTypeActionGroup.addAction(self._vertexSegmentAction) self._pixelUnitsAction = ProjectSnappingUnitAction(Snapping.Pixels, self) self._layerUnitsAction = ProjectSnappingUnitAction(Snapping.LayerUnits, self) self._projectUnitsAction = ProjectSnappingUnitAction(Snapping.ProjectUnits, self) self._unitTypeActionGroup = QActionGroup(self) self._unitTypeActionGroup.addAction(self._pixelUnitsAction) self._unitTypeActionGroup.addAction(self._layerUnitsAction) self._unitTypeActionGroup.addAction(self._projectUnitsAction) self._toleranceAction = ProjectSnappingToleranceAction(parent) menu = ControlMenu(parent) menu.addActions(self._snappingModeActionGroup.actions()) menu.addSeparator() menu.addActions(self._snappingTypeActionGroup.actions()) menu.addSeparator() menu.addAction(self._toleranceAction) menu.addActions(self._unitTypeActionGroup.actions()) self.setMenu(menu) self._refreshAction() # Make sure we catch changes in the main snapping dialog QgsProject.instance().snapSettingsChanged.connect(self._refreshAction) def setInterface(self, iface): self._toleranceAction.setInterface(iface) def unload(self): super(ProjectSnappingAction, self).unload() self._currentAction.unload() self._allAction.unload() self._selectedAction.unload() self._vertexAction.unload() self._segmentAction.unload() self._vertexSegmentAction.unload() self._pixelUnitsAction.unload() self._layerUnitsAction.unload() self._projectUnitsAction.unload() self._toleranceAction.unload() QgsProject.instance().snapSettingsChanged.disconnect(self._refreshAction) # Private API def _refreshAction(self): snapMode = Snapping.snappingMode() if snapMode == Snapping.SelectedLayers: self.setIcon(self._selectedAction.icon()) elif snapMode == Snapping.CurrentLayer: self.setIcon(self._currentAction.icon()) elif snapMode == Snapping.AllLayers: self.setIcon(self._allAction.icon())
class Tool(QToolBar): def __init__(self,parent): QToolBar.__init__(self,parent) self.parent = parent self.action_NewProject = QAction(Icons.newprj, 'Project', self) self.action_NewProject.triggered.connect(self.parent.treeWidget.newProject) self.action_NewProject.setToolTip("Create a New Project") self.action_Open = QAction(Icons.open, 'Open', self) self.action_Open.triggered.connect(self.parent.fileOpen) self.action_Open.setToolTip("Open File") self.action_Save = QAction(Icons.save, 'Save', self) self.action_Save.setShortcut('Ctrl+S') self.action_Save.triggered.connect(self.parent.fileSave) self.action_Save.setToolTip("Save Current File") self.action_SaveAll = QAction(Icons.saveall, 'SaveAll', self) self.action_SaveAll.setShortcut('Ctrl+A') self.action_SaveAll.triggered.connect(self.parent.fileSaveAll) self.action_SaveAll.setToolTip("Save All Files") self.action_Build = QAction(Icons.thread_view, 'Build', self) self.action_Build.setShortcut('Ctrl+B') self.action_Build.triggered.connect(self.parent.build_project) self.action_Debug = QAction(Icons.debug_exec, 'Debug', self) self.action_Refresh = QAction(Icons.refresh_tab, 'Refresh', self) self.action_Refresh.triggered.connect(self.parent.treeWidget.refreshCurrentProject) self.action_Run = QAction(Icons.run, 'Run', self) self.action_Run.setShortcut('Ctrl+R') self.action_Run.triggered.connect(self.parent.adb.run) self.action_RunFile = QAction(Icons.go, 'Cmd', self) self.action_RunFile.triggered.connect(self.parent.openCommand) self.parent.runButton.clicked.connect(self.parent.command.setCmdLine) self.action_Stop = QAction(Icons.stop, 'Stop', self) self.action_Stop.setShortcut('Ctrl+Q') self.action_Stop.triggered.connect(self.parent.adb.stop) self.action_Design = QAction(Icons.color_palette, 'Design', self) self.action_Design.triggered.connect(self.parent.design) self.action_Level = QAction(Icons.cmpC_pal, 'Level', self) self.action_Level.triggered.connect(self.parent.level) self.action_Todo = QAction(Icons.task_set, 'Todo', self) self.action_Todo.triggered.connect(self.parent.todo) self.action_Help = QAction(Icons.toc_open, 'Help', self) self.action_Help.triggered.connect(self.parent.help) self.action_Full = QAction(Icons.fullscreen, 'Full', self) self.action_Full.triggered.connect(self.parent.full) self.action_Stop.setDisabled(True) self.setToolLabel() self.setAllowedAreas(Qt.AllToolBarAreas) #self.setFixedHeight(40) #self.setIconSize(QSize(config.iconSize(),config.iconSize())) ''' Adding all Actions ''' self.addAction(self.action_NewProject) self.addAction(self.action_Open) self.addAction(self.action_Save) self.addAction(self.action_SaveAll) #self.addAction(self.action_Refresh) self.addSeparator() self.addAction(self.action_Build) self.addAction(self.action_Run) #self.addAction(self.action_RunFile) self.addAction(self.action_Stop) self.addAction(self.action_Debug) self.addSeparator() self.addAction(self.action_Design) self.addAction(self.action_Level) self.addAction(self.action_Todo) self.initOptionsMenu() self.addSeparator() self.initStyleMenu() self.initLexerMenu() self.initApiMenu() #self.addAction(self.action_Help) #self.addAction(self.action_Full) self.addSeparator() self.initModeMenu() def colorChange(self, text, color): #print "colorChange ",text,color editStyle = config.readStyle() editStyle[text] = color config.writeStyle(editStyle) for i in range(len(self.parent.files)): self.parent.tabWidget.widget(i).setEditorStyle() def setColors(self,action): print action.text() def changeAll(self): self.colorChange("base", "#ffffff") def setIcon(self,val): config.setIconSize(val) self.setIconSize(QSize(val,val)) def setToolLabel(self): if (config.toolLabel()): self.setToolButtonStyle(Qt.ToolButtonIconOnly) self.setIconSize(QSize(24,24)) else: self.setIconSize(QSize(16,16)) self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) '''Important for multiple callbacks in for loop''' def make_callback(self, text): return lambda:self.colorChange(text) ''' Options Menu ''' def initOptionsMenu(self): men = QMenu() #Threshold Slider self.threshSlider = QSlider() self.threshSlider.setTickPosition(QSlider.TicksLeft) self.threshSlider.setOrientation(Qt.Horizontal) self.threshSlider.setValue(config.thresh()) self.threshSlider.setMinimum(0) self.threshSlider.setMaximum(5) self.threshSlider.valueChanged.connect(self.parent.setThreshold) self.threshSliderAction = QWidgetAction(men) self.threshSliderAction.setDefaultWidget(self.threshSlider) #TabsWidth Slider self.tabsSlider = QSlider() self.tabsSlider.setTickPosition(QSlider.TicksLeft) self.tabsSlider.setOrientation(Qt.Horizontal) self.tabsSlider.setValue(config.tabwidth()) self.tabsSlider.setMinimum(0) self.tabsSlider.setMaximum(8) self.tabsSlider.valueChanged.connect(self.parent.setTabWidth) self.tabsSliderAction = QWidgetAction(men) self.tabsSliderAction.setDefaultWidget(self.tabsSlider) #iconSize Slider self.iconSlider = QSlider() self.iconSlider.setTickPosition(QSlider.TicksLeft) self.iconSlider.setOrientation(Qt.Horizontal) self.iconSlider.setValue(config.iconSize()) self.iconSlider.setMinimum(16) self.iconSlider.setMaximum(32) self.iconSlider.setSingleStep(2) self.iconSlider.valueChanged.connect(self.setIcon) self.iconSliderAction = QWidgetAction(men) self.iconSliderAction.setDefaultWidget(self.iconSlider) '''Font Button''' self.fontCombo = QFontComboBox() self.fontCombo.currentFontChanged.connect(self.parent.setFont) self.fontCombo.setCurrentFont(QFont(config.fontName())) self.fontComboMenu = QWidgetAction(men) self.fontComboMenu.setDefaultWidget(self.fontCombo) '''Font Size''' self.fontSizeCombo = QComboBox() for size in range(1,40): self.fontSizeCombo.addItem(str(size)) self.fontSizeCombo.setCurrentIndex(config.fontSize()) self.fontSizeCombo.currentIndexChanged.connect(self.parent.setFontSize) self.fontSizeComboMenu = QWidgetAction(men) self.fontSizeComboMenu.setDefaultWidget(self.fontSizeCombo) action_Android = QAction(Icons.android,'Android', self) action_Android.triggered.connect(self.parent.android) action_Ant = QAction(Icons.ant_view,'Ant', self) action_Ant.triggered.connect(self.parent.antt) action_Squirrel = QAction(Icons.nut,'Squirrel', self) action_Squirrel.triggered.connect(self.parent.squirrel) action_Ios1 = QAction(Icons.ios,'iOS', self) action_Update = QAction(Icons.update,"Update",self) action_Update.triggered.connect(self.parent.update) action_explorer = QAction("Explorer",self) action_explorer.triggered.connect(self.parent.exp) action_explorer.setCheckable(True) action_explorer.setChecked(True) action_console = QAction("Console",self) action_console.triggered.connect(self.parent.cmd) action_console.setCheckable(True) action_console.setChecked(False) #action_designer = QAction("Designer",self) #action_designer.triggered.connect(self.parent.design) action_Indentation = QAction("Indentation Guides",self) action_Indentation.triggered.connect(self.parent.setIndent) action_Indentation.setCheckable(True) action_Indentation.setChecked(config.indent()) action_WhiteSpace = QAction("WhiteSpace",self) action_WhiteSpace.triggered.connect(self.parent.setWhiteSpace) action_WhiteSpace.setCheckable(True) action_WhiteSpace.setChecked(config.whiteSpace()) action_EndLine = QAction("End of Lines",self) action_EndLine.triggered.connect(self.parent.setEndLine) action_EndLine.setCheckable(True) action_Margin = QAction("Line Numbers",self) action_Margin.triggered.connect(self.parent.setMargin) action_Margin.setCheckable(True) action_Margin.setChecked(config.margin()) action_ToolLabel = QAction("Tool Labels",self) action_ToolLabel.triggered.connect(self.setToolLabel) action_ToolLabel.setCheckable(True) #action_ToolLabel.setChecked(config.toolLabel()) '''Encoding''' encodingGroup = QActionGroup(self) encodingGroup.setExclusive(True) action_Ascii = QAction("Ascii",encodingGroup) action_Ascii.setCheckable(True) action_Unicode = QAction("Unicode",encodingGroup) action_Unicode.setCheckable(False) encodingGroup.addAction(action_Ascii) encodingGroup.addAction(action_Unicode) encodingGroup.selected.connect(self.parent.setEncoding) if(config.encoding() == Encoding.ASCII): action_Ascii.setChecked(True) else: action_Unicode.setChecked(True) men.addAction(action_Update) men.addAction(self.action_Help) men.addAction(self.action_Full) men.addSeparator() men.addAction(action_Android) men.addAction(action_Ant) men.addAction(action_Squirrel) men.addAction(action_Ios1) men.addSeparator() men.addAction(action_explorer) men.addAction(action_console) #men.addAction(action_designer) men.addSeparator() men.addAction(action_Indentation) men.addAction(action_WhiteSpace) men.addAction(action_EndLine) men.addAction(action_Margin) men.addAction(action_ToolLabel) men.addSeparator() men.addActions(encodingGroup.actions()) men.addSeparator() head_font = QLabel("Font---------------------") fnt = head_font.font() fnt.setBold(True) head_font.setFont(fnt) head_fontWidgetAction = QWidgetAction(men) head_fontWidgetAction.setDefaultWidget(head_font) men.addAction(head_fontWidgetAction) men.addAction(self.fontComboMenu) men.addAction(self.fontSizeComboMenu) men.addSeparator() men.addAction(QAction("TabWidth",self)) men.addAction(self.tabsSliderAction) men.addSeparator() men.addAction(QAction("Threshold",self)) men.addAction(self.threshSliderAction) #men.addAction(QAction("Icon Size",self)) #men.addAction(self.iconSliderAction) self.action_Options = QAction(Icons.emblem_system, 'Options', self) self.action_Options.setMenu(men) self.addAction(self.action_Options) ''' Mode Menu ''' def initModeMenu(self): self.modeGroup = QActionGroup(self) self.modeGroup.setExclusive(True) self.modeGroup.selected.connect(self.parent.setMode) self.action_Squirrel = QAction(Icons.nut, 'Squ', self.modeGroup) self.action_Squirrel.setCheckable(True) self.action_Emo = QAction(Icons.emo, 'Emo', self.modeGroup) self.action_Emo.setCheckable(True) self.action_And = QAction(Icons.android, 'Android', self.modeGroup) self.action_And.setCheckable(True) self.action_Ios = QAction(Icons.ios, 'ios', self.modeGroup) self.action_Ios.setCheckable(True) self.modeGroup.addAction(self.action_Squirrel) self.modeGroup.addAction(self.action_Emo) self.modeGroup.addAction(self.action_And) self.modeGroup.addAction(self.action_Ios) self.addActions(self.modeGroup.actions()) if(config.mode() == 0): self.action_Squirrel.setChecked(True) self.action_Build.setEnabled(False) self.action_Run.setEnabled(False) elif(config.mode() == 1): self.action_Emo.setChecked(True) self.action_Build.setEnabled(True) self.action_Run.setEnabled(True) elif(config.mode() == 2): self.action_And.setChecked(True) self.action_Build.setEnabled(True) self.action_Run.setEnabled(True) elif(config.mode() == 3): self.action_Ios.setChecked(True) self.action_Build.setEnabled(False) self.action_Run.setEnabled(False) ''' Style Menu ''' def initStyleMenu(self): editStyle = config.readStyle() self.action_Style = QAction(Icons.style, 'Style', self) men = QMenu(self) men1 = QMenu() self.base = StyleWidget(self,"base",editStyle["base"]) self.back = StyleWidget(self,"back",editStyle["back"]) self.caret = StyleWidget(self,"caret",editStyle["caret"]) self.margin = StyleWidget(self,"margin",editStyle["margin"]) self.marker = StyleWidget(self,"marker",editStyle["marker"]) self.comment = StyleWidget(self,"comment",editStyle["comment"]) self.number = StyleWidget(self,"number",editStyle["number"]) self.keyword = StyleWidget(self,"keyword",editStyle["keyword"]) self.string = StyleWidget(self,"string",editStyle["string"]) self.operator = StyleWidget(self,"operator",editStyle["operator"]) self.connect(self.base, SIGNAL("colorChange"),self.colorChange) self.connect(self.back, SIGNAL("colorChange"),self.colorChange) self.connect(self.caret, SIGNAL("colorChange"),self.colorChange) self.connect(self.margin, SIGNAL("colorChange"),self.colorChange) self.connect(self.marker, SIGNAL("colorChange"),self.colorChange) self.connect(self.comment, SIGNAL("colorChange"),self.colorChange) self.connect(self.number, SIGNAL("colorChange"),self.colorChange) self.connect(self.keyword, SIGNAL("colorChange"),self.colorChange) self.connect(self.string, SIGNAL("colorChange"),self.colorChange) self.connect(self.operator, SIGNAL("colorChange"),self.colorChange) self.baseMenu = QWidgetAction(men) self.baseMenu.setDefaultWidget(self.base) self.backMenu = QWidgetAction(men) self.backMenu.setDefaultWidget(self.back) self.caretMenu = QWidgetAction(men) self.caretMenu.setDefaultWidget(self.caret) self.marginMenu = QWidgetAction(men) self.marginMenu.setDefaultWidget(self.margin) self.markerMenu = QWidgetAction(men) self.markerMenu.setDefaultWidget(self.marker) self.commentMenu = QWidgetAction(men) self.commentMenu.setDefaultWidget(self.comment) self.numberMenu = QWidgetAction(men) self.numberMenu.setDefaultWidget(self.number) self.keywordMenu = QWidgetAction(men) self.keywordMenu.setDefaultWidget(self.keyword) self.stringMenu = QWidgetAction(men) self.stringMenu.setDefaultWidget(self.string) self.operatorMenu = QWidgetAction(men) self.operatorMenu.setDefaultWidget(self.operator) self.styleGroup = QActionGroup(self) self.styleGroup.setExclusive(True) self.styleGroup.selected.connect(self.setColors) self.style1 = QAction("All Hallow's Eve",self.styleGroup) self.style1.setCheckable(True) self.style2 = QAction("Amy",self.styleGroup) self.style2.setCheckable(True) self.style3 = QAction("Aptana Studio",self.styleGroup) self.style3.setCheckable(True) self.style4 = QAction("Bespin",self.styleGroup) self.style4.setCheckable(True) self.style5 = QAction("Blackboard",self.styleGroup) self.style5.setCheckable(True) self.style6 = QAction("Choco",self.styleGroup) self.style6.setCheckable(True) self.style7 = QAction("Cobalt",self.styleGroup) self.style7.setCheckable(True) self.style8 = QAction("Dawn",self.styleGroup) self.style8.setCheckable(True) self.style9 = QAction("Eclipse",self.styleGroup) self.style9.setCheckable(True) self.styleGroup.addAction(self.style1) self.styleGroup.addAction(self.style2) self.styleGroup.addAction(self.style3) self.styleGroup.addAction(self.style4) self.styleGroup.addAction(self.style5) self.styleGroup.addAction(self.style6) self.styleGroup.addAction(self.style7) self.styleGroup.addAction(self.style8) self.styleGroup.addAction(self.style9) men1.addAction(self.baseMenu) men1.addAction(self.backMenu) men1.addAction(self.caretMenu) men1.addAction(self.marginMenu) men1.addAction(self.markerMenu) men1.addAction(self.commentMenu) men1.addAction(self.numberMenu) men1.addAction(self.keywordMenu) men1.addAction(self.stringMenu) men1.addAction(self.operatorMenu) men1.addSeparator() men2 = QMenu(self) men2.setTitle("Styles") men2.addActions(self.styleGroup.actions()) men1.addMenu(men2) self.action_Style.setMenu(men1) self.addAction(self.action_Style) ''' Lexer Menu''' def make_action_lex(self, text): action = QAction(text, self.lexGroup) action.setCheckable(True) return action def initLexerMenu(self): self.action_Lexer = QAction(Icons.file_obj, 'Lexer', self) men = QMenu() self.lexGroup = QActionGroup(self) self.lexGroup.setExclusive(True) self.lexGroup.selected.connect(self.parent.setLexer) #langs = [i for i in dir(Qsci) if i.startswith('QsciLexer')] langs = ['Bash', 'Batch', 'CMake', 'CPP', 'CSS', 'C#','HTML','Java', 'JavaScript', 'Lua', 'Makefile','Python', 'SQL', 'XML', 'YAML'] for l in langs: act = self.make_action_lex(l) self.lexGroup.addAction(act) if(langs.index(l) == 8): #For javascript act.setChecked(True) #print l[9:] # we don't need to print "QsciLexer" before each name men.addActions(self.lexGroup.actions()) self.action_Lexer.setMenu(men) self.addAction(self.action_Lexer) ''' Api Menu ''' def make_action_api(self, text): action = QAction(text, self.apiGroup) action.setCheckable(True) return action def initApiMenu(self): self.action_Api = QAction(Icons.lib, 'Api', self) men = QMenu() self.apiGroup = QActionGroup(self) self.apiGroup.setExclusive(True) self.apiGroup.selected.connect(self.parent.setApi) list = oslistdir(apiDir) apis = [] if(list != None): for i in list: if i.endswith("api"): apis.append(i.replace(".api", "")) if(apis != None): for i in apis: act = self.make_action_api(i) self.apiGroup.addAction(act) if(i == "emo"): #For emo act.setChecked(True) men.addActions(self.apiGroup.actions()) self.action_Api.setMenu(men) self.addAction(self.action_Api)
class ProjectSnappingAction(ProjectSnappingEnabledAction): """Action to configure snapping.""" snapSettingsChanged = pyqtSignal() def __init__(self, parent=None): super(ProjectSnappingAction, self).__init__(parent) self.setCheckable(True) self._currentAction = SnappingModeAction(Snapping.CurrentLayer, self) self._allAction = SnappingModeAction(Snapping.AllLayers, self) self._selectedAction = SnappingModeAction(Snapping.SelectedLayers, self) self._snappingModeActionGroup = QActionGroup(self) self._snappingModeActionGroup.addAction(self._currentAction) self._snappingModeActionGroup.addAction(self._allAction) self._snappingModeActionGroup.addAction(self._selectedAction) self._vertexAction = ProjectSnappingTypeAction(Snapping.Vertex, self) self._segmentAction = ProjectSnappingTypeAction(Snapping.Segment, self) self._vertexSegmentAction = ProjectSnappingTypeAction( Snapping.VertexAndSegment, self) self._snappingTypeActionGroup = QActionGroup(self) self._snappingTypeActionGroup.addAction(self._vertexAction) self._snappingTypeActionGroup.addAction(self._segmentAction) self._snappingTypeActionGroup.addAction(self._vertexSegmentAction) self._pixelUnitsAction = ProjectSnappingUnitAction( Snapping.Pixels, self) self._layerUnitsAction = ProjectSnappingUnitAction( Snapping.LayerUnits, self) self._projectUnitsAction = ProjectSnappingUnitAction( Snapping.ProjectUnits, self) self._unitTypeActionGroup = QActionGroup(self) self._unitTypeActionGroup.addAction(self._pixelUnitsAction) self._unitTypeActionGroup.addAction(self._layerUnitsAction) self._unitTypeActionGroup.addAction(self._projectUnitsAction) self._toleranceAction = ProjectSnappingToleranceAction(parent) menu = ControlMenu(parent) menu.addActions(self._snappingModeActionGroup.actions()) menu.addSeparator() menu.addActions(self._snappingTypeActionGroup.actions()) menu.addSeparator() menu.addAction(self._toleranceAction) menu.addActions(self._unitTypeActionGroup.actions()) self.setMenu(menu) self._refreshAction() # Make sure we catch changes in the main snapping dialog QgsProject.instance().snapSettingsChanged.connect(self._refreshAction) def setInterface(self, iface): self._toleranceAction.setInterface(iface) def unload(self): super(ProjectSnappingAction, self).unload() self._currentAction.unload() self._allAction.unload() self._selectedAction.unload() self._vertexAction.unload() self._segmentAction.unload() self._vertexSegmentAction.unload() self._pixelUnitsAction.unload() self._layerUnitsAction.unload() self._projectUnitsAction.unload() self._toleranceAction.unload() QgsProject.instance().snapSettingsChanged.disconnect( self._refreshAction) # Private API def _refreshAction(self): snapMode = Snapping.snappingMode() if snapMode == Snapping.SelectedLayers: self.setIcon(self._selectedAction.icon()) elif snapMode == Snapping.CurrentLayer: self.setIcon(self._currentAction.icon()) elif snapMode == Snapping.AllLayers: self.setIcon(self._allAction.icon())
class MainWindow(base_class, ui_class): implements(IObserver) def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.saved_account_state = None notification_center = NotificationCenter() notification_center.add_observer(self, name='SIPApplicationWillStart') notification_center.add_observer(self, name='SIPApplicationDidStart') notification_center.add_observer(self, name='SIPAccountGotMessageSummary') notification_center.add_observer(self, name='SIPAccountGotPendingWatcher') notification_center.add_observer(self, name='BlinkSessionNewOutgoing') notification_center.add_observer(self, name='BlinkSessionDidReinitializeForOutgoing') notification_center.add_observer(self, name='BlinkFileTransferNewIncoming') notification_center.add_observer(self, name='BlinkFileTransferNewOutgoing') notification_center.add_observer(self, name='DocumentSharingFileTransferCompleted') notification_center.add_observer(self, sender=AccountManager()) icon_manager = IconManager() self.pending_watcher_dialogs = [] self.mwi_icons = [QIcon(Resources.get('icons/mwi-%d.png' % i)) for i in xrange(0, 11)] self.mwi_icons.append(QIcon(Resources.get('icons/mwi-many.png'))) with Resources.directory: self.setupUi() self.setWindowTitle('Blink') self.setWindowIconText('Blink') geometry = QSettings().value("main_window/geometry") if geometry: self.restoreGeometry(geometry) self.default_icon_path = Resources.get('icons/default-avatar.png') self.default_icon = QIcon(self.default_icon_path) self.last_icon_directory = Path('~').normalized self.set_user_icon(icon_manager.get('avatar')) self.active_sessions_label.hide() self.enable_call_buttons(False) self.conference_button.setEnabled(False) self.hangup_all_button.setEnabled(False) self.sip_server_settings_action.setEnabled(False) self.search_for_people_action.setEnabled(False) self.history_on_server_action.setEnabled(False) self.main_view.setCurrentWidget(self.contacts_panel) self.contacts_view.setCurrentWidget(self.contact_list_panel) self.search_view.setCurrentWidget(self.search_list_panel) # System tray if QSystemTrayIcon.isSystemTrayAvailable(): self.system_tray_icon = QSystemTrayIcon(QIcon(Resources.get('icons/blink.png')), self) self.system_tray_icon.activated.connect(self._SH_SystemTrayIconActivated) menu = QMenu(self) menu.addAction(QAction("Show", self, triggered=self._AH_SystemTrayShowWindow)) menu.addAction(QAction(QIcon(Resources.get('icons/application-exit.png')), "Quit", self, triggered=self._AH_QuitActionTriggered)) self.system_tray_icon.setContextMenu(menu) self.system_tray_icon.show() else: self.system_tray_icon = None # Accounts self.account_model = AccountModel(self) self.enabled_account_model = ActiveAccountModel(self.account_model, self) self.server_tools_account_model = ServerToolsAccountModel(self.account_model, self) self.identity.setModel(self.enabled_account_model) # Contacts self.contact_model = ContactModel(self) self.contact_search_model = ContactSearchModel(self.contact_model, self) self.contact_list.setModel(self.contact_model) self.search_list.setModel(self.contact_search_model) # Sessions (audio) self.session_model = AudioSessionModel(self) self.session_list.setModel(self.session_model) self.session_list.selectionModel().selectionChanged.connect(self._SH_SessionListSelectionChanged) # History self.history_manager = HistoryManager() # Windows, dialogs and panels self.about_panel = AboutPanel(self) self.conference_dialog = ConferenceDialog(self) self.contact_editor_dialog = ContactEditorDialog(self) self.google_contacts_dialog = GoogleContactsDialog(self) self.filetransfer_window = FileTransferWindow() self.preferences_window = PreferencesWindow(self.account_model, None) self.server_tools_window = ServerToolsWindow(self.server_tools_account_model, None) self.documents_window = DocumentsWindow() # Signals self.account_state.stateChanged.connect(self._SH_AccountStateChanged) self.account_state.clicked.connect(self._SH_AccountStateClicked) self.activity_note.editingFinished.connect(self._SH_ActivityNoteEditingFinished) self.add_contact_button.clicked.connect(self._SH_AddContactButtonClicked) self.add_search_contact_button.clicked.connect(self._SH_AddContactButtonClicked) self.audio_call_button.clicked.connect(self._SH_AudioCallButtonClicked) self.video_call_button.clicked.connect(self._SH_VideoCallButtonClicked) self.chat_session_button.clicked.connect(self._SH_ChatSessionButtonClicked) self.share_document_button.clicked.connect(self._SH_ShareDocumentButtonClicked) self.back_to_contacts_button.clicked.connect(self.search_box.clear) # this can be set in designer -Dan self.conference_button.makeConference.connect(self._SH_MakeConference) self.conference_button.breakConference.connect(self._SH_BreakConference) self.contact_list.selectionModel().selectionChanged.connect(self._SH_ContactListSelectionChanged) self.contact_model.itemsAdded.connect(self._SH_ContactModelAddedItems) self.contact_model.itemsRemoved.connect(self._SH_ContactModelRemovedItems) self.display_name.editingFinished.connect(self._SH_DisplayNameEditingFinished) self.hangup_all_button.clicked.connect(self._SH_HangupAllButtonClicked) self.identity.activated[int].connect(self._SH_IdentityChanged) self.identity.currentIndexChanged[int].connect(self._SH_IdentityCurrentIndexChanged) self.mute_button.clicked.connect(self._SH_MuteButtonClicked) self.search_box.textChanged.connect(self._SH_SearchBoxTextChanged) self.search_box.returnPressed.connect(self._SH_SearchBoxReturnPressed) self.search_box.shortcut.activated.connect(self.search_box.setFocus) self.search_list.selectionModel().selectionChanged.connect(self._SH_SearchListSelectionChanged) self.server_tools_account_model.rowsInserted.connect(self._SH_ServerToolsAccountModelChanged) self.server_tools_account_model.rowsRemoved.connect(self._SH_ServerToolsAccountModelChanged) self.session_model.sessionAdded.connect(self._SH_AudioSessionModelAddedSession) self.session_model.sessionRemoved.connect(self._SH_AudioSessionModelRemovedSession) self.session_model.structureChanged.connect(self._SH_AudioSessionModelChangedStructure) self.silent_button.clicked.connect(self._SH_SilentButtonClicked) self.switch_view_button.viewChanged.connect(self._SH_SwitchViewButtonChangedView) # Blink menu actions self.about_action.triggered.connect(self.about_panel.show) self.add_account_action.triggered.connect(self.preferences_window.show_add_account_dialog) self.manage_accounts_action.triggered.connect(self.preferences_window.show_for_accounts) self.help_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/help-qt.phtml'))) self.preferences_action.triggered.connect(self.preferences_window.show) self.auto_accept_chat_action.triggered.connect(self._AH_AutoAcceptChatActionTriggered) self.received_messages_sound_action.triggered.connect(self._AH_ReceivedMessagesSoundActionTriggered) self.answering_machine_action.triggered.connect(self._AH_EnableAnsweringMachineActionTriggered) self.release_notes_action.triggered.connect(partial(QDesktopServices.openUrl, QUrl(u'http://icanblink.com/changelog-qt.phtml'))) self.quit_action.triggered.connect(self._AH_QuitActionTriggered) # Call menu actions self.redial_action.triggered.connect(self._AH_RedialActionTriggered) self.join_conference_action.triggered.connect(self.conference_dialog.show) self.history_menu.aboutToShow.connect(self._SH_HistoryMenuAboutToShow) self.history_menu.triggered.connect(self._AH_HistoryMenuTriggered) self.output_devices_group.triggered.connect(self._AH_AudioOutputDeviceChanged) self.input_devices_group.triggered.connect(self._AH_AudioInputDeviceChanged) self.alert_devices_group.triggered.connect(self._AH_AudioAlertDeviceChanged) self.video_devices_group.triggered.connect(self._AH_VideoDeviceChanged) self.mute_action.triggered.connect(self._SH_MuteButtonClicked) self.silent_action.triggered.connect(self._SH_SilentButtonClicked) # Tools menu actions self.sip_server_settings_action.triggered.connect(self._AH_SIPServerSettings) self.search_for_people_action.triggered.connect(self._AH_SearchForPeople) self.history_on_server_action.triggered.connect(self._AH_HistoryOnServer) # Window menu actions self.chat_window_action.triggered.connect(self._AH_ChatWindowActionTriggered) self.transfers_window_action.triggered.connect(self._AH_TransfersWindowActionTriggered) self.logs_window_action.triggered.connect(self._AH_LogsWindowActionTriggered) self.received_files_window_action.triggered.connect(self._AH_ReceivedFilesWindowActionTriggered) self.screenshots_window_action.triggered.connect(self._AH_ScreenshotsWindowActionTriggered) self.documents_window_action.triggered.connect(self._AH_DocumentsWindowActionTriggered) def setupUi(self): super(MainWindow, self).setupUi(self) self.search_box.shortcut = QShortcut(self.search_box) self.search_box.shortcut.setKey('Ctrl+F') self.output_devices_group = QActionGroup(self) self.input_devices_group = QActionGroup(self) self.alert_devices_group = QActionGroup(self) self.video_devices_group = QActionGroup(self) self.request_screen_action = QAction('Request screen', self, triggered=self._AH_RequestScreenActionTriggered) self.share_my_screen_action = QAction('Share my screen', self, triggered=self._AH_ShareMyScreenActionTriggered) self.screen_sharing_button.addAction(self.request_screen_action) self.screen_sharing_button.addAction(self.share_my_screen_action) # adjust search box height depending on theme as the value set in designer isn't suited for all themes search_box = self.search_box option = QStyleOptionFrameV2() search_box.initStyleOption(option) frame_width = search_box.style().pixelMetric(QStyle.PM_DefaultFrameWidth, option, search_box) if frame_width < 4: search_box.setMinimumHeight(20 + 2*frame_width) # adjust the combo boxes for themes with too much padding (like the default theme on Ubuntu 10.04) option = QStyleOptionComboBox() self.identity.initStyleOption(option) wide_padding = self.identity.style().subControlRect(QStyle.CC_ComboBox, option, QStyle.SC_ComboBoxEditField, self.identity).height() < 10 self.identity.setStyleSheet("""QComboBox { padding: 0px 4px 0px 4px; }""" if wide_padding else "") def closeEvent(self, event): QSettings().setValue("main_window/geometry", self.saveGeometry()) super(MainWindow, self).closeEvent(event) self.about_panel.close() self.contact_editor_dialog.close() self.google_contacts_dialog.close() self.server_tools_window.close() for dialog in self.pending_watcher_dialogs[:]: dialog.close() def show(self): super(MainWindow, self).show() self.raise_() self.activateWindow() def set_user_icon(self, icon): self.account_state.setIcon(icon or self.default_icon) def enable_call_buttons(self, enabled): self.audio_call_button.setEnabled(enabled) self.video_call_button.setEnabled(enabled) self.chat_session_button.setEnabled(enabled) self.screen_sharing_button.setEnabled(enabled) self.share_document_button.setEnabled(enabled) def load_audio_devices(self): settings = SIPSimpleSettings() action = QAction(u'System default', self.output_devices_group) action.setData(u'system_default') self.output_device_menu.addAction(action) self.output_device_menu.addSeparator() for device in SIPApplication.engine.output_devices: action = QAction(device, self.output_devices_group) action.setData(device) self.output_device_menu.addAction(action) action = QAction(u'None', self.output_devices_group) action.setData(None) self.output_device_menu.addAction(action) for action in self.output_devices_group.actions(): action.setCheckable(True) if settings.audio.output_device == action.data(): action.setChecked(True) action = QAction(u'System default', self.input_devices_group) action.setData(u'system_default') self.input_device_menu.addAction(action) self.input_device_menu.addSeparator() for device in SIPApplication.engine.input_devices: action = QAction(device, self.input_devices_group) action.setData(device) self.input_device_menu.addAction(action) action = QAction(u'None', self.input_devices_group) action.setData(None) self.input_device_menu.addAction(action) for action in self.input_devices_group.actions(): action.setCheckable(True) if settings.audio.input_device == action.data(): action.setChecked(True) action = QAction(u'System default', self.alert_devices_group) action.setData(u'system_default') self.alert_device_menu.addAction(action) self.alert_device_menu.addSeparator() for device in SIPApplication.engine.output_devices: action = QAction(device, self.alert_devices_group) action.setData(device) self.alert_device_menu.addAction(action) action = QAction(u'None', self.alert_devices_group) action.setData(None) self.alert_device_menu.addAction(action) for action in self.alert_devices_group.actions(): action.setCheckable(True) if settings.audio.alert_device == action.data(): action.setChecked(True) def load_video_devices(self): settings = SIPSimpleSettings() action = QAction(u'System default', self.video_devices_group) action.setData(u'system_default') self.video_camera_menu.addAction(action) self.video_camera_menu.addSeparator() for device in SIPApplication.engine.video_devices: action = QAction(device, self.video_devices_group) action.setData(device) self.video_camera_menu.addAction(action) action = QAction(u'None', self.video_devices_group) action.setData(None) self.video_camera_menu.addAction(action) for action in self.video_devices_group.actions(): action.setCheckable(True) if settings.video.device == action.data(): action.setChecked(True) def _AH_AccountActionTriggered(self, action, enabled): account = action.data() account.enabled = enabled account.save() def _AH_AudioAlertDeviceChanged(self, action): settings = SIPSimpleSettings() settings.audio.alert_device = action.data() settings.save() def _AH_AudioInputDeviceChanged(self, action): settings = SIPSimpleSettings() settings.audio.input_device = action.data() settings.save() def _AH_AudioOutputDeviceChanged(self, action): settings = SIPSimpleSettings() settings.audio.output_device = action.data() settings.save() def _AH_VideoDeviceChanged(self, action): settings = SIPSimpleSettings() settings.video.device = action.data() settings.save() def _AH_AutoAcceptChatActionTriggered(self, checked): settings = SIPSimpleSettings() settings.chat.auto_accept = checked settings.save() def _AH_ReceivedMessagesSoundActionTriggered(self, checked): settings = SIPSimpleSettings() settings.sounds.play_message_alerts = checked settings.save() def _AH_EnableAnsweringMachineActionTriggered(self, checked): settings = SIPSimpleSettings() settings.answering_machine.enabled = checked settings.save() def _AH_GoogleContactsActionTriggered(self): settings = SIPSimpleSettings() if settings.google_contacts.authorization_token is not None: settings.google_contacts.authorization_token = None settings.save() self.google_contacts_dialog.hide() else: self.google_contacts_dialog.open() def _AH_RedialActionTriggered(self): session_manager = SessionManager() if session_manager.last_dialed_uri is not None: contact, contact_uri = URIUtils.find_contact(session_manager.last_dialed_uri) session_manager.create_session(contact, contact_uri, [StreamDescription('audio')]) # TODO: remember used media types and redial with them. -Saul def _AH_SIPServerSettings(self, checked): account = self.identity.itemData(self.identity.currentIndex()).account account = account if account is not BonjourAccount() and account.server.settings_url else None self.server_tools_window.open_settings_page(account) def _AH_SearchForPeople(self, checked): account = self.identity.itemData(self.identity.currentIndex()).account account = account if account is not BonjourAccount() and account.server.settings_url else None self.server_tools_window.open_search_for_people_page(account) def _AH_HistoryOnServer(self, checked): account = self.identity.itemData(self.identity.currentIndex()).account account = account if account is not BonjourAccount() and account.server.settings_url else None self.server_tools_window.open_history_page(account) def _AH_ChatWindowActionTriggered(self, checked): blink = QApplication.instance() blink.chat_window.show() def _AH_TransfersWindowActionTriggered(self, checked): self.filetransfer_window.show() def _AH_LogsWindowActionTriggered(self, checked): directory = ApplicationData.get('logs') makedirs(directory) QDesktopServices.openUrl(QUrl.fromLocalFile(directory)) def _AH_ReceivedFilesWindowActionTriggered(self, checked): settings = BlinkSettings() directory = settings.transfers_directory.normalized makedirs(directory) QDesktopServices.openUrl(QUrl.fromLocalFile(directory)) def _AH_ScreenshotsWindowActionTriggered(self, checked): settings = BlinkSettings() directory = settings.screenshots_directory.normalized makedirs(directory) QDesktopServices.openUrl(QUrl.fromLocalFile(directory)) def _AH_DocumentsWindowActionTriggered(self, checked): self.documents_window.show() def _AH_VoicemailActionTriggered(self, action, checked): account = action.data() contact, contact_uri = URIUtils.find_contact(account.voicemail_uri, display_name='Voicemail') session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('audio')], account=account) def _SH_HistoryMenuAboutToShow(self): self.history_menu.clear() if self.history_manager.calls: for entry in reversed(self.history_manager.calls): action = self.history_menu.addAction(entry.icon, entry.text) action.entry = entry action.setToolTip(entry.uri) else: action = self.history_menu.addAction("Call history is empty") action.setEnabled(False) def _AH_HistoryMenuTriggered(self, action): account_manager = AccountManager() session_manager = SessionManager() try: account = account_manager.get_account(action.entry.account_id) except KeyError: account = None contact, contact_uri = URIUtils.find_contact(action.entry.uri) session_manager.create_session(contact, contact_uri, [StreamDescription('audio')], account=account) # TODO: memorize media type and use it? -Saul (not sure about history in/out -Dan) def _AH_SystemTrayShowWindow(self, checked): self.show() self.raise_() self.activateWindow() def _AH_QuitActionTriggered(self, checked): if self.system_tray_icon is not None: self.system_tray_icon.hide() QApplication.instance().quit() def _SH_AccountStateChanged(self): self.activity_note.setText(self.account_state.note) if self.account_state.state is AccountState.Invisible: self.activity_note.inactiveText = u'(invisible)' self.activity_note.setEnabled(False) else: if not self.activity_note.isEnabled(): self.activity_note.inactiveText = u'Add an activity note here' self.activity_note.setEnabled(True) if not self.account_state.state.internal: self.saved_account_state = None blink_settings = BlinkSettings() blink_settings.presence.current_state = PresenceState(self.account_state.state, self.account_state.note) blink_settings.presence.state_history = [PresenceState(state, note) for state, note in self.account_state.history] blink_settings.save() def _SH_AccountStateClicked(self, checked): filename = QFileDialog.getOpenFileName(self, u'Select Icon', self.last_icon_directory, u"Images (*.png *.tiff *.jpg *.xmp *.svg)") if filename: self.last_icon_directory = os.path.dirname(filename) filename = filename if os.path.realpath(filename) != os.path.realpath(self.default_icon_path) else None blink_settings = BlinkSettings() icon_manager = IconManager() if filename is not None: icon = icon_manager.store_file('avatar', filename) if icon is not None: blink_settings.presence.icon = IconDescriptor(FileURL(icon.filename), hashlib.sha1(icon.content).hexdigest()) else: icon_manager.remove('avatar') blink_settings.presence.icon = None else: icon_manager.remove('avatar') blink_settings.presence.icon = None blink_settings.save() def _SH_ActivityNoteEditingFinished(self): self.activity_note.clearFocus() note = self.activity_note.text() if note != self.account_state.note: self.account_state.state.internal = False self.account_state.setState(self.account_state.state, note) def _SH_AddContactButtonClicked(self, clicked): self.contact_editor_dialog.open_for_add(self.search_box.text(), None) def _SH_AudioCallButtonClicked(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list if list_view.detail_view.isVisible(): list_view.detail_view._AH_StartAudioCall() else: selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('audio')]) def _SH_VideoCallButtonClicked(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list if list_view.detail_view.isVisible(): list_view.detail_view._AH_StartVideoCall() else: selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('audio'), StreamDescription('video')]) def _SH_ChatSessionButtonClicked(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list if list_view.detail_view.isVisible(): list_view.detail_view._AH_StartChatSession() else: selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('chat')], connect=False) def _AH_RequestScreenActionTriggered(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list if list_view.detail_view.isVisible(): list_view.detail_view._AH_RequestScreen() else: selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('screen-sharing', mode='viewer'), StreamDescription('audio')]) def _AH_ShareMyScreenActionTriggered(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list if list_view.detail_view.isVisible(): list_view.detail_view._AH_ShareMyScreen() else: selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('screen-sharing', mode='server'), StreamDescription('audio')]) def _SH_ShareDocumentButtonClicked(self): list_view = self.contact_list if self.contacts_view.currentWidget() is self.contact_list_panel else self.search_list selected_indexes = list_view.selectionModel().selectedIndexes() if selected_indexes: contact = selected_indexes[0].data(Qt.UserRole) contact_uri = contact.uri else: contact, contact_uri = URIUtils.find_contact(self.search_box.text()) filename = QFileDialog.getOpenFileName(self, "Share a Document", "", "OpenDocument Files (*.odt)") if filename: session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('document-sharing', filename=filename)]) def _SH_BreakConference(self): active_session = self.session_list.selectionModel().selectedIndexes()[0].data(Qt.UserRole) self.session_model.breakConference(active_session.client_conference) def _SH_ContactListSelectionChanged(self, selected, deselected): account_manager = AccountManager() selected_items = self.contact_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)==1 and isinstance(selected_items[0].data(Qt.UserRole), Contact)) def _SH_ContactModelAddedItems(self, items): if not self.search_box.text(): return active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel self.search_view.setCurrentWidget(active_widget) def _SH_ContactModelRemovedItems(self, items): if not self.search_box.text(): return if any(type(item) is Contact for item in items) and self.contact_search_model.rowCount() == 0: self.search_box.clear() # check this. it is no longer be the correct behaviour as now contacts can be deleted from remote -Dan else: active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel self.search_view.setCurrentWidget(active_widget) def _SH_DisplayNameEditingFinished(self): self.display_name.clearFocus() index = self.identity.currentIndex() if index != -1: name = self.display_name.text() account = self.identity.itemData(index).account account.display_name = name if name else None account.save() def _SH_HangupAllButtonClicked(self): for session in self.session_model.sessions: session.end() def _SH_IdentityChanged(self, index): account_manager = AccountManager() account_manager.default_account = self.identity.itemData(index).account def _SH_IdentityCurrentIndexChanged(self, index): if index != -1: account = self.identity.itemData(index).account self.display_name.setText(account.display_name or u'') self.display_name.setEnabled(True) self.activity_note.setEnabled(True) self.account_state.setEnabled(True) else: self.display_name.clear() self.display_name.setEnabled(False) self.activity_note.setEnabled(False) self.account_state.setEnabled(False) self.account_state.setState(AccountState.Invisible) self.saved_account_state = None def _SH_MakeConference(self): self.session_model.conferenceSessions([session for session in self.session_model.active_sessions if session.client_conference is None]) def _SH_MuteButtonClicked(self, muted): settings = SIPSimpleSettings() settings.audio.muted = muted settings.save() def _SH_SearchBoxReturnPressed(self): address = self.search_box.text() if address: contact, contact_uri = URIUtils.find_contact(address) session_manager = SessionManager() session_manager.create_session(contact, contact_uri, [StreamDescription('audio')]) def _SH_SearchBoxTextChanged(self, text): self.contact_search_model.setFilterFixedString(text) account_manager = AccountManager() if text: self.switch_view_button.view = SwitchViewButton.ContactView if self.contacts_view.currentWidget() is not self.search_panel: self.search_list.selectionModel().clearSelection() self.contacts_view.setCurrentWidget(self.search_panel) self.search_view.setCurrentWidget(self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel) selected_items = self.search_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1) else: self.contacts_view.setCurrentWidget(self.contact_list_panel) selected_items = self.contact_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)==1 and type(selected_items[0].data(Qt.UserRole)) is Contact) self.search_list.detail_model.contact = None self.search_list.detail_view.hide() def _SH_SearchListSelectionChanged(self, selected, deselected): account_manager = AccountManager() selected_items = self.search_list.selectionModel().selectedIndexes() self.enable_call_buttons(account_manager.default_account is not None and len(selected_items)<=1) def _SH_ServerToolsAccountModelChanged(self, parent_index, start, end): server_tools_enabled = self.server_tools_account_model.rowCount() > 0 self.sip_server_settings_action.setEnabled(server_tools_enabled) self.search_for_people_action.setEnabled(server_tools_enabled) self.history_on_server_action.setEnabled(server_tools_enabled) def _SH_SessionListSelectionChanged(self, selected, deselected): selected_indexes = selected.indexes() active_session = selected_indexes[0].data(Qt.UserRole) if selected_indexes else Null if active_session.client_conference: self.conference_button.setEnabled(True) self.conference_button.setChecked(True) else: self.conference_button.setEnabled(len([session for session in self.session_model.active_sessions if session.client_conference is None]) > 1) self.conference_button.setChecked(False) def _SH_AudioSessionModelAddedSession(self, session_item): if len(session_item.blink_session.streams) == 1: self.switch_view_button.view = SwitchViewButton.SessionView def _SH_AudioSessionModelRemovedSession(self, session_item): if self.session_model.rowCount() == 0: self.switch_view_button.view = SwitchViewButton.ContactView def _SH_AudioSessionModelChangedStructure(self): active_sessions = self.session_model.active_sessions self.active_sessions_label.setText(u'There is 1 active call' if len(active_sessions)==1 else u'There are %d active calls' % len(active_sessions)) self.active_sessions_label.setVisible(any(active_sessions)) self.hangup_all_button.setEnabled(any(active_sessions)) selected_indexes = self.session_list.selectionModel().selectedIndexes() active_session = selected_indexes[0].data(Qt.UserRole) if selected_indexes else Null if active_session.client_conference: self.conference_button.setEnabled(True) self.conference_button.setChecked(True) else: self.conference_button.setEnabled(len([session for session in active_sessions if session.client_conference is None]) > 1) self.conference_button.setChecked(False) if active_sessions: if self.account_state.state is not AccountState.Invisible: if self.saved_account_state is None: self.saved_account_state = self.account_state.state, self.activity_note.text() self.account_state.setState(AccountState.Busy.Internal, note=u'On the phone') elif self.saved_account_state is not None: state, note = self.saved_account_state self.saved_account_state = None self.account_state.setState(state, note) def _SH_SilentButtonClicked(self, silent): settings = SIPSimpleSettings() settings.audio.silent = silent settings.save() def _SH_SwitchViewButtonChangedView(self, view): self.main_view.setCurrentWidget(self.contacts_panel if view is SwitchViewButton.ContactView else self.sessions_panel) def _SH_PendingWatcherDialogFinished(self, result): self.pending_watcher_dialogs.remove(self.sender()) def _SH_SystemTrayIconActivated(self, reason): if reason == QSystemTrayIcon.Trigger: self.show() self.raise_() self.activateWindow() @run_in_gui_thread def handle_notification(self, notification): handler = getattr(self, '_NH_%s' % notification.name, Null) handler(notification) def _NH_SIPApplicationWillStart(self, notification): account_manager = AccountManager() settings = SIPSimpleSettings() self.silent_action.setChecked(settings.audio.silent) self.silent_button.setChecked(settings.audio.silent) self.answering_machine_action.setChecked(settings.answering_machine.enabled) self.auto_accept_chat_action.setChecked(settings.chat.auto_accept) self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts) if settings.google_contacts.authorization_token is None: self.google_contacts_action.setText(u'Enable &Google Contacts...') else: self.google_contacts_action.setText(u'Disable &Google Contacts') self.google_contacts_action.triggered.connect(self._AH_GoogleContactsActionTriggered) if not any(account.enabled for account in account_manager.iter_accounts()): self.display_name.setEnabled(False) self.activity_note.setEnabled(False) self.account_state.setEnabled(False) def _NH_SIPApplicationDidStart(self, notification): self.load_audio_devices() self.load_video_devices() notification.center.add_observer(self, name='CFGSettingsObjectDidChange') notification.center.add_observer(self, name='AudioDevicesDidChange') blink_settings = BlinkSettings() self.account_state.history = [(item.state, item.note) for item in blink_settings.presence.state_history] state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available) self.account_state.setState(state, blink_settings.presence.current_state.note) def _NH_AudioDevicesDidChange(self, notification): for action in self.output_device_menu.actions(): self.output_devices_group.removeAction(action) self.output_device_menu.removeAction(action) for action in self.input_device_menu.actions(): self.input_devices_group.removeAction(action) self.input_device_menu.removeAction(action) for action in self.alert_device_menu.actions(): self.alert_devices_group.removeAction(action) self.alert_device_menu.removeAction(action) if self.session_model.active_sessions: old_devices = set(notification.data.old_devices) new_devices = set(notification.data.new_devices) added_devices = new_devices - old_devices if added_devices: new_device = added_devices.pop() settings = SIPSimpleSettings() settings.audio.input_device = new_device settings.audio.output_device = new_device settings.save() self.load_audio_devices() def _NH_CFGSettingsObjectDidChange(self, notification): settings = SIPSimpleSettings() blink_settings = BlinkSettings() icon_manager = IconManager() if notification.sender is settings: if 'audio.muted' in notification.data.modified: self.mute_action.setChecked(settings.audio.muted) self.mute_button.setChecked(settings.audio.muted) if 'audio.silent' in notification.data.modified: self.silent_action.setChecked(settings.audio.silent) self.silent_button.setChecked(settings.audio.silent) if 'audio.output_device' in notification.data.modified: action = (action for action in self.output_devices_group.actions() if action.data() == settings.audio.output_device).next() action.setChecked(True) if 'audio.input_device' in notification.data.modified: action = (action for action in self.input_devices_group.actions() if action.data() == settings.audio.input_device).next() action.setChecked(True) if 'audio.alert_device' in notification.data.modified: action = (action for action in self.alert_devices_group.actions() if action.data() == settings.audio.alert_device).next() action.setChecked(True) if 'video.device' in notification.data.modified: action = (action for action in self.video_devices_group.actions() if action.data() == settings.video.device).next() action.setChecked(True) if 'answering_machine.enabled' in notification.data.modified: self.answering_machine_action.setChecked(settings.answering_machine.enabled) if 'chat.auto_accept' in notification.data.modified: self.auto_accept_chat_action.setChecked(settings.chat.auto_accept) if 'sounds.play_message_alerts' in notification.data.modified: self.received_messages_sound_action.setChecked(settings.sounds.play_message_alerts) if 'google_contacts.authorization_token' in notification.data.modified: authorization_token = notification.sender.google_contacts.authorization_token if authorization_token is None: self.google_contacts_action.setText(u'Enable &Google Contacts...') else: self.google_contacts_action.setText(u'Disable &Google Contacts') if authorization_token is InvalidToken: self.google_contacts_dialog.open_for_incorrect_password() elif notification.sender is blink_settings: if 'presence.current_state' in notification.data.modified: state = getattr(AccountState, blink_settings.presence.current_state.state, AccountState.Available) self.account_state.setState(state, blink_settings.presence.current_state.note) if 'presence.icon' in notification.data.modified: self.set_user_icon(icon_manager.get('avatar')) if 'presence.offline_note' in notification.data.modified: # TODO: set offline note -Saul pass elif isinstance(notification.sender, (Account, BonjourAccount)): account_manager = AccountManager() account = notification.sender if 'enabled' in notification.data.modified: action = (action for action in self.accounts_menu.actions() if action.data() is account).next() action.setChecked(account.enabled) if 'display_name' in notification.data.modified and account is account_manager.default_account: self.display_name.setText(account.display_name or u'') if set(['enabled', 'message_summary.enabled', 'message_summary.voicemail_uri']).intersection(notification.data.modified): action = (action for action in self.voicemail_menu.actions() if action.data() is account).next() action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled) action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None) def _NH_SIPAccountManagerDidAddAccount(self, notification): account = notification.data.account action = QAction(account.id if account is not BonjourAccount() else u'Bonjour', None) action.setEnabled(True if account is not BonjourAccount() else BonjourAccount.mdns_available) action.setCheckable(True) action.setChecked(account.enabled) action.setData(account) action.triggered.connect(partial(self._AH_AccountActionTriggered, action)) self.accounts_menu.addAction(action) action = QAction(self.mwi_icons[0], account.id, None) action.setVisible(False if account is BonjourAccount() else account.enabled and account.message_summary.enabled) action.setEnabled(False if account is BonjourAccount() else account.voicemail_uri is not None) action.setData(account) action.triggered.connect(partial(self._AH_VoicemailActionTriggered, action)) self.voicemail_menu.addAction(action) def _NH_SIPAccountManagerDidRemoveAccount(self, notification): account = notification.data.account action = (action for action in self.accounts_menu.actions() if action.data() is account).next() self.accounts_menu.removeAction(action) action = (action for action in self.voicemail_menu.actions() if action.data() is account).next() self.voicemail_menu.removeAction(action) def _NH_SIPAccountManagerDidChangeDefaultAccount(self, notification): if notification.data.account is None: self.enable_call_buttons(False) else: selected_items = self.contact_list.selectionModel().selectedIndexes() self.enable_call_buttons(len(selected_items)==1 and isinstance(selected_items[0].data(Qt.UserRole), Contact)) def _NH_SIPAccountGotMessageSummary(self, notification): account = notification.sender summary = notification.data.message_summary action = (action for action in self.voicemail_menu.actions() if action.data() is account).next() action.setEnabled(account.voicemail_uri is not None) if summary.messages_waiting: try: new_messages = limit(int(summary.summaries['voice-message']['new_messages']), min=0, max=11) except (KeyError, ValueError): new_messages = 0 else: new_messages = 0 action.setIcon(self.mwi_icons[new_messages]) def _NH_SIPAccountGotPendingWatcher(self, notification): dialog = PendingWatcherDialog(notification.sender, notification.data.uri, notification.data.display_name) dialog.finished.connect(self._SH_PendingWatcherDialogFinished) self.pending_watcher_dialogs.append(dialog) dialog.show() def _NH_BlinkSessionNewOutgoing(self, notification): self.search_box.clear() def _NH_BlinkSessionDidReinitializeForOutgoing(self, notification): self.search_box.clear() def _NH_BlinkFileTransferNewIncoming(self, notification): self.filetransfer_window.show(activate=QApplication.activeWindow() is not None) def _NH_BlinkFileTransferNewOutgoing(self, notification): self.filetransfer_window.show(activate=QApplication.activeWindow() is not None)
class XViewProfileToolBar(XToolBar): profileCreated = qt.Signal(qt.PyObject) profileChanged = qt.Signal(qt.PyObject) profileRemoved = qt.Signal(qt.PyObject) currentProfileChanged = qt.Signal(qt.PyObject) def __init__( self, parent ): super(XViewProfileToolBar, self).__init__(parent) # create custom properties self._editingEnabled = True self._viewWidget = None self._profileGroup = QActionGroup(self) # set the default options self.setIconSize(QSize(48, 48)) self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.setContextMenuPolicy(Qt.CustomContextMenu) # create connections self.actionTriggered.connect(self.handleActionTrigger) self.customContextMenuRequested.connect(self.showProfileMenu) def addProfile(self, profile): """ Adds the inputed profile as an action to the toolbar. :param profile | <projexui.widgets.xviewwidget.XViewProfile> """ act = XViewProfileAction(profile, self) self._profileGroup.addAction(act) self.addAction(act) return act def currentProfile( self ): """ Returns the current profile for this toolbar. :return <projexui.widgets.xviewwidget.XViewProfile> || None """ act = self._profileGroup.checkedAction() if ( act ): return act.profile() return None def createProfile( self, profile = None, clearLayout = True ): """ Prompts the user to create a new profile. """ if ( profile ): prof = profile elif ( not self.viewWidget() or clearLayout ): prof = XViewProfile() else: prof = self.viewWidget().saveProfile() blocked = self.signalsBlocked() self.blockSignals(False) changed = self.editProfile(prof) self.blockSignals(blocked) if ( not changed ): return act = self.addProfile(prof) act.setChecked(True) # update the interface if ( self.viewWidget() and (profile or clearLayout) ): self.viewWidget().restoreProfile(prof) if ( not self.signalsBlocked() ): self.profileCreated.emit(prof) @qt.Slot(qt.PyObject) def editProfile( self, profile ): """ Prompts the user to edit the given profile. :param profile | <projexui.widgets.xviewwidget.XViewProfile> """ mod = XViewProfileDialog.edit(self, profile) if ( not mod ): return False # update the action interface for act in self._profileGroup.actions(): if ( act.profile() == profile ): act.setProfile(profile) break # signal the change if ( not self.signalsBlocked() ): self.profileChanged.emit(profile) return True def exportProfiles( self, filename = None ): """ Exports this toolbar to the given filename. :param filename | <str> || None """ if ( not filename ): filename = QFileDialog.getSaveFileName(self, 'Export Toolbar', '', 'Toolbar Files (*.xtool)') if ( not filename ): return False profile_xml = self.toXml() projex.text.xmlindent(profile_xml) profile_string = ElementTree.tostring(profile_xml) f = open(str(filename), 'w') f.write(profile_string) f.close() return True def handleActionTrigger(self, action): """ Handles when an action has been triggered. If the inputed action is a XViewProfileAction, then the currentProfileChanged signal will emit. :param action | <QAction> """ # trigger a particular profile if ( isinstance(action, XViewProfileAction) ): if ( not self.signalsBlocked() ): self.currentProfileChanged.emit(action.profile()) if ( self._viewWidget ): self._viewWidget.restoreProfile(action.profile()) def importProfiles( self, filename = None ): """ Imports the profiles from the given filename. :param filename | <str> || None """ if ( not filename ): filename = QFileDialog.getOpenFileName( self, 'Import Toolbar', '', 'Toolbar Files (*.xtool)') if type(filename) == tuple: filename = str(filename[0]) if ( not (filename and os.path.exists(filename)) ): return False f = open(str(filename), 'r') profile_string = f.read() f.close() self.loadString(profile_string) # load the default toolbar action = self._profileGroup.checkedAction() if ( action ): self.handleActionTrigger(action) def isEditingEnabled( self ): """ Sets whether or not the create is enabled for this toolbar. :return <bool> """ return self._editingEnabled def isEmpty( self ): """ Returns whether or not this toolbar is empty. :return <bool> """ return len(self._profileGroup.actions()) == 0 def loadString( self, profilestr ): """ Loads the information for this toolbar from the inputed string. :param profilestr | <str> """ try: xtoolbar = ElementTree.fromstring(str(profilestr)) except ExpatError, e: return self.clear() curr = xtoolbar.get('current') for xprofile in xtoolbar: prof = XViewProfile.fromXml(xprofile) act = self.addProfile(prof) if ( prof.name() == curr ): act.setChecked(True)