Robin Clark's original xacc-0.9 source

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@4 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 1997-11-01 01:39:32 +00:00
parent 97d79a0468
commit 1668431953
28 changed files with 8637 additions and 0 deletions

96
CHANGES Normal file
View File

@ -0,0 +1,96 @@
Version history:
------- -------
0.9 - 08 Sep 97
o Lots of code-cleanup.
o Adjust Balance window.
o Reconcile window! Makes it easy to reconcile your account
at the end of the month when you get your new bank statement.
o Hypertext, context sensitive help. A pretty nice add-on,
thanks to libhtmlw, from NCSA Mosaic. (Now someone just
has to write some decent help pages!)
o Fixed busy cursor. Previously the code the switched cursors
caused the program to crash, so it wasn't enabled. Now it
works, and is enabled.
0.7 - 14 Jul 97
o Started adding support for account types other than "BANK".
Still no support for Portfolio and Mutual accounts. (They
are greyed out in the "New Account" window for now.)
o Changed the balance field to use red/black text to denote
negative/positive balance (instead of using a sign... If you
define USE_NO_COLOR when compiling, it will revert to the
old method of displaying a '-' in front of negative balances)
o Fixed bug in automatic transfers that cause the "From"
account to always be the first account, and the "To" account
to possibly be incorrect. Also, added "[To: ]" "[From: ]"
(with to account name, and from account name) to the start
of the memo field, so you can keep track of where the money
comes from/goes to.
0.6 - 28 Jun 97
o Fixed balance/reconciled field (in bottom right corner
of register window. (It sorta works now, with lesstif.
I don't know about motif... you have to leave the current
transaction for the balances to be recalculated.)
o Rearranged directory structure... the source was growing
to too many files to have it all in one directory.
0.5 - 6 Jun 97 Mostly, minor bug fixes
o verifyDate -- affects when accelerator keys in the
register window cause the date to cross a year boundary
o Fixed handling of the date in the transfer window. Before
if the user pressed the "transfer" button with an incomplete
date in the date field, the resulting date would be
undefined.
o If the user doesn't enter data in the description field,
The number field, the memo field, or one of the amount
fields, the the new transaction isn't added when the
user leaves the new transaction, or presses "Record"
o Now user is prevented from entering more than one '.'
in the amount fields in the register and transfer windows.
Also, the user is prevented from entering more than two
'/' in the date field in the transfer window.
o Fixed a (very small) memory leak in the transfer window.
o Fixed a bug in the transfer window that resulted in a
different amount subtracted from the "from" account as was
added to the "to" account.
o Fixed bug that caused a segfault when deleting the last
transaction in the register window.
o Now if the user is in the last transaction (the empty
transaction) in the register window, the "Delete" button
does not do anything.
0.4 - 3 Jun 97
o Added "Balance" and "Reconciled" balance to the bottom
right corner of the register window.
o The main window uses an Xbae-Matrix widget now, instead
of a list, in order to line up the account names, types,
and balances in nice columns.
0.2 - First (mostly) functional release. Most of the buttons,
and menu bar choices actually do something now.
0.1 - First demo release. Lots of buttons, and menu bar choices
Don't do anything. The register window is still pretty
buggy.
Things to do/fix: (in no particular order)
------ -- ------
o Reg window segfaults on close... (I think this might be a
lesstif problem, so try a newer version)
o memorized transactions/quickfill (They work, but you need
a newer than v4.6.1 Xbae Widget)
o Bug Fixes! There are still a few bugs floating around.
(Let me know if you find any)
o a README and/or man page!
o use configure or Imake? or at least a proper "make install"

339
COPYING Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

155
Docs/pix.xpm Normal file
View File

@ -0,0 +1,155 @@
/* XPM */
static char * EscherCube_xpm[] = {
"48 48 104 2",
" c None",
". c #30C230C22081",
"X c #30C230C230C2",
"o c #30C2410330C2",
"O c #410330C24103",
"+ c #410341034103",
"@ c #514451445144",
"# c #514461855144",
"$ c #618551446185",
"% c #618561856185",
"& c #71C671C671C6",
"* c #71C6820771C6",
"= c #965882078617",
"- c #861792488617",
"; c #965892489658",
": c #9658A2899658",
"> c #9E79A2899E79",
", c #AEBAAEBA9E79",
"< c #AEBAAEBAAEBA",
"1 c #AEBABEFBAEBA",
"2 c #BEFBBEFBBEFB",
"3 c #CF3CBEFBCF3C",
"4 c #CF3CCF3CCF3C",
"5 c #DF7DCF3CCF3C",
"6 c #DF7DDF7DCF3C",
"7 c #DF7DDF7DDF7D",
"8 c #EFBEDF7DDF7D",
"9 c #DF7DEFBEDF7D",
"0 c #EFBEDF7DEFBE",
"q c #EFBEEFBEDF7D",
"w c #208130C22081",
"e c #410351445144",
"r c #514451446185",
"t c #71C6618571C6",
"y c #861771C68617",
"u c #9E7992489E79",
"i c #9E79AEBA9E79",
"p c #BEFBAEBABEFB",
"a c #BEFBCF3CBEFB",
"s c #BEFBCF3CCF3C",
"d c #CF3CCF3CDF7D",
"f c #CF3CDF7DCF3C",
"g c #DF7DDF7DEFBE",
"h c #208120812081",
"j c #30C2208130C2",
"k c #410330C230C2",
"l c #4103410330C2",
"z c #410351444103",
"x c #618551445144",
"c c #618561855144",
"v c #618571C66185",
"b c #861771C671C6",
"n c #8617820771C6",
"m c #965882079658",
"M c #9E7992489658",
"N c #AEBAA289AEBA",
"B c #BEFBAEBAAEBA",
"V c #DF7DCF3CDF7D",
"C c #CF3CDF7DDF7D",
"Z c #208120811040",
"A c #965892488617",
"S c #104020812081",
"D c #861782078617",
"F c #861792489658",
"G c #965892489E79",
"H c #104020811040",
"J c #208110402081",
"K c #30C220812081",
"L c #BEFBBEFBCF3C",
"P c #104010401040",
"I c #208110401040",
"U c #618571C671C6",
"Y c #71C671C68617",
"T c #71C682078617",
"R c #CF3CBEFBBEFB",
"E c #CF3CCF3CBEFB",
"W c #000010401040",
"Q c #104010402081",
"! c #9E79AEBAAEBA",
"~ c #104010400000",
"^ c #AEBAA2899E79",
"/ c #71C671C66185",
"( c #000010400000",
") c #000000000000",
"_ c #104000001040",
"` c #2081208130C2",
"' c #9658A2899E79",
"] c #104000000000",
"[ c #000000001040",
"{ c #30C241034103",
"} c #9E79A289AEBA",
"| c #AEBABEFBBEFB",
" . c #514461856185",
".. c #9E79A2899658",
"X. c #71C661856185",
"o. c #30C230C24103",
"O. c #514441035144",
"+. c #514451444103",
"@. c #410341035144",
"#. c #AEBAAEBABEFB",
"$. c #208130C230C2",
"%. c #6185618571C6",
"&. c #514441034103",
"*. c #861782079658",
" . X o O + @ # $ % & * = - ; : > , < 1 2 2 3 4 5 6 7 7 8 9 0 q ",
" w X X O + @ e r % t & y - ; : u i < < p a 3 s d f 7 7 g 9 0 9 ; ",
" h j X k l + z x c t v b n m ; M > N < B 2 2 a 3 4 V 6 7 7 0 9 m ; ",
" h h w X f d f d f V f V f 7 f 7 C 7 f V f V f d f V f 7 9 g 9 m ; ; ",
" Z h w j - 4 4 5 4 5 4 5 4 V f V 6 V f V f V 4 5 4 5 4 V 7 7 7 m A ; ; ",
" S h h j - D s 4 4 4 4 4 4 4 4 d f V f d f d 4 d 4 4 4 V C 7 7 m - ; F G ",
" H J Z K * D D m ; M 5 4 V 7 = D m - ; ; ",
" H h S h * y D L F ; : 4 f V C D D m a ; ; G ",
" P I H J & b n 2 2 m A M 3 4 5 f y D = 2 2 A ; ; ",
" P P H J U Y & p 1 2 - ; : 4 4 d f y T D 1 p 1 ; F G ",
" P P H J % t & < < < m ; u R E 4 f b * y B < < A ; ; ",
" W P P Q % t v < ! < - ; : L a 4 4 & * y < < ! ; ; G ",
" ~ P ~ I c $ % > ^ > m ; M 2 2 3 4 t / b ^ i ^ ; M ; ",
" ( P W P # $ % > > > F ; : p a 3 s t U & > > > ; ; G ",
" ) _ ( _ @ $ # M ; u m ; u p 2 2 a % v t M ; u ; M ; ",
" ( _ ( P P P H h h ` w X o : ; F F ; : & * D - G ' > i < 1 2 a % v t : ; F ; : u ",
" ) ] ( _ ~ P P I Z h w j X O m - m ; ; M & y - m ; > i N < 2 2 $ c % m - m ; M : ",
") [ ( _ W P P Q H h h j X O { D D - F G : y T m ; u > } < p | r .% D D - G : u ",
"V f 5 4 5 f V f V f V f V f V y * y m ; u f 5 f V f 5 4 V f x @ $ y * y : u ..",
"4 d f 4 f d f d 4 d f V f V f U & U F G : d f d f d f 4 4 d @ r # U & U G : > ",
"3 4 3 E 4 E 4 4 3 4 4 4 5 4 5 t v X.; ; u 4 4 4 4 E 4 E 3 4 @ @ x t v X.; u ..",
"a 4 a o.{ + .% v ; G > 3 a 4 e @ # .% v u ' > ",
"3 2 3 X O o $ # $ ; ; u 2 3 2 O.+.@ $ # $ : u > ",
"a 2 a X o + @ @ @ ; u ' 2 2 2 z @ @ @ @ @ u > } ",
"p < p X k l O.z O.; : u 1 p < O.+.@ O.z O...> i ",
"1 < 1 o.o + @.z @.; G > #.1 < z O.@ + @.z > > } ",
"N , N X O o l + o ; ; u 1 1 1 O.+.@ O l + : u > ",
"i } i o.o + O o o.; u o + z @ # % v } i } e @ @ } < #.| L a 4 f V o o.o G ' > ",
"> ..u o O + . X . ; o O + O.@ $ % & u u ..@ @ x , < 1 2 2 3 4 5 6 X . X ; u ..",
"' u : O + + j $.j $.o.{ O.e r % %.U G : u @ r # < < p 2 3 s d f 7 $.j $.u : u ",
"; A M l + + h j . K h j h K h h h h ; ; A x @ $ h h h h h K h j 6 7 7 0 : u ..",
"- m - + { @. h h w %.w h h h h h S h S m - m # r # h S h S h h h f 7 9 g F G : ",
"y D D l + + Z h h t % h Z J Z J Z J Z J D y D x # $ H J Z J Z J f V 7 7 - M ; ",
"* y * + z O. S h h & U t y * y @ $ . 4 d C 7 - m ; ",
"& / b l + + P J Z y & t & & / x c $ E 5 4 V n = D ",
"v %.v + z O. H J H D * & & v %.# % . a 4 f V * D - ",
"X.% % + &.z P P H D n y c $ % $ c $ a 3 4 V * y D ",
"# $ # + z @ P P H J m - D $ # $ # $ % 2 3 4 d * y T ",
"@ @ x + + z W P P Q m D m @ @ @ $ c % 2 R E 4 & b * ",
"z O.e + z @ P ~ I ; ; *. @ z O. .% % L s 4 U & * ",
"&.+ &.l &.+.W P M ; m + &.+ $ c X.2 3 v t & ",
"{ + { @.z O._ u ' ; + { + .$ % 3 v t & ",
"O o k + O.P P P H h h ` w X o l + z @ c X./ b n m ; u o O o $ % % % t v ",
"$.X $.@._ ~ P P I Z h w j X O + + @ # % v & * D - ; : X $.X .% v %.v ",
"j . j _ W P P Q H h h j X O { + &.@ $ c t & y D m ; > . j . % c X.% ",
"w j w ` w j w ` w ` h ` h h S h h h h ` h ` w ` w j w ` w j .% % ",
"h h K h h h h h h h J h J H J Z J H J h h h h h h h J h h h $ % ",
"S h h h H h S h S h S h H Q H J H Q H h H h S h S h S h S h . "};

38
Docs/xacc-about.html Normal file
View File

@ -0,0 +1,38 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>About X-Accountant</title>
</head>
<body bgcolor=#eeeeee>
<h1>About X-Accountant</h1>
<hr>
X-Accountant is a program to keep track of your finances. Some
of the features are:
<ul>
<li> Multiple accounts, which can be open at
the same time. Create one xacc account
for each of your bank accounts.
<li> Each account keeps a running balance and
a reconciled balance, so you can keep track
of the checks that have clear your account.
<li> A simple interface. If you can use the
register in the back of your checkbook,
you can use xacc.
<li> Automatic account reconciling. At the end
of the month, open up the reconcile window,
enter your bank statement's ending balance,
and check off the transactions that appear
in the bank statement. This makes it easy
to track down any discrepancies.
<li> QuickFill... if you begin typing a description
in the description fields, and it matches an
previous transaction, hitting TAB will copy
the previous transaction. Handy if you have
similar transactions on a regular basis.
</body>
</html>

330
Docs/xacc-gpl.html Normal file
View File

@ -0,0 +1,330 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>GNU General Public License</title>
</head>
<body bgcolor=#eeeeee>
<h1>GNU General Public License</h1>
<h2>Version 2, June 1991</h2>
<CENTER>
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA<P>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.<P>
</CENTER>
<P>
<h3><a name="SEC001">Preamble</a></h3>
<P>
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
<P>
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
<P>
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
<P>
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
<P>
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
<P>
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
<P>
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
<P>
The precise terms and conditions for copying, distribution and
modification follow.
<HR>
<h3>GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</h3>
<P>
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
<P>
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
<P>
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
<P>
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
<P>
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
<blockquote>
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
<P>
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
<P>
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
</blockquote>
<HR>
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
<P>
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
<P>
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
<P>
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
<blockquote>
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
<P>
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
<P>
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
</blockquote>
<P>
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
<P>
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
<HR>
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
<P>
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
<P>
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
<P>
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
<P>
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
<P>
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
<HR>
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
<P>
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
<P>
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
<P>
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
<P>
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
<P>
<h3>NO WARRANTY</h3>
<P>
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
<P>
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
<h3>END OF TERMS AND CONDITIONS</h3>
<hr>
</body>
</html>

16
Docs/xacc-main.html Normal file
View File

@ -0,0 +1,16 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>Help</title>
</head>
<body>
For help on a specific topic:
<ul>
<li><a href="xacc-gpl.html" name="SEC001">Creating a new account</a>
<li><a href="xacc-gpl.html">Creating a new account</a>
<li><a href="xacc-about.html">Creating a new account</a>
<hr>
</body>
</html>

13
Docs/xacc-recnwin.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title></title>
</head>
<body>
<h1></h1>
<hr>
</body>
</html>

13
Docs/xacc-regwin.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title></title>
</head>
<body>
<h1></h1>
<hr>
</body>
</html>

73
Makefile Normal file
View File

@ -0,0 +1,73 @@
######################################################################
#********************************************************************
#* Makefile -- makefile for xacc (X-Accountant) *
#* Copyright (C) 1997 Robin D. Clark *
#* *
#* This program is free software; you can redistribute it and/or *
#* modify it under the terms of the GNU General Public License as *
#* published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU General Public License for more details. *
#* *
#* You should have received a copy of the GNU General Public License*
#* along with this program; if not, write to the Free Software *
#* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
#* *
#* Author: Rob Clark *
#* Internet: rclark@cs.hmc.edu *
#* Address: 609 8th Street *
#* Huntington Beach, CA 92648-4632 *
#********************************************************************
######################################################################
# CONFIGURABLE STUFF: #
CC = gcc
AR = ar r
RANLIB = ranlib
# USE_NO_COLOR - don't use red/black colors to denote neg/positive
# balances, but instead display a signed number in
# the balance field
# USEQUICKFILL - comment out if you get a compile error about
# XbaeMatrixSetCursorPosition
# HYPER_HELP - include hyper-text help system
# DEBUGMEMORY - does some accounting whenever malloc/free
# is called.
# USEDEBUG - causes debugging info to be displayed
CFLAGS = $(LFLAGS) -I../include -I../libhtmlw -I/usr/X11/include \
-I/usr/local/include -DMOTIF1_2 \
-DUSEQUICKFILL # -DUSE_NO_COLOR -DDEBUGMEMORY -DUSEDEBUG
LFLAGS = -g -L/usr/local/lib -L/usr/X11/lib
LIBS = -lXm -lXmu -lXbae -lXt -lXext -lX11 -lSM -lICE -lXpm
######################################################################
######################################################################
# DO NOT EDIT THE STUFF BELOW THIS LINE! #
OPTIONS = "CC = $(CC)" "LFLAGS = $(LFLAGS)" \
"CFLAGS = $(CFLAGS)" "LIBS = $(LIBS)" \
"RANLIB = $(RANLIB)" "AR = $(AR)"
default :
@cd libhtmlw ; $(MAKE) $(OPTIONS)
@cd src ; $(MAKE) $(OPTIONS)
clean :
rm -f *~ *.bak
@cd include ; rm -f *~
@cd help ; rm -f *~
@cd libhtmlw ; $(MAKE) clean
@cd src ; $(MAKE) clean
really_clean : clean
@cd src ; $(MAKE) really_clean
depend :
@cd src ; $(MAKE) depend $(OPTIONS)

38
README Normal file
View File

@ -0,0 +1,38 @@
X-Accountant
------------
xacc is a program to keep track of your finances. It is similar in
concept to Quicken(TM). Although xacc still lacks the advanced
features of quicken, it does have the basic functionality. Some
of the features of xacc are:
- Multiple Accounts
- Each account keeps a running balance and
a reconciled balance, so you can keep track
of the checks that have clear your account.
- A simple interface. If you can use the
register in the back of your checkbook,
you can use xacc.
- QuickFill... if you begin typing a description
in the description fields, and it matches an
previous transaction, hitting <TAB> will copy
the previous transaction. Handy if you have
similar transactions on a regular basis.
(such as depositing your paycheck every week :)
To install:
-----------
First check the makefile to ensure that all the paths are ok.
Also, make sure that the Xbae-Matrix widget and Motif or
Lesstif are installed. You can get Lesstif from
http://www.lesstif.org. You can get The Xbae widget from
ftp://ftp.x.org/contrib/widgets/motif/ or any mirror. If
you are using a version of Xbae 4.6.1, you will need to
comment out "-DUSEQUICKFILL" in the Makefile.
# make depend
# make
sorry, no "make install" yet.

672
src/AccWindow.c Normal file
View File

@ -0,0 +1,672 @@
/********************************************************************\
* AccWindow.c -- window for creating new accounts for xacc *
* (X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include <Xm/Xm.h>
#include <Xm/DialogS.h>
#include <Xm/Form.h>
#include <Xm/Frame.h>
#include <Xm/RowColumn.h>
#include <Xm/LabelGP.h>
#include <Xm/ToggleB.h>
#include <Xm/PushB.h>
#include <Xm/Text.h>
#include <string.h>
#include "Account.h"
#include "Data.h"
#include "main.h"
#include "util.h"
/* NOTE: notes has to be at the beginning of the struct! Order is
* important */
typedef struct _accwindow {
String notes; /* The text from the "Notes" window */
/* The account type buttons: */
Widget bank;
Widget cash;
Widget asset;
Widget credit;
Widget liability;
Widget portfolio;
Widget mutual;
/* The text fields: */
Widget name; /* The account name text field */
Widget desc; /* Account description text field */
} AccWindow;
/* NOTE: notes has to be at the beginning of the struct! Order is
* important */
typedef struct _editaccwindow {
String notes; /* The text from the "Notes" window */
/* The text fields: */
Widget name; /* The account name text field */
Widget desc; /* Account description text field */
Account *account; /* The text from the "Notes" window */
} EditAccWindow;
/** GLOBALS *********************************************************/
extern Data *data;
extern Widget toplevel;
/** PROTOTYPES ******************************************************/
void closeAccWindow( Widget mw, XtPointer cd, XtPointer cb );
void closeEditAccWindow( Widget mw, XtPointer cd, XtPointer cb );
void notesCB( Widget mw, XtPointer cd, XtPointer cb );
void createCB( Widget mw, XtPointer cd, XtPointer cb );
void editCB( Widget mw, XtPointer cd, XtPointer cb );
/********************************************************************\
* accWindow *
* opens up a window to create a new account... the account is *
* actually created in the "create" callback *
* *
* Args: parent - the parent of the window to be created *
* Return: none *
\********************************************************************/
void
accWindow( Widget parent )
{
Widget dialog, form, frame, rc, widget,
label, buttonform;
AccWindow *accData;
int position;
setBusyCursor( parent );
accData = (AccWindow *)_malloc(sizeof(AccWindow));
accData->notes = XtNewString("");
/* force the size of the dialog so it is not resizable */
dialog = XtVaCreatePopupShell( "dialog",
xmDialogShellWidgetClass, parent,
XmNtitle, "Set Up Account",
XmNdeleteResponse, XmDESTROY,
XmNwidth, 350,
XmNminWidth, 350,
XmNmaxWidth, 350,
XmNheight, 300,
XmNminHeight, 300,
XmNmaxHeight, 300,
NULL );
XtAddCallback( dialog, XmNdestroyCallback,
closeAccWindow, (XtPointer)accData );
/* The form to put everything in the dialog in */
form = XtVaCreateWidget( "form", xmFormWidgetClass, dialog, NULL );
/******************************************************************\
* The account type area *
\******************************************************************/
/* Label tells the user what this area is */
widget = XtVaCreateManagedWidget( "Account Type",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 20,
NULL );
/* Makes a nice looking frame around the radio buttons */
frame = XtVaCreateManagedWidget( "frame",
xmFrameWidgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, widget,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 20,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 20,
NULL);
/* A RowCol goes in the frame, to place the buttons */
rc = XtVaCreateManagedWidget( "rowcol",
xmRowColumnWidgetClass, frame,
/*XmNentryAlignment, XmALIGNMENT_CENTER,*/
XmNorientation, XmVERTICAL,
XmNmarginHeight, 10,
XmNmarginWidth, 10,
/*XmNpacking, XmPACK_TIGHT,*/
XmNradioBehavior, True,
XmNnumColumns, 2,
NULL );
/* Create the buttons */
accData->bank =
XtVaCreateManagedWidget( "Bank",
xmToggleButtonWidgetClass, rc,
XmNindicatorType, XmONE_OF_MANY,
XmNset, True,
NULL);
accData->cash =
XtVaCreateManagedWidget( "Cash",
xmToggleButtonWidgetClass, rc,
XmNindicatorType, XmONE_OF_MANY,
NULL);
accData->asset =
XtVaCreateManagedWidget( "Asset",
xmToggleButtonWidgetClass, rc,
XmNindicatorType, XmONE_OF_MANY,
NULL);
accData->credit =
XtVaCreateManagedWidget( "Credit Card",
xmToggleButtonWidgetClass, rc,
XmNindicatorType, XmONE_OF_MANY,
NULL);
accData->liability =
XtVaCreateManagedWidget( "Liability",
xmToggleButtonWidgetClass, rc,
XmNindicatorType, XmONE_OF_MANY,
NULL);
accData->portfolio =
XtVaCreateManagedWidget( "Portfolio",
xmToggleButtonWidgetClass, rc,
XmNindicatorType, XmONE_OF_MANY,
NULL);
/* Portfolio account not supported yet, so grey it out: */
XtSetSensitive( accData->portfolio, False );
accData->mutual =
XtVaCreateManagedWidget( "Mutual Fund",
xmToggleButtonWidgetClass, rc,
XmNindicatorType, XmONE_OF_MANY,
NULL);
/* Mutual Fund account not supported yet, so grey it out: */
XtSetSensitive( accData->mutual, False );
/******************************************************************\
* Text fields.... *
\******************************************************************/
label =
XtVaCreateManagedWidget( "Account Name:",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, frame,
XmNtopOffset, 10,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 35, /* 35% */
NULL );
accData->name =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNmaxLength, 40,
XmNcolumns, 25,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, frame,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 35, /* 35% */
NULL );
label =
XtVaCreateManagedWidget( "Description:",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, accData->name,
XmNtopOffset, 10,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 35, /* 35% */
NULL );
accData->desc =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNmaxLength, 40,
XmNcolumns, 30,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, accData->name,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 35, /* 35% */
NULL );
/******************************************************************\
* The buttons at the bottom... *
\******************************************************************/
buttonform = XtVaCreateWidget( "form",
xmFormWidgetClass, form,
XmNfractionBase, 5,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, accData->desc,
XmNtopOffset, 10,
XmNbottomAttachment, XmATTACH_FORM,
XmNbottomOffset, 10,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL );
position = 1; /* puts the buttons in the right place */
/* The "Notes" button opens a window to a few lines of notes about
* the account */
widget = XtVaCreateManagedWidget( "Notes",
xmPushButtonWidgetClass, buttonform,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
notesCB, (XtPointer)accData );
/* The "Cancel" button */
widget = XtVaCreateManagedWidget( "Cancel",
xmPushButtonWidgetClass, buttonform,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
/* We need to do something to clean up memory too! */
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)dialog );
/* The "Create" button creates the new account with the data
* that the user entered */
widget = XtVaCreateManagedWidget( "Create",
xmPushButtonWidgetClass, buttonform,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
createCB, (XtPointer)accData );
/* We need to do something to clean up memory too! */
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)dialog );
XtManageChild(buttonform);
/******************************************************************/
XtManageChild(form);
XtPopup( dialog, XtGrabNone );
unsetBusyCursor( parent );
}
/********************************************************************\
* closeAccWindow *
* frees memory allocated for an accWindow, and other cleanup *
* stuff *
* *
* Args: mw - *
* cd - accData - the struct for the accWindow that is *
* being closed *
* cb - *
* Return: none *
\********************************************************************/
void
closeAccWindow( Widget mw, XtPointer cd, XtPointer cb )
{
AccWindow *accData = (AccWindow *)cd;
_free(accData);
DEBUG("close AccWindow");
}
/********************************************************************\
* editAccWindow *
* opens up a window to edit an account *
* *
* Args: parent - the parent of the window to be created *
* account - the account to edit *
* Return: none *
\********************************************************************/
void
editAccWindow( Widget parent, Account *account )
{
Widget dialog, form, widget, label, buttonform;
EditAccWindow *editAccData;
int position;
setBusyCursor( parent );
editAccData = (EditAccWindow *)_malloc(sizeof(EditAccWindow));
editAccData->notes = account->notes;
editAccData->account = account;
/* force the size of the dialog so it is not resizable */
dialog = XtVaCreatePopupShell( "dialog",
xmDialogShellWidgetClass, parent,
XmNtitle, "Edit Account",
XmNdeleteResponse, XmDESTROY,
XmNwidth, 350,
XmNminWidth, 350,
XmNmaxWidth, 350,
XmNheight, 150,
XmNminHeight, 150,
XmNmaxHeight, 150,
NULL );
XtAddCallback( dialog, XmNdestroyCallback,
closeEditAccWindow, (XtPointer)editAccData );
/* The form to put everything in the dialog in */
form = XtVaCreateWidget( "form", xmFormWidgetClass, dialog, NULL );
/******************************************************************\
* Text fields.... *
\******************************************************************/
label =
XtVaCreateManagedWidget( "Account Name:",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 10,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 35, /* 35% */
NULL );
editAccData->name =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNmaxLength, 40,
XmNcolumns, 25,
XmNvalue, account->accountName,
XmNeditable, True,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 35, /* 35% */
NULL );
label =
XtVaCreateManagedWidget( "Description:",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, editAccData->name,
XmNtopOffset, 10,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 35, /* 35% */
NULL );
editAccData->desc =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNmaxLength, 40,
XmNcolumns, 30,
XmNvalue, account->description,
XmNeditable, True,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, editAccData->name,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 35, /* 35% */
NULL );
/******************************************************************\
* The buttons at the bottom... *
\******************************************************************/
buttonform =
XtVaCreateWidget( "form",
xmFormWidgetClass, form,
XmNfractionBase, 5,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, editAccData->desc,
XmNtopOffset, 10,
XmNbottomAttachment, XmATTACH_FORM,
XmNbottomOffset, 10,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL );
position = 1; /* puts the buttons in the right place */
/* The "Notes" button opens a window to a few lines of notes about
* the account */
widget =
XtVaCreateManagedWidget( "Notes",
xmPushButtonWidgetClass, buttonform,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
notesCB, (XtPointer)editAccData );
/* The "Cancel" button */
widget =
XtVaCreateManagedWidget( "Cancel",
xmPushButtonWidgetClass, buttonform,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
/* We need to do something to clean up memory too! */
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)dialog );
/* The "Create" button creates the new account with the data
* that the user entered */
widget =
XtVaCreateManagedWidget( "Ok",
xmPushButtonWidgetClass, buttonform,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
editCB, (XtPointer)editAccData );
/* We need to do something to clean up memory too! */
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)dialog );
XtManageChild(buttonform);
/******************************************************************/
XtManageChild(form);
XtPopup( dialog, XtGrabNone );
unsetBusyCursor( parent );
}
/********************************************************************\
* closeEditAccWindow *
* frees memory allocated for an editAccWindow, and other cleanup *
* stuff *
* *
* Args: mw - *
* cd - editAccData - the struct for the editAccWindow *
* that is being closed *
* cb - *
* Return: none *
\********************************************************************/
void
closeEditAccWindow( Widget mw, XtPointer cd, XtPointer cb )
{
EditAccWindow *editAccData = (EditAccWindow *)cd;
_free(editAccData);
DEBUG("close EditAccWindow");
}
/********************************************************************\
* notesCB -- called when the user presses the "Notes" Button *
* *
* Args: mw - the widget that called us *
* cd - accData - the struct that has the notes text in it *
* cb - *
* Return: none *
* Global: toplevel - the toplevel widget *
\********************************************************************/
void
notesCB( Widget mw, XtPointer cd, XtPointer cb )
{
AccWindow *accData = (AccWindow *)cd;
accData->notes = textBox( toplevel, "Notes", accData->notes, True );
}
/********************************************************************\
* createCB -- creates the new account from data in the newaccount *
* dialog window *
* *
* Args: mw - the widget that called us *
* cd - accData - the struct of data associated with this *
* accWindow. *
* cb - *
* Return: none *
* Global: data - the data from the datafile *
* toplevel - the toplevel widget *
\********************************************************************/
void
createCB( Widget mw, XtPointer cd, XtPointer cb )
{
int i,num;
Transaction *trans;
Account *acc;
AccWindow *accData = (AccWindow *)cd;
String name = XmTextGetString(accData->name);
String desc = XmTextGetString(accData->desc);
/* The account has to have a name! */
if( strcmp( name, "" ) == 0 )
return;
acc = mallocAccount();
acc->flags = 0;
acc->accountName = name;
acc->description = desc;
acc->notes = accData->notes;
/* figure out account type */
{
Boolean set = False;
XtVaGetValues( accData->bank, XmNset, &set, NULL );
if(set)
acc->type = BANK;
XtVaGetValues( accData->cash, XmNset, &set, NULL );
if(set)
acc->type = CASH;
XtVaGetValues( accData->asset, XmNset, &set, NULL );
if(set)
acc->type = ASSET;
XtVaGetValues( accData->credit, XmNset, &set, NULL );
if(set)
acc->type = CREDIT;
XtVaGetValues( accData->liability, XmNset, &set, NULL );
if(set)
acc->type = LIABILITY;
XtVaGetValues( accData->portfolio, XmNset, &set, NULL );
if(set)
acc->type = PORTFOLIO;
XtVaGetValues( accData->mutual, XmNset, &set, NULL );
if(set)
acc->type = MUTUAL;
}
/* Add an opening balance transaction (as the first transaction) */
trans = (Transaction *)_malloc(sizeof(Transaction));
todaysDate( &(trans->date) );
trans->num = XtNewString("");
trans->description = XtNewString("Opening Balance\0");
trans->memo = XtNewString("");
trans->catagory = 0;
trans->reconciled = NREC;
trans->amount = 0;
/* add the new transaction to the account */
insertTransaction( acc, trans );
/* once the account is set up, add it to data */
insertAccount( data, acc );
/* make sure the accountlist is updated to reflect the new account */
refreshMainWindow();
/* open up the account window for the user */
regWindow( toplevel, acc );
}
/********************************************************************\
* editCB -- records the edits made by in the editAccWindow *
* *
* Args: mw - the widget that called us *
* cd - editAccData - the struct of data associated with *
* the EditAccWindow *
* cb - *
* Return: none *
* Global: data - the data from the datafile *
\********************************************************************/
void
editCB( Widget mw, XtPointer cd, XtPointer cb )
{
EditAccWindow *editAccData = (EditAccWindow *)cd;
String name = XmTextGetString(editAccData->name);
String desc = XmTextGetString(editAccData->desc);
/* The account has to have a name! */
if( strcmp( name, "" ) != 0 )
{
XtFree(editAccData->account->accountName);
editAccData->account->accountName = name;
}
XtFree(editAccData->account->description);
editAccData->account->description = name;
refreshMainWindow();
}

