diff options
-rw-r--r-- | plugins/quickopen/quickopen/__init__.py | 2 | ||||
-rw-r--r-- | plugins/quickopen/quickopen/popup.py | 124 | ||||
-rw-r--r-- | plugins/quickopen/quickopen/virtualdirs.py | 8 | ||||
-rw-r--r-- | plugins/quickopen/quickopen/windowhelper.py | 28 |
4 files changed, 94 insertions, 68 deletions
diff --git a/plugins/quickopen/quickopen/__init__.py b/plugins/quickopen/quickopen/__init__.py index 3ae72a45..17ccdf7c 100644 --- a/plugins/quickopen/quickopen/__init__.py +++ b/plugins/quickopen/quickopen/__init__.py @@ -18,7 +18,7 @@ # Boston, MA 02110-1301, USA. from gi.repository import GObject, Peas -from windowhelper import WindowHelper +from .windowhelper import WindowHelper class QuickOpenPlugin(GObject.Object, Peas.Activatable): __gtype_name__ = "QuickOpenPlugin" diff --git a/plugins/quickopen/quickopen/popup.py b/plugins/quickopen/quickopen/popup.py index c6cc8016..be40509f 100644 --- a/plugins/quickopen/quickopen/popup.py +++ b/plugins/quickopen/quickopen/popup.py @@ -18,10 +18,11 @@ # Boston, MA 02110-1301, USA. import os +import sys import fnmatch import xml.sax.saxutils from gi.repository import GObject, Gio, GLib, Gdk, Gtk, Pango, Pluma -from virtualdirs import VirtualDirectory +from .virtualdirs import VirtualDirectory class Popup(Gtk.Dialog): __gtype_name__ = "QuickOpenPopup" @@ -30,11 +31,12 @@ class Popup(Gtk.Dialog): Gtk.Dialog.__init__(self, title=_('Quick Open'), parent=window, - flags=Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL, - buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)) - - self._open_button = self.add_button(Gtk.STOCK_OPEN, Gtk.ResponseType.ACCEPT) + flags=Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL) + self._add_button(_("_Cancel"), Gtk.ResponseType.CANCEL, "process-stop") + self._open_button = self._add_button(_("_Open"), + Gtk.ResponseType.ACCEPT, + "document-open") self._handler = handler self._build_ui() @@ -48,7 +50,10 @@ class Popup(Gtk.Dialog): self._busy_cursor = Gdk.Cursor(Gdk.CursorType.WATCH) accel_group = Gtk.AccelGroup() - accel_group.connect(Gdk.KEY_l, Gdk.ModifierType.CONTROL_MASK, 0, self.on_focus_entry) + accel_group.connect(Gdk.keyval_from_name('l'), + Gdk.ModifierType.CONTROL_MASK, + 0, + self.on_focus_entry) self.add_accel_group(accel_group) @@ -63,10 +68,11 @@ class Popup(Gtk.Dialog): return self._size def _build_ui(self): + self.set_border_width(5) vbox = self.get_content_area() vbox.set_spacing(3) - self._entry = Gtk.Entry() + self._entry = Gtk.SearchEntry() self._entry.connect('changed', self.on_changed) self._entry.connect('key-press-event', self.on_key_press_event) @@ -78,7 +84,10 @@ class Popup(Gtk.Dialog): tv = Gtk.TreeView() tv.set_headers_visible(False) - self._store = Gtk.ListStore(Gio.Icon, str, GObject.Object, Gio.FileType) + self._store = Gtk.ListStore(Gio.Icon, + str, + GObject.Object, + Gio.FileType) tv.set_model(self._store) self._treeview = tv @@ -106,7 +115,7 @@ class Popup(Gtk.Dialog): vbox.pack_start(sw, True, True, 0) lbl = Gtk.Label() - lbl.set_alignment(0, 0.5) + lbl.set_halign(Gtk.Align.START) lbl.set_ellipsize(Pango.EllipsizeMode.MIDDLE) self._info_label = lbl @@ -129,19 +138,22 @@ class Popup(Gtk.Dialog): cell.set_property('cell-background-set', False) cell.set_property('style-set', False) - def _icon_from_stock(self, stock): - theme = Gtk.icon_theme_get_default() - size = Gtk.icon_size_lookup(Gtk.IconSize.MENU) - pixbuf = theme.load_icon(stock, size[0], Gtk.IconLookupFlags.USE_BUILTIN) - - return pixbuf + def _add_button(self, label, response, icon=None): + button = self.add_button(label, response) + if icon: + image = Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.BUTTON) + button.set_image(image) + button.set_property("always-show-image", True) + return button def _list_dir(self, gfile): entries = [] try: - ret = gfile.enumerate_children("standard::*", Gio.FileQueryInfoFlags.NONE, None) - except GLib.GError: + ret = gfile.enumerate_children("standard::*", + Gio.FileQueryInfoFlags.NONE, + None) + except GLib.Error: pass if isinstance(ret, Gio.FileEnumerator): @@ -151,27 +163,23 @@ class Popup(Gtk.Dialog): if not entry: break - entries.append((gfile.get_child(entry.get_name()), entry)) + if not entry.get_is_backup(): + entries.append((gfile.get_child(entry.get_name()), entry)) else: entries = ret children = [] for entry in entries: - children.append((entry[0], entry[1].get_name(), entry[1].get_file_type(), entry[1].get_icon())) + children.append((entry[0], + entry[1].get_name(), + entry[1].get_file_type(), + entry[1].get_icon())) return children - def _compare_entries(self, a, b, lpart): - if lpart in a: - if lpart in b: - return cmp(a.index(lpart), b.index(lpart)) - else: - return -1 - elif lpart in b: - return 1 - else: - return 0 + def _key_entries(self, pos): + return pos if pos >= 0 else sys.maxsize def _match_glob(self, s, glob): if glob: @@ -185,8 +193,7 @@ class Popup(Gtk.Dialog): if not d in self._cache: entries = self._list_dir(d) - entries.sort(lambda x, y: cmp(x[1].lower(), y[1].lower())) - + entries.sort(key=lambda x: x[1].lower()) self._cache[d] = entries else: entries = self._cache[d] @@ -212,7 +219,7 @@ class Popup(Gtk.Dialog): (not lpart or len(parts) == 1): found.append(entry) - found.sort(lambda a, b: self._compare_entries(a[1].lower(), b[1].lower(), lpart)) + found.sort(key=lambda x: self._key_entries(x[1].lower().find(lpart))) if lpart == '..': newdirs.append(d.get_parent()) @@ -251,7 +258,9 @@ class Popup(Gtk.Dialog): return os.sep.join(out) def _get_icon(self, f): - query = f.query_info(Gio.FILE_ATTRIBUTE_STANDARD_ICON, Gio.FileQueryInfoFlags.NONE, None) + query = f.query_info(Gio.FILE_ATTRIBUTE_STANDARD_ICON, + Gio.FileQueryInfoFlags.NONE, + None) if not query: return None @@ -304,7 +313,10 @@ class Popup(Gtk.Dialog): for d in self._dirs: if isinstance(d, VirtualDirectory): for entry in d.enumerate_children("standard::*", 0, None): - self._append_to_store((entry[1].get_icon(), xml.sax.saxutils.escape(entry[1].get_name()), entry[0], entry[1].get_file_type())) + self._append_to_store((entry[1].get_icon(), + xml.sax.saxutils.escape(entry[1].get_name()), + entry[0], + entry[1].get_file_type())) def _set_busy(self, busy): if busy: @@ -337,14 +349,17 @@ class Popup(Gtk.Dialog): for d in self._dirs: for entry in self.do_search_dir(parts, d): pathparts = self._make_parts(d, entry[0], parts) - self._append_to_store((entry[3], self.make_markup(parts, pathparts), entry[0], entry[2])) + self._append_to_store((entry[3], + self.make_markup(parts, pathparts), + entry[0], + entry[2])) piter = self._store.get_iter_first() if piter: - self._treeview.get_selection().select_path(self._store.get_path(piter)) + path = self._store.get_path(piter) + self._treeview.get_selection().select_path(path) - self.get_window().set_cursor(None) self._set_busy(False) def do_show(self): @@ -366,7 +381,7 @@ class Popup(Gtk.Dialog): model, rows = selection.get_selected_rows() start = rows[0] - self._shift_start = Gtk.TreeRowReference(self._store, start) + self._shift_start = Gtk.TreeRowReference.new(self._store, start) else: start = self._shift_start.get_path() @@ -419,7 +434,7 @@ class Popup(Gtk.Dialog): else: self._select_index(num - 1, hasctrl, hasshift) else: - idx = path[0] + idx = path.get_indices()[0] if idx + howmany < 0: self._select_index(0, hasctrl, hasshift) @@ -461,19 +476,22 @@ class Popup(Gtk.Dialog): if text[i] == os.sep: break - self._entry.set_text(os.path.join(text[:i], os.path.basename(info[0].get_uri())) + os.sep) + self._entry.set_text(os.path.join(text[:i], + os.path.basename(info[0].get_uri())) + os.sep) self._entry.set_position(-1) self._entry.grab_focus() return True if rows and ret: - self.destroy() + # We destroy the popup in an idle callback to work around a crash that happens with + # GTK_IM_MODULE=xim. See https://bugzilla.gnome.org/show_bug.cgi?id=737711 . + GLib.idle_add(self.destroy) if not rows: gfile = self._direct_file() if gfile and self._handler(gfile): - self.destroy() + GLib.idle_add(self.destroy) else: ret = False else: @@ -495,20 +513,24 @@ class Popup(Gtk.Dialog): def on_key_press_event(self, widget, event): move_mapping = { - Gdk.KEY_Down: 1, - Gdk.KEY_Up: -1, - Gdk.KEY_Page_Down: 5, - Gdk.KEY_Page_Up: -5 + "Down": 1, + "Up": -1, + "Page_Down": 5, + "Page_Up": -5 } - if event.keyval == Gdk.KEY_Escape: + keyname = Gdk.keyval_name(event.keyval) + + if keyname == "Escape": self.destroy() return True - elif event.keyval in move_mapping: - return self._move_selection(move_mapping[event.keyval], event.state & Gdk.ModifierType.CONTROL_MASK, event.state & Gdk.ModifierType.SHIFT_MASK) - elif event.keyval in [Gdk.KEY_Return, Gdk.KEY_KP_Enter, Gdk.KEY_Tab, Gdk.KEY_ISO_Left_Tab]: + elif keyname in move_mapping: + return self._move_selection(move_mapping[keyname], + event.state & Gdk.ModifierType.CONTROL_MASK, + event.state & Gdk.ModifierType.SHIFT_MASK) + elif keyname in ["Return", "KP_Enter", "Tab", "ISO_Left_Tab"]: return self._activate() - elif event.keyval == Gdk.KEY_space and event.state & Gdk.ModifierType.CONTROL_MASK: + elif keyname == "space" and event.state & Gdk.ModifierType.CONTROL_MASK: self.toggle_cursor() return False diff --git a/plugins/quickopen/quickopen/virtualdirs.py b/plugins/quickopen/quickopen/virtualdirs.py index 53d716a2..7bf66b8e 100644 --- a/plugins/quickopen/quickopen/virtualdirs.py +++ b/plugins/quickopen/quickopen/virtualdirs.py @@ -38,7 +38,9 @@ class VirtualDirectory(object): return try: - info = child.query_info("standard::*", Gio.FileQueryInfoFlags.NONE, None) + info = child.query_info("standard::*", + Gio.FileQueryInfoFlags.NONE, + None) if info: self._children.append((child, info)) @@ -46,7 +48,7 @@ class VirtualDirectory(object): pass class RecentDocumentsDirectory(VirtualDirectory): - def __init__(self, maxitems=10): + def __init__(self, maxitems=200): VirtualDirectory.__init__(self, 'recent') self._maxitems = maxitems @@ -56,7 +58,7 @@ class RecentDocumentsDirectory(VirtualDirectory): manager = Gtk.RecentManager.get_default() items = manager.get_items() - items.sort(lambda a, b: cmp(b.get_visited(), a.get_visited())) + items.sort(key=lambda a: a.get_visited(), reverse=True) added = 0 diff --git a/plugins/quickopen/quickopen/windowhelper.py b/plugins/quickopen/quickopen/windowhelper.py index 19e44cba..7f9ab123 100644 --- a/plugins/quickopen/quickopen/windowhelper.py +++ b/plugins/quickopen/quickopen/windowhelper.py @@ -17,11 +17,12 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, # Boston, MA 02110-1301, USA. -from popup import Popup import os +import codecs from gi.repository import Gio, GLib, Gtk, Pluma -from virtualdirs import RecentDocumentsDirectory -from virtualdirs import CurrentDocumentsDirectory +from .popup import Popup +from .virtualdirs import RecentDocumentsDirectory +from .virtualdirs import CurrentDocumentsDirectory ui_str = """<ui> <menubar name="MenuBar"> @@ -60,12 +61,13 @@ class WindowHelper: def _install_menu(self): manager = self._window.get_ui_manager() + action = Gtk.Action.new("QuickOpen", + _("Quick open"), + _("Quickly open documents")) + action.set_icon_name("document-open") + action.connect("activate", self.on_quick_open_activate) self._action_group = Gtk.ActionGroup("PlumaQuickOpenPluginActions") - self._action_group.add_actions([ - ("QuickOpen", Gtk.STOCK_OPEN, _("Quick open"), - '<Ctrl><Alt>O', _("Quickly open documents"), - self.on_quick_open_activate) - ]) + self._action_group.add_action_with_accel(action, "<Ctrl><Alt>O") manager.insert_action_group(self._action_group, -1) self._ui_id = manager.add_ui_from_string(ui_str) @@ -95,10 +97,10 @@ class WindowHelper: if uri: gfile = Gio.file_new_for_uri(uri) - if gfile.is_native(): + if gfile and gfile.is_native(): paths.append(gfile) - except StandardError: + except Exception: pass # Recent documents @@ -128,14 +130,14 @@ class WindowHelper: self._popup.connect('destroy', self.on_popup_destroy) def _local_bookmarks(self): - filename = os.path.expanduser('~/.gtk-bookmarks') + filename = os.path.expanduser('~/.config/gtk-3.0/bookmarks') if not os.path.isfile(filename): return [] paths = [] - for line in file(filename, 'r').xreadlines(): + for line in codecs.open(filename, 'r', encoding='utf-8'): uri = line.strip().split(" ")[0] f = Gio.file_new_for_uri(uri) @@ -160,7 +162,7 @@ class WindowHelper: desktopdir = None if os.path.isfile(config): - for line in file(config, 'r').xreadlines(): + for line in codecs.open(config, 'r', encoding='utf-8'): line = line.strip() if line.startswith('XDG_DESKTOP_DIR'): |