Commit dfdeb65e authored by Philipp Hörist's avatar Philipp Hörist
Browse files

New AccountsWindow

parent 41b977b9
This diff is collapsed.
......@@ -9,6 +9,7 @@
<property name="default_width">350</property>
<property name="default_height">300</property>
<property name="type_hint">dialog</property>
<signal name="destroy" handler="on_destroy" swapped="no"/>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox7">
<property name="visible">True</property>
......
......@@ -30,14 +30,34 @@ #ServerInfoGrid > list > row { padding: 10px 20px 10px 10px; }
#ServerInfoGrid > list > label { padding:10px; color: @insensitive_fg_color; font-weight: bold; }
#ServerInfoGrid > list > row.activatable:active { box-shadow: none; }
/* Generic Options Dialog */
#OptionsDialog list > row { border-bottom: 1px solid; border-color: @theme_unfocused_bg_color; }
#OptionsDialog list > row:last-child { border-bottom: 0px}
#OptionsDialog list > row { padding: 10px; }
#OptionsDialog list > row.activatable:active { box-shadow: none; }
/* OptionsBox */
#OptionsBox > row { border-bottom: 1px solid; border-color: @theme_unfocused_bg_color; }
#OptionsBox > row:last-child { border-bottom: 0px}
#OptionsBox > row.activatable:active { box-shadow: none; }
#OptionsBox > row { padding: 10px 20px 10px 10px; }
#OptionsBox > row:not(.activatable) label { color: @insensitive_fg_color }
/* GenericOption */
#SubDescription { color: @insensitive_fg_color;}
#GenericOptionBox { margin-left: 30px; }
#GenericOptionBox > label { padding-right: 3px; }
/* Generic Popover Menu with Buttons */
.PopoverButtonListbox { padding-left: 0px; padding-right: 0px; }
.PopoverButtonListbox > list { margin-top: 10px; margin-bottom: 10px; }
.PopoverButtonListbox > list > row { padding: 10px 20px 10px 20px; }
.PopoverButtonListbox > list > row.activatable:active { box-shadow: none; background-color: @theme_selected_bg_color }
/* Accounts Window */
#AccountsWindow > box { padding:30px 30px 30px 30px;}
#AccountsWindow scrolledwindow {border: none;}
#AccountsWindow list {border: 1px solid; border-color: @borders;}
#AccountsWindow > box actionbar box {border: none;}
#AccountNameEntry:disabled { font-size: 16px;
font-weight: bold;
border: none;
background-color: @theme_unfocused_bg_color;
color: @theme_text_color; }
This diff is collapsed.
......@@ -25,10 +25,12 @@
from gi.repository import Gtk
import sys
import os
from gajim import config
from gajim import dialogs
from gajim import features_window
from gajim import shortcuts_window
from gajim import accounts_window
import gajim.plugins.gui
from gajim import history_window
from gajim import disco
......@@ -57,10 +59,10 @@ def on_plugins(self, action, param):
interface.instances['plugins'] = gajim.plugins.gui.PluginsWindow()
def on_accounts(self, action, param):
if 'accounts' in interface.instances:
interface.instances['accounts'].window.present()
if 'accounts' in app.interface.instances:
app.interface.instances['accounts'].present()
else:
interface.instances['accounts'] = config.AccountsWindow()
app.interface.instances['accounts'] = accounts_window.AccountsWindow()
def on_history_manager(self, action, param):
from gajim.history_manager import HistoryManager
......@@ -131,6 +133,35 @@ def on_new_chat(self, action, param):
def on_single_message(self, action, param):
dialogs.SingleMessageWindow(param.get_string(), action='send')
def on_merge_accounts(self, action, param):
action.set_state(param)
value = param.get_boolean()
app.config.set('mergeaccounts', value)
if len(app.connections) >= 2: # Do not merge accounts if only one active
app.interface.roster.regroup = value
else:
app.interface.roster.regroup = False
app.interface.roster.setup_and_draw_roster()
def on_use_pgp_agent(self, action, param):
action.set_state(param)
app.config.set('use_gpg_agent', param.get_boolean())
def on_add_account(self, action, param):
if 'account_creation_wizard' in app.interface.instances:
app.interface.instances['account_creation_wizard'].window.present()
else:
app.interface.instances['account_creation_wizard'] = \
config.AccountCreationWizardWindow()
def on_import_contacts(self, action, param):
account = param.get_string()
if 'import_contacts' in app.interface.instances:
app.interface.instances['import_contacts'].dialog.present()
else:
app.interface.instances['import_contacts'] = \
dialogs.SynchroniseSelectAccountDialog(account)
# Advanced Actions
def on_archiving_preferences(self, action, param):
......@@ -174,6 +205,13 @@ def on_xml_console(self, action, param):
interface.instances[account]['xml_console'] = \
dialogs.XMLConsoleWindow(account)
def on_manage_proxies(self, action, param):
if 'manage_proxies' in app.interface.instances:
app.interface.instances['manage_proxies'].window.present()
else:
app.interface.instances['manage_proxies'] = \
config.ManageProxiesWindow(interface.roster.window)
# Admin Actions
def on_set_motd(self, action, param):
......
......@@ -325,6 +325,7 @@ class Config:
__options_per_key = {
'accounts': ({
'name': [ opt_str, '', '', True ],
'account_label': [ opt_str, '', '', False ],
'hostname': [ opt_str, '', '', True ],
'anonymous_auth': [ opt_bool, False ],
'client_cert': [ opt_str, '', '', True ],
......
from enum import IntEnum, unique
from collections import namedtuple
Option = namedtuple('Option', 'kind label type value name callback data desc enabledif props')
Option.__new__.__defaults__ = (None,) * len(Option._fields)
@unique
class OptionKind(IntEnum):
ENTRY = 0
SWITCH = 1
SPIN = 2
ACTION = 3
LOGIN = 4
DIALOG = 5
CALLBACK = 6
PROXY = 7
HOSTNAME = 8
PRIORITY = 9
FILECHOOSER = 10
CHANGEPASSWORD = 11
GPG = 12
@unique
class OptionType(IntEnum):
ACCOUNT_CONFIG = 0
CONFIG = 1
BOOL = 2
ACTION = 3
DIALOG = 4
THANKS = u"""\
Alexander Futász
Alexander V. Butenko
......
......@@ -3158,10 +3158,10 @@ def _on_remove_success(self, res):
app.app.remove_account_actions(self.account)
gui_menu_builder.build_accounts_menu()
if 'accounts' in app.interface.instances:
app.interface.instances['accounts'].init_accounts()
app.interface.instances['accounts'].init_account()
app.interface.instances['accounts'].remove_account(self.account)
self.window.destroy()
#---------- ManageBookmarksWindow class -------------#
class ManageBookmarksWindow:
def __init__(self):
......@@ -3733,7 +3733,7 @@ def on_forward_button_clicked(self, widget):
self.account = server
i = 1
while self.account in app.connections:
while self.account in app.config.get_per('accounts'):
self.account = server + str(i)
i += 1
......@@ -3754,7 +3754,7 @@ def on_forward_button_clicked(self, widget):
return
self.account = server
i = 1
while self.account in app.connections:
while self.account in app.config.get_per('accounts'):
self.account = server + str(i)
i += 1
......@@ -3982,7 +3982,7 @@ def _nec_acc_is_not_ok(self, obj):
def on_advanced_button_clicked(self, widget):
if 'accounts' in app.interface.instances:
app.interface.instances['accounts'].window.present()
app.interface.instances['accounts'].present()
else:
app.interface.instances['accounts'] = AccountsWindow()
app.interface.instances['accounts'].select_account(self.account)
......@@ -4083,9 +4083,11 @@ def create_vars(self, config):
app.gajim_optional_features[self.account] = []
app.caps_hash[self.account] = ''
helpers.update_optional_features(self.account)
# action must be added before account window is updated
app.app.add_account_actions(self.account)
# refresh accounts window
if 'accounts' in app.interface.instances:
app.interface.instances['accounts'].init_accounts()
app.interface.instances['accounts'].add_account(self.account)
# refresh roster
if len(app.connections) >= 2:
# Do not merge accounts if only one exists
......@@ -4093,7 +4095,6 @@ def create_vars(self, config):
else:
app.interface.roster.regroup = False
app.interface.roster.setup_and_draw_roster()
app.app.add_account_actions(self.account)
gui_menu_builder.build_accounts_menu()
class ManagePEPServicesWindow:
......
......@@ -48,6 +48,8 @@
from gajim.common import pep
from gajim.common import ged
from gajim.common import const
from gajim.options_dialog import OptionsDialog
from gajim.common.const import Option, OptionKind, OptionType
try:
from gajim import gtkspell
......@@ -2675,7 +2677,7 @@ def __init__(self, account):
self.account = account
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'].window)
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)
......@@ -2731,6 +2733,10 @@ def on_ok_button_clicked(self, widget):
return
self.dialog.destroy()
@staticmethod
def on_destroy(widget):
del app.interface.instances['import_contacts']
class SynchroniseSelectContactsDialog:
def __init__(self, account, remote_account):
self.local_account = account
......@@ -3323,6 +3329,8 @@ def __init__(self, account):
setattr(self, obj, self.builder.get_object(obj))
self.set_titlebar(self.headerbar)
jid = app.get_jid_from_account(account)
self.headerbar.set_subtitle(jid)
self.set_default_size(600, 600)
self.add(self.box)
......@@ -3434,26 +3442,30 @@ def on_input(self, button, *args):
def on_filter_options(self, *args):
options = [
SwitchOption('Presence', self.presence,
self.on_option,
'presence'),
SwitchOption('Message', self.message,
self.on_option,
'message'),
SwitchOption('Iq', self.iq,
self.on_option,
'iq'),
SwitchOption('Stream\nManagement', self.stream,
self.on_option,
'stream'),
SwitchOption('In', self.incoming,
self.on_option,
'incoming'),
SwitchOption('Out', self.outgoing,
self.on_option,
'outgoing')]
OptionsDialog(self, 'Filter', options)
Option(OptionKind.SWITCH, 'Presence',
OptionType.BOOL, self.presence,
callback=self.on_option, data='presence'),
Option(OptionKind.SWITCH, 'Message',
OptionType.BOOL, self.message,
callback=self.on_option, data='message'),
Option(OptionKind.SWITCH, 'Iq', OptionType.BOOL, self.iq,
callback=self.on_option, data='iq'),
Option(OptionKind.SWITCH, 'Stream\nManagement',
OptionType.BOOL, self.stream,
callback=self.on_option, data='stream'),
Option(OptionKind.SWITCH, 'In', OptionType.BOOL, self.incoming,
callback=self.on_option, data='incoming'),
Option(OptionKind.SWITCH, 'Out', OptionType.BOOL, self.outgoing,
callback=self.on_option, data='outgoing'),
]
OptionsDialog(self, 'Filter', Gtk.DialogFlags.DESTROY_WITH_PARENT,
options, self.account)
def on_clear(self, *args):
buffer_ = self.textview.get_buffer().set_text('')
......@@ -3468,13 +3480,12 @@ def on_destroy(self, *args):
def on_enable(self, switch, param):
self.enabled = switch.get_active()
def on_option(self, switch, param, *user_data):
kind = user_data[0]
setattr(self, kind, switch.get_active())
value = not switch.get_active()
def on_option(self, value, data):
setattr(self, data, value)
value = not value
table = self.textview.get_buffer().get_tag_table()
tag = table.lookup(kind)
if kind in ('incoming', 'outgoing'):
tag = table.lookup(data)
if data in ('incoming', 'outgoing'):
if value:
tag.set_priority(table.get_size() - 1)
else:
......@@ -3522,58 +3533,6 @@ def print_stanza(self, stanza, kind):
if at_the_end:
GLib.idle_add(gtkgui_helpers.scroll_to_end, self.scrolled)
class OptionsDialog(Gtk.Dialog):
def __init__(self, parent, title, options):
Gtk.Dialog.__init__(self, title, parent,
Gtk.DialogFlags.DESTROY_WITH_PARENT)
self.set_name('OptionsDialog')
self.set_resizable(False)
self.set_default_size(250, -1)
self.remove(self.get_content_area())
listbox = Gtk.ListBox()
listbox.set_hexpand(True)
listbox.set_selection_mode(Gtk.SelectionMode.NONE)
for option in options:
listbox.add(option)
self.add(listbox)
self.show_all()
listbox.connect('row-activated', self.on_row_activated)
def on_row_activated(self, listbox, row):
row.get_child().set_switch_state()
class SwitchOption(Gtk.Grid):
def __init__(self, label, state, callback, *user_data):
Gtk.Grid.__init__(self)
self.set_column_spacing(6)
label = Gtk.Label(label=label)
label.set_hexpand(True)
label.set_halign(Gtk.Align.START)
self.switch = Gtk.Switch()
self.switch.set_active(state)
self.switch.connect("notify::active", callback, *user_data)
self.switch.set_hexpand(True)
self.switch.set_halign(Gtk.Align.END)
self.switch.set_valign(Gtk.Align.CENTER)
self.add(label)
self.add(self.switch)
self.show_all()
def set_switch_state(self):
state = self.switch.get_active()
self.switch.set_active(not state)
#Action that can be done with an incoming list of contacts
TRANSLATED_ACTION = {'add': _('add'), 'modify': _('modify'),
'remove': _('remove')}
......@@ -4580,7 +4539,7 @@ def on_ok(widget, callback):
FileChooserDialog.__init__(self,
title_text=_('Choose Client Cert #PCKS12'),
transient_for=app.interface.instances['accounts'].window,
transient_for=app.interface.instances['accounts'],
action=Gtk.FileChooserAction.OPEN,
buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK),
......
......@@ -319,6 +319,7 @@ def warn_with_traceback(message, category, filename, lineno,
def add_actions(self):
''' Build Application Actions '''
from gajim.app_actions import AppActions
from gajim.common import app
action = AppActions(self)
self.account_actions = [
......@@ -339,12 +340,30 @@ def add_actions(self):
('-update-motd', action.on_update_motd, 'online', 's'),
('-delete-motd', action.on_delete_motd, 'online', 's'),
('-activate-bookmark',
action.on_activate_bookmark, 'online', 'a{sv}')
action.on_activate_bookmark, 'online', 'a{sv}'),
('-import-contacts', action.on_import_contacts, 'online', 's')
]
# General Stateful Actions
act = Gio.SimpleAction.new_stateful(
'merge', None,
GLib.Variant.new_boolean(app.config.get('mergeaccounts')))
act.connect('change-state', action.on_merge_accounts)
self.add_action(act)
act = Gio.SimpleAction.new_stateful(
'agent', None,
GLib.Variant.new_boolean(app.config.get('use_gpg_agent')))
self.add_action(act)
# General Actions
self.general_actions = [
('quit', action.on_quit),
('accounts', action.on_accounts),
('add-account', action.on_add_account),
('manage-proxies', action.on_manage_proxies),
('bookmarks', action.on_manage_bookmarks),
('history-manager', action.on_history_manager),
('preferences', action.on_preferences),
......@@ -364,8 +383,7 @@ def add_actions(self):
act.connect("activate", func)
self.add_action(act)
from gajim.common import app
accounts_list = sorted(app.contacts.get_accounts())
accounts_list = sorted(app.config.get_per('accounts'))
if not accounts_list:
return
if len(accounts_list) > 1:
......
......@@ -107,15 +107,16 @@ def add_image_to_button(button, icon_name):
button.set_image(img)
def get_image_button(icon_name, tooltip, toggle=False):
icon = get_icon_pixmap(icon_name)
image = Gtk.Image()
image.set_from_pixbuf(icon)
if toggle:
button = Gtk.ToggleButton()
icon = get_icon_pixmap(icon_name)
image = Gtk.Image()
image.set_from_pixbuf(icon)
button.set_image(image)
else:
button = Gtk.Button()
button = Gtk.Button.new_from_icon_name(
icon_name, Gtk.IconSize.MENU)
button.set_tooltip_text(_(tooltip))
button.set_image(image)
return button
GUI_DIR = os.path.join(app.DATA_DIR, 'gui')
......
from gi.repository import Gtk, GLib, Gdk, GObject
from gajim.common import app
from gajim.common import passwords
from gajim import gtkgui_helpers
from gajim.common.const import OptionKind, OptionType
from gajim.common.exceptions import GajimGeneralException
from gajim import dialogs
class OptionsDialog(Gtk.ApplicationWindow):
def __init__(self, parent, title, flags, options, account):
Gtk.ApplicationWindow.__init__(self)
self.set_application(app.app)
self.set_show_menubar(False)
self.set_title(title)
self.set_transient_for(parent)
self.set_resizable(False)
self.set_default_size(250, -1)
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
self.account = account
if flags == Gtk.DialogFlags.MODAL:
self.set_modal(True)
elif flags == Gtk.DialogFlags.DESTROY_WITH_PARENT:
self.set_destroy_with_parent(True)
self.listbox = OptionsBox(account)
self.listbox.set_hexpand(True)
self.listbox.set_selection_mode(Gtk.SelectionMode.NONE)
for option in options:
self.listbox.add_option(option)
self.listbox.update_states()
self.add(self.listbox)
self.show_all()
self.listbox.connect('row-activated', self.on_row_activated)
@staticmethod
def on_row_activated(listbox, row):
row.get_child().on_row_activated()
def get_option(self, name):
return self.listbox.get_option(name)
class OptionsBox(Gtk.ListBox):
def __init__(self, account):
Gtk.ListBox.__init__(self)
self.set_name('OptionsBox')
self.account = account
self.named_options = {}
self.map = {
OptionKind.SWITCH: SwitchOption,
OptionKind.SPIN: SpinOption,
OptionKind.DIALOG: DialogOption,
OptionKind.ENTRY: EntryOption,
OptionKind.ACTION: ActionOption,
OptionKind.LOGIN: LoginOption,
OptionKind.FILECHOOSER: FileChooserOption,
OptionKind.CALLBACK: CallbackOption,
OptionKind.PROXY: ProxyComboOption,
OptionKind.PRIORITY: PriorityOption,
OptionKind.HOSTNAME: CutstomHostnameOption,
OptionKind.CHANGEPASSWORD: ChangePasswordOption,
OptionKind.GPG: GPGOption,
}
def add_option(self, option):
if option.props is not None:
listitem = self.map[option.kind](
self.account, *option[1:-1], **option.props)
else:
listitem = self.map[option.kind](self.account, *option[1:-1])
listitem.connect('notify::option-value', self.on_option_changed)
if option.name is not None:
self.named_options[option.name] = listitem
self.add(listitem)
def get_option(self, name):
return self.named_options[name]
def update_states(self):
values = []
values.append((None, None))
for row in self.get_children():
name = row.get_child().name
if name is None:
continue
value = row.get_child().get_property('option-value')
values.append((name, value))
for name, value in values:
for row in self.get_children():
row.get_child().set_activatable(name, value)
def on_option_changed(self, widget, *args):
value = widget.get_property('option-value')
for row in self.get_children():
row.get_child().set_activatable(widget.name, value)
class GenericOption(Gtk.Grid):
def __init__(self, account, label, type_, value,
name, callback, data, desc, enabledif):
Gtk.Grid.__init__(self)
self.set_column_spacing(12)
self.set_size_request(-1, 25)
self.callback = callback
self.type_ = type_
self.value = value
self.data = data
self.label = label
self.account = account
self.name = name
self.enabledif = enabledif
self.option_value = self.get_value()
description_box = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL, spacing=0)
description_box.set_valign(Gtk.Align.CENTER)
optiontext = Gtk.Label(label=label)
optiontext.set_hexpand(True)