New Service Discovery, couple of quick notes about this commit:

* src/disco.py contains all the disco stuff
 * registration remains in src/config.py
 * data/pixmaps/agents contains the icons used in the toplevel server browser
   and the banner. They're referenced at the top of src/disco.py.
This commit is contained in:
shteef 2005-10-30 09:58:13 +00:00
parent 56bc8d4709
commit b69bc501ae
17 changed files with 1707 additions and 445 deletions

1
README
View File

@ -79,4 +79,5 @@ sounds and stellar iconstyle taken from Psi
some emoticons taken from Psi
the basic emoticons taken from Gossip
gossip iconstyle taken from Gossip
service discovery icons taken from Gaim and the GNOME hi-color theme
If you think we're violating a license please inform us

BIN
data/pixmaps/agents/aim.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
data/pixmaps/agents/icq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
data/pixmaps/agents/irc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
data/pixmaps/agents/msn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -207,7 +207,7 @@ class Connection:
def discoverInfo(self, jid, node = None):
'''According to JEP-0030:
For identity: category, name is mandatory, type is optional.
For identity: category, type is mandatory, name is optional.
For feature: var is mandatory'''
self._discover(common.xmpp.NS_DISCO_INFO, jid, node)
@ -1048,6 +1048,11 @@ class Connection:
self.dispatch('ROSTER_INFO', (jid, name, sub, ask, groups))
raise common.xmpp.NodeProcessed
def _DiscoverItemsErrorCB(self, con, iq_obj):
gajim.log.debug('DiscoverItemsErrorCB')
jid = iq_obj.getFrom()
self.dispatch('AGENT_ERROR_ITEMS', (jid))
def _DiscoverItemsCB(self, con, iq_obj):
gajim.log.debug('DiscoverItemsCB')
q = iq_obj.getTag('query')
@ -1066,12 +1071,17 @@ class Connection:
jid = unicode(iq_obj.getFrom())
self.dispatch('AGENT_INFO_ITEMS', (jid, node, items))
def _DiscoverInfoErrorCB(self, con, iq_obj):
gajim.log.debug('DiscoverInfoErrorCB')
jid = iq_obj.getFrom()
self.dispatch('AGENT_ERROR_INFO', (jid))
def _DiscoverInfoCB(self, con, iq_obj):
gajim.log.debug('DiscoverInfoCB')
# According to JEP-0030:
# For identity: category, name is mandatory, type is optional.
# For identity: category, type is mandatory, name is optional.
# For feature: var is mandatory
identities, features = [], []
identities, features, data = [], [], []
q = iq_obj.getTag('query')
node = q.getAttr('node')
if not node:
@ -1087,9 +1097,12 @@ class Connection:
identities.append(attr)
elif i.getName() == 'feature':
features.append(i.getAttr('var'))
elif i.getName() == 'x' and i.getAttr('xmlns') == NS_DATA:
data.append(common.xmpp.DataForm(node=i))
jid = unicode(iq_obj.getFrom())
if identities: #if not: an error occured
self.dispatch('AGENT_INFO_INFO', (jid, node, identities, features))
self.dispatch('AGENT_INFO_INFO', (jid, node, identities,
features, data))
def _VersionCB(self, con, iq_obj):
gajim.log.debug('VersionCB')
@ -1487,8 +1500,12 @@ class Connection:
common.xmpp.NS_BYTESTREAM)
con.RegisterHandler('iq', self._DiscoverItemsCB, 'result',
common.xmpp.NS_DISCO_ITEMS)
con.RegisterHandler('iq', self._DiscoverItemsErrorCB, 'error',
common.xmpp.NS_DISCO_ITEMS)
con.RegisterHandler('iq', self._DiscoverInfoCB, 'result',
common.xmpp.NS_DISCO_INFO)
con.RegisterHandler('iq', self._DiscoverInfoErrorCB, 'error',
common.xmpp.NS_DISCO_INFO)
con.RegisterHandler('iq', self._VersionCB, 'get',
common.xmpp.NS_VERSION)
con.RegisterHandler('iq', self._VersionResultCB, 'result',
@ -1789,13 +1806,6 @@ class Connection:
self.connection.getRoster().setItem(jid = jid, name = name,
groups = groups)
def request_agents(self, jid, node):
if self.connection:
iq = common.xmpp.Iq(to = jid, typ = 'get',
queryNS = common.xmpp.NS_DISCO_ITEMS)
if node: iq.setQuerynode(node)
self.to_be_sent.append(iq)
def request_register_agent_info(self, agent):
if not self.connection:
return None

View File

@ -60,7 +60,7 @@ def discoverInfo(disp,jid,node=None):
""" Query remote object about info that it publishes. Returns identities and features lists."""
""" According to JEP-0030:
query MAY have node attribute
identity: MUST HAVE category and name attributes and MAY HAVE type attribute.
identity: MUST HAVE category and type attributes and MAY HAVE name attribute.
feature: MUST HAVE var attribute"""
identities , features = [] , []
for i in _discover(disp,NS_DISCO_INFO,jid,node):

View File

@ -1282,7 +1282,7 @@ _('To change the account name, you must be disconnected.')).get_response()
gajim.events_for_ui[name] = gajim.events_for_ui[self.account]
#upgrade account variable in opened windows
for kind in ('infos', 'chats', 'gc', 'gc_config'):
for kind in ('infos', 'disco', 'chats', 'gc', 'gc_config'):
for j in gajim.interface.windows[name][kind]:
gajim.interface.windows[name][kind][j].account = name
@ -1346,8 +1346,8 @@ _('To change the account name, you must be disconnected.')).get_response()
if config['savepass']:
gajim.connections[name].password = config['password']
#update variables
gajim.interface.windows[name] = {'infos': {}, 'chats': {}, 'gc': {}, \
'gc_config': {}}
gajim.interface.windows[name] = {'infos': {}, 'disco': {}, 'chats': {},
'gc': {}, 'gc_config': {}}
gajim.interface.windows[name]['xml_console'] = \
dialogs.XMLConsoleWindow(name)
gajim.awaiting_events[name] = {}
@ -2162,315 +2162,6 @@ class ManageEmoticonsWindow:
if event.keyval == gtk.keysyms.Delete:
self.on_button_remove_emoticon_clicked(widget)
#---------- ServiceDiscoveryWindow class -------------#
class ServiceDiscoveryWindow:
'''Class for Service Discovery Window:
to know the services on a server'''
def on_service_discovery_window_destroy(self, widget):
del gajim.interface.windows[self.account]['disco']
def on_close_button_clicked(self, widget):
self.window.destroy()
def __init__(self, account):
self.account = account
self.agent_infos = {}
self.items_asked = [] #we already asked items to these jids
if gajim.connections[account].connected < 2:
dialogs.ErrorDialog(_('You are not connected to the server'),
_('Without a connection, you can not browse available services')).get_response()
raise RuntimeError, 'You must be connected to browse services'
xml = gtk.glade.XML(GTKGUI_GLADE, 'service_discovery_window', APP)
self.window = xml.get_widget('service_discovery_window')
if len(gajim.connections):
self.window.set_title(_('Service Discovery using %s account') %account)
else:
self.window.set_title(_('Service Discovery'))
self.services_treeview = xml.get_widget('services_treeview')
self.join_button = xml.get_widget('join_button')
self.register_button = xml.get_widget('register_button')
self.address_comboboxentry = xml.get_widget('address_comboboxentry')
self.address_comboboxentry_entry = self.address_comboboxentry.child
self.address_comboboxentry_entry.set_activates_default(True)
model = gtk.TreeStore(str, str, str)
model.set_sort_column_id(0, gtk.SORT_ASCENDING)
self.services_treeview.set_model(model)
#columns
renderer = gtk.CellRendererText()
renderer.set_data('column', 0)
col = self.services_treeview.insert_column_with_attributes(-1,
_('Name'), renderer, text = 0)
col.set_resizable(True)
renderer = gtk.CellRendererText()
renderer.set_data('column', 1)
col = self.services_treeview.insert_column_with_attributes(-1,
_('Service'), renderer, text = 1)
col.set_resizable(True)
renderer = gtk.CellRendererText()
renderer.set_data('column', 1)
col = self.services_treeview.insert_column_with_attributes(-1,
_('Node'), renderer, text = 2)
col.set_resizable(True)
self.address_comboboxentry = xml.get_widget('address_comboboxentry')
liststore = gtk.ListStore(str)
self.address_comboboxentry.set_model(liststore)
self.address_comboboxentry.set_text_column(0)
self.latest_addresses = gajim.config.get('latest_disco_addresses').split()
server_address = gajim.get_hostname_from_account(self.account)
if server_address in self.latest_addresses:
self.latest_addresses.remove(server_address)
self.latest_addresses.insert(0, server_address)
if len(self.latest_addresses) > 10:
self.latest_addresses = self.latest_addresses[0:10]
for j in self.latest_addresses:
self.address_comboboxentry.append_text(j)
self.address_comboboxentry.child.set_text(server_address)
self.register_button.set_sensitive(False)
self.join_button.set_sensitive(False)
xml.signal_autoconnect(self)
self.browse(server_address)
self.window.show_all()
def browse(self, jid, node = ''):
'''Send a request to the core to know the available services'''
model = self.services_treeview.get_model()
if not model.get_iter_first():
# we begin to fill the treevier with the first line
iter = model.append(None, (jid, jid, node))
self.agent_infos[jid] = {'features' : []}
gajim.connections[self.account].request_agents(jid, node)
self.items_asked.append(jid+node)
def agents(self, agents):
'''When list of available agent arrive:
Fill the treeview with it'''
model = self.services_treeview.get_model()
for agent in agents:
node = ''
if agent.has_key('node'):
node = agent['node']
iter = model.append(None, (agent['name'], agent['jid'], node))
self.agent_infos[agent['jid'] + node] = {'features' : []}
def iter_is_visible(self, iter):
if not iter:
return False
model = self.services_treeview.get_model()
iter = model.iter_parent(iter)
while iter:
if not self.services_treeview.row_expanded(model.get_path(iter)):
return False
iter = model.iter_parent(iter)
return True
def on_services_treeview_row_expanded(self, widget, iter, path):
model = self.services_treeview.get_model()
if model.iter_n_children(iter) > 15:
return
child = model.iter_children(iter)
while child:
child_jid = model.get_value(child, 1).decode('utf-8')
child_node = model.get_value(child, 2).decode('utf-8')
# We never requested its infos
if child_jid + child_node not in self.items_asked:
self.browse(child_jid, child_node)
child = model.iter_next(child)
def agent_info_info(self, agent, node, identities, features):
'''When we recieve informations about an agent, but not its items'''
model = self.services_treeview.get_model()
iter = model.get_iter_root()
# We look if this agent is in the treeview
while (iter):
if agent == model[iter][1].decode('utf-8') and\
node == model.get_value(iter, 2).decode('utf-8'):
break
if model.iter_has_child(iter):
iter = model.iter_children(iter)
else:
if not model.iter_next(iter):
iter = model.iter_parent(iter)
if iter:
iter = model.iter_next(iter)
if not iter: #If it is not we stop
return
self.agent_infos[agent + node]['features'] = features
if len(identities):
self.agent_infos[agent + node]['identities'] = identities
if identities[0].has_key('name'):
model.set_value(iter, 0, identities[0]['name'])
self.update_buttons()
def agent_info_items(self, agent, node, items, do_browse = True):
'''When we recieve items about an agent'''
model = self.services_treeview.get_model()
iter = model.get_iter_root()
# We look if this agent is in the treeview
while (iter):
if agent == model[iter][1].decode('utf-8') and\
node == model.get_value(iter, 2).decode('utf-8'):
break
if model.iter_has_child(iter):
iter = model.iter_children(iter)
else:
if not model.iter_next(iter):
iter = model.iter_parent(iter)
if iter:
iter = model.iter_next(iter)
if not iter: #If it is not, we stop
return
expand = False
if len(model.get_path(iter)) == 1:
expand = True
for item in items:
name = ''
if item.has_key('name'):
name = item['name']
node = ''
if item.has_key('node'):
node = item['node']
# We look if this item is already in the treeview
iter_child = model.iter_children(iter)
while iter_child:
if item['jid'] == model.get_value(iter_child, 1).decode('utf-8') and\
node == model.get_value(iter_child, 2).decode('utf-8'):
break
iter_child = model.iter_next(iter_child)
if not iter_child: # If it is not we add it
iter_child = model.append(iter, (name, item['jid'], node))
self.agent_infos[item['jid'] + node] = {'identities': [item]}
else:
self.agent_infos[item['jid'] + node]['identities'] = [item]
if self.iter_is_visible(iter_child) and not expand and do_browse:
self.browse(item['jid'], node)
if expand:
self.services_treeview.expand_row((model.get_path(iter)), False)
def agent_info(self, agent, identities, features, items):
'''When we recieve informations about an agent'''
self.agent_info_info(agent, '', identities, features)
self.agent_info_items(agent, '', items, False)
def on_refresh_button_clicked(self, widget):
'''When refresh button is clicked: refresh list: clear and rerequest it'''
self.services_treeview.get_model().clear()
self.items_asked = []
jid = self.address_comboboxentry.child.get_text().decode('utf-8')
self.browse(jid)
def on_address_comboboxentry_changed(self, widget):
'is executed on each keypress'
if self.address_comboboxentry.get_active() != -1:
# user selected one of the entries so do auto-visit
self.services_treeview.get_model().clear()
self.items_asked = []
server_address = self.address_comboboxentry.child.get_text().decode('utf-8')
self.browse(server_address)
def on_services_treeview_row_activated(self, widget, path, col = 0):
'''When a row is activated: Register or join the selected agent'''
#if both buttons are sensitive, it will register [default]
if self.register_button.get_property('sensitive'):
self.on_register_button_clicked(widget)
elif self.join_button.get_property('sensitive'):
self.on_join_button_clicked(widget)
def on_join_button_clicked(self, widget):
'''When we want to join a conference:
Ask specific informations about the selected agent and close the window'''
model, iter = self.services_treeview.get_selection().get_selected()
if not iter:
return
service = model[iter][1].decode('utf-8')
room = ''
if service.find('@') != -1:
services = service.split('@')
room = services[0]
service = services[1]
if not gajim.interface.windows[self.account].has_key('join_gc'):
dialogs.JoinGroupchatWindow(self.account, service, room)
else:
gajim.interface.windows[self.account]['join_gc'].window.present()
def on_register_button_clicked(self, widget):
'''When we want to register an agent:
Ask specific informations about the selected agent and close the window'''
model, iter = self.services_treeview.get_selection().get_selected()
if not iter :
return
service = model[iter][1].decode('utf-8')
gajim.connections[self.account].request_register_agent_info(service)
self.window.destroy()
def update_buttons(self):
self.join_button.set_sensitive(False)
self.register_button.set_sensitive(False)
model, iter = self.services_treeview.get_selection().get_selected()
if not iter:
return
path = model.get_path(iter)
if len(path) == 1: # we selected the jabber server
return
jid = model[iter][1].decode('utf-8')
node = model[iter][2].decode('utf-8')
registered_transports = []
contacts = gajim.contacts[self.account]
for j in contacts:
if _('Transports') in contacts[j][0].groups:
registered_transports.append(j)
if jid in registered_transports:
self.register_button.set_label(_('_Edit'))
else:
self.register_button.set_label(_('Re_gister'))
if self.agent_infos[jid + node].has_key('features'):
if common.xmpp.NS_REGISTER in self.agent_infos[jid + node]['features']:
self.register_button.set_sensitive(True)
if self.agent_infos[jid + node].has_key('identities') and \
len(self.agent_infos[jid + node]['identities']):
if self.agent_infos[jid + node]['identities'][0].has_key('category'):
if self.agent_infos[jid + node]['identities'][0]['category'] == \
'conference':
self.join_button.set_sensitive(True)
def on_services_treeview_cursor_changed(self, widget):
'''When we select a row :
activate buttons if needed'''
self.update_buttons()
model, iter = self.services_treeview.get_selection().get_selected()
if not iter:
return
path = model.get_path(iter)
if len(path) == 1: # we selected the jabber server
return
jid = model[iter][1].decode('utf-8')
node = model[iter][2].decode('utf-8')
if jid+node not in self.items_asked:
self.browse(jid, node)
if not self.agent_infos[jid + node].has_key('features'):
gajim.connections[self.account].discoverInfo(jid, node)
def on_go_button_clicked(self, widget):
server_address = self.address_comboboxentry.child.get_text().decode('utf-8')
if server_address in self.latest_addresses:
self.latest_addresses.remove(server_address)
self.latest_addresses.insert(0, server_address)
if len(self.latest_addresses) > 10:
self.latest_addresses = self.latest_addresses[0:10]
self.address_comboboxentry.get_model().clear()
for j in self.latest_addresses:
self.address_comboboxentry.append_text(j)
gajim.config.set('latest_disco_addresses',
' '.join(self.latest_addresses))
self.services_treeview.get_model().clear()
self.items_asked = []
self.browse(server_address)
gajim.interface.save_config()
class GroupchatConfigWindow(DataFormWindow):
'''GroupchatConfigWindow class'''
def __init__(self, account, room_jid, config):
@ -2997,8 +2688,8 @@ _('You need to enter a valid server address to continue.')).get_response()
if config['savepass']:
gajim.connections[name].password = config['password']
# update variables
gajim.interface.windows[name] = {'infos': {}, 'chats': {}, 'gc': {},
'gc_config': {}}
gajim.interface.windows[name] = {'infos': {}, 'disco': {}, 'chats': {},
'gc': {}, 'gc_config': {}}
gajim.interface.windows[name]['xml_console'] = \
dialogs.XMLConsoleWindow(name)
gajim.awaiting_events[name] = {}

