Exemple #1
0
    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()
Exemple #2
0
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
Exemple #3
0
    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")
Exemple #4
0
    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)
Exemple #5
0
    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)
Exemple #6
0
    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])
Exemple #7
0
 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()
Exemple #9
0
 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")
Exemple #10
0
    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")
Exemple #11
0
 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)
Exemple #12
0
    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()
Exemple #14
0
    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)
Exemple #15
0
 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)
Exemple #16
0
    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")
Exemple #17
0
    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()
Exemple #18
0
    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()
Exemple #19
0
    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")
Exemple #20
0
    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")
Exemple #21
0
    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")
Exemple #22
0
 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
Exemple #23
0
    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()
Exemple #24
0
    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")
Exemple #25
0
    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")
Exemple #26
0
    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)
Exemple #27
0
    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)
Exemple #28
0
    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)
Exemple #29
0
    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()
Exemple #31
0
 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
Exemple #32
0
    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)
Exemple #33
0
    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')
Exemple #34
0
 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")
Exemple #35
0
    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")
Exemple #36
0
    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
Exemple #37
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)
Exemple #38
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)
Exemple #39
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()
Exemple #40
0
    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
Exemple #41
0
    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)
Exemple #42
0
    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")
Exemple #43
0
    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)
Exemple #44
0
    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)
Exemple #45
0
    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")
Exemple #46
0
    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)
Exemple #47
0
    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, 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")
Exemple #49
0
    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, 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")
Exemple #51
0
    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")
Exemple #52
0
    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
Exemple #53
0
    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")
Exemple #54
0
    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")
Exemple #55
0
    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")
Exemple #56
0
    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
Exemple #57
0
    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)
Exemple #58
0
    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)