dialogs.py 70.7 KB
Newer Older
1
# -*- coding: utf-8 -*-
roidelapluie's avatar
roidelapluie committed
2
## src/dialogs.py
Yann Leboulanger's avatar
Yann Leboulanger committed
3
##
roidelapluie's avatar
roidelapluie committed
4
## Copyright (C) 2003-2005 Vincent Hanquez <tab AT snarc.org>
Dicson's avatar
Dicson committed
5
## Copyright (C) 2003-2014 Yann Leboulanger <asterix AT lagaule.org>
roidelapluie's avatar
roidelapluie committed
6 7 8 9 10 11 12 13 14 15
## Copyright (C) 2005 Alex Mauer <hawke AT hawkesnest.net>
## Copyright (C) 2005-2006 Dimitur Kirov <dkirov AT gmail.com>
##                         Travis Shirk <travis AT pobox.com>
## Copyright (C) 2005-2008 Nikos Kouremenos <kourem AT gmail.com>
## Copyright (C) 2006-2008 Jean-Marie Traissard <jim AT lapin.org>
## Copyright (C) 2007 Lukas Petrovicky <lukas AT petrovicky.net>
## Copyright (C) 2007-2008 Brendan Taylor <whateley AT gmail.com>
##                         Julien Pivotto <roidelapluie AT gmail.com>
##                         Stephan Erb <steve-e AT h3c.de>
## Copyright (C) 2008 Jonathan Schleifer <js-gajim AT webkeks.org>
Yann Leboulanger's avatar
Yann Leboulanger committed
16
##
Yann Leboulanger's avatar
Yann Leboulanger committed
17 18 19
## This file is part of Gajim.
##
## Gajim is free software; you can redistribute it and/or modify
Yann Leboulanger's avatar
Yann Leboulanger committed
20
## it under the terms of the GNU General Public License as published
Yann Leboulanger's avatar
Yann Leboulanger committed
21
## by the Free Software Foundation; version 3 only.
Yann Leboulanger's avatar
Yann Leboulanger committed
22
##
Yann Leboulanger's avatar
Yann Leboulanger committed
23
## Gajim is distributed in the hope that it will be useful,
Yann Leboulanger's avatar
Yann Leboulanger committed
24
## but WITHOUT ANY WARRANTY; without even the implied warranty of
roidelapluie's avatar
roidelapluie committed
25
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Yann Leboulanger's avatar
Yann Leboulanger committed
26 27
## GNU General Public License for more details.
##
Yann Leboulanger's avatar
Yann Leboulanger committed
28
## You should have received a copy of the GNU General Public License
roidelapluie's avatar
roidelapluie committed
29
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
Yann Leboulanger's avatar
Yann Leboulanger committed
30
##
Yann Leboulanger's avatar
Yann Leboulanger committed
31

32
from gi.repository import Gtk
Yann Leboulanger's avatar
Yann Leboulanger committed
33
from gi.repository import Gdk
Yann Leboulanger's avatar
Yann Leboulanger committed
34
from gi.repository import GLib
Philipp Hörist's avatar
Philipp Hörist committed
35

36
import os
37
import logging
38

André's avatar
André committed
39 40 41
from gajim import gtkgui_helpers
from gajim import vcard
from gajim import dataforms_widget
Yann Leboulanger's avatar
Yann Leboulanger committed
42 43

from random import randrange
André's avatar
André committed
44
from gajim.common import ged
45
from gajim.common.const import ACTIVITIES
46
from gajim.common.const import MOODS
47

48
from gajim.common import app
André's avatar
André committed
49 50
from gajim.common import helpers
from gajim.common import i18n
51
from gajim.common.modules import dataforms
André's avatar
André committed
52
from gajim.common.exceptions import GajimGeneralException
Yann Leboulanger's avatar
Yann Leboulanger committed
53

54 55 56
# Compat with Gajim 1.0.3 for plugins
from gajim.gtk import *

Philipp Hörist's avatar
Philipp Hörist committed
57

58 59
log = logging.getLogger('gajim.dialogs')

lovetox's avatar
lovetox committed
60

61
class EditGroupsDialog:
62 63 64 65 66 67 68 69
    """
    Class for the edit group dialog window
    """

    def __init__(self, list_):
        """
        list_ is a list of (contact, account) tuples
        """
70 71
        self.xml = gtkgui_helpers.get_gtk_builder('edit_groups_dialog.ui')
        self.dialog = self.xml.get_object('edit_groups_dialog')
72
        self.dialog.set_transient_for(app.interface.roster.window)
73 74
        self.list_ = list_
        self.changes_made = False
75
        self.treeview = self.xml.get_object('groups_treeview')
76 77
        if len(list_) == 1:
            contact = list_[0][0]
78
            self.xml.get_object('nickname_label').set_markup(
79
                    _('Contact name: <i>%s</i>') % contact.get_shown_name())
80
            self.xml.get_object('jid_label').set_markup(
81
                    _('JID: <i>%s</i>') % contact.jid)
82
        else:
83 84 85 86
            self.xml.get_object('nickname_label').set_no_show_all(True)
            self.xml.get_object('nickname_label').hide()
            self.xml.get_object('jid_label').set_no_show_all(True)
            self.xml.get_object('jid_label').hide()
87

88
        self.xml.connect_signals(self)
89 90 91 92 93
        self.init_list()

        self.dialog.show_all()
        if self.changes_made:
            for (contact, account) in self.list_:
94
                app.connections[account].update_contact(contact.jid,
Dicson's avatar
Dicson committed
95
                    contact.name, contact.groups)
96 97

    def on_edit_groups_dialog_response(self, widget, response_id):
98
        if response_id == Gtk.ResponseType.CLOSE:
99 100 101 102 103 104 105
            self.dialog.destroy()

    def remove_group(self, group):
        """
        Remove group group from all contacts and all their brothers
        """
        for (contact, account) in self.list_:
106
            app.interface.roster.remove_contact_from_groups(contact.jid,
Dicson's avatar
Dicson committed
107
                account, [group])
108 109

        # FIXME: Ugly workaround.
110
        app.interface.roster.draw_group(_('General'), account)
111 112 113 114 115 116

    def add_group(self, group):
        """
        Add group group to all contacts and all their brothers
        """
        for (contact, account) in self.list_:
117
            app.interface.roster.add_contact_to_groups(contact.jid, account,
Dicson's avatar
Dicson committed
118
                [group])
119

Dicson's avatar
Dicson committed
120 121
        # FIXME: Ugly workaround.
        # Maybe we haven't been in any group (defaults to General)
122
        app.interface.roster.draw_group(_('General'), account)
123 124

    def on_add_button_clicked(self, widget):
125
        group = self.xml.get_object('group_entry').get_text()
126 127 128 129 130 131 132
        if not group:
            return
        # Do not allow special groups
        if group in helpers.special_groups:
            return
        # check if it already exists
        model = self.treeview.get_model()
133
        iter_ = model.get_iter_first()
134
        while iter_:
135
            if model.get_value(iter_, 0) == group:
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
                return
            iter_ = model.iter_next(iter_)
        self.changes_made = True
        model.append((group, True, False))
        self.add_group(group)
        self.init_list() # Re-draw list to sort new item

    def group_toggled_cb(self, cell, path):
        self.changes_made = True
        model = self.treeview.get_model()
        if model[path][2]:
            model[path][2] = False
            model[path][1] = True
        else:
            model[path][1] = not model[path][1]
151
        group = model[path][0]
152 153 154 155 156 157
        if model[path][1]:
            self.add_group(group)
        else:
            self.remove_group(group)

    def init_list(self):
158
        store = Gtk.ListStore(str, bool, bool)
159 160 161 162 163 164 165 166 167 168 169
        self.treeview.set_model(store)
        for column in self.treeview.get_columns():
            # Clear treeview when re-drawing
            self.treeview.remove_column(column)
        accounts = []
        # Store groups in a list so we can sort them and the number of contacts in
        # it
        groups = {}
        for (contact, account) in self.list_:
            if account not in accounts:
                accounts.append(account)
170
                for g in app.groups[account].keys():
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
                    if g in groups:
                        continue
                    groups[g] = 0
            c_groups = contact.groups
            for g in c_groups:
                groups[g] += 1
        group_list = []
        # Remove special groups if they are empty
        for group in groups:
            if group not in helpers.special_groups or groups[group] > 0:
                group_list.append(group)
        group_list.sort()
        for group in group_list:
            iter_ = store.append()
            store.set(iter_, 0, group) # Group name
            if groups[group] == 0:
                store.set(iter_, 1, False)
            else:
                store.set(iter_, 1, True)
                if groups[group] == len(self.list_):
                    # all contacts are in this group
                    store.set(iter_, 2, False)
                else:
                    store.set(iter_, 2, True)
195
        column = Gtk.TreeViewColumn(_('Group'))
196 197
        column.set_expand(True)
        self.treeview.append_column(column)
198
        renderer = Gtk.CellRendererText()
Yann Leboulanger's avatar
Yann Leboulanger committed
199 200
        column.pack_start(renderer, True)
        column.add_attribute(renderer, 'text', 0)
201

202
        column = Gtk.TreeViewColumn(_('In the group'))
203 204
        column.set_expand(False)
        self.treeview.append_column(column)
205
        renderer = Gtk.CellRendererToggle()
Yann Leboulanger's avatar
Yann Leboulanger committed
206
        column.pack_start(renderer, True)
207 208
        renderer.set_property('activatable', True)
        renderer.connect('toggled', self.group_toggled_cb)
Yann Leboulanger's avatar
Yann Leboulanger committed
209 210
        column.add_attribute(renderer, 'active', 1)
        column.add_attribute(renderer, 'inconsistent', 2)
211

212
class PassphraseDialog:
213 214 215 216
    """
    Class for Passphrase dialog
    """
    def __init__(self, titletext, labeltext, checkbuttontext=None,
217
    ok_handler=None, cancel_handler=None, transient_for=None):
218 219 220
        self.xml = gtkgui_helpers.get_gtk_builder('passphrase_dialog.ui')
        self.window = self.xml.get_object('passphrase_dialog')
        self.passphrase_entry = self.xml.get_object('passphrase_entry')
221 222
        self.passphrase = -1
        self.window.set_title(titletext)
223
        self.xml.get_object('message_label').set_text(labeltext)
224 225 226 227 228

        self.ok = False

        self.cancel_handler = cancel_handler
        self.ok_handler = ok_handler
229
        okbutton = self.xml.get_object('ok_button')
230
        okbutton.connect('clicked', self.on_okbutton_clicked)
231
        cancelbutton = self.xml.get_object('cancel_button')
232 233
        cancelbutton.connect('clicked', self.on_cancelbutton_clicked)

234
        self.xml.connect_signals(self)
235 236 237
        if transient_for is None:
            transient_for = app.app.get_active_window()
        self.window.set_transient_for(transient_for)
238 239 240
        self.window.show_all()

        self.check = bool(checkbuttontext)
241
        checkbutton =   self.xml.get_object('save_passphrase_checkbutton')
242 243 244 245 246 247 248 249 250
        if self.check:
            checkbutton.set_label(checkbuttontext)
        else:
            checkbutton.hide()

    def on_okbutton_clicked(self, widget):
        if not self.ok_handler:
            return

251
        passph = self.passphrase_entry.get_text()
252 253

        if self.check:
254
            checked = self.xml.get_object('save_passphrase_checkbutton').\
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
                    get_active()
        else:
            checked = False

        self.ok = True

        self.window.destroy()

        if isinstance(self.ok_handler, tuple):
            self.ok_handler[0](passph, checked, *self.ok_handler[1:])
        else:
            self.ok_handler(passph, checked)

    def on_cancelbutton_clicked(self, widget):
        self.window.destroy()

    def on_passphrase_dialog_destroy(self, widget):
        if self.cancel_handler and not self.ok:
            self.cancel_handler()
Yann Leboulanger's avatar
Yann Leboulanger committed
274

275
class ChooseGPGKeyDialog:
276 277 278 279 280
    """
    Class for GPG key dialog
    """

    def __init__(self, title_text, prompt_text, secret_keys, on_response,
281
            selected=None, transient_for=None):
282 283
        '''secret_keys : {keyID: userName, ...}'''
        self.on_response = on_response
284 285
        xml = gtkgui_helpers.get_gtk_builder('choose_gpg_key_dialog.ui')
        self.window = xml.get_object('choose_gpg_key_dialog')
286
        self.window.set_title(title_text)
287
        self.window.set_transient_for(transient_for)
288 289
        self.keys_treeview = xml.get_object('keys_treeview')
        prompt_label = xml.get_object('prompt_label')
290
        prompt_label.set_text(prompt_text)
291
        model = Gtk.ListStore(str, str)
292
        model.set_sort_func(1, self.sort_keys)
293
        model.set_sort_column_id(1, Gtk.SortType.ASCENDING)
294 295
        self.keys_treeview.set_model(model)
        #columns
296
        renderer = Gtk.CellRendererText()
297 298 299
        self.keys_treeview.insert_column_with_attributes(-1, _('KeyID'),
            renderer, text=0)
        col = self.keys_treeview.get_column(0)
300
        col.set_sort_column_id(0)
301
        renderer = Gtk.CellRendererText()
302 303 304
        self.keys_treeview.insert_column_with_attributes(-1, _('Contact name'),
            renderer, text=1)
        col = self.keys_treeview.get_column(1)
305 306 307 308
        col.set_sort_column_id(1)
        self.keys_treeview.set_search_column(1)
        self.fill_tree(secret_keys, selected)
        self.window.connect('response', self.on_dialog_response)
309
        self.window.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
310 311
        self.window.show_all()

312
    def sort_keys(self, model, iter1, iter2, data=None):
313 314 315 316 317 318 319 320 321 322 323 324 325
        value1 = model[iter1][1]
        value2 = model[iter2][1]
        if value1 == _('None'):
            return -1
        elif value2 == _('None'):
            return 1
        elif value1 < value2:
            return -1
        return 1

    def on_dialog_response(self, dialog, response):
        selection = self.keys_treeview.get_selection()
        (model, iter_) = selection.get_selected()
326
        if iter_ and response == Gtk.ResponseType.OK:
327
            keyID = [ model[iter_][0], model[iter_][1] ]
328 329 330 331 332 333 334 335 336 337 338 339
        else:
            keyID = None
        self.on_response(keyID)
        self.window.destroy()

    def fill_tree(self, list_, selected):
        model = self.keys_treeview.get_model()
        for keyID in list_.keys():
            iter_ = model.append((keyID, list_[keyID]))
            if keyID == selected:
                path = model.get_path(iter_)
                self.keys_treeview.set_cursor(path)
340 341


342
class ChangeActivityDialog:
343 344 345 346 347 348 349 350 351
    PAGELIST = ['doing_chores', 'drinking', 'eating', 'exercising', 'grooming',
            'having_appointment', 'inactive', 'relaxing', 'talking', 'traveling',
            'working']

    def __init__(self, on_response, activity=None, subactivity=None, text=''):
        self.on_response = on_response
        self.activity = activity
        self.subactivity = subactivity
        self.text = text
352
        self.xml = gtkgui_helpers.get_gtk_builder('change_activity_dialog.ui')
353
        self.window = self.xml.get_object('change_activity_dialog')
354
        self.window.set_transient_for(app.interface.roster.window)
355

356 357 358
        self.checkbutton = self.xml.get_object('enable_checkbutton')
        self.notebook = self.xml.get_object('notebook')
        self.entry = self.xml.get_object('description_entry')
359 360 361 362

        rbtns = {}
        group = None

363
        for category in ACTIVITIES:
364
            item = self.xml.get_object(category + '_image')
365 366
            item.set_from_pixbuf(
                    gtkgui_helpers.load_activity_icon(category).get_pixbuf())
367
            item.set_tooltip_text(ACTIVITIES[category]['category'])
368

369
            vbox = self.xml.get_object(category + '_vbox')
370 371 372 373 374 375
            vbox.set_border_width(5)

            # Other
            act = category + '_other'

            if group:
Dicson's avatar
Dicson committed
376 377
                rbtns[act] = Gtk.RadioButton()
                rbtns[act].join_group(group)
378
            else:
379
                rbtns[act] = group = Gtk.RadioButton()
380

Yann Leboulanger's avatar
Yann Leboulanger committed
381
            hbox = Gtk.HBox(homogeneous=False, spacing=5)
Dicson's avatar
Dicson committed
382 383
            hbox.pack_start(gtkgui_helpers.load_activity_icon(category,
                activity), False, False, 0)
384
            lbl = Gtk.Label(label='<b>' + ACTIVITIES[category]['category'] \
Dicson's avatar
Dicson committed
385
                + '</b>')
386 387 388 389 390 391 392 393
            lbl.set_use_markup(True)
            hbox.pack_start(lbl, False, False, 0)
            rbtns[act].add(hbox)
            rbtns[act].connect('toggled', self.on_rbtn_toggled,
                    [category, 'other'])
            vbox.pack_start(rbtns[act], False, False, 0)

            activities = []
394
            for activity in ACTIVITIES[category]:
395 396 397 398 399 400 401 402 403
                activities.append(activity)
            activities.sort()
            for activity in activities:
                if activity == 'category':
                    continue

                act = category + '_' + activity

                if group:
Dicson's avatar
Dicson committed
404 405
                    rbtns[act] = Gtk.RadioButton()
                    rbtns[act].join_group(group)
406
                else:
407
                    rbtns[act] = group = Gtk.RadioButton()
408

Yann Leboulanger's avatar
Yann Leboulanger committed
409
                hbox = Gtk.HBox(homogeneous=False, spacing=5)
410 411
                hbox.pack_start(gtkgui_helpers.load_activity_icon(category,
                        activity), False, False, 0)
412
                hbox.pack_start(Gtk.Label(label=ACTIVITIES[category][activity]),
413 414 415 416 417 418 419
                        False, False, 0)
                rbtns[act].connect('toggled', self.on_rbtn_toggled,
                        [category, activity])
                rbtns[act].add(hbox)
                vbox.pack_start(rbtns[act], False, False, 0)


420 421
        self.default_radio = rbtns['doing_chores_other']

422 423
        if self.activity in ACTIVITIES:
            if not self.subactivity in ACTIVITIES[self.activity]:
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
                self.subactivity = 'other'

            rbtns[self.activity + '_' + self.subactivity].set_active(True)

            self.checkbutton.set_active(True)
            self.notebook.set_sensitive(True)
            self.entry.set_sensitive(True)

            self.notebook.set_current_page(
                    self.PAGELIST.index(self.activity))

            self.entry.set_text(text)

        else:
            self.checkbutton.set_active(False)

440
        self.xml.connect_signals(self)
441
        self.window.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
442 443 444 445 446
        self.window.show_all()

    def on_enable_checkbutton_toggled(self, widget):
        self.notebook.set_sensitive(widget.get_active())
        self.entry.set_sensitive(widget.get_active())
447 448
        if not self.activity:
            self.default_radio.set_active(True)
449 450 451 452 453 454 455 456 457 458 459 460

    def on_rbtn_toggled(self, widget, data):
        if widget.get_active():
            self.activity = data[0]
            self.subactivity = data[1]

    def on_ok_button_clicked(self, widget):
        """
        Return activity and messsage (None if no activity selected)
        """
        if self.checkbutton.get_active():
            self.on_response(self.activity, self.subactivity,
461
                    self.entry.get_text())
462 463 464 465 466 467
        else:
            self.on_response(None, None, '')
        self.window.destroy()

    def on_cancel_button_clicked(self, widget):
        self.window.destroy()
468

469
class ChangeMoodDialog:
470 471 472 473 474 475
    COLS = 11

    def __init__(self, on_response, mood=None, text=''):
        self.on_response = on_response
        self.mood = mood
        self.text = text
476
        self.xml = gtkgui_helpers.get_gtk_builder('change_mood_dialog.ui')
477

478
        self.window = self.xml.get_object('change_mood_dialog')
479
        self.window.set_transient_for(app.interface.roster.window)
480 481
        self.window.set_title(_('Set Mood'))

