Commit e6145b72 authored by Dan Pascu's avatar Dan Pascu

Modernized code and improved PEP-8 compliance

parent 8c6e300f
#
# Boring file regular expresions
# Boring file regular expressions
#
~$
......
__all__ = ['Blink']
__version__ = '1.4.2'
__date__ = 'December 4th 2015'
import os
import sys
import sip
......@@ -42,6 +38,7 @@ try:
from blink import branding
except ImportError:
branding = Null
from blink.chatwindow import ChatWindow
from blink.configuration.account import AccountExtension, BonjourAccountExtension
from blink.configuration.addressbook import ContactExtension, GroupExtension
......@@ -56,6 +53,9 @@ from blink.update import UpdateManager
from blink.util import QSingleton, run_in_gui_thread
__all__ = ['Blink']
if hasattr(sys, 'frozen'):
output = sys.stdout
makedirs(ApplicationData.get('logs'))
......@@ -293,7 +293,7 @@ class Blink(QApplication):
self.main_window.show()
settings = SIPSimpleSettings()
accounts = AccountManager().get_accounts()
if not accounts or (self.first_run and accounts==[BonjourAccount()]):
if not accounts or (self.first_run and accounts == [BonjourAccount()]):
self.main_window.preferences_window.show_create_account_dialog()
if settings.google_contacts.authorization_token is InvalidToken:
self.main_window.google_contacts_dialog.open_for_incorrect_password()
......
__all__ = ['AboutPanel']
from PyQt4 import uic
from blink import __date__, __version__
......@@ -8,6 +6,9 @@ from blink.resources import Resources
from blink.util import QSingleton
__all__ = ['AboutPanel']
credits_text = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html>
......@@ -32,6 +33,7 @@ credits_text = """
ui_class, base_class = uic.loadUiType(Resources.get('about_panel.ui'))
class AboutPanel(base_class, ui_class):
__metaclass__ = QSingleton
......@@ -43,7 +45,7 @@ class AboutPanel(base_class, ui_class):
self.version.setText(u'Version %s\n%s' % (__version__, __date__))
credits_width = self.credits_text.fontMetrics().width("NLNET Foundation" + "http://sipsimpleclient.org") + 40
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)
self.credits_text.setHtml(credits_text)
......
__all__ = ['AccountModel', 'ActiveAccountModel', 'AccountSelector', 'AddAccountDialog', 'ServerToolsAccountModel', 'ServerToolsWindow']
import os
import re
import sys
......@@ -31,17 +29,23 @@ from blink.widgets.labels import Status
from blink.util import QSingleton, call_in_gui_thread, run_in_gui_thread
__all__ = ['AccountModel', 'ActiveAccountModel', 'AccountSelector', 'AddAccountDialog', 'ServerToolsAccountModel', 'ServerToolsWindow']
class IconDescriptor(object):
def __init__(self, filename):
self.filename = filename
self.icon = None
def __get__(self, obj, objtype):
def __get__(self, instance, owner):
if self.icon is None:
self.icon = QIcon(self.filename)
self.icon.filename = self.filename
return self.icon
def __set__(self, obj, value):
raise AttributeError("attribute cannot be set")
def __delete__(self, obj):
raise AttributeError("attribute cannot be deleted")
......@@ -222,6 +226,7 @@ class AccountSelector(QComboBox):
ui_class, base_class = uic.loadUiType(Resources.get('add_account.ui'))
class AddAccountDialog(base_class, ui_class):
__metaclass__ = QSingleton
......@@ -587,6 +592,7 @@ class ServerToolsWebView(QWebView):
ui_class, base_class = uic.loadUiType(Resources.get('server_tools.ui'))
class ServerToolsWindow(base_class, ui_class):
__metaclass__ = QSingleton
......@@ -629,7 +635,7 @@ class ServerToolsWindow(base_class, ui_class):
self.spinner_label.show()
self.spinner_movie.start()
self.progress_bar.setValue(0)
#self.progress_bar.show()
# self.progress_bar.show()
def _SH_WebViewLoadFinished(self, load_ok):
self.spinner_movie.stop()
......
......@@ -171,10 +171,10 @@ class ChatContentBooleanOption(object):
def __init__(self, name):
self.name = name
def __get__(self, obj, objtype):
if obj is None:
def __get__(self, instance, owner):
if instance is None:
return self
return self.name in obj.__cssclasses__
return self.name in instance.__cssclasses__
def __set__(self, obj, value):
if value:
......@@ -188,6 +188,7 @@ class ChatContentBooleanOption(object):
class AnyValue: __metaclass__ = MarkerType
class ChatContentStringAttribute(object):
"""A string attribute that is also added as a css class"""
......@@ -195,11 +196,11 @@ class ChatContentStringAttribute(object):
self.name = name
self.allowed_values = allowed_values
def __get__(self, obj, objtype):
if obj is None:
def __get__(self, instance, owner):
if instance is None:
return self
try:
return obj.__dict__[self.name]
return instance.__dict__[self.name]
except KeyError:
raise AttributeError("'{}' attribute is not set".format(self.name))
......@@ -338,10 +339,10 @@ class ChatWebPage(QWebPage):
super(ChatWebPage, self).__init__(parent)
self.setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
self.linkClicked.connect(self._SH_LinkClicked)
#self.downloadRequested.connect(self._SH_DownloadRequested)
#self.setForwardUnsupportedContent(True)
#self.unsupportedContent.connect(self._SH_UnsupportedContent)
#allowed_actions = {QWebPage.InspectElement, QWebPage.CopyLinkToClipboard, QWebPage.CopyImageToClipboard, QWebPage.CopyImageUrlToClipboard}
# self.downloadRequested.connect(self._SH_DownloadRequested)
# self.setForwardUnsupportedContent(True)
# self.unsupportedContent.connect(self._SH_UnsupportedContent)
# allowed_actions = {QWebPage.InspectElement, QWebPage.CopyLinkToClipboard, QWebPage.CopyImageToClipboard, QWebPage.CopyImageUrlToClipboard}
disable_actions = {QWebPage.OpenLink, QWebPage.OpenLinkInNewWindow, QWebPage.DownloadLinkToDisk, QWebPage.OpenImageInNewWindow, QWebPage.DownloadImageToDisk,
QWebPage.Back, QWebPage.Forward, QWebPage.Stop, QWebPage.Reload}
for action in (self.action(action) for action in disable_actions):
......@@ -360,10 +361,10 @@ class ChatWebPage(QWebPage):
def _SH_LinkClicked(self, url):
QDesktopServices.openUrl(url)
#def _SH_DownloadRequested(self, request):
# def _SH_DownloadRequested(self, request):
# print "-- download requested", request.url().toString()
#def _SH_UnsupportedContent(self, reply):
# def _SH_UnsupportedContent(self, reply):
# print "-- unsupported", reply.url().toString()
......@@ -558,7 +559,7 @@ class IconDescriptor(object):
self.filename = filename
self.icon = None
def __get__(self, obj, objtype):
def __get__(self, instance, owner):
if self.icon is None:
self.icon = QIcon(self.filename)
self.icon.filename = self.filename
......@@ -701,10 +702,10 @@ class ChatWidget(base_class, ui_class):
self.session.chat_stream.send_message(content, content_type, recipients, courtesy_recipients, subject, timestamp, required, additional_headers)
def _align_chat(self, scroll=False):
#frame_height = self.chat_view.page().mainFrame().contentsSize().height()
# frame_height = self.chat_view.page().mainFrame().contentsSize().height()
widget_height = self.chat_view.size().height()
content_height = self.chat_element.geometry().height()
#print widget_height, frame_height, content_height
# print widget_height, frame_height, content_height
if widget_height > content_height:
self.chat_element.setStyleProperty('position', 'relative')
self.chat_element.setStyleProperty('top', '%dpx' % (widget_height-content_height))
......@@ -713,10 +714,10 @@ class ChatWidget(base_class, ui_class):
self.chat_element.setStyleProperty('top', None)
frame = self.chat_view.page().mainFrame()
if scroll or frame.scrollBarMaximum(Qt.Vertical) - frame.scrollBarValue(Qt.Vertical) <= widget_height*0.2:
#print "scroll requested or scrollbar is closer than %dpx to the bottom" % (widget_height*0.2)
#self._print_scrollbar_position()
# print "scroll requested or scrollbar is closer than %dpx to the bottom" % (widget_height*0.2)
# self._print_scrollbar_position()
self._scroll_to_bottom()
#self._print_scrollbar_position()
# self._print_scrollbar_position()
def _scroll_to_bottom(self):
frame = self.chat_view.page().mainFrame()
......@@ -801,11 +802,11 @@ class ChatWidget(base_class, ui_class):
self.chat_input.setHtml(user_text)
def _SH_ChatViewSizeChanged(self):
#print "chat view size changed"
# print "chat view size changed"
self._align_chat(scroll=True)
def _SH_ChatViewFrameContentsSizeChanged(self, size):
#print "frame contents size changed to %r (current=%r)" % (size, self.chat_view.page().mainFrame().contentsSize())
# print "frame contents size changed to %r (current=%r)" % (size, self.chat_view.page().mainFrame().contentsSize())
self._align_chat(scroll=True)
def _SH_ChatInputTextChanged(self):
......@@ -882,6 +883,7 @@ class VideoToolButton(QToolButton):
ui_class, base_class = uic.loadUiType(Resources.get('video_widget.ui'))
class VideoWidget(VideoSurface, ui_class):
implements(IObserver)
......@@ -922,7 +924,7 @@ class VideoWidget(VideoSurface, ui_class):
self.no_flicker_widget = QLabel()
self.no_flicker_widget.setWindowFlags(Qt.FramelessWindowHint)
#self.no_flicker_widget.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
# self.no_flicker_widget.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.camera_preview = VideoSurface(self, framerate=10)
self.camera_preview.interactive = True
......@@ -935,7 +937,7 @@ class VideoWidget(VideoSurface, ui_class):
self.detach_animation = QPropertyAnimation(self, 'geometry')
self.detach_animation.setDuration(200)
#self.detach_animation.setEasingCurve(QEasingCurve.Linear)
# self.detach_animation.setEasingCurve(QEasingCurve.Linear)
self.preview_animation = QPropertyAnimation(self.camera_preview, 'geometry')
self.preview_animation.setDuration(500)
......@@ -1031,7 +1033,7 @@ class VideoWidget(VideoSurface, ui_class):
super(VideoWidget, self).mousePressEvent(event)
if self._interaction.active:
for button in self.active_tool_buttons:
button.show() # show or hide the toolbuttons while we move/resize? -Dan
button.show() # show or hide the tool buttons while we move/resize? -Dan
self.idle_timer.stop()
def mouseReleaseEvent(self, event):
......@@ -1251,7 +1253,7 @@ class VideoWidget(VideoSurface, ui_class):
self.preview_animation.start()
def _NH_VideoDeviceDidChangeCamera(self, notification):
#self.camera_preview.producer = SIPApplication.video_device.producer
# self.camera_preview.producer = SIPApplication.video_device.producer
self.camera_preview.producer = notification.data.new_camera
def _NH_CFGSettingsObjectDidChange(self, notification):
......@@ -1285,8 +1287,8 @@ class VideoWidget(VideoSurface, ui_class):
self.fullscreen_button.show()
else:
if not self.detach_button.isChecked():
self.setGeometry(self.geometryHint(self.parent_widget)) # force a geometry change before reparenting, else we will get a change from (-1, -1) to the parent geometry hint
self.setParent(self.parent_widget) # this is probably because since it unmaps when it's reparented, the geometry change won't appear from fullscreen
self.setGeometry(self.geometryHint(self.parent_widget)) # force a geometry change before re-parenting, else we will get a change from (-1, -1) to the parent geometry hint
self.setParent(self.parent_widget) # this is probably because since it unmaps when it's re-parented, the geometry change won't appear from fullscreen
self.setGeometry(self.geometryHint()) # to the new size, since we changed the geometry after returning from fullscreen, while invisible
self.mute_button.active = False
self.hold_button.active = False
......@@ -1378,15 +1380,15 @@ class VideoWidget(VideoSurface, ui_class):
self.no_flicker_widget.setGeometry(self.geometry())
self.no_flicker_widget.show()
self.no_flicker_widget.raise_()
#self.no_flicker_widget.repaint()
#self.repaint()
# self.no_flicker_widget.repaint()
# self.repaint()
self.setParent(self.parent_widget)
self.setGeometry(self.geometryHint())
self.show() # solve the flicker -Dan
#self.repaint()
#self.no_flicker_widget.lower()
# self.repaint()
# self.no_flicker_widget.lower()
self.no_flicker_widget.hide()
#self.window().show()
# self.window().show()
self.mute_button.active = False
self.hold_button.active = False
self.close_button.active = False
......@@ -1431,6 +1433,7 @@ class NoSessionsLabel(QLabel):
ui_class, base_class = uic.loadUiType(Resources.get('chat_window.ui'))
class ChatWindow(base_class, ui_class, ColorHelperMixin):
implements(IObserver)
......@@ -1504,7 +1507,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
notification_center.add_observer(self, name='MediaStreamDidEnd')
notification_center.add_observer(self, name='MediaStreamWillEnd')
#self.splitter.splitterMoved.connect(self._SH_SplitterMoved) # check this and decide on what size to have in the window (see Notes) -Dan
# self.splitter.splitterMoved.connect(self._SH_SplitterMoved) # check this and decide on what size to have in the window (see Notes) -Dan
def _SH_SplitterMoved(self, pos, index):
print "-- splitter:", pos, index, self.splitter.sizes()
......@@ -1580,7 +1583,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
self.control_button.actions.end_screen_sharing = QAction("End screen sharing", self, triggered=self._AH_EndScreenSharing)
self.control_button.actions.main_window = QAction("Main Window", self, triggered=self._AH_MainWindow, shortcut='Ctrl+B', shortcutContext=Qt.ApplicationShortcut)
self.addAction(self.control_button.actions.main_window) # make this active even when it's not in the contol_button's menu
self.addAction(self.control_button.actions.main_window) # make this active even when it's not in the control_button's menu
self.slide_direction = self.session_details.RightToLeft # decide if we slide from one direction only -Dan
self.slide_direction = self.session_details.Automatic
......@@ -1689,7 +1692,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
menu.hide()
blink_session = self.selected_session.blink_session
state = blink_session.state
if state=='connecting/*' and blink_session.direction=='outgoing' or state=='connected/sent_proposal':
if state=='connecting/*' and blink_session.direction == 'outgoing' or state == 'connected/sent_proposal':
self.control_button.setMenu(None)
self.control_button.setIcon(self.cancel_icon)
elif state == 'connected/received_proposal':
......@@ -1894,7 +1897,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
self.screen_encryption_label.setToolTip(u'Media is encrypted using TLS')
self.screen_connection_label.setVisible(screen_info.remote_address is not None)
self.screen_encryption_label.setVisible(screen_info.remote_address is not None and screen_info.transport=='tls')
self.screen_encryption_label.setVisible(screen_info.remote_address is not None and screen_info.transport == 'tls')
if 'statistics' in elements:
self.duration_value_label.value = session_info.duration
......@@ -2206,7 +2209,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
if message.content_type.startswith('image/'):
content = u'''<img src="data:{};base64,{}" class="scaled-to-fit" />'''.format(message.content_type, message.content.encode('base64').rstrip())
elif message.content_type.startswith('text/'):
content = HtmlProcessor.autolink(message.content if message.content_type=='text/html' else QTextDocument(message.content).toHtml())
content = HtmlProcessor.autolink(message.content if message.content_type == 'text/html' else QTextDocument(message.content).toHtml())
else:
return
......@@ -2221,7 +2224,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
else:
sender = ChatSender(message.sender.display_name or session.name, uri, session.icon.filename)
is_status_message = any(h.name=='Message-Type' and h.value=='status' and h.namespace=='urn:ag-projects:xml:ns:cpim' for h in message.additional_headers)
is_status_message = any(h.name == 'Message-Type' and h.value == 'status' and h.namespace == 'urn:ag-projects:xml:ns:cpim' for h in message.additional_headers)
if is_status_message:
session.chat_widget.add_message(ChatStatus(content))
else:
......@@ -2283,7 +2286,7 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
session = notification.sender.blink_session.items.chat
if session is None:
return
#session.chat_widget.add_message(ChatStatus('Connecting...')) # disable it until we can replace it in the DOM -Dan
# session.chat_widget.add_message(ChatStatus('Connecting...')) # disable it until we can replace it in the DOM -Dan
def _NH_MediaStreamDidNotInitialize(self, notification):
if notification.sender.type != 'chat':
......@@ -2413,12 +2416,12 @@ class ChatWindow(base_class, ui_class, ColorHelperMixin):
def _SH_SessionModelSessionAboutToBeRemoved(self, session):
# choose another one to select (a chat only or ended session if available, else one with audio but keep audio on hold? or select nothing and display the dummy tab?)
#selection_model = self.session_list.selectionModel()
#selection_model.clearSelection()
# selection_model = self.session_list.selectionModel()
# selection_model.clearSelection()
pass
def _SH_SessionListSelectionChanged(self, selected, deselected):
#print "-- chat selection changed %s -> %s" % ([x.row() for x in deselected.indexes()], [x.row() for x in selected.indexes()])
# print "-- chat selection changed %s -> %s" % ([x.row() for x in deselected.indexes()], [x.row() for x in selected.indexes()])
self.selected_session = selected[0].topLeft().data(Qt.UserRole) if selected else None
if self.selected_session is not None:
self.tab_widget.setCurrentWidget(self.selected_session.chat_widget) # why do we switch the tab here, but do everything else in the selected_session property setter? -Dan
......@@ -2556,7 +2559,7 @@ del ui_class, base_class
#
class HtmlProcessor(object):
_autolink_re = [#re.compile(r"(?P<body>https?://(?:[^:@]+(?::[^@]*)?@)?(?P<host>[a-z0-9.-]+)(?::\d*)?(?:/[\w/%!$@#*&='~():;,.+-]*(?:\?[\w%!$@*&='~():;,.+-]*)?)?)", re.I|re.U),
_autolink_re = [ # re.compile(r"(?P<body>https?://(?:[^:@]+(?::[^@]*)?@)?(?P<host>[a-z0-9.-]+)(?::\d*)?(?:/[\w/%!$@#*&='~():;,.+-]*(?:\?[\w%!$@*&='~():;,.+-]*)?)?)", re.I|re.U),
re.compile(r"""
(?P<body>
https?://(?:[^:@]+(?::[^@]*)?@)?(?P<host>[a-z0-9.-]+)(?::\d*)? # scheme :// [ user [ : password ] @ ] host [ : port ]
......
......@@ -176,7 +176,7 @@ class IconDescriptor(object):
def __eq__(self, other):
if isinstance(other, IconDescriptor):
return self.url==other.url and self.etag==other.etag
return self.url == other.url and self.etag == other.etag
return NotImplemented
def __ne__(self, other):
......@@ -208,7 +208,7 @@ class PresenceState(object):
def __eq__(self, other):
if isinstance(other, PresenceState):
return self.state==other.state and self.note==other.note
return self.state == other.state and self.note == other.note
return NotImplemented
def __ne__(self, other):
......
......@@ -83,7 +83,7 @@ class SIPSimpleSettingsExtension(SettingsObjectExtension):
sounds = SoundSettings
tls = TLSSettingsExtension
user_agent = Setting(type=str, default='Blink %s (%s)' % (__version__, platform.system() if sys.platform!='darwin' else 'MacOSX Qt'))
user_agent = Setting(type=str, default='Blink %s (%s)' % (__version__, platform.system() if sys.platform != 'darwin' else 'MacOSX Qt'))
class SessionInfoSettings(SettingsGroup):
......
__all__ = ['Group', 'Contact', 'BonjourNeighbour', 'GoogleContact', 'ContactModel', 'ContactSearchModel', 'ContactListView', 'ContactSearchListView', 'ContactEditorDialog', 'GoogleContactsDialog', 'URIUtils']
import cPickle as pickle
import os
import re
......@@ -56,6 +54,10 @@ from blink.google.gdata.contacts.service import ContactsQuery
from blink.google.gdata.gauth import ClientLoginToken
__all__ = ['Group', 'Contact', 'BonjourNeighbour', 'GoogleContact', 'ContactModel', 'ContactSearchModel', 'ContactListView', 'ContactSearchListView',
'ContactEditorDialog', 'GoogleContactsDialog', 'URIUtils']
class VirtualGroupManager(object):
__metaclass__ = Singleton
implements(IObserver)
......@@ -170,14 +172,19 @@ class VirtualGroup(SettingsState):
class AllContactsList(object):
def __init__(self):
self.manager = addressbook.AddressbookManager()
def __iter__(self):
return iter(self.manager.get_contacts())
def __getitem__(self, id):
return self.manager.get_contact(id)
def __contains__(self, id):
return self.manager.has_contact(id)
def __len__(self):
return len(self.manager.get_contacts())
__hash__ = None
......@@ -271,26 +278,36 @@ class BonjourNeighbourURI(object):
class BonjourNeighbourURIList(object):
def __init__(self, uris):
self._uri_map = OrderedDict((uri.id, uri) for uri in uris)
def __getitem__(self, id):
return self._uri_map[id]
def __contains__(self, id):
return id in self._uri_map
def __iter__(self):
return iter(self._uri_map.values())
def __len__(self):
return len(self._uri_map)
__hash__ = None
def get(self, key, default=None):
return self._uri_map.get(key, default)
def add(self, uri):
self._uri_map[uri.id] = uri
def pop(self, id, *args):
return self._uri_map.pop(id, *args)
def remove(self, uri):
self._uri_map.pop(uri.id, None)
@property
def default(self):
return sorted(self, key=lambda item: 0 if item.uri.transport=='tls' else 1 if item.uri.transport=='tcp' else 2)[0] if self._uri_map else None
return sorted(self, key=lambda item: 0 if item.uri.transport == 'tls' else 1 if item.uri.transport == 'tcp' else 2)[0] if self._uri_map else None
class BonjourPresence(object):
......@@ -314,19 +331,27 @@ class BonjourNeighbour(object):
class BonjourNeighboursList(object):
def __init__(self):
self._contact_map = {}
def __getitem__(self, id):
return self._contact_map[id]
def __contains__(self, id):
return id in self._contact_map
def __iter__(self):
return iter(self._contact_map.values())
def __len__(self):
return len(self._contact_map)
__hash__ = None
def add(self, contact):
self._contact_map[contact.id] = contact
def pop(self, id, *args):
return self._contact_map.pop(id, *args)
def remove(self, contact):
return self._contact_map.pop(contact.id, None)
......@@ -439,7 +464,7 @@ class GoogleContactURI(object):
@classmethod
def from_number(cls, number):
return cls(re.sub('[\s()-]', '', number.text), cls._get_label(number), number.primary=='true')
return cls(re.sub('[\s()-]', '', number.text), cls._get_label(number), number.primary == 'true')
@classmethod
def from_email(cls, email):
......@@ -456,23 +481,33 @@ class GoogleContactURI(object):
class GoogleContactURIList(object):
def __init__(self, uris):
self._uri_map = OrderedDict((uri.id, uri) for uri in uris)
def __getitem__(self, id):
return self._uri_map[id]
def __contains__(self, id):
return id in self._uri_map
def __iter__(self):
return iter(self._uri_map.values())
def __len__(self):
return len(self._uri_map)
__hash__ = None
def get(self, key, default=None):
return self._uri_map.get(key, default)
def add(self, uri):
self._uri_map[uri.id] = uri
def pop(self, id, *args):
return self._uri_map.pop(id, *args)
def remove(self, uri):
self._uri_map.pop(uri.id, None)
@property
def default(self):
try:
......@@ -500,27 +535,35 @@ class GoogleContact(object):
self.preferred_media = PreferredMedia('audio')
def __reduce__(self):
return (self.__class__, (self.id, self.name, self.company, self.icon, self.uris))
return self.__class__, (self.id, self.name, self.company, self.icon, self.uris)
class GoogleContactsList(object):
def __init__(self):
self._contact_map = {}
self.timestamp = None
def __getitem__(self, id):
return self._contact_map[id]
def __contains__(self, id):
return id in self._contact_map
def __iter__(self):
return iter(self._contact_map.values())
def __len__(self):
return len(self._contact_map)
__hash__ = None
def __setstate__(self, state):
self.__dict__.update(state)
self._contact_map # accessing this will fail if the pickle was created by an older version of the code, thus invalidating the unpickling
def add(self, contact):
self._contact_map[contact.id] = contact
def pop(self, id, *args):
return self._contact_map.pop(id, *args)
......@@ -654,7 +697,7 @@ class GoogleContactsManager(object):
self.client.auth_token = ClientLoginToken(settings.google_contacts.authorization_token)
try:
group_id = next(entry.id.text for entry in self.client.get_groups().entry if entry.title.text=='System Group: My Contacts')
group_id = next(entry.id.text for entry in self.client.get_groups().entry if entry.title.text == 'System Group: My Contacts')
if self.need_sync:
query = ContactsQuery(feed=self.client.get_feed_uri(kind='contacts'), group=group_id, params={})
feed = self.client.get_feed(query.ToUri(), desired_class=ContactsFeed)
......@@ -838,23 +881,33 @@ class DummyContactURI(object):
class DummyContactURIList(object):
def __init__(self, uris):
self._uri_map = OrderedDict((uri.id, uri) for uri in uris)
def __getitem__(self, id):
return self._uri_map[id]
def __contains__(self, id):
return id in self._uri_map
def __iter__(self):
return iter(self._uri_map.values())
def __len__(self):
return len(self._uri_map)
__hash__ = None
def get(self, key, default=None):
return self._uri_map.get(key, default)
def add(self, uri):
self._uri_map[uri.id] = uri
def pop(self, id, *args):
return self._uri_map.pop(id, *args)
def remove(self, uri):
self._uri_map.pop(uri.id, None)
@property
def default(self):
try:
......@@ -877,7 +930,7 @@ class DummyContact(object):
self.preferred_media = PreferredMedia('audio')
def __reduce__(self):
return (self.__class__, (self.name, self.uris))
return self.__class__, (self.name, self.uris)
class Group(object):
......@@ -903,7 +956,7 @@ class Group(object):
return "%s(%r)" % (self.__class__.__name__, self.settings)
def __getstate__(self):
return (self.settings.id, dict(widget=Null, saved_state=self.saved_state, reference_group=self.reference_group))
return self.settings.id, dict(widget=Null, saved_state=self.saved_state, reference_group=self.reference_group)
def __setstate__(self, state):
group_id, state = state
......@@ -990,14 +1043,17 @@ class ContactIconDescriptor(object):
def __init__(self, filename):
self.filename = filename
self.icon = None
def __get__(self, obj, objtype):
def __get__(self, instance, owner):
if self.icon is None:
self.icon = QIcon(self.filename)
self.icon.filename = self.filename
return self.icon
def __set__(self, obj, value):
def __set__(self, instance, value):
raise AttributeError("attribute cannot be set")
def __delete__(self, obj):
def __delete__(self, instance):
raise AttributeError("attribute cannot be deleted")
......@@ -1046,7 +1102,7 @@ class Contact(object):
return '%s(%r, %r)' % (self.__class__.__name__, self.settings, self.group)
def __getstate__(self):
return (self.settings.id, dict(group=self.group))
return self.settings.id, dict(group=self.group)
def __setstate__(self, state):
contact_id, state = state
......@@ -1172,7 +1228,7 @@ class Contact(object):
handler(notification)
def _NH_AddressbookContactDidChange(self, notification):
if set(['icon', 'alternate_icon']).intersection(notification.data.modified):
if {'icon', 'alternate_icon'}.intersection(notification.data.modified):
self.__dict__.pop('icon', None)
self.__dict__.pop('pixmap', None)
notification.center.post_notification('BlinkContactDidChange', sender=self)
......@@ -1206,7 +1262,7 @@ class ContactDetail(object):
return '%s(%r)' % (self.__class__.__name__, self.settings)
def __getstate__(self):
return (self.settings.id, {})
return self.settings.id, {}
def __setstate__(self, state):
contact_id, state = state
......@@ -1368,7 +1424,7 @@ class ContactURI(object):
else:
uri_id = None
state_dict = dict(uri=self.uri)
return (self.contact.id, uri_id, state_dict)
return self.contact.id, uri_id, state_dict
def __setstate__(self, state):
contact_id, uri_id, state = state
......@@ -1414,6 +1470,7 @@ class GoogleAuthorizationData(object):
ui_class, base_class = uic.loadUiType(Resources.get('google_contacts_dialog.ui'))
class GoogleContactsDialog(base_class, ui_class):
__metaclass__ = QSingleton
......@@ -1556,6 +1613,7 @@ del ui_class, base_class
ui_class, base_class = uic.loadUiType(Resources.get('contact.ui'))
class ContactWidget(base_class, ui_class):
def __init__(self, parent=None):
super(ContactWidget, self).__init__(parent)
......@@ -1589,6 +1647,7 @@ del ui_class, base_class
ui_class, base_class = uic.loadUiType(Resources.get('contact_group.ui'))
class GroupWidget(base_class, ui_class):
def __init__(self, parent=None):
super(GroupWidget, self).__init__(parent)
......@@ -1624,7 +1683,7 @@ class GroupWidget(base_class, ui_class):
return
self.__dict__['selected'] = value
self.name_label.setStyleSheet("color: #ffffff; font-weight: bold;" if value else "color: #000000;")
#self.name_label.setForegroundRole(QPalette.BrightText if value else QPalette.WindowText)
# self.name_label.setForegroundRole(QPalette.BrightText if value else QPalette.WindowText)
self.update()
selected = property(_get_selected, _set_selected)
......@@ -1646,7 +1705,7 @@ class GroupWidget(base_class, ui_class):
self._start_editing()
def _start_editing(self):
#self.name_editor.setText(self.name_label.text())
# self.name_editor.setText(self.name_label.text())
self.name_editor.selectAll()
self.name_view.setCurrentWidget(self.editor_widget)
self.name_editor.setFocus()
......@@ -1784,7 +1843,7 @@ class ContactDelegate(QStyledItemDelegate, ColorHelperMixin):
def editorEvent(self, event, model, option, index):
arrow_rect = QRect(0, 0, 14, option.rect.height())
arrow_rect.moveTopRight(option.rect.topRight())
if event.type()==QEvent.MouseButtonRelease and event.button()==Qt.LeftButton and event.modifiers()==Qt.NoModifier and arrow_rect.contains(event.pos()):
if event.type() == QEvent.MouseButtonRelease and event.button() == Qt.LeftButton and event.modifiers() == Qt.NoModifier and arrow_rect.contains(event.pos()):
model.contact_list.detail_model.contact = index.data(Qt.UserRole).settings
detail_view = model.contact_list.detail_view
detail_view.animation.setDirection(QPropertyAnimation.Forward)
......@@ -1841,8 +1900,8 @@ class ContactDelegate(QStyledItemDelegate, ColorHelperMixin):
gradient.setColorAt(1.0, self.color_with_alpha(base_contrast_color, 0.8*255))
contrast_color = QBrush(gradient)
else:
#foreground_color = option.palette.color(QPalette.Normal, QPalette.WindowText)
#background_color = option.palette.color(QPalette.Window)
# foreground_color = option.palette.color(QPalette.Normal, QPalette.WindowText)
# background_color = option.palette.color(QPalette.Window)
foreground_color = widget.palette().color(QPalette.Normal, widget.foregroundRole())
background_color = widget.palette().color(widget.backgroundRole())
contrast_color = self.calc_light_color(background_color)
......@@ -1909,7 +1968,7 @@ class ContactDetailDelegate(QStyledItemDelegate, ColorHelperMixin):
def editorEvent(self, event, model, option, index):
arrow_rect = QRect(0, 0, 14, option.rect.height())
arrow_rect.moveTopRight(option.rect.topRight())
if index.row()==0 and event.type()==QEvent.MouseButtonRelease and event.button()==Qt.LeftButton and event.modifiers()==Qt.NoModifier and arrow_rect.contains(event.pos()):
if index.row() == 0 and event.type() == QEvent.MouseButtonRelease and event.button() == Qt.LeftButton and event.modifiers() == Qt.NoModifier and arrow_rect.contains(event.pos()):
detail_view = self.parent()
detail_view.animation.setDirection(QPropertyAnimation.Backward)
detail_view.animation.start()
......@@ -2068,6 +2127,7 @@ class ContactDetailDelegate(QStyledItemDelegate, ColorHelperMixin):
class Operation(object):
__params__ = ()
__priority__ = None
def __init__(self, **params):
for name, value in params.iteritems():
setattr(self, name, value)
......@@ -2075,14 +2135,17 @@ class Operation(object):
raise ValueError("missing operation parameter: '%s'" % param)
self.timestamp = datetime.utcnow()
class AddContactOperation(Operation):
__params__ = ('contact', 'group_ids', 'icon', 'alternate_icon')
__priority__ = 0
class AddGroupOperation(Operation):
__params__ = ('group',)
__priority__ = 1
class AddGroupMemberOperation(Operation):
__params__ = ('group_id', 'contact_id')
__priority__ = 2
......@@ -2319,15 +2382,15 @@ class ContactModel(QAbstractListModel):
drop_group = next(group for group in groups if group not in moved_groups)
drop_position = self.contact_list.AboveItem
elif group is groups[-1] and group in moved_groups:
drop_group = (group for group in reversed(groups) if group not in moved_groups).next()
drop_group = next(group for group in reversed(groups) if group not in moved_groups)
drop_position = self.contact_list.BelowItem
elif group in moved_groups:
position = groups.index(group)
if drop_indicator is self.contact_list.AboveItem:
drop_group = (group for group in reversed(groups[:position]) if group not in moved_groups).next()
drop_group = next(group for group in reversed(groups[:position]) if group not in moved_groups)
drop_position = self.contact_list.BelowItem
else:
drop_group = (group for group in groups[position:] if group not in moved_groups).next()
drop_group = next(group for group in groups[position:] if group not in moved_groups)
drop_position = self.contact_list.AboveItem
else:
drop_group = group
......@@ -2538,8 +2601,8 @@ class ContactModel(QAbstractListModel):
if contact.presence.policy == 'default':
contact.presence.policy = 'allow' if contact.presence.subscribe else 'block'
contact.save()
elif contact.presence.subscribe != (True if contact.presence.policy=='allow' else False):
contact.presence.subscribe = True if contact.presence.policy=='allow' else False
elif contact.presence.subscribe != (True if contact.presence.policy == 'allow' else False):
contact.presence.subscribe = True if contact.presence.policy == 'allow' else False
contact.save()
@staticmethod
......@@ -3163,13 +3226,13 @@ class ContactListView(QListView):
def keyPressEvent(self, event):
if event.key() in (Qt.Key_Enter, Qt.Key_Return):
selected_indexes = self.selectionModel().selectedIndexes()
item = selected_indexes[0].data(Qt.UserRole) if len(selected_indexes)==1 else None
item = selected_indexes[0].data(Qt.UserRole) if len(selected_indexes) == 1 else None
if isinstance(item, Contact):
session_manager = SessionManager()
session_manager.create_session(item, item.uri, item.preferred_media.stream_descriptions, connect=item.preferred_media.autoconnect)
elif event.key() == Qt.Key_Space:
selected_indexes = self.selectionModel().selectedIndexes()
item = selected_indexes[0].data(Qt.UserRole) if len(selected_indexes)==1 else None
item = selected_indexes[0].data(Qt.UserRole) if len(selected_indexes) == 1 else None
if isinstance(item, Contact) and self.detail_view.isHidden() and self.detail_view.animation.state() == QPropertyAnimation.Stopped:
self.detail_model.contact = item.settings
self.detail_view.animation.setDirection(QPropertyAnimation.Forward)
......@@ -3306,7 +3369,7 @@ class ContactListView(QListView):
groups.add(item)
elif isinstance(item, Contact) and not item.group.virtual:
groups.add(item.group)
preferred_group = groups.pop() if len(groups)==1 else None
preferred_group = groups.pop() if len(groups) == 1 else None
main_window = QApplication.instance().main_window
main_window.contact_editor_dialog.open_for_add(main_window.search_box.text(), preferred_group)
......@@ -3624,7 +3687,7 @@ class ContactSearchListView(QListView):
def keyPressEvent(self, event):
if event.key() in (Qt.Key_Enter, Qt.Key_Return):
selected_indexes = self.selectionModel().selectedIndexes()
item = selected_indexes[0].data(Qt.UserRole) if len(selected_indexes)==1 else None
item = selected_indexes[0].data(Qt.UserRole) if len(selected_indexes) == 1 else None
if isinstance(item, Contact):
session_manager = SessionManager()
session_manager.create_session(item, item.uri, item.preferred_media.stream_descriptions, connect=item.preferred_media.autoconnect)
......@@ -3632,7 +3695,7 @@ class ContactSearchListView(QListView):
QApplication.instance().main_window.search_box.clear()
elif event.key() == Qt.Key_Space:
selected_indexes = self.selectionModel().selectedIndexes()
item = selected_indexes[0].data(Qt.UserRole) if len(selected_indexes)==1 else None
item = selected_indexes[0].data(Qt.UserRole) if len(selected_indexes) == 1 else None
if isinstance(item, Contact) and self.detail_view.isHidden() and self.detail_view.animation.state() == QPropertyAnimation.Stopped:
self.detail_model.contact = item.settings
self.detail_view.animation.setDirection(QPropertyAnimation.Forward)
......@@ -4358,7 +4421,7 @@ class ContactURIModel(QAbstractTableModel):
elif column == ContactURIModel.DefaultColumn:
if value:
for position, item in enumerate(self.items):
item.default = position==row
item.default = position == row
else:
self.items[row].default = False
else:
......@@ -4477,6 +4540,7 @@ class ContactURITableView(QTableView):
ui_class, base_class = uic.loadUiType(Resources.get('contact_editor.ui'))
class ContactEditorDialog(base_class, ui_class):
implements(IObserver)
......
__all__ = ['CallFunctionEvent']
from PyQt4.QtCore import QEvent
from application.python.descriptor import classproperty
__all__ = ['CallFunctionEvent']
class EventMeta(type(QEvent)):
def __init__(cls, name, bases, dct):
super(EventMeta, cls).__init__(name, bases, dct)
......@@ -35,4 +36,3 @@ class CallFunctionEvent(EventBase):
self.args = args
self.kw = kw
__all__ = ['FileTransferWindow']
import os
from PyQt4 import uic
......@@ -18,8 +16,12 @@ 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'))
class FileTransferWindow(base_class, ui_class):
implements(IObserver)
......@@ -63,7 +65,7 @@ class FileTransferWindow(base_class, ui_class):
def update_status(self):
total = len(self.model.items)
active = len([item for item in self.model.items if not item.ended])
text = u'%d %s' % (total, 'transfer' if total==1 else 'transfers')
text = u'%d %s' % (total, 'transfer' if total == 1 else 'transfers')
if active > 0:
text += u' (%d active)' % active
self.status_label.setText(text)
......
__all__ = ['HistoryManager']
import bisect
import cPickle as pickle
import re
......@@ -23,6 +21,9 @@ from blink.resources import ApplicationData, Resources
from blink.util import run_in_gui_thread
__all__ = ['HistoryManager']
class HistoryManager(object):
__metaclass__ = Singleton
implements(IObserver)
......@@ -86,13 +87,16 @@ class IconDescriptor(object):
def __init__(self, filename):
self.filename = filename
self.icon = None
def __get__(self, obj, objtype):
def __get__(self, instance, owner):
if self.icon is None:
self.icon = QIcon(self.filename)
self.icon.filename = self.filename
return self.icon
def __set__(self, obj, value):
raise AttributeError("attribute cannot be set")
def __delete__(self, obj):
raise AttributeError("attribute cannot be deleted")
......@@ -116,7 +120,7 @@ class HistoryEntry(object):
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))
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
......@@ -174,7 +178,7 @@ class HistoryEntry(object):
@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 may have ended 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:
......
__all__ = ['LogManager']
import os
import sys
......@@ -21,6 +19,9 @@ from sipsimple.configuration.settings import SIPSimpleSettings
from blink.resources import ApplicationData
__all__ = ['LogManager']
class NotificationQueue(object):
implements(IObserver)
......@@ -161,10 +162,10 @@ class LogManager(object):
direction = "RECEIVED"
else:
direction = "SENDING"
buf = ["%s: Packet %d, +%s" % (direction, self._siptrace_packet_count, (notification.datetime - self._siptrace_start_time))]
buf.append("%(source_ip)s:%(source_port)d -(SIP over %(transport)s)-> %(destination_ip)s:%(destination_port)d" % notification.data.__dict__)
buf.append(notification.data.data)
buf.append('--')
buf = ["%s: Packet %d, +%s" % (direction, self._siptrace_packet_count, (notification.datetime - self._siptrace_start_time)),
"%(source_ip)s:%(source_port)d -(SIP over %(transport)s)-> %(destination_ip)s:%(destination_port)d" % notification.data.__dict__,
notification.data.data,
'--']
message = '\n'.join(buf)
try:
self.siptrace_file.write('%s [%s %d]: %s\n' % (notification.datetime, self.name, self.pid, message))
......@@ -236,4 +237,3 @@ class LogManager(object):
except Exception:
pass
__all__ = ['MainWindow']
import hashlib
import os
......@@ -36,8 +34,12 @@ 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'))
class MainWindow(base_class, ui_class):
implements(IObserver)
......@@ -585,7 +587,7 @@ class MainWindow(base_class, ui_class):
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))
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():
......@@ -663,7 +665,7 @@ class MainWindow(base_class, ui_class):
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.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()
......@@ -698,7 +700,7 @@ class MainWindow(base_class, ui_class):
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.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()
......@@ -803,16 +805,16 @@ class MainWindow(base_class, ui_class):
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 = next(action for action in self.output_devices_group.actions() if action.data() == settings.audio.output_device)
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 = next(action for action in self.input_devices_group.actions() if action.data() == settings.audio.input_device)
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 = next(action for action in self.alert_devices_group.actions() if action.data() == settings.audio.alert_device)
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 = next(action for action in self.video_devices_group.actions() if action.data() == settings.video.device)
action.setChecked(True)
if 'answering_machine.enabled' in notification.data.modified:
self.answering_machine_action.setChecked(settings.answering_machine.enabled)
......@@ -841,12 +843,12 @@ class MainWindow(base_class, ui_class):
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 = next(action for action in self.accounts_menu.actions() if action.data() is account)
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()
if {'enabled', 'message_summary.enabled', 'message_summary.voicemail_uri'}.intersection(notification.data.modified):
action = next(action for action in self.voicemail_menu.actions() if action.data() is account)
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)
......@@ -868,9 +870,9 @@ class MainWindow(base_class, ui_class):
def _NH_SIPAccountManagerDidRemoveAccount(self, notification):
account = notification.data.account
action = (action for action in self.accounts_menu.actions() if action.data() is account).next()
action = next(action for action in self.accounts_menu.actions() if action.data() is account)
self.accounts_menu.removeAction(action)
action = (action for action in self.voicemail_menu.actions() if action.data() is account).next()
action = next(action for action in self.voicemail_menu.actions() if action.data() is account)
self.voicemail_menu.removeAction(action)
def _NH_SIPAccountManagerDidChangeDefaultAccount(self, notification):
......@@ -878,12 +880,12 @@ class MainWindow(base_class, ui_class):
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))
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 = next(action for action in self.voicemail_menu.actions() if action.data() is account)
action.setEnabled(account.voicemail_uri is not None)
if summary.messages_waiting:
try:
......@@ -918,4 +920,3 @@ class MainWindow(base_class, ui_class):
del ui_class, base_class
__all__ = ['PreferencesWindow', 'AccountListView', 'SIPPortEditor']
import os
import urlparse
......@@ -31,6 +29,8 @@ from blink.logging import LogManager
from blink.util import QSingleton, call_in_gui_thread, run_in_gui_thread
__all__ = ['PreferencesWindow', 'AccountListView', 'SIPPortEditor']
# LineEdit and ComboBox validators
#
......@@ -139,7 +139,7 @@ class AccountListView(QListView):
def __init__(self, parent=None):
super(AccountListView, self).__init__(parent)
self.setItemDelegate(AccountDelegate(self))
#self.setDropIndicatorShown(False)
# self.setDropIndicatorShown(False)
def selectionChanged(self, selected, deselected):
super(AccountListView, self).selectionChanged(selected, deselected)
......@@ -153,9 +153,11 @@ class AccountListView(QListView):
class blocked_qt_signals(object):
def __init__(self, qobject):
self.qobject = qobject
def __enter__(self):
self.qobject.blockSignals(True)
return self.qobject
def __exit__(self, type, value, traceback):
self.qobject.blockSignals(False)
......@@ -174,6 +176,7 @@ class UnspecifiedMSRPRelay(object):
ui_class, base_class = uic.loadUiType(Resources.get('preferences.ui'))
class PreferencesWindow(base_class, ui_class):
__metaclass__ = QSingleton
......@@ -331,7 +334,7 @@ class PreferencesWindow(base_class, ui_class):
self.tls_ca_file_editor.locationCleared.connect(self._SH_TLSCAFileEditorLocationCleared)
self.tls_ca_file_browse_button.clicked.connect(self._SH_TLSCAFileBrowseButtonClicked)
# Setup initial state (show the acounts page right after start)
# Setup initial state (show the accounts page right after start)
self.accounts_action.trigger()
self.account_tab_widget.setCurrentIndex(0)
......@@ -653,7 +656,7 @@ class PreferencesWindow(base_class, ui_class):
item = QListWidgetItem(codec, self.audio_codecs_list)
item.setCheckState(Qt.Checked if codec in settings.rtp.audio_codec_list else Qt.Unchecked)
# Asnwering Machine settings
# Answering Machine settings
self.enable_answering_machine_button.setChecked(settings.answering_machine.enabled)
with blocked_qt_signals(self.answer_delay):
self.answer_delay.setValue(settings.answering_machine.answer_delay)
......@@ -729,9 +732,9 @@ class PreferencesWindow(base_class, ui_class):
for button in self.sip_transports_button_group.buttons():
button.setChecked(button.name in settings.sip.transport_list)
if settings.sip.tcp_port and settings.sip.tcp_port==settings.sip.tls_port:
if settings.sip.tcp_port and settings.sip.tcp_port == settings.sip.tls_port:
log.warning("the SIP TLS and TCP ports cannot be the same")
settings.sip.tls_port = settings.sip.tcp_port+1 if settings.sip.tcp_port<65535 else 65534
settings.sip.tls_port = settings.sip.tcp_port+1 if settings.sip.tcp_port < 65535 else 65534
settings.save()
with blocked_qt_signals(self.udp_port):
......@@ -893,7 +896,7 @@ class PreferencesWindow(base_class, ui_class):
account_manager = AccountManager()
default_account = account_manager.default_account
try:
index = (index for index, account in enumerate(model.accounts) if account==default_account).next()
index = next(index for index, account in enumerate(model.accounts) if account is default_account)
except StopIteration:
index = 0
selection_model.select(model.index(index), selection_model.ClearAndSelect)
......@@ -944,7 +947,7 @@ class PreferencesWindow(base_class, ui_class):
def _update_pstn_example_label(self):
prefix = self.prefix_button.currentText()
idd_prefix = self.idd_prefix_button.currentText()
self.pstn_example_transformed_label.setText(u"%s%s442079460000" % ('' if prefix=='None' else prefix, idd_prefix))
self.pstn_example_transformed_label.setText(u"%s%s442079460000" % ('' if prefix == 'None' else prefix, idd_prefix))
def _align_style_preview(self, scroll=False):
chat_element = self.style_view.page().mainFrame().findFirstElement('#chat')
......@@ -1065,14 +1068,14 @@ class PreferencesWindow(base_class, ui_class):
def _SH_AccountAudioCodecsListItemChanged(self, item):
account = self.selected_account
items = [self.account_audio_codecs_list.item(row) for row in xrange(self.account_audio_codecs_list.count())]
account.rtp.audio_codec_list = [item.text() for item in items if item.checkState()==Qt.Checked]
account.rtp.audio_codec_list = [item.text() for item in items if item.checkState() == Qt.Checked]
account.rtp.audio_codec_order = [item.text() for item in items]
account.save()
def _SH_AccountAudioCodecsListModelRowsMoved(self, source_parent, source_start, source_end, dest_parent, dest_row):
account = self.selected_account
items = [self.account_audio_codecs_list.item(row) for row in xrange(self.account_audio_codecs_list.count())]
account.rtp.audio_codec_list = [item.text() for item in items if item.checkState()==Qt.Checked]
account.rtp.audio_codec_list = [item.text() for item in items if item.checkState() == Qt.Checked]
account.rtp.audio_codec_order = [item.text() for item in items]
account.save()
......@@ -1095,14 +1098,14 @@ class PreferencesWindow(base_class, ui_class):
def _SH_AccountVideoCodecsListItemChanged(self, item):
account = self.selected_account
items = [self.account_video_codecs_list.item(row) for row in xrange(self.account_video_codecs_list.count())]
account.rtp.video_codec_list = [item.text() for item in items if item.checkState()==Qt.Checked]
account.rtp.video_codec_list = [item.text() for item in items if item.checkState() == Qt.Checked]
account.rtp.video_codec_order = [item.text() for item in items]
account.save()
def _SH_AccountVideoCodecsListModelRowsMoved(self, source_parent, source_start, source_end, dest_parent, dest_row):
account = self.selected_account
items = [self.account_video_codecs_list.item(row) for row in xrange(self.account_video_codecs_list.count())]
account.rtp.video_codec_list = [item.text() for item in items if item.checkState()==Qt.Checked]
account.rtp.video_codec_list = [item.text() for item in items if item.checkState() == Qt.Checked]
account.rtp.video_codec_order = [item.text() for item in items]
account.save()
......@@ -1260,7 +1263,7 @@ class PreferencesWindow(base_class, ui_class):
def _SH_IDDPrefixButtonActivated(self, text):
self._update_pstn_example_label()
account = self.selected_account
idd_prefix = None if text=='+' else text
idd_prefix = None if text == '+' else text
if account.pstn.idd_prefix != idd_prefix:
account.pstn.idd_prefix = idd_prefix
account.save()
......@@ -1268,7 +1271,7 @@ class PreferencesWindow(base_class, ui_class):
def _SH_PrefixButtonActivated(self, text):
self._update_pstn_example_label()
account = self.selected_account
prefix = None if text=='None' else text
prefix = None if text == 'None' else text
if account.pstn.prefix != prefix:
account.pstn.prefix = prefix
account.save()
......@@ -1342,14 +1345,14 @@ class PreferencesWindow(base_class, ui_class):
def _SH_AudioCodecsListItemChanged(self, item):
settings = SIPSimpleSettings()
item_iterator = (self.audio_codecs_list.item(row) for row in xrange(self.audio_codecs_list.count()))
settings.rtp.audio_codec_list = [item.text() for item in item_iterator if item.checkState()==Qt.Checked]
settings.rtp.audio_codec_list = [item.text() for item in item_iterator if item.checkState() == Qt.Checked]
settings.save()
def _SH_AudioCodecsListModelRowsMoved(self, source_parent, source_start, source_end, dest_parent, dest_row):
settings = SIPSimpleSettings()
items = [self.audio_codecs_list.item(row) for row in xrange(self.audio_codecs_list.count())]
settings.rtp.audio_codec_order = [item.text() for item in items]
settings.rtp.audio_codec_list = [item.text() for item in items if item.checkState()==Qt.Checked]
settings.rtp.audio_codec_list = [item.text() for item in items if item.checkState() == Qt.Checked]
settings.save()
# Answering machine signal handlers
......@@ -1371,7 +1374,7 @@ class PreferencesWindow(base_class, ui_class):
settings.save()
def _SH_MaxRecordingValueChanged(self, value):
self.max_recording_minutes_label.setText(u'minute' if value==1 else u'minutes')
self.max_recording_minutes_label.setText(u'minute' if value == 1 else u'minutes')
settings = SIPSimpleSettings()
if settings.answering_machine.max_recording != value:
settings.answering_machine.max_recording = value
......@@ -1401,14 +1404,14 @@ class PreferencesWindow(base_class, ui_class):
def _SH_VideoCodecsListItemChanged(self, item):
settings = SIPSimpleSettings()
item_iterator = (self.video_codecs_list.item(row) for row in xrange(self.video_codecs_list.count()))
settings.rtp.video_codec_list = [item.text() for item in item_iterator if item.checkState()==Qt.Checked]
settings.rtp.video_codec_list = [item.text() for item in item_iterator if item.checkState() == Qt.Checked]
settings.save()
def _SH_VideoCodecsListModelRowsMoved(self, source_parent, source_start, source_end, dest_parent, dest_row):
settings = SIPSimpleSettings()
items = [self.video_codecs_list.item(row) for row in xrange(self.video_codecs_list.count())]
settings.rtp.video_codec_order = [item.text() for item in items]
settings.rtp.video_codec_list = [item.text() for item in items if item.checkState()==Qt.Checked]
settings.rtp.video_codec_list = [item.text() for item in items if item.checkState() == Qt.Checked]
settings.save()
def _SH_VideoCodecBitrateButtonActivated(self, index):
......
__all__ = ['PresenceManager', 'PendingWatcherDialog']
import base64
import hashlib
import re
......@@ -36,6 +34,9 @@ from blink.resources import IconManager, Resources
from blink.util import run_in_gui_thread
__all__ = ['PresenceManager', 'PendingWatcherDialog']
epoch = datetime.fromtimestamp(0, tzutc())
......@@ -50,7 +51,7 @@ class BlinkPresenceState(object):
state = blink_settings.presence.current_state.state
note = blink_settings.presence.current_state.note
state = 'offline' if state=='Invisible' else state.lower()
state = 'offline' if state == 'Invisible' else state.lower()
if self.account is BonjourAccount():
return BonjourPresenceState(state, note)
......@@ -182,10 +183,10 @@ class PresencePublicationHandler(object):
account.presence_state = BlinkPresenceState(account).online_state
else:
account = notification.sender
if set(['xcap.enabled', 'xcap.xcap_root']).intersection(notification.data.modified):
if {'xcap.enabled', 'xcap.xcap_root'}.intersection(notification.data.modified):
account.xcap.icon = None
account.save()
elif set(['presence.enabled', 'display_name', 'xcap.icon']).intersection(notification.data.modified) and account.presence.enabled:
elif {'presence.enabled', 'display_name', 'xcap.icon'}.intersection(notification.data.modified) and account.presence.enabled:
account.presence_state = BlinkPresenceState(account).online_state
def _NH_SIPAccountWillActivate(self, notification):
......@@ -219,11 +220,11 @@ class PresencePublicationHandler(object):
blink_settings.presence.current_state = new_state
if new_state.note:
try:
next(state for state in blink_settings.presence.state_history if state==new_state)
next(state for state in blink_settings.presence.state_history if state == new_state)
except StopIteration:
blink_settings.presence.state_history = [new_state] + blink_settings.presence.state_history
else:
blink_settings.presence.state_history = [new_state] + [state for state in blink_settings.presence.state_history if state!=new_state]
blink_settings.presence.state_history = [new_state] + [state for state in blink_settings.presence.state_history if state != new_state]
blink_settings.save()
def _NH_SIPAccountDidDiscoverXCAPSupport(self, notification):
......@@ -334,11 +335,11 @@ class PresenceSubscriptionHandler(object):
def service_sort_key(service):
timestamp = service.timestamp.value if service.timestamp else epoch
if service.status.extended is not None:
return (100, timestamp)
return 100, timestamp
elif service.status.basic == 'open':
return (10, timestamp)
return 10, timestamp
else:
return (0, timestamp)
return 0, timestamp
current_pidf_map = {}
contact_pidf_map = {}
......@@ -365,7 +366,7 @@ class PresenceSubscriptionHandler(object):
if service.status.extended:
state = unicode(service.status.extended)
else:
state = 'available' if service.status.basic=='open' else 'offline'
state = 'available' if service.status.basic == 'open' else 'offline'
note = unicode(next(iter(service.notes))) if service.notes else None
icon_url = unicode(service.icon) if service.icon else None
......@@ -406,7 +407,7 @@ class PresenceSubscriptionHandler(object):
self._winfo_map.pop(old_id, None)
self._process_presence_data()
return
if set(['enabled', 'presence.enabled']).intersection(notification.data.modified):
if {'enabled', 'presence.enabled'}.intersection(notification.data.modified):
if not account.enabled or not account.presence.enabled:
self._pidf_map.pop(account.id, None)
self._winfo_map.pop(account.id, None)
......
"""Provide access to Blink's resources"""
__all__ = ['ApplicationData', 'Resources', 'IconManager']
import __main__
import imghdr
import os
......@@ -21,10 +19,14 @@ from sipsimple.configuration.datatypes import Path
from blink.util import run_in_gui_thread
__all__ = ['ApplicationData', 'Resources', 'IconManager']
class DirectoryContextManager(unicode):
def __enter__(self):
self.directory = os.getcwdu()
os.chdir(self)
def __exit__(self, type, value, traceback):
os.chdir(self.directory)
......
__all__ = ['ScreensharingWindow', 'VNCViewer', 'VNCClient', 'RFBSettings', 'ServerDefault', 'TrueColor', 'HighColor', 'LowColor']
from blink.screensharing.vncclient import VNCClient, RFBSettings, ServerDefault, TrueColor, HighColor, LowColor
from blink.screensharing.vncviewer import ScreensharingWindow, VNCViewer
__all__ = ['ScreensharingWindow', 'VNCViewer', 'VNCClient', 'RFBSettings', 'ServerDefault', 'TrueColor', 'HighColor', 'LowColor']
__all__ = ['RFBClient', 'RFBClientError']
from sip import voidptr
from PyQt4.QtCore import QThread
from PyQt4.QtGui import QImage
......@@ -12,6 +10,9 @@ from libc.stdlib cimport calloc, malloc, free
from libc.string cimport memcpy, strlen
__all__ = ['RFBClient', 'RFBClientError']
# external declarations
#
......
__all__ = ['VNCClient', 'RFBSettings', 'ServerDefault', 'TrueColor', 'HighColor', 'LowColor']
from PyQt4.QtCore import QObject, QSize, QSocketNotifier, QThread, pyqtSignal
from PyQt4.QtGui import QApplication
......@@ -13,6 +10,9 @@ from blink.event import EventBase
from blink.screensharing._rfb import RFBClient, RFBClientError
__all__ = ['VNCClient', 'RFBSettings', 'ServerDefault', 'TrueColor', 'HighColor', 'LowColor']
class RFBSettings(object):
depth = WriteOnceAttribute()
quality = WriteOnceAttribute()
......@@ -101,6 +101,7 @@ class VNCClient(QObject):
def _get_settings(self):
return self.__dict__['settings']
def _set_settings(self, settings):
old_settings = self.__dict__.get('settings', None)
if settings == old_settings:
......@@ -108,6 +109,7 @@ class VNCClient(QObject):
self.__dict__['settings'] = settings
if self.thread.isRunning():
QApplication.postEvent(self, RFBConfigureClientEvent())
settings = property(_get_settings, _set_settings)
del _get_settings, _set_settings
......
from __future__ import division
__all__ = ['ScreensharingWindow', 'VNCViewer']
import os
import platform
......@@ -28,6 +24,9 @@ from blink.resources import Resources
from blink.screensharing.vncclient import ServerDefault, TrueColor, HighColor, LowColor
__all__ = ['ScreensharingWindow', 'VNCViewer']
class ButtonMaskMapper(dict):
class qt:
NoButton = Qt.NoButton
......@@ -47,7 +46,7 @@ class ButtonMaskMapper(dict):
def __init__(self):
mapping = {self.qt.NoButton: self.vnc.NoButton, self.qt.LeftButton: self.vnc.LeftButton, self.qt.MidButton: self.vnc.MidButton, self.qt.RightButton: self.vnc.RightButton}
super(ButtonMaskMapper, self).__init__({int(b1|b2|b3): mapping[b1]|mapping[b2]|mapping[b3] for b1 in mapping for b2 in mapping for b3 in mapping})
super(ButtonMaskMapper, self).__init__({int(b1 | b2 | b3): mapping[b1] | mapping[b2] | mapping[b3] for b1 in mapping for b2 in mapping for b3 in mapping})
self._button_mask = int(self.qt.LeftButton|self.qt.MidButton|self.qt.RightButton)
def __getitem__(self, key):
......@@ -172,14 +171,14 @@ class VNCViewer(QWidget):
super(VNCViewer, self).__init__(parent)
self.setMouseTracking(True)
self.setFocusPolicy(Qt.WheelFocus)
#self.setCursor(Qt.BlankCursor)
# self.setCursor(Qt.BlankCursor)
self.client = vncclient or parent.client
self.client.started.connect(self._SH_ClientStarted)
self.client.finished.connect(self._SH_ClientFinished)
self.client.imageSizeChanged.connect(self._SH_ImageSizeChanged)
self.client.imageChanged.connect(self._SH_ImageUpdated)
self.client.passwordRequested.connect(self._SH_PasswordRequested, Qt.BlockingQueuedConnection)
self.colors_8bit = [qRgb((i&0x07) << 5, (i&0x38) << 2, i&0xc0) for i in range(256)]
self.colors_8bit = [qRgb((i & 0x07) << 5, (i & 0x38) << 2, i & 0xc0) for i in range(256)]
self.scale = False
self.view_only = False
self._client_active = False
......@@ -188,6 +187,7 @@ class VNCViewer(QWidget):
def _get_scale(self):
return self.__dict__['scale']
def _set_scale(self, scale):
self.__dict__['scale'] = scale
if not scale:
......@@ -197,11 +197,13 @@ class VNCViewer(QWidget):
elif self.parent() is not None:
self.resize(self.parent().size())
self.update()
scale = property(_get_scale, _set_scale)
del _get_scale, _set_scale
def _get_view_only(self):
return self.__dict__['view_only']
def _set_view_only(self, view_only):
old_value = self.__dict__.get('view_only', None)
new_value = self.__dict__['view_only'] = view_only
......@@ -211,6 +213,7 @@ class VNCViewer(QWidget):
self.grabKeyboard()
else:
self.releaseKeyboard()
view_only = property(_get_view_only, _set_view_only)
del _get_view_only, _set_view_only
......@@ -307,15 +310,15 @@ class VNCViewer(QWidget):
button_mask = self.button_mask_map[event.buttons()]
if event.type() == QEvent.Wheel:
if event.delta() > 0:
wheel_button_mask = self.button_mask_map.vnc.WheelUp if event.orientation()==Qt.Vertical else self.button_mask_map.vnc.WheelLeft
wheel_button_mask = self.button_mask_map.vnc.WheelUp if event.orientation() == Qt.Vertical else self.button_mask_map.vnc.WheelLeft
else:
wheel_button_mask = self.button_mask_map.vnc.WheelDown if event.orientation()==Qt.Vertical else self.button_mask_map.vnc.WheelRight
wheel_button_mask = self.button_mask_map.vnc.WheelDown if event.orientation() == Qt.Vertical else self.button_mask_map.vnc.WheelRight
self.client.mouse_event(x, y, button_mask | wheel_button_mask)
self.client.mouse_event(x, y, button_mask)
def keyEvent(self, event):
vnc_key = VNCKey.from_event(event)
key_down = event.type()==QEvent.KeyPress
key_down = event.type() == QEvent.KeyPress
if vnc_key:
expected_modifiers = self._active_keys.modifiers
keyboard_modifiers = event.modifiers()
......@@ -376,6 +379,7 @@ class VNCViewer(QWidget):
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)
......@@ -399,7 +403,7 @@ class ScreensharingDialog(base_class, ui_class):
self.setMinimumHeight(190)
self.resize(self.minimumSize())
result = self.exec_()
return (self.username_editor.text(), self.password_editor.text()) if result==self.Accepted else (None, None)
return (self.username_editor.text(), self.password_editor.text()) if result == self.Accepted else (None, None)
def get_password(self):
self.message_label.setText(u'Screen sharing requires a password')
......@@ -411,13 +415,14 @@ class ScreensharingDialog(base_class, ui_class):
self.setMinimumHeight(165)
self.resize(self.minimumSize())
result = self.exec_()
return self.password_editor.text() if result==self.Accepted else None
return self.password_editor.text() if result == self.Accepted else None
del ui_class, base_class
ui_class, base_class = uic.loadUiType(Resources.get('screensharing_toolbox.ui'))
class ScreensharingToolbox(base_class, ui_class):
exposedPixels = 3
......@@ -530,6 +535,7 @@ del ui_class, base_class
ui_class, base_class = uic.loadUiType(Resources.get('screensharing_window.ui'))
class ScreensharingWindow(base_class, ui_class):
def __init__(self, vncclient, parent=None):
super(ScreensharingWindow, self).__init__(parent)
......
__all__ = ['ClientConference', 'ConferenceDialog', 'AudioSessionModel', 'AudioSessionListView', 'ChatSessionModel', 'ChatSessionListView', 'SessionManager']
import bisect
import cPickle as pickle
import contextlib
......@@ -55,7 +53,11 @@ from blink.widgets.util import ContextMenuActions, QtDynamicProperty
from blink.widgets.zrtp import ZRTPWidget
class Container(object): pass
__all__ = ['ClientConference', 'ConferenceDialog', 'AudioSessionModel', 'AudioSessionListView', 'ChatSessionModel', 'ChatSessionListView', 'SessionManager']
class Container(object):
pass
class RTPStreamInfo(object):
......@@ -379,10 +381,10 @@ class StreamListDescriptor(object):
def __init__(self):
self.values = defaultweakobjectmap(StreamMap)
def __get__(self, obj, objtype):
if obj is None:
def __get__(self, instance, owner):
if instance is None:
return self
return StreamContainer(obj, self.values[obj])
return StreamContainer(instance, self.values[instance])
def __set__(self, obj, value):
raise AttributeError("Attribute cannot be set")
......@@ -421,8 +423,8 @@ class SessionItemsDescriptor(object):
def __init__(self):
self.values = defaultweakobjectmap(self.SessionItems)
def __get__(self, obj, objtype):
return self.values[obj] if obj is not None else None
def __get__(self, instance, owner):
return self.values[instance] if instance is not None else None
def __set__(self, obj, value):
raise AttributeError("Attribute cannot be set")
......@@ -636,7 +638,7 @@ class BlinkSession(BlinkSessionBase):
notification_center.post_notification('BlinkSessionWillReinitialize', sender=self)
self._initialize(reinitialize=True)
else:
self._delete_when_done = len(streams)==1 and streams[0].type=='audio'
self._delete_when_done = len(streams) == 1 and streams[0].type == 'audio'
self.direction = 'incoming'
self.sip_session = sip_session
self.account = sip_session.account
......@@ -662,7 +664,7 @@ class BlinkSession(BlinkSessionBase):
notification_center.post_notification('BlinkSessionWillReinitialize', sender=self)
self._initialize(reinitialize=True)
else:
self._delete_when_done = len(stream_descriptions)==1 and stream_descriptions[0].type=='audio'
self._delete_when_done = len(stream_descriptions) == 1 and stream_descriptions[0].type == 'audio'
self.direction = 'outgoing'
self.account = account
self.contact = contact
......@@ -998,7 +1000,7 @@ class BlinkSession(BlinkSessionBase):
self._terminate(reason=reason, error=True)
def _NH_SIPSessionDidEnd(self, notification):
self._terminate('Call ended' if notification.data.originator=='local' else 'Call ended by remote')
self._terminate('Call ended' if notification.data.originator == 'local' else 'Call ended by remote')
def _NH_SIPSessionDidChangeHoldState(self, notification):
if notification.data.originator == 'remote':
......@@ -1085,7 +1087,7 @@ class BlinkSession(BlinkSessionBase):
stream = notification.sender
audio_stream = self.streams.get('audio')
if stream.type == 'chat' and stream.session.remote_focus and 'com.ag-projects.zrtp-sas' in stream.chatroom_capabilities and audio_stream is not None:
secure_chat = stream.transport == 'tls' and all(len(path)==1 for path in (stream.msrp.full_local_path, stream.msrp.full_remote_path)) # tls & direct connection
secure_chat = stream.transport == 'tls' and all(len(path) == 1 for path in (stream.msrp.full_local_path, stream.msrp.full_remote_path)) # tls & direct connection
if audio_stream.encryption.type == 'ZRTP' and audio_stream.encryption.zrtp.sas is not None and not audio_stream.encryption.zrtp.verified and secure_chat:
stream.send_message(audio_stream.encryption.zrtp.sas, 'application/blink-zrtp-sas')
......@@ -1372,8 +1374,8 @@ class ConferenceParticipant(object):
self.active_media.add('chat')
else:
self.active_media.add(media.media_type.value)
audio_endpoints = [endpt for endpt in data if any(media.media_type=='audio' for media in endpt)]
self.on_hold = all(endpt.status=='on-hold' for endpt in audio_endpoints) if audio_endpoints else False
audio_endpoints = [endpt for endpt in data if any(media.media_type == 'audio' for media in endpt)]
self.on_hold = all(endpt.status == 'on-hold' for endpt in audio_endpoints) if audio_endpoints else False
for attr, value in old_values.iteritems():
if value != getattr(self, attr):
NotificationCenter().post_notification('ConferenceParticipantDidChange', sender=self)
......@@ -2008,7 +2010,7 @@ class AudioSessionItem(object):
if self.audio_stream in self.blink_session.streams.proposed and self.blink_session.state == 'connected/sent_proposal':
self.blink_session.sip_session.cancel_proposal()
# review this -Dan
#elif len(self.blink_session.streams) > 1 and self.blink_session.state == 'connected':
# elif len(self.blink_session.streams) > 1 and self.blink_session.state == 'connected':
# self.blink_session.remove_stream(self.audio_stream)
elif 'chat' in self.blink_session.streams and self.blink_session.state == 'connected':
self.blink_session.remove_streams([stream for stream in self.blink_session.streams if stream.type != 'chat'])
......@@ -2078,7 +2080,7 @@ class AudioSessionItem(object):
if stage == 'dns_lookup':
self.status = Status('Looking up destination...')
elif stage == 'connecting':
self.tls = self.blink_session.transport=='tls'
self.tls = self.blink_session.transport == 'tls'
self.status = Status('Connecting...')
elif stage == 'ringing':
self.status = Status('Ringing...')
......@@ -2117,7 +2119,7 @@ class AudioSessionItem(object):
def _NH_BlinkSessionDidConnect(self, notification):
session = notification.sender
self.tls = session.transport=='tls'
self.tls = session.transport == 'tls'
if 'audio' in session.streams:
self.widget.mute_button.setEnabled(True)
self.widget.hold_button.setEnabled(True)
......@@ -2364,12 +2366,12 @@ class AudioSessionModel(QAbstractListModel):
if len(dragged.client_conference.sessions) == 2:
dragged.client_conference = None
sibling.client_conference = None
## eventually only move past the last conference to minimize movement. see how this feels during usage. (or sort them alphabetically with conferences at the top) -Dan
#for position, session in enumerate(self.sessions):
# # maybe only move past the last conference to minimize movement. see how this feels during usage. (or sort them alphabetically with conferences at the top) -Dan
# for position, session in enumerate(self.sessions):
# if session not in (dragged, sibling) and session.client_conference is None:
# move_point = position
# break
#else:
# else:
# move_point = len(self.sessions)
move_point = len(self.sessions)
dragged_row = self.sessions.index(dragged)
......@@ -2747,7 +2749,7 @@ class AudioSessionListView(QListView):
else:
self.setCurrentIndex(self.model().index(-1))
self.context_menu.hide()
#print "-- audio selection changed %s -> %s (ignore=%s)" % ([x.row() for x in deselected.indexes()], [x.row() for x in selected.indexes()], self.ignore_selection_changes)
# print "-- audio selection changed %s -> %s (ignore=%s)" % ([x.row() for x in deselected.indexes()], [x.row() for x in selected.indexes()], self.ignore_selection_changes)
if self.ignore_selection_changes:
return
notification_center = NotificationCenter()
......@@ -2911,14 +2913,14 @@ class AudioSessionListView(QListView):
if notification.data.active_session is None:
selection = selection_model.selection()
# check the code in this if branch if it's needed -Dan
#selected_blink_session = selection[0].topLeft().data(Qt.UserRole).blink_session if selection else None
#if notification.data.previous_active_session is selected_blink_session:
# selected_blink_session = selection[0].topLeft().data(Qt.UserRole).blink_session if selection else None
# if notification.data.previous_active_session is selected_blink_session:
# print "-- audio session list updating selection to None None"
# selection_model.clearSelection()
else:
model = self.model()
position = model.sessions.index(notification.data.active_session.items.audio)
#print "-- audio session list updating selection to", position, notification.data.active_session
# print "-- audio session list updating selection to", position, notification.data.active_session
selection_model.select(model.index(position), selection_model.ClearAndSelect)
self.ignore_selection_changes = False
......@@ -2996,8 +2998,8 @@ class ChatSessionWidget(base_class, ui_class):
self.screen_sharing_icon.installEventFilter(self)
self.widget_layout.invalidate()
self.widget_layout.activate()
#self.setAttribute(103) # Qt.WA_DontShowOnScreen == 103 and is missing from pyqt, but is present in qt and pyside -Dan
#self.show()
# self.setAttribute(103) # Qt.WA_DontShowOnScreen == 103 and is missing from pyqt, but is present in qt and pyside -Dan
# self.show()
def _get_display_mode(self):
return self.__dict__['display_mode']
......@@ -3227,7 +3229,7 @@ class ChatSessionDelegate(QStyledItemDelegate, ColorHelperMixin):
super(ChatSessionDelegate, self).__init__(parent)
def editorEvent(self, event, model, option, index):
if event.type()==QEvent.MouseButtonRelease and event.button()==Qt.LeftButton and event.modifiers()==Qt.NoModifier:
if event.type() == QEvent.MouseButtonRelease and event.button() == Qt.LeftButton and event.modifiers() == Qt.NoModifier:
arrow_rect = option.rect.adjusted(option.rect.width()-14, option.rect.height()/2, 0, 0) # bottom half of the rightmost 14 pixels
cross_rect = option.rect.adjusted(option.rect.width()-14, 0, 0, -option.rect.height()/2) # top half of the rightmost 14 pixels
if arrow_rect.contains(event.pos()):
......@@ -3277,8 +3279,8 @@ class ChatSessionDelegate(QStyledItemDelegate, ColorHelperMixin):
gradient.setColorAt(1.0, self.color_with_alpha(base_contrast_color, 0.8*255))
contrast_color = QBrush(gradient)
else:
#foreground_color = option.palette.color(QPalette.Normal, QPalette.WindowText)
#background_color = option.palette.color(QPalette.Window)
# foreground_color = option.palette.color(QPalette.Normal, QPalette.WindowText)
# background_color = option.palette.color(QPalette.Window)
foreground_color = widget.palette().color(QPalette.Normal, widget.foregroundRole())
background_color = widget.palette().color(widget.backgroundRole())
contrast_color = self.calc_light_color(background_color)
......@@ -3374,7 +3376,7 @@ class ChatSessionModel(QAbstractListModel):
return None
def supportedDropActions(self):
return Qt.CopyAction# | Qt.MoveAction
return Qt.CopyAction # | Qt.MoveAction
def dropMimeData(self, mime_data, action, row, column, parent_index):
# this is here just to keep the default Qt DnD API happy
......@@ -3465,9 +3467,9 @@ class ChatSessionListView(QListView):
self.setAutoFillBackground(True)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
#self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # default
# self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # default
self.setDragEnabled(False) # default
#self.setDropIndicatorShown(True)
# self.setDropIndicatorShown(True)
self.setDragDropMode(QListView.DropOnly)
self.setSelectionMode(QListView.SingleSelection) # default
......@@ -3638,14 +3640,14 @@ class ChatSessionListView(QListView):
if notification.data.active_session is None:
selection = selection_model.selection()
# check the code in this if branch if it's needed -Dan (if not also remove previous_active_session maybe)
#selected_blink_session = selection[0].topLeft().data(Qt.UserRole).blink_session if selection else None
#if notification.data.previous_active_session is selected_blink_session:
# selected_blink_session = selection[0].topLeft().data(Qt.UserRole).blink_session if selection else None
# if notification.data.previous_active_session is selected_blink_session:
# print "-- chat session list updating selection to None None"
# selection_model.clearSelection()
else:
model = self.model()
position = model.sessions.index(notification.data.active_session.items.chat)
#print "-- chat session list updating selection to", position, notification.data.active_session
# print "-- chat session list updating selection to", position, notification.data.active_session
selection_model.select(model.index(position), selection_model.ClearAndSelect)
self.ignore_selection_changes = False
......@@ -4096,6 +4098,7 @@ class TransferStateLabel(QLabel, ColorHelperMixin):
def _get_display_mode(self):
return self.__dict__['display_mode']
def _set_display_mode(self, value):
if value not in (self.ProgressDisplayMode, self.InactiveDisplayMode):
raise ValueError("invalid display_mode: %r" % value)
......@@ -4103,34 +4106,41 @@ class TransferStateLabel(QLabel, ColorHelperMixin):
new_value = self.__dict__['display_mode'] = value
if new_value != old_value:
self.update()
display_mode = property(_get_display_mode, _set_display_mode)
del _get_display_mode, _set_display_mode
def _get_show_cancel_button(self):
return self.__dict__['show_cancel_button']
def _set_show_cancel_button(self, value):
old_value = self.__dict__.get('show_cancel_button', False)
new_value = self.__dict__['show_cancel_button'] = bool(value)
if new_value != old_value:
self.update()
show_cancel_button = property(_get_show_cancel_button, _set_show_cancel_button)
del _get_show_cancel_button, _set_show_cancel_button
def _get_show_retry_button(self):
return self.__dict__['show_retry_button']
def _set_show_retry_button(self, value):
old_value = self.__dict__.get('show_retry_button', False)
new_value = self.__dict__['show_retry_button'] = bool(value)
if new_value != old_value:
self.update()
show_retry_button = property(_get_show_retry_button, _set_show_retry_button)
del _get_show_retry_button, _set_show_retry_button
def _get_progress(self):
return self.__dict__['progress']
def _set_progress(self, value):
self.__dict__['progress'] = value
self.update()
progress = property(_get_progress, _set_progress)
del _get_progress, _set_progress
......@@ -4208,6 +4218,7 @@ class TransferStateLabel(QLabel, ColorHelperMixin):
ui_class, base_class = uic.loadUiType(Resources.get('filetransfer_item.ui'))
class FileTransferItemWidget(base_class, ui_class):
class StandardDisplayMode: __metaclass__ = MarkerType
class AlternateDisplayMode: __metaclass__ = MarkerType
......@@ -4419,7 +4430,7 @@ class FileTransferDelegate(QStyledItemDelegate):
super(FileTransferDelegate, self).__init__(parent)
def editorEvent(self, event, model, option, index):
if event.type()==QEvent.MouseButtonDblClick and event.button()==Qt.LeftButton and event.modifiers()==Qt.NoModifier:
if event.type() == QEvent.MouseButtonDblClick and event.button() == Qt.LeftButton and event.modifiers() == Qt.NoModifier:
item = index.data(Qt.UserRole)
if item.ended and not item.failed:
QDesktopServices.openUrl(QUrl.fromLocalFile(item.filename))
......@@ -4436,7 +4447,7 @@ class FileTransferDelegate(QStyledItemDelegate):
if not rect.contains(event.pos()):
QDesktopServices.openUrl(QUrl.fromLocalFile(item.filename))
return True
elif event.type()==QEvent.MouseButtonRelease and event.button()==Qt.LeftButton and event.modifiers()==Qt.NoModifier:
elif event.type() == QEvent.MouseButtonRelease and event.button() == Qt.LeftButton and event.modifiers() == Qt.NoModifier:
item = index.data(Qt.UserRole)
indicator = item.widget.state_indicator
margin = indicator.margin()
......@@ -4588,7 +4599,7 @@ class FileTransferModel(QAbstractListModel):
def _NH_BlinkFileTransferNewIncoming(self, notification):
transfer = notification.sender
with self.history.transaction():
for item in (item for item in self.items if item.failed and item.direction=='incoming'):
for item in (item for item in self.items if item.failed and item.direction == 'incoming'):
if item.transfer.contact == transfer.contact and item.transfer.hash == transfer.hash:
self.removeItem(item)
break
......@@ -4696,7 +4707,7 @@ class ConferenceParticipantDelegate(QStyledItemDelegate, ColorHelperMixin):
super(ConferenceParticipantDelegate, self).__init__(parent)
def editorEvent(self, event, model, option, index):
if event.type()==QEvent.MouseButtonRelease and event.button()==Qt.LeftButton and event.modifiers()==Qt.NoModifier:
if event.type() == QEvent.MouseButtonRelease and event.button() == Qt.LeftButton and event.modifiers() == Qt.NoModifier:
cross_rect = option.rect.adjusted(option.rect.width()-14, 0, 0, -option.rect.height()/2) # top half of the rightmost 14 pixels
if cross_rect.contains(event.pos()):
item = index.data(Qt.UserRole)
......@@ -4813,7 +4824,7 @@ class ConferenceParticipantModel(QAbstractListModel):
return None
def supportedDropActions(self):
return Qt.CopyAction# | Qt.MoveAction
return Qt.CopyAction # | Qt.MoveAction
def dropMimeData(self, mime_data, action, row, column, parent_index):
# this is here just to keep the default Qt DnD API happy
......@@ -4955,12 +4966,12 @@ class ConferenceParticipantListView(QListView, ColorHelperMixin):
super(ConferenceParticipantListView, self).paintEvent(event)
if self.paint_drop_indicator:
rect = self.viewport().rect() # or should this be self.contentsRect() ? -Dan
#color = QColor('#b91959')
#color = QColor('#00aaff')
#color = QColor('#55aaff')
#color = QColor('#00aa00')
#color = QColor('#aa007f')
#color = QColor('#dd44aa')
# color = QColor('#b91959')
# color = QColor('#00aaff')
# color = QColor('#55aaff')
# color = QColor('#00aa00')
# color = QColor('#aa007f')
# color = QColor('#dd44aa')
color = QColor('#aa007f')
pen_color = self.color_with_alpha(color, 120)
brush_color = self.color_with_alpha(color, 10)
......@@ -5016,8 +5027,8 @@ class ConferenceParticipantListView(QListView, ColorHelperMixin):
def _DH_TextUriList(self, event):
event.ignore(self.viewport().rect())
#event.accept(self.viewport().rect())
#self.paint_drop_indicator = True
# event.accept(self.viewport().rect())
# self.paint_drop_indicator = True
# Session management
......@@ -5082,6 +5093,7 @@ class IncomingDialogBase(QDialog):
ui_class, base_class = uic.loadUiType(Resources.get('incoming_dialog.ui'))
class IncomingDialog(IncomingDialogBase, ui_class):
def __init__(self, parent=None):
super(IncomingDialog, self).__init__(parent)
......@@ -5113,7 +5125,7 @@ class IncomingDialog(IncomingDialogBase, ui_class):
@property
def streams(self):
return (self.audio_stream, self.chat_stream, self.screensharing_stream, self.video_stream)
return self.audio_stream, self.chat_stream, self.screensharing_stream, self.video_stream
@property
def accepted_streams(self):
......@@ -5363,6 +5375,7 @@ class IncomingFileTransferRequest(QObject):
ui_class, base_class = uic.loadUiType(Resources.get('incoming_calltransfer_dialog.ui'))
class IncomingCallTransferDialog(IncomingDialogBase, ui_class):
def __init__(self, parent=None):
super(IncomingCallTransferDialog, self).__init__(parent)
......@@ -5441,6 +5454,7 @@ class IncomingCallTransferRequest(QObject):
ui_class, base_class = uic.loadUiType(Resources.get('conference_dialog.ui'))
class ConferenceDialog(base_class, ui_class):
def __init__(self, parent=None):
super(ConferenceDialog, self).__init__(parent)
......@@ -5495,10 +5509,10 @@ class RingtoneDescriptor(object):
def __init__(self):
self.values = weakobjectmap()
def __get__(self, obj, objtype):
if obj is None:
def __get__(self, instance, owner):
if instance is None:
return self
return self.values[obj]
return self.values[instance]
def __set__(self, obj, ringtone):
old_ringtone = self.values.get(obj, Null)
......@@ -5659,7 +5673,7 @@ class SessionManager(object):
inbound_ringtone = Null
# Hold tone
connected_sessions = [session for session in self.sessions if session.state=='connected/*']
connected_sessions = [session for session in self.sessions if session.state == 'connected/*']
connected_on_hold_sessions = [session for session in connected_sessions if session.on_hold]
if outbound_ringtone is Null and inbound_ringtone is Null and connected_sessions:
if len(connected_sessions) == len(connected_on_hold_sessions):
......
__all__ = ['IUpdateManager', 'UpdateManager']
import sys
from application.python import Null
from zope.interface import Interface
__all__ = ['IUpdateManager', 'UpdateManager']
class IUpdateManager(Interface):
def initialize(self):
pass
def shutdown(self):
pass
def check_for_updates(self):
pass
......@@ -23,4 +26,3 @@ if sys.platform == 'win32':
UpdateManager = Null
else:
UpdateManager = Null
......@@ -19,14 +19,13 @@ def library_locations(name):
for path in additional_paths:
yield os.path.join(path, library_name)
def load_library(name):
for library in library_locations(name):
try:
return CDLL(library)
except OSError:
pass
else:
break
else:
raise RuntimeError('cannot find %s on this system' % name)
......
__all__ = ['QSingleton', 'call_in_gui_thread', 'call_later', 'run_in_gui_thread']
from PyQt4.QtCore import QObject, QThread, QTimer
from PyQt4.QtGui import QApplication
from application.python.decorator import decorator, preserve_signature
......@@ -9,6 +7,9 @@ from application.python.types import Singleton
from blink.event import CallFunctionEvent
__all__ = ['QSingleton', 'call_in_gui_thread', 'call_later', 'run_in_gui_thread']
class QSingleton(Singleton, type(QObject)):
"""A metaclass for making Qt objects singletons"""
......
__all__ = ['ToolButton', 'ConferenceButton', 'StreamButton', 'SegmentButton', 'SingleSegment', 'LeftSegment', 'MiddleSegment', 'RightSegment', 'RecordButton', 'SwitchViewButton',
'StateButton', 'AccountState']
from PyQt4.QtCore import Qt, QLineF, QPointF, QRectF, QSize, QTimer, pyqtSignal, pyqtSignature
from PyQt4.QtGui import QAction, QBrush, QColor, QCommonStyle, QLinearGradient, QIcon, QMenu, QPainter, QPainterPath, QPalette, QPen, QPixmap
from PyQt4.QtGui import QPolygonF, QPushButton, QStyle, QStyleOptionToolButton, QStylePainter, QToolButton
......@@ -10,8 +7,13 @@ from blink.resources import Resources
from blink.widgets.color import ColorScheme, ColorUtils, ColorHelperMixin
__all__ = ['ToolButton', 'ConferenceButton', 'StreamButton', 'SegmentButton', 'SingleSegment', 'LeftSegment', 'MiddleSegment', 'RightSegment',
'RecordButton', 'SwitchViewButton', 'StateButton', 'AccountState']
class ToolButton(QToolButton):
"""A custom QToolButton that doesn't show a menu indicator arrow"""
def paintEvent(self, event):
painter = QStylePainter(self)
option = QStyleOptionToolButton()
......@@ -102,10 +104,12 @@ class SegmentTypeMeta(type):
def __repr__(cls):
return cls.__name__
class SegmentType(object):
__metaclass__ = SegmentTypeMeta
style_sheet = ''
class SingleSegment(SegmentType):
style_sheet = """
QToolButton {
......@@ -122,6 +126,7 @@ class SingleSegment(SegmentType):
}
"""
class LeftSegment(SegmentType):
style_sheet = """
QToolButton {
......@@ -139,6 +144,7 @@ class LeftSegment(SegmentType):
}
"""
class MiddleSegment(SegmentType):
style_sheet = """
QToolButton {
......@@ -155,6 +161,7 @@ class MiddleSegment(SegmentType):
}
"""
class RightSegment(SegmentType):
style_sheet = """
QToolButton {
......@@ -387,7 +394,7 @@ class StateButtonStyle(QCommonStyle, ColorHelperMixin):
return super(StateButtonStyle, self).sizeFromContents(element, option, size, widget)
def toolButtonSizeFromContents(self, option, size, widget):
# Make width >= height to avoid super-skiny buttons
# Make width >= height to avoid super-skinny buttons
margin = 2 * (self._pixel_metrics[QStyle.PM_DefaultFrameWidth] + self._pixel_metrics[QStyle.PM_ButtonMargin])
if option.features & QStyleOptionToolButton.MenuButtonPopup:
margin_size = QSize(margin+1, margin)
......@@ -450,7 +457,7 @@ class StateButtonStyle(QCommonStyle, ColorHelperMixin):
else:
blend.setColorAt(0.0, Qt.transparent) # or @0.5
blend.setColorAt(0.9, self.color_with_alpha(shadow_color, 0x10))
#blend.setColorAt(1-4.0/glow_rect.height(), self.color_with_alpha(shadow_color, 0x10)) # this is for exactly 4 pixels from bottom
# blend.setColorAt(1-4.0/glow_rect.height(), self.color_with_alpha(shadow_color, 0x10)) # this is for exactly 4 pixels from bottom
blend.setColorAt(1.0, self.color_with_alpha(shadow_color, 0x30)) # 0x25, 0x30 or 0x35
painter.setBrush(blend)
painter.drawRoundedRect(glow_rect, 5, 5) # 5 or 6
......@@ -685,6 +692,7 @@ class AccountState(StateButton):
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:]:
......@@ -698,6 +706,7 @@ class AccountState(StateButton):
action.state = state
action.note = note
menu.addAction(action)
history = property(_get_history, _set_history)
del _get_history, _set_history
......
__all__ = ['ColorScheme', 'ColorUtils', 'ColorHelperMixin']
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QColor
from application.python import limit
......@@ -8,8 +6,11 @@ from application.python.decorator import decorator, preserve_signature
from math import fmod, isnan
__all__ = ['ColorScheme', 'ColorUtils', 'ColorHelperMixin']
class HCYColor(object):
"""Hue/chroma/luma colorspace"""
"""Hue/chroma/luma color space"""
luma_r = 0.2126
luma_g = 0.7152
......@@ -202,9 +203,11 @@ class ColorUtils(object):
def color_key(instance, color):
return color.rgba()
def color_ratio_key(instance, color, ratio):
return color.rgba() << 32 | int(ratio*512)
def background_color_key(instance, background, color):
return background.rgba() << 32 | color.rgba()
......
__all__ = ['SlidingStackedWidget']
from PyQt4.QtCore import QEasingCurve, QParallelAnimationGroup, QPropertyAnimation, QPoint, pyqtSignal
from PyQt4.QtGui import QStackedWidget
from blink.widgets.util import QtDynamicProperty
__all__ = ['SlidingStackedWidget']
class SlidingStackedWidget(QStackedWidget):
animationEasingCurve = QtDynamicProperty('animationEasingCurve', int)
animationDuration = QtDynamicProperty('animationDuration', int)
......@@ -65,9 +66,9 @@ class SlidingStackedWidget(QStackedWidget):
next_widget.setGeometry(0, 0, width, height)
if direction in (self.TopToBottom, self.BottomToTop):
offset = QPoint(0, height if direction==self.TopToBottom else -height)
offset = QPoint(0, height if direction == self.TopToBottom else -height)
elif direction in (self.LeftToRight, self.RightToLeft):
offset = QPoint(width if direction==self.LeftToRight else -width, 0)
offset = QPoint(width if direction == self.LeftToRight else -width, 0)
# re-position the next widget outside of the display area
prev_widget_position = prev_widget.pos()
......@@ -101,7 +102,7 @@ class SlidingStackedWidget(QStackedWidget):
next_widget = next_widget_animation.targetObject()
self.setCurrentWidget(next_widget)
prev_widget.hide() # this may have been done already by QStackedWidget when changing the current widget above -Dan
prev_widget.move(prev_widget_animation.startValue()) # move the outshifted widget back to its original position
prev_widget.move(prev_widget_animation.startValue()) # move the out-shifted widget back to its original position
self._animation_group.clear()
self._active = False
self.animationFinished.emit()
......
__all__ = ['BackgroundFrame']
from PyQt4.QtCore import Qt, QEvent, QPoint, QRect, QSize
from PyQt4.QtGui import QColor, QFrame, QPainter, QPixmap
......@@ -8,6 +6,9 @@ from blink.resources import Resources
from blink.widgets.util import QtDynamicProperty
__all__ = ['BackgroundFrame']
class BackgroundFrame(QFrame):
backgroundColor = QtDynamicProperty('backgroundColor', unicode)
backgroundImage = QtDynamicProperty('backgroundImage', unicode)
......@@ -70,4 +71,3 @@ class BackgroundFrame(QFrame):
painter.drawPixmap(self.image_position, self.scaled_pixmap)
painter.end()
__all__ = ['Graph', 'GraphWidget', 'HeightScaler', 'LogarithmicScaler', 'MaxScaler', 'SoftScaler']
from PyQt4.QtCore import Qt, QLine, QPointF, QMetaObject, pyqtSignal
from PyQt4.QtGui import QColor, QLinearGradient, QPainterPath, QPen, QPolygonF, QStyle, QStyleOption, QStylePainter, QWidget
......@@ -14,6 +12,9 @@ from blink.widgets.color import ColorHelperMixin
from blink.widgets.util import QtDynamicProperty
__all__ = ['Graph', 'GraphWidget', 'HeightScaler', 'LogarithmicScaler', 'MaxScaler', 'SoftScaler']
class HeightScaler(object):
__metaclass__ = ABCMeta
......@@ -196,13 +197,13 @@ class GraphWidget(QWidget, ColorHelperMixin):
cx_offset = self.horizontalPixelsPerUnit / 3.0
smoothness = self.smoothFactor
last_values = deque(3*[dataset.next() * height_scaling], maxlen=3) # last 3 values: 0 last, 1 previous, 2 previous previous
last_values = deque(3*[next(dataset) * height_scaling], maxlen=3) # last 3 values: 0 last, 1 previous, 2 previous previous
envelope = QPainterPath()
envelope.moveTo(0, last_values[0])
for x, y in enumerate(dataset, 1):
x = x * self.horizontalPixelsPerUnit
y = y * height_scaling * (1 - smoothness) + last_values[0] * smoothness
x *= self.horizontalPixelsPerUnit
y *= height_scaling * (1 - smoothness) + last_values[0] * smoothness
last_values.appendleft(y)
c1x = x - cx_offset * 2
c2x = x - cx_offset
......@@ -236,7 +237,7 @@ class GraphWidget(QWidget, ColorHelperMixin):
painter.restore()
# queue the 'updated' signal to be emited after returning to the main loop
# queue the 'updated' signal to be emitted after returning to the main loop
QMetaObject.invokeMethod(self, 'updated', Qt.QueuedConnection)
def add_graph(self, graph):
......@@ -254,4 +255,3 @@ class GraphWidget(QWidget, ColorHelperMixin):
self.graphs = []
self.update()
__all__ = ['DurationLabel', 'IconSelector', 'LatencyLabel', 'PacketLossLabel', 'Status', 'StatusLabel', 'StreamInfoLabel', 'ElidedLabel', 'ContactState']
import os
from datetime import timedelta
......@@ -16,6 +14,9 @@ from blink.widgets.color import ColorHelperMixin
from blink.widgets.util import QtDynamicProperty, ContextMenuActions
__all__ = ['DurationLabel', 'IconSelector', 'LatencyLabel', 'PacketLossLabel', 'Status', 'StatusLabel', 'StreamInfoLabel', 'ElidedLabel', 'ContactState']
class IconSelector(QLabel):
default_icon = QtDynamicProperty('default_icon', QIcon)
icon_size = QtDynamicProperty('icon_size', int)
......@@ -283,6 +284,7 @@ class StateColor(QColor):
def stroke(self):
return self.darker(200)
class StateColorMapping(dict):
def __missing__(self, key):
if key == 'offline':
......@@ -294,7 +296,7 @@ class StateColorMapping(dict):
elif key == 'busy':
return self.setdefault(key, StateColor('#ff0000'))
else:
return StateColor(Qt.transparent) #StateColor('#d0d0d0')
return StateColor(Qt.transparent) # StateColor('#d0d0d0')
class ContactState(QLabel, ColorHelperMixin):
......@@ -323,4 +325,3 @@ class ContactState(QLabel, ColorHelperMixin):
painter.setPen(QPen(QBrush(gradient), 1))
painter.drawRoundedRect(-4, 0, self.width()+4, self.height(), 3.7, 3.7)
__all__ = ['LineEdit', 'ValidatingLineEdit', 'SearchBox', 'LocationBar']
import re
from PyQt4.QtCore import Qt, QEvent, pyqtSignal
......@@ -10,6 +8,9 @@ from blink.resources import Resources
from blink.widgets.util import QtDynamicProperty
__all__ = ['LineEdit', 'ValidatingLineEdit', 'SearchBox', 'LocationBar']
class SideWidget(QWidget):
sizeHintChanged = pyqtSignal()
......@@ -307,4 +308,3 @@ class LocationBar(LineEdit):
def _SH_TextChanged(self, text):
self.clear_button.setVisible(bool(text))
__all__ = ['QtDynamicProperty', 'ContextMenuActions']
from PyQt4.QtCore import QPyNullVariant
__all__ = ['QtDynamicProperty', 'ContextMenuActions']
class QtDynamicProperty(object):
def __init__(self, name, type=unicode):
self.name = name
self.type = type
def __get__(self, obj, objtype):
if obj is None:
def __get__(self, instance, owner):
if instance is None:
return self
value = obj.property(self.name)
value = instance.property(self.name)
if isinstance(value, QPyNullVariant):
value = self.type()
return value
def __set__(self, obj, value):
if value is not None and not isinstance(value, self.type):
value = self.type(value)
obj.setProperty(self.name, value)
def __delete__(self, obj):
raise AttributeError("attribute cannot be deleted")
......
from __future__ import division
__all__ = ['VideoSurface']
from PyQt4.QtCore import Qt, QMetaObject, QPoint, QRect, QTimer, pyqtSignal
from PyQt4.QtGui import QColor, QCursor, QIcon, QImage, QPainter, QPixmap, QTransform, QWidget
......@@ -16,7 +12,11 @@ from sipsimple.core import FrameBufferVideoRenderer
from blink.resources import Resources
class Container(object): pass
__all__ = ['VideoSurface']
class Container(object):
pass
class InteractionState(object):
......@@ -197,13 +197,13 @@ class VideoSurface(QWidget):
delta_x = -(self.width_for_height(geometry.height() - delta_y) - geometry.width())
geometry.setTopLeft(geometry.topLeft() + QPoint(delta_x, delta_y))
elif self._interaction.resize_corner is self.TopRightCorner:
delta_x = (self.width_for_height(geometry.height() - delta_y) - geometry.width())
delta_x = +(self.width_for_height(geometry.height() - delta_y) - geometry.width())
geometry.setTopRight(geometry.topRight() + QPoint(delta_x, delta_y))
elif self._interaction.resize_corner is self.BottomLeftCorner:
delta_x = -(self.width_for_height(geometry.height() + delta_y) - geometry.width())
geometry.setBottomLeft(geometry.bottomLeft() + QPoint(delta_x, delta_y))
else:
delta_x = (self.width_for_height(geometry.height() + delta_y) - geometry.width())
delta_x = +(self.width_for_height(geometry.height() + delta_y) - geometry.width())
geometry.setBottomRight(geometry.bottomRight() + QPoint(delta_x, delta_y))
if self.minimumHeight() <= geometry.height() <= self.maximumHeight() and (self.parent() is None or self.parent().rect().contains(geometry)):
......@@ -224,4 +224,3 @@ class VideoSurface(QWidget):
super(VideoSurface, self).closeEvent(event)
self.stop()
__all__ = ['ZRTPWidget']
from PyQt4 import uic
from PyQt4.QtCore import Qt, pyqtSignal
from PyQt4.QtGui import QStyle, QStyleOption, QStylePainter
......@@ -9,8 +6,12 @@ from PyQt4.QtGui import QStyle, QStyleOption, QStylePainter
from blink.resources import Resources
__all__ = ['ZRTPWidget']
ui_class, base_class = uic.loadUiType(Resources.get('zrtp_widget.ui'))
class ZRTPWidget(base_class, ui_class):
closed = pyqtSignal()
nameChanged = pyqtSignal()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment