Merge lp:~samd/wxbanker/per-account-currencies into lp:wxbanker

Proposed by Michael Rooney
Status: Merged
Merged at revision: 869
Proposed branch: lp:~samd/wxbanker/per-account-currencies
Merge into: lp:wxbanker
Diff against target: 850 lines (+260/-56)
13 files modified
wxbanker/accountconfigdialog.py (+45/-0)
wxbanker/accountlistctrl.py (+17/-2)
wxbanker/bankobjects/account.py (+13/-3)
wxbanker/bankobjects/accountlist.py (+8/-2)
wxbanker/bankobjects/bankmodel.py (+23/-14)
wxbanker/bankobjects/transaction.py (+9/-1)
wxbanker/controller.py (+18/-0)
wxbanker/currencies.py (+4/-1)
wxbanker/data/exchanges.xml (+3/-3)
wxbanker/menubar.py (+19/-3)
wxbanker/persistentstore.py (+18/-6)
wxbanker/plots/cairopanel.py (+28/-3)
wxbanker/transactionolv.py (+55/-18)
To merge this branch: bzr merge lp:~samd/wxbanker/per-account-currencies
Reviewer Review Type Date Requested Status
Michael Rooney Needs Information
Review via email: mp+108499@code.launchpad.net

Description of the change

I'm going to propose a merge for easier discussion and change review!

To post a comment you must log in.
Revision history for this message
Michael Rooney (mrooney) wrote :

Thanks for this awesome code, overall it looks pretty great! A few comments:

* it would be great to remove usages of "from wxbanker.currconvert import *", for an easier to follow namespace. If you don't want to have to type the full path each time, you could use "from wxbanker import currconvert" and then use it that way.
* is it no longer using Account.Balance, but the GetCurrentBalance function? I'm just wondering if this defeats the point of caching this value and now has to add up all transactions for all accounts to display the totals. If so, maybe it could just convert the cached .Balance attribute, but if I'm misunderstanding, let me know.
* it would be great to add a few tests (there are bunch located at wxbanker/tests/ including UI tests)! I think I did a bad job at documenting how to run them so I'll attempt to get them running with nose and a simple "setup.py test" or something.
* regarding your exchanges.xml question, the idea was the ship each version with an up-to-date (at the time) version for offline use, but on startup grab the latest data if online (from http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml) and write it back to exchanges.xml. I can help implement this feature if you'd like.

review: Needs Information
849. By Sam Dieck

Reduced import scopes for easier to follow namespace.

Revision history for this message
Sam Dieck (samd) wrote :

* Namespaces are now corrected and not using * when importing.

* About the use of the .Balance attribute, i think that the code in question is the following:

            def GetBalance(self):
    208 - return sum([account.Balance for account in self])
    209 + totalCurrency = self.Store.getGlobalCurrency()
    210 + total = 0
    211 + for account in self:
    212 + total = total + account.GetCurrentBalance(totalCurrency)
    213 + return total

  Here are my thoughts on this code, and hopefully you could clarify me on this. From what I see in the function "GetCurrentBalance" the attribute ".Balance" contains even future transactions, and that's the difference between using "GetCurrentBalance and the attribute "Balance" (actually, even GetCurrentBalance() makes use of .Balance) ; do we want to include future transactions on total balances? even if those transactions have not been made? If that's the case, its just matter of creating a new function ".GetBalance(currency)" in the account class which returns the ".Balance" property converted to the desired currency without substracting future transactions (as GetCurrentBalance() does).

* I would be more than happy to run/add more tests, is there anything i need to know before going into that?

* Alright, i got ya on the exchanges.xml, ill start implementing it and tell you if i run into any problems and need help. Dont you think that it'll be better to add a "currency rates settings" where you can see current rates, click on an "update" button to update current rates, and possibly add an option for "check for currency updates automatically on startup" as i don't think that blindly pulling things from the internet without even a notification to the user is a good idea.

Revision history for this message
Michael Rooney (mrooney) wrote :
Download full text (4.0 KiB)

Thanks again Sam for all this awesome code, sorry for the delay! I've
merged this and made my first pass of changes at
http://bazaar.launchpad.net/~wxbanker-devs/wxbanker/trunk/revision/870.
Mostly minor changes, except that I made "Show currency names" non-default,
otherwise that would be a big change for everyone upgrading and it wouldn't
be useful for most people using only one currency.

As you mentioned, one of your changes does change the balances to be as of
today and not total including future as they were, and since that's kind of
an unrelated change (but something I do want to improve), I'll keep it
showing the grand total for now.

A few questions for you:

   1. Now the Currency menu drop-down just changes the global currency,
   where as before it changed them all. I'm wondering if this behavior will be
   immediately understandable, or if we should prompt when you change it
   asking if you want to change the global currency, the currency for all
   accounts (since that is what it used to do and changing them all
   individually would be a pain), or the currency for the current account.
   2. What do you think should happen for new accounts? Should they be the
   localized currency by default, or the global currency?
   3. If you are able to add some tests, it would be really helpful to make
   sure all these cases going forward. Particularly, tests that handle the
   rendering with nicknames, and making sure the total balance is handled
   correctly, and such. You can run them via "python -m
   wxbanker/tests/alltests" (I think a few translation tests will fail without
   certain language packs, you can ignore those or I can let you know which
   packs are required).

Thanks again. I'm going to do a performance review (there does seem to be a
big performance regression in startup time so I need to figure that one
out), and make a few tweaks, and figure out the best way to update the
exchanges.xml, then we can release 0.9!

On Thu, Jun 7, 2012 at 12:06 AM, Sam Dieck <email address hidden> wrote:

> * Namespaces are now corrected and not using * when importing.
>
> * About the use of the .Balance attribute, i think that the code in
> question is the following:
>
> def GetBalance(self):
> 208 - return sum([account.Balance for account in self])
> 209 + totalCurrency = self.Store.getGlobalCurrency()
> 210 + total = 0
> 211 + for account in self:
> 212 + total = total +
> account.GetCurrentBalance(totalCurrency)
> 213 + return total
>
> Here are my thoughts on this code, and hopefully you could clarify me on
> this. From what I see in the function "GetCurrentBalance" the attribute
> ".Balance" contains even future transactions, and that's the difference
> between using "GetCurrentBalance and the attribute "Balance" (actually,
> even GetCurrentBalance() makes use of .Balance) ; do we want to include
> future transactions on total balances? even if those transactions have not
> been made? If that's the case, its just matter of creating a new function
> ".GetBalance(currency)" in the account class which returns the ".Balance"
> property converted to the ...