211
src/Account.c Normal file
View File

@ -0,0 +1,211 @@
/********************************************************************\
* Account.c -- the Account data structure *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include "util.h"
#include "main.h"
#include "Data.h"
#include "Account.h"
#include "date.h"
extern Data *data;
/********************************************************************\
* Because I can't use C++ for this project, doesn't mean that I *
* can't pretend too! These functions perform actions on the *
* account data structure, in order to encapsulate the knowledge *
* of the internals of the Account in one file. *
\********************************************************************/
/********************************************************************\
\********************************************************************/
Account *
mallocAccount( void )
{
Account *acc = (Account *)_malloc(sizeof(Account));
acc->flags = 0;
acc->type = 0;
acc->accountName = NULL;
acc->description = NULL;
acc->notes = NULL;
acc->regData = NULL;
acc->recnData = NULL;
acc->adjBData = NULL;
acc->qfRoot = mallocQuickFill();
acc->numTrans = 0;
acc->transaction = NULL; /* Initially there are no transactions
* in this account's transaction
* array */
return acc;
}
/********************************************************************\
\********************************************************************/
void
freeAccount( Account *acc )
{
if( acc != NULL )
{
int i;
XtFree(acc->accountName);
XtFree(acc->description);
XtFree(acc->notes);
freeQuickFill(acc->qfRoot);
for( i=0; i<acc->numTrans; i++ )
_free( acc->transaction[i] );
_free( acc->transaction );
_free(acc);
}
}
/********************************************************************\
\********************************************************************/
Transaction *
getTransaction( Account *acc, int num )
{
if( acc != NULL )
{
if( (0 <= num) && (num < acc->numTrans) )
return acc->transaction[num];
else
return NULL;
}
else
return NULL;
}
/********************************************************************\
\********************************************************************/
Transaction *
removeTransaction( Account *acc, int num )
{
Transaction *trans = NULL;
if( acc != NULL )
{
int i,j;
Transaction **oldTrans = acc->transaction;
/* Set this flag, so we know we need to save the data file: */
if( data != NULL )
data->saved = False;
acc->numTrans--;
acc->transaction = (Transaction **)_malloc((acc->numTrans)*
sizeof(Transaction *));
trans = oldTrans[acc->numTrans];/* In case we are deleting last in
* old array */
for( i=0,j=0; i<acc->numTrans; i++,j++ )
{
if( j != num )
acc->transaction[i] = oldTrans[j];
else
{
trans = oldTrans[j];
i--;
}
}
_free(oldTrans);
}
return trans;
}
/********************************************************************\
\********************************************************************/
int
insertTransaction( Account *acc, Transaction *trans )
{
int position=-1;
if( acc != NULL )
{
int i,j;
Date *dj,*dt;
int inserted = False;
Transaction **oldTrans = acc->transaction;
/* mark the data file as needing to be saved: */
if( data != NULL )
data->saved = False;
acc->numTrans++;
acc->transaction = (Transaction **)_malloc((acc->numTrans)*
sizeof(Transaction *));
/* dt is the date of the transaction we are inserting, and dj
* is the date of the "cursor" transaction... we want to insert
* the new transaction before the first transaction of the same
* or later date. The !inserted bit is a bit of a kludge to
* make sure we only insert the new transaction once! */
dt = &(trans->date);
for( i=0,j=0; i<acc->numTrans; i++,j++ )
{
/* if we didn't do this, and we needed to insert into the
* last spot in the array, we would walk off the end of the
* old array, which is no good! */
if( j>=(acc->numTrans-1) )
{
position = i;
acc->transaction[i] = trans;
break;
}
else
{
dj = &(oldTrans[j]->date);
if( (datecmp(dj,dt) > 0) & !inserted )
{
position = i;
acc->transaction[i] = trans;
j--;
inserted = True;
}
else
acc->transaction[i] = oldTrans[j];
}
}
_free(oldTrans);
}
if( position != -1 )
qfInsertTransaction( acc->qfRoot, trans );
return position;
}

315
src/AdjBWindow.c Normal file
View File

