~gnome-zeitgeist/gnome-activity-journal/minimal

« back to all changes in this revision

Viewing changes to src/store.py

  • Committer: tehk
  • Date: 2010-05-04 05:27:03 UTC
  • mfrom: (843.1.42 journal-rewrite)
  • Revision ID: tehk@tehk-desktop-20100504052703-pqp9o4yuewaoc9lv
new-core branch was merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -.- coding: utf-8 -.-
 
2
#
 
3
# store.py
 
4
#
 
5
# Copyright © 2010 Randal Barlow
 
6
#
 
7
# This program is free software: you can redistribute it and/or modify
 
8
# it under the terms of the GNU General Public License as published by
 
9
# the Free Software Foundation, either version 3 of the License, or
 
10
# (at your option) any later version.
 
11
#
 
12
# This program is distributed in the hope that it will be useful,
 
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
# GNU Lesser General Public License for more details.
 
16
#
 
17
# You should have received a copy of the GNU General Public License
 
18
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
 
 
20
import datetime
 
21
import gobject
 
22
import sys
 
23
import time
 
24
from zeitgeist.client import ZeitgeistClient, ZeitgeistDBusInterface
 
25
from zeitgeist.datamodel import Event, ResultType, Interpretation
 
26
 
 
27
import content_objects
 
28
 
 
29
CLIENT = ZeitgeistClient()
 
30
INTERFACE = ZeitgeistDBusInterface()
 
31
MAXEVENTS = 999999
 
32
 
 
33
#content_object_selector_function = (lambda x: None)
 
34
content_object_selector_function = content_objects.choose_content_object
 
35
 
 
36
tdelta = lambda x: datetime.timedelta(days=x)
 
37
 
 
38
 
 
39
def reduce_dates_by_timedelta(dates, delta):
 
40
    new_dates = []
 
41
    for date in dates:
 
42
        new_dates += [date + delta]
 
43
    return new_dates
 
44
 
 
45
 
 
46
class DoEmit(object):
 
47
    """
 
48
    Calls emit_update on the methods class
 
49
    """
 
50
    def __init__(self, signal):
 
51
        self.signal = signal
 
52
 
 
53
    def __call__(self, function):
 
54
        def wrapper(instance, *args, **kwargs):
 
55
            value = function(instance, *args, **kwargs)
 
56
            instance.emit(self.signal)
 
57
            return value
 
58
        return wrapper
 
59
 
 
60
 
 
61
class CachedAttribute(object):
 
62
    """
 
63
    runs the method once, finds the value, and replace the descriptor
 
64
    in the instance with the found value
 
65
    """
 
66
    def __init__(self, method, name=None):
 
67
        self.method = method
 
68
        self.attr_name = name or method.__name__
 
69
 
 
70
    def __get__(self, instance, cls):
 
71
        if instance is None:
 
72
            return self
 
73
        value = self.method(instance)
 
74
        setattr(instance, self.attr_name, value)
 
75
        return value
 
76
 
 
77
 
 
78
class ContentStruct(object):
 
79
    id = 0
 
80
    event = None
 
81
 
 
82
    @CachedAttribute
 
83
    def content_object(self):
 
84
        return content_object_selector_function(self.event)
 
85
 
 
86
    @CachedAttribute
 
87
    def event(self):
 
88
        events = INTERFACE.GetEvents([self.id])
 
89
        if events:
 
90
            return Event(events[0])
 
91
 
 
92
    def __init__(self, id, event=None, content_object=None, build=False):
 
93
        self.id = id
 
94
        if event:
 
95
            self.event = event
 
96
        if content_object:
 
97
            self.content_object = content_object
 
98
        if build:
 
99
            CLIENT.get_events([self.id], self.set_event)
 
100
 
 
101
    def set_event(self, value):
 
102
        if isinstance(value, tuple) or isinstance(value, list) and len(value):
 
103
            self.event = value[0]
 
104
        elif isinstance(value, Event):
 
105
            self.event = value
 
106
        else:
 
107
            self.event = ContentStruct.event
 
108
 
 
109
    def do_build(self):
 
110
        CLIENT.get_events([self.id], self.set_event)
 
111
 
 
112
 
 
113
class Day(gobject.GObject):
 
114
    __gsignals__ = {
 
115
        "update" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())
 
116
    }
 
117
 
 
118
 
 
119
    date = None
 
120
    start = 0
 
121
    end = 86400
 
122
 
 
123
    @property
 
124
    def time_range(self):
 
125
        return [self.start*1000, self.end*1000]
 
126
 
 
127
    @property
 
128
    def items(self):
 
129
        return self._items.values()
 
130
 
 
131
    @CachedAttribute
 
132
    def templates(self):
 
133
        return [Event.new_for_values()]
 
134
 
 
135
    def __init__(self, date):
 
136
        super(Day, self).__init__()
 
137
        self.date = date
 
138
        self._items = {}#id:ContentItem
 
139
        self.start = int(time.mktime(date.timetuple()))
 
140
        self.end = self.start+86399
 
141
        CLIENT.find_event_ids_for_templates(self.templates, self.set_ids, self.time_range, num_events=MAXEVENTS)
 
142
        CLIENT.install_monitor(self.time_range, self.templates, self.insert_events, self.remove_ids)
 
