Last active
September 28, 2021 18:39
-
-
Save muguu/675d229ef59ec26c8e49780c688c3ae0 to your computer and use it in GitHub Desktop.
Plugin for ZimWiki >0.61 and < V0.66
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# Plugin for ZimWiki: Search tagged pages. | |
# Copyright 2015 Murat Güven <[email protected]> | |
# Copyright ZimWiki: 2009-2013 Jaap Karssenberg <[email protected]> | |
# V1.15 | |
# Change Log | |
# V1.15: If cursor is at empty line, don't go back to previous line / word and lookup a tag. | |
# Also changed search beaviour. Now looks for word which is right to the cursor instead of left | |
# V1.14: Now getting word at cursor position without the need to mark the text in order to look it up | |
# V1.13: Little bug fix | |
# V1.12: Added functionality to lookup a tag which is selected. | |
import gtk | |
import gtk.gdk | |
from zim.plugins import PluginClass, extends, WindowExtension | |
from zim.notebook import Path | |
from zim.search import * | |
from zim.signals import ConnectorMixin | |
from zim.actions import action | |
ALTSHIFTQ = '<alt><shift>q' | |
ENTRY_LABEL_WIDTH_PIX = 50 | |
BUTTON_HIGHT_PIX = 25 | |
BUTTON_WIDTH_PIX = 80 | |
H_SPACING_PIX = 3 | |
TABLE_PADDING_LEFT_PIX = 10 | |
TABLE_PADDING_TOP_PIX = 0 | |
TABLE_COL_SPACINGS = 10 | |
TABLE_ROW_SPACINGS = 2 | |
ENTRY_HIGHT_PIX = 25 | |
ENTRY_WIDTH_PIX = 180 | |
PADDING_TOP_PIX = 10 | |
CHECK_BOX_PADDING_LEFT_PIX = ENTRY_LABEL_WIDTH_PIX + 1 | |
SIZE_X = H_SPACING_PIX + ENTRY_LABEL_WIDTH_PIX + H_SPACING_PIX + ENTRY_WIDTH_PIX + H_SPACING_PIX + BUTTON_WIDTH_PIX + H_SPACING_PIX + BUTTON_WIDTH_PIX + 8 * H_SPACING_PIX | |
TAG_ENTRY_WIDTH_PIX = (SIZE_X - 2 * TABLE_PADDING_LEFT_PIX - 3 * TABLE_COL_SPACINGS) / 2 | |
class SearchTaggedPagesPlugin(PluginClass): | |
plugin_info = { | |
'name': _('Search tagged pages'), # T: plugin name | |
'description': _('''\ | |
This plugin helps finding pages or tags by narrowing down to selected and common tags. | |
In addition you can use an open search filter. | |
V1.15 | |
'''), # T: plugin description | |
'author': 'Murat Güven', | |
'help': 'Plugins:Search tagged pages', | |
} | |
plugin_preferences = ( | |
# T: label for plugin preferences dialog | |
('add_pages_separator', 'string', _('Add pages as link function: Tag separator to use'), '||'), | |
('add_pages_atsign', 'bool', _('Add pages as link function: Paste tags as tags (with @)'), False), | |
# T: plugin preference | |
) | |
@extends('MainWindow') | |
class SearchTaggedPagesMainWindowExtension(WindowExtension, ConnectorMixin): | |
uimanager_xml = ''' | |
<ui> | |
<menubar name='menubar'> | |
<menu action='search_menu'> | |
<placeholder name='plugin_items'> | |
<menuitem action='search_tagged_pages'/> | |
</placeholder> | |
</menu> | |
</menubar> | |
<toolbar name='toolbar'> | |
<placeholder name='tools'> | |
<toolitem action='search_tagged_pages'/> | |
</placeholder> | |
</toolbar> | |
</ui> | |
''' | |
accel_key = ALTSHIFTQ | |
@action(_('Search tagged pages'), stock='gtk-find', accelerator=accel_key, readonly=True) # T: menu item | |
def search_tagged_pages(self): | |
self.ui = self.window.ui | |
self.index = self.window.ui.notebook.index | |
self.table_selected_tags = gtk.Table() | |
self.table_selected_tags.set_col_spacings(TABLE_COL_SPACINGS) | |
self.table_selected_tags.set_row_spacings(TABLE_ROW_SPACINGS) | |
self.table_common_tags = gtk.Table() | |
self.table_common_tags.set_col_spacings(TABLE_COL_SPACINGS) | |
self.table_common_tags.set_row_spacings(TABLE_ROW_SPACINGS) | |
self.search_win = gtk.Window() | |
self.search_win.set_title("Search tagged pages") | |
self.v_paned_main = gtk.VPaned() | |
self.v_paned_top = gtk.VPaned() | |
self.v_paned_bottom = gtk.VPaned() | |
# homogeneous=False, spacing=0 | |
self.hbox1_buttons = gtk.HBox(False, H_SPACING_PIX) | |
self.hbox2_buttons = gtk.HBox(False, H_SPACING_PIX) | |
self.hbox3_buttons = gtk.HBox(False, H_SPACING_PIX) | |
self.vbox_buttons = gtk.VBox(False, H_SPACING_PIX) | |
self.vbox_selected_tags = gtk.VBox(False, H_SPACING_PIX) | |
self.vbox_common_tags = gtk.VBox(False, H_SPACING_PIX) | |
# xalign=0.0, yalign=0.0, xscale=0.0, yscale=0.0 | |
self.halign1_buttons = gtk.Alignment(0, 0, 0, 0) | |
self.halign2_buttons = gtk.Alignment(0, 0, 0, 0) | |
self.halign3_buttons = gtk.Alignment(0, 0, 0, 0) | |
self.halign_table_selected_tags = gtk.Alignment(0, 0, 0, 0) | |
self.halign_label_selected_tags = gtk.Alignment(0, 0, 0, 0) | |
self.halign_label_common_tags = gtk.Alignment(0, 0, 0, 0) | |
self.halign_table_common_tags = gtk.Alignment(0, 0, 0, 0) | |
self.search_scrolled_win_buttons = gtk.ScrolledWindow() | |
self.search_scrolled_win_selected_tags = gtk.ScrolledWindow() | |
self.search_scrolled_win_common_tags = gtk.ScrolledWindow() | |
self.search_scrolled_win_pages = gtk.ScrolledWindow() | |
self.main_entry = gtk.Entry() | |
self.filter_entry = gtk.Entry() | |
self.completion = gtk.EntryCompletion() | |
self.tag_list_store = gtk.ListStore(str) | |
self.pages_tree_store = gtk.TreeStore(str, int) | |
self.pages_tree_view = gtk.TreeView(self.pages_tree_store) | |
self.pages_column = gtk.TreeViewColumn("Pages") | |
self.score_column = gtk.TreeViewColumn("Score") | |
self.cell_text = gtk.CellRendererText() | |
self.progress_bar = gtk.ProgressBar() | |
self.progress_bar_fraction = self.index.n_list_all_pages() / 100000.0 | |
self.checkbutton_inter_state = 1 | |
self.checkbutton_union_state = 0 | |
self.intersect_pages_list = [] | |
self.query = Query | |
self.selection = SearchSelection(self.ui.notebook) | |
self.filter_hit_store = gtk.ListStore(str, int) | |
self.cancelled = False | |
self.tree_selection = self.pages_tree_view.get_selection() | |
self.tag_matrix_common = { | |
1: [0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], | |
2: [1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] | |
} | |
# tag_matrix_common primarily needed to fill the window with | |
# dummy entries, otherwise 2 elements (equals one line) were | |
# enough | |
# table: | |
# 0/1: x1 = left_attach, x2 = right_attach | |
# 2/3: y1 = top_attach, y2 = bottom_attach | |
# 4: entry = store entry object to find when deleted or to delete all | |
# 5: status_occupied: 0 = empty, 1: cell occupied ( in table) | |
# 6: status_enabled: 0 = disabled (greyed out), 1: enabled | |
# 7: entrystyle = store entry style object | |
# 8: show tag in completion: 0: no, 1: yes | |
# 9: pages: all pages for a tag | |
# 10: the tag | |
# 11: # of tags with common pages | |
self.tag_matrix_selected = { | |
1: [0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], | |
2: [1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] | |
} | |
# tag_matrix_common primarily needed to fill the window with | |
# dummy entries, otherwise 2 elements (equals one line) were | |
# enough | |
# table: | |
# 0/1: x1 = left_attach, x2 = right_attach | |
# 2/3: y1 = top_attach, y2 = bottom_attach | |
# 4: entry = store entry object to find when deleted or to delete all | |
# 5: status_occupied: 0 = empty, 1: cell occupied ( in table) | |
# 6: status_enabled: 0 = disabled (greyed out), 1: enabled | |
# 7: entrystyle = store entry style object | |
# 8: show tag in completion: 0: no, 1: yes | |
# 9: pages: all pages for a tag | |
# 10: the tag | |
# 11: # of tags with common pages | |
self.search_help_text = ( | |
'For advanced search you can use operators like\n' | |
'+ AND and &&,\n' | |
'OR or ||, \n' | |
'- NOT \n' | |
'Keywords:\n' | |
'Content: or Name: or NameSpace:\n' | |
'Links: or LinksFrom: or LinksTo:\n' | |
'See the help page for the general search function for more details.' | |
) # T: help text for the search dialog | |
self.tag_help_text = ( | |
'Enter and select a tag from a list of your tags.\n' | |
'The tag entered here will be shown below in selected tags.\n\n' | |
'The available list of your tags will show all tags\n' | |
'which have common pages with the selected tags\n' | |
) | |
self.search_win.set_default_size(SIZE_X, 800) | |
self.search_win.set_geometry_hints(min_width=SIZE_X) | |
self.v_paned_main.set_position(250) | |
self.search_win.add(self.v_paned_main) | |
self.v_paned_top.set_position(100) | |
self.v_paned_bottom.set_position(180) | |
self.v_paned_top.add1(self.vbox_buttons) | |
# self.v_paned_top.add1(self.search_scrolled_win_buttons) | |
self.v_paned_top.add2(self.search_scrolled_win_selected_tags) | |
self.v_paned_main.add1(self.v_paned_top) | |
self.table_selected_tags.set_homogeneous(False) | |
# Populate Buttons Window_________________________________________________________________________________ | |
# padding_top, padding_bottom, padding_left, padding_right | |
self.halign1_buttons.set_padding(PADDING_TOP_PIX, 0, 0, 0) | |
self.halign2_buttons.set_padding(0, 0, 0, 0) | |
self.halign3_buttons.set_padding(PADDING_TOP_PIX, 0, CHECK_BOX_PADDING_LEFT_PIX, 0) | |
self.halign1_buttons.add(self.hbox1_buttons) | |
self.halign2_buttons.add(self.hbox2_buttons) | |
self.halign3_buttons.add(self.hbox3_buttons) | |
self.vbox_buttons.pack_start(self.halign1_buttons, False, False, 0) | |
self.vbox_buttons.pack_start(self.halign2_buttons, False, False, 0) | |
self.vbox_buttons.pack_start(self.halign3_buttons, False, False, 0) | |
# Add Main Entry field ___________________________________________________________________________________ | |
main_entry_label = gtk.Label("Tag:") | |
main_entry_label.set_size_request(ENTRY_LABEL_WIDTH_PIX, ENTRY_HIGHT_PIX) | |
self.main_entry.set_tooltip_text(self.tag_help_text) | |
self.main_entry.set_icon_from_stock(1, "gtk-clear") | |
self.main_entry.set_size_request(ENTRY_WIDTH_PIX, ENTRY_HIGHT_PIX) | |
self.hbox1_buttons.add(main_entry_label) | |
self.hbox1_buttons.add(self.main_entry) | |
# ________________________________________________________________________________________________________ | |
# Add Show All Button_____________________________________________________________________________________ | |
self.button_show_all = gtk.Button("Show all") | |
self.button_show_all.set_size_request(BUTTON_WIDTH_PIX, BUTTON_HIGHT_PIX) | |
self.hbox1_buttons.add(self.button_show_all) | |
# _________________________________________________________________________________________________________ | |
# Add Remove all Button____________________________________________________________________________________ | |
self.button_remove_all = gtk.Button("Remove all") | |
self.button_remove_all.set_size_request(BUTTON_WIDTH_PIX, BUTTON_HIGHT_PIX) | |
self.hbox1_buttons.add(self.button_remove_all) | |
# _________________________________________________________________________________________________________ | |
# Add Filter Entry field___________________________________________________________________________________ | |
self.filter_entry.set_tooltip_text(self.search_help_text) | |
filter_entry_label = gtk.Label("Filter:") | |
filter_entry_label.set_size_request(ENTRY_LABEL_WIDTH_PIX, ENTRY_HIGHT_PIX) | |
self.filter_entry.set_icon_from_stock(1, "gtk-clear") | |
self.filter_entry.set_size_request(ENTRY_WIDTH_PIX, ENTRY_HIGHT_PIX) | |
self.hbox2_buttons.add(filter_entry_label) | |
self.hbox2_buttons.add(self.filter_entry) | |
# _________________________________________________________________________________________________________ | |
# Add search / progress bar ______________________________________________________________________________ | |
self.button_search = gtk.Button("Search") | |
self.button_search.set_size_request(BUTTON_WIDTH_PIX, BUTTON_HIGHT_PIX) | |
self.button_cancel_search = gtk.Button("Stopp") | |
self.button_cancel_search.set_size_request(BUTTON_WIDTH_PIX, BUTTON_HIGHT_PIX) | |
self.progress_bar.set_size_request(BUTTON_WIDTH_PIX, BUTTON_HIGHT_PIX) | |
self.hbox2_buttons.add(self.button_search) | |
self.hbox2_buttons.add(self.button_cancel_search) | |
self.hbox2_buttons.add(self.progress_bar) | |
# _________________________________________________________________________________________________________ | |
# Add Check boxes__________________________________________________________________________________________ | |
self.checkbutton_inter = gtk.CheckButton("Common pages") | |
self.checkbutton_inter.set_active(is_active=1) | |
self.checkbutton_union = gtk.CheckButton("Unique pages") | |
self.hbox3_buttons.add(self.checkbutton_inter) | |
self.hbox3_buttons.add(self.checkbutton_union) | |
# _________________________________________________________________________________________________________ | |
# Add Page add button__________________________________________________________________________________________ | |
self.button_add_page = gtk.Button("Add pages as link") | |
self.button_add_page.set_size_request(BUTTON_WIDTH_PIX + 50, BUTTON_HIGHT_PIX) | |
self.hbox3_buttons.add(self.button_add_page) | |
# _________________________________________________________________________________________________________ | |
self.search_scrolled_win_buttons.add_with_viewport(self.vbox_buttons) | |
# Add selected tags text___________________________________________________________________________________ | |
self.separator = gtk.HSeparator() | |
selected_tags_label = gtk.Label("Selected tags: ") | |
self.separator2 = gtk.HSeparator() | |
common_tags_label = gtk.Label("Common tags of selected tags: ") | |
self.halign_label_selected_tags.add(selected_tags_label) | |
self.halign_label_selected_tags.set_padding(5, 0, TABLE_PADDING_LEFT_PIX, 0) | |
self.halign_label_common_tags.add(common_tags_label) | |
self.halign_label_common_tags.set_padding(5, 0, TABLE_PADDING_LEFT_PIX, 0) | |
self.halign_table_selected_tags.add(self.table_selected_tags) | |
self.halign_table_selected_tags.set_padding(TABLE_PADDING_TOP_PIX, 0, TABLE_PADDING_LEFT_PIX, 0) | |
self.halign_table_common_tags.add(self.table_common_tags) | |
self.halign_table_common_tags.set_padding(TABLE_PADDING_TOP_PIX, 0, TABLE_PADDING_LEFT_PIX, 0) | |
self.vbox_selected_tags.pack_start(self.halign_label_selected_tags, False, False, 0) | |
self.vbox_selected_tags.pack_start(self.separator, False, False, 0) | |
self.vbox_selected_tags.pack_start(self.halign_table_selected_tags, False, False, 0) | |
self.vbox_common_tags.pack_start(self.halign_label_common_tags, False, False, 0) | |
self.vbox_common_tags.pack_start(self.separator2, False, False, 0) | |
self.vbox_common_tags.pack_start(self.halign_table_common_tags, False, False, 0) | |
self.search_scrolled_win_selected_tags.add_with_viewport(self.vbox_selected_tags) | |
self.search_scrolled_win_common_tags.add_with_viewport(self.vbox_common_tags) | |
self.search_scrolled_win_pages.add(self.pages_tree_view) | |
self.v_paned_main.add2(self.v_paned_bottom) | |
self.v_paned_bottom.add1(self.search_scrolled_win_common_tags) | |
self.v_paned_bottom.add2(self.search_scrolled_win_pages) | |
self.pages_tree_view.append_column(self.pages_column) | |
self.pages_column.pack_start(self.cell_text, False) | |
self.pages_column.add_attribute(self.cell_text, "text", 0) | |
self.pages_column.set_sort_column_id(0) | |
self.pages_column.set_resizable(True) | |
self.pages_column.set_max_width(SIZE_X-60) | |
self.pages_tree_view.append_column(self.score_column) | |
self.score_column.pack_start(self.cell_text, False) | |
self.score_column.add_attribute(self.cell_text, "text", 1) | |
self.score_column.set_sort_column_id(1) | |
self.pages_tree_store.set_sort_column_id(1, gtk.SORT_DESCENDING) | |
self.set_entry_completion(self.index.list_all_tags(), 'all') | |
self.completion.set_inline_completion(True) | |
self.completion.set_inline_selection(True) | |
self.main_entry.set_completion(self.completion) | |
self.completion.set_text_column(0) | |
self.completion.set_popup_single_match(False) | |
self.search_win.show_all() | |
self.progress_bar.hide_all() | |
self.button_cancel_search.hide_all() | |
self.main_entry.connect("icon-press", self.clear_entry) | |
self.filter_entry.connect("icon-press", self.clear_filter_entry) | |
self.main_entry.connect('activate', self.main_entry_return) | |
self.filter_entry.connect('activate', self.search_filter) | |
self.completion.connect('match-selected', self.match_selected) | |
self.button_remove_all.connect("clicked", self.button_remove_all_clicked) | |
self.button_show_all.connect("clicked", self.button_show_all_clicked) | |
self.button_search.connect("clicked", self.search_filter) | |
self.button_cancel_search.connect("clicked", self.search_cancel) | |
self.button_add_page.connect("clicked", self.button_add_page_clicked) | |
self.checkbutton_inter.connect("toggled", self.checkbutton_inter_toggled) | |
self.checkbutton_union.connect("toggled", self.checkbutton_union_toggled) | |
self.tree_selection.connect("changed", self.page_selected, self.tree_selection) | |
self.auto_fill_tag() | |
def auto_fill_tag(self): | |
# get the text buffer from the note | |
self.buffer = self.window.pageview.view.get_buffer() | |
word = self.get_word_at_cursor_pos(self.buffer) | |
tags = self.index.list_all_tags() | |
if word: | |
for tag in tags: | |
if word == tag.name.decode('utf-8'): | |
word = word.strip('@') | |
self.main_entry.append_text(word) | |
self.main_entry_return(None) | |
break | |
def page_selected(self, widget, tree_selection): | |
# This function displays the page in Zim when selected in result list | |
(model, pathlist) = tree_selection.get_selected_rows() | |
for path in pathlist: | |
tree_iter = model.get_iter(path) | |
page = model.get_value(tree_iter, 0) | |
page_name_index = self.intersect_pages_list[1].index(page) | |
page_path = Path(self.intersect_pages_list[0][page_name_index]) | |
if page_path: | |
self.ui.open_page(page_path) | |
def checkbutton_inter_toggled(self, widget): | |
if self.checkbutton_inter_state: | |
self.checkbutton_inter_state = 0 | |
else: | |
self.checkbutton_inter_state = 1 | |
# TODO: handle error when no tags are shown | |
self.show_pages() | |
def checkbutton_union_toggled(self, widget): | |
if self.checkbutton_union_state: | |
self.checkbutton_union_state = 0 | |
else: | |
self.checkbutton_union_state = 1 | |
# TODO: handle error when no tags are shown | |
self.show_pages() | |
def button_remove_all_clicked(self, widget): | |
self.main_entry.set_text('') | |
self.filter_entry.set_text('') | |
self.clear_pages() | |
self.remove_all_entries() | |
self.set_entry_completion(self.index.list_all_tags(), 'all') # to fill the completion list with all tags again | |
def button_add_page_clicked(self, widget): | |
# get the windows, buffer and cursor position | |
main_window = self.window.pageview.view | |
zim_buffer = self.window.pageview.view.get_buffer() | |
cursor = zim_buffer.get_iter_at_mark(zim_buffer.get_insert()) | |
# add text to the page | |
zim_buffer.insert(cursor, "== Pages with following tag(s) in common ==\n") | |
# get the selected tags and add them to the page | |
tags = self.get_active_tags() | |
atsign="" | |
if self.plugin.preferences['add_pages_atsign']: | |
atsign = "@" | |
separator = self.plugin.preferences['add_pages_separator'] | |
tags_n = len(tags) | |
for tag in sorted(tags): | |
tags_n -= 1 | |
if tags_n == 0: # Don't add a separator for the last tag (or if only one tag) | |
separator = "" | |
zim_buffer.insert(cursor, atsign + tag + " " + separator + " ") | |
zim_buffer.insert(cursor, "\n") | |
# get the pages to be linked and put them into the page | |
intersect_pages, union_pages = self.get_common_pages_of_active_tags() | |
for page in sorted(intersect_pages): | |
page_link = "[[" + page.name + "]]" + "\n" | |
zim_buffer.insert(cursor, page_link) | |
def remove_all_entries(self): | |
self.remove_all_entries_selected_tags() | |
self.remove_all_entries_common_tags() | |
def remove_all_entries_selected_tags(self): | |
for key in self.tag_matrix_selected.keys(): | |
entry = self.tag_matrix_selected[key][4] | |
if entry: | |
self.table_selected_tags.remove(entry) | |
self.tag_matrix_selected[key][4:] = [0, 0, 0, 0, 0, 0, 0, 0] | |
def remove_all_entries_common_tags(self): | |
for key in self.tag_matrix_common.keys(): | |
entry = self.tag_matrix_common[key][4] | |
if entry: | |
self.table_common_tags.remove(entry) | |
self.tag_matrix_common[key][4:] = [0, 0, 0, 0, 0, 0, 0, 0] | |
def button_show_all_clicked(self, widget): | |
self.main_entry.set_text('') # delete the text in the main_entry | |
if self.get_entry_occupied_status(1, self.tag_matrix_selected): | |
self.main_entry.set_text('Tag already selected!') | |
return | |
# Show all tags as 'disabled' | |
self.set_entry_completion(self.index.list_all_tags(), 'all') | |
self.show_all_tag_entries() | |
def show_all_tag_entries(self): | |
for tag in self.tag_list_store: | |
self.show_tag(tag[0], self.search_scrolled_win_common_tags, self.tag_matrix_common, self.table_common_tags, | |
None, None, tag_toggle=1) | |
def main_entry_return(self, entry): | |
tag_exists = False | |
tag_entered = unicode(self.main_entry.get_text()) | |
if tag_entered == '': | |
return | |
for tag in self.tag_list_store: | |
if tag[0] == tag_entered: | |
tag_exists = True | |
break | |
if not tag_exists: | |
return | |
self.place_tag(tag_entered) | |
def search_filter(self, widget): | |
if not self.get_entry_occupied_status(1, self.tag_matrix_selected): | |
self.main_entry.set_text('Select tag first!') | |
return | |
self.switch_progress_bar("on") | |
self.clear_pages() | |
self.filter_hit_store.clear() | |
filter = unicode(self.filter_entry.get_text().strip()) | |
query = self.query(filter) | |
self.selection.search(query, callback=self.search_callback) | |
# TODO: handle error when no tags are shown | |
self.show_pages() | |
self.switch_progress_bar("off") | |
self.cancelled = False | |
def switch_progress_bar(self, switch): | |
if switch == "on": | |
self.progress_bar.set_fraction(0) | |
self.progress_bar.show() | |
self.button_cancel_search.show_all() | |
self.button_search.hide_all() | |
if switch == "off": | |
self.progress_bar.hide_all() | |
self.button_cancel_search.hide_all() | |
self.button_search.show_all() | |
self.progress_bar.set_fraction(0) | |
def set_progress_bar(self): | |
value = self.progress_bar.get_fraction() + self.progress_bar_fraction | |
percent = value * 100 | |
percent = str(int(percent)) | |
if not value > 1: | |
self.progress_bar.set_fraction(value) | |
self.progress_bar.set_text(percent + "%") | |
def search_cancel(self, widget): | |
self.cancelled = True | |
def search_callback(self, results, path): | |
while gtk.events_pending(): | |
gtk.main_iteration(block=False) | |
if results is not None: | |
if results.scores.get(path): # so, only if there is a path.name | |
self.filter_hit_store.append((path.name, results.scores.get(path))) | |
self.set_progress_bar() | |
return not self.cancelled | |
def match_selected(self, completion, model, iter): | |
tag_selected = unicode(model[iter][0]) | |
if tag_selected: | |
self.place_tag(tag_selected) | |
def place_tag(self, tag): | |
# place / toggle tag into top window | |
self.main_entry.set_text('') # Delete text doesn't work when tag is selected from popup :( | |
key_common = self.get_key_for_common_tag(tag) | |
if not key_common: # so it has not been placed yet | |
self.show_tag(tag, self.search_scrolled_win_selected_tags, | |
self.tag_matrix_selected, self.table_selected_tags, | |
None, None, tag_toggle=0) # 0 as it will be toggled to 1 | |
else: # needs to be toggled to selected tags | |
entry = self.get_entry(key_common, self.tag_matrix_common) | |
self.toggle_tag(tag, entry, self.tag_matrix_common, self.table_common_tags) | |
self.update_common_tags() | |
def show_tag(self, tag, window, matrix, table, left_info, right_info, tag_toggle): | |
tag_to_place = unicode(tag) | |
free_cell_key = self.get_free_cell_key(matrix) | |
if free_cell_key == False: # no free cell available | |
# start a new pair (equals new line) | |
# I need to add +1 to y1 and y2 for new index | |
# If I need to start a new line then x1=0, x2=1 for column 1 and | |
# x1=1, x2=2 for column 2 | |
last_key = len(matrix) | |
n_all_tags = self.index.n_list_all_tags() | |
# if show all is pressed more than once, but there should be a better way to handle this | |
if (last_key == n_all_tags) & (tag_toggle == 1): | |
return | |
# get y1, y2 from last matrix element | |
y1 = matrix[last_key][2] + 1 # add a new line to table | |
y2 = matrix[last_key][3] + 1 # just for readability. same as y2 = y1+1 | |
matrix[last_key + 1] = [0, 1, y1, y2, 0, 0, 0, 0, 0, 0, 0, 0] # new key | |
matrix[last_key + 2] = [1, 2, y1, y2, 0, 0, 0, 0, 0, 0, 0, 0] # new key | |
free_cell_key = self.get_free_cell_key(matrix) # now as we have 2 new free cells, get the 1. free cell key | |
x1, x2, y1, y2 = self.get_cell_pos(free_cell_key, matrix) | |
current_key = free_cell_key | |
entry = gtk.Entry() | |
entry_style = entry.get_style() # to get the current style of the entry | |
entry.set_property("editable", False) # Text in entry shall not be editable | |
entry.set_icon_from_stock(0, "gtk-convert") | |
entry.set_icon_tooltip_text(0, "Toggle tag from filter") | |
# entry.set_icon_from_stock(1, "gtk-close") ###### Removed for later implementation | |
# entry.set_icon_tooltip_text(1, "Remove tag from filter") ###### Removed for later implementation | |
n_tagged_pages = self.index.n_list_tagged_pages(tag_to_place) | |
entry.set_text("[" + str(n_tagged_pages) + "p] " + tag_to_place) # put the tag into the entry field | |
entry.set_tooltip_text(str(n_tagged_pages) + " pages with @" + tag_to_place) | |
entry.set_size_request(TAG_ENTRY_WIDTH_PIX, ENTRY_HIGHT_PIX) | |
entry.connect("icon-press", self.handle_entry_icon, tag_to_place, current_key, matrix, table) | |
table.attach(entry, x1, x2, y1, y2, xoptions=gtk.EXPAND, yoptions=gtk.EXPAND) | |
matrix[current_key][4] = entry # put the entry into the dict to find it | |
matrix[current_key][5] = 1 # table cell is occupied | |
matrix[current_key][6] = tag_toggle # toggle entry style | |
matrix[current_key][7] = entry_style # style for each entry (if needed) | |
matrix[current_key][9] = self.get_pages_for_tag(tag_to_place) # store all pages for this tag | |
matrix[current_key][10] = tag_to_place | |
# TODO: update pages in taq_matrix on signal, otherwise, data gets outdated | |
self.toggle_entry_status(entry, matrix) | |
window.show_all() | |
def toggle_tag(self, tag, entry, matrix, table): | |
self.main_entry.set_text('') # just in case | |
entry_key = self.get_entry_key(entry, matrix) | |
entry_status = self.get_entry_enabled_status(entry_key, matrix) | |
if entry_status: # so the tag is enabled and in the top window | |
# disable | |
matrix[entry_key][5] = 0 # set flag to free within tag_matrix_selected | |
# and move from top to bottom window | |
table.remove(entry) | |
self.show_tag(tag, self.search_scrolled_win_common_tags, self.tag_matrix_common, self.table_common_tags, | |
None, None, tag_toggle=1) | |
else: # the tag is disabled and in the bottom window | |
# enable | |
matrix[entry_key][5] = 0 # flag to free, as it will be moved up to selected | |
table.remove(entry) | |
self.show_tag(tag, self.search_scrolled_win_selected_tags, self.tag_matrix_selected, | |
self.table_selected_tags, None, None, tag_toggle=0) | |
return | |
def update_common_tags(self): | |
common_tags = self.get_common_tags_for_active_tags() # now get new common tags of selected tags | |
self.remove_all_entries_common_tags() | |
for common_tag in sorted(common_tags, key=lambda tag: tag.name): | |
self.show_tag(common_tag.name, self.search_scrolled_win_common_tags, self.tag_matrix_common, | |
self.table_common_tags, None, None, tag_toggle=1) # 0 as it will be toggled to 1 | |
self.show_pages() | |
self.set_entry_completion(common_tags, 'common') | |
return common_tags | |
def set_entry_completion(self, tags_list, scope): | |
if scope == 'all': | |
self.tag_list_store.clear() | |
for tag in tags_list: | |
self.tag_list_store.append([tag.name]) | |
self.completion.set_model(self.tag_list_store) | |
return | |
if scope == 'common': | |
tags_list_sorted = sorted(tags_list, key=lambda tag: tag.name) | |
common_tag_list_store = gtk.ListStore(str) | |
for tag in tags_list_sorted: | |
common_tag_list_store.append([tag.name]) | |
self.completion.set_model(common_tag_list_store) | |
return | |
def handle_entry_icon(self, entry, icon_pos, event, tag, key, matrix, table): | |
if icon_pos == 0: | |
self.handle_left_entry_icon(tag, key, entry, matrix, table) | |
# if icon_pos == 1: | |
# self.handle_right_entry_icon(entry, matrix, table) | |
def handle_right_entry_icon(self, entry, matrix, table): | |
# not used yet | |
table.remove(entry) | |
self.mark_cell_free(entry, matrix) | |
def handle_left_entry_icon(self, tag, key, entry, matrix, table): | |
self.toggle_tag(tag, entry, matrix, table) | |
self.update_common_tags() | |
def show_pages(self): | |
intersect_pages, union_pages = self.get_common_pages_of_active_tags() | |
filter_len = len(self.filter_hit_store) | |
if self.filter_entry.get_text() and filter_len: | |
intersect_pages_node_text = "All common pages of selected tags [" + str(len(intersect_pages)) + "p] " +\ | |
"with filter [" + str(len(self.filter_hit_store)) + "p]" | |
union_pages_node_text = "All unique pages of selected tags [" + str(len(intersect_pages)) + "p] " +\ | |
"with filter [" + str(len(self.filter_hit_store)) + "p]" | |
else: | |
intersect_pages_node_text = "All common pages of selected tags [" + str(len(intersect_pages)) + "p]" | |
union_pages_node_text = "All unique pages of selected tags [" + str(len(union_pages)) + "p]" | |
self.place_pages(intersect_pages, intersect_pages_node_text, union_pages, union_pages_node_text) | |
def clear_pages(self): | |
self.pages_tree_store.clear() | |
def place_pages(self, intersect_pages, intersect_pages_node_text, union_pages, union_pages_node_text): | |
self.clear_pages() | |
self.place_pages_with_nodes(intersect_pages, union_pages) | |
if self.checkbutton_inter_state: | |
parent_intersection = self.pages_tree_store.append(None, (intersect_pages_node_text, 0)) | |
for page in intersect_pages: | |
# for page in self.intersect_pages_list[1]: | |
# self.pages_tree_store.append(intersection, [page]) | |
if self.filter_entry.get_text() and self.filter_hit_store: | |
for hit in self.filter_hit_store: | |
if hit[0] == page.name: | |
self.pages_tree_store.append(parent_intersection, (page.basename, (hit[1] + 1))) | |
else: | |
self.pages_tree_store.append(parent_intersection, (page.basename, 1)) | |
self.pages_tree_view.expand_all() | |
if self.checkbutton_union_state: | |
parent_union = self.pages_tree_store.append(None, (union_pages_node_text, 0)) | |
for page in union_pages: | |
if self.filter_entry.get_text() and self.filter_hit_store: | |
for hit in self.filter_hit_store: | |
if hit[0] == page.name: | |
print ("Score: " + str(hit[1])) | |
print page.name | |
self.pages_tree_store.append(parent_union, (page.basename, (hit[1] + 1))) | |
else: | |
self.pages_tree_store.append(parent_union, (page.basename, 1)) | |
self.pages_tree_view.expand_all() | |
def place_pages_with_nodes(self, intersect_pages, union_pages): | |
page_roots_list = [] | |
intersect_page_namespace_set = set() | |
self.intersect_pages_list.append([]) | |
self.intersect_pages_list.append([]) | |
self.intersect_pages_list.append([]) | |
self.intersect_pages_list.append([]) | |
self.intersect_pages_list.append([]) | |
self.intersect_pages_list.append([]) | |
self.pages_tree_view.append_column(self.pages_column) | |
if self.checkbutton_inter_state: | |
for page in intersect_pages: | |
self.intersect_pages_list[0].append(page.name) | |
self.intersect_pages_list[1].append(page.basename) | |
# following not implemented yet | |
# self.intersect_pages_list[2].append(page.parts) | |
# self.intersect_pages_list[3].append(page.namespace) | |
# self.intersect_pages_list[4].append(page.parent.name) | |
# self.intersect_pages_list[5].append(page.isroot) | |
# http://cbio.ufs.ac.za/live_docs/nbn_tut/trees.html | |
# intersect_page_namespace_set.add(page.namespace) | |
def clear_entry(self, entry, iconpos, event): | |
entry.set_text('') | |
def clear_filter_entry(self, entry, iconpos, event): | |
if entry.get_text(): | |
entry.set_text('') | |
self.clear_pages() | |
self.filter_hit_store.clear() | |
self.show_pages() | |
def toggle_entry_status(self, entry, matrix): | |
entry_key = self.get_entry_key(entry, matrix) | |
entry_status = self.get_entry_enabled_status(entry_key, matrix) | |
entry_style = self.get_entry_style(entry_key, matrix) | |
if entry_status: | |
# disable | |
entry.modify_text(gtk.STATE_NORMAL, gtk.gdk.color_parse("grey")) | |
matrix[entry_key][6] = 0 # flag to disabled | |
else: | |
# enable | |
entry.modify_text(gtk.STATE_NORMAL, entry_style.text[gtk.STATE_NORMAL]) | |
matrix[entry_key][6] = 1 # flag to enabled | |
return | |
def get_common_tags_for_active_tags(self): | |
common_tags_list = [] | |
common_tags_set = set() | |
active_tags = self.get_active_tags() | |
for each_active_tag in active_tags: | |
common_tags_set_tmp = self.get_common_tags_for_tag(each_active_tag) | |
common_tags_list.append(common_tags_set_tmp) | |
if common_tags_list: | |
common_tags_set = set.intersection(*common_tags_list) | |
return common_tags_set | |
def get_common_tags_for_tags(self): | |
selected_tags_list = [] | |
common_tags_list = set() | |
tags = self.index.list_all_tags() | |
active_tags = self.get_active_tags() | |
# this is to get the tag name and index to lookup from db | |
for tag in tags: | |
for active_tag in active_tags: | |
if tag.name == active_tag: | |
selected_tags_list.append(tag) | |
intersecting_tags_name = self.index.list_intersecting_tags(selected_tags_list) | |
for each_tag in intersecting_tags_name: | |
common_tags_list.add(each_tag) | |
return common_tags_list | |
def get_common_tags_for_tag(self, tag): | |
common_tags_set = set() | |
tagged_pages_names_each_tag_set = set() | |
tagged_pages_names_selected_tag_set = set() | |
all_tags = self.index.list_all_tags() | |
tagged_pages_list_of_selected_tag = self.index.list_tagged_pages(tag) | |
# Put all pages of the selected tag into a set | |
for page in tagged_pages_list_of_selected_tag: | |
tagged_pages_names_selected_tag_set.add(page.name) | |
# now run through all tags except the selected tag | |
for each_tag in all_tags: | |
if each_tag.name == tag: | |
continue | |
tagged_pages_list_of_each_tag = self.index.list_tagged_pages(each_tag) | |
# put all pages of the current tag into another set | |
for page in tagged_pages_list_of_each_tag: | |
tagged_pages_names_each_tag_set.add(page.name) | |
# now do a intersection between both lists. | |
# Result is a list set with unique list of pages which both tags have in common | |
intersection_pages_set = (tagged_pages_names_selected_tag_set & tagged_pages_names_each_tag_set) | |
# if both tags, the selected and the current from the loop have at least one page in common then: | |
if intersection_pages_set: | |
# as the current tag has at least one page in common with the selected tag, add this tag into the list to show | |
common_tags_set.add(each_tag) | |
# just clear the temporary set to run over with the next tag | |
tagged_pages_names_each_tag_set.clear() | |
return common_tags_set | |
def get_common_pages_of_active_tags(self): | |
active_tags = self.get_active_tags() | |
tagged_pages_list_of_active_tags = [] | |
is_tagged_pages_of_active_tags = set() | |
u_tagged_pages_of_active_tags = set() | |
for active_tag in active_tags: | |
tagged_pages_set_of_active_tag = set(self.index.list_tagged_pages(active_tag)) | |
if tagged_pages_set_of_active_tag: | |
tagged_pages_list_of_active_tags.append(tagged_pages_set_of_active_tag) | |
if tagged_pages_list_of_active_tags: | |
is_tagged_pages_of_active_tags = set.intersection(*tagged_pages_list_of_active_tags) | |
u_tagged_pages_of_active_tags = set.union(*tagged_pages_list_of_active_tags) | |
return is_tagged_pages_of_active_tags, u_tagged_pages_of_active_tags | |
def get_entry_style(self, key, matrix): | |
return matrix[key][7] | |
def get_entry_enabled_status(self, key, matrix): | |
return matrix[key][6] | |
def get_entry_occupied_status(self, key, matrix): | |
return matrix[key][5] | |
def get_entry(self, key, matrix): | |
return matrix[key][4] | |
def get_entry_key(self, entry, matrix): | |
for key in matrix.keys(): | |
if matrix[key][4] == entry: # look for the cell pos of the deleted entry | |
return key | |
return False | |
def get_cell_pos(self, key, matrix): | |
x1 = matrix[key][0] | |
x2 = matrix[key][1] | |
y1 = matrix[key][2] | |
y2 = matrix[key][3] | |
return x1, x2, y1, y2 | |
def mark_cell_free(self, entry, matrix): | |
key = self.get_entry_key(entry, matrix) | |
if key: | |
matrix[key][5] = 0 # mark status of cell pos as 0 = empty | |
def get_free_cell_key(self, matrix): | |
for key in matrix.keys(): | |
if matrix[key][5] == 0: | |
return key | |
return False | |
def get_active_tags(self): | |
active_tags = [] | |
for key in self.tag_matrix_selected.keys(): | |
# the tag can be de-selected again | |
if self.tag_matrix_selected[key][5] and self.tag_matrix_selected[key][6]: | |
active_tags.append(self.tag_matrix_selected[key][10]) | |
return active_tags | |
def get_n_common_tags_shown(self): | |
common_tags_shown = [] | |
for key in self.tag_matrix_common.keys(): | |
# the tag can be de-selected again | |
if self.tag_matrix_common[key][5] and not self.tag_matrix_common[key][6]: | |
common_tags_shown.append(self.tag_matrix_common[key][10]) | |
return len(common_tags_shown) | |
def get_key_for_common_tag(self, tag): | |
for key in self.tag_matrix_common.keys(): | |
if self.tag_matrix_common[key][10] == tag: | |
return key | |
return False | |
def get_pages_for_tag(self, tag): | |
return self.index.list_tagged_pages(tag) | |
def get_word_at_cursor_pos(self, buffer): | |
try: | |
# preserve cursor position | |
cursor_orig = buffer.get_iter_at_mark(buffer.get_insert()) | |
cursor = buffer.get_iter_at_mark(buffer.get_insert()) | |
# no need to look up if cursor is at empty line | |
if cursor.ends_line() and cursor.starts_line(): | |
return | |
cursor.forward_word_end() | |
buffer.place_cursor(cursor) | |
word_end = buffer.get_iter_at_mark(buffer.get_insert()) | |
cursor.backward_word_start() | |
buffer.place_cursor(cursor) | |
word_start = buffer.get_iter_at_mark(buffer.get_insert()) | |
# just to not have changed anything, move cursor to start position | |
buffer.place_cursor(cursor_orig) | |
word = word_end.get_text(word_start) | |
except ValueError: | |
dummy = 0 | |
return False | |
return word |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment