class AccountInfo(object): active_icon = IconDescriptor(Resources.get('icons/circle-dot.svg')) inactive_icon = IconDescriptor(Resources.get('icons/circle-grey.svg')) activity_icon = IconDescriptor(Resources.get('icons/circle-progress.svg')) def __init__(self, account): self.account = account self.registration_state = None @property def name(self): return u'Bonjour' if self.account is BonjourAccount() else unicode( self.account.id) @property def icon(self): if self.registration_state == 'started': return self.activity_icon elif self.registration_state == 'succeeded': return self.active_icon else: return self.inactive_icon def __eq__(self, other): if isinstance(other, basestring): return self.name == other elif isinstance(other, (Account, BonjourAccount)): return self.account == other elif isinstance(other, AccountInfo): return self.account == other.account return False def __ne__(self, other): return not self.__eq__(other)
class TLSSettingsExtension(TLSSettings): ca_list = Setting(type=ApplicationDataPath, default=ApplicationDataPath(Resources.get('tls/ca.crt')), nillable=True) certificate = Setting(type=ApplicationDataPath, default=ApplicationDataPath( Resources.get('tls/default.crt')), nillable=True) verify_server = Setting(type=bool, default=True)
class SoundSettings(SettingsGroup): inbound_ringtone = Setting( type=SoundFile, default=SoundFile(Resources.get('sounds/inbound_ringtone.wav')), nillable=True) outbound_ringtone = Setting( type=SoundFile, default=SoundFile(Resources.get('sounds/outbound_ringtone.wav')), nillable=True) play_message_alerts = Setting(type=bool, default=True)
def __init__(self, parent=None, framerate=None): super(VideoSurface, self).__init__(parent) self.setAttribute(Qt.WA_OpaquePaintEvent, True) self.setMouseTracking(True) self.cursors = Cursors() self.cursors.resize_top = QCursor(QIcon(Resources.get('icons/resize-top.svg')).pixmap(16), hotX=8, hotY=0) self.cursors.resize_bottom = QCursor(QIcon(Resources.get('icons/resize-bottom.svg')).pixmap(16), hotX=8, hotY=16) if framerate is not None: self._clock = QTimer() self._clock.setInterval(1000/framerate) self._clock.timeout.connect(self.update) else: self._clock = None self._interaction = InteractionState() self._image = None
def __init__(self, parent=None, framerate=None): super(VideoSurface, self).__init__(parent) self.setAttribute(Qt.WA_OpaquePaintEvent, True) self.setMouseTracking(True) self.cursors = Container() self.cursors.resize_top = QCursor(QIcon(Resources.get('icons/resize-top.svg')).pixmap(16), hotX=8, hotY=0) self.cursors.resize_bottom = QCursor(QIcon(Resources.get('icons/resize-bottom.svg')).pixmap(16), hotX=8, hotY=16) if framerate is not None: self._clock = QTimer() self._clock.setInterval(1000/framerate) self._clock.timeout.connect(self.update) else: self._clock = None self._interaction = InteractionState() self._image = None
def createRequest(self, op, req, data): #print "createRequest: req.url()", req.url() if req.url().host() != "webodf": return super(WebODFNetworkManager, self).createRequest(op, req, data) path = QUrl("http://webodf/").resolved(req.url()).path() print "Request for", path if op == QNetworkAccessManager.GetOperation: reply = None if path.startswith("/dijit"): path = "/wodo" + path # TODO: why gets wodo/ lost? resourcePath = Resources.get("documentsharing" + path) if os.path.exists(resourcePath): print "reply for resource:", resourcePath reply = ResourceReply(resourcePath, self) elif path == self.genesisDocumentPath: print "reply for genesis document:", self.genesisDocumentPath reply = ResourceReply(self.genesisDocumentPath, self) else: avatarUrl = self.sessionBackend.resolveAvatarUrl(path) if avatarUrl != "": print "reply for avatar url:", avatarUrl reply = ResourceReply(avatarUrl, self) if reply is not None: return reply print "Request for unknown resource:", path return super(WebODFNetworkManager, self).createRequest(op, req, data)
def __init__(self, model, parent=None): super(ServerToolsWindow, self).__init__(parent) with Resources.directory: self.setupUi(self) self.spinner_movie = QMovie(Resources.get("icons/servertools-spinner.mng")) self.spinner_label.setMovie(self.spinner_movie) self.spinner_label.hide() self.progress_bar.hide() while self.tab_widget.count(): self.tab_widget.removeTab(0) # remove the tab(s) added in designer self.tab_widget.tabBar().hide() self.account_button.setMenu(QMenu(self.account_button)) self.setWindowTitle("Blink Server Tools") self.setWindowIconText("Server Tools") self.model = model self.tab_widget.addTab(ServerToolsWebView(self), "") font = self.account_label.font() font.setPointSizeF(self.account_label.fontInfo().pointSizeF() + 2) font.setFamily("Sans Serif") self.account_label.setFont(font) self.model.rowsInserted.connect(self._SH_ModelChanged) self.model.rowsRemoved.connect(self._SH_ModelChanged) self.account_button.menu().triggered.connect(self._SH_AccountButtonMenuTriggered) web_view = self.tab_widget.currentWidget() web_view.loadStarted.connect(self._SH_WebViewLoadStarted) web_view.loadFinished.connect(self._SH_WebViewLoadFinished) web_view.loadProgress.connect(self._SH_WebViewLoadProgress)
def _SH_WebViewLoadFinished(self, load_ok): self.spinner_movie.stop() self.spinner_label.hide() self.progress_bar.hide() if not load_ok: web_view = self.tab_widget.currentWidget() icon_path = Resources.get("icons/invalid.png") error_message = web_view.last_error or "Unknown error" html = """ <html> <head> <style> .icon { width: 64px; height: 64px; float: left; } .message { margin-left: 74px; line-height: 64px; vertical-align: middle; } </style> </head> <body> <img class="icon" src="file:%s" /> <div class="message">Failed to load web page: <b>%s</b></div> </body> </html> """ % ( icon_path, error_message, ) web_view.loadStarted.disconnect(self._SH_WebViewLoadStarted) web_view.loadFinished.disconnect(self._SH_WebViewLoadFinished) web_view.setHtml(html) web_view.loadStarted.connect(self._SH_WebViewLoadStarted) web_view.loadFinished.connect(self._SH_WebViewLoadFinished)
def _SH_WebViewLoadFinished(self, load_ok): self.spinner_movie.stop() self.spinner_label.hide() self.progress_bar.hide() if not load_ok: web_view = self.tab_widget.currentWidget() icon_path = Resources.get('icons/invalid.png') error_message = web_view.last_error or 'Unknown error' html = """ <html> <head> <style> .icon { width: 64px; height: 64px; float: left; } .message { margin-left: 74px; line-height: 64px; vertical-align: middle; } </style> </head> <body> <img class="icon" src="file:%s" /> <div class="message">Failed to load web page: <b>%s</b></div> </body> </html> """ % (icon_path, error_message) web_view.loadStarted.disconnect(self._SH_WebViewLoadStarted) web_view.loadFinished.disconnect(self._SH_WebViewLoadFinished) web_view.setHtml(html) web_view.loadStarted.connect(self._SH_WebViewLoadStarted) web_view.loadFinished.connect(self._SH_WebViewLoadFinished)
def createRequest(self, op, req, data): #print "createRequest: req.url()", req.url() if req.url().host() != "webodf": return super(WebODFNetworkManager, self).createRequest(op, req, data); path = QUrl("http://webodf/").resolved(req.url()).path() print "Request for", path if op == QNetworkAccessManager.GetOperation: reply = None; if path.startswith("/dijit"): path = "/wodo" + path # TODO: why gets wodo/ lost? resourcePath = Resources.get("documentsharing"+path) if os.path.exists(resourcePath): print "reply for resource:", resourcePath reply = ResourceReply(resourcePath, self) elif path == self.genesisDocumentPath: print "reply for genesis document:", self.genesisDocumentPath reply = ResourceReply(self.genesisDocumentPath, self) else: avatarUrl = self.sessionBackend.resolveAvatarUrl(path) if avatarUrl != "": print "reply for avatar url:", avatarUrl reply = ResourceReply(avatarUrl, self) if reply is not None: return reply print "Request for unknown resource:", path return super(WebODFNetworkManager, self).createRequest(op, req, data)
def __init__(self, model, parent=None): super(ServerToolsWindow, self).__init__(parent) with Resources.directory: self.setupUi(self) self.spinner_movie = QMovie( Resources.get('icons/servertools-spinner.mng')) self.spinner_label.setMovie(self.spinner_movie) self.spinner_label.hide() self.progress_bar.hide() while self.tab_widget.count(): self.tab_widget.removeTab(0) # remove the tab(s) added in designer self.tab_widget.tabBar().hide() self.account_button.setMenu(QMenu(self.account_button)) self.setWindowTitle('Blink Server Tools') self.setWindowIconText('Server Tools') self.model = model self.tab_widget.addTab(ServerToolsWebView(self), '') font = self.account_label.font() font.setPointSizeF(self.account_label.fontInfo().pointSizeF() + 2) font.setFamily("Sans Serif") self.account_label.setFont(font) self.model.rowsInserted.connect(self._SH_ModelChanged) self.model.rowsRemoved.connect(self._SH_ModelChanged) self.account_button.menu().triggered.connect( self._SH_AccountButtonMenuTriggered) web_view = self.tab_widget.currentWidget() web_view.loadStarted.connect(self._SH_WebViewLoadStarted) web_view.loadFinished.connect(self._SH_WebViewLoadFinished) web_view.loadProgress.connect(self._SH_WebViewLoadProgress)
def _set_filename(self, filename): self.__dict__['filename'] = filename filename = ApplicationData.get(filename) if filename else Resources.get(self.default_icon) pixmap = QPixmap() if pixmap.load(filename): self.setPixmap(pixmap.scaled(32, 32, Qt.KeepAspectRatio, Qt.SmoothTransformation)) else: self.setPixmap(pixmap)
class AnsweringMachineSettings(SettingsGroup): enabled = Setting(type=bool, default=False) answer_delay = Setting(type=NonNegativeInteger, default=10) max_recording = Setting(type=PositiveInteger, default=3) unavailable_message = Setting( type=SoundFile, default=SoundFile(Resources.get('sounds/unavailable_message.wav')), nillable=True)
def capture(self): try: self.image = self.vncclient.image.copy() except AttributeError: pass else: player = WavePlayer(SIPApplication.alert_audio_bridge.mixer, Resources.get('sounds/screenshot.wav'), volume=30) SIPApplication.alert_audio_bridge.add(player) player.start()
def setupUi(self): super(ServerToolsWindow, self).setupUi(self) self.account_button.default_avatar = QIcon(Resources.get('icons/default-avatar.png')) self.account_button.setIcon(IconManager().get('avatar') or self.account_button.default_avatar) self.account_button.setMenu(QMenu(self.account_button)) self.back_button.setMenu(QMenu(self.back_button)) self.back_button.setEnabled(False) self.forward_button.setMenu(QMenu(self.forward_button)) self.forward_button.setEnabled(False)
def __init__(self): super(Blink, self).__init__(sys.argv) self.setAttribute(Qt.AA_DontShowIconsInMenus, False) self.sip_application = SIPApplication() self.first_run = False self.setOrganizationDomain("ag-projects.com") self.setOrganizationName("AG Projects") self.setApplicationName("Blink") self.setApplicationVersion(__version__) self.main_window = MainWindow() self.chat_window = ChatWindow() self.main_window.__closed__ = True self.chat_window.__closed__ = True self.main_window.installEventFilter(self) self.chat_window.installEventFilter(self) self.main_window.addAction(self.chat_window.control_button.actions.main_window) self.chat_window.addAction(self.main_window.quit_action) self.chat_window.addAction(self.main_window.help_action) self.chat_window.addAction(self.main_window.redial_action) self.chat_window.addAction(self.main_window.join_conference_action) self.chat_window.addAction(self.main_window.mute_action) self.chat_window.addAction(self.main_window.silent_action) self.chat_window.addAction(self.main_window.preferences_action) self.chat_window.addAction(self.main_window.transfers_window_action) self.chat_window.addAction(self.main_window.logs_window_action) self.chat_window.addAction(self.main_window.received_files_window_action) self.chat_window.addAction(self.main_window.screenshots_window_action) self.ip_address_monitor = IPAddressMonitor() self.log_manager = LogManager() self.presence_manager = PresenceManager() self.session_manager = SessionManager() self.update_manager = UpdateManager() # Prevent application from exiting after last window is closed if system tray was initialized if self.main_window.system_tray_icon: self.setQuitOnLastWindowClosed(False) self.main_window.check_for_updates_action.triggered.connect(self.update_manager.check_for_updates) self.main_window.check_for_updates_action.setVisible(self.update_manager != Null) if getattr(sys, "frozen", False): XMLDocument.schema_path = Resources.get("xml-schemas") Account.register_extension(AccountExtension) BonjourAccount.register_extension(BonjourAccountExtension) Contact.register_extension(ContactExtension) Group.register_extension(GroupExtension) SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension) notification_center = NotificationCenter() notification_center.add_observer(self, sender=self.sip_application) branding.setup(self)
def __init__(self): super(Blink, self).__init__(sys.argv) self.setAttribute(Qt.AA_DontShowIconsInMenus, False) self.sip_application = SIPApplication() self.first_run = False self.setOrganizationDomain("ag-projects.com") self.setOrganizationName("AG Projects") self.setApplicationName("Blink") self.setApplicationVersion(__version__) self.main_window = MainWindow() self.chat_window = ChatWindow() self.main_window.__closed__ = True self.chat_window.__closed__ = True self.main_window.installEventFilter(self) self.chat_window.installEventFilter(self) self.main_window.addAction(self.chat_window.control_button.actions.main_window) self.chat_window.addAction(self.main_window.quit_action) self.chat_window.addAction(self.main_window.help_action) self.chat_window.addAction(self.main_window.redial_action) self.chat_window.addAction(self.main_window.join_conference_action) self.chat_window.addAction(self.main_window.mute_action) self.chat_window.addAction(self.main_window.silent_action) self.chat_window.addAction(self.main_window.preferences_action) self.chat_window.addAction(self.main_window.transfers_window_action) self.chat_window.addAction(self.main_window.logs_window_action) self.chat_window.addAction(self.main_window.received_files_window_action) self.chat_window.addAction(self.main_window.screenshots_window_action) self.ip_address_monitor = IPAddressMonitor() self.log_manager = LogManager() self.presence_manager = PresenceManager() self.session_manager = SessionManager() self.update_manager = UpdateManager() # Prevent application from exiting after last window is closed if system tray was initialized if self.main_window.system_tray_icon: self.setQuitOnLastWindowClosed(False) self.main_window.check_for_updates_action.triggered.connect(self.update_manager.check_for_updates) self.main_window.check_for_updates_action.setVisible(self.update_manager != Null) if getattr(sys, 'frozen', False): XMLDocument.schema_path = Resources.get('xml-schemas') Account.register_extension(AccountExtension) BonjourAccount.register_extension(BonjourAccountExtension) Contact.register_extension(ContactExtension) Group.register_extension(GroupExtension) SIPSimpleSettings.register_extension(SIPSimpleSettingsExtension) notification_center = NotificationCenter() notification_center.add_observer(self, sender=self.sip_application) branding.setup(self)
def __init__(self, parent=None, size=16): super(SearchIcon, self).__init__(parent) self.setFocusPolicy(Qt.NoFocus) self.setVisible(True) self.setMinimumSize(size+2, size+2) pixmap = QPixmap() if pixmap.load(Resources.get("icons/search.svg")): self.icon = pixmap.scaled(size, size, Qt.KeepAspectRatio, Qt.SmoothTransformation) else: self.icon = None
def _NH_SIPAccountManagerDidAddAccount(self, notification): account = notification.data.account icon = None if account is BonjourAccount(): pixmap = QPixmap() if pixmap.load(Resources.get("icons/bonjour.png")): pixmap = pixmap.scaled(16, 16, Qt.KeepAspectRatio, Qt.SmoothTransformation) icon = QIcon(pixmap) self.beginInsertRows(QModelIndex(), len(self.accounts), len(self.accounts)) self.accounts.append(AccountInfo(account, icon)) self.endInsertRows()
def __init__(self, parent=None, size=16): super(SearchIcon, self).__init__(parent) self.setFocusPolicy(Qt.NoFocus) self.setVisible(True) self.setMinimumSize(size + 2, size + 2) pixmap = QPixmap() if pixmap.load(Resources.get("icons/search.svg")): self.icon = pixmap.scaled(size, size, Qt.KeepAspectRatio, Qt.SmoothTransformation) else: self.icon = None
class BlinkWebODFSessionBackendBase(QObject): default_user_icon_filename = Resources.get('icons/default-avatar.png') serverOpspecsArrived = pyqtSignal('QVariantMap') replayFinished = pyqtSignal() reconnectFinished = pyqtSignal() clientOpspecsSent = pyqtSignal('QVariantMap') closed = pyqtSignal() connectedChanged = pyqtSignal(bool) def __init__(self, account): super(BlinkWebODFSessionBackendBase, self).__init__(); self.account = account self._hasUnsynchronizedChanges = False self._baseHeadId = "" # SessionBackend API @pyqtSlot(result="QString") def memberId(self): return str(self.account.uri) # SessionBackend API def resolveAvatarUrl(self, url): if url.startswith("/avatar/"): uri = SIPURI.parse(url[8:].decode("hex")) # TODO: see if there is an official way to get this, including notification of changes # also needs fixing of webodf, allowing custom avatar renderer if self.account.uri == uri: avatar = IconManager().get('avatar') return avatar.filename if avatar != None else self.default_user_icon_filename contact, contact_uri = URIUtils.find_contact(uri) return contact.icon.filename return "" # SessionBackend API @pyqtSlot() def close(self): self.closed.emit() # SessionBackend API @pyqtSlot('bool', 'QString') def updateSyncState(self, hasUnsynchronizedChanges, baseHeadId): print "updateSyncState: ", hasUnsynchronizedChanges, " baseHeadId: ", baseHeadId self._hasUnsynchronizedChanges = hasUnsynchronizedChanges self._baseHeadId = baseHeadId
def event(self, event): if event.type() == QEvent.DynamicPropertyChange: if event.propertyName() == 'backgroundImage': self.pixmap = QPixmap() if self.backgroundImage and self.pixmap.load(Resources.get(self.backgroundImage)): self.scaled_pixmap = self.pixmap.scaled(self.image_size, Qt.KeepAspectRatio, Qt.SmoothTransformation) else: self.pixmap = self.scaled_pixmap = None self.update() elif event.propertyName() == 'imageGeometry' and self.pixmap: self.scaled_pixmap = self.pixmap.scaled(self.image_size, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.update() elif event.propertyName() == 'backgroundColor': self.update() return super(BackgroundFrame, self).event(event)
def __init__(self, parent=None): super(ValidatingLineEdit, self).__init__(parent) self.invalid_entry_label = QLabel(self) self.invalid_entry_label.setFixedSize(18, 16) self.invalid_entry_label.setPixmap(QPixmap(Resources.get('icons/invalid16.png'))) self.invalid_entry_label.setScaledContents(False) self.invalid_entry_label.setAlignment(Qt.AlignCenter) self.invalid_entry_label.setObjectName('invalid_entry_label') self.invalid_entry_label.hide() self.addTailWidget(self.invalid_entry_label) option = QStyleOptionFrame() self.initStyleOption(option) frame_width = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth, option, self) self.setMinimumHeight(self.invalid_entry_label.minimumHeight() + 2 + 2*frame_width) self.textChanged.connect(self._SH_TextChanged) self.text_correct = True self.text_allowed = True self.exceptions = set() self.regexp = re.compile(r'.*')
def __init__(self, parent=None, size=16): super(ClearButton, self).__init__(parent) self.setCursor(Qt.ArrowCursor) self.setFocusPolicy(Qt.NoFocus) self.setToolTip(u"Clear") self.setVisible(False) self.setMinimumSize(size+2, size+2) pixmap = QPixmap() if pixmap.load(Resources.get("icons/delete.svg")): self.icon = pixmap.scaled(size, size, Qt.KeepAspectRatio, Qt.SmoothTransformation) # Use QImage because QPainter using a QPixmap does not support CompositionMode_Multiply -Dan image = self.icon.toImage() painter = QPainter(image) painter.setRenderHint(QPainter.Antialiasing, True) painter.setCompositionMode(QPainter.CompositionMode_Multiply) painter.drawPixmap(0, 0, self.icon) painter.end() self.icon_pressed = QPixmap(image) else: self.icon = self.icon_pressed = None
def __init__(self, model, parent=None): super(ServerToolsWindow, self).__init__(parent) with Resources.directory: self.setupUi() self.setWindowTitle('Blink Server Tools') self.setWindowIcon(QIcon(Resources.get('icons/blink48.png'))) self.model = model self.model.rowsInserted.connect(self._SH_ModelChanged) self.model.rowsRemoved.connect(self._SH_ModelChanged) self.account_button.menu().triggered.connect(self._SH_AccountButtonMenuTriggered) self.back_button.clicked.connect(self._SH_BackButtonClicked) self.back_button.triggered.connect(self._SH_NavigationButtonTriggered) self.forward_button.clicked.connect(self._SH_ForwardButtonClicked) self.forward_button.triggered.connect(self._SH_NavigationButtonTriggered) self.home_button.clicked.connect(self._SH_HomeButtonClicked) self.web_view.loadStarted.connect(self._SH_WebViewLoadStarted) self.web_view.loadFinished.connect(self._SH_WebViewLoadFinished) self.web_view.titleChanged.connect(self._SH_WebViewTitleChanged) notification_center = NotificationCenter() notification_center.add_observer(self, name='SIPApplicationDidStart')
def __init__(self, parent=None, size=16): super(ClearButton, self).__init__(parent) self.setCursor(Qt.ArrowCursor) self.setFocusPolicy(Qt.NoFocus) self.setToolTip("Clear") self.setVisible(False) self.setMinimumSize(size + 2, size + 2) pixmap = QPixmap() if pixmap.load(Resources.get("icons/delete.svg")): self.icon = pixmap.scaled(size, size, Qt.KeepAspectRatio, Qt.SmoothTransformation) # Use QImage because QPainter using a QPixmap does not support CompositionMode_Multiply -Dan image = self.icon.toImage() painter = QPainter(image) painter.setRenderHint(QPainter.Antialiasing, True) painter.setCompositionMode(QPainter.CompositionMode_Multiply) painter.drawPixmap(0, 0, self.icon) painter.end() self.icon_pressed = QPixmap(image) else: self.icon = self.icon_pressed = None
def __init__(self, parent=None): super(ValidatingLineEdit, self).__init__(parent) self.invalid_entry_label = QLabel(self) self.invalid_entry_label.setFixedSize(18, 16) self.invalid_entry_label.setPixmap( QPixmap(Resources.get('icons/invalid16.png'))) self.invalid_entry_label.setScaledContents(False) self.invalid_entry_label.setAlignment(Qt.AlignCenter) self.invalid_entry_label.setObjectName('invalid_entry_label') self.invalid_entry_label.hide() self.addTailWidget(self.invalid_entry_label) option = QStyleOptionFrame() self.initStyleOption(option) frame_width = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth, option, self) self.setMinimumHeight(self.invalid_entry_label.minimumHeight() + 2 + 2 * frame_width) self.textChanged.connect(self._SH_TextChanged) self.text_correct = True self.text_allowed = True self.exceptions = set() self.regexp = re.compile(r'.*')
def _SH_WebViewLoadFinished(self, load_ok): self.spinner.hide() if not load_ok: icon_path = Resources.get('icons/invalid.png') error_message = self.web_view.last_error or 'Unknown error' html = """ <html> <head> <style> .icon { width: 64px; height: 64px; float: left; } .message { margin-left: 74px; line-height: 64px; vertical-align: middle; } </style> </head> <body> <img class="icon" src="file:%s" /> <div class="message">Failed to load web page: <b>%s</b></div> </body> </html> """ % (icon_path, error_message) self.web_view.blockSignals(True) self.web_view.setHtml(html) self.web_view.blockSignals(False) self._update_navigation_buttons()
if self.scale: self.update(self.transform.mapRect(QRect(x, y, w, h)).adjusted(-1, -1, 1, 1).intersected(self.rect())) else: self.update(x, y, w, h) def _SH_PasswordRequested(self, with_username): dialog = ScreensharingDialog(self) if with_username: username, password = dialog.get_credentials() else: username, password = None, dialog.get_password() self.client.username = username self.client.password = password ui_class, base_class = uic.loadUiType(Resources.get('screensharing_dialog.ui')) class ScreensharingDialog(base_class, ui_class): def __init__(self, parent=None): super(ScreensharingDialog, self).__init__(parent) with Resources.directory: self.setupUi(self) self.setWindowModality(Qt.WindowModal) parent.installEventFilter(self) def eventFilter(self, watched, event): if watched is self.parent() and event.type() in (QEvent.Close, QEvent.Hide): self.reject() return False def get_credentials(self):
class HistoryEntry(object): phone_number_re = re.compile(r'^(?P<number>(0|00|\+)[1-9]\d{7,14})@') incoming_normal_icon = IconDescriptor( Resources.get('icons/arrow-inward-blue.svg')) outgoing_normal_icon = IconDescriptor( Resources.get('icons/arrow-outward-green.svg')) incoming_failed_icon = IconDescriptor( Resources.get('icons/arrow-inward-red.svg')) outgoing_failed_icon = IconDescriptor( Resources.get('icons/arrow-outward-red.svg')) def __init__(self, direction, name, uri, account_id, call_time, duration, failed=False, reason=None): self.direction = direction self.name = name self.uri = uri self.account_id = account_id self.call_time = call_time self.duration = duration self.failed = failed self.reason = reason def __reduce__(self): return (self.__class__, (self.direction, self.name, self.uri, self.account_id, self.call_time, self.duration, self.failed, self.reason)) def __eq__(self, other): return self is other def __ne__(self, other): return self is not other def __lt__(self, other): return self.call_time < other.call_time def __le__(self, other): return self.call_time <= other.call_time def __gt__(self, other): return self.call_time > other.call_time def __ge__(self, other): return self.call_time >= other.call_time @property def icon(self): if self.failed: return self.incoming_failed_icon if self.direction == 'incoming' else self.outgoing_failed_icon else: return self.incoming_normal_icon if self.direction == 'incoming' else self.outgoing_normal_icon @property def text(self): result = unicode(self.name or self.uri) if self.call_time: call_time = self.call_time.astimezone(tzlocal()) call_date = call_time.date() today = date.today() days = (today - call_date).days if call_date == today: result += call_time.strftime(" at %H:%M") elif days == 1: result += call_time.strftime(" Yesterday at %H:%M") elif days < 7: result += call_time.strftime(" on %A") elif call_date.year == today.year: result += call_time.strftime(" on %B %d") else: result += call_time.strftime(" on %Y-%m-%d") if self.duration: seconds = int(self.duration.total_seconds()) if seconds >= 3600: result += """ (%dh%02d'%02d")""" % (seconds / 3600, (seconds % 3600) / 60, seconds % 60) else: result += """ (%d'%02d")""" % (seconds / 60, seconds % 60) elif self.reason: result += ' (%s)' % self.reason.title() return result @classmethod def from_session(cls, session): if session.start_time is None and session.end_time is not None: # Session may have anded before it fully started session.start_time = session.end_time call_time = session.start_time or ISOTimestamp.now() if session.start_time and session.end_time: duration = session.end_time - session.start_time else: duration = None remote_uri = '%s@%s' % (session.remote_identity.uri.user, session.remote_identity.uri.host) match = cls.phone_number_re.match(remote_uri) if match: remote_uri = match.group('number') try: contact = next(contact for contact in AddressbookManager().get_contacts() if remote_uri in (addr.uri for addr in contact.uris)) except StopIteration: display_name = session.remote_identity.display_name else: display_name = contact.name return cls(session.direction, display_name, remote_uri, unicode(session.account.id), call_time, duration)
source_model = model.sourceModel() account_index = source_model.accounts.index(account) self.setCurrentIndex( model.mapFromSource(source_model.index(account_index)).row()) def _NH_SIPAccountManagerDidChangeDefaultAccount(self, notification): account = notification.data.account if account is not None: model = self.model() source_model = model.sourceModel() account_index = source_model.accounts.index(account) self.setCurrentIndex( model.mapFromSource(source_model.index(account_index)).row()) ui_class, base_class = uic.loadUiType(Resources.get('add_account.ui')) class AddAccountDialog(base_class, ui_class): __metaclass__ = QSingleton implements(IObserver) def __init__(self, parent=None): super(AddAccountDialog, self).__init__(parent) with Resources.directory: self.setupUi(self) self.background_frame.setStyleSheet("") self.button_group = QButtonGroup(self) self.button_group.setObjectName("button_group") self.button_group.addButton(
a:link { text-decoration: none; color: #1f487f; } </style> </head> <body> <table width="100%" cellspacing="2" cellpadding="0" border="0"> <tr><td class="name" align="right">AG Projects</td><td align="left"><a href="http://ag-projects.com/">http://ag-projects.com/</a></td></tr> <tr><td class="name" align="right">NLnet Foundation</td><td align="left"><a href="http://nlnet.nl/">http://nlnet.nl/</a></td></tr> <tr><td class="name" align="right">IETF Community</td><td align="left"><a href="http://ietf.org/">http://ietf.org/</a></td></tr> <tr><td class="name" align="right">SIP Simple Client</td><td align="left"><a href="http://sipsimpleclient.org/">http://sipsimpleclient.org/</a></td></tr> </table> </body> </html> """ ui_class, base_class = uic.loadUiType(Resources.get('about_panel.ui')) class AboutPanel(base_class, ui_class): __metaclass__ = QSingleton def __init__(self, parent=None): super(AboutPanel, self).__init__(parent) with Resources.directory: self.setupUi(self) self.version.setText(u'Version %s\n%s' % (__version__, __date__)) credits_width = self.credits_text.fontMetrics().width("NLNET Foundation" + "http://sipsimpleclient.org") + 40 self.credits_text.setFixedWidth(credits_width) self.credits_text.document().documentLayout().documentSizeChanged.connect(self._credits_size_changed)
def setupUi(self): super(ScreensharingToolbox, self).setupUi(self) # fix the SVG icons, as the generated code loads them as pixmaps, losing their ability to scale -Dan scale_icon = QIcon() scale_icon.addFile(Resources.get('icons/scale.svg'), mode=QIcon.Normal, state=QIcon.Off) viewonly_icon = QIcon() viewonly_icon.addFile(Resources.get('icons/viewonly.svg'), mode=QIcon.Normal, state=QIcon.Off) screenshot_icon = QIcon() screenshot_icon.addFile(Resources.get('icons/screenshot.svg'), mode=QIcon.Normal, state=QIcon.Off) fullscreen_icon = QIcon() fullscreen_icon.addFile(Resources.get('icons/fullscreen.svg'), mode=QIcon.Normal, state=QIcon.Off) fullscreen_icon.addFile(Resources.get('icons/fullscreen-exit.svg'), mode=QIcon.Normal, state=QIcon.On) fullscreen_icon.addFile(Resources.get('icons/fullscreen-exit.svg'), mode=QIcon.Active, state=QIcon.On) fullscreen_icon.addFile(Resources.get('icons/fullscreen-exit.svg'), mode=QIcon.Disabled, state=QIcon.On) fullscreen_icon.addFile(Resources.get('icons/fullscreen-exit.svg'), mode=QIcon.Selected, state=QIcon.On) minimize_icon = QIcon() minimize_icon.addFile(Resources.get('icons/minimize.svg'), mode=QIcon.Normal, state=QIcon.Off) minimize_icon.addFile(Resources.get('icons/minimize-active.svg'), mode=QIcon.Active, state=QIcon.Off) close_icon = QIcon() close_icon.addFile(Resources.get('icons/close.svg'), mode=QIcon.Normal, state=QIcon.Off) close_icon.addFile(Resources.get('icons/close-active.svg'), mode=QIcon.Active, state=QIcon.Off) self.scale_action.setIcon(scale_icon) self.viewonly_action.setIcon(viewonly_icon) self.screenshot_action.setIcon(screenshot_icon) self.fullscreen_action.setIcon(fullscreen_icon) self.minimize_action.setIcon(minimize_icon) self.close_action.setIcon(close_icon) self.scale_button.setIcon(scale_icon) self.viewonly_button.setIcon(viewonly_icon) self.screenshot_button.setIcon(screenshot_icon) self.fullscreen_button.setIcon(fullscreen_icon) self.minimize_button.setIcon(minimize_icon) self.close_button.setIcon(close_icon) self.scale_button.setDefaultAction(self.scale_action) self.viewonly_button.setDefaultAction(self.viewonly_action) self.screenshot_button.setDefaultAction(self.screenshot_action) self.fullscreen_button.setDefaultAction(self.fullscreen_action) self.minimize_button.setDefaultAction(self.minimize_action) self.close_button.setDefaultAction(self.close_action) self.color_depth_button.clear() self.color_depth_button.addItem('Default Color Depth', ServerDefault) self.color_depth_button.addItem('TrueColor (24 bits)', TrueColor) self.color_depth_button.addItem('HighColor (16 bits)', HighColor) self.color_depth_button.addItem('LowColor (8 bits)', LowColor)
def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton and self.rect().contains(event.pos()): filename = unicode(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) self.filename = filename if os.path.realpath(filename) != os.path.realpath(Resources.get(self.default_icon)) else None super(IconSelector, self).mouseReleaseEvent(event)
class PresenceManager(object): def __init__(self): self.publication_handler = PresencePublicationHandler() self.subscription_handler = PresenceSubscriptionHandler() def start(self): self.publication_handler.start() self.subscription_handler.start() def stop(self): self.publication_handler.stop() self.subscription_handler.stop() ui_class, base_class = uic.loadUiType(Resources.get('pending_watcher.ui')) class PendingWatcherDialog(base_class, ui_class): def __init__(self, account, uri, display_name, parent=None): super(PendingWatcherDialog, self).__init__(parent) self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) self.setAttribute(Qt.WA_DeleteOnClose) with Resources.directory: self.setupUi(self) default_font_size = self.uri_label.fontInfo().pointSizeF() name_font_size = limit(default_font_size + 3, max=14) font = self.name_label.font() font.setPointSizeF(name_font_size) self.name_label.setFont(font) addressbook_manager = addressbook.AddressbookManager()
from blink.configuration.account import AccountExtension, BonjourAccountExtension from blink.configuration.addressbook import ContactExtension, GroupExtension from blink.configuration.settings import SIPSimpleSettingsExtension from blink.logging import LogManager from blink.mainwindow import MainWindow from blink.presence import PresenceManager from blink.resources import ApplicationData, Resources from blink.sessions import SessionManager from blink.update import UpdateManager from blink.util import QSingleton, run_in_gui_thread __all__ = ['Blink'] if hasattr(sys, 'frozen'): import httplib2 httplib2.CA_CERTS = os.environ['SSL_CERT_FILE'] = Resources.get( 'tls/cacerts.pem') makedirs(ApplicationData.get('logs')) sys.stdout.file = ApplicationData.get('logs/output.log') class IPAddressMonitor(object): """ An object which monitors the IP address used for the default route of the host and posts a SystemIPAddressDidChange notification when a change is detected. """ def __init__(self): self.greenlet = None @run_in_green_thread def start(self):
from blink.presence import PresenceManager from blink.resources import ApplicationData, Resources from blink.sessions import SessionManager from blink.update import UpdateManager from blink.util import QSingleton, run_in_gui_thread __all__ = ["Blink"] if hasattr(sys, "frozen"): makedirs(ApplicationData.get("logs")) sys.stdout.file = open(ApplicationData.get("logs/output.log"), "a", 0) import httplib2 httplib2.CA_CERTS = os.environ["SSL_CERT_FILE"] = Resources.get("tls/cacerts.pem") class IPAddressMonitor(object): """ An object which monitors the IP address used for the default route of the host and posts a SystemIPAddressDidChange notification when a change is detected. """ def __init__(self): self.greenlet = None @run_in_green_thread def start(self): notification_center = NotificationCenter()
from blink.filetransferwindow import FileTransferWindow from blink.history import HistoryManager from blink.preferences import PreferencesWindow from blink.sessions import ConferenceDialog, SessionManager, AudioSessionModel, StreamDescription from blink.configuration.datatypes import IconDescriptor, FileURL, PresenceState from blink.configuration.settings import BlinkSettings from blink.presence import PendingWatcherDialog from blink.resources import ApplicationData, IconManager, Resources from blink.util import run_in_gui_thread from blink.widgets.buttons import AccountState, SwitchViewButton __all__ = ['MainWindow'] ui_class, base_class = uic.loadUiType(Resources.get('blink.ui')) @implementer(IObserver) class MainWindow(base_class, ui_class): 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')
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='BlinkSessionTransferNewOutgoing') notification_center.add_observer(self, name='BlinkFileTransferNewIncoming') notification_center.add_observer(self, name='BlinkFileTransferNewOutgoing') 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 range(0, 11)] self.mwi_icons.append(QIcon(Resources.get('icons/mwi-many.png'))) with Resources.directory: self.setupUi() self.setWindowTitle('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("Show", self._AH_SystemTrayShowWindow) menu.addAction(QIcon(Resources.get('icons/application-exit.png')), "Quit", 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.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('http://icanblink.com/help/'))) 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('http://icanblink.com/changelog/'))) 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) self.google_contacts_action.triggered.connect(self._AH_GoogleContactsActionTriggered) # 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)
if account is not None: model = self.model() source_model = model.sourceModel() account_index = source_model.accounts.index(account) self.setCurrentIndex(model.mapFromSource(source_model.index(account_index)).row()) def _NH_SIPAccountManagerDidChangeDefaultAccount(self, notification): account = notification.data.account if account is not None: model = self.model() source_model = model.sourceModel() account_index = source_model.accounts.index(account) self.setCurrentIndex(model.mapFromSource(source_model.index(account_index)).row()) ui_class, base_class = uic.loadUiType(Resources.get("add_account.ui")) class AddAccountDialog(base_class, ui_class): __metaclass__ = QSingleton implements(IObserver) def __init__(self, parent=None): super(AddAccountDialog, self).__init__(parent) with Resources.directory: self.setupUi(self) self.background_frame.setStyleSheet("") self.button_group = QButtonGroup(self) self.button_group.setObjectName("button_group") self.button_group.addButton(self.add_account_button, self.panel_view.indexOf(self.add_account_panel))
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)
class PresenceManager(object): def __init__(self): self.publication_handler = PresencePublicationHandler() self.subscription_handler = PresenceSubscriptionHandler() def start(self): self.publication_handler.start() self.subscription_handler.start() def stop(self): self.publication_handler.stop() self.subscription_handler.stop() ui_class, base_class = uic.loadUiType(Resources.get('pending_watcher.ui')) class PendingWatcherDialog(base_class, ui_class): def __init__(self, account, uri, display_name, parent=None): super(PendingWatcherDialog, self).__init__(parent) self.setWindowFlags(Qt.WindowStaysOnTopHint) self.setAttribute(Qt.WA_DeleteOnClose) with Resources.directory: self.setupUi(self) addressbook_manager = addressbook.AddressbookManager() try: self.contact = next(contact for contact in addressbook_manager.get_contacts() if uri in (addr.uri for addr in contact.uris)) except StopIteration: self.contact = None else: display_name = self.contact.name
import re from PyQt5 import uic from PyQt5.QtCore import Qt, pyqtSignal from PyQt5.QtWidgets import QStyle, QStyleOption, QStylePainter from blink.resources import Resources from blink.sessions import SMPVerification __all__ = ['OTRWidget'] ui_class, base_class = uic.loadUiType(Resources.get('otr_widget.ui')) class OTRWidget(base_class, ui_class): closed = pyqtSignal() nameChanged = pyqtSignal() statusChanged = pyqtSignal() color_table = {'green': 'hsv(100, 85%, 100%)', 'orange': 'hsv(20, 85%, 100%)'} def __init__(self, parent=None): super(OTRWidget, self).__init__(parent) with Resources.directory: self.setupUi(self) self.__dict__.update(peer_verified=False, smp_status=SMPVerification.Unavailable) # interdependent properties (they need to preexist as their setters read each other) self.peer_name = '' self.peer_verified = False
class AccountState(StateButton): Invisible = PresenceState('Invisible', '#efedeb', Resources.get('icons/state-invisible.svg')) Available = PresenceState('Available', '#00ff00', Resources.get('icons/state-available.svg')) Away = PresenceState('Away', '#ffff00', Resources.get('icons/state-away.svg')) Busy = PresenceState('Busy', '#ff0000', Resources.get('icons/state-busy.svg')) stateChanged = pyqtSignal() history_size = 7 def __init__(self, parent=None): super(AccountState, self).__init__(parent) menu = QMenu(self) for state in (self.Available, self.Away, self.Busy, self.Invisible): action = menu.addAction(QIcon(state.icon), state.name) action.state = state action.note = None menu.addSeparator() menu.triggered.connect(self._SH_MenuTriggered) self.setMenu(menu) self.state = self.Invisible self.note = None def _get_history(self): return [(action.state.name, action.note) for action in self.menu().actions()[5:]] def _set_history(self, values): menu = self.menu() for action in menu.actions()[5:]: menu.removeAction(action) for state_name, note in values: try: state = getattr(self, state_name) except AttributeError: continue action = menu.addAction(QIcon(state.icon), note) action.state = state action.note = note history = property(_get_history, _set_history) del _get_history, _set_history def _SH_MenuTriggered(self, action): if hasattr(action, 'state'): self.setState(action.state, action.note) def mousePressEvent_no(self, event): if event.button() == Qt.LeftButton and self.popupMode( ) == QToolButton.MenuButtonPopup: option = QStyleOptionToolButton() self.initStyleOption(option) position = self.style().subControlRect(QStyle.CC_ToolButton, option, QStyle.SC_ToolButtonMenu, self).center() event = event.__class__(event.type(), position, self.mapToGlobal(position), event.button(), event.buttons(), event.modifiers()) return super(AccountState, self).mousePressEvent(event) def setState(self, state, note=None): if state == self.state and note == self.note: return self.state = state self.note = note palette = self.palette() palette.setColor(QPalette.Button, QColor(state.color)) self.setPalette(palette) if note and not state.internal: menu = self.menu() actions = menu.actions()[5:] try: action = next(action for action in actions if action.state is state and action.note == note) except StopIteration: action = QAction(QIcon(state.icon), note, menu) if len(actions) == 0: menu.addAction(action) else: if len(actions) >= self.history_size: menu.removeAction(actions[-1]) menu.insertAction(actions[0], action) action.state = state action.note = note else: if action is not actions[0]: menu.removeAction(action) menu.insertAction(actions[0], action) self.stateChanged.emit()
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 __init__(self, parent=None, icon='icons/spinner.svg'): super(Spinner, self).__init__(parent) self._original_viewbox = QRectF() self.icon_crop = 0 self.icon_size = None self.icon_file = Resources.get(icon)
class TLSSettingsExtension(TLSSettings): ca_list = Setting(type=ApplicationDataPath, default=ApplicationDataPath(Resources.get('tls/ca.crt')), nillable=True)
from PyQt5.QtGui import QDesktopServices from PyQt5.QtWidgets import QAction, QMenu from application.notification import IObserver, NotificationCenter from application.python import Null from application.system import makedirs from zope.interface import implementer from blink.configuration.settings import BlinkSettings from blink.resources import Resources from blink.sessions import FileTransferDelegate, FileTransferModel from blink.widgets.util import ContextMenuActions __all__ = ['FileTransferWindow'] ui_class, base_class = uic.loadUiType(Resources.get('filetransfer_window.ui')) @implementer(IObserver) class FileTransferWindow(base_class, ui_class): def __init__(self, parent=None): super(FileTransferWindow, self).__init__(parent) with Resources.directory: self.setupUi(self) self.model = FileTransferModel(self) self.listview.setModel(self.model) self.listview.setItemDelegate(FileTransferDelegate(self.listview)) self.listview.customContextMenuRequested.connect( self._SH_ContextMenuRequested)
self.transform.mapRect(QRect(x, y, w, h)).adjusted( -1, -1, 1, 1).intersected(self.rect())) else: self.update(x, y, w, h) def _SH_PasswordRequested(self, with_username): dialog = ScreensharingDialog(self) if with_username: username, password = dialog.get_credentials() else: username, password = None, dialog.get_password() self.client.username = username self.client.password = password ui_class, base_class = uic.loadUiType(Resources.get('screensharing_dialog.ui')) class ScreensharingDialog(base_class, ui_class): def __init__(self, parent=None): super(ScreensharingDialog, self).__init__(parent) with Resources.directory: self.setupUi(self) self.setWindowModality(Qt.WindowModal) parent.installEventFilter(self) def eventFilter(self, watched, event): if watched is self.parent() and event.type() in (QEvent.Close, QEvent.Hide): self.reject() return False
from PyQt4 import uic from PyQt4.QtCore import Qt, QUrl from PyQt4.QtGui import QAction, QDesktopServices, QMenu from application.notification import IObserver, NotificationCenter from application.python import Null from application.system import makedirs from zope.interface import implements from blink.configuration.settings import BlinkSettings from blink.resources import Resources from blink.sessions import FileTransferDelegate, FileTransferModel from blink.widgets.util import ContextMenuActions ui_class, base_class = uic.loadUiType(Resources.get('filetransfer_window.ui')) class FileTransferWindow(base_class, ui_class): implements(IObserver) def __init__(self, parent=None): super(FileTransferWindow, self).__init__(parent) with Resources.directory: self.setupUi(self) self.model = FileTransferModel(self) self.listview.setModel(self.model) self.listview.setItemDelegate(FileTransferDelegate(self.listview)) self.listview.customContextMenuRequested.connect(self._SH_ContextMenuRequested) self.context_menu = QMenu(self.listview)
from blink.aboutpanel import AboutPanel from blink.accounts import AccountModel, ActiveAccountModel, ServerToolsAccountModel, ServerToolsWindow from blink.contacts import Contact, ContactEditorDialog, ContactModel, ContactSearchModel, GoogleContactsDialog, URIUtils from blink.filetransferwindow import FileTransferWindow from blink.history import HistoryManager from blink.preferences import PreferencesWindow from blink.sessions import ConferenceDialog, SessionManager, AudioSessionModel, StreamDescription from blink.configuration.datatypes import IconDescriptor, FileURL, InvalidToken, PresenceState from blink.configuration.settings import BlinkSettings from blink.presence import PendingWatcherDialog from blink.resources import ApplicationData, IconManager, Resources from blink.util import run_in_gui_thread from blink.widgets.buttons import AccountState, SwitchViewButton ui_class, base_class = uic.loadUiType(Resources.get('blink.ui')) 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')