def _populate_category(self, categoryname=None): """ Populates combobox with existing categories """ # Connects to the database actions = Actions() # List of categories from database categories = [] records = actions.get_categories() ret = 0 empty_color = create_pixbuf() for rec in records: #if [rec['categoryname'], rec['id']] not in categories: #TODO: Better put color creation in a function color = rec.color and rec.color or '#000' categories.append([create_pixbuf(color=color), rec.name, int(rec.id)]) if categoryname and categoryname == rec.name: ret = len(categories) + 1 store = gtk.ListStore(gtk.gdk.Pixbuf, str, int) self.category.set_model(store) store.append([empty_color, _("None"), 0]) store.append([None, "---", -1]) for category in categories: store.append(category) store.append([None, "---", -1]) store.append([empty_color, _("New Category"), -2]) self.category.set_active(ret) return ret
def _populate_widgets_with_record(self): # Format the amount field if self.currentrecord.amount: self.amount.set_text( utils.float_to_currency(self.currentrecord.amount)) else: self.amount.set_text("") # Format the dueDate field dt = self.currentrecord.dueDate self.dueDate.set_date(dt) utils.select_combo_text(self.payee, self.currentrecord.payee) if self.currentrecord.category: actions = Actions() cat_name = self.currentrecord.category.name records = actions.get_categories(name=cat_name) if records: categoryname = records[0].name utils.select_combo_text(self.category, categoryname, 1) else: self.category.set_active(0) if self.currentrecord.notes: self.txtbuffer.set_text(self.currentrecord.notes) #self.chkPaid.set_active(self.currentrecord.Paid) if self.currentrecord.alarmDate: self.alarmbutton.set_date(self.currentrecord.alarmDate)
def _populate_widgets_with_record(self): # Format the amount field if self.currentrecord.amount: self.amount.set_text(utils.float_to_currency(self.currentrecord.amount)) else: self.amount.set_text("") # Format the dueDate field dt = self.currentrecord.dueDate self.dueDate.set_date(dt) utils.select_combo_text(self.payee, self.currentrecord.payee) if self.currentrecord.category: actions = Actions() cat_name = self.currentrecord.category.name records = actions.get_categories(name=cat_name) if records: categoryname = records[0].name utils.select_combo_text(self.category, categoryname, 1) else: self.category.set_active(0) if self.currentrecord.notes: self.txtbuffer.set_text(self.currentrecord.notes) #self.chkPaid.set_active(self.currentrecord.Paid) if self.currentrecord.alarmDate: self.alarmbutton.set_date(self.currentrecord.alarmDate)
def _populate_category(self, categoryname=None): """ Populates combobox with existing categories """ # Connects to the database actions = Actions() # List of categories from database categories = [] records = actions.get_categories() ret = 0 empty_color = create_pixbuf() for rec in records: #if [rec['categoryname'], rec['id']] not in categories: #TODO: Better put color creation in a function color = rec.color and rec.color or '#000' categories.append( [create_pixbuf(color=color), rec.name, int(rec.id)]) if categoryname and categoryname == rec.name: ret = len(categories) + 1 store = gtk.ListStore(gtk.gdk.Pixbuf, str, int) self.category.set_model(store) store.append([empty_color, _("None"), 0]) store.append([None, "---", -1]) for category in categories: store.append(category) store.append([None, "---", -1]) store.append([empty_color, _("New Category"), -2]) self.category.set_active(ret) return ret
def __init__(self, parent=None, new=False): gtk.Dialog.__init__(self, title=_("Categories Manager"), parent=parent, flags=gtk.DIALOG_MODAL) self.closebutton = self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) self.okbutton = self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) self.set_icon_from_file(common.APP_ICON) self.new = new if parent: self.set_transient_for(parent) self.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.currentrecord = None # Set up the UI self._initialize_dialog_widgets() self._connect_fields() #self._populate_fields() self.actions = Actions() self._populateTreeView(self.actions.get_categories()) if new: self._on_newbutton_clicked(None) self.topcontainer.get_label_widget().set_markup("<b>%s</b>" \ % _("New Category")) self.okbutton.set_label(gtk.STOCK_SAVE) self.closebutton.set_label(gtk.STOCK_CANCEL) else: index = parent.category.get_active()-2 if index >= 0: self.list.set_cursor((index,))
def _get_category(self): """ Extracts information typed into comboboxentry """ actions = Actions() if self.category.get_active_iter() is not None: model = self.category.get_model() iteration = self.category.get_active_iter() if iteration: name = model.get_value(iteration, 1) else: name = None if not name or name == _("None"): return None records = actions.get_categories(name=name) if records: return records[0] else: return None
def _populate_payee(self): """ Populates combobox with existing payees """ # Connects to the database actions = Actions() # List of payees from database payees = [] records = actions.get_bills() for rec in records: if rec.payee not in payees: payees.append(rec.payee) store = gtk.ListStore(gobject.TYPE_STRING) for payee in payees: store.append([payee]) self.payee.set_model(store) self.payeecompletion.set_model(store) self.payee.set_text_column(0) self.payeecompletion.set_text_column(0) self.payeeEntry = self.payee.child self.selectedText = ''
def __init__(self, options): # Verify if Lock File exist and if there is another instance running if not lock(): lockfd = open(common.DAEMON_LOCK_FILE, 'r') lockpid = int(lockfd.readline()) lockfd.close() if verify_pid(lockpid): print _('Lock File found:' \ ' You have another instance running. (pid=%d)') % \ lockpid raise SystemExit else: print _('Lock File found: ' \ 'Possibly the program was exited unexpectedly.') try: print _('Removing Lock File...') os.remove(common.DAEMON_LOCK_FILE) print _('Successfully.') except OSError: print _('Failed.') # Verify if there is another Billreminder-Daemon DBus Service if verify_service(common.DBUS_INTERFACE): print _('BillReminder Notifier is already running.') raise SystemExit Daemon.__init__(self, options) self.client_pid = None self.actions = Actions() self.dbus_server = Server(self) if options.app_opengui: gui = Popen('billreminder', shell=True) self.client_pid = gui.pid self.alarm = Alarm(self) # Create the mainloop self.mainloop = gobject.MainLoop() self.mainloop.run()
def __init__(self): gobject.GObject.__init__(self) if exists(join(USER_CFG_PATH, CFG_NAME)): from lib.migrate_to_gconf import migrate migrate(join(USER_CFG_PATH, CFG_NAME)) self.gconf_client = Configuration() self.message = Message() # Connects to the database self.actions = Actions() self.ui = gtk.Builder() self.ui.add_from_file(os.path.join(DEFAULT_CFG_PATH, "main.ui")) self.window = self.ui.get_object("main_window") self.window.set_title("%s" % common.APPNAME) self.window.set_icon_from_file(common.APP_ICON) # ViewBill self.list = ViewBill() self.list.connect("cursor_changed", self._on_list_cursor_changed) self.list.connect("row_activated", self._on_list_row_activated) self.list.connect("button_press_event", self._on_list_button_press_event) self.ui.get_object("bill_box").add(self.list) # Toolbar self.toolbar = self.ui.get_object("toolbar") # Menubar self._populate_menubar() # Statusbar self.statusbar = Statusbar() self.ui.get_object("statusbar_box").add(self.statusbar) # Restore timeline zoom timeline_count = self.gconf_client.get("timeline_count") # Timeline self.timeline = Timeline(count=timeline_count, callback=self.on_timeline_cb) self.timeline.connect("range-changed", self._on_timeline_changed) self.timeline.connect("button-press-event", self._on_timeline_click) self.timeline.connect("cleared", self._on_timeline_cleared) self.ui.get_object("timeline_box").add(self.timeline) # Chart self.chart = ChartWidget() self.chart.set_border_width(10) self.ui.get_object("chart_box").add(self.chart) # Restore position and size of window width = self.gconf_client.get("window_width") height = self.gconf_client.get("window_height") x = self.gconf_client.get("window_position_x") y = self.gconf_client.get("window_position_y") if width and height: self.window.resize(width, height) if x and y: self.window.move(x, y) self.window.show_all() # Whether to display toolbar or not self.on_showToolbar_toggled(self.ui.get_object("showToolbar")) self.list.grab_focus() if self.gconf_client.get("start_in_tray"): self.window.hide() self.toggle_buttons() # Connects to the Daemon self.iface = None iface = get_dbus_interface(common.DBUS_INTERFACE, common.DBUS_PATH) if iface: iface.connect_to_signal("bill_edited", self.reloadTreeView) iface.connect_to_signal("bill_edited", self.reloadTimeline) iface.connect_to_signal("show_main_window", self.window.show) self.iface = iface gobject.timeout_add(2000, self._send_tray_hints) self.set_action_strings() self.ui.connect_signals(self) # populate treeview self.reloadTreeView() self.notify = NotifyIcon(self) # Integrate with Ubuntu Unity if UNITY: self.unity = UnityIntegration(self)
class MainDialog(gobject.GObject): search_text = "" _bullet_cache = {} __gsignals__ = { "bill-added": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "bill-updated": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "bill-removed": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), } def __init__(self): gobject.GObject.__init__(self) if exists(join(USER_CFG_PATH, CFG_NAME)): from lib.migrate_to_gconf import migrate migrate(join(USER_CFG_PATH, CFG_NAME)) self.gconf_client = Configuration() self.message = Message() # Connects to the database self.actions = Actions() self.ui = gtk.Builder() self.ui.add_from_file(os.path.join(DEFAULT_CFG_PATH, "main.ui")) self.window = self.ui.get_object("main_window") self.window.set_title("%s" % common.APPNAME) self.window.set_icon_from_file(common.APP_ICON) # ViewBill self.list = ViewBill() self.list.connect("cursor_changed", self._on_list_cursor_changed) self.list.connect("row_activated", self._on_list_row_activated) self.list.connect("button_press_event", self._on_list_button_press_event) self.ui.get_object("bill_box").add(self.list) # Toolbar self.toolbar = self.ui.get_object("toolbar") # Menubar self._populate_menubar() # Statusbar self.statusbar = Statusbar() self.ui.get_object("statusbar_box").add(self.statusbar) # Restore timeline zoom timeline_count = self.gconf_client.get("timeline_count") # Timeline self.timeline = Timeline(count=timeline_count, callback=self.on_timeline_cb) self.timeline.connect("range-changed", self._on_timeline_changed) self.timeline.connect("button-press-event", self._on_timeline_click) self.timeline.connect("cleared", self._on_timeline_cleared) self.ui.get_object("timeline_box").add(self.timeline) # Chart self.chart = ChartWidget() self.chart.set_border_width(10) self.ui.get_object("chart_box").add(self.chart) # Restore position and size of window width = self.gconf_client.get("window_width") height = self.gconf_client.get("window_height") x = self.gconf_client.get("window_position_x") y = self.gconf_client.get("window_position_y") if width and height: self.window.resize(width, height) if x and y: self.window.move(x, y) self.window.show_all() # Whether to display toolbar or not self.on_showToolbar_toggled(self.ui.get_object("showToolbar")) self.list.grab_focus() if self.gconf_client.get("start_in_tray"): self.window.hide() self.toggle_buttons() # Connects to the Daemon self.iface = None iface = get_dbus_interface(common.DBUS_INTERFACE, common.DBUS_PATH) if iface: iface.connect_to_signal("bill_edited", self.reloadTreeView) iface.connect_to_signal("bill_edited", self.reloadTimeline) iface.connect_to_signal("show_main_window", self.window.show) self.iface = iface gobject.timeout_add(2000, self._send_tray_hints) self.set_action_strings() self.ui.connect_signals(self) # populate treeview self.reloadTreeView() self.notify = NotifyIcon(self) # Integrate with Ubuntu Unity if UNITY: self.unity = UnityIntegration(self) def set_action_strings(self): # for some reason the actions strings do not get translated yet # so we define them here so they would be picked up by the pyfile scanner self.ui.get_object("newBill").set_label(_("_New")) self.ui.get_object("newBill").set_tooltip(_("Add new bill")) self.ui.get_object("editBill").set_label(_("_Edit")) self.ui.get_object("editBill").set_tooltip(_("Edit a bill")) self.ui.get_object("removeBill").set_label(_("_Delete")) self.ui.get_object("removeBill").set_tooltip(_("Delete selected bill")) self.ui.get_object("markPaid").set_label(_("P_aid")) self.ui.get_object("markPaid").set_tooltip(_("Mark as paid")) self.ui.get_object("markNotPaid").set_label(_("No_t Paid")) self.ui.get_object("markNotPaid").set_tooltip(_("Mark as not paid")) self.ui.get_object("showToolbar").set_label(_("_Show Toolbar")) self.ui.get_object("showToolbar").set_tooltip(_("Show the toolbar")) # Methods: UI def _send_tray_hints(self): self.iface.set_tray_hints(force_string(self.notify.get_hints())) gobject.timeout_add(60000, self._send_tray_hints) def get_window_visibility(self): return self.window.get_property("visible") def show_hide_window(self): if self.window.get_property("visible"): self.window.hide() else: self.window.show() def get_selected_record(self): """ Returns a bill object from the current selected record """ if len(self.list.listStore) > 0: model_ = self.list.get_model() if self.list.get_cursor()[0]: index = self.list.get_cursor()[0][0] else: index = 0 b_id = model_[index][0] records = self.actions.get_bills(id=b_id) self.currentrecord = records[0] else: self.currentrecord = None print "Current record is: %s" % self.currentrecord def populate_view(self, records): """ Populates the treeview control with the records passed """ # Reset list self.list.listStore.clear() if not records: return 0 # Loops through bills collection path = 0 for rec in records: # Format the record prior to adding it to treeview row = self.format_row(rec) self.list.add(row) # Set the cursor to the first (top) record self.list.set_cursor(path) # Returns how many records there are in the treeview return len(records) def reloadTreeView(self, *arg): # Update list with updated record status = self.gconf_client.get("show_paid_bills") path = self.list.get_cursor()[0] self.list.listStore.clear() self.currentrecord = None first = self.timeline.start_date last = self.timeline.end_date # Get list of records records = self.actions.get_interval_bills(first, last, status) # Populate treeview self.populate_view(records) # Update status bar self.update_statusbar() # populate chart self._populate_chart(status, first, last) return len(records) def format_row(self, row): """ Formats a bill to be displayed as a row. """ categoryName = row.category.name if row.category else _("None") categoryColor = row.category.color if row.category else "#d3d7cf" formatted = [ row.id, create_pixbuf(color=categoryColor), categoryName, row.payee, row.dueDate.strftime(_("%m/%d").encode("ASCII")), row.amount, row.notes, int(row.paid), None, ] return formatted def _populate_chart(self, status, start, end): records = [] categories = [] totals = [] records = self.actions.get_monthly_totals(start, end, status) # Chart widget takes data in format (('CategoryName', amount),) categories = [cat or "None" for cat, total in records] totals = [float(total) for cat, total in records] # records = [(c if c else 'None',float(t)) for c,t in records] # set bar colors all_categories = self.actions.get_categories() self.chart.chart.key_colors = dict([(cat.name or "None", cat.color) for cat in all_categories]) self.chart.plot(categories, totals) def _populate_menubar(self): try: saved_view = self.gconf_client.get("show_paid_bills") except: saved_view = 1 self.gconf_client.set("show_paid_bills", saved_view) if saved_view == 0: self.ui.get_object("showNotPaid").set_active(True) elif saved_view == 1: self.ui.get_object("showPaid").set_active(True) else: self.ui.get_object("showAll").set_active(True) # Check whether we display the toolbar or not self.ui.get_object("showToolbar").set_active(self.gconf_client.get("show_toolbar")) def add_bill(self): selectedDate = self.timeline.value records = dialogs.add_dialog(parent=self.window, selectedDate=selectedDate) # Checks if the user did not cancel the action if records: # Add new bill to database for rec in records: bill_id = self.actions.add(rec) bill = self.actions.get_bills(id=bill_id)[0] if bill: self.list.add(self.format_row(bill)) self.update_statusbar() # Reload records tree (something changed) self.reloadTreeView() self.reloadTimeline() def edit_bill(self): records = dialogs.edit_dialog(parent=self.window, record=self.currentrecord) # Checks if the user did not cancel the action if records: for rec in records: # Edit bill to database rec = self.actions.edit(rec) self.emit("bill-updated", rec) # Reload records tree (something changed) self.reloadTreeView() self.reloadTimeline() def remove_bill(self): self.actions.delete(self.currentrecord) self.list.remove() self.emit("bill-removed", None) self.update_statusbar() self.reloadTreeView() self.reloadTimeline() def toggle_bill_paid(self): # Fetch record from database record = self.actions.get_bills(id=self.currentrecord.id)[0] # Toggle paid field record.paid = False if record.paid else True # Edit bill in the database transaction = self.actions.add(record) self.emit("bill-updated", record) # Update our current copy self.currentrecord = self.actions.get_bills(id=self.currentrecord.id)[0] # Update timeline widget to reflect change self._bullet_cache[self.currentrecord.dueDate] = [self.currentrecord] # Update list with updated record idx = self.list.get_cursor()[0][0] self.update_statusbar(idx) self.reloadTreeView() self.reloadTimeline() def about(self): dialogs.about_dialog(parent=self.window) def preferences(self): dialogs.preferences_dialog(parent=self.window) # Methods def _quit_application(self): self.save_position() self.save_size() self.save_timeline_zoom() gtk.main_quit() return False def save_position(self): x, y = self.window.get_position() self.gconf_client.set("window_position_x", x) self.gconf_client.set("window_position_y", y) def save_size(self): width, height = self.window.get_size() self.gconf_client.set("window_width", width) self.gconf_client.set("window_height", height) def save_timeline_zoom(self): count = self.timeline.count self.gconf_client.set("timeline_count", count) def toggle_buttons(self, paid=None): """ Toggles all buttons conform number of records present and their state """ for widget in ["editBill", "removeBill", "markPaid", "markNotPaid"]: self.ui.get_object(widget).set_sensitive(len(self.list.listStore) > 0) if len(self.list.listStore) > 0: self.ui.get_object("markPaid").set_sensitive(paid == False) self.ui.get_object("markNotPaid").set_sensitive(paid == True) def update_statusbar(self, index=0): """ This function is used to update status bar informations about the list """ records = len(self.list.listStore) # Record count self.statusbar.Records(records) if self.currentrecord: # Display the status self.statusbar.Notes(self.currentrecord.notes) # Toggles toolbar buttons on/off self.toggle_buttons(self.currentrecord.paid) else: # Clear the status for the selected row self.statusbar.Notes("") # Toggles toolbar buttons on/off self.toggle_buttons() show_paid_bills = self.gconf_client.get("show_paid_bills") if show_paid_bills is 0: self.statusbar.Info(_("Not Paid Only")) elif show_paid_bills is 1: self.statusbar.Info(_("Paid Only")) else: self.statusbar.Info("") # Event handlers def _on_list_button_press_event(self, widget, event): """ This function will handle the signal to show a popup menu sent by a right click on tvBill widget. """ if event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: self.get_selected_record() c = self.ui.get_object("context_menu") c.popup(None, None, None, event.button, event.get_time()) def _on_list_row_activated(self, widget, path, column): self._on_list_cursor_changed(widget) self.on_editBill_activate(None) def _on_list_cursor_changed(self, widget): # Get currently selected bill self.get_selected_record() # Update statusbar self.update_statusbar() def on_newBill_activate(self, toolbutton): self.add_bill() def on_editBill_activate(self, toolbutton): if self.currentrecord: self.edit_bill() def on_removeBill_activate(self, toolbutton): if self.currentrecord: resp = self.message.ShowQuestionYesNo( _('Do you really want to delete "%s"?') % self.currentrecord.payee, self.window, _("Confirmation") ) if resp: self.remove_bill() def on_markNotPaid_activate(self, toolbutton): self.on_markPaid_activate(toolbutton) # forward def on_markPaid_activate(self, toolbutton): if self.currentrecord: self.toggle_bill_paid() def on_btnAbout_activate(self, toolbutton): self.about() def on_btnPrefs_activate(self, toolbutton): self.preferences() def on_btnQuit_activate(self, toolbutton): self._quit_application() def on_delete_event(self, widget, event, data=None): self._quit_application() def _on_timeline_changed(self, widget, args): self.reloadTreeView() def _on_timeline_cleared(self, widget, args): self._bullet_cache = {} def _on_timeline_click(self, widget, event): if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS: self.add_bill() def switch_view(self, view_number): self.gconf_client.set("show_paid_bills", view_number) self.reloadTreeView() self.reloadTimeline() def on_showNotPaid_toggled(self, action): if action.get_active(): self.switch_view(0) def on_showPaid_toggled(self, action): if action.get_active(): self.switch_view(1) def on_showAll_toggled(self, action): if action.get_active(): self.switch_view(2) def on_showToolbar_toggled(self, action): # Toggle toolbar's visibility if action.get_active(): self.toolbar.show_all() else: self.toolbar.hide_all() self.gconf_client.set("show_toolbar", action.get_active()) def reloadTimeline(self, *args): self._bullet_cache = {} self.timeline.refresh() def on_timeline_cb(self, date, display_type, force=False): # TODO: Improve tooltip # TODO: Improve cache if date in self._bullet_cache.keys() and not force: return None self._bullet_cache[date] = self.actions.get_bills(dueDate=date) if self._bullet_cache[date]: status = self.gconf_client.get("show_paid_bills") amount = 0 amount_not_paid = 0 tooltip = "" bullet = Event() bullet.date = date for bill in self._bullet_cache[date]: amount += bill.amount if tooltip: tooltip += "\n" tooltip += bill.payee + " (" + str(float_to_currency(bill.amount)) + ")" if bill.paid: tooltip += " [%s]" % _("Paid") if status == 0: return False bullet.status = bullet.status | bullet.PAID else: amount_not_paid += bill.amount if date <= datetime.date.today(): if status == 1: return False bullet.status = bullet.status | bullet.OVERDUE else: if status == 1: return False bullet.status = bullet.status | bullet.TO_BE_PAID if bill.notes: tooltip += " - " + bill.notes bullet.amountdue = amount_not_paid if amount_not_paid else amount bullet.payee = bill.payee bills = len(self._bullet_cache[date]) if bills > 1: bullet.multi = bills bullet.payee = "%d bills" % bills bullet.tooltip = tooltip return bullet return None
def __init__(self): self.gui = GTKWrappers() self.actions = Actions() # setup a default icon self.icons = gtk.icon_theme_get_default() self.current_category_id = 0 self.gui.get_glade(MAIN_GLADE, 'window_main') #Main widget self.window_main = self.gui.get_widget('window_main') self.window_main.set_icon(load_pixbuf_image('iug')[0]) # Sexy search entry self.search_hbox = self.gui.get_widget('search_hbox') self.search_entry = SearchEntry(self.icons) self.search_hbox.add(self.search_entry) self.search_entry.show() #creates the GamesListView to view a list of games self.scrolled_window = self.gui.get_widget('scrolled_window') self.treeview_games = GamesListView() self.scrolled_window.add(self.treeview_games) self.treeview_games.show() #create the description listview to show games info. self.scrolled_description = self.gui.get_widget('scrolled_description') self.treeview_description = DescriptionTreeView() self.scrolled_description.add(self.treeview_description) self.treeview_description.show() #Application menu self.menu_download = self.gui.get_widget('menu_download') self.menu_download.set_sensitive(False) self.menu_viewsite = self.gui.get_widget('menu_viewsite') self.menu_viewsite.set_sensitive(False) self.menu_quit = self.gui.get_widget('menu_quit') self.menu_preferences = self.gui.get_widget('menu_preferences') self.menu_fullscreen = self.gui.get_widget('menu_fullscreen') self.menu_fullscreen.set_sensitive(False) self.menu_reportbug = self.gui.get_widget('menu_reportbug') self.menu_about = self.gui.get_widget('menu_about') #Application buttons self.button_close = self.gui.get_widget('button_close') self.button_download = self.gui.get_widget('button_download') self.button_zoom = self.gui.get_widget("button_zoom") self.menu_viewsite.set_sensitive(False) self.button_download.set_sensitive(False) self.menu_download.set_sensitive(False) self.button_zoom.set_sensitive(False) # image widget to show the game screenshot self.image_game = self.gui.get_widget('image_game') # create the category treeview self.treeview_categories = self.gui.get_widget('treeview_categories') renderer_cat_name = gtk.CellRendererText() renderer_cat_name.set_property('scale', 1.0) column_cat = gtk.TreeViewColumn(MSG_000001,renderer_cat_name) column_cat.add_attribute(renderer_cat_name, 'markup', COL_CAT_NAME) self.treeview_categories.append_column(column_cat) self.treeview_categories.set_search_column(COL_CAT_NAME) self.category_selection = self.treeview_categories.get_selection() self.category_selection.set_mode(gtk.SELECTION_SINGLE) self.window_main.show() self.connect_events() self.check_version() self.fill_category() self.search_entry.grab_focus()
class IUG(): def __init__(self): self.gui = GTKWrappers() self.actions = Actions() # setup a default icon self.icons = gtk.icon_theme_get_default() self.current_category_id = 0 self.gui.get_glade(MAIN_GLADE, 'window_main') #Main widget self.window_main = self.gui.get_widget('window_main') self.window_main.set_icon(load_pixbuf_image('iug')[0]) # Sexy search entry self.search_hbox = self.gui.get_widget('search_hbox') self.search_entry = SearchEntry(self.icons) self.search_hbox.add(self.search_entry) self.search_entry.show() #creates the GamesListView to view a list of games self.scrolled_window = self.gui.get_widget('scrolled_window') self.treeview_games = GamesListView() self.scrolled_window.add(self.treeview_games) self.treeview_games.show() #create the description listview to show games info. self.scrolled_description = self.gui.get_widget('scrolled_description') self.treeview_description = DescriptionTreeView() self.scrolled_description.add(self.treeview_description) self.treeview_description.show() #Application menu self.menu_download = self.gui.get_widget('menu_download') self.menu_download.set_sensitive(False) self.menu_viewsite = self.gui.get_widget('menu_viewsite') self.menu_viewsite.set_sensitive(False) self.menu_quit = self.gui.get_widget('menu_quit') self.menu_preferences = self.gui.get_widget('menu_preferences') self.menu_fullscreen = self.gui.get_widget('menu_fullscreen') self.menu_fullscreen.set_sensitive(False) self.menu_reportbug = self.gui.get_widget('menu_reportbug') self.menu_about = self.gui.get_widget('menu_about') #Application buttons self.button_close = self.gui.get_widget('button_close') self.button_download = self.gui.get_widget('button_download') self.button_zoom = self.gui.get_widget("button_zoom") self.menu_viewsite.set_sensitive(False) self.button_download.set_sensitive(False) self.menu_download.set_sensitive(False) self.button_zoom.set_sensitive(False) # image widget to show the game screenshot self.image_game = self.gui.get_widget('image_game') # create the category treeview self.treeview_categories = self.gui.get_widget('treeview_categories') renderer_cat_name = gtk.CellRendererText() renderer_cat_name.set_property('scale', 1.0) column_cat = gtk.TreeViewColumn(MSG_000001,renderer_cat_name) column_cat.add_attribute(renderer_cat_name, 'markup', COL_CAT_NAME) self.treeview_categories.append_column(column_cat) self.treeview_categories.set_search_column(COL_CAT_NAME) self.category_selection = self.treeview_categories.get_selection() self.category_selection.set_mode(gtk.SELECTION_SINGLE) self.window_main.show() self.connect_events() self.check_version() self.fill_category() self.search_entry.grab_focus() def connect_events(self): # Make things responsible self.gui.connect(self.button_zoom,'clicked', self.on_zoom) self.gui.connect(self.menu_fullscreen,'activate', self.on_zoom) self.gui.connect(self.menu_viewsite,'activate', self.on_menu_viewsite) self.gui.connect(self.window_main, 'delete-event', gtk.main_quit) self.gui.connect(self.window_main, 'destroy', gtk.main_quit) self.gui.connect(self.menu_quit, 'activate', gtk.main_quit) self.gui.connect(self.treeview_games,"game-selected", self.on_treeview_games_selected) self.gui.connect(self.category_selection,'changed', self.on_treeview_categories_changed) self.gui.connect(self.button_download, 'clicked', self.on_button_download) self.gui.connect(self.menu_download, 'activate', self.on_button_download) self.gui.connect(self.menu_reportbug, 'activate', self.on_menu_reportbug) self.gui.connect(self.menu_about, 'activate', self.on_menu_about) self.search_entry.connect("terms-changed", self.on_search) def download_images(self, categoryid): need_download = [] cat = self.actions.get_games({'category':categoryid}) if cat: for n in cat: if load_pixbuf_image(n['image_file'])[1]: need_download.append(n) if len(need_download)>0: dialog = ProgressDialog(self.window_main ,'') dialog.connect("download-failed", self._fileDownloadFailed) # Download queue downloadItems = set() for n in need_download: downloadItems.add(DownloadItem('%s image' % n['game'], n['image_url'], os.path.join(CONFIG_DIR, n['image_file']))) # Try to download all items #response = dialog.download(downloadItems) dialog.message('Downloading Games images...') response = dialog.download(downloadItems) # Destroy wizard dialog.destroy() # Abort installation if user pressed cancel during the download #if response == gtk.RESPONSE_ACCEPT: self.window_main.set_sensitive(True) def on_search(self, widget, search_string): print 'on_search' self.gui.setBusy(self.window_main, True) search_terms = search_string.lower() model = self.treeview_games.get_model() if search_terms != None: for it in lib.utils.iterate_list_store(model, model.get_iter_first()): aname = model.get_value(it, COL_ITEM).lower() if search_terms in aname.split(' '): print "selecting: %s (%s)" % (search_terms, model.get_path(it)) self.treeview_games.set_cursor(model.get_path(it)) self.gui.setBusy(self.window_main, False) return elif len(model) > 0: self.treeview_games.set_cursor(0) self.gui.setBusy(self.window_main, False) def on_menu_viewsite(self,widget): game = self.treeview_games.get_selected_game() website = game.website lib.utils.url_open(website) def on_menu_reportbug(self,widget): lib.utils.url_open('https://bugs.edge.launchpad.net/iug/+filebug') def on_menu_about(self,widget): dialog = ui.aboutdialog.AboutDialog() def check_version(self): version = IUGVersionChecker() if not version.check_version(self.actions): dlg = CacheDialog(self.window_main) title = MSG_000002 dlg.set_title(title) result = dlg.run() dlg.destroy() if result == gtk.RESPONSE_YES : dialog = DownloadWizard(self.window_main,MSG_000003, True) dialog.connect("download-failed", self._fileDownloadFailed) # Download queue downloadItems = set() downloadItems.add(DownloadItem(MSG_000011, 'http://archive.ubuntugames.org/iug/version.txt', '/tmp/version.txt')) downloadItems.add(DownloadItem(MSG_000012, 'http://archive.ubuntugames.org/iug/iug.xml', '/tmp/iug.xml')) # Try to download all items response = dialog.download(downloadItems) # Destroy wizard dialog.destroy() # Abort installation if user pressed cancel during the download. txt_file = '/tmp/version.txt' xml_file = '/tmp/iug.xml' if response == gtk.RESPONSE_ACCEPT: if os.path.exists(txt_file) and os.path.exists(txt_file): self.parse_files(txt_file, xml_file) else: dlg_error = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, None) dlg_error.set_markup(txt_file + ' or ' + xml_file + '\n\nFile not found. Verify if the download was done.') dlg_error.run() dlg_error.destroy() print 'File not found. Verify if the download was done.' self.window_main.set_sensitive(True) def on_button_download(self, widget): game = self.treeview_games.get_selected_game() download_type = game.download_type install_command = game.download_url if download_type == 'wget': self.gui.show_info('<b>%s</b>\n%s' % (download_type,install_command), self.window_main) dialog = ProgressDialog(self.window_main ,'') dialog.connect("download-failed", self._fileDownloadFailed) # Download queue downloadItems = set() filedownload = os.path.join('/tmp/',game.download_url.split('/')[-1]) downloadItems.add(DownloadItem(game.game,game.download_url, filedownload)) # Try to download all items #response = dialog.download(downloadItems) dialog.message('Downloading Game...') response = dialog.download(downloadItems) if response == gtk.RESPONSE_ACCEPT: commands = game.install_command.split('|') if lib.utils.get_mimetype(filedownload) == 'application/x-tar': gunzip(filedownload) # Destroy wizard dialog.destroy() elif download_type =='deb': print 'gnome-terminal --command sudo dpkg -i %s' % game.install_command os.system('gnome-terminal --command sudo dpkg -i %s' % game.deb_filename) else: self.gui.show_info('Instalando:%s' % download_type, self.window_main) def on_zoom(self, widget): zoom = ZoomWindow(self.window_main, self.treeview_games.get_selected_game().image_filename) zoom.run() def _fileDownloadFailed(self, wizard, handle): print "Could not fetch file.", handle.item.source def parse_files(self, versionfile, xmlfile): self.gui.setBusy(self.window_main) dversion = open(versionfile).readline() dversion = float(dversion) print "version:", dversion rec = self.actions.get_iugversion()[0] id = rec['id'] lversion = rec['version'] print id, lversion , lversion < dversion,lversion , dversion if lversion < dversion : self.actions.edit_iugversion({'version': dversion,'id': id, 'version_date': get_current_date()}) xFile = XML2obj(xmlfile) xobj = xFile.get_python_from_xml() game = xobj.game for n in game: exist = self.actions.get_categories({'categoryname':decode(n.category)}) if not exist: self.actions.add_category({'categoryname':decode(n.category)}) cat = self.actions.get_categories({'categoryname':decode(n.category)})[0] game_exist = self.actions.get_games({'game': decode(n.name)}) print decode(n.description) if not game_exist : game_dict=dict({'category': cat['id'], 'game': decode(n.name), 'description': decode(n.description), 'image_url': decode(n.image_url), 'image_file': get_file_name(decode(n.image_url)), 'requires': decode(n.requires), 'download_url':decode(n.download_url), 'download_type':decode(n.download_type), 'file_size':decode(n.file_size), 'website': decode(n.site), 'deb_filename':decode(n.deb_filename), 'install_command':decode(n.install_command), 'version':decode(n.version), 'file_size': decode(n.file_size), 'rate':decode(n.rate)}) self.actions.add_game(game_dict); else: game_dict=dict({'category': cat['id'], 'id' : game_exist[0]['id'], 'game': decode(n.name), 'description': decode(n.description), 'image_url': decode(n.image_url), 'image_file': get_file_name(decode(n.image_url)), 'requires': decode(n.requires), 'download_url':decode(n.download_url), 'download_type':decode(n.download_type), 'file_size':decode(n.file_size), 'website': decode(n.site), 'deb_filename':decode(n.deb_filename), 'install_command':decode(n.install_command), 'version':decode(n.version), 'file_size': decode(n.file_size), 'rate':decode(n.rate)}) self.actions.edit_game(game_dict) self.gui.setBusy(self.window_main, True) def fill_category(self): self.gui.setBusy(self.window_main, True) model = gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_INT) self.treeview_categories.set_model(model) cat = self.actions.get_categories('') #added a category to show all games in the list model.append([MSG_000026,0]) for n in cat: model.append([n['categoryname'],n['id']]) self.gui.setBusy(self.window_main) def fill_games(self, categoryid): self.gui.setBusy(self.window_main, True) self.treeview_games.clear() if categoryid == 0: cat = self.actions.get_games() else: cat = self.actions.get_games({'category':categoryid}) if cat: self.download_images(categoryid) for n in cat: game = Game(n['game']) game.game_id = n['id'] game.category = n['category'] game.rate = n['rate'] game.description = n['description'] game.image_filename = n['image_file'] game.version = n['version'] game.file_size = n['file_size'] game.image_url = n['image_url'] game.website = n['website'] game.requires = n['requires'] game.install_command = n['install_command'] game.deb_filename = n['deb_filename'] game.download_url = n['download_url'] game.download_type= n['download_type'] game.localpicture = not load_pixbuf_image(game.image_filename)[1] self.treeview_games.add(game) self.gui.setBusy(self.window_main) # widget event handler def on_treeview_games_selected(self, widget, game): self.treeview_description.clear() self.image_game.clear() self.menu_viewsite.set_sensitive(True) self.button_download.set_sensitive(True) self.menu_download.set_sensitive(True) self.button_zoom.set_sensitive(True) self.menu_fullscreen.set_sensitive(True) self.treeview_description.add(game) pixbuf,isdefault = load_pixbuf_image(game.image_filename) pixscaled = self.gui.scale(pixbuf,192,192) self.image_game.set_from_pixbuf(pixscaled) def on_treeview_categories_changed(self, treeview): model, iter = treeview.get_selected() if iter: self.menu_viewsite.set_sensitive(False) self.button_download.set_sensitive(False) self.menu_download.set_sensitive(False) self.button_zoom.set_sensitive(False) self.menu_fullscreen.set_sensitive(False) self.treeview_description.clear() self.image_game.clear() self.fill_games( model.get_value(iter,COL_CAT_ITEM))
class CategoriesDialog(gtk.Dialog): """ Class used to generate dialog to allow user to enter/edit categories. """ def __init__(self, parent=None, new=False): gtk.Dialog.__init__(self, title=_("Categories Manager"), parent=parent, flags=gtk.DIALOG_MODAL) self.closebutton = self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE) self.okbutton = self.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) self.set_icon_from_file(common.APP_ICON) self.new = new if parent: self.set_transient_for(parent) self.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.currentrecord = None # Set up the UI self._initialize_dialog_widgets() self._connect_fields() #self._populate_fields() self.actions = Actions() self._populateTreeView(self.actions.get_categories()) if new: self._on_newbutton_clicked(None) self.topcontainer.get_label_widget().set_markup("<b>%s</b>" \ % _("New Category")) self.okbutton.set_label(gtk.STOCK_SAVE) self.closebutton.set_label(gtk.STOCK_CANCEL) else: index = parent.category.get_active()-2 if index >= 0: self.list.set_cursor((index,)) def _initialize_dialog_widgets(self): self.vbox.set_spacing(8) self.topcontainer = gtk.Frame("<b>%s</b>" % _("Categories")) self.topcontainer.props.label_widget.set_use_markup(True) self.topcontainer.set_shadow_type(gtk.SHADOW_NONE) self.topcontainer_alignment = gtk.Alignment() self.topcontainer_alignment.set_padding(10, 0, 12, 0) self.topcontainer.add(self.topcontainer_alignment) self.fieldbox = gtk.VBox(homogeneous=False, spacing=6) self.list = ViewCategory() self.list.set_size_request(300, 150) # ScrolledWindow self.scrolledwindow = gtk.ScrolledWindow() self.scrolledwindow.set_shadow_type(gtk.SHADOW_OUT) self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.scrolledwindow.add(self.list) self.table = gtk.Table(rows=2, columns=2, homogeneous=False) self.table.set_col_spacing(0, 6) self.table.set_row_spacing(0, 6) self.namelabel = gtk.Label() self.namelabel.set_markup("%s " % _("Name:")) self.namelabel.set_alignment(0.00, 0.50) self.colorlabel = gtk.Label() self.colorlabel.set_markup("%s " % _("Color:")) self.colorlabel.set_alignment(0.00, 0.50) self.name_ = gtk.Entry() self.color = gtk.ColorButton() self.table.attach(self.namelabel, 0, 1, 0, 1, gtk.FILL, gtk.FILL) self.table.attach(self.colorlabel, 0, 1, 1, 2, gtk.FILL, gtk.FILL) self.table.attach(self.name_, 1, 2, 0, 1) self.table.attach(self.color, 1, 2, 1, 2) self.actionspack = gtk.HButtonBox() self.actionspack.set_layout(gtk.BUTTONBOX_END) self.actionspack.set_spacing(6) self.newbutton = gtk.Button(stock=gtk.STOCK_NEW) self.savebutton = gtk.Button(stock=gtk.STOCK_SAVE) self.deletebutton = gtk.Button(stock=gtk.STOCK_DELETE) self.actionspack.pack_start(self.newbutton) self.actionspack.pack_start(self.savebutton) self.actionspack.pack_start(self.deletebutton) if not self.new: self.fieldbox.pack_start(self.scrolledwindow, expand=True, fill=True) self.fieldbox.pack_start(self.table, expand=False, fill=True) if not self.new: self.fieldbox.pack_start(self.actionspack, expand=False, fill=True) self.topcontainer_alignment.add(self.fieldbox) self.vbox.pack_start(self.topcontainer, expand=True, fill=True, padding=10) # Show all widgets self.show_all() def _connect_fields(self): self.list.connect('cursor_changed', self._on_list_cursor_changed) self.name_.connect("changed", self._on_edit) self.color.connect("color-set", self._on_edit) self.newbutton.connect("clicked", self._on_newbutton_clicked) self.savebutton.connect("clicked", self._on_savebutton_clicked) self.deletebutton.connect("clicked", self._on_deletebutton_clicked) def _populateTreeView(self, records): """ Populates the treeview control with the records passed """ # Loops through bills collection path = 0 found = 0 for rec in records: self.list.add(self._formated_row(rec)) if self.currentrecord: if rec.name == self.currentrecord.name: found = path path += 1 # Only select an item if we have data if len(self.list): self.list.set_cursor(found) return def _formated_row(self, row): """ Formats a bill to be displayed as a row. """ color = row.color and row.color or '#d3d7cf' formated = [] formated.append(row.id) formated.append(create_pixbuf(color=color)) formated.append(row.name) formated.append(row.color) return formated def _on_list_cursor_changed(self, widget): # Get currently selected bill self._get_selected_record() # Update statusbar self._update_fields() self.deletebutton.set_sensitive(True) self.savebutton.set_sensitive(False) def _get_selected_record(self): """ Keeps track of the currently selected record """ if len(self.list.listStore) > 0: selection = self.list.get_selection() _model, iteration = selection.get_selected() # The ID for the selected record category_id = _model.get_value(iteration, 0) # Now fetch it from the database self.currentrecord = self.actions.get_categories(id=category_id)[0] else: self.currentrecord = None def _update_fields(self): if not self.currentrecord: self.name_.set_text("") self.color.set_color(gtk.gdk.color_parse("#d3d7cf")) else: self.name_.set_text(self.currentrecord.name) color = self.currentrecord.color and self.currentrecord.color or '#d3d7cf' color = gtk.gdk.color_parse(color) self.color.set_color(color) def reloadTreeView(self, *arg): # Update list with updated record self.list.listStore.clear() self._populateTreeView(self.actions.get_categories()) def _on_newbutton_clicked(self, button): self.currentrecord = None self.name_.set_text("") self.color.set_color(gtk.gdk.color_parse("#d3d7cf")) self.deletebutton.set_sensitive(False) self.savebutton.set_sensitive(False) self.name_.grab_focus() def _on_savebutton_clicked(self, button): # Extract input data name = self.name_.get_text() color = self.color.get_color().to_string() # Check if it already exists rec = self.actions.get_categories(name=name) if rec: message = Message() if message.ShowQuestionYesNo(_("The category \"%s\" already exists in the database!\n\n"\ "Do you want to save your change to the existing category?") % name, self): # We're updating an existing category. cat = rec[0] cat.name = name cat.color = color row = self.actions.edit(cat) # We're adding a new category. else: cat = Category(name, color) row = self.actions.add(cat) # Update our local "copy" directly from database self.currentrecord = self.actions.get_categories(name=name)[0] # Repopulate the grid self.reloadTreeView() def _on_deletebutton_clicked(self, button): if self.currentrecord: id = self.currentrecord.id more = self.actions.get_bills(id=id) if len(more) > 1: message = Message() confirm = message.ShowQuestionYesNo("%s%s" % ( _("Do you really want to delete this category?\n") , ngettext("There is %d more bill in this category.", "There are %d more bills in this category.", (len(more) - 1)) % (len(more) - 1)), parentWindow=self, title=_("Confirmation")) if not confirm: return try: row = self.actions.delete(self.currentrecord) self.currentrecord = None self.name_.set_text("") self.color.set_color(gtk.gdk.color_parse("#d3d7cf")) self.savebutton.set_sensitive(False) self.reloadTreeView() except Exception, e: print "Failed to delete the selected category with error: %s" % str(e)
def __init__(self): gobject.GObject.__init__(self) if exists(join(USER_CFG_PATH, CFG_NAME)): from lib.migrate_to_gconf import migrate migrate(join(USER_CFG_PATH, CFG_NAME)) self.gconf_client = Configuration() self.message = Message() # Connects to the database self.actions = Actions() self.ui = gtk.Builder() self.ui.add_from_file(os.path.join(DEFAULT_CFG_PATH, "main.ui")) self.window = self.ui.get_object("main_window") self.window.set_title("%s" % common.APPNAME) self.window.set_icon_from_file(common.APP_ICON) # ViewBill self.list = ViewBill() self.list.connect('cursor_changed', self._on_list_cursor_changed) self.list.connect('row_activated', self._on_list_row_activated) self.list.connect('button_press_event', self._on_list_button_press_event) self.ui.get_object("bill_box").add(self.list) # Toolbar self.toolbar = self.ui.get_object("toolbar") # Menubar self._populate_menubar() # Statusbar self.statusbar = Statusbar() self.ui.get_object("statusbar_box").add(self.statusbar) # Restore timeline zoom timeline_count = self.gconf_client.get('timeline_count') # Timeline self.timeline = Timeline(count=timeline_count, callback=self.on_timeline_cb) self.timeline.connect("value-changed", self._on_timeline_changed) self.timeline.connect("cleared", self._on_timeline_cleared) self.ui.get_object("timeline_box").add(self.timeline) # Chart self.chart = ChartWidget() self.chart.set_border_width(10) self.ui.get_object("chart_box").add(self.chart) # Restore position and size of window width = self.gconf_client.get('window_width') height = self.gconf_client.get('window_height') x = self.gconf_client.get('window_position_x') y = self.gconf_client.get('window_position_y') if width and height: self.window.resize(width, height) if x and y: self.window.move(x, y) self.window.show_all() # Whether to display toolbar or not self.on_showToolbar_toggled(self.ui.get_object("showToolbar")) self.list.grab_focus() if self.gconf_client.get('start_in_tray'): self.window.hide() self.toggle_buttons() # Connects to the Daemon self.iface = None iface = get_dbus_interface(common.DBUS_INTERFACE, common.DBUS_PATH) if iface: iface.connect_to_signal("bill_edited", self.reloadTreeView) iface.connect_to_signal("bill_edited", self.reloadTimeline) iface.connect_to_signal("show_main_window", self.window.show) self.iface = iface timeout_add(2000, self._send_tray_hints) self.set_action_strings() self.ui.connect_signals(self) # populate treeview self.reloadTreeView() self.notify = NotifyIcon(self) # Integrate with Ubuntu Unity if UNITY: self.unity = UnityIntegration(self)
class MainDialog(gobject.GObject): search_text = "" _bullet_cache = {} __gsignals__ = { 'bill-added': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )), 'bill-updated': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )), 'bill-removed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )) } def __init__(self): gobject.GObject.__init__(self) if exists(join(USER_CFG_PATH, CFG_NAME)): from lib.migrate_to_gconf import migrate migrate(join(USER_CFG_PATH, CFG_NAME)) self.gconf_client = Configuration() self.message = Message() # Connects to the database self.actions = Actions() self.ui = gtk.Builder() self.ui.add_from_file(os.path.join(DEFAULT_CFG_PATH, "main.ui")) self.window = self.ui.get_object("main_window") self.window.set_title("%s" % common.APPNAME) self.window.set_icon_from_file(common.APP_ICON) # ViewBill self.list = ViewBill() self.list.connect('cursor_changed', self._on_list_cursor_changed) self.list.connect('row_activated', self._on_list_row_activated) self.list.connect('button_press_event', self._on_list_button_press_event) self.ui.get_object("bill_box").add(self.list) # Toolbar self.toolbar = self.ui.get_object("toolbar") # Menubar self._populate_menubar() # Statusbar self.statusbar = Statusbar() self.ui.get_object("statusbar_box").add(self.statusbar) # Restore timeline zoom timeline_count = self.gconf_client.get('timeline_count') # Timeline self.timeline = Timeline(count=timeline_count, callback=self.on_timeline_cb) self.timeline.connect("value-changed", self._on_timeline_changed) self.timeline.connect("cleared", self._on_timeline_cleared) self.ui.get_object("timeline_box").add(self.timeline) # Chart self.chart = ChartWidget() self.chart.set_border_width(10) self.ui.get_object("chart_box").add(self.chart) # Restore position and size of window width = self.gconf_client.get('window_width') height = self.gconf_client.get('window_height') x = self.gconf_client.get('window_position_x') y = self.gconf_client.get('window_position_y') if width and height: self.window.resize(width, height) if x and y: self.window.move(x, y) self.window.show_all() # Whether to display toolbar or not self.on_showToolbar_toggled(self.ui.get_object("showToolbar")) self.list.grab_focus() if self.gconf_client.get('start_in_tray'): self.window.hide() self.toggle_buttons() # Connects to the Daemon self.iface = None iface = get_dbus_interface(common.DBUS_INTERFACE, common.DBUS_PATH) if iface: iface.connect_to_signal("bill_edited", self.reloadTreeView) iface.connect_to_signal("bill_edited", self.reloadTimeline) iface.connect_to_signal("show_main_window", self.window.show) self.iface = iface timeout_add(2000, self._send_tray_hints) self.set_action_strings() self.ui.connect_signals(self) # populate treeview self.reloadTreeView() self.notify = NotifyIcon(self) # Integrate with Ubuntu Unity if UNITY: self.unity = UnityIntegration(self) def set_action_strings(self): # for some reason the actions strings do not get translated yet # so we define them here so they would be picked up by the pyfile scanner self.ui.get_object("newBill").set_label(_("_New")) self.ui.get_object("newBill").set_tooltip(_("Add new bill")) self.ui.get_object("editBill").set_label(_("_Edit")) self.ui.get_object("editBill").set_tooltip(_("Edit a bill")) self.ui.get_object("removeBill").set_label(_("_Delete")) self.ui.get_object("removeBill").set_tooltip(_("Delete selected bill")) self.ui.get_object("markPaid").set_label(_("P_aid")) self.ui.get_object("markPaid").set_tooltip(_("Mark as paid")) self.ui.get_object("markNotPaid").set_label(_("No_t Paid")) self.ui.get_object("markNotPaid").set_tooltip(_("Mark as not paid")) self.ui.get_object("showToolbar").set_label(_("_Show Toolbar")) self.ui.get_object("showToolbar").set_tooltip(_("Show the toolbar")) # Methods: UI def _send_tray_hints(self): self.iface.set_tray_hints(force_string(self.notify.get_hints())) timeout_add(60000, self._send_tray_hints) def get_window_visibility(self): return self.window.get_property("visible") def show_hide_window(self): if self.window.get_property("visible"): self.window.hide() else: self.window.show() def get_selected_record(self): """ Returns a bill object from the current selected record """ if len(self.list.listStore) > 0: model_ = self.list.get_model() if self.list.get_cursor()[0]: index = self.list.get_cursor()[0][0] else: index = 0 b_id = model_[index][0] records = self.actions.get_bills(id=b_id) self.currentrecord = records[0] else: self.currentrecord = None print "Current record is: %s" % self.currentrecord def populate_view(self, records): """ Populates the treeview control with the records passed """ # Reset list self.list.listStore.clear() if not records: return 0 # Loops through bills collection path = 0 for rec in records: # Format the record prior to adding it to treeview row = self.format_row(rec) self.list.add(row) # Set the cursor to the first (top) record self.list.set_cursor(path) # Returns how many records there are in the treeview return len(records) def reloadTreeView(self, *arg): # Update list with updated record status = self.gconf_client.get('show_paid_bills') path = self.list.get_cursor()[0] self.list.listStore.clear() self.currentrecord = None first = self.timeline.start_date last = self.timeline.end_date # Get list of records records = self.actions.get_interval_bills(first, last, status) # Populate treeview self.populate_view(records) # Update status bar self.update_statusbar() # populate chart self._populate_chart(status, first, last) return len(records) def format_row(self, row): """ Formats a bill to be displayed as a row. """ categoryName = row.category.name if row.category else _('None') categoryColor = row.category.color if row.category else '#d3d7cf' formatted = [ row.id, create_pixbuf(color=categoryColor), categoryName, row.payee, row.dueDate.strftime(_('%m/%d').encode('ASCII')), row.amount, row.notes, int(row.paid), None ] return formatted def _populate_chart(self, status, start, end): records = [] categories = [] totals = [] records = self.actions.get_monthly_totals(start, end, status) # Chart widget takes data in format (('CategoryName', amount),) categories = [cat or 'None' for cat, total in records] totals = [float(total) for cat, total in records] #records = [(c if c else 'None',float(t)) for c,t in records] # set bar colors all_categories = self.actions.get_categories() self.chart.chart.key_colors = dict([(cat.name or 'None', cat.color) for cat in all_categories]) self.chart.plot(categories, totals) def _populate_menubar(self): try: saved_view = self.gconf_client.get('show_paid_bills') except: saved_view = 1 self.gconf_client.set("show_paid_bills", saved_view) if saved_view == 0: self.ui.get_object("showNotPaid").set_active(True) elif saved_view == 1: self.ui.get_object("showPaid").set_active(True) else: self.ui.get_object("showAll").set_active(True) # Check whether we display the toolbar or not self.ui.get_object("showToolbar").set_active( self.gconf_client.get('show_toolbar')) def add_bill(self): selectedDate = self.timeline.value records = dialogs.add_dialog(parent=self.window, selectedDate=selectedDate) # Checks if the user did not cancel the action if records: # Add new bill to database for rec in records: bill_id = self.actions.add(rec) bill = self.actions.get_bills(id=bill_id)[0] if bill: self.list.add(self.format_row(bill)) self.update_statusbar() # Reload records tree (something changed) self.reloadTreeView() self.reloadTimeline() def edit_bill(self): records = dialogs.edit_dialog(parent=self.window, record=self.currentrecord) # Checks if the user did not cancel the action if records: for rec in records: # Edit bill to database rec = self.actions.edit(rec) self.emit('bill-updated', rec) # Reload records tree (something changed) self.reloadTreeView() self.reloadTimeline() def remove_bill(self): self.actions.delete(self.currentrecord) self.list.remove() self.emit('bill-removed', None) self.update_statusbar() self.reloadTreeView() self.reloadTimeline() def toggle_bill_paid(self): # Fetch record from database record = self.actions.get_bills(id=self.currentrecord.id)[0] # Toggle paid field record.paid = False if record.paid else True # Edit bill in the database transaction = self.actions.add(record) self.emit('bill-updated', record) # Update our current copy self.currentrecord = self.actions.get_bills( id=self.currentrecord.id)[0] # Update timeline widget to reflect change self._bullet_cache[self.currentrecord.dueDate] = [self.currentrecord] # Update list with updated record idx = self.list.get_cursor()[0][0] self.update_statusbar(idx) self.reloadTreeView() self.reloadTimeline() def about(self): dialogs.about_dialog(parent=self.window) def preferences(self): dialogs.preferences_dialog(parent=self.window) # Methods def _quit_application(self): self.save_position() self.save_size() self.save_timeline_zoom() gtk.main_quit() return False def save_position(self): x, y = self.window.get_position() self.gconf_client.set('window_position_x', x) self.gconf_client.set('window_position_y', y) def save_size(self): width, height = self.window.get_size() self.gconf_client.set('window_width', width) self.gconf_client.set('window_height', height) def save_timeline_zoom(self): count = self.timeline.count self.gconf_client.set('timeline_count', count) def toggle_buttons(self, paid=None): """ Toggles all buttons conform number of records present and their state """ for widget in ["editBill", "removeBill", "markPaid", "markNotPaid"]: self.ui.get_object(widget).set_sensitive( len(self.list.listStore) > 0) if len(self.list.listStore) > 0: self.ui.get_object("markPaid").set_sensitive(paid == False) self.ui.get_object("markNotPaid").set_sensitive(paid == True) def update_statusbar(self, index=0): """ This function is used to update status bar informations about the list """ records = len(self.list.listStore) # Record count self.statusbar.Records(records) if self.currentrecord: # Display the status self.statusbar.Notes(self.currentrecord.notes) # Toggles toolbar buttons on/off self.toggle_buttons(self.currentrecord.paid) else: # Clear the status for the selected row self.statusbar.Notes("") # Toggles toolbar buttons on/off self.toggle_buttons() show_paid_bills = self.gconf_client.get('show_paid_bills') if show_paid_bills is 0: self.statusbar.Info(_("Not Paid Only")) elif show_paid_bills is 1: self.statusbar.Info(_("Paid Only")) else: self.statusbar.Info('') # Event handlers def _on_list_button_press_event(self, widget, event): """ This function will handle the signal to show a popup menu sent by a right click on tvBill widget. """ if event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: self.get_selected_record() c = self.ui.get_object("context_menu") c.popup(None, None, None, event.button, event.get_time()) def _on_list_row_activated(self, widget, path, column): self._on_list_cursor_changed(widget) self.on_editBill_activate(None) def _on_list_cursor_changed(self, widget): # Get currently selected bill self.get_selected_record() # Update statusbar self.update_statusbar() def on_newBill_activate(self, toolbutton): self.add_bill() def on_editBill_activate(self, toolbutton): if self.currentrecord: self.edit_bill() def on_removeBill_activate(self, toolbutton): if self.currentrecord: resp = self.message.ShowQuestionYesNo( _("Do you really want to delete \"%s\"?") % \ self.currentrecord.payee, self.window, _("Confirmation")) if resp: self.remove_bill() def on_markNotPaid_activate(self, toolbutton): self.on_markPaid_activate(toolbutton) # forward def on_markPaid_activate(self, toolbutton): if self.currentrecord: self.toggle_bill_paid() def on_btnAbout_activate(self, toolbutton): self.about() def on_btnPrefs_activate(self, toolbutton): self.preferences() def on_btnQuit_activate(self, toolbutton): self._quit_application() def on_delete_event(self, widget, event, data=None): self._quit_application() def _on_timeline_changed(self, widget, args): self.reloadTreeView() def _on_timeline_cleared(self, widget, args): self._bullet_cache = {} def switch_view(self, view_number): self.gconf_client.set('show_paid_bills', view_number) self.reloadTreeView() self.reloadTimeline() def on_showNotPaid_toggled(self, action): if action.get_active(): self.switch_view(0) def on_showPaid_toggled(self, action): if action.get_active(): self.switch_view(1) def on_showAll_toggled(self, action): if action.get_active(): self.switch_view(2) def on_showToolbar_toggled(self, action): # Toggle toolbar's visibility if action.get_active(): self.toolbar.show_all() else: self.toolbar.hide_all() self.gconf_client.set("show_toolbar", action.get_active()) def reloadTimeline(self, *args): self._bullet_cache = {} self.timeline.refresh() def on_timeline_cb(self, date, display_type, force=False): # TODO: Improve tooltip # TODO: Improve cache if date in self._bullet_cache.keys() and not force: return None self._bullet_cache[date] = self.actions.get_bills(dueDate=date) if self._bullet_cache[date]: status = self.gconf_client.get('show_paid_bills') amount = 0 amount_not_paid = 0 tooltip = '' bullet = Event() bullet.date = date for bill in self._bullet_cache[date]: amount += bill.amount if tooltip: tooltip += '\n' tooltip += bill.payee + ' (' + str( float_to_currency(bill.amount)) + ')' if bill.paid: tooltip += ' [%s]' % _('Paid') if status == 0: return False bullet.status = bullet.status | bullet.PAID else: amount_not_paid += bill.amount if date <= datetime.date.today(): if status == 1: return False bullet.status = bullet.status | bullet.OVERDUE else: if status == 1: return False bullet.status = bullet.status | bullet.TO_BE_PAID if bill.notes: tooltip += ' - ' + bill.notes bullet.amountdue = amount_not_paid if amount_not_paid else amount bullet.payee = bill.payee bills = len(self._bullet_cache[date]) if bills > 1: bullet.multi = bills bullet.payee = '%d bills' % bills bullet.tooltip = tooltip return bullet return None