diff options
author | Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com> | 2012-10-12 16:56:17 +0200 |
---|---|---|
committer | Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com> | 2012-10-12 16:56:17 +0200 |
commit | 491dbf8d1c90cd029d78276065ab3d9c299a27aa (patch) | |
tree | d679e0f9479134c607dfade84c0a640e402427c6 /tools | |
parent | b08cb136d69093e12c8d7ad730f1ce2230c7a48a (diff) | |
download | zeitgeist-491dbf8d1c90cd029d78276065ab3d9c299a27aa.tar.gz |
Add zeitgeist-explorer tool
This is a copy of the code from:
lp:~zeitgeist/zeitgeist-explorer/trunk-old
For an alternative, more advanced tool see:
https://launchpad.net/zeitgeist-explorer
Diffstat (limited to 'tools')
-rw-r--r-- | tools/zeitgeist-explorer/details.py | 194 | ||||
-rw-r--r-- | tools/zeitgeist-explorer/ontology.py | 116 | ||||
-rw-r--r-- | tools/zeitgeist-explorer/remote.py | 72 | ||||
-rw-r--r-- | tools/zeitgeist-explorer/widgets.py | 101 | ||||
-rwxr-xr-x | tools/zeitgeist-explorer/zeitgeist-explorer | 186 |
5 files changed, 669 insertions, 0 deletions
diff --git a/tools/zeitgeist-explorer/details.py b/tools/zeitgeist-explorer/details.py new file mode 100644 index 00000000..1c39fd82 --- /dev/null +++ b/tools/zeitgeist-explorer/details.py @@ -0,0 +1,194 @@ +# -.- coding: utf-8 -.- +# +# Zeitgeist Explorer +# +# Copyright © 2011 Collabora Ltd. +# By Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com> +# Copyright © 2010 Siegfried Gevatter <siegfried@gevatter.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gtk +import gobject + +from zeitgeist.datamodel import Interpretation, Manifestation + +import ontology + +class _DetailsWindow(gtk.Window): + + _main_box = None + _main_table = None + + def __init__(self, *args, **kwargs): + super(_DetailsWindow, self).__init__() + self.set_resizable(False) + + self._main_box = gtk.VBox() + self.add(self._main_box) + + self._build_window(*args, **kwargs) + + button_box = gtk.HBox() + button_box.pack_start(gtk.Label("")) + close_button = gtk.Button(stock=gtk.STOCK_CLOSE) + close_button.connect('clicked', lambda *discard: self.destroy()) + button_box.pack_start(close_button, False) + self._main_box.pack_start(button_box, True, False) + close_button.grab_focus() + + self.show_all() + + def _add_title(self, title_text): + title = gtk.Label() + title.set_markup('<b>%s</b>' % title_text) + title.set_alignment(0, 0) + title.set_padding(5, 5) + title.set_selectable(True) + self._main_box.pack_start(title, False) + + def _add_table_entry(self, pos, label, value, tooltip=None, info=None): + entry_label = gtk.Label() + entry_label.set_markup('<b>%s:</b>' % label) + entry_label.set_alignment(0, 0) + entry_label.set_selectable(True) + + value_label = gtk.Label() + if value: + value_label.set_text(value) + else: + value_label.set_markup('<i>%s</i>' % _('No value')) + value_label.set_alignment(0, 0) + value_label.set_selectable(True) + + if tooltip: + value_label.set_tooltip_text(tooltip) + + self._main_table.attach(entry_label, 0, 1, pos, pos + 1, + xoptions=gtk.FILL, yoptions=gtk.FILL, xpadding=5, ypadding=5) + self._main_table.attach(value_label, 1, 2, pos, pos + 1, + yoptions=gtk.FILL, xpadding=5, ypadding=5) + + if info: + info_image = gtk.Image() + info_image.set_from_stock(gtk.STOCK_INFO, gtk.ICON_SIZE_BUTTON) + info_button = gtk.Button() + info_button.set_image(info_image) + info_button.connect('clicked', lambda *discard: info()) + self._main_table.attach(info_button, 2, 3, pos, pos + 1, + xoptions=gtk.FILL, yoptions=gtk.FILL) + + def _add_table_separator(self, pos): + self._main_table.attach(gtk.HSeparator(), 0, 3, pos, pos + 1) + +class EventDetails(_DetailsWindow): + + _event = None + _subjects_view = None + + def _build_window(self, event): + self.set_title(_('Event #%s: %s') % (event.id, event.date_string)) + self._event = event + + self._add_title(_('Event #%s') % event.id) + + self._main_table = gtk.Table(5, 3) + self._main_box.pack_start(self._main_table, False) + + timestamp_text = '%s (%.3f)' % (event.date_string, + int(event.timestamp) / 1000.0) + self._add_table_entry(0, _('Timestamp'), timestamp_text) + self._add_table_entry(1, _('Interpretation'), event.interp_string, + event.interpretation, ontology.EventInterpretationHelp) + self._add_table_entry(2, _('Manifestation'), event.manif_string, + event.manifestation, ontology.EventManifestationHelp) + self._add_table_entry(3, _('Actor'), event.actor) + self._add_table_entry(4, _('Origin'), event.origin) + + self._subjects_view = EventSubjectsTreeView() + self._main_box.pack_start(self._subjects_view, False) + + for subject in event.subjects: + self._subjects_view.add_subject(subject) + +class SubjectDetails(_DetailsWindow): + + _subject = None + + def _build_window(self, subject): + self.set_title(_('Subject: %s') % subject.text) + self._subject = subject + + self._add_title(_('Subject: %s') % subject.text) + + self._main_table = gtk.Table(8, 3) + self._main_box.pack_start(self._main_table, False) + + self._add_table_entry(0, _('URI'), subject.uri) + self._add_table_entry(1, _('Interpretation'), subject.interp_string, + subject.interpretation, ontology.SubjectInterpretationHelp) + self._add_table_entry(2, _('Manifestation'), subject.manif_string, + subject.manifestation, ontology.SubjectManifestationHelp) + self._add_table_entry(3, _('Origin'), subject.origin) + self._add_table_entry(4, _('MIME-Type'), subject.mimetype) + self._add_table_entry(5, _('Storage'), subject.storage) + self._add_table_separator(6) + self._add_table_entry(7, _('Current URI'), subject.current_uri) + + self.show_all() + +class EventSubjectsTreeView(gtk.TreeView): + + _store = None + + def __init__(self): + super(EventSubjectsTreeView, self).__init__() + + self._store = gtk.TreeStore(str, str, str, gobject.TYPE_PYOBJECT) + self.set_model(self._store) + self.set_search_column(0) + + col = self._create_column(_('Subject'), 0) + col = self._create_column(_('Interpretation'), 1) + col = self._create_column(_('Manifestation'), 2) + + self.connect('button-press-event', self._on_click) + + def _get_data_from_event(self, event): + x, y = (int(round(event.x)), int(round(event.y))) + treepath = self.get_path_at_pos(x, y)[0] + treeiter = self._store.get_iter(treepath) + return self._store.get_value(treeiter, 3) + + def _on_click(self, widget, event): + if event.type == gtk.gdk._2BUTTON_PRESS: + data = self._get_data_from_event(event) + SubjectDetails(data) + + def _create_column(self, name, data_col, cell_renderer=gtk.CellRendererText()): + column = gtk.TreeViewColumn(name, cell_renderer) + column.set_expand(True) + column.set_sort_column_id(data_col) + column.add_attribute(cell_renderer, 'text', data_col) + self.append_column(column) + return (column, cell_renderer) + + def add_subject(self, subject): + self._store.append(None, [ + subject.text, + Interpretation[subject.interpretation].display_name, + Manifestation[subject.manifestation].display_name, + subject]) + +# vim:noexpandtab:ts=4:sw=4 diff --git a/tools/zeitgeist-explorer/ontology.py b/tools/zeitgeist-explorer/ontology.py new file mode 100644 index 00000000..72875e75 --- /dev/null +++ b/tools/zeitgeist-explorer/ontology.py @@ -0,0 +1,116 @@ +# -.- coding: utf-8 -.- +# +# Zeitgeist Explorer +# +# Copyright © 2011 Collabora Ltd. +# By Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com> +# Copyright © 2010 Siegfried Gevatter <siegfried@gevatter.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gtk +import gobject + +from zeitgeist.datamodel import Interpretation, Manifestation + +class _HelpWindow(gtk.Window): + + def __init__(self, title): + super(_HelpWindow, self).__init__() + self.set_title(title) + self.set_size_request(700, 400) + + self._main_box = gtk.VBox() + self.add(self._main_box) + + values = self._get_values() + + self._main_table = gtk.Table(len(values) * 2, 2) + sw = gtk.ScrolledWindow() + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + sw.add_with_viewport(self._main_table) + self._main_box.pack_start(sw) + + for i, value in enumerate(values): + self._add_table_entry(2*i, value.display_name, value.uri, value.doc) + + self.show_all() + + def _add_table_entry(self, pos, name, uri, doc): + entry_label = gtk.Label() + entry_label.set_markup('<b>%s</b>' % name) + entry_label.set_alignment(0, 0) + entry_label.set_selectable(True) + + value_label = gtk.Label() + value_label.set_text(uri) + value_label.set_alignment(0, 0) + value_label.set_selectable(True) + + doc_label = gtk.Label() + doc_label.set_markup('<i>%s</i>' % doc) + doc_label.set_alignment(0, 0) + doc_label.set_line_wrap(True) + doc_label.set_selectable(True) + + self._main_table.attach(entry_label, 0, 1, pos, pos + 1, + xoptions=gtk.FILL, yoptions=gtk.FILL, xpadding=5, ypadding=5) + self._main_table.attach(value_label, 1, 2, pos, pos + 1, + yoptions=gtk.FILL, xpadding=5, ypadding=5) + self._main_table.attach(doc_label, 0, 2, pos + 1, pos + 2, + yoptions=gtk.FILL, xpadding=5, ypadding=5) + +class EventInterpretationHelp(_HelpWindow): + + def __init__(self): + title = _('Event Interpretations') + super(EventInterpretationHelp, self).__init__(title) + + def _get_values(self): + return Interpretation.EVENT_INTERPRETATION.get_all_children() + +class SubjectInterpretationHelp(_HelpWindow): + + def __init__(self): + title = _('Subject Interpretations') + super(SubjectInterpretationHelp, self).__init__(title) + + def _get_values(self): + interpretations = set() + for child in Interpretation.iter_all_children(): + if not child.is_child_of(Interpretation.EVENT_INTERPRETATION): + interpretations.add(child) + return interpretations + +class EventManifestationHelp(_HelpWindow): + + def __init__(self): + title = _('Event Manifestations') + super(EventManifestationHelp, self).__init__(title) + + def _get_values(self): + return Manifestation.EVENT_MANIFESTATION.get_all_children() + +class SubjectManifestationHelp(_HelpWindow): + + def __init__(self): + title = _('Subject Manifestations') + super(SubjectManifestationHelp, self).__init__(title) + + def _get_values(self): + manifestations = set() + for child in Manifestation.iter_all_children(): + if not child.is_child_of(Manifestation.EVENT_MANIFESTATION): + manifestations.add(child) + return manifestations diff --git a/tools/zeitgeist-explorer/remote.py b/tools/zeitgeist-explorer/remote.py new file mode 100644 index 00000000..1983a030 --- /dev/null +++ b/tools/zeitgeist-explorer/remote.py @@ -0,0 +1,72 @@ +# -.- coding: utf-8 -.- +# +# Zeitgeist Explorer +# +# Copyright © 2011-2012 Collabora Ltd. +# By Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import time + +from zeitgeist.client import ZeitgeistClient +from zeitgeist.datamodel import * + +__all__ = ['get_interface'] + +class CustomSubject(Subject): + + @property + def interp_string(self): + try: + return Interpretation[self.interpretation].display_name + except (KeyError, AttributeError): + return None + + @property + def manif_string(self): + try: + return Manifestation[self.manifestation].display_name + except (KeyError, AttributeError): + return None + +class CustomEvent(Event): + + _subject_type = CustomSubject + + @property + def date_string(self): + return time.ctime(int(self.timestamp) / 1000) + + @property + def interp_string(self): + try: + return Interpretation[self.interpretation].display_name + except (KeyError, AttributeError): + return None + + @property + def manif_string(self): + try: + return Manifestation[self.manifestation].display_name + except (KeyError, AttributeError): + return None + +_zg = None +def get_interface(): + global _zg + if _zg is None: + _zg = ZeitgeistClient() + _zg.register_event_subclass(CustomEvent) + return _zg diff --git a/tools/zeitgeist-explorer/widgets.py b/tools/zeitgeist-explorer/widgets.py new file mode 100644 index 00000000..baf136c4 --- /dev/null +++ b/tools/zeitgeist-explorer/widgets.py @@ -0,0 +1,101 @@ +# -.- coding: utf-8 -.- +# +# Zeitgeist Explorer +# +# Copyright © 2011 Collabora Ltd. +# By Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com> +# Copyright © 2011 Stefano Candori <stefano.candori@gmail.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gtk +import time +import gobject + +class CalendarPopup(gtk.Dialog): + + calendar = None + + _callback = None + _associated_widget = None + + def __init__(self, associated_widget, callback=None): + super(CalendarPopup, self).__init__(None) + self.calendar = gtk.Calendar() + self._associated_widget = associated_widget + self._callback = callback + self.vbox.pack_start(self.calendar) + self.set_decorated(False) + self.set_position(gtk.WIN_POS_NONE) + self.set_property('skip-taskbar-hint', True) + self.connect('focus-out-event', + lambda *discard: self.hide(False)) + self.calendar.connect('day-selected-double-click', + lambda *discard: self.hide(True)) + + def hide(self, accepted=False): + super(CalendarPopup, self).hide() + if accepted and self._callback: + self._callback(self.calendar.get_date()) + + def show(self): + widget_pos = self._associated_widget.get_allocation() + parent_pos = self._associated_widget.get_parent_window().get_position() + self.move(parent_pos[0] + widget_pos.x, + parent_pos[1] + widget_pos.y + widget_pos.height) + self.show_all() + +class DateSelector(gtk.Button): + + _calendar_popup = None + + def __init__(self): + super(DateSelector, self).__init__() + def cb(foo): + print foo + self._calendar_popup = CalendarPopup(self, cb) + self.connect('clicked', lambda *discard: self._calendar_popup.show()) + self.set_label('%d-%d-%d' % self._calendar_popup.calendar.get_date()) + + @property + def calendar(self): + return self._calendar_popup.calendar + +class TimeSelector(gtk.HBox): + + _hour_selector = None + _minute_selector = None + + def __init__(self): + super(TimeSelector, self).__init__() + self._hour_selector = gtk.SpinButton(gtk.Adjustment(0, 0, 24, 1)) + self._minute_selector = gtk.SpinButton(gtk.Adjustment(0, 0, 60, 1)) + self.pack_start(self._hour_selector) + self.pack_start(gtk.Label(':')) + self.pack_start(self._minute_selector) + +class DateTimeSelector(gtk.HBox): + + _date_selector = None + _time_selector = None + + def __init__(self): + super(DateTimeSelector, self).__init__() + self._date_selector = DateSelector() + self._time_selector = TimeSelector() + self.pack_start(self._date_selector) + self.pack_start(self._time_selector) + + def get_timestamp(self): + return 0 diff --git a/tools/zeitgeist-explorer/zeitgeist-explorer b/tools/zeitgeist-explorer/zeitgeist-explorer new file mode 100755 index 00000000..7d69992b --- /dev/null +++ b/tools/zeitgeist-explorer/zeitgeist-explorer @@ -0,0 +1,186 @@ +#! /usr/bin/env python +# -.- coding: utf-8 -.- +# +# Zeitgeist Explorer +# +# Copyright © 2011-2012 Collabora Ltd. +# By Siegfried-Angel Gevatter Pujals <siegfried@gevatter.com> +# Copyright © 2010 Siegfried Gevatter <siegfried@gevatter.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import gtk +import gobject + +from zeitgeist.datamodel import Event, Subject, Interpretation, Manifestation, \ + ResultType + +import remote +import details +from widgets import DateTimeSelector + +class MainWindow(gtk.Window): + + _main_box = None + _filter_box = None + _event_list = None + _remote = None + + _start_date = None + _end_date = None + _result_type = None + + def __init__(self): + super(MainWindow, self).__init__() + self.connect('destroy', gtk.main_quit) + self.set_title(_('Zeitgeist Explorer')) + self.set_size_request(700, 400) + self._remote = remote.get_interface() + + self._main_box = gtk.VBox() + self.add(self._main_box) + + self._filter_box = gtk.Expander(_('Query')) + self._filter_box.set_expanded(False) + self._main_box.pack_start(self._filter_box, False) + + self._create_filter_box() + + separator = gtk.HSeparator() + separator.set_size_request(-1, 15) + self._main_box.pack_start(separator, False) + + self._event_list = MainTreeView() + sw = gtk.ScrolledWindow() + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + sw.add(self._event_list) + self._main_box.pack_start(sw) + + self.show_all() + self._refresh() + + def _create_filter_box(self): + self._filter_vbox = gtk.VBox() + self._filter_box.add(self._filter_vbox) + + def create_label(label): + label_widget = gtk.Label(label) + label_widget.set_size_request(100, -1) + return label_widget + + def add_property(label, other_widget): + timestamp_box = gtk.HBox() + timestamp_box.pack_start(create_label(label), False) + timestamp_box.pack_start(other_widget, False) + self._filter_vbox.add(timestamp_box) + + self._start_date = DateTimeSelector() + self._end_date = DateTimeSelector() + add_property(_('Start date:'), self._start_date) + add_property(_('End date:'), self._end_date) + + result_types_model = gtk.ListStore(str, str) + self._result_type = gtk.ComboBox(result_types_model) + cell_renderer = gtk.CellRendererText() + self._result_type.pack_start(cell_renderer, True) + self._result_type.add_attribute(cell_renderer, 'text', 0) + add_property(_('Result type:'), self._result_type) + + for i, (result_type, number) in enumerate(ResultType.iteritems()): + result_types_model.append((result_type, number)) + if number == ResultType.MostRecentEvents: + self._result_type.set_active(i) + + refresh = gtk.Button(stock=gtk.STOCK_REFRESH) + refresh.connect('clicked', self._refresh) + self._filter_vbox.pack_start(refresh, False) + + def _refresh(self, *discard): + self._remote.find_events_for_templates ([], self._populate_list, + num_events=100, result_type=ResultType.MostRecentEvents) + + def _populate_list(self, events): + self._event_list.set_events(events) + return False + +class MainTreeView(gtk.TreeView): + + _store = None + + def __init__(self): + super(MainTreeView, self).__init__() + + # TODO: It may make sense to use GenericTreeModel here. + self._store = gtk.TreeStore(str, str, str, gobject.TYPE_PYOBJECT) + self.set_model(self._store) + self.set_search_column(0) + + col = self._create_column(_('Event'), 0) + col = self._create_column(_('Interpretation'), 1) + col = self._create_column(_('Manifestation'), 2) + + self.connect('button-press-event', self._on_click) + + def _get_data_from_event(self, event): + x, y = (int(round(event.x)), int(round(event.y))) + treepath = self.get_path_at_pos(x, y)[0] + treeiter = self._store.get_iter(treepath) + return self._store.get_value(treeiter, 3) + + def _on_click(self, widget, event): + if event.type == gtk.gdk._2BUTTON_PRESS: + data = self._get_data_from_event(event) + if isinstance(data, Event): + details.EventDetails(data) + elif isinstance(data, Subject): + details.SubjectDetails(data) + else: + print 'Unknown row selected.' + + def _create_column(self, name, data_col, cell_renderer=gtk.CellRendererText()): + column = gtk.TreeViewColumn(name, cell_renderer) + column.set_expand(True) + column.set_sort_column_id(data_col) + column.add_attribute(cell_renderer, 'text', data_col) + self.append_column(column) + return (column, cell_renderer) + + def _event_to_text(self, event): + return '%s' % (event.date_string) + + def _subject_to_text(self, subject): + return '%s' % (subject.text) + + def _add_item(self, event): + def _event_row(event): + return [self._event_to_text(event), event.interp_string, + event.manif_string, event] + event_iter = self._store.append(None, _event_row(event)) + for subject in event.get_subjects(): + self._store.append(event_iter, [self._subject_to_text(subject), + subject.interp_string, subject.manif_string, subject]) + + def set_events(self, events): + self._store.clear() + map(self._add_item, events) + self.expand_all() + +if __name__ == '__main__': + try: + main_window = MainWindow() + gtk.main() + except KeyboardInterrupt: + print 'Bye...' + +# vim:noexpandtab:ts=4:sw=4 |