482 483 484
        table = self.xml.get_object('mood_icons_table')
        self.label = self.xml.get_object('mood_label')
        self.entry = self.xml.get_object('description_entry')
485

486
        no_mood_button = self.xml.get_object('no_mood_button')
487 488 489 490 491 492 493 494 495 496
        no_mood_button.set_mode(False)
        no_mood_button.connect('clicked',
                self.on_mood_button_clicked, None)

        x = 1
        y = 0
        self.mood_buttons = {}

        # Order them first
        self.MOODS = []
497
        for mood in MOODS:
498 499 500 501
            self.MOODS.append(mood)
        self.MOODS.sort()

        for mood in self.MOODS:
Dicson's avatar
Dicson committed
502 503
            self.mood_buttons[mood] = Gtk.RadioButton()
            self.mood_buttons[mood].join_group(no_mood_button)
504 505
            self.mood_buttons[mood].set_mode(False)
            self.mood_buttons[mood].add(gtkgui_helpers.load_mood_icon(mood))
506
            self.mood_buttons[mood].set_relief(Gtk.ReliefStyle.NONE)
507
            self.mood_buttons[mood].set_tooltip_text(MOODS[mood])
508
            self.mood_buttons[mood].connect('clicked',
509 510
                self.on_mood_button_clicked, mood)
            table.attach(self.mood_buttons[mood], x, y, 1, 1)
511 512 513 514 515 516 517

            # Calculate the next position
            x += 1
            if x >= self.COLS:
                x = 0
                y += 1

518
        if self.mood in MOODS:
519
            self.mood_buttons[self.mood].set_active(True)
520
            self.label.set_text(MOODS[self.mood])
521 522 523 524 525 526 527 528
            self.entry.set_sensitive(True)
            if self.text:
                self.entry.set_text(self.text)
        else:
            self.label.set_text(_('None'))
            self.entry.set_text('')
            self.entry.set_sensitive(False)

529
        self.xml.connect_signals(self)
530
        self.window.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
531 532 533 534
        self.window.show_all()

    def on_mood_button_clicked(self, widget, data):
        if data:
535
            self.label.set_text(MOODS[data])
536 537 538 539 540 541 542 543 544
            self.entry.set_sensitive(True)
        else:
            self.label.set_text(_('None'))
            self.entry.set_text('')
            self.entry.set_sensitive(False)
        self.mood = data

    def on_ok_button_clicked(self, widget):
        '''Return mood and messsage (None if no mood selected)'''
545
        message = self.entry.get_text()
546 547 548 549 550
        self.on_response(self.mood, message)
        self.window.destroy()

    def on_cancel_button_clicked(self, widget):
        self.window.destroy()
551

552
class TimeoutDialog:
553 554 555 556
    """
    Class designed to be derivated to create timeout'd dialogs (dialogs that
    closes automatically after a timeout)
    """
557
    def __init__(self, timeout):
558 559 560 561 562 563 564
        self.countdown_left = timeout
        self.countdown_enabled = True
        self.title_text = ''

    def run_timeout(self):
        if self.countdown_left > 0:
            self.countdown()
Yann Leboulanger's avatar
Yann Leboulanger committed
565
            GLib.timeout_add_seconds(1, self.countdown)
566

567
    def on_timeout(self):
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
        """
        To be implemented in derivated classes
        """
        pass

    def countdown(self):
        if self.countdown_enabled:
            if self.countdown_left <= 0:
                self.on_timeout()
                return False
            self.dialog.set_title('%s [%s]' % (self.title_text,
                    str(self.countdown_left)))
            self.countdown_left -= 1
            return True
        else:
            self.dialog.set_title(self.title_text)
            return False
585 586

class ChangeStatusMessageDialog(TimeoutDialog):
587
    def __init__(self, on_response, show=None, show_pep=True):
588
        countdown_time = app.config.get('change_status_window_timeout')
589
        TimeoutDialog.__init__(self, countdown_time)
590 591 592 593
        self.show = show
        self.pep_dict = {}
        self.show_pep = show_pep
        self.on_response = on_response
594 595
        self.xml = gtkgui_helpers.get_gtk_builder('change_status_message_dialog.ui')
        self.dialog = self.xml.get_object('change_status_message_dialog')
596
        self.dialog.set_transient_for(app.interface.roster.window)
597 598 599 600
        msg = None
        if show:
            uf_show = helpers.get_uf_show(show)
            self.title_text = _('%s Status Message') % uf_show
601
            msg = app.config.get_per('statusmsg', '_last_' + self.show,
602
                                                               'message')
603
            self.pep_dict['activity'] = app.config.get_per('statusmsg',
Dicson's avatar
Dicson committed
604
                '_last_' + self.show, 'activity')
605
            self.pep_dict['subactivity'] = app.config.get_per('statusmsg',
Dicson's avatar
Dicson committed
606
                '_last_' + self.show, 'subactivity')
607
            self.pep_dict['activity_text'] = app.config.get_per('statusmsg',
Dicson's avatar
Dicson committed
608
                '_last_' + self.show, 'activity_text')
609
            self.pep_dict['mood'] = app.config.get_per('statusmsg',
Dicson's avatar
Dicson committed
610
                '_last_' + self.show, 'mood')
611
            self.pep_dict['mood_text'] = app.config.get_per('statusmsg',
Dicson's avatar
Dicson committed
612
                '_last_' + self.show, 'mood_text')
613 614 615 616
        else:
            self.title_text = _('Status Message')
        self.dialog.set_title(self.title_text)

617
        message_textview = self.xml.get_object('message_textview')
618 619 620 621 622 623 624 625 626
        self.message_buffer = message_textview.get_buffer()
        self.message_buffer.connect('changed', self.on_message_buffer_changed)
        if not msg:
            msg = ''
        msg = helpers.from_one_line(msg)
        self.message_buffer.set_text(msg)

        # have an empty string selectable, so user can clear msg
        self.preset_messages_dict = {'': ['', '', '', '', '', '']}
627
        for msg_name in app.config.get_per('statusmsg'):
628 629 630 631 632
            if msg_name.startswith('_last_'):
                continue
            opts = []
            for opt in ['message', 'activity', 'subactivity', 'activity_text',
                                    'mood', 'mood_text']:
633
                opts.append(app.config.get_per('statusmsg', msg_name, opt))
634 635 636 637
            opts[0] = helpers.from_one_line(opts[0])
            self.preset_messages_dict[msg_name] = opts
        sorted_keys_list = helpers.get_sorted_keys(self.preset_messages_dict)

638
        self.message_liststore = Gtk.ListStore(str) # msg_name
639
        self.message_combobox = self.xml.get_object('message_combobox')
640
        self.message_combobox.set_model(self.message_liststore)
641
        cellrenderertext = Gtk.CellRendererText()