@ -0,0 +1,315 @@
/********************************************************************\
* AdjBWindow.c -- the adjust balance window *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <Xm/DialogS.h>
#include <Xm/PanedW.h>
#include <Xm/PushB.h>
#include <Xm/LabelGP.h>
#include "main.h"
#include "util.h"
#include "date.h"
#include "Data.h"
#include "MainWindow.h"
#include "Account.h"
/** GLOBALS *********************************************************/
extern Data *data;
/** STRUCTS *********************************************************/
typedef struct _AdjBWindow
{
Account *acc; /* The account that we are adjusting */
Widget dialog; /* The adjust balance dialog */
Widget balance; /* Text field, the new balance */
Widget date; /* Text field, the date for the balance */
} AdjBWindow;
/** PROTOTYPES ******************************************************/
void adjBOkCB( Widget mw, XtPointer cd, XtPointer cb );
void adjBClose( Widget mw, XtPointer cd, XtPointer cb );
/********************************************************************\
* adjBWindow *
* opens up the window to adjust the balance *
* *
* Args: parent - the parent of this window *
* account - the account to adjust *
* Return: recnData - the instance of this AdjBWindow *
\********************************************************************/
AdjBWindow *
adjBWindow( Widget parent, Account *acc )
{
Widget widget, pane, controlform, actionform;
Date date;
AdjBWindow *adjBData;
char buf[BUFSIZE];
setBusyCursor( parent );
adjBData = (AdjBWindow *)_malloc(sizeof(AdjBWindow));
adjBData->acc = acc;
/* Create the dialog box... */
sprintf( buf, "%s: Adjust Balance", acc->accountName );
adjBData->dialog =
XtVaCreatePopupShell( "dialog",
xmDialogShellWidgetClass, parent,
XmNdialogStyle, XmDIALOG_APPLICATION_MODAL,
XmNtitle, buf,
XmNdeleteResponse, XmDESTROY,
NULL );
/* ... and so memory gets freed: */
XtAddCallback( adjBData->dialog, XmNdestroyCallback,
adjBClose, (XtPointer)adjBData );
/* Create a PanedWindow Manager for the dialog box... the child
* of optiondialog the paned window is the parent of the two
* forms which comprise the two areas of the dialog box...
* The sash is set to minimun size to make it invisible */
pane = XtVaCreateWidget( "pane",
xmPanedWindowWidgetClass, adjBData->dialog,
XmNsashWidth, 1,
XmNsashHeight, 1,
XmNtraversalOn, False,
NULL );
/** CONTROLFORM ****************************************
* Create a controlform for control area of dialog box */
controlform = XtVaCreateWidget( "controlform",
xmFormWidgetClass, pane,
NULL );
widget = XtVaCreateManagedWidget( "Date",
xmLabelGadgetClass, controlform,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 10,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 50,
NULL );
todaysDate(&date);
sprintf(buf,"%2d/%2d/%4d\0", date.month, date.day, date.year);
adjBData->date =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, controlform,
XmNvalue, buf,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 50,
NULL );
/* The dateCB ensures the data entered in the date field is
* in a valid format */
XtAddCallback( adjBData->date, XmNmodifyVerifyCallback,
dateCB, (XtPointer)NULL );
widget = XtVaCreateManagedWidget( "New Balance $",
xmLabelGadgetClass, controlform,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, adjBData->date,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 50,
NULL );
adjBData->balance =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, controlform,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, adjBData->date,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 50,
NULL );
/* The amountCB ensures the data entered in the balance field is
* in a valid format */
XtAddCallback( adjBData->balance, XmNmodifyVerifyCallback,
amountCB, (XtPointer)NULL );
XtManageChild( controlform );
/** ACTIONFORM ********************************************
* Create a Form actionform for action area of dialog box */
actionform = XtVaCreateWidget( "actionform",
xmFormWidgetClass, pane,
XmNfractionBase, 8,
NULL );
/* The OK button is anchored to the form, between divider 1 & 2
* (in the fraction base) */
widget = XtVaCreateManagedWidget( "Ok",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 1,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 3,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
adjBOkCB, (XtPointer)adjBData );
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)(adjBData->dialog) );
/* The cancel button! */
widget = XtVaCreateManagedWidget( "Cancel",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 3,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 5,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)(adjBData->dialog) );
/* A help button will pop-up context sensitive help */
widget = XtVaCreateManagedWidget( "Help",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 5,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 7,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
helpMenubarCB, (XtPointer)HMB_ADJBWIN );
/* Fix action area of the pane to its current size, and not let it
* resize. */
XtManageChild( actionform );
{
Dimension h;
XtVaGetValues( widget, XmNheight, &h, NULL );
XtVaSetValues( actionform, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL );
}
XtManageChild( pane );
XtPopup( adjBData->dialog, XtGrabNone );
unsetBusyCursor( parent );
return adjBData;
}
/********************************************************************\
* adjBClose *
* frees memory allocated for an adjBWindow, and other cleanup *
* stuff *
* *
* Args: mw - the widget that called us *
* cd - adjBData - the data struct for this window *
* cb - *
* Return: none *
\********************************************************************/
void
adjBClose( Widget mw, XtPointer cd, XtPointer cb )
{
AdjBWindow *adjBData = (AdjBWindow *)cd;
Account *acc = adjBData->acc;
_free(adjBData);
acc->adjBData = NULL;
DEBUG("closed AdjBWindow");
}
/********************************************************************\
* adjBOkCB *
* creates the new transaction to adjust the account when the *
* user clicks "Ok" *
* *
* Args: mw - the widget that called us *
* cd - adjBData - the data struct for this window *
* cb - *
* Return: none *
\********************************************************************/
void
adjBOkCB( Widget mw, XtPointer cd, XtPointer cb )
{
AdjBWindow *adjBData = (AdjBWindow *)cd;
Transaction *trans, *tempTrans;
Account *acc;
String str;
int dollar=0,cent=0;
int pos=0;
int amount=0,currAmount=0;
int i;
data->saved = False;
acc = adjBData->acc;
/* allocate mem for the new transaction */
trans = (Transaction *)_malloc(sizeof(Transaction));
/* Create the "trans" transaction */
str = XmTextGetString(adjBData->date);
todaysDate(&(trans->date)); /* In case the date field is empty */
sscanf( str, "%d/%d/%d", &(trans->date.month),
&(trans->date.day), &(trans->date.year) );
str = XmTextGetString(adjBData->balance);
sscanf( str, "%d.%2d", &dollar, &cent );
amount = 100*dollar + cent;
/* fill out the rest of the fields */
trans->num = XtNewString("");
trans->memo = XtNewString("");
trans->description = XtNewString("Adjust Balance");
trans->catagory = 0;
trans->reconciled = NREC;
pos = insertTransaction( acc, trans );
/* figure out what the amount for this transaction... figure out
* the current balance, and take the diff from amount */
for( i=0; i<pos; i++ )
{
tempTrans = getTransaction(acc,i);
currAmount += tempTrans->amount;
}
trans->amount = amount - currAmount;
/* Refresh the account register window */
regRefresh(acc->regData);
/* Refresh the account reconcile window */
recnRefresh(acc->recnData);
refreshMainWindow();
}

218
src/BuildMenu.c Normal file
View File

@ -0,0 +1,218 @@
/* Written by Dan Heller and Paula Ferguson.
* Copyright 1994, O'Reilly & Associates, Inc.
* Permission to use, copy, and modify this program without
* restriction is hereby granted, as long as this copyright
* notice appears in each copy of the program source code.
* This program is freely distributable without licensing fees and
* is provided without guarantee or warrantee expressed or implied.
* This program is -not- in the public domain.
*/
/* Modified by Rob Clark on Nov 26, 1995
* Changes made: reorginization of code, and addition choice of initial
* option menu selection
* - moved the creation of cascade buttion for
* option and pulldown menu till after the
* items in the menu are created... this way
* I can specify a widget (item in menu) to
* be the inital choice for option menues!
* - Added argument (int)initial to
* facilitate choice of initial choice.
* - modified the for loop which adds menu items.
* If the menu item number (0,1,2,..) of the
* menu item being created corresponds to the
* (int)initial specified by the caller of
* the function, then make note of the widget
* id of menu item so we can use it to set
* initial menu choice. If the menu item
* created is the first menu item, make note
* of it's widget id, in case (int)initial
* specified by user is bigger than the number
* of menu items.
* - Added check to see if initial_choice was set
* equal to a widget id. If (int)initial is
* bigger than number of menu items, then set
* initial_choice to = first menu item's widget
* id, to prevent bad things from happening.
*/
#include <Xm/Xm.h>
#include <X11/cursorfont.h>
#include <string.h>
#include <Xm/DrawingA.h>
#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include <Xm/MainW.h>
#include <Xm/FileSB.h>
#include <Xm/MessageB.h>
#include <Xm/DialogS.h>
#include <Xm/PanedW.h>
#include <Xm/ScrolledW.h>
#include <Xm/DrawnB.h>
#include <Xm/ToggleB.h>
#include <Xm/ToggleBG.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/CascadeBG.h>
#include <Xm/Label.h>
#include <Xm/LabelG.h>
#include <Xm/Scale.h>
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/SeparatoG.h>
#include "BuildMenu.h"
/* Build popup, option and pulldown menus, depending on the menu_type.
* It may be XmMENU_PULLDOWN, XmMENU_OPTION or XmMENU_POPUP. Pulldowns
* return the CascadeButton that pops up the menu. Popups return the menu.
* Option menus are created, but the RowColumn that acts as the option
* "area" is returned unmanaged. (The user must manage it.)
* Pulldown menus are built from cascade buttons, so this function
* also builds pullright menus. The function also adds the right
* callback for PushButton or ToggleButton menu items.
*/
Widget BuildMenu( Widget parent, int menu_type, char *menu_title,
char menu_mnemonic, Boolean tear_off, int initial,
MenuItem *items)
{
Widget menu,
cascade,
widget,
first_menuitem,
initial_choice;
int i;
XmString str;
if( menu_type == XmMENU_PULLDOWN || menu_type == XmMENU_OPTION )
menu = XmCreatePulldownMenu( parent, "_pulldown", NULL, 0 );
else if( menu_type == XmMENU_POPUP )
menu = XmCreatePopupMenu( parent, "_popup", NULL, 0 );
else
{
XtWarning ("Invalid menu type passed to BuildMenu()");
return NULL;
}
if(tear_off)
XtVaSetValues( menu, XmNtearOffModel, XmTEAR_OFF_ENABLED, NULL );
/* Now add the menu items */
for( i=0; items[i].label != NULL; i++ )
{
/* If subitems exist, create the pull-right menu by calling this
* function recursively. Since the function returns a cascade
* button, the widget returned is used..
*/
if( items[i].subitems )
{
if( menu_type == XmMENU_OPTION )
{
XtWarning("You can't have submenus from option menu items.");
continue;
}
else
widget = BuildMenu( menu, XmMENU_PULLDOWN, items[i].label,
items[i].mnemonic, tear_off, 0,
items[i].subitems);
}
else
{
widget = XtVaCreateManagedWidget( items[i].label,
*(items[i].wclass), menu,
NULL );
}
/* If the current widget (menu item) being created corresponds to the
* int that the user specified as initial choice, then set initial_choice
* = widget. The (int)initial specified by caller of function is the
* number of the menu item (ie, 0th, 1st, 2nd,...), but when we create
* the cascade button a little later, we need a widget id to specify as
* the inital choice.
*/
if( i == initial )
initial_choice = widget;
/* If this is the first menu item, set first_menuitem = widget
* This is incase (int)initial > (number of menu items), we need to
* set (Widget)initial_choice equal to the first menu item
*/
if( i == 0 )
first_menuitem = widget;
/* Whether the item is a real item or a cascade button with a
* menu, it can still have a mnemonic.
*/
if(items[i].mnemonic)
XtVaSetValues( widget, XmNmnemonic, items[i].mnemonic, NULL );
/* any item can have an accelerator, except cascade menus. But,
* we don't worry about that; we know better in our declarations.
*/
if(items[i].accelerator)
{
str = XmStringCreateLocalized(items[i].accel_text);
XtVaSetValues( widget,
XmNaccelerator, items[i].accelerator,
XmNacceleratorText, str,
NULL );
XmStringFree(str);
}
if( items[i].callback )
{
if( (items[i].wclass == &xmToggleButtonWidgetClass) ||
(items[i].wclass == &xmToggleButtonGadgetClass) )
{
XtAddCallback( widget, XmNvalueChangedCallback,
items[i].callback, items[i].callback_data );
}
else
{
XtAddCallback( widget, XmNactivateCallback,
items[i].callback, items[i].callback_data );
}
}
}
/* If the (int)initial set by user is greater than the number of menu
* items, initial_choice will not have been set in the for loop where
* the menu items are added. If this is the case, we will default to
* the first menu item
*/
if( initial > (i-1) )
initial_choice = first_menuitem;
/* Pulldown menus require a cascade button to be made */
if( menu_type == XmMENU_PULLDOWN )
{
str = XmStringCreateLocalized (menu_title);
cascade = XtVaCreateManagedWidget( menu_title,
xmCascadeButtonGadgetClass, parent,
XmNsubMenuId, menu,
XmNlabelString, str,
XmNmnemonic, menu_mnemonic,
NULL );
XmStringFree (str);
}
else if( menu_type == XmMENU_OPTION )
{
/* Option menus are a special case, but not hard to handle */
Arg args[3];
int n = 0;
str = XmStringCreateLocalized(menu_title);
XtSetArg( args[n], XmNsubMenuId, menu ); n++;
XtSetArg( args[n], XmNlabelString, str ); n++;
XtSetArg( args[n], XmNmenuHistory, initial_choice ); n++;
/* This really isn't a cascade, but this is the widget handle
* we're going to return at the end of the function.
*/
cascade = XmCreateOptionMenu( parent, menu_title, args, n );
XmStringFree(str);
}
/* for popup menus, just return the menu; pulldown menus, return
* the cascade button; option menus, return the thing returned
* from XmCreateOptionMenu(). This isn't a menu, or a cascade button!
*/
return (menu_type == XmMENU_POPUP) ? menu : cascade;
}

149
src/Data.c Normal file
View File

@ -0,0 +1,149 @@
/********************************************************************\
* Data.c -- the main data structure of the program *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include "Data.h"
#include "Account.h"
#include "util.h"
/********************************************************************\
* Because I can't use C++ for this project, doesn't mean that I *
* can't pretend too! These functions perform actions on the *
* Data data structure, in order to encapsulate the knowledge *
* of the internals of the Data in one file. *
\********************************************************************/
/********************************************************************\
\********************************************************************/
Data *
mallocData( void )
{
Data *data = (Data *)_malloc(sizeof(Data));
data->saved = True;
data->new = False;
data->numAcc = 0;
data->account = NULL;
return data;
}
/********************************************************************\
\********************************************************************/
void
freeData( Data *data )
{
if( data != NULL )
{
int i;
for( i=0; i<data->numAcc; i++ )
freeAccount( data->account[i] );
_free( data->account );
_free(data);
}
}
/********************************************************************\
\********************************************************************/
Account *
getAccount( Data *data, int num )
{
if( data != NULL )
{
if( (0 <= num) && (num < data->numAcc) )
return data->account[num];
else
return NULL;
}
else
return NULL;
}
/********************************************************************\
\********************************************************************/
Account *
removeAccount( Data *data, int num )
{
Account *acc = NULL;
if( data != NULL )
{
int i,j;
Account **oldAcc = data->account;
data->saved = False;
data->numAcc--;
data->account = (Account **)_malloc((data->numAcc)*sizeof(Account *));
acc = oldAcc[data->numAcc]; /* In case we are deleting last in
* old array */
for( i=0,j=0; i<data->numAcc; i++,j++ )
{
if( j != num )
data->account[i] = oldAcc[j];
else
{
acc = oldAcc[j];
j--;
}
}
_free(oldAcc);
}
return acc;
}
/********************************************************************\
\********************************************************************/
int
insertAccount( Data *data, Account *acc )
{
int i=-1;
if( data != NULL )
{
Account **oldAcc = data->account;
data->saved = False;
data->numAcc++;
data->account = (Account **)_malloc((data->numAcc)*sizeof(Account *));
for( i=0; i<(data->numAcc-1); i++ )
data->account[i] = oldAcc[i];
data->account[i] = acc;
_free(oldAcc);
}
return i;
}

144
src/FileBox.c Normal file
View File

@ -0,0 +1,144 @@
/********************************************************************\
* FileBox.c -- the file dialog box *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include <Xm/Xm.h>
#include <Xm/FileSB.h>
#include "FileBox.h"
#include "util.h"
/** GLOBALS *********************************************************/
extern XtAppContext app;
Boolean done=True;
/** PROTOTYPES ******************************************************/
void fileBoxCB( Widget mw, XtPointer cd, XtPointer cb );
/********************************************************************\
* fileBox *
* pops up a file selection dialog (either a "Save As" or an *
* "Open"), and returns the name of the file the users selected. *
* (This function does not return until the user selects a file *
* or pressed "Cancel") *
* *
* NOTE: fileBox is not re-entrant... if an instance of fileBox *
* already exists, the latter call will return NULL *
* *
* Args: parent - the parent of this window *
* type - either OPEN or SAVE *
* Return: none *
* Global: app - the XtAppContext *
* done - whether fileBox should return *
\********************************************************************/
char *
fileBox( Widget parent, int type )
{
Widget dialog;
char* fileName = NULL;
XmString filterpattern = XmStringCreateSimple( "*.dat" ),
dialogname;
if( !done )
return NULL; /* Don't open if there already is
* an instance of fileBox */
done = False;
ENTER("fileBox");
// setBusyCursor( parent );
if( type == OPEN )
{
dialogname = XmStringCreateSimple( "Open" );
dialog = XmCreateFileSelectionDialog( parent, "Open", NULL, 0 );
}
else if( type == SAVE )
{
dialogname = XmStringCreateSimple( "Save" );
dialog = XmCreateFileSelectionDialog( parent, "Save", NULL, 0 );
}
XtVaSetValues( dialog,
XmNpattern, filterpattern,
XmNdialogTitle, dialogname,
XmNminWidth, 350,
XmNminHeight, 350,
NULL );
XtUnmanageChild( XmFileSelectionBoxGetChild(dialog,XmDIALOG_HELP_BUTTON) );
/* Add the "ok" button callbacks... first save the name, then
* destroy the dialog */
XtAddCallback( dialog, XmNokCallback,
fileBoxCB, (XtPointer)&fileName );
XtAddCallback( dialog, XmNokCallback,
destroyShellCB, (XtPointer)dialog );
/* Add the cancel button callback */
XtAddCallback( dialog, XmNcancelCallback,
fileBoxCB, (XtPointer)NULL );
XtAddCallback( dialog, XmNcancelCallback,
destroyShellCB, (XtPointer)dialog );
XmStringFree( filterpattern );
XtManageChild( dialog );
// unsetBusyCursor( parent );
/* while the user hasn't pushed "Ok", simulate XtMainLoop.*/
while( !done || XtAppPending(app) )
XtAppProcessEvent( app, XtIMAll );
LEAVE("fileBox");
return fileName;
}
/********************************************************************\
* fileBoxCB *
* callback that saves the name of the file so that fileBox *
* can return *
* *
* Args: mw - the widget that called us *
* cd - fileName *
* cb - *
* Return: none *
* Global: done - whether fileBox should return *
\********************************************************************/
void
fileBoxCB( Widget mw, XtPointer cd, XtPointer cb )
{
char **fileName = (char **)cd;
ENTER("fileBoxCB");
if( cd != NULL )
{
XmFileSelectionBoxCallbackStruct *cbs =
(XmFileSelectionBoxCallbackStruct *)cb;
if( !XmStringGetLtoR(cbs->value,charset,fileName) )
*fileName = NULL;
}
done = True;
LEAVE("fileBoxCB");
}

615
src/FileIO.c Normal file
View File

