Merge one_window branch

Merged revisions 9143,9145-9155,9157-9162,9164-9169,9171-9177 via svnmerge from
svn://88.191.11.156/gajim/branches/one_window

........
  r9145 | nicfit | 2007-12-13 21:49:09 -0700 (Thu, 13 Dec 2007) | 2 lines

  Implemented the original Nikos patch with an HPaned instead of a HBox and only do this mode when one_message_window == 'always'
........
  r9152 | nicfit | 2007-12-15 13:33:56 -0700 (Sat, 15 Dec 2007) | 2 lines

  Added config and GUI for one_message_window_with_roster
........
  r9153 | nicfit | 2007-12-15 13:41:46 -0700 (Sat, 15 Dec 2007) | 2 lines

  Use one_message_window_with_roster and some whitespace cleanup
........
  r9154 | nicfit | 2007-12-15 14:04:49 -0700 (Sat, 15 Dec 2007) | 2 lines

  Scratch the chckbox for with roster mode, use one_message_window opt and combo
........
  r9155 | nicfit | 2007-12-15 17:01:13 -0700 (Sat, 15 Dec 2007) | 2 lines

  MessageWindowMgr knows about ONE_MESSAGE_WINDOW_ALWAYS_WITH_ROSTER and MessageWindow can reparent itself rather then the roster having to do so.
........
  r9157 | nicfit | 2007-12-15 17:47:20 -0700 (Sat, 15 Dec 2007) | 2 lines

  Resizing fixes and make the roster window shrink when last tab is removed
........
  r9158 | nicfit | 2007-12-15 19:15:11 -0700 (Sat, 15 Dec 2007) | 2 lines

  Added "Show roster" (CTRL+R) to view menu when using always_with_roster to quickly hide/show the roster.
........
  r9159 | nicfit | 2007-12-15 19:49:30 -0700 (Sat, 15 Dec 2007) | 2 lines

  Handle window title setting in always_with_roster mode.
........
  r9160 | nicfit | 2007-12-15 20:13:57 -0700 (Sat, 15 Dec 2007) | 2 lines

  Removed FIXME
........
  r9167 | nicfit | 2007-12-17 18:40:59 -0700 (Mon, 17 Dec 2007) | 2 lines

  When roster is hidden, show it when the number of MessageWindow controls == 0
........
  r9168 | nicfit | 2007-12-17 19:07:49 -0700 (Mon, 17 Dec 2007) | 2 lines

  Disable hiding roster when there are no message controls open
........
  r9169 | nicfit | 2007-12-17 20:41:11 -0700 (Mon, 17 Dec 2007) | 2 lines

  Bunch of saved size bugs fixed
........
This commit is contained in:
Travis Shirk 2007-12-18 23:42:22 +00:00
parent e7d711e753
commit 0afc7b2328
8 changed files with 718 additions and 579 deletions

File diff suppressed because it is too large Load diff

View file

@ -230,6 +230,17 @@
<signal name="activate" handler="on_show_transports_menuitem_activate"/> <signal name="activate" handler="on_show_transports_menuitem_activate"/>
</widget> </widget>
</child> </child>
<child>
<widget class="GtkCheckMenuItem" id="show_roster_menuitem">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="label" translatable="yes">Show _roster</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<signal name="toggled" handler="on_show_roster_menuitem_toggled"/>
<accelerator key="R" modifiers="GDK_CONTROL_MASK" signal="activate"/>
</widget>
</child>
<child> <child>
<widget class="GtkSeparatorMenuItem" id="separator3"> <widget class="GtkSeparatorMenuItem" id="separator3">
<property name="visible">True</property> <property name="visible">True</property>
@ -352,45 +363,65 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkScrolledWindow" id="scrolledwindow"> <widget class="GtkHPaned" id="roster_hpaned">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="border_width">2</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<child> <child>
<widget class="GtkTreeView" id="roster_treeview"> <widget class="GtkVBox" id="roster_vbox2">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="headers_visible">False</property> <child>
<property name="reorderable">True</property> <widget class="GtkScrolledWindow" id="scrolledwindow">
<signal name="leave_notify_event" handler="on_roster_treeview_leave_notify_event"/> <property name="visible">True</property>
<signal name="button_press_event" handler="on_roster_treeview_button_press_event"/> <property name="can_focus">True</property>
<signal name="motion_notify_event" handler="on_roster_treeview_motion_notify_event"/> <property name="border_width">2</property>
<signal name="row_collapsed" handler="on_roster_treeview_row_collapsed"/> <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
<signal name="row_expanded" handler="on_roster_treeview_row_expanded"/> <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
<signal name="key_press_event" handler="on_roster_treeview_key_press_event"/> <child>
<signal name="row_activated" handler="on_roster_treeview_row_activated"/> <widget class="GtkTreeView" id="roster_treeview">
<signal name="button_release_event" handler="on_roster_treeview_button_release_event"/> <property name="visible">True</property>
<signal name="scroll_event" handler="on_roster_treeview_scroll_event"/> <property name="can_focus">True</property>
<signal name="style_set" handler="on_roster_treeview_style_set"/> <property name="headers_visible">False</property>
<property name="reorderable">True</property>
<signal name="leave_notify_event" handler="on_roster_treeview_leave_notify_event"/>
<signal name="button_press_event" handler="on_roster_treeview_button_press_event"/>
<signal name="motion_notify_event" handler="on_roster_treeview_motion_notify_event"/>
<signal name="row_collapsed" handler="on_roster_treeview_row_collapsed"/>
<signal name="row_expanded" handler="on_roster_treeview_row_expanded"/>
<signal name="key_press_event" handler="on_roster_treeview_key_press_event"/>
<signal name="row_activated" handler="on_roster_treeview_row_activated"/>
<signal name="button_release_event" handler="on_roster_treeview_button_release_event"/>
<signal name="scroll_event" handler="on_roster_treeview_scroll_event"/>
<signal name="style_set" handler="on_roster_treeview_style_set"/>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkComboBox" id="status_combobox">
<property name="visible">True</property>
<signal name="changed" handler="on_status_combobox_changed"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget> </widget>
<packing>
<property name="resize">False</property>
<property name="shrink">True</property>
</packing>
</child>
<child>
<placeholder/>
</child> </child>
</widget> </widget>
<packing> <packing>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkComboBox" id="status_combobox">
<property name="visible">True</property>
<signal name="changed" handler="on_status_combobox_changed"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">2</property>
</packing>
</child>
</widget> </widget>
</child> </child>
</widget> </widget>

View file

