Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

first development release

svn path=/trunk/; revision=2
  • Loading branch information...
commit 902cf61de20f731ddffa708fe960ea6d0abdcbf4 0 parents
Toms Baugis authored
1  AUTHORS
@@ -0,0 +1 @@
+Toms Bauģis <toms.baugis@gmail.com>
166 COPYING
@@ -0,0 +1,166 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+
6 ChangeLog
@@ -0,0 +1,6 @@
+2007-07-27 Toms <toms.baugis@gmail.com>
+
+ * folder/file (something.function):
+ - 0.1 revision
+ - i don't know how to write changelogs.
+
236 INSTALL
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about. Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory. After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script). Here is a another example:
+
+ /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+ Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
1  MAINTAINERS
@@ -0,0 +1 @@
+i'm the one!
9 Makefile.am
@@ -0,0 +1,9 @@
+SUBDIRS = hamster data
+
+DISTCHECK_CONFIGURE_FLAGS = --disable-scrollkeeper
+
+DISTCLEANFILES =
+
+EXTRA_DIST = \
+ MAINTAINERS \
+ TODO
1  NEWS
@@ -0,0 +1 @@
+Hear, hear, the hamster is here!
3  README
@@ -0,0 +1,3 @@
+Hamster GNOME applet
+
+This applet allows you to keep track on where are you spending your time.
0  TODO
No changes.
40 acinclude.m4
@@ -0,0 +1,40 @@
+dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
+dnl
+dnl example
+dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
+dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
+
+AC_DEFUN([AS_AC_EXPAND],
+[
+ EXP_VAR=[$1]
+ FROM_VAR=[$2]
+
+ dnl first expand prefix and exec_prefix if necessary
+ prefix_save=$prefix
+ exec_prefix_save=$exec_prefix
+
+ dnl if no prefix given, then use /usr/local, the default prefix
+ if test "x$prefix" = "xNONE"; then
+ prefix=$ac_default_prefix
+ fi
+ dnl if no exec_prefix given, then use prefix
+ if test "x$exec_prefix" = "xNONE"; then
+ exec_prefix=$prefix
+ fi
+
+ full_var="$FROM_VAR"
+ dnl loop until it doesn't change anymore
+ while true; do
+ new_full_var="`eval echo $full_var`"
+ if test "x$new_full_var"="x$full_var"; then break; fi
+ full_var=$new_full_var
+ done
+
+ dnl clean up
+ full_var=$new_full_var
+ AC_SUBST([$1], "$full_var")
+
+ dnl restore prefix and exec_prefix
+ prefix=$prefix_save
+ exec_prefix=$exec_prefix_save
+])
42 autogen.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+PKG_NAME="hamster-applet"
+ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I m4"
+REQUIRED_AUTOCONF_VERSION=2.60
+REQUIRED_AUTOMAKE_VERSION=1.9.2
+REQUIRED_MACROS="python.m4"
+
+(test -f $srcdir/configure.ac \
+ && test -f $srcdir/autogen.sh) || {
+ echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+ echo " top-level $PKG_NAME directory"
+ exit 1
+}
+
+DIE=0
+
+gnome_autogen=
+gnome_datadir=
+
+ifs_save="$IFS"; IFS=":"
+for dir in $PATH ; do
+ test -z "$dir" && dir=.
+ if test -f $dir/gnome-autogen.sh ; then
+ gnome_autogen="$dir/gnome-autogen.sh"
+ gnome_datadir=`echo $dir | sed -e 's,/bin$,/share,'`
+ break
+ fi
+done
+IFS="$ifs_save"
+
+if test -z "$gnome_autogen" ; then
+ echo "You need to install the gnome-common module and make"
+ echo "sure the gnome-autogen.sh script is in your \$PATH."
+ exit 1
+fi
+
+GNOME_DATADIR="$gnome_datadir" USE_GNOME2_MACROS=1 . $gnome_autogen
8 bye-hamster.sh
@@ -0,0 +1,8 @@
+sudo rm -Rf /usr/lib/python2.5/site-packages/hamster/
+sudo rm -f /usr/lib/bonobo/servers/Hamster_Applet.server
+sudo rm -Rf /usr/share/hamster-applet/
+sudo rm -Rf /usr/lib/hamster-applet/
+sudo rm -Rf /usr/local/lib/python2.5/site-packages/hamster/
+sudo rm -f /usr/local/lib/bonobo/servers/Hamster_Applet.server
+sudo rm -Rf /usr/local/share/hamster-applet/
+sudo rm -Rf /usr/local/lib/hamster-applet/
116 configure.ac
@@ -0,0 +1,116 @@
+AC_INIT(hamster-applet, 0.1, toms.baugis@gmail.com)
+AC_CONFIG_SRCDIR(hamster/__init__.py)
+AC_CONFIG_HEADERS(config.h)
+AC_CONFIG_MACRO_DIR([m4])
+
+AM_INIT_AUTOMAKE
+GNOME_COMMON_INIT
+
+AM_MAINTAINER_MODE
+AM_DISABLE_STATIC
+AM_PROG_LIBTOOL
+AC_SUBST(ACLOCAL_AMFLAGS, "$ACLOCAL_FLAGS -I m4")
+AC_PROG_CC
+
+dnl ****************************************************************************
+dnl * Pkg-Config
+dnl ****************************************************************************
+AC_CHECK_PROG(HAVE_PKGCONFIG, pkg-config, yes, no)
+if test "x$HAVE_PKGCONFIG" = "xno"; then
+ AC_MSG_ERROR(you need to have pkgconfig installed !)
+fi
+
+dnl ****************************************************************************
+dnl * Python 2.4
+dnl ****************************************************************************
+AM_PATH_PYTHON(2.4)
+AM_CHECK_PYTHON_HEADERS(,[AC_MSG_ERROR(could not find Python headers)])
+
+dnl ****************************************************************************
+dnl * Write the values of various paths in defs.py
+dnl ****************************************************************************
+AC_SUBST(VERSION)
+AC_SUBST(PACKAGE)
+
+AS_AC_EXPAND(DATADIR, $datarootdir)
+AC_SUBST(DATADIR)
+
+AS_AC_EXPAND(LIBDIR, $libdir)
+AC_SUBST(LIBDIR)
+
+AS_AC_EXPAND(PYTHONDIR, $pythondir)
+AC_SUBST(PYTHONDIR)
+
+dnl ****************************************************************************
+dnl * PyGTK & co for Gnome Streamer
+dnl ****************************************************************************
+PKG_CHECK_MODULES(DESKBAR,
+ gtk+-2.0 >= 2.6
+ pygtk-2.0 >= 2.6
+ pygobject-2.0 >= 2.6
+ gnome-python-2.0 >= 2.10
+ gnome-desktop-2.0 >= 2.10
+)
+AC_SUBST(DESKBAR_CFLAGS)
+AC_SUBST(DESKBAR_LIBS)
+
+AC_MSG_CHECKING([for gnomeapplet module])
+if AC_RUN_LOG([DISPLAY= $PYTHON -c '
+try:
+ import gnomeapplet
+except ImportError, e:
+ if str(e).find("gnomeapplet") >= 0:
+ raise
+except:
+ pass
+']); then
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([gnomeapplet Python module required to build deskbar])
+fi
+
+dnl ****************************************************************************
+dnl * PyGTK Codegen and defs files
+dnl ****************************************************************************
+AC_PATH_PROG(PYGTK_CODEGEN, pygtk-codegen-2.0, no)
+if test "x$PYGTK_CODEGEN" = xno; then
+ AC_MSG_ERROR(could not find pygtk-codegen-2.0 script)
+fi
+
+AC_MSG_CHECKING(for pygtk defs)
+PYGTK_DEFSDIR=`$PKG_CONFIG --variable=defsdir pygtk-2.0`
+AC_SUBST(PYGTK_DEFSDIR)
+AC_MSG_RESULT($PYGTK_DEFSDIR)
+
+dnl ****************************************************************************
+dnl * Check for prctl()
+dnl ****************************************************************************
+AC_CHECK_FUNC(prctl, HAVE_PRCTL="yes", HAVE_PRCTL="yes")
+if test "x$HAVE_PRCTL" = "xyes"; then
+ AC_CHECK_DECL(PR_SET_NAME, STILL_HAVE_PRCTL="yes", STILL_HAVE_PRCTL="no", [#include <sys/prctl.h>])
+ if test "x$STILL_HAVE_PRCTL" = "xyes"; then
+ AC_DEFINE(HAVE_PRCTL, 1, [Defined as 1 if prctl and PR_SET_NAME are available])
+ fi
+fi
+
+dnl ****************************************************************************
+dnl * --------------------------------------------------------------------------
+dnl ****************************************************************************
+AC_OUTPUT([
+Makefile
+hamster/Makefile
+hamster/defs.py
+data/Makefile
+data/art/Makefile
+])
+
+echo
+echo $PACKAGE v$VERSION
+echo
+
+echo Prefix............... : $prefix
+
+echo "Now type make to compile"
+echo "Then su to root and type: make install"
+echo
22 data/Hamster_Applet.server.in
@@ -0,0 +1,22 @@
+<oaf_info>
+ <oaf_server iid="OAFIID:Hamster_Applet_Factory" type="exe" location="@LIBEXECDIR@/hamster-applet">
+ <oaf_attribute name="repo_ids" type="stringv">
+ <item value="IDL:Bonobo/GenericFactory:1.0"/>
+ <item value="IDL:Bonobo/Unknown:1.0"/>
+ </oaf_attribute>
+ <oaf_attribute name="name" type="string" value="Hamster"/>
+ <oaf_attribute name="description" type="string" value="Time tracking for masses"/>
+ </oaf_server>
+
+ <oaf_server iid="OAFIID:Hamster_Applet" type="factory" location="OAFIID:Hamster_Applet_Factory">
+ <oaf_attribute name="repo_ids" type="stringv">
+ <item value="IDL:GNOME/Vertigo/PanelAppletShell:1.0"/>
+ <item value="IDL:Bonobo/Control:1.0"/>
+ <item value="IDL:Bonobo/Unknown:1.0"/>
+ </oaf_attribute>
+ <oaf_attribute name="name" type="string" value="Hamster"/>
+ <oaf_attribute name="description" type="string" value="Time tracking for masses"/>
+ <oaf_attribute name="panel:category" type="string" value="Accessories"/>
+ <oaf_attribute name="panel:icon" type="string" value="bug-buddy.png"/>
+ </oaf_server>
+</oaf_info>
7 data/Hamster_Applet.xml
@@ -0,0 +1,7 @@
+<Root>
+ <popups>
+ <popup name="button3">
+ <menuitem name="About" verb="About" label="About" pixtype="stock" pixname="gtk-about"/>
+ </popup>
+ </popups>
+</Root>
28 data/Makefile.am
@@ -0,0 +1,28 @@
+SUBDIRS = art
+
+serverdir = $(libdir)/bonobo/servers
+
+server_DATA = Hamster_Applet.server
+
+hamsterbindir = $(libdir)/hamster-applet
+
+$(server_DATA): $(server_DATA:.server=.server.in)
+ sed -e "s|\@LIBEXECDIR\@|$(hamsterbindir)|" $< > $@
+
+resourcesdir = $(pkgdatadir)
+resources_DATA = \
+ activities.glade \
+ overview.glade \
+ Hamster_Applet.xml
+
+
+DISTCLEANFILES = \
+ $(server_in_files) \
+ $(server_DATA)
+
+EXTRA_DIST = \
+ Hamster_Applet.server.in \
+ $(resources_DATA) \
+ $(server_DATA)
+
+
91 data/activities.glade
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.2.0 on Sun Jul 29 23:33:29 2007 by toms@toms-xps-->
+<glade-interface>
+ <widget class="GtkWindow" id="activities_window">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="title" translatable="yes">Edit Activities</property>
+ <property name="default_width">300</property>
+ <property name="default_height">300</property>
+ <signal name="destroy" handler="destroy_cb"/>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH_HORIZ</property>
+ <child>
+ <widget class="GtkToolButton" id="add_activity">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label">Add</property>
+ <property name="stock_id">gtk-add</property>
+ <signal name="clicked" handler="on_add_activity_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="remove_activity">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label">Remove</property>
+ <property name="stock_id">gtk-remove</property>
+ <signal name="clicked" handler="on_remove_activity_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="promote_activity">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label">Up</property>
+ <property name="stock_id">gtk-go-up</property>
+ <signal name="clicked" handler="on_promote_activity_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="demote_activity">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label">Down</property>
+ <property name="stock_id">gtk-go-down</property>
+ <signal name="clicked" handler="on_demote_activity_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkTreeView" id="activity_list">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_clickable">True</property>
+ <property name="reorderable">True</property>
+ <property name="rules_hint">True</property>
+ <property name="enable_search">False</property>
+ <signal name="cursor_changed" handler="row_selected_cb"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
10 data/art/Makefile.am
@@ -0,0 +1,10 @@
+# ******************************************************************************
+# Images and icon
+# ******************************************************************************
+artdir = $(pkgdatadir)/art
+art_DATA = \
+ tm.png
+
+EXTRA_DIST = \
+ $(art_DATA)
+
BIN  data/art/tm.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 data/db/create_hamster_db
@@ -0,0 +1,12 @@
+create table activities(id integer primary key, name varchar2(500), work integer, activity_order integer, deleted integer);
+insert into activities values (0,'Hello world', 0, 3, 0);
+insert into activities values (1,'How are you?', 0, 1, 0);
+insert into activities values (2,'Thanks, fine, but i am the most important of all tasks', 0, 0, 0);
+
+# fact_date is ISO format (YYYYMMDD) date converted to integer
+# this way we will be able to do simple selects
+create table facts(id integer primary key, activity_id integer, fact_date integer, fact_time varchar2(4));
+
+
+1|15|20070729|1108|jauns darbs
+2|5|20070729|1232|Dear Hamsters
BIN  data/db/hamsterdb
Binary file not shown
636 data/overview.glade
@@ -0,0 +1,636 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.2.0 on Wed Aug 1 23:43:54 2007 by toms@toms-xps-->
+<glade-interface>
+ <widget class="GtkWindow" id="overview_window">
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="default_width">900</property>
+ <property name="default_height">700</property>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH_HORIZ</property>
+ <child>
+ <widget class="GtkToolButton" id="prev">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label">Go back</property>
+ <property name="stock_id">gtk-go-back</property>
+ <signal name="clicked" handler="on_prev_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="home">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label">Select today</property>
+ <property name="stock_id">gtk-home</property>
+ <signal name="clicked" handler="on_home_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="next">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="label">Go forward</property>
+ <property name="stock_id">gtk-go-forward</property>
+ <signal name="clicked" handler="on_next_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkTable" id="daygrid">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">4</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkLabel" id="label_0">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Today</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="day_0">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ <property name="rules_hint">True</property>
+ <property name="enable_search">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="totals_0">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="x_padding">6</property>
+ <property name="y_padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkLabel" id="label_2">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Today</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="day_2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ <property name="rules_hint">True</property>
+ <property name="enable_search">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow6">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="totals_2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="x_padding">6</property>
+ <property name="y_padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkLabel" id="label_1">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Today</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow7">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="day_1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ <property name="rules_hint">True</property>
+ <property name="enable_search">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow8">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="totals_1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_padding">6</property>
+ <property name="y_padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkLabel" id="label_3">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Today</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow9">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="day_3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ <property name="rules_hint">True</property>
+ <property name="enable_search">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow10">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="totals_3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="x_padding">6</property>
+ <property name="y_padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkLabel" id="label_4">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Today</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow11">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="day_4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ <property name="rules_hint">True</property>
+ <property name="enable_search">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow12">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="totals_4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_padding">6</property>
+ <property name="y_padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox8">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkLabel" id="label_5">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Today</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow13">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="day_5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ <property name="rules_hint">True</property>
+ <property name="enable_search">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow14">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="totals_5">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_padding">6</property>
+ <property name="y_padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox9">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkLabel" id="label_6">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Today</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow15">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="day_6">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ <property name="rules_hint">True</property>
+ <property name="enable_search">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow16">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="totals_6">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">6</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_padding">6</property>
+ <property name="y_padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox10">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <widget class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Totals</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">6</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow18">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTreeView" id="totals">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">6</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_padding">6</property>
+ <property name="y_padding">6</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
42 hamster/About.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+from os.path import join
+from gettext import gettext as _
+from hamster.defs import VERSION
+import gtk, gnomevfs
+import hamster
+
+
+def on_email(about, mail):
+ gnomevfs.url_show("mailto:%s" % mail)
+
+def on_url(about, link):
+ gnomevfs.url_show(link)
+
+gtk.about_dialog_set_email_hook(on_email)
+gtk.about_dialog_set_url_hook(on_url)
+
+def show_about(parent):
+ about = gtk.AboutDialog()
+ infos = {
+ "name" : _("Hamster"),
+ "logo-icon-name" : "bug-buddy",
+ "version" : VERSION,
+ "comments" : _("Time tracking for masses."),
+ "copyright" : "Copyright © 2007 Toms Baugis.",
+ "website" : "http://live.gnome.org/ProjectHamster",
+ "website-label" : _("Hamster Website"),
+ }
+
+ about.set_authors(["Toms Baugis <toms.baugis@gmail.com>"])
+# about.set_artists([])
+# about.set_documenters([])
+
+ #translators: These appear in the About dialog, usual format applies.
+ #about.set_translator_credits( _("translator-credits") )
+
+ for prop, val in infos.items():
+ about.set_property(prop, val)
+
+ about.connect("response", lambda self, *args: self.destroy())
+ about.set_screen(parent.get_screen())
+ about.show_all()
94 hamster/HamsterApplet.py
@@ -0,0 +1,94 @@
+import os, time
+from os.path import *
+import gnomeapplet, gtk
+import hamster, hamster.db
+from hamster.About import show_about
+
+
+class HamsterApplet(object):
+ def __init__(self, applet):
+ self.applet = applet
+ self.label = gtk.Label("Hamster")
+
+ self.menu = gtk.Menu()
+ # build the menu
+ update_menu(self.menu)
+
+
+ self.evBox = gtk.EventBox()
+ self.evBox.add(self.label)
+ self.evBox.connect("button-press-event", self.clicked)
+ self.applet.add(self.evBox)
+
+ self.applet.setup_menu_from_file (
+ hamster.SHARED_DATA_DIR, "Hamster_Applet.xml",
+ None, [
+ ("About", self.on_about),
+ ])
+
+ self.applet.show_all()
+
+ def clicked(self, event_box, event):
+ if event.button == 1:
+ self.menu.popup(None, None, None, event.button, gtk.get_current_event_time())
+
+ def on_about (self, component, verb):
+ show_about(self.applet)
+
+
+def edit_activities(menu_item):
+ from hamster.activities import ActivitiesEditor
+ activities_editor = ActivitiesEditor()
+ store = activities_editor.get_store()
+
+ # inform widgets of changes in model
+ store.connect("row_changed", activities_changed_cb, menu_item.parent)
+ store.connect("rows_reordered", activities_reordered_cb, menu_item.parent)
+ store.connect("row_deleted", activity_deleted_cb, menu_item.parent)
+ activities_editor.show()
+
+def show_overview(menu_item):
+ from hamster.overview import OverviewController
+ overview = OverviewController()
+ overview.show()
+
+
+def activities_changed_cb(model, path, row, menu):
+ update_menu(menu)
+
+def activities_reordered_cb(model, path, row1, row2, menu):
+ update_menu(menu)
+
+def activity_deleted_cb(model, path, menu):
+ update_menu(menu)
+
+def changeActivity(menu, activity_id):
+ hamster.db.add_fact(activity_id)
+
+def update_menu(menu):
+ #remove all items
+ children = menu.get_children()
+ for child in children:
+ menu.remove(child)
+
+ #populate fresh list from DB
+ activities = hamster.db.get_activity_list()
+ for activity in activities:
+ item = gtk.MenuItem(activity['name'])
+ item.connect("activate", changeActivity, activity['id'])
+ menu.add(item)
+
+ separator = gtk.SeparatorMenuItem()
+ menu.add(separator)
+
+ menu_edit_activities = gtk.MenuItem('Edit activities');
+ menu_edit_activities.connect("activate", edit_activities)
+ menu.add(menu_edit_activities)
+
+ menu_show_overview = gtk.MenuItem('Overview');
+ menu_show_overview.connect("activate", show_overview)
+ menu.add(menu_show_overview)
+
+ menu.show_all()
+
+
31 hamster/Makefile.am
@@ -0,0 +1,31 @@
+SUBDIRS =
+
+hamster-applet: hamster-applet.py
+ sed -e "s|\@PYTHONDIR\@|$(pythondir)/hamster|" $< > $@
+
+hamsterbindir = $(libdir)/hamster-applet
+hamsterbin_SCRIPTS = hamster-applet
+
+hamsterdir = $(pythondir)/hamster
+hamster_PYTHON = \
+ defs.py \
+ db.py \
+ activities.py \
+ overview.py \
+ HamsterApplet.py \
+ About.py \
+ __init__.py
+
+BUILT_SOURCES = \
+ hamster-applet
+
+CLEANFILES = \
+ $(BUILT_SOURCES)
+
+DISTCLEANFILES = \
+ defs.py \
+ $(CLEANFILES)
+
+EXTRA_DIST = \
+ defs.py.in \
+ hamster-applet.py
40 hamster/__init__.py
@@ -0,0 +1,40 @@
+import os, sys
+from os.path import join, exists, isdir, isfile, dirname, abspath, expanduser
+
+import gtk
+
+# Autotools set the actual data_dir in defs.py
+from defs import *
+
+try:
+ # Allows to load uninstalled .la libs
+ import ltihooks
+except ImportError:
+ pass
+
+# Allow to use not installed hamster
+UNINSTALLED_HAMSTER = False
+def _check(path):
+ return exists(path) and isdir(path) and isfile(path+"/AUTHORS")
+
+name = join(dirname(__file__), '..')
+if _check(name):
+ UNINSTALLED_HAMSTER = True
+
+# Sets SHARED_DATA_DIR to local copy, or the system location
+# Typically shared data dir is /usr/share/hamster-applet
+if UNINSTALLED_HAMSTER:
+ SHARED_DATA_DIR = abspath(join(dirname(__file__), '..', 'data'))
+else:
+ SHARED_DATA_DIR = join(DATA_DIR, "hamster-applet")
+print "Data Dir: %s" % SHARED_DATA_DIR
+
+USER_HAMSTER_DIR = expanduser("~/.gnome2/hamster-applet")
+if not exists(USER_HAMSTER_DIR):
+ try:
+ os.makedirs(USER_HAMSTER_DIR, 0744)
+ except Exception , msg:
+ print 'Error:could not create user dir (%s): %s' % (USER_HAMSTER_DIR, msg)
+
+# Path to images, icons
+ART_DATA_DIR = join(SHARED_DATA_DIR, "art")
203 hamster/activities.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python
+import pygtk
+pygtk.require('2.0')
+
+import os
+import gtk
+import gtk.glade
+
+import hamster
+import hamster.db
+
+def get_prev(selection, model):
+ (model, iter) = selection.get_selected()
+
+ #previous item
+ path = model.get_path(iter)[0] - 1
+ if path >= 0:
+ return model.get_iter_from_string(str(path))
+ else:
+ return None
+
+def ordered_list(row, columns):
+ #FIXME - i know there was some cool short way to map directly
+ res = []
+ for column in columns:
+ res.append(row[column])
+ return res
+
+class ActivityStore(gtk.ListStore):
+ columns = ['id', 'name', 'work', 'activity_order']
+
+ def __init__(self):
+ #id, name, work, order
+ gtk.ListStore.__init__(self, int, str, 'gboolean', int)
+
+ def load(self):
+ """ Loads activity list from database, ordered by
+ activity_order """
+
+ activity_list = hamster.db.get_activity_list()
+
+ for activity in activity_list:
+ self.append(ordered_list(activity, self.columns)) #performing the magick, so we don't risk with database field order change
+
+ def value(self, path, column):
+ return self[path][self.columns.index(column)]
+
+ def update(self, path, column, new_value):
+ self[path][self.columns.index(column)] = new_value
+
+class ActivitiesEditor:
+ def __init__(self):
+ self.wTree = gtk.glade.XML(os.path.join(hamster.SHARED_DATA_DIR, "activities.glade"))
+ self.window = self.get_widget('activities_window')
+
+ activities = hamster.db.get_activity_list()
+
+ # create and fill store with activities
+ self.store = ActivityStore()
+ self.store.load() #get data from DB
+
+ self.configure_tree()
+ self.wTree.signal_autoconnect(self)
+
+ def get_widget(self, name):
+ """ skip one variable (huh) """
+ return self.wTree.get_widget(name)
+
+ def get_store(self):
+ """returns store, so we can add some watchers in case if anything changes"""
+ return self.store
+
+ def show(self):
+ self.selection_changed_cb(self.treeview.get_selection(), self.store)
+ self.window.show_all()
+
+ def configure_tree(self):
+ """ Fills store with activities, and connects it to tree """
+
+ self.treeview = treeview = self.get_widget('activity_list')
+
+ nameColumn = gtk.TreeViewColumn('Name')
+ nameColumn.set_expand(True)
+ nameCell = gtk.CellRendererText()
+ nameCell.set_property('editable', True)
+ nameCell.connect('edited', self.name_edited_cb, self.store)
+ nameColumn.pack_start(nameCell, True)
+ nameColumn.set_attributes(nameCell, text = self.store.columns.index('name'))
+ nameColumn.set_sort_column_id(1)
+ treeview.append_column(nameColumn)
+
+ categoryColumn = gtk.TreeViewColumn('Work?')
+ categoryColumn.set_expand(False)
+ categoryCell = gtk.CellRendererToggle()
+ categoryCell.set_property('activatable', True);
+ categoryCell.connect('toggled', self.work_toggled_cb, self.store)
+ categoryColumn.pack_start(categoryCell, True)
+ categoryColumn.set_attributes(categoryCell, active = self.store.columns.index('work'))
+ treeview.append_column(categoryColumn)
+
+ treeview.set_model(self.store)
+
+
+ self.selection = treeview.get_selection()
+ self.selection.connect('changed', self.selection_changed_cb, self.store)
+
+ def update_activity(self, tree_row):
+ print "Update activity: ", tree_row[3]
+ #map to dictionary, for easier updates
+ row_data = {'name': tree_row[1],
+ 'work': tree_row[2],
+ 'id': tree_row[0]}
+
+ # update id (necessary for new records)
+ tree_row[0] = hamster.db.update_activity(row_data)
+
+ # callbacks
+ def work_toggled_cb(self, cell, path, model):
+ model.update(path, 'work', not model.value(path, 'work')) #inverse
+ self.update_activity(model[path])
+ return True
+
+ def name_edited_cb(self, cell, path, new_text, model):
+ model.update(path, 'name', new_text)
+ self.update_activity(model[path])
+ return True
+
+ def selection_changed_cb(self, selection, model):
+ """ enables and disables action buttons depending on selected item """
+ (model, iter) = selection.get_selected()
+
+ if iter == None:
+ self.get_widget('remove_activity').set_sensitive(False)
+ self.get_widget('promote_activity').set_sensitive(False)
+ self.get_widget('demote_activity').set_sensitive(False)
+ else:
+ self.get_widget('remove_activity').set_sensitive(True)
+
+ first_item = model.get_path(iter) == (0,)
+ self.get_widget('promote_activity').set_sensitive(not first_item)
+
+ last_item = model.iter_next(iter) == None
+ self.get_widget('demote_activity').set_sensitive(not last_item)
+ return True
+
+ #toolbar button clicks
+ def on_add_activity_clicked(self, button):
+ """ appends row, jumps to it and allows user to input name """
+ new_activity = self.store.append([-1, "New activity", True, -1])
+
+ (model, iter) = self.selection.get_selected()
+
+ self.treeview.set_cursor_on_cell(model.get_string_from_iter(new_activity),
+ focus_column = self.treeview.get_column(0),
+ focus_cell = None,
+ start_editing = True)
+ return
+
+ def on_remove_activity_clicked(self, button):
+ (model, iter) = self.selection.get_selected()
+
+ next_row = model.iter_next(iter)
+
+ if next_row:
+ self.selection.select_iter(next_row)
+ else:
+ path = self.store.get_path(iter)[0] - 1
+ if path > 0:
+ self.selection.select_path(path)
+
+ hamster.db.remove_activity(model[iter][0])
+ model.remove(iter)
+ return
+
+
+ def on_promote_activity_clicked(self, button):
+ (model, iter) = self.selection.get_selected()
+
+ #previous item
+ prev_iter = get_prev(self.selection, model)
+ hamster.db.swap_activity(model[iter][0], model[prev_iter][0])
+ model.move_before(iter, prev_iter)
+
+ self.selection_changed_cb(self.selection, model)
+ return
+
+ def on_demote_activity_clicked(self, button):
+ (model, iter) = self.selection.get_selected()
+
+ next_iter = model.iter_next(iter)
+ hamster.db.swap_activity(model[iter][0], model[next_iter][0])
+ self.store.move_after(iter, next_iter)
+
+ self.selection_changed_cb(self.selection, model)
+ return
+
+
+if __name__ == '__main__':
+ controller = ActivitiesController()
+ controller.show()
+ gtk.main()
+
+
128 hamster/db.py
@@ -0,0 +1,128 @@
+"""separate file for database operations"""
+
+from pysqlite2 import dbapi2 as sqlite
+import os, time
+import hamster
+
+# we are saving data under $HOME/.hamsterdb
+DBFILE = os.path.join(hamster.USER_HAMSTER_DIR, 'hamster.db')
+con = None # Connection will be created on demand
+
+def get_facts(date):
+ query = """SELECT a.id, a.fact_date, a.fact_time, b.name
+ FROM facts a
+ LEFT JOIN activities b ON a.activity_id = b.id
+ WHERE a.fact_date = ?
+ ORDER BY a.fact_time
+ """
+
+ return fetchall(query, (date,))
+
+def add_fact(activity_id):
+ last_fact = fetchone("select max(id) from facts")
+ if last_fact: #avoid emptyness
+ id = last_fact[0] + 1
+ else:
+ last_fact = 0
+
+ insert = """INSERT INTO facts(id, activity_id,
+ fact_date, fact_time)
+ VALUES (?, ?, ?, ?)
+ """
+
+ fact_date = time.strftime('%Y%m%d')
+ fact_time = time.strftime('%H%M')
+
+ execute(insert, (id, activity_id, fact_date, fact_time))
+
+
+def get_activity_list():
+ """returns list of configured activities, in user specified order"""
+ query = """SELECT *
+ FROM activities
+ WHERE coalesce(deleted, 0) = 0
+ ORDER BY activity_order
+ """
+ activities = fetchall(query)
+
+ return activities
+
+def remove_activity(id):
+ """ sets activity to deleted = True """
+ print "would like to remove activity %d" % (id)
+ execute("update activities set deleted = 1 where id = ?", (id,))
+
+def swap_activity(id1, id2):
+ """ swaps nearby activities """
+ # TODO - 2 selects and 2 updates is wrong we could live without selects
+ priority1 = fetchone("select activity_order from activities where id = ?", (id1,))[0]
+ priority2 = fetchone("select activity_order from activities where id = ?", (id2,))[0]
+
+
+ execute("update activities set activity_order = ? where id = ?", (priority1, id2) )
+ execute("update activities set activity_order = ? where id = ?", (priority2, id1) )
+
+def update_activity(activity):
+ if activity['work']:
+ work = 1
+ else:
+ work = 0
+
+ if activity['id'] == -1: # -1 means, we have a new entry!
+ new_rec = fetchone("select max(id) +1 , max(activity_order) + 1 from activities")
+ new_id, new_order = 0, 0
+ if new_rec: # handle case when we have no activities at all
+ new_id, new_order = new_rec[0], new_rec[1]
+
+ insert = """insert into activities (id, name, work, activity_order)
+ values (?, ?, ?, ?);"""
+ execute(insert, (new_id, activity['name'], work, new_order))
+ activity['id'] = new_id
+
+ else: # Update
+ update = "UPDATE activities SET name = ?, work = ? WHERE id = ?;"
+ execute(update, (activity['name'], work, activity['id']))
+
+ return activity['id']
+
+
+""" Here be dragons (lame connection/cursor wrappers) """
+def get_connection():
+ global con
+ if con == None:
+ con = sqlite.connect(DBFILE)
+
+ con.row_factory = sqlite.Row
+ return con
+
+def fetchall(query, params = None):
+ con = get_connection()
+ cur = con.cursor()
+
+ if params:
+ cur.execute(query, params)
+ else:
+ cur.execute(query)
+
+ res = cur.fetchall()
+ cur.close()
+
+ return res
+
+def fetchone(query, params = None):
+ res = fetchall(query, params)
+ if res:
+ return res[0]
+ else:
+ return None
+
+def execute(statement, params):
+ con = get_connection()
+ cur = con.cursor()
+
+ res = cur.execute(statement, params)
+
+ con.commit()
+ cur.close()
+
+
5 hamster/defs.py.in
@@ -0,0 +1,5 @@
+DATA_DIR = "@DATADIR@"
+LIB_DIR = "@LIBDIR@"
+VERSION = "@VERSION@"
+PACKAGE = "@PACKAGE@"
+PYTHONDIR = "@PYTHONDIR@"
111 hamster/hamster-applet.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+#
+# (C) 2007 Toms Baugis
+# Licensed under the GNU LGPL v3.
+PROFILE = False
+if PROFILE:
+ import statprof
+ statprof.start()
+
+import gtk, gnomeapplet
+import getopt, sys
+from os.path import *
+
+# Allow to use uninstalled
+def _check(path):
+ return exists(path) and isdir(path) and isfile(path+"/AUTHORS")
+
+name = join(dirname(__file__), '..')
+if _check(name):
+ print 'Running uninstalled hamster, modifying PYTHONPATH'
+ sys.path.insert(0, abspath(name))
+else:
+ sys.path.insert(0, abspath("@PYTHONDIR@"))
+ print "Running installed hamster, using [@PYTHONDIR@:$PYTHONPATH]"
+
+# Now the path is set, import our applet
+import hamster, hamster.HamsterApplet, hamster.defs
+
+def applet_factory(applet, iid):
+ print 'Starting Hamster instance:', applet, iid
+ hamster.HamsterApplet.HamsterApplet(applet)
+ return True
+
+# Return a standalone window that holds the applet
+def build_window():
+ app = gtk.Window(gtk.WINDOW_TOPLEVEL)
+ app.set_title("Hamster Applet")
+ app.connect("destroy", gtk.main_quit)
+
+ applet = gnomeapplet.Applet()
+ applet.get_orient = lambda: gnomeapplet.ORIENT_DOWN
+ applet_factory(applet, None)
+ applet.reparent(app)
+
+ app.show_all()
+
+ return app
+
+def usage():
+ print """=== Hamster applet: Usage
+$ hamster-applet [OPTIONS]
+
+OPTIONS:
+ -w, --window Launch the applet in a standalone window for test purposes (default=no).
+ -t, --trace Use tracing (default=no).
+ """
+ sys.exit()
+
+if __name__ == "__main__":
+ standalone = False
+ do_trace = False
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "wt", ["window", "trace"])
+ except getopt.GetoptError:
+ # Unknown args were passed, we fallback to bahave as if
+ # no options were passed
+ print "WARNING: Unknown arguments passed, using defaults."
+ opts = []
+ args = sys.argv[1:]
+
+ for o, a in opts:
+ if o in ("-w", "--window"):
+ standalone = True
+ elif o in ("-t", "--trace"):
+ do_trace = True
+
+ print 'Running with options:', {
+ 'standalone': standalone,
+ 'do_trace': do_trace,
+ }
+
+ if standalone:
+ import gnome
+ gnome.init(hamster.defs.PACKAGE, hamster.defs.VERSION)
+ build_window()
+
+ # run the new command using the given trace
+ if do_trace:
+ import trace
+ trace = trace.Trace(
+ ignoredirs=[sys.prefix],
+ ignoremods=['sys', 'os', 'getopt', 'libxml2', 'ltihooks'],
+ trace=True,
+ count=False)
+ trace.run('gtk.main()')
+ else:
+ gtk.main()
+
+ else:
+ gnomeapplet.bonobo_factory(
+ "OAFIID:Hamster_Applet_Factory",
+ gnomeapplet.Applet.__gtype__,
+ hamster.defs.PACKAGE,
+ hamster.defs.VERSION,
+ applet_factory)
+
+ if PROFILE:
+ statprof.stop()
+ statprof.display()
+
141 hamster/overview.py
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+import pygtk
+pygtk.require('2.0')
+
+import os
+import gtk
+import gtk.glade
+
+import hamster
+import hamster.db
+import time
+import datetime as dt
+
+GLADE_FILE = "overview.glade"
+
+class DayStore(object):
+ """A day view contains a treeview for facts of the day and another
+ one for totals. It creates those widgets on init, user
+ fill_view(store) to fill the tree and calculate totals """
+
+ def __init__(self, date = time.strftime('%Y%m%d')):
+ self.fact_store = gtk.ListStore(str, str)
+ self.total_store = gtk.ListStore(str, str)
+
+ db_facts = hamster.db.get_facts(date)
+
+ prev_fact, prev_time = None, None
+ self.totals = {}
+
+ for fact in db_facts:
+ hours = fact['fact_time'][:2]
+ minutes = fact['fact_time'][2:4]
+ self.fact_store.append([fact['name'], hours + ':' + minutes])
+
+ # we need time only for delta, so let's convert to mins
+ fact_time = int(hours) * 60 + int(minutes)
+
+ if prev_fact:
+ duration = fact_time - prev_time
+ if not self.totals.has_key('prev_fact'):
+ self.totals[prev_fact] = 0
+
+ self.totals[prev_fact] += duration
+
+ prev_fact, prev_time = fact['name'], fact_time
+
+ # now we are good to append totals!
+ # no sorting - chronological is intuitive
+ for total in self.totals:
+ in_hours = self.totals[total] / 60.0
+ self.total_store.append(["%.1fh" % in_hours, total])
+
+
+class OverviewController:
+ def __init__(self):
+ self.wTree = gtk.glade.XML(os.path.join(hamster.SHARED_DATA_DIR, GLADE_FILE))
+ self.window = self.get_widget('overview_window')
+
+ self.today = dt.datetime.today()
+ self.monday = self.today - dt.timedelta(self.today.weekday())
+
+ # now let's set up tree columns!
+ for i in range(7):
+ treeview = self.get_widget('day_' + str(i))
+ timeColumn = gtk.TreeViewColumn('Time')
+ timeColumn.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
+ timeColumn.set_expand(False)
+ timeCell = gtk.CellRendererText()
+ timeColumn.pack_start(timeCell, True)
+ timeColumn.set_attributes(timeCell, text=1)
+ treeview.append_column(timeColumn)
+
+ nameColumn = gtk.TreeViewColumn('Name')
+ nameColumn.set_expand(True)
+ nameCell = gtk.CellRendererText()
+ nameColumn.pack_start(nameCell, True)
+ nameColumn.set_attributes(nameCell, text=0)
+ treeview.append_column(nameColumn)
+
+ treeview = self.get_widget('totals_' + str(i))
+ nameColumn = gtk.TreeViewColumn('Name')
+ nameColumn.set_expand(True)
+ nameCell = gtk.CellRendererText()
+ nameColumn.pack_start(nameCell, True)
+ nameColumn.set_attributes(nameCell, text=1)
+ treeview.append_column(nameColumn)
+
+ timeColumn = gtk.TreeViewColumn('Time')
+ timeColumn.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE)
+ timeColumn.set_expand(False)
+ timeCell = gtk.CellRendererText()
+ timeColumn.pack_start(timeCell, True)
+ timeColumn.set_attributes(timeCell, text=0)
+ treeview.append_column(timeColumn)