@ -0,0 +1,615 @@
/********************************************************************\
* FileIO.c -- read from and writing to a datafile for xacc *
* (X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
* *
* *
* NOTE: the readxxxx/writexxxx functions changed the current *
* position in the file, and so the order which these *
* functions are called in important *
* *
* the format of the data in the file: *
* file ::== token numAccounts (Account)^numAccounts *
* Account ::== flags type accountName description notes *
* numTran (Transaction)^numTrans *
* Transaction ::== num date description memo catagory reconciled *
* amount *
* token ::== int [the version of file format == VERSION] *
* numTrans ::== int *
* numAccounts ::== int *
* flags ::== char *
* type ::== char *
* accountName ::== String *
* description ::== String *
* notes ::== String *
* num ::== String *
* date ::== Date *
* description ::== String *
* memo ::== String *
* catagory ::== int *
* reconciled ::== char *
* amount ::== int *
* String ::== size (char)^size *
* size ::== int *
* Date ::== year month day *
* month ::== int *
* day ::== int *
* year ::== int *
\********************************************************************/
#include <Xm/Xm.h>
#include <fcntl.h>
#include "main.h"
#include "util.h"
#include "Account.h"
#include "Data.h"
#define PERMS 0666
#define WFLAGS (O_WRONLY | O_CREAT | O_TRUNC)
#define RFLAGS O_RDONLY
#define VERSION 1
/** GLOBALS *********************************************************/
extern Widget toplevel;
/** PROTOTYPES ******************************************************/
Account *readAccount( int fd, int token );
Transaction *readTransaction( int fd, int token );
char *readString( int fd, int token );
Date *readDate( int fd, int token );
int writeAccount( int fd, Account *account );
int writeTransaction( int fd, Transaction *trans );
int writeString( int fd, char *str );
int writeDate( int fd, Date *date );
/********************************************************************\
********************** LOAD DATA ***********************************
\********************************************************************/
/********************************************************************\
* readData *
* reads in the data from file datafile *
* *
* Args: datafile - the file to load the data from *
* Return: the struct with the program data in it *
\********************************************************************/
Data *
readData( char *datafile )
{
int fd;
int numAcc;
int err=0;
int token=0;
int i;
Data *data = mallocData();
fd = open( datafile, RFLAGS, 0 );
if( fd == -1 )
{
ERROR();
freeData(data);
return NULL;
}
/* Read in the file format token */
err = read( fd, &token, sizeof(int) );
if( err == -1 )
{
ERROR();
close(fd);
freeData(data);
return NULL;
}
/* If this is an old file, ask the user if the file
* should be updated */
if( token < VERSION )
{
char msg[BUFSIZE];
sprintf( (char *)&msg, FILE_TOO_OLD_MSG );
if( !verifyBox( toplevel, msg ) )
return NULL;
}
/* If this is a newer file than we know how to deal
* with, warn the user */
if( token > VERSION )
{
char msg[BUFSIZE];
sprintf( (char *)&msg, FILE_TOO_NEW_MSG );
if( !verifyBox( toplevel, msg ) )
return NULL;
}
/* read numAccs */
err = read( fd, &numAcc, sizeof(int) );
if( err == -1 )
{
close(fd);
freeData(data);
return NULL;
}
/* read in the accounts */
for( i=0; i<numAcc; i++ )
{
Account *acc;
acc = readAccount( fd, token );
if( acc == NULL )
{
close(fd);
printf(" numAcc = %d\n i = %d\n",numAcc,i);
return data;
}
else
insertAccount( data, acc );
}
close(fd);
return data;
}
/********************************************************************\
* readAccount *
* reads in the data for an account from the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* token - the datafile version *
* Return: the account structure *
\********************************************************************/
Account *
readAccount( int fd, int token )
{
int err=0;
int i;
int numTrans;
Account *acc = mallocAccount();
err = read( fd, &(acc->flags), sizeof(char) );
if( err != sizeof(char) )
{
freeAccount(acc);
return NULL;
}
err = read( fd, &(acc->type), sizeof(char) );
if( err != sizeof(char) )
{
freeAccount(acc);
return NULL;
}
acc->accountName = readString( fd, token );
if( acc->accountName == NULL )
{
freeAccount(acc);
return NULL;
}
acc->description = readString( fd, token );
if( acc->accountName == NULL )
{
freeAccount(acc);
return NULL;
}
acc->notes = readString( fd, token );
if( acc->accountName == NULL )
{
freeAccount(acc);
return NULL;
}
err = read( fd, &numTrans, sizeof(int) );
if( err != sizeof(int) )
{
freeAccount(acc);
return NULL;
}
/* read the transactions */
for( i=0; i<numTrans; i++ )
{
Transaction *trans;
trans = readTransaction( fd, token );
if( trans == NULL )
{
printf(" numTrans = %d\n i = %d\n",numTrans,i);
return acc;
}
else
insertTransaction( acc, trans );
}
return acc;
}
/********************************************************************\
* readTransaction *
* reads in the data for a transaction from the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* token - the datafile version *
* Return: the transaction structure *
\********************************************************************/
Transaction *
readTransaction( int fd, int token )
{
int err=0;
Date *date;
Transaction *trans = (Transaction *)_malloc(sizeof(Transaction));
trans->num = readString( fd, token );
if( trans->num == NULL )
{
_free(trans);
return NULL;
}
date = readDate( fd, token );
if( date == NULL )
{
XtFree(trans->num);
_free(trans);
return NULL;
}
trans->date = *date;
_free(date);
trans->description = readString( fd, token );
if( trans->description == NULL )
{
XtFree(trans->num);
_free(trans);
return NULL;
}
trans->memo = readString( fd, token );
if( trans->memo == NULL )
{
XtFree(trans->description);
XtFree(trans->num);
_free(trans);
return NULL;
}
err = read( fd, &(trans->catagory), sizeof(int) );
if( err != sizeof(int) )
{
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
_free(trans);
return NULL;
}
err = read( fd, &(trans->reconciled), sizeof(char) );
if( err != sizeof(char) )
{
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
_free(trans);
return NULL;
}
/* What used to be reconciled, is now cleared... transactions
* aren't reconciled until you get your bank statement, and
* use the reconcile window to mark the transaction reconciled */
if( token == 0 )
if( trans->reconciled == YREC )
trans->reconciled = CREC;
/* make sure the value of trans->reconciled is valid...
* I have to do this mainly for if I change what NREC and
* YREC are defined to be... this way it might loose all
* the reconciled data, but at least the field is valid */
if( (trans->reconciled != YREC) && (trans->reconciled != CREC) )
trans->reconciled = NREC;
err = read( fd, &(trans->amount), sizeof(int) );
if( err != sizeof(int) )
{
XtFree(trans->memo);
XtFree(trans->description);
XtFree(trans->num);
_free(trans);
return NULL;
}
return trans;
}
/********************************************************************\
* readString *
* reads in a string (char *) from the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* token - the datafile version *
* Return: the string *
\********************************************************************/
char *
readString( int fd, int token )
{
int err=0;
int size;
char *str;
err = read( fd, &size, sizeof(int) );
if( err != sizeof(int) )
return NULL;
str = (char *)XtMalloc(size);
err = read( fd, str, size );
if( err != size )
{
printf( " size = %d\n err = %d\n str = %s\n", size, err, str );
_free(str);
return NULL;
}
return str;
}
/********************************************************************\
* readDate *
* reads in a Date struct from the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* token - the datafile version *
* Return: the Date struct *
\********************************************************************/
Date *
readDate( int fd, int token )
{
int err=0;
Date *date = (Date *)_malloc(sizeof(Date));
err = read( fd, &(date->year), sizeof(int) );
if( err != sizeof(int) )
{
_free(date);
return NULL;
}
err = read( fd, &(date->month), sizeof(int) );
if( err != sizeof(int) )
{
_free(date);
return NULL;
}
err = read( fd, &(date->day), sizeof(int) );
if( err != sizeof(int) )
{
_free(date);
return NULL;
}
return date;
}
/********************************************************************\
********************** SAVE DATA ***********************************
\********************************************************************/
/********************************************************************\
* writeData *
* flattens the program data and saves it in a file *
* *
* Args: datafile - the file to store the data in *
* Return: -1 on failure *
\********************************************************************/
int
writeData( char *datafile, Data *data )
{
int i,numAcc;
int err = 0;
int token = VERSION; /* The file format version */
int fd;
fd = open( datafile, WFLAGS, PERMS );
if( fd == -1 )
{
ERROR();
return -1;
}
err = write( fd, &token, sizeof(int) );
if( err != sizeof(int) )
{
ERROR();
close(fd);
return -1;
}
numAcc = data->numAcc;
err = write( fd, &numAcc, sizeof(int) );
if( err != sizeof(int) )
return -1;
for( i=0; i<numAcc; i++ )
{
err = writeAccount( fd, getAccount(data,i) );
if( err == -1 )
return err;
}
close(fd);
return err;
}
/********************************************************************\
* writeAccount *
* saves the data for an account to the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* acc - the account data to save *
* Return: -1 on failure *
\********************************************************************/
int
writeAccount( int fd, Account *acc )
{
Transaction *trans;
int err=0;
int i,numTrans;
err = write( fd, &(acc->flags), sizeof(char) );
if( err != sizeof(char) )
return -1;
err = write( fd, &(acc->type), sizeof(char) );
if( err != sizeof(char) )
return -1;
err = writeString( fd, acc->accountName );
if( err == -1 )
return err;
err = writeString( fd, acc->description );
if( err == -1 )
return err;
err = writeString( fd, acc->notes );
if( err == -1 )
return err;
/* figure out numTrans */
for( numTrans = 0; getTransaction(acc,numTrans) != NULL; numTrans++ )
{}
err = write( fd, &numTrans, sizeof(int) );
if( err != sizeof(int) )
return -1;
for( i=0; i<numTrans; i++ )
{
err = writeTransaction( fd, getTransaction(acc,i) );
if( err == -1 )
return err;
}
return err;
}
/********************************************************************\
* writeTransaction *
* saves the data for a transaction to the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* trans - the transaction data to save *
* Return: -1 on failure *
\********************************************************************/
int
writeTransaction( int fd, Transaction *trans )
{
int err=0;
err = writeString( fd, trans->num );
if( err == -1 )
return err;
err = writeDate( fd, &(trans->date) );
if( err == -1 )
return err;
err = writeString( fd, trans->description );
if( err == -1 )
return err;
err = writeString( fd, trans->memo );
if( err == -1 )
return err;
err = write( fd, &(trans->catagory), sizeof(int) );
if( err != sizeof(int) )
return -1;
err = write( fd, &(trans->reconciled), sizeof(char) );
if( err != sizeof(char) )
return -1;
err = write( fd, &(trans->amount), sizeof(int) );
if( err != sizeof(int) )
return -1;
return err;
}
/********************************************************************\
* writeString *
* saves a string to the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* str - the String to save *
* Return: -1 on failure *
\********************************************************************/
int
writeString( int fd, char *str )
{
int err=0;
int size;
for( size=0; str[size] != '\0'; size++ )
{}
size++; /* we want to make sure we include the '\0'!
* Otherwise, bad things happen */
err = write( fd, &size, sizeof(int) );
if( err != sizeof(int) )
return -1;
err = write( fd, str, size );
if( err != size )
return -1;
return err;
}
/********************************************************************\
* writeDate *
* saves a Date to the datafile *
* *
* Args: fd - the filedescriptor of the data file *
* date - the Date to save *
* Return: -1 on failure *
\********************************************************************/
int
writeDate( int fd, Date *date )
{
int err=0;
err = write( fd, &(date->year), sizeof(int) );
if( err != sizeof(int) )
return -1;
err = write( fd, &(date->month), sizeof(int) );
if( err != sizeof(int) )
return -1;
err = write( fd, &(date->day), sizeof(int) );
if( err != sizeof(int) )
return -1;
return err;
}

487
src/HelpWindow.c Normal file
View File

@ -0,0 +1,487 @@
/********************************************************************\
* HelpWindow.c -- a help window for hypertext help. *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#define USEDEBUG
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <Xm/Xm.h>
#include <Xm/DialogS.h>
#include <Xm/PanedW.h>
#include <Xm/Frame.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <X11/xpm.h>
#include "main.h"
#include "util.h"
#include "HTML.h"
/********************************************************************\
* HTML History functions *
\********************************************************************/
typedef struct _HTMLHistory {
char *htmlfile;
struct _HTMLHistory *last;
struct _HTMLHistory *next;
} HTMLHistory;
/* insert an htmlfile into history. Return TRUE if this
* is the first element in the history. If not last element
* in history, all next pages are deleted */
int
historyInsert( HTMLHistory **history, char *htmlfile )
{
if( (*history) != NULL )
{
HTMLHistory *temp;
/* delete all next pages: */
while( (*history)->next != NULL )
{
temp = (*history)->next;
(*history)->next = temp->next;
_free(temp->htmlfile);
_free(temp);
}
/* Add new node to history: */
temp = (HTMLHistory *)_malloc(sizeof(HTMLHistory));
temp->htmlfile = (char *)_malloc((strlen(htmlfile)+1)*sizeof(char));
sprintf(temp->htmlfile,"%s",htmlfile);
temp->next = NULL;
temp->last = (*history);
(*history) = temp;
return FALSE;
}
else
{
/* This must be the first node in the history... */
(*history) = (HTMLHistory *)_malloc(sizeof(HTMLHistory));
(*history)->htmlfile = (char *)_malloc((strlen(htmlfile)+1)*sizeof(char));
sprintf((*history)->htmlfile,"%s",htmlfile);
(*history)->last = NULL;
(*history)->next = NULL;
/* ...so return TRUE */
return TRUE;
}
}
/* Move forward in history, and return current htmlfile */
char *
historyFwd( HTMLHistory **history )
{
if( (*history) != NULL )
{
if( (*history)->next != NULL )
(*history) = (*history)->next;
return (*history)->htmlfile;
}
else
return NULL;
}
/* Move back in history, and return current htmlfile */
char *
historyBack( HTMLHistory **history )
{
if( (*history) != NULL )
{
if( (*history)->last != NULL )
(*history) = (*history)->last;
return (*history)->htmlfile;
}
else
return NULL;
}
/* Return current htmlfile */
char *
historyCurrent( HTMLHistory **history )
{
if( (*history) != NULL )
return (*history)->htmlfile;
else
return NULL;
}
/* Remove all entries from history: */
void
historyClear( HTMLHistory **history )
{
/* move to beginning of history: */
while( (*history)->last != NULL )
(*history) = (*history)->last;
/* delete all next pages: */
while( (*history)->next != NULL )
{
HTMLHistory *temp = (*history)->next;
(*history)->next = temp->next;
_free(temp->htmlfile);
_free(temp);
}
/* delete current page: */
_free((*history)->htmlfile);
_free(*history);
(*history) = NULL;
}
/********************************************************************\
* Help Window stuff... *
\********************************************************************/
/** GLOBALS *********************************************************/
Widget helpwidget;
HTMLHistory *helpHistory = NULL;
/** PROTOTYPES ******************************************************/
static void closeHelpWin( Widget mw, XtPointer cd, XtPointer cb );
static void helpBackCB( Widget mw, XtPointer cd, XtPointer cb );
static void helpFwdCB( Widget mw, XtPointer cd, XtPointer cb );
static void helpAnchorCB( Widget mw, XtPointer cd, XtPointer cb );
char *htmlRead( char *file );
ImageInfo *htmlResolveImage( Widget wm, char *file, int nl );
/********************************************************************\
* helpWindow *
* opens up a help window, and displays html *
* *
* Args: parent - the parent widget *
* title - the title of the window *
* htmlfile - the file name of the help file to display *
* Return: none *
\********************************************************************/
void
helpWindow( Widget parent, char *title, char *htmlfile )
{
Widget dialog,
pane,
controlform,
actionform,
widget;
int position=0;
setBusyCursor( parent );
/* if the help window isn't open, then open it... otherwise, load
* new help page into current help window */
if( historyInsert(&helpHistory,htmlfile) )
{
/* Create the dialog box... XmNdeleteResponse is set to
* XmDESTROY so the dialog's memory is freed when it is closed */
dialog = XtVaCreatePopupShell( "dialog",
xmDialogShellWidgetClass, parent,
XmNdialogStyle, XmDIALOG_APPLICATION_MODAL,
XmNtitle, title,
XmNdeleteResponse, XmDESTROY,
XmNminWidth, 500,
XmNminHeight, 400,
NULL );
XtAddCallback( dialog, XmNdestroyCallback, closeHelpWin, NULL );
/* Create a PanedWindow Manager for the dialog box... the child
* of optiondialog the paned window is the parent of the two
* forms which comprise the two areas of the dialog box...
* The sash is set to minimun size to make it invisible */
pane = XtVaCreateWidget( "pane",
xmPanedWindowWidgetClass, dialog,
XmNsashWidth, 1,
XmNsashHeight, 1,
XmNtraversalOn, False,
NULL );
/** CONTROLFORM ****************************************
* Create a controlform for control area of dialog box */
controlform = XtVaCreateWidget( "frame",
xmFrameWidgetClass, pane,
NULL );
helpwidget =
XtVaCreateManagedWidget( "help",
htmlWidgetClass, controlform,
WbNresolveImageFunction, htmlResolveImage,
WbNdelayImageLoads, False,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL );
XtAddCallback( helpwidget, WbNanchorCallback, helpAnchorCB, NULL );
XtManageChild( controlform );
/* we have to load the page after the widget is realized, so
* the pictures can be drawn */
XtVaSetValues( helpwidget, WbNtext, htmlRead(htmlfile), NULL );
/** ACTIONFORM ********************************************
* Create a Form actionform for action area of dialog box */
actionform = XtVaCreateWidget( "actionform",
xmFormWidgetClass, pane,
XmNfractionBase, 7,
NULL );
position=0;
/* The "Back" button */
widget = XtVaCreateManagedWidget( "Back",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, ++position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback, helpBackCB, NULL );
/* The "Forward" button */
widget = XtVaCreateManagedWidget( "Forward",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, ++position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback, helpFwdCB, NULL );
/* The "Close" button */
widget = XtVaCreateManagedWidget( "Close",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, ++position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback, destroyShellCB, dialog );
/* Fix action area of the pane to its current size, and not let it
* resize. */
XtManageChild( actionform );
{
Dimension h;
XtVaGetValues( widget, XmNheight, &h, NULL );
XtVaSetValues( actionform, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL );
}
XtManageChild( pane );
XtPopup( dialog, XtGrabNone );
}
/* if help window is already open, just load new page */
else
XtVaSetValues( helpwidget, WbNtext, htmlRead(htmlfile), NULL );
unsetBusyCursor( parent );
}
/********************************************************************\
* callback functions... *
\********************************************************************/
/********************************************************************\
* helpBackCB - called when user clicks "Back" button... shows last *
* help page in history *
* *
* Args: mw - *
* cd - *
* cb - *
* Return: none *
\********************************************************************/
static void
helpBackCB( Widget mw, XtPointer cd, XtPointer cb )
{
char *file = historyBack(&helpHistory);
if( file != NULL )
{
XtVaSetValues( helpwidget,
WbNtext, htmlRead(file),
NULL );
}
}
/********************************************************************\
* helpFwdCB - called when user clicks "Forward" button... shows *
* next help page in the history *
* *
* Args: mw - *
* cd - *
* cb - *
* Return: none *
\********************************************************************/
static void
helpFwdCB( Widget mw, XtPointer cd, XtPointer cb )
{
char *file = historyFwd(&helpHistory);
if( file != NULL )
{
XtVaSetValues( helpwidget,
WbNtext, htmlRead(file),
NULL );
}
}
/********************************************************************\
* closeHelpWin - called when the help window is closed *
* *
* Args: mw - *
* cd - *
* cb - *
* Return: none *
\********************************************************************/
static void
closeHelpWin( Widget mw, XtPointer cd, XtPointer cb )
{
/* Delete the history: */
historyClear(&helpHistory);
}
/********************************************************************\
* helpAnchorCB - called when user clicks on html anchor tag *
* *
* Args: mw - the html widget that called us *
* cd - *
* cb - the anchor call-back struct *
* Return: none *
\********************************************************************/
static void
helpAnchorCB( Widget mw, XtPointer cd, XtPointer cb )
{
WbAnchorCallbackData *acbs = (WbAnchorCallbackData *)cb;
fprintf(stderr,"%d %s\n",acbs->element_id, acbs->text);
if( historyInsert(&helpHistory,acbs->href) )
{ERROR();} /* CB shouldn't be called if there is not history!!! */
else
XtVaSetValues( mw, WbNtext, htmlRead(acbs->href), NULL );
}
/********************************************************************\
* HTML functions... *
\********************************************************************/
/********************************************************************\
* htmlRead *
* *
* Args: file - the name of the html file to read *
* Return: none *
\********************************************************************/
char *
htmlRead( char *file )
{
char *buf=NULL;
char filename[BUFSIZE];
int size=0;
int fd;
sprintf( (char *)&filename, "%s/%s", HELP_ROOT, file );
/* Open file: */
fd = open( filename, O_RDONLY );
if( fd == -1 )
{
ERROR();
return NULL;
}
/* Find size: */
size = lseek( fd, 0, SEEK_END );
lseek( fd, 0, SEEK_SET );
/* Allocate memory... don't use _malloc(), `cause it is
* freed elsewhere */
buf = (char *)malloc(size*sizeof(char));
/* read in file */
if( read(fd,buf,size) == -1 )
{
free(buf);
buf=NULL;
}
close(fd);
return buf;
}
/********************************************************************\
* htmlResolveImage *
* *
* Args: mw - the html widge *
* file - the name of the html file to read *
* nl - ??? *
* Return: none *
\********************************************************************/
extern Widget toplevel;
ImageInfo *
htmlResolveImage( Widget mw, char *file, int nl )
{
ImageInfo *img = (ImageInfo *)malloc(sizeof(ImageInfo));
XpmImage xpm;
XpmAttributes attr;
int err,i;
char filename[BUFSIZE];
sprintf( (char *)&filename, "%s/%s", HELP_ROOT, file );
/* initialize stuff: */
memset( img, 0, sizeof(ImageInfo) );
memset( &attr, 0, sizeof(XpmAttributes) );
memset( &xpm, 0, sizeof(XpmImage) );
err = XpmReadFileToXpmImage( filename, &xpm, NULL );
img->width = xpm.width;
img->height = xpm.height;
img->num_colors = xpm.ncolors;
img->image_data = None;
err = XpmCreatePixmapFromXpmImage( XtDisplay(mw), XtWindow(mw), &xpm,
&(img->image), NULL, NULL );
if( err != 0 )
ERROR();
return img;
}

698
src/MainWindow.c Normal file
View File

@ -0,0 +1,698 @@
/********************************************************************\
* MainWindow.c -- the main window, and associated helper functions *
* and callback functions for xacc (X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include <Xm/Xm.h>
#include <Xm/PanedW.h>
#include <Xm/Form.h>
#include <Xm/MainW.h>
#include <Xm/Label.h>
#include <Xm/LabelGP.h>
#include <Xm/List.h>
#include <Xm/RowColumn.h>
#include <Xbae/Matrix.h>
#include "main.h"
#include "util.h"
#include "Data.h"
#include "Account.h"
#include "FileIO.h"
#include "FileBox.h"
#include "BuildMenu.h"
#include "MainWindow.h"
#include "RegWindow.h"
#include "XferWindow.h"
#include "HelpWindow.h"
/** PROTOTYPES ******************************************************/
void closeMainWindow( Widget mw, XtPointer cd, XtPointer cb );
void listCB( Widget mw, XtPointer cd, XtPointer cb );
void fileMenubarCB( Widget mw, XtPointer cd, XtPointer cb );
void accountMenubarCB( Widget mw, XtPointer cd, XtPointer cb );
void helpMenubarCB( Widget mw, XtPointer cd, XtPointer cb );
/** GLOBALS *********************************************************/
extern Data *data;
extern char *datafile;
extern Widget toplevel;
int row; /* The selected row of accountlist */
Widget accountlist;
char *type[] = { "Bank","Cash","Asset","Credit Card",
"Liability","Portfolio","Mutual Fund" };
/* Pixel values are used to color the balance field text
* when computing the balance */
#ifndef USE_NO_COLOR
# define POSITIVE_BALANCE "black"
# define NEGATIVE_BALANCE "red"
Pixel posPixel, negPixel;
Boolean havePixels = False;
#endif
/********************************************************************\
* refreshMainWindow *
* *
* Args: none *
* Return: none *
* Global: data - the data from the datafile *
* accountlist - the widget that has the list of accounts *
\********************************************************************/
void
refreshMainWindow( void )
{
int i,j,nrows;
char buf[BUFSIZE];
XtVaGetValues( accountlist, XmNrows, &nrows, NULL );
XbaeMatrixDeleteRows( accountlist, 0, nrows );
/* Add all the accounts to the list */
for( i=0; i<data->numAcc; i++ )
{
String rows[3];
Transaction *trans=NULL;
Account *acc = getAccount( data, i );
int balance = 0;
j=0;
while( (trans = getTransaction(acc,j++)) != NULL )
balance += trans->amount;
if( balance < 0 )
sprintf( buf,"-$%d.%02d\0", ABS(balance/100), ABS(balance % 100) );
else
sprintf( buf,"$%d.%02d\0", ABS(balance/100), ABS(balance % 100) );
rows[0] = acc->accountName;
rows[1] = type[acc->type];
rows[2] = XtNewString(buf);
XtVaGetValues( accountlist, XmNrows, &nrows, NULL );
XbaeMatrixAddRows( accountlist, nrows, rows, NULL, NULL, 1 );
#ifndef USE_NO_COLOR
/* Set the color of the text, depending on whether the
* balance is negative or positive */
if( balance < 0 )
XbaeMatrixSetCellColor( accountlist, nrows, 2, negPixel );
else
XbaeMatrixSetCellColor( accountlist, nrows, 2, posPixel );
#endif
}
}
/********************************************************************\
* mainWindow -- the main window... (normally) the first window *
* that pops up. Has list of accounts that the user can open. *
* Opening an account produces a register window. The user *
* can also create new accounts and edit existing accounts. *
* *
* Args: parent - the parent of the window to be created *
* Return: none *
* Global: data - the data from the datafile *
* accountlist - the widget that has the list of accounts *
\********************************************************************/
void
mainWindow( Widget parent )
{
Widget mainwindow,menubar,actionform,controlform,pane,widget;
int position;
/******************************************************************\
* Set up the menubar *
\******************************************************************/
MenuItem fileMenu[] = {
{ "New File...", &xmPushButtonWidgetClass, 'N', NULL, NULL,
fileMenubarCB, (XtPointer)FMB_NEW, (MenuItem *)NULL },
{ "Open File... ",&xmPushButtonWidgetClass, 'O', NULL, NULL,
fileMenubarCB, (XtPointer)FMB_OPEN, (MenuItem *)NULL },
{ "", &xmSeparatorWidgetClass, 0, NULL, NULL,
NULL, NULL, (MenuItem *)NULL },
{ "Save", &xmPushButtonWidgetClass, 'S', NULL, NULL,
fileMenubarCB, (XtPointer)FMB_SAVE, (MenuItem *)NULL },
{ "Save As...", &xmPushButtonWidgetClass, 'A', NULL, NULL,
fileMenubarCB, (XtPointer)FMB_SAVEAS,(MenuItem *)NULL },
{ "", &xmSeparatorWidgetClass, 0, NULL, NULL,
NULL, NULL, (MenuItem *)NULL },
{ "Quit", &xmPushButtonWidgetClass, 'Q', NULL, NULL,
fileMenubarCB, (XtPointer)FMB_QUIT, (MenuItem *)NULL },
NULL,
};
MenuItem accountMenu[] = {
{ "New Account...", &xmPushButtonWidgetClass, 'N', NULL, NULL,
accountMenubarCB, (XtPointer)AMB_NEW, (MenuItem *)NULL },
{ "Open Account", &xmPushButtonWidgetClass, 'O', NULL, NULL,
accountMenubarCB, (XtPointer)AMB_OPEN, (MenuItem *)NULL },
{ "Edit Account...", &xmPushButtonWidgetClass, 'E', NULL, NULL,
accountMenubarCB, (XtPointer)AMB_EDIT, (MenuItem *)NULL },
{ "Delete Account...", &xmPushButtonWidgetClass, 'D', NULL, NULL,
accountMenubarCB, (XtPointer)AMB_DEL, (MenuItem *)NULL },
{ "", &xmSeparatorWidgetClass, 0, NULL, NULL,
NULL, NULL, (MenuItem *)NULL },
{ "Transfer", &xmPushButtonWidgetClass, 'C', NULL, NULL,
accountMenubarCB, (XtPointer)AMB_TRNS, (MenuItem *)NULL },
{ "Report", &xmPushButtonWidgetClass, 'R', NULL, NULL,
accountMenubarCB, (XtPointer)AMB_RPRT, (MenuItem *)NULL },
#if 0
{ "Edit Categories...", &xmPushButtonWidgetClass, 'C', NULL, NULL,
accountMenubarCB, (XtPointer)AMB_CAT, (MenuItem *)NULL },
#endif
NULL,
};
MenuItem helpMenu[] = {
{ "About...", &xmPushButtonWidgetClass, 'A', NULL, NULL,
helpMenubarCB, (XtPointer)HMB_ABOUT, (MenuItem *)NULL },
{ "Help...", &xmPushButtonWidgetClass, 'H', NULL, NULL,
helpMenubarCB, (XtPointer)HMB_MAIN, (MenuItem *)NULL },
{ "", &xmSeparatorWidgetClass, 0, NULL, NULL,
NULL, NULL, (MenuItem *)NULL },
{ "License...", &xmPushButtonWidgetClass, 'L', NULL, NULL,
helpMenubarCB, (XtPointer)HMB_LIC, (MenuItem *)NULL },
NULL,
};
mainwindow = XtVaCreateManagedWidget( "mainwindow",
xmMainWindowWidgetClass, parent,
XmNdeleteResponse, XmDESTROY,
NULL );
/* Umm... this doesn't seem to be getting called */
XtAddCallback( mainwindow, XmNdestroyCallback,
closeMainWindow, (XtPointer)NULL );
menubar = XmCreateMenuBar( mainwindow, "menubar", NULL, 0 );
BuildMenu( menubar, XmMENU_PULLDOWN, "File", 'F', False, 0, fileMenu );
BuildMenu( menubar, XmMENU_PULLDOWN, "Account",'A', False, 0, accountMenu );
BuildMenu( menubar, XmMENU_PULLDOWN, "Help", 'H', False, 0, helpMenu );
XtManageChild( menubar );
/******************************************************************\
* If they haven't already been initialize, initialize the Pixel *
* values that are used for foreground colors for the balance *
\******************************************************************/
#ifndef USE_NO_COLOR
if( !havePixels )
{
XrmValue colorValue, pixelValue;
colorValue.size = strlen(POSITIVE_BALANCE);
colorValue.addr = (XtPointer)POSITIVE_BALANCE;
pixelValue.size = sizeof(Pixel);
pixelValue.addr = (XtPointer)0;
XtConvertAndStore( parent,
XtRString, &colorValue,
XtRPixel, &pixelValue );
posPixel = (*(Pixel *)pixelValue.addr);
colorValue.size = strlen(NEGATIVE_BALANCE);
colorValue.addr = (XtPointer)NEGATIVE_BALANCE;
pixelValue.size = sizeof(Pixel);
pixelValue.addr = (XtPointer)0;
XtConvertAndStore( parent,
XtRString, &colorValue,
XtRPixel, &pixelValue );
negPixel = (*(Pixel *)pixelValue.addr);
havePixels = True;
}
#endif
/* Create a PanedWindow Manager for the dialog box... the paned
* window is the parent of the two forms which comprise the two
* areas of the dialog box */
pane = XtVaCreateWidget( "pane",
xmPanedWindowWidgetClass, mainwindow,
XmNsashWidth, 1,
XmNsashHeight, 1,
XmNtraversalOn, False,
NULL );
/******************************************************************\
* The account list -- the top part of the window *
\******************************************************************/
/* form to help place the accountlist */
actionform = XtVaCreateWidget( "form",
xmFormWidgetClass, pane,
NULL );
/* Create a matrix widget to hold the account list... the
* listCB helps make this matrix think it is a list. We
* use the matrix instead of a list to get the accounts
* up in columns */
{
String labels[3] = {"Account Name","Type","Balance"};
short colWidths[] = {16,10,8};
unsigned char alignments[3] = {XmALIGNMENT_BEGINNING,
XmALIGNMENT_CENTER,
XmALIGNMENT_END};
accountlist
= XtVaCreateWidget( "list",
xbaeMatrixWidgetClass, actionform,
XmNvisibleRows, 7,
XmNcolumns, 3,
XmNcolumnWidths, colWidths,
XmNcolumnAlignments, alignments,
XmNcolumnLabels, labels,
XmNtraversalOn, False,
XmNfill, True,
XmNcellMarginHeight, 0,
XmNcellMarginWidth, 0,
XmNgridType, XmGRID_NONE,
XmNcellShadowThickness, 0,
XmNverticalScrollBarDisplayPolicy,XmDISPLAY_STATIC,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL);
XtAddCallback( accountlist, XmNenterCellCallback,
listCB, (XtPointer)NULL );
/* If the user double-clicks on an account in the list, open
* up the detail view (ie the regWindow, or whatever) for
* that type of account */
XtAddCallback( accountlist, XmNdefaultActionCallback,
accountMenubarCB, (XtPointer)AMB_OPEN );
}
refreshMainWindow();
XtManageChild(accountlist);
/******************************************************************\
* The button area -- has buttons to create a new account, or *
* delete an account, or whatever other button I think up *
* NOTE: the buttons are just shortcuts to the account menubar, *
* and this is why all the callbacks are accountMenubarCB *
\******************************************************************/
/* create form that will contain most everything in this window...
* The fractionbase divides the form into segments, so we have
* better control over where to put the buttons */
controlform = XtVaCreateWidget( "form",
xmFormWidgetClass, pane,
XmNfractionBase, 5,
NULL );
position = 0; /* puts the buttons in the right place */
/* The "Open" button */
widget = XtVaCreateManagedWidget( "Open",
xmPushButtonWidgetClass, controlform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
accountMenubarCB, (XtPointer)AMB_OPEN );
/* The "New" button, to create a new account */
widget = XtVaCreateManagedWidget( "New",
xmPushButtonWidgetClass, controlform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
accountMenubarCB, (XtPointer)AMB_NEW );
/* The "Edit" button */
widget = XtVaCreateManagedWidget( "Edit",
xmPushButtonWidgetClass, controlform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
accountMenubarCB, (XtPointer)AMB_EDIT );
/* The "Delete" button */
widget = XtVaCreateManagedWidget( "Delete",
xmPushButtonWidgetClass, controlform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
accountMenubarCB, (XtPointer)AMB_DEL );
/* Fix button area of the pane to its current size, and not let
* it resize. */
XtManageChild( controlform );
{
Dimension h;
XtVaGetValues( widget, XmNheight, &h, NULL );
XtVaSetValues( controlform, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL );
}
/* Fix action area of the pane to its current size, and not let
* it resize. */
XtManageChild( actionform );
{
Dimension h;
XtVaGetValues( accountlist, XmNheight, &h, NULL );
XtVaSetValues( actionform, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL );
}
/******************************************************************/
XtManageChild(pane);
}
/********************************************************************\
* closeMainWindow *
* frees memory allocated for an regWindow, and other cleanup *
* stuff *
* *
* Args: mw - the widget that called us *
* cd - *
* cb - *
* Return: none *
\********************************************************************/
void
closeMainWindow( Widget mw, XtPointer cd, XtPointer cb )
{
DEBUG("closed MainWindow");
DEBUGCMD(printf(" coresize = %d\n",_coresize()));
exit(0);
}
/********************************************************************\
* listCB -- makes the matrix widget behave like a list widget *
* *
* Args: mw - the widget that called us *
* cd - *
* cb - *
* Return: none *
* Global: accountlist - the widget that has the list of accounts *
\********************************************************************/
void
listCB( Widget mw, XtPointer cd, XtPointer cb )
{
XbaeMatrixEnterCellCallbackStruct *cbs =
(XbaeMatrixEnterCellCallbackStruct *)cb;
int rows = XbaeMatrixNumRows(accountlist);
cbs->doit = False;
cbs->map = False;
row = cbs->row;
XbaeMatrixDeselectAll(accountlist);
XbaeMatrixSelectRow( accountlist, row );
}
/********************************************************************\
* fileMenubarCB -- handles file menubar choices *
* *
* Args: mw - the widget that called us *
* cd - *
* cb - const that lets us know which choice was selected *
* Return: none *
* Global: data - the data from the datafile *
* datafile - the name of the user's datafile *
* toplevel - the toplevel widget *
\********************************************************************/
void
fileMenubarCB( Widget mw, XtPointer cd, XtPointer cb )
{
int button = (int)cd;
/*
* which of the file menubar options was chosen
* FMB_NEW - New datafile
* FMB_OPEN - Open datfile
* FMB_SAVE - Save datafile
* FMB_SAVEAS - Save datafile As
* FMB_QUIT - Quit
*/
switch( button )
{
case FMB_NEW:
DEBUG("FMB_NEW");
if( (!(data->saved)) && (datafile != NULL) )
{
char *msg = SAVE_MSG;
if( verifyBox(toplevel,msg) )
fileMenubarCB( mw, (XtPointer)FMB_SAVE, cb );
}
datafile = NULL;
freeData(data);
data = mallocData();
data->new = True; /* so we have to do a "SaveAs" when
* the file is first saved */
break;
case FMB_OPEN:
DEBUG("FMB_OPEN");
if( (!(data->saved)) && (datafile != NULL) )
{
char *msg = SAVE_MSG;
if( verifyBox(toplevel,msg) )
fileMenubarCB( mw, (XtPointer)FMB_SAVE, cb );
}
freeData(data);
while( (datafile = fileBox(toplevel,OPEN)) == NULL )
printf("Bad File\n");
/* load the accounts from the users datafile */
data = readData(datafile);
if( data == NULL )
{
/* the file could not be found */
data = mallocData();
}
break;
case FMB_SAVE:
DEBUG("FMB_SAVE");
/* ??? Somehow make sure all in-progress edits get committed! */
writeData( datafile, data );
data->saved = True;
break;
case FMB_SAVEAS:
DEBUG("FMB_SAVEAS");
while( (datafile = fileBox(toplevel,OPEN)) == NULL )
printf("Bad File\n");
fileMenubarCB( mw, (XtPointer)FMB_SAVE, cb );
break;
case FMB_QUIT:
DEBUG("FMB_QUIT");
{
Account *acc;
int i=0;
while( (acc=getAccount(data,i++)) != NULL )
{
if( acc->regData != NULL )
{
/* ??? */
acc->regData = NULL;
}
if( acc->recnData != NULL )
{
/* ??? */
acc->recnData = NULL;
}
}
if( (!(data->saved)) && (datafile != NULL) )
{
char *msg = SAVE_MSG;
if( verifyBox(toplevel,msg) )
fileMenubarCB( mw, (XtPointer)FMB_SAVE, cb );
}
freeData(data);
XtUnmapWidget(toplevel); /* make it disappear quickly */
XtDestroyWidget(toplevel);
return; /* to avoid the refreshMainWindow */
}
break;
default:
DEBUG("We shouldn't be here!");
}
refreshMainWindow();
}
/********************************************************************\
* accountMenubarCB -- handles account menubar choices *
* *
* Args: mw - the widget that called us *
* cd - const that lets us know which choice was selected *
* cb - *
* Return: none *
* Global: data - the data from the datafile *
* row - the selected row number *
* toplevel - the toplevel widget *
\********************************************************************/
void
accountMenubarCB( Widget mw, XtPointer cd, XtPointer cb )
{
int button = (int)cd;
int *posList;
int numPos;
/*
* which of the file menubar options was chosen
* AMB_NEW - New account
* AMB_OPEN - Open account
* AMB_EDIT - Edit account
* AMB_DEL - Delete account
* AMB_CAT - Edit catagories
*/
switch( button )
{
case AMB_NEW:
DEBUG("AMB_NEW");
accWindow(toplevel);
break;
case AMB_OPEN:
DEBUG("AMB_OPEN");
{
Account *acc = getAccount(data,row);
if( acc->regData == NULL )
acc->regData = regWindow( toplevel, acc );
}
break;
case AMB_EDIT:
DEBUG("AMB_EDIT");
editAccWindow( toplevel, getAccount(data,row) );
break;
case AMB_DEL:
DEBUG("AMB_DEL");
{
char *msg = "Are you sure you want to delete this account?";
if( verifyBox(toplevel,msg) )
{
freeAccount( removeAccount(data,row) );
refreshMainWindow();
}
}
break;
case AMB_TRNS:
DEBUG("AMB_TRNS");
xferWindow(toplevel);
break;
case AMB_RPRT:
DEBUG("AMB_RPRT");
simpleReportWindow(toplevel);
break;
case AMB_CAT:
DEBUG("AMB_CAT");
break;
default:
DEBUG("We shouldn't be here!");
}
}
/********************************************************************\
* helpMenubarCB -- handles help menubar choices *
* *
* Args: mw - the widget that called us *
* cd - const that lets us know which choice was selected *
* cb - *
* Return: none *
* Global: toplevel - the toplevel widget *
\********************************************************************/
void
helpMenubarCB( Widget mw, XtPointer cd, XtPointer cb )
{
int button = (int)cd;
int *posList;
int numPos;
/*
* which of the file menubar options was chosen
* HMB_ABOUT - About this program
* HMB_MAIN - Display help window for the main window
* HMB_REGWIN - Display help window for the Register Window
* HMB_RECNWIN - Display help window for the Reconcile Window
* HMB_LIC - GPL Licence info
*/
switch( button )
{
case HMB_ABOUT:
DEBUG("HMB_ABOUT");
helpWindow( toplevel, "About", HH_ABOUT );
break;
case HMB_REGWIN:
/* When the user selects "Help" in the RegWindow */
DEBUG("HMB_REGWIN");
helpWindow( toplevel, "Help", HH_REGWIN );
break;
case HMB_RECNWIN:
/* When the user selects "Help" in the RecnWindow */
DEBUG("HMB_RECNWIN");
helpWindow( toplevel, "Help", HH_RECNWIN );
break;
case HMB_ADJBWIN:
/* When the user selects "Help" in the AdjBWindow */
DEBUG("HMB_ADJBWIN");
helpWindow( toplevel, "Help", HH_ADJBWIN );
break;
case HMB_MAIN:
/* When the user selects "Help" in the MainWindow */
DEBUG("HMB_HELP");
helpWindow( toplevel, "Help", HH_MAIN );
break;
case HMB_LIC:
/* The GNU Public License */
DEBUG("HMB_LIC");
helpWindow( toplevel, "License", HH_GPL );
break;
default:
DEBUG("We shouldn't be here!");
}
}

56
src/Makefile Normal file
View File

@ -0,0 +1,56 @@
######################################################################
#********************************************************************
#* Makefile -- makefile for xacc (X-Accountant) *
#* Copyright (C) 1997 Robin D. Clark *
#* *
#* This program is free software; you can redistribute it and/or *
#* modify it under the terms of the GNU General Public License as *
#* published by the Free Software Foundation; either version 2 of *
#* the License, or (at your option) any later version. *
#* *
#* This program is distributed in the hope that it will be useful, *
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
#* GNU General Public License for more details. *
#* *
#* You should have received a copy of the GNU General Public License*
#* along with this program; if not, write to the Free Software *
#* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
#* *
#* Author: Rob Clark *
#* Internet: rclark@cs.hmc.edu *
#* Address: 609 8th Street *
#* Huntington Beach, CA 92648-4632 *
#********************************************************************
######################################################################
# DO NOT EDIT THE STUFF BELOW THIS LINE! #
OBJS = main.o util.o date.o MainWindow.o RegWindow.o BuildMenu.o \
AccWindow.o FileIO.o Account.o Data.o XferWindow.o FileBox.o \
QuickFill.o Reports.o RecnWindow.o HelpWindow.o AdjBWindow.o
SRCS = ${OBJS:.o=.c}
TARGET = ../xacc
default: $(TARGET)
$(TARGET): $(OBJS) ../libhtmlw/libhtmlw.a
@echo "++++++"
$(CC) $(OBJS) $(LFLAGS) $(LIBS) ../libhtmlw/libhtmlw.a -o $@
.c.o: Makefile
@echo "+++"
$(CC) $(CFLAGS) -c $<
depend:
makedepend -- $(CFLAGS) -- $(SRCS)
clean:
rm -f *.o *~ *.bak
really_clean:
makedepend -- --
# DO NOT DELETE THIS LINE -- make depend depends on it.