Dicson's avatar
Dicson committed
642
        self.message_combobox.pack_start(cellrenderertext, True)
643 644 645 646 647 648 649 650 651
        self.message_combobox.add_attribute(cellrenderertext, 'text', 0)
        for msg_name in sorted_keys_list:
            self.message_liststore.append((msg_name,))

        if show_pep:
            self.draw_activity()
            self.draw_mood()
        else:
            # remove acvtivity / mood lines
652 653 654 655 656 657 658 659 660 661
            self.xml.get_object('activity_label').set_no_show_all(True)
            self.xml.get_object('activity_button').set_no_show_all(True)
            self.xml.get_object('mood_label').set_no_show_all(True)
            self.xml.get_object('mood_button').set_no_show_all(True)
            self.xml.get_object('activity_label').hide()
            self.xml.get_object('activity_button').hide()
            self.xml.get_object('mood_label').hide()
            self.xml.get_object('mood_button').hide()

        self.xml.connect_signals(self)
662 663
        self.run_timeout()
        self.dialog.connect('response', self.on_dialog_response)
664
        self.dialog.set_position(Gtk.WindowPosition.CENTER_ON_PARENT)
665 666 667 668 669 670
        self.dialog.show_all()

    def draw_activity(self):
        """
        Set activity button
        """
671 672
        img = self.xml.get_object('activity_image')
        label = self.xml.get_object('activity_button_label')
673
        if 'activity' in self.pep_dict and self.pep_dict['activity'] in \
674
           ACTIVITIES:
675
            if 'subactivity' in self.pep_dict and self.pep_dict['subactivity'] \
676
            in ACTIVITIES[self.pep_dict['activity']]:
677
                img.set_from_pixbuf(gtkgui_helpers.load_activity_icon(
678 679
                    self.pep_dict['activity'], self.pep_dict['subactivity']).\
                        get_pixbuf())
680 681
            else:
                img.set_from_pixbuf(gtkgui_helpers.load_activity_icon(
682
                    self.pep_dict['activity']).get_pixbuf())
683 684 685 686 687 688 689 690 691 692 693 694
            if self.pep_dict['activity_text']:
                label.set_text(self.pep_dict['activity_text'])
            else:
                label.set_text('')
        else:
            img.set_from_pixbuf(None)
            label.set_text('')

    def draw_mood(self):
        """
        Set mood button
        """
695 696
        img = self.xml.get_object('mood_image')
        label = self.xml.get_object('mood_button_label')
697
        if 'mood' in self.pep_dict and self.pep_dict['mood'] in MOODS:
698
            img.set_from_pixbuf(gtkgui_helpers.load_mood_icon(
699
                self.pep_dict['mood']).get_pixbuf())
700 701 702 703 704 705 706 707 708 709 710
            if self.pep_dict['mood_text']:
                label.set_text(self.pep_dict['mood_text'])
            else:
                label.set_text('')
        else:
            img.set_from_pixbuf(None)
            label.set_text('')

    def on_timeout(self):
        # Prevent GUI freeze when the combobox menu is opened on close
        self.message_combobox.popdown()
711
        self.dialog.response(Gtk.ResponseType.OK)
712 713

    def on_dialog_response(self, dialog, response):
714
        if response == Gtk.ResponseType.OK:
715
            beg, end = self.message_buffer.get_bounds()
716
            message = self.message_buffer.get_text(beg, end, True).strip()
717 718 719
            message = helpers.remove_invalid_xml_chars(message)
            msg = helpers.to_one_line(message)
            if self.show:
720
                app.config.set_per('statusmsg', '_last_' + self.show,
Dicson's avatar
Dicson committed
721
                    'message', msg)
722
                if self.show_pep:
723
                    app.config.set_per('statusmsg', '_last_' + self.show,
Dicson's avatar
Dicson committed
724
                        'activity', self.pep_dict['activity'])
725
                    app.config.set_per('statusmsg', '_last_' + self.show,
Dicson's avatar
Dicson committed
726
                        'subactivity', self.pep_dict['subactivity'])
727
                    app.config.set_per('statusmsg', '_last_' + self.show,
Dicson's avatar
Dicson committed
728
                        'activity_text', self.pep_dict['activity_text'])
729
                    app.config.set_per('statusmsg', '_last_' + self.show,
Dicson's avatar
Dicson committed
730
                        'mood', self.pep_dict['mood'])
731
                    app.config.set_per('statusmsg', '_last_' + self.show,
Dicson's avatar
Dicson committed
732
                        'mood_text', self.pep_dict['mood_text'])
733 734 735 736 737 738 739 740 741 742 743
        else:
            message = None # user pressed Cancel button or X wm button
        self.dialog.destroy()
        self.on_response(message, self.pep_dict)

    def on_message_combobox_changed(self, widget):
        self.countdown_enabled = False
        model = widget.get_model()
        active = widget.get_active()
        if active < 0:
            return None
744
        name = model[active][0]
745 746 747 748 749 750 751 752 753 754 755
        self.message_buffer.set_text(self.preset_messages_dict[name][0])
        self.pep_dict['activity'] = self.preset_messages_dict[name][1]
        self.pep_dict['subactivity'] = self.preset_messages_dict[name][2]
        self.pep_dict['activity_text'] = self.preset_messages_dict[name][3]
        self.pep_dict['mood'] = self.preset_messages_dict[name][4]
        self.pep_dict['mood_text'] = self.preset_messages_dict[name][5]
        self.draw_activity()
        self.draw_mood()

    def on_change_status_message_dialog_key_press_event(self, widget, event):
        self.countdown_enabled = False
756 757 758 759
        if event.keyval == Gdk.KEY_Return or \
           event.keyval == Gdk.KEY_KP_Enter: # catch CTRL+ENTER
            if (event.get_state() & Gdk.ModifierType.CONTROL_MASK):
                self.dialog.response(Gtk.ResponseType.OK)
760 761 762 763 764 765 766 767
                # Stop the event
                return True

    def on_message_buffer_changed(self, widget):
        self.countdown_enabled = False
        self.toggle_sensitiviy_of_save_as_preset()

    def toggle_sensitiviy_of_save_as_preset(self):
768
        btn = self.xml.get_object('save_as_preset_button')
769 770 771 772 773 774 775 776 777
        if self.message_buffer.get_char_count() == 0:
            btn.set_sensitive(False)
        else:
            btn.set_sensitive(True)

    def on_save_as_preset_button_clicked(self, widget):
        self.countdown_enabled = False
        start_iter, finish_iter = self.message_buffer.get_bounds()
        status_message_to_save_as_preset = self.message_buffer.get_text(
778
                start_iter, finish_iter, True)
779
        def on_ok(msg_name):
780
            msg_text = status_message_to_save_as_preset
781 782
            msg_text_1l = helpers.to_one_line(msg_text)
            if not msg_name: # msg_name was ''
783
                msg_name = msg_text_1l
784 785

            def on_ok2():
Dicson's avatar
Dicson committed
786 787 788 789 790
                self.preset_messages_dict[msg_name] = [
                    msg_text, self.pep_dict.get('activity'),
                    self.pep_dict.get('subactivity'),
                    self.pep_dict.get('activity_text'),
                    self.pep_dict.get('mood'), self.pep_dict.get('mood_text')]
791
                app.config.set_per('statusmsg', msg_name, 'message',
Dicson's avatar
Dicson committed
792
                    msg_text_1l)
793
                app.config.set_per('statusmsg', msg_name, 'activity',
Dicson's avatar
Dicson committed
794
                    self.pep_dict.get('activity'))
795
                app.config.set_per('statusmsg', msg_name, 'subactivity',
Dicson's avatar
Dicson committed
796
                    self.pep_dict.get('subactivity'))
797
                app.config.set_per('statusmsg', msg_name, 'activity_text',
Dicson's avatar
Dicson committed
798
                    self.pep_dict.get('activity_text'))
799
                app.config.set_per('statusmsg', msg_name, 'mood',
Dicson's avatar
Dicson committed
800
                    self.pep_dict.get('mood'))
801
                app.config.set_per('statusmsg', msg_name, 'mood_text',
Dicson's avatar
Dicson committed
802
                    self.pep_dict.get('mood_text'))
803 804
            if msg_name in self.preset_messages_dict:
                ConfirmationDialog(_('Overwrite Status Message?'),
Dicson's avatar
Dicson committed
805
                    _('This name is already used. Do you want to overwrite this '
806
                    'status message?'), on_response_ok=on_ok2, transient_for=self.dialog)
807
                return
808
            app.config.add_per('statusmsg', msg_name)
809 810 811 812 813
            on_ok2()
            iter_ = self.message_liststore.append((msg_name,))
            # select in combobox the one we just saved
            self.message_combobox.set_active_iter(iter_)
        InputDialog(_('Save as Preset Status Message'),
Dicson's avatar
Dicson committed
814 815
            _('Please type a name for this status message'), is_modal=False,
            ok_handler=on_ok)
816 817 818 819 820 821 822 823 824

    def on_activity_button_clicked(self, widget):
        self.countdown_enabled = False
        def on_response(activity, subactivity, text):
            self.pep_dict['activity'] = activity or ''
            self.pep_dict['subactivity'] = subactivity or ''
            self.pep_dict['activity_text'] = text
            self.draw_activity()
        ChangeActivityDialog(on_response, self.pep_dict['activity'],
Dicson's avatar
Dicson committed
825
            self.pep_dict['subactivity'], self.pep_dict['activity_text'])
826 827 828 829 830 831 832 833 834

    def on_mood_button_clicked(self, widget):
        self.countdown_enabled = False
        def on_response(mood, text):
            self.pep_dict['mood'] = mood or ''
            self.pep_dict['mood_text'] = text
            self.draw_mood()
        ChangeMoodDialog(on_response, self.pep_dict['mood'],
                                         self.pep_dict['mood_text'])
835

836

837 838
class SubscriptionRequestWindow(Gtk.ApplicationWindow):
    def __init__(self, jid, text, account, user_nick=None):
839
        Gtk.ApplicationWindow.__init__(self)
840
        self.set_name('SubscriptionRequest')
841 842 843
        self.set_application(app.app)
        self.set_show_menubar(False)
        self.set_resizable(False)
844 845
        self.set_position(Gtk.WindowPosition.CENTER)
        self.set_title(_('Subscription Request'))
846

847 848 849
        xml = gtkgui_helpers.get_gtk_builder('subscription_request_window.ui')
        self.add(xml.get_object('subscription_box'))
        self.jid = jid
850
        self.account = account
851 852 853 854 855 856 857
        self.user_nick = user_nick
        if len(app.connections) >= 2:
            prompt_text = \
                _('Subscription request for account %(account)s from %(jid)s')\
                % {'account': account, 'jid': self.jid}
        else:
            prompt_text = _('Subscription request from %s') % self.jid
858

859 860
        from_label = xml.get_object('from_label')
        from_label.set_text(prompt_text)
861

862 863
        textview = xml.get_object('message_textview')
        textview.get_buffer().set_text(text)
864

865 866
        self.set_default(xml.get_object('authorize_button'))
        xml.connect_signals(self)
867
        self.show_all()
868

869 870 871 872 873 874 875
    def on_subscription_request_window_destroy(self, widget):
        """
        Close window
        """
        if self.jid in app.interface.instances[self.account]['sub_request']:
            # remove us from open windows
            del app.interface.instances[self.account]['sub_request'][self.jid]
876

877 878
    def on_close_button_clicked(self, widget):
        self.destroy()
879

880
    def on_authorize_button_clicked(self, widget):
881
        """
882
        Accept the request
883
        """
884
        app.connections[self.account].get_module('Presence').subscribed(self.jid)
885
        self.destroy()
886 887 888
        contact = app.contacts.get_contact(self.account, self.jid)
        if not contact or _('Not in Roster') in contact.groups:
            AddNewContactWindow(self.account, self.jid, self.user_nick)
889

890
    def on_contact_info_activate(self, widget):
891
        """
892
        Ask vcard
893
        """
894 895
        if self.jid in app.interface.instances[self.account]['infos']:
            app.interface.instances[self.account]['infos'][self.jid].window.present()
896
        else:
897 898 899 900 901 902
            contact = app.contacts.create_contact(jid=self.jid, account=self.account)
            app.interface.instances[self.account]['infos'][self.jid] = \
                     vcard.VcardWindow(contact, self.account)
            # Remove jabber page
            app.interface.instances[self.account]['infos'][self.jid].xml.\
                     get_object('information_notebook').remove_page(0)
903

904 905 906 907 908
    def on_start_chat_activate(self, widget):
        """
        Open chat
        """
        app.interface.new_chat_from_jid(self.account, self.jid)
909

910 911 912 913
    def on_deny_button_clicked(self, widget):
        """
        Refuse the request
        """
914
        app.connections[self.account].get_module('Presence').unsubscribed(self.jid)
915 916 917
        contact = app.contacts.get_contact(self.account, self.jid)
        if contact and _('Not in Roster') in contact.get_shown_groups():
            app.interface.roster.remove_contact(self.jid, self.account)
918
        self.destroy()
919

920 921 922 923 924 925 926
class SynchroniseSelectAccountDialog:
    def __init__(self, account):
        # 'account' can be None if we are about to create our first one
        if not account or app.connections[account].connected < 2:
            ErrorDialog(_('You are not connected to the server'),
                _('Without a connection, you can not synchronise your contacts.'))
            raise GajimGeneralException('You are not connected to the server')
927
        self.account = account
928 929 930 931 932 933 934 935 936 937 938 939 940
        self.xml = gtkgui_helpers.get_gtk_builder('synchronise_select_account_dialog.ui')
        self.dialog = self.xml.get_object('synchronise_select_account_dialog')
        self.dialog.set_transient_for(app.interface.instances['accounts'])
        self.accounts_treeview = self.xml.get_object('accounts_treeview')
        model = Gtk.ListStore(str, str, bool)
        self.accounts_treeview.set_model(model)
        # columns
        renderer = Gtk.CellRendererText()
        self.accounts_treeview.insert_column_with_attributes(-1, _('Name'),
            renderer, text=0)
        renderer = Gtk.CellRendererText()
        self.accounts_treeview.insert_column_with_attributes(-1, _('Server'),
            renderer, text=1)
941

942 943 944
        self.xml.connect_signals(self)
        self.init_accounts()
        self.dialog.show_all()
945

946 947 948 949 950 951 952 953 954
    def on_accounts_window_key_press_event(self, widget, event):
        if event.keyval == Gdk.KEY_Escape:
            self.window.destroy()

    def init_accounts(self):
        """
        Initialize listStore with existing accounts
        """
        model = self.accounts_treeview.get_model()
955
        model.clear()
956 957 958 959 960 961 962
        for remote_account in app.connections:
            if remote_account == self.account:
                # Do not show the account we're sync'ing
                continue
            iter_ = model.append()
            model.set(iter_, 0, remote_account, 1,
                app.get_hostname_from_account(remote_account))
963

964 965
    def on_cancel_button_clicked(self, widget):
        self.dialog.destroy()
966

967 968 969 970 971 972 973 974 975 976 977
    def on_ok_button_clicked(self, widget):
        sel = self.accounts_treeview.get_selection()
        (model, iter_) = sel.get_selected()
        if not iter_:
            return
        remote_account = model.get_value(iter_, 0)

        if app.connections[remote_account].connected < 2:
            ErrorDialog(_('This account is not connected to the server'),
                _('You cannot synchronize with an account unless it is connected.'))
            return
978
        else:
979 980 981 982
            try:
                SynchroniseSelectContactsDialog(self.account, remote_account)
            except GajimGeneralException:
                # if we showed ErrorDialog, there will not be dialog instance
983
                return
984
        self.dialog.destroy()
985

986 987 988
    @staticmethod
    def on_destroy(widget):
        del app.interface.instances['import_contacts']
989

990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
class SynchroniseSelectContactsDialog:
    def __init__(self, account, remote_account):
        self.local_account = account
        self.remote_account = remote_account
        self.xml = gtkgui_helpers.get_gtk_builder(
            'synchronise_select_contacts_dialog.ui')
        self.dialog = self.xml.get_object('synchronise_select_contacts_dialog')
        self.contacts_treeview = self.xml.get_object('contacts_treeview')
        model = Gtk.ListStore(bool, str)
        self.contacts_treeview.set_model(model)
        # columns
        renderer1 = Gtk.CellRendererToggle()
        renderer1.set_property('activatable', True)
        renderer1.connect('toggled', self.toggled_callback)
        self.contacts_treeview.insert_column_with_attributes(-1,
            _('Synchronise'), renderer1, active=0)
        renderer2 = Gtk.CellRendererText()
        self.contacts_treeview.insert_column_with_attributes(-1, _('Name'),
            renderer2, text=1)
1009

1010 1011 1012
        self.xml.connect_signals(self)
        self.init_contacts()
        self.dialog.show_all()
1013

1014 1015 1016 1017
    def toggled_callback(self, cell, path):
        model = self.contacts_treeview.get_model()
        iter_ = model.get_iter(path)
        model[iter_][0] = not cell.get_active()
1018

1019 1020 1021
    def on_contacts_window_key_press_event(self, widget, event):
        if event.keyval == Gdk.KEY_Escape:
            self.window.destroy()
1022

1023 1024 1025 1026 1027 1028
    def init_contacts(self):
        """
        Initialize listStore with existing accounts
        """
        model = self.contacts_treeview.get_model()
        model.clear()
1029

1030 1031
        # recover local contacts
        local_jid_list = app.contacts.get_contacts_jid_list(self.local_account)
1032

1033 1034 1035 1036 1037 1038
        remote_jid_list = app.contacts.get_contacts_jid_list(
                self.remote_account)
        for remote_jid in remote_jid_list:
            if remote_jid not in local_jid_list:
                iter_ = model.append()
                model.set(iter_, 0, True, 1, remote_jid)
nkour's avatar
nkour committed
1039

1040 1041
    def on_cancel_button_clicked(self, widget):
        self.dialog.destroy()
1042

1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
    def on_ok_button_clicked(self, widget):
        model = self.contacts_treeview.get_model()
        iter_ = model.get_iter_first()
        while iter_:
            if model[iter_][0]:
                # it is selected
                remote_jid = model[iter_][1]
                message = 'I\'m synchronizing my contacts from my %s account, could you please add this address to your contact list?' % \
                    app.get_hostname_from_account(self.remote_account)
                remote_contact = app.contacts.get_first_contact_from_jid(
                        self.remote_account, remote_jid)
                # keep same groups and same nickname
                app.interface.roster.req_sub(self, remote_jid, message,
                    self.local_account, groups = remote_contact.groups,
                    nickname = remote_contact.name, auto_auth = True)
            iter_ = model.iter_next(iter_)
        self.dialog.destroy()
1060

Philipp Hörist's avatar
Philipp Hörist committed
1061

1062 1063
#Action that can be done with an incoming list of contacts
TRANSLATED_ACTION = {'add': _('add'), 'modify': _('modify'),
1064
    'remove': _('remove')}
1065
class RosterItemExchangeWindow:
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
    """
    Windows used when someone send you a exchange contact suggestion
    """

    def __init__(self, account, action, exchange_list, jid_from,
                    message_body=None):
        self.account = account
        self.action = action
        self.exchange_list = exchange_list
        self.message_body = message_body
        self.jid_from = jid_from

        show_dialog = False

1080
        # Connect to gtk builder
Dicson's avatar
Dicson committed
1081 1082
        self.xml = gtkgui_helpers.get_gtk_builder(
            'roster_item_exchange_window.ui')
1083
        self.window = self.xml.get_object('roster_item_exchange_window')
1084 1085 1086 1087

        # Add Widgets.
        for widget_to_add in ['accept_button_label', 'type_label',
        'body_scrolledwindow', 'body_textview', 'items_list_treeview']:
1088
            self.__dict__[widget_to_add] = self.xml.get_object(widget_to_add)
