# 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 .
#!/usr/bin/env python
"""Finance - Home financial software for the OLPC XO."""
# Import standard Python modules.
import logging, os, math, time, copy, time, datetime, locale
from gettext import gettext as _
from port import json
# 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.toggletoolbutton import ToggleToolButton
from sugar.graphics.toolbutton import ToolButton
from sugar.graphics.toolcombobox import ToolComboBox
from sugar.graphics import *
OLD_TOOLBAR = False
try:
from sugar.graphics.toolbarbox import ToolbarBox
from sugar.graphics.toolbarbox import ToolbarButton
from sugar.graphics.radiotoolbutton import RadioToolButton
from sugar.activity.widgets import StopButton
from sugar.activity.widgets import ActivityToolbarButton
except ImportError:
OLD_TOOLBAR = True
# Initialize logging.
log = logging.getLogger('Finance')
log.setLevel(logging.DEBUG)
logging.basicConfig()
# Import screen classes.
import registerscreen, chartscreen, budgetscreen
CATEGORY_COLORS = [
(1.0,1.0,1.0),
(1.0,1.0,0.6),
(1.0,1.0,0.8),
(1.0,0.6,1.0),
(1.0,0.6,0.6),
(1.0,0.6,0.8),
(1.0,0.8,1.0),
(1.0,0.8,0.6),
(1.0,0.8,0.8),
(0.6,1.0,1.0),
(0.6,1.0,0.6),
(0.6,1.0,0.8),
(0.6,0.6,1.0),
(0.6,0.6,0.6),
(0.6,0.6,0.8),
(0.6,0.8,1.0),
(0.6,0.8,0.6),
(0.6,0.8,0.8),
(0.8,1.0,1.0),
(0.8,1.0,0.6),
(0.8,1.0,0.8),
(0.8,0.6,1.0),
(0.8,0.6,0.6),
(0.8,0.6,0.8),
(0.8,0.8,1.0),
(0.8,0.8,0.6),
(0.8,0.8,0.8),
]
def get_category_color(catname):
return CATEGORY_COLORS[catname.__hash__() % len(CATEGORY_COLORS)]
def get_category_color_str(catname):
color = get_category_color(catname)
return "#%02x%02x%02x" % (int(color[0]*255), int(color[1]*255), int(color[2]*255))
# This is the main Finance activity class.
#
# It owns the main application window, and all the various toolbars and options.
# Screens are stored in a stack, with the currently active screen on top.
class Finance(sugar.activity.activity.Activity):
def __init__ (self, handle):
sugar.activity.activity.Activity.__init__(self, handle)
self.set_title(_("Finance"))
# Initialize database.
# data
# next_id
# transactions
# id, name, type, amount, date, category
# budgets
# category, period, amount, budget
self.data = {
'next_id': 0,
'transactions': [],
'budgets': {}
}
self.transaction_map = {}
self.visible_transactions = []
self.transaction_names = {}
self.category_names = {}
#self.create_test_data()
# Initialize view period to the first of the month.
self.period = _('Month')
self.period_start = self.get_this_period()
# Create screens.
self.register = registerscreen.RegisterScreen(self)
self.chart = chartscreen.ChartScreen(self)
self.budget = budgetscreen.BudgetScreen(self)
self.build_toolbox()
self.screens = []
self.screenbox = gtk.VBox()
# Add the context sensitive help.
self.helplabel = gtk.Label()
self.helplabel.set_padding(10, 10)
self.helpbox = gtk.EventBox()
self.helpbox.modify_bg(gtk.STATE_NORMAL, self.helpbox.get_colormap().alloc_color('#000000'))
self.helpbox.add(self.helplabel)
# Add the header.
self.periodlabel = gtk.Label()
self.periodlabel.set_padding(10, 0)
headerbox = gtk.HBox()
headerbox.pack_end(self.periodlabel, False, False)
# Add the summary data.
self.startlabel = gtk.Label()
self.creditslabel = gtk.Label()
self.debitslabel = gtk.Label()
self.balancelabel = gtk.Label()
summarybox = gtk.HBox()
summarybox.pack_start(self.startlabel, True, False)
summarybox.pack_start(self.creditslabel, True, False)
summarybox.pack_start(self.debitslabel, True, False)
summarybox.pack_start(self.balancelabel, True, False)
vbox = gtk.VBox()
vbox.pack_start(self.helpbox, False, False, 10)
vbox.pack_start(headerbox, False, False, 10)
vbox.pack_start(gtk.HSeparator(), False, False, 0)
vbox.pack_start(self.screenbox, True, True, 0)
vbox.pack_start(summarybox, False, False, 10)
# Start with the main screen.
self.push_screen(self.register)
# This has to happen last, because it calls the read_file method when restoring from the Journal.
self.set_canvas(vbox)
self.show_all()
if OLD_TOOLBAR:
# Hide the sharing button from the activity toolbar since
# we don't support it.
activity_toolbar = self.tbox.get_activity_toolbar()
activity_toolbar.share.props.visible = False
def build_toolbox(self):
self.newcreditbtn = ToolButton('row-insert-credit')
self.newcreditbtn.set_tooltip(_("New Credit"))
self.newcreditbtn.props.accelerator = 'A'
self.newcreditbtn.connect('clicked', self.register.newcredit_cb)
self.newdebitbtn = ToolButton('row-insert-debit')
self.newdebitbtn.set_tooltip(_("New Debit"))
self.newdebitbtn.props.accelerator = 'D'
self.newdebitbtn.connect('clicked', self.register.newdebit_cb)
self.eraseitembtn = ToolButton('row-remove-transaction')
self.eraseitembtn.set_tooltip(_("Erase Transaction"))
self.eraseitembtn.props.accelerator = 'E'
self.eraseitembtn.connect('clicked', self.register.eraseitem_cb)
transactionbar = gtk.Toolbar()
transactionbar.insert(self.newcreditbtn, -1)
transactionbar.insert(self.newdebitbtn, -1)
transactionbar.insert(self.eraseitembtn, -1)
self.thisperiodbtn = ToolButton('go-down')
self.thisperiodbtn.props.accelerator = 'Down'
self.thisperiodbtn.connect('clicked', self.thisperiod_cb)
self.prevperiodbtn = ToolButton('go-previous-paired')
self.prevperiodbtn.props.accelerator = 'Left'
self.prevperiodbtn.connect('clicked', self.prevperiod_cb)
self.nextperiodbtn = ToolButton('go-next-paired')
self.nextperiodbtn.props.accelerator = 'Right'
self.nextperiodbtn.connect('clicked', self.nextperiod_cb)
periodsep = gtk.SeparatorToolItem()
periodsep.set_expand(True)
periodsep.set_draw(False)
periodlabel = gtk.Label(_('Period: '))
periodlabelitem = gtk.ToolItem()
periodlabelitem.add(periodlabel)
periodcombo = gtk.combo_box_new_text()
periodcombo.append_text(_('Day'))
periodcombo.append_text(_('Week'))
periodcombo.append_text(_('Month'))
periodcombo.append_text(_('Year'))
periodcombo.append_text(_('Forever'))
periodcombo.set_active(2)
periodcombo.connect('changed', self.period_changed_cb)
perioditem = ToolComboBox(periodcombo)
view_tool_group = None
registerbtn = RadioToolButton()
registerbtn.props.icon_name = 'view-list'
registerbtn.props.label = _('Register')
registerbtn.set_tooltip(_("Register"))
registerbtn.props.group = view_tool_group
view_tool_group = registerbtn
registerbtn.props.accelerator = '1'
registerbtn.connect('clicked', self.register_cb)
budgetbtn = RadioToolButton()
budgetbtn.props.icon_name = 'budget'
budgetbtn.props.label = _('Budget')
budgetbtn.set_tooltip(_("Budget"))
budgetbtn.props.group = view_tool_group
budgetbtn.props.accelerator = '2'
budgetbtn.connect('clicked', self.budget_cb)
chartbtn = RadioToolButton()
chartbtn.props.icon_name = 'chart'
chartbtn.props.label = _('Chart')
chartbtn.set_tooltip(_("Chart"))
chartbtn.props.group = view_tool_group
chartbtn.props.accelerator = '3'
chartbtn.connect('clicked', self.chart_cb)
viewbar = gtk.Toolbar()
viewbar.insert(registerbtn, -1)
viewbar.insert(budgetbtn, -1)
viewbar.insert(chartbtn, -1)
helpbtn = ToggleToolButton('help')
helpbtn.set_active(True)
helpbtn.set_tooltip(_("Show Help"))
helpbtn.connect('clicked', self.help_cb)
if OLD_TOOLBAR:
periodbar = gtk.Toolbar()
periodbar.insert(self.prevperiodbtn, -1)
periodbar.insert(self.nextperiodbtn, -1)
periodbar.insert(self.thisperiodbtn, -1)
periodbar.insert(periodsep, -1)
periodbar.insert(periodlabelitem, -1)
periodbar.insert(perioditem, -1)
self.tbox = sugar.activity.activity.ActivityToolbox(self)
self.tbox.add_toolbar(_('Transaction'), transactionbar)
self.tbox.add_toolbar(_('Period'), periodbar)
self.tbox.add_toolbar(_('View'), viewbar)
self.tbox.show_all()
# Add help button in place of share:
activity_toolbar = self.tbox.get_activity_toolbar()
share_idx = activity_toolbar.get_item_index(activity_toolbar.share)
activity_toolbar.insert(helpbtn, share_idx)
helpbtn.show_all()
self.set_toolbox(self.tbox)
else:
self.toolbar_box = ToolbarBox()
activity_button = ActivityToolbarButton(self)
self.toolbar_box.toolbar.insert(activity_button, 0)
activity_button.show()
transaction_toolbar_button = ToolbarButton(
page=transactionbar,
icon_name='transaction')
transactionbar.show_all()
view_toolbar_button = ToolbarButton(
page=viewbar,
icon_name='toolbar-view')
viewbar.show_all()
self.toolbar_box.toolbar.insert(transaction_toolbar_button, -1)
transaction_toolbar_button.show()
self.toolbar_box.toolbar.view = view_toolbar_button
self.toolbar_box.toolbar.insert(view_toolbar_button, -1)
view_toolbar_button.show()
separator = gtk.SeparatorToolItem()
separator.set_draw(True)
self.toolbar_box.toolbar.insert(separator, -1)
self.toolbar_box.toolbar.insert(periodlabelitem, -1)
self.toolbar_box.toolbar.insert(perioditem, -1)
self.toolbar_box.toolbar.insert(self.prevperiodbtn, -1)
self.toolbar_box.toolbar.insert(self.nextperiodbtn, -1)
self.toolbar_box.toolbar.insert(self.thisperiodbtn, -1)
separator = gtk.SeparatorToolItem()
separator.props.draw = False
separator.set_expand(True)
self.toolbar_box.toolbar.insert(separator, -1)
self.toolbar_box.toolbar.insert(helpbtn, -1)
self.toolbar_box.toolbar.insert(StopButton(self), -1)
self.set_toolbar_box(self.toolbar_box)
self.toolbar_box.show_all()
def set_help(self, text):
if self.helplabel != None:
self.helplabel.set_markup('' + text + '')
def help_cb(self, widget):
if widget.get_active():
self.helpbox.show()
else:
self.helpbox.hide()
def register_cb(self, widget):
self.pop_screen()
self.push_screen(self.register)
def budget_cb(self, widget):
self.pop_screen()
self.push_screen(self.budget)
def chart_cb(self, widget):
self.pop_screen()
self.push_screen(self.chart)
def push_screen(self, screen):
if len(self.screens):
self.screenbox.remove(self.screens[-1])
self.screenbox.pack_start(screen, True, True)
self.screens.append(screen)
self.build_screen()
def pop_screen(self):
self.screenbox.remove(self.screens[-1])
self.screens.pop()
if len(self.screens):
self.screenbox.pack_start(self.screens[-1])
def build_screen(self):
self.build_visible_transactions()
if len(self.screens):
self.screens[-1].build()
self.update_header()
self.update_summary()
self.update_toolbar()
def update_header(self):
if self.period == _('Day'):
text = self.period_start.strftime("%B %d, %Y")
elif self.period == _('Week'):
text = _('Week of') + self.period_start.strftime(" %B %d, %Y")
elif self.period == _('Month'):
text = self.period_start.strftime("%B, %Y")
elif self.period == _('Year'):
text = self.period_start.strftime("%Y")
elif self.period == _('Forever'):
text = _('Forever')
self.periodlabel.set_markup("" + text + "")
def update_summary(self):
# Calculate starting balance.
start = 0.0
for t in self.data['transactions']:
d = t['date']
if d < self.period_start.toordinal():
if t['type'] == 'credit':
start += t['amount']
else:
start -= t['amount']
# Calculate totals for this period.
credit_count = 0
credit_total = 0.0
debit_count = 0
debit_total = 0.0
total = start
for t in self.visible_transactions:
if t['type'] == 'credit':
credit_count += 1
credit_total += t['amount']
total += t['amount']
else:
debit_count += 1
debit_total += t['amount']
total -= t['amount']
# Update Balance.
if total >= 0.0:
balancecolor = '#4040ff'
else:
balancecolor = '#ff4040'
balance = "" % balancecolor
balance += _('Balance: ') + locale.currency(total)
balance += ""
self.balancelabel.set_markup(balance)
self.startlabel.set_markup('Starting Balance: ' + locale.currency(start))
self.creditslabel.set_markup('%s in %d credits' % (locale.currency(credit_total), credit_count))
self.debitslabel.set_markup('%s in %d debits' % (locale.currency(debit_total), debit_count))
def update_toolbar(self):
# Disable the navigation when Forever is selected.
next_prev = self.period != _('Forever')
self.prevperiodbtn.set_sensitive(next_prev)
self.thisperiodbtn.set_sensitive(next_prev)
self.nextperiodbtn.set_sensitive(next_prev)
# Update the label self.period to reflect the period.
self.prevperiodbtn.set_tooltip(_('Previous') + ' ' + self.period)
self.thisperiodbtn.set_tooltip(_('This') + ' ' + self.period)
self.nextperiodbtn.set_tooltip(_('Next') + ' ' + self.period)
# Only add and delete transactions on register screen.
add_del = self.screens[-1] == self.register
self.newcreditbtn.set_sensitive(add_del)
self.newdebitbtn.set_sensitive(add_del)
self.eraseitembtn.set_sensitive(add_del)
def get_this_period(self):
today = datetime.date.today()
if self.period == _('Day'):
return today
elif self.period == _('Week'):
while today.weekday() != 0:
today -= datetime.timedelta(days=1)
return today
elif self.period == _('Month'):
return datetime.date(today.year, today.month, 1)
elif self.period == _('Year'):
return datetime.date(today.year, 1, 1)
elif self.period == _('Forever'):
return datetime.date(1900, 1, 1)
def get_next_period(self, start):
if self.period == _('Day'):
return start + datetime.timedelta(days=1)
elif self.period == _('Week'):
return start + datetime.timedelta(days=7)
elif self.period == _('Month'):
if start.month == 12:
return datetime.date(start.year+1, 1, 1)
else:
return datetime.date(start.year, start.month+1, 1)
elif self.period == _('Year'):
return datetime.date(start.year+1, 1, 1)
def get_prev_period(self, start):
if self.period == _('Day'):
return start - datetime.timedelta(days=1)
elif self.period == _('Week'):
return start - datetime.timedelta(days=7)
elif self.period == _('Month'):
if start.month == 1:
return datetime.date(start.year-1, 12, 1)
else:
return datetime.date(start.year, start.month-1, 1)
elif self.period == _('Year'):
return datetime.date(start.year-1, 1, 1)
def thisperiod_cb(self, widget):
if self.period != _('Forever'):
self.period_start = self.get_this_period()
self.build_screen()
def nextperiod_cb(self, widget):
if self.period != _('Forever'):
self.period_start = self.get_next_period(self.period_start)
self.build_screen()
def prevperiod_cb(self, widget):
if self.period != _('Forever'):
self.period_start = self.get_prev_period(self.period_start)
self.build_screen()
def period_changed_cb(self, widget):
self.period = widget.get_active_text()
self.update_toolbar()
# Jump to 'this period'.
self.period_start = self.get_this_period()
self.build_screen()
def build_visible_transactions(self):
if self.period == _('Forever'):
self.visible_transactions = self.data['transactions']
else:
period_start_ord = self.period_start.toordinal()
period_end_ord = self.get_next_period(self.period_start).toordinal()
self.visible_transactions = []
for t in self.data['transactions']:
d = t['date']
if d >= period_start_ord and d < period_end_ord:
self.visible_transactions.append(t)
self.visible_transactions.sort(lambda a,b: a['date'] - b['date'])
def build_transaction_map(self):
self.transaction_map = {}
for t in self.data['transactions']:
self.transaction_map[t['id']] = t
def create_transaction(self, name='', type='debit', amount=0, category='', date=datetime.date.today()):
id = self.data['next_id']
self.data['next_id'] += 1
t = {
'id': id,
'name': name,
'type': type,
'amount': amount,
'date': date.toordinal(),
'category': category
}
self.data['transactions'].append(t)
self.transaction_map[id] = t
self.build_visible_transactions()
return id
def destroy_transaction(self, id):
t = self.transaction_map[id]
self.data['transactions'].remove(t)
del self.transaction_map[id]
def build_names(self):
self.transaction_names = {}
self.category_names = {}
for t in self.data['transactions']:
self.transaction_names[t['name']] = 1
self.category_names[t['category']] = 1
def create_test_data(self):
cur_date = datetime.date.today()
cur_date = datetime.date(cur_date.year, cur_date.month, 1)
self.create_transaction('Initial Balance', type='credit', amount=632, category='Initial Balance', date=cur_date)
cur_date += datetime.timedelta(days=1)
self.create_transaction('Fix Car', amount=75.84, category='Transportation', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Adopt Cat', amount=100, category='Pets', date=cur_date)
self.create_transaction('New Coat', amount=25.53, category='Clothing', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Pay Rent', amount=500, category='Housing', date=cur_date)
cur_date += datetime.timedelta(days=1)
self.create_transaction('Funky Cafe', amount=5.20, category='Food', date=cur_date)
self.create_transaction('Groceries', amount=50.92, category='Food', date=cur_date)
self.create_transaction('Cat Food', amount=5.40, category='Pets', date=cur_date)
cur_date += datetime.timedelta(days=4)
self.create_transaction('Paycheck', type='credit', amount=700, category='Paycheck', date=cur_date)
self.create_transaction('Gas', amount=21.20, category='Transportation', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Cat Toys', amount=10.95, category='Pets', date=cur_date)
self.create_transaction('Gift for Sister', amount=23.20, category='Gifts', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Pay Rent', amount=500, category='Housing', date=cur_date)
cur_date += datetime.timedelta(days=1)
self.create_transaction('Funky Cafe', amount=5.20, category='Food', date=cur_date)
self.create_transaction('Groceries', amount=50.92, category='Food', date=cur_date)
self.create_transaction('Cat Food', amount=5.40, category='Pets', date=cur_date)
cur_date += datetime.timedelta(days=4)
self.create_transaction('Paycheck', type='credit', amount=700, category='Paycheck', date=cur_date)
self.create_transaction('Gas', amount=21.20, category='Transportation', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Cat Toys', amount=10.95, category='Pets', date=cur_date)
self.create_transaction('Gift for Sister', amount=23.20, category='Gifts', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Pay Rent', amount=500, category='Housing', date=cur_date)
cur_date += datetime.timedelta(days=1)
self.create_transaction('Funky Cafe', amount=5.20, category='Food', date=cur_date)
self.create_transaction('Groceries', amount=50.92, category='Food', date=cur_date)
self.create_transaction('Cat Food', amount=5.40, category='Pets', date=cur_date)
cur_date += datetime.timedelta(days=4)
self.create_transaction('Paycheck', type='credit', amount=700, category='Paycheck', date=cur_date)
self.create_transaction('Gas', amount=21.20, category='Transportation', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Cat Toys', amount=10.95, category='Pets', date=cur_date)
self.create_transaction('Gift for Sister', amount=23.20, category='Gifts', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Pay Rent', amount=500, category='Housing', date=cur_date)
cur_date += datetime.timedelta(days=1)
self.create_transaction('Funky Cafe', amount=5.20, category='Food', date=cur_date)
self.create_transaction('Groceries', amount=50.92, category='Food', date=cur_date)
self.create_transaction('Cat Food', amount=5.40, category='Pets', date=cur_date)
cur_date += datetime.timedelta(days=4)
self.create_transaction('Paycheck', type='credit', amount=700, category='Paycheck', date=cur_date)
self.create_transaction('Gas', amount=21.20, category='Transportation', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Cat Toys', amount=10.95, category='Pets', date=cur_date)
self.create_transaction('Gift for Sister', amount=23.20, category='Gifts', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Pay Rent', amount=500, category='Housing', date=cur_date)
cur_date += datetime.timedelta(days=1)
self.create_transaction('Funky Cafe', amount=5.20, category='Food', date=cur_date)
self.create_transaction('Groceries', amount=50.92, category='Food', date=cur_date)
self.create_transaction('Cat Food', amount=5.40, category='Pets', date=cur_date)
cur_date += datetime.timedelta(days=4)
self.create_transaction('Paycheck', type='credit', amount=700, category='Paycheck', date=cur_date)
self.create_transaction('Gas', amount=21.20, category='Transportation', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Cat Toys', amount=10.95, category='Pets', date=cur_date)
self.create_transaction('Gift for Sister', amount=23.20, category='Gifts', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Pay Rent', amount=500, category='Housing', date=cur_date)
cur_date += datetime.timedelta(days=1)
self.create_transaction('Funky Cafe', amount=5.20, category='Food', date=cur_date)
self.create_transaction('Groceries', amount=50.92, category='Food', date=cur_date)
self.create_transaction('Cat Food', amount=5.40, category='Pets', date=cur_date)
cur_date += datetime.timedelta(days=4)
self.create_transaction('Paycheck', type='credit', amount=700, category='Paycheck', date=cur_date)
self.create_transaction('Gas', amount=21.20, category='Transportation', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Cat Toys', amount=10.95, category='Pets', date=cur_date)
self.create_transaction('Gift for Sister', amount=23.20, category='Gifts', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Pay Rent', amount=500, category='Housing', date=cur_date)
cur_date += datetime.timedelta(days=1)
self.create_transaction('Funky Cafe', amount=5.20, category='Food', date=cur_date)
self.create_transaction('Groceries', amount=50.92, category='Food', date=cur_date)
self.create_transaction('Cat Food', amount=5.40, category='Pets', date=cur_date)
cur_date += datetime.timedelta(days=4)
self.create_transaction('Paycheck', type='credit', amount=700, category='Paycheck', date=cur_date)
self.create_transaction('Gas', amount=21.20, category='Transportation', date=cur_date)
cur_date += datetime.timedelta(days=2)
self.create_transaction('Cat Toys', amount=10.95, category='Pets', date=cur_date)
self.create_transaction('Gift for Sister', amount=23.20, category='Gifts', date=cur_date)
self.build_transaction_map()
self.build_names()
def read_file(self, file_path):
if self.metadata['mime_type'] != 'text/plain':
return
fd = open(file_path, 'r')
try:
text = fd.read()
self.data = json.loads(text)
finally:
fd.close()
self.build_transaction_map()
self.build_names()
self.build_screen()
def write_file(self, file_path):
if not self.metadata['mime_type']:
self.metadata['mime_type'] = 'text/plain'
fd = open(file_path, 'w')
try:
text = json.dumps(self.data)
fd.write(text)
finally:
fd.close()