129
src/QuickFill.c Normal file
View File

@ -0,0 +1,129 @@
/********************************************************************\
* QuickFill.h -- the quickfill tree data structure *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include <string.h>
#include "util.h"
#include "main.h"
#include "Account.h"
#include "date.h"
#include "QuickFill.h"
/** PROTOTYPES ******************************************************/
void qfInsertTransactionRec( QuickFill *qf, Transaction *trans, int depth );
/** GLOBALS *********************************************************/
/********************************************************************\
* Because I can't use C++ for this project, doesn't mean that I *
* can't pretend too! These functions perform actions on the *
* QuickFill tree structure, in order to encapsulate the knowledge *
* of the internals of QuickFill into one file. *
\********************************************************************/
inline int
CHAR_TO_INDEX( char c )
{
c = toupper(c)-0x40;
if( (c < 0) || (c >= QFNUM) )
return 0;
else
return c;
}
/********************************************************************\
\********************************************************************/
QuickFill *
mallocQuickFill( void )
{
int i;
QuickFill *qf = (QuickFill *)_malloc(sizeof(QuickFill));
for( i=0; i<QFNUM; i++ )
qf->qf[i] = NULL;
qf->trans = NULL;
return qf;
}
/********************************************************************\
\********************************************************************/
void
freeQuickFill( QuickFill *qf )
{
if( qf != NULL )
{
int i;
for( i=0; i<QFNUM; i++ )
freeQuickFill( qf->qf[i] );
_free(qf);
}
}
/********************************************************************\
\********************************************************************/
QuickFill *
getQuickFill( QuickFill *qf, char c )
{
if( qf != NULL )
{
DEBUGCMD(printf(" index = %d\n",CHAR_TO_INDEX(c)));
return qf->qf[CHAR_TO_INDEX(c)];
}
else
return NULL;
}
/********************************************************************\
\********************************************************************/
void
qfInsertTransaction( QuickFill *qf, Transaction *trans )
{
qfInsertTransactionRec( qf, trans, 0 );
}
/********************************************************************\
\********************************************************************/
void
qfInsertTransactionRec( QuickFill *qf, Transaction *trans, int depth )
{
if( qf != NULL )
{
if( trans->description[depth] != '\0' )
{
int index = CHAR_TO_INDEX( trans->description[depth] );
if( qf->qf[index] == NULL )
qf->qf[index] = mallocQuickFill();
qf->qf[index]->trans = trans;
qfInsertTransactionRec( qf->qf[index], trans, ++depth );
}
}
}

841
src/RecnWindow.c Normal file
View File

@ -0,0 +1,841 @@
/********************************************************************\
* RecnWindow.c -- the reconcile window *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <Xm/DialogS.h>
#include <Xm/PanedW.h>
#include <Xm/Frame.h>
#include <Xm/PushB.h>
#include <Xm/LabelGP.h>
#include <Xbae/Matrix.h>
#include "Data.h"
#include "Account.h"
#include "RegWindow.h"
#include "MainWindow.h"
#include "main.h"
#include "util.h"
/** STRUCTS *********************************************************/
typedef struct _RecnWindow
{
Account *acc; /* The account that we are reconciling */
int diff; /* The amount ($$$) to reconcile */
Widget dialog; /* The reconcile window dialog */
Widget difference; /* Text field, amount left to reconcile */
Widget totDebit; /* Text field, total debit reconciled */
Widget totCredit; /* Text field, total credit reconciled */
Widget debit; /* Debit matrix show unreconciled debit */
Widget credit; /* Credit matrix, shows credits... */
} RecnWindow;
/** PROTOTYPES ******************************************************/
void recnRecalculateBalance( RecnWindow *recnData );
void recnClose( Widget mw, XtPointer cd, XtPointer cb );
void recnOkCB( Widget mw, XtPointer cd, XtPointer cb );
void recnCB( Widget mw, XtPointer cd, XtPointer cb );
/** GLOBALS *********************************************************/
extern Data *data;
extern XtAppContext app;
/********************************************************************/
/********************************************************************\
* recnRefresh *
* refreshes the transactions in the reconcile window *
* *
* Args: recnData -- the reconcile window to refresh *
* Return: none *
\********************************************************************/
void
recnRefresh( RecnWindow *recnData )
{
if( recnData != NULL )
{
int i,nrows;
char buf[BUFSIZE];
Transaction *trans;
/* NOTE: an improvement of the current design would be to use the
* user-data in the rows to detect where transactions need
* to be inserted/delete, instead of deleting and re-inserting
* all the transactions! */
/* Delete all the entries in the debit matrix */
XtVaGetValues( recnData->debit, XmNrows, &nrows, NULL );
XbaeMatrixDeleteRows( recnData->debit, 0, nrows );
/* Delete all the entries in the credit matrix */
XtVaGetValues( recnData->credit, XmNrows, &nrows, NULL );
XbaeMatrixDeleteRows( recnData->credit, 0, nrows );
/* Add the non-reconciled transactions */
i=0;
while( (trans=getTransaction(recnData->acc,i++)) != NULL )
{
String rows[5];
if( trans->reconciled != YREC )
{
sprintf( buf, "%c", trans->reconciled );
rows[0] = XtNewString(buf);
rows[1] = trans->num;
sprintf( buf, "%2d/%2d/%02d\0",
trans->date.month,
trans->date.day,
(trans->date.year%100) );
rows[2] = XtNewString(buf);
rows[3] = trans->description;
sprintf( buf, "%d.%02d\0",
ABS(trans->amount/100),
ABS(trans->amount % 100) );
rows[4] = XtNewString(buf);
if( trans->amount < 0 )
{
XtVaGetValues( recnData->debit, XmNrows, &nrows, NULL );
XbaeMatrixAddRows( recnData->debit, nrows, rows, NULL, NULL, 1 );
XbaeMatrixSetRowUserData( recnData->debit, nrows, (XtPointer)trans );
}
else
{
XtVaGetValues( recnData->credit, XmNrows, &nrows, NULL );
XbaeMatrixAddRows( recnData->credit, nrows, rows, NULL, NULL, 1 );
XbaeMatrixSetRowUserData( recnData->credit,nrows, (XtPointer)trans );
}
}
}
recnRecalculateBalance(recnData);
}
}
/********************************************************************\
* recnRecalculateBalance *
* refreshes the balances in the reconcile window *
* *
* Args: recnData -- the reconcile window to refresh *
* Return: none *
\********************************************************************/
void
recnRecalculateBalance( RecnWindow *recnData )
{
Transaction *trans;
char buf[BUFSIZE];
int i,nrows;
int debit = 0;
int credit = 0;
int diff = 0;
/* Calculate the total debit: */
XtVaGetValues( recnData->debit, XmNrows, &nrows, NULL );
for( i=0; i<nrows; i++ )
{
String recn = XbaeMatrixGetCell( recnData->debit, i, 0 );
if( recn[0] == YREC )
{
trans = (Transaction *)XbaeMatrixGetRowUserData( recnData->debit, i );
debit += trans->amount;
}
}
/* Calculate the total credit: */
XtVaGetValues( recnData->credit, XmNrows, &nrows, NULL );
for( i=0; i<nrows; i++ )
{
String recn = XbaeMatrixGetCell( recnData->credit, i, 0 );
if( recn[0] == YREC )
{
trans = (Transaction *)XbaeMatrixGetRowUserData( recnData->credit, i );
credit += trans->amount;
}
}
/* Update the difference field, and the total fields */
sprintf( buf, " $ %d.%02d\0",
ABS(debit/100), ABS(debit%100) );
XmTextSetString( recnData->totDebit, buf );
sprintf( buf, " $ %d.%02d\0",
(credit/100), ABS(credit%100) );
XmTextSetString( recnData->totCredit, buf );
diff = recnData->diff + credit + debit;
if( diff < 0 )
sprintf( buf, "-$ %d.%02d\0",
ABS(diff/100), ABS(diff%100) );
else
sprintf( buf, " $ %d.%02d\0",
(diff/100), ABS(diff%100) );
XmTextSetString( recnData->difference, buf );
}
/********************************************************************\
* startRecnWindow: gets the ending balance for reconcile window *
\********************************************************************/
void
startRecnOkCB( Widget wm, XtPointer cd, XtPointer cb )
{ *(int *)cd = 1; }
void
startRecnCancelCB( Widget wm, XtPointer cd, XtPointer cb )
{ *(int *)cd = 0; }
/********************************************************************\
* startRecnWindow *
* opens up the window to prompt the user to enter the ending *
* balance from bank statement *
* *
* NOTE: This dialog does not return until the user presses "Ok" *
* or "Cancel" *
* *
* Args: parent - the parent of this window *
* acc - the account to reconcile *
* diff - returns the amount from ending balance field *
* Return: True, if the user presses "Ok", else False *
* Global: app - the app context *
\********************************************************************/
Boolean
startRecnWindow( Widget parent, Account *acc, int *diff )
{
Widget dialog,
pane,
controlform,
actionform,
widget, endB, newB;
Transaction *trans;
char buf[BUFSIZE];
int j, endBalance;
int done=-1;
setBusyCursor( parent );
/* Figure out previous ending balance: */
endBalance=0;
j=0;
while( (trans = getTransaction(acc,j++)) != NULL )
if( trans->reconciled == YREC )
endBalance += trans->amount;
/* Create the dialog box... XmNdeleteResponse is set to
* XmDESTROY so the dialog's memory is freed when it is closed */
sprintf( buf, "%s: Reconcile", acc->accountName );
dialog = XtVaCreatePopupShell( "dialog",
xmDialogShellWidgetClass, parent,
XmNdialogStyle, XmDIALOG_APPLICATION_MODAL,
XmNtitle, buf,
XmNdeleteResponse, XmDESTROY,
XmNminWidth, 250,
XmNminHeight, 150,
NULL );
/* Create a PanedWindow Manager for the dialog box... the child
* of optiondialog the paned window is the parent of the two
* forms which comprise the two areas of the dialog box...
* The sash is set to minimun size to make it invisible */
pane = XtVaCreateWidget( "pane",
xmPanedWindowWidgetClass, dialog,
XmNsashWidth, 1,
XmNsashHeight, 1,
XmNtraversalOn, False,
NULL );
/** CONTROLFORM ****************************************
* Create a controlform for control area of dialog box */
controlform = XtVaCreateWidget( "controlform",
xmFormWidgetClass, pane,
NULL );
widget = XtVaCreateManagedWidget( "Previous Balance: $",
xmLabelGadgetClass, controlform,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 10,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 50,
NULL );
sprintf( buf, "%d.%02d", (endBalance/100), ABS(endBalance%100) );
endB = XtVaCreateManagedWidget( "text",
xmTextWidgetClass, controlform,
XmNvalue, buf,
XmNeditable, False,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 50,
NULL );
widget = XtVaCreateManagedWidget( "Ending Balance: $",
xmLabelGadgetClass, controlform,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, endB,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 50,
NULL );
newB = XtVaCreateManagedWidget( "text",
xmTextWidgetClass, controlform,
XmNeditable, True,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, endB,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 50,
NULL );
/* The amountCB ensures the data entered in the amount field is
* in a valid format */
XtAddCallback( newB, XmNmodifyVerifyCallback,
amountCB, (XtPointer)NULL );
XtManageChild( controlform );
/** ACTIONFORM ********************************************
* Create a Form actionform for action area of dialog box */
actionform = XtVaCreateWidget( "actionform",
xmFormWidgetClass, pane,
XmNfractionBase, 8,
NULL );
/* The OK button is anchored to the form, between divider 1 & 2
* (in the fraction base) */
widget = XtVaCreateManagedWidget( "Ok",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 1,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 3,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
startRecnOkCB, (XtPointer)&done );
/* The cancel button! */
widget = XtVaCreateManagedWidget( "Cancel",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 3,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 5,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
startRecnCancelCB, (XtPointer)&done );
/* A help button will pop-up context sensitive help */
widget = XtVaCreateManagedWidget( "Help",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 5,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 7,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
helpMenubarCB, (XtPointer)HMB_RECNWIN );
/* Fix action area of the pane to its current size, and not let it
* resize. */
XtManageChild( actionform );
{
Dimension h;
XtVaGetValues( widget, XmNheight, &h, NULL );
XtVaSetValues( actionform, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL );
}
XtManageChild( pane );
XtPopup( dialog, XtGrabNone );
unsetBusyCursor( parent );
/* while the user hasn't pushed "Ok", simulate XtMainLoop. */
while( (done == -1) || XtAppPending(app) )
XtAppProcessEvent( app, XtIMAll );
/* Get the amount from the "end-balance" field */
{
String str;
int dollar=0,cent=0;
str = XmTextGetString(newB);
sscanf( str, "%d.%2d", &dollar, &cent );
*diff = endBalance - (100*dollar + cent);
}
XtDestroyWidget(dialog);
return done;
}
/********************************************************************\
* recnWindow *
* opens up the window to reconcile an account *
* *
* Args: parent - the parent of this window *
* account - the account to reconcile *
* Return: recnData - the instance of this RecnWindow *
\********************************************************************/
RecnWindow *
recnWindow( Widget parent, Account *acc )
{
Widget pane, form, widget;
int position;
char title[BUFSIZE];
RecnWindow *recnData;
int diff;
/* Popup a little window to prompt the user to enter the
* ending balance for his/her bank statement */
if( !startRecnWindow(parent,acc,&diff) )
return NULL;
setBusyCursor(parent);
recnData = (RecnWindow *)_malloc(sizeof(RecnWindow));
recnData->acc = acc;
recnData->diff = diff;
sprintf( title, "%s: Reconcile", acc->accountName );
/* force the size of the dialog so it is not resizable */
recnData->dialog =
XtVaCreatePopupShell( "dialog",
xmDialogShellWidgetClass, parent,
XmNtitle, title,
XmNdeleteResponse, XmDESTROY,
NULL );
XtAddCallback( recnData->dialog, XmNdestroyCallback,
recnClose, (XtPointer)recnData );
/* The reconcile window is a paned window, with the top pane
* used for the Debits, and Credits matrices, and the bottom pane
* has the misc stuff, like "New Balance" field, "Difference" field,
* and the buttons. The Debit/Credit pane have a matrix, and a
* "total" field */
pane = XtVaCreateWidget( "pane",
xmPanedWindowWidgetClass, recnData->dialog,
XmNsashWidth, 1,
XmNsashHeight, 1,
XmNtraversalOn, False,
NULL );
/******************************************************************\
* The top pane has the debit and credit matrices *
\******************************************************************/
{
Widget frame, rowcol;
short colWidths[] = {1,5,8,20,8}; /* the widths of columns */
String labels[] = {"","Num","Date","Description","Amount"};
unsigned char alignments[] = {XmALIGNMENT_CENTER,
XmALIGNMENT_END,
XmALIGNMENT_CENTER,
XmALIGNMENT_BEGINNING,
XmALIGNMENT_END};
rowcol = XtVaCreateWidget( "rowcol",
xmRowColumnWidgetClass, pane,
XmNnumColumns, 2,
XmNorientation, XmHORIZONTAL,
NULL );
/******************************************************************\
* The "Debits" area *
\******************************************************************/
form = XtVaCreateWidget( "form",
xmFormWidgetClass, rowcol,
NULL );
widget = XtVaCreateManagedWidget( "Debits:",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 20,
NULL );
frame = XtVaCreateWidget( "frame",
xmFrameWidgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, widget,
XmNleftAttachment, XmATTACH_FORM,
NULL );
recnData->debit =
XtVaCreateWidget( "recn",
xbaeMatrixWidgetClass, frame,
XmNfixedRows, 0,
XmNfixedColumns, 0,
XmNrows, 1,
XmNvisibleRows, 10,
XmNfill, True,
XmNcolumns, 5,
XmNcolumnLabels, labels,
XmNcolumnWidths, colWidths,
XmNcolumnAlignments, alignments,
XmNtraverseFixedCells, False,
XmNgridType, XmGRID_SHADOW_IN,
XmNshadowType, XmSHADOW_ETCHED_IN,
XmNverticalScrollBarDisplayPolicy,XmDISPLAY_STATIC,
XmNselectScrollVisible, True,
NULL );
XtAddCallback( recnData->debit, XmNenterCellCallback,
recnCB, (XtPointer)recnData );
XtManageChild(recnData->debit);
widget = XtVaCreateManagedWidget( "Total:",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, frame,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 20,
NULL );
recnData->totDebit =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNeditable, False,
XmNmarginHeight, 1,
XmNmarginWidth, 1,
XmNmaxLength, 10,
XmNcolumns, 10,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, frame,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 20,
NULL );
XtManageChild(frame);
XtManageChild(form);
/******************************************************************\
* The "Credits" area *
\******************************************************************/
form = XtVaCreateWidget( "form",
xmFormWidgetClass, rowcol,
NULL );
widget = XtVaCreateManagedWidget( "Credits:",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 20,
NULL );
frame = XtVaCreateWidget( "frame",
xmFrameWidgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, widget,
XmNleftAttachment, XmATTACH_FORM,
NULL );
recnData->credit =
XtVaCreateWidget( "recn",
xbaeMatrixWidgetClass, frame,
XmNfixedRows, 0,
XmNfixedColumns, 0,
XmNrows, 1,
XmNvisibleRows, 10,
XmNfill, True,
XmNcolumns, 5,
XmNcolumnLabels, labels,
XmNcolumnWidths, colWidths,
XmNcolumnAlignments, alignments,
XmNtraverseFixedCells, False,
XmNgridType, XmGRID_SHADOW_IN,
XmNshadowType, XmSHADOW_ETCHED_IN,
XmNverticalScrollBarDisplayPolicy,XmDISPLAY_STATIC,
XmNselectScrollVisible, True,
NULL );
XtAddCallback( recnData->credit, XmNenterCellCallback,
recnCB, (XtPointer)recnData );
XtManageChild(recnData->credit);
widget = XtVaCreateManagedWidget( "Total:",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, frame,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 20,
NULL );
recnData->totCredit =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNeditable, False,
XmNmarginHeight, 1,
XmNmarginWidth, 1,
XmNmaxLength, 10,
XmNcolumns, 10,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, frame,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 20,
NULL );
XtManageChild(frame);
XtManageChild(form);
XtManageChild(rowcol);
}
/******************************************************************\
* The buttons at the bottom... *
\******************************************************************/
form = XtVaCreateWidget( "form",
xmFormWidgetClass, pane,
XmNfractionBase, 6,
NULL );
position=0;
widget = XtVaCreateManagedWidget( "Difference:",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment,XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
NULL );
recnData->difference =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNeditable, False,
XmNmarginHeight, 1,
XmNmarginWidth, 1,
XmNmaxLength, 10,
XmNcolumns, 10,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 6,
XmNbottomAttachment,XmATTACH_FORM,
XmNbottomOffset, 6,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position++,
NULL );
position++;
/* The "Ok" button: */
widget = XtVaCreateManagedWidget( "Ok",
xmPushButtonWidgetClass, form,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
recnOkCB, (XtPointer)recnData );
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)(recnData->dialog) );
/* The "Cancel" button: */
widget = XtVaCreateManagedWidget( "Cancel",
xmPushButtonWidgetClass, form,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)(recnData->dialog) );
/* The "Help" button pops up the reconcile window help page: */
widget = XtVaCreateManagedWidget( "Help",
xmPushButtonWidgetClass, form,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
helpMenubarCB, (XtPointer)HMB_RECNWIN );
/* Fix button area of the pane to its current size, and not let
* it resize. */
{
Dimension h;
XtVaGetValues( widget, XmNheight, &h, NULL );
XtVaSetValues( form, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL );
}
XtManageChild(form);
XtManageChild(pane);
XtManageChild(recnData->dialog);
/* now that the matices are set up, fill 'em in with transactions: */
recnRefresh(recnData);
/* and then refresh the total/difference balance fields: */
recnRecalculateBalance(recnData);
unsetBusyCursor(parent);
return recnData;
}
/********************************************************************\
* recnClose *
* frees memory allocated for an recnWindow, and other cleanup *
* stuff *
* *
* Args: mw - the widget that called us *
* cd - recnData - the data struct for this window *
* cb - *
* Return: none *
\********************************************************************/
void
recnClose( Widget mw, XtPointer cd, XtPointer cb )
{
RecnWindow *recnData = (RecnWindow *)cd;
Account *acc = recnData->acc;
_free(recnData);
acc->recnData = NULL;
DEBUG("closed RecnWindow");
}
/********************************************************************\
* recnOkCB *
* saves account stuff, when the user clicks "Ok" *
* *
* Args: mw - the widget that called us *
* cd - recnData - the data struct for this window *
* cb - *
* Return: none *
* Global: data *
\********************************************************************/
void
recnOkCB( Widget mw, XtPointer cd, XtPointer cb )
{
int nrows,i;
Transaction *trans;
RecnWindow *recnData = (RecnWindow *)cd;
/* Update the debit transactions: */
XtVaGetValues( recnData->debit, XmNrows, &nrows, NULL );
for( i=0; i<nrows; i++ )
{
String recn = XbaeMatrixGetCell( recnData->debit, i, 0 );
if( recn[0] == YREC )
{
trans = (Transaction *)XbaeMatrixGetRowUserData( recnData->debit, i );
trans->reconciled = YREC;
/* mark the datafile as needing to be saved: */
data->saved = False;
}
}
/* Update the credit transactions: */
XtVaGetValues( recnData->credit, XmNrows, &nrows, NULL );
for( i=0; i<nrows; i++ )
{
String recn = XbaeMatrixGetCell( recnData->credit, i, 0 );
if( recn[0] == YREC )
{
trans = (Transaction *)XbaeMatrixGetRowUserData( recnData->credit, i );
trans->reconciled = YREC;
/* mark the datafile as needing to be saved: */
data->saved = False;
}
}
/* refresh the register window */
regRefresh(recnData->acc->regData);
}
/********************************************************************\
* recnCB *
* called whenever the users does anything in the debit/credit *
* matrices *
* *
* Args: mw - the matrix widget that called us *
* cd - recnData - the data struct for this window *
* cb - *
* Return: none *
\********************************************************************/
void
recnCB( Widget mw, XtPointer cd, XtPointer cb )
{
RecnWindow *recnData = (RecnWindow *)cd;
XbaeMatrixEnterCellCallbackStruct *cbs =
(XbaeMatrixEnterCellCallbackStruct *)cb;
int rows = XbaeMatrixNumRows(mw);
cbs->doit = False;
cbs->map = False;
XbaeMatrixDeselectAll(mw);
XbaeMatrixSelectRow( mw, cbs->row );
/* If we are in the "reconciled" cell, toggle value */
if( cbs->column == 0 )
{
char buf[BUFSIZE];
String val = XbaeMatrixGetCell( mw, cbs->row, cbs->column );
if( val[0] == YREC )
{
Transaction *trans =
(Transaction *)XbaeMatrixGetRowUserData( mw, cbs->row );
sprintf( buf, "%c", trans->reconciled );
XbaeMatrixSetCell( mw, cbs->row, cbs->column, buf );
}
else
{
sprintf( buf, "%c", YREC );
XbaeMatrixSetCell( mw, cbs->row, cbs->column, buf );
}
/* recalculate the total/difference balance fields: */
recnRecalculateBalance(recnData);
}
}