Read more...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'wxbanker/accountconfigdialog.py'
--- wxbanker/accountconfigdialog.py 2010-08-09 00:31:45 +0000
+++ wxbanker/accountconfigdialog.py 2012-06-07 03:50:23 +0000
@@ -19,6 +19,7 @@
19import wx19import wx
20from wx.lib.pubsub import Publisher20from wx.lib.pubsub import Publisher
21from wxbanker.transactionctrl import TransactionCtrl21from wxbanker.transactionctrl import TransactionCtrl
22from wxbanker.currencies import CurrencyStrings, GetCurrencyInt
2223
23from wxbanker.mint.api import Mint24from wxbanker.mint.api import Mint
24try:25try:
@@ -238,7 +239,49 @@
238 def onTransactionChoice(self, event):239 def onTransactionChoice(self, event):
239 transaction = self.GetCurrentRecurringTransaction()240 transaction = self.GetCurrentRecurringTransaction()
240 self.transactionCtrl.FromRecurring(transaction)241 self.transactionCtrl.FromRecurring(transaction)
242
243class CurrencyConfigPanel(wx.Panel):
244 def __init__(self, parent, account):
245 self.Account = account
246 wx.Panel.__init__(self, parent)
247 self.headerText = wx.StaticText(self, -1, _("Account currency: "))
248
249 saveButton = wx.Button(self, label=_("Save"), id=wx.ID_SAVE)
250 closeButton = wx.Button(self, label=_("Cancel"), id=wx.ID_CLOSE)
251
252 buttonSizer = wx.BoxSizer()
253 buttonSizer.Add(saveButton)
254 buttonSizer.AddSpacer(12)
255 buttonSizer.Add(closeButton)
256 buttonSizer.AddSpacer(6)
257
258 #base currency = global currency
259 currencies = ["Base currency"] + CurrencyStrings
260 self.currencyCombo = wx.Choice(self, choices=currencies)
261 # we have to add 1 to the current indext because we added the "base currency" entry
262 self.currencyCombo.SetSelection(GetCurrencyInt(self.Account.GetCurrency())+1)
241263
264 self.Sizer = wx.BoxSizer(wx.VERTICAL)
265 self.Sizer.AddSpacer(6)
266 self.Sizer.Add(self.headerText, 0, wx.LEFT, 6)
267 self.Sizer.AddSpacer(6)
268 self.Sizer.Add(self.currencyCombo, 0, wx.LEFT, 6)
269 self.Sizer.AddStretchSpacer(1)
270 self.Sizer.Add(buttonSizer, flag=wx.ALIGN_RIGHT)
271 self.Sizer.AddSpacer(6)
272 self.Bind(wx.EVT_BUTTON, self.onButton)
273
274 def onButton(self, event):
275 """If the save button was clicked save, and close the dialog in any case (Close/Cancel/Save)."""
276 assert event.Id in (wx.ID_CLOSE, wx.ID_SAVE)
277
278 if event.Id == wx.ID_SAVE:
279 #we have to substract 1 from combo_box selection because we added the "base currency" entry
280 selectedCurrency = self.currencyCombo.GetSelection() - 1
281 Publisher.sendMessage("user.account_currency_changed", (self.Account, selectedCurrency))
282
283 self.GrandParent.Destroy()
284
242class AccountConfigDialog(wx.Dialog):285class AccountConfigDialog(wx.Dialog):
243 def __init__(self, parent, account, tab="default"):286 def __init__(self, parent, account, tab="default"):
244 wx.Dialog.__init__(self, parent, title=account.Name, size=(600, 400))287 wx.Dialog.__init__(self, parent, title=account.Name, size=(600, 400))
@@ -248,8 +291,10 @@
248 291
249 self.recurringPanel = RecurringConfigPanel(self.notebook, account)292 self.recurringPanel = RecurringConfigPanel(self.notebook, account)
250 self.mintPanel = MintConfigPanel(self.notebook, account)293 self.mintPanel = MintConfigPanel(self.notebook, account)
294 self.currencyPanel = CurrencyConfigPanel(self.notebook, account)
251 self.notebook.AddPage(self.recurringPanel, _("Recurring Transactions"))295 self.notebook.AddPage(self.recurringPanel, _("Recurring Transactions"))
252 self.notebook.AddPage(self.mintPanel, _("Mint.com Integration"))296 self.notebook.AddPage(self.mintPanel, _("Mint.com Integration"))
297 self.notebook.AddPage(self.currencyPanel, _("Currency Settings"))
253 298
254 if tab == "mint":299 if tab == "mint":
255 # Setting the selection synchronously gets changed back somewhere in the event queue.300 # Setting the selection synchronously gets changed back somewhere in the event queue.
256301
=== modified file 'wxbanker/accountlistctrl.py'
--- wxbanker/accountlistctrl.py 2010-08-19 04:30:23 +0000
+++ wxbanker/accountlistctrl.py 2012-06-07 03:50:23 +0000
@@ -116,6 +116,7 @@
116 Publisher.subscribe(self.onAccountAdded, "account.created")116 Publisher.subscribe(self.onAccountAdded, "account.created")
117 Publisher.subscribe(self.onCurrencyChanged, "currency_changed")117 Publisher.subscribe(self.onCurrencyChanged, "currency_changed")
118 Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled")118 Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled")
119 Publisher.subscribe(self.onShowCurrencyNickToggled, "controller.show_currency_nick_toggled")
119 Publisher.subscribe(self.onAccountChanged, "user.account changed")120 Publisher.subscribe(self.onAccountChanged, "user.account changed")
120 Publisher.subscribe(self.onSelectNextAccount, "user.next account")121 Publisher.subscribe(self.onSelectNextAccount, "user.next account")
121 Publisher.subscribe(self.onSelectPreviousAccount, "user.previous account")122 Publisher.subscribe(self.onSelectPreviousAccount, "user.previous account")
@@ -165,7 +166,7 @@
165 mintCtrl.SetBitmap(wx.ArtProvider.GetBitmap("wxART_%s" % bitmapName))166 mintCtrl.SetBitmap(wx.ArtProvider.GetBitmap("wxART_%s" % bitmapName))
166 mintCtrl.SetToolTipString(tooltip)167 mintCtrl.SetToolTipString(tooltip)
167168
168 def onCurrencyChanged(self, message):169 def refreshBalances(self):
169 # Update all the accounts.170 # Update all the accounts.
170 for account, textCtrl in zip(self.accountObjects, self.totalTexts):171 for account, textCtrl in zip(self.accountObjects, self.totalTexts):
171 textCtrl.Label = account.float2str(account.Balance)172 textCtrl.Label = account.float2str(account.Balance)
@@ -173,6 +174,15 @@
173 self.updateGrandTotal()174 self.updateGrandTotal()
174 self.Parent.Layout()175 self.Parent.Layout()
175 176
177 def onCurrencyChanged(self, message):
178 self.refreshBalances()
179
180 def onShowCurrencyNickToggled(self, message):
181 val = message.data
182 for account in self.Model.Accounts:
183 account.ShowCurrencyNick = val
184 self.refreshBalances()
185
176 def onToggleMintIntegration(self, message):186 def onToggleMintIntegration(self, message):
177 enabled = message.data187 enabled = message.data
178 if enabled:188 if enabled:
@@ -326,6 +336,10 @@
326 break336 break
327 index += 1337 index += 1
328338
339 # Check if we should set account to show currency NIcks,
340 # wouldn't it be better to have per-account show-currency-nick setting?
341 account.ShowCurrencyNick = self.bankController.ShowCurrencyNick
342
329 self._InsertItem(index, account)343 self._InsertItem(index, account)
330344
331 if select:345 if select:
@@ -427,7 +441,8 @@
427 self._UpdateMintStatuses()441 self._UpdateMintStatuses()
428442
429 def updateGrandTotal(self):443 def updateGrandTotal(self):
430 self.totalText.Label = self.Model.float2str( self.Model.Balance )444 shownick = self.bankController.ShowCurrencyNick
445 self.totalText.Label = self.Model.float2str( self.Model.Balance, withNick=shownick )
431446
432 def onAddButton(self, event):447 def onAddButton(self, event):
433 self.showEditCtrl()448 self.showEditCtrl()
434449
=== modified file 'wxbanker/bankobjects/account.py'
--- wxbanker/bankobjects/account.py 2010-10-05 21:34:34 +0000
+++ wxbanker/bankobjects/account.py 2012-06-07 03:50:23 +0000
@@ -26,13 +26,16 @@
26from wxbanker import currencies, bankexceptions, debug26from wxbanker import currencies, bankexceptions, debug
27from wxbanker.mint.api import Mint27from wxbanker.mint.api import Mint
2828
29from wxbanker.currencies import CurrencyList
30from wxbanker.currconvert import CurrencyConverter
31
29import datetime32import datetime
3033
31class Account(ORMObject):34class Account(ORMObject):
32 ORM_TABLE = "accounts"35 ORM_TABLE = "accounts"
33 ORM_ATTRIBUTES = ["Name", "Balance", "MintId"]36 ORM_ATTRIBUTES = ["Name", "Balance", "MintId"]
34 37
35 def __init__(self, store, aID, name, currency=0, balance=0.0, mintId=None):38 def __init__(self, store, aID, name, currency=0, balance=0.0, mintId=None, currNick=False):
36 ORMObject.__init__(self)39 ORMObject.__init__(self)
37 self.IsFrozen = True40 self.IsFrozen = True
38 self.Store = store41 self.Store = store
@@ -45,6 +48,7 @@
45 self.Currency = currency or 048 self.Currency = currency or 0
46 self.Balance = balance or 0.049 self.Balance = balance or 0.0
47 self.MintId = mintId50 self.MintId = mintId
51 self.ShowCurrencyNick = currNick or False
48 self.IsFrozen = False52 self.IsFrozen = False
4953
50 Publisher.subscribe(self.onTransactionAmountChanged, "ormobject.updated.Transaction.Amount")54 Publisher.subscribe(self.onTransactionAmountChanged, "ormobject.updated.Transaction.Amount")
@@ -86,7 +90,7 @@
86 def GetCurrency(self):90 def GetCurrency(self):
87 return self._Currency91 return self._Currency
88 92
89 def GetCurrentBalance(self):93 def GetCurrentBalance(self, currency=None):
90 """Returns the balance up to and including today, but not transactions in the future."""94 """Returns the balance up to and including today, but not transactions in the future."""
91 currentBalance = self.Balance95 currentBalance = self.Balance
92 today = datetime.date.today()96 today = datetime.date.today()
@@ -96,6 +100,12 @@
96 while index >= 0 and transactions[index].Date > today:100 while index >= 0 and transactions[index].Date > today:
97 currentBalance -= transactions[index].Amount101 currentBalance -= transactions[index].Amount
98 index -= 1102 index -= 1
103
104 if currency:
105 conv = CurrencyConverter()
106 destCurrency = CurrencyList[currency]().GetCurrencyNick()
107 srcCurrency = self.GetCurrency().GetCurrencyNick()
108 return conv.Convert(currentBalance, srcCurrency, destCurrency)
99 return currentBalance109 return currentBalance
100 110
101 def GetRecurringTransactions(self):111 def GetRecurringTransactions(self):
@@ -329,7 +339,7 @@
329 debug.debug("Ignoring transaction because I am %s: %s" % (self.Name, transaction))339 debug.debug("Ignoring transaction because I am %s: %s" % (self.Name, transaction))
330340
331 def float2str(self, *args, **kwargs):341 def float2str(self, *args, **kwargs):
332 return self.Currency.float2str(*args, **kwargs)342 return self.Currency.float2str(withNick=self.ShowCurrencyNick, *args, **kwargs)
333343
334 def __cmp__(self, other):344 def __cmp__(self, other):
335 return cmp(self.Name, other.Name)345 return cmp(self.Name, other.Name)
336346
=== modified file 'wxbanker/bankobjects/accountlist.py'
--- wxbanker/bankobjects/accountlist.py 2010-08-09 00:31:45 +0000
+++ wxbanker/bankobjects/accountlist.py 2012-06-07 03:50:23 +0000
@@ -21,6 +21,7 @@
21from wx.lib.pubsub import Publisher21from wx.lib.pubsub import Publisher
22from wxbanker import bankexceptions22from wxbanker import bankexceptions
2323
24
24class AccountList(list):25class AccountList(list):
25 def __init__(self, store):26 def __init__(self, store):
26 list.__init__(self, store.GetAccounts())27 list.__init__(self, store.GetAccounts())
@@ -43,7 +44,11 @@
43 return allRecurrings44 return allRecurrings
4445
45 def GetBalance(self):46 def GetBalance(self):
46 return sum([account.Balance for account in self])47 totalCurrency = self.Store.getGlobalCurrency()
48 total = 0
49 for account in self:
50 total = total + account.GetCurrentBalance(totalCurrency)
51 return total
47 52
48 def GetById(self, theId):53 def GetById(self, theId):
49 for account in self:54 for account in self:
@@ -103,4 +108,5 @@
103 def onAccountRenamed(self, message):108 def onAccountRenamed(self, message):
104 self.sort()109 self.sort()
105110
106 Balance = property(GetBalance)
107\ No newline at end of file111\ No newline at end of file
112 Balance = property(GetBalance)
113
108114
=== modified file 'wxbanker/bankobjects/bankmodel.py'
--- wxbanker/bankobjects/bankmodel.py 2010-08-09 00:31:45 +0000
+++ wxbanker/bankobjects/bankmodel.py 2012-06-07 03:50:23 +0000
@@ -28,6 +28,8 @@
28from wxbanker.bankobjects.accountlist import AccountList28from wxbanker.bankobjects.accountlist import AccountList
29from wxbanker.mint.api import Mint29from wxbanker.mint.api import Mint
3030
31from wxbanker.currencies import GetCurrencyInt
32
31class BankModel(ORMKeyValueObject):33class BankModel(ORMKeyValueObject):
32 ORM_TABLE = "meta"34 ORM_TABLE = "meta"
33 ORM_ATTRIBUTES = ["LastAccountId", "MintEnabled"]35 ORM_ATTRIBUTES = ["LastAccountId", "MintEnabled"]
@@ -42,7 +44,8 @@
42 if self.MintEnabled:44 if self.MintEnabled:
43 delayedresult.startWorker(lambda result: Publisher.sendMessage("mint.updated"), Mint.LoginFromKeyring, wkwargs={"notify": False})45 delayedresult.startWorker(lambda result: Publisher.sendMessage("mint.updated"), Mint.LoginFromKeyring, wkwargs={"notify": False})
4446
45 Publisher.subscribe(self.onCurrencyChanged, "user.currency_changed")47 Publisher.subscribe(self.onGlobalCurrencyChanged, "user.global_currency_changed")
48 Publisher.subscribe(self.onAccountCurrencyChanged, "user.account_currency_changed")
46 Publisher.subscribe(self.onMintToggled, "user.mint.toggled")49 Publisher.subscribe(self.onMintToggled, "user.mint.toggled")
47 Publisher.subscribe(self.onAccountChanged, "view.account changed")50 Publisher.subscribe(self.onAccountChanged, "view.account changed")
48 Publisher.subscribe(self.onTransactionTagged, "transaction.tagged")51 Publisher.subscribe(self.onTransactionTagged, "transaction.tagged")
@@ -84,8 +87,10 @@
84 """87 """
85 if account is None:88 if account is None:
86 transactions = self.GetTransactions()89 transactions = self.GetTransactions()
90 currency = self.GlobalCurrency
87 else:91 else:
88 transactions = account.Transactions[:]92 transactions = account.Transactions[:]
93 currency = GetCurrencyInt(account.GetCurrency())
89 transactions.sort()94 transactions.sort()
90 95
91 if transactions == []:96 if transactions == []:
@@ -104,7 +109,7 @@
104 if t.Date > endDate:109 if t.Date > endDate:
105 endi = i110 endi = i
106 break111 break
107 total += t.Amount112 total += t.GetAmount(currency)
108 113
109 transactions = transactions[starti:endi]114 transactions = transactions[starti:endi]
110 else:115 else:
@@ -126,7 +131,7 @@
126 balance = startingBalance131 balance = startingBalance
127 while currDate <= endDate:132 while currDate <= endDate:
128 while tindex < len(transactions) and transactions[tindex].Date <= currDate:133 while tindex < len(transactions) and transactions[tindex].Date <= currDate:
129 balance += transactions[tindex].Amount134 balance += transactions[tindex].GetAmount(currency)
130 tindex += 1135 tindex += 1
131 totals.append([currDate, balance])136 totals.append([currDate, balance])
132 currDate += onedaydelta137 currDate += onedaydelta
@@ -167,23 +172,27 @@
167 Handle representing floats as strings for non172 Handle representing floats as strings for non
168 account-specific amounts, such as totals.173 account-specific amounts, such as totals.
169 """174 """
170 if len(self.Accounts) == 0:175 currencyID = self.Store.getGlobalCurrency()
171 currency = currencies.CurrencyList[0]()176 currency = currencies.CurrencyList[currencyID]()
172 else:
173 currency = self.Accounts[0].Currency
174
175 return currency.float2str(*args, **kwargs)177 return currency.float2str(*args, **kwargs)
176178
177 def setCurrency(self, currencyIndex):179 def setGlobalCurrency(self, currencyIndex):
178 self.Store.setCurrency(currencyIndex)180 self.Store.setCurrency(currencyIndex)
179 for account in self.Accounts:
180 account.Currency = currencyIndex
181 Publisher.sendMessage("currency_changed", currencyIndex)181 Publisher.sendMessage("currency_changed", currencyIndex)
182182
183 def onCurrencyChanged(self, message):183 def setAccountCurrency(self, account, currencyIndex):
184 self.Store.setCurrency(currencyIndex, account)
185 account.SetCurrency(currencyIndex)
186 Publisher.sendMessage("currency_changed", currencyIndex)
187
188 def onGlobalCurrencyChanged(self, message):
184 currencyIndex = message.data189 currencyIndex = message.data
185 self.setCurrency(currencyIndex)190 self.setGlobalCurrency(currencyIndex)
186 191
192 def onAccountCurrencyChanged(self, message):
193 account, currency = message.data
194 self.setAccountCurrency(account, currency)
195
187 def onAccountChanged(self, message):196 def onAccountChanged(self, message):
188 account = message.data197 account = message.data
189 if account:198 if account:
190199
=== modified file 'wxbanker/bankobjects/transaction.py'
--- wxbanker/bankobjects/transaction.py 2010-08-10 04:47:02 +0000
+++ wxbanker/bankobjects/transaction.py 2012-06-07 03:50:23 +0000
@@ -26,6 +26,9 @@
26from wxbanker.bankobjects.tag import Tag, EmptyTagException26from wxbanker.bankobjects.tag import Tag, EmptyTagException
27from wxbanker import debug27from wxbanker import debug
2828
29from wxbanker.currencies import CurrencyList
30from wxbanker.currconvert import CurrencyConverter
31
29class Transaction(ORMObject):32class Transaction(ORMObject):
30 """33 """
31 An object which represents a transaction.34 An object which represents a transaction.
@@ -152,7 +155,12 @@
152 def SetTags(self, tagList):155 def SetTags(self, tagList):
153 self._Tags = tagList156 self._Tags = tagList
154157
155 def GetAmount(self):158 def GetAmount(self, currency=None):
159 if currency:
160 conv = CurrencyConverter()
161 destCurrency = CurrencyList[currency]().GetCurrencyNick()
162 srcCurrency = self.Parent.GetCurrency().GetCurrencyNick()
163 return conv.Convert(self._Amount, srcCurrency, destCurrency)
156 return self._Amount164 return self._Amount
157165
158 def SetAmount(self, amount, fromLink=False):166 def SetAmount(self, amount, fromLink=False):
159167
=== modified file 'wxbanker/controller.py'
--- wxbanker/controller.py 2010-10-09 22:39:26 +0000
+++ wxbanker/controller.py 2012-06-07 03:50:23 +0000
@@ -29,6 +29,7 @@
29 def __init__(self, path=None):29 def __init__(self, path=None):
30 self._AutoSave = True30 self._AutoSave = True
31 self._ShowZeroBalanceAccounts = True31 self._ShowZeroBalanceAccounts = True
32 self._ShowCurrencyNick = True
32 self.Models = []33 self.Models = []
33 34
34 self.InitConfig()35 self.InitConfig()
@@ -36,6 +37,7 @@
3637
37 Publisher.subscribe(self.onAutoSaveToggled, "user.autosave_toggled")38 Publisher.subscribe(self.onAutoSaveToggled, "user.autosave_toggled")
38 Publisher.subscribe(self.onShowZeroToggled, "user.showzero_toggled")39 Publisher.subscribe(self.onShowZeroToggled, "user.showzero_toggled")
40 Publisher.subscribe(self.onShowCurrencyNickToggled, "user.show_currency_nick_toggled")
39 Publisher.subscribe(self.onSaveRequest, "user.saved")41 Publisher.subscribe(self.onSaveRequest, "user.saved")
40 42
41 def MigrateIfFound(self, fromPath, toPath):43 def MigrateIfFound(self, fromPath, toPath):
@@ -82,10 +84,13 @@
82 config.WriteBool("AUTO-SAVE", True)84 config.WriteBool("AUTO-SAVE", True)
83 if not config.HasEntry("HIDE_ZERO_BALANCE_ACCOUNTS"):85 if not config.HasEntry("HIDE_ZERO_BALANCE_ACCOUNTS"):
84 config.WriteBool("HIDE_ZERO_BALANCE_ACCOUNTS", False)86 config.WriteBool("HIDE_ZERO_BALANCE_ACCOUNTS", False)
87 if not config.HasEntry("SHOW_CURRENCY_NICK"):
88 config.WriteBool("SHOW_CURRENCY_NICK", True)
8589
86 # Set the auto-save option as appropriate.90 # Set the auto-save option as appropriate.
87 self.AutoSave = config.ReadBool("AUTO-SAVE")91 self.AutoSave = config.ReadBool("AUTO-SAVE")
88 self.ShowZeroBalanceAccounts = not config.ReadBool("HIDE_ZERO_BALANCE_ACCOUNTS")92 self.ShowZeroBalanceAccounts = not config.ReadBool("HIDE_ZERO_BALANCE_ACCOUNTS")
93 self.ShowCurrencyNick = config.ReadBool("SHOW_CURRENCY_NICK")
8994
90 def onAutoSaveToggled(self, message):95 def onAutoSaveToggled(self, message):
91 val = message.data96 val = message.data
@@ -95,6 +100,10 @@
95 val = message.data100 val = message.data
96 self.ShowZeroBalanceAccounts = val101 self.ShowZeroBalanceAccounts = val
97102
103 def onShowCurrencyNickToggled(self, message):
104 val = message.data
105 self.ShowCurrencyNick = val
106
98 def onSaveRequest(self, message):107 def onSaveRequest(self, message):
99 self.Model.Save()108 self.Model.Save()
100109
@@ -121,6 +130,14 @@
121 wx.Config.Get().WriteBool("HIDE_ZERO_BALANCE_ACCOUNTS", not val)130 wx.Config.Get().WriteBool("HIDE_ZERO_BALANCE_ACCOUNTS", not val)
122 Publisher.sendMessage("controller.showzero_toggled", val)131 Publisher.sendMessage("controller.showzero_toggled", val)
123132
133 def GetShowCurrencyNick(self):
134 return self._ShowCurrencyNick
135
136 def SetShowCurrencyNick(self, val):
137 self._ShowCurrencyNick = val
138 wx.Config.Get().WriteBool("SHOW_CURRENCY_NICK", val)
139 Publisher.sendMessage("controller.show_currency_nick_toggled", val)
140
124 def LoadPath(self, path, use=False):141 def LoadPath(self, path, use=False):
125 if path is None:142 if path is None:
126 path = fileservice.getDataFilePath(self.DB_NAME)143 path = fileservice.getDataFilePath(self.DB_NAME)
@@ -153,3 +170,4 @@
153170
154 AutoSave = property(GetAutoSave, SetAutoSave)171 AutoSave = property(GetAutoSave, SetAutoSave)
155 ShowZeroBalanceAccounts = property(GetShowZero, SetShowZero)172 ShowZeroBalanceAccounts = property(GetShowZero, SetShowZero)
173 ShowCurrencyNick = property(GetShowCurrencyNick, SetShowCurrencyNick)
156174
=== modified file 'wxbanker/currencies.py'
--- wxbanker/currencies.py 2010-08-09 00:31:45 +0000
+++ wxbanker/currencies.py 2012-06-07 03:50:23 +0000
@@ -69,7 +69,7 @@
69 def GetCurrencyNick(self):69 def GetCurrencyNick(self):
70 return self.LOCALECONV["int_curr_symbol"].strip()70 return self.LOCALECONV["int_curr_symbol"].strip()
7171
72 def float2str(self, val, just=0):72 def float2str(self, val, just=0, withNick=True):
73 """Formats float values as currency strings according to the currency settings in self.LOCALECONV"""73 """Formats float values as currency strings according to the currency settings in self.LOCALECONV"""
74 # Don't show negative zeroes!74 # Don't show negative zeroes!
75 if abs(val) < .001:75 if abs(val) < .001:
@@ -89,6 +89,9 @@
89 if not isinstance(s, unicode):89 if not isinstance(s, unicode):
90 s = unicode(s, locale.getlocale()[1])90 s = unicode(s, locale.getlocale()[1])
9191
92 if withNick:
93 s = self.GetCurrencyNick() + " " + s
94
92 # Justify as appropriate.95 # Justify as appropriate.
93 s = s.rjust(just)96 s = s.rjust(just)
9497
9598
=== modified file 'wxbanker/data/exchanges.xml'
--- wxbanker/data/exchanges.xml 2009-12-06 23:24:24 +0000
+++ wxbanker/data/exchanges.xml 2012-06-07 03:50:23 +0000
@@ -6,7 +6,7 @@
6 </gesmes:Sender>6 </gesmes:Sender>
7 <Cube>7 <Cube>
8 <Cube time='2009-02-25'>8 <Cube time='2009-02-25'>
9 <Cube currency='USD' rate='1.2795'/>9 <Cube currency='USD' rate='1.2489'/>
10 <Cube currency='JPY' rate='123.76'/>10 <Cube currency='JPY' rate='123.76'/>
11 <Cube currency='BGN' rate='1.9558'/>11 <Cube currency='BGN' rate='1.9558'/>
12 <Cube currency='CZK' rate='28.350'/>12 <Cube currency='CZK' rate='28.350'/>
@@ -32,7 +32,7 @@
32 <Cube currency='IDR' rate='15385.99'/>32 <Cube currency='IDR' rate='15385.99'/>
33 <Cube currency='INR' rate='63.7700'/>33 <Cube currency='INR' rate='63.7700'/>
34 <Cube currency='KRW' rate='1938.03'/>34 <Cube currency='KRW' rate='1938.03'/>
35 <Cube currency='MXN' rate='18.9687'/>35 <Cube currency='MXN' rate='17.3842235'/>
36 <Cube currency='MYR' rate='4.6951'/>36 <Cube currency='MYR' rate='4.6951'/>
37 <Cube currency='NZD' rate='2.4847'/>37 <Cube currency='NZD' rate='2.4847'/>
38 <Cube currency='PHP' rate='61.610'/>38 <Cube currency='PHP' rate='61.610'/>
@@ -41,4 +41,4 @@
41 <Cube currency='ZAR' rate='12.7223'/>41 <Cube currency='ZAR' rate='12.7223'/>
42 </Cube>42 </Cube>
43 </Cube>43 </Cube>
44</gesmes:Envelope>
45\ No newline at end of file44\ No newline at end of file
45</gesmes:Envelope>
4646
=== modified file 'wxbanker/menubar.py'
--- wxbanker/menubar.py 2010-08-19 04:27:51 +0000
+++ wxbanker/menubar.py 2012-06-07 03:50:23 +0000
@@ -39,6 +39,7 @@
39 ID_REQUESTFEATURE = wx.NewId()39 ID_REQUESTFEATURE = wx.NewId()
40 ID_TRANSLATE = wx.NewId()40 ID_TRANSLATE = wx.NewId()
41 IDS_CURRENCIES = [wx.NewId() for i in range(len(CurrencyStrings))]41 IDS_CURRENCIES = [wx.NewId() for i in range(len(CurrencyStrings))]
42 ID_SHOWCURRENCYNICK = wx.NewId()
42 ID_MINTINTEGRATION = wx.NewId()43 ID_MINTINTEGRATION = wx.NewId()
43 ID_REQUESTCURRENCY = wx.NewId()44 ID_REQUESTCURRENCY = wx.NewId()
44 ID_IMPORT_CSV = wx.NewId()45 ID_IMPORT_CSV = wx.NewId()
@@ -49,6 +50,7 @@
49 self.bankController = bankController50 self.bankController = bankController
50 autosave = bankController.AutoSave51 autosave = bankController.AutoSave
51 showZero = bankController.ShowZeroBalanceAccounts52 showZero = bankController.ShowZeroBalanceAccounts
53 showcurrnick = bankController.ShowCurrencyNick
52 self.currencyStrings = CurrencyStrings[:]54 self.currencyStrings = CurrencyStrings[:]
5355
54 # File menu.56 # File menu.
@@ -76,7 +78,7 @@
76 settingsMenu = wx.Menu()78 settingsMenu = wx.Menu()
7779
78 ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.80 ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
79 currencyMenu = wx.MenuItem(settingsMenu, -1, _("&Currency"), _("Select currency to display"))81 currencyMenu = wx.MenuItem(settingsMenu, -1, _("Base &Currency"), _("Select currency for the 'All accounts balance'"))
80 currencyMenu.SetBitmap(wx.ArtProvider.GetBitmap("wxART_money"))82 currencyMenu.SetBitmap(wx.ArtProvider.GetBitmap("wxART_money"))
8183
82 # Add an entry for each available currency.84 # Add an entry for each available currency.
@@ -97,6 +99,8 @@
9799
98 settingsMenu.AppendItem(currencyMenu)100 settingsMenu.AppendItem(currencyMenu)
99 101
102 self.showCurrencyNickItem = settingsMenu.AppendCheckItem(self.ID_SHOWCURRENCYNICK, _("Show currencies nick"), _("Show currencies nick before quantities"))
103
100 self.mintEnabledItem = settingsMenu.AppendCheckItem(self.ID_MINTINTEGRATION, _("Integrate with Mint.com"), _("Sync account balances with an existing Mint.com account"))104 self.mintEnabledItem = settingsMenu.AppendCheckItem(self.ID_MINTINTEGRATION, _("Integrate with Mint.com"), _("Sync account balances with an existing Mint.com account"))
101105
102 # Help menu.106 # Help menu.
@@ -142,8 +146,10 @@
142 helpMenu.Bind(wx.EVT_MENU, self.onClickAbout)146 helpMenu.Bind(wx.EVT_MENU, self.onClickAbout)
143147
144 self.toggleAutoSave(autosave)148 self.toggleAutoSave(autosave)
149 self.toggleShowCurrencyNick(showcurrnick)
145 Publisher.subscribe(self.onAutoSaveToggled, "controller.autosave_toggled")150 Publisher.subscribe(self.onAutoSaveToggled, "controller.autosave_toggled")
146 Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled")151 Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled")
152 Publisher.subscribe(self.onShowCurrencyNickToggled, "controller.show_currency_nick_toggled")
147 # Subscribe to a Mint update event, which tells us the checkbox should be enabled after startup.153 # Subscribe to a Mint update event, which tells us the checkbox should be enabled after startup.
148 Publisher.subscribe(self.onMintUpdate, "mint.updated")154 Publisher.subscribe(self.onMintUpdate, "mint.updated")
149155
@@ -170,6 +176,7 @@
170 self.ID_EXPORT_CSV: self.onClickExportCsv,176 self.ID_EXPORT_CSV: self.onClickExportCsv,
171 wx.ID_ABOUT: self.onClickAbout,177 wx.ID_ABOUT: self.onClickAbout,
172 self.ID_REQUESTCURRENCY: self.onClickRequestCurrency,178 self.ID_REQUESTCURRENCY: self.onClickRequestCurrency,
179 self.ID_SHOWCURRENCYNICK: self.onClickShowCurrencyNick,
173 self.ID_MINTINTEGRATION: self.onClickMintIntegration,180 self.ID_MINTINTEGRATION: self.onClickMintIntegration,
174 }.get(ID, lambda e: e.Skip())181 }.get(ID, lambda e: e.Skip())
175182
@@ -190,6 +197,12 @@
190 197
191 def toggleShowZero(self, showzero):198 def toggleShowZero(self, showzero):
192 self.showZeroMenuItem.Check(showzero)199 self.showZeroMenuItem.Check(showzero)
200
201 def onShowCurrencyNickToggled(self, message):
202 self.toggleShowCurrencyNick(message.data)
203
204 def toggleShowCurrencyNick(self, showcurr):
205 self.showCurrencyNickItem.Check(showcurr)
193 206
194 def toggleMintEnabled(self, enabled):207 def toggleMintEnabled(self, enabled):
195 self.mintEnabledItem.Check(enabled)208 self.mintEnabledItem.Check(enabled)
@@ -216,7 +229,7 @@
216 Publisher.sendMessage("quit")229 Publisher.sendMessage("quit")
217230
218 def onSelectCurrency(self, currencyIndex):231 def onSelectCurrency(self, currencyIndex):
219 Publisher.sendMessage("user.currency_changed", currencyIndex)232 Publisher.sendMessage("user.global_currency_changed", currencyIndex)
220233
221 def onClickFAQs(self, event):234 def onClickFAQs(self, event):
222 webbrowser.open("https://answers.launchpad.net/wxbanker/+faqs")235 webbrowser.open("https://answers.launchpad.net/wxbanker/+faqs")
@@ -236,6 +249,9 @@
236 def onClickRequestCurrency(self, event):249 def onClickRequestCurrency(self, event):
237 webbrowser.open("https://answers.launchpad.net/wxbanker/+faq/477")250 webbrowser.open("https://answers.launchpad.net/wxbanker/+faq/477")
238 251
252 def onClickShowCurrencyNick(self, event):
253 Publisher.sendMessage("user.show_currency_nick_toggled", event.Checked())
254
239 def onClickMintIntegration(self, event):255 def onClickMintIntegration(self, event):
240 Publisher.sendMessage("user.mint.toggled", event.Checked())256 Publisher.sendMessage("user.mint.toggled", event.Checked())
241257
@@ -278,4 +294,4 @@
278 if result == wx.ID_OK:294 if result == wx.ID_OK:
279 csvpath = dlg.GetPath()295 csvpath = dlg.GetPath()
280 CsvExporter.Export(self.bankController.Model, csvpath) 296 CsvExporter.Export(self.bankController.Model, csvpath)
281
282\ No newline at end of file297\ No newline at end of file
298
283299
=== modified file 'wxbanker/persistentstore.py'
--- wxbanker/persistentstore.py 2010-08-09 00:31:45 +0000
+++ wxbanker/persistentstore.py 2012-06-07 03:50:23 +0000
@@ -53,7 +53,7 @@
53 """53 """
54 def __init__(self, path, autoSave=True):54 def __init__(self, path, autoSave=True):
55 self.Subscriptions = []55 self.Subscriptions = []
56 self.Version = 1156 self.Version = 12
57 self.Path = path57 self.Path = path
58 self.AutoSave = False58 self.AutoSave = False
59 self.Dirty = False59 self.Dirty = False
@@ -209,6 +209,10 @@
209 cursor.execute('CREATE TABLE meta (id INTEGER PRIMARY KEY, name VARCHAR(255), value VARCHAR(255))')209 cursor.execute('CREATE TABLE meta (id INTEGER PRIMARY KEY, name VARCHAR(255), value VARCHAR(255))')
210 cursor.execute('INSERT INTO meta VALUES (null, ?, ?)', ('VERSION', '2'))210 cursor.execute('INSERT INTO meta VALUES (null, ?, ?)', ('VERSION', '2'))
211211
212 def getGlobalCurrency(self):
213 results = self.dbconn.cursor().execute('SELECT value FROM meta WHERE name="GlobalCurrency"').fetchall()
214 return int(results[0][0])
215
212 def getMeta(self):216 def getMeta(self):
213 try:217 try:
214 results = self.dbconn.cursor().execute('SELECT * FROM meta').fetchall()218 results = self.dbconn.cursor().execute('SELECT * FROM meta').fetchall()
@@ -288,6 +292,9 @@
288 # This is tested by testOrphanedTransactionsAreDeleted (dbupgradetests.DBUpgradeTest)292 # This is tested by testOrphanedTransactionsAreDeleted (dbupgradetests.DBUpgradeTest)
289 # Also takes care of LP #249954 without the explicit need to defensively remove on any account creation.293 # Also takes care of LP #249954 without the explicit need to defensively remove on any account creation.
290 self.cleanOrphanedTransactions()294 self.cleanOrphanedTransactions()
295 elif fromVer == 11:
296 # globalCurrency entry
297 cursor.execute('INSERT INTO meta VALUES (null, ?, ?)', ('GlobalCurrency', 0))
291 else:298 else:
292 raise Exception("Cannot upgrade database from version %i"%fromVer)299 raise Exception("Cannot upgrade database from version %i"%fromVer)
293 300
@@ -442,11 +449,16 @@
442 def renameAccount(self, oldName, account):449 def renameAccount(self, oldName, account):
443 self.dbconn.cursor().execute("UPDATE accounts SET name=? WHERE name=?", (account.Name, oldName))450 self.dbconn.cursor().execute("UPDATE accounts SET name=? WHERE name=?", (account.Name, oldName))
444 self.commitIfAppropriate()451 self.commitIfAppropriate()
445452
446 def setCurrency(self, currencyIndex):453 def setCurrency(self, currencyIndex, account=None):
447 self.dbconn.cursor().execute('UPDATE accounts SET currency=?', (currencyIndex,))454 if account:
448 self.commitIfAppropriate()455 self.dbconn.cursor().execute('UPDATE accounts SET currency=? WHERE id=?', (currencyIndex, account.ID))
449456 else:
457 #Since no account received, we are updating the global currency
458 self.dbconn.cursor().execute('UPDATE meta SET value=? WHERE name="GlobalCurrency"', (currencyIndex,))
459 self.commitIfAppropriate()
460
461
450 def __print__(self):462 def __print__(self):
451 cursor = self.dbconn.cursor()463 cursor = self.dbconn.cursor()
452 for account in cursor.execute("SELECT * FROM accounts").fetchall():464 for account in cursor.execute("SELECT * FROM accounts").fetchall():
453465
=== modified file 'wxbanker/plots/cairopanel.py'
--- wxbanker/plots/cairopanel.py 2010-09-13 07:40:38 +0000
+++ wxbanker/plots/cairopanel.py 2012-06-07 03:50:23 +0000
@@ -1,6 +1,7 @@
1import wx1import wx
2import datetime2import datetime
3from wxbanker.plots import plotfactory3from wxbanker.plots import plotfactory
4from wx.lib.pubsub import Publisher
45
5try:6try:
6 try:7 try:
@@ -17,7 +18,7 @@
17 self.Plots = [CairoPlotPanel, CairoPlotPanelMonthly]18 self.Plots = [CairoPlotPanel, CairoPlotPanelMonthly]
18 19
19class BaseCairoPlotPanel(wx.Panel, baseplot.BasePlot):20class BaseCairoPlotPanel(wx.Panel, baseplot.BasePlot):
20 def __init__(self, bankController, parent):21 def __init__(self, bankController, parent, plotSettings=None):
21 wx.Panel.__init__(self, parent)22 wx.Panel.__init__(self, parent)
22 baseplot.BasePlot.__init__(self)23 baseplot.BasePlot.__init__(self)
23 self.bankController = bankController24 self.bankController = bankController
@@ -25,6 +26,14 @@
25 self.Bind(wx.EVT_SIZE, self.OnSize)26 self.Bind(wx.EVT_SIZE, self.OnSize)
26 self.data = None27 self.data = None
27 self.x_labels = None28 self.x_labels = None
29 self.plotSettings = plotSettings
30
31 # watch if there's any currency change to repaint the plot.
32 Publisher.subscribe(self.currencyChanged, "controller.show_currency_nick_toggled")
33 Publisher.subscribe(self.currencyChanged, "currency_changed")
34
35 def currencyChanged(self, message):
36 self.Refresh()
28 37
29 def OnSize(self, event):38 def OnSize(self, event):
30 self.Refresh()39 self.Refresh()
@@ -33,6 +42,7 @@
33 NAME = _("monthly")42 NAME = _("monthly")
34 43
35 def plotBalance(self, totals, plotSettings):44 def plotBalance(self, totals, plotSettings):
45 self.plotSettings = plotSettings
36 model = self.bankController.Model46 model = self.bankController.Model
37 transactions = model.GetTransactions()47 transactions = model.GetTransactions()
38 earnings = baseplot.BasePlot.plotMonthly(self, transactions, plotSettings['Months'])48 earnings = baseplot.BasePlot.plotMonthly(self, transactions, plotSettings['Months'])
@@ -56,6 +66,13 @@
56 66
57 cr = wx.lib.wxcairo.ContextFromDC(dc)67 cr = wx.lib.wxcairo.ContextFromDC(dc)
58 size = self.GetClientSize()68 size = self.GetClientSize()
69
70 # try to format Y axes labels according to the account's currency.
71 if self.plotSettings['Account']:
72 value_formatter = lambda s: self.plotSettings['Account'].float2str(s)
73 else:
74 value_formatter = lambda s: self.bankController.Model.float2str(s)
75
59 cairoplot.vertical_bar_plot(76 cairoplot.vertical_bar_plot(
60 cr.get_target(),77 cr.get_target(),
61 data = self.data,78 data = self.data,
@@ -65,7 +82,7 @@
65 colors = ["green"],82 colors = ["green"],
66 #series_legend = True,83 #series_legend = True,
67 display_values = True,84 display_values = True,
68 value_formatter = lambda s: self.bankController.Model.float2str(s),85 value_formatter = value_formatter,
69 #x_title=_("Earnings"),86 #x_title=_("Earnings"),
70 #y_title=_("Month"),87 #y_title=_("Month"),
71 rounded_corners = True,88 rounded_corners = True,
@@ -76,6 +93,7 @@
76 NAME = _("balance")93 NAME = _("balance")
77 94
78 def plotBalance(self, totals, plotSettings, xunits="Days"):95 def plotBalance(self, totals, plotSettings, xunits="Days"):
96 self.plotSettings = plotSettings
79 amounts, dates, strdates, trendable = baseplot.BasePlot.plotBalance(self, totals, plotSettings, xunits)97 amounts, dates, strdates, trendable = baseplot.BasePlot.plotBalance(self, totals, plotSettings, xunits)
80 data = [(i, total) for i, total in enumerate(amounts)]98 data = [(i, total) for i, total in enumerate(amounts)]
81 self.data = {99 self.data = {
@@ -107,6 +125,13 @@
107 125
108 cr = wx.lib.wxcairo.ContextFromDC(dc)126 cr = wx.lib.wxcairo.ContextFromDC(dc)
109 size = self.GetClientSize()127 size = self.GetClientSize()
128
129 # try to format Y axes labels according to the account's currency.
130 if self.plotSettings['Account']:
131 y_formatter = lambda s: self.plotSettings['Account'].float2str(s)
132 else:
133 y_formatter = lambda s: self.bankController.Model.float2str(s)
134
110 cairoplot.scatter_plot(135 cairoplot.scatter_plot(
111 cr.get_target(),136 cr.get_target(),
112 data = self.data,137 data = self.data,
@@ -118,7 +143,7 @@
118 series_colors = ["green", "blue"],143 series_colors = ["green", "blue"],
119 series_legend = True,144 series_legend = True,
120 x_labels=self.x_labels,145 x_labels=self.x_labels,
121 y_formatter=lambda s: self.bankController.Model.float2str(s),146 y_formatter=y_formatter,
122 x_title=_("Time"),147 x_title=_("Time"),
123 y_title=_("Balance"),148 y_title=_("Balance"),
124 )149 )
125150
=== modified file 'wxbanker/transactionolv.py'
--- wxbanker/transactionolv.py 2010-12-25 13:45:21 +0000
+++ wxbanker/transactionolv.py 2012-06-07 03:50:23 +0000
@@ -33,6 +33,7 @@
33from wxbanker.ObjectListView import GroupListView, ColumnDefn, CellEditorRegistry33from wxbanker.ObjectListView import GroupListView, ColumnDefn, CellEditorRegistry
34from wxbanker import bankcontrols, tagtransactiondialog34from wxbanker import bankcontrols, tagtransactiondialog
3535
36from wxbanker.currencies import GetCurrencyInt
3637
37class TransactionOLV(GroupListView):38class TransactionOLV(GroupListView):
38 EMPTY_MSG_NORMAL = _("No transactions entered.")39 EMPTY_MSG_NORMAL = _("No transactions entered.")
@@ -43,6 +44,7 @@
43 self.LastSearch = None44 self.LastSearch = None
44 self.CurrentAccount = None45 self.CurrentAccount = None
45 self.BankController = bankController46 self.BankController = bankController
47 self.GlobalCurrency = self.BankController.Model.Store.getGlobalCurrency()
4648
47 self.showGroups = False49 self.showGroups = False
48 #WXTODO: figure out these (and the text color, or is that already?) from theme (LP: ???)50 #WXTODO: figure out these (and the text color, or is that already?) from theme (LP: ???)
@@ -66,7 +68,7 @@
66 self.SetColumns([68 self.SetColumns([
67 ColumnDefn(_("Date"), valueGetter=self.getDateAndIDOf, valueSetter=self.setDateOf, stringConverter=self.renderDateIDTuple, editFormatter=self.renderEditDate, width=dateWidth),69 ColumnDefn(_("Date"), valueGetter=self.getDateAndIDOf, valueSetter=self.setDateOf, stringConverter=self.renderDateIDTuple, editFormatter=self.renderEditDate, width=dateWidth),
68 ColumnDefn(_("Description"), valueGetter="Description", isSpaceFilling=True, editFormatter=self.renderEditDescription),70 ColumnDefn(_("Description"), valueGetter="Description", isSpaceFilling=True, editFormatter=self.renderEditDescription),
69 ColumnDefn(_("Amount"), "right", valueGetter="Amount", stringConverter=self.renderFloat, editFormatter=self.renderEditFloat),71 ColumnDefn(_("Amount"), "right", valueGetter=self.getAmount, valueSetter=self.setAmount, stringConverter=self.renderFloat, editFormatter=self.renderEditFloat),
70 ColumnDefn(_("Balance"), "right", valueGetter=self.getTotal, stringConverter=self.renderFloat, isEditable=False),72 ColumnDefn(_("Balance"), "right", valueGetter=self.getTotal, stringConverter=self.renderFloat, isEditable=False),
71 ])73 ])
72 # Our custom hack in OLV.py:2017 will render amount floats appropriately as %.2f when editing.74 # Our custom hack in OLV.py:2017 will render amount floats appropriately as %.2f when editing.
@@ -84,13 +86,14 @@
84 (self.onTransactionAdded, "transaction.created"),86 (self.onTransactionAdded, "transaction.created"),
85 (self.onTransactionsRemoved, "transactions.removed"),87 (self.onTransactionsRemoved, "transactions.removed"),
86 (self.onCurrencyChanged, "currency_changed"),88 (self.onCurrencyChanged, "currency_changed"),
89 (self.onShowCurrencyNickToggled, "controller.show_currency_nick_toggled"),
87 (self.updateTotals, "ormobject.updated.Transaction.Amount"),90 (self.updateTotals, "ormobject.updated.Transaction.Amount"),
88 (self.onTransactionDateUpdated, "ormobject.updated.Transaction.Date"),91 (self.onTransactionDateUpdated, "ormobject.updated.Transaction.Date"),
89 )92 )
9093
91 for callback, topic in self.Subscriptions:94 for callback, topic in self.Subscriptions:
92 Publisher.subscribe(callback, topic)95 Publisher.subscribe(callback, topic)
9396
94 def SetObjects(self, objs, *args, **kwargs):97 def SetObjects(self, objs, *args, **kwargs):
95 """98 """
96 Override the default SetObjects to properly refresh the auto-size,99 Override the default SetObjects to properly refresh the auto-size,
@@ -127,6 +130,12 @@
127 self.Freeze()130 self.Freeze()
128 self.SortBy(self.SORT_COL)131 self.SortBy(self.SORT_COL)
129 self.Thaw()132 self.Thaw()
133
134 def setAmount(self, transaction, amount):
135 transaction.Amount = amount
136 self.Freeze()
137 self.SortBy(self.SORT_COL)
138 self.Thaw()
130139
131 def getTotal(self, transObj):140 def getTotal(self, transObj):
132 if not hasattr(transObj, "_Total"):141 if not hasattr(transObj, "_Total"):
@@ -139,23 +148,42 @@
139 if first is None:148 if first is None:
140 return149 return
141 150
142 first._Total = first.Amount151 if not self.CurrentAccount:
152 #This means we are in 'All accounts' so we need to convert each total
153 # to the global currency
154 balance_currency = self.GlobalCurrency
155 else:
156 #we are just viewing a single account
157 # balance currency = accounts currency
158 balance_currency = GetCurrencyInt(self.CurrentAccount.GetCurrency())
159
160 first._Total = first.GetAmount(balance_currency)
143 161
144 b = first162 b = first
145 for i in range(1, len(self.GetObjects())):163 for i in range(1, len(self.GetObjects())):
146 a, b = b, self.GetObjectAt(i)164 a, b = b, self.GetObjectAt(i)
147 b._Total = a._Total + b.Amount165 b._Total = a._Total + b.GetAmount(balance_currency)
148 166
149 def renderDateIDTuple(self, pair):167 def renderDateIDTuple(self, pair):
150 return str(pair[0])168 return str(pair[0])
151 169
152 def renderFloat(self, floatVal):170 def getAmount(self, obj):
153 if self.CurrentAccount:171 #Return the whole transaction/float since we need to use its
154 return self.CurrentAccount.float2str(floatVal)172 #renderAmount method to support multiple currencies.
173 return obj
174
175 def renderFloat(self, value):
176 if isinstance(value, float):
177 #this is a 'balance' column, its ok to use the bank model's float2str
178 # as long as we'r not in an account.
179 if self.CurrentAccount:
180 return self.CurrentAccount.float2str(value)
181 else:
182 return self.BankController.Model.float2str(value)
155 else:183 else:
156 #WXTODO: fix me, this function should be given the object which should have a float2str method184 #this is a trnasaction, so it belogns to the 'Amount' column, render
157 # so that for multiple currencies they can be displayed differently when viewing all.185 # it with its appropieate currency
158 return self.BankController.Model.float2str(floatVal)186 return value.RenderAmount()
159 187
160 def renderEditDate(self, transaction):188 def renderEditDate(self, transaction):
161 return str(transaction.Date)189 return str(transaction.Date)
@@ -413,13 +441,22 @@
413 self.Refresh()441 self.Refresh()
414442
415 def onCurrencyChanged(self, message):443 def onCurrencyChanged(self, message):
416 # Refresh all the transaction objects, re-rendering the amounts.444 self.GlobalCurrency = message.data
417 self.RefreshObjects()445 # Refresh all the transaction objects, re-rendering the amounts.
418 # The current likely changed the widths of the amount/total column.446 self.RefreshObjects()
419 self.sizeAmounts()447 # The current likely changed the widths of the amount/total column.
420 # Now we need to adjust the description width so we don't have a horizontal scrollbar.448 self.sizeAmounts()
421 self.AutoSizeColumns()449 # Now we need to adjust the description width so we don't have a horizontal scrollbar.
422450 self.AutoSizeColumns()
451
452 def onShowCurrencyNickToggled(self, message):
453 # Refresh all the transaction objects, re-rendering the amounts.
454 self.RefreshObjects()
455 # The current likely changed the widths of the amount/total column.
456 self.sizeAmounts()
457 # Now we need to adjust the description width so we don't have a horizontal scrollbar.
458 self.AutoSizeColumns()
459
423 def __del__(self):460 def __del__(self):
424 for callback, topic in self.Subscriptions:461 for callback, topic in self.Subscriptions:
425 Publisher.unsubscribe(callback)462 Publisher.unsubscribe(callback)

Subscribers

People subscribed via source and target branches

to all changes: