318 lines
11 KiB
Python
318 lines
11 KiB
Python
|
|
import gtk
|
|
import gobject
|
|
from datetime import *
|
|
|
|
class Window:
|
|
def __init__(self, progName, ds):
|
|
self.ds = ds
|
|
self.shown_projects = []
|
|
now = datetime.now()
|
|
self.monday = now.date() - timedelta(now.weekday())
|
|
|
|
# Top-level Window creation
|
|
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
|
self.window.set_title(progName)
|
|
self.window.set_geometry_hints()
|
|
self.window.connect("delete_event", self.delete_event)
|
|
self.window.connect("destroy", self.destroy_event)
|
|
self.window.connect("key-press-event", self.window_key_press_event)
|
|
|
|
# Menu Bar
|
|
self.menubar = gtk.MenuBar()
|
|
mi = gtk.MenuItem('_File')
|
|
self.menubar.append(mi)
|
|
mi = gtk.MenuItem('_Report')
|
|
self.menubar.append(mi)
|
|
mi = gtk.MenuItem('_Help')
|
|
self.menubar.append(mi)
|
|
|
|
# Projects Table
|
|
self.projects_present = False
|
|
self.currProject = 0
|
|
self.projects_container = gtk.VBox()
|
|
self.updateProjects()
|
|
|
|
# Bottom Control Bar
|
|
self.mark_label = gtk.Label()
|
|
adjust_button = gtk.Button('Adjust')
|
|
in_button = gtk.Button('In')
|
|
out_button = gtk.Button('Out')
|
|
exit_button = gtk.Button('Exit')
|
|
|
|
hbox = gtk.HBox()
|
|
hbox.pack_start(self.mark_label, expand = True, fill = False)
|
|
hbox.pack_start(adjust_button, expand = False)
|
|
hbox.pack_start(in_button, expand = False)
|
|
hbox.pack_start(out_button, expand = False)
|
|
hbox.pack_start(exit_button, expand = False)
|
|
|
|
vbox = gtk.VBox()
|
|
vbox.pack_start(self.menubar)
|
|
vbox.pack_start(self.projects_container)
|
|
vbox.pack_start(gtk.HSeparator())
|
|
vbox.pack_start(hbox)
|
|
|
|
self.window.add(vbox)
|
|
|
|
def updateProjects(self):
|
|
def projTblCell(text, pnum):
|
|
lbl = gtk.Label(text)
|
|
e = gtk.EventBox()
|
|
e.add(lbl)
|
|
if pnum == self.currProject:
|
|
e.set_state(gtk.STATE_SELECTED)
|
|
return e
|
|
|
|
if self.projects_present:
|
|
self.projects_container.remove(self.projects_table)
|
|
self.projects = self.ds.getProjects()
|
|
self.project_hour_labels = {}
|
|
projects_to_show = {}
|
|
for p in self.shown_projects:
|
|
projects_to_show[p] = 1
|
|
project_week_hours = self.getProjectWeekHours()
|
|
for p in project_week_hours:
|
|
projects_to_show[p] = 1
|
|
|
|
self.tasks = self.ds.getTasks(self.currProject)
|
|
self.task_hour_labels = {}
|
|
|
|
# Header row
|
|
col_headers = ('Project',
|
|
'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Tot')
|
|
rows = 3 + len(projects_to_show) + len(self.tasks)
|
|
columns = len(col_headers)
|
|
self.projects_table = gtk.Table(rows = rows, columns = columns)
|
|
|
|
row = 0
|
|
for i in range(len(col_headers)):
|
|
l = gtk.Label()
|
|
l.set_markup('<b>%s</b>' % col_headers[i])
|
|
if i == 0:
|
|
l.set_alignment(0.0, 0.0)
|
|
l.set_size_request(60, -1)
|
|
else:
|
|
l.set_size_request(40, -1)
|
|
self.projects_table.attach(l, i, i + 1, row, row + 1)
|
|
|
|
row += 1
|
|
pnames_to_show = map(lambda x: self.projects[x], projects_to_show)
|
|
pnames_to_show.sort()
|
|
for pname in pnames_to_show:
|
|
pnum = self.getProjectNum(pname)
|
|
e = projTblCell(pname, pnum)
|
|
e.get_child().set_alignment(0.0, 0.0)
|
|
e.add_events(gtk.gdk.BUTTON_PRESS_MASK)
|
|
e.connect("button-press-event", self.project_click_event)
|
|
self.projects_table.attach(e, 0, 1, row, row + 1)
|
|
self.project_hour_labels[pnum] = {}
|
|
for i in range(8):
|
|
e = projTblCell(" ", pnum)
|
|
self.projects_table.attach(e, i + 1, i + 2, row, row + 1)
|
|
self.project_hour_labels[pnum][i] = l
|
|
row += 1
|
|
|
|
# Totals row
|
|
l = gtk.Label()
|
|
l.set_markup('<b>Total</b>')
|
|
l.set_alignment(0.0, 0.0)
|
|
self.projects_table.attach(l, 0, 1, row, rows + 1)
|
|
row += 1
|
|
|
|
# Add project row
|
|
self.new_project_combobox = gtk.combo_box_entry_new_text()
|
|
self.new_project_combobox.set_size_request(250, -1)
|
|
self.new_project_combobox.connect("key-release-event",
|
|
self.project_key_press_event)
|
|
project_names = self.projects.values()
|
|
project_names.sort()
|
|
for project in project_names:
|
|
self.new_project_combobox.append_text(project)
|
|
self.add_project_button = gtk.Button('Add')
|
|
self.add_project_button.connect('clicked', self.add_project_event)
|
|
hbox = gtk.HBox()
|
|
hbox.pack_start(self.new_project_combobox, expand = False)
|
|
hbox.pack_start(self.add_project_button, expand = False)
|
|
self.projects_table.attach(hbox, 0, columns, row, row + 1)
|
|
self.projects_table.set_row_spacings(3)
|
|
row += 1
|
|
|
|
# Add Tasks information of we have a current project
|
|
if self.currProject > 0:
|
|
l = gtk.Label()
|
|
l.set_markup('<b>Tasks</b>')
|
|
self.projects_table.attach(l, 0, 1, row, row + 1)
|
|
row += 1
|
|
for tnum in self.tasks:
|
|
l = gtk.Label(self.tasks[tnum])
|
|
l.set_alignment(0.0, 0.0)
|
|
e = gtk.EventBox()
|
|
e.add(l)
|
|
e.add_events(gtk.gdk.BUTTON_PRESS_MASK)
|
|
e.connect("button-press-event", self.task_click_event)
|
|
self.projects_table.attach(e, 0, 1, row, row + 1)
|
|
self.task_hour_labels[tnum] = {}
|
|
for i in range(8):
|
|
l = gtk.Label()
|
|
self.projects_table.attach(l, i + 1, i + 2, row, row + 1)
|
|
self.task_hour_labels[tnum][i] = l
|
|
row += 1
|
|
|
|
# Totals row
|
|
l = gtk.Label()
|
|
l.set_markup('<b>Total</b>')
|
|
l.set_alignment(0.0, 0.0)
|
|
self.projects_table.attach(l, 0, 1, row, row + 1)
|
|
row += 1
|
|
|
|
# Add task row
|
|
self.new_task_combobox = gtk.combo_box_entry_new_text()
|
|
self.new_task_combobox.set_size_request(250, -1)
|
|
self.new_task_combobox.connect("key-release-event",
|
|
self.task_key_press_event)
|
|
task_names = self.tasks.values()
|
|
task_names.sort()
|
|
for task in task_names:
|
|
self.new_task_combobox.append_text(task)
|
|
self.add_task_button = gtk.Button('Add')
|
|
self.add_task_button.connect('clicked', self.add_task_event)
|
|
hbox = gtk.HBox()
|
|
hbox.pack_start(self.new_task_combobox, expand = False)
|
|
hbox.pack_start(self.add_task_button, expand = False)
|
|
self.projects_table.attach(hbox, 0, columns, row, row + 1)
|
|
self.projects_table.set_row_spacings(3)
|
|
row += 1
|
|
|
|
self.projects_container.pack_start(self.projects_table)
|
|
self.projects_present = True
|
|
self.projects_table.show_all()
|
|
|
|
self.updateProjectHours()
|
|
|
|
def updateProjectHours(self):
|
|
totals = {}
|
|
for day in range(7):
|
|
dt = str(self.monday + timedelta(day))
|
|
day_hours = self.ds.getProjectDailyHours(dt)
|
|
for p in day_hours:
|
|
if p in self.project_hour_labels:
|
|
hrs = self.hoursFromSeconds(day_hours[p])
|
|
if not p in totals:
|
|
totals[p] = 0
|
|
totals[p] += float(hrs)
|
|
self.project_hour_labels[p][day].set_text(hrs)
|
|
for p in totals:
|
|
if p in self.project_hour_labels:
|
|
self.project_hour_labels[p][7].set_text(str(totals[p]))
|
|
|
|
def getProjectWeekHours(self):
|
|
proj_week_hours = {}
|
|
for day in range(7):
|
|
dt = str(self.monday + timedelta(day))
|
|
day_hours = self.ds.getProjectDailyHours(dt)
|
|
for p in day_hours:
|
|
if not p in proj_week_hours:
|
|
proj_week_hours[p] = 0
|
|
proj_week_hours[p] += float(day_hours[p])
|
|
return proj_week_hours
|
|
|
|
def hoursFromSeconds(self, secs):
|
|
if secs < 0.01 * 60 * 60:
|
|
secs = 0.01 * 60 * 60;
|
|
return "%.2f" % (secs / 60.0 / 60.0)
|
|
|
|
def main(self):
|
|
self.window.show_all()
|
|
gtk.main()
|
|
|
|
def getProjectNum(self, pname):
|
|
for p in self.projects:
|
|
if self.projects[p] == pname:
|
|
return p
|
|
return 0
|
|
|
|
def getTaskNum(self, tname):
|
|
for t in self.tasks:
|
|
if self.tasks[t] == tname:
|
|
return t
|
|
return 0
|
|
|
|
def add_project_event(self, button, data=None):
|
|
pname = self.new_project_combobox.get_active_text()
|
|
if pname in self.projects.values():
|
|
pnum = self.getProjectNum(pname)
|
|
elif len(pname.strip()):
|
|
pnum = self.ds.createProject(pname)
|
|
else:
|
|
pnum = 0
|
|
if pnum:
|
|
self.shown_projects.append(pnum)
|
|
self.updateProjects()
|
|
|
|
def project_key_press_event(self, widget, event, data=None):
|
|
if event.keyval == gtk.gdk.keyval_from_name("Return"):
|
|
self.add_project_event(1)
|
|
return True
|
|
return False
|
|
|
|
def project_click_event(self, ebox, event, data=None):
|
|
lbl = ebox.get_child()
|
|
if lbl:
|
|
if event.button == 1:
|
|
return self.project_select_event(lbl.get_text())
|
|
elif event.button == 3:
|
|
print "Right Click"
|
|
return True
|
|
return False
|
|
|
|
def project_select_event(self, projectName):
|
|
pnum = self.getProjectNum(projectName)
|
|
if pnum:
|
|
print "Selected project '%s' (%d)" % (projectName, pnum)
|
|
self.currProject = pnum
|
|
self.updateProjects()
|
|
return True
|
|
return False
|
|
|
|
def add_task_event(self, button, data=None):
|
|
tname = self.new_task_combobox.get_active_text()
|
|
if tname in self.tasks.values():
|
|
tnum = self.getTaskNum(tname)
|
|
elif len(tname.strip()):
|
|
tnum = self.ds.createTask(self.currProject, tname)
|
|
self.updateProjects()
|
|
|
|
def task_key_press_event(self, widget, event, data=None):
|
|
if event.keyval == gtk.gdk.keyval_from_name("Return"):
|
|
self.add_task_event(1)
|
|
return True
|
|
return False
|
|
|
|
def task_click_event(self, ebox, event, data=None):
|
|
lbl = ebox.get_child()
|
|
if lbl:
|
|
if event.button == 1:
|
|
return self.task_select_event(lbl.get_text())
|
|
elif event.button == 3:
|
|
print "Right Click"
|
|
return True
|
|
return False
|
|
|
|
def task_select_event(self, taskName):
|
|
tnum = self.getTaskNum(taskName)
|
|
if tnum:
|
|
print "Selected task '%s' (%d)" % (taskName, tnum)
|
|
return True
|
|
return False
|
|
|
|
def delete_event(self, widget, event, data=None):
|
|
return False
|
|
|
|
def destroy_event(self, widget, data=None):
|
|
gtk.main_quit()
|
|
|
|
def window_key_press_event(self, widget, event, data=None):
|
|
if event.keyval == gtk.gdk.keyval_from_name("Escape"):
|
|
gtk.main_quit()
|