1440
src/RegWindow.c Normal file

File diff suppressed because it is too large Load Diff

125
src/Reports.c Normal file
View File

@ -0,0 +1,125 @@
/********************************************************************\
* Reports.c -- generate an account report window *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <Xm/DialogS.h>
#include <Xm/PanedW.h>
#include <Xm/Frame.h>
#include <Xm/PushB.h>
#include <Xm/LabelGP.h>
#include "Reports.h"
#include "util.h"
/********************************************************************\
* simpleReportWindow *
* *
* Args: parent - the parent of this window *
* Return: none *
\********************************************************************/
void
simpleReportWindow( Widget parent )
{
Widget dialog, form, frame, rc, widget,
label, buttonform;
int position; /* ???? */
setBusyCursor( parent );
/* force the size of the dialog so it is not resizable */
dialog = XtVaCreatePopupShell( "dialog",
xmDialogShellWidgetClass, parent,
XmNtitle, "Report",
XmNdeleteResponse, XmDESTROY,
XmNwidth, 350,
XmNminWidth, 350,
XmNmaxWidth, 350,
XmNheight, 300,
XmNminHeight, 300,
XmNmaxHeight, 300,
NULL );
/* The form to put everything in the dialog in */
form = XtVaCreateWidget( "form", xmFormWidgetClass, dialog, NULL );
/******************************************************************\
* The report type area *
\******************************************************************/
/* Makes a nice looking frame */
frame = XtVaCreateManagedWidget( "frame",
xmFrameWidgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, widget,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 20,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 20,
NULL);
/******************************************************************\
* The buttons at the bottom... *
\******************************************************************/
buttonform = XtVaCreateWidget( "form",
xmFormWidgetClass, form,
XmNfractionBase, 5,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, frame,
XmNtopOffset, 10,
XmNbottomAttachment, XmATTACH_FORM,
XmNbottomOffset, 10,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL );
position = 1; /* puts the buttons in the right place */
/* The "Ok" button */
widget = XtVaCreateManagedWidget( "Ok",
xmPushButtonWidgetClass, buttonform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)dialog );
XtManageChild(buttonform);
/******************************************************************/
XtManageChild(form);
XtPopup( dialog, XtGrabNone );
unsetBusyCursor( parent );
}

505
src/XferWindow.c Normal file
View File

@ -0,0 +1,505 @@
/********************************************************************\
* XferWindow.c -- the transfer window for xacc (X-Accountant) *
* (for transferring between accounts) *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include <Xm/Xm.h>
#include <Xm/DialogS.h>
#include <Xm/Form.h>
#include <Xm/LabelGP.h>
#include <Xm/PushB.h>
#include <Xm/Text.h>
#include <string.h>
#include "BuildMenu.h"
#include "Account.h"
#include "Data.h"
#include "main.h"
#include "util.h"
typedef struct _menuData
{
int choice;
int *accNum;
} MenuData;
typedef struct _xferwindow
{
Widget date;
Widget desc;
Widget amount;
Widget memo;
int to; /* to and from hold the index of */
int from; /* the chosen to/from accounts */
int numMenuData;
MenuData **menuData;
} XferWindow;
/** GLOBALS *********************************************************/
extern Data *data;
/** PROTOTYPES ******************************************************/
void closeXferWindow( Widget mw, XtPointer cd, XtPointer cb );
void menuCB( Widget mw, XtPointer cd, XtPointer cb );
void xferCB( Widget mw, XtPointer cd, XtPointer cb );
/********************************************************************\
* xfewWindow *
* opens up a window to do an automatic transfer between accounts *
* *
* Args: parent - the parent of the window to be created *
* Return: none *
* Global: data - the accounts, and stuff... *
\********************************************************************/
void
xferWindow( Widget parent )
{
Date date;
char buf[BUFSIZE];
Widget dialog, form, widget, label, buttonform, menu;
MenuItem *accountMenu;
XferWindow *xferData;
int position,i;
int initial = 0;
setBusyCursor( parent );
xferData = (XferWindow *)_malloc(sizeof(XferWindow));
xferData->to = initial;
xferData->from = initial;
xferData->menuData = NULL;
xferData->numMenuData = 0;
/* force the size of the dialog so it is not resizable */
dialog = XtVaCreatePopupShell( "dialog",
xmDialogShellWidgetClass, parent,
XmNtitle, "Transfer Money",
XmNdeleteResponse, XmDESTROY,
XmNwidth, 450,
XmNminWidth, 450,
XmNmaxWidth, 450,
XmNheight, 230,
XmNminHeight, 230,
XmNmaxHeight, 230,
NULL );
XtAddCallback( dialog, XmNdestroyCallback,
closeXferWindow, (XtPointer)xferData );
/* The form to put everything in the dialog in */
form = XtVaCreateWidget( "form", xmFormWidgetClass, dialog, NULL );
/******************************************************************\
* Text fields.... *
\******************************************************************/
label =
XtVaCreateManagedWidget( "Date",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 65,
NULL );
todaysDate(&date);
sprintf(buf,"%2d/%2d/%4d\0", date.month, date.day, date.year);
xferData->date =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNvalue, buf,
XmNtopAttachment, XmATTACH_FORM,
XmNtopOffset, 10,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 10,
XmNleftAttachment, XmATTACH_WIDGET,
XmNleftWidget, label,
NULL );
/* The dateCB ensures that the data that the user enters in
* in a valid date format. */
XtAddCallback( xferData->date, XmNmodifyVerifyCallback,
dateCB, (XtPointer)NULL );
label =
XtVaCreateManagedWidget( "Description",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, xferData->date,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 10,
NULL );
xferData->desc =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNvalue, "Transfer",
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, xferData->date,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_WIDGET,
XmNleftWidget, label,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 65,
NULL );
label =
XtVaCreateManagedWidget( "$",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, xferData->date,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 65,
NULL );
xferData->amount =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, xferData->date,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_WIDGET,
XmNleftWidget, label,
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 10,
NULL );
/* The amountCB ensures the data entered in the amount field is
* in a valid format */
XtAddCallback( xferData->amount, XmNmodifyVerifyCallback,
amountCB, (XtPointer)NULL );
label =
XtVaCreateManagedWidget( "Memo",
xmLabelGadgetClass, form,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, xferData->desc,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 10,
NULL );
xferData->memo =
XtVaCreateManagedWidget( "text",
xmTextWidgetClass, form,
XmNmaxLength, 40,
XmNcolumns, 40,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, xferData->desc,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_WIDGET,
XmNleftWidget, label,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 65,
NULL );
/******************************************************************\
* The popup menus that let the user choose the account to *
* transfer to and the account to transfer from *
\******************************************************************/
accountMenu = (MenuItem *)_malloc((data->numAcc+1)*sizeof(MenuItem));
/* We have to keep track of the menuData stuff so we can free this
* memory when the transfer window is closed... the even slots in
* this array are used by the "Frow" menu, and the odd slots are
* used by the "To" menu. (The even/odd way was a simple way to
* still use i as a index to the array... it makes sense to me,
* at least) */
xferData->menuData = (MenuData **)_malloc(2*data->numAcc*sizeof(MenuData *));
xferData->numMenuData = 2 * data->numAcc;
for( i=0; i<xferData->numMenuData; i++ )
xferData->menuData[i] = NULL;
for( i=0; i<data->numAcc; i++ )
{
Account *acc = getAccount( data, i );
/* This account menu uses the even menuData slots (ie (2*i) ) */
xferData->menuData[2*i] = (MenuData *)_malloc(sizeof(MenuData));
xferData->menuData[2*i]->choice = i;
xferData->menuData[2*i]->accNum = &(xferData->from);
accountMenu[i].label = acc->accountName;
accountMenu[i].wclass = &xmPushButtonWidgetClass;
accountMenu[i].mnemonic = 0;
accountMenu[i].accelerator = NULL;
accountMenu[i].accel_text = NULL;
accountMenu[i].callback = menuCB;
accountMenu[i].callback_data = xferData->menuData[2*i];
accountMenu[i].subitems = (MenuItem *)NULL;
}
accountMenu[i] .label= NULL;
widget = BuildMenu( form, XmMENU_OPTION, "From:", 'F',
False, initial, accountMenu );
XtVaSetValues( widget,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, xferData->memo,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 10,
NULL );
XtManageChild(widget);
for( i=0; i<data->numAcc; i++ )
{
Account *acc = getAccount( data, i );
/* This account menu uses the odd menuData slots (ie (2*i)+1 ) */
xferData->menuData[2*i+1] = (MenuData *)_malloc(sizeof(MenuData));
xferData->menuData[2*i+1]->choice = i;
xferData->menuData[2*i+1]->accNum = &(xferData->to);
accountMenu[i].label = acc->accountName;
accountMenu[i].wclass = &xmPushButtonWidgetClass;
accountMenu[i].mnemonic = 0;
accountMenu[i].accelerator = NULL;
accountMenu[i].accel_text = NULL;
accountMenu[i].callback = menuCB;
accountMenu[i].callback_data = xferData->menuData[2*i+1];
accountMenu[i].subitems = (MenuItem *)NULL;
}
accountMenu[i] .label= NULL;
widget = BuildMenu( form, XmMENU_OPTION, "To:", 'T',
False, initial, accountMenu );
XtVaSetValues( widget,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, xferData->memo,
XmNtopOffset, 10,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 50,
NULL );
XtManageChild(widget);
_free(accountMenu);
/******************************************************************\
* The buttons at the bottom... *
\******************************************************************/
buttonform = XtVaCreateWidget( "form",
xmFormWidgetClass, form,
XmNfractionBase, 5,
XmNtopAttachment, XmATTACH_WIDGET,
XmNtopWidget, widget,
XmNtopOffset, 10,
XmNbottomAttachment, XmATTACH_FORM,
XmNbottomOffset, 10,
XmNleftAttachment, XmATTACH_FORM,
XmNrightAttachment, XmATTACH_FORM,
NULL );
position = 1; /* puts the buttons in the right place */
/* The "Cancel" button */
widget = XtVaCreateManagedWidget( "Cancel",
xmPushButtonWidgetClass, buttonform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)dialog );
/* The "Transfer" button creates the transfer */
widget = XtVaCreateManagedWidget( "Transfer",
xmPushButtonWidgetClass, buttonform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, position,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, ++position,
XmNshowAsDefault, True,
NULL );
XtAddCallback( widget, XmNactivateCallback,
xferCB, (XtPointer)xferData );
XtAddCallback( widget, XmNactivateCallback,
destroyShellCB, (XtPointer)dialog );
XtManageChild(buttonform);
/******************************************************************/
XtManageChild(form);
XtPopup( dialog, XtGrabNone );
unsetBusyCursor( parent );
}
/********************************************************************\
* closeXferWindow *
* frees memory allocated for an XferWindow, and other cleanup *
* stuff *
* *
* Args: mw - *
* cd - xferData - the struct for the XferWindow that is *
* being closed *
* cb - *
* Return: none *
\********************************************************************/
void
closeXferWindow( Widget mw, XtPointer cd, XtPointer cb )
{
int i;
XferWindow *xferData = (XferWindow *)cd;
for( i=0; i<xferData->numMenuData; i++ )
_free(xferData->menuData[i]);
_free(xferData->menuData);
_free(xferData);
DEBUG("close XferWindow");
}
/********************************************************************\
* menuCB -- keeps track of the to and from menues *
* *
* Args: mw - the widget that called us *
* cd - menuData - has the menu choice and a pointer to *
* either the to of from fields in XferWindow *
* cb - *
* Return: none *
\********************************************************************/
void
menuCB( Widget mw, XtPointer cd, XtPointer cb )
{
MenuData *menuData = (MenuData *)cd;
*(menuData->accNum) = menuData->choice;
}
/********************************************************************\
* xferCB -- creates the transfer between accounts *
* *
* Args: mw - the widget that called us *
* cd - xferData - the struct of data associated with *
* the XfewWindow *
* cb - *
* Return: none *
* Global: data - the data from the datafile *
\********************************************************************/
void
xferCB( Widget mw, XtPointer cd, XtPointer cb )
{
XferWindow *xferData = (XferWindow *)cd;
Transaction *toTrans, *fromTrans;
Account *acc;
String str;
int dollar=0,cent=0,pos=0;
data->saved = False;
/* "toTrans" is the transfer transaction that goes into the to account,
* and "fromTrans" goes into the from account */
toTrans = (Transaction *)_malloc(sizeof(Transaction));
fromTrans = (Transaction *)_malloc(sizeof(Transaction));
/* Create the "toTrans" transaction */
str = XmTextGetString(xferData->date);
todaysDate(&(toTrans->date));
sscanf( str, "%d/%d/%d", &(toTrans->date.month),
&(toTrans->date.day), &(toTrans->date.year) );
str = XmTextGetString(xferData->amount);
sscanf( str, "%d.%2d", &dollar, &cent );
toTrans->amount = 100*dollar + cent;
toTrans->num = XtNewString("");
/* Get the memo, and add the "from" account name to it */
{
String memo = NULL;
/* Note, don't use _malloc/_free here, because otherwise it
* would mess up the memory accounting if memory debugging
* is turned on */
acc = getAccount(data,xferData->from);
str = XmTextGetString(xferData->memo);
memo = (String)malloc(strlen(str)+
strlen(acc->accountName)+
strlen("[From: ] ") );
sprintf( memo, "[From: %s] %s\0", acc->accountName, str );
toTrans->memo = memo;
free(str);
}
toTrans->description = XmTextGetString(xferData->desc);
toTrans->catagory = 0;
toTrans->reconciled = NREC;
acc = getAccount(data,xferData->to);
pos = insertTransaction( acc, toTrans );
/* Refresh the "to" account register window */
regRefresh(acc->regData);
/* Refresh the "to" account reconcile window */
recnRefresh(acc->recnData);
/* Create the "fromTrans" transaction */
str = XmTextGetString(xferData->date);
todaysDate(&(fromTrans->date));
sscanf( str, "%d/%d/%d", &(fromTrans->date.month),
&(fromTrans->date.day), &(fromTrans->date.year) );
fromTrans->amount = -1*toTrans->amount;
fromTrans->num = XtNewString("");
/* Get the memo, and add the "to" account name to it */
{
String memo = NULL;
/* Note, don't use _malloc/_free here, because otherwise it
* would mess up the memory accounting if memory debugging
* is turned on */
acc = getAccount(data,xferData->to);
str = XmTextGetString(xferData->memo);
memo = (String)malloc(strlen(str)+
strlen(acc->accountName)+
strlen("[To: ] ") );
sprintf( memo, "[To: %s] %s\0", acc->accountName, str );
fromTrans->memo = memo;
free(str);
}
fromTrans->description = XmTextGetString(xferData->desc);
fromTrans->catagory = 0;
fromTrans->reconciled = NREC;
acc = getAccount(data,xferData->from);
pos = insertTransaction( acc, fromTrans );
/* Refresh the "from" account register window */
regRefresh(acc->regData);
/* Refresh the "from" account reconcile window */
recnRefresh(acc->recnData);
refreshMainWindow();
}

185
src/date.c Normal file
View File

@ -0,0 +1,185 @@
/********************************************************************\
* date.c -- utility functions to handle the date (adjusting, get *
* current date, etc.) for xacc (X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
* *
* *
* TODO: - for now, every year is leap year *
* *
\********************************************************************/
#include <time.h>
#include "date.h"
#include "util.h"
#define False 0
#define True 1
/** PROTOTYPES ******************************************************/
int validateDate( Date *date );
/** GLOBALS *********************************************************/
char days[12] = { 31,29,31,30,31,30,31,31,30,31,30,31 };
/********************************************************************\
* adjustDay *
* adds adj to the current day of the month... the resulting day *
* of the month is a valid day of the month *
* *
* Args: date - the date structure to edit *
* adj - the amount to adjust the day of the month by *
* Return: none *
\********************************************************************/
void
adjustDay( Date *date, int adj )
{
date->day += adj;
validateDate(date);
}
/********************************************************************\
* adjustMonth *
* adds adj to the current month of the year.. the resulting *
* month of the year is corrected to be in the range [1..12], *
* incrementing/decrementing the year if necessary. *
* *
* Args: date - the date structure to edit *
* adj - the amount to adjust the day of the month by *
* Return: none *
\********************************************************************/
void
adjustMonth( Date *date, int adj )
{
date->month += adj;
validateDate(date);
}
/********************************************************************\
* validateDate *
* ensures that all the fields in date are in the valid range *
* (ie month = [1..12], day is not less than 1, and not greater *
* than last day of the month.). If fields are not in the valid *
* range, they are adjusted. *
* *
* Args: date - the date structure to edit *
* Return: True if date was changed, otherwise False *
\********************************************************************/
int
validateDate( Date *date )
{
int valid = True;
/* the "% 12" business is because month might not be valid!*/
while( date->day > days[(date->month+11) % 12] )
{
valid = False;
date->day -= days[(date->month+11) % 12];
date->month++;
}
while( date->day < 1 )
{
valid = False;
date->month--;
date->day += days[(date->month+11) % 12];
}
while( date->month > 12 )
{
valid = False;
date->month -= 12;
date->year++;
}
while( date->month < 1 )
{
valid = False;
date->month += 12;
date->year--;
}
return valid;
}
/********************************************************************\
* todaysDate *
* takes a (Date *) and fills it in with today's date *
* *
* Args: date - the struct to be filled in *
* Return: today's date *
\********************************************************************/
Date*
todaysDate( Date *date )
{
time_t t;
struct tm *theTime;
time(&t);
theTime = localtime(&t);
date->day = theTime->tm_mday;
date->month = theTime->tm_mon + 1;
date->year = theTime->tm_year + 1900;
// _free(theTime);
return date;
}
/********************************************************************\
* daysInMonth *
* returns the number of days in month *
* *
* Args: month - the current month *
* Return: the number of days in month *
\********************************************************************/
int
daysInMonth( int month )
{
return days[month-1];
}
/********************************************************************\
* datecmp *
* compares date1 and date2 *
* *
* Args: date1 - the first date to look at *
* date2 - the second date in the comparison *
* Return: < 0 if date1<date2, == 0 if date1==date2, > 0 otherwise *
\********************************************************************/
int
datecmp( Date *date1, Date *date2 )
{
if( date1 == NULL )
return 0;
else if( date2 == NULL )
return 0;
else
{
unsigned int d1 = date1->day + (31 * date1->month) + (365 * date1->year);
unsigned int d2 = date2->day + (31 * date2->month) + (365 * date2->year);
if( d1 < d2 )
return -1;
if( d1 == d2 )
return 0;
else
return 1;
}
}

