[hamster-applet/windows] Merged win32 into src
- From: Matthew Howle <mdhowle src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [hamster-applet/windows] Merged win32 into src
- Date: Fri, 25 Mar 2011 23:14:11 +0000 (UTC)
commit 8123c3ef3ae9efd2b2ecb90e46c6b4b88b12bfe5
Author: Matthew Howle <matthew howle org>
Date: Fri Mar 25 08:14:36 2011 -0400
Merged win32 into src
src/.gitignore | 1 -
src/docky_control/2.0/hamster_control.py | 115 --
src/docky_control/2.0/hamster_control.py.info | 3 -
src/docky_control/2.1/hamster_control.py | 115 --
src/docky_control/2.1/hamster_control.py.info | 4 -
src/hamster-applet | 135 --
src/hamster-cli | 284 ----
src/hamster-service | 23 -
src/hamster-time-tracker | 51 +-
src/hamster/applet.py | 712 ----------
src/hamster/client.py | 259 +++-
src/hamster/configuration.py | 137 ++-
src/hamster/db.py | 18 +-
src/hamster/external.py | 1 -
src/hamster/idle.py | 242 ++--
src/hamster/lib/graphics.py | 2 +
src/hamster/lib/stuff.py | 21 +-
src/hamster/overview.py | 4 +-
src/hamster/storage.py | 320 -----
src/hamster/widgets/rangepick.py | 2 +
win32/hamster-time-tracker | 515 -------
win32/hamster/.gitignore | 4 -
win32/hamster/__init__.py | 1 -
win32/hamster/about.py | 64 -
win32/hamster/client.py | 452 ------
win32/hamster/configuration.py | 332 -----
win32/hamster/db.py | 1206 ----------------
win32/hamster/defs.py.in | 5 -
win32/hamster/edit_activity.py | 306 ----
win32/hamster/external.py | 110 --
win32/hamster/idle.py | 138 --
win32/hamster/lib/charting.py | 346 -----
win32/hamster/lib/graphics.py | 1839 -------------------------
win32/hamster/lib/i18n.py | 42 -
win32/hamster/lib/pytweener.py | 605 --------
win32/hamster/lib/stuff.py | 362 -----
win32/hamster/lib/trophies.py | 201 ---
win32/hamster/overview.py | 415 ------
win32/hamster/overview_activities.py | 203 ---
win32/hamster/overview_totals.py | 253 ----
win32/hamster/preferences.py | 721 ----------
win32/hamster/reports.py | 326 -----
win32/hamster/stats.py | 450 ------
win32/hamster/widgets/__init__.py | 91 --
win32/hamster/widgets/activityentry.py | 339 -----
win32/hamster/widgets/dateinput.py | 186 ---
win32/hamster/widgets/dayline.py | 375 -----
win32/hamster/widgets/facttree.py | 662 ---------
win32/hamster/widgets/rangepick.py | 138 --
win32/hamster/widgets/reportchooserdialog.py | 139 --
win32/hamster/widgets/tags.py | 349 -----
win32/hamster/widgets/timechart.py | 426 ------
win32/hamster/widgets/timeinput.py | 267 ----
53 files changed, 470 insertions(+), 13847 deletions(-)
---
diff --git a/src/hamster-time-tracker b/src/hamster-time-tracker
index f57ebc4..a138481 100755
--- a/src/hamster-time-tracker
+++ b/src/hamster-time-tracker
@@ -23,7 +23,6 @@ import logging
import datetime as dt
import gtk, gobject
-import dbus, dbus.service, dbus.mainloop.glib
class ProjectHamster(object):
def __init__(self, window_name = None):
@@ -59,16 +58,6 @@ class ProjectHamster(object):
self.get_widget("today_box").add(self.treeview)
self.new_name.grab_focus()
- # DBus Setup
- try:
- dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
- # Set up connection to the screensaver
- self.dbusIdleListener = idle.DbusIdleListener()
- self.dbusIdleListener.connect('idle-changed', self.on_idle_changed)
-
- except dbus.DBusException, e:
- logging.error("Can't init dbus: %s" % e)
-
# configuration
self.timeout_enabled = conf.get("enable_timeout")
self.notify_on_idle = conf.get("notify_on_idle")
@@ -151,8 +140,8 @@ class ProjectHamster(object):
return True
def check_user(self):
- if not self.notification:
- return
+# if not self.notification:
+# return
if self.notify_interval <= 0 or self.notify_interval >= 121:
return
@@ -174,7 +163,7 @@ class ProjectHamster(object):
message = _(u"No activity")
- if message:
+ if self.notification and message:
self.notification.update(_("Time Tracker"), message, "hamster-applet")
self.notification.show()
@@ -281,7 +270,8 @@ class ProjectHamster(object):
def on_menu_preferences_activate(self, menu_item):
dialogs.prefs.show(self.window)
def on_menu_help_contents_activate(self, *args):
- gtk.show_uri(gtk.gdk.Screen(), "ghelp:hamster-applet", 0L)
+ #TODO: provide some help; maybe local HTML files and launch the default browser
+ #gtk.show_uri(gtk.gdk.Screen(), "ghelp:hamster-applet", 0L)
trophies.unlock("basic_instructions")
@@ -302,8 +292,8 @@ class ProjectHamster(object):
self.refresh_hamster()
elif self.timeout_enabled and self.last_activity and \
self.last_activity.end_time is None:
-
- runtime.storage.stop_tracking(end_time = self.dbusIdleListener.getIdleFrom())
+ #TODO: need a Windows way to get idle time
+ runtime.storage.stop_tracking(end_time = dt.datetime.now())
def on_workspace_changed(self, screen, previous_workspace):
if not previous_workspace:
@@ -437,11 +427,11 @@ class ProjectHamster(object):
def close_window(self, *args):
# properly saving window state and position
- maximized = self.window.get_window().get_state() & gtk.gdk.WINDOW_STATE_MAXIMIZED
+ maximized = self.window.get_window().get_state() == gtk.gdk.WINDOW_STATE_MAXIMIZED
conf.set("standalone_window_maximized", maximized)
# make sure to remember dimensions only when in normal state
- if maximized == False and not self.window.get_window().get_state() & gtk.gdk.WINDOW_STATE_ICONIFIED:
+ if maximized == False and not self.window.get_window().get_state() == gtk.gdk.WINDOW_STATE_ICONIFIED:
x, y = self.window.get_position()
w, h = self.window.get_size()
conf.set("standalone_window_box", [x, y, w, h])
@@ -451,16 +441,10 @@ class ProjectHamster(object):
# maintain just one instance. this code feels hackish
-class WindowServer(dbus.service.Object):
- __dbus_object_path__ = "/org/gnome/Hamster/WindowServer"
-
+class WindowServer(gobject.GObject):
def __init__(self):
self.app = None
- self.bus = dbus.SessionBus()
- bus_name = dbus.service.BusName("org.gnome.Hamster.WindowServer", bus=self.bus)
- dbus.service.Object.__init__(self, bus_name, self.__dbus_object_path__)
- @dbus.service.method("org.gnome.Hamster.WindowServer")
def main(self):
if self.app:
self.app.window.show()
@@ -468,19 +452,14 @@ class WindowServer(dbus.service.Object):
else:
self.app = ProjectHamster()
- @dbus.service.method("org.gnome.Hamster.WindowServer")
def edit(self): dialogs.edit.show(self.app)
- @dbus.service.method("org.gnome.Hamster.WindowServer")
def overview(self): dialogs.overview.show(self.app)
- @dbus.service.method("org.gnome.Hamster.WindowServer")
def about(self): dialogs.about.show(self.app)
- @dbus.service.method("org.gnome.Hamster.WindowServer")
def statistics(self): dialogs.stats.show(self.app)
- @dbus.service.method("org.gnome.Hamster.WindowServer")
def preferences(self): dialogs.prefs.show(self.app)
@@ -509,14 +488,6 @@ if __name__ == "__main__":
from hamster.configuration import runtime, dialogs, conf, load_ui_file
- # if there is windowserver hanging in dbus - call that and exit
- bus = dbus.SessionBus()
- if "org.gnome.Hamster.WindowServer" in dbus.SessionBus().list_names():
- server = bus.get_object("org.gnome.Hamster.WindowServer", WindowServer.__dbus_object_path__)
- getattr(server, window)()
- sys.exit(0)
-
-
# otherwise proceed and do all the import and everything
gtk.gdk.threads_init()
gtk.window_set_default_icon_name("hamster-applet")
@@ -539,4 +510,6 @@ if __name__ == "__main__":
getattr(WindowServer(), window)()
+ gtk.gdk.threads_enter()
gtk.main()
+ gtk.gdk.threads_leave()
diff --git a/src/hamster/client.py b/src/hamster/client.py
index 1473f36..050692b 100644
--- a/src/hamster/client.py
+++ b/src/hamster/client.py
@@ -21,11 +21,24 @@
import datetime as dt
from calendar import timegm
-import dbus, dbus.mainloop.glib
+import db
import gobject
from lib import stuff, trophies
-
+def to_dbus_fact(fact):
+ """Perform the conversion between fact database query and
+ dbus supported data types
+ """
+ return (fact['id'],
+ timegm(fact['start_time'].timetuple()),
+ timegm(fact['end_time'].timetuple()) if fact['end_time'] else 0,
+ fact['description'] or '',
+ fact['name'] or '',
+ fact['activity_id'] or 0,
+ fact['category'] or '',
+ fact['tags'],
+ timegm(fact['date'].timetuple()),
+ fact['delta'].days * 24 * 60 * 60 + fact['delta'].seconds)
def from_dbus_fact(fact):
"""unpack the struct into a proper dict"""
@@ -65,17 +78,8 @@ class Storage(gobject.GObject):
def __init__(self):
gobject.GObject.__init__(self)
- dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
- self.bus = dbus.SessionBus()
self._connection = None # will be initiated on demand
- self.bus.add_signal_receiver(self._on_tags_changed, 'TagsChanged', 'org.gnome.Hamster')
- self.bus.add_signal_receiver(self._on_facts_changed, 'FactsChanged', 'org.gnome.Hamster')
- self.bus.add_signal_receiver(self._on_activities_changed, 'ActivitiesChanged', 'org.gnome.Hamster')
- self.bus.add_signal_receiver(self._on_toggle_called, 'ToggleCalled', 'org.gnome.Hamster')
-
- self.bus.add_signal_receiver(self._on_dbus_connection_change, 'NameOwnerChanged',
- 'org.freedesktop.DBus', arg0='org.gnome.Hamster')
@staticmethod
def _to_dict(columns, result_list):
return [dict(zip(columns, row)) for row in result_list]
@@ -83,9 +87,7 @@ class Storage(gobject.GObject):
@property
def conn(self):
if not self._connection:
- self._connection = dbus.Interface(self.bus.get_object('org.gnome.Hamster',
- '/org/gnome/Hamster'),
- dbus_interface='org.gnome.Hamster')
+ self._connection = db.Storage()
return self._connection
def _on_dbus_connection_change(self, name, old, new):
@@ -111,7 +113,7 @@ class Storage(gobject.GObject):
"""returns facts of the current date, respecting hamster midnight
hamster midnight is stored in gconf, and presented in minutes
"""
- return [from_dbus_fact(fact) for fact in self.conn.GetTodaysFacts()]
+ return [from_dbus_fact(fact) for fact in self.GetTodaysFacts()]
def get_facts(self, date, end_date = None, search_terms = ""):
"""Returns facts for the time span matching the optional filter criteria.
@@ -124,7 +126,7 @@ class Storage(gobject.GObject):
if end_date:
end_date = timegm(end_date.timetuple())
- return [from_dbus_fact(fact) for fact in self.conn.GetFacts(date,
+ return [from_dbus_fact(fact) for fact in self.GetFacts(date,
end_date,
search_terms)]
@@ -133,15 +135,15 @@ class Storage(gobject.GObject):
results are sorted by most recent usage.
search is case insensitive
"""
- return self._to_dict(('name', 'category'), self.conn.GetActivities(search))
+ return self._to_dict(('name', 'category'), self.GetActivities(search))
def get_categories(self):
"""returns list of categories"""
- return self._to_dict(('id', 'name'), self.conn.GetCategories())
+ return self._to_dict(('id', 'name'), self.GetCategories())
def get_tags(self, only_autocomplete = False):
"""returns list of all tags. by default only those that have been set for autocomplete"""
- return self._to_dict(('id', 'name', 'autocomplete'), self.conn.GetTags(only_autocomplete))
+ return self._to_dict(('id', 'name', 'autocomplete'), self.GetTags(only_autocomplete))
def get_tag_ids(self, tags):
@@ -151,16 +153,16 @@ class Storage(gobject.GObject):
be created.
on database changes the `tags-changed` signal is emitted.
"""
- return self._to_dict(('id', 'name', 'autocomplete'), self.conn.GetTagIds(tags))
+ return self._to_dict(('id', 'name', 'autocomplete'), self.GetTagIds(tags))
def update_autocomplete_tags(self, tags):
"""update list of tags that should autocomplete. this list replaces
anything that is currently set"""
- self.conn.SetTagsAutocomplete(tags)
+ self.SetTagsAutocomplete(tags)
def get_fact(self, id):
"""returns fact by it's ID"""
- return from_dbus_fact(self.conn.GetFact(id))
+ return from_dbus_fact(self.GetFact(id))
def add_fact(self, fact, temporary_activity = False):
"""Add fact. activity name can use the
@@ -180,7 +182,7 @@ class Storage(gobject.GObject):
if end_timestamp:
end_timestamp = timegm(end_timestamp.timetuple())
- new_id = self.conn.AddFact(serialized,
+ new_id = self.AddFact(serialized,
start_timestamp,
end_timestamp,
temporary_activity)
@@ -195,11 +197,11 @@ class Storage(gobject.GObject):
"""Stop tracking current activity. end_time can be passed in if the
activity should have other end time than the current moment"""
end_time = timegm((end_time or dt.datetime.now()).timetuple())
- return self.conn.StopTracking(end_time)
+ return self.StopTracking(end_time)
def remove_fact(self, fact_id):
"delete fact from database"
- self.conn.RemoveFact(fact_id)
+ self.RemoveFact(fact_id)
def update_fact(self, fact_id, fact, temporary_activity = False):
"""Update fact values. See add_fact for rules.
@@ -214,7 +216,7 @@ class Storage(gobject.GObject):
if end_time:
end_time = timegm(end_time.timetuple())
- new_id = self.conn.UpdateFact(fact_id,
+ new_id = self.UpdateFact(fact_id,
fact.serialized_name(),
start_time,
end_time,
@@ -228,11 +230,11 @@ class Storage(gobject.GObject):
"""Return activities for category. If category is not specified, will
return activities that have no category"""
category_id = category_id or -1
- return self._to_dict(('id', 'name', 'category_id', 'category'), self.conn.GetCategoryActivities(category_id))
+ return self._to_dict(('id', 'name', 'category_id', 'category'), self.GetCategoryActivities(category_id))
def get_category_id(self, category_name):
"""returns category id by name"""
- return self.conn.GetCategoryId(category_name)
+ return self.GetCategoryId(category_name)
def get_activity_by_name(self, activity, category_id = None, resurrect = True):
"""returns activity dict by name and optionally filtering by category.
@@ -240,26 +242,211 @@ class Storage(gobject.GObject):
unless told otherise in the resurrect param
"""
category_id = category_id or 0
- return self.conn.GetActivityByName(activity, category_id, resurrect)
+ return self.GetActivityByName(activity, category_id, resurrect)
# category and activity manipulations (normally just via preferences)
def remove_activity(self, id):
- self.conn.RemoveActivity(id)
+ self.RemoveActivity(id)
def remove_category(self, id):
- self.conn.RemoveCategory(id)
+ self.RemoveCategory(id)
def change_category(self, id, category_id):
- return self.conn.ChangeCategory(id, category_id)
+ return self.ChangeCategory(id, category_id)
def update_activity(self, id, name, category_id):
- return self.conn.UpdateActivity(id, name, category_id)
+ return self.UpdateActivity(id, name, category_id)
def add_activity(self, name, category_id = -1):
- return self.conn.AddActivity(name, category_id)
+ return self.AddActivity(name, category_id)
def update_category(self, id, name):
- return self.conn.UpdateCategory(id, name)
+ return self.UpdateCategory(id, name)
def add_category(self, name):
- return self.conn.AddCategory(name)
+ return self.AddCategory(name)
+
+ def AddFact(self, fact, start_time, end_time, temporary = False):
+ start_time = start_time or None
+ if start_time:
+ start_time = dt.datetime.utcfromtimestamp(start_time)
+
+ end_time = end_time or None
+ if end_time:
+ end_time = dt.datetime.utcfromtimestamp(end_time)
+
+# self.start_transaction()
+ result = self.conn.__add_fact(fact, start_time, end_time, temporary)
+# self.end_transaction()
+
+ if result:
+ self._on_facts_changed()
+
+ return result or 0
+
+ def GetFact(self, fact_id):
+ """Get fact by id. For output format see GetFacts"""
+ fact = dict(self.conn.__get_fact(fact_id))
+ fact['date'] = fact['start_time'].date()
+ fact['delta'] = dt.timedelta()
+ return to_dbus_fact(fact)
+
+ def UpdateFact(self, fact_id, fact, start_time, end_time, temporary = False):
+ if start_time:
+ start_time = dt.datetime.utcfromtimestamp(start_time)
+ else:
+ start_time = None
+
+ if end_time:
+ end_time = dt.datetime.utcfromtimestamp(end_time)
+ else:
+ end_time = None
+
+# self.start_transaction()
+ self.conn.__remove_fact(fact_id)
+ result = self.conn.__add_fact(fact, start_time, end_time, temporary)
+
+# self.end_transaction()
+
+ if result:
+ self._on_facts_changed()
+ return result
+
+ def StopTracking(self, end_time):
+ """Stops tracking the current activity"""
+ end_time = dt.datetime.utcfromtimestamp(end_time)
+
+ facts = self.conn.__get_todays_facts()
+ if facts:
+ self.conn.__touch_fact(facts[-1], end_time)
+ self._on_facts_changed()
+
+ def RemoveFact(self, fact_id):
+ """Remove fact from storage by it's ID"""
+ fact = self.conn.__get_fact(fact_id)
+ if fact:
+ self.conn.__remove_fact(fact_id)
+ self._on_facts_changed()
+
+
+ def GetFacts(self, start_date, end_date, search_terms):
+ """Gets facts between the day of start_date and the day of end_date.
+ Parameters:
+ i start_date: Seconds since epoch (timestamp). Use 0 for today
+ i end_date: Seconds since epoch (timestamp). Use 0 for today
+ s search_terms: Bleh
+ Returns Array of fact where fact is struct of:
+ i id
+ i start_time
+ i end_time
+ s description
+ s activity name
+ i activity id
+ i category name
+ as List of fact tags
+ i date
+ i delta
+ """
+ #TODO: Assert start > end ?
+ start = dt.date.today()
+ if start_date:
+ start = dt.datetime.utcfromtimestamp(start_date).date()
+
+ end = None
+ if end_date:
+ end = dt.datetime.utcfromtimestamp(end_date).date()
+
+ return [to_dbus_fact(fact) for fact in self.conn.__get_facts(start, end, search_terms)]
+
+ def GetTodaysFacts(self):
+ """Gets facts of today, respecting hamster midnight. See GetFacts for
+ return info"""
+ return [to_dbus_fact(fact) for fact in self.conn.__get_todays_facts()]
+
+
+ # categories
+
+ def AddCategory(self, name):
+ res = self.conn.__add_category(name)
+ self._on_activities_changed()
+ return res
+
+
+ def GetCategoryId(self, category):
+ return self.conn.__get_category_id(category)
+
+
+ def UpdateCategory(self, id, name):
+ self.conn.__update_category(id, name)
+ self._on_activities_changed()
+
+ def RemoveCategory(self, id):
+ self.conn.__remove_category(id)
+ self._on_activities_changed()
+
+ def GetCategories(self):
+ return [(category['id'], category['name']) for category in self.conn.__get_categories()]
+
+ # activities
+
+ def AddActivity(self, name, category_id = -1):
+ new_id = self.conn.__add_activity(name, category_id)
+ self._on_activities_changed()
+ return new_id
+
+ def UpdateActivity(self, id, name, category_id):
+ self.conn.__update_activity(id, name, category_id)
+ self._on_activities_changed()
+
+
+
+ def RemoveActivity(self, id):
+ result = self.conn.__remove_activity(id)
+ self._on_activities_changed()
+ return result
+
+ def GetCategoryActivities(self, category_id = -1):
+
+ return [(row['id'],
+ row['name'],
+ row['category_id'],
+ row['name'] or '') for row in
+ self.conn.__get_category_activities(category_id = category_id)]
+
+
+ def GetActivities(self, search = ""):
+ return [(row['name'], row['category'] or '') for row in self.conn.__get_activities(search)]
+
+
+ def ChangeCategory(self, id, category_id):
+ changed = self.conn.__change_category(id, category_id)
+ if changed:
+ self._on_activities_changed()
+ return changed
+
+
+ def GetActivityByName(self, activity, category_id, resurrect = True):
+ category_id = category_id or None
+
+ if activity:
+ return dict(self.conn.__get_activity_by_name(activity, category_id, resurrect))
+ else:
+ return {}
+
+ # tags
+ def GetTags(self, only_autocomplete):
+ return [(tag['id'], tag['name'], tag['autocomplete']) for tag in self.conn.__get_tags(only_autocomplete)]
+
+
+ def GetTagIds(self, tags):
+ tags, new_added = self.conn.__get_tag_ids(tags)
+ if new_added:
+ self._on_tags_changed()
+ return [(tag['id'], tag['name'], tag['autocomplete']) for tag in tags]
+
+
+ def SetTagsAutocomplete(self, tags):
+ changes = self.conn.__update_autocomplete_tags(tags)
+ if changes:
+ self._on_tags_changed()
+
diff --git a/src/hamster/configuration.py b/src/hamster/configuration.py
index f4aafee..8a78d97 100644
--- a/src/hamster/configuration.py
+++ b/src/hamster/configuration.py
@@ -17,15 +17,13 @@
# You should have received a copy of the GNU General Public License
# along with Project Hamster. If not, see <http://www.gnu.org/licenses/>.
-"""
-gconf part of this code copied from Gimmie (c) Alex Gravely via Conduit (c) John Stowers, 2006
-License: GPLv2
-"""
+try:
+ import ConfigParser as configparser
+except ImportError:
+ import configparser
-import gconf
import os
from client import Storage
-from xdg.BaseDirectory import xdg_data_home
import logging
import datetime as dt
import gobject, gtk
@@ -57,7 +55,7 @@ class RuntimeStore(Singleton):
import defs
self.data_dir = os.path.join(defs.DATA_DIR, "hamster-applet")
self.version = defs.VERSION
- except:
+ except ImportError:
# if defs is not there, we are running from sources
module_dir = os.path.dirname(os.path.realpath(__file__))
self.data_dir = os.path.join(module_dir, '..', '..', 'data')
@@ -68,8 +66,13 @@ class RuntimeStore(Singleton):
self.storage = Storage()
+ if os.environ.has_key('APPDATA'):
+ self.home_data_dir = os.path.realpath(os.path.join(os.environ['APPDATA'], "hamster-applet"))
+ else:
+ logging.error("APPDATA variable is not set")
+ raise Exception("APPDATA environment variable is not defined")
- self.home_data_dir = os.path.realpath(os.path.join(xdg_data_home, "hamster-applet"))
+
@property
def art_dir(self):
@@ -153,13 +156,13 @@ def load_ui_file(name):
ui.add_from_file(os.path.join(runtime.data_dir, name))
return ui
-class GConfStore(gobject.GObject, Singleton):
+class INIStore(gobject.GObject, Singleton):
"""
- Settings implementation which stores settings in GConf
- Snatched from the conduit project (http://live.gnome.org/Conduit)
+ Settings implementation which stores settings in an INI file.
"""
- GCONF_DIR = "/apps/hamster-applet/"
+ SECTION = 'Settings' # Section to read/store settings in INI file
VALID_KEY_TYPES = (bool, str, int, list, tuple)
+ #TODO: Remove non-Windows related settings
DEFAULTS = {
'enable_timeout' : False, # Should hamster stop tracking on idle
'stop_on_shutdown' : False, # Should hamster stop tracking on shutdown
@@ -180,11 +183,34 @@ class GConfStore(gobject.GObject, Singleton):
"conf-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT))
}
def __init__(self):
+ self._client = configparser.ConfigParser()
+
+ #TODO: Store file in home_data_dir
+ self.config = "hamster.ini"
+ if not os.path.isfile(self.config):
+ self._client.add_section(self.SECTION)
+ self._flush()
+ try:
+ fcfg = open(self.config,'r')
+ self._client.readfp(fcfg)
+ fcfg.close()
+ except IOError,e:
+ log.error("Error reading configurationfile: %s" % e)
+ raise
+
gobject.GObject.__init__(self)
- self._client = gconf.client_get_default()
- self._client.add_dir(self.GCONF_DIR[:-1], gconf.CLIENT_PRELOAD_RECURSIVE)
self._notifications = []
+ def _flush(self):
+ """Write configuration values to INI file"""
+ try:
+ fcfg = open(self.config,'w')
+ self._client.write(fcfg)
+ fcfg.close()
+ except IOError,e:
+ log.error("Error writing to configuration file: %s" % e)
+ raise
+
def _fix_key(self, key):
"""
Appends the GCONF_PREFIX to the key if needed
@@ -194,43 +220,50 @@ class GConfStore(gobject.GObject, Singleton):
@returns: The fixed key
@rtype: C{string}
"""
- if not key.startswith(self.GCONF_DIR):
- return self.GCONF_DIR + key
- else:
- return key
+ #TODO: Remove calls to this function
+ return key
- def _key_changed(self, client, cnxn_id, entry, data=None):
+# def _key_changed(self, client, cnxn_id, entry, data=None):
+ def _key_changed(self, key):
"""
Callback when a gconf key changes
"""
- key = self._fix_key(entry.key)[len(self.GCONF_DIR):]
- value = self._get_value(entry.value, self.DEFAULTS[key])
+ return #TODO: Fix or remove calls
+ #key = self._fix_key(entry.key)[len(self.GCONF_DIR):]
+ #value = self._get_value(entry.value, self.DEFAULTS[key])
- self.emit('conf-changed', key, value)
+ #self.emit('conf-changed', key, value)
- def _get_value(self, value, default):
- """calls appropriate gconf function by the default value"""
+ def _get_value(self, key, default):
+ """calls appropriate configparser function by the default value"""
vtype = type(default)
-
- if vtype is bool:
- return value.get_bool()
- elif vtype is str:
- return value.get_string()
- elif vtype is int:
- return value.get_int()
- elif vtype in (list, tuple):
- l = []
- for i in value.get_list():
- l.append(i.get_string())
- return l
+ try:
+ if vtype is bool:
+ return self._client.getboolean(self.SECTION, key)
+ elif vtype is str:
+ return self._client.get(self.SECTION, key)
+ elif vtype is int:
+ return self._client.getint(self.SECTION, key)
+ elif vtype in (list, tuple):
+ l = []
+ temp = self._client.get(self.SECTION, key)
+ for i in temp.split(','):
+ l.append(i.strip())
+ return l
+ except configparser.NoOptionError:
+ return None
+ except TypeError:
+ return None
+ except AttributeError:
+ return None
return None
def get(self, key, default=None):
"""
Returns the value of the key or the default value if the key is
- not yet in gconf
+ not yet in config
"""
#function arguments override defaults
@@ -248,19 +281,16 @@ class GConfStore(gobject.GObject, Singleton):
return None
#for gconf refer to the full key path
- key = self._fix_key(key)
+ #key = self._fix_key(key)
- if key not in self._notifications:
- self._client.notify_add(key, self._key_changed)
- self._notifications.append(key)
+ #if key not in self._notifications:
+ # self._notifications.append(key)
- value = self._client.get(key)
+ value = self._get_value(key, default)
if value is None:
self.set(key, default)
return default
-
- value = self._get_value(value, default)
- if value is not None:
+ elif value is not None:
return value
log.warn("Unknown gconf key: %s" % key)
@@ -282,20 +312,21 @@ class GConfStore(gobject.GObject, Singleton):
return False
#for gconf refer to the full key path
- key = self._fix_key(key)
+ #key = self._fix_key(key)
if vtype is bool:
- self._client.set_bool(key, value)
+ self._client.set(self.SECTION, key, value)
elif vtype is str:
- self._client.set_string(key, value)
+ self._client.set(self.SECTION, key, value)
elif vtype is int:
- self._client.set_int(key, value)
+ self._client.set(self.SECTION, key, value)
elif vtype in (list, tuple):
- #Save every value as a string
- strvalues = [str(i) for i in value]
- self._client.set_list(key, gconf.VALUE_STRING, strvalues)
+ # flatten list/tuple
+ self._client.set(self.SECTION, key, ",".join([str(i) for i in value]))
+
+ self._flush()
return True
-conf = GConfStore()
+conf = INIStore()
diff --git a/src/hamster/db.py b/src/hamster/db.py
index 33da02e..893518b 100644
--- a/src/hamster/db.py
+++ b/src/hamster/db.py
@@ -34,22 +34,19 @@ except ImportError:
import os, time
import datetime
-import storage
from shutil import copy as copyfile
import itertools
import datetime as dt
import gio
-from xdg.BaseDirectory import xdg_data_home
from lib import stuff, trophies
-class Storage(storage.Storage):
+class Storage(object):
con = None # Connection will be created on demand
- def __init__(self, loop):
+ def __init__(self):
"""
Delayed setup so we don't do everything at the same time
"""
- storage.Storage.__init__(self, loop)
self.__con = None
self.__cur = None
@@ -84,7 +81,12 @@ class Storage(storage.Storage):
self.run_fixtures()
def __init_db_file(self):
- home_data_dir = os.path.realpath(os.path.join(xdg_data_home, "hamster-applet"))
+ if os.environ.has_key('APPDATA'):
+ home_data_dir = os.path.realpath(os.path.join(os.environ['APPDATA'], "hamster-applet"))
+ else:
+ logging.error("APPDATA is not defined")
+ raise Exception("APPDATA environment variable is not defined")
+
if not os.path.exists(home_data_dir):
os.makedirs(home_data_dir, 0744)
@@ -161,6 +163,10 @@ class Storage(storage.Storage):
return self.__get_tag_ids(tags)[0], True # all done, recurse
else:
return db_tags, changes
+
+ def GetTagIds(self, tags):
+ tags, new_added = self.__get_tag_ids(tags)
+ return [(tag['id'], tag['name'], tag['autocomplete']) for tag in tags]
def __update_autocomplete_tags(self, tags):
tags = [tag.strip() for tag in tags.split(",") if tag.strip()] # split by comma
diff --git a/src/hamster/external.py b/src/hamster/external.py
index 05624c3..774c5c0 100644
--- a/src/hamster/external.py
+++ b/src/hamster/external.py
@@ -21,7 +21,6 @@
import logging
from configuration import conf
import gobject
-import dbus, dbus.mainloop.glib
try:
import evolution
diff --git a/src/hamster/idle.py b/src/hamster/idle.py
index 886cbcb..f305db7 100644
--- a/src/hamster/idle.py
+++ b/src/hamster/idle.py
@@ -16,125 +16,123 @@
# You should have received a copy of the GNU General Public License
# along with Project Hamster. If not, see <http://www.gnu.org/licenses/>.
-
-import logging
-import dbus
-from dbus.lowlevel import Message
-import gconf
-import datetime as dt
-import gobject
-
-class DbusIdleListener(gobject.GObject):
- """
- Listen for idleness coming from org.gnome.ScreenSaver
-
- Monitors org.gnome.ScreenSaver for idleness. There are two types,
- implicit (due to inactivity) and explicit (lock screen), that need to be
- handled differently. An implicit idle state should subtract the
- time-to-become-idle (as specified in the gconf) from the last activity,
- but an explicit idle state should not.
-
- The signals are inspected for the "ActiveChanged" and "Lock"
- members coming from the org.gnome.ScreenSaver interface and the
- and is_screen_locked members are updated appropriately.
- """
- __gsignals__ = {
- "idle-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
- }
- def __init__(self):
- gobject.GObject.__init__(self)
-
- self.screensaver_uri = "org.gnome.ScreenSaver"
- self.screen_locked = False
- self.idle_from = None
- self.timeout_minutes = 0 # minutes after session is considered idle
- self.idle_was_there = False # a workaround variable for pre 2.26
-
- try:
- self.bus = dbus.SessionBus()
- except:
- return 0
- # Listen for chatter on the screensaver interface.
- # We cannot just add additional match strings to narrow down
- # what we hear because match strings are ORed together.
- # E.g., if we were to make the match string
- # "interface='org.gnome.ScreenSaver', type='method_call'",
- # we would not get only screensaver's method calls, rather
- # we would get anything on the screensaver interface, as well
- # as any method calls on *any* interface. Therefore the
- # bus_inspector needs to do some additional filtering.
- self.bus.add_match_string_non_blocking("interface='%s'" %
- self.screensaver_uri)
- self.bus.add_message_filter(self.bus_inspector)
-
-
- def bus_inspector(self, bus, message):
- """
- Inspect the bus for screensaver messages of interest
- """
-
- # We only care about stuff on this interface. We did filter
- # for it above, but even so we still hear from ourselves
- # (hamster messages).
- if message.get_interface() != self.screensaver_uri:
- return True
-
- member = message.get_member()
-
- if member in ("SessionIdleChanged", "ActiveChanged"):
- logging.debug("%s -> %s" % (member, message.get_args_list()))
-
- idle_state = message.get_args_list()[0]
- if idle_state:
- self.idle_from = dt.datetime.now()
-
- # from gnome screensaver 2.24 to 2.28 they have switched
- # configuration keys and signal types.
- # luckily we can determine key by signal type
- if member == "SessionIdleChanged":
- delay_key = "/apps/gnome-screensaver/idle_delay"
- else:
- delay_key = "/desktop/gnome/session/idle_delay"
-
- client = gconf.client_get_default()
- self.timeout_minutes = client.get_int(delay_key)
-
- else:
- self.screen_locked = False
- self.idle_from = None
-
- if member == "ActiveChanged":
- # ActiveChanged comes before SessionIdleChanged signal
- # as a workaround for pre 2.26, we will wait a second - maybe
- # SessionIdleChanged signal kicks in
- def dispatch_active_changed(idle_state):
- if not self.idle_was_there:
- self.emit('idle-changed', idle_state)
- self.idle_was_there = False
-
- gobject.timeout_add_seconds(1, dispatch_active_changed, idle_state)
-
- else:
- # dispatch idle status change to interested parties
- self.idle_was_there = True
- self.emit('idle-changed', idle_state)
-
- elif member == "Lock":
- # in case of lock, lock signal will be sent first, followed by
- # ActiveChanged and SessionIdle signals
- logging.debug("Screen Lock Requested")
- self.screen_locked = True
-
- return
-
-
- def getIdleFrom(self):
- if not self.idle_from:
- return dt.datetime.now()
-
- if self.screen_locked:
- return self.idle_from
- else:
- # Only subtract idle time from the running task when
- # idleness is due to time out, not a screen lock.
- return self.idle_from - dt.timedelta(minutes = self.timeout_minutes)
+#
+#import logging
+#import dbus
+#import datetime as dt
+#import gobject
+# TODO: Create a Windows alternative
+#class DbusIdleListener(gobject.GObject):
+# """
+# Listen for idleness coming from org.gnome.ScreenSaver
+#
+# Monitors org.gnome.ScreenSaver for idleness. There are two types,
+# implicit (due to inactivity) and explicit (lock screen), that need to be
+# handled differently. An implicit idle state should subtract the
+# time-to-become-idle (as specified in the gconf) from the last activity,
+# but an explicit idle state should not.
+#
+# The signals are inspected for the "ActiveChanged" and "Lock"
+# members coming from the org.gnome.ScreenSaver interface and the
+# and is_screen_locked members are updated appropriately.
+# """
+# __gsignals__ = {
+# "idle-changed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,))
+# }
+# def __init__(self):
+# gobject.GObject.__init__(self)
+#
+# self.screensaver_uri = "org.gnome.ScreenSaver"
+# self.screen_locked = False
+# self.idle_from = None
+# self.timeout_minutes = 0 # minutes after session is considered idle
+# self.idle_was_there = False # a workaround variable for pre 2.26
+#
+# try:
+# self.bus = dbus.SessionBus()
+# except:
+# return 0
+# # Listen for chatter on the screensaver interface.
+# # We cannot just add additional match strings to narrow down
+# # what we hear because match strings are ORed together.
+# # E.g., if we were to make the match string
+# # "interface='org.gnome.ScreenSaver', type='method_call'",
+# # we would not get only screensaver's method calls, rather
+# # we would get anything on the screensaver interface, as well
+# # as any method calls on *any* interface. Therefore the
+# # bus_inspector needs to do some additional filtering.
+# self.bus.add_match_string_non_blocking("interface='%s'" %
+# self.screensaver_uri)
+# self.bus.add_message_filter(self.bus_inspector)
+#
+#
+# def bus_inspector(self, bus, message):
+# """
+# Inspect the bus for screensaver messages of interest
+# """
+#
+# # We only care about stuff on this interface. We did filter
+# # for it above, but even so we still hear from ourselves
+# # (hamster messages).
+# if message.get_interface() != self.screensaver_uri:
+# return True
+#
+# member = message.get_member()
+#
+# if member in ("SessionIdleChanged", "ActiveChanged"):
+# logging.debug("%s -> %s" % (member, message.get_args_list()))
+#
+# idle_state = message.get_args_list()[0]
+# if idle_state:
+# self.idle_from = dt.datetime.now()
+#
+# # from gnome screensaver 2.24 to 2.28 they have switched
+# # configuration keys and signal types.
+# # luckily we can determine key by signal type
+# if member == "SessionIdleChanged":
+# delay_key = "/apps/gnome-screensaver/idle_delay"
+# else:
+# delay_key = "/desktop/gnome/session/idle_delay"
+#
+# client = gconf.client_get_default()
+# self.timeout_minutes = client.get_int(delay_key)
+#
+# else:
+# self.screen_locked = False
+# self.idle_from = None
+#
+# if member == "ActiveChanged":
+# # ActiveChanged comes before SessionIdleChanged signal
+# # as a workaround for pre 2.26, we will wait a second - maybe
+# # SessionIdleChanged signal kicks in
+# def dispatch_active_changed(idle_state):
+# if not self.idle_was_there:
+# self.emit('idle-changed', idle_state)
+# self.idle_was_there = False
+#
+# gobject.timeout_add_seconds(1, dispatch_active_changed, idle_state)
+#
+# else:
+# # dispatch idle status change to interested parties
+# self.idle_was_there = True
+# self.emit('idle-changed', idle_state)
+#
+# elif member == "Lock":
+# # in case of lock, lock signal will be sent first, followed by
+# # ActiveChanged and SessionIdle signals
+# logging.debug("Screen Lock Requested")
+# self.screen_locked = True
+#
+# return
+#
+#
+# def getIdleFrom(self):
+# if not self.idle_from:
+# return dt.datetime.now()
+#
+# if self.screen_locked:
+# return self.idle_from
+# else:
+# # Only subtract idle time from the running task when
+# # idleness is due to time out, not a screen lock.
+# return self.idle_from - dt.timedelta(minutes = self.timeout_minutes)
diff --git a/src/hamster/lib/graphics.py b/src/hamster/lib/graphics.py
index e6ca0cf..5dcc6b7 100644
--- a/src/hamster/lib/graphics.py
+++ b/src/hamster/lib/graphics.py
@@ -1643,6 +1643,8 @@ class Scene(gtk.DrawingArea):
if self.tweener:
self.tweener.update(delta)
+ if delta <= delta:
+ delta = 1
self.fps = 1 / delta
diff --git a/src/hamster/lib/stuff.py b/src/hamster/lib/stuff.py
index d874d82..247909a 100644
--- a/src/hamster/lib/stuff.py
+++ b/src/hamster/lib/stuff.py
@@ -33,6 +33,14 @@ import time
import re
import locale
import os
+try:
+ import _winreg as winreg
+except ImportError:
+ try:
+ import winreg
+ except ImportError:
+ logging.warn("WARNING - Could not load Registry module.")
+ winreg = None
def format_duration(minutes, human = True):
"""formats duration in a human readable format.
@@ -152,16 +160,13 @@ def locale_to_utf8(locale_str):
def locale_first_weekday():
"""figure if week starts on monday or sunday"""
- first_weekday = 6 #by default settle on monday
+ first_weekday = 1 #by default settle on monday
+ if not winreg: return first_weekday
try:
- process = os.popen("locale first_weekday week-1stday")
- week_offset, week_start = process.read().split('\n')[:2]
- process.close()
- week_start = dt.date(*time.strptime(week_start, "%Y%m%d")[:3])
- week_offset = dt.timedelta(int(week_offset) - 1)
- beginning = week_start + week_offset
- first_weekday = int(beginning.strftime("%w"))
+ key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Control Panel\International")
+ value, vtype = winreg.QueryValueEx(key, "iFirstDayOfWeek")
+ first_weekday = (int(value)+1) % 7
except:
logging.warn("WARNING - Failed to get first weekday from locale")
diff --git a/src/hamster/overview.py b/src/hamster/overview.py
index 3898aed..ab20f49 100644
--- a/src/hamster/overview.py
+++ b/src/hamster/overview.py
@@ -395,11 +395,11 @@ class Overview(object):
def close_window(self):
# properly saving window state and position
- maximized = self.window.get_window().get_state() & gtk.gdk.WINDOW_STATE_MAXIMIZED
+ maximized = self.window.get_window().get_state() == gtk.gdk.WINDOW_STATE_MAXIMIZED
conf.set("overview_window_maximized", maximized)
# make sure to remember dimensions only when in normal state
- if maximized == False and not self.window.get_window().get_state() & gtk.gdk.WINDOW_STATE_ICONIFIED:
+ if maximized == False and not self.window.get_window().get_state() == gtk.gdk.WINDOW_STATE_ICONIFIED:
x, y = self.window.get_position()
w, h = self.window.get_size()
conf.set("overview_window_box", [x, y, w, h])
diff --git a/src/hamster/widgets/rangepick.py b/src/hamster/widgets/rangepick.py
index a9abb74..a49392b 100644
--- a/src/hamster/widgets/rangepick.py
+++ b/src/hamster/widgets/rangepick.py
@@ -102,10 +102,12 @@ class RangePick(gtk.ToggleButton):
end_cal.select_month(self.end_date.month - 1, self.end_date.year)
end_cal.select_day(self.end_date.day)
+ self.popup.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
self.popup.show_all()
self.get_widget("day").grab_focus()
self.set_active(True)
+
def emit_range(self, range, start, end):
self.hide()
self.emit("range-selected", range, start, end)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]