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
8e38a1ae
Commit
8e38a1ae
authored
Aug 03, 2010
by
Saul Ibarra
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added integration with Google Contacts
parent
f8ba1d97
Changes
8
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
889 additions
and
7 deletions
+889
-7
datatypes.py
blink/configuration/datatypes.py
+31
-1
settings.py
blink/configuration/settings.py
+7
-1
contacts.py
blink/contacts.py
+394
-4
data.py
blink/google/gdata/contacts/data.py
+6
-0
mainwindow.py
blink/mainwindow.py
+31
-1
resources.py
blink/resources.py
+36
-0
blink.ui
resources/blink.ui
+7
-0
google_contacts_dialog.ui
resources/google_contacts_dialog.ui
+377
-0
No files found.
blink/configuration/datatypes.py
View file @
8e38a1ae
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
"""Definitions of datatypes for use in settings extensions."""
"""Definitions of datatypes for use in settings extensions."""
__all__
=
[
'ApplicationDataPath'
,
'SoundFile'
,
'DefaultPath'
,
'CustomSoundFile'
,
'HTTPURL'
]
__all__
=
[
'ApplicationDataPath'
,
'SoundFile'
,
'DefaultPath'
,
'CustomSoundFile'
,
'HTTPURL'
,
'InvalidToken'
,
'AuthorizationToken'
]
import
os
import
os
import
re
import
re
...
@@ -113,3 +113,33 @@ class HTTPURL(unicode):
...
@@ -113,3 +113,33 @@ class HTTPURL(unicode):
return
value
return
value
class
InvalidToken
(
object
):
def
__repr__
(
self
):
return
self
.
__class__
.
__name__
class
AuthorizationToken
(
object
):
def
__init__
(
self
,
token
=
None
):
self
.
token
=
token
def
__getstate__
(
self
):
if
self
.
token
is
InvalidToken
:
return
u'invalid'
else
:
return
u'value:
%
s'
%
(
self
.
__dict__
[
'token'
])
def
__setstate__
(
self
,
state
):
match
=
re
.
match
(
r'^(?P<type>invalid|value:)(?P<token>.+?)?$'
,
state
)
if
match
is
None
:
raise
ValueError
(
'illegal value:
%
r'
%
state
)
data
=
match
.
groupdict
()
if
data
.
pop
(
'type'
)
==
'invalid'
:
data
[
'token'
]
=
InvalidToken
self
.
__init__
(
data
[
'token'
])
def
__nonzero__
(
self
):
return
self
.
token
is
not
InvalidToken
def
__repr__
(
self
):
return
'
%
s(
%
r)'
%
(
self
.
__class__
.
__name__
,
self
.
token
)
blink/configuration/settings.py
View file @
8e38a1ae
...
@@ -12,7 +12,7 @@ from sipsimple.configuration import Setting, SettingsGroup, SettingsObjectExtens
...
@@ -12,7 +12,7 @@ from sipsimple.configuration import Setting, SettingsGroup, SettingsObjectExtens
from
sipsimple.configuration.settings
import
AudioSettings
,
LogsSettings
,
TLSSettings
from
sipsimple.configuration.settings
import
AudioSettings
,
LogsSettings
,
TLSSettings
from
blink
import
__version__
from
blink
import
__version__
from
blink.configuration.datatypes
import
ApplicationDataPath
,
HTTPURL
,
SoundFile
from
blink.configuration.datatypes
import
ApplicationDataPath
,
AuthorizationToken
,
HTTPURL
,
SoundFile
from
blink.resources
import
Resources
from
blink.resources
import
Resources
...
@@ -20,6 +20,11 @@ class AudioSettingsExtension(AudioSettings):
...
@@ -20,6 +20,11 @@ class AudioSettingsExtension(AudioSettings):
recordings_directory
=
Setting
(
type
=
ApplicationDataPath
,
default
=
ApplicationDataPath
(
'recordings'
),
nillable
=
False
)
recordings_directory
=
Setting
(
type
=
ApplicationDataPath
,
default
=
ApplicationDataPath
(
'recordings'
),
nillable
=
False
)
class
GoogleContactsSettings
(
SettingsGroup
):
authorization_token
=
Setting
(
type
=
AuthorizationToken
,
default
=
None
,
nillable
=
True
)
username
=
Setting
(
type
=
unicode
,
default
=
None
,
nillable
=
True
)
class
LogsSettingsExtension
(
LogsSettings
):
class
LogsSettingsExtension
(
LogsSettings
):
trace_sip
=
Setting
(
type
=
bool
,
default
=
False
)
trace_sip
=
Setting
(
type
=
bool
,
default
=
False
)
trace_pjsip
=
Setting
(
type
=
bool
,
default
=
False
)
trace_pjsip
=
Setting
(
type
=
bool
,
default
=
False
)
...
@@ -42,6 +47,7 @@ class TLSSettingsExtension(TLSSettings):
...
@@ -42,6 +47,7 @@ class TLSSettingsExtension(TLSSettings):
class
SIPSimpleSettingsExtension
(
SettingsObjectExtension
):
class
SIPSimpleSettingsExtension
(
SettingsObjectExtension
):
audio
=
AudioSettingsExtension
audio
=
AudioSettingsExtension
google_contacts
=
GoogleContactsSettings
logs
=
LogsSettingsExtension
logs
=
LogsSettingsExtension
server
=
ServerSettings
server
=
ServerSettings
sounds
=
SoundSettings
sounds
=
SoundSettings
...
...
blink/contacts.py
View file @
8e38a1ae
This diff is collapsed.
Click to expand it.
blink/google/gdata/contacts/data.py
View file @
8e38a1ae
...
@@ -410,6 +410,12 @@ class ContactEntry(PersonEntry):
...
@@ -410,6 +410,12 @@ class ContactEntry(PersonEntry):
return
a_link
return
a_link
return
None
return
None
def
get_entry_photo_data
(
self
):
photo
=
self
.
GetPhotoLink
()
if
photo
.
_other_attributes
.
get
(
'{http://schemas.google.com/g/2005}etag'
):
return
(
photo
.
href
,
photo
.
_other_attributes
.
get
(
'{http://schemas.google.com/g/2005}etag'
)
.
strip
(
'"'
))
return
(
None
,
None
)
class
ContactsFeed
(
gdata_data
.
BatchFeed
):
class
ContactsFeed
(
gdata_data
.
BatchFeed
):
"""A collection of Contacts."""
"""A collection of Contacts."""
...
...
blink/mainwindow.py
View file @
8e38a1ae
...
@@ -22,7 +22,7 @@ from sipsimple.configuration.settings import SIPSimpleSettings
...
@@ -22,7 +22,7 @@ from sipsimple.configuration.settings import SIPSimpleSettings
from
blink.aboutpanel
import
AboutPanel
from
blink.aboutpanel
import
AboutPanel
from
blink.accounts
import
AccountModel
,
ActiveAccountModel
,
AddAccountDialog
,
ServerToolsAccountModel
,
ServerToolsWindow
from
blink.accounts
import
AccountModel
,
ActiveAccountModel
,
AddAccountDialog
,
ServerToolsAccountModel
,
ServerToolsWindow
from
blink.contacts
import
BonjourNeighbour
,
Contact
,
ContactGroup
,
ContactEditorDialog
,
ContactModel
,
ContactSearchModel
from
blink.contacts
import
BonjourNeighbour
,
Contact
,
ContactGroup
,
ContactEditorDialog
,
ContactModel
,
ContactSearchModel
,
GoogleContactsDialog
from
blink.sessions
import
SessionManager
,
SessionModel
from
blink.sessions
import
SessionManager
,
SessionModel
from
blink.resources
import
Resources
from
blink.resources
import
Resources
from
blink.util
import
call_in_auxiliary_thread
,
run_in_gui_thread
from
blink.util
import
call_in_auxiliary_thread
,
run_in_gui_thread
...
@@ -81,6 +81,7 @@ class MainWindow(base_class, ui_class):
...
@@ -81,6 +81,7 @@ class MainWindow(base_class, ui_class):
self
.
about_panel
=
AboutPanel
(
self
)
self
.
about_panel
=
AboutPanel
(
self
)
self
.
add_account_dialog
=
AddAccountDialog
(
self
)
self
.
add_account_dialog
=
AddAccountDialog
(
self
)
self
.
contact_editor_dialog
=
ContactEditorDialog
(
self
.
contact_model
,
self
)
self
.
contact_editor_dialog
=
ContactEditorDialog
(
self
.
contact_model
,
self
)
self
.
google_contacts_dialog
=
GoogleContactsDialog
(
self
)
self
.
server_tools_window
=
ServerToolsWindow
(
self
.
server_tools_account_model
,
None
)
self
.
server_tools_window
=
ServerToolsWindow
(
self
.
server_tools_account_model
,
None
)
# Signals
# Signals
...
@@ -195,6 +196,7 @@ class MainWindow(base_class, ui_class):
...
@@ -195,6 +196,7 @@ class MainWindow(base_class, ui_class):
self
.
about_panel
.
close
()
self
.
about_panel
.
close
()
self
.
add_account_dialog
.
close
()
self
.
add_account_dialog
.
close
()
self
.
contact_editor_dialog
.
close
()
self
.
contact_editor_dialog
.
close
()
self
.
google_contacts_dialog
.
close
()
self
.
server_tools_window
.
close
()
self
.
server_tools_window
.
close
()
def
set_user_icon
(
self
,
image_file_name
):
def
set_user_icon
(
self
,
image_file_name
):
...
@@ -290,6 +292,15 @@ class MainWindow(base_class, ui_class):
...
@@ -290,6 +292,15 @@ class MainWindow(base_class, ui_class):
settings
.
audio
.
output_device
=
action
.
data
()
.
toPyObject
()
settings
.
audio
.
output_device
=
action
.
data
()
.
toPyObject
()
call_in_auxiliary_thread
(
settings
.
save
)
call_in_auxiliary_thread
(
settings
.
save
)
def
_AH_GoogleContactsActionTriggered
(
self
):
settings
=
SIPSimpleSettings
()
if
settings
.
google_contacts
.
authorization_token
:
settings
=
SIPSimpleSettings
()
settings
.
google_contacts
.
authorization_token
=
None
settings
.
save
()
else
:
self
.
google_contacts_dialog
.
open
()
def
_AH_RedialActionTriggered
(
self
):
def
_AH_RedialActionTriggered
(
self
):
session_manager
=
SessionManager
()
session_manager
=
SessionManager
()
if
session_manager
.
last_dialed_uri
is
not
None
:
if
session_manager
.
last_dialed_uri
is
not
None
:
...
@@ -493,6 +504,16 @@ class MainWindow(base_class, ui_class):
...
@@ -493,6 +504,16 @@ class MainWindow(base_class, ui_class):
notification_center
.
add_observer
(
self
,
sender
=
account_manager
)
notification_center
.
add_observer
(
self
,
sender
=
account_manager
)
self
.
silent_action
.
setChecked
(
settings
.
audio
.
silent
)
self
.
silent_action
.
setChecked
(
settings
.
audio
.
silent
)
self
.
silent_button
.
setChecked
(
settings
.
audio
.
silent
)
self
.
silent_button
.
setChecked
(
settings
.
audio
.
silent
)
if
settings
.
google_contacts
.
authorization_token
:
self
.
google_contacts_action
.
setText
(
u'Disable Google Contacts'
)
elif
settings
.
google_contacts
.
authorization_token
is
not
None
:
# Token is invalid
self
.
google_contacts_action
.
setText
(
u'Disable Google Contacts'
)
# Maybe this should be moved to DidStart so that the dialog is shown *after* the MainWindow. -Saul
self
.
google_contacts_dialog
.
open_for_incorrect_password
()
else
:
self
.
google_contacts_action
.
setText
(
u'Enable Google Contacts'
)
self
.
google_contacts_action
.
triggered
.
connect
(
self
.
_AH_GoogleContactsActionTriggered
)
if
all
(
not
account
.
enabled
for
account
in
account_manager
.
iter_accounts
()):
if
all
(
not
account
.
enabled
for
account
in
account_manager
.
iter_accounts
()):
self
.
display_name
.
setEnabled
(
False
)
self
.
display_name
.
setEnabled
(
False
)
self
.
activity_note
.
setEnabled
(
False
)
self
.
activity_note
.
setEnabled
(
False
)
...
@@ -539,6 +560,15 @@ class MainWindow(base_class, ui_class):
...
@@ -539,6 +560,15 @@ class MainWindow(base_class, ui_class):
if
'audio.alert_device'
in
notification
.
data
.
modified
:
if
'audio.alert_device'
in
notification
.
data
.
modified
:
action
=
(
action
for
action
in
self
.
alert_devices_group
.
actions
()
if
action
.
data
()
.
toPyObject
()
==
settings
.
audio
.
alert_device
)
.
next
()
action
=
(
action
for
action
in
self
.
alert_devices_group
.
actions
()
if
action
.
data
()
.
toPyObject
()
==
settings
.
audio
.
alert_device
)
.
next
()
action
.
setChecked
(
True
)
action
.
setChecked
(
True
)
if
'google_contacts.authorization_token'
in
notification
.
data
.
modified
:
authorization_token
=
notification
.
sender
.
google_contacts
.
authorization_token
if
authorization_token
:
self
.
google_contacts_action
.
setText
(
u'Disable Google Contacts'
)
elif
authorization_token
is
not
None
:
# Token is invalid
self
.
google_contacts_dialog
.
open_for_incorrect_password
()
else
:
self
.
google_contacts_action
.
setText
(
u'Enable Google Contacts'
)
elif
isinstance
(
notification
.
sender
,
(
Account
,
BonjourAccount
)):
elif
isinstance
(
notification
.
sender
,
(
Account
,
BonjourAccount
)):
if
'enabled'
in
notification
.
data
.
modified
:
if
'enabled'
in
notification
.
data
.
modified
:
account
=
notification
.
sender
account
=
notification
.
sender
...
...
blink/resources.py
View file @
8e38a1ae
...
@@ -16,6 +16,7 @@ from application import log
...
@@ -16,6 +16,7 @@ from application import log
from
application.python.util
import
Singleton
from
application.python.util
import
Singleton
from
application.system
import
unlink
from
application.system
import
unlink
from
collections
import
deque
from
collections
import
deque
from
hashlib
import
sha512
from
sipsimple.util
import
classproperty
,
makedirs
from
sipsimple.util
import
classproperty
,
makedirs
...
@@ -165,4 +166,39 @@ class IconCache(object):
...
@@ -165,4 +166,39 @@ class IconCache(object):
self
.
available_names
.
appendleft
(
os
.
path
.
basename
(
destination_name
))
self
.
available_names
.
appendleft
(
os
.
path
.
basename
(
destination_name
))
return
filename
return
filename
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
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
else
:
self
.
available_names
.
appendleft
(
os
.
path
.
basename
(
destination_name
))
return
None
resources/blink.ui
View file @
8e38a1ae
...
@@ -1032,6 +1032,8 @@ padding: 2px;</string>
...
@@ -1032,6 +1032,8 @@ padding: 2px;</string>
<addaction
name=
"separator"
/>
<addaction
name=
"separator"
/>
<addaction
name=
"file_transfers_action"
/>
<addaction
name=
"file_transfers_action"
/>
<addaction
name=
"logs_action"
/>
<addaction
name=
"logs_action"
/>
<addaction
name=
"separator"
/>
<addaction
name=
"google_contacts_action"
/>
</widget>
</widget>
<addaction
name=
"blink_menu"
/>
<addaction
name=
"blink_menu"
/>
<addaction
name=
"audio_menu"
/>
<addaction
name=
"audio_menu"
/>
...
@@ -1249,6 +1251,11 @@ padding: 2px;</string>
...
@@ -1249,6 +1251,11 @@ padding: 2px;</string>
<string>
Donate if you like Blink
</string>
<string>
Donate if you like Blink
</string>
</property>
</property>
</action>
</action>
<action
name=
"google_contacts_action"
>
<property
name=
"text"
>
<string>
Enable Google Contacts
</string>
</property>
</action>
<action
name=
"history_on_server_action"
>
<action
name=
"history_on_server_action"
>
<property
name=
"text"
>
<property
name=
"text"
>
<string>
Call history on server...
</string>
<string>
Call history on server...
</string>
...
...
resources/google_contacts_dialog.ui
0 → 100644
View file @
8e38a1ae
This diff is collapsed.
Click to expand it.
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