def onButton(self, event): """If the save button was clicked save, and close the dialog in any case (Close/Cancel/Save).""" assert event.Id in (wx.ID_CLOSE, wx.ID_SAVE, wx.ID_DELETE) if event.Id == wx.ID_SAVE: self.transactionCtrl.ToRecurring() originalTransaction = self.transactions[ self.transactionChoice.Selection] modifiedTransaction = self.transactionCtrl.recurringObj originalTransaction.UpdateFrom(modifiedTransaction) # Let everyone know about this, someone might want to check if there are new pending transactions. Publisher.sendMessage("recurringtransaction.updated") elif event.Id == wx.ID_DELETE: recurring = self.GetCurrentRecurringTransaction() warningMsg = _( "This will permanently remove this recurring transaction. Continue?" ) dlg = wx.MessageDialog(self, warningMsg, _("Warning"), style=wx.YES_NO | wx.ICON_EXCLAMATION) result = dlg.ShowModal() if result == wx.ID_YES: recurring.Parent.RemoveRecurringTransaction(recurring) self.GrandParent.Destroy()
def init(path=None, welcome=True): import wx, sys from wxbanker import fileservice from wxbanker.controller import Controller bankController = Controller(path) # We can initialize the wx locale now that the wx.App is initialized. localization.initWxLocale() # Push our custom art provider. import wx.lib.art.img2pyartprov as img2pyartprov from wxbanker.art import silk, transparent for provider in (silk, transparent): wx.ArtProvider.Push(img2pyartprov.Img2PyArtProvider(provider)) # Initialize the wxBanker frame! frame = BankerFrame(bankController, welcome) # Greet the user if it appears this is their first time using wxBanker. config = wx.Config.Get() firstTime = not config.ReadBool("RUN_BEFORE") if firstTime: Publisher.sendMessage("first run") config.WriteBool("RUN_BEFORE", True) return bankController.wxApp
def __init__(self, store, aID, name, currency=0, balance=0.0, mintId=None, currNick=False): ORMObject.__init__(self) self.IsFrozen = True self.Store = store self.ID = aID self._Name = name self._Transactions = None self._RecurringTransactions = [] self._preTransactions = [] # Make sure that Currency and Balance are not None (bug #653716) self.Currency = currency or 0 self.Balance = balance or 0.0 self.MintId = mintId or None self.ShowCurrencyNick = currNick or False self.IsFrozen = False Publisher.subscribe(self.onTransactionAmountChanged, "ormobject.updated.Transaction.Amount")
def __init__(self, parent, editing=None): wx.Panel.__init__(self, parent) # Create the recurring object we will use internally. self.recurringObj = RecurringTransaction(None, None, 0, "", datetime.date.today(), RecurringTransaction.DAILY) self.Sizer = wx.GridBagSizer(0, 3) self.Sizer.SetEmptyCellSize((0, 0)) self.recurringRow = RecurringRow(self, self.RECURRING_ROW) self.recurringSummaryRow = RecurringSummaryRow(self, self.SUMMARY_ROW) self.weeklyRecurringRow = WeeklyRecurringRow(self, self.WEEKLY_ROW) self.transferRow = TransferRow(self, self.TRANSFER_ROW) self.transactionRow = NewTransactionRow(self, self.TRANSACTION_ROW, editing=editing) # can not set 2nd column growable in wx3.0 if Sizer is empty self.Sizer.AddGrowableCol(1, 1) # RecurringRow needs an update once both it and the other controls exist. self.recurringRow.Update() # Hide everything up to the actual transaction row initially. if not editing: for i in range(self.TRANSACTION_ROW): self.ShowRow(i, False) ctrlId = id(self.transactionRow) Publisher.subscribe(self.onTransferToggled, "newtransaction.%i.transfertoggled" % ctrlId) Publisher.subscribe(self.onRecurringToggled, "newtransaction.%i.recurringtoggled" % ctrlId)
def __init__(self, parent, editing=None): wx.Panel.__init__(self, parent) # Create the recurring object we will use internally. self.recurringObj = RecurringTransaction(None, None, 0, "", datetime.date.today(), RecurringTransaction.DAILY) self.Sizer = wx.GridBagSizer(0, 3) self.Sizer.SetEmptyCellSize((0,0)) self.recurringRow = RecurringRow(self, self.RECURRING_ROW) self.recurringSummaryRow = RecurringSummaryRow(self, self.SUMMARY_ROW) self.weeklyRecurringRow = WeeklyRecurringRow(self, self.WEEKLY_ROW) self.transferRow = TransferRow(self, self.TRANSFER_ROW) self.transactionRow = NewTransactionRow(self, self.TRANSACTION_ROW, editing=editing) # can not set 2nd column growable in wx3.0 if Sizer is empty self.Sizer.AddGrowableCol(1, 1) # RecurringRow needs an update once both it and the other controls exist. self.recurringRow.Update() # Hide everything up to the actual transaction row initially. if not editing: for i in range(self.TRANSACTION_ROW): self.ShowRow(i, False) ctrlId = id(self.transactionRow) Publisher.subscribe(self.onTransferToggled, "newtransaction.%i.transfertoggled"%ctrlId) Publisher.subscribe(self.onRecurringToggled, "newtransaction.%i.recurringtoggled"%ctrlId)
def OnPaneChanged(self, evt=None): """Redo the text and layout when the widget state is toggled.""" self.Layout() # Change the labels expanded = int(self.IsExpanded()) self.Label = self.Labels[expanded] Publisher.sendMessage("CALCULATOR.TOGGLED", ("SHOW", "HIDE")[expanded])
def onNewTransaction(self, event=None): # First, ensure an account is selected. destAccount = self.CurrentAccount if destAccount is None: dlg = wx.MessageDialog( self.Parent, _("Please select an account and then try again."), _("No account selected"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() return # Grab the transaction values from the control. result = self.getValues() if result is None: # Validation failed, user was informed. return amount, desc, date = result # If a search is active, we have to ask the user what they want to do. if self.Parent.Parent.searchActive: msg = _("A search is currently active.") + " " + _( 'Would you like to clear the current search and make this transaction in "%s"?' ) % (destAccount.Name) dlg = wx.MessageDialog(self.Parent, msg, _("Clear search?"), style=wx.YES_NO | wx.ICON_WARNING) result = dlg.ShowModal() if result == wx.ID_YES: Publisher.sendMessage("SEARCH.CANCELLED") else: return sourceAccount = None # If the transfer box is checked, this is a transfer! if self.transferCheck.Value: result = self.Parent.transferRow.GetAccounts(destAccount) if result is None: dlg = wx.MessageDialog( self.Parent, _("This transaction is marked as a transfer. Please select the transfer account." ), _("No account selected"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() return sourceAccount, destAccount = result # Now let's see if this is a recurring transaction if self.recursCheck.GetValue(): settings = self.Parent.GetSettings() args = [amount, desc, date] + list(settings) + [sourceAccount] destAccount.AddRecurringTransaction(*args) else: destAccount.AddTransaction(amount, desc, date, sourceAccount) # A transaction was added, we can stop flashing if we were. self.newButton.StopFlashing() # Reset the controls and focus to their default values. self.clear()
def AddTransactions(self, transactions, sources=None): Publisher.sendMessage("batch.start") # If we don't have any sources, we want None for each transaction. if sources is None: sources = [None for i in range(len(transactions))] for t, source in zip(transactions, sources): self.AddTransaction(transaction=t, source=source) Publisher.sendMessage("batch.end")
def onAccountClick(self, event): """ This method is called when the current account has been changed by clicking on an account name. """ radio = event.EventObject if radio is self.allAccountsRadio: account = None else: account = self.accountObjects[radio.AccountIndex] Publisher.sendMessage("user.account changed", account)
def Remove(self, accountName): index = self.AccountIndex(accountName) if index == -1: raise bankexceptions.InvalidAccountException(accountName) account = self.pop(index) # Remove all the transactions associated with this account. account.Purge() Publisher.sendMessage("account.removed.%s" % accountName, account)
def onButton(self, event): """If the save button was clicked save, and close the dialog in any case (Close/Cancel/Save).""" assert event.Id in (wx.ID_CLOSE, wx.ID_SAVE) if event.Id == wx.ID_SAVE: #we have to substract 1 from combo_box selection because we added the "base currency" entry selectedCurrency = self.currencyCombo.GetSelection() - 1 Publisher.sendMessage("user.account_currency_changed", (self.Account, selectedCurrency)) self.GrandParent.Destroy()
def Remove(self, accountName): index = self.AccountIndex(accountName) if index == -1: raise bankexceptions.InvalidAccountException(accountName) account = self.pop(index) # Remove all the transactions associated with this account. account.Purge() Publisher.sendMessage("account.removed.%s"%accountName, account)
def __init__(self, parent, plotFactory, bankController): wx.Panel.__init__(self, parent) self.plotFactory = plotFactory self.bankController = bankController self.plotSettings = {'FitDegree': 2, 'Granularity': 100, 'Account': None, 'Months': 12} self.plotLabels = [_("Trend Degree"), _("Months")] self.currentPlotIndex = 0 self.cachedData = None self.dateRange = None self.isActive = False # create the plot panel self.plotPanel = plotFactory.createPanel(self, bankController) # create the controls at the bottom controlSizer = wx.BoxSizer() self.graphChoice = wx.Choice(self, choices=[plot.NAME for plot in plotFactory.Plots]) self.optionCtrl = wx.SpinCtrl(self, min=1, max=24, initial=self.plotSettings['FitDegree']) # the date range controls self.startDate = bankcontrols.DateCtrlFactory(self) self.endDate = bankcontrols.DateCtrlFactory(self) self.optionText = wx.StaticText(self, label=self.plotLabels[0]) self.fromText = wx.StaticText(self, label=_("From")) self.toText = wx.StaticText(self, label=_("until")) controlSizer.Add(wx.StaticText(self, label=_("Graph")), 0, wx.ALIGN_CENTER_VERTICAL) controlSizer.AddSpacer(5) controlSizer.Add(self.graphChoice, 0, wx.ALIGN_CENTER_VERTICAL) controlSizer.AddSpacer(10) controlSizer.Add(self.fromText, 0, wx.ALIGN_CENTER_VERTICAL) controlSizer.AddSpacer(5) controlSizer.Add(self.startDate, 0, wx.ALIGN_CENTER_VERTICAL) controlSizer.AddSpacer(5) controlSizer.Add(self.toText, 0, wx.ALIGN_CENTER_VERTICAL) controlSizer.AddSpacer(5) controlSizer.Add(self.endDate, 0, wx.ALIGN_CENTER_VERTICAL) controlSizer.AddSpacer(10) controlSizer.Add(self.optionText, 0, wx.ALIGN_CENTER_VERTICAL) controlSizer.AddSpacer(5) controlSizer.Add(self.optionCtrl, 0, wx.ALIGN_CENTER_VERTICAL) self.optionCtrl.SetMinSize = (20, -1) # put it all together self.Sizer = wx.BoxSizer(wx.VERTICAL) self.Sizer.Add(self.plotPanel, 1, wx.EXPAND) self.Sizer.Add(controlSizer, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 6) self.Layout() # bind to the spin buttons self.graphChoice.Bind(wx.EVT_CHOICE, self.onGraphChoice) self.optionCtrl.Bind(wx.EVT_SPINCTRL, self.onOptionSpin) self.Bind(wx.EVT_DATE_CHANGED, self.onDateRangeChanged) Publisher.subscribe(self.onAccountSelect, "view.account changed")
def __init__(self, path, autoSave=True): self.Subscriptions = [] self.Version = 13 self.Path = path self.AutoSave = False self.Dirty = False self.BatchDepth = 0 self.cachedModel = None # Upgrades can't enable syncing if needed from older versions. self.needsSync = False existed = True # See if the path already exists to decide what to do. if not os.path.exists(self.Path): existed = False # Initialize the connection and optimize it. connection = sqlite.connect(self.Path) self.dbconn = connection # Disable synchronous I/O, which makes everything MUCH faster, at the potential cost of durability. self.dbconn.execute("PRAGMA synchronous=OFF;") # If the db doesn't exist, initialize it. if not existed: debug.debug('Initializing', self.Path) self.initialize() else: debug.debug('Loading', self.Path) self.Meta = self.getMeta() debug.debug(self.Meta) while self.Meta['VERSION'] < self.Version: # If we are creating a new db, we don't need to backup each iteration. self.upgradeDb(self.Meta['VERSION'], backup=existed) self.Meta = self.getMeta() debug.debug(self.Meta) # We have to subscribe before syncing otherwise it won't get synced if there aren't other changes. self.Subscriptions = ( (self.onORMObjectUpdated, "ormobject.updated"), (self.onAccountBalanceChanged, "account.balance changed"), (self.onAccountRemoved, "account.removed"), (self.onBatchEvent, "batch"), (self.onExit, "exiting"), ) for callback, topic in self.Subscriptions: Publisher.subscribe(callback, topic) # If the upgrade process requires a sync, do so now. if self.needsSync: self.syncBalances() self.needsSync = False self.AutoSave = autoSave self.commitIfAppropriate()
def __init__(self, bankmodel, store): list.__init__(self, store.GetAccounts()) # Make sure all the items know their parent list. for account in self: account.Parent = self self.BankModel = bankmodel self.Store = store self.sort() Publisher.subscribe(self.onAccountRenamed, "ormobject.updated.Account.Name")
def SetAutoSave(self, val): self._AutoSave = val wx.Config.Get().WriteBool("AUTO-SAVE", val) Publisher.sendMessage("controller.autosave_toggled", val) for model in self.Models: debug.debug("Setting auto-save to: %s" % val) model.Store.AutoSave = val # If the user enables auto-save, we want to also save. if self.AutoSave: Publisher.sendMessage("user.saved")
def AddRecurringTransaction(self, amount, description, date, repeatType, repeatEvery=1, repeatOn=None, endDate=None, source=None): # Create the recurring transaction object. recurring = RecurringTransaction(None, self, amount, description, date, repeatType, repeatEvery, repeatOn, endDate, source) # Store it. self.Store.MakeRecurringTransaction(recurring) # Add it to our internal list. self.RecurringTransactions.append(recurring) Publisher.sendMessage("recurringtransaction.created", (self, recurring)) return recurring
def Login(cls, username, password, notify=True): if cls.IsLoggedIn(): return accounts = {} for account in mintapi.get_accounts(username, password): account['balance'] = account['value'] # convert to wxBanker speak accounts[account['accountId']] = account cls._CachedAccounts = accounts if notify: Publisher.sendMessage("mint.updated")
def onSearch(self, event=None): # Stop any timer that may be active, in the case of a manual search. self.SearchTimer.Stop() searchString = self.searchCtrl.Value # For a date, should be YYYY-MM-DD. matchType = self.matchChoices.index(self.matchBox.Value) searchInfo = (searchString, matchType) # Consider a blank search as a search cancellation. if searchString == "": self.onCancel() else: Publisher.sendMessage("SEARCH.INITIATED", searchInfo)
def __init__(self, parent, bankController): GroupListView.__init__(self, parent, style=wx.LC_REPORT|wx.SUNKEN_BORDER, name="TransactionOLV") self.LastSearch = None self.CurrentAccount = None self.BankController = bankController self.showGroups = False #WXTODO: figure out these (and the text color, or is that already?) from theme (LP: ???) self.evenRowsBackColor = wx.Colour(224,238,238) self.oddRowsBackColor = wx.WHITE self.cellEditMode = GroupListView.CELLEDIT_DOUBLECLICK self.SetEmptyListMsg(self.EMPTY_MSG_NORMAL) # Calculate the necessary width for the date column. dateStr = str(datetime.date.today()) dateWidth = self.GetTextExtent(dateStr)[0] + 10 # Define some constants to use throughout. self.COL_DATE = 0 self.COL_DESCRIPTION = 1 self.COL_AMOUNT = 2 self.COL_TOTAL = 3 # If you change these column names, update sizeAmounts()! self.SetColumns([ ColumnDefn(_("Date"), valueGetter=self.getDateAndIDOf, valueSetter=self.setDateOf, stringConverter=self.renderDateIDTuple, editFormatter=self.renderEditDate, width=dateWidth), ColumnDefn(_("Description"), valueGetter="Description", isSpaceFilling=True, editFormatter=self.renderEditDescription), ColumnDefn(_("Amount"), "right", valueGetter=self.getAmount, valueSetter=self.setAmount, stringConverter=self.renderFloat, editFormatter=self.renderEditFloat), ColumnDefn(_("Balance"), "right", valueGetter=self.getTotal, stringConverter=self.renderFloat, isEditable=False), ]) # Our custom hack in OLV.py:2017 will render amount floats appropriately as %.2f when editing. # By default, sort by the date column, ascending. self.SORT_COL = self.COL_DATE self.SortBy(self.SORT_COL) self.Bind(wx.EVT_RIGHT_DOWN, self.onRightDown) self.Subscriptions = ( (self.onSearch, "SEARCH.INITIATED"), (self.onSearchCancelled, "SEARCH.CANCELLED"), (self.onSearchMoreToggled, "SEARCH.MORETOGGLED"), (self.onTransactionAdded, "transaction.created"), (self.onTransactionsRemoved, "transactions.removed"), (self.onCurrencyChanged, "currency_changed"), (self.onShowCurrencyNickToggled, "controller.show_currency_nick_toggled"), (self.updateTotals, "ormobject.updated.Transaction.Amount"), (self.onTransactionDateUpdated, "ormobject.updated.Transaction.Date"), ) for callback, topic in self.Subscriptions: Publisher.subscribe(callback, topic)
def __init__(self, parent, bankController): wx.Panel.__init__(self, parent) self.ID_TIMER = wx.NewId() self.SearchTimer = wx.Timer(self, self.ID_TIMER) self.bankController = bankController self.searchCtrl = bankcontrols.UpdatableSearchCtrl(self, value="", size=(200, -1), style=wx.TE_PROCESS_ENTER) # Try to grab the GTK system icon for clearing a search, otherwise we'll get the wxPython one. iconSize = self.searchCtrl.GetClientRect().GetHeight() - 2 clearBitmap = wx.ArtProvider.GetBitmap('edit-clear', wx.ART_OTHER, [iconSize, iconSize]) if clearBitmap: self.searchCtrl.SetCancelBitmap(clearBitmap) self.searchCtrl.ShowCancelButton(True) self.searchCtrl.ShowSearchButton(False) self.searchCtrl.DescriptiveText = _("Search transactions") self.searchCtrl.SetForegroundColour('DARK GRAY') # The More/Less button. self.moreButton = bankcontrols.MultiStateButton(self, labelDict={True: _("More options"), False: _("Less options")}, state=True) self.matchChoices = [_("Amount"), _("Description"), _("Date")] self.descriptionSelection = 1 self.matchBox = bankcontrols.CompactableComboBox(self, value=self.matchChoices[1], choices=self.matchChoices, style=wx.CB_READONLY) topSizer = wx.BoxSizer() topSizer.Add(self.searchCtrl, 0, wx.ALIGN_CENTER_VERTICAL) topSizer.AddSpacer(10) topSizer.Add(self.moreButton, 0, wx.ALIGN_CENTER_VERTICAL) self.moreSizer = moreSizer = wx.BoxSizer() moreSizer.Add(wx.StaticText(self, label=_("Match: ")), 0, wx.ALIGN_CENTER_VERTICAL) moreSizer.Add(self.matchBox, 0, wx.ALIGN_CENTER_VERTICAL) self.Sizer = wx.BoxSizer(wx.VERTICAL) self.Sizer.Add(topSizer, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM, 2) self.Sizer.Add(moreSizer, 0, wx.ALIGN_RIGHT|wx.BOTTOM, 2) self.matchBox.Compact() self.Layout() self.searchCtrl.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN, self.onCancel) self.searchCtrl.Bind(wx.EVT_TEXT, self.onText) #self.searchCtrl.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.onSearch) self.searchCtrl.Bind(wx.EVT_TEXT_ENTER, self.onSearch) self.moreButton.Bind(wx.EVT_BUTTON, self.onToggleMore) # Bindings to search on settings change automatically. self.matchBox.Bind(wx.EVT_COMBOBOX, self.onSearchTrigger) self.Bind(wx.EVT_TIMER, self.onSearchTimer) Publisher.subscribe(self.onExternalSearch, "SEARCH.EXTERNAL") # Initially hide the extra search options. self.onToggleMore()
def onNewTransaction(self, event=None): # First, ensure an account is selected. destAccount = self.CurrentAccount if destAccount is None: dlg = wx.MessageDialog(self.Parent, _("Please select an account and then try again."), _("No account selected"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() return # Grab the transaction values from the control. result = self.getValues() if result is None: # Validation failed, user was informed. return amount, desc, date = result # If a search is active, we have to ask the user what they want to do. if self.Parent.Parent.searchActive: msg = _("A search is currently active.") + " " + _('Would you like to clear the current search and make this transaction in "%s"?') % (destAccount.Name) dlg = wx.MessageDialog(self.Parent, msg, _("Clear search?"), style=wx.YES_NO|wx.ICON_WARNING) result = dlg.ShowModal() if result == wx.ID_YES: Publisher.sendMessage("SEARCH.CANCELLED") else: return sourceAccount = None # If the transfer box is checked, this is a transfer! if self.transferCheck.Value: result = self.Parent.transferRow.GetAccounts(destAccount) if result is None: dlg = wx.MessageDialog(self.Parent, _("This transaction is marked as a transfer. Please select the transfer account."), _("No account selected"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() return sourceAccount, destAccount = result # Now let's see if this is a recurring transaction if self.recursCheck.GetValue(): settings = self.Parent.GetSettings() args = [amount, desc, date] + list(settings) + [sourceAccount] destAccount.AddRecurringTransaction(*args) else: destAccount.AddTransaction(amount, desc, date, sourceAccount) # A transaction was added, we can stop flashing if we were. self.newButton.StopFlashing() # Reset the controls and focus to their default values. self.clear()
def getTransactionsFrom(self, account): transactions = TransactionList() # Generate a map of recurring transaction IDs to the objects for fast look-up. recurringCache = {} for recurring in account.Parent.GetRecurringTransactions(): recurringCache[recurring.ID] = recurring Publisher.sendMessage("batch.start") for result in self.dbconn.cursor().execute('SELECT * FROM transactions WHERE accountId=?', (account.ID,)).fetchall(): t = self.result2transaction(result, account, recurringCache=recurringCache) transactions.append(t) Publisher.sendMessage("batch.end") return transactions
def __init__(self, parent, bankController): wx.Panel.__init__(self, parent) self.bankController = bankController self.mainPanel = managetab.MainPanel(self, bankController) Publisher.subscribe(self.onRecurringTransactionAdded, "recurringtransaction.created") Publisher.subscribe(self.onRecurringTransactionUpdated, "recurringtransaction.updated") self.Sizer = wx.BoxSizer(wx.VERTICAL) self.Sizer.Add(self.mainPanel, 1, wx.EXPAND) wx.CallLater(1000, self.CheckRecurringTransactions)
def onSearch(self, event=None): # Stop any timer that may be active, in the case of a manual search. self.SearchTimer.Stop() searchString = self.searchCtrl.Value # For a date, should be YYYY-MM-DD. matchType = self.matchChoices.index(self.matchBox.Value) searchInfo = (searchString, matchType) # Consider a blank search as a search cancellation. if searchString == "": self.onCancel() else: Publisher.sendMessage("SEARCH.INITIATED", searchInfo) self.searchCtrl.SetForegroundColour('BLACK')
def __init__(self, bankController, parent, plotSettings=None): wx.Panel.__init__(self, parent) baseplot.BasePlot.__init__(self) self.bankController = bankController self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnSize) self.data = None self.x_labels = None self.plotSettings = plotSettings # watch if there's any currency change to repaint the plot. Publisher.subscribe(self.currencyChanged, "controller.show_currency_nick_toggled") Publisher.subscribe(self.currencyChanged, "currency_changed")
def Create(self, accountName): self.ThrowExceptionOnInvalidName(accountName) currency = 0 if len(self): # If the list contains items, the currency needs to be consistent. currency = self[-1].Currency account = self.Store.CreateAccount(accountName, currency) # Make sure this account knows its parent. account.Parent = self self.append(account) self.sort() Publisher.sendMessage("account.created.%s" % accountName, account) return account
def testToggleShowZero(self): # Create two accounts, make sure they are visible. a = self.Model.CreateAccount("A") b = self.Model.CreateAccount("B") b.AddTransaction(1) self.assertEqual(self.AccountListCtrl.GetVisibleCount(), 2) # Disable showing zero balance accounts, make sure the menu item is unchecked and one account is hidden. Publisher.sendMessage("user.showzero_toggled", False) self.assertFalse( self.Frame.MenuBar.showZeroMenuItem.IsChecked() ) self.assertEqual(self.AccountListCtrl.GetVisibleCount(), 1) # Make sure that a balance going to / coming from zero results in a visibility toggle. b.AddTransaction(-1) self.assertEqual(self.AccountListCtrl.GetVisibleCount(), 0)
def testToggleShowZero(self): # Create two accounts, make sure they are visible. a = self.Model.CreateAccount("A") b = self.Model.CreateAccount("B") b.AddTransaction(1) self.assertEqual(self.AccountListCtrl.GetVisibleCount(), 2) # Disable showing zero balance accounts, make sure the menu item is unchecked and one account is hidden. Publisher.sendMessage("user.showzero_toggled", False) self.assertFalse(self.Frame.MenuBar.showZeroMenuItem.IsChecked()) self.assertEqual(self.AccountListCtrl.GetVisibleCount(), 1) # Make sure that a balance going to / coming from zero results in a visibility toggle. b.AddTransaction(-1) self.assertEqual(self.AccountListCtrl.GetVisibleCount(), 0)
def onWarning(self, message): warning = message.topic[1] if warning == "dirty exit": event = message.data title = _("Save changes?") msg = _("You have made changes since the last save. Would you like to save before exiting?") msg += "\n\n" + _("Note that enabling auto-save from the File menu will eliminate the need for manual saving.") dlg = wx.MessageDialog(self, msg, title, style=wx.CANCEL|wx.YES_NO|wx.ICON_WARNING) result = dlg.ShowModal() if result == wx.ID_YES: Publisher.sendMessage("user.saved") elif result == wx.ID_CANCEL: # The user cancelled the close, so cancel the event skip. event.Skip(False) dlg.Destroy()
def onCalculatorAction(self, transactions, col, i): """ Given an action to perform on the calculator, and the row and col, generate the string of characters necessary to perform that action in the calculator, and push them. """ if col == self.COL_TOTAL: # Use the last total if multiple are selected. amount = transactions[-1]._Total else: amount = sum((t.Amount for t in transactions)) pushStr = ('C%s', '+%s=', '-%s=')[i] # Send, Add, Subtract commands pushStr %= amount Publisher.sendMessage("CALCULATOR.PUSH_CHARS", pushStr)
def onToggleMore(self, event=None): # Show or hide the advanced search options. showLess = self.Sizer.IsShown(self.moreSizer) self.Sizer.Show(self.moreSizer, not showLess) # Update appropriate strings, and make them fully translatable. self.moreButton.State = showLess if showLess: tipActionStr = _("Show advanced search options") else: tipActionStr = _("Hide advanced search options") self.moreButton.SetToolTipString(tipActionStr) # Give or take the appropriate amount of space. self.Parent.Layout() Publisher.sendMessage("SEARCH.MORETOGGLED")
def testAnnouncedAccountHasParent(self): """ Make sure the account has a Parent when it announces itself. To do this we need to test this in a listener. """ parent = [] def listener(message): account = message.data parent.append(account.Parent) # Subscribe our listener Publisher.subscribe(listener, "account.created") # Create an account, which should trigger the listener baby = self.Model.CreateAccount("Baby") # Make sure the listener updated state appropriately self.assertTrue(parent)
def __init__(self, parent, row): bankcontrols.GBRow.__init__(self, parent, row) self.accountDict = {} self.nullChoice = ["----------"] self.fromtoBox = wx.Choice(parent, choices=[_("from"), _("to")]) self.accountSelection = wx.Choice(parent, choices=[]) hSizer = wx.BoxSizer() hSizer.Add(wx.StaticText(parent, label=_("Transfer")), flag=wx.ALIGN_CENTER_VERTICAL) hSizer.AddSpacer(3) hSizer.Add(self.fromtoBox, flag=wx.ALIGN_CENTER_VERTICAL) self.AddNext(hSizer) self.AddNext(self.accountSelection) Publisher.subscribe(self.onAccountChanged, "view.account changed")
def getTransactionsFrom(self, account): transactions = TransactionList() # Generate a map of recurring transaction IDs to the objects for fast look-up. recurringCache = {} for recurring in account.Parent.GetRecurringTransactions(): recurringCache[recurring.ID] = recurring Publisher.sendMessage("batch.start") for result in self.dbconn.cursor().execute( 'SELECT * FROM transactions WHERE accountId=?', (account.ID, )).fetchall(): t = self.result2transaction(result, account, recurringCache=recurringCache) transactions.append(t) Publisher.sendMessage("batch.end") return transactions
def testDirtyExitWarns(self): """ This test is kind of hilarious. We want to make sure we are warned of exiting with a dirty model, so we create an account, register a callback which will change its name when the dirty warning goes out, then trigger a dirty exit and make sure the account name has changed. """ self.Controller.AutoSave = False a = self.Model.CreateAccount("Unwarned!") # Create and register our callback to test for the warning message. def cb(message): a.Name = "Warned" Publisher.subscribe(cb, "warning.dirty exit") # Now send the exiting message, which should cause our callback to fire if everything is well. Publisher.sendMessage("exiting") self.assertEqual(a.Name, "Warned")
def SelectItem(self, index): """Given an index (zero-based), select the appropriate account.""" if index is None: account = None self.allAccountsRadio.Value = True else: account = self.accountObjects[index] # Set the value in case it wasn't a click that triggered this. self.radioButtons[index].Value = True self.currentIndex = index # Update the remove/edit buttons. self.removeButton.Enabled = index is not None self.editButton.Enabled = index is not None self.configureButton.Enabled = index is not None # Inform everyone that we've changed. This is different from the 'user.account changed' event, # as account changes are also triggered by account removals and additions. Publisher.sendMessage("view.account changed", account) return account
def __init__(self, path=None): self._AutoSave = True self._ShowZeroBalanceAccounts = True self._ShowCurrencyNick = True self.Models = [] self.InitConfig() self.LoadPath(path, use=True) Publisher.subscribe(self.onAutoSaveToggled, "user.autosave_toggled") Publisher.subscribe(self.onShowZeroToggled, "user.showzero_toggled") Publisher.subscribe(self.onShowCurrencyNickToggled, "user.show_currency_nick_toggled") Publisher.subscribe(self.onSaveRequest, "user.saved")
def __init__(self, parent, bankController): wx.Panel.__init__(self, parent) self.searchActive = False subpanel = wx.Panel(self) # The search control self.searchCtrl = searchctrl.SearchCtrl(self, bankController) self.transactionCtrl = transactionCtrl = TransactionCtrl(subpanel, bankController) self.newTransCtrl = newTransCtrl = transactionctrl.TransactionCtrl(self) subpanel.Sizer = wx.BoxSizer() subpanel.Sizer.Add(transactionCtrl, 1, wx.EXPAND) self.Sizer = wx.BoxSizer(wx.VERTICAL) self.Sizer.Add(self.searchCtrl, 0, wx.ALIGN_RIGHT|wx.RIGHT, 6) self.Sizer.Add(subpanel, 1, wx.EXPAND) self.Sizer.Add(newTransCtrl, 0, wx.EXPAND|wx.LEFT, 6) self.Sizer.AddSpacer(3) for message in ["account.created", "account.removed"]: Publisher.subscribe(self.onSearchInvalidatingChange, message)
def __init__(self, parent): wx.Panel.__init__(self, parent) self.numberClears = True sizer = wx.BoxSizer(wx.VERTICAL) self.display = wx.TextCtrl(self, -1, '0.00', style=wx.TE_RIGHT) self.display.Bind(wx.EVT_CHAR, self.onChar) sizer.Add(self.display, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 4) gs = wx.GridSizer(5, 4, 3, 3) for lbl in "C ()789/456*123-0.+=": if not lbl == ' ': btn = wx.Button(self, label=lbl) btn.Bind(wx.EVT_BUTTON, self.onButton) else: btn = wx.StaticText(self) gs.Add(btn, 1, wx.EXPAND) sizer.Add(gs, 1, wx.EXPAND) self.SetSizer(sizer) Publisher.subscribe(self.onPushChars, "CALCULATOR.PUSH_CHARS") wx.CallLater(50, self.display.SetInsertionPointEnd)