Exemple #1
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 #2
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 #3
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 #4
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 #5
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 #6
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 #7
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 #8
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 #9
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()
Exemple #10
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 #11
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 #12
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 #13
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 #14
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 #15
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 #16
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)
    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 #18
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 #20
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 #21
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 #22
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 #23
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 #24
0
    def __init__(self, bankController, welcome):
        # Load our window settings.
        config = wx.Config.Get()
        size = config.ReadInt('SIZE_X'), config.ReadInt('SIZE_Y')
        pos = config.ReadInt('POS_X'), config.ReadInt('POS_Y')

        BrandedFrame.__init__(self, None, title="wxBanker", size=size, pos=pos)

        self.Panel = BankerPanel(self, bankController)

        Publisher.subscribe(self.onQuit, "quit")
        Publisher.subscribe(self.onWarning, "warning")
        
        if welcome:
            Publisher.subscribe(self.onFirstRun, "first run")

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_MOVE, self.OnMove)
        self.Bind(wx.EVT_CLOSE, self.OnClose)

        menuBar = BankMenuBar(bankController)
        self.SetMenuBar(menuBar)
        #self.CreateStatusBar()

        self.Bind(wx.EVT_MENU, menuBar.onMenuEvent)
Exemple #25
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(4, 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)
Exemple #26
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 #27
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)
Exemple #28
0
    def __init__(self, parent, bankController):
        wx.Panel.__init__(self, parent)

        ## Left side, the account list and calculator
        self.leftPanel = leftPanel = wx.Panel(self)
        leftPanel.Sizer = wx.BoxSizer(wx.VERTICAL)

        self.accountCtrl = accountCtrl = accountlistctrl.AccountListCtrl(leftPanel, bankController)
        
        calcWidget = CollapsableWidget(leftPanel, SimpleCalculator, (_("Show Calculator"), _("Hide Calculator")))

        leftPanel.Sizer.Add(accountCtrl, 0, wx.EXPAND)
        leftPanel.Sizer.AddStretchSpacer(1)
        leftPanel.Sizer.Add(calcWidget, 0, wx.EXPAND)

        # Force the calculator widget (and parent) to take on the desired size.
        for widget in [calcWidget.widget, leftPanel]:
            widget.SetMinSize((accountCtrl.BestSize[0], -1))

        ## Right side, the transaction panel:
        self.tabPanel = TabPanel(self, bankController)

        self.Sizer = topSizer = wx.BoxSizer()
        topSizer.Add(leftPanel, 0, wx.EXPAND|wx.ALL, 5)
        topSizer.Add(self.tabPanel, 1, wx.EXPAND|wx.ALL, 0)

        # Subscribe to messages that interest us.
        Publisher.subscribe(self.onChangeAccount, "view.account changed")
        Publisher.subscribe(self.onCalculatorToggled, "CALCULATOR.TOGGLED")

        # Select the last-selected account.
        # Windows needs a delay, to work around LP #339860.
        wx.CallLater(50, Publisher.sendMessage, "user.account changed", bankController.Model.GetLastAccount())

        self.Layout()

        # Ensure the calculator is displayed as desired.
        calcWidget.SetExpanded(wx.Config.Get().ReadBool("SHOW_CALC"))
Exemple #29
0
    def __init__(self, parent, bankController, autoPopulate=True):
        wx.Panel.__init__(self, parent, name="AccountListCtrl")
        self.bankController = bankController
        self.Model = bankController.Model

        # Initialize some attributes to their default values.
        self.editCtrl = self.hiddenIndex = None
        self.currentIndex = None
        self.radioButtons, self.totalTexts, self.accountObjects, self.mintStatuses = [], [], [], []

        # Create the staticboxsizer which is the home for everything.
        # This *MUST* be created first to ensure proper z-ordering (as per docs).
        self.staticBox = wx.StaticBox(self, label=_("Accounts"))

        # Create a single panel to be the "child" of the static box sizer,
        # to work around a wxPython regression that prevents tooltips. lp: xxxxxx
        self.childPanel = wx.Panel(self)
        self.childSizer = childSizer = wx.BoxSizer(wx.VERTICAL)

        ## Create and set up the buttons.
        # The ADD account button.
        BMP = self.addBMP = wx.ArtProvider.GetBitmap('wxART_add')
        self.addButton = addButton = bankcontrols.FlashableButton(self.childPanel, bitmap=BMP)
        addButton.SetToolTipString(_("Add a new account"))
        # The REMOVE account button.
        BMP = wx.ArtProvider.GetBitmap('wxART_delete')
        self.removeButton = removeButton = wx.BitmapButton(self.childPanel, bitmap=BMP)
        removeButton.SetToolTipString(_("Remove the selected account"))
        removeButton.Enabled = False
        # The EDIT account button.
        BMP = wx.ArtProvider.GetBitmap('wxART_textfield_rename')
        self.editButton = editButton = wx.BitmapButton(self.childPanel, bitmap=BMP)
        editButton.SetToolTipString(_("Rename the selected account"))
        editButton.Enabled = False
        # The CONFIGURE account button.
        BMP = wx.ArtProvider.GetBitmap('wxART_cog')
        self.configureButton = configureButton = wx.BitmapButton(self.childPanel, bitmap=BMP)
        configureButton.SetToolTipString(_("Configure the selected account"))
        configureButton.Enabled = False

        # Layout the buttons.
        buttonSizer = wx.BoxSizer()
        buttonSizer.Add(addButton)
        buttonSizer.AddSpacer(6)
        buttonSizer.Add(editButton)
        buttonSizer.AddSpacer(6)
        buttonSizer.Add(configureButton)
        buttonSizer.AddSpacer(6)
        buttonSizer.Add(removeButton)

        # Set up the "Total" sizer.
        self.totalText = wx.StaticText(self.childPanel, label=self.Model.float2str(0))
        self.totalTexts.append(self.totalText)
        miniSizer = wx.BoxSizer()
        self.allAccountsRadio = wx.RadioButton(self.childPanel, label=_("All accounts"))
        miniSizer.Add(self.allAccountsRadio, 1, wx.ALIGN_CENTER)
        miniSizer.Add(self.totalText, 0, wx.ALIGN_CENTER|wx.LEFT, 10)
        miniSizer.AddSpacer(3)

        #self.staticBoxSizer = SmoothStaticBoxSizer(self.staticBox, wx.VERTICAL)
        self.staticBoxSizer = wx.StaticBoxSizer(self.staticBox, wx.VERTICAL)
        #self.staticBoxSizer.SetSmooth(False)
        childSizer.Add(buttonSizer, 0, wx.BOTTOM, 9)
        # Add just a tiny bit of padding between the accounts and the total item.
        childSizer.AddSpacer(3)
        childSizer.Add(miniSizer, 0, wx.EXPAND)
        self.childPanel.Sizer = childSizer
        self.staticBoxSizer.Add(self.childPanel, 1, wx.EXPAND)

        # Set up the button bindings.
        addButton.Bind(wx.EVT_BUTTON, self.onAddButton)
        removeButton.Bind(wx.EVT_BUTTON, self.onRemoveButton)
        editButton.Bind(wx.EVT_BUTTON, self.onRenameButton)
        configureButton.Bind(wx.EVT_BUTTON, self.onConfigureButton)
        # Set up the link binding.
        self.Bind(wx.EVT_RADIOBUTTON, self.onAccountClick)

        # Subscribe to messages we are concerned about.
        Publisher.subscribe(self.onAccountBalanceChanged, "ormobject.updated.Account.Balance")
        Publisher.subscribe(self.onAccountRenamed, "ormobject.updated.Account.Name")
        Publisher.subscribe(self.onTransactionDateChanged, "ormobject.updated.Transaction.Date")
        Publisher.subscribe(self.onAccountMintIdChanged, "ormobject.updated.Account.MintId")
        Publisher.subscribe(self.onAccountRemoved, "account.removed")
        Publisher.subscribe(self.onAccountAdded, "account.created")
        Publisher.subscribe(self.onCurrencyChanged, "currency_changed")
        Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled")
        Publisher.subscribe(self.onShowCurrencyNickToggled, "controller.show_currency_nick_toggled")
        Publisher.subscribe(self.onAccountChanged, "user.account changed")
        Publisher.subscribe(self.onSelectNextAccount, "user.next account")
        Publisher.subscribe(self.onSelectPreviousAccount, "user.previous account")
        Publisher.subscribe(self.onToggleMintIntegration, "user.mint.toggled")
        Publisher.subscribe(self.onMintDataUpdated, "mint.updated")

        # Populate ourselves initially unless explicitly told not to.
        if autoPopulate:
            for account in self.Model.Accounts:
                self._PutAccount(account)

        self.Sizer = self.staticBoxSizer
        # Set the minimum size to the amount it needs to display the edit box.
        self.Freeze()
        self.showEditCtrl(focus=False)
        minWidth = max((self.staticBoxSizer.CalcMin()[0], 250))
        self.onHideEditCtrl()
        self.Thaw()
        self.staticBoxSizer.SetMinSize((minWidth, -1))
        
        # Initially load the visibility of zero-balance accounts!
        # Don't refresh the selection or we'll send an account changed message which will overwrite the LastAccountId before it gets used!
        self.refreshVisibility(refreshSelection=False)

        self.staticBoxSizer.Layout()
        #self.staticBoxSizer.SetSmooth(True)

        if not self.GetCount():
            self.addButton.StartFlashing()
