From a7161eda49cb154e63265b8edb65001e1525b30f Mon Sep 17 00:00:00 2001 From: Steve Youngs Date: Tue, 13 Dec 2011 17:55:55 +1000 Subject: [PATCH 1/1] Initial git import Signed-off-by: Steve Youngs --- .gitignore | 4 + ChangeLog.d/ChangeLog-0.1 | 29 + ChangeLog.d/ChangeLog-0.2 | 318 +++++++ ChangeLog.d/ChangeLog-0.3 | 69 ++ ChangeLog.d/ChangeLog-0.4 | 129 +++ ChangeLog.d/ChangeLog-0.5 | 40 + ChangeLog.d/ChangeLog.SFCVS | 206 +++++ Makefile | 169 ++++ TODO | 48 + codenames | 51 ++ emoney.el | 1676 +++++++++++++++++++++++++++++++++++ 11 files changed, 2739 insertions(+) create mode 100644 .gitignore create mode 100644 ChangeLog.d/ChangeLog-0.1 create mode 100644 ChangeLog.d/ChangeLog-0.2 create mode 100644 ChangeLog.d/ChangeLog-0.3 create mode 100644 ChangeLog.d/ChangeLog-0.4 create mode 100644 ChangeLog.d/ChangeLog-0.5 create mode 100644 ChangeLog.d/ChangeLog.SFCVS create mode 100644 Makefile create mode 100644 TODO create mode 100644 codenames create mode 100644 emoney.el diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5904682 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.elc +*~ +*.bak +emoney-version.el diff --git a/ChangeLog.d/ChangeLog-0.1 b/ChangeLog.d/ChangeLog-0.1 new file mode 100644 index 0000000..24717d5 --- /dev/null +++ b/ChangeLog.d/ChangeLog-0.1 @@ -0,0 +1,29 @@ +# do not edit -- automatically generated by arch changelog +# non-id: automatic-ChangeLog--steve@sxemacs.org--2004/emoney--main--0.1 +# + +2004-11-12 08:57:51 GMT Steve Youngs patch-1 + + Summary: + Remove ChangeLog file + Revision: + emoney--main--0.1--patch-1 + + + removed files: + .arch-ids/ChangeLog.id ChangeLog + + +2004-10-20 11:47:14 GMT Steve Youngs base-0 + + Summary: + Initial import + Revision: + emoney--main--0.1--base-0 + + Initial import of eMoney into arch + + new files: + ChangeLog ChangeLog.SFCVS Makefile codenames emoney.el + + diff --git a/ChangeLog.d/ChangeLog-0.2 b/ChangeLog.d/ChangeLog-0.2 new file mode 100644 index 0000000..2bd9dba --- /dev/null +++ b/ChangeLog.d/ChangeLog-0.2 @@ -0,0 +1,318 @@ +# do not edit -- automatically generated by arch changelog +# non-id: automatic-ChangeLog--steve@sxemacs.org--2005/emoney--main--0.2 +# + +2005-12-26 02:35:24 GMT Steve Youngs version-0 + + Summary: + eMoney 0.2 is released! + Revision: + emoney--main--0.2--version-0 + + eMoney 0.2 has been released. + + * emoney.el: Move "Todo" section into its own file. + + + new files: + .arch-ids/TODO.id TODO + + modified files: + emoney.el + + +2005-11-03 14:37:16 GMT Steve Youngs patch-12 + + Summary: + Typo fix + Revision: + emoney--main--0.2--patch-12 + + * emoney.el (emoney-go-to-bank): Fix typo. + + + modified files: + emoney.el + + +2005-10-09 04:41:09 GMT Steve Youngs patch-11 + + Summary: + Bitrot removal and some minor clean up + Revision: + emoney--main--0.2--patch-11 + + This change removes the "demo" mode. It was written before eMoney had + anything resembling a UI. It may return in a future version of eMoney, + but for now it's history. + + Also removed is the very old (from balance.el days) hard-coded LaTeX + cheque printing. That only ever worked on balance.el's author's printer, + wasn't customisable, and... well you get the picture. It's gone! + + * emoney.el (emoney-in-demo-mode): Removed. + (emoney-mode): Update doc string... don't mention `emoney-demo'... it + doesn't exist anymore. + (emoney-demonstration-data): Removed. + (emoney-demonstration-help): Removed. + (emoney-demo): Removed. + (emoney-recalculate-buffer): Don't check is we're in "demo" mode. No + such thing anymore. + (emoney-setup-accounts-buffer): 80 column clean up. + (emoney-transfer-funds): Ditto. + (emoney-parse-transaction-data): Remove the print stuff. + (emoney-number-it): Removed. Old, bitrotted, hard-coded cheque + printing via LaTeX. + (emoney-print-make-words): Ditto. + (emoney-print-check): Ditto. + (emoney-setup-control-buffer): 80 column clean up. + + + modified files: + emoney.el + + +2005-10-09 03:42:58 GMT Steve Youngs patch-10 + + Summary: + Bring eMoney to life in a blaze of colour. + Revision: + emoney--main--0.2--patch-10 + + * emoney.el (emoney-faces): New custom group. + (emoney-account-name-face): New face. + (emoney-debit-face): Ditto. + (emoney-credit-face): Ditto. + (emoney-date-face): Ditto. + (emoney-clear-tran-face): Ditto. + (emoney-unclear-tran-face): Ditto. + (emoney-header-face): Ditto. + (emoney-setup-accounts-buffer): Use new eMoney faces. + (emoney-setup-header-buffer): Ditto. + (emoney-update-acc-buf-bal): Ditto. + (emoney-font-lock-keywords): New. For the font-lock thang. + + + modified files: + emoney.el + + +2005-10-08 02:21:07 GMT Steve Youngs patch-9 + + Summary: + Fix balance display in A/C's buffer + Revision: + emoney--main--0.2--patch-9 + + * emoney.el (emoney-setup-accounts-buffer): Allow for situation where the + account hasn't been "recalculated". + + + modified files: + emoney.el + + +2005-10-08 01:26:12 GMT Steve Youngs patch-8 + + Summary: + Display each A/C's current balance in *Accounts Buffer* + Revision: + emoney--main--0.2--patch-8 + + * emoney.el (emoney-accounts-buffer-width): Set default to 25. The + increase is to allow for balances being in the buffer. + (emoney-setup-accounts-buffer): Insert each account's current balance + into the buffer. + (emoney-largest-balance): Move it higher in the file to avoid a + compiler warning. + (emoney-update-acc-buf-bal): New. Updates the balances in the Accounts + buffer. + (emoney-recalculate-buffer): Use it. + + + modified files: + emoney.el + + +2005-10-06 03:45:48 GMT Steve Youngs patch-7 + + Summary: + Build cleanup + Revision: + emoney--main--0.2--patch-7 + + * Makefile: Remove "superupgrade" target. + + * emoney.el: Autoload `browse-url' at compile-time + + + modified files: + Makefile emoney.el + + +2005-10-06 01:20:54 GMT Steve Youngs patch-6 + + Summary: + Menu and keymap additions -- calc & bank + Revision: + emoney--main--0.2--patch-6 + + * emoney.el (emoney-accounts-buffer-width): Make it customisable. + (emoney-accounts-buffer-height): Make it customisable, default it to 9. + (emoney-header-buffer-height): Make it customisable, default it to 4. + (emoney-mode-menu): Add menu items for opening Bank URL, and + calculator. + (emoney-calc): New. Wrapper to work around a bug in Emacs Calc... The + dreaded "window-edges" bug. + (emoney-mode-map): Bind `C-c c' to `emoney-calc'. + (emoney-setup-control-buffer): Use `emoney-calc'. + + + modified files: + emoney.el + + +2005-09-21 01:59:08 GMT Steve Youngs patch-5 + + Summary: + Go to your bank's web site from within eMoney + Revision: + emoney--main--0.2--patch-5 + + * emoney.el (emoney-bank-url): New. + (emoney-setup-control-buffer): Add button for surfing to your bank's + web site. + (emoney-go-to-bank): New. For browsing to your bank's web site. + Default binding is `C-c b'. Also used in + `emoney-setup-control-buffer'. + (emoney-mode-map): Bind `C-c b' to `emoney-go-to-bank'. + + + modified files: + emoney.el + + +2005-09-12 13:29:37 GMT Steve Youngs patch-4 + + Summary: + Switch accounts via keyboard + Revision: + emoney--main--0.2--patch-4 + + I almost can't believe I let this go so long without adding it. Now you + can switch accounts via the keyboard... bound to `C-c s' + + * emoney.el (emoney-switch-to-account): Renamed to + `emoney-mouse-switch-to-account'. + (emoney-mouse-switch-to-account): New. + (emoney-accounts-buffer-map): Use it. + (emoney-switch-to-account): New version of this function, now it is for + switching accounts via the keyboard. + (emoney-mode-map): Bind `C-c b' to `emoney-switch-to-account'. + + + modified files: + emoney.el + + +2005-09-12 00:05:40 GMT Steve Youngs patch-3 + + Summary: + Makefile tweak + Revision: + emoney--main--0.2--patch-3 + + * Makefile (INSTALL): Drop the user/group options so eMoney can be + installed by non-root users. + + + modified files: + Makefile + + +2005-09-11 23:37:40 GMT Steve Youngs patch-2 + + Summary: + Window config improvements + Revision: + emoney--main--0.2--patch-2 + + This change works around a problem in Emacs Calc. Calc wouldn't put + point back to the place it was before calc was called. We fix it by + defadvice'ing `calc' and `calc-quit'. + + Also, we only save/restore the "pre eMoney" window configuration if + eMoney isn't running in its own frame. + + * emoney.el (calc): defadvice it so it saves the window config before + calc starts. + (calc-quit): defadvice it so that the "pre calc" window config is + restored when calc exits. + (emoney): Save the window config to a register instead of using a + global variable. Only save the config if eMoney is _not_ using its own + frame. + (emoney-quit): Restore the window config from a register, only if + eMoney is _not_ using its own frame. + (emoney-old-window-config): Removed. + + + modified files: + emoney.el + + +2005-01-01 01:36:48 GMT Steve Youngs patch-1 + + Summary: + tla style version string + Revision: + emoney--main--0.2--patch-1 + + The patch introduces a tla style version string, something like... + + steve@sxemacs.org--2005/emoney--main--0.2--base-0 + + It also adds the ChangeLog file from the previous version. It is in + ./ChangeLog.d/ + + * Makefile (VER): Bump to 0.2. + (EXTRA_SRC): Remove ChangeLog... we let tla do the job of tracking + changes. + (all): Add emoney-version.el + (auto-autoloads.el): emoney-version.el is a dependency + (emoney-version.el): New target. + (version): Alias to above. + (distclean): Remove emoney-version.el* as well. + (.PHONY): New. To ensure the emoney-version is built. + + * emoney.el (emoney-codename): "Capital Gain" + + * emoney.el (emoney-version): Require emoney-version. + + + new files: + .arch-ids/.arch-inventory.id .arch-inventory + ChangeLog.d/.arch-ids/=id + ChangeLog.d/.arch-ids/ChangeLog-0.1.id + ChangeLog.d/ChangeLog-0.1 + + modified files: + Makefile emoney.el + + new directories: + ChangeLog.d ChangeLog.d/.arch-ids + + +2005-01-01 00:24:51 GMT Steve Youngs base-0 + + Summary: + tag of steve@sxemacs.org--2004/emoney--main--0.1--patch-1 + Revision: + emoney--main--0.2--base-0 + + (automatically generated log message) + + new patches: + steve@sxemacs.org--2004/emoney--main--0.1--base-0 + steve@sxemacs.org--2004/emoney--main--0.1--patch-1 + + diff --git a/ChangeLog.d/ChangeLog-0.3 b/ChangeLog.d/ChangeLog-0.3 new file mode 100644 index 0000000..0f23891 --- /dev/null +++ b/ChangeLog.d/ChangeLog-0.3 @@ -0,0 +1,69 @@ +# do not edit -- automatically generated by arch changelog +# non-id: automatic-ChangeLog--steve@sxemacs.org--2006/emoney--main--0.3 +# + +2006-09-21 04:38:09 GMT Steve Youngs patch-2 + + Summary: + Give the eMoney frame a name + Revision: + emoney--main--0.3--patch-2 + + * emoney.el (emoney): Give the eMoney frame a name property. By + side-effect, this sets the X11 window class which in turn means easier + manipulation and control for WMs, for example, Sawfish's "matched + windows". + + + modified files: + emoney.el + + +2005-12-26 14:06:32 GMT Steve Youngs patch-1 + + Summary: + Prepare for 0.3 release cycle + Revision: + emoney--main--0.3--patch-1 + + * Makefile (VER): Bump to 0.3 + + * emoney.el (emoney-codename): Set to "Currency". + + + new files: + ChangeLog.d/.arch-ids/ChangeLog-0.2.id + ChangeLog.d/ChangeLog-0.2 + + modified files: + Makefile emoney.el + + +2005-12-26 03:43:41 GMT Steve Youngs base-0 + + Summary: + tag of steve@sxemacs.org--2005/emoney--main--0.2--version-0 + Revision: + emoney--main--0.3--base-0 + + (automatically generated log message) + + new patches: + steve@sxemacs.org--2004/emoney--main--0.1--base-0 + steve@sxemacs.org--2004/emoney--main--0.1--patch-1 + steve@sxemacs.org--2005/emoney--main--0.2--base-0 + steve@sxemacs.org--2005/emoney--main--0.2--patch-1 + steve@sxemacs.org--2005/emoney--main--0.2--patch-2 + steve@sxemacs.org--2005/emoney--main--0.2--patch-3 + steve@sxemacs.org--2005/emoney--main--0.2--patch-4 + steve@sxemacs.org--2005/emoney--main--0.2--patch-5 + steve@sxemacs.org--2005/emoney--main--0.2--patch-6 + steve@sxemacs.org--2005/emoney--main--0.2--patch-7 + steve@sxemacs.org--2005/emoney--main--0.2--patch-8 + steve@sxemacs.org--2005/emoney--main--0.2--patch-9 + steve@sxemacs.org--2005/emoney--main--0.2--patch-10 + steve@sxemacs.org--2005/emoney--main--0.2--patch-11 + steve@sxemacs.org--2005/emoney--main--0.2--patch-12 + steve@sxemacs.org--2005/emoney--main--0.2--version-0 + + diff --git a/ChangeLog.d/ChangeLog-0.4 b/ChangeLog.d/ChangeLog-0.4 new file mode 100644 index 0000000..9460ece --- /dev/null +++ b/ChangeLog.d/ChangeLog-0.4 @@ -0,0 +1,129 @@ +# do not edit -- automatically generated by arch changelog +# non-id: automatic-ChangeLog--steve@sxemacs.org--2007/emoney--main--0.4 +# + +2007-08-04 07:38:20 GMT Steve Youngs patch-4 + + Summary: + Fix some font-locking issues. + Revision: + emoney--main--0.4--patch-4 + + This changeset fixes a couple of font-locking issues introduced in the + previous changeset. + + * emoney.el (emoney-build-type-regexp): Use #'append instead of #'push. + (emoney-credit-type-keywords): Add in `emoney-cr-transfer-transaction-type'. + (emoney-debit-type-keywords): Add in `emoney-db-transfer-transaction-type'. + + + modified files: + emoney.el + + +2007-08-04 05:07:56 GMT Steve Youngs patch-3 + + Summary: + Minor tidy up and fix bug in transfers + Revision: + emoney--main--0.4--patch-3 + + This changeset cleans up a bit of the code and fixes a bug in + transactions that transfer between a/c's. The accounts buffer was + getting out of sync. + + * emoney.el (emoney-accounts-directory): Use #'user-home-directory + instead of environment variable, $HOME. + (emoney-history-directory): New. Where previous years a/c files go. + (emoney-cheque-type): Typo fix. + (emoney-mode-map): Use [key] syntax. I think it looks better. :-) + (emoney-accounts-buffer-map): Typo fix. + (emoney-calc): Typo fix. + (emoney-credit-transaction-types): Remove transfer types. + (emoney-debit-transaction-types): Ditto. + (emoney-cr-transfer-transaction-type): New. + (emoney-db-transfer-transaction-type): New. + (emoney-build-types-list): Include the new transfer types. + (emoney-build-type-regexp): Typo fix. + (emoney-append-transaction): Use new transfer types. + (emoney-transfer-funds): Use the new transfer types and fix the bug + that messed up the a/c's buffer whenever a transfer was done. + + + modified files: + emoney.el + + +2007-01-01 02:10:28 GMT Steve Youngs patch-2 + + Summary: + Improve UI a tiny bit + Revision: + emoney--main--0.4--patch-2 + + Hopefully this will help with the initial buffer/frame set up. + + * emoney.el (emoney-accounts-buffer-width): Increase to 30. + + + modified files: + emoney.el + + +2007-01-01 00:49:11 GMT Steve Youngs patch-1 + + Summary: + Prepare for 0.4 release cycle + Revision: + emoney--main--0.4--patch-1 + + Just the normal new release administrivia. Plus a couple of makefile + improvements. + + * emoney.el (emoney-codename): is now `Deficit'. + + * Makefile (VER): Bump. + (XEMACS): Default to `sxemacs'. + (PREFIX): Handle the differences between XEmacs and SXEmacs for + $PREFIX. + + + new files: + ChangeLog.d/.arch-ids/ChangeLog-0.3.id + ChangeLog.d/ChangeLog-0.3 + + modified files: + Makefile emoney.el + + +2007-01-01 00:21:13 GMT Steve Youngs base-0 + + Summary: + tag of steve@sxemacs.org--2006/emoney--main--0.3--patch-2 + Revision: + emoney--main--0.4--base-0 + + (automatically generated log message) + + new patches: + steve@sxemacs.org--2004/emoney--main--0.1--base-0 + steve@sxemacs.org--2004/emoney--main--0.1--patch-1 + steve@sxemacs.org--2005/emoney--main--0.2--base-0 + steve@sxemacs.org--2005/emoney--main--0.2--patch-1 + steve@sxemacs.org--2005/emoney--main--0.2--patch-2 + steve@sxemacs.org--2005/emoney--main--0.2--patch-3 + steve@sxemacs.org--2005/emoney--main--0.2--patch-4 + steve@sxemacs.org--2005/emoney--main--0.2--patch-5 + steve@sxemacs.org--2005/emoney--main--0.2--patch-6 + steve@sxemacs.org--2005/emoney--main--0.2--patch-7 + steve@sxemacs.org--2005/emoney--main--0.2--patch-8 + steve@sxemacs.org--2005/emoney--main--0.2--patch-9 + steve@sxemacs.org--2005/emoney--main--0.2--patch-10 + steve@sxemacs.org--2005/emoney--main--0.2--patch-11 + steve@sxemacs.org--2005/emoney--main--0.2--patch-12 + steve@sxemacs.org--2005/emoney--main--0.2--version-0 + steve@sxemacs.org--2006/emoney--main--0.3--base-0 + steve@sxemacs.org--2006/emoney--main--0.3--patch-1 + steve@sxemacs.org--2006/emoney--main--0.3--patch-2 + + diff --git a/ChangeLog.d/ChangeLog-0.5 b/ChangeLog.d/ChangeLog-0.5 new file mode 100644 index 0000000..42b6fea --- /dev/null +++ b/ChangeLog.d/ChangeLog-0.5 @@ -0,0 +1,40 @@ +# do not edit -- automatically generated by arch changelog +# non-id: automatic-ChangeLog--steve@sxemacs.org--2008/emoney--main--0.5 +# + +2008-01-02 02:03:57 GMT Steve Youngs base-0 + + Summary: + tag of steve@sxemacs.org--2007/emoney--main--0.4--patch-4 + Revision: + emoney--main--0.5--base-0 + + (automatically generated log message) + + new patches: + steve@sxemacs.org--2004/emoney--main--0.1--base-0 + steve@sxemacs.org--2004/emoney--main--0.1--patch-1 + steve@sxemacs.org--2005/emoney--main--0.2--base-0 + steve@sxemacs.org--2005/emoney--main--0.2--patch-1 + steve@sxemacs.org--2005/emoney--main--0.2--patch-2 + steve@sxemacs.org--2005/emoney--main--0.2--patch-3 + steve@sxemacs.org--2005/emoney--main--0.2--patch-4 + steve@sxemacs.org--2005/emoney--main--0.2--patch-5 + steve@sxemacs.org--2005/emoney--main--0.2--patch-6 + steve@sxemacs.org--2005/emoney--main--0.2--patch-7 + steve@sxemacs.org--2005/emoney--main--0.2--patch-8 + steve@sxemacs.org--2005/emoney--main--0.2--patch-9 + steve@sxemacs.org--2005/emoney--main--0.2--patch-10 + steve@sxemacs.org--2005/emoney--main--0.2--patch-11 + steve@sxemacs.org--2005/emoney--main--0.2--patch-12 + steve@sxemacs.org--2005/emoney--main--0.2--version-0 + steve@sxemacs.org--2006/emoney--main--0.3--base-0 + steve@sxemacs.org--2006/emoney--main--0.3--patch-1 + steve@sxemacs.org--2006/emoney--main--0.3--patch-2 + steve@sxemacs.org--2007/emoney--main--0.4--base-0 + steve@sxemacs.org--2007/emoney--main--0.4--patch-1 + steve@sxemacs.org--2007/emoney--main--0.4--patch-2 + steve@sxemacs.org--2007/emoney--main--0.4--patch-3 + steve@sxemacs.org--2007/emoney--main--0.4--patch-4 + + diff --git a/ChangeLog.d/ChangeLog.SFCVS b/ChangeLog.d/ChangeLog.SFCVS new file mode 100644 index 0000000..4bc0424 --- /dev/null +++ b/ChangeLog.d/ChangeLog.SFCVS @@ -0,0 +1,206 @@ +This is the old ChangeLog from when eMoney was in SF.net CVS + +2004-06-28 Steve Youngs + + * eMoney 0.03 "Blue Chip" is released. + + * Makefile (VER): 0.03 + + * emoney.el (emoney-days-to-time): New. + (emoney-time-add): New. + (emoney-append-transaction): Use them to specify dates that aren't + today. + (emoney-is-beta): Make it a `defconst'. + (emoney-mode-map): Add bindings for `emoney-quit' and + `emoney-recalc-and-exit'. + (emoney-mode-menu): Move "New A/C" to top of menu. + Add entry for `emoney-recalc-and-exit'. + (emoney-check-transaction-type): Clarify doc string. + (emoney-recalc-and-exit): New. + (emoney-is-exiting): New. + (emoney-recalculate-buffer): Use it. + (emoney-quit): Ditto. + Use `emoney-use-new-frame'. + (emoney): Use `emoney-use-new-frame'. + (emoney-find-next-transaction): Don't untabify here. + (emoney-recalculate): Untabify the region. + (emoney-frame): New. + (emoney-version): 0.03 + +2004-03-24 Steve Youngs + + * emoney.el (emoney-setup-control-buffer): Rearrange the version + string that is output from the "Version" button. + (emoney-version): 0.03pre1 + (emoney-mode-map): Bind `C-c C-x' to `emoney-transfer-funds'. + (emoney-mode-hooks): New. + (emoney-hooks): New custom group. + (emoney-switch-account-hook): New. + (emoney-switch-to-account): Use it. + (emoney-setup-accounts-buffer-hook): New. + (emoney-setup-accounts-buffer): Use it. + (emoney-setup-header-buffer-hook): New. + (emoney-setup-header-buffer): Use it. + (emoney-setup-control-buffer-hook): New. + (emoney-setup-control-buffer): Use it. + (emoney-transaction-hook): New. + (emoney-transaction-cheque-hook): New. + (emoney-append-next-cheque): Use them. + (emoney-transaction-transfer-hook): New. + (emoney-transfer-funds): Use it. + (emoney-append-transaction): Use `emoney-transaction-hook'. + (emoney-recalculate-before-hook): New. + (emoney-recalculate-after-hook): New. + (emoney-recalculate): Use them. + (emoney-summarise-cheques-hook): New. + (emoney-summarise-cheques): Use it. + (emoney-new-account-hook): New. + (emoney-new-account): Use it. + (emoney-quit-before-hook): New. + (emoney-quit-after-hook): New. + (emoney-quit): Use them. + +2004-03-23 Steve Youngs + + * eMoney 0.02 "Bankruptcy" is released. + + * Makefile (VER): 0.02. + + * emoney.el (emoney-transfer-account-history): New. + (emoney-transfer-funds): New. + (emoney-setup-control-buffer): Add a "Transfer" button. + (emoney-mode-menu): Add a "Transfer Funds" entry, and a "New A/C" + entry. + (emoney-chart-of-accounts): Set sane defaults. + (emoney-version): Bump to 0.02. + (emoney-codename): "Bankruptcy". + +2004-01-29 Steve Youngs + + * emoney.el (emoney-version): 0.02pre7 + (emoney-setup-control-buffer): Rename "Rec Trans" button to "End + Trans". + Add help-echo strings for each button. + (emoney-summarise-cheques): Use `switch-to-buffer' instead of + `pop-to-buffer'. + +2004-01-21 Steve Youngs + + * emoney.el: Drag in `calc'. + + * Makefile (dist): New target for creating source tarballs. + +2004-01-20 Steve Youngs + + * emoney.el (emoney-switch-to-account): Guard against inf-loops. + (emoney-setup-control-buffer): Add a "Exit" button. + (emoney-append-transaction): Add arguments so it can be called + non-interactively. + (emoney-new-account): Write it. + (emoney-version): Bump to 0.02pre6 + +2004-01-19 Steve Youngs + + * emoney.el (emoney-setup-control-buffer): Add a "Calculator" + button to invoke Emacs Calc. + (emoney-old-window-config): New. + (emoney-quit): Use it. + (emoney): Ditto. + (emoney-version): Bump to 0.02pre5 + +2004-01-17 Steve Youngs + + * emoney.el (emoney): Ensure that `emoney-current-account-name' is + always initialised to `emoney-default-account' when eMoney starts + up. + (emoney-recalculate-buffer): Use `message-or-box' instead of + `message'. + (emoney-recalculate-region): Ditto. + (emoney-switch-to-account): Guard against messing up the window + configuration regardless of which buffer point is in when this + function is called. Always leave point in the "Account Register" + buffer. + (emoney-accounts-buffer-map): Remove the binding for RET. + (emoney-version): Bump to 0.02pre4 + +2004-01-16 Steve Youngs + + * Makefile (distclean): Remove TAGS files too. + (all): Build autoloads and custom-loads before byte-compiling + anything. + (compile): Byte-compile all files from a single instance of + XEmacs. + (auto-autoloads.el): Don't byte-compile here, do it at `compile' + target. + (custom-load.el): Ditto. + + * emoney.el: Require wid-edit. + (emoney-switch-to-account): New. + (emoney-accounts-buffer-map): New. + (emoney-setup-accounts-buffer): Use them. + (emoney-new-account): New. Empty function, to be written. + (emoney-setup-control-buffer): + s/emoney-current-account/emoney-current-account-name/ + (emoney-version): Bump to 0.02pre3 + +2004-01-15 Steve Youngs + + * emoney.el (emoney-show-buffers): Fix buffer layout. + (emoney-setup-accounts-buffer): Only turn off scrollbars and + modeline in this buffer, not globally. + (emoney-setup-header-buffer): Ditto. + (emoney-setup-control-buffer): Ditto. + (emoney-mode): Don't insert a header into the account file because + there is now a static buffer containing the header. + (emoney-setup-header-buffer): Insert blank line between a/c name + and header. + (emoney-insert-header-maybe): Removed. + (emoney-codename): Update. + (emoney-version): Bump to 0.02pre2 + + * codenames: New file. + +2004-01-14 Steve Youngs + + * emoney.el (emoney-use-new-frame): New. + (emoney-accounts-buffer-width): New. + (emoney-accounts-buffer-height): New. + (emoney-header-buffer-height): New. + (emoney-accounts-buffer): New. + (emoney-control-buffer): New. + (emoney-header-buffer): New. + (emoney-setup-accounts-buffer): New. + (emoney-current-account-name): New. + (emoney-setup-header-buffer): New. + (emoney-setup-control-buffer): New. + (emoney-show-buffers): New. + +2004-01-14 Steve Youngs + + * emoney.el (emoney-version): Bump to 0.02pre1 + + * Makefile (compile): New target. + (all): Use it. + (distclean): Remove `core*' instead of just `core'. + + * emoney.el (emoney): New. + (emoney-quit): New. + (emoney-recalculate-on-quit): New. + (emoney-mode-menu): Add `emoney-quit'. + +2004-01-13 Steve Youngs + + * emoney.el (emoney-accounts-directory): New. + (emoney-chart-of-accounts): New. + (emoney-default-account): New. + +2003-10-03 Steve Youngs + + * emoney.el: Update my email address. + +2003-06-04 Steve Youngs + + * Makefile: New. + + * emoney.el: New. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..59f0175 --- /dev/null +++ b/Makefile @@ -0,0 +1,169 @@ +## Makefile for eMoney -*-Makefile-*- +## $Id: Makefile,v 1.6 2004/06/29 23:31:14 youngs Exp $ +## +## Copyright (C) 2003 - 2007 Steve Youngs +## +## This file is part of eMoney. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## +## 1. Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## +## 2. Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## +## 3. Neither the name of the author nor the names of any contributors +## may be used to endorse or promote products derived from this +## software without specific prior written permission. +## +## THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +## IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +## WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +## DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +PACKAGE = emoney +VER = 0.6 + +# csh... yell no, we won't go! +SHELL = /bin/sh + +# Programs and their flags. +ifndef XEMACS + XEMACS = sxemacs +endif +XEMACS_FLAGS = -batch -no-autoloads +INSTALL = install +PKG_INSTALL = $(INSTALL) +TAR = tar +TAR_FLAGS = \ + --create \ + --owner=0 \ + --group=0 \ + --gzip \ + --file + + +# Our prefix. Everything hangs off this. +ifndef PREFIX + ifeq ('$(XEMACS)','sxemacs') + PREFIX = /usr/local/share/sxemacs/site-packages + else + PREFIX = /usr/local/lib/xemacs/site-packages + endif +endif + +# Where the lisp files go. +LISP_DIR = $(PREFIX)/lisp/$(PACKAGE) + +# If you want to make a tarball that you can just unpack on all your +# PC's you can 'make pkg'. The 'pkg' target uses these directories to +# build the tarball. +STAGING = ../build-pkg +INFO_STAGING = $(STAGING)/info +LISP_STAGING = $(STAGING)/lisp/$(PACKAGE) + + +############################################################################ +## No User Configurable Items Below Here ## +############################################################################ + +SOURCES = $(wildcard ./emoney*.el) +OBJECTS = $(SOURCES:.el=.elc) +EXTRA_SRC = +EXTRA_OBJ = $(wildcard ./auto-autoloads.el*) $(wildcard ./custom-load.el*) + +PRELOADS = -eval \("push default-directory load-path"\) +AUTOLOAD_PACKAGE_NAME = (setq autoload-package-name \"$(PACKAGE)\") +AUTOLOAD_FILE = (setq generated-autoload-file \"./auto-autoloads.el\") + + +.SUFFIXES: +.SUFFIXES: .elc .el + +all:: emoney-version.el autoloads customloads compile + +autoloads: auto-autoloads.el + +customloads: custom-load.el + +compile: $(SOURCES) auto-autoloads.el custom-load.el + $(XEMACS) $(XEMACS_FLAGS) $(PRELOADS) \ + -l bytecomp \ + -l byte-optimize \ + -f batch-byte-compile $^ + +auto-autoloads.el : $(SOURCES) emoney-version.el + $(XEMACS) $(XEMACS_FLAGS) $(PRELOADS) \ + -eval "$(AUTOLOAD_PACKAGE_NAME)" \ + -eval "$(AUTOLOAD_FILE)" \ + -l autoload -f batch-update-autoloads $^ + @rm -f $(AUTOLOAD_PATH)/auto-autoloads.el~ + +custom-load.el : $(SOURCES) + $(XEMACS) $(XEMACS_FLAGS) $(PRELOADS) -l cus-dep \ + -f Custom-make-dependencies ./ + @touch ./custom-load.el + @rm -f ./custom-load.el~ + +emoney-version.el: + echo ";;; Automatically generated file -- DO NOT EDIT OR DELETE" > $@ + echo ";;;###autoload" >> $@ + echo "(defconst emoney-version" >> $@ + if [[ -d "./{arch}" && -x `which tla 2>/dev/null` ]]; then \ + printf ' "%s"' `tla logs -f|tail -n1` >> $@; \ + else \ + echo -n ' "$(VER)"' >> $@; \ + fi + echo ")" >> $@ + echo "(provide 'emoney-version)" >> $@ + +version: emoney-version.el + +install: all + $(INSTALL) -d $(LISP_DIR) + $(INSTALL) -m 644 $(SOURCES) $(EXTRA_SRC) $(OBJECTS) $(EXTRA_OBJ) \ + $(LISP_DIR) + +pkg: all + $(PKG_INSTALL) -d $(STAGING) $(LISP_STAGING) + $(PKG_INSTALL) -m 644 $(SOURCES) $(EXTRA_SRC) $(OBJECTS) $(EXTRA_OBJ) \ + $(LISP_STAGING) + (cd $(STAGING); \ + $(TAR) $(TAR_FLAGS) $(PACKAGE)-$(VER)-pkg.tar.gz ./*) + +upgrade: uninstall install + +uninstall:: + rm -rf $(LISP_DIR) + # rm -f $(INFO_DIR)/$(INFO_FILES) + + +clean:: + rm -f $(OBJECTS) $(INFO_FILES) \ + auto-autoloads.el* custom-load.el* + +distclean: clean + rm -f core* *~ TAGS tags emoney-version.el* + +# Developer targets +tags: TAGS + +TAGS: $(SOURCES) + etags $(SOURCES) + +dist: distclean + (cd ../ ; \ + $(TAR) $(TAR_FLAGS) $(PACKAGE)-$(VER).tar.gz ./$(PACKAGE)/) + +.PHONY: emoney-version.el version diff --git a/TODO b/TODO new file mode 100644 index 0000000..ea3d49c --- /dev/null +++ b/TODO @@ -0,0 +1,48 @@ +-*- outline -*- + +What appears here is a list of _possible_ additions/improvements to +eMoney. They are in no order of priority, and just because something +is listed here, doesn't mean that it will one day become part of +eMoney. + +* Credit card a/c's. + +Credit a/c's should show the credit limit, available credit, and +amount currently owing. + +* Recurring transactions. + +Probably use abbrevs to "remember" certain transactions. + +* Bank reconciliation. + +Something akin to the way Quicken does it... displaying a list of +uncleared transactions that you mark as cleared from your bank +statement. BTW, you should know that the last time I used Quicken, it +was the M$-DOS version (there wasn't a windoze version), so my memory +could be a little hazy. + +* End of year stuff. + +For folks who want to keep each year's transactions in separate +files. + +* Simple reporting (P/L, balance sheet etc). + +This might turn into a simple "show transactions where foo=bar" type +of thing. + +* Currency conversion. + +There's gotta be some web site we could hook into for this. + +* Stock quotes. + +See Currency conversion + +* Invoicing. + +* Import/Export to and from Gnucash format (maybe). + +* Import/Export to and from Quicken qif format (maybe). + diff --git a/codenames b/codenames new file mode 100644 index 0000000..f8379e8 --- /dev/null +++ b/codenames @@ -0,0 +1,51 @@ +Accountant +Actuary +Bankruptcy +Blue Chip +Capital Gain +Currency +Deficit +Depreciation +Encumbrance +Equity +Finance +Fiscal +General Ledger +Gross Domestic Product +Homo Economicus +Hostile Takeover +Income Tax +Inflation +Joint Account +Junk Bond +Keogh Plan +Kickback +Letter of Credit +Leveraged Buyout +Managed Account +Marginal Tax Rate +Negative Gearing +Nest Egg +Offshore Mutual Fund +Online Banking +Paid-Up Capital +Petty Cash +Quality of Earnings +Quid Pro Quo +Real Rate of Return +Red Chip +Sales Tax +Shotgun Clause +Tangible Asset +Tax Haven +Undervalued +Unlisted Security +Variable Cost +Vertical Market +Wall Street +White Elephant +Xenocurrency +Year To Date +Yield +Zero Balance +Zombies diff --git a/emoney.el b/emoney.el new file mode 100644 index 0000000..b0fc78f --- /dev/null +++ b/emoney.el @@ -0,0 +1,1676 @@ +;; emoney.el --- A home finance package. + +;; Copyright (C) 2003 - 2009 Steve Youngs + +;; Author: Steve Youngs +;; Maintainer: Steve Youngs +;; Created: <2003-06-04> +;; Keywords: money finance banking cash + +;; This file is part of eMoney. + +;; Redistribution and use in source and binary forms, with or without +;; modification, are permitted provided that the following conditions +;; are met: +;; +;; 1. Redistributions of source code must retain the above copyright +;; notice, this list of conditions and the following disclaimer. +;; +;; 2. Redistributions in binary form must reproduce the above copyright +;; notice, this list of conditions and the following disclaimer in the +;; documentation and/or other materials provided with the distribution. +;; +;; 3. Neither the name of the author nor the names of any contributors +;; may be used to endorse or promote products derived from this +;; software without specific prior written permission. +;; +;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +;; DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +;;; Commentary: +;; +;; eMoney is based on balance.el, originally by Jason Baietto +;; and later maintained by Bob Newell +;; . +;; +;; eMoney tries to give the user a reasonably self-contained finance +;; solution. The target audience is the home user and possibly the +;; small (very small) business operator. It probably will never be +;; compatible with any commercial finance packages available. +;; +;; Right now, eMoney is nothing more than a very simple cash book +;; program. Use it to balance your cheque book. See the "Todo:" +;; section for a partial list of possible upcoming features. +;; +;; Installation (from source): +;; +;; tar zxf emoney-x.xx.tar.gz +;; cd emoney-x.xx +;; check the paths in Makefile +;; make +;; make install (you may need to be root for this) +;; +;; Installation (from XEmacs package tarball): +;; +;; cd /usr/local/share/sxemacs/site-packages +;; (/usr/local/lib/xemacs/site-packages for XEmacs) +;; tar zxf /path/to/emoney-x.xx-pkg.tar.gz +;; +;; (Re)start (S)XEmacs and do `M-x emoney RET' +;; +;; You can also invoke `emoney-mode' by simply visiting a file with a +;; `.emy' extension. +;; +;; Please note that I use SXEmacs exclusively, I have no idea whether +;; or not this will run or even byte-compile with GNU/Emacs (it _will_ +;; work fine with XEmacs). Also, I have no desire or intentions of +;; making this package portable between XEmacs and GNU/Emacs. Harsh +;; words? No, not really, I simply don't have the time or resources to +;; invest in the extra work involved. And also there is no way that +;; I'd be able to support GNU/Emacs users because I'm not familiar with +;; that flavour of Emacs. If you want to port it, be my guest, this is +;; an Open Source project. +;; +;; Another note: This package uses correct English spelling wherever +;; possible. For example, "cheque" instead of "check", "summarise" +;; instead of "summarize". Although I welcome and encourage _ALL_ +;; contributions, patches that s/que/ch/ or s/ise/ize/ will go straight +;; to /dev/null. + +;;; ChangeLog: +;; +;; This is just a place holder so `emoney-commentary' will work +;; properly. See the ChangeLog file for changes. + +;;; Code: + +;; Drag in what we need. +(eval-and-compile + (autoload 'calc "calc" nil t) + (autoload 'clear-rectangle "rect" nil t) + (autoload 'completing-read "minibuf") + (autoload 'customize-group "cus-edit") + (autoload 'lm-commentary "lisp-mnt") + (autoload 'sort-numeric-fields "sort" nil t) + (autoload 'untabify "tabify" nil t) + (autoload 'with-electric-help "ehelp") + (require 'wid-edit)) + +(eval-when-compile + (autoload 'eval-when "cl-macs" nil nil 'macro) + (autoload 'calc-quit "calc" nil t) + (require 'advice) + (defvar calc-was-split) + (autoload 'browse-url "browse-url" nil t) + (autoload 'regexp-opt "regexp-opt")) + +;; Custom. +(defgroup emoney nil + "Customisations for `emoney-mode'." + :prefix "emoney-" + :group 'tools) + +(defcustom emoney-accounts-buffer-width 30 + "How wide in columns for the accounts buffer." + :type 'integer + :group 'emoney) + +(defcustom emoney-accounts-buffer-height 9 + "How high in lines for the accounts buffer." + :type 'integer + :group 'emoney) + +(defcustom emoney-header-buffer-height 4 + "How high in lines for the header buffer." + :type 'integer + :group 'emoney) + +(defcustom emoney-accounts-directory (file-name-as-directory + (expand-file-name ".emoney" + (user-home-directory))) + "*The directory where your eMoney account files are located." + :type 'directory + :group 'emoney) + +(defcustom emoney-history-directory (file-name-as-directory + (expand-file-name "history" + emoney-accounts-directory)) + "*Directory containing previous years account files." + :type 'directory + :group 'emoney) + +(defcustom emoney-chart-of-accounts + (if (file-directory-p emoney-accounts-directory) + (directory-files emoney-accounts-directory nil "\\.emy$" nil t) + nil) + "*A list of eMoney accounts in `emoney-accounts-directory'." + :type '(repeat + (string :tag "Account Name")) + :group 'emoney) + +(defcustom emoney-default-account (or (car emoney-chart-of-accounts) + "default.emy") + "*The default eMoney account to use. + +This is the account that has the focus when you start eMoney." + :type 'string + :group 'emoney) + +(defcustom emoney-credit-transaction-types + '("autotellcr" "atmcr" "bankcredit" "bcr" "deposit" "dep" "directcr" + "dcr" "internetcr" "netcr" "phonecr" "phcr") + "*List of valid credit transaction types. + +The default types are: + + autotellcr -- Automatic Teller Machine deposit + atmcr -- short version of 'autotellcr' + + bankcredit -- Bank initiated credits like interest etc + bcr -- short version of 'bankcredit' + + deposit -- Manual, non-direct deposits + dep -- short version of 'deposit' + + directcr -- Direct credit transactions + dcr -- short version of 'directcr' + + internetcr -- Internet credit transactions + netcr -- short version of 'internetcr' + + phonecr -- Telephone credit transactions + phcr -- short version of 'phonecr'" + :type '(repeat string) + :group 'emoney) + +(defcustom emoney-debit-transaction-types + '("autotelldb" "atmdb" "bankfee" "fee" "directdb" "ddb" "eftpos" + "eft" "internetdb" "netdb" "phonedb" "phdb" "withdrawal" "wdl") + "*List of valid debit transaction types. + +The default types are: + + autotelldb -- Automatic Teller Machine transaction + atmdb -- short version of 'autoteller' + + bankfee -- Bank fees + fee -- short version of 'bankfee' + + directdb -- Direct debit transactions + ddb -- short version of 'directdb' + + eftpos -- Electronic Funds Transfer Point Of Sale + eft -- short version of 'eftpos' + + internetdb -- Internet transactions + netdb -- short version of 'internet' + + phonedb -- Telephone transactions + phcr -- short version of 'phone' + + withdrawal -- Over the counter withdrawal. + wdl -- short version of 'withdrawal'" + :type '(repeat string) + :group 'emoney) + +(defcustom emoney-cr-transfer-transaction-type "xfrcr" + "*Credit transfer transaction types." + :type 'string + :group 'emoney) + +(defcustom emoney-db-transfer-transaction-type "xfrdb" + "*Debit transfer transaction type." + :type 'string + :group 'emoney) + +(defcustom emoney-date-format "%Y-%m-%d" + "*The format that `emoney-mode' uses for dates." + :type '(choice + (const :tag "yyyy-mm-dd" + :value "%Y-%m-%d") + (const :tag "yyyy/mm/dd" + :value "%Y/%m/%d") + (const :tag "mm/dd/yy" + :value "%m/%d/%y") + (const :tag "mm/dd/yyyy" + :value "%m/%d/%Y") + (const :tag "mm-dd-yy" + :value "%m-%d-%y") + (const :tag "mm-dd-yyyy" + :value "%m-%d-%Y") + (const :tag "dd/mm/yy" + :value "%d/%m/%y") + (const :tag "dd/mm/yyyy" + :value "%d/%m/%Y") + (const :tag "dd-mm-yy" + :value "%d-%m-%y") + (const :tag "dd-mm-yyyy" + :value "%d-%m-%Y") + (const :tag "yy/mm/dd" + :value "%y/%m/%d") + (const :tag "yy-mm-dd" + :value "%y-%m-%d")) + :group 'emoney) + +(defcustom emoney-uk-cheque-spelling t + "*When non-nil, use UK spelling: \"chq\" instead of \"chk\"." + :type 'boolean + :group 'emoney) + +(defcustom emoney-save-after-recalculate t + "*If non-nil, save the buffer after a recalculate. + +See `emoney-recalculate-buffer'." + :type 'boolean + :group 'emoney) + +(defcustom emoney-recalculate-on-quit nil + "*If non-nil, recalculate each eMoney account buffer when quitting eMoney." + :type 'boolean + :group 'emoney) + +(defcustom emoney-use-new-frame nil + "*If non-nil, eMoney will start in a new frame." + :type 'boolean + :group 'emoney) + +(defcustom emoney-bank-url "unset" + "The URL of your bank's web page." + :type 'string + :group 'emoney) + +;; Hooks +(defgroup emoney-hooks nil + "Various hooks for eMoney." + :prefix "emoney-" + :group 'emoney) + +(defcustom emoney-mode-hooks nil + "*Hooks run after `emoney-mode' is entered." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-switch-account-hook nil + "*Hooks run after switching accounts." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-setup-accounts-buffer-hook nil + "*Hooks run after setting up the accounts buffer." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-setup-header-buffer-hook nil + "*Hooks run after setting up the header buffer." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-setup-control-buffer-hook nil + "*Hooks run after setting up the control buffer." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-transaction-hook nil + "*Hooks run after appending a new transaction. + +These hooks are run after any new transaction, including cheque +and transfers. If you want to do additional things with cheque or +transfer transactions, see `emoney-transaction-cheque-hook' & +`emoney-transaction-transfer-hook'." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-transaction-cheque-hook nil + "*Hooks run after appending a cheque transaction." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-transaction-transfer-hook nil + "*Hooks run after appending a transfer transaction." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-recalculate-before-hook nil + "*Hooks run just prior to recalculating an eMoney buffer. + +See `emoney-recalculate-after-hook' for doing things after recalculating." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-recalculate-after-hook nil + "*Hooks run just after recalculating an eMoney buffer. + +See `emoney-recalculate-before-hook' for doing things before recalculating." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-summarise-cheques-hook nil + "*Hooks run after doing `emoney-summarise-cheques'." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-new-account-hook nil + "*Hooks run after creating a new account." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-quit-before-hook nil + "*Hooks run just prior to eMoney exiting." + :type 'hook + :group 'emoney-hooks) + +(defcustom emoney-quit-after-hook nil + "*Hooks run as the last thing when eMoney exits." + :type 'hook + :group 'emoney-hooks) + +;; Faces +(defgroup emoney-faces nil + "eMoney faces." + :prefix "emoney-" + :group 'emoney) + +(make-face 'emoney-account-name-face) +(set-face-parent 'emoney-account-name-face 'font-lock-variable-name-face) + +(make-face 'emoney-debit-face) +(set-face-parent 'emoney-debit-face 'font-lock-warning-face) + +(make-face 'emoney-credit-face) +(set-face-parent 'emoney-credit-face 'font-lock-function-name-face) + +(make-face 'emoney-date-face) +(set-face-parent 'emoney-date-face 'font-lock-keyword-face) + +(make-face 'emoney-clear-tran-face) +(set-face-parent 'emoney-clear-tran-face 'font-lock-string-face) + +(make-face 'emoney-unclear-tran-face) +(set-face-parent 'emoney-unclear-tran-face 'font-lock-comment-face) + +(make-face 'emoney-header-face) +(set-face-parent 'emoney-header-face 'font-lock-comment-face) + +(defcustom emoney-account-name-face 'emoney-account-name-face + "Face for highlighting eMoney account names." + :type 'face + :group 'emoney-faces) + +(defcustom emoney-debit-face 'emoney-debit-face + "Face for highlighting debit amounts in eMoney." + :type 'face + :group 'emoney-faces) + +(defcustom emoney-credit-face 'emoney-credit-face + "Face for highlighting credit amounts in eMoney." + :type 'face + :group 'emoney-faces) + +(defcustom emoney-date-face 'emoney-date-face + "Face for highlighting dates in eMoney." + :type 'face + :group 'emoney-faces) + +(defcustom emoney-clear-tran-face 'emoney-clear-tran-face + "Face for highlighting cleared transactions in eMoney." + :type 'face + :group 'emoney-faces) + +(defcustom emoney-unclear-tran-face 'emoney-unclear-tran-face + "Face for highlighting uncleared transactions in eMoney." + :type 'face + :group 'emoney-faces) + +(defcustom emoney-header-face 'emoney-header-face + "Face for highlighting the column header in eMoney." + :type 'face + :group 'emoney-faces) + +;;; Internal variables +(defconst emoney-codename "Equity" + "The codename of the current version of eMoney.") + +(defconst emoney-is-beta t + "Non-nil if the current version of eMoney is beta.") + +(eval-when (load eval) + (unless (file-directory-p emoney-accounts-directory) + (make-directory-path emoney-accounts-directory))) + +(require 'emoney-version) + +;;;###autoload +(defun emoney-version (&optional arg) + "*Display the current version information for eMoney. + +Optional prefix Argument ARG, print version information at point +in the current buffer." + (interactive "P") + (if emoney-is-beta + (if arg + (insert (format "eMoney: %s, \"%s\" [Beta]" + emoney-version emoney-codename)) + (message (format "eMoney: %s, \"%s\" [Beta]" + emoney-version emoney-codename))) + (if arg + (insert (format "eMoney: %s, \"%s\"" + emoney-version emoney-codename)) + (message (format "eMoney: %s, \"%s\"" + emoney-version emoney-codename))))) + +;;;###autoload +(defun emoney-commentary () + "*Display the commentary section of emoney.el." + (interactive) + (with-electric-help + '(lambda () + (insert + (with-temp-buffer + (erase-buffer) + (insert (lm-commentary (locate-library "emoney.el"))) + (goto-char (point-min)) + (while (re-search-forward "^;+ ?" nil t) + (replace-match "" nil nil)) + (buffer-string (current-buffer))))) + "*eMoney Commentary*")) + +;;;###autoload +(defun emoney-copyright () + "*Display the copyright notice for eMoney." + (interactive) + (with-electric-help + '(lambda () + (insert + (with-temp-buffer + (erase-buffer) + (insert-file-contents (locate-library "emoney.el")) + (goto-char (point-min)) + (re-search-forward ";;; Commentary" nil t) + (beginning-of-line) + (narrow-to-region (point-min) (point)) + (while (re-search-backward "^;+ ?" nil t) + (replace-match "" nil nil)) + (buffer-string (current-buffer))))) + "*eMoney Copyright Notice*")) + +(defvar emoney-frame nil + "The frame where eMoney is displayed, if in a new frame.") + +(defconst emoney-accounts-buffer "*eMoney A/C's*" + "The buffer that holds the list of eMoney accounts.") + +(defconst emoney-control-buffer "*eMoney Control*" + "The buffer containing the eMoney control buttons.") + +(defconst emoney-header-buffer "*eMoney Header*" + "The buffer for the eMoney account register header line.") + +(defvar emoney-current-account-name + (file-name-sans-extension emoney-default-account)) + +(defun emoney-switch-to-account (&optional account) + "Switch to account, ACCOUNT." + (interactive) + (let ((switch-acc (or account + (emoney-completing-read "Switch to A/C: " + emoney-chart-of-accounts nil t)))) + (select-window (get-buffer-window + (concat emoney-current-account-name ".emy"))) + (switch-to-buffer switch-acc) + (goto-char (point-max)) + (setq emoney-current-account-name + (file-name-sans-extension switch-acc)) + (select-window (get-buffer-window emoney-header-buffer)) + (emoney-setup-header-buffer) + (switch-to-buffer emoney-header-buffer) + (select-window (get-buffer-window + (concat emoney-current-account-name ".emy"))) + (run-hooks 'emoney-switch-account-hook))) + +(defun emoney-mouse-switch-to-account (event) + "Switch to account under EVENT." + (interactive "e") + (save-excursion + (set-buffer (window-buffer (event-window event))) + (let ((switch-acc (extent-string (extent-at-event event)))) + (select-window (get-buffer-window + (concat emoney-current-account-name ".emy"))) + (switch-to-buffer (concat switch-acc ".emy")) + (goto-char (point-max)) + (setq emoney-current-account-name switch-acc) + (select-window (get-buffer-window emoney-header-buffer)) + (emoney-setup-header-buffer) + (switch-to-buffer emoney-header-buffer))) + (select-window (get-buffer-window + (concat emoney-current-account-name ".emy"))) + (run-hooks 'emoney-switch-account-hook)) + +(defconst emoney-accounts-buffer-map + (let* ((map (make-sparse-keymap 'emoney-accounts-buffer-map))) + (define-key map [button2] #'emoney-mouse-switch-to-account) + map) + "A keymap for the extents in eMoney Accounts buffer.") + +(defconst emoney-largest-balance "999999999.99" + "This is only used for formatting purposes.") + +(defun emoney-setup-accounts-buffer () + "Set up the eMoney \"Accounts\" buffer." + (let ((buf emoney-accounts-buffer) + (accounts emoney-chart-of-accounts) + help-msg cbal) + (save-excursion + (when (buffer-live-p (get-buffer-create buf)) + (kill-buffer buf)) + (set-buffer (get-buffer-create buf)) + (while accounts + (setq help-msg (concat "Switch to A/C: " + (file-name-sans-extension (car accounts)))) + (insert (file-name-sans-extension (car accounts))) + (set-extent-properties + (make-extent (point-at-bol) (point)) + `(face emoney-account-name-face + mouse-face highlight + help-echo ,help-msg + balloon-help ,help-msg + keymap ,emoney-accounts-buffer-map)) + (with-current-buffer (car accounts) + (goto-char (point-max)) + (re-search-backward "\\s-[\\+-=]\\s-" nil t) + (setq cbal (nth 2 (emoney-parse-transaction-data + (buffer-substring (point) (point-at-eol)))))) + (move-to-column 13 'force) + (if cbal + (insert-face + (format + (concat "%" + (number-to-string (- (length emoney-largest-balance) + (length (format "%.2f" cbal)))) + "s$%.2f") "" cbal) + (if (< cbal 0) + 'emoney-debit-face + 'emoney-credit-face)) + (insert " Needs Recalc")) + (insert "\n") + (setq cbal nil) + (setq accounts (cdr accounts))) + (set-specifier horizontal-scrollbar-visible-p nil (current-buffer)) + (set-specifier has-modeline-p nil (current-buffer)) + (run-hooks 'emoney-setup-accounts-buffer-hook)))) + +(defconst emoney-header + "Date Type C Description Amount Balance +===============================================================================\n" + "The header inserted at the top of a `emoney-mode' buffer.") + +(defun emoney-setup-header-buffer () + "Set up the eMoney \"Account Register Header\" buffer." + (let ((buf emoney-header-buffer)) + (save-excursion + (when (buffer-live-p (get-buffer-create buf)) + (kill-buffer buf)) + (set-buffer (get-buffer-create buf)) + (insert-face emoney-current-account-name 'emoney-account-name-face) + (insert "\n\n") + (insert-face emoney-header 'emoney-header-face) + (set-specifier horizontal-scrollbar-visible-p nil (current-buffer)) + (set-specifier vertical-scrollbar-visible-p nil (current-buffer)) + (set-specifier has-modeline-p nil (current-buffer)) + (goto-char (point-min)) + (run-hooks 'emoney-setup-header-buffer-hook)))) + +;;;###autoload +(defun emoney-customise () + "*Convenience function to customise eMoney." + (interactive) + (customize-group 'emoney)) + +;; Because lots of people in the world can't spell. +;;;###autoload +(defalias 'emoney-customize 'emoney-customise) + +(defvar emoney-transaction-types '("init" "") + "A list of valid transaction types. + +It is a combination of `emoney-credit-transaction-types', +`emoney-debit-transaction-types', and a blank type.") + +(defconst emoney-cheque-type + (if emoney-uk-cheque-spelling + "chq[ \t]+\\([0-9]+\\)" + "chk[ \t]+\\([0-9]+\\)") + "Type field for cheque transactions. + +This is defined separately from the other transaction types because +it is used by functions that perform special operations on cheque. +transactions.") + +(defconst emoney-date-column 0 + "Column where transaction date begins.") + +(defconst emoney-type-column 11 + "Column where transaction type begins.") + +(defconst emoney-clear-column 22 + "Column where status appears.") + +(defconst emoney-description-column 24 + "Column where transaction description begins.") + +(defconst emoney-sign-column 52 + "Column where transaction sign begins.") + +(defconst emoney-amount-column 54 + "Column where transaction amount begins.") + +(defconst emoney-current-balance-column 65 + "Column where current emoney begins.") + +(defconst emoney-tab-stop-list + (list + emoney-date-column + emoney-type-column + emoney-clear-column + emoney-description-column + emoney-sign-column + emoney-amount-column + emoney-current-balance-column) + "List of tab stops that define the start of all transaction fields.") + +(defvar emoney-mode-map + (let ((map (make-sparse-keymap 'emoney-mode-map))) + (define-key map [(control c) (control b)] #'emoney-backward-field) + (define-key map [(control c) (control c)] #'emoney-recalculate-buffer) + (define-key map [(control c) (control d)] #'emoney-clear-current-field) + (define-key map [(control c) (control f)] #'emoney-forward-field) + (define-key map [(control c) (control n)] #'emoney-append-next-cheque) + (define-key map [(control c) (control r)] #'emoney-summarise-cheques-region) + (define-key map [(control c) (control s)] #'emoney-summarise-cheques-buffer) + (define-key map [(control c) (control t)] #'emoney-append-transaction) + (define-key map [(control c) (control x)] #'emoney-transfer-funds) + (define-key map [tab] #'emoney-forward-field) + (define-key map [(control c) b] #'emoney-go-to-bank) + (define-key map [(control c) c] #'emoney-calc) + (define-key map [(control c) s] #'emoney-switch-to-account) + (define-key map [(control c) q] #'emoney-quit) + (define-key map [(control c) (control q)] #'emoney-recalc-and-exit) + map) + "Keymap for emoney buffer.") + +(defconst emoney-mode-menu + '("eMoney" + ["New A/C" emoney-new-account t] + "---" + [(concat "New " + (if emoney-uk-cheque-spelling + "Cheque " + "Check ") + "Transaction") emoney-append-next-cheque t] + ["New Transaction" emoney-append-transaction t] + ["Transfer Funds" emoney-transfer-funds t] + "---" + ["Next Field" emoney-forward-field t] + ["Previous Field" emoney-backward-field t] + ["Clear Current Field" emoney-clear-current-field t] + "---" + [(concat "Summary of " + (if emoney-uk-cheque-spelling + "cheques " + "checks ") + "(buffer)") emoney-summarise-cheques-buffer t] + [(concat "Summary of " + (if emoney-uk-cheque-spelling + "cheques " + "checks ") + "(region)") emoney-summarise-cheques-region t] + "---" + ["Recalculate Buffer" emoney-recalculate-buffer t] + "---" + ["Go To The Bank!" emoney-go-to-bank t] + ["Calculator" emoney-calc t] + "---" + ["Recalc All A/C's and Exit" emoney-recalc-and-exit t] + ["Exit eMoney" emoney-quit t]) + "Menu for `emoney-mode' buffers.") + +(easy-menu-define + emoney-mode-easymenu nil "eMoney" emoney-mode-menu) + +(defvar emoney-credit-type-keywords + (regexp-opt (append emoney-credit-transaction-types + (list emoney-cr-transfer-transaction-type))) + "eMoney font lock keywords for credit tran types") + +(defvar emoney-debit-type-keywords + (regexp-opt (append emoney-debit-transaction-types + (list emoney-db-transfer-transaction-type))) + "eMoney font lock keywords for debit tran types") + +(defvar emoney-font-lock-keywords + `(("x\\s-\\(.*\\)[\\+-]\\s-" (1 emoney-clear-tran-face)) + ("o\\s-\\(.*\\)[\\+-]\\s-" (1 emoney-unclear-tran-face)) + (,emoney-credit-type-keywords . emoney-credit-face) + (,emoney-debit-type-keywords . emoney-debit-face) + ("\\(^[0-9]+\\(-\\|\\/\\)[0-9]+\\(-\\|\\/\\)[0-9]+\\)" + (1 emoney-date-face)) + ("-\\s-+\\([0-9]+\\.[0-9][0-9]\\)" (1 emoney-debit-face)) + ("-[0-9]+\\.[0-9]+" . emoney-debit-face) + ("[^-]\\([0-9]+\\.[0-9]+$\\)" (1 emoney-credit-face)) + ("\\+\\s-+\\([0-9]+\\.[0-9][0-9]\\)" (1 emoney-credit-face))) + "Font lock keywords for `emoney-mode'.") + + +;;;###autoload +(defun emoney-mode () + "Major mode for editing a buffer containing financial transactions. +The following bindings provide the main functionality of this mode: + +\\{emoney-mode-map} + +Transactions occur on a single line and have the following fields (in +order): + + date The transaction date. See `emoney-date-format'. + type This field must either be blank or match one of the + expressions defined in `emoney-credit-transaction-types' + and `emoney-debit-transaction-types'. + clear Status of transaction, 'o' is open, 'x' is cleared. New + transactions default to 'o'. + description A possibly blank transaction description. + sign This field must either be '+', '-' or '='. '+' means + credit, '-' means debit, and '=' resets balance. eMoney + will usually guess the correct sign to use. + amount The transaction amount. + balance The balance after this transaction. This field will be + computed upon recalculation, you _don't_ need to fill it + in. Just do: \\[emoney-recalculate-buffer]. + +Any line in the buffer that does not begin with a date will be +considered a comment and ignored. Among other things, this allows +the transaction description to span several lines. + +Changing any amount and recalculating again will update all visible +balances. Transactions may be commented out by putting a semi-colon +\(or any other non-numerical character\) at the beginning of the line. + +Entering `emoney-mode' runs the `emoney-mode-hooks' if any exist." + (interactive) + (kill-all-local-variables) + (setq major-mode 'emoney-mode) + (setq mode-name "eMoney") + (use-local-map emoney-mode-map) + (easy-menu-add emoney-mode-easymenu) + (make-local-variable 'tab-stop-list) + (setq tab-stop-list emoney-tab-stop-list) + (make-local-variable 'indent-tabs-mode) + (setq indent-tabs-mode nil) + (setq indent-line-function 'emoney-forward-field) + (overwrite-mode 1) + (run-hooks 'emoney-mode-hooks)) + +(defun emoney-current-line () + "Return the current buffer line at point." + (save-excursion + (beginning-of-line) + (count-lines (point-min) (point)))) + +(defun emoney-completing-read (prompt table &optional predicate require-match + initial-contents history default) + "Like `completing-read', but also accepts strings. + +Arguments PROMPT, TABLE, PREDICATE, REQUIRE-MATCH, INITIAL-CONTENTS, +HISTORY, DEFAULT are as per `completing-read'." + (completing-read + prompt + (if (vectorp table) + table + (mapcar 'list table)) + predicate require-match initial-contents history default)) + +(defun emoney-forward-field () + "Move the cursor to the next field on the current line." + (interactive) + (move-to-tab-stop)) + +(defun emoney-go-to-bank (&optional url) + "Open your bank's URL with `browse-url'." + (interactive) + (let ((url (or url + emoney-bank-url))) + (if (or (equal url "unset") + (not url)) + (message-or-box "Please customise `emoney-bank-url'.") + (browse-url url)))) + +(defun emoney-calc () + "Wrapper around `calc' to get around \"window-edges bug\"." + (interactive) + (add-hook 'calc-end-hook #'(lambda () + (setq calc-was-split nil))) + (calc)) + +(defun emoney-last (list) + "Return last element in LIST." + (cond + ((null list) + '()) + ((null (cdr list)) + (car list)) + (t (emoney-last (cdr list))))) + +(defun emoney-find-largest-less-than (list item) + "Search a sorted LIST of numbers, return the largest number that is < ITEM." + (let ((list-car (car list)) + (list-cdr (cdr list)) + (last nil)) + (while (and list-car (< list-car item)) + (setq last list-car) + (setq list-car (car list-cdr)) + (setq list-cdr (cdr list-cdr))) + last)) + +(defun emoney-find-largest-less-than-equal (list item) + "Return cdr of LIST starting @ the largest number that is <= to ITEM." + (let ((list-car (car list)) + (list-cdr (cdr list)) + (last nil)) + (while (and list-car (<= list-car item)) + (setq last (cons list-car list-cdr)) + (setq list-car (car list-cdr)) + (setq list-cdr (cdr list-cdr))) + last)) + +(defun emoney-find-field (column) + "Return a list of the start and end of the field around COLUMN. + +End may be nil if column is after the last defined tab stop." + (let ((field (emoney-find-largest-less-than-equal + emoney-tab-stop-list column))) + (if (equal 1 (length field)) + (list (car field) nil) + (list (nth 0 field) (nth 1 field))))) + +(defun emoney-backward-field () + "Move the cursor to the previous entry field on the current line." + (interactive) + (let* ((col (current-column)) + (prev (emoney-find-largest-less-than emoney-tab-stop-list col))) + (if prev + (move-to-column prev) + (move-to-column (emoney-last emoney-tab-stop-list))))) + +(defun emoney-clear-current-field () + "Fill the field around point with spaces, leave point at start of field." + (interactive) + (let* ((field (emoney-find-field (current-column))) + (line-start (progn (beginning-of-line) (point))) + (line-end (progn + (end-of-line) + (untabify line-start (point)) + (point))) + (field-start (+ line-start (nth 0 field))) + (field-end (if (nth 1 field) + (+ line-start (nth 1 field)) + line-end))) + (clear-rectangle field-start field-end) + (goto-char field-start))) + +(defsubst emoney-build-types-list () + "Dynamically build a list of transaction types. + +This is done dynamically so that the user can change or add to the +list of transaction types without having to reload eMoney." + ;; Initialise to ("init" ""). + (setq emoney-transaction-types '("init" "")) + ;; Load the debit and credit transaction types. + (setq emoney-transaction-types + (append emoney-transaction-types + emoney-debit-transaction-types + emoney-credit-transaction-types + (list emoney-cr-transfer-transaction-type) + (list emoney-db-transfer-transaction-type)))) + +;; Stolen from Gnus' time-date.el +(defun emoney-days-to-time (days) + "Convert DAYS into a time value." + (let* ((seconds (* 1.0 days 60 60 24)) + (rest (expt 2 16)) + (ms (condition-case nil (floor (/ seconds rest)) + (range-error (expt 2 16))))) + (list ms (condition-case nil (round (- seconds (* ms rest))) + (range-error (expt 2 16)))))) + +;; Stolen from Gnus' time-date.el +(defun emoney-time-add (t1 t2) + "Add two time values. One should represent a time difference." + (let ((high (car t1)) + (low (if (consp (cdr t1)) (nth 1 t1) (cdr t1))) + (micro (if (numberp (car-safe (cdr-safe (cdr t1)))) + (nth 2 t1) + 0)) + (high2 (car t2)) + (low2 (if (consp (cdr t2)) (nth 1 t2) (cdr t2))) + (micro2 (if (numberp (car-safe (cdr-safe (cdr t2)))) + (nth 2 t2) + 0))) + ;; Add + (setq micro (+ micro micro2)) + (setq low (+ low low2)) + (setq high (+ high high2)) + + ;; Normalize + ;; `/' rounds towards zero while `mod' returns a positive number, + ;; so we can't rely on (= a (+ (* 100 (/ a 100)) (mod a 100))). + (setq low (+ low (/ micro 1000000) (if (< micro 0) -1 0))) + (setq micro (mod micro 1000000)) + (setq high (+ high (/ low 65536) (if (< low 0) -1 0))) + (setq low (logand low 65535)) + + (list high low micro))) + +(defun emoney-append-transaction (&optional trans-type description amount) + "Add a transaction to the end of current buffer using today's date." + (interactive) + (goto-char (point-max)) + (if (not (equal 0 (current-column))) + (newline)) + (let* ((date-variance + (read-number "Date (RET for current; -DAYS past; DAYS future): " + 'integers-only "0")) + (tran-date + (format-time-string emoney-date-format + (emoney-time-add + (current-time) + (emoney-days-to-time date-variance))))) + (insert tran-date)) + (move-to-tab-stop) + (emoney-build-types-list) + (let* ((type (or trans-type + (emoney-completing-read "Transaction type: " + emoney-transaction-types)))) + (insert type) + (move-to-tab-stop) + (insert "o") + (move-to-tab-stop) + (let ((before-descript (point)) + (start-column (current-column)) + (fill-column (- emoney-sign-column + emoney-description-column + 1))) + (save-excursion + (insert (or description + (read-string "Description: "))) + (save-restriction + (narrow-to-region before-descript (point)) + (goto-char before-descript) + (while (progn (move-to-column fill-column) (not (eobp))) + (search-forward " " nil t) + (insert "\n")) + (fill-paragraph 1) + (goto-char before-descript) + (forward-line 1) + (while (progn (beginning-of-line) (not (eobp))) + (indent-to-column start-column) + (forward-line 1))))) + (move-to-tab-stop) + (cond ((or (member type emoney-credit-transaction-types) + (string= type emoney-cr-transfer-transaction-type)) + (insert "+")) + ((or (member type emoney-debit-transaction-types) + (string= type emoney-db-transfer-transaction-type)) + (insert "-")) + ((string= type "init") + (insert "=")) + (t (if (y-or-n-p "Is this a credit transaction? ") + (insert "+") + (if (y-or-n-p "Is this a debit transaction? ") + (insert "-") + (if (y-or-n-p "Is this an initialising transaction? ") + (insert "=") + (warn "Couldn't determine +/-/=, leaving blank")))))) + (move-to-tab-stop) + (insert (if amount + (number-to-string amount) + (read-string "Amount: "))) + (run-hooks 'emoney-transaction-hook))) + +(defun emoney-append-next-cheque () + "Add a cheque transaction to the end of the current buffer using today's date. + +Inserts the cheque number following the last cheque number written into the +transaction type column. Loses if you write cheques out of order." + (interactive) + (goto-char (point-max)) + (if (not (equal 0 (current-column))) + (newline)) + (insert (format-time-string emoney-date-format)) + (move-to-tab-stop) + (let (cheque cheque-number noinit) + (save-excursion + (if (search-backward-regexp emoney-cheque-type 0 t) + (progn + (setq cheque (buffer-substring (match-beginning 1) (match-end 1))) + (setq noinit nil)) + (move-to-column emoney-type-column) + (if (< (current-column) emoney-type-column) + (indent-to-column emoney-type-column)) + (if emoney-uk-cheque-spelling + (insert "chq 000001") + (insert "chk 000001")) + (setq noinit t))) + (unless noinit + (setq cheque-number (1+ (string-to-number cheque))) + (move-to-column emoney-type-column) + (if (< (current-column) emoney-type-column) + (indent-to-column emoney-type-column)) + (if emoney-uk-cheque-spelling + (insert (format "chq %06d" cheque-number)) + (insert (format "chk %06d" cheque-number)))) + (move-to-tab-stop) + (insert "o") + (move-to-tab-stop) + (let ((before-descript (point)) + (start-column (current-column)) + (fill-column (- emoney-sign-column + emoney-description-column + 1))) + (save-excursion + (insert (read-string "Payable To: ")) + (save-restriction + (narrow-to-region before-descript (point)) + (goto-char before-descript) + (while (progn (move-to-column fill-column) (not (eobp))) + (search-forward " " nil t) + (insert "\n")) + (fill-paragraph 1) + (goto-char before-descript) + (forward-line 1) + (while (progn (beginning-of-line) (not (eobp))) + (indent-to-column start-column) + (forward-line 1))))) + (move-to-tab-stop) + (insert "-") + (move-to-tab-stop) + (insert (read-string "Amount: ")) + (run-hooks 'emoney-transaction-hook) + (run-hooks 'emoney-transaction-cheque-hook))) + +(defvar emoney-transfer-account-history nil) + +(defun emoney-transfer-funds (&optional from to amount) + "Transfer funds from one eMoney account to another. + +Argument FROM is the account to transfer from. +Argument To is the account to transfer to. +Argument AMOUNT is how much to transfer." + (interactive) + (let ((from (or from + (emoney-completing-read "Transfer from: " + emoney-chart-of-accounts + nil + t + (concat emoney-current-account-name + ".emy") + emoney-transfer-account-history))) + (to (or to + (emoney-completing-read "Transfer to: " + emoney-chart-of-accounts nil t nil + emoney-transfer-account-history))) + (amount (or amount + (read-number "Amount: "))) + (current-ac (concat emoney-current-account-name ".emy"))) + (with-current-buffer from + (emoney-append-transaction + emoney-db-transfer-transaction-type + (concat "T'fer to " (file-name-sans-extension to)) + amount)) + (with-current-buffer to + (emoney-append-transaction + emoney-cr-transfer-transaction-type + (concat "T'fer from " (file-name-sans-extension from)) + amount)) + (loop for buf in '(from to) + do (emoney-switch-to-account (symbol-value buf)) + do (emoney-recalculate-buffer)) + (run-hooks 'emoney-transaction-transfer-hook) + (emoney-switch-to-account current-ac))) + +(defsubst emoney-build-type-regexp () + "Return a regular expression that will match any valid transaction type. + +This is done dynamically so users can redefine the valid transactions in +their `user-init-file' even after this file has been loaded." + (emoney-build-types-list) + (let ((types (append emoney-transaction-types + (list emoney-cheque-type)))) + (concat + "^\\(" + (mapconcat + #'(lambda(x) x) types "\\|") + "\\)[ \t]*$"))) + +(defun emoney-check-transaction-type (line-start) + "Check to make sure a valid transaction type has been used. + +Argument LINE-START is the starting point. + +Please note that the word \"check\" here means \"verify\" and it has +nothing to do with the American spelling of the word \"cheque\"." + (let* ((type-regexp (emoney-build-type-regexp)) + (type-start (+ line-start emoney-type-column)) + (type-end (+ line-start emoney-clear-column)) + (type-string (buffer-substring type-start type-end))) + (if (string-match type-regexp type-string) + nil + (error "Line %d, invalid type: %s" + (1+ (emoney-current-line)) type-string)))) + +(defun emoney-find-next-transaction () + "Find the next line that is a complete transaction. + +Return a list of the line start, numeric data start and line end +points." + (let ((found nil) + (line-regexp + "^\\([0-90-9]\\)+.*$") + line-start + line-end + data-start) + (while (and + (not found) + (search-forward-regexp line-regexp (point-max) t)) + (setq line-start (match-beginning 0)) + (setq line-end (progn (end-of-line) (point))) + (setq data-start (+ line-start emoney-sign-column)) + (if (> line-end data-start) + (setq found t))) + (if found + (list line-start data-start line-end) + nil))) + +(defun emoney-parse-transaction-data (data) + "Return a list of floating point numbers from DATA. + +DATA is a string representing the sign, amount and optionally balance of a +transaction. Balance is nil if not present." + (let ((data-regexp "\\([-+=]\\)[ \t]*\\([0-9.]+\\)?[ \t]*\\([-]?[0-9.]+\\)?") + (balance nil) + (reset nil) + string sign amount) + (string-match data-regexp data) + (if (match-beginning 1) + (setq sign (substring data (match-beginning 1) (match-end 1))) + (error "Line %d, missing sign" (1+ (emoney-current-line)))) + (if (equal "=" sign) + (progn + (setq sign "+") + (setq reset t))) + (if (match-beginning 2) + (progn + (setq string (substring data (match-beginning 2) (match-end 2))) + (setq amount (string-to-number (concat sign string)))) + (error "Line %d, missing amount" (1+ (emoney-current-line)))) + (if (match-beginning 3) + (progn + (setq string (substring data (match-beginning 3) (match-end 3))) + (setq balance (string-to-number string)))) + (if reset (setq sign "=")) + (list sign amount balance))) + +(defun emoney-same (amount1 amount2) + "Compare two dollar amounts, AMOUNT1 AMOUNT2, for equivalence." + (let ((string1 (format "%10.2f" amount1)) + (string2 (format "%10.2f" amount2))) + (equal string1 string2))) + +(defun emoney-form-transaction-data (sign amount balance) + "Given SIGN, AMOUNT and a BALANCE, return a string. + +The string is suitable for placing in the numeric region of a +transaction, based on the defined input columns." + (let* ((amount (abs amount)) + (width1 (- emoney-amount-column emoney-sign-column)) + (width2 (- emoney-current-balance-column emoney-amount-column)) + (len (length emoney-largest-balance)) + (gap (- width2 len)) + (value (concat "%" (number-to-string len) ".2f")) + (format-string (concat "%-" (number-to-string width1) + "s" value + "%" (number-to-string gap) "s" value))) + (format format-string sign amount "" balance))) + +(defun emoney-recalculate (start end) + "Recalculate the balances for region START END. + +The final balance, uncleared total, and the number of balances that +changed, and the transaction count are returned in a list." + (run-hooks 'emoney-recalculate-before-hook) + (let ((current-balance 0) + (changes 0) + (uncleared 0) + (transactions 0) + line-points) + (save-excursion + (save-restriction + (narrow-to-region start end) + (untabify (point-min) (point-max)) + (goto-char (point-min)) + (while (setq line-points (emoney-find-next-transaction)) + (setq transactions (1+ transactions)) + (let* ((line-start (nth 0 line-points)) + (data-start (nth 1 line-points)) + (data-end (nth 2 line-points)) + (clear-flag (buffer-substring + (+ line-start emoney-clear-column) + (+ 1 line-start emoney-clear-column))) + (data-string (buffer-substring data-start data-end)) + (data-values (emoney-parse-transaction-data data-string)) + (sign (nth 0 data-values)) + (amount (nth 1 data-values)) + (balance (nth 2 data-values)) + (new-balance (if (equal sign "=") + amount + (+ current-balance amount))) + (new-uncleared (if (equal clear-flag "x") + uncleared + (+ uncleared amount))) + (new-string + (emoney-form-transaction-data sign amount new-balance))) + (emoney-check-transaction-type line-start) + (setq current-balance new-balance) + (setq uncleared new-uncleared) + (if (or (null balance) (not (emoney-same balance new-balance))) + (setq changes (1+ changes))) + (if (not (equal data-string new-string)) + (progn + (delete-region data-start data-end) + (goto-char data-start) + (insert new-string))))) + (widen))) + (run-hooks 'emoney-recalculate-after-hook) + (list current-balance uncleared changes transactions))) + +(defvar emoney-is-exiting nil + "Non-nil when eMoney is in the process of quitting.") + +(defun emoney-update-acc-buf-bal (account balance) + "Update ACCOUNT BALANCE in accounts buffer." + (with-current-buffer emoney-accounts-buffer + (goto-char (point-min)) + (search-forward account) + (kill-line) + (move-to-column 13 'force) + (insert-face + (format (concat "%" + (number-to-string (- (length emoney-largest-balance) + (length (format "%.2f" balance)))) + "s$%.2f") "" balance) + (if (< balance 0) + 'emoney-debit-face + 'emoney-credit-face)))) + +(defun emoney-recalculate-buffer () + "Recalculate the current buffer. + +See `emoney-recalculate'." + (interactive) + (let* ((result (emoney-recalculate (point-min) (point-max))) + (balance (nth 0 result)) + (uncleared (nth 1 result)) + (changes (nth 2 result)) + (total (nth 3 result))) + (when emoney-save-after-recalculate + (save-buffer (current-buffer))) + (emoney-update-acc-buf-bal emoney-current-account-name balance) + (if emoney-is-exiting + (message + (format "book bal %.2f unclrd %.2f bank bal %.2f (%d/%d recalcs)" + balance uncleared (- balance uncleared) changes total)) + (message-or-box + (format "book bal %.2f unclrd %.2f bank bal %.2f (%d/%d recalcs)" + balance uncleared (- balance uncleared) changes total))) + (if (> changes 0) + (end-of-line)))) + +(defun emoney-recalculate-region (start end) + "Recalculate the current region, START END. + +See `emoney-recalculate'." + (interactive "r") + (let* ((result (emoney-recalculate start end)) + (balance (nth 0 result)) + (uncleared (nth 1 result)) + (changes (nth 2 result)) + (total (nth 3 result))) + (message-or-box (format "Region balance %.2f uncleared %.2f (%d/%d recalcs)" + balance uncleared changes total)) + (if (> changes 0) + (end-of-line)))) + +(defun emoney-summarise-cheques (start end) + "Create a buffer that lists only the cheques in the specified region. + +The region is denoted by START END. + +The list is sorted on cheque number. Breaks in sequence are denoted by lines +containing an asterisk between the cheques where the break occurs. The buffer +is also recalculated, thus showing to total of the cheques summarised." + (let ((emoney-buffer (current-buffer)) + (summary-buffer (get-buffer-create "*cheque summary*")) + (cheque-count 0) + (sequence-breaks 0) + line-points) + (save-excursion + (save-restriction + (set-buffer summary-buffer) + (delete-region (point-min) (point-max)) + (set-buffer emoney-buffer) + (narrow-to-region start end) + (goto-char (point-min)) + (while (setq line-points (emoney-find-next-transaction)) + (let* ((line-start (nth 0 line-points)) + (line-end (nth 2 line-points)) + (type-start (+ line-start emoney-type-column)) + (type-end (+ line-start emoney-description-column)) + (type-string (buffer-substring type-start type-end))) + (if (string-match emoney-cheque-type type-string) + (progn + (append-to-buffer + summary-buffer line-start (1+ line-end)) + (setq cheque-count (1+ cheque-count)))))) + (widen) + (set-buffer summary-buffer) + (sort-numeric-fields 3 (point-min) (point-max)) + (setq sequence-breaks (emoney-find-sequence-breaks)) + (goto-char (point-max)) + (insert (format "\n%d cheque%s summarised, %d sequence break%s\n" + cheque-count + (if (equal 1 cheque-count) "" "s") + sequence-breaks + (if (equal 1 sequence-breaks) "" "s"))) + (set-buffer emoney-buffer))) + (with-electric-help + '(lambda () + (insert + (with-temp-buffer + (erase-buffer) + (insert-buffer summary-buffer) + (buffer-string (current-buffer))))) + "*cheque summary*")) + (run-hooks 'emoney-summarise-cheques-hook)) + +(defun emoney-find-sequence-breaks () + "Find cheque sequence breaks in the current cheque summary buffer. + +Mark breaks in sequence by inserting a line with an asterisk between +the offending cheques. Return the count of sequence breaks found." + (let ((last-cheque nil) + (sequence-breaks 0)) + (goto-char (point-min)) + (while (search-forward-regexp + (concat "\\([0-9/]+\\)[ \t]+" emoney-cheque-type) + (point-max) t) + (let* ((cheque-start (match-beginning 2)) + (cheque-end (match-end 2)) + (cheque-string (buffer-substring cheque-start cheque-end)) + (cheque-number (string-to-int cheque-string))) + (if (not last-cheque) + (setq last-cheque cheque-number) + (if (not (equal cheque-number (1+ last-cheque))) + (progn + (setq sequence-breaks (1+ sequence-breaks)) + (beginning-of-line) + (open-line 1) + (insert "*") + (next-line 2))) + (setq last-cheque cheque-number)))) + sequence-breaks)) + +(defun emoney-summarise-cheques-buffer () + "Summarise the cheque transactions in the current buffer." + (interactive) + (emoney-summarise-cheques (point-min) (point-max)) + (emoney-recalculate (point-min) (point-max))) + +(defun emoney-summarise-cheques-region (start end) + "Summarise the cheque transactions in region START - END." + (interactive "r") + (emoney-summarise-cheques start end) + (emoney-recalculate (point-min) (point-max))) + +(defun emoney-new-account (&optional name balance) + "*Create a new A/C named NAME for use with eMoney." + (interactive) + (let ((new-acc (concat (or name + (read-string "New A/C Name: ")) ".emy")) + (bal (or balance + (read-number "Initial Balance: " nil 0)))) + (find-file-noselect + (expand-file-name new-acc emoney-accounts-directory)) + (setq emoney-chart-of-accounts + (push new-acc emoney-chart-of-accounts)) + (select-window (get-buffer-window + (concat emoney-current-account-name ".emy"))) + (switch-to-buffer new-acc) + (setq emoney-current-account-name + (file-name-sans-extension new-acc)) + (emoney-append-transaction "init" "Opening Balance" bal) + (emoney-recalculate-buffer) + (emoney-show-buffers) + (switch-to-buffer new-acc) + (goto-char (point-max)) + (run-hooks 'emoney-new-account-hook))) + +(defun emoney-setup-control-buffer () + "Set up the eMoney \"Control\" buffer." + (let ((buf emoney-control-buffer)) + (save-excursion + (when (buffer-live-p (get-buffer-create buf)) + (kill-buffer buf)) + (set-buffer (get-buffer-create buf)) + (widget-create 'push-button + :notify (lambda (&rest ignore) + (emoney-new-account)) + :help-echo "Create a new eMoney account." + " New A/C ") + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (save-excursion + (set-buffer + (concat emoney-current-account-name ".emy")) + (emoney-append-transaction))) + :help-echo "Add a new transaction\n +If you want to add a cheque transaction +use \"Add Chq\" instead." + "Add Trans") + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (save-excursion + (set-buffer + (concat emoney-current-account-name ".emy")) + (emoney-append-next-cheque))) + :help-echo (if emoney-uk-cheque-spelling + "Add a new cheque transaction." + "Add a new check transaction.") + (if emoney-uk-cheque-spelling + " Add Chq " + " Add Chk ")) + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (save-excursion + (set-buffer + (concat emoney-current-account-name ".emy")) + (emoney-recalculate-buffer))) + :help-echo "Record the last transaction.\n +Also recalculates the buffer." + "End Trans") + (widget-insert "\n\n") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (save-excursion + (set-buffer + (concat emoney-current-account-name ".emy")) + (emoney-transfer-funds))) + :help-echo "Transfer funds between accounts." + "Transfer ") + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (save-excursion + (set-buffer + (concat emoney-current-account-name ".emy")) + (emoney-summarise-cheques-buffer))) + :help-echo (if emoney-uk-cheque-spelling + "Display a summary of cheques." + "Display a summary of checks.") + (if emoney-uk-cheque-spelling + " Chq Sum " + " Chk Sum ")) + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (emoney-calc)) + :help-echo "Start the Emacs Calculator.\n +So you can count up all +of your millions!" + " Calc ") + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (if emoney-is-beta + (message-or-box + "eMoney: %s, \"%s\" [Beta]" + emoney-version emoney-codename) + (message-or-box + "eMoney: %s, \"%s\"" + emoney-version emoney-codename))) + :help-echo "Display eMoney version info." + " Version ") + (widget-insert "\n\n") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (emoney-go-to-bank)) + :help-echo "Open your bank's web site in your browser." + " Bank ") + (widget-insert " ") + (widget-create 'push-button + :notify (lambda (&rest ignore) + (emoney-quit)) + :help-echo "Exit eMoney." + " Exit ") + (set-specifier horizontal-scrollbar-visible-p nil (current-buffer)) + (set-specifier vertical-scrollbar-visible-p nil (current-buffer)) + (set-specifier has-modeline-p nil (current-buffer)) + (run-hooks 'emoney-setup-control-buffer-hook)))) + +(defun emoney-show-buffers () + "Display all the eMoney buffers." + (emoney-setup-accounts-buffer) + (emoney-setup-control-buffer) + (emoney-setup-header-buffer) + (delete-other-windows nil) + (switch-to-buffer emoney-accounts-buffer) + (split-window nil emoney-accounts-buffer-height) + (split-window nil emoney-accounts-buffer-width t) + (other-window 1) + (switch-to-buffer emoney-control-buffer) + (other-window 1) + (switch-to-buffer emoney-header-buffer) + (split-window nil emoney-header-buffer-height) + (other-window 1)) + +(defun emoney-quit () + "*Exit from eMoney, optionally recalculating all accounts first. + +To have all of your accounts recalculated before eMoney exits set +`emoney-recalculate-on-quit' to `t' + +If `emoney-save-after-recalculate' is also `t' the account buffers +will be saved before eMoney exits." + (interactive) + (run-hooks 'emoney-quit-before-hook) + (let ((accounts emoney-chart-of-accounts)) + (setq emoney-is-exiting t) + (dolist (buf accounts) + (when emoney-recalculate-on-quit + (set-buffer buf) + (emoney-recalculate-buffer)) + (kill-buffer buf)) + (kill-buffer emoney-accounts-buffer) + (kill-buffer emoney-control-buffer) + (kill-buffer emoney-header-buffer) + (run-hooks 'emoney-quit-after-hook) + (when (and emoney-use-new-frame + (frame-live-p emoney-frame)) + (delete-frame emoney-frame)) + (setq emoney-frame nil) + (unless emoney-use-new-frame + (jump-to-register ?\$)) + (setq emoney-is-exiting nil))) + +(defun emoney-recalc-and-exit () + "*Exit form eMoney, recalculating all accounts first." + (interactive) + (let ((old-recalc-val emoney-recalculate-on-quit)) + (setq emoney-recalculate-on-quit t) + (emoney-quit) + (setq emoney-recalculate-on-quit old-recalc-val))) + +;;;###autoload +(defun emoney () + "*Start a new eMoney session." + (interactive) + (unless emoney-use-new-frame + (window-configuration-to-register ?\$)) + (unless (frame-live-p emoney-frame) + (setq emoney-frame + (if emoney-use-new-frame + (make-frame '((name . "eMoney"))) + (selected-frame)))) + (select-frame emoney-frame) + (let ((accounts emoney-chart-of-accounts) + (dir emoney-accounts-directory)) + (while accounts + (find-file (expand-file-name (car accounts) dir)) + (unless (eq major-mode 'emoney-mode) + (emoney-mode)) + (setq accounts (cdr accounts))) + (setq emoney-current-account-name + (file-name-sans-extension emoney-default-account)) + (emoney-show-buffers) + (switch-to-buffer emoney-default-account) + (goto-char (point-max))) + (focus-frame emoney-frame)) + +;; Work around a problem with Emacs calc. If you start calc in a +;; frame with multiple buffers visible when calc exits it doesn't +;; return point to the place it was when you called calc. These +;; advices overcome that. +(defadvice calc (before em-calc-win-save first activate) + "Before starting calc, save the window config. +This is so we can restore the window config when calc exits because +calc doesn't DTRT in this regard by itself." + (push-window-configuration)) + +(defadvice calc-quit (after em-calc-win-restore last activate) + "Restore the \"pre calc\" window config on calc exit." + (pop-window-configuration)) + + +;;;###autoload(add-to-list 'auto-mode-alist '("\\.emy$" . emoney-mode)) + +(provide 'emoney) + +;;; emoney.el ends here -- 2.25.1