Esempio n. 1
0
    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 ) )
Esempio n. 2
0
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()
Esempio n. 3
0
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()
Esempio n. 4
0
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()
Esempio n. 5
0
    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))
Esempio n. 6
0
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()
Esempio n. 7
0
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])
Esempio n. 8
0
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)
Esempio n. 9
0
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)
Esempio n. 10
0
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
Esempio n. 11
0
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)
Esempio n. 12
0
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()
Esempio n. 13
0
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)
Esempio n. 15
0
 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)
Esempio n. 16
0
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()
Esempio n. 18
0
    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)
Esempio n. 19
0
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)
Esempio n. 20
0
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())
Esempio n. 22
0
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())
Esempio n. 24
0
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)