# Copyright 2008 by Wade Brainerd.
# This file is part of Finance.
#
# Finance is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Finance is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Finance. If not, see .
# Import standard Python modules.
import logging, os, math, time, copy, json, time, datetime, locale
from gettext import gettext as _
# Set up localization.
locale.setlocale(locale.LC_ALL, '')
# Import PyGTK.
import gobject, pygtk, gtk, pango, cairo
# Import Sugar UI modules.
import sugar.activity.activity
from sugar.graphics import *
# Import activity module
import finance
REGISTER_HELP = _('Welcome to Finance! This activity keeps track of income and expenses for anything that earns\nor spends money, like a school club. To get started, use the Transaction box to add credits and debits.\nOnce you have entered some transactions, visit the Chart and Budget views to see more.')
class RegisterScreen(gtk.VBox):
def __init__(self, activity):
gtk.VBox.__init__(self)
self.activity = activity
# Build the transaction list.
self.treeview = gtk.TreeView()
self.treeview.set_rules_hint(True)
self.treeview.set_enable_search(False)
# Note that the only thing we store in our liststore is the transaction id.
# All the actual data is in the activity database.
self.liststore = gtk.ListStore(gobject.TYPE_INT)
self.treeview.set_model(self.liststore)
# Construct the columns.
renderer = gtk.CellRendererText()
renderer.props.editable = True
renderer.connect('editing-started', self.description_editing_started_cb)
renderer.connect('edited', self.description_edit_cb)
col = gtk.TreeViewColumn(_('Description'), renderer)
col.set_cell_data_func(renderer, self.description_render_cb)
col.set_expand(True)
self.treeview.append_column(col)
renderer = gtk.CellRendererText()
renderer.props.editable = True
renderer.connect('edited', self.amount_edit_cb)
col = gtk.TreeViewColumn(_('Amount'), renderer)
col.set_cell_data_func(renderer, self.amount_render_cb)
col.set_alignment(0.5)
col.set_min_width(120)
self.treeview.append_column(col)
renderer = gtk.CellRendererText()
renderer.props.editable = True
renderer.connect('edited', self.date_edit_cb)
col = gtk.TreeViewColumn(_('Date'), renderer)
col.set_alignment(0.5)
col.set_cell_data_func(renderer, self.date_render_cb)
col.set_min_width(150)
self.treeview.append_column(col)
renderer = gtk.CellRendererText()
renderer.props.editable = True
renderer.connect('editing-started', self.category_editing_started_cb)
renderer.connect('edited', self.category_edit_cb)
col = gtk.TreeViewColumn(_('Category'), renderer)
col.set_cell_data_func(renderer, self.category_render_cb)
col.set_alignment(0.5)
col.set_min_width(300)
self.treeview.append_column(col)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.add(self.treeview)
self.pack_start(scroll, True, True, 0)
def build(self):
# Build liststore.
self.liststore.clear()
for t in self.activity.visible_transactions:
self.liststore.append((t['id'],))
# Update the help text.
self.activity.set_help(REGISTER_HELP)
def description_render_cb(self, column, cell_renderer, model, iter):
id = model.get_value(iter, 0)
t = self.activity.transaction_map[id]
cell_renderer.set_property('text', t['name'])
def description_editing_started_cb(self, cell_renderer, editable, path):
completion = gtk.EntryCompletion()
completion.set_inline_completion(True)
completion.set_popup_completion(True)
completion.set_minimum_key_length(0)
store = gtk.ListStore(str)
for c in self.activity.transaction_names.keys():
store.append([c])
completion.set_model(store)
completion.set_text_column(0)
editable.set_completion(completion)
def description_edit_cb(self, cell_renderer, path, new_text):
id = self.liststore[path][0]
t = self.activity.transaction_map[id]
t['name'] = new_text
# Automatically fill in category if empty, and if transaction name is known.
if t['category'] == '' and self.activity.transaction_names.has_key(new_text):
for ct in self.activity.data['transactions']:
if ct['name'] == new_text and ct['category'] != '':
t['category'] = ct['category']
def amount_render_cb(self, column, cell_renderer, model, iter):
id = model.get_value(iter, 0)
t = self.activity.transaction_map[id]
cell_renderer.set_property('xalign', 1.0)
if t['type'] == 'credit':
cell_renderer.set_property('foreground', '#4040ff')
cell_renderer.set_property('text', locale.currency(t['amount'], False))
else:
cell_renderer.set_property('foreground', '#ff4040')
cell_renderer.set_property('text', locale.currency(-t['amount'], False))
def amount_edit_cb(self, cell_renderer, path, new_text):
id = self.liststore[path][0]
t = self.activity.transaction_map[id]
t['amount'] = abs(locale.atof(new_text))
self.activity.update_summary()
def date_render_cb(self, column, cell_renderer, model, iter):
id = model.get_value(iter, 0)
t = self.activity.transaction_map[id]
when = datetime.date.fromordinal(t['date'])
cell_renderer.set_property('text', when.isoformat())
cell_renderer.set_property('xalign', 0.5)
def date_edit_cb(self, cell_renderer, path, new_text):
id = self.liststore[path][0]
t = self.activity.transaction_map[id]
when = time.strptime(new_text, "%Y-%m-%d")
when = datetime.date(when[0], when[1], when[2])
t['date'] = when.toordinal()
self.activity.build_screen()
def category_render_cb(self, column, cell_renderer, model, iter):
id = model.get_value(iter, 0)
t = self.activity.transaction_map[id]
cell_renderer.set_property('text', t['category'])
cell_renderer.set_property('background', finance.get_category_color_str(t['category']))
def category_editing_started_cb(self, cell_renderer, editable, path):
completion = gtk.EntryCompletion()
completion.set_inline_completion(True)
completion.set_popup_completion(True)
completion.set_minimum_key_length(0)
store = gtk.ListStore(str)
for c in self.activity.category_names.keys():
store.append([c])
completion.set_model(store)
completion.set_text_column(0)
editable.set_completion(completion)
def category_edit_cb(self, cell_renderer, path, new_text):
id = self.liststore[path][0]
t = self.activity.transaction_map[id]
t['category'] = new_text
if new_text != '':
self.activity.category_names[new_text] = 1
def newcredit_cb(self, widget):
# Automatically display the register screen.
if self.activity.screens[-1] != self.activity.register:
self.activity.pop_screen()
self.activity.push_screen(self)
id = self.activity.create_transaction(_('New Credit'), 'credit', 0)
iter = self.liststore.append((id,))
# Set cursor and begin editing the description.
self.treeview.set_cursor(self.liststore.get_path(iter), self.treeview.get_column(0), True)
def newdebit_cb(self, widget):
# Automatically display the register screen.
if self.activity.screens[-1] != self.activity.register:
self.activity.pop_screen()
self.activity.push_screen(self)
id = self.activity.create_transaction(_('New Debit'), 'debit', 0)
iter = self.liststore.append((id,))
# Set cursor and begin editing the description.
self.treeview.set_cursor(self.liststore.get_path(iter), self.treeview.get_column(0), True)
def eraseitem_cb(self, widget):
# Ignore unless on the register screen.
if self.activity.screens[-1] != self.activity.register:
return
sel = self.treeview.get_selection()
model, iter = sel.get_selected()
if iter:
id = model.get_value(iter, 0)
self.activity.destroy_transaction(id)
self.activity.update_summary()
path = model.get_path(iter)
model.remove(iter)
# Select the next item, or else the last item.
sel.select_path(path)
if not sel.path_is_selected(path):
row = path[0]-1
if row >= 0:
sel.select_path((row,))