1447
src/disco.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -148,6 +148,7 @@ import roster_window
import systray
import dialogs
import config
import disco
GTKGUI_GLADE = 'gtkgui.glade'
@ -230,7 +231,6 @@ class Interface:
def allow_notif(self, account):
gajim.allow_notifications[account] = True
def handle_event_status(self, account, status): # OUR status
#('STATUS', account, status)
model = self.roster.status_combobox.get_model()
@ -565,12 +565,20 @@ class Interface:
_('You will always see him as offline.'))
if self.remote and self.remote.is_enabled():
self.remote.raise_signal('Unsubscribed', (account, jid))
def handle_event_agent_info(self, account, array):
#('AGENT_INFO', account, (agent, identities, features, items))
if self.windows[account].has_key('disco'):
self.windows[account]['disco'].agent_info(array[0], array[1], \
array[2], array[3])
def handle_event_agent_info_error(self, account, agent):
#('AGENT_ERROR_INFO', account, (agent))
try:
gajim.connections[account].services_cache.agent_info_error(agent)
except AttributeError:
return
def handle_event_agent_items_error(self, account, agent):
#('AGENT_ERROR_INFO', account, (agent))
try:
gajim.connections[account].services_cache.agent_items_error(agent)
except AttributeError:
return
def handle_event_register_agent_info(self, account, array):
#('REGISTER_AGENT_INFO', account, (agent, infos, is_form))
@ -583,15 +591,19 @@ class Interface:
def handle_event_agent_info_items(self, account, array):
#('AGENT_INFO_ITEMS', account, (agent, node, items))
if self.windows[account].has_key('disco'):
self.windows[account]['disco'].agent_info_items(array[0], array[1],
array[2])
try:
gajim.connections[account].services_cache.agent_items(array[0],
array[1], array[2])
except AttributeError:
return
def handle_event_agent_info_info(self, account, array):
#('AGENT_INFO_INFO', account, (agent, node, identities, features))
if self.windows[account].has_key('disco'):
self.windows[account]['disco'].agent_info_info(array[0], array[1], \
array[2], array[3])
#('AGENT_INFO_INFO', account, (agent, node, identities, features, data))
try:
gajim.connections[account].services_cache.agent_info(array[0],
array[1], array[2], array[3], array[4])
except AttributeError:
return
def handle_event_acc_ok(self, account, array):
#('ACC_OK', account, (name, config))
@ -603,7 +615,8 @@ class Interface:
gajim.config.set_per('accounts', name, opt, array[1][opt])
if self.windows.has_key('account_modification'):
self.windows['account_modification'].account_is_ok(array[0])
self.windows[name] = {'infos': {}, 'chats': {}, 'gc': {}, 'gc_config': {}}
self.windows[name] = {'infos': {}, 'disco': {}, 'chats': {},
'gc': {}, 'gc_config': {}}
self.windows[name]['xml_console'] = dialogs.XMLConsoleWindow(name)
gajim.awaiting_events[name] = {}
# disconnect from server - our status in roster is offline
@ -1119,7 +1132,8 @@ class Interface:
'SUBSCRIBED': self.handle_event_subscribed,
'UNSUBSCRIBED': self.handle_event_unsubscribed,
'SUBSCRIBE': self.handle_event_subscribe,
'AGENT_INFO': self.handle_event_agent_info,
'AGENT_ERROR_INFO': self.handle_event_agent_info_error,
'AGENT_ERROR_ITEMS': self.handle_event_agent_items_error,
'REGISTER_AGENT_INFO': self.handle_event_register_agent_info,
'AGENT_INFO_ITEMS': self.handle_event_agent_info_items,
'AGENT_INFO_INFO': self.handle_event_agent_info_info,
@ -1275,7 +1289,8 @@ class Interface:
self.avatar_pixbufs = {}
for a in gajim.connections:
self.windows[a] = {'infos': {}, 'chats': {}, 'gc': {}, 'gc_config': {}}
self.windows[a] = {'infos': {}, 'disco': {}, 'chats': {},
'gc': {}, 'gc_config': {}}
gajim.contacts[a] = {}
gajim.groups[a] = {}
gajim.gc_contacts[a] = {}

