class ResourceManagementGUI: timeout_id = None time_clock = None def __init__(self, id_=None): self.builder = Gtk.Builder() self.builder.add_from_file(UI_FILE) self.builder.connect_signals(self) self.cursor = DB.cursor() self.handler_ids = list() for connection in (("shutdown", self.main_shutdown), ): handler = broadcaster.connect(connection[0], connection[1]) self.handler_ids.append(handler) renderer = CellRendererRgbaArray() treecolumn = self.builder.get_object('treeviewcolumn6') treecolumn.pack_start(renderer, True) treecolumn.set_attributes(renderer, RGBA_array=7) renderer.set_property('editable', True) renderer.connect('editing-started', self.tag_editing_started) self.timer_timeout = None self.row_id = None self.join_filter = '' self.resource_store = self.builder.get_object('resource_store') self.contact_store = self.builder.get_object('contact_store') self.contact_completion = self.builder.get_object('contact_completion') self.contact_completion.set_match_func(self.contact_match_func) textview = self.builder.get_object('textview1') spell_check.add_checker_to_widget(textview) self.dated_for_calendar = DateTimeCalendar() no_date_button = self.builder.get_object('button5') self.dated_for_calendar.pack_start(no_date_button) treeview = self.builder.get_object('treeview1') self.dated_for_calendar.set_relative_to(treeview) self.dated_for_calendar.connect('day-selected', self.dated_for_calendar_day_selected) self.older_than_calendar = DateTimeCalendar() self.older_than_calendar.connect('day-selected', self.older_than_date_selected) entry = self.builder.get_object('entry1') self.older_than_calendar.set_relative_to(entry) if id_ != None: selection = self.builder.get_object('treeview-selection1') for row in self.resource_store: if row[0] == id_: selection.select_path(row.path) self.cursor.execute("SELECT notes FROM resources " "WHERE id = %s", (id_, )) for row in self.cursor.fetchall(): text = row[0] self.builder.get_object('notes_buffer').set_text(text) self.window = self.builder.get_object('window1') self.window.show_all() self.older_than_calendar.set_today() self.populate_stores() def destroy(self, widget): if self.timeout_id: self.save_notes() for handler in self.handler_ids: broadcaster.disconnect(handler) self.cursor.close() def main_shutdown(self, main): if self.timeout_id: self.save_notes() def focus_in_event(self, window, event): self.populate_stores() def row_limit_value_changed(self, spinbutton): self.populate_resource_store() def resource_threaded_checkbutton_toggled(self, checkbutton): self.populate_resource_store() def treeview_button_release_event(self, treeview, event): if event.button == 3: menu = self.builder.get_object('menu1') menu.popup_at_pointer() def delete_activated(self, menuitem): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path != []: row_id = model[path][0] try: self.cursor.execute("DELETE FROM resources " "WHERE id = %s", (row_id, )) DB.commit() except Exception as e: self.show_message(e) DB.rollback() self.populate_resource_store() def block_number_activated(self, menuitem): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path != []: phone_number = model[path][11] try: self.cursor.execute( "INSERT INTO phone_blacklist " "(number, blocked_calls) VALUES (%s, 0)", (phone_number, )) DB.commit() except Exception as e: self.show_message(e) DB.rollback() def contact_hub_activated(self, menuitem): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path != []: contact_id = model[path][2] if contact_id == 0: self.show_message("No contact selected for this row!") return import contact_hub contact_hub.ContactHubGUI(contact_id) def report_hub_activated(self, button): treeview = self.builder.get_object('treeview1') from reports import report_hub report_hub.ReportHubGUI(treeview) def remove_manual_sort_activated(self, menuitem): c = DB.cursor() c.execute("UPDATE resources SET sort = 0 WHERE posted = False") DB.commit() self.populate_resource_store() def remove_tags(self): flowbox = self.builder.get_object('tag_flowbox') for child in flowbox.get_children(): flowbox.remove(child) def populate_tag_flowbox(self): self.remove_tags() flowbox = self.builder.get_object('tag_flowbox') c = DB.cursor() c.execute( "SELECT " "tag, " "red, " "green, " "blue, " "alpha " "FROM resource_ids_tag_ids AS riti " "JOIN resource_tags AS rt ON rt.id = riti.resource_tag_id " "WHERE riti.resource_id = %s", (self.row_id, )) for row in c.fetchall(): tag_name = row[0] red = int(row[1] * 255) green = int(row[2] * 255) blue = int(row[3] * 255) alpha = int(row[4] * 255) hex_color = '#%02x%02x%02x%02x' % (red, green, blue, alpha) string = "<span foreground='%s'>%s</span>\n" % (hex_color, tag_name) label = Gtk.Label() label.set_markup(string) label.show() flowbox.add(label) def populate_tags_applied_store(self): store = self.builder.get_object('tags_applied_store') store.clear() c = DB.cursor() c.execute( "SELECT id::text, tag, red, green, blue, alpha, " "(SELECT True FROM resource_ids_tag_ids AS riti " "WHERE (riti.resource_id, resource_tag_id) = (%s, rt.id)) " "FROM resource_tags AS rt " "ORDER BY tag", (self.row_id, )) for row in c.fetchall(): tag_id = row[0] tag_name = row[1] rgba = Gdk.RGBA(1, 1, 1, 1) rgba.red = row[2] rgba.green = row[3] rgba.blue = row[4] rgba.alpha = row[5] applied = row[6] store.append([tag_id, tag_name, rgba, applied]) def tag_toggled(self, cellrenderertoggle, path): store = self.builder.get_object('tags_applied_store') active = cellrenderertoggle.get_active() tag_id = store[path][0] store[path][3] = not active selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: return resource_id = model[path][0] c = DB.cursor() if not active: c.execute( "INSERT INTO resource_ids_tag_ids " "(resource_id, resource_tag_id) VALUES " "(%s, %s) " "ON CONFLICT (resource_id, resource_tag_id) " "DO NOTHING ", (resource_id, tag_id)) else: c.execute( "DELETE FROM resource_ids_tag_ids WHERE " "(resource_id, resource_tag_id) = " "(%s, %s)", (resource_id, tag_id)) DB.commit() def tag_popover_closed(self, popover): self.populate_tag_flowbox() selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: return iter_ = self.resource_store.get_iter(path) self.populate_row_tag_list(iter_) def row_activated(self, treeview, path, treeview_column): if self.timeout_id: self.save_notes() self.row_id = self.resource_store[path][0] self.populate_notes() self.populate_tag_flowbox() self.populate_tags_applied_store() def populate_notes(self): if self.row_id == None: return self.cursor.execute("SELECT notes FROM resources " "WHERE id = %s", (self.row_id, )) for row in self.cursor.fetchall(): text = row[0] self.builder.get_object('notes_buffer').set_text(text) break else: self.builder.get_object('notes_buffer').set_text('') DB.rollback() def contact_match_func(self, completion, key, iter): split_search_text = key.split() for text in split_search_text: if text not in self.contact_store[iter][1].lower(): return False # no match return True # it's a hit! def contact_match_selected(self, completion, model, iter_): contact_id = model[iter_][0] selection = self.builder.get_object('treeview-selection1') tree_model, path = selection.get_selected_rows() id_ = tree_model[path][0] self.cursor.execute( "UPDATE resources " "SET (contact_id, phone_number) = " "(%s, (SELECT phone FROM contacts WHERE id = %s)) " "WHERE id = %s ", (contact_id, contact_id, id_)) DB.commit() self.populate_resource_store() def contact_editing_started(self, renderer_combo, combobox, path): entry = combobox.get_child() entry.set_completion(self.contact_completion) def contact_changed(self, renderer_combo, path, tree_iter): contact_id = self.contact_store[tree_iter][0] id_ = self.resource_store[path][0] self.cursor.execute( "UPDATE resources " "SET (contact_id, phone_number) = " "(%s, (SELECT phone FROM contacts WHERE id = %s)) " "WHERE id = %s", (contact_id, contact_id, id_)) DB.commit() self.populate_resource_store() def populate_stores(self): self.contact_store.clear() self.cursor.execute("SELECT " "id::text, " "name, " "ext_name, " "phone " "FROM contacts " "WHERE deleted = False ORDER BY name") for row in self.cursor.fetchall(): self.contact_store.append(row) active = self.builder.get_object('tag_combo').get_active() store = self.builder.get_object('tag_store') store.clear() store.append(['', 'All tags', Gdk.RGBA(0, 0, 0, 0)]) self.cursor.execute("SELECT id::text, tag, red, green, blue, alpha " "FROM resource_tags " "ORDER BY tag") for row in self.cursor.fetchall(): tag_id = row[0] tag_name = row[1] rgba = Gdk.RGBA(1, 1, 1, 1) rgba.red = row[2] rgba.green = row[3] rgba.blue = row[4] rgba.alpha = row[5] store.append([tag_id, tag_name, rgba]) self.builder.get_object('tag_combo').set_active(active) DB.rollback() def new_entry_clicked(self, button): self.cursor.execute("INSERT INTO resources " "(tag_id) " "SELECT id FROM resource_tags " "WHERE finished = False LIMIT 1 " "RETURNING id") new_id = self.cursor.fetchone()[0] DB.commit() self.populate_resource_store() for row in self.resource_store: if row[0] == new_id: treeview = self.builder.get_object('treeview1') c = treeview.get_column(0) treeview.set_cursor(row.path[0], c, True) break def post_entry_clicked(self, button): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: return row_id = model[path][0] c = DB.cursor() c.execute( "UPDATE resources SET posted = True WHERE id = %s; " "UPDATE time_clock_projects " "SET active = False " "WHERE resource_id = %s ", (row_id, row_id)) DB.commit() self.populate_resource_store() self.builder.get_object('notes_buffer').set_text('') def subject_edited(self, renderer_text, path, text): self.editing = False id_ = self.resource_store[path][0] self.cursor.execute( "UPDATE resources " "SET subject = %s " "WHERE id = %s", (text, id_)) DB.commit() self.resource_store[path][1] = text def dated_for_calendar_day_selected(self, calendar): date = calendar.get_date() selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() id_ = model[path][0] self.cursor.execute( "UPDATE resources " "SET dated_for = %s " "WHERE id = %s", (date, id_)) DB.commit() self.populate_resource_store() def dated_for_editing_started(self, widget, entry, text): event = Gtk.get_current_event() rect = Gdk.Rectangle() rect.x = event.x rect.y = event.y + 30 rect.width = rect.height = 1 self.dated_for_calendar.set_pointing_to(rect) selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() row_id = model[path][0] self.cursor.execute( "SELECT COALESCE(dated_for, CURRENT_DATE) " "FROM resources WHERE id = %s", (row_id, )) for row in self.cursor.fetchall(): self.dated_for_calendar.set_datetime(row[0]) GLib.idle_add(self.dated_for_calendar.show) # this hides the entry DB.rollback() def tag_editing_started(self, renderer_combo, combobox, path): event = Gtk.get_current_event() rect = Gdk.Rectangle() rect.x = event.x rect.y = event.y + 30 rect.width = rect.height = 1 combobox.hide() popover = self.builder.get_object('tag_popover') popover.set_pointing_to(rect) GLib.idle_add(popover.show) def sort_by_combo_changed(self, combobox): self.populate_resource_store() def tag_combo_changed(self, combobox): tag_id = combobox.get_active_id() if tag_id == None: return if tag_id == '': self.join_filter = '' else: self.join_filter = 'JOIN resource_ids_tag_ids AS riti '\ 'ON riti.resource_id = rm.id '\ 'AND riti.resource_tag_id = %s' % tag_id self.populate_resource_store() def notes_buffer_changed(self, text_buffer): #only save changes created by user if not self.builder.get_object('textview1').is_focus(): return selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: return self.row_id = model[path][0] start = text_buffer.get_start_iter() end = text_buffer.get_end_iter() self.notes = text_buffer.get_text(start, end, True) if self.timeout_id: GLib.source_remove(self.timeout_id) self.timeout_id = GLib.timeout_add_seconds(10, self.save_notes) def save_notes(self): if self.timeout_id: GLib.source_remove(self.timeout_id) self.cursor.execute("UPDATE resources SET notes = %s " "WHERE id = %s", (self.notes, self.row_id)) DB.commit() self.timeout_id = None def populate_resource_store(self): id_ = None selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path != []: id_ = model[path][0] self.resource_store.clear() self.builder.get_object('notes_buffer').set_text('') row_limit = self.builder.get_object('spinbutton1').get_value() sort = self.builder.get_object('sort_by_combo').get_active_id() c = DB.cursor() c.execute("SELECT " "rm.id, " "subject, " "COALESCE(contact_id, 0), " "COALESCE(name, ''), " "COALESCE(ext_name, ''), " "to_char(timed_seconds, 'HH24:MI:SS')::text AS time, " "format_date(dated_for), " "'', " "phone_number, " "to_do " "FROM resources AS rm " "%s " "LEFT JOIN contacts " "ON rm.contact_id = contacts.id " "WHERE (dated_for <= '%s' OR dated_for IS NULL) " "AND posted = False " "ORDER BY %s, rm.id " "LIMIT %s" % (self.join_filter, self.older_than_date, sort, row_limit)) for row in c.fetchall(): row_id = row[0] iter_ = self.resource_store.append(row) self.populate_row_tag_list(iter_) if row_id == id_: selection.select_iter(iter_) c.close() self.populate_notes() DB.rollback() def populate_row_tag_list(self, iter_): row_id = self.resource_store[iter_][0] c = DB.cursor() tag_list = list() c.execute( "SELECT " "red, " "green, " "blue, " "alpha " "FROM resources AS r " "JOIN resource_ids_tag_ids AS riti " "ON riti.resource_id = r.id " "JOIN resource_tags AS rt " "ON rt.id = riti.resource_tag_id " "WHERE r.id = %s ORDER BY rt.id", (row_id, )) for row in c.fetchall(): rgba = Gdk.RGBA(row[0], row[1], row[2], row[3]) tag_list.append(rgba) self.resource_store[iter_][7] = tag_list def time_clock_project_clicked(self, button): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: self.show_message("Please select a row") return resource_id = model[path][0] subject = model[path][1] self.builder.get_object('project_name_entry').set_text(subject) dialog = self.builder.get_object('time_clock_create_dialog') result = dialog.run() dialog.hide() if result != Gtk.ResponseType.ACCEPT: return subject = self.builder.get_object('project_name_entry').get_text() try: self.cursor.execute( "INSERT INTO time_clock_projects " "(name, start_date, active, permanent, " "resource_id) " "VALUES (%s, now(), True, False, %s)" "ON CONFLICT (resource_id) " "DO UPDATE SET name = %s " "WHERE time_clock_projects.resource_id = %s", (subject, resource_id, subject, resource_id)) except Exception as e: self.show_message(e) DB.rollback() return DB.commit() if self.builder.get_object( 'time_clock_checkbutton').get_active() == True: if not self.time_clock: import time_clock self.time_clock = time_clock.TimeClockGUI() else: self.time_clock.present() def older_than_entry_icon_released(self, entry, icon, event): self.older_than_calendar.set_relative_to(entry) self.older_than_calendar.show() def older_than_date_selected(self, calendar): date_text = calendar.get_text() self.builder.get_object('entry1').set_text(date_text) self.older_than_date = calendar.get_date() if self.older_than_date == None: self.older_than_date = datetime.today() self.populate_resource_store() def tags_activated(self, button): import resource_management_tags resource_management_tags.ResourceManagementTagsGUI() def down_clicked(self, button): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: return iter_ = model.get_iter(path) iter_next = model.iter_next(iter_) model.move_after(iter_, iter_next) self.save_row_ordering() self.builder.get_object('sort_by_combo').set_active_id('sort') def up_clicked(self, button): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: return iter_ = model.get_iter(path) iter_prev = model.iter_previous(iter_) model.move_before(iter_, iter_prev) self.save_row_ordering() self.builder.get_object('sort_by_combo').set_active_id('sort') def save_row_ordering(self): for row_count, row in enumerate(self.resource_store): row_id = row[0] self.cursor.execute( "UPDATE resources " "SET sort = %s WHERE id = %s", (row_count, row_id)) DB.commit() def no_date_clicked(self, button): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: return id_ = model[path][0] self.cursor.execute( "UPDATE resources " "SET dated_for = NULL " "WHERE id = %s", (id_, )) DB.commit() self.populate_resource_store() self.dated_for_calendar.hide() def to_do_toggled(self, renderer, path): active = not self.resource_store[path][9] self.resource_store[path][9] = active id_ = self.resource_store[path][0] self.cursor.execute("UPDATE resources SET to_do = %s " "WHERE id = %s", (active, id_)) DB.commit() def show_message(self, message): dialog = Gtk.MessageDialog(message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.CLOSE) dialog.set_transient_for(self.window) dialog.set_markup(message) dialog.run() dialog.destroy() def treeview_key_release_event(self, treeview, event): keyname = Gdk.keyval_name(event.keyval) path, col = treeview.get_cursor() # only visible columns!! columns = [c for c in treeview.get_columns() if c.get_visible()] colnum = columns.index(col) if keyname == "Tab" or keyname == "Esc": if colnum + 1 < len(columns): next_column = columns[colnum + 1] else: tmodel = treeview.get_model() titer = tmodel.iter_next(tmodel.get_iter(path)) if titer is None: titer = tmodel.get_iter_first() path = tmodel.get_path(titer) next_column = columns[0] if keyname == 'Tab': GLib.timeout_add(10, treeview.set_cursor, path, next_column, True) elif keyname == 'Escape': pass
class ResourceManagementGUI: timeout_id = None def __init__(self, main, id_ = None): self.builder = Gtk.Builder() self.builder.add_from_file(UI_FILE) self.builder.connect_signals(self) main.connect("shutdown", self.main_shutdown) self.main = main self.db = main.db self.cursor = main.db.cursor() self.editing = False self.timer_timeout = None self.resource_store = self.builder.get_object('resource_store') self.contact_store = self.builder.get_object('contact_store') self.contact_completion = self.builder.get_object('contact_completion') self.contact_completion.set_match_func(self.contact_match_func) self.tag_store = self.builder.get_object('tag_store') textview = self.builder.get_object('textview1') spell_check.add_checker_to_widget (textview) self.dated_for_calendar = DateTimeCalendar() no_date_button = self.builder.get_object('button5') self.dated_for_calendar.pack_start(no_date_button) date_label = self.builder.get_object('treeviewcolumn5').get_widget() self.dated_for_calendar.set_relative_to(date_label) self.dated_for_calendar.connect('day-selected', self.dated_for_calendar_day_selected ) self.older_than_calendar = DateTimeCalendar() self.older_than_calendar.connect('day-selected', self.older_than_date_selected ) self.older_than_calendar.set_today() self.populate_stores() self.populate_resource_store () if id_ != None: selection = self.builder.get_object('treeview-selection1') for row in self.resource_store: if row[0] == id_: selection.select_path(row.path) self.editing_buffer = True self.cursor.execute("SELECT notes FROM resources " "WHERE id = %s", (id_,)) for row in self.cursor.fetchall(): text = row[0] self.builder.get_object('textbuffer1').set_text(text) break else: self.builder.get_object('textbuffer1').set_text('') self.editing_buffer = False self.window = self.builder.get_object('window1') self.window.show_all() def main_shutdown (self, main): if self.timeout_id: self.save_notes() def focus_in_event (self, window, event): self.populate_stores () def unfinished_only_toggled (self, togglebutton): self.populate_resource_store () def row_limit_value_changed (self, spinbutton): self.populate_resource_store () def resource_threaded_checkbutton_toggled (self, checkbutton): self.populate_resource_store () def treeview_button_release_event (self, treeview, event): if event.button == 3: menu = self.builder.get_object('menu1') menu.popup(None, None, None, None, event.button, event.time) menu.show_all() def delete_activated (self, menuitem): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path != []: row_id = model[path][0] try: self.cursor.execute("DELETE FROM resources " "WHERE id = %s", (row_id,)) self.db.commit() except Exception as e: self.show_message (e) self.db.rollback() self.populate_resource_store() def block_number_activated (self, menuitem): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path != []: phone_number = model[path][11] try: self.cursor.execute("INSERT INTO phone_blacklist " "(number, blocked_calls) VALUES (%s, 0)", (phone_number,)) self.db.commit() except Exception as e: self.show_message (e) self.db.rollback() def row_activated (self, treeview, path, treeview_column): if self.timeout_id: self.save_notes() self.editing_buffer = True row_id = self.resource_store[path][0] self.cursor.execute("SELECT notes FROM resources " "WHERE id = %s", (row_id,)) for row in self.cursor.fetchall(): text = row[0] self.builder.get_object('textbuffer1').set_text(text) break else: self.builder.get_object('textbuffer1').set_text('') self.editing_buffer = False def contact_match_func(self, completion, key, iter): split_search_text = key.split() for text in split_search_text: if text not in self.contact_store[iter][1].lower(): return False # no match return True # it's a hit! def contact_match_selected(self, completion, model, iter_): contact_id = model[iter_][0] selection = self.builder.get_object('treeview-selection1') tree_model, path = selection.get_selected_rows() id_ = tree_model[path][0] self.cursor.execute("UPDATE resources " "SET contact_id = %s " "WHERE id = %s", (contact_id, id_)) self.db.commit() self.editing = False self.populate_resource_store(id_) def contact_editing_started (self, renderer_combo, combobox, path): self.editing = True entry = combobox.get_child() entry.set_completion(self.contact_completion) def contact_changed (self, renderer_combo, path, tree_iter): contact_id = self.contact_store[tree_iter][0] id_ = self.resource_store[path][0] self.cursor.execute("UPDATE resources " "SET contact_id = %s " "WHERE id = %s", (contact_id, id_)) self.db.commit() self.editing = False self.populate_resource_store(id_) def contact_edited (self, renderer_combo, path, text): self.editing = False def contact_editing_canceled (self, renderer): self.editing = False def populate_stores (self): self.contact_store.clear() self.cursor.execute("SELECT id::text, name, ext_name, phone FROM contacts " "WHERE deleted = False ORDER BY name") for row in self.cursor.fetchall(): contact_id = row[0] contact_name = row[1] ext_name = row[2] contact_phone = row[3] self.contact_store.append([contact_id, contact_name, ext_name, contact_phone]) self.tag_store.clear() self.cursor.execute("SELECT id, tag, red, green, blue, alpha " "FROM resource_tags " "ORDER BY tag") for row in self.cursor.fetchall(): tag_id = row[0] tag_name = row[1] rgba = Gdk.RGBA(1, 1, 1, 1) rgba.red = row[2] rgba.green = row[3] rgba.blue = row[4] rgba.alpha = row[5] self.tag_store.append([str(tag_id), tag_name, rgba]) for row in self.resource_store: if row[8] == tag_id: row[10] = rgba def new_entry_clicked (self, button): self.cursor.execute("INSERT INTO resources " "(tag_id) " "SELECT id FROM resource_tags " "WHERE finished = False LIMIT 1 " "RETURNING id") new_id = self.cursor.fetchone()[0] self.populate_resource_store(new_id, new = True) def subject_editing_started (self, renderer_entry, entry, path): self.editing = True def subject_edited (self, renderer_text, path, text): self.editing = False id_ = self.resource_store[path][0] self.cursor.execute("UPDATE resources " "SET subject = %s " "WHERE id = %s", (text, id_)) self.db.commit() self.resource_store[path][1] = text def subject_editing_canceled (self, renderer): self.editing = False def dated_for_calendar_day_selected (self, calendar): date = calendar.get_date() selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() id_ = model[path][0] self.cursor.execute("UPDATE resources " "SET dated_for = %s " "WHERE id = %s", (date, id_)) self.db.commit() self.populate_resource_store(id_) def dated_for_editing_started (self, widget, entry, text): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() row_id = model[path][0] self.cursor.execute("SELECT dated_for FROM resources " "WHERE id = %s AND dated_for IS NOT NULL", (row_id,)) for row in self.cursor.fetchall(): self.dated_for_calendar.set_datetime(row[0]) break else: self.dated_for_calendar.set_today() GLib.idle_add(self.dated_for_calendar.show) def tag_editing_started (self, renderer_combo, combobox, path): self.editing = True def tag_changed (self, renderer_combo, path, tree_iter): self.editing = False tag_id = self.tag_store[tree_iter][0] id_ = self.resource_store[path][0] self.cursor.execute("UPDATE resources " "SET tag_id = %s " "WHERE id = %s; " "UPDATE time_clock_projects AS tcp " "SET active = NOT rt.finished " "FROM resource_tags AS rt " "WHERE (rt.id, rt.finished) = (%s, True) " "AND tcp.resource_id = %s", (tag_id, id_, tag_id, id_)) self.db.commit() self.populate_resource_store(id_) def tag_editing_canceled (self, renderer): self.editing = False def text_buffer_changed (self, text_buffer): if self.editing_buffer == True: return selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: self.show_message("Please select a row") return self.row_id = model[path][0] start = text_buffer.get_start_iter() end = text_buffer.get_end_iter() self.notes = text_buffer.get_text(start,end,True) if self.timeout_id: GLib.source_remove(self.timeout_id) self.timeout_id = GLib.timeout_add_seconds(10, self.save_notes) def save_notes (self ): if self.timeout_id: GLib.source_remove(self.timeout_id) self.cursor.execute("UPDATE resources SET notes = %s " "WHERE id = %s", (self.notes, self.row_id)) self.db.commit() self.timeout_id = None def populate_resource_store (self, id_ = None, new = False): self.resource_store.clear() row_limit = self.builder.get_object('spinbutton1').get_value() finished = self.builder.get_object('checkbutton3').get_active() self.cursor.execute("SELECT " "rm.id, " "subject, " "COALESCE(contact_id, 0), " "COALESCE(name, ''), " "COALESCE(ext_name, ''), " "to_char(timed_seconds, 'HH24:MI:SS')::text, " "dated_for, " "format_date(dated_for), " "rmt.id, " "tag, " "red, " "green, " "blue, " "alpha, " "phone_number, " "call_received_time, " "format_timestamp(call_received_time), " "to_do " "FROM resources AS rm " "LEFT JOIN resource_tags AS rmt " "ON rmt.id = rm.tag_id " "LEFT JOIN contacts " "ON rm.contact_id = contacts.id " "WHERE date_created <= %s " "AND finished != %s OR finished IS NULL " "AND diary != True ORDER BY rm.id " "LIMIT %s", (self.older_than_date, finished, row_limit)) for row in self.cursor.fetchall(): rgba = Gdk.RGBA(1, 1, 1, 1) row_id = row[0] subject = row[1] contact_id = row[2] contact_name = row[3] ext_name = row[4] time_formatted = row[5] dated_for = row[6] date_formatted = row[7] tag_id = row[8] tag_name = row[9] if tag_id == None: tag_id = 0 tag_name = '' else: rgba.red = row[10] rgba.green = row[11] rgba.blue = row[12] rgba.alpha = row[13] phone_number = row[14] call_received_time = row[15] c_r_time_formatted = row[16] to_do = row[17] iter_ = self.resource_store.append([row_id, subject, contact_id, contact_name, ext_name, 0, time_formatted, date_formatted, tag_id, tag_name, rgba, phone_number, call_received_time, c_r_time_formatted, to_do]) if row_id == id_: self.builder.get_object('treeview-selection1').select_iter(iter_) if new == True: treeview = self.builder.get_object('treeview1') c = treeview.get_column(0) path = self.resource_store.get_path(iter_) treeview.set_cursor(path, c, True) def time_clock_project_clicked (self, button): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: self.show_message("Please select a row") return resource_id = model[path][0] subject = model[path][1] self.builder.get_object('project_name_entry').set_text(subject) dialog = self.builder.get_object('time_clock_create_dialog') result = dialog.run() dialog.hide() if result != Gtk.ResponseType.ACCEPT: return subject = self.builder.get_object('project_name_entry').get_text() try: self.cursor.execute("INSERT INTO time_clock_projects " "(name, start_date, active, permanent, " "resource_id) " "VALUES (%s, now(), True, False, %s)" "ON CONFLICT (resource_id) " "DO UPDATE SET name = %s " "WHERE time_clock_projects.resource_id = %s", (subject, resource_id, subject, resource_id)) except Exception as e: self.show_message (e) self.db.rollback () return self.db.commit() if self.builder.get_object('time_clock_checkbutton').get_active() == True: if not self.time_clock: import time_clock self.time_clock = time_clock.TimeClockGUI(self.main) else: self.time_clock.present() def older_than_entry_icon_released (self, entry, icon, event): self.older_than_calendar.set_relative_to(entry) self.older_than_calendar.show() def older_than_date_selected (self, calendar): date_text = calendar.get_text () self.builder.get_object('entry1').set_text(date_text) self.older_than_date = calendar.get_date() self.populate_resource_store () def tags_clicked (self, button): import resource_management_tags resource_management_tags.ResourceManagementTagsGUI (self.db) def no_date_clicked (self, button): selection = self.builder.get_object('treeview-selection1') model, path = selection.get_selected_rows() if path == []: return id_ = model[path][0] self.cursor.execute("UPDATE resources " "SET dated_for = NULL " "WHERE id = %s", ( id_, )) self.db.commit() self.populate_resource_store(id_) self.dated_for_calendar.hide() def to_do_toggled (self, renderer, path): active = not self.resource_store[path][14] self.resource_store[path][14] = active id_ = self.resource_store[path][0] self.cursor.execute("UPDATE resources SET to_do = %s " "WHERE id = %s", (active, id_)) self.db.commit() def show_message (self, message): dialog = Gtk.MessageDialog( self.window, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, str(message)) dialog.run() dialog.destroy() def treeview_key_release_event (self, treeview, event): keyname = Gdk.keyval_name(event.keyval) path, col = treeview.get_cursor() # only visible columns!! columns = [c for c in treeview.get_columns() if c.get_visible()] colnum = columns.index(col) if keyname=="Tab" or keyname=="Esc": if colnum + 1 < len(columns): next_column = columns[colnum + 1] else: tmodel = treeview.get_model() titer = tmodel.iter_next(tmodel.get_iter(path)) if titer is None: titer = tmodel.get_iter_first() path = tmodel.get_path(titer) next_column = columns[0] if keyname == 'Tab': GLib.timeout_add(10, treeview.set_cursor, path, next_column, True) elif keyname == 'Escape': pass