Commit 8fd67017 authored by Dan Pascu's avatar Dan Pascu

Added contacts editing panel

parent 4147aca4
......@@ -3,16 +3,16 @@
from __future__ import with_statement
__all__ = ['BonjourGroup', 'BonjourNeighbour', 'Contact', 'ContactGroup', 'ContactModel', 'ContactSearchModel', 'ContactListView', 'ContactSearchListView']
__all__ = ['BonjourGroup', 'BonjourNeighbour', 'Contact', 'ContactGroup', 'ContactModel', 'ContactSearchModel', 'ContactListView', 'ContactSearchListView', 'ContactEditorDialog']
import cPickle as pickle
import errno
import os
from PyQt4 import uic
from PyQt4.QtCore import Qt, QAbstractListModel, QByteArray, QEvent, QMimeData, QModelIndex, QPointF, QRectF, QSize, QStringList, QTimer
from PyQt4.QtCore import Qt, QAbstractListModel, QByteArray, QEvent, QMimeData, QModelIndex, QPointF, QRectF, QRegExp, QSize, QStringList, QTimer, pyqtSignal
from PyQt4.QtGui import QBrush, QColor, QLinearGradient, QPainter, QPainterPath, QPalette, QPen, QPixmap, QPolygonF, QStyle
from PyQt4.QtGui import QAction, QKeyEvent, QListView, QMenu, QMouseEvent, QSortFilterProxyModel, QStyledItemDelegate
from PyQt4.QtGui import QAction, QKeyEvent, QListView, QMenu, QMouseEvent, QRegExpValidator, QSortFilterProxyModel, QStyledItemDelegate
from application.notification import IObserver, NotificationCenter
from application.python.decorator import decorator, preserve_signature
......@@ -155,7 +155,7 @@ class Contact(object):
self.name = name
self.uri = uri
self.image = image
self.icon = self.default_user_icon if image is None else ContactIconDescriptor(image).__get__(self, self.__class__)
self.preferred_media = 'Audio'
self.status = 'unknown'
def __repr__(self):
......@@ -165,7 +165,21 @@ class Contact(object):
return u'%s <%s>' % (self.name, self.uri) if self.name else self.uri
def __reduce__(self):
return (self.__class__, (self.group, self.name, self.uri, self.image), None)
return (self.__class__, (self.group, self.name, self.uri, self.image), dict(preferred_media=self.preferred_media))
def _get_image(self):
return self.__dict__['image']
def _set_image(self, image):
self.__dict__['image'] = image
self.__dict__['icon'] = self.default_user_icon if image is None else ContactIconDescriptor(image).__get__(self, self.__class__)
image = property(_get_image, _set_image)
del _get_image, _set_image
@property
def icon(self):
return self.__dict__['icon']
class NoGroup(object):
......@@ -198,7 +212,7 @@ class ContactWidget(base_class, ui_class):
self.setupUi(self)
def set_contact(self, contact):
self.name.setText(contact.name)
self.name.setText(contact.name or contact.uri)
self.uri.setText(contact.uri)
self.icon.setPixmap(contact.icon)
......@@ -454,6 +468,9 @@ class ContactDelegate(QStyledItemDelegate):
class ContactModel(QAbstractListModel):
implements(IObserver)
itemsAdded = pyqtSignal(list)
itemsRemoved = pyqtSignal(list)
# The MIME types we accept in drop operations, in the order they should be handled
accepted_mime_types = ['application/x-blink-contact-group-list', 'application/x-blink-contact-list', 'text/uri-list']
......@@ -461,6 +478,7 @@ class ContactModel(QAbstractListModel):
super(ContactModel, self).__init__(parent)
self.items = []
self.deleted_items = []
self.main_window = parent
self.contact_list = parent.contact_list
if not hasattr(self, 'beginResetModel'):
# emulate beginResetModel/endResetModel for QT < 4.6
......@@ -555,7 +573,7 @@ class ContactModel(QAbstractListModel):
else:
drop_group = group
drop_position = drop_indicator
items = self.popItems(selected_indexes)
items = self._pop_items(selected_indexes)
contact_groups = self.contact_groups # they changed so refresh them
if drop_position is self.contact_list.AboveItem:
position = self.items.index(drop_group)
......@@ -579,9 +597,9 @@ class ContactModel(QAbstractListModel):
if group.widget.drop_indicator is None:
return False
indexes = [index for index in self.contact_list.selectionModel().selectedIndexes() if self.items[index.row()].movable]
for contact in self.popItems(indexes):
for contact in self._pop_items(indexes):
contact.group = group
self.addContact(contact)
self._add_contact(contact)
return True
def _DH_TextUriList(self, mime_data, action, index):
......@@ -617,8 +635,7 @@ class ContactModel(QAbstractListModel):
if indexes:
yield (last, end)
@updates_contacts_db
def addContact(self, contact):
def _add_contact(self, contact):
if contact.group in self.items:
for position in xrange(self.items.index(contact.group)+1, len(self.items)):
item = self.items[position]
......@@ -638,41 +655,96 @@ class ContactModel(QAbstractListModel):
self.contact_list.openPersistentEditor(self.index(position))
self.endInsertRows()
@updates_contacts_db
def removeContact(self, contact):
if contact not in self.items:
return
def _add_group(self, group):
position = len(self.items)
self.beginInsertRows(QModelIndex(), position, position)
self.items.append(group)
self.contact_list.openPersistentEditor(self.index(position))
self.endInsertRows()
def _pop_contact(self, contact):
position = self.items.index(contact)
self.beginRemoveRows(QModelIndex(), position, position)
del self.items[position]
self.endRemoveRows()
return contact
def _pop_group(self, group):
start = self.items.index(group)
end = start + len([item for item in self.items if isinstance(item, Contact) and item.group==group])
self.beginRemoveRows(QModelIndex(), start, end)
items = self.items[start:end+1]
del self.items[start:end+1]
self.endRemoveRows()
return items
def _pop_items(self, indexes):
items = []
rows = set(index.row() for index in indexes if index.isValid())
removed_groups = set(self.items[row] for row in rows if isinstance(self.items[row], ContactGroup))
rows.update(row for row, item in enumerate(self.items) if isinstance(item, Contact) and item.group in removed_groups)
for start, end in self.reversed_range_iterator(rows):
self.beginRemoveRows(QModelIndex(), start, end)
items[0:0] = self.items[start:end+1]
del self.items[start:end+1]
self.endRemoveRows()
return items
@updates_contacts_db
def addContact(self, contact):
if contact in self.items:
return
added_items = [contact.group, contact] if contact.group in self.items else [contact]
self._add_contact(contact)
self.itemsAdded.emit(added_items)
@updates_contacts_db
def updateContact(self, contact, attributes):
group = attributes.pop('group')
for name, value in attributes.iteritems():
setattr(contact, name, value)
if contact.group != group:
new_group = group not in self.items
self._pop_contact(contact)
contact.group = group
self._add_contact(contact)
if new_group:
self.itemsAdded.emit([group])
else:
index = self.index(self.items.index(contact))
self.dataChanged.emit(index, index)
@updates_contacts_db
def removeContact(self, contact):
if contact not in self.items:
return
self._pop_contact(contact)
if type(contact) is Contact:
self.deleted_items.append([contact])
self.itemsRemoved.emit([contact])
@updates_contacts_db
def addGroup(self, group):
if group in self.items:
return
position = len(self.items)
self.beginInsertRows(QModelIndex(), position, position)
self.items.append(group)
self.contact_list.openPersistentEditor(self.index(position))
self.endInsertRows()
self._add_group(group)
self.itemsAdded.emit([group])
@updates_contacts_db
def removeGroup(self, group):
if group not in self.items:
return
start = self.items.index(group)
end = start + len([item for item in self.items if isinstance(item, Contact) and item.group==group])
self.beginRemoveRows(QModelIndex(), start, end)
del self.items[start:end+1]
self.endRemoveRows()
items = self._pop_group(group)
if type(group) is ContactGroup:
self.deleted_items.append(items)
self.itemsRemoved.emit(items)
@updates_contacts_db
def moveGroup(self, group, reference):
contact_groups = self.contact_groups
if group not in contact_groups or contact_groups.index(group)+1 == (contact_groups.index(reference) if reference in contact_groups else len(contact_groups)):
return
items = self.popItems([self.index(self.items.index(group))])
items = self._pop_group(group)
start = self.items.index(reference) if reference in contact_groups else len(self.items)
end = start + len(items) - 1
self.beginInsertRows(QModelIndex(), start, end)
......@@ -682,30 +754,11 @@ class ContactModel(QAbstractListModel):
@updates_contacts_db
def removeItems(self, indexes):
rows = set(index.row() for index in indexes if index.isValid())
removed_groups = set(self.items[row] for row in rows if isinstance(self.items[row], ContactGroup))
rows.update(row for row, item in enumerate(self.items) if isinstance(item, Contact) and item.group in removed_groups)
for start, end in self.reversed_range_iterator(rows):
self.beginRemoveRows(QModelIndex(), start, end)
deleted_items = self.items[start:end+1]
for item in (item for item in deleted_items if isinstance(item, ContactGroup)):
items = self._pop_items(indexes)
for item in (item for item in items if isinstance(item, ContactGroup)):
item.widget = Null
self.deleted_items.append(deleted_items)
del self.items[start:end+1]
self.endRemoveRows()
@updates_contacts_db
def popItems(self, indexes):
items = []
rows = set(index.row() for index in indexes if index.isValid())
removed_groups = set(self.items[row] for row in rows if isinstance(self.items[row], ContactGroup))
rows.update(row for row, item in enumerate(self.items) if isinstance(item, Contact) and item.group in removed_groups)
for start, end in self.reversed_range_iterator(rows):
self.beginRemoveRows(QModelIndex(), start, end)
items[0:0] = self.items[start:end+1]
del self.items[start:end+1]
self.endRemoveRows()
return items
self.deleted_items.append(items)
self.itemsRemoved.emit(items)
def load(self):
try:
......@@ -785,7 +838,7 @@ class ContactModel(QAbstractListModel):
@ignore_contacts_db_updates
def _NH_BonjourAccountDidRemoveNeighbour(self, notification):
for contact in (c for c in self.items[:] if type(c) is BonjourNeighbour):
for contact in [c for c in self.items if type(c) is BonjourNeighbour]:
if contact.uri == unicode(notification.data.uri):
self.removeContact(contact)
......@@ -801,7 +854,7 @@ class ContactModel(QAbstractListModel):
@ignore_contacts_db_updates
def _NH_SIPAccountManagerDidStart(self, notification):
if not BonjourAccount().enabled and self.bonjour_group in self.contact_groups:
if not BonjourAccount().enabled and self.bonjour_group in self.items:
self.removeGroup(self.bonjour_group)
if notification.sender.default_account is BonjourAccount():
group = self.bonjour_group
......@@ -845,6 +898,7 @@ class ContactSearchModel(QSortFilterProxyModel):
def __init__(self, model, parent=None):
super(ContactSearchModel, self).__init__(parent)
self.main_window = parent
self.setSourceModel(model)
self.setDynamicSortFilter(True)
self.sort(0)
......@@ -1112,22 +1166,27 @@ class ContactListView(QListView):
def _AH_AddContact(self):
model = self.model()
selected_rows = sorted(index.row() for index in self.selectionModel().selectedIndexes() if type(model.data(index)) in (Contact, ContactGroup))
if selected_rows:
item = model.items[selected_rows[0]]
main_window = model.main_window
selected_items = ((index.row(), model.data(index)) for index in self.selectionModel().selectedIndexes())
try:
item = (item for row, item in sorted(selected_items) if type(item) in (Contact, ContactGroup)).next()
preferred_group = item if type(item) is ContactGroup else item.group
else:
except StopIteration:
try:
preferred_group = (group for group in model.contact_groups if type(group) is ContactGroup).next()
except StopIteration:
preferred_group = None
main_window.contact_editor.open_for_add(main_window.search_box.text(), preferred_group)
def _AH_EditItem(self):
model = self.model()
index = self.selectionModel().selectedIndexes()[0]
item = self.model().data(index)
item = model.data(index)
if isinstance(item, ContactGroup):
self.scrollTo(index)
item.widget.edit()
else:
model.main_window.contact_editor.open_for_edit(item)
def _AH_DeleteSelection(self):
model = self.model()
......@@ -1330,7 +1389,9 @@ class ContactSearchListView(QListView):
self.drop_indicator_index = QModelIndex()
def _AH_EditItem(self):
contact = self.model().data(self.selectionModel().selectedIndexes()[0])
model = self.model()
contact = model.data(self.selectionModel().selectedIndexes()[0])
model.main_window.contact_editor.open_for_edit(contact)
def _AH_DeleteSelection(self):
model = self.model()
......@@ -1372,3 +1433,105 @@ class ContactSearchListView(QListView):
event.ignore(rect)
# The contact editor dialog
#
class ContactEditorGroupModel(QSortFilterProxyModel):
def __init__(self, contact_model, parent=None):
super(ContactEditorGroupModel, self).__init__(parent)
self.setSourceModel(contact_model)
def data(self, index, role=Qt.DisplayRole):
if role in (Qt.DisplayRole, Qt.EditRole):
return super(ContactEditorGroupModel, self).data(index, Qt.DisplayRole).toPyObject().name
elif role == Qt.UserRole:
return super(ContactEditorGroupModel, self).data(index, Qt.DisplayRole).toPyObject()
else:
return super(ContactEditorGroupModel, self).data(index, role)
def filterAcceptsRow(self, source_row, source_parent):
source_model = self.sourceModel()
item = source_model.data(source_model.index(source_row, 0, source_parent), Qt.DisplayRole)
return True if type(item) is ContactGroup else False
ui_class, base_class = uic.loadUiType(Resources.get('contact_editor.ui'))
class ContactEditorDialog(base_class, ui_class):
def __init__(self, contact_model, parent=None):
super(ContactEditorDialog, self).__init__(parent)
with Resources.directory:
self.setupUi(self)
self.edited_contact = None
self.group.setModel(ContactEditorGroupModel(contact_model, parent))
self.sip_address_editor.setValidator(QRegExpValidator(QRegExp("\S+"), self))
self.sip_address_editor.textChanged.connect(self.enable_accept_button)
self.clear_button.clicked.connect(self.reset_icon)
self.accepted.connect(self.process_contact)
def open_for_add(self, sip_address=u'', target_group=None):
self.sip_address_editor.setText(sip_address)
self.display_name_editor.setText(u'')
for index in xrange(self.group.count()):
if self.group.itemData(index).toPyObject() is target_group:
break
else:
index = 0
self.group.setCurrentIndex(index)
self.icon_selector.filename = None
self.preferred_media.setCurrentIndex(0)
self.accept_button.setText(u'Add')
self.accept_button.setEnabled(sip_address != u'')
self.open()
def open_for_edit(self, contact):
self.edited_contact = contact
self.sip_address_editor.setText(contact.uri)
self.display_name_editor.setText(contact.name)
for index in xrange(self.group.count()):
if self.group.itemData(index).toPyObject() is contact.group:
break
else:
index = 0
self.group.setCurrentIndex(index)
self.icon_selector.filename = contact.image
self.preferred_media.setCurrentIndex(self.preferred_media.findText(contact.preferred_media))
self.accept_button.setText(u'Ok')
self.accept_button.setEnabled(True)
self.open()
def reset_icon(self):
self.icon_selector.filename = None
def enable_accept_button(self, text):
self.accept_button.setEnabled(text != u'')
@updates_contacts_db
def process_contact(self):
contact_model = self.parent().contact_model
uri = unicode(self.sip_address_editor.text())
name = unicode(self.display_name_editor.text())
image = IconCache().store(self.icon_selector.filename)
preferred_media = unicode(self.preferred_media.currentText())
group_index = self.group.currentIndex()
group_name = self.group.currentText()
if group_name != self.group.itemText(group_index):
# user edited the group name. first look if we already have a group with that name
index = self.group.findText(group_name)
if index >= 0:
group = self.group.itemData(index).toPyObject()
else:
group = ContactGroup(unicode(group_name))
else:
group = self.group.itemData(group_index).toPyObject()
if self.edited_contact is None:
contact = Contact(group, name, uri, image)
contact_model.addContact(contact)
else:
attributes = dict(group=group, name=name, uri=uri, image=image, preferred_media=preferred_media)
contact_model.updateContact(self.edited_contact, attributes)
self.edited_contact = None
del ui_class, base_class
......@@ -15,7 +15,7 @@ from zope.interface import implements
from sipsimple.account import AccountManager, BonjourAccount
from blink.contacts import Contact, ContactModel, ContactSearchModel
from blink.contacts import Contact, ContactGroup, ContactEditorDialog, ContactModel, ContactSearchModel
from blink.resources import Resources
from blink.util import run_in_gui_thread
......@@ -47,6 +47,8 @@ class MainWindow(base_class, ui_class):
self.contact_model.load()
self.contact_editor = ContactEditorDialog(self.contact_model, self)
self.contacts_panel.sibling_panel = self.sessions_panel
self.contacts_panel.sibling_name = u'Sessions'
self.sessions_panel.sibling_panel = self.contacts_panel
......@@ -56,12 +58,16 @@ class MainWindow(base_class, ui_class):
self.contacts_view.setCurrentWidget(self.contact_list_panel)
self.search_view.setCurrentWidget(self.search_list_panel)
self.switch_view.clicked.connect(self.switch_main_view)
self.switch_view_button.clicked.connect(self.switch_main_view)
self.search_box.textChanged.connect(self.search_box_text_changed)
self.contact_model.itemsAdded.connect(self.contact_model_added_items)
self.contact_model.itemsRemoved.connect(self.contact_model_removed_items)
self.back_to_contacts_button.clicked.connect(self.search_box.clear) # this can be set in designer -Dan
self.back_to_contacts.clicked.connect(self.search_box.clear) # this can be set in designer -Dan
self.add_contact.clicked.connect(self.test_add_contact)
self.add_contact_button.clicked.connect(self.add_contact)
self.add_search_contact_button.clicked.connect(self.add_contact)
self.identity.activated[int].connect(self.set_identity)
......@@ -73,6 +79,19 @@ class MainWindow(base_class, ui_class):
notification_center.add_observer(self, name="SIPAccountDidActivate")
notification_center.add_observer(self, name="SIPAccountDidDeactivate")
def add_contact(self, clicked):
model = self.contact_model
selected_items = ((index.row(), model.data(index)) for index in self.contact_list.selectionModel().selectedIndexes())
try:
item = (item for row, item in sorted(selected_items) if type(item) in (Contact, ContactGroup)).next()
preferred_group = item if type(item) is ContactGroup else item.group
except StopIteration:
try:
preferred_group = (group for group in model.contact_groups if type(group) is ContactGroup).next()
except StopIteration:
preferred_group = None
self.contact_editor.open_for_add(self.search_box.text(), preferred_group)
def set_user_icon(self, image_file_name):
pixmap = QPixmap(32, 32)
pixmap.fill(QColor(Qt.transparent))
......@@ -91,9 +110,9 @@ class MainWindow(base_class, ui_class):
self.image.setPixmap(pixmap)
def enable_call_buttons(self, enabled):
self.audio_call.setEnabled(enabled)
self.im_session.setEnabled(enabled)
self.ds_session.setEnabled(enabled)
self.audio_call_button.setEnabled(enabled)
self.im_session_button.setEnabled(enabled)
self.ds_session_button.setEnabled(enabled)
def set_identity(self, index):
account_manager = AccountManager()
......@@ -102,7 +121,7 @@ class MainWindow(base_class, ui_class):
def search_box_text_changed(self, text):
if text:
self.main_view.setCurrentWidget(self.contacts_panel)
self.switch_view.setText(u"Sessions")
self.switch_view_button.setText(u"Sessions")
self.enable_call_buttons(True)
else:
selected_items = self.contact_list.selectionModel().selectedIndexes()
......@@ -113,6 +132,21 @@ class MainWindow(base_class, ui_class):
active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel
self.search_view.setCurrentWidget(active_widget)
def contact_model_added_items(self, items):
if self.search_box.text().isEmpty():
return
active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel
self.search_view.setCurrentWidget(active_widget)
def contact_model_removed_items(self, items):
if self.search_box.text().isEmpty():
return
if any(type(item) is Contact for item in items) and self.contact_search_model.rowCount() == 0:
self.search_box.clear()
else:
active_widget = self.search_list_panel if self.contact_search_model.rowCount() else self.not_found_panel
self.search_view.setCurrentWidget(active_widget)
def contact_list_selection_changed(self, selected, deselected):
selected_items = self.contact_list.selectionModel().selectedIndexes()
self.enable_call_buttons(len(selected_items)==1 and type(self.contact_model.data(selected_items[0])) is Contact)
......@@ -120,19 +154,7 @@ class MainWindow(base_class, ui_class):
def switch_main_view(self):
widget = self.main_view.currentWidget().sibling_panel
self.main_view.setCurrentWidget(widget)
self.switch_view.setText(widget.sibling_name)
def test_add_contact(self):
from blink.contacts import Contact, ContactGroup
import random
no = random.randrange(1, 100)
try:
test_group = (group for group in self.contact_model.contact_groups if group.name=='Test').next()
except StopIteration:
test_group = ContactGroup('Test')
contact = Contact(test_group, 'John Doe %02d' % no, 'user%02d@test.com' % no)
contact.status = random.choice(('online', 'away', 'busy', 'offline'))
self.contact_model.addContact(contact)
self.switch_view_button.setText(widget.sibling_name)
@run_in_gui_thread
def handle_notification(self, notification):
......
# Copyright (c) 2010 AG Projects. See LICENSE for details.
#
import os
from PyQt4.QtCore import Qt
from PyQt4.QtGui import QFileDialog, QLabel, QPixmap
from blink.resources import ApplicationData, Resources
from blink.widgets.util import QtDynamicProperty
class IconSelector(QLabel):
default_icon = QtDynamicProperty('default_icon', unicode)
def __init__(self, parent=None):
super(QLabel, self).__init__(parent)
self.setMinimumSize(36, 36)
self.filename = None
self.default_icon = None
self.last_icon_directory = os.path.expanduser('~')
def _get_filename(self):
return self.__dict__['filename']
def _set_filename(self, filename):
self.__dict__['filename'] = filename
filename = ApplicationData.get(filename) if filename else Resources.get(self.default_icon)
pixmap = QPixmap()
if pixmap.load(filename):
self.setPixmap(pixmap.scaled(32, 32, Qt.KeepAspectRatio, Qt.SmoothTransformation))
else:
self.setPixmap(pixmap)
filename = property(_get_filename, _set_filename)
del _get_filename, _set_filename
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton and self.rect().contains(event.pos()):
filename = unicode(QFileDialog.getOpenFileName(self, u'Select Icon', self.last_icon_directory, u"Images (*.png *.tiff *.jpg *.xmp *.svg)"))
if filename:
self.last_icon_directory = os.path.dirname(filename)
self.filename = filename if os.path.realpath(filename) != os.path.realpath(Resources.get(self.default_icon)) else None
super(IconSelector, self).mouseReleaseEvent(event)
......@@ -230,7 +230,7 @@
</layout>
</item>
<item>
<widget class="QPushButton" name="switch_view">
<widget class="QPushButton" name="switch_view_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
......@@ -345,7 +345,7 @@
<number>3</number>
</property>
<item>
<widget class="QPushButton" name="back_to_contacts">
<widget class="QPushButton" name="back_to_contacts_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
......@@ -367,7 +367,7 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="add_search_contact">
<widget class="QPushButton" name="add_search_contact_button">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
......@@ -486,7 +486,7 @@ buttons below.</string>
<number>3</number>
</property>
<item>
<widget class="QToolButton" name="add_contact">
<widget class="QToolButton" name="add_contact_button">
<property name="minimumSize">
<size>
<width>29</width>
......@@ -533,7 +533,7 @@ buttons below.</string>
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="audio_call">
<widget class="QToolButton" name="audio_call_button">
<property name="minimumSize">
<size>
<width>29</width>
......@@ -559,7 +559,7 @@ buttons below.</string>
</widget>
</item>
<item>
<widget class="QToolButton" name="im_session">
<widget class="QToolButton" name="im_session_button">
<property name="minimumSize">
<size>
<width>29</width>
......@@ -584,7 +584,7 @@ buttons below.</string>
</widget>
</item>
<item>
<widget class="QToolButton" name="ds_session">
<widget class="QToolButton" name="ds_session_button">
<property name="minimumSize">
<size>
<width>29</width>
......@@ -625,7 +625,7 @@ buttons below.</string>
</spacer>
</item>
<item>
<widget class="QToolButton" name="silent">
<widget class="QToolButton" name="silent_button">
<property name="minimumSize">
<size>
<width>29</width>
......@@ -690,7 +690,7 @@ buttons below.</string>
<number>3</number>
</property>
<item>
<widget class="QPushButton" name="hangup_all">
<widget class="QPushButton" name="hangup_all_button">
<property name="minimumSize">
<size>
<width>0</width>
......@@ -712,7 +712,7 @@ buttons below.</string>
</widget>
</item>
<item>
<widget class="QPushButton" name="conference">
<widget class="QPushButton" name="conference_button">
<property name="minimumSize">
<size>
<width>0</width>
......@@ -747,7 +747,7 @@ buttons below.</string>
</spacer>
</item>
<item>
<widget class="QToolButton" name="mute">
<widget class="QToolButton" name="mute_button">
<property name="minimumSize">
<size>
<width>29</width>
......
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ContactEditor</class>
<widget class="QDialog" name="ContactEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>435</width>
<height>325</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>435</width>
<height>325</height>
</size>
</property>
<property name="windowTitle">
<string>Contact Editor</string>
</property>
<layout class="QGridLayout" name="grid_layout">
<property name="leftMargin">
<number>10</number>
</property>
<property name="topMargin">
<number>15</number>
</property>
<property name="rightMargin">
<number>10</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="sip_address_label">
<property name="text">
<string>SIP Address:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="LineEdit" name="sip_address_editor">
<property name="inactiveText" stdset="0">
<string>user@domain</string>
</property>
<property name="widgetSpacing" stdset="0">
<number>0</number>
</property>
</widget>
</item>
<item row="0" column="2" rowspan="3">
<layout class="QVBoxLayout" name="icon_layout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>5</number>
</property>
<property name="rightMargin">
<number>5</number>
</property>
<item>
<widget class="IconSelector" name="icon_selector">
<property name="minimumSize">
<size>
<width>60</width>
<height>60</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>60</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap>icons/default-avatar.png</pixmap>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="default_icon" stdset="0">
<string>icons/default-avatar.png</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clear_button">
<property name="maximumSize">
<size>
<width>60</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="display_name_label">
<property name="text">
<string>Display Name:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="LineEdit" name="display_name_editor">
<property name="inactiveText" stdset="0">
<string>Contact Name</string>
</property>
<property name="widgetSpacing" stdset="0">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="group_label">
<property name="text">
<string>Group:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="group">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::NoInsert</enum>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<spacer name="section_spacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>412</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QLabel" name="chat_aliases_label">
<property name="text">
<string>SIP Aliases:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="1" colspan="2">
<widget class="LineEdit" name="chat_aliases_editor">
<property name="inactiveText" stdset="0">
<string>List of SIP addresses separated by ;</string>
</property>
<property name="widgetSpacing" stdset="0">
<number>0</number>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="storage_place_label">
<property name="text">
<string>Storage Place:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="1" colspan="2">
<widget class="QComboBox" name="storage_place">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Local</string>
</property>
</item>
<item>
<property name="text">
<string>XCAP</string>
</property>
</item>
</widget>
</item>
<item row="8" column="1" colspan="2">
<widget class="QCheckBox" name="subscribe_presence">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Subscribe To Presence</string>
</property>
</widget>
</item>
<item row="9" column="1" colspan="2">
<widget class="QCheckBox" name="subscribe_dialogs">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Subscribe To Dialogs</string>
</property>
</widget>
</item>
<item row="10" column="0" colspan="3">
<spacer name="grid_spacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>412</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="11" column="0" colspan="3">
<layout class="QHBoxLayout" name="button_box_layout">
<property name="spacing">
<number>6</number>
</property>
<item>
<spacer name="button_box_spacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="reject_button">
<property name="minimumSize">
<size>
<width>85</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="accept_button">
<property name="minimumSize">
<size>
<width>85</width>
<height>25</height>
</size>
</property>
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="1" colspan="2">
<widget class="QComboBox" name="preferred_media">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Audio</string>
</property>
</item>
<item>
<property name="text">
<string>Chat</string>
</property>
</item>
<item>
<property name="text">
<string>SMS</string>
</property>
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="preferred_media_label">
<property name="text">
<string>Preferred Media:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LineEdit</class>
<extends>QLineEdit</extends>
<header>blink.widgets.lineedit</header>
</customwidget>
<customwidget>
<class>IconSelector</class>
<extends>QLabel</extends>
<header>blink.widgets.iconselector</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>sip_address_editor</tabstop>
<tabstop>display_name_editor</tabstop>
<tabstop>group</tabstop>
<tabstop>clear_button</tabstop>
<tabstop>preferred_media</tabstop>
<tabstop>chat_aliases_editor</tabstop>
<tabstop>storage_place</tabstop>
<tabstop>subscribe_presence</tabstop>
<tabstop>subscribe_dialogs</tabstop>
<tabstop>reject_button</tabstop>
<tabstop>accept_button</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>accept_button</sender>
<signal>clicked()</signal>
<receiver>ContactEditor</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>396</x>
<y>301</y>
</hint>
<hint type="destinationlabel">
<x>341</x>
<y>190</y>
</hint>
</hints>
</connection>
<connection>
<sender>reject_button</sender>
<signal>clicked()</signal>
<receiver>ContactEditor</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>292</x>
<y>306</y>
</hint>
<hint type="destinationlabel">
<x>272</x>
<y>131</y>
</hint>
</hints>
</connection>
</connections>
<designerdata>
<property name="gridDeltaX">
<number>10</number>
</property>
<property name="gridDeltaY">
<number>10</number>
</property>
<property name="gridSnapX">
<bool>true</bool>
</property>
<property name="gridSnapY">
<bool>true</bool>
</property>
<property name="gridVisible">
<bool>true</bool>
</property>
</designerdata>
</ui>
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