View File

@ -2661,13 +2661,11 @@
</widget>
<widget class="GtkWindow" id="service_discovery_window">
<property name="border_width">12</property>
<property name="border_width">13</property>
<property name="title" translatable="yes"></property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="default_width">500</property>
<property name="default_height">300</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
@ -2685,7 +2683,54 @@
<property name="spacing">12</property>
<child>
<widget class="GtkHBox" id="hbox2942">
<widget class="GtkEventBox" id="banner_agent_eventbox">
<property name="visible">True</property>
<property name="visible_window">True</property>
<property name="above_child">False</property>
<child>
<widget class="GtkHBox" id="banner_agent_hbox">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="banner_agent_label">
<property name="visible">True</property>
<property name="label">&lt;span weight=&quot;heavy&quot; size=&quot;large&quot;&gt;Agent name&lt;/span&gt;
Agent JID - node</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.0500000007451</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">6</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="address_hbox">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
@ -2718,6 +2763,7 @@
<child>
<widget class="GtkComboBoxEntry" id="address_comboboxentry">
<property name="width_request">250</property>
<property name="visible">True</property>
<property name="add_tearoffs">False</property>
<property name="has_frame">True</property>
@ -2733,81 +2779,17 @@
</child>
<child>
<widget class="GtkButton" id="go_button">
<widget class="GtkButton" id="browse_button">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Go</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_go_button_clicked" last_modification_time="Sun, 27 Mar 2005 08:47:16 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="scrolledwindow9">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
<widget class="GtkTreeView" id="services_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">True</property>
<property name="rules_hint">False</property>
<property name="reorderable">False</property>
<property name="enable_search">True</property>
<property name="fixed_height_mode">False</property>
<property name="hover_selection">False</property>
<property name="hover_expand">False</property>
<signal name="row_activated" handler="on_services_treeview_row_activated" last_modification_time="Mon, 28 Mar 2005 00:28:25 GMT"/>
<signal name="cursor_changed" handler="on_services_treeview_cursor_changed" last_modification_time="Mon, 28 Mar 2005 00:28:33 GMT"/>
<signal name="row_expanded" handler="on_services_treeview_row_expanded" last_modification_time="Mon, 28 Mar 2005 00:28:39 GMT"/>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkHButtonBox" id="hbuttonbox4">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<property name="spacing">6</property>
<child>
<widget class="GtkButton" id="refresh_button">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_refresh_button_clicked" last_modification_time="Tue, 01 Mar 2005 14:17:42 GMT"/>
<signal name="clicked" handler="on_go_button_clicked" last_modification_time="Sun, 04 Sep 2005 20:37:26 GMT"/>
<child>
<widget class="GtkAlignment" id="alignment16">
<widget class="GtkAlignment" id="alignment93">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
@ -2819,15 +2801,15 @@
<property name="right_padding">0</property>
<child>
<widget class="GtkHBox" id="hbox20">
<widget class="GtkHBox" id="hbox2995">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">2</property>
<child>
<widget class="GtkImage" id="image105">
<widget class="GtkImage" id="image1148">
<property name="visible">True</property>
<property name="stock">gtk-refresh</property>
<property name="stock">gtk-jump-to</property>
<property name="icon_size">4</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
@ -2842,10 +2824,9 @@
</child>
<child>
<widget class="GtkLabel" id="label29">
<widget class="GtkLabel" id="label362">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_Refresh</property>
<property name="label" translatable="yes">G_o</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
@ -2871,44 +2852,158 @@
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkScrolledWindow" id="services_scrollwin">
<property name="height_request">200</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
<child>
<widget class="GtkButton" id="register_button">
<widget class="GtkTreeView" id="services_treeview">
<property name="height_request">150</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Re_gister</property>
<property name="headers_visible">False</property>
<property name="rules_hint">False</property>
<property name="reorderable">False</property>
<property name="enable_search">True</property>
<property name="fixed_height_mode">False</property>
<property name="hover_selection">False</property>
<property name="hover_expand">False</property>
<signal name="row_activated" handler="on_services_treeview_row_activated" last_modification_time="Mon, 28 Mar 2005 00:28:25 GMT"/>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="filter_hbox">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">6</property>
<child>
<widget class="GtkLabel" id="label361">
<property name="visible">True</property>
<property name="label" translatable="yes">_Filter:</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_register_button_clicked" last_modification_time="Sat, 26 Mar 2005 15:07:31 GMT"/>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="mnemonic_widget">filter_entry</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="join_button">
<widget class="GtkEntry" id="filter_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_Join</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_join_button_clicked" last_modification_time="Sat, 26 Mar 2005 15:08:01 GMT"/>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">*</property>
<property name="activates_default">False</property>
<signal name="changed" handler="on_filter_entry_changed" last_modification_time="Sun, 04 Sep 2005 11:35:21 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox2994">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">12</property>
<child>
<widget class="GtkProgressBar" id="services_progressbar">
<property name="visible">True</property>
<property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
<property name="fraction">0</property>
<property name="pulse_step">0.10000000149</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="close_button">
<widget class="GtkHButtonBox" id="action_buttonbox">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="label">gtk-close</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_close_button_clicked" last_modification_time="Sat, 26 Mar 2005 15:05:59 GMT"/>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<property name="spacing">6</property>
<child>
<widget class="GtkButton" id="close_button">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="label">gtk-close</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_close_button_clicked" last_modification_time="Sat, 26 Mar 2005 15:05:59 GMT"/>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>