@ -45,7 +45,7 @@ opt_int = [ 'integer', 0 ]
opt_str = [ 'string', 0 ] opt_str = [ 'string', 0 ]
opt_bool = [ 'boolean', 0 ] opt_bool = [ 'boolean', 0 ]
opt_color = [ 'color', '^(#[0-9a-fA-F]{6})|()$' ] opt_color = [ 'color', '^(#[0-9a-fA-F]{6})|()$' ]
opt_one_window_types = ['never', 'always', 'peracct', 'pertype'] opt_one_window_types = ['never', 'always', 'always_with_roster', 'peracct', 'pertype']
opt_treat_incoming_messages = ['', 'chat', 'normal'] opt_treat_incoming_messages = ['', 'chat', 'normal']
class Config: class Config:
@ -229,7 +229,7 @@ class Config:
'send_sha_in_gc_presence': [opt_bool, True, _('Jabberd1.4 does not like sha info when one join a password protected group chat. Turn this option to False to stop sending sha info in group chat presences.')], 'send_sha_in_gc_presence': [opt_bool, True, _('Jabberd1.4 does not like sha info when one join a password protected group chat. Turn this option to False to stop sending sha info in group chat presences.')],
'one_message_window': [opt_str, 'always', 'one_message_window': [opt_str, 'always',
#always, never, peracct, pertype should not be translated #always, never, peracct, pertype should not be translated
_('Controls the window where new messages are placed.\n\'always\' - All messages are sent to a single window.\n\'never\' - All messages get their own window.\n\'peracct\' - Messages for each account are sent to a specific window.\n\'pertype\' - Each message type (e.g., chats vs. groupchats) are sent to a specific window. Note, changing this option requires restarting Gajim before the changes will take effect.')], _('Controls the window where new messages are placed.\n\'always\' - All messages are sent to a single window.\n\'always_with_roster\' - Like \'always\' but the messages are in a single window along with the roster.\n\'never\' - All messages get their own window.\n\'peracct\' - Messages for each account are sent to a specific window.\n\'pertype\' - Each message type (e.g., chats vs. groupchats) are sent to a specific window.')],
'show_avatar_in_chat': [opt_bool, True, _('If False, you will no longer see the avatar in the chat window.')], 'show_avatar_in_chat': [opt_bool, True, _('If False, you will no longer see the avatar in the chat window.')],
'escape_key_closes': [opt_bool, True, _('If True, pressing the escape key closes a tab/window.')], 'escape_key_closes': [opt_bool, True, _('If True, pressing the escape key closes a tab/window.')],
'compact_view': [opt_bool, False, _('Hides the buttons in chat windows.')], 'compact_view': [opt_bool, False, _('Hides the buttons in chat windows.')],

View file

@ -6,6 +6,7 @@
## Copyright (C) 2003-2005 Vincent Hanquez <tab@snarc.org> ## Copyright (C) 2003-2005 Vincent Hanquez <tab@snarc.org>
## Copyright (C) 2006 Stefan Bethge <stefan@lanpartei.de> ## Copyright (C) 2006 Stefan Bethge <stefan@lanpartei.de>
## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de> ## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de>
## Copyright (C) 2007 Travis Shirk <travis@pobox.com>
## ##
## This file is part of Gajim. ## This file is part of Gajim.
## ##
@ -174,7 +175,7 @@ class PreferencesWindow:
# iconset # iconset
iconsets_list = os.listdir(os.path.join(gajim.DATA_DIR, 'iconsets')) iconsets_list = os.listdir(os.path.join(gajim.DATA_DIR, 'iconsets'))
if os.path.isdir(gajim.MY_ICONSETS_PATH): if os.path.isdir(gajim.MY_ICONSETS_PATH):
iconsets_list += os.listdir(gajim.MY_ICONSETS_PATH) iconsets_list += os.listdir(gajim.MY_ICONSETS_PATH)
# new model, image in 0, string in 1 # new model, image in 0, string in 1
model = gtk.ListStore(gtk.Image, str) model = gtk.ListStore(gtk.Image, str)
renderer_image = cell_renderer_image.CellRendererImage(0, 0) renderer_image = cell_renderer_image.CellRendererImage(0, 0)
@ -537,9 +538,9 @@ class PreferencesWindow:
self.on_msg_treemodel_row_deleted) self.on_msg_treemodel_row_deleted)
self.default_msg_tree.get_model().connect('row-changed', self.default_msg_tree.get_model().connect('row-changed',
self.on_default_msg_treemodel_row_changed) self.on_default_msg_treemodel_row_changed)
self.theme_preferences = None self.theme_preferences = None
self.notebook.set_current_page(0) self.notebook.set_current_page(0)
if not gajim.config.get('use_pep'): if not gajim.config.get('use_pep'):
self.notebook.remove_page(4) self.notebook.remove_page(4)

View file

@ -1,6 +1,6 @@
## message_control.py ## message_control.py
## ##
## Copyright (C) 2006 Travis Shirk <travis@pobox.com> ## Copyright (C) 2006-2007 Travis Shirk <travis@pobox.com>
## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de> ## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de>
## ##
## This file is part of Gajim. ## This file is part of Gajim.
@ -34,7 +34,7 @@ class MessageControl:
def __init__(self, type_id, parent_win, widget_name, contact, account, resource = None): def __init__(self, type_id, parent_win, widget_name, contact, account, resource = None):
# dict { cb id : widget} # dict { cb id : widget}
# keep all registered callbacks of widgets, created by self.xml # keep all registered callbacks of widgets, created by self.xml
self.handlers = {} self.handlers = {}
self.type_id = type_id self.type_id = type_id
self.parent_win = parent_win self.parent_win = parent_win
self.widget_name = widget_name self.widget_name = widget_name
@ -126,8 +126,8 @@ class MessageControl:
if self.session.enable_encryption: if self.session.enable_encryption:
was_encrypted = True was_encrypted = True
print "starting a new session, dropping the old one!" gajim.connections[self.account].delete_session(self.session.jid,
gajim.connections[self.account].delete_session(self.session.jid, self.session.thread_id) self.session.thread_id)
self.session = session self.session = session

View file

