zim-wiki team mailing list archive
-
zim-wiki team
-
Mailing list archive
-
Message #03574
Archive plugin
Attached a quick version of a plugin to automate archiving pages.
What it does:
1/ Adds a menu item "File --> Archive"
- this menu item moves current page to the archive and adds date stamp
2/ Adds a menu item "View --> Archived versions"
- shows a dialog with all archived versions of the current page (if any)
Still to do:
1/ Change search dialog to hide archived pages but add a button "show X
results from archived pages"
2/ Change auto-completion in "jump to" dialog to put archive lower in the
list
Please let me know what you think
Regards,
Jaap
# -*- coding: utf-8 -*-
# Copyright 2015 Jaap Karssenberg <jaap.karssenberg@xxxxxxxxx>
# TODO - hook into search dialog - hide archive + show button with "show X archived pages"
# TODO - hook into auto-completion - put archive lower in the list
from __future__ import with_statement
import gobject
import gtk
import re
import datetime
import logging
from zim.plugins import PluginClass, extends, WindowExtension
from zim.actions import action
from zim.notebook import Path
from zim.gui.widgets import ui_environment, Dialog, Button, \
WindowSidePaneWidget, LEFT_PANE, TOP, WIDGET_POSITIONS, \
BrowserTreeView, ScrolledWindow
logger = logging.getLogger('zim.plugins.archive')
class ArchivePlugin(PluginClass):
plugin_info = {
'name': _('Archive'), # T: plugin name
'description': _('''\
This plugin uses a section of the notebook as an archive.
This archive section is used to get pages out of the way from the
active notebook structere.
'''),
# T: plugin description
'author': 'Jaap Karssenberg',
'help': 'Plugins:Archive',
}
plugin_preferences = (
# key, type, label, default
('namespace', 'namespace', _('Section'), Path(':Archive')), # T: input label
#~ ('embedded', 'bool', _('Show calendar in sidepane instead of as dialog'), False), # T: preferences option
#~ ('pane', 'choice', _('Position in the window'), (LEFT_PANE, TOP), WIDGET_POSITIONS), # T: preferences option
)
# TODO disable pane setting if not embedded
def __init__(self, config=None):
PluginClass.__init__(self, config)
#~ self.preferences.connect('changed', self.on_preferences_changed)
#~ self.on_preferences_changed(self.preferences)
#~ def on_preferences_changed(self, preferences):
#~ if preferences['embedded']:
#~ self.set_extension_class('MainWindow', MainWindowExtensionEmbedded)
#~ else:
#~ self.set_extension_class('MainWindow', MainWindowExtensionDialog)
def archive_page(self, notebook, page):
postfix = datetime.date.today().strftime("_%Y%m%d")
section = self.preferences['namespace']
newpage = notebook.get_page(section + (page.name + postfix))
if newpage.exists():
i = 1
postfix = postfix + '_(%i)' % i
newpage = notebook.get_page(section + (page.name + postfix))
while new_page.exists():
i += 1
postfix = postfix + '_(%i)' % i
newpage = notebook.get_page(Path(page.name + postfix))
notebook.move_page(page, newpage)
def list_archived_versions(self, notebook, page):
# Find all pages in archive that look like page + postfix
# Find all pages in archive that look like page where parent
# has a postfix
# Yield pages and archive dates
def _versions(trunk, remainder):
basename = remainder.pop(0)
pattern = re.compile(re.escape(basename) + r'[ _](\d{8})([ _]\(\d+\))?$')
for path in notebook.index.list_pages(trunk):
match = pattern.search(path.basename)
if match: # branch with archive date
date = match.group(1)
if remainder:
child = path + remainder
if notebook.get_page(child).exists():
yield child, date
else:
yield path, date
elif path.basename == basename:
if remainder: # follow trunk
for r in _versions(path, remainder):
yield r
else:
pass # empty parent of archived pages
section = self.preferences['namespace']
for path, date in _versions(section, page.parts):
yield path, date
@extends('MainWindow')
class MainWindowExtensionDialog(WindowExtension):
'''Extension used to add calendar dialog to mainwindow'''
uimanager_xml = '''
<ui>
<menubar name='menubar'>
<menu action='file_menu'>
<placeholder name='page_modification_actions'>
<menuitem action='archive_page'/>
</placeholder>
</menu>
<menu action='view_menu'>
<placeholder name='plugin_items'>
<menuitem action='show_archived_versions'/>
</placeholder>
</menu>
</menubar>
</ui>
'''
@action(_('_Archive Page')) # T: menu item
def archive_page(self):
self.window.ui.save_page() # XXX
notebook = self.window.ui.notebook # XXX
page = self.window.pageview.get_page()
self.plugin.archive_page(notebook, page)
@action(_('_Archived Versions...'), tooltip=_('Show Archived Versions...')) # T: menu item
def show_archived_versions(self):
notebook = self.window.ui.notebook # XXX
page = self.window.pageview.get_page()
opener = self.window.get_resource_opener()
dialog = ArchivedVersionsDialog(self.window, self.plugin, notebook, page, opener)
dialog.present()
#~ @extends('SearchDialog')
#~ class SearchDialogExtension(WindowExtension):
#~ def __init__(self, plugin, window):
#~ WindowExtension.__init__(self, plugin, window)
# Install filter + button
#~ def teardown(self):
# REmove filter + button
class ArchivedVersionsDialog(Dialog):
# TODO "open" button that opens current selected version
def __init__(self, parent, plugin, notebook, page, opener):
Dialog.__init__(self, parent, _('Archived Pages'), # T: dialog title
defaultwindowsize=(400, 300),
buttons=gtk.BUTTONS_CLOSE,
)
label = gtk.Label(_('Archived versions of: <b>%s</b>') % page.name) # T: label, "%s" is the full page name
label.set_use_markup(True)
self.vbox.pack_start(label, False)
model = gtk.ListStore(str, str) # date, page
for path, date in plugin.list_archived_versions(notebook, page):
# TODO - get ctime and mtime for page
# TODO - get more user readable rendering of date - same as in "recent pages" dialog
date = "%s-%s-%s" % (date[0:4], date[4:6] ,date[6:8]) # year, month, day
model.append((date, path.name))
model.set_sort_column_id(0, gtk.SORT_DESCENDING)
treeview = BrowserTreeView()
self.vbox.add(ScrolledWindow(treeview))
cell_renderer = gtk.CellRendererText()
for name, i in (
(_('Date'), 0), # T: Column header archive dialog
(_('Page'), 1), # T: Column header archive dialog
):
column = gtk.TreeViewColumn(name, cell_renderer, text=i)
column.set_sort_column_id(i)
treeview.append_column(column)
treeview.set_model(model)
def on_open_page(view, path, col):
page = Path( view.get_model()[path][1].decode('utf-8') )
opener.open_page(page)
treeview.connect('row-activated', on_open_page)