3
# Copyright (C) 2008, J. Félix Ontañón <fontanon at emergya dot es>
4
# Thanks to John Carr for helpful patching
6
# This file is part of Project Hamster.
8
# Project Hamster is free software: you can redistribute it and/or modify
9
# it under the terms of the GNU General Public License as published by
10
# the Free Software Foundation, either version 3 of the License, or
11
# (at your option) any later version.
13
# Project Hamster is distributed in the hope that it will be useful,
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
# GNU General Public License for more details.
18
# You should have received a copy of the GNU General Public License
19
# along with Project Hamster. If not, see <http://www.gnu.org/licenses/>.
25
from calendar import timegm
27
from configuration import runtime
29
# DBus service parameters
30
HAMSTER_URI = "org.gnome.Hamster"
33
class HamsterDbusController(dbus.service.Object):
34
# Non-initialized current fact id
37
def __init__(self, bus_name):
38
"""HamsterDbusController encapsulates the dbus api logic
39
for the hamster-applet and performs the necesary conversion
40
between dbus types and hamster-applet data types
43
dbus.service.Object.__init__(self, bus_name, "/org/gnome/Hamster")
45
# KeyError is thrown when the dbus interface is taken
46
# that is there is other hamster running somewhere
47
logging.warn("D-Bus interface registration failed - other hamster running somewhere")
50
def _to_dbus_fact(fact):
51
"""Perform the conversion between fact database query and
52
dbus supported data types
55
return dbus.Dictionary({}, signature='sv')
58
for key in fact.keys():
59
fact[key] = fact[key] or 0
61
# make sure we return correct type where strings are expected
62
if not fact[key] and key in ('name', 'category', 'description'):
65
# convert times to gmtime
66
if isinstance(fact[key], datetime.datetime) or isinstance(fact[key], datetime.date):
67
fact[key] = timegm(fact[key].timetuple())
68
elif isinstance(fact[key], datetime.timedelta) :
69
fact[key] = fact[key].days * 24 * 60 * 60 + fact[key].seconds
74
@dbus.service.method(HAMSTER_URI, out_signature='a{sv}')
75
def GetCurrentFact(self):
76
"""Gets the current displaying fact
78
i id: Unique fact identifier
80
s category: Category name
81
s description: Description of the fact
82
u start_time: Seconds since epoch (timestamp)
83
u end_time: Seconds since epoch (timestamp)
84
u end_time: Seconds since epoch (timestamp)
85
as tags: List of tags used
87
return HamsterDbusController._to_dbus_fact(runtime.storage.get_last_activity())
89
@dbus.service.method(HAMSTER_URI, in_signature='i', out_signature='a{sv}')
90
def GetFactById(self, fact_id):
91
"""Gets the current displaying fact
93
i id: Unique fact identifier
95
i id: Unique fact identifier
97
s category: Category name
98
s description: Description of the fact
99
u start_time: Seconds since epoch (timestamp)
100
u end_time: Seconds since epoch (timestamp)
101
as tags: List of tags used
103
return HamsterDbusController._to_dbus_fact(runtime.storage.get_fact(fact_id))
105
@dbus.service.method(HAMSTER_URI, in_signature='uu', out_signature='aa{sv}')
106
def GetFacts(self, start_date, end_date):
107
"""Gets facts between the day of start_date and the day of end_date.
109
u start_date: Seconds since epoch (timestamp). Use 0 for today
110
u end_date: Seconds since epoch (timestamp). Use 0 for today
111
Returns Array of fact where fact it's Dict of:
112
i id: Unique fact identifier
113
s name: Activity name
114
s category: Category name
115
s description: Description of the fact
116
u start_time: Seconds since epoch (timestamp)
117
u end_time: Seconds since epoch (timestamp)
118
as tags: List of tags used
120
#TODO: Assert start > end ?
122
start = datetime.datetime.utcfromtimestamp(start_date).date()
124
start = datetime.date.today()
127
end = datetime.datetime.utcfromtimestamp(end_date).date()
129
end = datetime.date.today()
131
facts = dbus.Array([], signature='a{sv}')
132
for fact in runtime.storage.get_facts(start, end):
133
facts.append(HamsterDbusController._to_dbus_fact(fact))
137
@dbus.service.method(HAMSTER_URI, out_signature='a(ss)')
138
def GetActivities(self):
139
"""Gets all defined activities with matching category
141
s activity: Activity name
142
s category: Category name
144
activities = dbus.Array([], signature='(ss)')
145
for act in runtime.storage.get_autocomplete_activities():
146
activities.append((act['name'] or '', act['category'] or ''))
149
@dbus.service.method(HAMSTER_URI, out_signature='as')
151
"""Returns array of all active tags"""
152
tags = dbus.Array([], signature='s')
154
for tag in runtime.storage.get_tags():
155
tags.append(tag['name'] or '')
158
@dbus.service.method(HAMSTER_URI, in_signature='s')
159
def SetAutocompleteTags(self, tags):
160
"""Update autocomplete tags with the given comma-delimited list.
161
If a tag is gone missing, it will be deleted if it has not been used.
162
If it has been used, it will be marked as not to be used in autocomplete
163
(and revived on first use). New tags will just appear.
165
s tags: Comma-separated tags ("tag1, tag2, tag3, and so, on")
167
runtime.storage.update_autocomplete_tags(tags)
169
@dbus.service.method(HAMSTER_URI, out_signature='ss')
170
def GetCurrentActivity(self):
171
"""Returns the Activity currently being used, or blanks if Hamster is not tracking currently
172
s activity: Activity name
173
s category: Category name
175
last_activity = runtime.storage.get_last_activity()
177
return (last_activity['name'] or '', last_activity['category'] or '')
181
@dbus.service.method(HAMSTER_URI, out_signature='as')
182
def GetCategories(self):
183
"""Gets all defined categories
185
s category: Category name
187
categories = dbus.Array([], signature='s')
188
for cat in runtime.storage.get_category_list():
189
categories.append(cat['name'] or '')
192
@dbus.service.method(HAMSTER_URI, in_signature='suu', out_signature='i')
193
def AddFact(self, activity, start_time, end_time):
196
s activity: Activity name with optional category, description and tags
198
'activity_name[@category_name][,description][#tag1 #tagN]'
199
Activity, matching category and tags will be refered or
201
u start_time: Seconds since epoch (timestamp). Use 0 for 'now'
202
u end_time: Seconds since epoch (timestamp). Use 0 for ongoing task
204
#TODO: Assert start > end ?
205
start, end = None, None
208
start = datetime.datetime.utcfromtimestamp(start_time)
210
end = datetime.datetime.utcfromtimestamp(end_time)
212
return runtime.storage.add_fact(activity, "", start, end)
214
@dbus.service.method(HAMSTER_URI, in_signature='ss')
215
def AddActivity(self, activity, category):
216
"""Add a new activity
218
s activity: Activity name
219
s category: Category name. It will be created if it doesn't exists
220
Use '' for Unsorted activity
225
category_id = runtime.storage.get_category_by_name(category) \
226
or runtime.storage.add_category(category)
228
runtime.storage.add_activity(activity, category_id)
230
@dbus.service.method(HAMSTER_URI, in_signature='s')
231
def AddCategory(self, category):
232
"""Add a new category
234
s category: category name
236
if category and not runtime.storage.get_category_by_name(category):
237
runtime.storage.add_category(category)
239
@dbus.service.method(HAMSTER_URI)
240
def StopTracking(self):
241
"""Stops the current fact tracking"""
242
last_activity = runtime.storage.get_last_activity()
244
runtime.storage.touch_fact(last_activity)
246
@dbus.service.method(HAMSTER_URI, in_signature='i')
247
def RemoveFact(self, fact_id):
250
i id: Unique fact identifier
252
runtime.storage.remove_fact(fact_id)
254
@dbus.service.method(HAMSTER_URI, in_signature='ss')
255
def RemoveActivity(self, activity_name, category):
256
"""Removes an activity
258
s activity: Activity name
259
s category: Category name. Use '' for Unsorted activity
261
category_id = runtime.storage.get_category_by_name(category)
262
activity = runtime.storage.get_activity_by_name(activity_name, category_id)
265
runtime.storage.remove_activity(activity['id'])
267
@dbus.service.method(HAMSTER_URI, in_signature='s')
268
def RemoveCategory(self, category):
269
"""Removes a category
271
s category: Category name
273
category_id = runtime.storage.get_category_by_name(category)
275
runtime.storage.remove_category(category_id)
277
@dbus.service.signal(HAMSTER_URI, signature='i')
278
def FactUpdated(self, fact_id):
279
"""Notifies fact changes
281
i id: Unique fact identifier
283
self.current_fact_id = fact_id
285
@dbus.service.signal(HAMSTER_URI)
286
def TrackingStopped(self):
287
"""Notifies the fact tracking has been stopped"""
288
self.current_fact_id = 0