コード例 #1
0
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
コード例 #2
0
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