@ -6,10 +6,9 @@
## Vincent Hanquez <tab@snarc.org> ## Vincent Hanquez <tab@snarc.org>
## Nikos Kouremenos <kourem@gmail.com> ## Nikos Kouremenos <kourem@gmail.com>
## Dimitur Kirov <dkirov@gmail.com> ## Dimitur Kirov <dkirov@gmail.com>
## Travis Shirk <travis@pobox.com>
## Norman Rasmussen <norman@rasmussen.co.za> ## Norman Rasmussen <norman@rasmussen.co.za>
## Copyright (C) 2006 Travis Shirk <travis@pobox.com> ## Copyright (C) 2005-2007 Travis Shirk <travis@pobox.com>
## Geobert Quach <geobert@gmail.com> ## Copyright (C) 2006 Geobert Quach <geobert@gmail.com>
## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de> ## Copyright (C) 2007 Stephan Erb <steve-e@h3c.de>
## ##
## This file is part of Gajim. ## This file is part of Gajim.
@ -39,7 +38,7 @@ from common import gajim
#################### ####################
class MessageWindow: class MessageWindow(object):
'''Class for windows which contain message like things; chats, '''Class for windows which contain message like things; chats,
groupchats, etc.''' groupchats, etc.'''
@ -53,8 +52,8 @@ class MessageWindow:
CLOSE_COMMAND, CLOSE_COMMAND,
CLOSE_CTRL_KEY CLOSE_CTRL_KEY
) = range(5) ) = range(5)
def __init__(self, acct, type): def __init__(self, acct, type, parent_window=None, parent_paned=None):
# A dictionary of dictionaries where _contacts[account][jid] == A MessageControl # A dictionary of dictionaries where _contacts[account][jid] == A MessageControl
self._controls = {} self._controls = {}
# If None, the window is not tied to any specific account # If None, the window is not tied to any specific account
@ -68,6 +67,18 @@ class MessageWindow:
self.widget_name = 'message_window' self.widget_name = 'message_window'
self.xml = gtkgui_helpers.get_glade('%s.glade' % self.widget_name) self.xml = gtkgui_helpers.get_glade('%s.glade' % self.widget_name)
self.window = self.xml.get_widget(self.widget_name) self.window = self.xml.get_widget(self.widget_name)
self.notebook = self.xml.get_widget('notebook')
self.parent_paned = None
if parent_window:
orig_window = self.window
self.window = parent_window
self.parent_paned = parent_paned
self.notebook.reparent(self.parent_paned)
self.parent_paned.pack2(self.notebook, resize=True, shrink=True)
orig_window.destroy()
del orig_window
id = self.window.connect('delete-event', self._on_window_delete) id = self.window.connect('delete-event', self._on_window_delete)
self.handlers[id] = self.window self.handlers[id] = self.window
id = self.window.connect('destroy', self._on_window_destroy) id = self.window.connect('destroy', self._on_window_destroy)
@ -91,7 +102,6 @@ class MessageWindow:
self.window.add_events(gtk.gdk.POINTER_MOTION_MASK) self.window.add_events(gtk.gdk.POINTER_MOTION_MASK)
self.alignment = self.xml.get_widget('alignment') self.alignment = self.xml.get_widget('alignment')
self.notebook = self.xml.get_widget('notebook')
id = self.notebook.connect('switch-page', id = self.notebook.connect('switch-page',
self._on_notebook_switch_page) self._on_notebook_switch_page)
self.handlers[id] = self.notebook self.handlers[id] = self.notebook
@ -144,6 +154,9 @@ class MessageWindow:
n += len(dict) n += len(dict)
return n return n
def resize(self, width, height):
gtkgui_helpers.resize_window(self.window, width, height)
def _on_window_focus(self, widget, event): def _on_window_focus(self, widget, event):
# window received focus, so if we had urgency REMOVE IT # window received focus, so if we had urgency REMOVE IT
# NOTE: we do not have to read the message (it maybe in a bg tab) # NOTE: we do not have to read the message (it maybe in a bg tab)
@ -179,6 +192,8 @@ class MessageWindow:
for ctrl in self.controls(): for ctrl in self.controls():
ctrl.shutdown() ctrl.shutdown()
self._controls.clear() self._controls.clear()
# Clean up handlers connected to the parent window, this is important since
# self.window may be the RosterWindow
for i in self.handlers.keys(): for i in self.handlers.keys():
if self.handlers[i].handler_is_connected(i): if self.handlers[i].handler_is_connected(i):
self.handlers[i].disconnect(i) self.handlers[i].disconnect(i)
@ -210,8 +225,9 @@ class MessageWindow:
widget = xml.get_widget('tab_close_button') widget = xml.get_widget('tab_close_button')
id = widget.connect('clicked', self._on_close_button_clicked, control) id = widget.connect('clicked', self._on_close_button_clicked, control)
control.handlers[id] = widget control.handlers[id] = widget
id = tab_label_box.connect('button-press-event', self.on_tab_eventbox_button_press_event, control.widget) id = tab_label_box.connect('button-press-event', self.on_tab_eventbox_button_press_event,
control.widget)
control.handlers[id] = tab_label_box control.handlers[id] = tab_label_box
self.notebook.append_page(control.widget, tab_label_box) self.notebook.append_page(control.widget, tab_label_box)
@ -263,7 +279,7 @@ class MessageWindow:
if not control: if not control:
# No more control in this window # No more control in this window
return return
# CTRL mask # CTRL mask
if modifier & gtk.gdk.CONTROL_MASK: if modifier & gtk.gdk.CONTROL_MASK:
if keyval == gtk.keysyms.h: if keyval == gtk.keysyms.h:
@ -286,7 +302,7 @@ class MessageWindow:
# Tab switch bindings # Tab switch bindings
if keyval == gtk.keysyms.Right: # ALT + RIGHT if keyval == gtk.keysyms.Right: # ALT + RIGHT
new = self.notebook.get_current_page() + 1 new = self.notebook.get_current_page() + 1
if new >= self.notebook.get_n_pages(): if new >= self.notebook.get_n_pages():
new = 0 new = 0
self.notebook.set_current_page(new) self.notebook.set_current_page(new)
elif keyval == gtk.keysyms.Left: # ALT + LEFT elif keyval == gtk.keysyms.Left: # ALT + LEFT
@ -307,7 +323,7 @@ class MessageWindow:
'''When close button is pressed: close a tab''' '''When close button is pressed: close a tab'''
self.remove_tab(control, self.CLOSE_CLOSE_BUTTON) self.remove_tab(control, self.CLOSE_CLOSE_BUTTON)
def show_title(self, urgent = True, control = None): def show_title(self, urgent=True, control=None):
'''redraw the window's title''' '''redraw the window's title'''
if not control: if not control:
control = self.get_active_control() control = self.get_active_control()
@ -341,10 +357,7 @@ class MessageWindow:
name += '/' + control.resource name += '/' + control.resource
window_mode = gajim.interface.msg_win_mgr.mode window_mode = gajim.interface.msg_win_mgr.mode
if window_mode == MessageWindowMgr.ONE_MSG_WINDOW_PERTYPE:
if self.get_num_controls() == 1:
label = name
elif window_mode == MessageWindowMgr.ONE_MSG_WINDOW_PERTYPE:
# Show the plural form since number of tabs > 1 # Show the plural form since number of tabs > 1
if self.type == 'chat': if self.type == 'chat':
label = _('Chats') label = _('Chats')
@ -352,9 +365,16 @@ class MessageWindow:
label = _('Group Chats') label = _('Group Chats')
else: else:
label = _('Private Chats') label = _('Private Chats')
elif window_mode == MessageWindowMgr.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
label = None
elif self.get_num_controls() == 1:
label = name
else: else:
label = _('Messages') label = _('Messages')
title = _('%s - Gajim') % label
title = 'Gajim'
if label:
title = _('%s - %s') % (label, title)
if window_mode == MessageWindowMgr.ONE_MSG_WINDOW_PERACCT: if window_mode == MessageWindowMgr.ONE_MSG_WINDOW_PERACCT:
title = title + ": " + control.account title = title + ": " + control.account
@ -370,7 +390,7 @@ class MessageWindow:
ctrl = self._controls[acct][jid] ctrl = self._controls[acct][jid]
ctrl_page = self.notebook.page_num(ctrl.widget) ctrl_page = self.notebook.page_num(ctrl.widget)
self.notebook.set_current_page(ctrl_page) self.notebook.set_current_page(ctrl_page)
def remove_tab(self, ctrl, method, reason = None, force = False): def remove_tab(self, ctrl, method, reason = None, force = False):
'''reason is only for gc (offline status message) '''reason is only for gc (offline status message)
if force is True, do not ask any confirmation''' if force is True, do not ask any confirmation'''
@ -413,7 +433,13 @@ class MessageWindow:
gajim.interface.msg_win_mgr._on_window_destroy(self.window) gajim.interface.msg_win_mgr._on_window_destroy(self.window)
# dnd clean up # dnd clean up
self.notebook.drag_dest_unset() self.notebook.drag_dest_unset()
self.window.destroy() if self.parent_paned:
# Don't close parent window, just remove the child
child = self.parent_paned.get_child2()
self.parent_paned.remove(child)
# FIXME: restore preferred roster size
else:
self.window.destroy()
return # don't show_title, we are dead return # don't show_title, we are dead
elif self.get_num_controls() == 1: # we are going from two tabs to one elif self.get_num_controls() == 1: # we are going from two tabs to one
show_tabs_if_one_tab = gajim.config.get('tabs_always_visible') show_tabs_if_one_tab = gajim.config.get('tabs_always_visible')
@ -542,7 +568,7 @@ class MessageWindow:
first_composing_ind = -1 # id of first composing ctrl to switch to first_composing_ind = -1 # id of first composing ctrl to switch to
# if no others controls have awaiting events # if no others controls have awaiting events
# loop until finding an unread tab or having done a complete cycle # loop until finding an unread tab or having done a complete cycle
while True: while True:
if forward == True: # look for the first unread tab on the right if forward == True: # look for the first unread tab on the right
ind = ind + 1 ind = ind + 1
if ind >= self.notebook.get_n_pages(): if ind >= self.notebook.get_n_pages():
@ -590,7 +616,7 @@ class MessageWindow:
if old_no >= 0: if old_no >= 0:
old_ctrl = self._widget_to_control(notebook.get_nth_page(old_no)) old_ctrl = self._widget_to_control(notebook.get_nth_page(old_no))
old_ctrl.set_control_active(False) old_ctrl.set_control_active(False)
new_ctrl = self._widget_to_control(notebook.get_nth_page(page_num)) new_ctrl = self._widget_to_control(notebook.get_nth_page(page_num))
new_ctrl.set_control_active(True) new_ctrl.set_control_active(True)
self.show_title(control = new_ctrl) self.show_title(control = new_ctrl)
@ -598,8 +624,8 @@ class MessageWindow:
def _on_notebook_key_press(self, widget, event): def _on_notebook_key_press(self, widget, event):
control = self.get_active_control() control = self.get_active_control()
# Ctrl+PageUP / DOWN has to be handled by notebook # Ctrl+PageUP / DOWN has to be handled by notebook
if event.state & gtk.gdk.CONTROL_MASK and event.keyval in ( if (event.state & gtk.gdk.CONTROL_MASK and
gtk.keysyms.Page_Down, gtk.keysyms.Page_Up): event.keyval in (gtk.keysyms.Page_Down, gtk.keysyms.Page_Up)):
return False return False
if isinstance(control, ChatControlBase): if isinstance(control, ChatControlBase):
# we forwarded it to message textview # we forwarded it to message textview
@ -609,7 +635,7 @@ class MessageWindow:
def setup_tab_dnd(self, child): def setup_tab_dnd(self, child):
'''Set tab label as drag source and connect the drag_data_get signal''' '''Set tab label as drag source and connect the drag_data_get signal'''
tab_label = self.notebook.get_tab_label(child) tab_label = self.notebook.get_tab_label(child)
tab_label.dnd_handler = tab_label.connect('drag_data_get', tab_label.dnd_handler = tab_label.connect('drag_data_get',
self.on_tab_label_drag_data_get_cb) self.on_tab_label_drag_data_get_cb)
self.handlers[tab_label.dnd_handler] = tab_label self.handlers[tab_label.dnd_handler] = tab_label
tab_label.drag_source_set(gtk.gdk.BUTTON1_MASK, self.DND_TARGETS, tab_label.drag_source_set(gtk.gdk.BUTTON1_MASK, self.DND_TARGETS,
@ -630,11 +656,11 @@ class MessageWindow:
source_child = self.notebook.get_nth_page(source_page_num) source_child = self.notebook.get_nth_page(source_page_num)
if dest_page_num != source_page_num: if dest_page_num != source_page_num:
self.notebook.reorder_child(source_child, dest_page_num) self.notebook.reorder_child(source_child, dest_page_num)
def get_tab_at_xy(self, x, y): def get_tab_at_xy(self, x, y):
'''Thanks to Gaim '''Thanks to Gaim
Return the tab under xy and Return the tab under xy and
if its nearer from left or right side of the tab if its nearer from left or right side of the tab
''' '''
page_num = -1 page_num = -1
to_right = False to_right = False
@ -655,7 +681,7 @@ class MessageWindow:
if (y >= tab_alloc.y) and \ if (y >= tab_alloc.y) and \
(y <= (tab_alloc.y + tab_alloc.height)): (y <= (tab_alloc.y + tab_alloc.height)):
page_num = i page_num = i
if y > tab_alloc.y + (tab_alloc.height / 2.0): if y > tab_alloc.y + (tab_alloc.height / 2.0):
to_right = True to_right = True
break break
@ -679,36 +705,53 @@ class MessageWindow:
tab_label.disconnect(tab_label.dnd_handler) tab_label.disconnect(tab_label.dnd_handler)
################################################################################ ################################################################################
class MessageWindowMgr: class MessageWindowMgr(gobject.GObject):
'''A manager and factory for MessageWindow objects''' '''A manager and factory for MessageWindow objects'''
__gsignals__ = {
'window-delete': (gobject.SIGNAL_RUN_LAST, None, (object,)),
}
# These constants map to common.config.opt_one_window_types indices # These constants map to common.config.opt_one_window_types indices
( (
ONE_MSG_WINDOW_NEVER, ONE_MSG_WINDOW_NEVER,
ONE_MSG_WINDOW_ALWAYS, ONE_MSG_WINDOW_ALWAYS,
ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER,
ONE_MSG_WINDOW_PERACCT, ONE_MSG_WINDOW_PERACCT,
ONE_MSG_WINDOW_PERTYPE ONE_MSG_WINDOW_PERTYPE,
) = range(4) ) = range(5)
# A key constant for the main window for all messages # A key constant for the main window in ONE_MSG_WINDOW_ALWAYS mode
MAIN_WIN = 'main' MAIN_WIN = 'main'
# A key constant for the main window in ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER mode
ROSTER_MAIN_WIN = 'roster'
def __init__(self): def __init__(self, parent_window, parent_paned):
''' A dictionary of windows; the key depends on the config: ''' A dictionary of windows; the key depends on the config:
ONE_MSG_WINDOW_NEVER: The key is the contact JID ONE_MSG_WINDOW_NEVER: The key is the contact JID
ONE_MSG_WINDOW_ALWAYS: The key is MessageWindowMgr.MAIN_WIN ONE_MSG_WINDOW_ALWAYS: The key is MessageWindowMgr.MAIN_WIN
ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER: The key is MessageWindowMgr.MAIN_WIN
ONE_MSG_WINDOW_PERACCT: The key is the account name ONE_MSG_WINDOW_PERACCT: The key is the account name
ONE_MSG_WINDOW_PERTYPE: The key is a message type constant''' ONE_MSG_WINDOW_PERTYPE: The key is a message type constant'''
gobject.GObject.__init__(self)
self._windows = {} self._windows = {}
# Map the mode to a int constant for frequent compares # Map the mode to a int constant for frequent compares
mode = gajim.config.get('one_message_window') mode = gajim.config.get('one_message_window')
self.mode = common.config.opt_one_window_types.index(mode) self.mode = common.config.opt_one_window_types.index(mode)
self.parent_win = parent_window
self.parent_paned = parent_paned
def change_account_name(self, old_name, new_name): def change_account_name(self, old_name, new_name):
for win in self.windows(): for win in self.windows():
win.change_account_name(old_name, new_name) win.change_account_name(old_name, new_name)
def _new_window(self, acct, type): def _new_window(self, acct, type):
win = MessageWindow(acct, type) parent_win = None
parent_paned = None
if self.mode == self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
parent_win = self.parent_win
parent_paned = self.parent_paned
win = MessageWindow(acct, type, parent_win, parent_paned)
# we track the lifetime of this window # we track the lifetime of this window
win.window.connect('delete-event', self._on_window_delete) win.window.connect('delete-event', self._on_window_delete)
win.window.connect('destroy', self._on_window_destroy) win.window.connect('destroy', self._on_window_destroy)
@ -729,7 +772,7 @@ class MessageWindowMgr:
def has_window(self, jid, acct): def has_window(self, jid, acct):
return self.get_window(jid, acct) != None return self.get_window(jid, acct) != None
def one_window_opened(self, contact, acct, type): def one_window_opened(self, contact=None, acct=None, type=None):
try: try:
return self._windows[self._mode_to_key(contact, acct, type)] != None return self._windows[self._mode_to_key(contact, acct, type)] != None
except KeyError: except KeyError:
@ -739,10 +782,14 @@ class MessageWindowMgr:
'''Resizes window according to config settings''' '''Resizes window according to config settings'''
if not gajim.config.get('saveposition'): if not gajim.config.get('saveposition'):
return return
if self.mode == self.ONE_MSG_WINDOW_ALWAYS: if self.mode in (self.ONE_MSG_WINDOW_ALWAYS,
self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER):
size = (gajim.config.get('msgwin-width'), size = (gajim.config.get('msgwin-width'),
gajim.config.get('msgwin-height')) gajim.config.get('msgwin-height'))
if self.mode == self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
parent_size = win.window.get_size()
size = (parent_size[0] + size[0], size[1])
elif self.mode == self.ONE_MSG_WINDOW_PERACCT: elif self.mode == self.ONE_MSG_WINDOW_PERACCT:
size = (gajim.config.get_per('accounts', acct, 'msgwin-width'), size = (gajim.config.get_per('accounts', acct, 'msgwin-width'),
gajim.config.get_per('accounts', acct, 'msgwin-height')) gajim.config.get_per('accounts', acct, 'msgwin-height'))
@ -754,13 +801,13 @@ class MessageWindowMgr:
size = (gajim.config.get(opt_width), gajim.config.get(opt_height)) size = (gajim.config.get(opt_width), gajim.config.get(opt_height))
else: else:
return return
win.resize(size[0], size[1])
gtkgui_helpers.resize_window(win.window, size[0], size[1])
def _position_window(self, win, acct, type): def _position_window(self, win, acct, type):
'''Moves window according to config settings''' '''Moves window according to config settings'''
if not gajim.config.get('saveposition') or\ if (not gajim.config.get('saveposition') or
self.mode == self.ONE_MSG_WINDOW_NEVER: self.mode in [self.ONE_MSG_WINDOW_NEVER,
self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER]):
return return
if self.mode == self.ONE_MSG_WINDOW_ALWAYS: if self.mode == self.ONE_MSG_WINDOW_ALWAYS:
@ -782,21 +829,22 @@ class MessageWindowMgr:
key = acct + contact.jid key = acct + contact.jid
if resource: if resource:
key += '/' + resource key += '/' + resource
return key
elif self.mode == self.ONE_MSG_WINDOW_ALWAYS: elif self.mode == self.ONE_MSG_WINDOW_ALWAYS:
key = self.MAIN_WIN return self.MAIN_WIN
elif self.mode == self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
return self.ROSTER_MAIN_WIN
elif self.mode == self.ONE_MSG_WINDOW_PERACCT: elif self.mode == self.ONE_MSG_WINDOW_PERACCT:
key = acct return acct
elif self.mode == self.ONE_MSG_WINDOW_PERTYPE: elif self.mode == self.ONE_MSG_WINDOW_PERTYPE:
key = type return type
return key
def create_window(self, contact, acct, type, resource = None): def create_window(self, contact, acct, type, resource = None):
key = None
win_acct = None win_acct = None
win_type = None win_type = None
win_role = 'messages' win_role = None # X11 window role
key = self._mode_to_key(contact, acct, type, resource) win_key = self._mode_to_key(contact, acct, type, resource)
if self.mode == self.ONE_MSG_WINDOW_PERACCT: if self.mode == self.ONE_MSG_WINDOW_PERACCT:
win_acct = acct win_acct = acct
win_role = acct win_role = acct
@ -806,21 +854,24 @@ class MessageWindowMgr:
elif self.mode == self.ONE_MSG_WINDOW_NEVER: elif self.mode == self.ONE_MSG_WINDOW_NEVER:
win_type = type win_type = type
win_role = contact.jid win_role = contact.jid
elif self.mode == self.ONE_MSG_WINDOW_ALWAYS:
win_role = 'messages'
win = None win = None
try: try:
win = self._windows[key] win = self._windows[win_key]
except KeyError: except KeyError:
win = self._new_window(win_acct, win_type) win = self._new_window(win_acct, win_type)
win.window.set_role(win_role) if win_role:
win.window.set_role(win_role)
# Position and size window based on saved state and window mode # Position and size window based on saved state and window mode
if not self.one_window_opened(contact, acct, type): if not self.one_window_opened(contact, acct, type):
self._position_window(win, acct, type) self._position_window(win, acct, type)
self._resize_window(win, acct, type) self._resize_window(win, acct, type)
self._windows[key] = win self._windows[win_key] = win
return win return win
def change_key(self, old_jid, new_jid, acct): def change_key(self, old_jid, new_jid, acct):
@ -842,6 +893,7 @@ class MessageWindowMgr:
def _on_window_destroy(self, win): def _on_window_destroy(self, win):
for k in self._windows.keys(): for k in self._windows.keys():
if self._windows[k].window == win: if self._windows[k].window == win:
self.emit('window-delete', self._windows[k])
del self._windows[k] del self._windows[k]
return return
@ -870,17 +922,17 @@ class MessageWindowMgr:
for c in w.controls(): for c in w.controls():
yield c yield c
def shutdown(self): def shutdown(self, width_adjust=0):
for w in self.windows(): for w in self.windows():
self.save_state(w) self.save_state(w, width_adjust)
w.window.hide() w.window.hide()
w.window.destroy() w.window.destroy()
gajim.interface.save_config() gajim.interface.save_config()
def save_state(self, msg_win): def save_state(self, msg_win, width_adjust=0):
if not gajim.config.get('saveposition'): if not gajim.config.get('saveposition'):
return return
# Save window size and position # Save window size and position
pos_x_key = 'msgwin-x-position' pos_x_key = 'msgwin-x-position'
pos_y_key = 'msgwin-y-position' pos_y_key = 'msgwin-y-position'
@ -907,6 +959,9 @@ class MessageWindowMgr:
type = msg_win.type type = msg_win.type
size_width_key = type + '-msgwin-width' size_width_key = type + '-msgwin-width'
size_height_key = type + '-msgwin-height' size_height_key = type + '-msgwin-height'
elif self.mode == self.ONE_MSG_WINDOW_ALWAYS_WITH_ROSTER:
# Ignore any hpaned width
width = msg_win.notebook.allocation.width
if acct: if acct:
gajim.config.set_per('accounts', acct, size_width_key, width) gajim.config.set_per('accounts', acct, size_width_key, width)
@ -915,11 +970,12 @@ class MessageWindowMgr:
if self.mode != self.ONE_MSG_WINDOW_NEVER: if self.mode != self.ONE_MSG_WINDOW_NEVER:
gajim.config.set_per('accounts', acct, pos_x_key, x) gajim.config.set_per('accounts', acct, pos_x_key, x)
gajim.config.set_per('accounts', acct, pos_y_key, y) gajim.config.set_per('accounts', acct, pos_y_key, y)
else: else:
width += width_adjust
gajim.config.set(size_width_key, width) gajim.config.set(size_width_key, width)
gajim.config.set(size_height_key, height) gajim.config.set(size_height_key, height)
if self.mode != self.ONE_MSG_WINDOW_NEVER: if self.mode != self.ONE_MSG_WINDOW_NEVER:
gajim.config.set(pos_x_key, x) gajim.config.set(pos_x_key, x)
gajim.config.set(pos_y_key, y) gajim.config.set(pos_y_key, y)
@ -944,8 +1000,7 @@ class MessageWindowMgr:
w.notebook.remove_page(0) w.notebook.remove_page(0)
page.unparent() page.unparent()
controls.append(ctrl) controls.append(ctrl)
# Must clear _controls from window to prevent # Must clear _controls from window to prevent MessageControl.shutdown calls
# MessageControl.shutdown calls
w._controls = {} w._controls = {}
w.window.destroy() w.window.destroy()

View file

@ -6,6 +6,7 @@
## Copyright (C) 2005-2006 Andrew Sayman <lorien420@myrealbox.com> ## Copyright (C) 2005-2006 Andrew Sayman <lorien420@myrealbox.com>
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net> ## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com> ## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
## Copyright (C) 2007 Travis Shirk <travis@pobox.com>
## ##
## This file is part of Gajim. ## This file is part of Gajim.
## ##

View file

@ -3,6 +3,7 @@
## ##
## Copyright (C) 2003-2007 Yann Leboulanger <asterix@lagaule.org> ## Copyright (C) 2003-2007 Yann Leboulanger <asterix@lagaule.org>
## Copyright (C) 2005-2007 Nikos Kouremenos <kourem@gmail.com> ## Copyright (C) 2005-2007 Nikos Kouremenos <kourem@gmail.com>
## Travis Shirk <travis@pobox.com>
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov@gmail.com> ## Copyright (C) 2005-2006 Dimitur Kirov <dkirov@gmail.com>
## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net> ## Copyright (C) 2007 Lukas Petrovicky <lukas@petrovicky.net>
## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com> ## Copyright (C) 2007 Julien Pivotto <roidelapluie@gmail.com>
@ -1019,7 +1020,7 @@ class RosterWindow:
if gajim.config.get_per('accounts', account, 'is_zeroconf'): if gajim.config.get_per('accounts', account, 'is_zeroconf'):
continue continue
# single message # single message
single_message_item = gtk.MenuItem(_('using account %s') % account, single_message_item = gtk.MenuItem(_('using account %s') % account,
False) False)
@ -1378,8 +1379,7 @@ class RosterWindow:
if contact.resource != '': if contact.resource != '':
name += '/' + contact.resource name += '/' + contact.resource
jid_with_resource = contact.jid + '/' + contact.resource jid_with_resource = contact.jid + '/' + contact.resource
if gajim.interface.msg_win_mgr.has_window(jid_with_resource, if gajim.interface.msg_win_mgr.has_window(jid_with_resource, account):
account):
win = gajim.interface.msg_win_mgr.get_window(jid_with_resource, win = gajim.interface.msg_win_mgr.get_window(jid_with_resource,
account) account)
ctrl = win.get_control(jid_with_resource, account) ctrl = win.get_control(jid_with_resource, account)
@ -2661,7 +2661,7 @@ class RosterWindow:
ctrl = gajim.interface.minimized_controls[account][jid] ctrl = gajim.interface.minimized_controls[account][jid]
mw = gajim.interface.msg_win_mgr.get_window(ctrl.contact.jid, ctrl.account) mw = gajim.interface.msg_win_mgr.get_window(ctrl.contact.jid, ctrl.account)
if not mw: if not mw:
mw = gajim.interface.msg_win_mgr.create_window(ctrl.contact, \ mw = gajim.interface.msg_win_mgr.create_window(ctrl.contact,
ctrl.account, ctrl.type_id) ctrl.account, ctrl.type_id)
ctrl.parent_win = mw ctrl.parent_win = mw
mw.new_tab(ctrl) mw.new_tab(ctrl)
@ -3085,8 +3085,8 @@ class RosterWindow:
contact = gajim.contacts.create_contact(jid = hostname) # Fake contact contact = gajim.contacts.create_contact(jid = hostname) # Fake contact
execute_command_menuitem.connect('activate', execute_command_menuitem.connect('activate',
self.on_execute_command, contact, account) self.on_execute_command, contact, account)
start_chat_menuitem.connect('activate', start_chat_menuitem.connect('activate',
self.on_new_chat_menuitem_activate, account) self.on_new_chat_menuitem_activate, account)
gc_sub_menu = gtk.Menu() # gc is always a submenu gc_sub_menu = gtk.Menu() # gc is always a submenu
@ -4150,7 +4150,7 @@ class RosterWindow:
gajim.interface.instances['file_transfers'].window.present() gajim.interface.instances['file_transfers'].window.present()
else: else:
gajim.interface.instances['file_transfers'].window.show_all() gajim.interface.instances['file_transfers'].window.show_all()
def on_history_menuitem_activate(self, widget): def on_history_menuitem_activate(self, widget):
if gajim.interface.instances.has_key('logs'): if gajim.interface.instances.has_key('logs'):
gajim.interface.instances['logs'].window.present() gajim.interface.instances['logs'].window.present()
@ -4252,6 +4252,7 @@ class RosterWindow:
def quit_gtkgui_interface(self): def quit_gtkgui_interface(self):
'''When we quit the gtk interface : '''When we quit the gtk interface :
tell that to the core and exit gtk''' tell that to the core and exit gtk'''
msgwin_width_adjust = 0
if gajim.config.get('saveposition'): if gajim.config.get('saveposition'):
# in case show_roster_on_start is False and roster is never shown # in case show_roster_on_start is False and roster is never shown
# window.window is None # window.window is None
@ -4260,12 +4261,21 @@ class RosterWindow:
gajim.config.set('roster_x-position', x) gajim.config.set('roster_x-position', x)
gajim.config.set('roster_y-position', y) gajim.config.set('roster_y-position', y)
width, height = self.window.get_size() width, height = self.window.get_size()
# For the width use the size of the vbox containing the tree and
# status combo, this will cancel out any hpaned width
width = self.xml.get_widget('roster_vbox2').allocation.width
gajim.config.set('roster_width', width) gajim.config.set('roster_width', width)
gajim.config.set('roster_height', height) gajim.config.set('roster_height', height)
if not self.xml.get_widget('roster_vbox2').get_property('visible'):
# The roster vbox is hidden, so the message window is larger
# then we want to save (i.e. the window will grow every startup)
# so adjust.
msgwin_width_adjust = -1 * width
gajim.config.set('show_roster_on_startup', gajim.config.set('show_roster_on_startup',
self.window.get_property('visible')) self.window.get_property('visible'))
gajim.interface.msg_win_mgr.shutdown() gajim.interface.msg_win_mgr.shutdown(msgwin_width_adjust)
gajim.config.set('collapsed_rows', '\t'.join(self.collapsed_rows)) gajim.config.set('collapsed_rows', '\t'.join(self.collapsed_rows))
gajim.interface.save_config() gajim.interface.save_config()
@ -4667,6 +4677,25 @@ class RosterWindow:
gajim.config.set('showoffline', not gajim.config.get('showoffline')) gajim.config.set('showoffline', not gajim.config.get('showoffline'))
self.draw_roster() self.draw_roster()
def on_view_menu_activate(self, widget):
# Hide the show roster menu if we are not in the right windowing mode.
if self.hpaned.get_child2() is not None:
self.xml.get_widget('show_roster_menuitem').show()
else:
self.xml.get_widget('show_roster_menuitem').hide()
def on_show_roster_menuitem_toggled(self, widget):
# when num controls is 0 this menuitem is hidden, but still need to
# disable keybinding
if self.hpaned.get_child2() is not None:
self.show_roster_vbox(widget.get_active())
def show_roster_vbox(self, active):
if active:
self.xml.get_widget('roster_vbox2').show()
else:
self.xml.get_widget('roster_vbox2').hide()
def set_renderer_color(self, renderer, style, set_background = True): def set_renderer_color(self, renderer, style, set_background = True):
'''set style for treeview cell, using PRELIGHT system color''' '''set style for treeview cell, using PRELIGHT system color'''
if set_background: if set_background:
@ -4986,7 +5015,7 @@ class RosterWindow:
# FIXME: Why do groups have to be redrawn by hand? # FIXME: Why do groups have to be redrawn by hand?
for g in old_groups: for g in old_groups:
self.draw_group(g, account_source) self.draw_group(g, account_source)
self.draw_account(account_source) self.draw_account(account_source)
context.finish(True, True, etime) context.finish(True, True, etime)
confirm_metacontacts = gajim.config.get('confirm_metacontacts') confirm_metacontacts = gajim.config.get('confirm_metacontacts')
@ -5058,7 +5087,7 @@ class RosterWindow:
return return
if position == gtk.TREE_VIEW_DROP_BEFORE and len(path_dest) == 2: if position == gtk.TREE_VIEW_DROP_BEFORE and len(path_dest) == 2:
# dropped before a group: we drop it in the previous group every time # dropped before a group: we drop it in the previous group every time
path_dest = (path_dest[0], path_dest[1]-1) path_dest = (path_dest[0], path_dest[1]-1)
# destination: the row something got dropped on # destination: the row something got dropped on
iter_dest = model.get_iter(path_dest) iter_dest = model.get_iter(path_dest)
type_dest = model[iter_dest][C_TYPE].decode('utf-8') type_dest = model[iter_dest][C_TYPE].decode('utf-8')
@ -5112,7 +5141,7 @@ class RosterWindow:
uri_splitted)) uri_splitted))
dialog.popup() dialog.popup()
return return
# a roster entry was dragged and dropped somewhere in the roster # a roster entry was dragged and dropped somewhere in the roster
# source: the row that was dragged # source: the row that was dragged
@ -5120,9 +5149,9 @@ class RosterWindow:
iter_source = model.get_iter(path_source) iter_source = model.get_iter(path_source)
type_source = model[iter_source][C_TYPE] type_source = model[iter_source][C_TYPE]
account_source = model[iter_source][C_ACCOUNT].decode('utf-8') account_source = model[iter_source][C_ACCOUNT].decode('utf-8')
# Only normal contacts can be dragged # Only normal contacts can be dragged
if type_source != 'contact': if type_source != 'contact':
return return
if gajim.config.get_per('accounts', account_source, 'is_zeroconf'): if gajim.config.get_per('accounts', account_source, 'is_zeroconf'):
return return
@ -5172,7 +5201,7 @@ class RosterWindow:
if grp_source == grp_dest and account_source == account_dest: if grp_source == grp_dest and account_source == account_dest:
# Drop on self # Drop on self
return return
# contact drop somewhere in or on a foreign account # contact drop somewhere in or on a foreign account
if (type_dest == 'account' or not self.regroup) and \ if (type_dest == 'account' or not self.regroup) and \
account_source != account_dest: account_source != account_dest:
@ -5180,7 +5209,7 @@ class RosterWindow:
dialogs.AddNewContactWindow(account = account_dest, jid = jid_source, dialogs.AddNewContactWindow(account = account_dest, jid = jid_source,
user_nick = c_source.name, group = grp_dest) user_nick = c_source.name, group = grp_dest)
return return
# we may not add contacts from special_groups # we may not add contacts from special_groups
if grp_source in helpers.special_groups : if grp_source in helpers.special_groups :
return return
@ -5194,7 +5223,7 @@ class RosterWindow:
self.on_drop_in_group(None, account_source, c_source, grp_dest, self.on_drop_in_group(None, account_source, c_source, grp_dest,
is_big_brother, context, etime, grp_source) is_big_brother, context, etime, grp_source)
return return
# Contact drop on another contact, make meta contacts # Contact drop on another contact, make meta contacts
if position == gtk.TREE_VIEW_DROP_INTO_OR_AFTER or \ if position == gtk.TREE_VIEW_DROP_INTO_OR_AFTER or \
position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE: position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE:
@ -5209,21 +5238,30 @@ class RosterWindow:
def show_title(self): def show_title(self):
change_title_allowed = gajim.config.get('change_roster_title') change_title_allowed = gajim.config.get('change_roster_title')
if not change_title_allowed:
return
if gajim.config.get('one_message_window') == 'always_with_roster':
# always_with_roster mode defers to the MessageWindow
if not gajim.interface.msg_win_mgr.one_window_opened():
# No MessageWindow to defer to
self.window.set_title('Gajim')
return
nb_unread = 0 nb_unread = 0
if change_title_allowed: start = ''
start = '' for account in gajim.connections:
for account in gajim.connections: # Count events in roster title only if we don't auto open them
# Count events in roster title only if we don't auto open them if not helpers.allow_popup_window(account):
if not helpers.allow_popup_window(account): nb_unread += gajim.events.get_nb_events(['chat', 'normal',
nb_unread += gajim.events.get_nb_events(['chat', 'normal', 'file-request', 'file-error', 'file-completed',
'file-request', 'file-error', 'file-completed', 'file-request-error', 'file-send-error', 'file-stopped',
'file-request-error', 'file-send-error', 'file-stopped', 'printed_chat'], account)
'printed_chat'], account) if nb_unread > 1:
if nb_unread > 1: start = '[' + str(nb_unread) + '] '
start = '[' + str(nb_unread) + '] ' elif nb_unread == 1:
elif nb_unread == 1: start = '* '
start = '* ' self.window.set_title(start + 'Gajim')
self.window.set_title(start + 'Gajim')
gtkgui_helpers.set_unset_urgency_hint(self.window, nb_unread) gtkgui_helpers.set_unset_urgency_hint(self.window, nb_unread)
@ -5304,7 +5342,7 @@ class RosterWindow:
accels = gtk.AccelGroup() accels = gtk.AccelGroup()
self.xml.get_widget('roster_window').add_accel_group(accels) self.xml.get_widget('roster_window').add_accel_group(accels)
prefs_item.add_accelerator('activate', accels, ord(','), prefs_item.add_accelerator('activate', accels, ord(','),
gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
app_menu.append(prefs_item) app_menu.append(prefs_item)
app_menu.append(gtk.MenuItem('__SKIP__')) app_menu.append(gtk.MenuItem('__SKIP__'))
app_menu.append(gtk.MenuItem('__SKIP__')) app_menu.append(gtk.MenuItem('__SKIP__'))
@ -5322,11 +5360,20 @@ class RosterWindow:
#self.xml.get_widget('menubar').hide() #self.xml.get_widget('menubar').hide()
return return
def _on_message_window_delete(self, win_mgr, msg_win):
if gajim.config.get('one_message_window') == 'always_with_roster':
self.show_roster_vbox(True)
gtkgui_helpers.resize_window(self.window,
gajim.config.get('roster_width'),
gajim.config.get('roster_height'))
def __init__(self): def __init__(self):
self.xml = gtkgui_helpers.get_glade('roster_window.glade') self.xml = gtkgui_helpers.get_glade('roster_window.glade')
self.window = self.xml.get_widget('roster_window') self.window = self.xml.get_widget('roster_window')
self.hpaned = self.xml.get_widget('roster_hpaned')
self._music_track_changed_signal = None self._music_track_changed_signal = None
gajim.interface.msg_win_mgr = MessageWindowMgr() gajim.interface.msg_win_mgr = MessageWindowMgr(self.window, self.hpaned)
gajim.interface.msg_win_mgr.connect('window-delete', self._on_message_window_delete)
self.advanced_menus = [] # We keep them to destroy them self.advanced_menus = [] # We keep them to destroy them
if gajim.config.get('roster_window_skip_taskbar'): if gajim.config.get('roster_window_skip_taskbar'):
self.window.set_property('skip-taskbar-hint', True) self.window.set_property('skip-taskbar-hint', True)
@ -5460,6 +5507,8 @@ class RosterWindow:
self.xml.get_widget('show_transports_menuitem').set_active( self.xml.get_widget('show_transports_menuitem').set_active(
show_transports_group) show_transports_group)
self.xml.get_widget('show_roster_menuitem').set_active(True)
# columns # columns
# this col has 3 cells: # this col has 3 cells:
@ -5549,3 +5598,4 @@ class RosterWindow:
if sys.platform == 'darwin': if sys.platform == 'darwin':
self.setup_for_osx() self.setup_for_osx()