diff --git a/Changelog b/Changelog index 7856b930bd774a0a88196596c6f18bf109001133..f214903006421f07f09465268a1375d1b9e2d922 100644 --- a/Changelog +++ b/Changelog @@ -1,14 +1,38 @@ +Gajim 0.11 (XX October 2006) + + * Put your stuff here [each dev put their own please; next time we do this everytime we commit sth major and not in the end] + + * We can now operate on more than one contact in one in time in roster (#1514) + * Connection lost is now a non-intrusive popup + * Try to get contact desired nick when we add him to roster aka User Nickname (JEP-0172) + * Better design of User Profile window, with a progress bar + * New Add User dialog, with possibility to register to transport directly from it + * Completion for "Start Chat" input dialog + * We can now have a different spellchecking language in each chat window. (#2383 and #746) + * Support for Privacy Lists + * Forbid to run multiple instances (but you can use differents profiles) + * We can save avatar with right click on avatar in chat banner + * Use differents colors for nickname colors of occupants in groupchats. + * Ability to show only Join/Leave in groupchats instead of all status changes + * New possibilities to insert nickname of an occupant in groupchats conversations : Tab in an empty line now cycle through nicks, maj+right click->insert nickname, maj+click on name in gc-roster, /names command to show all users presents + + * Fixed bugs when removing or renaming an account with tabs open (#2369 and #2370) + + * FIXME : Ad-Hoc for 0.11 ? + * FIXME : does that work ? not tested : Metacontacts across accounts (#1596) + * Gajim now requires Python 2.4 to run + Gajim 0.10.1 (06 June 2006) - * freeze and lost contacts in roster (#1953) - * popup menus are correctly placed - * high CPU usage on FreeBSD (#1963) - * nickname can contain '|' (#1913) - * update pl, cs, fr translations - * don't play sound, when no event is shown (#1970) - * set gajim icon for history manager + * Freeze and lost contacts in roster (#1953) + * Popup menus are correctly placed + * High CPU usage on FreeBSD (#1963) + * Nickname can contain '|' (#1913) + * Update pl, cs, fr translations + * Don't play sound, when no event is shown (#1970) + * Set gajim icon for history manager * gajim.desktop is generated with translation (#834) - * preventing several TBs and annoyances (r6273, r6275, r6279, r6301, + * Preventing several TBs and annoyances (r6273, r6275, r6279, r6301, r6308, r6311, r6323, r6326, r6327, r6335, r6342, r6346, r6348) Gajim 0.10 (01 May 2006) diff --git a/README b/README index 9f11c85524835f61823f1ae0b1dcf2152cd831c5..5e2ad7468ff941b5a208878218ad8be0426ae39f 100644 --- a/README +++ b/README @@ -1,10 +1,10 @@ Welcome and thanks for trying out Gajim. =RUNTIME REQUIREMENTS= -python2.4 (python2.3 should work too) +python2.4 or higher pygtk2.6 or higher python-libglade -pysqlite2 (aka. python-pysqlite2) +pysqlite2 (if you have python 2.5, you already have this) some distros also split too much python standard library. I know SUSE does. In such distros you also need python-xml @@ -29,7 +29,8 @@ notification-daemon (and D-Bus) to get cooler popups D-Bus to have gajim-remote working NOTE TO PACKAGERS: -Gajim is a GTK+ app and not a gnome one. Just do 'make' so you don't require gnomepythonextras +Gajim is a GTK+ app and not a gnome one. +Just do 'make' so you don't require gnomepythonextras which is gnome dep =INSTALLATION PROCEDURE= @@ -65,9 +66,6 @@ you're advised to enable verbose via advanced configuration window. If you don't want to make this permanent, execute gajim with --verbose everytime you want to have verbose output. -Cannot join room with password: -please read the FAQ for the reply on this issue - =FAQ/Wiki= FAQ can be found at http://trac.gajim.org/wiki/GajimFaq Wiki can be found at http://trac.gajim.org/wiki @@ -75,13 +73,13 @@ Wiki can be found at http://trac.gajim.org/wiki That is all, enjoy! -(C) 2003-2005 +(C) 2003-2006 The Gajim Team http://gajim.org PS. -we use original art and parts of sounds and other art from Psi, Gossip, +We use original art and parts of sounds and other art from Psi, Gossip, Gnomebaker, Gaim and some icons from various gnome-icons (mostly Dropline Etiquette) we found at art.gnome.org -If you think we're violating a license please inform us +If you think we're violating a license please inform us. Thank you diff --git a/data/glade/gajim_themes_window.glade b/data/glade/gajim_themes_window.glade index 44d7e381c3c2d91c8359b0b3e99df55e2cf80161..9f0dd0092f09ca504e88581f70de732b6a41be74 100644 --- a/data/glade/gajim_themes_window.glade +++ b/data/glade/gajim_themes_window.glade @@ -554,52 +554,6 @@ Banner</property> </packing> </child> - <child> - <widget class="GtkLabel" id="label388"> - <property name="visible">True</property> - <property name="label" translatable="yes">Active</property> - <property name="use_underline">False</property> - <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</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</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="left_attach">0</property> - <property name="right_attach">1</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkColorButton" id="active_colorbutton"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="use_alpha">False</property> - <property name="focus_on_click">True</property> - <signal name="color_set" handler="on_active_colorbutton_color_set" last_modification_time="Sat, 18 Mar 2006 22:34:13 GMT"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">fill</property> - <property name="y_options"></property> - </packing> - </child> - <child> <widget class="GtkLabel" id="label393"> <property name="visible">True</property> diff --git a/data/glade/message_window.glade b/data/glade/message_window.glade index ecd51204d2e00380cd924d6842aa79acdbe2da46..d4678bfd35c2b993849de33802a1c4d4c2741b21 100644 --- a/data/glade/message_window.glade +++ b/data/glade/message_window.glade @@ -374,7 +374,7 @@ Status message</property> <child> <widget class="GtkImage" id="image1338"> <property name="visible">True</property> - <property name="stock">gtk-preferences</property> + <property name="stock">gtk-execute</property> <property name="icon_size">4</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> @@ -916,7 +916,7 @@ topic</property> <child> <widget class="GtkImage" id="image1344"> <property name="visible">True</property> - <property name="stock">gtk-preferences</property> + <property name="stock">gtk-execute</property> <property name="icon_size">4</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> diff --git a/data/glade/preferences_window.glade b/data/glade/preferences_window.glade index f5aceb5ffe6551aef3a7d081f55e96db51e8f12e..573c182a832bbed2d73239a5cfbabc94c42485b0 100644 --- a/data/glade/preferences_window.glade +++ b/data/glade/preferences_window.glade @@ -819,7 +819,7 @@ Per type</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> - <property name="mnemonic_widget">before_time_entry</property> + <property name="mnemonic_widget">scrolledwindow25</property> <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> <property name="width_chars">-1</property> <property name="single_line_mode">False</property> @@ -848,7 +848,7 @@ Per type</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> - <property name="mnemonic_widget">after_nickname_entry</property> + <property name="mnemonic_widget">scrolledwindow28</property> <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> <property name="width_chars">-1</property> <property name="single_line_mode">False</property> @@ -998,7 +998,7 @@ Per type</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> - <property name="mnemonic_widget">after_time_entry</property> + <property name="mnemonic_widget">scrolledwindow26</property> <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> <property name="width_chars">-1</property> <property name="single_line_mode">False</property> @@ -1027,7 +1027,7 @@ Per type</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> - <property name="mnemonic_widget">before_nickname_entry</property> + <property name="mnemonic_widget">scrolledwindow27</property> <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> <property name="width_chars">-1</property> <property name="single_line_mode">False</property> @@ -1043,54 +1043,6 @@ Per type</property> </packing> </child> - <child> - <widget class="GtkEntry" id="after_time_entry"> - <property name="width_request">39</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <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="focus_out_event" handler="on_after_time_entry_focus_out_event" last_modification_time="Fri, 01 Apr 2005 15:57:17 GMT"/> - </widget> - <packing> - <property name="left_attach">3</property> - <property name="right_attach">4</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - <property name="x_options"></property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkEntry" id="after_nickname_entry"> - <property name="width_request">40</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <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="focus_out_event" handler="on_after_nickname_entry_focus_out_event" last_modification_time="Fri, 01 Apr 2005 15:58:07 GMT"/> - </widget> - <packing> - <property name="left_attach">3</property> - <property name="right_attach">4</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options"></property> - <property name="y_options"></property> - </packing> - </child> - <child> <widget class="GtkColorButton" id="incoming_msg_colorbutton"> <property name="visible">True</property> @@ -1132,54 +1084,6 @@ Per type</property> </packing> </child> - <child> - <widget class="GtkEntry" id="before_nickname_entry"> - <property name="width_request">40</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <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="focus_out_event" handler="on_before_nickname_entry_focus_out_event" last_modification_time="Fri, 01 Apr 2005 15:57:44 GMT"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options"></property> - <property name="y_options"></property> - </packing> - </child> - - <child> - <widget class="GtkEntry" id="before_time_entry"> - <property name="width_request">40</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <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="focus_out_event" handler="on_before_time_entry_focus_out_event" last_modification_time="Fri, 01 Apr 2005 15:54:51 GMT"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - <property name="x_options"></property> - <property name="y_options"></property> - </packing> - </child> - <child> <widget class="GtkHBox" id="hbox3022"> <property name="visible">True</property> @@ -1298,6 +1202,170 @@ Per type</property> <property name="x_options">fill</property> </packing> </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow26"> + <property name="height_request">30</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="after_time_textview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="overwrite">False</property> + <property name="accepts_tab">True</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_CHAR</property> + <property name="cursor_visible">True</property> + <property name="pixels_above_lines">0</property> + <property name="pixels_below_lines">0</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">0</property> + <property name="right_margin">0</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + <signal name="focus_out_event" handler="on_after_time_textview_focus_out_event" last_modification_time="Wed, 20 Sep 2006 19:52:22 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow28"> + <property name="height_request">30</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="after_nickname_textview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="overwrite">False</property> + <property name="accepts_tab">True</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_CHAR</property> + <property name="cursor_visible">True</property> + <property name="pixels_above_lines">0</property> + <property name="pixels_below_lines">0</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">0</property> + <property name="right_margin">0</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + <signal name="focus_out_event" handler="on_after_nickname_textview_focus_out_event" last_modification_time="Wed, 20 Sep 2006 19:52:51 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">3</property> + <property name="right_attach">4</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow27"> + <property name="height_request">30</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="before_nickname_textview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="overwrite">False</property> + <property name="accepts_tab">True</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_CHAR</property> + <property name="cursor_visible">True</property> + <property name="pixels_above_lines">0</property> + <property name="pixels_below_lines">0</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">0</property> + <property name="right_margin">0</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + <signal name="focus_out_event" handler="on_before_nickname_textview_focus_out_event" last_modification_time="Wed, 20 Sep 2006 19:52:05 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow25"> + <property name="height_request">30</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="before_time_textview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="overwrite">False</property> + <property name="accepts_tab">True</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_CHAR</property> + <property name="cursor_visible">True</property> + <property name="pixels_above_lines">0</property> + <property name="pixels_below_lines">0</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">0</property> + <property name="right_margin">0</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + <signal name="focus_out_event" handler="on_before_time_textview_focus_out_event" last_modification_time="Wed, 20 Sep 2006 18:21:39 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> </widget> <packing> <property name="padding">0</property> @@ -2543,6 +2611,26 @@ Disabled</property> </packing> </child> + <child> + <widget class="GtkCheckButton" id="set_status_msg_from_current_music_track_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Set status message to reflect currently playing _music track</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="set_status_msg_from_current_music_track_checkbutton_toggled" last_modification_time="Fri, 22 Sep 2006 18:13:39 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + <child> <widget class="GtkEventBox" id="eventbox6"> <property name="visible">True</property> diff --git a/data/glade/privacy_list_window.glade b/data/glade/privacy_list_window.glade new file mode 100644 index 0000000000000000000000000000000000000000..1f14d6b71b086c88ce3d05c97897293fd6c1d38c --- /dev/null +++ b/data/glade/privacy_list_window.glade @@ -0,0 +1,779 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> + +<widget class="GtkWindow" id="privacy_list_edit_window"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="title" translatable="yes">Privacy List</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">False</property> + <property name="destroy_with_parent">False</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <signal name="destroy" handler="on_privacy_list_edit_window_destroy" last_modification_time="Sun, 02 Jul 2006 22:34:41 GMT"/> + + <child> + <widget class="GtkVBox" id="main_vbox"> + <property name="width_request">600</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="title_hbox"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="privacy_lists_title_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"><i>Privacy List</i></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.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</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="GtkCheckButton" id="privacy_list_active_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Active for this session</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_privacy_list_active_checkbutton_toggled" last_modification_time="Sat, 01 Jul 2006 13:09:51 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="privacy_list_default_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Active on each startup</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_privacy_list_default_checkbutton_toggled" last_modification_time="Sat, 01 Jul 2006 13:10:00 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="GtkHSeparator" id="title_hseparator"> + <property name="visible">True</property> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="list_of_rules_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>List of rules</b></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.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</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">5</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="list_of_rules_combobox"> + <property name="visible">True</property> + <property name="items" translatable="yes"></property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + <signal name="changed" handler="on_list_of_rules_combobox_changed" last_modification_time="Mon, 03 Jul 2006 20:44:19 GMT"/> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="delete_open_buttons_hbox"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkButton" id="new_rule_button"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-add</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_new_rule_button_clicked" last_modification_time="Sat, 01 Jul 2006 13:09:03 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="delete_rule_button"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-remove</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_delete_rule_button_clicked" last_modification_time="Sat, 01 Jul 2006 13:08:57 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="open_rule_button"> + <property name="border_width">6</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-edit</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_open_rule_button_clicked" last_modification_time="Sat, 01 Jul 2006 13:08:50 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="GtkVBox" id="add_edit_vbox"> + <property name="border_width">5</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHSeparator" id="edit_between_list_edit_hseparator"> + <property name="visible">True</property> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="add_edit_rule_label"> + <property name="visible">True</property> + <property name="label" translatable="yes"><b>Add / Edit a rule</b></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.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</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">5</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="edit_fields_hbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkVBox" id="edit_allow_deny_vbox"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="edit_allow_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Allow</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkRadioButton" id="edit_deny_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Deny</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">edit_allow_radiobutton</property> + </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">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="edit_type_vbox"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="edit_type_jabberid_hbox"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="edit_type_jabberid_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">JabberID</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="edit_type_jabberid_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <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> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </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="edit_type_group_hbox"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="edit_type_group_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">all in the group</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">edit_type_jabberid_radiobutton</property> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="edit_type_group_combobox"> + <property name="visible">True</property> + <property name="items" translatable="yes"></property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </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="edit_type_subscription_hbox"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="edit_type_subscription_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">all by subscription</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">edit_type_jabberid_radiobutton</property> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkComboBox" id="edit_type_subscription_combobox"> + <property name="visible">True</property> + <property name="items" translatable="yes">none +both +from +to</property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </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="edit_type_select_all_hbox"> + <property name="border_width">10</property> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkRadioButton" id="edit_type_select_all_radiobutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">All</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + <property name="group">edit_type_jabberid_radiobutton</property> + </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">False</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="edit_items_vbox"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkCheckButton" id="edit_send_messages_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">to send me messages</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="edit_queries_send_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">to send me queries</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="edit_send_status_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">to view my status</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="edit_view_status_checkbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">to send me status</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </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">True</property> + <property name="fill">True</property> + </packing> + </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="edit_order_new_save_buttons_hbox"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkHBox" id="edit_order_hbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="edit_order_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Order:</property> + <property name="use_underline">False</property> + <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="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">5</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkSpinButton" id="edit_order_spinbutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="climb_rate">1</property> + <property name="digits">0</property> + <property name="numeric">False</property> + <property name="update_policy">GTK_UPDATE_ALWAYS</property> + <property name="snap_to_ticks">False</property> + <property name="wrap">False</property> + <property name="adjustment">1 0 100 1 10 10</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="save_rule_button"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-save</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_save_rule_button_clicked" last_modification_time="Sat, 01 Jul 2006 13:08:40 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">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="edit_last_buttons_separator"> + <property name="visible">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="last_buttons_hbox"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkButton" id="privacy_list_refresh_button"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-refresh</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_privacy_list_refresh_button_clicked" last_modification_time="Sat, 01 Jul 2006 13:09:35 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="privacy_list_close_button"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_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_privacy_list_close_button_clicked" last_modification_time="Sat, 01 Jul 2006 13:09:28 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> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/data/glade/privacy_lists_window.glade b/data/glade/privacy_lists_window.glade new file mode 100644 index 0000000000000000000000000000000000000000..7a747012315a527587a08b35d6de4d9f05a89d03 --- /dev/null +++ b/data/glade/privacy_lists_window.glade @@ -0,0 +1,255 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> + +<widget class="GtkWindow" id="privacy_lists_first_window"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="title" translatable="yes">window1</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <signal name="destroy" handler="on_privacy_lists_first_window_destroy" last_modification_time="Sun, 02 Jul 2006 20:56:21 GMT"/> + + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkLabel" id="Server-based_privacy_lists_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Server-based Privacy Lists</property> + <property name="use_underline">False</property> + <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">5</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="GtkComboBox" id="list_of_privacy_lists_combobox"> + <property name="border_width">4</property> + <property name="visible">True</property> + <property name="items" translatable="yes"></property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="buttons_hbox"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkButton" id="delete_privacy_list_button"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-delete</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_delete_privacy_list_button_clicked" last_modification_time="Sun, 02 Jul 2006 16:47:54 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="open_privacy_list_button"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-open</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_open_privacy_list_button_clicked" last_modification_time="Sun, 02 Jul 2006 16:47:34 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">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="hseparator1"> + <property name="visible">True</property> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="create_privacy_list_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Create your own Privacy Lists</property> + <property name="use_underline">False</property> + <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">5</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="GtkEntry" id="new_privacy_list_entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <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> + </widget> + <packing> + <property name="padding">4</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="new_privacy_list_button"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-new</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_new_privacy_list_button_clicked" last_modification_time="Sun, 02 Jul 2006 16:47:16 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkHSeparator" id="hseparator2"> + <property name="visible">True</property> + </widget> + <packing> + <property name="padding">5</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <property name="homogeneous">True</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkButton" id="privacy_lists_refresh_button"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-refresh</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_privacy_lists_refresh_button_clicked" last_modification_time="Sun, 02 Jul 2006 16:46:48 GMT"/> + </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_privacy_lists_window_button"> + <property name="border_width">5</property> + <property name="visible">True</property> + <property name="can_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="Sun, 02 Jul 2006 20:53:03 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">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/data/glade/profile_window.glade b/data/glade/profile_window.glade index aeaaa851887ae6e9e004aa8d9e0de6a5ad94afc5..723df7548c4b3117ce2fe3e795dd857bcb0a42bc 100644 --- a/data/glade/profile_window.glade +++ b/data/glade/profile_window.glade @@ -4,7 +4,6 @@ <glade-interface> <widget class="GtkWindow" id="profile_window"> - <property name="border_width">12</property> <property name="title">Personal Information</property> <property name="type">GTK_WINDOW_TOPLEVEL</property> <property name="window_position">GTK_WIN_POS_NONE</property> @@ -29,6 +28,7 @@ <child> <widget class="GtkNotebook" id="information_notebook"> + <property name="border_width">6</property> <property name="visible">True</property> <property name="show_tabs">True</property> <property name="show_border">True</property> @@ -1016,7 +1016,7 @@ </child> </widget> <packing> - <property name="left_attach">0</property> + <property name="left_attach">1</property> <property name="right_attach">4</property> <property name="top_attach">6</property> <property name="bottom_attach">7</property> @@ -1024,6 +1024,34 @@ <property name="y_options">expand</property> </packing> </child> + + <child> + <widget class="GtkLabel" id="label58"> + <property name="visible">True</property> + <property name="label" translatable="yes">Avatar:</property> + <property name="use_underline">False</property> + <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</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</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="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">6</property> + <property name="bottom_attach">7</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> </widget> <packing> <property name="tab_expand">False</property> @@ -1800,159 +1828,201 @@ </child> <child> - <widget class="GtkHButtonBox" id="information_hbuttonbox"> + <widget class="GtkHBox" id="hbox2"> + <property name="border_width">6</property> <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_END</property> - <property name="spacing">12</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> <child> - <widget class="GtkButton" id="publish_button"> + <widget class="GtkProgressBar" id="progressbar"> <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_publish_button_clicked"/> + <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="GtkHButtonBox" id="information_hbuttonbox"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">12</property> <child> - <widget class="GtkAlignment" id="alignment1"> + <widget class="GtkButton" id="publish_button"> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="yalign">0</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <property name="top_padding">0</property> - <property name="bottom_padding">0</property> - <property name="left_padding">0</property> - <property name="right_padding">0</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_publish_button_clicked"/> <child> - <widget class="GtkHBox" id="hbox1"> + <widget class="GtkAlignment" id="alignment1"> <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">2</property> - - <child> - <widget class="GtkImage" id="image1"> - <property name="visible">True</property> - <property name="stock">gtk-go-up</property> - <property name="icon_size">4</property> - <property name="xalign">0</property> - <property name="yalign">0</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> <child> - <widget class="GtkLabel" id="label1"> + <widget class="GtkHBox" id="hbox1"> <property name="visible">True</property> - <property name="label" translatable="yes">_Publish</property> - <property name="use_underline">True</property> - <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</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</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> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="stock">gtk-go-up</property> + <property name="icon_size">4</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Publish</property> + <property name="use_underline">True</property> + <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</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</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> </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> </child> </widget> </child> </widget> </child> - </widget> - </child> - - <child> - <widget class="GtkButton" id="retrieve_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_retrieve_button_clicked"/> <child> - <widget class="GtkAlignment" id="alignment2"> + <widget class="GtkButton" id="retrieve_button"> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="yalign">0</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <property name="top_padding">0</property> - <property name="bottom_padding">0</property> - <property name="left_padding">0</property> - <property name="right_padding">0</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_retrieve_button_clicked"/> <child> - <widget class="GtkHBox" id="hbox2"> + <widget class="GtkAlignment" id="alignment2"> <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">2</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> <child> - <widget class="GtkImage" id="image2"> + <widget class="GtkHBox" id="hbox2"> <property name="visible">True</property> - <property name="stock">gtk-go-down</property> - <property name="icon_size">4</property> - <property name="xalign">0</property> - <property name="yalign">0</property> - <property name="xpad">0</property> - <property name="ypad">0</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="stock">gtk-go-down</property> + <property name="icon_size">4</property> + <property name="xalign">0</property> + <property name="yalign">0</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Retrieve</property> + <property name="use_underline">True</property> + <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</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</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> </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - - <child> - <widget class="GtkLabel" id="label2"> - <property name="visible">True</property> - <property name="label" translatable="yes">_Retrieve</property> - <property name="use_underline">True</property> - <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</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</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> </widget> </child> </widget> </child> + + <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="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="Mon, 25 Sep 2006 04:58:43 GMT"/> + </widget> + </child> </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> </child> </widget> <packing> @@ -1961,6 +2031,18 @@ <property name="fill">True</property> </packing> </child> + + <child> + <widget class="GtkStatusbar" id="statusbar"> + <property name="visible">True</property> + <property name="has_resize_grip">False</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> </widget> </child> </widget> diff --git a/data/glade/roster_window.glade b/data/glade/roster_window.glade index 94c8b896ae25b927542163cdef9455909d0732f1..d1c9cf1941f89c8d53d5d81dd3fc494144197aff 100644 --- a/data/glade/roster_window.glade +++ b/data/glade/roster_window.glade @@ -1,328 +1,413 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> -<!-- Generated with glade3 - Version: 3.0.0 - Date: Fri Aug 18 19:07:58 2006 - User: kirov - Host: kirov ---> +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + <glade-interface> - <widget class="GtkWindow" id="roster_window"> - <property name="width_request">85</property> - <property name="height_request">200</property> - <property name="title">Gajim</property> - <property name="role">roster</property> - <property name="default_width">150</property> - <property name="default_height">400</property> - <signal name="focus_out_event" handler="on_roster_window_focus_out_event"/> - <signal name="focus_in_event" handler="on_roster_window_focus_in_event"/> - <signal name="key_press_event" handler="on_roster_window_key_press_event"/> - <signal name="delete_event" handler="on_roster_window_delete_event"/> - <child> - <widget class="GtkVBox" id="roster_vbox"> - <property name="visible">True</property> - <child> - <widget class="GtkMenuBar" id="menubar"> - <property name="visible">True</property> - <child> - <widget class="GtkMenuItem" id="actions_menu"> - <property name="visible">True</property> - <property name="label">_Actions</property> - <property name="use_underline">True</property> - <signal name="activate" handler="on_actions_menuitem_activate"/> - <child> - <widget class="GtkMenu" id="actions_menu_menu"> - <child> - <widget class="GtkImageMenuItem" id="new_chat_menuitem"> - <property name="visible">True</property> - <property name="label">_Start Chat</property> - <property name="use_underline">True</property> - <child internal-child="image"> - <widget class="GtkImage" id="image1444"> - <property name="visible">True</property> - <property name="xalign">0,000000</property> - <property name="yalign">0,000000</property> - <property name="stock">gtk-jump-to</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkImageMenuItem" id="join_gc_menuitem"> - <property name="visible">True</property> - <property name="label">_Group Chat</property> - <property name="use_underline">True</property> - <child internal-child="image"> - <widget class="GtkImage" id="image1445"> - <property name="visible">True</property> - <property name="xalign">0,000000</property> - <property name="yalign">0,000000</property> - <property name="stock">gtk-connect</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkSeparatorMenuItem" id="separatormenuitem1"> - <property name="visible">True</property> - </widget> - </child> - <child> - <widget class="GtkImageMenuItem" id="add_new_contact_menuitem"> - <property name="visible">True</property> - <property name="label">Add _Contact</property> - <property name="use_underline">True</property> - <child internal-child="image"> - <widget class="GtkImage" id="image1446"> - <property name="visible">True</property> - <property name="xalign">0,000000</property> - <property name="yalign">0,000000</property> - <property name="stock">gtk-add</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkImageMenuItem" id="service_disco_menuitem"> - <property name="visible">True</property> - <property name="label">_Discover Services</property> - <property name="use_underline">True</property> - <child internal-child="image"> - <widget class="GtkImage" id="image1447"> - <property name="visible">True</property> - <property name="xalign">0,000000</property> - <property name="yalign">0,000000</property> - <property name="stock">gtk-find</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkMenuItem" id="advanced_menuitem"> - <property name="visible">True</property> - <property name="label">_Advanced</property> - <property name="use_underline">True</property> - </widget> - </child> - <child> - <widget class="GtkCheckMenuItem" id="show_offline_contacts_menuitem"> - <property name="visible">True</property> - <property name="label">Show _Offline Contacts</property> - <property name="use_underline">True</property> - <signal name="activate" handler="on_show_offline_contacts_menuitem_activate"/> - <accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/> - </widget> - </child> - <child> - <widget class="GtkSeparatorMenuItem" id="separator1"> - <property name="visible">True</property> - </widget> - </child> - <child> - <widget class="GtkImageMenuItem" id="quit_menuitem"> - <property name="visible">True</property> - <property name="label">_Quit</property> - <property name="use_underline">True</property> - <signal name="activate" handler="on_quit_menuitem_activate"/> - <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/> - <child internal-child="image"> - <widget class="GtkImage" id="image1448"> - <property name="visible">True</property> - <property name="xalign">0,000000</property> - <property name="yalign">0,000000</property> - <property name="stock">gtk-quit</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkMenuItem" id="edit_menu"> - <property name="visible">True</property> - <property name="label">_Edit</property> - <property name="use_underline">True</property> - <signal name="activate" handler="on_edit_menuitem_activate"/> - <child> - <widget class="GtkMenu" id="edit_menu_menu"> - <child> - <widget class="GtkImageMenuItem" id="accounts_menuitem"> - <property name="visible">True</property> - <property name="label">A_ccounts</property> - <property name="use_underline">True</property> - <signal name="activate" handler="on_accounts_menuitem_activate"/> - <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/> - <child internal-child="image"> - <widget class="GtkImage" id="image1449"> - <property name="visible">True</property> - <property name="xalign">0,000000</property> - <property name="yalign">0,000000</property> - <property name="stock">gtk-network</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkImageMenuItem" id="file_transfers_menuitem"> - <property name="visible">True</property> - <property name="label">File _Transfers</property> - <property name="use_underline">True</property> - <signal name="activate" handler="on_file_transfers_menuitem_activate"/> - <accelerator key="T" modifiers="GDK_CONTROL_MASK" signal="activate"/> - <child internal-child="image"> - <widget class="GtkImage" id="image1450"> - <property name="visible">True</property> - <property name="xalign">0,000000</property> - <property name="yalign">0,000000</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkImageMenuItem" id="profile_avatar_menuitem"> - <property name="visible">True</property> - <property name="label">Profile, Avatar</property> - <property name="use_underline">True</property> - <child internal-child="image"> - <widget class="GtkImage" id="image1305"> - <property name="visible">True</property> - <property name="xalign">0,000000</property> - <property name="yalign">0,000000</property> - <property name="stock">gtk-properties</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkSeparatorMenuItem" id="separator2"> - <property name="visible">True</property> - </widget> - </child> - <child> - <widget class="GtkImageMenuItem" id="preferences_menuitem"> - <property name="visible">True</property> - <property name="label">_Preferences</property> - <property name="use_underline">True</property> - <signal name="activate" handler="on_preferences_menuitem_activate"/> - <accelerator key="P" modifiers="GDK_CONTROL_MASK" signal="activate"/> - <child internal-child="image"> - <widget class="GtkImage" id="image1451"> - <property name="visible">True</property> - <property name="xalign">0,000000</property> - <property name="yalign">0,000000</property> - <property name="stock">gtk-preferences</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkMenuItem" id="help_menu"> - <property name="visible">True</property> - <property name="label">_Help</property> - <property name="use_underline">True</property> - <child> - <widget class="GtkMenu" id="help_menu_menu"> - <child> - <widget class="GtkImageMenuItem" id="contents_menuitem"> - <property name="visible">True</property> - <property name="tooltip">Help online</property> - <property name="label">_Contents</property> - <property name="use_underline">True</property> - <signal name="activate" handler="on_contents_menuitem_activate"/> - <child internal-child="image"> - <widget class="GtkImage" id="image1452"> - <property name="visible">True</property> - <property name="xalign">0,000000</property> - <property name="yalign">0,000000</property> - <property name="stock">gtk-help</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkMenuItem" id="faq_menuitem"> - <property name="visible">True</property> - <property name="tooltip">Frequently Asked Questions (online)</property> - <property name="label">_FAQ</property> - <property name="use_underline">True</property> - <signal name="activate" handler="on_faq_menuitem_activate"/> - </widget> - </child> - <child> - <widget class="GtkImageMenuItem" id="about_menuitem"> - <property name="visible">True</property> - <property name="label">gtk-about</property> - <property name="use_underline">True</property> - <property name="use_stock">True</property> - <signal name="activate" handler="on_about_menuitem_activate"/> - </widget> - </child> - </widget> - </child> - </widget> - </child> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <widget class="GtkScrolledWindow" id="scrolledwindow"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="border_width">2</property> - <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> - <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <child> - <widget class="GtkTreeView" id="roster_treeview"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <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="scroll_event" handler="on_roster_treeview_scroll_event"/> - <signal name="style_set" handler="on_roster_treeview_style_set"/> - </widget> - </child> - </widget> - <packing> - <property name="position">1</property> - </packing> - </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> - </child> - </widget> + +<widget class="GtkWindow" id="roster_window"> + <property name="width_request">85</property> + <property name="height_request">200</property> + <property name="title" translatable="yes">Gajim</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">150</property> + <property name="default_height">400</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="role">roster</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <signal name="delete_event" handler="on_roster_window_delete_event" last_modification_time="Mon, 21 Mar 2005 12:34:59 GMT"/> + <signal name="focus_in_event" handler="on_roster_window_focus_in_event" last_modification_time="Sun, 04 Sep 2005 16:33:35 GMT"/> + <signal name="key_press_event" handler="on_roster_window_key_press_event" last_modification_time="Tue, 20 Sep 2005 19:26:27 GMT"/> + <signal name="focus_out_event" handler="on_roster_window_focus_out_event" last_modification_time="Tue, 08 Nov 2005 14:01:01 GMT"/> + + <child> + <widget class="GtkVBox" id="roster_vbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkMenuBar" id="menubar"> + <property name="visible">True</property> + <property name="pack_direction">GTK_PACK_DIRECTION_LTR</property> + <property name="child_pack_direction">GTK_PACK_DIRECTION_LTR</property> + + <child> + <widget class="GtkMenuItem" id="actions_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Actions</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_actions_menuitem_activate" last_modification_time="Sun, 19 Feb 2006 17:10:56 GMT"/> + + <child> + <widget class="GtkMenu" id="actions_menu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="new_chat_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Start Chat</property> + <property name="use_underline">True</property> + + <child internal-child="image"> + <widget class="GtkImage" id="image1444"> + <property name="visible">True</property> + <property name="stock">gtk-jump-to</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="join_gc_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Group Chat</property> + <property name="use_underline">True</property> + + <child internal-child="image"> + <widget class="GtkImage" id="image1445"> + <property name="visible">True</property> + <property name="stock">gtk-connect</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separatormenuitem1"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="add_new_contact_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Add _Contact</property> + <property name="use_underline">True</property> + + <child internal-child="image"> + <widget class="GtkImage" id="image1446"> + <property name="visible">True</property> + <property name="stock">gtk-add</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="service_disco_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Discover Services</property> + <property name="use_underline">True</property> + + <child internal-child="image"> + <widget class="GtkImage" id="image1447"> + <property name="visible">True</property> + <property name="stock">gtk-find</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="advanced_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Advanced</property> + <property name="use_underline">True</property> + </widget> + </child> + + <child> + <widget class="GtkCheckMenuItem" id="show_offline_contacts_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Show _Offline Contacts</property> + <property name="use_underline">True</property> + <property name="active">False</property> + <signal name="activate" handler="on_show_offline_contacts_menuitem_activate" last_modification_time="Tue, 01 Mar 2005 23:29:52 GMT"/> + <accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator1"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="quit_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Quit</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_quit_menuitem_activate" last_modification_time="Tue, 01 Mar 2005 23:37:49 GMT"/> + <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1448"> + <property name="visible">True</property> + <property name="stock">gtk-quit</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="edit_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Edit</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_edit_menuitem_activate" last_modification_time="Fri, 07 Apr 2006 22:46:56 GMT"/> + + <child> + <widget class="GtkMenu" id="edit_menu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="accounts_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">A_ccounts</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_accounts_menuitem_activate" last_modification_time="Tue, 01 Mar 2005 23:23:19 GMT"/> + <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1449"> + <property name="visible">True</property> + <property name="stock">gtk-network</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="file_transfers_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">File _Transfers</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_file_transfers_menuitem_activate" last_modification_time="Wed, 03 Aug 2005 15:44:28 GMT"/> + <accelerator key="T" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1450"> + <property name="visible">True</property> + <property name="stock">gtk-file</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="profile_avatar_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Profile, Avatar</property> + <property name="use_underline">True</property> + + <child internal-child="image"> + <widget class="GtkImage" id="image1305"> + <property name="visible">True</property> + <property name="stock">gtk-properties</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator2"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="preferences_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Preferences</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_preferences_menuitem_activate" last_modification_time="Tue, 01 Mar 2005 22:58:18 GMT"/> + <accelerator key="P" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1451"> + <property name="visible">True</property> + <property name="stock">gtk-preferences</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="help_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Help</property> + <property name="use_underline">True</property> + + <child> + <widget class="GtkMenu" id="help_menu_menu"> + + <child> + <widget class="GtkImageMenuItem" id="contents_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Help online</property> + <property name="label" translatable="yes">_Contents</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_contents_menuitem_activate" last_modification_time="Thu, 06 Oct 2005 23:29:10 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image1452"> + <property name="visible">True</property> + <property name="stock">gtk-help</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkMenuItem" id="faq_menuitem"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Frequently Asked Questions (online)</property> + <property name="label" translatable="yes">_FAQ</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_faq_menuitem_activate" last_modification_time="Thu, 06 Oct 2005 23:29:10 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="about_menuitem"> + <property name="visible">True</property> + <property name="label">gtk-about</property> + <property name="use_stock">True</property> + <signal name="activate" handler="on_about_menuitem_activate" last_modification_time="Tue, 01 Mar 2005 22:56:45 GMT"/> + </widget> + </child> + </widget> + </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="GtkScrolledWindow" id="scrolledwindow"> + <property name="border_width">2</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="roster_treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <property name="rules_hint">False</property> + <property name="reorderable">True</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="button_press_event" handler="on_roster_treeview_button_press_event" last_modification_time="Mon, 28 Feb 2005 14:16:44 GMT"/> + <signal name="row_activated" handler="on_roster_treeview_row_activated" last_modification_time="Mon, 28 Feb 2005 14:18:06 GMT"/> + <signal name="row_expanded" handler="on_roster_treeview_row_expanded" last_modification_time="Mon, 28 Feb 2005 14:18:14 GMT"/> + <signal name="row_collapsed" handler="on_roster_treeview_row_collapsed" last_modification_time="Mon, 28 Feb 2005 14:18:33 GMT"/> + <signal name="key_press_event" handler="on_roster_treeview_key_press_event" last_modification_time="Sat, 26 Mar 2005 20:39:36 GMT"/> + <signal name="motion_notify_event" handler="on_roster_treeview_motion_notify_event" last_modification_time="Wed, 06 Jul 2005 14:38:58 GMT"/> + <signal name="leave_notify_event" handler="on_roster_treeview_leave_notify_event" last_modification_time="Wed, 06 Jul 2005 14:39:06 GMT"/> + <signal name="scroll_event" handler="on_roster_treeview_scroll_event" last_modification_time="Fri, 08 Jul 2005 22:09:03 GMT"/> + <signal name="style_set" handler="on_roster_treeview_style_set" last_modification_time="Tue, 08 Nov 2005 14:03:30 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="GtkComboBox" id="status_combobox"> + <property name="visible">True</property> + <property name="add_tearoffs">False</property> + <property name="focus_on_click">True</property> + <signal name="changed" handler="on_status_combobox_changed" last_modification_time="Sat, 05 Nov 2005 18:07:49 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + </glade-interface> diff --git a/data/glade/systray_context_menu.glade b/data/glade/systray_context_menu.glade index 0f3aaec88436d4ee692650d7b52a59ded92117e8..c82aec544fbae6841750aeab4e65e24a88bc9680 100644 --- a/data/glade/systray_context_menu.glade +++ b/data/glade/systray_context_menu.glade @@ -2,6 +2,7 @@ <!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> <glade-interface> + <widget class="GtkMenu" id="systray_context_menu"> <child> @@ -11,7 +12,7 @@ <property name="use_underline">True</property> <child internal-child="image"> - <widget class="GtkImage" id="image1371"> + <widget class="GtkImage" id="image1455"> <property name="visible">True</property> <property name="stock">gtk-network</property> <property name="icon_size">1</property> @@ -31,7 +32,7 @@ <property name="use_underline">True</property> <child internal-child="image"> - <widget class="GtkImage" id="image1372"> + <widget class="GtkImage" id="image1456"> <property name="visible">True</property> <property name="stock">gtk-jump-to</property> <property name="icon_size">1</property> @@ -51,7 +52,7 @@ <property name="use_underline">True</property> <child internal-child="image"> - <widget class="GtkImage" id="image1445"> + <widget class="GtkImage" id="image1457"> <property name="visible">True</property> <property name="stock">gtk-connect</property> <property name="icon_size">1</property> @@ -71,7 +72,7 @@ <property name="use_underline">True</property> <child internal-child="image"> - <widget class="GtkImage" id="image1373"> + <widget class="GtkImage" id="image1458"> <property name="visible">True</property> <property name="stock">gtk-new</property> <property name="icon_size">1</property> @@ -107,7 +108,7 @@ <signal name="activate" handler="on_show_roster_menuitem_activate" last_modification_time="Sat, 29 Oct 2005 23:55:24 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image1374"> + <widget class="GtkImage" id="image1459"> <property name="visible">True</property> <property name="stock">gtk-home</property> <property name="icon_size">1</property> @@ -144,4 +145,5 @@ </widget> </child> </widget> + </glade-interface> diff --git a/data/glade/vcard_information_window.glade b/data/glade/vcard_information_window.glade index 7b9eed48847b33efdda97bce2ae12a48cc372ab5..3b88416c0e274ecd6ac9809e753f764ac511bb41 100644 --- a/data/glade/vcard_information_window.glade +++ b/data/glade/vcard_information_window.glade @@ -652,7 +652,7 @@ </child> <child> - <widget class="GtkTable" id="table2"> + <widget class="GtkTable" id="personal_info_table"> <property name="border_width">12</property> <property name="visible">True</property> <property name="n_rows">6</property> @@ -1640,34 +1640,6 @@ </packing> </child> - <child> - <widget class="GtkLabel" id="URL_label"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes"></property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - <property name="yalign">0</property> - <property name="xpad">5</property> - <property name="ypad">5</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="left_attach">1</property> - <property name="right_attach">4</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> <widget class="GtkLabel" id="TEL_HOME_NUMBER_label"> <property name="visible">True</property> @@ -2581,6 +2553,60 @@ <property name="fill">True</property> </packing> </child> + + <child> + <widget class="GtkHBox" id="hbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkProgressBar" id="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="GtkHButtonBox" id="hbuttonbox1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <property name="spacing">0</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="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="Mon, 25 Sep 2006 05:08:55 GMT"/> + </widget> + </child> + </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">True</property> + <property name="fill">True</property> + </packing> + </child> </widget> </child> </widget> diff --git a/po/pl.po b/po/pl.po index 54bdb4a3b45bd7a66480c53ab7263b88426fedb2..6303d70241c433792fdad98ed0ddd1d3e24bfc56 100644 --- a/po/pl.po +++ b/po/pl.po @@ -1334,7 +1334,7 @@ msgstr "W każdej _wiadomoÅ›ci" #: ../data/glade/preferences_window.glade.h:58 msgid "One message _window:" -msgstr "WyÅ›lij wiadomość i _zamknij okno" +msgstr "Grupuj okna:" #: ../data/glade/preferences_window.glade.h:59 msgid "Play _sounds" diff --git a/src/chat_control.py b/src/chat_control.py index b9cf730a7918a091839395a3d46a8c6d211c4a99..7b19fc563920c1caeaa17f1c148eae4d8f31956f 100644 --- a/src/chat_control.py +++ b/src/chat_control.py @@ -196,7 +196,6 @@ def __init__(self, type_id, parent_win, widget_name, display_names, contact, self.msg_textview.lang = lang spell.set_language(lang) except (gobject.GError, RuntimeError), msg: - #FIXME: add a ui for this use spell.set_language() dialogs.ErrorDialog(unicode(msg), _('If that is not your language ' 'for which you want to highlight misspelled words, then please ' 'set your $LANG as appropriate. Eg. for French do export ' @@ -1018,7 +1017,7 @@ def draw_banner(self, chatstate = None): acct_info = '' self.account_displayed = False for ctrl in self.parent_win.controls(): - if ctrl == self: + if ctrl == self or ctrl.type_id == 'gc': continue if self.contact.get_shown_name() == ctrl.contact.get_shown_name()\ and not avoid_showing_account_too: @@ -1276,9 +1275,6 @@ def get_tab_label(self, chatstate): elif chatstate == 'paused': color = gajim.config.get_per('themes', theme, 'state_paused_color') - else: - color = gajim.config.get_per('themes', theme, - 'state_active_color') if color: # We set the color for when it's the current tab or not color = gtk.gdk.colormap_get_system().alloc_color(color) @@ -1287,6 +1283,9 @@ def get_tab_label(self, chatstate): if chatstate in ('inactive', 'gone') and\ self.parent_win.get_active_control() != self: color = self.lighten_color(color) + elif chatstate == 'active' : # active, get color from gtk + color = self.parent_win.notebook.style.fg[gtk.STATE_ACTIVE] + name = self.contact.get_shown_name() if self.resource: diff --git a/src/common/config.py b/src/common/config.py index 1a0f188650ad10757defd16b6bf554102611fdc6..08b198644042cbbac4bc03fe6917a144540e08c0 100644 --- a/src/common/config.py +++ b/src/common/config.py @@ -37,6 +37,8 @@ opt_color = [ 'color', '^(#[0-9a-fA-F]{6})|()$' ] opt_one_window_types = ['never', 'always', 'peracct', 'pertype'] +DEFAULT_ICONSET = 'dcraven' + class Config: __options = { @@ -67,7 +69,7 @@ class Config: 'last_status_msg_invisible': [ opt_str, '' ], 'last_status_msg_offline': [ opt_str, '' ], 'trayicon': [ opt_bool, True, '', True ], - 'iconset': [ opt_str, 'dcraven', '', True ], + 'iconset': [ opt_str, DEFAULT_ICONSET, '', True ], 'use_transports_iconsets': [ opt_bool, True, '', True ], 'inmsgcolor': [ opt_color, '#a34526', '', True ], 'outmsgcolor': [ opt_color, '#164e6f', '', True ], @@ -126,6 +128,7 @@ class Config: 'before_nickname': [ opt_str, '' ], 'after_nickname': [ opt_str, ':' ], 'send_os_info': [ opt_bool, True ], + 'set_status_msg_from_current_music_track': [ opt_bool, False ], 'notify_on_new_gmail_email': [ opt_bool, True ], 'notify_on_new_gmail_email_extra': [ opt_bool, False ], 'usegpg': [ opt_bool, False, '', True ], @@ -188,7 +191,7 @@ class Config: 'restored_messages_color': [opt_str, 'grey'], 'restored_messages_small': [opt_bool, True, _('If True, restored messages will use a smaller font than the default one.')], 'hide_avatar_of_transport': [opt_bool, False, _('Don\'t show avatar for the transport itself.')], - 'roster_window_skip_taskbar': [opt_bool, False], + 'roster_window_skip_taskbar': [opt_bool, False, _('Don\'t show roster in the system taskbar.')], 'use_urgency_hint': [opt_bool, True, _('If True and installed GTK+ and PyGTK versions are at least 2.8, make the window flash (the default behaviour in most Window Managers) when holding pending events.')], 'notification_timeout': [opt_int, 5], 'send_sha_in_gc_presence': [opt_bool, True, _('Jabberd1.4 does not like sha info when one join a password protected room. Turn this option to False to stop sending sha info in group chat presences.')], @@ -290,8 +293,6 @@ class Config: 'bannerfontattrs': [ opt_str, 'B', '', True ], # http://www.pitt.edu/~nisg/cis/web/cgi/rgb.html - # FIXME: not black but the default color from gtk+ theme - 'state_active_color': [ opt_color, 'black' ], 'state_inactive_color': [ opt_color, 'grey62' ], 'state_composing_color': [ opt_color, 'green4' ], 'state_paused_color': [ opt_color, 'mediumblue' ], diff --git a/src/common/connection_handlers.py b/src/common/connection_handlers.py index dc15c9b8e11d845cda78df0b0af2707dcbf27507..c29cf539a122de5ea5172186990a239f2b8ee0ca 100644 --- a/src/common/connection_handlers.py +++ b/src/common/connection_handlers.py @@ -175,7 +175,7 @@ def send_socks5_info(self, file_props, fast = True, receiver = None, except socket.gaierror: self.dispatch('ERROR', (_('Wrong host'), _('The host you configured as the ft_override_host_to_send advanced option is not valid, so ignored.'))) ft_override_host_to_send = self.peerhost[0] - listener = gajim.socks5queue.start_listener(self.peerhost[0], port, + listener = gajim.socks5queue.start_listener(port, sha_str, self._result_socks5_sid, file_props['sid']) if listener == None: file_props['error'] = -5 @@ -1134,6 +1134,12 @@ def _HttpAuthCB(self, con, iq_obj): raise common.xmpp.NodeProcessed def _ErrorCB(self, con, iq_obj): + gajim.log.debug('ErrorCB') + if iq_obj.getQueryNS() == common.xmpp.NS_VERSION: + who = helpers.get_full_jid_from_iq(iq_obj) + jid_stripped, resource = gajim.get_room_and_nick_from_fjid(who) + self.dispatch('OS_INFO', (jid_stripped, resource, '', '')) + return errmsg = iq_obj.getErrorMsg() errcode = iq_obj.getErrorCode() jid_from = helpers.get_full_jid_from_iq(iq_obj) diff --git a/src/common/helpers.py b/src/common/helpers.py index 1226f2cd54f6dd8216b93ff00affef4c88f3d27f..1f3a7206b385115005fede2de5c471e9addc5f3b 100644 --- a/src/common/helpers.py +++ b/src/common/helpers.py @@ -290,6 +290,21 @@ def get_uf_role(role, plural = False): else: role_name = _('Visitor') return role_name + +def get_uf_affiliation(affiliation): + '''Get a nice and translated affilition for muc''' + if affiliation == 'none': + affiliation_name = Q_('?Group Chat Contact Affiliation:None') + elif affiliation == 'owner': + affiliation_name = _('Owner') + elif affiliation == 'admin': + affiliation_name = _('Administrator') + elif affiliation == 'member': + affiliation_name = _('Member') + else: # Argl ! An unknown affiliation ! + affiliation_name = affiliation.capitalize() + return affiliation_name + def get_sorted_keys(adict): keys = adict.keys() diff --git a/src/common/socks5.py b/src/common/socks5.py index 6e472e1b8174500a375ed67ff207d75bea815e11..26d8e567274badf5afbf9ad60e17b30eaa9b3d9a 100644 --- a/src/common/socks5.py +++ b/src/common/socks5.py @@ -74,13 +74,13 @@ def __init__(self, idlequeue, complete_transfer_cb = None, progress_transfer_cb self.on_success = None self.on_failure = None - def start_listener(self, host, port, sha_str, sha_handler, sid): + def start_listener(self, port, sha_str, sha_handler, sid): ''' start waiting for incomming connections on (host, port) and do a socks5 authentication using sid for generated sha ''' self.sha_handlers[sha_str] = (sha_handler, sid) if self.listener == None: - self.listener = Socks5Listener(self.idlequeue, host, port) + self.listener = Socks5Listener(self.idlequeue, port) self.listener.queue = self self.listener.bind() if self.listener.started is False: @@ -790,12 +790,12 @@ def disconnect(self, cb = True): self.queue.remove_sender(self.queue_idx, False) class Socks5Listener(IdleObject): - def __init__(self, idlequeue, host, port): - ''' handle all incomming connections on (host, port) + def __init__(self, idlequeue, port): + ''' handle all incomming connections on (0.0.0.0, port) This class implements IdleObject, but we will expect only pollin events though ''' - self.host, self.port = host, port + self.port = port self.queue_idx = -1 self.idlequeue = idlequeue self.queue = None diff --git a/src/common/xmpp/protocol.py b/src/common/xmpp/protocol.py index 2ac25069db77eab9f2ef2fb21d67cbf3c0fbfb8d..b9d2ad9ff57a7b6653e566fd36f34ffc53d07e77 100644 --- a/src/common/xmpp/protocol.py +++ b/src/common/xmpp/protocol.py @@ -19,7 +19,7 @@ xmpp-related data structures. """ -from simplexml import Node,ustr +from simplexml import Node,NodeBuilder,ustr import time NS_ACTIVITY ='http://jabber.org/protocol/activity' # JEP-0108 NS_ADDRESS ='http://jabber.org/protocol/address' # JEP-0033 @@ -94,6 +94,7 @@ NS_VERSION ='jabber:iq:version' NS_WAITINGLIST ='http://jabber.org/protocol/waitinglist' # JEP-0130 NS_XHTML_IM ='http://jabber.org/protocol/xhtml-im' # JEP-0071 +NS_XHTML = 'http://www.w3.org/1999/xhtml' # " NS_DATA_LAYOUT ='http://jabber.org/protocol/xdata-layout' # JEP-0141 NS_DATA_VALIDATE='http://jabber.org/protocol/xdata-validate' # JEP-0122 NS_XMPP_STREAMS ='urn:ietf:params:xml:ns:xmpp-streams' @@ -385,16 +386,21 @@ def __setitem__(self,item,val): class Message(Protocol): """ XMPP Message stanza - "push" mechanism.""" - def __init__(self, to=None, body=None, typ=None, subject=None, attrs={}, frm=None, payload=[], timestamp=None, xmlns=NS_CLIENT, node=None): + def __init__(self, to=None, body=None, xhtml=None, typ=None, subject=None, attrs={}, frm=None, payload=[], timestamp=None, xmlns=NS_CLIENT, node=None): """ Create message object. You can specify recipient, text of message, type of message any additional attributes, sender of the message, any additional payload (f.e. jabber:x:delay element) and namespace in one go. Alternatively you can pass in the other XML object as the 'node' parameted to replicate it as message. """ Protocol.__init__(self, 'message', to=to, typ=typ, attrs=attrs, frm=frm, payload=payload, timestamp=timestamp, xmlns=xmlns, node=node) if body: self.setBody(body) + if xhtml: self.setXHTML(xhtml) if subject: self.setSubject(subject) def getBody(self): """ Returns text of the message. """ return self.getTagData('body') + def getXHTML(self): + """ Returns serialized xhtml-im body text of the message. """ + xhtml = self.getTag('html') + return str(xhtml.getTag('body')) def getSubject(self): """ Returns subject of the message. """ return self.getTagData('subject') @@ -404,6 +410,11 @@ def getThread(self): def setBody(self,val): """ Sets the text of the message. """ self.setTagData('body',val) + def setXHTML(self,val): + """ Sets the xhtml text of the message (JEP-0071). + The parameter is the "inner html" to the body.""" + dom = NodeBuilder(val) + self.setTag('html',namespace=NS_XHTML_IM).setTag('body',namespace=NS_XHTML).addChild(node=dom.getDom()) def setSubject(self,val): """ Sets the subject of the message. """ self.setTagData('subject',val) diff --git a/src/config.py b/src/config.py index 30748c007cadfcfa7f6f355cd7017bb59f3cbf9c..312b13408c1dcda7fcaa1711db69426c8a77e61c 100644 --- a/src/config.py +++ b/src/config.py @@ -1,7 +1,7 @@ ## config.py ## ## Copyright (C) 2003-2006 Yann Le Boulanger <asterix@lagaule.org> -## Copyright (C) 2005-2006 Nikos Kouremenos <nkour@jabber.org> +## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com> ## Copyright (C) 2005 Dimitur Kirov <dkirov@gmail.com> ## Copyright (C) 2003-2005 Vincent Hanquez <tab@snarc.org> ## @@ -182,7 +182,7 @@ def __init__(self): theme = config_theme.replace('_', ' ') model.append([theme]) if gajim.config.get('roster_theme') == config_theme: - theme_combobox.set_active(i) + theme_combobox.set_active(i) i += 1 self.on_theme_combobox_changed(theme_combobox) @@ -212,19 +212,23 @@ def __init__(self): #before time st = gajim.config.get('before_time') - self.xml.get_widget('before_time_entry').set_text(st) + st = helpers.from_one_line(st) + self.xml.get_widget('before_time_textview').get_buffer().set_text(st) #after time st = gajim.config.get('after_time') - self.xml.get_widget('after_time_entry').set_text(st) + st = helpers.from_one_line(st) + self.xml.get_widget('after_time_textview').get_buffer().set_text(st) #before nickname st = gajim.config.get('before_nickname') - self.xml.get_widget('before_nickname_entry').set_text(st) + st = helpers.from_one_line(st) + self.xml.get_widget('before_nickname_textview').get_buffer().set_text(st) #after nickanme st = gajim.config.get('after_nickname') - self.xml.get_widget('after_nickname_entry').set_text(st) + st = helpers.from_one_line(st) + self.xml.get_widget('after_nickname_textview').get_buffer().set_text(st) #Color for incomming messages colSt = gajim.config.get('inmsgcolor') @@ -455,12 +459,18 @@ def __init__(self): # send os info st = gajim.config.get('send_os_info') self.xml.get_widget('send_os_info_checkbutton').set_active(st) + + # set status msg from currently playing music track + st = gajim.config.get('set_status_msg_from_current_music_track') + self.xml.get_widget( + 'set_status_msg_from_current_music_track_checkbutton').set_active(st) # Notify user of new gmail e-mail messages, # only show checkbox if user has a gtalk account frame_gmail = self.xml.get_widget('frame_gmail') notify_gmail_checkbutton = self.xml.get_widget('notify_gmail_checkbutton') - notify_gmail_extra_checkbutton = self.xml.get_widget('notify_gmail_extra_checkbutton') + notify_gmail_extra_checkbutton = self.xml.get_widget( + 'notify_gmail_extra_checkbutton') frame_gmail.set_no_show_all(True) for account in gajim.config.get_per('accounts'): @@ -512,6 +522,8 @@ def on_trayicon_checkbutton_toggled(self, widget): gajim.interface.systray.change_status(show) else: gajim.config.set('trayicon', False) + if not gajim.interface.roster.window.get_property('visible'): + gajim.interface.roster.window.present() gajim.interface.hide_systray() gajim.config.set('show_roster_on_startup', True) # no tray, show roster! gajim.interface.roster.draw_roster() @@ -523,7 +535,7 @@ def on_save_position_checkbutton_toggled(self, widget): def on_sort_by_show_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'sort_by_show') gajim.interface.roster.draw_roster() - + def on_show_status_msgs_in_roster_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'show_status_msgs_in_roster') gajim.interface.roster.draw_roster() @@ -643,9 +655,9 @@ def on_speller_checkbutton_toggled(self, widget): def _set_sensitivity_for_before_after_time_widgets(self, sensitive): self.xml.get_widget('before_time_label').set_sensitive(sensitive) - self.xml.get_widget('before_time_entry').set_sensitive(sensitive) + self.xml.get_widget('before_time_textview').set_sensitive(sensitive) self.xml.get_widget('after_time_label').set_sensitive(sensitive) - self.xml.get_widget('after_time_entry').set_sensitive(sensitive) + self.xml.get_widget('after_time_textview').set_sensitive(sensitive) def on_time_never_radiobutton_toggled(self, widget): if widget.get_active(): @@ -665,20 +677,33 @@ def on_time_always_radiobutton_toggled(self, widget): self._set_sensitivity_for_before_after_time_widgets(True) gajim.interface.save_config() - def on_before_time_entry_focus_out_event(self, widget, event): - gajim.config.set('before_time', widget.get_text().decode('utf-8')) + def _get_textview_text(self, tv): + buffer = tv.get_buffer() + begin, end = buffer.get_bounds() + return buffer.get_text(begin, end).decode('utf-8') + + def on_before_time_textview_focus_out_event(self, widget, event): + text = self._get_textview_text(widget) + text = helpers.to_one_line(text) + gajim.config.set('before_time', text) gajim.interface.save_config() - def on_after_time_entry_focus_out_event(self, widget, event): - gajim.config.set('after_time', widget.get_text().decode('utf-8')) + def on_after_time_textview_focus_out_event(self, widget, event): + text = self._get_textview_text(widget) + text = helpers.to_one_line(text) + gajim.config.set('after_time', text) gajim.interface.save_config() - def on_before_nickname_entry_focus_out_event(self, widget, event): - gajim.config.set('before_nickname', widget.get_text().decode('utf-8')) + def on_before_nickname_textview_focus_out_event(self, widget, event): + text = self._get_textview_text(widget) + text = helpers.to_one_line(text) + gajim.config.set('before_nickname', text) gajim.interface.save_config() - def on_after_nickname_entry_focus_out_event(self, widget, event): - gajim.config.set('after_nickname', widget.get_text().decode('utf-8')) + def on_after_nickname_textview_focus_out_event(self, widget, event): + text = self._get_textview_text(widget) + text = helpers.to_one_line(text) + gajim.config.set('after_nickname', text) gajim.interface.save_config() def update_text_tags(self): @@ -1064,6 +1089,13 @@ def on_open_advanced_editor_button_clicked(self, widget, data = None): gajim.interface.instances['advanced_config'] = \ dialogs.AdvancedConfigurationWindow() + def set_status_msg_from_current_music_track_checkbutton_toggled(self, + widget): + self.on_checkbutton_toggled(widget, + 'set_status_msg_from_current_music_track') + gajim.interface.roster.enable_syncing_status_msg_from_current_music_track( + widget.get_active()) + #---------- AccountModificationWindow class -------------# class AccountModificationWindow: '''Class for account informations''' @@ -1097,11 +1129,12 @@ def on_checkbutton_toggled(self, widget, widgets): '''set or unset sensitivity of widgets when widget is toggled''' for w in widgets: w.set_sensitive(widget.get_active()) - + def init_account_gpg(self): keyid = gajim.config.get_per('accounts', self.account, 'keyid') keyname = gajim.config.get_per('accounts', self.account, 'keyname') - savegpgpass = gajim.config.get_per('accounts', self.account,'savegpgpass') + savegpgpass = gajim.config.get_per('accounts', self.account, + 'savegpgpass') if not keyid or not gajim.config.get('usegpg'): return @@ -1358,8 +1391,7 @@ def on_save_button_clicked(self, widget): gajim.events.change_account_name(self.account, name) # change account variable for chat / gc controls - for ctrl in gajim.interface.msg_win_mgr.get_controls(): - ctrl.account = name + gajim.interface.msg_win_mgr.change_account_name(self.account, name) # upgrade account variable in opened windows for kind in ('infos', 'disco', 'gc_config'): for j in gajim.interface.instances[name][kind]: @@ -1857,6 +1889,7 @@ def on_merge_checkbutton_toggled(self, widget): else: gajim.interface.roster.regroup = False gajim.interface.roster.draw_roster() + def on_enable_zeroconf_checkbutton_toggled(self, widget): if gajim.config.get('enable_zeroconf'): @@ -2987,9 +3020,6 @@ def save_account(self, login, server, savepass, password): con = connection.Connection(self.account) con.password = password - if not savepass: - password = "" - config = {} config['name'] = login config['hostname'] = server @@ -3018,6 +3048,10 @@ def save_account(self, login, server, savepass, password): def create_vars(self, config): gajim.config.add_per('accounts', self.account) + + if not config['savepass']: + config['password'] = '' + for opt in config: gajim.config.set_per('accounts', self.account, opt, config[opt]) diff --git a/src/conversation_textview.py b/src/conversation_textview.py index 888c9d2b367d72f7f37cc12181ac6e7fe3dc4880..daf1fc7c3b24a20c1980e30d4faeed97e6573c97 100644 --- a/src/conversation_textview.py +++ b/src/conversation_textview.py @@ -138,6 +138,9 @@ def __init__(self, account): self.focus_out_end_iter_offset = None self.line_tooltip = tooltips.BaseTooltip() + + path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'muc_separator.png') + self.focus_out_line_pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file) def del_handlers(self): for i in self.handlers.keys(): @@ -230,19 +233,14 @@ def show_focus_out_line(self): end_iter_for_previous_line) # add the new focus out line - # FIXME: Why is this loaded from disk everytime - path_to_file = os.path.join(gajim.DATA_DIR, 'pixmaps', 'muc_separator.png') - focus_out_line_pixbuf = gtk.gdk.pixbuf_new_from_file(path_to_file) end_iter = buffer.get_end_iter() buffer.insert(end_iter, '\n') - buffer.insert_pixbuf(end_iter, focus_out_line_pixbuf) + buffer.insert_pixbuf(end_iter, self.focus_out_line_pixbuf) end_iter = buffer.get_end_iter() before_img_iter = end_iter.copy() before_img_iter.backward_char() # one char back (an image also takes one char) buffer.apply_tag_by_name('focus-out-line', before_img_iter, end_iter) - #FIXME: remove this workaround when bug is fixed - # c http://bugzilla.gnome.org/show_bug.cgi?id=318569 self.allow_focus_out_line = False @@ -562,6 +560,7 @@ def print_special_text(self, special_text, other_tags): img.show() #add with possible animation self.tv.add_child_at_anchor(img, anchor) + #FIXME: one day, somehow sync with regexp in gajim.py elif special_text.startswith('http://') or \ special_text.startswith('www.') or \ special_text.startswith('ftp://') or \ @@ -664,7 +663,9 @@ def print_conversation_line(self, text, jid, kind, name, tim, current_print_time = gajim.config.get('print_time') if current_print_time == 'always' and kind != 'info': before_str = gajim.config.get('before_time') + before_str = helpers.from_one_line(before_str) after_str = gajim.config.get('after_time') + after_str = helpers.from_one_line(after_str) # get difference in days since epoch (86400 = 24*3600) # number of days since epoch for current time (in GMT) - # number of days since epoch for message (in GMT) @@ -748,7 +749,9 @@ def print_name(self, name, kind, other_tags_for_name): name_tags = other_tags_for_name[:] # create a new list name_tags.append(kind) before_str = gajim.config.get('before_nickname') + before_str = helpers.from_one_line(before_str) after_str = gajim.config.get('after_nickname') + after_str = helpers.from_one_line(after_str) format = before_str + name + after_str + ' ' buffer.insert_with_tags_by_name(end_iter, format, *name_tags) diff --git a/src/dbus_support.py b/src/dbus_support.py index 59e751c417ee84b0b3975ec51adcb2fb5d6d7971..d4f7542a3f846518765bb15ee7b1102afe49f75c 100644 --- a/src/dbus_support.py +++ b/src/dbus_support.py @@ -23,25 +23,17 @@ try: import dbus - version = getattr(dbus, 'version', (0, 20, 0)) - supported = True + import dbus.service + import dbus.glib + supported = True # does use have D-Bus bindings? except ImportError: - version = (0, 0, 0) supported = False if not os.name == 'nt': # only say that to non Windows users print _('D-Bus python bindings are missing in this computer') print _('D-Bus capabilities of Gajim cannot be used') - -# dbus 0.23 leads to segfault with threads_init() -if sys.version[:4] >= '2.4' and version[1] < 30: - supported = False - -if version >= (0, 41, 0): - import dbus.service - import dbus.glib # cause dbus 0.35+ doesn't return signal replies without it class SessionBus: - '''A Singleton for the DBus SessionBus''' + '''A Singleton for the D-Bus SessionBus''' def __init__(self): self.session_bus = None diff --git a/src/dialogs.py b/src/dialogs.py index 6a8ec5de3e8e71e9351486a72f43d9d4d559622d..d6183ea8ac3156a5dd1e9fbd51920095ec18893d 100644 --- a/src/dialogs.py +++ b/src/dialogs.py @@ -837,27 +837,31 @@ def __init__(self, title_text, action, buttons, default_response, self.set_current_folder(current_folder) else: self.set_current_folder(helpers.get_documents_path()) - - buttons = self.action_area.get_children() - possible_responses = {gtk.STOCK_OPEN: on_response_ok, - gtk.STOCK_SAVE: on_response_ok, - gtk.STOCK_CANCEL: on_response_cancel} - for b in buttons: - for response in possible_responses: - if b.get_label() == response: - if not possible_responses[response]: - b.connect('clicked', self.just_destroy) - elif isinstance(possible_responses[response], tuple): - if len(possible_responses[response]) == 1: - b.connect('clicked', possible_responses[response][0]) - else: - b.connect('clicked', *possible_responses[response]) - else: - b.connect('clicked', possible_responses[response]) - break - + self.response_ok, self.response_cancel = \ + on_response_ok, on_response_cancel + # in gtk+-2.10 clicked signal on some of the buttons in a dialog + # is emitted twice, so we cannot rely on 'clicked' signal + self.connect('response', self.on_dialog_response) self.show_all() + def on_dialog_response(self, dialog, response): + if response in (gtk.RESPONSE_CANCEL, gtk.RESPONSE_CLOSE): + if self.response_cancel: + if isinstance(self.response_cancel, tuple): + self.response_cancel[0](dialog, *self.response_cancel[1:]) + else: + self.response_cancel(dialog) + else: + self.just_destroy(dialog) + elif response == gtk.RESPONSE_OK: + if self.response_ok: + if isinstance(self.response_ok, tuple): + self.response_ok[0](dialog, *self.response_ok[1:]) + else: + self.response_ok(dialog) + else: + self.just_destroy(dialog) + def just_destroy(self, widget): self.destroy() @@ -1192,7 +1196,7 @@ def __init__(self, account): title = _('Start Chat with account %s') % account else: title = _('Start Chat') - prompt_text = _('Fill in the jid, or nick of the contact you would like\nto send a chat message to:') + prompt_text = _('Fill in the nickname or the Jabber ID of the contact you would like\nto send a chat message to:') InputDialog.__init__(self, title, prompt_text, is_modal = False) self.completion_dict = {} @@ -1725,10 +1729,13 @@ def on_expander_activate(self, widget): self.input_textview.grab_focus() class PrivacyListWindow: - def __init__(self, account, privacy_list, list_type): - '''list_type can be 0 if list is created or 1 if it id edited''' + '''Window that is used for creating NEW or EDITING already there privacy + lists''' + def __init__(self, account, privacy_list_name, action): + '''action is 'edit' or 'new' depending on if we create a new priv list + or edit an already existing one''' self.account = account - self.privacy_list = privacy_list + self.privacy_list_name = privacy_list_name # Dicts and Default Values self.active_rule = '' @@ -1740,7 +1747,7 @@ def __init__(self, account, privacy_list, list_type): self.allow_deny = 'allow' # Connect to glade - self.xml = gtkgui_helpers.get_glade('privacy_list_edit_window.glade') + self.xml = gtkgui_helpers.get_glade('privacy_list_window.glade') self.window = self.xml.get_widget('privacy_list_edit_window') # Add Widgets @@ -1762,10 +1769,10 @@ def __init__(self, account, privacy_list, list_type): 'privacy_list_default_checkbutton']: self.__dict__[widget_to_add] = self.xml.get_widget(widget_to_add) - # Send translations + self.privacy_lists_title_label.set_label( _('Privacy List <b><i>%s</i></b>') % \ - gtkgui_helpers.escape_for_pango_markup(self.privacy_list)) + gtkgui_helpers.escape_for_pango_markup(self.privacy_list_name)) if len(gajim.connections) > 1: title = _('Privacy List for %s') % self.account @@ -1777,8 +1784,7 @@ def __init__(self, account, privacy_list, list_type): self.privacy_list_active_checkbutton.set_sensitive(False) self.privacy_list_default_checkbutton.set_sensitive(False) - # Check if list is created (0) or edited (1) - if list_type == 1: + if action == 'edit': self.refresh_rules() count = 0 @@ -1799,16 +1805,16 @@ def __init__(self, account, privacy_list, list_type): def on_privacy_list_edit_window_destroy(self, widget): '''close window''' if gajim.interface.instances[self.account].has_key('privacy_list_%s' % \ - self.privacy_list): + self.privacy_list_name): del gajim.interface.instances[self.account]['privacy_list_%s' % \ - self.privacy_list] + self.privacy_list_name] def check_active_default(self, a_d_dict): - if a_d_dict['active'] == self.privacy_list: + if a_d_dict['active'] == self.privacy_list_name: self.privacy_list_active_checkbutton.set_active(True) else: self.privacy_list_active_checkbutton.set_active(False) - if a_d_dict['default'] == self.privacy_list: + if a_d_dict['default'] == self.privacy_list_name: self.privacy_list_default_checkbutton.set_active(True) else: self.privacy_list_default_checkbutton.set_active(False) @@ -1845,7 +1851,7 @@ def privacy_list_received(self, rules): gajim.connections[self.account].get_active_default_lists() def refresh_rules(self): - gajim.connections[self.account].get_privacy_list(self.privacy_list) + gajim.connections[self.account].get_privacy_list(self.privacy_list_name) def on_delete_rule_button_clicked(self, widget): tags = [] @@ -1854,7 +1860,7 @@ def on_delete_rule_button_clicked(self, widget): self.list_of_rules_combobox.get_active_text().decode('utf-8'): tags.append(self.global_rules[rule]) gajim.connections[self.account].set_privacy_list( - self.privacy_list, tags) + self.privacy_list_name, tags) self.privacy_list_received(tags) self.add_edit_vbox.hide() @@ -1918,13 +1924,13 @@ def on_open_rule_button_clicked(self, widget): def on_privacy_list_active_checkbutton_toggled(self, widget): if widget.get_active(): - gajim.connections[self.account].set_active_list(self.privacy_list) + gajim.connections[self.account].set_active_list(self.privacy_list_name) else: gajim.connections[self.account].set_active_list(None) def on_privacy_list_default_checkbutton_toggled(self, widget): if widget.get_active(): - gajim.connections[self.account].set_default_list(self.privacy_list) + gajim.connections[self.account].set_default_list(self.privacy_list_name) else: gajim.connections[self.account].set_default_list(None) @@ -1994,7 +2000,7 @@ def on_save_rule_button_clicked(self, widget): else: tags.append(current_tags) - gajim.connections[self.account].set_privacy_list(self.privacy_list, tags) + gajim.connections[self.account].set_privacy_list(self.privacy_list_name, tags) self.privacy_list_received(tags) self.add_edit_vbox.hide() @@ -2019,7 +2025,9 @@ def on_privacy_list_refresh_button_clicked(self, widget): self.add_edit_vbox.hide() class PrivacyListsWindow: -# To do: UTF-8 ??????? + '''Window that is the main window for Privacy Lists; + we can list there the privacy lists and ask to create a new one + or edit an already there one''' def __init__(self, account): self.account = account @@ -2027,7 +2035,7 @@ def __init__(self, account): self.privacy_lists_save = [] - self.xml = gtkgui_helpers.get_glade('privacy_lists_first_window.glade') + self.xml = gtkgui_helpers.get_glade('privacy_lists_window.glade') self.window = self.xml.get_widget('privacy_lists_first_window') for widget_to_add in ['list_of_privacy_lists_combobox', @@ -2087,7 +2095,7 @@ def on_delete_privacy_list_button_clicked(self, widget): self.list_of_privacy_lists_combobox.get_active()] gajim.connections[self.account].del_privacy_list(active_list) self.privacy_lists_save.remove(active_list) - self.privacy_lists_received({'lists':self.privacy_lists_save}) + self.privacy_lists_received({'lists': self.privacy_lists_save}) def privacy_lists_received(self, lists): if not lists: @@ -2107,7 +2115,7 @@ def on_new_privacy_list_button_clicked(self, widget): window.present() else: gajim.interface.instances[self.account]['privacy_list_%s' % name] = \ - PrivacyListWindow(self.account, name, 0) + PrivacyListWindow(self.account, name, 'new') self.new_privacy_list_entry.set_text('') def on_privacy_lists_refresh_button_clicked(self, widget): @@ -2122,7 +2130,7 @@ def on_open_privacy_list_button_clicked(self, widget): window.present() else: gajim.interface.instances[self.account]['privacy_list_%s' % name] = \ - PrivacyListWindow(self.account, name, 1) + PrivacyListWindow(self.account, name, 'edit') class InvitationReceivedDialog: def __init__(self, account, room_jid, contact_jid, password = None, comment = None): @@ -2291,6 +2299,18 @@ def update_preview(self, widget): return widget.get_preview_widget().set_from_pixbuf(pixbuf) +class AvatarChooserDialog(ImageChooserDialog): + def __init__(self, path_to_file = '', on_response_ok = None, + on_response_cancel = None, on_response_clear = None): + ImageChooserDialog.__init__(self, path_to_file, on_response_ok, + on_response_cancel) + button = gtk.Button(None, gtk.STOCK_CLEAR) + if on_response_clear: + button.connect('clicked', on_response_clear) + button.show_all() + self.action_area.pack_start(button) + self.action_area.reorder_child(button, 0) + class AddSpecialNotificationDialog: def __init__(self, jid): '''jid is the jid for which we want to add special notification diff --git a/src/disco.py b/src/disco.py index f56f70a1cc5efb08e0b8be4f4b6e3beb7f0c5e77..e0f928f91fb11c5b30a90998eff3c4d38741ddca 100644 --- a/src/disco.py +++ b/src/disco.py @@ -36,10 +36,10 @@ # - def update_actions(self) # - def default_action(self) # - def _find_item(self, jid, node) -# - def _add_item(self, model, jid, node, item, force) -# - def _update_item(self, model, iter, jid, node, item) -# - def _update_info(self, model, iter, jid, node, identities, features, data) -# - def _update_error(self, model, iter, jid, node) +# - def _add_item(self, jid, node, item, force) +# - def _update_item(self, iter, jid, node, item) +# - def _update_info(self, iter, jid, node, identities, features, data) +# - def _update_error(self, iter, jid, node) # # * Should call the super class for this method. # All others do not have to call back to the super class. (but can if they want @@ -215,8 +215,8 @@ class ServicesCache: ServiceCache instance.''' def __init__(self, account): self.account = account - self._items = CacheDictionary(15, getrefresh = False) - self._info = CacheDictionary(15, getrefresh = False) + self._items = CacheDictionary(1, getrefresh = True) + self._info = CacheDictionary(1, getrefresh = True) self._cbs = {} def _clean_closure(self, cb, type, addr): @@ -422,6 +422,7 @@ def __init__(self, account, jid = '', node = '', self.xml = gtkgui_helpers.get_glade('service_discovery_window.glade') self.window = self.xml.get_widget('service_discovery_window') self.services_treeview = self.xml.get_widget('services_treeview') + self.model = None # This is more reliable than the cursor-changed signal. selection = self.services_treeview.get_selection() selection.connect_after('changed', @@ -452,7 +453,6 @@ def __init__(self, account, jid = '', node = '', 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() if jid in self.latest_addresses: @@ -720,9 +720,9 @@ def _create_treemodel(self): note that the first two columns should ALWAYS be of type string and contain the JID and node of the item respectively.''' # JID, node, name, address - model = gtk.ListStore(str, str, str, str) - model.set_sort_column_id(3, gtk.SORT_ASCENDING) - self.window.services_treeview.set_model(model) + self.model = gtk.ListStore(str, str, str, str) + self.model.set_sort_column_id(3, gtk.SORT_ASCENDING) + self.window.services_treeview.set_model(self.model) # Name column col = gtk.TreeViewColumn(_('Name')) renderer = gtk.CellRendererText() @@ -740,7 +740,7 @@ def _create_treemodel(self): self.window.services_treeview.set_headers_visible(True) def _clean_treemodel(self): - self.window.services_treeview.get_model().clear() + self.model.clear() for col in self.window.services_treeview.get_columns(): self.window.services_treeview.remove_column(col) self.window.services_treeview.set_headers_visible(False) @@ -872,8 +872,7 @@ def _default_action(self, jid, node, identities, features, data): def browse(self, force = False): '''Fill the treeview with agents, fetching the info if necessary.''' - model = self.window.services_treeview.get_model() - model.clear() + self.model.clear() self._total_items = self._progress = 0 self.window.progressbar.show() self._pulse_timeout = gobject.timeout_add(250, self._pulse_timeout_cb) @@ -890,21 +889,21 @@ def _pulse_timeout_cb(self, *args): def _find_item(self, jid, node): '''Check if an item is already in the treeview. Return an iter to it if so, None otherwise.''' - model = self.window.services_treeview.get_model() - iter = model.get_iter_root() + iter = self.model.get_iter_root() while iter: - cjid = model.get_value(iter, 0).decode('utf-8') - cnode = model.get_value(iter, 1).decode('utf-8') + cjid = self.model.get_value(iter, 0).decode('utf-8') + cnode = self.model.get_value(iter, 1).decode('utf-8') if jid == cjid and node == cnode: break - iter = model.iter_next(iter) + iter = self.model.iter_next(iter) if iter: return iter return None def _agent_items(self, jid, node, items, force): '''Callback for when we receive a list of agent items.''' - model = self.window.services_treeview.get_model() + self.model.clear() + self._total_items = 0 gobject.source_remove(self._pulse_timeout) self.window.progressbar.hide() # The server returned an error @@ -916,53 +915,48 @@ def _agent_items(self, jid, node, items, force): _('This service does not contain any items to browse.')) return # We got a list of items + self.window.services_treeview.set_model(None) for item in items: jid = item['jid'] node = item.get('node', '') - iter = self._find_item(jid, node) - if iter: - # Already in the treeview - self._update_item(model, iter, jid, node, item) - else: - # Not in the treeview - self._total_items += 1 - self._add_item(model, jid, node, item, force) + self._total_items += 1 + self._add_item(jid, node, item, force) + self.window.services_treeview.set_model(self.model) def _agent_info(self, jid, node, identities, features, data): '''Callback for when we receive info about an agent's item.''' addr = get_agent_address(jid, node) - model = self.window.services_treeview.get_model() iter = self._find_item(jid, node) if not iter: # Not in the treeview, stop return if identities == 0: # The server returned an error - self._update_error(model, iter, jid, node) + self._update_error(iter, jid, node) else: # We got our info - self._update_info(model, iter, jid, node, + self._update_info(iter, jid, node, identities, features, data) self.update_actions() - def _add_item(self, model, jid, node, item, force): + def _add_item(self, jid, node, item, force): '''Called when an item should be added to the model. The result of a disco#items query.''' - model.append((jid, node, item.get('name', ''), + self.model.append((jid, node, item.get('name', ''), get_agent_address(jid, node))) - def _update_item(self, model, iter, jid, node, item): + def _update_item(self, iter, jid, node, item): '''Called when an item should be updated in the model. The result of a disco#items query. (seldom)''' if item.has_key('name'): - model[iter][2] = item['name'] + self.model[iter][2] = item['name'] - def _update_info(self, model, iter, jid, node, identities, features, data): + def _update_info(self, iter, jid, node, identities, features, data): '''Called when an item should be updated in the model with further info. The result of a disco#info query.''' - model[iter][2] = identities[0].get('name', '') + self.model[iter][2] = identities[0].get('name', '') - def _update_error(self, model, iter, jid, node): + def _update_error(self, iter, jid, node): '''Called when a disco#info query failed for an item.''' pass @@ -1046,14 +1040,12 @@ def _show_tooltip(self, state): # These are all callbacks to make tooltips work def on_treeview_leave_notify_event(self, widget, event): - model = widget.get_model() props = widget.get_path_at_pos(int(event.x), int(event.y)) if self.tooltip.timeout > 0: if not props or self.tooltip.id == props[0]: self.tooltip.hide_tooltip() def on_treeview_motion_notify_event(self, widget, event): - model = widget.get_model() props = widget.get_path_at_pos(int(event.x), int(event.y)) if self.tooltip.timeout > 0: if not props or self.tooltip.id != props[0]: @@ -1062,12 +1054,12 @@ def on_treeview_motion_notify_event(self, widget, event): [row, col, x, y] = props iter = None try: - iter = model.get_iter(row) + iter = self.model.get_iter(row) except: self.tooltip.hide_tooltip() return - jid = model[iter][0] - state = model[iter][4] + jid = self.model[iter][0] + state = self.model[iter][4] # Not a category, and we have something to say about state if jid and state > 0 and \ (self.tooltip.timeout == 0 or self.tooltip.id != props[0]): @@ -1084,10 +1076,10 @@ def _create_treemodel(self): # JID, node, icon, description, state # State means 2 when error, 1 when fetching, 0 when succes. view = self.window.services_treeview - model = gtk.TreeStore(str, str, gtk.gdk.Pixbuf, str, int) - model.set_sort_func(4, self._treemodel_sort_func) - model.set_sort_column_id(4, gtk.SORT_ASCENDING) - view.set_model(model) + self.model = gtk.TreeStore(str, str, gtk.gdk.Pixbuf, str, int) + self.model.set_sort_func(4, self._treemodel_sort_func) + self.model.set_sort_column_id(4, gtk.SORT_ASCENDING) + view.set_model(self.model) col = gtk.TreeViewColumn() # Icon Renderer @@ -1329,41 +1321,38 @@ def _friendly_category(self, category, type=None): def _create_category(self, cat, type=None): '''Creates a category row.''' - model = self.window.services_treeview.get_model() cat, prio = self._friendly_category(cat, type) - return model.append(None, ('', '', None, cat, prio)) + return self.model.append(None, ('', '', None, cat, prio)) def _find_category(self, cat, type=None): '''Looks up a category row and returns the iterator to it, or None.''' - model = self.window.services_treeview.get_model() cat, prio = self._friendly_category(cat, type) - iter = model.get_iter_root() + iter = self.model.get_iter_root() while iter: - if model.get_value(iter, 3).decode('utf-8') == cat: + if self.model.get_value(iter, 3).decode('utf-8') == cat: break - iter = model.iter_next(iter) + iter = self.model.iter_next(iter) if iter: return iter return None def _find_item(self, jid, node): - model = self.window.services_treeview.get_model() iter = None - cat_iter = model.get_iter_root() + cat_iter = self.model.get_iter_root() while cat_iter and not iter: - iter = model.iter_children(cat_iter) + iter = self.model.iter_children(cat_iter) while iter: - cjid = model.get_value(iter, 0).decode('utf-8') - cnode = model.get_value(iter, 1).decode('utf-8') + cjid = self.model.get_value(iter, 0).decode('utf-8') + cnode = self.model.get_value(iter, 1).decode('utf-8') if jid == cjid and node == cnode: break - iter = model.iter_next(iter) - cat_iter = model.iter_next(cat_iter) + iter = self.model.iter_next(iter) + cat_iter = self.model.iter_next(cat_iter) if iter: return iter return None - def _add_item(self, model, jid, node, item, force): + def _add_item(self, jid, node, item, force): # Row text addr = get_agent_address(jid, node) if item.has_key('name'): @@ -1387,21 +1376,21 @@ def _add_item(self, model, jid, node, item, force): cat = self._find_category(*cat_args) if not cat: cat = self._create_category(*cat_args) - model.append(cat, (item['jid'], item.get('node', ''), pix, descr, 1)) + self.model.append(cat, (item['jid'], item.get('node', ''), pix, descr, 1)) self._expand_all() # Grab info on the service self.cache.get_info(jid, node, self._agent_info, force = force) self._update_progressbar() - def _update_item(self, model, iter, jid, node, item): + def _update_item(self, iter, jid, node, item): addr = get_agent_address(jid, node) if item.has_key('name'): descr = "<b>%s</b>\n%s" % (item['name'], addr) else: descr = "<b>%s</b>" % addr - model[iter][3] = descr + self.model[iter][3] = descr - def _update_info(self, model, iter, jid, node, identities, features, data): + def _update_info(self, iter, jid, node, identities, features, data): addr = get_agent_address(jid, node) name = identities[0].get('name', '') if name: @@ -1423,32 +1412,32 @@ def _update_info(self, model, iter, jid, node, identities, features, data): break # Check if we have to move categories - old_cat_iter = model.iter_parent(iter) - old_cat = model.get_value(old_cat_iter, 3).decode('utf-8') - if model.get_value(old_cat_iter, 3) == cat: + old_cat_iter = self.model.iter_parent(iter) + old_cat = self.model.get_value(old_cat_iter, 3).decode('utf-8') + if self.model.get_value(old_cat_iter, 3) == cat: # Already in the right category, just update - model[iter][2] = pix - model[iter][3] = descr - model[iter][4] = 0 + self.model[iter][2] = pix + self.model[iter][3] = descr + self.model[iter][4] = 0 return # Not in the right category, move it. - model.remove(iter) + self.model.remove(iter) # Check if the old category is empty - if not model.iter_is_valid(old_cat_iter): + if not self.model.iter_is_valid(old_cat_iter): old_cat_iter = self._find_category(old_cat) - if not model.iter_children(old_cat_iter): - model.remove(old_cat_iter) + if not self.model.iter_children(old_cat_iter): + self.model.remove(old_cat_iter) cat_iter = self._find_category(cat, type) if not cat_iter: cat_iter = self._create_category(cat, type) - model.append(cat_iter, (jid, node, pix, descr, 0)) + self.model.append(cat_iter, (jid, node, pix, descr, 0)) self._expand_all() - def _update_error(self, model, iter, jid, node): + def _update_error(self, iter, jid, node): addr = get_agent_address(jid, node) - model[iter][4] = 2 + self.model[iter][4] = 2 self._progress += 1 self._update_progressbar() @@ -1462,11 +1451,13 @@ def _create_treemodel(self): # JID, node, name, users, description, fetched # This is rather long, I'd rather not use a data_func here though. # Users is a string, because want to be able to leave it empty. - model = gtk.ListStore(str, str, str, str, str, bool) - model.set_sort_column_id(2, gtk.SORT_ASCENDING) - self.window.services_treeview.set_model(model) + self.model = gtk.ListStore(str, str, str, str, str, bool) + self.model.set_sort_column_id(2, gtk.SORT_ASCENDING) + self.window.services_treeview.set_model(self.model) # Name column col = gtk.TreeViewColumn(_('Name')) + col.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + col.set_fixed_width(100) renderer = gtk.CellRendererText() col.pack_start(renderer) col.set_attributes(renderer, text = 2) @@ -1486,6 +1477,13 @@ def _create_treemodel(self): col.set_attributes(renderer, text = 4) self.window.services_treeview.insert_column(col, -1) col.set_resizable(True) + # Id column + col = gtk.TreeViewColumn(_('Id')) + renderer = gtk.CellRendererText() + col.pack_start(renderer) + col.set_attributes(renderer, text = 0) + self.window.services_treeview.insert_column(col, -1) + col.set_resizable(True) self.window.services_treeview.set_headers_visible(True) # Source id for idle callback used to start disco#info queries. self._fetch_source = None @@ -1568,7 +1566,6 @@ def _query_visible(self): # Prevent a silly warning, try again in a bit. self._fetch_source = gobject.timeout_add(100, self._start_info_query) return - model = view.get_model() # We have to do this in a pygtk <2.8 compatible way :/ #start, end = self.window.services_treeview.get_visible_range() rect = view.get_visible_rect() @@ -1577,7 +1574,7 @@ def _query_visible(self): try: sx, sy = view.tree_to_widget_coords(rect.x, rect.y) spath = view.get_path_at_pos(sx, sy)[0] - iter = model.get_iter(spath) + iter = self.model.get_iter(spath) except TypeError: self._fetch_source = None return @@ -1591,14 +1588,14 @@ def _query_visible(self): except TypeError: # We're at the end of the model, we can leave end=None though. pass - while iter and model.get_path(iter) != end: - if not model.get_value(iter, 5): - jid = model.get_value(iter, 0).decode('utf-8') - node = model.get_value(iter, 1).decode('utf-8') + while iter and self.model.get_path(iter) != end: + if not self.model.get_value(iter, 5): + jid = self.model.get_value(iter, 0).decode('utf-8') + node = self.model.get_value(iter, 1).decode('utf-8') self.cache.get_info(jid, node, self._agent_info) self._fetch_source = True return - iter = model.iter_next(iter) + iter = self.model.iter_next(iter) self._fetch_source = None def _channel_altinfo(self, jid, node, items, name = None): @@ -1619,22 +1616,21 @@ def _channel_altinfo(self, jid, node, items, name = None): self._fetch_source = None return else: - model = self.window.services_treeview.get_model() iter = self._find_item(jid, node) if iter: if name: - model[iter][2] = name - model[iter][3] = len(items) # The number of users - model[iter][5] = True + self.model[iter][2] = name + self.model[iter][3] = len(items) # The number of users + self.model[iter][5] = True self._fetch_source = None self._query_visible() - def _add_item(self, model, jid, node, item, force): - model.append((jid, node, item.get('name', ''), '', '', False)) + def _add_item(self, jid, node, item, force): + self.model.append((jid, node, item.get('name', ''), '', '', False)) if not self._fetch_source: self._fetch_source = gobject.idle_add(self._start_info_query) - def _update_info(self, model, iter, jid, node, identities, features, data): + def _update_info(self, iter, jid, node, identities, features, data): name = identities[0].get('name', '') for form in data: typefield = form.getField('FORM_TYPE') @@ -1644,14 +1640,14 @@ def _update_info(self, model, iter, jid, node, identities, features, data): users = form.getField('muc#roominfo_occupants') descr = form.getField('muc#roominfo_description') if users: - model[iter][3] = users.getValue() + self.model[iter][3] = users.getValue() if descr: - model[iter][4] = descr.getValue() + self.model[iter][4] = descr.getValue() # Only set these when we find a form with additional info # Some servers don't support forms and put extra info in # the name attribute, so we preserve it in that case. - model[iter][2] = name - model[iter][5] = True + self.model[iter][2] = name + self.model[iter][5] = True break else: # We didn't find a form, switch to alternate query mode @@ -1661,7 +1657,7 @@ def _update_info(self, model, iter, jid, node, identities, features, data): self._fetch_source = None self._query_visible() - def _update_error(self, model, iter, jid, node): + def _update_error(self, iter, jid, node): # switch to alternate query mode self.cache.get_items(jid, node, self._channel_altinfo) diff --git a/src/filetransfers_window.py b/src/filetransfers_window.py index 0e31e8a4ed166ffe8e43923b81a57198dda86d72..3560d784cae2f2ec09274e92491aa9a0b20af753 100644 --- a/src/filetransfers_window.py +++ b/src/filetransfers_window.py @@ -246,11 +246,16 @@ def on_ok(widget): gtk.RESPONSE_OK, True, # select multiple true as we can select many files to send gajim.config.get('last_send_dir'), + on_response_ok = on_ok, + on_response_cancel = lambda e:dialog.destroy() ) - btn = dialog.add_button(_('_Send'), gtk.RESPONSE_OK) - btn.set_use_stock(True) # FIXME: add send icon to this button (JUMP_TO) - btn.connect('clicked', on_ok) + btn = gtk.Button(_('_Send')) + btn.set_property('can-default', True) + # FIXME: add send icon to this button (JUMP_TO) + dialog.add_action_widget(btn, gtk.RESPONSE_OK) + dialog.set_default_response(gtk.RESPONSE_OK) + btn.show() def send_file(self, account, contact, file_path): ''' start the real transfer(upload) of the file ''' @@ -450,8 +455,10 @@ def _remove_transfer(self, iter, sid, file_props): for ev_type in ('file-error', 'file-completed', 'file-request-error', 'file-send-error', 'file-stopped'): for event in gajim.events.get_events(account, jid, [ev_type]): - if event.parameters[1]['sid'] == file_props['sid']: + if event.parameters['sid'] == file_props['sid']: gajim.events.remove_events(account, jid, event) + gajim.interface.roster.draw_contact(jid, account) + gajim.interface.roster.show_title() del(self.files_props[sid[0]][sid[1:]]) del(file_props) diff --git a/src/gajim-remote.py b/src/gajim-remote.py index 563cc121ac284eb3aa70e8a3106c6c8db183b7f8..ffe9db7fcb9c4050da1b760ed1753f1bda3344c4 100755 --- a/src/gajim-remote.py +++ b/src/gajim-remote.py @@ -51,13 +51,10 @@ def send_error(error_message): try: import dbus -except: - raise exceptions.DbusNotSupported - -_version = getattr(dbus, 'version', (0, 20, 0)) -if _version[1] >= 41: import dbus.service import dbus.glib +except: + raise exceptions.DbusNotSupported OBJ_PATH = '/org/gajim/dbus/RemoteObject' INTERFACE = 'org.gajim.dbus.RemoteInterface' @@ -320,14 +317,8 @@ def init_connection(self): except: raise exceptions.SessionBusNotPresent - if _version[1] >= 30: - obj = self.sbus.get_object(SERVICE, OBJ_PATH) - interface = dbus.Interface(obj, INTERFACE) - elif _version[1] < 30: - self.service = self.sbus.get_service(SERVICE) - interface = self.service.get_object(OBJ_PATH, INTERFACE) - else: - send_error(_('Unknown D-Bus version: %s') % _version[1]) + obj = self.sbus.get_object(SERVICE, OBJ_PATH) + interface = dbus.Interface(obj, INTERFACE) # get the function asked self.method = interface.__getattr__(self.command) @@ -447,10 +438,7 @@ def call_remote_method(self): ''' calls self.method with arguments from sys.argv[2:] ''' args = sys.argv[2:] args = [i.decode(PREFERRED_ENCODING) for i in sys.argv[2:]] - if _version[1] >= 41: - args = [dbus.String(i) for i in args] - else: - args = [i.encode('UTF-8') for i in sys.argv[2:]] + args = [dbus.String(i) for i in args] try: res = self.method(*args) return res diff --git a/src/gajim.py b/src/gajim.py index b8e96dd630a269ed9ea3c7769b22a33f838b7dc8..70d8bfe545738ac311a331edd28fd0ce416ead7c 100755 --- a/src/gajim.py +++ b/src/gajim.py @@ -552,7 +552,7 @@ def handle_event_msg(self, account, array): chat_control = self.msg_win_mgr.get_control(jid, account) # Handle chat states - contact = gajim.contacts.get_contact(account, jid, resource) + contact = gajim.contacts.get_contact(account, jid) if contact and isinstance(contact, list): contact = contact[0] if contact: @@ -582,7 +582,10 @@ def handle_event_msg(self, account, array): if gajim.config.get('ignore_unknown_contacts') and \ not gajim.contacts.get_contact(account, jid) and not pm: return - + if not contact: + # contact is not in the roster, create a fake one to display + # notification + contact = common.contacts.Contact(jid = jid, resource = resource) advanced_notif_num = notify.get_advanced_notification('message_received', account, contact) @@ -606,7 +609,7 @@ def handle_event_msg(self, account, array): msg = message if subject: msg = _('Subject: %s') % subject + '\n' + msg - notify.notify('new_message', jid, account, [msg_type, first, nickname, + notify.notify('new_message', full_jid_with_resource, account, [msg_type, first, nickname, msg], advanced_notif_num) if self.remote_ctrl: @@ -851,6 +854,7 @@ def handle_event_last_status_time(self, account, array): self.remote_ctrl.raise_signal('LastStatusTime', (account, array)) def handle_event_os_info(self, account, array): + #'OS_INFO' (account, (jid, resource, client_info, os_info)) win = None if self.instances[account]['infos'].has_key(array[0]): win = self.instances[account]['infos'][array[0]] @@ -1010,7 +1014,7 @@ def handle_event_roster_info(self, account, array): return # Add it to roster contact = gajim.contacts.create_contact(jid = jid, name = name, - groups = groups, show = 'offline', sub = sub, ask = ask) + groups = groups, show = 'offline', sub = sub, ask = ask) gajim.contacts.add_contact(account, contact) self.roster.add_contact_to_roster(jid, account) else: @@ -1075,7 +1079,7 @@ def handle_event_gmail_notify(self, account, array): gmail_messages_list = array[2] if gajim.config.get('notify_on_new_gmail_email'): img = os.path.join(gajim.DATA_DIR, 'pixmaps', 'events', - 'single_msg_recv.png') #FIXME: find a better image + 'new_email_recv.png') title = _('New E-mail on %(gmail_mail_address)s') % \ {'gmail_mail_address': jid} text = i18n.ngettext('You have %d new E-mail message', 'You have %d new E-mail messages', gmail_new_messages, gmail_new_messages, gmail_new_messages) @@ -1328,7 +1332,9 @@ def handle_event_stanza_sent(self, account, stanza): self.instances[account]['xml_console'].print_stanza(stanza, 'outgoing') def handle_event_vcard_published(self, account, array): - dialogs.InformationDialog(_('vCard publication succeeded'), _('Your personal information has been published successfully.')) + if self.instances[account].has_key('profile'): + win = self.instances[account]['profile'] + win.vcard_published() for gc_control in self.msg_win_mgr.get_controls(message_control.TYPE_GC): if gc_control.account == account: show = gajim.SHOW_LIST[gajim.connections[account].connected] @@ -1337,7 +1343,9 @@ def handle_event_vcard_published(self, account, array): gc_control.room_jid, show, status) def handle_event_vcard_not_published(self, account, array): - dialogs.InformationDialog(_('vCard publication failed'), _('There was an error while publishing your personal information, try again later.')) + if self.instances[account].has_key('profile'): + win = self.instances[account]['profile'] + win.vcard_not_published() def handle_event_signed_in(self, account, empty): '''SIGNED_IN event is emitted when we sign in, so handle it''' @@ -1406,10 +1414,10 @@ def handle_event_zc_name_conflict(self, account, data): if response == gtk.RESPONSE_OK: new_name = dlg.input_entry.get_text() print 'account, data', account, data, new_name - gajim.config.set_per('accounts', gajim.LOCAL_ACC, 'name', new_name) + gajim.config.set_per('accounts', account, 'name', new_name) status = gajim.connections[account].status - print 'status', status - gajim.connections[account].reconnect() + gajim.connections[account].username = new_name + gajim.connections[account].change_status(status, '') def read_sleepy(self): @@ -1744,14 +1752,17 @@ def handle_event(self, account, jid, type_): jid = gajim.get_jid_without_resource(jid) if type_ in ('printed_gc_msg', 'gc_msg'): w = self.msg_win_mgr.get_window(jid, account) - elif type_ in ('printed_chat', 'chat'): + elif type_ in ('printed_chat', 'chat', ''): + # '' is for log in/out notifications if self.msg_win_mgr.has_window(fjid, account): w = self.msg_win_mgr.get_window(fjid, account) + elif self.msg_win_mgr.has_window(jid, account): + w = self.msg_win_mgr.get_window(jid, account) else: contact = gajim.contacts.get_contact(account, jid, resource) - if isinstance(contact, list): + if not contact or isinstance(contact, list): contact = gajim.contacts.get_first_contact_from_jid(account, jid) - self.roster.new_chat(contact, account, resource = resource) + self.roster.new_chat(contact, account) w = self.msg_win_mgr.get_window(fjid, account) gajim.last_message_time[account][jid] = 0 # long time ago elif type_ in ('printed_pm', 'pm'): @@ -1774,9 +1785,15 @@ def handle_event(self, account, jid, type_): elif type_ in ('normal', 'file-request', 'file-request-error', 'file-send-error', 'file-error', 'file-stopped', 'file-completed'): # Get the first single message event - event = gajim.events.get_first_event(account, jid, type_) - # Open the window - self.roster.open_event(account, jid, event) + event = gajim.events.get_first_event(account, fjid, type_) + if not event: + # default to jid without resource + event = gajim.events.get_first_event(account, jid, type_) + # Open the window + self.roster.open_event(account, jid, event) + else: + # Open the window + self.roster.open_event(account, fjid, event) elif type_ == 'gmail': if gajim.config.get_per('accounts', account, 'savepass'): url = ('http://www.google.com/accounts/ServiceLoginAuth?service=mail&Email=%s&Passwd=%s&continue=https://mail.google.com/mail') %\ @@ -1873,9 +1890,12 @@ def __init__(self): for account in gajim.config.get_per('accounts'): if account != gajim.ZEROCONF_ACC_NAME: gajim.connections[account] = common.connection.Connection(account) - + + # gtk hooks gtk.about_dialog_set_email_hook(self.on_launch_browser_mailer, 'mail') gtk.about_dialog_set_url_hook(self.on_launch_browser_mailer, 'url') + if gtk.pygtk_version >= (2, 10, 0) and gtk.gtk_version >= (2, 10, 0): + gtk.link_button_set_uri_hook(self.on_launch_browser_mailer, 'url') self.instances = {'logs': {}} @@ -1919,6 +1939,8 @@ def __init__(self): self.systray_capabilities = False if os.name == 'nt': + pass + ''' try: import systraywin32 except: # user doesn't have trayicon capabilities @@ -1926,6 +1948,7 @@ def __init__(self): else: self.systray_capabilities = True self.systray = systraywin32.SystrayWin32() + ''' else: self.systray_capabilities = systray.HAS_SYSTRAY_CAPABILITIES if self.systray_capabilities: diff --git a/src/gajim_themes_window.py b/src/gajim_themes_window.py index cc9b1742ee36ea5489ade54c10b2cdcc1147d2d1..ef40d4b2272e9b711830d0b2d2c9312ff015bdd0 100644 --- a/src/gajim_themes_window.py +++ b/src/gajim_themes_window.py @@ -51,7 +51,7 @@ def __init__(self): self.themes_tree = self.xml.get_widget('themes_treeview') self.theme_options_vbox = self.xml.get_widget('theme_options_vbox') self.colorbuttons = {} - for chatstate in ('active', 'inactive', 'composing', 'paused', 'gone', + for chatstate in ('inactive', 'composing', 'paused', 'gone', 'muc_msg', 'muc_directed_msg'): self.colorbuttons[chatstate] = self.xml.get_widget(chatstate + \ '_colorbutton') @@ -198,7 +198,7 @@ def set_theme_options(self, theme, option = 'account'): self.no_update = False gajim.interface.roster.change_roster_style(None) - for chatstate in ('active', 'inactive', 'composing', 'paused', 'gone', + for chatstate in ('inactive', 'composing', 'paused', 'gone', 'muc_msg', 'muc_directed_msg'): color = gajim.config.get_per('themes', theme, 'state_' + chatstate + \ '_color') @@ -333,11 +333,6 @@ def _get_font_props(self, font_name): font_props[1] = True return font_props - def on_active_colorbutton_color_set(self, widget): - self.no_update = True - self._set_color(True, widget, 'state_active_color') - self.no_update = False - def on_inactive_colorbutton_color_set(self, widget): self.no_update = True self._set_color(True, widget, 'state_inactive_color') diff --git a/src/groupchat_control.py b/src/groupchat_control.py index 38e20e5bfe49807f5c14e65643dc8f7eeae61304..607053d48d1ec570258b003c0ae71c9d61144cff 100644 --- a/src/groupchat_control.py +++ b/src/groupchat_control.py @@ -226,9 +226,6 @@ def __init__(self, parent_win, contact, acct): self.gc_popup_menu = xm.get_widget('gc_control_popup_menu') self.name_label = self.xml.get_widget('banner_name_label') - id = self.parent_win.window.connect('focus-in-event', - self._on_window_focus_in_event) - self.handlers[id] = self.parent_win.window # set the position of the current hpaned self.hpaned_position = gajim.config.get('gc-hpaned-position') @@ -320,11 +317,6 @@ def notify_on_new_messages(self): return gajim.config.get('notify_on_all_muc_messages') or \ self.attention_flag - def _on_window_focus_in_event(self, widget, event): - '''When window gets focus''' - if self.parent_win.get_active_jid() == self.room_jid: - self.conv_textview.allow_focus_out_line = True - def on_treeview_size_allocate(self, widget, allocation): '''The MUC treeview has resized. Move the hpaned in all tabs to match''' self.hpaned_position = self.hpaned.get_position() @@ -371,23 +363,24 @@ def get_tab_label(self, chatstate): has_focus = self.parent_win.window.get_property('has-toplevel-focus') current_tab = self.parent_win.get_active_control() == self + color_name = None color = None theme = gajim.config.get('roster_theme') if chatstate == 'attention' and (not has_focus or not current_tab): self.attention_flag = True - color = gajim.config.get_per('themes', theme, + color_name = gajim.config.get_per('themes', theme, 'state_muc_directed_msg_color') elif chatstate: if chatstate == 'active' or (current_tab and has_focus): self.attention_flag = False - color = gajim.config.get_per('themes', theme, - 'state_active_color') + # get active color from gtk + color = self.parent_win.notebook.style.fg[gtk.STATE_ACTIVE] elif chatstate == 'newmsg' and (not has_focus or not current_tab) and\ not self.attention_flag: - color = gajim.config.get_per('themes', theme, 'state_muc_msg_color') - if color: - color = gtk.gdk.colormap_get_system().alloc_color(color) - + color_name = gajim.config.get_per('themes', theme, 'state_muc_msg_color') + if color_name: + color = gtk.gdk.colormap_get_system().alloc_color(color_name) + label_str = self.name return (label_str, color) @@ -865,7 +858,9 @@ def chg_contact_status(self, nick, show, status, role, affiliation, jid, reason, print_status = gajim.config.get('print_status_in_muc') nick_jid = nick if jid: - nick_jid += ' (%s)' % jid + # delete ressource + simple_jid = gajim.get_jid_without_resource(jid) + nick_jid += ' (%s)' % simple_jid if show == 'offline' and print_status in ('all', 'in_and_out'): st = _('%s has left') % nick_jid if reason: @@ -1268,6 +1263,10 @@ def shutdown(self, status='offline'): del self.handlers[i] def allow_shutdown(self): + model, iter = self.list_treeview.get_selection().get_selected() + if iter: + self.list_treeview.get_selection().unselect_all() + return False retval = True includes = gajim.config.get('confirm_close_muc_rooms').split(' ') excludes = gajim.config.get('noconfirm_close_muc_rooms').split(' ') @@ -1293,6 +1292,7 @@ def allow_shutdown(self): return retval def set_control_active(self, state): + self.conv_textview.allow_focus_out_line = True self.attention_flag = False ChatControlBase.set_control_active(self, state) if not state: @@ -1453,7 +1453,11 @@ def handle_message_textview_mykey_press(self, widget, event_keyval, event_keymod def on_list_treeview_key_press_event(self, widget, event): if event.keyval == gtk.keysyms.Escape: - widget.get_selection().unselect_all() + selection = widget.get_selection() + model, iter = selection.get_selected() + if iter: + widget.get_selection().unselect_all() + return True def on_list_treeview_row_expanded(self, widget, iter, path): '''When a row is expanded: change the icon of the arrow''' diff --git a/src/gtkgui_helpers.py b/src/gtkgui_helpers.py index fb6e3eaa850c1738eaac52fa0644757b2d0b1964..7b99c3ae91c7de16e407928722887dbea2786db7 100644 --- a/src/gtkgui_helpers.py +++ b/src/gtkgui_helpers.py @@ -390,7 +390,7 @@ def possibly_move_window_in_current_desktop(window): current virtual desktop window is GTK window''' if os.name == 'nt': - return + return False root_window = gtk.gdk.screen_get_default().get_root_window() # current user's vd @@ -406,6 +406,8 @@ def possibly_move_window_in_current_desktop(window): # we are in another VD that the window was # so show it in current VD window.present() + return True + return False def file_is_locked(path_to_file): '''returns True if file is locked (WINDOWS ONLY)''' @@ -680,6 +682,14 @@ def on_ok2(widget, file_path, pixbuf): file_path = dialog.get_filename() file_path = decode_filechooser_file_paths((file_path,))[0] if os.path.exists(file_path): + # check if we have write permissions + if not os.access(file_path, os.W_OK): + file_name = os.path.basename(file_path) + dialogs.ErrorDialog(_('Cannot overwrite existing file "%s"' % + file_name), + _('A file with this name already exists and you do not have ' + 'permission to overwrite it.')) + return dialog2 = dialogs.FTOverwriteConfirmationDialog( _('This file already exists'), _('What do you want to do?'), False) @@ -688,6 +698,13 @@ def on_ok2(widget, file_path, pixbuf): response = dialog2.get_response() if response < 0: return + else: + dirname = os.path.dirname(file_path) + if not os.access(dirname, os.W_OK): + dialogs.ErrorDialog(_('Directory "%s" is not writable') % \ + dirname, _('You do not have permission to create files in this' + ' directory.')) + return # Get pixbuf pixbuf = None @@ -710,8 +727,8 @@ def on_ok2(widget, file_path, pixbuf): try: pixbuf.save(file_path, type_) except: - #XXX Check for permissions - os.remove(file_path) + if os.path.exists(file_path): + os.remove(file_path) new_file_path = '.'.join(file_path.split('.')[:-1]) + '.jpeg' dialog2 = dialogs.ConfirmationDialog(_('Extension not supported'), _('Image cannot be saved in %(type)s format. Save as %(new_filename)s?') % {'type': type_, 'new_filename': new_file_path}, @@ -735,3 +752,6 @@ def on_cancel(widget): dialog.set_current_name(default_name) dialog.connect('delete-event', lambda widget, event: on_cancel(widget)) + +def on_bm_header_changed_state(widget, event): + widget.set_state(gtk.STATE_NORMAL) #do not allow selected_state diff --git a/src/message_window.py b/src/message_window.py index f190956c8ae16831b04815411600d3c1792161dd..42be57e1cf69617cf691e93b01dd0b2ebfa91a74 100644 --- a/src/message_window.py +++ b/src/message_window.py @@ -104,6 +104,16 @@ def __init__(self, acct, type): self.notebook.drag_dest_set(gtk.DEST_DEFAULT_ALL, self.DND_TARGETS, gtk.gdk.ACTION_MOVE) + def change_account_name(self, old_name, new_name): + if self._controls.has_key(old_name): + self._controls[new_name] = self._controls[old_name] + del self._controls[old_name] + for ctrl in self.controls(): + if ctrl.account == old_name: + ctrl.account = new_name + if self.account == old_name: + self.account = new_name + def get_num_controls(self): n = 0 for dict in self._controls.values(): @@ -618,7 +628,11 @@ def __init__(self): # Map the mode to a int constant for frequent compares mode = gajim.config.get('one_message_window') self.mode = common.config.opt_one_window_types.index(mode) - + + def change_account_name(self, old_name, new_name): + for win in self.windows(): + win.change_account_name(old_name, new_name) + def _new_window(self, acct, type): win = MessageWindow(acct, type) # we track the lifetime of this window diff --git a/src/music_track_listener.py b/src/music_track_listener.py new file mode 100644 index 0000000000000000000000000000000000000000..b5bccbdc401e04c4dd5f529b4a66ad7b4e0c55c7 --- /dev/null +++ b/src/music_track_listener.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- +## musictracklistener.py +## +## Copyright (C) 2006 Gustavo Carneiro <gjcarneiro@gmail.com> +## Copyright (C) 2006 Nikos Kouremenos <kourem@gmail.com> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 2 only. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +import gobject +import dbus_support +if dbus_support.supported: + import dbus + import dbus.glib + +class MusicTrackInfo(object): + __slots__ = ['title', 'album', 'artist', 'duration', 'track_number'] + + +class MusicTrackListener(gobject.GObject): + __gsignals__ = { 'music-track-changed': (gobject.SIGNAL_RUN_LAST, None, + (object,)) } + + _instance = None + @classmethod + def get(cls): + if cls._instance is None: + cls._instance = cls() + return cls._instance + + def __init__(self): + super(MusicTrackListener, self).__init__() + bus = dbus.SessionBus() + bus.add_signal_receiver(self._muine_music_track_change_cb, 'SongChanged', + 'org.gnome.Muine.Player') + bus.add_signal_receiver(self._rhythmbox_music_track_change_cb, + 'playingUriChanged', 'org.gnome.Rhythmbox.Player') + + def _muine_properties_extract(self, song_string): + d = dict((x.strip() for x in s1.split(':', 1)) for s1 in song_string.split('\n')) + info = MusicTrackInfo() + info.title = d['title'] + info.album = d['album'] + info.artist = d['artist'] + info.duration = int(d['duration']) + info.track_number = int(d['track_number']) + return info + + def _muine_music_track_change_cb(self, arg): + info = self._muine_properties_extract(arg) + self.emit('music-track-changed', info) + + def _rhythmbox_properties_extract(self, props): + info = MusicTrackInfo() + info.title = props['title'] + info.album = props['album'] + info.artist = props['artist'] + info.duration = int(props['duration']) + info.track_number = int(props['track-number']) + return info + + def _rhythmbox_music_track_change_cb(self, uri): + bus = dbus.SessionBus() + rbshellobj = bus.get_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Shell') + rbshell = dbus.Interface(rbshellobj, 'org.gnome.Rhythmbox.Shell') + props = rbshell.getSongProperties(uri) + info = self._rhythmbox_properties_extract(props) + self.emit('music-track-changed', info) + + def get_playing_track(self): + '''Return a MusicTrackInfo for the currently playing + song, or None if no song is playing''' + + bus = dbus.SessionBus() + + ## Check Muine playing track + if dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(), + 'org.gnome.Muine'): + obj = bus.get_object('org.gnome.Muine', '/org/gnome/Muine/Player') + player = dbus.Interface(obj, 'org.gnome.Muine.Player') + if player.GetPlaying(): + song_string = player.GetCurrentSong() + song = self._muine_properties_extract(song_string) + return song + + ## Check Rhythmbox playing song + if dbus.dbus_bindings.bus_name_has_owner(bus.get_connection(), + 'org.gnome.Rhythmbox'): + rbshellobj = bus.get_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Shell') + player = dbus.Interface( + bus.get_object('org.gnome.Rhythmbox', '/org/gnome/Rhythmbox/Player'), + 'org.gnome.Rhythmbox.Player') + rbshell = dbus.Interface(rbshellobj, 'org.gnome.Rhythmbox.Shell') + uri = player.getPlayingUri() + props = rbshell.getSongProperties(uri) + info = self._rhythmbox_properties_extract(props) + return info + + return None + +# here we test :) +if __name__ == '__main__': + def music_track_change_cb(listener, music_track_info): + print music_track_info.title + listener = MusicTrackListener.get() + listener.connect('music-track-changed', music_track_change_cb) + track = listener.get_playing_track() + if track is None: + print 'Now not playing anything' + else: + print 'Now playing: "%s" by %s' % (track.title, track.artist) + gobject.MainLoop().run() diff --git a/src/notify.py b/src/notify.py index 908ff25d9de2e84fe1c94ce9c2e72dd6e70192d4..79fd847a9e5e59728f04fd3878511792c2c4318d 100644 --- a/src/notify.py +++ b/src/notify.py @@ -28,9 +28,8 @@ import dbus_support if dbus_support.supported: import dbus - if dbus_support.version >= (0, 41, 0): - import dbus.glib - import dbus.service + import dbus.glib + import dbus.service def get_show_in_roster(event, account, contact): '''Return True if this event must be shown in roster, else False''' @@ -42,11 +41,9 @@ def get_show_in_roster(event, account, contact): return False if event == 'message_received': chat_control = helpers.get_chat_control(account, contact) - if not chat_control: - return True - elif event == 'ft_request': - return True - return False + if chat_control: + return False + return True def get_show_in_systray(event, account, contact): '''Return True if this event must be shown in roster, else False''' @@ -56,10 +53,7 @@ def get_show_in_systray(event, account, contact): return True if gajim.config.get_per('notifications', str(num), 'systray') == 'no': return False - if event in ('message_received', 'ft_request', 'gc_msg_highlight', - 'ft_request'): - return True - return False + return True def get_advanced_notification(event, account, contact): '''Returns the number of the first advanced notification or None''' diff --git a/src/profile_window.py b/src/profile_window.py index 41bbd8de3c329248d77205ef72de5ffb0cbab361..badcbb310c447f324a40ef79a34a63e2bd98ada5 100644 --- a/src/profile_window.py +++ b/src/profile_window.py @@ -60,17 +60,40 @@ class ProfileWindow: def __init__(self, account): self.xml = gtkgui_helpers.get_glade('profile_window.glade') self.window = self.xml.get_widget('profile_window') + self.progressbar = self.xml.get_widget('progressbar') + self.statusbar = self.xml.get_widget('statusbar') + self.context_id = self.statusbar.get_context_id('profile') self.account = account self.jid = gajim.get_jid_from_account(account) self.avatar_mime_type = None self.avatar_encoded = None + self.message_id = self.statusbar.push(self.context_id, + _('Retrieving profile...')) + self.update_progressbar_timeout_id = gobject.timeout_add(100, + self.update_progressbar) + self.remove_statusbar_timeout_id = None + # Create Image for avatar button + image = gtk.Image() + self.xml.get_widget('PHOTO_button').set_image(image) self.xml.signal_autoconnect(self) self.window.show_all() + def update_progressbar(self): + self.progressbar.pulse() + return True # loop forever + + def remove_statusbar(self, message_id): + self.statusbar.remove(self.context_id, message_id) + self.remove_statusbar_timeout_id = None + def on_profile_window_destroy(self, widget): + if self.update_progressbar_timeout_id is not None: + gobject.source_remove(self.update_progressbar_timeout_id) + if self.remove_statusbar_timeout_id is not None: + gobject.source_remove(self.remove_statusbar_timeout_id) del gajim.interface.instances[self.account]['profile'] def on_profile_window_key_press_event(self, widget, event): @@ -79,8 +102,10 @@ def on_profile_window_key_press_event(self, widget, event): def on_clear_button_clicked(self, widget): # empty the image - self.xml.get_widget('PHOTO_image').set_from_icon_name('stock_person', - gtk.ICON_SIZE_DIALOG) + button = self.xml.get_widget('PHOTO_button') + image = button.get_image() + image.set_from_pixbuf(None) + button.set_label(_('Click to set your avatar')) self.avatar_encoded = None self.avatar_mime_type = None @@ -124,24 +149,39 @@ def on_ok(widget, path_to_file): pixbuf = gtkgui_helpers.get_pixbuf_from_data(data) # rescale it pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard') - image = self.xml.get_widget('PHOTO_image') + button = self.xml.get_widget('PHOTO_button') + image = button.get_image() image.set_from_pixbuf(pixbuf) + button.set_label('') self.avatar_encoded = base64.encodestring(data) # returns None if unknown type self.avatar_mime_type = mimetypes.guess_type(path_to_file)[0] - self.dialog = dialogs.ImageChooserDialog(on_response_ok = on_ok) + def on_clear(widget): + self.dialog.destroy() + self.on_clear_button_clicked(widget) + + self.dialog = dialogs.AvatarChooserDialog(on_response_ok = on_ok, + on_response_clear = on_clear) def on_PHOTO_button_press_event(self, widget, event): '''If right-clicked, show popup''' if event.button == 3 and self.avatar_encoded: # right click menu = gtk.Menu() - nick = gajim.config.get_per('accounts', self.account, 'name') - menuitem = gtk.ImageMenuItem(gtk.STOCK_SAVE_AS) - menuitem.connect('activate', - gtkgui_helpers.on_avatar_save_as_menuitem_activate, - self.jid, None, nick + '.jpeg') - menu.append(menuitem) + + # Try to get pixbuf + is_fake = False + if account and gajim.contacts.is_pm_from_jid(account, jid): + is_fake = True + pixbuf = get_avatar_pixbuf_from_cache(jid, is_fake) + + if pixbuf: + nick = gajim.config.get_per('accounts', self.account, 'name') + menuitem = gtk.ImageMenuItem(gtk.STOCK_SAVE_AS) + menuitem.connect('activate', + gtkgui_helpers.on_avatar_save_as_menuitem_activate, + self.jid, None, nick + '.jpeg') + menu.append(menuitem) # show clear menuitem = gtk.ImageMenuItem(gtk.STOCK_CLEAR) menuitem.connect('activate', self.on_clear_button_clicked) @@ -162,18 +202,23 @@ def set_value(self, entry_name, value): def set_values(self, vcard): if not 'PHOTO' in vcard: # set default image - image = self.xml.get_widget('PHOTO_image') - image.set_from_icon_name('stock_person', gtk.ICON_SIZE_DIALOG) + button = self.xml.get_widget('PHOTO_button') + image = button.get_image() + image.set_from_pixbuf(None) + button.set_label(_('Click to set your avatar')) for i in vcard.keys(): if i == 'PHOTO': pixbuf, self.avatar_encoded, self.avatar_mime_type = \ get_avatar_pixbuf_encoded_mime(vcard[i]) - image = self.xml.get_widget('PHOTO_image') + button = self.xml.get_widget('PHOTO_button') + image = button.get_image() if not pixbuf: - image.set_from_icon_name('stock_person', gtk.ICON_SIZE_DIALOG) + image.set_from_pixbuf(None) + button.set_label(_('Click to set your avatar')) continue pixbuf = gtkgui_helpers.get_scaled_pixbuf(pixbuf, 'vcard') image.set_from_pixbuf(pixbuf) + button.set_label('') continue if i == 'ADR' or i == 'TEL' or i == 'EMAIL': for entry in vcard[i]: @@ -191,6 +236,18 @@ def set_values(self, vcard): vcard[i], 0) else: self.set_value(i + '_entry', vcard[i]) + if self.update_progressbar_timeout_id is not None: + if self.message_id: + self.statusbar.remove(self.context_id, self.message_id) + self.message_id = self.statusbar.push(self.context_id, + _('Information received')) + self.remove_statusbar_timeout_id = gobject.timeout_add(3000, + self.remove_statusbar, self.message_id) + gobject.source_remove(self.update_progressbar_timeout_id) + # redraw progressbar after avatar is set so that windows is already + # resized. Else progressbar is not correctly redrawn + gobject.idle_add(self.progressbar.set_fraction, 0) + self.update_progressbar_timeout_id = None def add_to_vcard(self, vcard, entry, txt): '''Add an information to the vCard dictionary''' @@ -248,6 +305,9 @@ def make_vcard(self): return vcard def on_publish_button_clicked(self, widget): + if self.update_progressbar_timeout_id: + # Operation in progress + return if gajim.connections[self.account].connected < 2: dialogs.ErrorDialog(_('You are not connected to the server'), _('Without a connection you can not publish your contact ' @@ -261,8 +321,42 @@ def on_publish_button_clicked(self, widget): nick = gajim.config.get_per('accounts', self.account, 'name') gajim.nicks[self.account] = nick gajim.connections[self.account].send_vcard(vcard) + self.message_id = self.statusbar.push(self.context_id, + _('Sending profile...')) + self.update_progressbar_timeout_id = gobject.timeout_add(100, + self.update_progressbar) + + def vcard_published(self): + if self.message_id: + self.statusbar.remove(self.context_id, self.message_id) + self.message_id = self.statusbar.push(self.context_id, + _('Information published')) + self.remove_statusbar_timeout_id = gobject.timeout_add(3000, + self.remove_statusbar, self.message_id) + if self.update_progressbar_timeout_id is not None: + gobject.source_remove(self.update_progressbar_timeout_id) + self.progressbar.set_fraction(0) + self.update_progressbar_timeout_id = None + + def vcard_not_published(self): + if self.message_id: + self.statusbar.remove(self.context_id, self.message_id) + self.message_id = self.statusbar.push(self.context_id, + _('Information NOT published')) + self.remove_statusbar_timeout_id = gobject.timeout_add(3000, + self.remove_statusbar, self.message_id) + if self.update_progressbar_timeout_id is not None: + gobject.source_remove(self.update_progressbar_timeout_id) + self.progressbar.set_fraction(0) + self.update_progressbar_timeout_id = None + dialogs.InformationDialog(_('vCard publication failed'), + _('There was an error while publishing your personal information, ' + 'try again later.')) def on_retrieve_button_clicked(self, widget): + if self.update_progressbar_timeout_id: + # Operation in progress + return entries = ['FN', 'NICKNAME', 'BDAY', 'EMAIL_HOME_USERID', 'URL', 'TEL_HOME_NUMBER', 'N_FAMILY', 'N_GIVEN', 'N_MIDDLE', 'N_PREFIX', 'N_SUFFIX', 'ADR_HOME_STREET', 'ADR_HOME_EXTADR', 'ADR_HOME_LOCALITY', @@ -275,9 +369,18 @@ def on_retrieve_button_clicked(self, widget): for e in entries: self.xml.get_widget(e + '_entry').set_text('') self.xml.get_widget('DESC_textview').get_buffer().set_text('') - self.xml.get_widget('PHOTO_image').set_from_icon_name('stock_person', - gtk.ICON_SIZE_DIALOG) + button = self.xml.get_widget('PHOTO_button') + image = button.get_image() + image.set_from_pixbuf(None) + button.set_label(_('Click to set your avatar')) gajim.connections[self.account].request_vcard(self.jid) else: dialogs.ErrorDialog(_('You are not connected to the server'), - _('Without a connection, you can not get your contact information.')) + _('Without a connection, you can not get your contact information.')) + self.message_id = self.statusbar.push(self.context_id, + _('Retrieving profile...')) + self.update_progressbar_timeout_id = gobject.timeout_add(100, + self.update_progressbar) + + def on_close_button_clicked(self, widget): + self.window.destroy() diff --git a/src/remote_control.py b/src/remote_control.py index 05156cf84dafa87c3560fb6a1034d43e2b532a82..0ce901e242e2307a91e40e51787afe8eaa6db5de 100644 --- a/src/remote_control.py +++ b/src/remote_control.py @@ -1,19 +1,9 @@ ## remote_control.py ## -## Contributors for this file: -## - Yann Le Boulanger <asterix@lagaule.org> -## - Nikos Kouremenos <kourem@gmail.com> -## - Dimitur Kirov <dkirov@gmail.com> -## - Andrew Sayman <lorien420@myrealbox.com> -## -## Copyright (C) 2003-2004 Yann Le Boulanger <asterix@lagaule.org> -## Vincent Hanquez <tab@snarc.org> -## Copyright (C) 2005 Yann Le Boulanger <asterix@lagaule.org> -## Vincent Hanquez <tab@snarc.org> -## Nikos Kouremenos <nkour@jabber.org> -## Dimitur Kirov <dkirov@gmail.com> -## Travis Shirk <travis@pobox.com> -## Norman Rasmussen <norman@rasmussen.co.za> +## Copyright (C) 2005-2006 Yann Le Boulanger <asterix@lagaule.org> +## Copyright (C) 2005-2006 Nikos Kouremenos <kourem@gmail.com> +## Copyright (C) 2005-2006 Dimitur Kirov <dkirov@gmail.com> +## Copyright (C) 2005-2006 Andrew Sayman <lorien420@myrealbox.com> ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published @@ -36,57 +26,30 @@ import dbus_support if dbus_support.supported: import dbus - if dbus_support.version >= (0, 41, 0): + if dbus_support: import dbus.service - import dbus.glib # cause dbus 0.35+ doesn't return signal replies without it - DbusPrototype = dbus.service.Object - elif dbus_support.version >= (0, 20, 0): - DbusPrototype = dbus.Object - else: #dbus is not defined - DbusPrototype = str + import dbus.glib INTERFACE = 'org.gajim.dbus.RemoteInterface' OBJ_PATH = '/org/gajim/dbus/RemoteObject' SERVICE = 'org.gajim.dbus' -# type mapping, it is different in each version -ident = lambda e: e -if dbus_support.version[1] >= 43: - # in most cases it is a utf-8 string - DBUS_STRING = dbus.String - - # general type (for use in dicts, - # where all values should have the same type) - DBUS_VARIANT = dbus.Variant - DBUS_BOOLEAN = dbus.Boolean - DBUS_DOUBLE = dbus.Double - DBUS_INT32 = dbus.Int32 - # dictionary with string key and binary value - DBUS_DICT_SV = lambda : dbus.Dictionary({}, signature="sv") - # dictionary with string key and value - DBUS_DICT_SS = lambda : dbus.Dictionary({}, signature="ss") - # empty type - DBUS_NONE = lambda : dbus.Variant(0) - -else: # 33, 35, 36 - DBUS_DICT_SV = lambda : {} - DBUS_DICT_SS = lambda : {} - DBUS_STRING = lambda e: unicode(e).encode('utf-8') - # this is the only way to return lists and dicts of mixed types - DBUS_VARIANT = lambda e: (isinstance(e, (str, unicode)) and \ - DBUS_STRING(e)) or repr(e) - DBUS_NONE = lambda : '' - if dbus_support.version[1] >= 41: # 35, 36 - DBUS_BOOLEAN = dbus.Boolean - DBUS_DOUBLE = dbus.Double - DBUS_INT32 = dbus.Int32 - else: # 33 - DBUS_BOOLEAN = ident - DBUS_INT32 = ident - DBUS_DOUBLE = ident - -STATUS_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd', - 'invisible'] +# type mapping + +# in most cases it is a utf-8 string +DBUS_STRING = dbus.String + +# general type (for use in dicts, where all values should have the same type) +DBUS_VARIANT = dbus.Variant +DBUS_BOOLEAN = dbus.Boolean +DBUS_DOUBLE = dbus.Double +DBUS_INT32 = dbus.Int32 +# dictionary with string key and binary value +DBUS_DICT_SV = lambda : dbus.Dictionary({}, signature="sv") +# dictionary with string key and value +DBUS_DICT_SS = lambda : dbus.Dictionary({}, signature="ss") +# empty type +DBUS_NONE = lambda : dbus.Variant(0) def get_dbus_struct(obj): ''' recursively go through all the items and replace @@ -123,65 +86,35 @@ def __init__(self): self.signal_object = None session_bus = dbus_support.session_bus.SessionBus() - if dbus_support.version[1] >= 41: - service = dbus.service.BusName(SERVICE, bus=session_bus) - self.signal_object = SignalObject(service) - elif dbus_support.version[1] <= 40 and dbus_support.version[1] >= 20: - service=dbus.Service(SERVICE, session_bus) - self.signal_object = SignalObject(service) + service = dbus.service.BusName(SERVICE, bus=session_bus) + self.signal_object = SignalObject(service) def raise_signal(self, signal, arg): if self.signal_object: self.signal_object.raise_signal(signal, - get_dbus_struct(arg)) + get_dbus_struct(arg)) -class SignalObject(DbusPrototype): - ''' Local object definition for /org/gajim/dbus/RemoteObject. This doc must - not be visible, because the clients can access only the remote object. ''' +class SignalObject(dbus.service.Object): + ''' Local object definition for /org/gajim/dbus/RemoteObject. + (This docstring is not be visible, because the clients can access only the remote object.)''' def __init__(self, service): self.first_show = True self.vcard_account = None # register our dbus API - if dbus_support.version[1] >= 41: - DbusPrototype.__init__(self, service, OBJ_PATH) - elif dbus_support.version[1] >= 30: - DbusPrototype.__init__(self, OBJ_PATH, service) - else: - DbusPrototype.__init__(self, OBJ_PATH, service, - [ self.toggle_roster_appearance, - self.show_next_unread, - self.list_contacts, - self.list_accounts, - self.account_info, - self.change_status, - self.open_chat, - self.send_message, - self.send_single_message, - self.contact_info, - self.send_file, - self.prefs_list, - self.prefs_store, - self.prefs_del, - self.prefs_put, - self.add_contact, - self.remove_contact, - self.get_status, - self.get_status_message, - self.start_chat, - self.send_xml, - ]) + dbus.service.Object.__init__(self, service, OBJ_PATH) def raise_signal(self, signal, arg): - ''' raise a signal, with a single string message ''' + '''raise a signal, with a single string message''' from dbus import dbus_bindings message = dbus_bindings.Signal(OBJ_PATH, INTERFACE, signal) i = message.get_iter(True) i.append(arg) self._connection.send(message) + @dbus.service.method(INTERFACE) def get_status(self, *args): '''get_status(account = None) returns status (show to be exact) which is the global one @@ -193,8 +126,9 @@ def get_status(self, *args): return helpers.get_global_show() # return show for the given account index = gajim.connections[account].connected - return DBUS_STRING(STATUS_LIST[index]) + return DBUS_STRING(gajim.SHOW_LIST[index]) + @dbus.service.method(INTERFACE) def get_status_message(self, *args): '''get_status(account = None) returns status which is the global one @@ -208,7 +142,7 @@ def get_status_message(self, *args): status = gajim.connections[account].status return DBUS_STRING(status) - + @dbus.service.method(INTERFACE) def get_account_and_contact(self, account, jid): ''' get the account (if not given) and contact instance from jid''' connected_account = None @@ -236,6 +170,7 @@ def get_account_and_contact(self, account, jid): return connected_account, contact + @dbus.service.method(INTERFACE) def send_file(self, *args): '''send_file(file_path, jid, account=None) send file, located at 'file_path' to 'jid', using account @@ -254,7 +189,7 @@ def send_file(self, *args): return False def _send_message(self, jid, message, keyID, account, type = 'chat', subject = None): - ''' can be called from send_chat_message (default when send_message) + '''can be called from send_chat_message (default when send_message) or send_single_message''' if not jid or not message: return None # or raise error @@ -269,22 +204,25 @@ def _send_message(self, jid, message, keyID, account, type = 'chat', subject = N return True return False + @dbus.service.method(INTERFACE) def send_chat_message(self, *args): - ''' send_message(jid, message, keyID=None, account=None) + '''send_message(jid, message, keyID=None, account=None) send chat 'message' to 'jid', using account (optional) 'account'. if keyID is specified, encrypt the message with the pgp key ''' jid, message, keyID, account = self._get_real_arguments(args, 4) jid = self._get_real_jid(jid, account) return self._send_message(jid, message, keyID, account) + @dbus.service.method(INTERFACE) def send_single_message(self, *args): - ''' send_single_message(jid, subject, message, keyID=None, account=None) + '''send_single_message(jid, subject, message, keyID=None, account=None) send single 'message' to 'jid', using account (optional) 'account'. if keyID is specified, encrypt the message with the pgp key ''' jid, subject, message, keyID, account = self._get_real_arguments(args, 5) jid = self._get_real_jid(jid, account) return self._send_message(jid, message, keyID, account, type, subject) + @dbus.service.method(INTERFACE) def open_chat(self, *args): ''' start_chat(jid, account=None) -> shows the tabbed window for new message to 'jid', using account(optional) 'account' ''' @@ -332,6 +270,7 @@ def open_chat(self, *args): return True return False + @dbus.service.method(INTERFACE) def change_status(self, *args, **keywords): ''' change_status(status, message, account). account is optional - if not specified status is changed for all accounts. ''' @@ -352,13 +291,15 @@ def change_status(self, *args, **keywords): status, message) return None + @dbus.service.method(INTERFACE) def show_next_unread(self, *args): - ''' Show the window(s) with next waiting messages in tabbed/group chats. ''' + '''Show the window(s) with next waiting messages in tabbed/group chats. ''' if gajim.events.get_nb_events(): gajim.interface.systray.handle_first_event() + @dbus.service.method(INTERFACE) def contact_info(self, *args): - ''' get vcard info for a contact. Return cached value of the vcard. + '''get vcard info for a contact. Return cached value of the vcard. ''' [jid] = self._get_real_arguments(args, 1) if not isinstance(jid, unicode): @@ -375,8 +316,9 @@ def contact_info(self, *args): # return empty dict return DBUS_DICT_SV() + @dbus.service.method(INTERFACE) def list_accounts(self, *args): - ''' list register accounts ''' + '''list register accounts''' result = gajim.contacts.get_accounts() if result and len(result) > 0: result_array = [] @@ -385,8 +327,9 @@ def list_accounts(self, *args): return result_array return None + @dbus.service.method(INTERFACE) def account_info(self, *args): - ''' show info on account: resource, jid, nick, prio, message ''' + '''show info on account: resource, jid, nick, prio, message''' [for_account] = self._get_real_arguments(args, 1) if not gajim.connections.has_key(for_account): # account is invalid @@ -394,19 +337,20 @@ def account_info(self, *args): account = gajim.connections[for_account] result = DBUS_DICT_SS() index = account.connected - result['status'] = DBUS_STRING(STATUS_LIST[index]) + result['status'] = DBUS_STRING(gajim.SHOW_LIST[index]) result['name'] = DBUS_STRING(account.name) result['jid'] = DBUS_STRING(gajim.get_jid_from_account(account.name)) result['message'] = DBUS_STRING(account.status) result['priority'] = DBUS_STRING(unicode(gajim.config.get_per('accounts', - account.name, 'priority'))) + account.name, 'priority'))) result['resource'] = DBUS_STRING(unicode(gajim.config.get_per('accounts', - account.name, 'resource'))) + account.name, 'resource'))) return result + @dbus.service.method(INTERFACE) def list_contacts(self, *args): - ''' list all contacts in the roster. If the first argument is specified, - then return the contacts for the specified account ''' + '''list all contacts in the roster. If the first argument is specified, + then return the contacts for the specified account''' [for_account] = self._get_real_arguments(args, 1) result = [] accounts = gajim.contacts.get_accounts() @@ -428,6 +372,7 @@ def list_contacts(self, *args): return None return result + @dbus.service.method(INTERFACE) def toggle_roster_appearance(self, *args): ''' shows/hides the roster window ''' win = gajim.interface.roster.window @@ -441,6 +386,7 @@ def toggle_roster_appearance(self, *args): else: win.window.focus(long(time())) + @dbus.service.method(INTERFACE) def prefs_list(self, *args): prefs_dict = DBUS_DICT_SS() def get_prefs(data, name, path, value): @@ -455,6 +401,7 @@ def get_prefs(data, name, path, value): gajim.config.foreach(get_prefs) return prefs_dict + @dbus.service.method(INTERFACE) def prefs_store(self, *args): try: gajim.interface.save_config() @@ -462,6 +409,7 @@ def prefs_store(self, *args): return False return True + @dbus.service.method(INTERFACE) def prefs_del(self, *args): [key] = self._get_real_arguments(args, 1) if not key: @@ -475,6 +423,7 @@ def prefs_del(self, *args): gajim.config.del_per(key_path[0], key_path[1], key_path[2]) return True + @dbus.service.method(INTERFACE) def prefs_put(self, *args): [key] = self._get_real_arguments(args, 1) if not key: @@ -488,6 +437,7 @@ def prefs_put(self, *args): gajim.config.set_per(key_path[0], key_path[1], subname, value) return True + @dbus.service.method(INTERFACE) def add_contact(self, *args): [jid, account] = self._get_real_arguments(args, 2) if account: @@ -503,6 +453,7 @@ def add_contact(self, *args): AddNewContactWindow(account = None, jid = jid) return True + @dbus.service.method(INTERFACE) def remove_contact(self, *args): [jid, account] = self._get_real_arguments(args, 2) jid = self._get_real_jid(jid, account) @@ -597,9 +548,11 @@ def _contacts_as_dbus_structure(self, contacts): contact_dict['resources'] = DBUS_VARIANT(contact_dict['resources']) return contact_dict + @dbus.service.method(INTERFACE) def get_unread_msgs_number(self, *args): return str(gajim.events.get_nb_events) + @dbus.service.method(INTERFACE) def start_chat(self, *args): [account] = self._get_real_arguments(args, 1) if not account: @@ -608,6 +561,7 @@ def start_chat(self, *args): NewChatDialog(account) return True + @dbus.service.method(INTERFACE) def send_xml(self, *args): xml, account = self._get_real_arguments(args, 2) if account: @@ -615,36 +569,3 @@ def send_xml(self, *args): else: for acc in gajim.contacts.get_accounts(): gajim.connections[acc].send_stanza(xml) - - if dbus_support.version[1] >= 30 and dbus_support.version[1] <= 40: - method = dbus.method - signal = dbus.signal - elif dbus_support.version[1] >= 41: - method = dbus.service.method - signal = dbus.service.signal - - # prevent using decorators, because they are not supported - # on python < 2.4 - # FIXME: use decorators when python2.3 (and dbus 0.23) is OOOOOOLD - toggle_roster_appearance = method(INTERFACE)(toggle_roster_appearance) - list_contacts = method(INTERFACE)(list_contacts) - list_accounts = method(INTERFACE)(list_accounts) - show_next_unread = method(INTERFACE)(show_next_unread) - change_status = method(INTERFACE)(change_status) - open_chat = method(INTERFACE)(open_chat) - contact_info = method(INTERFACE)(contact_info) - send_message = method(INTERFACE)(send_chat_message) - send_single_message = method(INTERFACE)(send_single_message) - send_file = method(INTERFACE)(send_file) - prefs_list = method(INTERFACE)(prefs_list) - prefs_put = method(INTERFACE)(prefs_put) - prefs_del = method(INTERFACE)(prefs_del) - prefs_store = method(INTERFACE)(prefs_store) - remove_contact = method(INTERFACE)(remove_contact) - add_contact = method(INTERFACE)(add_contact) - get_status = method(INTERFACE)(get_status) - get_status_message = method(INTERFACE)(get_status_message) - account_info = method(INTERFACE)(account_info) - get_unread_msgs_number = method(INTERFACE)(get_unread_msgs_number) - start_chat = method(INTERFACE)(start_chat) - send_xml = method(INTERFACE)(send_xml) diff --git a/src/roster_window.py b/src/roster_window.py index 0ce9cd2dd01587722a9ca13179256ab4262edf6b..4100e54b3b8bc18e34e0ff2f3b8223ac6d87fb12 100644 --- a/src/roster_window.py +++ b/src/roster_window.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- ## roster_window.py ## ## Copyright (C) 2003-2006 Yann Le Boulanger <asterix@lagaule.org> @@ -39,6 +40,10 @@ from groupchat_control import GroupchatControl from groupchat_control import PrivateChatControl +import dbus_support +if dbus_support.supported: + from music_track_listener import MusicTrackListener + #(icon, name, type, jid, account, editable, second pixbuf) ( C_IMG, # image to show state (online, new message etc) @@ -50,9 +55,6 @@ C_SECPIXBUF, # secondary_pixbuf (holds avatar or padlock) ) = range(7) - -DEFAULT_ICONSET = 'dcraven' - class RosterWindow: '''Class for main window of gtkgui interface''' @@ -624,9 +626,6 @@ def on_bookmark_menuitem_activate(self, widget, account, bookmark): self.join_gc_room(account, bookmark['jid'], bookmark['nick'], bookmark['password']) - def on_bm_header_changed_state(self, widget, event): - widget.set_state(gtk.STATE_NORMAL) #do not allow selected_state - def on_send_server_message_menuitem_activate(self, widget, account): server = gajim.config.get_per('accounts', account, 'hostname') server += '/announce/online' @@ -717,6 +716,11 @@ def make_menu(self): return new_chat_menuitem = self.xml.get_widget('new_chat_menuitem') join_gc_menuitem = self.xml.get_widget('join_gc_menuitem') + iconset = gajim.config.get('iconset') + path = os.path.join(gajim.DATA_DIR, 'iconsets', iconset, '16x16') + state_images = self.load_iconset(path) + if state_images.has_key('muc_active'): + join_gc_menuitem.set_image(state_images['muc_active']) add_new_contact_menuitem = self.xml.get_widget('add_new_contact_menuitem') service_disco_menuitem = self.xml.get_widget('service_disco_menuitem') advanced_menuitem = self.xml.get_widget('advanced_menuitem') @@ -787,7 +791,7 @@ def make_menu(self): label.set_use_underline(False) gc_item = gtk.MenuItem() gc_item.add(label) - gc_item.connect('state-changed', self.on_bm_header_changed_state) + gc_item.connect('state-changed', gtkgui_helpers.on_bm_header_changed_state) gc_sub_menu.append(gc_item) self.add_bookmarks_list(gc_sub_menu, account) @@ -1084,8 +1088,12 @@ def chg_contact_status(self, contact, show, status, account): win.redraw_tab(ctrl) name = contact.get_shown_name() - if contact.resource != '': + + # if multiple resources (or second one disconnecting) + if (len(contact_instances) > 1 or (len(contact_instances) == 1 and \ + show in ('offline', 'error'))) and contact.resource != '': name += '/' + contact.resource + uf_show = helpers.get_uf_show(show) if status: ctrl.print_conversation(_('%s is now %s (%s)') % (name, uf_show, @@ -1204,7 +1212,7 @@ def on_edit_agent(self, widget, contact, account): gajim.connections[account].request_register_agent_info(contact.jid) def on_remove_agent(self, widget, list_): - '''When an agent is requested to log in or off. list_ is a list of + '''When an agent is requested to be removed. list_ is a list of (contact, account) tuple''' for (contact, account) in list_: if gajim.config.get_per('accounts', account, 'hostname') == \ @@ -1226,6 +1234,17 @@ def remove(widget, list_): gajim.contacts.remove_jid(account, contact.jid) gajim.contacts.remove_contact(account, contact) + # Check if there are unread events from some contacts + has_unread_events = False + for (contact, account) in list_: + for jid in gajim.events.get_events(account): + if jid.endswith(contact.jid): + has_unread_events = True + break + if has_unread_events: + dialogs.ErrorDialog(_('You have unread messages'), + _('You must read them before removing this transport.')) + return if len(list_) == 1: pritext = _('Transport "%s" will be removed') % contact.jid sectext = _('You will no longer be able to send and receive messages to contacts from this transport.') @@ -1332,7 +1351,7 @@ def make_contact_menu(self, event, iter): '''Make contact's popup menu''' model = self.tree.get_model() jid = model[iter][C_JID].decode('utf-8') - path = model.get_path(iter) + tree_path = model.get_path(iter) account = model[iter][C_ACCOUNT].decode('utf-8') our_jid = jid == gajim.get_jid_from_account(account) contact = gajim.contacts.get_contact_with_highest_priority(account, jid) @@ -1368,6 +1387,12 @@ def make_contact_menu(self, event, iter): img.set_from_file(path_to_kbd_input_img) rename_menuitem.set_image(img) + iconset = gajim.config.get('iconset') + path = os.path.join(gajim.DATA_DIR, 'iconsets', iconset, '16x16') + state_images = self.load_iconset(path) + if state_images.has_key('muc_active'): + invite_menuitem.set_image(state_images['muc_active']) + above_subscription_separator = xml.get_widget( 'above_subscription_separator') subscription_menuitem = xml.get_widget('subscription_menuitem') @@ -1387,8 +1412,6 @@ def make_contact_menu(self, event, iter): start_chat_menuitem.set_submenu(sub_menu) iconset = gajim.config.get('iconset') - if not iconset: - iconset = DEFAULT_ICONSET path = os.path.join(gajim.DATA_DIR, 'iconsets', iconset, '16x16') for c in contacts: # icon MUST be different instance for every item @@ -1403,7 +1426,7 @@ def make_contact_menu(self, event, iter): else: # one resource start_chat_menuitem.connect('activate', - self.on_roster_treeview_row_activated, path) + self.on_roster_treeview_row_activated, tree_path) if contact.resource: send_file_menuitem.connect('activate', @@ -1444,7 +1467,7 @@ def make_contact_menu(self, event, iter): menuitem.connect('activate', self.on_invite_to_room, [(contact, account)], room_jid, acct) submenu.append(menuitem) - rename_menuitem.connect('activate', self.on_rename, iter, path) + rename_menuitem.connect('activate', self.on_rename, iter, tree_path) remove_from_roster_menuitem.connect('activate', self.on_req_usub, [(contact, account)]) information_menuitem.connect('activate', self.on_info, contact, @@ -1774,8 +1797,6 @@ def build_account_menu(self, account): # we have to create our own set of icons for the menu # using self.jabber_status_images is poopoo iconset = gajim.config.get('iconset') - if not iconset: - iconset = DEFAULT_ICONSET path = os.path.join(gajim.DATA_DIR, 'iconsets', iconset, '16x16') state_images = self.load_iconset(path) @@ -1908,8 +1929,6 @@ def make_account_menu(self, event, iter): else: menu = gtk.Menu() iconset = gajim.config.get('iconset') - if not iconset: - iconset = DEFAULT_ICONSET path = os.path.join(gajim.DATA_DIR, 'iconsets', iconset, '16x16') accounts = [] # Put accounts in a list to sort them for account in gajim.connections: @@ -2419,6 +2438,41 @@ def on_status_combobox_changed(self, widget): self.send_status(acct, status, message) self.update_status_combobox() + ## enable setting status msg from currently playing music track + def enable_syncing_status_msg_from_current_music_track(self, enabled): + '''if enabled is True, we listen to events from music players about + currently played music track, and we update our + status message accordinly''' + if not dbus_support.supported: + # do nothing if user doesn't have D-Bus bindings + return + if enabled: + if self._music_track_changed_signal is None: + listener = MusicTrackListener.get() + self._music_track_changed_signal = listener.connect( + 'music-track-changed', self._music_track_changed) + track = listener.get_playing_track() + self._music_track_changed(listener, track) + else: + if self._music_track_changed_signal is not None: + listener = MusicTrackListener.get() + listener.disconnect(self._music_track_changed_signal) + self._music_track_changed_signal = None + self._music_track_changed(None, None) + + def _music_track_changed(self, unused_listener, music_track_info): + accounts = gajim.connections.keys() + if music_track_info is None: + status_message = '' + else: + status_message = _('♪ "%(title)s" by %(artist)s ♪') % \ + {'title': music_track_info.title, + 'artist': music_track_info.artist } + for acct in accounts: + current_show = gajim.SHOW_LIST[gajim.connections[acct].connected] + self.send_status(acct, current_show, status_message) + + def update_status_combobox(self): # table to change index in connection.connected to index in combobox table = {'offline':9, 'connecting':9, 'online':0, 'chat':1, 'away':2, @@ -2599,12 +2653,12 @@ def on_message(self, jid, msg, tim, account, encrypted = False, # We save it in a queue type_ = 'chat' + event_type = 'message_received' if msg_type == 'normal': type_ = 'normal' - show_in_roster = notify.get_show_in_roster('message_received', account, - contact) - show_in_systray = notify.get_show_in_systray('message_received', account, - contact) + event_type = 'single_message_received' + show_in_roster = notify.get_show_in_roster(event_type, account, contact) + show_in_systray = notify.get_show_in_systray(event_type, account, contact) event = gajim.events.create_event(type_, (msg, subject, msg_type, tim, encrypted, resource, msg_id), show_in_roster = show_in_roster, show_in_systray = show_in_systray) @@ -3134,8 +3188,13 @@ def load_iconset(self, path, pixbuf2 = None, transport = False): def make_jabber_state_images(self): '''initialise jabber_state_images dict''' iconset = gajim.config.get('iconset') - if not iconset: - iconset = 'dcraven' + if iconset: + path = os.path.join(gajim.DATA_DIR, 'iconsets', iconset, '16x16') + if not os.path.exists(path): + iconset = gajim.config.DEFAULT_ICONSET + else: + iconset = gajim.config.DEFAULT_ICONSET + path = os.path.join(gajim.DATA_DIR, 'iconsets', iconset, '32x32') self.jabber_state_images['32'] = self.load_iconset(path) @@ -3174,7 +3233,8 @@ def reload_jabber_state_images(self): model[iter][1] = self.jabber_state_images['16'][model[iter][2]] iter = model.iter_next(iter) # Update the systray - gajim.interface.systray.set_img() + if gajim.interface.systray_enabled: + gajim.interface.systray.set_img() for win in gajim.interface.msg_win_mgr.windows(): for ctrl in win.controls(): @@ -3722,6 +3782,7 @@ def _on_treeview_selection_changed(self, selection): def __init__(self): self.xml = gtkgui_helpers.get_glade('roster_window.glade') self.window = self.xml.get_widget('roster_window') + self._music_track_changed_signal = None gajim.interface.msg_win_mgr = MessageWindowMgr() self.advanced_menus = [] # We keep them to destroy them if gajim.config.get('roster_window_skip_taskbar'): @@ -3898,6 +3959,13 @@ def __init__(self): self.tooltip = tooltips.RosterTooltip() self.draw_roster() + ## Music Track notifications + ## FIXME: we use a timeout because changing status of + ## accounts has no effect until they are connected. + gobject.timeout_add(1000, + self.enable_syncing_status_msg_from_current_music_track, + gajim.config.get('set_status_msg_from_current_music_track')) + if gajim.config.get('show_roster_on_startup'): self.window.show_all() else: diff --git a/src/systray.py b/src/systray.py index 926c077d1361fbfa1333c14df054c18880b14609..ade7ffd81d47ea123ee74880aaf1f8cebfc5e143 100644 --- a/src/systray.py +++ b/src/systray.py @@ -124,11 +124,12 @@ def make_menu(self, event = None): # We need our own set of status icons, let's make 'em! iconset = gajim.config.get('iconset') - if not iconset: - iconset = 'dcraven' path = os.path.join(gajim.DATA_DIR, 'iconsets', iconset, '16x16') state_images = gajim.interface.roster.load_iconset(path) + if state_images.has_key('muc_active'): + join_gc_menuitem.set_image(state_images['muc_active']) + for show in ('online', 'chat', 'away', 'xa', 'dnd', 'invisible'): uf_show = helpers.get_uf_show(show, use_mnemonic = True) item = gtk.ImageMenuItem(uf_show) @@ -194,6 +195,7 @@ def make_menu(self, event = None): label.set_use_underline(False) gc_item = gtk.MenuItem() gc_item.add(label) + gc_item.connect('state-changed', gtkgui_helpers.on_bm_header_changed_state) gc_sub_menu.append(gc_item) gajim.interface.roster.add_bookmarks_list(gc_sub_menu, account) @@ -250,11 +252,11 @@ def on_left_click(self): if len(gajim.events.get_systray_events()) == 0: # no pending events, so toggle visible/hidden for roster window if win.get_property('visible'): # visible in ANY virtual desktop? - win.hide() # we hide it from VD that was visible in - # but we could be in another VD right now. eg vd2 - # and we want not only to hide it in vd1 but also show it in vd2 - gtkgui_helpers.possibly_move_window_in_current_desktop(win) + # we could be in another VD right now. eg vd2 + # and we want to show it in vd2 + if not gtkgui_helpers.possibly_move_window_in_current_desktop(win): + win.hide() # else we hide it from VD that was visible in else: win.present() else: diff --git a/src/vcard.py b/src/vcard.py index 009605b3825b41b1b7bc1c102202eeea2a070a6d..975d39a7404d4d418f7d42cd659997aeb6330ef7 100644 --- a/src/vcard.py +++ b/src/vcard.py @@ -61,6 +61,7 @@ def __init__(self, contact, account, is_fake = False): # the contact variable is the jid if vcard is true self.xml = gtkgui_helpers.get_glade('vcard_information_window.glade') self.window = self.xml.get_widget('vcard_information_window') + self.progressbar = self.xml.get_widget('progressbar') self.contact = contact self.account = account @@ -68,13 +69,23 @@ def __init__(self, contact, account, is_fake = False): self.avatar_mime_type = None self.avatar_encoded = None + self.vcard_arrived = False + self.os_info_arrived = False + self.update_progressbar_timeout_id = gobject.timeout_add(100, + self.update_progressbar) self.fill_jabber_page() self.xml.signal_autoconnect(self) self.window.show_all() + def update_progressbar(self): + self.progressbar.pulse() + return True # loop forever + def on_vcard_information_window_destroy(self, widget): + if self.update_progressbar_timeout_id is not None: + gobject.source_remove(self.update_progressbar_timeout_id) del gajim.interface.instances[self.account]['infos'][self.contact.jid] def on_vcard_information_window_key_press_event(self, widget, event): @@ -113,7 +124,15 @@ def on_PHOTO_eventbox_button_press_event(self, widget, event): def set_value(self, entry_name, value): try: - self.xml.get_widget(entry_name).set_text(value) + if value and entry_name == 'URL_label': + if gtk.pygtk_version >= (2, 10, 0) and gtk.gtk_version >= (2, 10, 0): + widget = gtk.LinkButton(value, value) + else: + widget = gtk.Label(value) + table = self.xml.get_widget('personal_info_table') + table.attach(widget, 1, 4, 3, 4, yoptions = 0) + else: + self.xml.get_widget(entry_name).set_text(value) except AttributeError: pass @@ -144,8 +163,17 @@ def set_values(self, vcard): if i == 'DESC': self.xml.get_widget('DESC_textview').get_buffer().set_text( vcard[i], 0) - else: + elif i != 'jid': # Do not override jid_label self.set_value(i + '_label', vcard[i]) + self.vcard_arrived = True + self.test_remove_progressbar() + + def test_remove_progressbar(self): + if self.update_progressbar_timeout_id is not None and \ + self.vcard_arrived and self.os_info_arrived: + gobject.source_remove(self.update_progressbar_timeout_id) + self.progressbar.hide() + self.update_progressbar_timeout_id = None def set_last_status_time(self): self.fill_status_label() @@ -174,6 +202,8 @@ def set_os_info(self, resource, client_info, os_info): os = Q_('?OS:Unknown') self.xml.get_widget('client_name_version_label').set_text(client) self.xml.get_widget('os_label').set_text(os) + self.os_info_arrived = True + self.test_remove_progressbar() def fill_status_label(self): if self.xml.get_widget('information_notebook').get_n_pages() < 4: @@ -251,8 +281,10 @@ def fill_jabber_page(self): gajim.connections[self.account].request_last_status_time(self.contact.jid, self.contact.resource) - # Request os info in contact is connected - if self.contact.show not in ('offline', 'error'): + # do not wait for os_info if contact is not connected + if self.contact.show in ('offline', 'error'): + self.os_info_arrived = True + else: # Request os info if contact is connected gobject.idle_add(gajim.connections[self.account].request_os_info, self.contact.jid, self.contact.resource) self.os_info = {0: {'resource': self.contact.resource, 'client': '', @@ -283,3 +315,6 @@ def fill_jabber_page(self): self.fill_status_label() gajim.connections[self.account].request_vcard(self.contact.jid, self.is_fake) + + def on_close_button_clicked(self, widget): + self.window.destroy()