View File

@ -31,6 +31,7 @@ import groupchat_window
import history_window
import dialogs
import config
import disco
import gtkgui_helpers
import cell_renderer_image
import tooltips
@ -1971,13 +1972,13 @@ _('If "%s" accepts this request you will know his status.') %jid)
model.set_value(iter, 5, False)
def on_service_disco_menuitem_activate(self, widget, account):
if gajim.interface.windows[account].has_key('disco'):
gajim.interface.windows[account]['disco'].window.present()
server_jid = gajim.config.get_per('accounts', account, 'hostname')
if gajim.interface.windows[account]['disco'].has_key(server_jid):
gajim.interface.windows[account]['disco'][server_jid].window.present()
else:
# c http://nkour.blogspot.com/2005/05/pythons-init-return-none-doesnt-return.html
try:
gajim.interface.windows[account]['disco'] = \
config.ServiceDiscoveryWindow(account)
# Object will add itself to the window dict
disco.ServiceDiscoveryWindow(account, address_entry=True)
except RuntimeError:
pass
@ -2044,6 +2045,8 @@ _('If "%s" accepts this request you will know his status.') %jid)
gajim.interface.windows[account]['chats'][jid].repaint_colored_widgets()
for jid in gajim.interface.windows[account]['gc']:
gajim.interface.windows[account]['gc'][jid].repaint_colored_widgets()
for addr in gajim.interface.windows[account]['disco']:
gajim.interface.windows[account]['disco'][addr].paint_banner()
def on_show_offline_contacts_menuitem_activate(self, widget):
'''when show offline option is changed: