import gtk import gobject from datetime import * class Window: def __init__(self, progName, ds): self.ds = ds self.shown_projects = [] self.taskStart = datetime.now() self.monday = \ self.taskStart.date() - timedelta(self.taskStart.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() m = gtk.Menu() mi = gtk.MenuItem('E_xit') mi.connect("activate", self.destroy_event) m.append(mi) mi = gtk.MenuItem('_File') mi.set_submenu(m) 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.currTask = 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') exit_button.connect("clicked", self.destroy_event) 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, expand = False) vbox.pack_start(self.projects_container, expand = False) vbox.pack_end(hbox, expand = False) vbox.pack_end(gtk.HSeparator(), expand = False) 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('%s' % 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] = e.get_child() row += 1 # Totals row l = gtk.Label() l.set_markup('Total') l.set_alignment(0.0, 0.0) self.projects_table.attach(l, 0, 1, row, row + 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 if we have a current project if self.currProject > 0: l = gtk.Label() l.set_markup('Tasks') 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('Total') 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, expand = False) self.projects_present = True self.projects_table.show_all() self.updateProjectHours() self.updateTaskHours() def updateProjectHours(self): totals = {} for day in range(7): dt = str(self.monday + timedelta(day)) day_hours = self.ds.getProjectDailyHours(dt) print day print day_hours 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) print totals for p in totals: if p in self.project_hour_labels: self.project_hour_labels[p][7].set_text(str(totals[p])) def updateTaskHours(self): totals = {} for day in range(7): dt = str(self.monday + timedelta(day)) day_hours = self.ds.getDailyHours(dt) if self.currProject in day_hours: for t in day_hours[self.currProject]: if t in self.task_hour_labels: hrs = self.hoursFromSeconds( day_hours[self.currProject][t]) if not t in totals: totals[t] = 0 totals[t] += float(hrs) self.task_hour_labels[t][day].set_text(hrs) for t in totals: if t in self.task_hour_labels: self.task_hour_labels[t][7].set_text(str(totals[t])) 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.project_select_event(pname) 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) else: tnum = 0 if tnum: self.tasks = self.ds.getTasks(self.currProject) self.task_select_event(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: self.updateCurrTaskHours() self.currTask = tnum print "Selected task '%s' (%d)" % (taskName, tnum) self.updateProjects() return True return False def updateCurrTaskHours(self): nst = datetime.now() delta = nst - self.taskStart self.ds.addTaskHours(self.currTask, nst.date(), delta.seconds) self.taskStart = nst def delete_event(self, widget, event, data=None): return False def destroy_event(self, widget, data=None): # could be called by window or exit button 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()