Commit 67fbb869 authored by Dan Pascu's avatar Dan Pascu

Improved displaying the account states in preferences and the main window

parent 7f72b155
......@@ -12,7 +12,7 @@ from collections import defaultdict
from PyQt4 import uic
from PyQt4.QtCore import Qt, QAbstractListModel, QModelIndex, QUrl
from PyQt4.QtGui import QAction, QButtonGroup, QComboBox, QIcon, QMenu, QMovie, QPalette, QPixmap, QSortFilterProxyModel, QStyledItemDelegate
from PyQt4.QtGui import QAction, QButtonGroup, QComboBox, QIcon, QMenu, QMovie, QSortFilterProxyModel
from PyQt4.QtNetwork import QNetworkAccessManager
from PyQt4.QtWebKit import QWebView
......@@ -33,16 +33,43 @@ from blink.widgets.labels import Status
from blink.util import QSingleton, call_in_gui_thread, run_in_gui_thread
class IconDescriptor(object):
def __init__(self, filename):
self.filename = filename
self.icon = None
def __get__(self, obj, objtype):
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")
class AccountInfo(object):
def __init__(self, account, icon=None):
active_icon = IconDescriptor(Resources.get('icons/circle-dot.svg'))
inactive_icon = IconDescriptor(Resources.get('icons/circle-grey.svg'))
activity_icon = IconDescriptor(Resources.get('icons/circle-progress.svg'))
def __init__(self, account):
self.account = account
self.icon = icon
self.registration_state = None
@property
def name(self):
return u'Bonjour' if self.account is BonjourAccount() else unicode(self.account.id)
@property
def icon(self):
if self.registration_state == 'started':
return self.activity_icon
elif self.registration_state == 'succeeded':
return self.active_icon
else:
return self.inactive_icon
def __eq__(self, other):
if isinstance(other, basestring):
return self.name == other
......@@ -97,14 +124,8 @@ class AccountModel(QAbstractListModel):
def _NH_SIPAccountManagerDidAddAccount(self, notification):
account = notification.data.account
icon = None
if account is BonjourAccount():
pixmap = QPixmap()
if pixmap.load(Resources.get('icons/bonjour.png')):
pixmap = pixmap.scaled(16, 16, Qt.KeepAspectRatio, Qt.SmoothTransformation)
icon = QIcon(pixmap)
self.beginInsertRows(QModelIndex(), len(self.accounts), len(self.accounts))
self.accounts.append(AccountInfo(account, icon))
self.accounts.append(AccountInfo(account))
self.endInsertRows()
def _NH_CFGSettingsObjectDidChange(self, notification):
......@@ -169,60 +190,16 @@ class ActiveAccountModel(QSortFilterProxyModel):
return account_info.account.enabled
class AccountStatePalettes(dict):
def __init__(self, palette):
super(AccountStatePalettes, self).__init__(succeeded=palette)
self.alternate_palette = QPalette(palette)
self.alternate_palette.setColor(QPalette.Text, self.alternate_palette.color(QPalette.Mid))
self.alternate_palette.setColor(QPalette.ButtonText, self.alternate_palette.color(QPalette.Mid))
self.alternate_palette.setColor(QPalette.WindowText, self.alternate_palette.color(QPalette.Mid))
def __missing__(self, key):
return self.setdefault(key, self.alternate_palette)
class AccountDelegate(QStyledItemDelegate):
def __init__(self, parent):
super(AccountDelegate, self).__init__(parent)
self.state_palette_map = AccountStatePalettes(parent.palette())
def paint(self, painter, option, index):
account_info = index.data(Qt.UserRole)
option.palette = self.state_palette_map[account_info.registration_state]
super(AccountDelegate, self).paint(painter, option, index)
class AccountSelector(QComboBox):
implements(IObserver)
def __init__(self, parent=None):
super(AccountSelector, self).__init__(parent)
self.state_palette_map = AccountStatePalettes(self.palette())
self.setItemDelegate(AccountDelegate(self.view()))
self.currentIndexChanged[int].connect(self._SH_SelectionChanged)
self.model().dataChanged.connect(self._SH_DataChanged)
notification_center = NotificationCenter()
notification_center.add_observer(self, name="SIPAccountManagerDidChangeDefaultAccount")
notification_center.add_observer(self, name="SIPAccountManagerDidStart")
def setModel(self, model):
self.model().dataChanged.disconnect(self._SH_DataChanged)
model.dataChanged.connect(self._SH_DataChanged)
super(AccountSelector, self).setModel(model)
def _SH_DataChanged(self, topLeft, bottomRight):
index = self.currentIndex()
if topLeft.row() <= index <= bottomRight.row():
account_info = self.itemData(index)
self.setPalette(self.state_palette_map[account_info.registration_state])
def _SH_SelectionChanged(self, index):
if index == -1:
return
account_info = self.itemData(index)
self.setPalette(self.state_palette_map[account_info.registration_state])
@run_in_gui_thread
def handle_notification(self, notification):
handler = getattr(self, '_NH_%s' % notification.name, Null)
......
......@@ -8,7 +8,7 @@ import urlparse
from PyQt4 import uic
from PyQt4.QtCore import Qt, QRegExp
from PyQt4.QtGui import QActionGroup, QButtonGroup, QFileDialog, QFont, QListView, QListWidgetItem, QMessageBox, QRegExpValidator, QSpinBox, QStyle, QStyleOptionComboBox, QValidator
from PyQt4.QtGui import QActionGroup, QButtonGroup, QFileDialog, QFont, QListView, QListWidgetItem, QMessageBox, QRegExpValidator, QSpinBox, QStyle, QStyleOptionComboBox, QStyledItemDelegate, QValidator
from application import log
from application.notification import IObserver, NotificationCenter
......@@ -129,10 +129,18 @@ class SIPPortEditor(QSpinBox):
return state, input, pos
class AccountDelegate(QStyledItemDelegate):
def paint(self, painter, option, index):
account_info = index.data(Qt.UserRole)
if not account_info.account.enabled:
option.state &= ~QStyle.State_Enabled
super(AccountDelegate, self).paint(painter, option, index)
class AccountListView(QListView):
def __init__(self, parent=None):
super(AccountListView, self).__init__(parent)
#self.setItemDelegate(AccountDelegate(self))
self.setItemDelegate(AccountDelegate(self))
#self.setDropIndicatorShown(False)
def selectionChanged(self, selected, deselected):
......
......@@ -45,12 +45,26 @@
<property name="maximumSize">
<size>
<width>16777215</width>
<height>20</height>
<height>21</height>
</size>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="toolTip">
<string>Select the SIP account used for outbound calls</string>
</property>
<property name="maxVisibleItems">
<number>20</number>
</property>
<property name="iconSize">
<size>
<width>14</width>
<height>14</height>
</size>
</property>
</widget>
</item>
<item>
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="12"
height="12"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="circle-dot.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="69.166667"
inkscape:cx="6"
inkscape:cy="6"
inkscape:document-units="px"
inkscape:current-layer="g3931"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1373"
inkscape:window-height="1040"
inkscape:window-x="211"
inkscape:window-y="4"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid2985"
empspacing="10"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
spacingx="0.5px"
spacingy="0.5px" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
style="display:inline"
inkscape:label="Circle dot"
inkscape:groupmode="layer"
id="g3931"
transform="translate(0,-1040.3622)">
<path
transform="matrix(1.268496,0,0,1.268496,1.560264,1043.191)"
d="M 6.9686747,2.5 C 6.9686747,4.4156961 5.4156961,5.9686747 3.5,5.9686747 1.5843039,5.9686747 0.03132534,4.4156961 0.03132534,2.5 c 0,-1.91569612 1.55297856,-3.46867466 3.46867466,-3.46867466 1.9156961,0 3.4686747,1.55297854 3.4686747,3.46867466 z"
sodipodi:ry="3.4686747"
sodipodi:rx="3.4686747"
sodipodi:cy="2.5"
sodipodi:cx="3.5"
id="path3933"
style="fill:none;stroke:#272727;stroke-width:0.94600224;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6"
sodipodi:type="arc" />
<path
sodipodi:type="arc"
style="fill:#272727;fill-opacity:1;stroke:#272727;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6"
id="path3935"
sodipodi:cx="4.5"
sodipodi:cy="4.5"
sodipodi:rx="0.5"
sodipodi:ry="0.5"
d="M 5,4.5 C 5,4.7761424 4.7761424,5 4.5,5 4.2238576,5 4,4.7761424 4,4.5 4,4.2238576 4.2238576,4 4.5,4 4.7761424,4 5,4.2238576 5,4.5 z"
transform="matrix(2,0,0,2,-3,1037.3622)" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="12"
height="12"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="circle-grey.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="69.166667"
inkscape:cx="6"
inkscape:cy="6"
inkscape:document-units="px"
inkscape:current-layer="g4210"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1373"
inkscape:window-height="1040"
inkscape:window-x="211"
inkscape:window-y="4"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid2985"
empspacing="10"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
spacingx="0.5px"
spacingy="0.5px" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
style="display:inline"
inkscape:label="Circle grey"
inkscape:groupmode="layer"
id="g4210"
transform="translate(0,-1040.3622)">
<path
transform="matrix(1.268496,0,0,1.268496,1.560264,1043.191)"
d="m 6.9686747,2.5 a 3.4686747,3.4686747 0 1 1 -6.93734936,0 3.4686747,3.4686747 0 1 1 6.93734936,0 z"
sodipodi:ry="3.4686747"
sodipodi:rx="3.4686747"
sodipodi:cy="2.5"
sodipodi:cx="3.5"
id="path4212"
style="fill:none;stroke:#909090;stroke-width:0.94600224;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6"
sodipodi:type="arc" />
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="12"
height="12"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="circle-progress.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="69.166667"
inkscape:cx="6"
inkscape:cy="6"
inkscape:document-units="px"
inkscape:current-layer="g4117"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1373"
inkscape:window-height="1040"
inkscape:window-x="211"
inkscape:window-y="4"
inkscape:window-maximized="0">
<inkscape:grid
type="xygrid"
id="grid2985"
empspacing="10"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true"
spacingx="0.5px"
spacingy="0.5px" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-1040.3622)"
id="g4117"
inkscape:groupmode="layer"
inkscape:label="Circle progress"
style="display:inline">
<path
sodipodi:type="arc"
style="fill:none;stroke:#272727;stroke-width:0.94600224;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.6"
id="path4119"
sodipodi:cx="3.5"
sodipodi:cy="2.5"
sodipodi:rx="3.4686747"
sodipodi:ry="3.4686747"
d="m 6.9686747,2.5 a 3.4686747,3.4686747 0 1 1 -6.93734936,0 3.4686747,3.4686747 0 1 1 6.93734936,0 z"
transform="matrix(1.268496,0,0,1.268496,1.560264,1043.191)" />
<path
sodipodi:type="arc"
style="fill:#272727;fill-opacity:1;stroke:none;display:inline"
id="path4119-4"
sodipodi:cx="3.5"
sodipodi:cy="2.5"
sodipodi:rx="3.4686747"
sodipodi:ry="3.4686747"
d="M 3.5000001,-0.96867466 A 3.4686747,3.4686747 0 0 1 5.9527233,4.9527234 L 3.5,2.5 z"
transform="matrix(1.268496,0,0,1.268496,1.560264,1043.191)"
sodipodi:start="4.712389"
sodipodi:end="7.0685835" />
</g>
</svg>
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