156
src/main.c Normal file
View File

@ -0,0 +1,156 @@
/********************************************************************\
* main.c -- main for xacc (X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include <Xm/Xm.h>
#include "BuildMenu.h"
#include "RegWindow.h"
#include "FileIO.h"
#include "FileBox.h"
#include "util.h"
#include "main.h"
/** PROTOTYPES ******************************************************/
/** GLOBALS *********************************************************/
Data *data = NULL;
char *datafile;
Widget toplevel;
Boolean realized=False; /* Has the toplevel been realized? */
XtAppContext app;
/* The names of the different types of accounts. For resource
* specification */
String accRes[] ={
"bank",
"cash",
"asset",
"credit",
"liability",
"portfolio",
"mutual"
};
/** FALLBACK RESOURCES **********************************************/
/* NOTE: These will eventually be moved out into a site-default file,
* but default-resources are here for now, for convenience */
String fbRes[] = {
"*fontList: -*-helvetica-bold-r-normal--*-120-*-*-*-*-*-*",
"*Background: grey",
"*text.fontList: -*-helvetica-medium-r-normal--*-100-*-*-*-*-*-*",
/* Help stuff" */
"*help*geometry: 530x480-0-0",
/* "*help*View*Background: #ffffff", */
/* MenuBar stuff: */
"*menubar*marginHeight: 1",
"*menubar*marginWidth: 1",
/* Register window account type specific stuff: */
"*regbank.oddRowBackground: #ffffaa",
"*regcash.oddRowBackground: #ccffcc",
"*regasset.oddRowBackground: #ccffcc",
"*regcredit.oddRowBackground: #ccccff",
"*regliability.oddRowBackground: #ffcccc",
"*regportfolio.oddRowBackground: grey",
"*regmutual.oddRowBackground: grey",
"*regportfolio.evenRowBackground:grey",
"*regmutual.evenRowBackground: grey",
/* Other register window account stuff: */
"*reg*fontList: -*-helvetica-medium-r-normal--*-100-*-*-*-*-*-*",
"*reg*evenRowBackground: white",
"*reg*shadowType: SHADOW_IN",
"*reg*shadowThickness: 1",
"*reg*cellShadowThickness: 1",
"*reg*cellShadowType: SHADOW_IN",
"*reg*cellMarginWidth: 1",
"*reg*cellMarginHeight: 0",
/* Reconcile window matrices stuff: */
"*recn*fontList: -*-helvetica-medium-r-normal--*-100-*-*-*-*-*-*",
"*recn*.oddRowBackground: white",
"*recn*.evenRowBackground: white",
"*recn*shadowType: SHADOW_ETCHED_IN",
"*recn*shadowThickness: 1",
"*recn*cellShadowThickness: 1",
"*recn*cellShadowType: SHADOW_ETCHED_IN",
"*recn*cellMarginWidth: 0",
"*recn*cellMarginHeight: 0",
NULL,
};
/********************************************************************\
* main *
* the entry point for the program... sets up the top level widget *
* and calls the mainWindow() function which creates the main *
* window. *
* *
* Args: argc, the number of command line arguments, and argv, *
* the array of command line args *
* Return: *
* Global: data - the data from the datafile *
* datafile - the name of the user's datafile *
* toplevel - the toplevel widget, for creating new windows *
* app - the XtAppContext *
\********************************************************************/
int
main( int argc, char *argv[] )
{
#ifdef DEBUGMEMORY
char *blk;
DEBUG("Initializing memory");
blk = (char *)_malloc(8192);
_free(blk);
printf(" coresize = %d\n",_coresize());
DEBUG("Done initializing memory");
#endif
data = NULL;
toplevel = XtVaAppInitialize( &app, "Xacc", NULL, 0,
&argc, argv, fbRes,
NULL );
/* read in the filename (should be the first arg after all
* the X11 stuff */
if( argc > 1 )
datafile = argv[1];
else
datafile = fileBox( toplevel, OPEN );
if( datafile != NULL )
data = readData(datafile); /* load the accounts data from datafile*/
if( data == NULL )
{
data = mallocData(); /* the file could not be found */
data->new = True;
}
/* Make main window */
mainWindow(toplevel);
/* Draw toplevel */
XtRealizeWidget(toplevel);
realized = TRUE;
/* Enter event loop */
XtAppMainLoop(app);
}

580
src/util.c Normal file
View File

@ -0,0 +1,580 @@
/********************************************************************\
* util.c -- utility functions that are used everywhere else for *
* xacc (X-Accountant) *
* Copyright (C) 1997 Robin D. Clark *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* Author: Rob Clark *
* Internet: rclark@cs.hmc.edu *
* Address: 609 8th Street *
* Huntington Beach, CA 92648-4632 *
\********************************************************************/
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/cursorfont.h>
#include <Xm/Xm.h>
#include <Xm/Text.h>
#include <Xm/PanedW.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Xm/DialogS.h>
#include <Xm/RowColumn.h>
#include <Xm/MessageB.h>
#include <Xbae/Matrix.h>
#include "util.h"
/** GLOBALS *********************************************************/
extern XtAppContext app;
extern int realized;
/********************************************************************\
* DEBUGGING MEMORY ALLOCATION STUFF *
\********************************************************************/
#ifdef DEBUGMEMORY
size_t core=0;
void
dfree( void *ptr )
{
core -= malloc_usable_size(ptr);
free(ptr);
}
void*
dmalloc( size_t size )
{
char *ptr = (char *)malloc(size);
int i;
for( i=0; i<size; i++ )
ptr[i] = '.';
core += malloc_usable_size(ptr);
return (void *)ptr;
}
size_t
dcoresize(void)
{
return core;
}
#endif
/********************************************************************\
* dateCB -- ensures the data the user enters in the date field *
* is in a valid format. *
* *
* Args: mw - the widget that called us *
* cd - *
* cb - the callback struct *
* Return: none *
\********************************************************************/
void
dateCB( Widget mw, XtPointer cd, XtPointer cb )
{
XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)cb;
char input;
/* TODO: ??? add support for date field accelerator keys!! */
if( cbs->text->ptr != NULL )
{
input = (cbs->text->ptr)[0];
switch( input )
{
case '/':
/* Make sure that there is at most two '/' */
{
String str = XmTextGetString(mw);
int i,count=0;
for( i=0; str[i] != '\0'; i++ )
if( str[i] == '/' )
count++;
if( count >= 2 )
cbs->doit = False;
}
break;
default:
/* only accept the input if it is a number */
cbs->doit = isNum(input);
}
}
}
/********************************************************************\
* amountCB -- ensures the data entered in the amount field is in *
* a valid format. *
* *
* Args: mw - the widget that called us *
* cd - *
* cb - the callback struct *
* Return: none *
\********************************************************************/
void
amountCB( Widget mw, XtPointer cd, XtPointer cb )
{
XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)cb;
char input;
if( cbs->text->ptr != NULL )
{
input = (cbs->text->ptr)[0];
switch( input )
{
case '.':
/* Make sure that there is only one '.' */
{
String str = XmTextGetString(mw);
int i,count=0;
for( i=0; str[i] != '\0'; i++ )
if( str[i] == '.' )
count++;
if( count >= 1 )
cbs->doit = False;
}
break;
default:
/* only accept the input if it is a number */
cbs->doit = isNum(input);
}
}
}
/********************************************************************\
* noeditCB *
* makes an Xbae matrix non-editable *
* *
* Args: mw - the widget that called us *
* cd - *
* cb - *
* Return: none *
\********************************************************************/
void
noeditCB( Widget mw, XtPointer cd, XtPointer cb )
{
XbaeMatrixEnterCellCallbackStruct *cbs =
(XbaeMatrixEnterCellCallbackStruct * )cb;
cbs->doit = False;
}
/********************************************************************\
* destroyShellCB *
* a callback to destroy a widget (cd, not w, because we want to *
* destroy a window, not a button!) *
* *
* Args: mw - the widget that called us *
* cd - the widget to destroy *
* cb - *
* Return: none *
\********************************************************************/
void
destroyShellCB( Widget w, XtPointer cd, XtPointer cb )
{
Widget window = (Widget)cd;
XtDestroyWidget(window);
}
/********************************************************************\
* setBusyCursor *
* sets the cursor to the busy watch *
* *
* Args: w - the widget over which to make cursor busy *
* Return: none *
\********************************************************************/
void
setBusyCursor( Widget w )
{
if( realized )
{
static Cursor watch = 0;
if( watch == 0 )
watch = XCreateFontCursor(XtDisplay(w),XC_watch);
XDefineCursor(XtDisplay(w),XtWindow(w),watch);
XmUpdateDisplay(w);
}
}
/********************************************************************\
* unsetBusyCursor *
* sets the cursor to the default cursor *
* *
* Args: w - the widget over which to make cursor normal *
* Return: none *
\********************************************************************/
void
unsetBusyCursor( Widget w )
{
if( realized )
{
XUndefineCursor(XtDisplay(w),XtWindow(w));
XmUpdateDisplay(w);
}
}
/********************************************************************\
**************** TEXTBOX STUFF *************************************
\********************************************************************/
typedef struct _textbox {
Widget textfield;
char *text;
} TextBox;
void textBoxCB( Widget mw, XtPointer cd, XtPointer cb );
/********************************************************************\
* textBox *
* opens up a text box, and displays text *
* *
* NOTE: This function does not return until the textBox is closed *
* *
* Args: parent - the parent widget *
* title - the title of the window *
* text - the initial text to display *
* editable - can this text be edited by the user? *
* Return: none *
\********************************************************************/
char *
textBox( Widget parent, char *title, char *text, Boolean editable )
{
Widget dialog,
pane,
controlform,
actionform,
widget;
Arg args[10];
TextBox *textData = (TextBox *)_malloc(sizeof(TextBox));
textData->text = NULL;
setBusyCursor( parent );
/* Create the dialog box... XmNdeleteResponse is set to
* XmDESTROY so the dialog's memory is freed when it is closed */
dialog = XtVaCreatePopupShell( "dialog",
xmDialogShellWidgetClass, parent,
XmNdialogStyle, XmDIALOG_APPLICATION_MODAL,
XmNtitle, title,
XmNdeleteResponse, XmDESTROY,
XmNminWidth, 150,
XmNminHeight, 200,
NULL );
/* Create a PanedWindow Manager for the dialog box... the child
* of optiondialog the paned window is the parent of the two
* forms which comprise the two areas of the dialog box...
* The sash is set to minimun size to make it invisible */
pane = XtVaCreateWidget( "pane",
xmPanedWindowWidgetClass, dialog,
XmNsashWidth, 1,
XmNsashHeight, 1,
XmNtraversalOn, False,
NULL );
/** CONTROLFORM ****************************************
* Create a controlform for control area of dialog box */
controlform = XtVaCreateWidget( "controlform",
xmFormWidgetClass, pane,
NULL );
/* Create a text widget as child of controlform */
XtSetArg( args[0], XmNeditMode, XmMULTI_LINE_EDIT );
XtSetArg( args[1], XmNwordWrap, True );
XtSetArg( args[2], XmNrows, 12 );
XtSetArg( args[3], XmNcolumns, 70 );
XtSetArg( args[4], XmNeditable, editable );
XtSetArg( args[5], XmNscrollHorizontal, False );
XtSetArg( args[6], XmNtopAttachment, XmATTACH_FORM );
XtSetArg( args[7], XmNbottomAttachment, XmATTACH_FORM );
XtSetArg( args[8], XmNleftAttachment, XmATTACH_FORM );
XtSetArg( args[9], XmNrightAttachment, XmATTACH_FORM );
textData->textfield =
XmCreateScrolledText( controlform, "text", args, 10 );
XtManageChild( textData->textfield );
XmTextSetString( textData->textfield, text );
XtManageChild( controlform );
/** ACTIONFORM ********************************************
* Create a Form actionform for action area of dialog box */
{
int fb = editable ? 5 : 3;
actionform = XtVaCreateWidget( "actionform",
xmFormWidgetClass, pane,
XmNfractionBase, fb,
NULL );
}
/* The OK button is anchored to the form, between divider 1 & 2
* (in the fraction base) */
widget = XtVaCreateManagedWidget( "Ok",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 1,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 2,
XmNshowAsDefault, True,
NULL );
/* Add callback function to Ok.. calls textBoxCB to save the text,
* and destroyOptionDialog to kill option dialog box */
XtAddCallback( widget, XmNactivateCallback, textBoxCB, textData );
XtAddCallback( widget, XmNactivateCallback, destroyShellCB, dialog );
if( editable )
{
/* If it is editable, provide a cancel button too! */
widget = XtVaCreateManagedWidget( "Cancel",
xmPushButtonWidgetClass, actionform,
XmNtopAttachment, XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_POSITION,
XmNleftPosition, 3,
XmNrightAttachment, XmATTACH_POSITION,
XmNrightPosition, 4,
XmNshowAsDefault, True,
NULL );
/* Add callback function to Cancel.. calls destroyOptionDialog to
* kill option dialog box */
XtAddCallback( widget, XmNactivateCallback, destroyShellCB, dialog );
}
/* Fix action area of the pane to its current size, and not let it
* resize. */
XtManageChild( actionform );
{
Dimension h;
XtVaGetValues( widget, XmNheight, &h, NULL );
XtVaSetValues( actionform, XmNpaneMaximum, h, XmNpaneMinimum, h, NULL );
}
XtManageChild( pane );
XtPopup( dialog, XtGrabNone );
unsetBusyCursor( parent );
/* while the user hasn't pushed "Ok", simulate XtMainLoop.
* When textData->text changes from NULL, it means the user
* has pressed "Ok". Don't break loop until XtAppPending()
* also returns False to assure widget destruction. */
while( textData->text == NULL || XtAppPending(app) )
XtAppProcessEvent( app, XtIMAll );
return textData->text;
}
/********************************************************************\
* textBoxCB *
* callback that saves the data in the the buffer before textBox *
* can return *
* *
* Args: mw - the widget that called us *
* cd - textData *
* cb - *
* Return: none *
\********************************************************************/
void
textBoxCB( Widget mw, XtPointer cd, XtPointer cb )
{
TextBox *textData = (TextBox *)cd;
textData->text = XmTextGetString( textData->textfield );
}
/********************************************************************\
*********************************************************************
\********************************************************************/
/********************************************************************\
**************** VERIFYBOX STUFF ***********************************
\********************************************************************/
typedef struct _verifybox {
Boolean done;
Boolean answer;
} VerifyBox;
void verifyBoxCB( Widget mw, XtPointer cd, XtPointer cb );
/********************************************************************\
* verifyBox *
* display a message, and asks the user to press "Ok" or "Cancel" *
* *
* NOTE: This function does not return until the dialog is closed *
* *
* Args: parent - the parent widget *
* title - the title of the window *
* text - the message to display *
* Return: none *
\********************************************************************/
Boolean
verifyBox( Widget parent, char *text )
{
Widget dialog,msgbox;
XmString message = XmStringCreateSimple(text);
XmString yes,no;
VerifyBox verifyData;
verifyData.done = False;
verifyData.answer = False;
setBusyCursor( parent );
/* Create the dialog box... XmNdeleteResponse is set to
* XmDESTROY so the dialog's memory is freed when it is closed */
dialog = XtVaCreatePopupShell( "dialog",
xmDialogShellWidgetClass, parent,
XmNdialogStyle, XmDIALOG_APPLICATION_MODAL,
XmNtitle, "",
XmNwidth, 300,
XmNdeleteResponse, XmDESTROY,
NULL );
yes = XmStringCreateSimple(" Yes ");
no = XmStringCreateSimple(" No ");
/* Create a messagebox.... has message and "Ok","Cancel" buttons */
msgbox =
XtVaCreateManagedWidget( "dialog",
xmMessageBoxWidgetClass, dialog,
XmNdialogType, XmDIALOG_QUESTION,
XmNdefaultButtonType,XmDIALOG_CANCEL_BUTTON,
XmNmessageString, message,
XmNcancelLabelString,no,
XmNokLabelString, yes,
NULL );
/* Get rid of the "Help" Button!! */
XtUnmanageChild( XmMessageBoxGetChild(msgbox, XmDIALOG_HELP_BUTTON) );
/* We can make verifyData an automatic variable, and pass it by
* reference because this function doesn't return until the
* dialog is destroyed, which means that the callbacks are done */
XtAddCallback( msgbox, XmNokCallback, verifyBoxCB, &verifyData );
XtAddCallback( msgbox, XmNcancelCallback, verifyBoxCB, &verifyData );
XtPopup( dialog, XtGrabNone );
unsetBusyCursor( parent );
/* while the user hasn't pushed "Ok" or "Cancel", simulate XtMainLoop.
* When verifyData.done changes from False, it means the user has
* pressed a button. Don't break loop until XtAppPending() also
* returns False to assure widget destruction. */
while( !(verifyData.done) || XtAppPending(app) )
XtAppProcessEvent( app, XtIMAll );
XmStringFree(message);
XmStringFree(yes);
XmStringFree(no);
return verifyData.answer;
}
/********************************************************************\
* verifyBoxCB *
* *
* Args: mw - the widget that called us *
* cd - verifyData *
* cb - *
* Return: none *
\********************************************************************/
void
verifyBoxCB( Widget mw, XtPointer cd, XtPointer cb )
{
XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *)cb;
VerifyBox *verifyData = (VerifyBox *)cd;
switch( cbs->reason )
{
case XmCR_OK:
verifyData->answer = True;
break;
case XmCR_CANCEL:
default:
verifyData->answer = False;
}
verifyData->done = True;
}
/********************************************************************\
*********************************************************************
\********************************************************************/
/********************************************************************\
* errorBox *
* displays an error dialog box *
* *
* Args: w - the parent widget *
* message - the error message to display *
* Return: none *
\********************************************************************/
void
errorBox( Widget parent, char *message )
{
Widget dialog,
pane,
controlform,
actionform,
widget;
if( message != NULL )
{
XmString warning_msg,
dialogname;
setBusyCursor( parent );
/* Create a warning dialog */
dialog = XmCreateWarningDialog( parent, "warning", NULL, 0 );
/* Create the warning XmString */
warning_msg = XmStringCreateLtoR( message, charset );
dialogname = XmStringCreateSimple( "WARNING" );
XtVaSetValues( dialog,
XmNdialogTitle, dialogname,
XmNmessageString, warning_msg,
NULL );
/* Get rid of the "Help" and "Cancel" buttons that would normally
* be in the warning dialog dialog by unmanaging them */
XtUnmanageChild( XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON) );
XtUnmanageChild( XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON) );
/* Register the callback for the "Ok" button */
XtAddCallback( dialog, XmNokCallback, destroyShellCB, dialog );
/* Free up the allocated XmStrings */
XmStringFree( warning_msg );
XmStringFree( dialogname );
XtManageChild( dialog );
unsetBusyCursor( parent );
}
}