Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vmj-qt
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kulya
vmj-qt
Commits
8f5ac8a1
Commit
8f5ac8a1
authored
Mar 18, 2013
by
Dan Pascu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Modified code to store contacts in XCAP
parent
8a70ef47
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1685 additions
and
1117 deletions
+1685
-1117
__init__.py
blink/__init__.py
+4
-0
addressbook.py
blink/configuration/addressbook.py
+28
-0
datatypes.py
blink/configuration/datatypes.py
+54
-1
contacts.py
blink/contacts.py
+1393
-749
mainwindow.py
blink/mainwindow.py
+12
-15
resources.py
blink/resources.py
+54
-120
sessions.py
blink/sessions.py
+8
-10
contact.ui
resources/contact.ui
+16
-19
contact_editor.ui
resources/contact_editor.ui
+116
-203
test-call.png
resources/icons/test-call.png
+0
-0
test-conference.png
resources/icons/test-conference.png
+0
-0
test-echo.png
resources/icons/test-echo.png
+0
-0
vuc-conference.png
resources/icons/vuc-conference.png
+0
-0
No files found.
blink/__init__.py
View file @
8f5ac8a1
...
...
@@ -28,6 +28,7 @@ from gnutls.errors import GNUTLSError
from
zope.interface
import
implements
from
sipsimple.account
import
Account
,
AccountManager
,
BonjourAccount
from
sipsimple.addressbook
import
Contact
,
Group
from
sipsimple.application
import
SIPApplication
from
sipsimple.configuration.settings
import
SIPSimpleSettings
from
sipsimple.storage
import
FileStorage
...
...
@@ -35,6 +36,7 @@ from sipsimple.threading import run_in_twisted_thread
from
sipsimple.threading.green
import
run_in_green_thread
from
blink.configuration.account
import
AccountExtension
,
BonjourAccountExtension
from
blink.configuration.addressbook
import
ContactExtension
,
GroupExtension
from
blink.configuration.datatypes
import
InvalidToken
from
blink.configuration.settings
import
SIPSimpleSettingsExtension
from
blink.logging
import
LogManager
...
...
@@ -101,6 +103,8 @@ class Blink(QApplication):
Account
.
register_extension
(
AccountExtension
)
BonjourAccount
.
register_extension
(
BonjourAccountExtension
)
Contact
.
register_extension
(
ContactExtension
)
Group
.
register_extension
(
GroupExtension
)
SIPSimpleSettings
.
register_extension
(
SIPSimpleSettingsExtension
)
session_manager
=
SessionManager
()
session_manager
.
initialize
(
self
.
main_window
,
self
.
main_window
.
session_model
)
...
...
blink/configuration/addressbook.py
0 → 100644
View file @
8f5ac8a1
# Copyright (C) 2013 AG Projects. See LICENSE for details.
#
"""Blink addressbook settings extensions."""
__all__
=
[
'ContactExtension'
,
'GroupExtension'
]
from
sipsimple.addressbook
import
ContactExtension
,
GroupExtension
,
SharedSetting
from
sipsimple.configuration
import
Setting
from
blink.configuration.datatypes
import
IconDescriptor
SharedSetting
.
set_namespace
(
'ag-projects:blink'
)
class
ContactExtension
(
ContactExtension
):
#auto_answer = SharedSetting(type=bool, default=False)
default_uri
=
SharedSetting
(
type
=
str
,
nillable
=
True
,
default
=
None
)
preferred_media
=
SharedSetting
(
type
=
str
,
default
=
'audio'
)
icon
=
Setting
(
type
=
IconDescriptor
,
nillable
=
True
,
default
=
None
)
class
GroupExtension
(
GroupExtension
):
position
=
Setting
(
type
=
int
,
nillable
=
True
)
collapsed
=
Setting
(
type
=
bool
,
default
=
False
)
blink/configuration/datatypes.py
View file @
8f5ac8a1
...
...
@@ -3,7 +3,7 @@
"""Definitions of datatypes for use in settings extensions."""
__all__
=
[
'ApplicationDataPath'
,
'SoundFile'
,
'DefaultPath'
,
'CustomSoundFile'
,
'HTTPURL'
,
'AuthorizationToken'
,
'InvalidToken'
]
__all__
=
[
'ApplicationDataPath'
,
'SoundFile'
,
'DefaultPath'
,
'CustomSoundFile'
,
'HTTPURL'
,
'AuthorizationToken'
,
'InvalidToken'
,
'IconDescriptor'
]
import
os
import
re
...
...
@@ -136,3 +136,56 @@ class AuthorizationToken(str):
InvalidToken
=
AuthorizationToken
()
# a valid token is never empty
class
IconDescriptor
(
object
):
def
__init__
(
self
,
url
,
etag
=
None
):
self
.
url
=
url
self
.
etag
=
etag
def
__getstate__
(
self
):
if
self
.
etag
is
None
:
return
unicode
(
self
.
url
)
else
:
return
u'
%
s,
%
s'
%
(
self
.
__dict__
[
'url'
],
self
.
etag
)
def
__setstate__
(
self
,
state
):
try
:
url
,
etag
=
state
.
rsplit
(
u','
,
1
)
except
ValueError
:
self
.
__init__
(
state
)
else
:
self
.
__init__
(
url
,
etag
)
def
__eq__
(
self
,
other
):
if
isinstance
(
other
,
IconDescriptor
):
return
self
.
url
==
other
.
url
and
self
.
etag
==
other
.
etag
return
NotImplemented
def
__ne__
(
self
,
other
):
equal
=
self
.
__eq__
(
other
)
return
NotImplemented
if
equal
is
NotImplemented
else
not
equal
def
__repr__
(
self
):
return
'
%
s(
%
r,
%
r)'
%
(
self
.
__class__
.
__name__
,
self
.
url
,
self
.
etag
)
def
_get_url
(
self
):
url
=
self
.
__dict__
[
'url'
]
file_scheme
=
'file://'
if
url
.
startswith
(
file_scheme
):
url
=
file_scheme
+
ApplicationData
.
get
(
url
[
len
(
file_scheme
):])
return
url
def
_set_url
(
self
,
url
):
file_scheme
=
'file://'
if
url
.
startswith
(
file_scheme
):
filename
=
os
.
path
.
normpath
(
url
[
len
(
file_scheme
):])
if
filename
.
startswith
(
ApplicationData
.
directory
+
os
.
path
.
sep
):
filename
=
filename
[
len
(
ApplicationData
.
directory
+
os
.
path
.
sep
):]
url
=
file_scheme
+
filename
self
.
__dict__
[
'url'
]
=
url
url
=
property
(
_get_url
,
_set_url
)
del
_get_url
,
_set_url
@
property
def
is_local
(
self
):
return
self
.
__dict__
[
'url'
]
.
startswith
(
'file://'
)
blink/contacts.py
View file @
8f5ac8a1
This source diff could not be displayed because it is too large. You can
view the blob
instead.
blink/mainwindow.py
View file @
8f5ac8a1
...
...
@@ -20,7 +20,7 @@ from sipsimple.configuration.settings import SIPSimpleSettings
from
blink.aboutpanel
import
AboutPanel
from
blink.accounts
import
AccountModel
,
ActiveAccountModel
,
ServerToolsAccountModel
,
ServerToolsWindow
from
blink.contacts
import
BonjourNeighbour
,
Contact
,
Contact
Group
,
ContactEditorDialog
,
ContactModel
,
ContactSearchModel
,
GoogleContactsDialog
from
blink.contacts
import
BonjourNeighbour
,
Contact
,
Group
,
ContactEditorDialog
,
ContactModel
,
ContactSearchModel
,
GoogleContactsDialog
from
blink.preferences
import
PreferencesWindow
from
blink.sessions
import
ConferenceDialog
,
SessionManager
,
SessionModel
from
blink.configuration.datatypes
import
InvalidToken
...
...
@@ -87,7 +87,7 @@ class MainWindow(base_class, ui_class):
# Windows, dialogs and panels
self
.
about_panel
=
AboutPanel
(
self
)
self
.
conference_dialog
=
ConferenceDialog
(
self
)
self
.
contact_editor_dialog
=
ContactEditorDialog
(
self
.
contact_model
,
self
)
self
.
contact_editor_dialog
=
ContactEditorDialog
(
self
)
self
.
google_contacts_dialog
=
GoogleContactsDialog
(
self
)
self
.
preferences_window
=
PreferencesWindow
(
self
.
account_model
,
None
)
self
.
server_tools_window
=
ServerToolsWindow
(
self
.
server_tools_account_model
,
None
)
...
...
@@ -163,8 +163,6 @@ class MainWindow(base_class, ui_class):
self
.
history_on_server_action
.
triggered
.
connect
(
self
.
_AH_HistoryOnServer
)
self
.
buy_pstn_access_action
.
triggered
.
connect
(
self
.
_AH_PurchasePstnAccess
)
self
.
contact_model
.
load
()
def
setupUi
(
self
):
super
(
MainWindow
,
self
)
.
setupUi
(
self
)
...
...
@@ -341,15 +339,14 @@ class MainWindow(base_class, ui_class):
def
_SH_AddContactButtonClicked
(
self
,
clicked
):
model
=
self
.
contact_model
selected_items
=
((
index
.
row
(),
model
.
data
(
index
))
for
index
in
self
.
contact_list
.
selectionModel
()
.
selectedIndexes
())
try
:
item
=
(
item
for
row
,
item
in
sorted
(
selected_items
)
if
type
(
item
)
in
(
Contact
,
ContactGroup
))
.
next
()
preferred_group
=
item
if
type
(
item
)
is
ContactGroup
else
item
.
group
except
StopIteration
:
try
:
preferred_group
=
(
group
for
group
in
model
.
contact_groups
if
type
(
group
)
is
ContactGroup
)
.
next
()
except
StopIteration
:
preferred_group
=
None
groups
=
set
()
for
index
in
self
.
contact_list
.
selectionModel
()
.
selectedIndexes
():
item
=
model
.
data
(
index
)
if
isinstance
(
item
,
Group
)
and
not
item
.
virtual
:
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
self
.
contact_editor_dialog
.
open_for_add
(
self
.
search_box
.
text
(),
preferred_group
)
def
_SH_AudioCallButtonClicked
(
self
):
...
...
@@ -359,7 +356,7 @@ class MainWindow(base_class, ui_class):
address
=
contact
.
uri
or
self
.
search_box
.
text
()
name
=
contact
.
name
or
None
session_manager
=
SessionManager
()
session_manager
.
start_call
(
name
,
address
,
contact
=
contact
,
account
=
BonjourAccount
()
if
isinstance
(
contact
,
BonjourNeighbour
)
else
None
)
session_manager
.
start_call
(
name
,
address
,
contact
=
contact
,
account
=
BonjourAccount
()
if
isinstance
(
contact
.
settings
,
BonjourNeighbour
)
else
None
)
def
_SH_BreakConference
(
self
):
active_session
=
self
.
session_model
.
data
(
self
.
session_list
.
selectionModel
()
.
selectedIndexes
()[
0
])
...
...
@@ -370,7 +367,7 @@ class MainWindow(base_class, ui_class):
if
not
isinstance
(
contact
,
Contact
):
return
session_manager
=
SessionManager
()
session_manager
.
start_call
(
contact
.
name
,
contact
.
uri
,
contact
=
contact
,
account
=
BonjourAccount
()
if
isinstance
(
contact
,
BonjourNeighbour
)
else
None
)
session_manager
.
start_call
(
contact
.
name
,
contact
.
uri
,
contact
=
contact
,
account
=
BonjourAccount
()
if
isinstance
(
contact
.
settings
,
BonjourNeighbour
)
else
None
)
def
_SH_ContactListSelectionChanged
(
self
,
selected
,
deselected
):
account_manager
=
AccountManager
()
...
...
blink/resources.py
View file @
8f5ac8a1
# Copyright (C) 2010 AG Projects. See LICENSE for details.
# Copyright (C) 2010
-2013
AG Projects. See LICENSE for details.
#
"""Provide access to Blink's resources"""
__all__
=
[
'ApplicationData'
,
'Resources'
,
'Icon
Cache
'
]
__all__
=
[
'ApplicationData'
,
'Resources'
,
'Icon
Manager
'
]
import
cPickle
as
pickle
import
os
import
platform
import
sys
from
PyQt4.QtCore
import
Qt
from
PyQt4.QtGui
import
QPixmap
from
application
import
log
from
PyQt4.QtGui
import
QIcon
,
QPixmap
from
application.python.descriptor
import
classproperty
from
application.python.types
import
Singleton
from
application.system
import
makedirs
,
unlink
from
collections
import
deque
from
hashlib
import
sha512
class
DirectoryContextManager
(
unicode
):
...
...
@@ -78,127 +74,65 @@ class Resources(object):
return
os
.
path
.
join
(
cls
.
directory
,
resource
or
u''
)
class
FileInfo
(
object
):
def
__init__
(
self
,
name
):
self
.
name
=
name
try
:
stat
=
os
.
stat
(
ApplicationData
.
get
(
os
.
path
.
join
(
'images'
,
name
)))
except
OSError
:
self
.
mtime
=
None
self
.
size
=
None
else
:
self
.
mtime
=
stat
.
st_mtime
self
.
size
=
stat
.
st_size
def
__hash__
(
self
):
return
hash
(
self
.
name
)
def
__eq__
(
self
,
other
):
return
isinstance
(
other
,
FileInfo
)
and
(
self
.
name
,
self
.
mtime
,
self
.
size
)
==
(
other
.
name
,
other
.
mtime
,
other
.
size
)
def
__ne__
(
self
,
other
):
return
not
self
.
__eq__
(
other
)
class
FileMapping
(
object
):
def
__init__
(
self
,
source
,
destination
):
self
.
source
=
source
self
.
destination
=
destination
class
IconCache
(
object
):
class
IconManager
(
object
):
__metaclass__
=
Singleton
max_size
=
256
def
__init__
(
self
):
makedirs
(
ApplicationData
.
get
(
'images'
))
try
:
self
.
filemap
=
pickle
.
load
(
open
(
ApplicationData
.
get
(
os
.
path
.
join
(
'images'
,
'.cached_icons.map'
))))
except
Exception
:
self
.
filemap
=
{}
all_names
=
set
(
'cached_icon_
%04
d.png'
%
x
for
x
in
xrange
(
1
,
10000
))
used_names
=
set
(
os
.
listdir
(
ApplicationData
.
get
(
'images'
)))
self
.
available_names
=
deque
(
sorted
(
all_names
-
used_names
))
def
store
(
self
,
filename
,
pixmap
=
None
):
if
filename
is
None
:
return
None
if
not
os
.
path
.
isabs
(
filename
):
return
filename
if
filename
.
startswith
(
ApplicationData
.
directory
+
os
.
path
.
sep
):
return
filename
[
len
(
ApplicationData
.
directory
+
os
.
path
.
sep
):]
self
.
iconmap
=
{}
def
get
(
self
,
id
):
try
:
file_mapping
=
self
.
filemap
[
filename
]
return
self
.
iconmap
[
id
]
except
KeyError
:
pass
else
:
source_info
=
FileInfo
(
filename
)
destination_info
=
FileInfo
(
file_mapping
.
destination
.
name
)
if
(
source_info
,
destination_info
)
==
(
file_mapping
.
source
,
file_mapping
.
destination
):
return
destination_info
.
name
try
:
destination_name
=
os
.
path
.
join
(
'images'
,
self
.
available_names
.
popleft
())
except
IndexError
:
# No more available file names. Return original file for now
return
filename
if
pixmap
is
None
:
pixmap
=
QPixmap
()
filename
=
ApplicationData
.
get
(
os
.
path
.
join
(
'images'
,
id
+
'.png'
))
if
pixmap
.
load
(
filename
):
pixmap
=
pixmap
.
scaled
(
32
,
32
,
Qt
.
KeepAspectRatio
,
Qt
.
SmoothTransformation
)
makedirs
(
ApplicationData
.
get
(
'images'
))
if
pixmap
.
save
(
ApplicationData
.
get
(
destination_name
)):
source_info
=
FileInfo
(
filename
)
destination_info
=
FileInfo
(
destination_name
)
file_mapping
=
FileMapping
(
source_info
,
destination_info
)
self
.
filemap
[
filename
]
=
file_mapping
map_filename
=
ApplicationData
.
get
(
os
.
path
.
join
(
'images'
,
'.cached_icons.map'
))
map_tempname
=
map_filename
+
'.tmp'
try
:
file
=
open
(
map_tempname
,
'wb'
)
pickle
.
dump
(
self
.
filemap
,
file
)
file
.
close
()
if
sys
.
platform
==
'win32'
:
unlink
(
map_filename
)
os
.
rename
(
map_tempname
,
map_filename
)
except
Exception
,
e
:
log
.
error
(
"could not save icon cache file mappings:
%
s"
%
e
)
return
destination_name
else
:
self
.
available_names
.
appendleft
(
os
.
path
.
basename
(
destination_name
))
return
filename
icon
=
QIcon
(
pixmap
)
icon
.
filename
=
filename
else
:
icon
=
None
return
self
.
iconmap
.
setdefault
(
id
,
icon
)
def
store_image
(
self
,
data
):
if
data
is
None
:
return
None
data_hash
=
sha512
(
data
)
.
hexdigest
()
try
:
return
self
.
filemap
[
data_hash
]
.
destination
except
KeyError
:
pass
try
:
destination_name
=
os
.
path
.
join
(
'images'
,
self
.
available_names
.
popleft
())
except
IndexError
:
# No more available file names.
return
None
def
store_data
(
self
,
id
,
data
):
directory
=
ApplicationData
.
get
(
'images'
)
filename
=
os
.
path
.
join
(
directory
,
id
+
'.png'
)
makedirs
(
directory
)
pixmap
=
QPixmap
()
if
data
is
not
None
and
pixmap
.
loadFromData
(
data
):
if
pixmap
.
size
()
.
width
()
>
self
.
max_size
or
pixmap
.
size
()
.
height
()
>
self
.
max_size
:
pixmap
=
pixmap
.
scaled
(
self
.
max_size
,
self
.
max_size
,
Qt
.
KeepAspectRatio
,
Qt
.
SmoothTransformation
)
pixmap
.
save
(
filename
)
icon
=
QIcon
(
pixmap
)
icon
.
filename
=
filename
else
:
unlink
(
filename
)
icon
=
None
self
.
iconmap
[
id
]
=
icon
return
icon
def
store_file
(
self
,
id
,
file
):
directory
=
ApplicationData
.
get
(
'images'
)
filename
=
os
.
path
.
join
(
directory
,
id
+
'.png'
)
if
filename
==
os
.
path
.
normpath
(
file
):
return
self
.
iconmap
.
get
(
id
,
None
)
makedirs
(
directory
)
pixmap
=
QPixmap
()
if
pixmap
.
loadFromData
(
data
):
pixmap
=
pixmap
.
scaled
(
32
,
32
,
Qt
.
KeepAspectRatio
,
Qt
.
SmoothTransformation
)
makedirs
(
ApplicationData
.
get
(
'images'
))
if
pixmap
.
save
(
ApplicationData
.
get
(
destination_name
)):
file_mapping
=
FileMapping
(
data_hash
,
destination_name
)
self
.
filemap
[
data_hash
]
=
file_mapping
map_filename
=
ApplicationData
.
get
(
os
.
path
.
join
(
'images'
,
'.cached_icons.map'
))
map_tempname
=
map_filename
+
'.tmp'
try
:
file
=
open
(
map_tempname
,
'wb'
)
pickle
.
dump
(
self
.
filemap
,
file
)
file
.
close
()
if
sys
.
platform
==
'win32'
:
unlink
(
map_filename
)
os
.
rename
(
map_tempname
,
map_filename
)
except
Exception
,
e
:
log
.
error
(
"could not save icon cache file mappings:
%
s"
%
e
)
return
destination_name
if
file
is
not
None
and
pixmap
.
load
(
file
):
if
pixmap
.
size
()
.
width
()
>
self
.
max_size
or
pixmap
.
size
()
.
height
()
>
self
.
max_size
:
pixmap
=
pixmap
.
scaled
(
self
.
max_size
,
self
.
max_size
,
Qt
.
KeepAspectRatio
,
Qt
.
SmoothTransformation
)
pixmap
.
save
(
filename
)
icon
=
QIcon
(
pixmap
)
icon
.
filename
=
filename
else
:
self
.
available_names
.
appendleft
(
os
.
path
.
basename
(
destination_name
))
return
None
unlink
(
filename
)
icon
=
None
self
.
iconmap
[
id
]
=
icon
return
icon
def
remove
(
self
,
id
):
self
.
iconmap
.
pop
(
id
,
None
)
unlink
(
ApplicationData
.
get
(
os
.
path
.
join
(
'images'
,
id
+
'.png'
)))
blink/sessions.py
View file @
8f5ac8a1
...
...
@@ -1588,7 +1588,7 @@ class IncomingSession(QObject):
self
.
dialog
.
uri_label
.
setText
(
address
)
if
self
.
contact
:
self
.
dialog
.
username_label
.
setText
(
contact
.
name
or
session
.
remote_identity
.
display_name
or
address
)
self
.
dialog
.
user_icon
.
setPixmap
(
contact
.
icon
)
self
.
dialog
.
user_icon
.
setPixmap
(
contact
.
pixmap
)
else
:
self
.
dialog
.
username_label
.
setText
(
session
.
remote_identity
.
display_name
or
address
)
if
self
.
audio_stream
:
...
...
@@ -1774,7 +1774,7 @@ class SessionManager(object):
session
=
Session
(
account
)
if
contact
is
None
:
for
contact
in
self
.
main_window
.
contact_model
.
iter_contacts
():
if
remote_uri
.
matches
(
self
.
normalize_number
(
account
,
contact
.
uri
))
or
any
(
remote_uri
.
matches
(
self
.
normalize_number
(
account
,
alias
))
for
alias
in
contact
.
sip_aliase
s
):
if
any
(
remote_uri
.
matches
(
self
.
normalize_number
(
account
,
uri
.
uri
))
for
uri
in
contact
.
uri
s
):
break
else
:
contact
=
None
...
...
@@ -1986,18 +1986,16 @@ class SessionManager(object):
session
.
reject
(
488
)
return
session
.
send_ring_indication
()
uri
=
session
.
remote_identity
.
uri
remote_
uri
=
session
.
remote_identity
.
uri
for
contact
in
self
.
main_window
.
contact_model
.
iter_contacts
():
if
uri
.
matches
(
self
.
normalize_number
(
session
.
account
,
contact
.
uri
))
or
any
(
uri
.
matches
(
self
.
normalize_number
(
session
.
account
,
alias
))
for
alias
in
contact
.
sip_aliase
s
):
if
any
(
remote_uri
.
matches
(
self
.
normalize_number
(
session
.
account
,
uri
.
uri
))
for
uri
in
contact
.
uri
s
):
break
else
:
matched_contacts
=
[]
number
=
uri
.
user
.
strip
(
'0'
)
if
self
.
number_re
.
match
(
uri
.
user
)
else
Null
number
=
remote_uri
.
user
.
strip
(
'0'
)
if
self
.
number_re
.
match
(
remote_
uri
.
user
)
else
Null
if
len
(
number
)
>
7
:
for
contact
in
self
.
main_window
.
contact_model
.
iter_contacts
():
if
self
.
number_re
.
match
(
contact
.
uri
)
and
self
.
normalize_number
(
session
.
account
,
contact
.
uri
)
.
endswith
(
number
):
matched_contacts
.
append
(
contact
)
elif
any
(
self
.
number_re
.
match
(
alias
)
and
self
.
normalize_number
(
session
.
account
,
alias
)
.
endswith
(
number
)
for
alias
in
contact
.
sip_aliases
):
if
any
(
self
.
number_re
.
match
(
uri
.
uri
)
and
self
.
normalize_number
(
session
.
account
,
uri
.
uri
)
.
endswith
(
number
)
for
uri
in
contact
.
uris
):
matched_contacts
.
append
(
contact
)
contact
=
matched_contacts
[
0
]
if
len
(
matched_contacts
)
==
1
else
None
if
filetransfer_streams
:
...
...
@@ -2033,9 +2031,9 @@ class SessionManager(object):
session
.
reject_proposal
(
488
)
return
session
.
send_ring_indication
()
uri
=
session
.
remote_identity
.
uri
remote_
uri
=
session
.
remote_identity
.
uri
for
contact
in
self
.
main_window
.
contact_model
.
iter_contacts
():
if
uri
.
matches
(
self
.
normalize_number
(
session
.
account
,
contact
.
uri
))
or
any
(
uri
.
matches
(
self
.
normalize_number
(
session
.
account
,
alias
))
for
alias
in
contact
.
sip_aliase
s
):
if
any
(
remote_uri
.
matches
(
self
.
normalize_number
(
session
.
account
,
uri
.
uri
))
for
uri
in
contact
.
uri
s
):
break
else
:
contact
=
None
...
...
resources/contact.ui
View file @
8f5ac8a1
...
...
@@ -13,7 +13,7 @@
<property
name=
"palette"
>
<palette>
<active>
<colorrole
role=
"
Base
"
>
<colorrole
role=
"
Window
"
>
<brush
brushstyle=
"SolidPattern"
>
<color
alpha=
"255"
>
<red>
255
</red>
...
...
@@ -22,18 +22,18 @@
</color>
</brush>
</colorrole>
<colorrole
role=
"
Window
"
>
<colorrole
role=
"
AlternateBase
"
>
<brush
brushstyle=
"SolidPattern"
>
<color
alpha=
"255"
>
<red>
2
55
</red>
<green>
2
55
</green>
<red>
2
40
</red>
<green>
2
44
</green>
<blue>
255
</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole
role=
"
Base
"
>
<colorrole
role=
"
Window
"
>
<brush
brushstyle=
"SolidPattern"
>
<color
alpha=
"255"
>
<red>
255
</red>
...
...
@@ -42,18 +42,18 @@
</color>
</brush>
</colorrole>
<colorrole
role=
"
Window
"
>
<colorrole
role=
"
AlternateBase
"
>
<brush
brushstyle=
"SolidPattern"
>
<color
alpha=
"255"
>
<red>
2
55
</red>
<green>
2
55
</green>
<red>
2
40
</red>
<green>
2
44
</green>
<blue>
255
</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole
role=
"
Base
"
>
<colorrole
role=
"
Window
"
>
<brush
brushstyle=
"SolidPattern"
>
<color
alpha=
"255"
>
<red>
255
</red>
...
...
@@ -62,11 +62,11 @@
</color>
</brush>
</colorrole>
<colorrole
role=
"
Window
"
>
<colorrole
role=
"
AlternateBase
"
>
<brush
brushstyle=
"SolidPattern"
>
<color
alpha=
"255"
>
<red>
2
55
</red>
<green>
2
55
</green>
<red>
2
40
</red>
<green>
2
44
</green>
<blue>
255
</blue>
</color>
</brush>
...
...
@@ -94,7 +94,7 @@
<number>
0
</number>
</property>
<item>
<widget
class=
"QLabel"
name=
"icon"
>
<widget
class=
"QLabel"
name=
"icon
_label
"
>
<property
name=
"minimumSize"
>
<size>
<width>
36
</width>
...
...
@@ -113,12 +113,12 @@
</widget>
</item>
<item>
<layout
class=
"QVBoxLayout"
name=
"name_
uri
_layout"
>
<layout
class=
"QVBoxLayout"
name=
"name_
info
_layout"
>
<property
name=
"spacing"
>
<number>
0
</number>
</property>
<item>
<widget
class=
"QLabel"
name=
"name"
>
<widget
class=
"QLabel"
name=
"name
_label
"
>
<property
name=
"sizePolicy"
>
<sizepolicy
hsizetype=
"Expanding"
vsizetype=
"Fixed"
>
<horstretch>
0
</horstretch>
...
...
@@ -131,10 +131,7 @@
</widget>
</item>
<item>
<widget
class=
"QLabel"
name=
"uri"
>
<property
name=
"enabled"
>
<bool>
false
</bool>
</property>
<widget
class=
"QLabel"
name=
"info_label"
>
<property
name=
"sizePolicy"
>
<sizepolicy
hsizetype=
"Expanding"
vsizetype=
"Fixed"
>
<horstretch>
0
</horstretch>
...
...
resources/contact_editor.ui
View file @
8f5ac8a1
...
...
@@ -32,134 +32,28 @@
<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=
"toolTip"
>
<string>
Click to select a picture
</string>
</property>
<property
name=
"frameShape"
>
<enum>
QFrame::StyledPanel
</enum>
</property>
<property
name=
"frameShadow"
>
<enum>
QFrame::Sunken
</enum>
</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>
<property
name=
"autoDefault"
>
<bool>
false
</bool>
</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>
<item
row=
"6"
column=
"1"
colspan=
"2"
>
<widget
class=
"QCheckBox"
name=
"subscribe_presence"
>
<property
name=
"enabled"
>
<bool>
false
</bool>
</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>
<string>
Subscribe To Presence
</string>
</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>
<item
row=
"8"
column=
"0"
colspan=
"3"
>
<spacer
name=
"grid_spacer"
>
<property
name=
"orientation"
>
<enum>
Qt::Vertical
</enum>
</property>
<property
name=
"insertPolicy"
>
<enum>
QComboBox::NoInsert
</enum>
<property
name=
"sizeHint"
stdset=
"0"
>
<size>
<width>
412
</width>
<height>
20
</height>
</size>
</property>
</
widget
>
</
spacer
>
</item>
<item
row=
"3"
column=
"0"
colspan=
"3"
>
<spacer
name=
"section_spacer"
>
...
...
@@ -177,41 +71,18 @@
</property>
</spacer>
</item>
<item
row=
"5"
column=
"0"
>
<widget
class=
"QLabel"
name=
"sip_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=
"sip_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"
>
<item
row=
"1"
column=
"0"
>
<widget
class=
"QLabel"
name=
"sip_address_label"
>
<property
name=
"text"
>
<string>
S
torage Place
:
</string>
<string>
S
IP Address
:
</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>
<item
row=
"4"
column=
"1"
colspan=
"2"
>
<widget
class=
"QComboBox"
name=
"preferred_media"
>
<property
name=
"sizePolicy"
>
<sizepolicy
hsizetype=
"Expanding"
vsizetype=
"Fixed"
>
<horstretch>
0
</horstretch>
...
...
@@ -220,50 +91,37 @@
</property>
<item>
<property
name=
"text"
>
<string>
Local
</string>
<string>
Audio
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
XCAP
</string>
<string>
Chat
</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>
<item
row=
"0"
column=
"0"
>
<widget
class=
"QLabel"
name=
"display_name_label"
>
<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>
<string>
Display Name:
</string>
</property>
<property
name=
"
tex
t"
>
<s
tring>
Subscribe To Dialogs
</string
>
<property
name=
"
alignmen
t"
>
<s
et>
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
</set
>
</property>
</widget>
</item>
<item
row=
"1
0"
column=
"0"
colspan=
"3
"
>
<
spacer
name=
"grid_space
r"
>
<property
name=
"
orientation
"
>
<
enum>
Qt::Vertical
</enum
>
<item
row=
"1
"
column=
"1
"
>
<
widget
class=
"LineEdit"
name=
"sip_address_edito
r"
>
<property
name=
"
inactiveText"
stdset=
"0
"
>
<
string>
user@domain
</string
>
</property>
<property
name=
"sizeHint"
stdset=
"0"
>
<size>
<width>
412
</width>
<height>
20
</height>
</size>
<property
name=
"widgetSpacing"
stdset=
"0"
>
<number>
0
</number>
</property>
</
spacer
>
</
widget
>
</item>
<item
row=
"
11
"
column=
"0"
colspan=
"3"
>
<item
row=
"
9
"
column=
"0"
colspan=
"3"
>
<layout
class=
"QHBoxLayout"
name=
"button_box_layout"
>
<property
name=
"spacing"
>
<number>
6
</number>
...
...
@@ -318,29 +176,14 @@
</item>
</layout>
</item>
<item
row=
"
4
"
column=
"1"
colspan=
"2"
>
<widget
class=
"QC
omboBox"
name=
"preferred_media
"
>
<property
name=
"
sizePolicy
"
>
<
sizepolicy
hsizetype=
"Expanding"
vsizetype=
"Fixed"
>
<horstretch>
0
</horstretch
>
<verstretch>
0
</verstretch
>
<
/sizepolicy
>
<item
row=
"
7
"
column=
"1"
colspan=
"2"
>
<widget
class=
"QC
heckBox"
name=
"subscribe_dialogs
"
>
<property
name=
"
enabled
"
>
<
bool>
false
</bool
>
</property
>
<property
name=
"text"
>
<
string>
Subscribe To Dialogs
</string
>
</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"
>
...
...
@@ -353,6 +196,79 @@
</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=
"toolTip"
>
<string>
Click to select a picture
</string>
</property>
<property
name=
"frameShape"
>
<enum>
QFrame::StyledPanel
</enum>
</property>
<property
name=
"frameShadow"
>
<enum>
QFrame::Sunken
</enum>
</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>
<property
name=
"autoDefault"
>
<bool>
false
</bool>
</property>
</widget>
</item>
</layout>
</item>
<item
row=
"0"
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>
</layout>
</widget>
<customwidgets>
...
...
@@ -368,13 +284,10 @@
</customwidget>
</customwidgets>
<tabstops>
<tabstop>
sip_address_editor
</tabstop>
<tabstop>
display_name_editor
</tabstop>
<tabstop>
group
</tabstop>
<tabstop>
sip_address_editor
</tabstop>
<tabstop>
clear_button
</tabstop>
<tabstop>
preferred_media
</tabstop>
<tabstop>
sip_aliases_editor
</tabstop>
<tabstop>
storage_place
</tabstop>
<tabstop>
subscribe_presence
</tabstop>
<tabstop>
subscribe_dialogs
</tabstop>
<tabstop>
reject_button
</tabstop>
...
...
resources/icons/
call-test-icon
.png
→
resources/icons/
test-call
.png
View file @
8f5ac8a1
File moved
resources/icons/
audio-conference-icon
.png
→
resources/icons/
test-conference
.png
View file @
8f5ac8a1
File moved
resources/icons/
echo-test-icon
.png
→
resources/icons/
test-echo
.png
View file @
8f5ac8a1
File moved
resources/icons/vuc-conference
-icon
.png
→
resources/icons/vuc-conference.png
View file @
8f5ac8a1
File moved
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment