# This file is part of Gajim. # # Gajim 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 3 only. # # Gajim 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. # # You should have received a copy of the GNU General Public License # along with Gajim. If not, see . from gi.repository import Gdk from gi.repository import Gtk from gi.repository import Gio from gi.repository import GObject from .util import get_builder from .util import EventHelper class Assistant(Gtk.ApplicationWindow, EventHelper): __gsignals__ = dict( button_clicked=( GObject.SignalFlags.RUN_LAST | GObject.SignalFlags.ACTION, None, (str, ) ), page_changed=( GObject.SignalFlags.RUN_LAST | GObject.SignalFlags.ACTION, None, (str, ) )) def __init__(self, transient_for=None, width=550, height=400, transition_duration=200): Gtk.ApplicationWindow.__init__(self) EventHelper.__init__(self) self.set_application(Gio.Application.get_default()) self.set_position(Gtk.WindowPosition.CENTER) self.set_show_menubar(False) self.set_name('Assistant') self.set_default_size(width, height) self.set_resizable(True) self.set_transient_for(transient_for) self.set_type_hint(Gdk.WindowTypeHint.DIALOG) self._pages = {} self._buttons = {} self._button_visible_func = None self._ui = get_builder('assistant.ui') self.add(self._ui.main_grid) self._ui.stack.set_transition_duration(transition_duration) self.connect('key-press-event', self._on_key_press_event) self.connect('destroy', self.__on_destroy) self._ui.connect_signals(self) def show_all(self): page_name = self._ui.stack.get_visible_child_name() self.emit('page-changed', page_name) Gtk.ApplicationWindow.show_all(self) def _on_key_press_event(self, _widget, event): if event.keyval == Gdk.KEY_Escape: self.destroy() def _update_page_complete(self, *args): page_widget = self._ui.stack.get_visible_child() for button, complete in self._buttons.values(): if complete: button.set_sensitive(page_widget.complete) def update_title(self): self.set_title(self._ui.stack.get_visible_child().title) def _hide_buttons(self): for button, _ in self._buttons.values(): button.hide() def _set_buttons_visible(self): page_name = self._ui.stack.get_visible_child_name() if self._button_visible_func is None: buttons = self.get_page(page_name).get_visible_buttons() if buttons is not None: if len(buttons) == 1: default = buttons[0] else: default = self.get_page(page_name).get_default_button() self.set_default_button(default) else: buttons = self._button_visible_func(self, page_name) self._update_page_complete() if buttons is None: return for button_name in buttons: button, _ = self._buttons[button_name] button.show() def set_button_visible_func(self, func): self._button_visible_func = func def set_default_button(self, button_name): button, _ = self._buttons[button_name] button.grab_default() def add_button(self, name, label, css_class=None, complete=False): button = Gtk.Button(label=label, can_default=True, no_show_all=True) button.connect('clicked', self.__on_button_clicked) if css_class is not None: button.get_style_context().add_class(css_class) self._buttons[name] = (button, complete) self._ui.action_area.pack_end(button, False, False, 0) def add_pages(self, pages): self._pages = pages for name, widget in pages.items(): widget.connect('update-page-complete', self._update_page_complete) self._ui.stack.add_named(widget, name) def add_default_page(self, name): if name == 'success': page = SuccessPage() elif name == 'error': page = ErrorPage() elif name == 'progress': page = ProgressPage() else: raise ValueError('Unknown page: %s' % name) self._pages[name] = page self._ui.stack.add_named(page, name) return page def get_current_page(self): return self._ui.stack.get_visible_child_name() def show_page(self, name, transition=Gtk.StackTransitionType.NONE): if self._ui.stack.get_visible_child_name() == name: return self._hide_buttons() self._ui.stack.set_visible_child_full(name, transition) def get_page(self, name): return self._pages[name] def _on_visible_child_name(self, stack, _param): if stack.get_visible_child_name() is None: # Happens for some reason when adding the first page return self.update_title() self._set_buttons_visible() self.emit('page-changed', stack.get_visible_child_name()) def __on_button_clicked(self, button): for button_name, button_data in self._buttons.items(): button_ = button_data[0] if button_ == button: self.emit('button-clicked', button_name) return def __on_destroy(self, *args): self._pages.clear() self._buttons.clear() class Page(Gtk.Box): __gsignals__: dict = { 'update-page-complete': (GObject.SignalFlags.RUN_LAST, None, ()), } def __init__(self): Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) self.set_spacing(18) self.set_valign(Gtk.Align.CENTER) self.title = '' self.complete = True def get_visible_buttons(self): return None def get_default_button(self): return None def update_page_complete(self): self.emit('update-page-complete') class DefaultPage(Page): def __init__(self, icon_name, icon_css_class): Page.__init__(self) self._heading = Gtk.Label() self._heading.get_style_context().add_class('large-header') self._heading.set_max_width_chars(30) self._heading.set_line_wrap(True) self._heading.set_halign(Gtk.Align.CENTER) self._heading.set_justify(Gtk.Justification.CENTER) icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.DIALOG) icon.get_style_context().add_class(icon_css_class) self._label = Gtk.Label() self._label.set_max_width_chars(50) self._label.set_line_wrap(True) self._label.set_halign(Gtk.Align.CENTER) self._label.set_justify(Gtk.Justification.CENTER) self.pack_start(self._heading, False, True, 0) self.pack_start(icon, False, True, 0) self.pack_start(self._label, False, True, 0) self.show_all() def set_heading(self, heading): self._heading.set_text(heading) def set_text(self, text): self._label.set_text(text) def set_title(self, title): self.title = title class ErrorPage(DefaultPage): def __init__(self): DefaultPage.__init__(self, icon_name='dialog-error-symbolic', icon_css_class='error-color') class SuccessPage(DefaultPage): def __init__(self): DefaultPage.__init__(self, icon_name='object-select-symbolic', icon_css_class='success-color') class ProgressPage(Page): def __init__(self): Page.__init__(self) self._label = Gtk.Label() self._label.set_max_width_chars(50) self._label.set_line_wrap(True) self._label.set_halign(Gtk.Align.CENTER) self._label.set_justify(Gtk.Justification.CENTER) spinner = Gtk.Spinner() spinner.start() self.pack_start(spinner, True, True, 0) self.pack_start(self._label, False, True, 0) self.show_all() def set_text(self, text): self._label.set_text(text) def set_title(self, title): self.title = title