1089 1090 1091 1092

        # Set labels
        # self.action can be 'add', 'modify' or 'remove'
        self.type_label.set_label(
Dicson's avatar
Dicson committed
1093 1094 1095
            _('<b>%(jid)s</b> would like you to <b>%(action)s</b> some contacts '
            'in your roster.') % {'jid': jid_from,
            'action': TRANSLATED_ACTION[self.action]})
1096 1097 1098 1099 1100 1101
        if message_body:
            buffer_ = self.body_textview.get_buffer()
            buffer_.set_text(self.message_body)
        else:
            self.body_scrolledwindow.hide()
        # Treeview
1102
        model = Gtk.ListStore(bool, str, str, str, str)
1103 1104
        self.items_list_treeview.set_model(model)
        # columns
1105
        renderer1 = Gtk.CellRendererToggle()
1106 1107 1108 1109 1110 1111 1112 1113 1114
        renderer1.set_property('activatable', True)
        renderer1.connect('toggled', self.toggled_callback)
        if self.action == 'add':
            title = _('Add')
        elif self.action == 'modify':
            title = _('Modify')
        elif self.action == 'delete':
            title = _('Delete')
        self.items_list_treeview.insert_column_with_attributes(-1, title,
Dicson's avatar
Dicson committed
1115
            renderer1, active=0)
1116
        renderer2 = Gtk.CellRendererText()
1117
        self.items_list_treeview.insert_column_with_attributes(-1, _('JID'),
Dicson's avatar
Dicson committed
1118
            renderer2, text=1)
1119
        renderer3 = Gtk.CellRendererText()
1120
        self.items_list_treeview.insert_column_with_attributes(-1, _('Name'),
Dicson's avatar
Dicson committed
1121
            renderer3, text=2)
1122
        renderer4 = Gtk.CellRendererText()
1123
        self.items_list_treeview.insert_column_with_attributes(-1, _('Groups'),
Dicson's avatar
Dicson committed
1124
            renderer4, text=3)
1125 1126 1127 1128 1129 1130 1131 1132 1133

        # Init contacts
        model = self.items_list_treeview.get_model()
        model.clear()

        if action == 'add':
            for jid in self.exchange_list:
                groups = ''
                is_in_roster = True
1134
                contact = app.contacts.get_contact_with_highest_priority(
Dicson's avatar
Dicson committed
1135
                    self.account, jid)
1136
                if not contact or _('Not in Roster') in contact.groups:
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
                    is_in_roster = False
                name = self.exchange_list[jid][0]
                num_list = len(self.exchange_list[jid][1])
                current = 0
                for group in self.exchange_list[jid][1]:
                    current += 1
                    if contact and not group in contact.groups:
                        is_in_roster = False
                    if current == num_list:
                        groups = groups + group
                    else:
                        groups = groups + group + ', '
                if not is_in_roster:
                    show_dialog = True
                    iter_ = model.append()
                    model.set(iter_, 0, True, 1, jid, 2, name, 3, groups)

            # Change label for accept_button to action name instead of 'OK'.
            self.accept_button_label.set_label(_('Add'))
        elif action == 'modify':
            for jid in self.exchange_list:
                groups = ''
                is_in_roster = True
                is_right = True
1161
                contact = app.contacts.get_contact_with_highest_priority(
Dicson's avatar
Dicson committed
1162
                    self.account, jid)
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
                name = self.exchange_list[jid][0]
                if not contact:
                    is_in_roster = False
                    is_right = False
                else:
                    if name != contact.name:
                        is_right = False
                num_list = len(self.exchange_list[jid][1])
                current = 0
                for group in self.exchange_list[jid][1]:
                    current += 1
                    if contact and not group in contact.groups:
                        is_right = False
                    if current == num_list:
                        groups = groups + group
                    else:
                        groups = groups + group + ', '
                if not is_right and is_in_roster:
                    show_dialog = True
                    iter_ = model.append()
                    model.set(iter_, 0, True, 1, jid, 2, name, 3, groups)

            # Change label for accept_button to action name instead of 'OK'.
            self.accept_button_label.set_label(_('Modify'))
        elif action == 'delete':
            for jid in self.exchange_list:
                groups = ''
                is_in_roster = True
1191
                contact = app.contacts.get_contact_with_highest_priority(
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
                        self.account, jid)
                name = self.exchange_list[jid][0]
                if not contact:
                    is_in_roster = False
                num_list = len(self.exchange_list[jid][1])
                current = 0
                for group in self.exchange_list[jid][1]:
                    current += 1
                    if current == num_list:
                        groups = groups + group
                    else:
                        groups = groups + group + ', '
                if is_in_roster:
                    show_dialog = True
                    iter_ = model.append()
                    model.set(iter_, 0, True, 1, jid, 2, name, 3, groups)

            # Change label for accept_button to action name instead of 'OK'.
            self.accept_button_label.set_label(_('Delete'))

        if show_dialog:
            self.window.show_all()
1214
            self.xml.connect_signals(self)
1215 1216 1217 1218 1219 1220 1221 1222

    def toggled_callback(self, cell, path):
        model = self.items_list_treeview.get_model()
        iter_ = model.get_iter(path)
        model[iter_][0] = not cell.get_active()

    def on_accept_button_clicked(self, widget):
        model = self.items_list_treeview.get_model()
1223
        iter_ = model.get_iter_first()
1224 1225 1226 1227 1228 1229
        if self.action == 'add':
            a = 0
            while iter_:
                if model[iter_][0]:
                    a+=1
                    # it is selected
1230
                    #remote_jid = model[iter_][1]
1231 1232 1233 1234 1235 1236
                    message = _('%s suggested me to add you in my roster.'
                            % self.jid_from)
                    # keep same groups and same nickname
                    groups = model[iter_][3].split(', ')
                    if groups == ['']:
                        groups = []
1237
                    jid = model[iter_][1]
1238
                    if app.jid_is_transport(self.jid_from):
1239 1240
                        con = app.connections[self.account]
                        con.get_module('Presence').automatically_added.append(jid)
1241
                    app.interface.roster.req_sub(self, jid, message,
1242 1243 1244
                            self.account, groups=groups, nickname=model[iter_][2],
                            auto_auth=True)
                iter_ = model.iter_next(iter_)
1245 1246
            InformationDialog(i18n.ngettext('Added %d contact',
                'Added %d contacts', a, a, a))
1247 1248 1249 1250 1251 1252
        elif self.action == 'modify':
            a = 0
            while iter_:
                if model[iter_][0]:
                    a+=1
                    # it is selected
1253
                    jid = model[iter_][1]
1254 1255 1256 1257
                    # keep same groups and same nickname
                    groups = model[iter_][3].split(', ')
                    if groups == ['']:
                        groups = []
1258
                    for u in app.contacts.get_contact(self.account, jid):
1259
                        u.name = model[iter_][2]
1260
                    app.connections[self.account].update_contact(jid,
1261
                            model[iter_][2], groups)
Dicson's avatar