Exemple #30
0
    def __init__(self, parent, bankController, autoPopulate=True):
        wx.Panel.__init__(self, parent, name="AccountListCtrl")
        self.bankController = bankController
        self.Model = bankController.Model

        # Initialize some attributes to their default values.
        self.editCtrl = self.hiddenIndex = None
        self.currentIndex = None
        self.radioButtons, self.totalTexts, self.accountObjects, self.mintStatuses = [], [], [], []

        # Create the staticboxsizer which is the home for everything.
        # This *MUST* be created first to ensure proper z-ordering (as per docs).
        self.staticBox = wx.StaticBox(self, label=_("Accounts"))

        # Create a single panel to be the "child" of the static box sizer,
        # to work around a wxPython regression that prevents tooltips. lp: xxxxxx
        self.childPanel = wx.Panel(self)
        self.childSizer = childSizer = wx.BoxSizer(wx.VERTICAL)

        ## Create and set up the buttons.
        # The ADD account button.
        BMP = self.addBMP = wx.ArtProvider.GetBitmap('wxART_add')
        self.addButton = addButton = bankcontrols.FlashableButton(
            self.childPanel, bitmap=BMP)
        addButton.SetToolTipString(_("Add a new account"))
        # The REMOVE account button.
        BMP = wx.ArtProvider.GetBitmap('wxART_delete')
        self.removeButton = removeButton = wx.BitmapButton(self.childPanel,
                                                           bitmap=BMP)
        removeButton.SetToolTipString(_("Remove the selected account"))
        removeButton.Enabled = False
        # The EDIT account button.
        BMP = wx.ArtProvider.GetBitmap('wxART_textfield_rename')
        self.editButton = editButton = wx.BitmapButton(self.childPanel,
                                                       bitmap=BMP)
        editButton.SetToolTipString(_("Rename the selected account"))
        editButton.Enabled = False
        # The CONFIGURE account button.
        BMP = wx.ArtProvider.GetBitmap('wxART_cog')
        self.configureButton = configureButton = wx.BitmapButton(
            self.childPanel, bitmap=BMP)
        configureButton.SetToolTipString(_("Configure the selected account"))
        configureButton.Enabled = False

        # Layout the buttons.
        buttonSizer = wx.BoxSizer()
        buttonSizer.Add(addButton)
        buttonSizer.AddSpacer(6)
        buttonSizer.Add(editButton)
        buttonSizer.AddSpacer(6)
        buttonSizer.Add(configureButton)
        buttonSizer.AddSpacer(6)
        buttonSizer.Add(removeButton)

        # Set up the "Total" sizer.
        self.totalText = wx.StaticText(self.childPanel,
                                       label=self.Model.float2str(0))
        self.totalTexts.append(self.totalText)
        miniSizer = wx.BoxSizer()
        self.allAccountsRadio = wx.RadioButton(self.childPanel,
                                               label=_("All accounts"))
        miniSizer.Add(self.allAccountsRadio, 1, wx.ALIGN_CENTER)
        miniSizer.Add(self.totalText, 0, wx.ALIGN_CENTER | wx.LEFT, 10)
        miniSizer.AddSpacer(3)

        #self.staticBoxSizer = SmoothStaticBoxSizer(self.staticBox, wx.VERTICAL)
        self.staticBoxSizer = wx.StaticBoxSizer(self.staticBox, wx.VERTICAL)
        #self.staticBoxSizer.SetSmooth(False)
        childSizer.Add(buttonSizer, 0, wx.BOTTOM, 9)
        # Add just a tiny bit of padding between the accounts and the total item.
        childSizer.AddSpacer(3)
        childSizer.Add(miniSizer, 0, wx.EXPAND)
        self.childPanel.Sizer = childSizer
        self.staticBoxSizer.Add(self.childPanel, 1, wx.EXPAND)

        # Set up the button bindings.
        addButton.Bind(wx.EVT_BUTTON, self.onAddButton)
        removeButton.Bind(wx.EVT_BUTTON, self.onRemoveButton)
        editButton.Bind(wx.EVT_BUTTON, self.onRenameButton)
        configureButton.Bind(wx.EVT_BUTTON, self.onConfigureButton)
        # Set up the link binding.
        self.Bind(wx.EVT_RADIOBUTTON, self.onAccountClick)

        # Subscribe to messages we are concerned about.
        Publisher.subscribe(self.onAccountBalanceChanged,
                            "ormobject.updated.Account.Balance")
        Publisher.subscribe(self.onAccountRenamed,
                            "ormobject.updated.Account.Name")
        Publisher.subscribe(self.onTransactionDateChanged,
                            "ormobject.updated.Transaction.Date")
        Publisher.subscribe(self.onAccountMintIdChanged,
                            "ormobject.updated.Account.MintId")
        Publisher.subscribe(self.onAccountRemoved, "account.removed")
        Publisher.subscribe(self.onAccountAdded, "account.created")
        Publisher.subscribe(self.onCurrencyChanged, "currency_changed")
        Publisher.subscribe(self.onShowZeroToggled,
                            "controller.showzero_toggled")
        Publisher.subscribe(self.onShowCurrencyNickToggled,
                            "controller.show_currency_nick_toggled")
        Publisher.subscribe(self.onAccountChanged, "user.account changed")
        Publisher.subscribe(self.onSelectNextAccount, "user.next account")
        Publisher.subscribe(self.onSelectPreviousAccount,
                            "user.previous account")
        Publisher.subscribe(self.onToggleMintIntegration, "user.mint.toggled")
        Publisher.subscribe(self.onMintDataUpdated, "mint.updated")

        # Populate ourselves initially unless explicitly told not to.
        if autoPopulate:
            for account in self.Model.Accounts:
                self._PutAccount(account)

        self.Sizer = self.staticBoxSizer
        # Set the minimum size to the amount it needs to display the edit box.
        self.Freeze()
        self.showEditCtrl(focus=False)
        minWidth = max((self.staticBoxSizer.CalcMin()[0], 250))
        self.onHideEditCtrl()
        self.Thaw()
        self.staticBoxSizer.SetMinSize((minWidth, -1))

        # Initially load the visibility of zero-balance accounts!
        # Don't refresh the selection or we'll send an account changed message which will overwrite the LastAccountId before it gets used!
        self.refreshVisibility(refreshSelection=False)

        self.staticBoxSizer.Layout()
        #self.staticBoxSizer.SetSmooth(True)

        if not self.GetCount():
            self.addButton.StartFlashing()
Exemple #31
0
    def __init__(self, bankController, *args, **kwargs):
        wx.MenuBar.__init__(self, *args, **kwargs)
        self.bankController = bankController
        autosave = bankController.AutoSave
        showZero = bankController.ShowZeroBalanceAccounts
        showcurrnick = bankController.ShowCurrencyNick
        self.currencyStrings = CurrencyStrings[:]

        # File menu.
        fileMenu = wx.Menu()
        self.saveMenuItem = fileMenu.Append(wx.ID_SAVE)
        self.autoSaveMenuItem = fileMenu.AppendCheckItem(self.ID_AUTOSAVE, _("Auto-save"), _("Automatically save changes"))
        fileMenu.AppendSeparator()
        importCsvMenu = fileMenu.Append(self.ID_IMPORT_CSV, _("Import from CSV"), _("Import transactions from a CSV file"))
        exportCsvMenu = fileMenu.Append(self.ID_EXPORT_CSV, _("Export to CSV"), _("Export transactions to a CSV file"))
        fileMenu.AppendSeparator()
        quitItem = fileMenu.Append(wx.ID_EXIT)
        
        # View menu.
        viewMenu = wx.Menu()
        viewMenu.Append(self.ID_VIEW_PREVACCOUNT, _("Previous account")+"\tCtrl+J")
        viewMenu.Append(self.ID_VIEW_NEXTACCOUNT, _("Next account")+"\tCtrl+K")
        viewMenu.Append(self.ID_VIEW_ALLACCOUNTS, _("All accounts")+"\tCtrl+T") 
        viewMenu.AppendSeparator()
        self.showZeroMenuItem = viewMenu.AppendCheckItem(self.ID_SHOWZERO, _("Show zero-balance accounts")+"\tCtrl+B", _("When disabled, accounts with a balance of $0.00 will be hidden from the list"))
        
        # Use the initial show-zero setting.
        self.showZeroMenuItem.Check(showZero)

        # Settings menu.
        settingsMenu = wx.Menu()

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        currencyMenu = wx.MenuItem(settingsMenu, -1, _("Base &currency"), _("Select currency for the 'All Accounts' balance"))
        currencyMenu.SetBitmap(wx.ArtProvider.GetBitmap("wxART_money"))

        # Add an entry for each available currency.
        currencies = wx.Menu()
        # Place the local detected one first, then the rest sorted.
        currencies.Append(self.IDS_CURRENCIES[0], self.currencyStrings[0])
        currencies.AppendSeparator()
        for i, cstr in enumerate(sorted(self.currencyStrings[1:])):
            idIndex = self.currencyStrings.index(cstr)
            item = wx.MenuItem(currencies, self.IDS_CURRENCIES[idIndex], cstr)
            currencies.AppendItem(item)
        # Add an entry to request a new currency.
        requestCurrencyItem = wx.MenuItem(currencies, self.ID_REQUESTCURRENCY, _("Request a Currency"))
        requestCurrencyItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_lightning")
        currencies.AppendSeparator()
        currencies.AppendItem(requestCurrencyItem)
        currencyMenu.SetSubMenu(currencies)

        settingsMenu.AppendItem(currencyMenu)
        
        self.showCurrencyNickItem = settingsMenu.AppendCheckItem(self.ID_SHOWCURRENCYNICK, _("Show currency names"), _("Show currency names with amounts"))

        self.mintEnabledItem = settingsMenu.AppendCheckItem(self.ID_MINTINTEGRATION, _("Integrate with Mint.com"), _("Sync account balances with an existing Mint.com account"))

        # Help menu.
        helpMenu = wx.Menu()

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        faqItem = wx.MenuItem(helpMenu, self.ID_FAQ, _("View &FAQs"), _("View Frequently Asked Questions online"))
        faqItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_comments")
        helpMenu.AppendItem(faqItem)

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        questionItem = wx.MenuItem(helpMenu, self.ID_QUESTION, _("Ask a &Question"), _("Ask a question online"))
        questionItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_user_comment")
        helpMenu.AppendItem(questionItem)

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        bugItem = wx.MenuItem(helpMenu, self.ID_REPORTBUG, _("&Report a Bug"), _("Report a bug to the developer online"))
        bugItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_bug")
        helpMenu.AppendItem(bugItem)

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        featureItem = wx.MenuItem(helpMenu, self.ID_REQUESTFEATURE, _("Request a Fea&ture"), _("Request a new feature to be implemented"))
        featureItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_lightbulb")
        helpMenu.AppendItem(featureItem)

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        translateItem = wx.MenuItem(helpMenu, self.ID_TRANSLATE, _("Tran&slate wxBanker"), _("Translate wxBanker to another language"))
        translateItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_flag_blue")
        helpMenu.AppendItem(translateItem)

        helpMenu.AppendSeparator()

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        aboutItem = helpMenu.Append(wx.ID_ABOUT, _("&About"), _("More information about wxBanker"))

        # Add everything to the main menu.
        self.Append(fileMenu, _("&File"))
        self.Append(viewMenu, _("&View"))
        self.Append(settingsMenu, _("&Settings"))
        self.Append(helpMenu, _("&Help"))

        self.toggleAutoSave(autosave)
        self.toggleShowCurrencyNick(showcurrnick)
        Publisher.subscribe(self.onAutoSaveToggled, "controller.autosave_toggled")
        Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled")
        Publisher.subscribe(self.onShowCurrencyNickToggled, "controller.show_currency_nick_toggled")
        # Subscribe to a Mint update event, which tells us the checkbox should be enabled after startup.
        Publisher.subscribe(self.onMintUpdate, "mint.updated")
    def __init__(self, parent, row, editing=None):
        bankcontrols.GBRow.__init__(self,
                                    parent,
                                    row,
                                    name="NewTransactionCtrl")
        self.CurrentAccount = editing
        self.isInitialAccountSet = False

        self.dateCtrl = bankcontrols.DateCtrlFactory(parent)
        self.startText = wx.StaticText(parent, label=_("Starts:"))

        # The Description and Amount controls.
        handler = self.dateCtrl.customKeyHandler
        self.descCtrl = bankcontrols.HintedTextCtrl(parent,
                                                    size=(140, -1),
                                                    style=wx.TE_PROCESS_ENTER,
                                                    hint=_("Description"),
                                                    icon="wxART_page_edit",
                                                    handler=handler)
        self.amountCtrl = bankcontrols.HintedTextCtrl(
            parent,
            size=(90, -1),
            style=wx.TE_PROCESS_ENTER | wx.TE_RIGHT,
            hint=_("Amount"),
            icon="wxART_money_dollar",
            handler=handler)

        # The add button.
        self.newButton = bankcontrols.FlashableButton(
            parent, bitmap=wx.ArtProvider.GetBitmap('wxART_money_add'))
        self.newButton.SetToolTipString(_("Enter this transaction"))

        checkSizer = wx.BoxSizer(wx.VERTICAL)

        # The transfer check.
        self.transferCheck = wx.CheckBox(parent, label=_("Transfer"))
        checkSizer.Add(self.transferCheck, 0, wx.RIGHT, 6)

        # The recurs check.
        self.recursCheck = wx.CheckBox(parent, label=_("Recurring"))
        checkSizer.Add(self.recursCheck, 0, wx.RIGHT, 6)

        # Checkboxes seem to have an overly large horizontal margin that looks bad.
        for check in (self.transferCheck, self.recursCheck):
            x, y = check.BestSize
            check.SetMinSize((x, y - 4))

        # Set up the layout.
        dateSizer = wx.BoxSizer()
        dateSizer.Add(self.startText, flag=wx.ALIGN_CENTER)
        dateSizer.Add(
            wx.StaticBitmap(parent,
                            bitmap=wx.ArtProvider.GetBitmap('wxART_date')), 0,
            wx.ALIGN_CENTER | wx.RIGHT, 2)
        dateSizer.Add(self.dateCtrl, flag=wx.ALIGN_CENTER | wx.EXPAND)
        self.startText.Hide()

        hSizer = wx.BoxSizer()
        hSizer.Add(self.amountCtrl, 0, wx.ALIGN_CENTER)
        hSizer.AddSpacer(5)
        hSizer.Add(self.newButton, 0, wx.ALIGN_CENTER)
        hSizer.AddSpacer(5)
        hSizer.Add(checkSizer, 0, wx.ALIGN_CENTER)

        descSizer = wx.BoxSizer()
        descSizer.Add(self.descCtrl, 1, flag=wx.ALIGN_CENTER)

        self.AddNext(dateSizer)
        self.AddNext(descSizer, flag=wx.EXPAND)
        self.AddNext(hSizer)

        # Initialize necessary bindings.
        parent.Bind(
            wx.EVT_TEXT_ENTER,
            self.onNewTransaction)  # Gives us enter from description/amount.
        self.newButton.Bind(wx.EVT_BUTTON, self.onNewTransaction)
        self.recursCheck.Bind(wx.EVT_CHECKBOX, self.onRecurringCheck)
        self.transferCheck.Bind(wx.EVT_CHECKBOX, self.onTransferCheck)

        try:
            self.amountCtrl.Children[0].Bind(wx.EVT_CHAR, self.onAmountChar)
        except IndexError:
            # On OSX for example, a SearchCtrl is native and has no Children.
            pass

        try:
            dateTextCtrl = self.dateCtrl.Children[0].Children[0]
        except IndexError:
            # This will fail on MSW + wxPython < 2.8.8.0, nothing we can do.
            pass
        else:
            # Bind to DateCtrl Enter (LP: 252454).
            dateTextCtrl.WindowStyleFlag |= wx.TE_PROCESS_ENTER
            dateTextCtrl.Bind(wx.EVT_TEXT_ENTER, self.onDateEnter)

        # If we are editing, it is inherently a recurring transaction.
        if editing:
            self.recursCheck.Hide()
            self.newButton.Hide()
        else:
            # Only subscribe to the event and set focus if it is the permanent control (LP: #623238)
            Publisher.subscribe(self.onAccountChanged, "view.account changed")
            wx.CallLater(50, self.initialFocus)
Exemple #33
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 __init__(self, parent, row, editing=None):
        bankcontrols.GBRow.__init__(self, parent, row, name="NewTransactionCtrl")
        self.CurrentAccount = editing
        self.isInitialAccountSet = False

        self.dateCtrl = bankcontrols.DateCtrlFactory(parent)
        self.startText = wx.StaticText(parent, label=_("Starts:"))

        # The Description and Amount controls.
        handler = self.dateCtrl.customKeyHandler
        self.descCtrl = bankcontrols.HintedTextCtrl(parent, size=(140, -1), style=wx.TE_PROCESS_ENTER, hint=_("Description"), icon="wxART_page_edit", handler=handler)
        self.amountCtrl = bankcontrols.HintedTextCtrl(parent, size=(90, -1), style=wx.TE_PROCESS_ENTER|wx.TE_RIGHT, hint=_("Amount"), icon="wxART_money_dollar", handler=handler)
        
        # The add button.
        self.newButton = bankcontrols.FlashableButton(parent, bitmap=wx.ArtProvider.GetBitmap('wxART_money_add'))
        self.newButton.SetToolTipString(_("Enter this transaction"))

        checkSizer = wx.BoxSizer(wx.VERTICAL)
        
        # The transfer check.
        self.transferCheck = wx.CheckBox(parent, label=_("Transfer"))
        checkSizer.Add(self.transferCheck, 0, wx.RIGHT, 6)
        
        # The recurs check.
        self.recursCheck = wx.CheckBox(parent, label=_("Recurring"))
        checkSizer.Add(self.recursCheck, 0, wx.RIGHT, 6)

        # Checkboxes seem to have an overly large horizontal margin that looks bad.
        for check in (self.transferCheck, self.recursCheck):
            x, y = check.BestSize
            check.SetMinSize((x, y-4))

        # Set up the layout.
        dateSizer = wx.BoxSizer()
        dateSizer.Add(self.startText, flag=wx.ALIGN_CENTER)
        dateSizer.Add(wx.StaticBitmap(parent, bitmap=wx.ArtProvider.GetBitmap('wxART_date')), 0, wx.ALIGN_CENTER|wx.RIGHT, 2)
        dateSizer.Add(self.dateCtrl, flag=wx.ALIGN_CENTER|wx.EXPAND)
        self.startText.Hide()
        
        hSizer = wx.BoxSizer()
        hSizer.Add(self.amountCtrl, 0, wx.ALIGN_CENTER)
        hSizer.AddSpacer(5)
        hSizer.Add(self.newButton, 0, wx.ALIGN_CENTER)
        hSizer.AddSpacer(5)
        hSizer.Add(checkSizer, 0, wx.ALIGN_CENTER)
        
        descSizer = wx.BoxSizer()
        descSizer.Add(self.descCtrl, 1, flag=wx.ALIGN_CENTER)
        
        self.AddNext(dateSizer)
        self.AddNext(descSizer, flag=wx.EXPAND)
        self.AddNext(hSizer)
        
        # Initialize necessary bindings.
        parent.Bind(wx.EVT_TEXT_ENTER, self.onNewTransaction) # Gives us enter from description/amount.
        self.newButton.Bind(wx.EVT_BUTTON, self.onNewTransaction)
        self.recursCheck.Bind(wx.EVT_CHECKBOX, self.onRecurringCheck)
        self.transferCheck.Bind(wx.EVT_CHECKBOX, self.onTransferCheck)

        try:
            self.amountCtrl.Children[0].Bind(wx.EVT_CHAR, self.onAmountChar)
        except IndexError:
            # On OSX for example, a SearchCtrl is native and has no Children.
            pass

        try:
            dateTextCtrl = self.dateCtrl.Children[0].Children[0]
        except IndexError:
            # This will fail on MSW + wxPython < 2.8.8.0, nothing we can do.
            pass
        else:
            # Bind to DateCtrl Enter (LP: 252454).
            dateTextCtrl.WindowStyleFlag |= wx.TE_PROCESS_ENTER
            dateTextCtrl.Bind(wx.EVT_TEXT_ENTER, self.onDateEnter)
            
    
        # If we are editing, it is inherently a recurring transaction.
        if editing:
            self.recursCheck.Hide()
            self.newButton.Hide()
        else:
            # Only subscribe to the event and set focus if it is the permanent control (LP: #623238)
            Publisher.subscribe(self.onAccountChanged, "view.account changed")
            wx.CallLater(50, self.initialFocus)
Exemple #35
0
    def __init__(self, bankController, *args, **kwargs):
        wx.MenuBar.__init__(self, *args, **kwargs)
        self.bankController = bankController
        autosave = bankController.AutoSave
        showZero = bankController.ShowZeroBalanceAccounts
        showcurrnick = bankController.ShowCurrencyNick
        self.currencyStrings = CurrencyStrings[:]

        # File menu.
        fileMenu = wx.Menu()
        self.saveMenuItem = fileMenu.Append(wx.ID_SAVE)
        self.autoSaveMenuItem = fileMenu.AppendCheckItem(self.ID_AUTOSAVE, _("Auto-save"), _("Automatically save changes"))
        fileMenu.AppendSeparator()
        importCsvMenu = fileMenu.Append(self.ID_IMPORT_CSV, _("Import from CSV"), _("Import transactions from a CSV file"))
        exportCsvMenu = fileMenu.Append(self.ID_EXPORT_CSV, _("Export to CSV"), _("Export transactions to a CSV file"))
        fileMenu.AppendSeparator()
        quitItem = fileMenu.Append(wx.ID_EXIT)
        
        # View menu.
        viewMenu = wx.Menu()
        viewMenu.Append(self.ID_VIEW_PREVACCOUNT, _("Previous account")+"\tCtrl+J")
        viewMenu.Append(self.ID_VIEW_NEXTACCOUNT, _("Next account")+"\tCtrl+K")
        viewMenu.Append(self.ID_VIEW_ALLACCOUNTS, _("All accounts")+"\tCtrl+T") 
        viewMenu.AppendSeparator()
        self.showZeroMenuItem = viewMenu.AppendCheckItem(self.ID_SHOWZERO, _("Show zero-balance accounts")+"\tCtrl+B", _("When disabled, accounts with a balance of $0.00 will be hidden from the list"))
        
        # Use the initial show-zero setting.
        self.showZeroMenuItem.Check(showZero)

        # Settings menu.
        settingsMenu = wx.Menu()

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        currencyMenu = wx.MenuItem(settingsMenu, -1, _("Base &currency"), _("Select currency for the 'All Accounts' balance"))
        currencyMenu.SetBitmap(wx.ArtProvider.GetBitmap("wxART_money"))

        # Add an entry for each available currency.
        currencies = wx.Menu()
        # Place the local detected one first, then the rest sorted.
        currencies.Append(self.IDS_CURRENCIES[0], self.currencyStrings[0])
        currencies.AppendSeparator()
        for i, cstr in enumerate(sorted(self.currencyStrings[1:])):
            idIndex = self.currencyStrings.index(cstr)
            item = wx.MenuItem(currencies, self.IDS_CURRENCIES[idIndex], cstr)
            currencies.AppendItem(item)
        # Add an entry to request a new currency.
        requestCurrencyItem = wx.MenuItem(currencies, self.ID_REQUESTCURRENCY, _("Request a Currency"))
        requestCurrencyItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_lightning")
        currencies.AppendSeparator()
        currencies.AppendItem(requestCurrencyItem)
        currencyMenu.SetSubMenu(currencies)

        settingsMenu.AppendItem(currencyMenu)
        
        self.showCurrencyNickItem = settingsMenu.AppendCheckItem(self.ID_SHOWCURRENCYNICK, _("Show currency names"), _("Show currency names with amounts"))

        self.mintEnabledItem = settingsMenu.AppendCheckItem(self.ID_MINTINTEGRATION, _("Integrate with Mint.com"), _("Sync account balances with an existing Mint.com account"))

        # Help menu.
        helpMenu = wx.Menu()

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        faqItem = wx.MenuItem(helpMenu, self.ID_FAQ, _("View &FAQs"), _("View Frequently Asked Questions online"))
        faqItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_comments")
        helpMenu.AppendItem(faqItem)

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        questionItem = wx.MenuItem(helpMenu, self.ID_QUESTION, _("Ask a &Question"), _("Ask a question online"))
        questionItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_user_comment")
        helpMenu.AppendItem(questionItem)

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        bugItem = wx.MenuItem(helpMenu, self.ID_REPORTBUG, _("&Report a Bug"), _("Report a bug to the developer online"))
        bugItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_bug")
        helpMenu.AppendItem(bugItem)

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        featureItem = wx.MenuItem(helpMenu, self.ID_REQUESTFEATURE, _("Request a Fea&ture"), _("Request a new feature to be implemented"))
        featureItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_lightbulb")
        helpMenu.AppendItem(featureItem)

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        translateItem = wx.MenuItem(helpMenu, self.ID_TRANSLATE, _("Tran&slate wxBanker"), _("Translate wxBanker to another language"))
        translateItem.Bitmap = wx.ArtProvider.GetBitmap("wxART_flag_blue")
        helpMenu.AppendItem(translateItem)

        helpMenu.AppendSeparator()

        ## TRANSLATORS: Put the ampersand (&) before the letter to use as the Alt shortcut.
        aboutItem = helpMenu.Append(wx.ID_ABOUT, _("&About"), _("More information about wxBanker"))

        # Add everything to the main menu.
        self.Append(fileMenu, _("&File"))
        self.Append(viewMenu, _("&View"))
        self.Append(settingsMenu, _("&Settings"))
        self.Append(helpMenu, _("&Help"))

        self.Bind(wx.EVT_MENU, self.onClickAbout)
        helpMenu.Bind(wx.EVT_MENU, self.onClickAbout)

        self.toggleAutoSave(autosave)
        self.toggleShowCurrencyNick(showcurrnick)
        Publisher.subscribe(self.onAutoSaveToggled, "controller.autosave_toggled")
        Publisher.subscribe(self.onShowZeroToggled, "controller.showzero_toggled")
        Publisher.subscribe(self.onShowCurrencyNickToggled, "controller.show_currency_nick_toggled")
        # Subscribe to a Mint update event, which tells us the checkbox should be enabled after startup.
        Publisher.subscribe(self.onMintUpdate, "mint.updated")
Exemple #36
0
    def __init__(self, store):
        ORMKeyValueObject.__init__(self, store)
        self.Store = store
        self.Accounts = AccountList(self, store)
        self._Tags = {}

        # Handle Mint integration, but send the message in the main thread, otherwise, dead.
        if self.MintEnabled:
            delayedresult.startWorker(lambda result: Publisher.sendMessage("mint.updated"), Mint.LoginFromKeyring, wkwargs={"notify": False})

        Publisher.subscribe(self.onGlobalCurrencyChanged, "user.global_currency_changed")
        Publisher.subscribe(self.onAccountCurrencyChanged, "user.account_currency_changed")
        Publisher.subscribe(self.onMintToggled, "user.mint.toggled")
        Publisher.subscribe(self.onAccountChanged, "view.account changed")
        Publisher.subscribe(self.onTransactionTagged, "transaction.tagged")
        Publisher.subscribe(self.onTransactionUntagged, "transaction.untagged")