Daniel Brötzmann pushed to branch master at gajim / gajim
Commits: 25af863a by wurstsalat at 2022-10-03T20:09:06+02:00 feat: PEPConfig: Add PEP item view
- - - - -
6 changed files:
- gajim/common/modules/pubsub.py - − gajim/data/gui/manage_pep_services_window.ui - + gajim/data/gui/pep_config.ui - gajim/gtk/builder.pyi - gajim/gtk/pep_config.py - pyrightconfig.json
Changes:
===================================== gajim/common/modules/pubsub.py ===================================== @@ -43,6 +43,7 @@ class PubSub(BaseModule): 'set_node_configuration', 'get_node_configuration', 'get_access_model', + 'request_items', ]
def __init__(self, con: types.Client) -> None:
===================================== gajim/data/gui/manage_pep_services_window.ui deleted ===================================== @@ -1,91 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.22.1 --> -<interface> - <requires lib="gtk+" version="3.20"/> - <object class="GtkBox" id="manage_pep_services"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="border_width">18</property> - <property name="orientation">vertical</property> - <property name="spacing">6</property> - <child> - <object class="GtkScrolledWindow"> - <property name="width_request">350</property> - <property name="height_request">250</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="shadow_type">in</property> - <child> - <object class="GtkTreeView" id="services_treeview"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child internal-child="selection"> - <object class="GtkTreeSelection" id="treeview-selection1"/> - </child> - </object> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">end</property> - <property name="spacing">12</property> - <child> - <object class="GtkButton" id="configure_button"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="tooltip_text" translatable="yes">Configure</property> - <property name="halign">center</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="_on_configure_button_clicked" swapped="no"/> - <child> - <object class="GtkImage" id="image1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="icon_name">preferences-system-symbolic</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="delete_button"> - <property name="label">_Delete</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="_on_delete_button_clicked" swapped="no"/> - <style> - <class name="destructive-action"/> - </style> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">2</property> - </packing> - </child> - </object> -</interface>
===================================== gajim/data/gui/pep_config.ui ===================================== @@ -0,0 +1,288 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.40.0 --> +<interface> + <requires lib="gtk+" version="3.20"/> + <requires lib="gtksourceview" version="4.0"/> + <object class="GtkStack" id="stack"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="transition-type">slide-left-right</property> + <child> + <object class="GtkBox" id="overview_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="border-width">18</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <object class="GtkScrolledWindow"> + <property name="width-request">350</property> + <property name="height-request">250</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="shadow-type">in</property> + <child> + <object class="GtkTreeView" id="services_treeview"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"/> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="spacing">12</property> + <child> + <object class="GtkButton" id="show_content_button"> + <property name="label" translatable="yes">Show Content</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="halign">center</property> + <signal name="clicked" handler="_on_show_content_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="delete_button"> + <property name="label">_Delete</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="use-underline">True</property> + <signal name="clicked" handler="_on_delete_button_clicked" swapped="no"/> + <style> + <class name="destructive-action"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="configure_button"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="tooltip-text" translatable="yes">Configure</property> + <property name="halign">center</property> + <property name="use-underline">True</property> + <signal name="clicked" handler="_on_configure_button_clicked" swapped="no"/> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">preferences-system-symbolic</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="name">overview</property> + </packing> + </child> + <child> + <object class="GtkBox" id="items_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="border-width">18</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="items_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="wrap">True</property> + <property name="wrap-mode">word-char</property> + <property name="max-width-chars">40</property> + <style> + <class name="bold16"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="shadow-type">in</property> + <child> + <object class="GtkViewport"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkSourceView" id="items_view"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="editable">False</property> + <property name="left-margin">3</property> + <property name="right-margin">3</property> + <property name="top-margin">3</property> + <property name="bottom-margin">3</property> + <property name="monospace">True</property> + <property name="show-line-numbers">True</property> + <property name="tab-width">4</property> + <property name="highlight-current-line">True</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton"> + <property name="label" translatable="yes">Back</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="halign">start</property> + <signal name="clicked" handler="_on_back_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="name">items</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox" id="config_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="border-width">18</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child> + <object class="GtkLabel" id="form_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="wrap">True</property> + <property name="wrap-mode">word-char</property> + <property name="max-width-chars">30</property> + <style> + <class name="bold16"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkButton"> + <property name="label" translatable="yes">Back</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="halign">start</property> + <signal name="clicked" handler="_on_back_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton"> + <property name="label" translatable="yes">Save</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="halign">end</property> + <signal name="clicked" handler="_on_save_config_clicked" swapped="no"/> + <style> + <class name="suggested-action"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkBox" id="form_box"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + <packing> + <property name="name">config</property> + <property name="position">2</property> + </packing> + </child> + </object> +</interface>
===================================== gajim/gtk/builder.pyi ===================================== @@ -550,15 +550,6 @@ class MamPreferencesBuilder(Builder): save_button: Gtk.Button
-class ManagePepServicesWindowBuilder(Builder): - manage_pep_services: Gtk.Box - services_treeview: Gtk.TreeView - treeview_selection1: Gtk.TreeSelection - configure_button: Gtk.Button - image1: Gtk.Image - delete_button: Gtk.Button - - class ManageProxiesBuilder(Builder): liststore1: Gtk.ListStore box: Gtk.Box @@ -609,6 +600,21 @@ class PasswordDialogBuilder(Builder): keyring_hint: Gtk.Label
+class PepConfigBuilder(Builder): + stack: Gtk.Stack + overview_box: Gtk.Box + services_treeview: Gtk.TreeView + show_content_button: Gtk.Button + delete_button: Gtk.Button + configure_button: Gtk.Button + items_box: Gtk.Box + items_label: Gtk.Label + items_view: GtkSource.View + config_box: Gtk.Box + form_label: Gtk.Label + form_box: Gtk.Box + + class PluginsBuilder(Builder): liststore: Gtk.ListStore plugins_box: Gtk.Box @@ -678,9 +684,9 @@ class PreviewBuilder(Builder): image_button: Gtk.Button link_button: Gtk.LinkButton button_box: Gtk.Box + download_button: Gtk.Button save_as_button: Gtk.Button open_folder_button: Gtk.Button - download_button: Gtk.Button file_name: Gtk.Label file_size: Gtk.Label info_message: Gtk.Label @@ -1004,8 +1010,6 @@ def get_builder(file_name: Literal['main.ui'], widgets: list[str] = ...) -> Main @overload def get_builder(file_name: Literal['mam_preferences.ui'], widgets: list[str] = ...) -> MamPreferencesBuilder: ... @overload -def get_builder(file_name: Literal['manage_pep_services_window.ui'], widgets: list[str] = ...) -> ManagePepServicesWindowBuilder: ... -@overload def get_builder(file_name: Literal['manage_proxies.ui'], widgets: list[str] = ...) -> ManageProxiesBuilder: ... @overload def get_builder(file_name: Literal['manage_sounds.ui'], widgets: list[str] = ...) -> ManageSoundsBuilder: ... @@ -1014,6 +1018,8 @@ def get_builder(file_name: Literal['message_actions_box.ui'], widgets: list[str] @overload def get_builder(file_name: Literal['password_dialog.ui'], widgets: list[str] = ...) -> PasswordDialogBuilder: ... @overload +def get_builder(file_name: Literal['pep_config.ui'], widgets: list[str] = ...) -> PepConfigBuilder: ... +@overload def get_builder(file_name: Literal['plugins.ui'], widgets: list[str] = ...) -> PluginsBuilder: ... @overload def get_builder(file_name: Literal['popup_notification_window.ui'], widgets: list[str] = ...) -> PopupNotificationWindowBuilder: ...
===================================== gajim/gtk/pep_config.py ===================================== @@ -12,13 +12,18 @@ # You should have received a copy of the GNU General Public License # along with Gajim. If not, see http://www.gnu.org/licenses/.
+from __future__ import annotations + +from typing import Optional + import logging
from gi.repository import Gdk from gi.repository import Gtk +from gi.repository import GtkSource
from nbxmpp.errors import StanzaError -from nbxmpp.modules.dataforms import SimpleDataForm +from nbxmpp.modules import dataforms from nbxmpp.simplexml import Node from nbxmpp.task import Task
@@ -28,11 +33,10 @@
from .dialogs import ErrorDialog from .dialogs import WarningDialog -from .dataform import DataFormDialog +from .dataform import DataFormWidget from .builder import get_builder
- -log = logging.getLogger('gajim.gui.pep') +log = logging.getLogger('gajim.gui.pep_config')
class PEPConfig(Gtk.ApplicationWindow): @@ -42,17 +46,29 @@ def __init__(self, account: str) -> None: self.set_position(Gtk.WindowPosition.CENTER) self.set_show_menubar(False) self.set_name('PEPConfig') - self.set_default_size(500, 350) + self.set_default_size(700, 800) self.set_resizable(True) self.set_transient_for(app.window)
- self._ui = get_builder('manage_pep_services_window.ui') - self.add(self._ui.manage_pep_services) + self._ui = get_builder('pep_config.ui') + self.add(self._ui.stack)
self.account = account self.set_title(_('PEP Service Configuration (%s)') % self.account) self._client = app.get_client(account)
+ self._result_node: Optional[Node] = None + self._dataform_widget: Optional[DataFormWidget] = None + + source_manager = GtkSource.LanguageManager.get_default() + lang = source_manager.get_language('xml') + self._ui.items_view.get_buffer().set_language(lang) + + self._style_scheme_manager = GtkSource.StyleSchemeManager.get_default() + style_scheme = self._get_style_scheme() + if style_scheme is not None: + self._ui.items_view.get_buffer().set_style_scheme(style_scheme) + self._init_services() self._ui.services_treeview.get_selection().connect( 'changed', self._on_services_selection_changed) @@ -61,6 +77,15 @@ def __init__(self, account: str) -> None: self.connect('key-press-event', self._on_key_press) self._ui.connect_signals(self)
+ def _get_style_scheme(self) -> Optional[GtkSource.StyleScheme]: + if app.css_config.prefer_dark: + style_scheme = self._style_scheme_manager.get_scheme( + 'solarized-dark') + else: + style_scheme = self._style_scheme_manager.get_scheme( + 'solarized-light') + return style_scheme + def _on_key_press(self, _widget: Gtk.Widget, event: Gdk.EventKey) -> None: if event.keyval == Gdk.KEY_Escape: self.destroy() @@ -68,7 +93,9 @@ def _on_key_press(self, _widget: Gtk.Widget, event: Gdk.EventKey) -> None: def _on_services_selection_changed(self, _selection: Gtk.TreeSelection ) -> None: + self._ui.configure_button.set_sensitive(True) + self._ui.show_content_button.set_sensitive(True) self._ui.delete_button.set_sensitive(True)
def _init_services(self): @@ -101,6 +128,20 @@ def _items_received(self, task: Task) -> None: if item.jid == jid and item.node is not None: self.treestore.append([item.node])
+ def _on_delete_button_clicked(self, _widget: Gtk.Button) -> None: + selection = self._ui.services_treeview.get_selection() + if not selection: + return + model, iter_ = selection.get_selected() + assert isinstance(model, Gtk.ListStore) + assert iter_ + node = model[iter_][0] + + self._client.get_module('PubSub').delete( + node, + callback=self._on_node_delete, + user_data=node) + def _on_node_delete(self, task: Task) -> None: node = task.get_user_data()
@@ -123,7 +164,7 @@ def _on_node_delete(self, task: Task) -> None: break iter_ = model.iter_next(iter_)
- def _on_delete_button_clicked(self, _widget: Gtk.Button) -> None: + def _on_configure_button_clicked(self, _button: Gtk.Button) -> None: selection = self._ui.services_treeview.get_selection() if not selection: return @@ -132,12 +173,44 @@ def _on_delete_button_clicked(self, _widget: Gtk.Button) -> None: assert iter_ node = model[iter_][0]
- self._client.get_module('PubSub').delete( + self._client.get_module('PubSub').get_node_configuration( node, - callback=self._on_node_delete, - user_data=node) + callback=self._on_pep_config_received)
- def _on_configure_button_clicked(self, _button: Gtk.Button) -> None: + def _on_pep_config_received(self, task: Task) -> None: + try: + result = task.finish() + except Exception: + log.exception('Failed to retrieve config') + return + + if self._dataform_widget is not None: + self._ui.form_box.remove(self._dataform_widget) + self._dataform_widget.destroy() + + self._result_node = result.node + + form = dataforms.extend_form(node=result.form) + self._dataform_widget = DataFormWidget(form) + self._dataform_widget.set_propagate_natural_height(True) + self._dataform_widget.show_all() + self._ui.form_box.add(self._dataform_widget) + self._ui.form_label.set_text(result.node) + + self._ui.stack.set_visible_child_name('config') + + def _on_save_config_clicked(self, _button: Gtk.Button) -> None: + assert self._dataform_widget is not None + form = self._dataform_widget.get_submit_form() + self._client.get_module('PubSub').set_node_configuration( + self._result_node, form) + + self._ui.stack.set_visible_child_name('overview') + + def _on_back_clicked(self, _button: Gtk.Button) -> None: + self._ui.stack.set_visible_child_name('overview') + + def _on_show_content_clicked(self, _button: Gtk.Button) -> None: selection = self._ui.services_treeview.get_selection() if not selection: return @@ -146,25 +219,30 @@ def _on_configure_button_clicked(self, _button: Gtk.Button) -> None: assert iter_ node = model[iter_][0]
- self._client.get_module('PubSub').get_node_configuration( + self._client.get_module('PubSub').request_items( node, - callback=self._nec_pep_config_received) - - def _on_config_submit(self, - form: SimpleDataForm, - node: Node - ) -> None: - self._client.get_module('PubSub').set_node_configuration(node, form) + callback=self._on_pep_items_received, + user_data=node)
- def _nec_pep_config_received(self, task: Task) -> None: + def _on_pep_items_received(self, task: Task) -> None: try: result = task.finish() except Exception: - log.exception('Failed to retrieve config') + log.exception('Failed to retrieve items') return
- DataFormDialog(_('Configure %s') % result.node, - self, - result.form, - result.node, - self._on_config_submit) + parent_node = task.get_user_data() + self._ui.items_label.set_text(str(parent_node)) + + buf = self._ui.items_view.get_buffer() + start, end = buf.get_bounds() + buf.delete(start, end) + + for node in result: + # pylint: disable=unnecessary-dunder-call + node = node.__str__(fancy=True) + + buf = self._ui.items_view.get_buffer() + buf.insert_at_cursor(str(node)) + + self._ui.stack.set_visible_child_name('items')
===================================== pyrightconfig.json ===================================== @@ -105,7 +105,6 @@ "gajim/gtk/notification.py", "gajim/gtk/notification_manager.py", "gajim/gtk/password_dialog.py", - "gajim/gtk/pep_config.py", "gajim/gtk/plugins.py", "gajim/gtk/preview.py", "gajim/gtk/preview_audio.py",
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/commit/25af863a278059c5abd02a0a67fb2ed4c...