143
 
 
144
    def has_id(self, id_):
 
145
        return self._items.has_key(id_)
 
146
 
 
147
    def __getitem__(self, id_):
 
148
        return self._items[id_]
 
149
 
 
150
    def __len__(self):
 
151
        return len(self._items)
 
152
 
 
153
    @DoEmit("update")
 
154
    def set_ids(self, event_ids):
 
155
        for id_ in event_ids:
 
156
            self._items[id_] = ContentStruct(id_)
 
157
 
 
158
    @DoEmit("update")
 
159
    def remove_ids(self, time_range, ids):
 
160
        for id_ in ids:
 
161
            try:
 
162
                del self._items[id_]
 
163
            except KeyError:
 
164
                pass
 
165
 
 
166
    @DoEmit("update")
 
167
    def insert_events(self, time_range, events):
 
168
        for event in events:
 
169
            self._items[event.id] = ContentStruct(event.id, event)
 
170
 
 
171
    def next(self, store):
 
172
        date = self.date + datetime.timedelta(days=1)
 
173
        return store[date]
 
174
 
 
175
    def previous(self, store):
 
176
        date = self.date + datetime.timedelta(days=-1)
 
177
        return store[date]
 
178
 
 
179
    def filter(self, event_template=None, result_type=None):
 
180
        items = self.filter_event_template(event_template)
 
181
        items = self.filter_result_type(items, result_type)
 
182
        return items
 
183
 
 
184
    def filter_event_template(self, event_template):
 
185
        items = []
 
186
        if isinstance(event_template, Event):
 
187
            for obj in self._items.values():
 
188
                if obj.event.matches_template(event_template):
 
189
                    items.append(obj)
 
190
        elif event_template:
 
191
            for template in event_template:
 
192
                items += self.filter(template)
 
193
            items = list(set(items))
 
194
        return items
 
195
 
 
196
    def filter_result_type(self, items, result_type):
 
197
        if items and result_type is ResultType.MostRecentSubjects:
 
198
            item_dict = {}
 
199
            for item in items:
 
200
                subject_uri = item.event.subjects[0].uri
 
201
                item_dict[subject_uri] = item
 
202
            items = item_dict.values()
 
203
        return items
 
204
 
 
205
    def get_time_map(self):
 
206
        start = self.start
 
207
        results = {}
 
208
        for item in self.items:
 
209
            uri = item.event.subjects[0].uri
 
210
            if not uri in results:
 
211
                results[uri] = []
 
212
            if not item.event.interpretation == Interpretation.CLOSE_EVENT.uri:
 
213
                results[uri].append([item, 0])
 
214
            else:
 
215
                if not len(results[uri]) == 0:
 
216
                    #print "***", results[uri]
 
217
                    results[uri][len(results[uri])-1][1] = (int(item.event.timestamp)) -  int(results[uri][-1][0].event.timestamp)
 
218
                else:
 
219
                    tend = int(item.event.timestamp)
 
220
                    item.event.timestamp = str(start)
 
221
                    results[uri].append([item, tend - start])
 
222
        results = list(sorted(results.itervalues(), key=lambda r: \
 
223
                             r[0][0].event.timestamp))
 
224
        return results
 
225
 
 
226
 
 
227
class Store(gobject.GObject):
 
228
    __gsignals__ = {
 
229
        "update" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ())
 
230
    }
 
231
 
 
232
    @property
 
233
    def today(self):
 
234
        return self[datetime.date.today()]
 
235
 
 
236
    @property
 
237
    def days(self):
 
238
        dates = self.dates
 
239
        return [self._days[date] for date in dates]
 
240
 
 
241
    @property
 
242
    def dates(self):
 
243
        dates = self._days.keys()
 
244
        dates.sort()
 
245
        return dates
 
246
 
 
247
    def __init__(self):
 
248
        super(Store, self).__init__()
 
249
        self._days = {}
 
250
        self._day_connections = {}
 
251
        today = datetime.date.today()
 
252
        t = time.mktime(today.timetuple())
 
253
        for i in range(1,30*10):
 
254
            date = datetime.date.fromtimestamp(t)
 
255
            day = Day(date)
 
256
            self.add_day(date, day)
 
257
            t -= 86400
 
258
 
 
259
    @DoEmit("update")
 
260
    def add_day(self, key, day):
 
261
        self._days[key] = day
 
262
        self._day_connections[key] = day.connect("update", lambda *args: self.emit("update"))
 
263
 
 
264
    def __getitem__(self, key):
 
265
        if isinstance(key, datetime.date):
 
266
            # Return day from date
 
267
            try:
 
268
                return self._days[key]
 
269
            except KeyError:
 
270
                day = Day(key)
 
271
                self.add_day(key, day)
 
272
                return day
 
273
        elif isinstance(key, int):
 
274
            # Return event id
 
275
            for date, obj in self._days.iteritems():
 
276
                if obj.has_id(id):
 
277
                    return obj[id]
 
278
        raise KeyError("%s Not found" % key)
 
279
 
 
280
    def __len__(self):
 
281
        i = 0
 
282
        for item in self._days.itervalues():
 
283
            i+=len(item)
 
284
        return i
 
285
 
 
286
gobject.type_register(Day)
 
287
gobject.type_register(Store)
 
288