Philipp Hörist pushed to branch master at gajim / gajim
Commits: 8146f01d by Philipp Hörist at 2019-08-09T13:49:11Z PrivateChatControl: Access config value with correct key
- - - - - 89d1e307 by Philipp Hörist at 2019-08-09T14:09:49Z PrivateChatControl: Make room_name a property
- - - - - b291d573 by Philipp Hörist at 2019-08-10T15:28:42Z Groupchat: Display groupchat names in banner
Name is determined in the following way:
1. Bookmark name 2. Disco info muc#roomconfig_roomname value 3. localpart of the JID
- - - - - f091cd0a by Philipp Hörist at 2019-08-10T17:11:51Z Rework Manage Bookmark dialog
- Make it single account - Use a Treeview - Move it to advanced sub menu
Manage Bookmarks should serve in the future as dialog for advanced users. During normal usage of Gajim there should be no need anymore to access this dialog.
- - - - -
13 changed files:
- gajim/app_actions.py - gajim/application.py - gajim/common/contacts.py - gajim/common/modules/bookmarks.py - gajim/data/gui/application_menu.ui - + gajim/data/gui/bookmarks.ui - − gajim/data/gui/manage_bookmarks_window.ui - gajim/data/style/gajim.css - gajim/groupchat_control.py - gajim/gtk/bookmarks.py - gajim/gui_menu_builder.py - gajim/privatechat_control.py - gajim/roster_window.py
Changes:
===================================== gajim/app_actions.py ===================================== @@ -36,7 +36,7 @@ from gajim.gtk.add_contact import AddNewContactWindow from gajim.gtk.single_message import SingleMessageWindow from gajim.gtk.about import AboutDialog from gajim.gtk.privacy_list import PrivacyListsWindow -from gajim.gtk.bookmarks import ManageBookmarksWindow +from gajim.gtk.bookmarks import Bookmarks from gajim.gtk.features import FeaturesDialog from gajim.gtk.account_wizard import AccountCreationWizard from gajim.gtk.history import HistoryWindow @@ -87,8 +87,13 @@ def on_history_manager(action, param): HistoryManager()
-def on_manage_bookmarks(action, param): - ManageBookmarksWindow() +def on_bookmarks(action, param): + account = param.get_string() + window = app.get_app_window(Bookmarks, account=account) + if window is None: + window = Bookmarks(account) + else: + window.present()
def on_quit(action, param):
===================================== gajim/application.py ===================================== @@ -428,7 +428,6 @@ class GajimApplication(Gtk.Application): ('quit', app_actions.on_quit), ('add-account', app_actions.on_add_account), ('manage-proxies', app_actions.on_manage_proxies), - ('bookmarks', app_actions.on_manage_bookmarks), ('history-manager', app_actions.on_history_manager), ('preferences', app_actions.on_preferences), ('plugins', app_actions.on_plugins), @@ -502,6 +501,7 @@ class GajimApplication(Gtk.Application): ]
return [ + ('-bookmarks', a.on_bookmarks, 'online', 's'), ('-start-single-chat', a.on_single_message, 'online', 's'), ('-start-chat', a.start_chat, 'online', 'as'), ('-add-contact', a.on_add_contact, 'online', 'as'),
===================================== gajim/common/contacts.py ===================================== @@ -173,12 +173,28 @@ class Contact(CommonContact): return self.jid
def get_shown_name(self): + if self._is_groupchat: + return self._get_groupchat_name() if self.name: return self.name if self.contact_name: return self.contact_name return self.jid.split('@')[0]
+ def _get_groupchat_name(self): + from gajim.common import app + con = app.connections[self.account.name] + name = con.get_module('Bookmarks').get_name_from_bookmark(self.jid) + if name: + return name + + cache = caps_cache.muc_caps_cache.cache + if self.jid in cache: + name = cache[self.jid].muc_room_name + if name: + return name + return self.jid.split('@')[0] + def get_shown_groups(self): if self.is_observer(): return [_('Observers')]
===================================== gajim/common/modules/bookmarks.py ===================================== @@ -18,8 +18,6 @@ from typing import Any from typing import List from typing import Optional
-import copy - import nbxmpp from nbxmpp.protocol import JID from nbxmpp.util import is_error_result @@ -122,27 +120,6 @@ class Bookmarks(BaseModule): if bookmark.jid == jid: return bookmark
- def get_sorted_bookmarks(self, short_name=False): - # This returns a sorted by name copy of the bookmarks - sorted_bookmarks = [] - for bookmark in self._bookmarks: - bookmark_copy = copy.deepcopy(bookmark) - if not bookmark_copy.name: - # No name was given for this bookmark - # Use the first part of JID instead - name = bookmark_copy.jid.getNode() - bookmark_copy = bookmark_copy._replace(name=name) - - if short_name: - name = bookmark_copy.name - name = (name[:42] + '..') if len(name) > 42 else name - bookmark_copy = bookmark_copy._replace(name=name) - - sorted_bookmarks.append(bookmark_copy) - - sorted_bookmarks.sort(key=lambda x: x.name.lower()) - return sorted_bookmarks - def _pubsub_support(self) -> bool: return (self._con.get_module('PEP').supported and self._con.get_module('PubSub').publish_options) @@ -246,11 +223,10 @@ class Bookmarks(BaseModule): self.store_bookmarks()
def get_name_from_bookmark(self, jid: str) -> str: - fallback = jid.split('@')[0] bookmark = self.get_bookmark_from_jid(jid) if bookmark is None: - return fallback - return bookmark.name or fallback + return + return bookmark.name
def is_bookmark(self, jid: str) -> bool: return self.get_bookmark_from_jid(jid) is not None
===================================== gajim/data/gui/application_menu.ui ===================================== @@ -79,11 +79,6 @@ <attribute name="accel"><Primary>G</attribute> <attribute name="target"></attribute> </item> - <item> - <attribute name="label" translatable="yes">Bookmarks</attribute> - <attribute name="action">app.bookmarks</attribute> - <attribute name="accel"><Primary>B</attribute> - </item> <item> <attribute name="label" translatable="yes">History Manager</attribute> <attribute name="action">app.history-manager</attribute>
===================================== gajim/data/gui/bookmarks.ui ===================================== @@ -0,0 +1,235 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface> + <requires lib="gtk+" version="3.20"/> + <object class="GtkListStore" id="bookmarks_store"> + <columns> + <!-- column-name jid --> + <column type="gchararray"/> + <!-- column-name name --> + <column type="gchararray"/> + <!-- column-name nick --> + <column type="gchararray"/> + <!-- column-name password --> + <column type="gchararray"/> + <!-- column-name autojoin --> + <column type="gboolean"/> + </columns> + </object> + <object class="GtkGrid" id="bookmarks_grid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="row_spacing">6</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkButton"> + <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_add_clicked" swapped="no"/> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">list-add-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="remove_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="halign">start</property> + <signal name="clicked" handler="_on_remove_clicked" swapped="no"/> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">list-remove-symbolic</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="hscrollbar_policy">never</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="bookmarks_view"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="model">bookmarks_store</property> + <property name="search_column">0</property> + <property name="enable_grid_lines">horizontal</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"> + <signal name="changed" handler="_on_selection_changed" swapped="no"/> + </object> + </child> + <child> + <object class="GtkTreeViewColumn"> + <property name="resizable">True</property> + <property name="title" translatable="yes">XMPP Address</property> + <property name="expand">True</property> + <property name="sort_indicator">True</property> + <property name="sort_column_id">0</property> + <child> + <object class="GtkCellRendererText" id="jid"> + <property name="editable">True</property> + <property name="ellipsize">end</property> + <property name="placeholder_text">chat@conference.example.org</property> + <signal name="edited" handler="_on_address_edited" swapped="no"/> + </object> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn"> + <property name="resizable">True</property> + <property name="min_width">100</property> + <property name="title" translatable="yes">Name</property> + <property name="sort_indicator">True</property> + <property name="sort_column_id">1</property> + <child> + <object class="GtkCellRendererText" id="name"> + <property name="editable">True</property> + <property name="ellipsize">end</property> + <signal name="edited" handler="_on_name_edited" swapped="no"/> + </object> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn"> + <property name="resizable">True</property> + <property name="title" translatable="yes">Nickname</property> + <property name="sort_indicator">True</property> + <property name="sort_column_id">2</property> + <child> + <object class="GtkCellRendererText" id="nick"> + <property name="editable">True</property> + <property name="ellipsize">end</property> + <signal name="edited" handler="_on_nick_edited" swapped="no"/> + </object> + <attributes> + <attribute name="text">2</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn"> + <property name="resizable">True</property> + <property name="title" translatable="yes">Password</property> + <property name="sort_indicator">True</property> + <property name="sort_column_id">3</property> + <child> + <object class="GtkCellRendererText" id="password"> + <property name="editable">True</property> + <property name="ellipsize">end</property> + <signal name="edited" handler="_on_password_edited" swapped="no"/> + </object> + <attributes> + <attribute name="text">3</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn"> + <property name="sizing">fixed</property> + <property name="title" translatable="yes">Autojoin</property> + <property name="alignment">0.5</property> + <property name="sort_indicator">True</property> + <property name="sort_column_id">4</property> + <child> + <object class="GtkCellRendererToggle" id="autojoin"> + <signal name="toggled" handler="_on_autojoin_toggled" swapped="no"/> + </object> + <attributes> + <attribute name="active">4</attribute> + </attributes> + </child> + </object> + </child> + <style> + <class name="gajim-treeview"/> + </style> + </object> + </child> + <style> + <class name="gajim-scrolled"/> + </style> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + <property name="width">2</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">_Apply</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="halign">end</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="_on_apply_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + <style> + <class name="padding-18"/> + </style> + </object> +</interface>
===================================== gajim/data/gui/manage_bookmarks_window.ui deleted ===================================== @@ -1,404 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.22.1 --> -<interface> - <requires lib="gtk+" version="3.20"/> - <object class="GtkListStore" id="liststore1"> - <columns> - <!-- column-name item --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkWindow" id="manage_bookmarks_window"> - <property name="can_focus">False</property> - <property name="title" translatable="yes">Group Chat Bookmarks</property> - <property name="default_width">550</property> - <property name="default_height">300</property> - <property name="type_hint">dialog</property> - <signal name="key-press-event" handler="on_key_press_event" swapped="no"/> - <child type="titlebar"> - <placeholder/> - </child> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="border_width">18</property> - <property name="spacing">18</property> - <child> - <object class="GtkBox"> - <property name="width_request">220</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkScrolledWindow"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="shadow_type">in</property> - <child> - <object class="GtkTreeView" id="bookmarks_treeview"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="headers_visible">False</property> - <child internal-child="selection"> - <object class="GtkTreeSelection" id="treeview-selection1"/> - </child> - <style> - <class name="space"/> - </style> - </object> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkToolbar"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="show_arrow">False</property> - <property name="icon_size">1</property> - <child> - <object class="GtkToolButton" id="add_bookmark_button"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="tooltip_text" translatable="yes">Add Bookmark</property> - <property name="use_underline">True</property> - <property name="icon_name">list-add-symbolic</property> - <signal name="clicked" handler="on_add_bookmark_button_clicked" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> - </packing> - </child> - <child> - <object class="GtkToolButton" id="remove_bookmark_button"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="tooltip_text" translatable="yes">Remove Bookmark</property> - <property name="use_underline">True</property> - <property name="icon_name">list-remove-symbolic</property> - <signal name="clicked" handler="on_remove_bookmark_button_clicked" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="homogeneous">False</property> - </packing> - </child> - <style> - <class name="inline-toolbar"/> - </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">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="orientation">vertical</property> - <property name="spacing">18</property> - <child> - <object class="GtkGrid"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="row_spacing">6</property> - <property name="column_spacing">12</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">end</property> - <property name="label" translatable="yes">N_ame</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">title_entry</property> - <property name="xalign">0</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="title_entry"> - <property name="width_request">230</property> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="tooltip_text" translatable="yes">Bookmark Name</property> - <property name="hexpand">True</property> - <property name="activates_default">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> - </packing> - </child> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">end</property> - <property name="margin_top">12</property> - <property name="label" translatable="yes">_Server</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">server_entry</property> - <property name="xalign">0</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">1</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="server_entry"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="margin_top">12</property> - <property name="activates_default">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">1</property> - </packing> - </child> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">end</property> - <property name="margin_top">12</property> - <property name="label" translatable="yes">_Nickname</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">nick_entry</property> - <property name="xalign">0</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">4</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="nick_entry"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="margin_top">12</property> - <property name="activates_default">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">4</property> - </packing> - </child> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">end</property> - <property name="label" translatable="yes">Roo_m</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">room_entry</property> - <property name="xalign">0</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">2</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="room_entry"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="activates_default">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">2</property> - </packing> - </child> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">end</property> - <property name="label" translatable="yes">_Password</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">pass_entry</property> - <property name="xalign">0</property> - <style> - <class name="dim-label"/> - </style> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">3</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="pass_entry"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="visibility">False</property> - <property name="activates_default">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">3</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkListBox" id="settings_box"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="selection_mode">none</property> - <child> - <object class="GtkListBoxRow"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="tooltip_text" translatable="yes">Join chat when connected</property> - <property name="valign">center</property> - <property name="spacing">12</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">_Join Automatically</property> - <property name="use_underline">True</property> - <property name="mnemonic_widget">autojoin_checkbutton</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="autojoin_checkbutton"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="halign">end</property> - <signal name="state-set" handler="on_autojoin_checkbutton_toggled" swapped="no"/> - </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> - </child> - </object> - </child> - <style> - <class name="settings"/> - </style> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkButtonBox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="valign">end</property> - <property name="vexpand">True</property> - <property name="spacing">12</property> - <property name="layout_style">end</property> - <child> - <object class="GtkButton" id="cancel_button"> - <property name="label">Cancel</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="receives_default">False</property> - <signal name="clicked" handler="on_cancel_button_clicked" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="ok_button"> - <property name="label">OK</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <property name="has_default">True</property> - <property name="receives_default">False</property> - <signal name="clicked" handler="on_ok_button_clicked" swapped="no"/> - <style> - <class name="suggested-action"/> - </style> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</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> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> -</interface>
===================================== gajim/data/style/gajim.css ===================================== @@ -227,6 +227,7 @@ list.settings > row > box { .margin-top12 { margin-top: 12px; } .margin-12 { margin: 12px; } .margin-18 { margin: 18px; } +.padding-18 { margin: 18px; }
/* Treeview */ treeview.space { padding: 6px; } @@ -266,5 +267,9 @@ button.flat.link { padding: 0; border: 0; } .search-treeview { padding: 5px; } .search-scrolled { border: 1px solid; border-color:@unfocused_borders; }
+.gajim-treeview { padding: 4px; } +.gajim-treeview check { padding: 0px; } +.gajim-scrolled { border: 1px solid; border-color:@unfocused_borders; } +
#GroupchatJoin > box {padding: 18px; } \ No newline at end of file
===================================== gajim/groupchat_control.py ===================================== @@ -110,7 +110,6 @@ class GroupchatControl(ChatControlBase): def __init__(self, parent_win, contact, muc_data, acct, is_continued=False): ChatControlBase.__init__(self, self.TYPE_ID, parent_win, 'groupchat_control', contact, acct) - self.force_non_minimizable = False self.is_continued = is_continued self.is_anonymous = True @@ -170,11 +169,6 @@ class GroupchatControl(ChatControlBase): self.room_jid = self.contact.jid self._muc_data = muc_data
- bm_module = app.connections[self.account].get_module('Bookmarks') - self.name = bm_module.get_name_from_bookmark(self.room_jid) - - self.contact.name = self.name - self.widget_set_visible(self.xml.get_object('banner_eventbox'), app.config.get('hide_groupchat_banner'))
@@ -370,6 +364,10 @@ class GroupchatControl(ChatControlBase): return '' return self._subject_data.subject
+ @property + def room_name(self): + return self.contact.get_shown_name() + def add_actions(self): super().add_actions() actions = [ @@ -998,7 +996,7 @@ class GroupchatControl(ChatControlBase): # if this is a continued conversation label_str = self.get_continued_conversation_name() else: - label_str = self.name + label_str = self.room_name label_str = GLib.markup_escape_text(label_str)
# count waiting highlighted messages @@ -1106,12 +1104,7 @@ class GroupchatControl(ChatControlBase): room jid """ self.name_label.set_ellipsize(Pango.EllipsizeMode.END) - if self.is_continued: - name = self.get_continued_conversation_name() - else: - name = self.room_jid - - self.name_label.set_text(name) + self.name_label.set_text(self.room_name)
def _nec_update_avatar(self, obj): if obj.contact.room_jid != self.room_jid: @@ -2221,7 +2214,7 @@ class GroupchatControl(ChatControlBase): _('Leave Group Chat'), _('Are you sure you want to leave this group chat?'), _('If you close this window, you will leave ' - ''%s'.') % self.name, + ''%s'.') % self.room_name, _('_Do not ask me again'), [DialogButton.make('Cancel', callback=on_cancel),
===================================== gajim/gtk/bookmarks.py ===================================== @@ -12,357 +12,148 @@ # You should have received a copy of the GNU General Public License # along with Gajim. If not, see http://www.gnu.org/licenses/.
+import logging from enum import IntEnum
from gi.repository import Gtk from gi.repository import Gdk from nbxmpp.structs import BookmarkData +from nbxmpp.protocol import validate_resourcepart
from gajim.common import app -from gajim.common import helpers +from gajim.common.helpers import validate_jid from gajim.common.i18n import _
-from gajim.gtk.dialogs import ErrorDialog from gajim.gtk.util import get_builder
-class Row(IntEnum): - ACCOUNT_JID = 0 - ROOM_NAME = 1 - ROOM_JID = 2 - AUTOJOIN = 3 - PASSWORD = 4 - NICK = 5 - LABEL = 6 - - -class ManageBookmarksWindow: - def __init__(self): - self._ui = get_builder('manage_bookmarks_window.ui') - self._ui.manage_bookmarks_window.set_transient_for( - app.interface.roster.window) - - self.ignore_events = False - - # Account-JID, RoomName, Room-JID, Autojoin, Password, Nick, Name - self.treestore = Gtk.TreeStore(str, str, str, bool, str, str, str) - self.treestore.set_sort_column_id(1, Gtk.SortType.ASCENDING) - - # Store bookmarks in treeview. - for account, account_label in app.get_enabled_accounts_with_labels( - connected_only=True, private_storage_only=True): - iter_ = self.treestore.append(None, [ - None, account, None, None, - None, None, account_label]) - - con = app.connections[account] - bookmarks = con.get_module('Bookmarks').get_sorted_bookmarks() - - for bookmark in bookmarks: - self.treestore.append(iter_, [account, - bookmark.name, - str(bookmark.jid), - bookmark.autojoin, - bookmark.password, - bookmark.nick, - bookmark.name]) - - self._ui.bookmarks_treeview.set_model(self.treestore) - self._ui.bookmarks_treeview.expand_all() - - renderer = Gtk.CellRendererText() - column = Gtk.TreeViewColumn('Bookmarks', renderer, text=Row.LABEL) - self._ui.bookmarks_treeview.append_column(column) - - self.selection = self._ui.bookmarks_treeview.get_selection() - self.selection.connect('changed', self.bookmark_selected) - - # Prepare input fields - self._ui.title_entry.connect('changed', self.on_title_entry_changed) - self._ui.nick_entry.connect('changed', self.on_nick_entry_changed) - self._ui.server_entry.connect( - 'focus-out-event', self.on_server_entry_focus_out) - self.room_entry_changed_id = self._ui.room_entry.connect( - 'changed', self.on_room_entry_changed) - self._ui.pass_entry.connect('changed', self.on_pass_entry_changed) +log = logging.getLogger('gajim.gtk.bookmarks')
- self._ui.connect_signals(self) - self._ui.manage_bookmarks_window.show_all() - # select root iter - first_iter = self.treestore.get_iter_first() - if first_iter: - self.selection.select_iter(first_iter)
- def on_key_press_event(self, widget, event): - if event.keyval == Gdk.KEY_Escape: - self._ui.manage_bookmarks_window.destroy() - - def on_add_bookmark_button_clicked(self, widget): - """ - Add a new bookmark - """ - # Get the account that is currently used - # (the parent of the currently selected item) - (model, iter_) = self.selection.get_selected() - if not iter_: # Nothing selected, do nothing - return +class Column(IntEnum): + ADDRESS = 0 + NAME = 1 + NICK = 2 + PASSWORD = 3 + AUTOJOIN = 4
- parent = model.iter_parent(iter_) - - if parent: - # We got a bookmark selected, so we add_to the parent - add_to = parent - else: - # No parent, so we got an account -> add to this. - add_to = iter_ - - account = model[add_to][1] - nick = app.nicks[account] - label = _('New Group Chat') - iter_ = self.treestore.append(add_to, [ - account, label, '@', False, '', nick, label]) - - self._ui.bookmarks_treeview.expand_row(model.get_path(add_to), True) - self._ui.bookmarks_treeview.set_cursor(model.get_path(iter_)) - - def on_remove_bookmark_button_clicked(self, widget): - """ - Remove selected bookmark - """ - (model, iter_) = self.selection.get_selected() - if not iter_: # Nothing selected - return
- if not model.iter_parent(iter_): - # Don't remove account iters - return +class Bookmarks(Gtk.ApplicationWindow): + def __init__(self, account): + Gtk.ApplicationWindow.__init__(self) + self.set_application(app.app) + self.set_position(Gtk.WindowPosition.CENTER) + self.set_show_menubar(False) + self.set_title(_('Bookmarks for %s' % app.get_account_label(account))) + self.set_default_size(700, 500)
- self.ignore_events = True - model.remove(iter_) - self.clear_fields() - self.ignore_events = False - self.bookmark_selected(self.selection) + self.account = account
- def check_valid_bookmark(self): - """ - Check if all necessary fields are entered correctly - """ - (model, iter_) = self.selection.get_selected() + self._ui = get_builder('bookmarks.ui') + self.add(self._ui.bookmarks_grid)
- if not model.iter_parent(iter_): - # Account data can't be changed - return + con = app.connections[account] + for bookmark in con.get_module('Bookmarks').bookmarks: + self._ui.bookmarks_store.append([str(bookmark.jid), + bookmark.name, + bookmark.nick, + bookmark.password, + bookmark.autojoin])
- server = self._ui.server_entry.get_text() - room = self._ui.room_entry.get_text() + self._ui.bookmarks_view.set_search_equal_func(self._search_func)
- if server == '' or room == '': - ErrorDialog( - _('This bookmark has invalid data'), - _('Please be sure to fill out server and group chat fields ' - 'or remove this bookmark.')) - return False + self._ui.connect_signals(self) + self.connect('key-press-event', self._on_key_press)
- return True + self.show_all()
- def on_ok_button_clicked(self, widget): - """ - Parse the treestore data into our new bookmarks array, then send the - new bookmarks to the server. - """ + def _on_key_press(self, _widget, event): + if event.keyval == Gdk.KEY_Escape: + self.destroy()
- (model, iter_) = self.selection.get_selected() - if iter_ and model.iter_parent(iter_): - # bookmark selected, check it - if not self.check_valid_bookmark(): - return + def _on_selection_changed(self, selection): + _, iter_ = selection.get_selected() + self._ui.remove_button.set_sensitive(iter_ is not None)
- for account in self.treestore: - acct = account[1] - con = app.connections[acct] - - bookmarks = [] - for bm in account.iterchildren(): - # create the bookmark-dict - bookmark = BookmarkData(jid=bm[Row.ROOM_JID], - name=bm[Row.ROOM_NAME], - autojoin=bm[Row.AUTOJOIN], - password=bm[Row.PASSWORD], - nick=bm[Row.NICK]) - bookmarks.append(bookmark) - con.get_module('Bookmarks').bookmarks = bookmarks - con.get_module('Bookmarks').store_bookmarks() - self._ui.manage_bookmarks_window.destroy() - - def on_cancel_button_clicked(self, widget): - self._ui.manage_bookmarks_window.destroy() - - def bookmark_selected(self, selection): - """ - Fill in the bookmark's data into the fields. - """ - (model, iter_) = selection.get_selected() - - if not iter_: - # After removing the last bookmark for one account - # this will be None, so we will just: + def _on_address_edited(self, _renderer, path, new_value): + iter_ = self._ui.bookmarks_store.get_iter(path) + if not new_value: return
- if model.iter_parent(iter_): - # make the fields sensitive - self.set_sensitive_all(True) - else: - # Top-level has no data (it's the account fields) - # clear fields & make them insensitive - self.clear_fields() - self.set_sensitive_all(False) + try: + jid = validate_jid(new_value) + except ValueError as error: + log.warning('Invalid JID: %s (%s)', error, new_value) return
- # Fill in the data for childs - self._ui.title_entry.set_text(model[iter_][Row.ROOM_NAME]) - room_jid = model[iter_][Row.ROOM_JID] - room_jid_s = room_jid.split('@') - if len(room_jid_s) == 1: - room = '' - server = room_jid - else: - (room, server) = room_jid_s - self._ui.room_entry.handler_block(self.room_entry_changed_id) - self._ui.room_entry.set_text(room) - self._ui.room_entry.handler_unblock(self.room_entry_changed_id) - self._ui.server_entry.set_text(server) - - self._ui.autojoin_checkbutton.set_active(model[iter_][Row.AUTOJOIN]) - # sensitive only if auto join is checked - - if model[iter_][Row.PASSWORD] is not None: - password = model[iter_][Row.PASSWORD] - else: - password = None - - if password: - self._ui.pass_entry.set_text(password) - else: - self._ui.pass_entry.set_text('') - nick = model[iter_][Row.NICK] - if nick: - self._ui.nick_entry.set_text(nick) - else: - self._ui.nick_entry.set_text('') - - def on_title_entry_changed(self, widget): - if self.ignore_events: - return - (model, iter_) = self.selection.get_selected() - if iter_: # After removing a bookmark, we got nothing selected - if model.iter_parent(iter_): - # Don't clear the title field for account nodes - model[iter_][Row.ROOM_NAME] = self._ui.title_entry.get_text() - - def on_nick_entry_changed(self, widget): - if self.ignore_events: + if not jid.isBare: + log.warning('Invalid JID: only bare JIDs allowed (%s)', jid) return - (model, iter_) = self.selection.get_selected() - if iter_: - nick = self._ui.nick_entry.get_text() + + self._ui.bookmarks_store.set_value(iter_, + Column.ADDRESS, + new_value or None) + + def _on_name_edited(self, _renderer, path, new_value): + iter_ = self._ui.bookmarks_store.get_iter(path) + self._ui.bookmarks_store.set_value(iter_, + Column.NAME, + new_value or None) + + def _on_nick_edited(self, _renderer, path, new_value): + iter_ = self._ui.bookmarks_store.get_iter(path) + + if new_value: try: - nick = helpers.parse_resource(nick) - except helpers.InvalidFormat: - ErrorDialog( - _('Invalid nickname'), - _('Character not allowed'), - transient_for=self._ui.manage_bookmarks_window) - self._ui.nick_entry.set_text(model[iter_][Row.NICK]) - return True - model[iter_][Row.NICK] = nick - - def on_server_entry_focus_out(self, widget, event): - if self.ignore_events: - return - (model, iter_) = self.selection.get_selected() - if not iter_: - return - server = widget.get_text() - if not server: - return - if '@' in server: - ErrorDialog( - _('Invalid server'), - _('Character not allowed'), - transient_for=self._ui.manage_bookmarks_window) - widget.set_text(server.replace('@', '')) - - room = self._ui.room_entry.get_text().strip() - if not room: - return - room_jid = room + '@' + server.strip() - try: - room_jid = helpers.parse_jid(room_jid) - except helpers.InvalidFormat: - ErrorDialog( - _('Invalid server'), - _('Character not allowed'), - transient_for=self._ui.manage_bookmarks_window) - self._ui.server_entry.set_text( - model[iter_][Row.ROOM_JID].split('@')[1]) - return True - model[iter_][Row.ROOM_JID] = room_jid - - def on_room_entry_changed(self, widget): - if self.ignore_events: - return - (model, iter_) = self.selection.get_selected() - if not iter_: - return - room = widget.get_text() - if not room: - return - if '@' in room: - room, server = room.split('@', 1) - widget.set_text(room) - if server: - self._ui.server_entry.set_text(server) - self._ui.server_entry.grab_focus() - server = self._ui.server_entry.get_text().strip() - if not server: - return - room_jid = room.strip() + '@' + server - try: - room_jid = helpers.parse_jid(room_jid) - except helpers.InvalidFormat: - ErrorDialog( - _('Invalid Group Chat'), - _('Character not allowed'), - transient_for=self._ui.manage_bookmarks_window) - return True - model[iter_][Row.ROOM_JID] = room_jid - - def on_pass_entry_changed(self, widget): - if self.ignore_events: - return - (model, iter_) = self.selection.get_selected() - if iter_: - model[iter_][Row.PASSWORD] = self._ui.pass_entry.get_text() + validate_resourcepart(new_value) + except ValueError as error: + log.warning('Invalid nickname: %s', error) + return
- def on_autojoin_checkbutton_toggled(self, widget, *args): - if self.ignore_events: - return - (model, iter_) = self.selection.get_selected() - if iter_: - model[iter_][Row.AUTOJOIN] = self._ui.autojoin_checkbutton.get_active() - - def clear_fields(self): - widgets = [ - self._ui.title_entry, self._ui.nick_entry, self._ui.room_entry, - self._ui.server_entry, self._ui.pass_entry] - for field in widgets: - field.set_text('') - self._ui.autojoin_checkbutton.set_active(False) - - def set_sensitive_all(self, sensitive): - widgets = [ - self._ui.title_entry, self._ui.nick_entry, self._ui.room_entry, - self._ui.server_entry, self._ui.pass_entry, self._ui.settings_box, - self._ui.remove_bookmark_button] - for field in widgets: - field.set_sensitive(sensitive) + self._ui.bookmarks_store.set_value(iter_, + Column.NICK, + new_value or None) + + def _on_password_edited(self, _renderer, path, new_value): + iter_ = self._ui.bookmarks_store.get_iter(path) + self._ui.bookmarks_store.set_value(iter_, + Column.PASSWORD, + new_value or None) + + def _on_autojoin_toggled(self, _renderer, path): + iter_ = self._ui.bookmarks_store.get_iter(path) + new_value = not self._ui.bookmarks_store[iter_][Column.AUTOJOIN] + self._ui.bookmarks_store.set_value(iter_, Column.AUTOJOIN, new_value) + + def _on_add_clicked(self, _button): + iter_ = self._ui.bookmarks_store.append([None, None, None, None, False]) + self._ui.bookmarks_view.get_selection().select_iter(iter_) + path = self._ui.bookmarks_store.get_path(iter_) + self._ui.bookmarks_view.scroll_to_cell(path, None, False) + + def _on_remove_clicked(self, _button): + mod, paths = self._ui.bookmarks_view.get_selection().get_selected_rows() + for path in paths: + iter_ = mod.get_iter(path) + self._ui.bookmarks_store.remove(iter_) + + def _on_apply_clicked(self, _button): + bookmarks = [] + for row in self._ui.bookmarks_store: + if not row[Column.ADDRESS]: + continue + bookmark = BookmarkData(jid=row[Column.ADDRESS], + name=row[Column.NAME], + autojoin=row[Column.AUTOJOIN], + password=row[Column.PASSWORD], + nick=row[Column.NICK]) + bookmarks.append(bookmark) + + con = app.connections[self.account] + con.get_module('Bookmarks').bookmarks = bookmarks + con.get_module('Bookmarks').store_bookmarks() + self.destroy() + + @staticmethod + def _search_func(model, _column, search_text, iter_): + return search_text.lower() not in model[iter_][0].lower()
===================================== gajim/gui_menu_builder.py ===================================== @@ -676,6 +676,7 @@ def get_account_menu(account): (_('Advanced'), [ ('-archive', _('Archiving Preferences')), ('-blocking', _('Blocking List')), + ('-bookmarks', _('Bookmarks')), ('-sync-history', _('Synchronise History')), ('-privacylists', _('Privacy Lists')), ('-server-info', _('Server Info')),
===================================== gajim/privatechat_control.py ===================================== @@ -54,10 +54,7 @@ class PrivateChatControl(ChatControl): room_jid, account) if room_jid in app.interface.minimized_controls[account]: self.room_ctrl = app.interface.minimized_controls[account][room_jid] - if self.room_ctrl: - self.room_name = self.room_ctrl.name - else: - self.room_name = room_jid + self.gc_contact = gc_contact ChatControl.__init__(self, parent_win, contact, account, session) self.TYPE_ID = 'pm' @@ -86,6 +83,12 @@ class PrivateChatControl(ChatControl): # TODO: remove all code that sets the contact here return
+ @property + def room_name(self): + if self.room_ctrl is not None: + return self.room_ctrl.room_name + return self.gc_contact.room_jid + def get_our_nick(self): return self.room_ctrl.nick
@@ -142,7 +145,7 @@ class PrivateChatControl(ChatControl): status=status) self.add_status_message(message)
- elif app.config.get_per('rooms', self.room_name, + elif app.config.get_per('rooms', self.gc_contact.room_jid, 'print_status', status_default): message = _('{nick} is now {show}{status}').format(nick=nick, show=show,
===================================== gajim/roster_window.py ===================================== @@ -77,7 +77,6 @@ from gajim.gtk.dialogs import InvitationReceivedDialog from gajim.gtk.single_message import SingleMessageWindow from gajim.gtk.add_contact import AddNewContactWindow from gajim.gtk.pep_config import ManagePEPServicesWindow -from gajim.gtk.bookmarks import ManageBookmarksWindow from gajim.gtk.account_wizard import AccountCreationWizard from gajim.gtk.service_registration import ServiceRegistration from gajim.gtk.discovery import ServiceDiscoveryWindow @@ -3521,9 +3520,6 @@ class RosterWindow: action.set_state(param) self.refilter_shown_roster_items()
- def on_manage_bookmarks_menuitem_activate(self, widget): - ManageBookmarksWindow() - def on_execute_command(self, widget, contact, account, resource=None): """ Execute command. Full JID needed; if it is other contact, resource is
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/61679239434380e1db657725ece35aa8e6...