Merge lp:~adorsaz/homebank/adv-budget-with-categories into lp:homebank/5.2.x

Proposed by Adrien Dorsaz on 2019-02-07
Status: Merged
Approved by: Maxime DOYEN on 2019-10-08
Approved revision: 128
Merge reported by: Maxime DOYEN
Merged at revision: not available
Proposed branch: lp:~adorsaz/homebank/adv-budget-with-categories
Merge into: lp:homebank/5.2.x
Diff against target: 6508 lines (+6445/-0) (has conflicts)
5 files modified
src/Makefile.am (+2/-0)
src/Makefile.in (+70/-0)
src/dsp_mainwindow.c.OTHER (+3388/-0)
src/ui-budget-tabview.c (+2916/-0)
src/ui-budget-tabview.h (+69/-0)
Text conflict in src/Makefile.in
Contents conflict in src/dsp_mainwindow.c
To merge this branch: bzr merge lp:~adorsaz/homebank/adv-budget-with-categories
Reviewer Review Type Date Requested Status
Maxime DOYEN 2019-02-07 Needs Fixing on 2019-07-07
Review via email: mp+362864@code.launchpad.net

Description of the change

Hello,

As I've said, I've worked again last month on the advanced budget manager for Home Bank last month.

This new merge propose is rebased on Home Bank 5.2.1 and includes already the first merge propose.

This one add the following features:

1. Categories can be managed directly from the view (rename category from the view, add, remove, merge categories from toolbar)
2. The view sorts by name categories inside the same hierarchy level
3. The view allows to expand and collapse lines as other Home Bank dialogs with a toolbar
4. A search widget is available to look fast for a category inside the view
5. The code has been refactored to correctly uses GTK objects (filter, sort...): the main model is built only once on dialog open and never rebuilt.
6. The "Monthly" columns now directly contains a toggle button to enable "same amount" feature and the entry to set the monthly amount (instead of two columns of first implementation)
7. The "Category Name" column now displays a toggle button in "Income" and "Expense" display mode to force the display in Balance mode
8. The view has vertical and horizontal scrollbars enabled (before, the horizontal one was disabled, but it did too big window when amounts were large)

To implement category management, I've based my work on the ui-category.c file (I needed to rewrite the UI part, but I was able to use same logic for the non-UI part).

Regards,
Adrien

To post a comment you must log in.
Maxime DOYEN (mdoyen) wrote :

merged this code with my local trunk for review

Maxime DOYEN (mdoyen) wrote :

Hi Adrien,

I finally took time this morning to review this code, I still would like to add this to 5.3 as promise. For now I am still working on some refinement for many things in 5.3, and will release a 5.3 RC in a few days (I hope).

Anyway I would suggest some changes in your proposal before including it, no hurry for you, as I plan to release a final 5.3 on September, after a quite long RC period, due to the very deep changes I have made.

Here is a list:

bug2fix:
- the selection remains on a wrong line, sometimes
  to reproduce with example file
 under expense, click on income tax, goes to balance: OK the selection remains
 under expense, click on income tax, goes to income: total is selected (default) ?
 under expense, click on any category with no budget (Car/Fuel), goes to balance: KO, invoice is selected

changes2make:
- global: rename file/func name, menu title, dialog title to something like 'Budget (table view)'; ui_bud_tabview_xxx, because the axis of the dialog is only visual (semantic)
- dialog: disable edition (add/remove/merge) with HB_BUD_TABVIEW_EDIT_ENABLE, for now I prefer keep budget to input budget only, and category management separately, with pragmas you will be able to compile with that if you want
- dialog: top radio button should be Summary(or Synthesis)/Expense/Income, to follow semantic and other Hb dialog
- dialog: move the searchbar to topright

- list: remove the '(check forced display)' into the title + checkbox in profit of a single toggle button at bottom (I added a pin icon in the budget list fro 5.3, and will also for your list), this with lighten the display
- list: center title column
- list: add an empty column as last column, to avoid ugly right justify on last column
- list: total column should be displayed in 2nd position to ease reading
- list: display category with budget in bold to ease visual anchor
- list: display subcategories in italic

add2do:
- a way (button below the list to enable clear a budget line (similar to clear input in my budget dialog)

things2consider:
- list: add an 'Average' (by month) column just after/before total ?
- list: hide 0.00 when not usefull (to focus reading) ?

review: Needs Fixing
Adrien Dorsaz (adorsaz) wrote :

Hi Maxime,

Thanks for this review, your suggestions are nice and well explained.

I've began to rename the dialog (and symbols), to build read-only by default and to re-order buttons on top.

For the bug of selection, I think I'll simply clear the current selection on view change, because there's a lot difference between them in the lines (especially between Expense and Credit which have only the total lines in common).

For the moment, the first lines in the tree are the "Incomes". Should I first display "Expense" to follow the order of top buttons ? (same question for the "Income" and "Expense" line of the "Totals" group ?)

Thanks again and see you !

105. By Adrien Dorsaz on 2019-07-22

rename ui-adv-budget to ui-budget-tabview

106. By Adrien Dorsaz on 2019-07-22

replace all `adv_budget` (and similar) prefix in symbols with `bud_tabview`

107. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: by default build tabview in read-only mode

108. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: reorder and rename top radio buttons

109. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: add empty last column to follow the window expension

110. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: on model toggle, reset scroll to top and unselect rows

111. By Adrien Dorsaz on 2019-07-22

budget-tabview: center title columns and hide tree lines

That's to be coherent with others tree view style

112. By Adrien Dorsaz on 2019-07-22

budget-tabview: place total column on second position

113. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: display category name with bold / italic

If it has budget, the font weight is bold.
If it is a subcategory, the style is italic.

For edition: adjust the GF_BUDGET flag according to GF_FORCED
as done in the ui-category source code.

114. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: add monthly average column

115. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: display category name with normal weight within Summary

116. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: edit mode is able to clear inputs

117. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: general redesign interface

Move the search entry to top right of UI.

Remove the "Category with checkbox" column.
Add a check button to (un)force monitoring Category.

Add some space between buttons to add/remove/merge category and the
clear input button.

Refactor Category search code to be reusable for delete, clear inputs
and toggle monitoring.

118. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: adjust documentation, adjust symbols with `_`

119. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: refactor merge dialog and avoid select merge source as target

120. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: refactor category_add to use the get_selected_category

121. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: hide amount if equals 0.0 (which allow to remove sensitive workaround)

122. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: use fg colors defined by user for debit/credit

123. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: monthly average uses homebank round helper

124. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: remove the useless right margin to align with the search entry above

125. By Adrien Dorsaz on 2019-07-22

ui-budget-tabview: remove "fill" property missly added to GtkBox (that's a child property, not a property of GtkBox)

Adrien Dorsaz (adorsaz) wrote :

Ok, I've fixed the bug and applied all suggested changes.

Note that to move the GtkSearchEntry to top right, I've added a GtkBox which contains it and the radio buttons.

I've decided to not add both widgets directly to the same cell of the grid (as made in ui-budget.c), as the Gtk documentation clearly says in such case the behavior is not defined. With my solution, the GtkSearchEntry remain visible even if the window become very small (the minimal window width is the sum of both widget width).

For the clear input button, I've used a GtkCheckButton for the moment, as I wasn't sure what you've made in 5.3. Although, that's pretty easy to move it to GtkToggleButton: you just have to change the function building the widget.

Finally, the branch seems clean on my side, but here (on the merge request web page), launchpad show a strange file added named "src/dsp_mainwindow.c.OTHER". I suppose that's because the 5.2.x branch has evolved since January and there's conflict to solve. I've tried to reproduce conflicts with Bazaar Explorer, but I failed, I hope you'll be able to manage them :-)

126. By Adrien Dorsaz on 2019-09-17

ui-budget-tabview: edit mode: on add, the default value can be the currently selected row if it's a root

127. By Adrien Dorsaz on 2019-09-17

ui-budget-tabview: edit mode: add dialog show available parents according to current view mode (Summary, Expense, Income)

128. By Adrien Dorsaz on 2019-09-17

ui-budget-tabview: fix typo in comments

Adrien Dorsaz (adorsaz) wrote :

Hi Maxime,

FYI, I've just added two revisions for the "add category" dialog for the edit mode:

* the parent default value can be "Debit" or "Credit" roots of the tree view if they are selected
* the parent category list is limited to "Income" when only the "Incomes" are viewed in the budget tabview (the same for "Expense"

Maxime DOYEN (mdoyen) wrote :

Hi Adrien,

Thanks for your time and work on this.
I have just merged this to my local trunk for a last "quick" review before including this into the I hope close release of 5.3-rc.

Max.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2019-04-11 20:36:11 +0000
+++ src/Makefile.am 2019-09-17 21:50:17 +0000
@@ -106,6 +106,8 @@
106 ui-assist-start.h \106 ui-assist-start.h \
107 ui-budget.c \107 ui-budget.c \
108 ui-budget.h \108 ui-budget.h \
109 ui-budget-tabview.c \
110 ui-budget-tabview.h \
109 ui-category.c \111 ui-category.c \
110 ui-category.h \112 ui-category.h \
111 ui-currency.c \113 ui-currency.c \
112114
=== modified file 'src/Makefile.in'
--- src/Makefile.in 2019-04-11 20:36:11 +0000
+++ src/Makefile.in 2019-09-17 21:50:17 +0000
@@ -119,12 +119,21 @@
119 rep-vehicle.$(OBJEXT) ui-account.$(OBJEXT) \119 rep-vehicle.$(OBJEXT) ui-account.$(OBJEXT) \
120 ui-archive.$(OBJEXT) ui-assign.$(OBJEXT) \120 ui-archive.$(OBJEXT) ui-assign.$(OBJEXT) \
121 ui-assist-import.$(OBJEXT) ui-assist-start.$(OBJEXT) \121 ui-assist-import.$(OBJEXT) ui-assist-start.$(OBJEXT) \
122<<<<<<< TREE
122 ui-budget.$(OBJEXT) ui-category.$(OBJEXT) \123 ui-budget.$(OBJEXT) ui-category.$(OBJEXT) \
123 ui-currency.$(OBJEXT) ui-dialogs.$(OBJEXT) ui-filter.$(OBJEXT) \124 ui-currency.$(OBJEXT) ui-dialogs.$(OBJEXT) ui-filter.$(OBJEXT) \
124 ui-hbfile.$(OBJEXT) ui-payee.$(OBJEXT) ui-pref.$(OBJEXT) \125 ui-hbfile.$(OBJEXT) ui-payee.$(OBJEXT) ui-pref.$(OBJEXT) \
125 ui-split.$(OBJEXT) ui-tag.$(OBJEXT) ui-transaction.$(OBJEXT) \126 ui-split.$(OBJEXT) ui-tag.$(OBJEXT) ui-transaction.$(OBJEXT) \
126 ui-txn-multi.$(OBJEXT) ui-widgets-data.$(OBJEXT) \127 ui-txn-multi.$(OBJEXT) ui-widgets-data.$(OBJEXT) \
127 ui-widgets.$(OBJEXT)128 ui-widgets.$(OBJEXT)
129=======
130 ui-budget.$(OBJEXT) ui-budget-tabview.$(OBJEXT) \
131 ui-category.$(OBJEXT) ui-currency.$(OBJEXT) \
132 ui-dialogs.$(OBJEXT) ui-filter.$(OBJEXT) ui-hbfile.$(OBJEXT) \
133 ui-payee.$(OBJEXT) ui-pref.$(OBJEXT) ui-split.$(OBJEXT) \
134 ui-transaction.$(OBJEXT) ui-txn-multi.$(OBJEXT) \
135 ui-widgets.$(OBJEXT)
136>>>>>>> MERGE-SOURCE
128homebank_OBJECTS = $(am_homebank_OBJECTS)137homebank_OBJECTS = $(am_homebank_OBJECTS)
129am__DEPENDENCIES_1 =138am__DEPENDENCIES_1 =
130homebank_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)139homebank_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@@ -441,6 +450,8 @@
441 ui-assist-start.h \450 ui-assist-start.h \
442 ui-budget.c \451 ui-budget.c \
443 ui-budget.h \452 ui-budget.h \
453 ui-budget-tabview.c \
454 ui-budget-tabview.h \
444 ui-category.c \455 ui-category.c \
445 ui-category.h \456 ui-category.h \
446 ui-currency.c \457 ui-currency.c \
@@ -561,6 +572,7 @@
561distclean-compile:572distclean-compile:
562 -rm -f *.tab.c573 -rm -f *.tab.c
563574
575<<<<<<< TREE
564@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp-account.Po@am__quote@ # am--include-marker576@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp-account.Po@am__quote@ # am--include-marker
565@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp-mainwindow.Po@am__quote@ # am--include-marker577@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp-mainwindow.Po@am__quote@ # am--include-marker
566@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-chart-colors.Po@am__quote@ # am--include-marker578@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-chart-colors.Po@am__quote@ # am--include-marker
@@ -627,6 +639,64 @@
627 @echo '# dummy' >$@-t && $(am__mv) $@-t $@639 @echo '# dummy' >$@-t && $(am__mv) $@-t $@
628640
629am--depfiles: $(am__depfiles_remade)641am--depfiles: $(am__depfiles_remade)
642=======
643@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp_account.Po@am__quote@
644@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp_mainwindow.Po@am__quote@
645@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-chart-colors.Po@am__quote@
646@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-chart-stack.Po@am__quote@
647@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-chart.Po@am__quote@
648@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-dateentry.Po@am__quote@
649@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-account.Po@am__quote@
650@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-archive.Po@am__quote@
651@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-assign.Po@am__quote@
652@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-category.Po@am__quote@
653@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-currency.Po@am__quote@
654@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-encoding.Po@am__quote@
655@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-export.Po@am__quote@
656@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-filter.Po@am__quote@
657@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-hbfile.Po@am__quote@
658@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-import-csv.Po@am__quote@
659@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-import-ofx.Po@am__quote@
660@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-import-qif.Po@am__quote@
661@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-import.Po@am__quote@
662@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-misc.Po@am__quote@
663@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-payee.Po@am__quote@
664@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-preferences.Po@am__quote@
665@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-report.Po@am__quote@
666@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-split.Po@am__quote@
667@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-tag.Po@am__quote@
668@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-transaction.Po@am__quote@
669@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-xml.Po@am__quote@
670@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/homebank.Po@am__quote@
671@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/language.Po@am__quote@
672@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list_account.Po@am__quote@
673@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list_operation.Po@am__quote@
674@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list_topspending.Po@am__quote@
675@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list_upcoming.Po@am__quote@
676@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rep_balance.Po@am__quote@
677@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rep_budget.Po@am__quote@
678@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rep_stats.Po@am__quote@
679@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rep_time.Po@am__quote@
680@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rep_vehicle.Po@am__quote@
681@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-account.Po@am__quote@
682@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-archive.Po@am__quote@
683@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-assign.Po@am__quote@
684@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-assist-import.Po@am__quote@
685@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-assist-start.Po@am__quote@
686@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-budget-tabview.Po@am__quote@
687@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-budget.Po@am__quote@
688@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-category.Po@am__quote@
689@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-currency.Po@am__quote@
690@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-dialogs.Po@am__quote@
691@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-filter.Po@am__quote@
692@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-hbfile.Po@am__quote@
693@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-payee.Po@am__quote@
694@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-pref.Po@am__quote@
695@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-split.Po@am__quote@
696@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-transaction.Po@am__quote@
697@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-txn-multi.Po@am__quote@
698@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-widgets.Po@am__quote@
699>>>>>>> MERGE-SOURCE
630700
631.c.o:701.c.o:
632@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<702@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
633703
=== added file 'src/dsp_mainwindow.c.OTHER'
--- src/dsp_mainwindow.c.OTHER 1970-01-01 00:00:00 +0000
+++ src/dsp_mainwindow.c.OTHER 2019-09-17 21:50:17 +0000
@@ -0,0 +1,3388 @@
1/* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 1995-2018 Maxime DOYEN
3 *
4 * This file is part of HomeBank.
5 *
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21#include "homebank.h"
22
23#include "dsp_mainwindow.h"
24
25#include "list_account.h"
26#include "list_upcoming.h"
27#include "list_topspending.h"
28
29#include "dsp_account.h"
30#include "ui-assist-import.h"
31#include "ui-assist-start.h"
32#include "ui-account.h"
33#include "ui-currency.h"
34#include "ui-payee.h"
35#include "ui-category.h"
36#include "ui-archive.h"
37#include "ui-assign.h"
38#include "ui-budget.h"
39#include "ui-budget-tabview.h"
40#include "ui-pref.h"
41#include "ui-hbfile.h"
42#include "ui-transaction.h"
43
44#include "rep_balance.h"
45#include "rep_budget.h"
46#include "rep_stats.h"
47#include "rep_time.h"
48#include "rep_vehicle.h"
49
50#include "gtk-chart.h"
51
52//old url prior 2018
53//#define HOMEBANK_URL_HELP "http://homebank.free.fr/help/"
54//#define HOMEBANK_URL_HELP_ONLINE "https://launchpad.net/homebank/+addquestion"
55//#define HOMEBANK_URL_HELP_PROBLEM "https://launchpad.net/homebank/+filebug"
56//#define HOMEBANK_URL_HELP_TRANSLATE "https://launchpad.net/homebank/+translations"
57
58#define HOMEBANK_URL_HELP "index.html"
59#define HOMEBANK_URL_HELP_ONLINE "http://homebank.free.fr/support.php"
60#define HOMEBANK_URL_HELP_UPDATES "http://homebank.free.fr/downloads.php"
61#define HOMEBANK_URL_HELP_PROBLEM "http://homebank.free.fr/development.php#bug"
62#define HOMEBANK_URL_HELP_TRANSLATE "http://homebank.free.fr/development.php#translate"
63
64
65/****************************************************************************/
66/* Debug macros */
67/****************************************************************************/
68#define MYDEBUG 0
69
70#if MYDEBUG
71#define DB(x) (x);
72#else
73#define DB(x);
74#endif
75
76/* our global datas */
77extern struct HomeBank *GLOBALS;
78extern struct Preferences *PREFS;
79extern gchar *homebank_pixmaps_dir;
80
81
82/* our functions prototype */
83static void ui_mainwindow_action_new(void);
84static void ui_mainwindow_action_open(void);
85static void ui_mainwindow_action_save(void);
86static void ui_mainwindow_action_saveas(void);
87static void ui_mainwindow_action_revert(void);
88static void ui_mainwindow_action_openbak(void);
89static void ui_mainwindow_action_properties(void);
90static void ui_mainwindow_action_close(void);
91static void ui_mainwindow_action_quit(void);
92
93static void ui_mainwindow_action_defcurrency(void);
94static void ui_mainwindow_action_defaccount(void);
95static void ui_mainwindow_action_defpayee(void);
96static void ui_mainwindow_action_defcategory(void);
97static void ui_mainwindow_action_defarchive(void);
98static void ui_mainwindow_action_defbudget(void);
99static void ui_mainwindow_action_defbudget_tabview(void);
100static void ui_mainwindow_action_defassign(void);
101static void ui_mainwindow_action_preferences(void);
102
103static void ui_mainwindow_action_toggle_toolbar(GtkToggleAction *action);
104static void ui_mainwindow_action_toggle_upcoming(GtkToggleAction *action);
105static void ui_mainwindow_action_toggle_topspending(GtkToggleAction *action);
106static void ui_mainwindow_action_toggle_minor(GtkToggleAction *action);
107
108static void ui_mainwindow_action_showtransactions(void);
109static void ui_mainwindow_action_showalltransactions(void);
110
111static void ui_mainwindow_action_addtransactions(void);
112static void ui_mainwindow_action_checkscheduled(void);
113
114static void ui_mainwindow_action_statistic(void);
115static void ui_mainwindow_action_trendtime(void);
116static void ui_mainwindow_action_budget(void);
117static void ui_mainwindow_action_balance(void);
118static void ui_mainwindow_action_vehiclecost(void);
119
120static void ui_mainwindow_action_import(GtkAction *action);
121static void ui_mainwindow_action_export(void);
122static void ui_mainwindow_action_anonymize(void);
123static void ui_mainwindow_action_file_statistics(void);
124
125static void ui_mainwindow_action_help(void);
126void ui_mainwindow_action_help_welcome(void);
127static void ui_mainwindow_action_help_online(void);
128static void ui_mainwindow_action_help_updates(void);
129static void ui_mainwindow_action_help_releasenotes(void);
130static void ui_mainwindow_action_help_translate(void);
131static void ui_mainwindow_action_help_problem(void);
132static void ui_mainwindow_action_about(void);
133
134
135static GtkWidget *ui_mainwindow_create_recent_chooser_menu (GtkRecentManager *manager);
136
137static void ui_mainwindow_populate_topspending(GtkWidget *widget, gpointer user_data);
138
139void ui_mainwindow_open(GtkWidget *widget, gpointer user_data);
140
141void ui_mainwindow_save(GtkWidget *widget, gpointer user_data);
142void ui_mainwindow_revert(GtkWidget *widget, gpointer user_data);
143void ui_mainwindow_action(GtkWidget *widget, gpointer user_data);
144void ui_mainwindow_toggle_minor(GtkWidget *widget, gpointer user_data);
145void ui_mainwindow_clear(GtkWidget *widget, gpointer user_data);
146
147gboolean ui_dialog_msg_savechanges(GtkWidget *widget, gpointer user_data);
148
149void ui_mainwindow_update(GtkWidget *widget, gpointer user_data);
150void ui_mainwindow_addtransactions(GtkWidget *widget, gpointer user_data);
151void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path);
152
153static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data);
154
155static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data);
156void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data);
157
158void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path);
159
160static void ui_panel_accounts_setup(struct hbfile_data *data);
161
162extern gchar *CYA_ACC_TYPE[];
163
164gchar *CYA_CATSUBCAT[] = {
165 N_("Category"),
166 N_("Subcategory"),
167 NULL
168};
169
170
171static GtkActionEntry entries[] = {
172
173 /* name, icon-name, label */
174
175 { "FileMenu" , NULL, N_("_File"), NULL, NULL, NULL },
176 //{ "ImportMenu" , NULL, N_("_Import"), NULL, NULL, NULL },
177 { "RecentMenu" , NULL, N_("Open _Recent"), NULL, NULL, NULL },
178 { "EditMenu" , NULL, N_("_Edit"), NULL, NULL, NULL },
179 { "ViewMenu" , NULL, N_("_View"), NULL, NULL, NULL },
180 { "ManageMenu" , NULL, N_("_Manage"), NULL, NULL, NULL },
181 { "TxnMenu" , NULL, N_("_Transactions"), NULL, NULL, NULL },
182 { "ReportMenu" , NULL, N_("_Reports"), NULL, NULL, NULL },
183 { "ToolsMenu" , NULL, N_("_Tools"), NULL, NULL, NULL },
184 { "HelpMenu" , NULL, N_("_Help"), NULL, NULL, NULL },
185
186// { "Import" , NULL, N_("Import") },
187// { "Export" , NULL, N_("Export to") },
188 /* name, icon-name, label, accelerator, tooltip */
189
190 /* FileMenu */
191 { "New" , ICONNAME_HB_FILE_NEW , N_("_New") , "<control>N", N_("Create a new file"), G_CALLBACK (ui_mainwindow_action_new) },
192 { "Open" , ICONNAME_HB_FILE_OPEN , N_("_Open...") , "<control>O", N_("Open a file"), G_CALLBACK (ui_mainwindow_action_open) },
193 { "Save" , ICONNAME_HB_FILE_SAVE , N_("_Save") , "<control>S", N_("Save the current file"), G_CALLBACK (ui_mainwindow_action_save) },
194 { "SaveAs" , ICONNAME_SAVE_AS , N_("Save _As...") , "<shift><control>S", N_("Save the current file with a different name"), G_CALLBACK (ui_mainwindow_action_saveas) },
195
196 { "Revert" , ICONNAME_REVERT , N_("Revert") , NULL, N_("Revert to a saved version of this file"), G_CALLBACK (ui_mainwindow_action_revert) },
197 { "OpenBak" , NULL , N_("Restore backup") , NULL, N_("Restore from a backup file"), G_CALLBACK (ui_mainwindow_action_openbak) },
198
199 { "Properties" , ICONNAME_PROPERTIES , N_("Properties..."), NULL, N_("Configure the file"), G_CALLBACK (ui_mainwindow_action_properties) },
200 { "Close" , ICONNAME_CLOSE , N_("_Close") , "<control>W", N_("Close the current file"), G_CALLBACK (ui_mainwindow_action_close) },
201 { "Quit" , ICONNAME_QUIT , N_("_Quit") , "<control>Q", N_("Quit HomeBank"), G_CALLBACK (ui_mainwindow_action_quit) },
202
203 /* Exchange */
204 { "Import" , ICONNAME_HB_FILE_IMPORT , N_("Import...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) },
205 //{ "ImportQIF" , ICONNAME_HB_FILE_IMPORT , N_("QIF file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) },
206 //{ "ImportOFX" , ICONNAME_HB_FILE_IMPORT , N_("OFX/QFX file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) },
207 //{ "ImportCSV" , ICONNAME_HB_FILE_IMPORT , N_("CSV file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) },
208
209 { "ExportQIF" , ICONNAME_HB_FILE_EXPORT , N_("Export as QIF...") , NULL, N_("Export all account in a QIF file"), G_CALLBACK (ui_mainwindow_action_export) },
210
211 /* EditMenu */
212 { "Preferences", ICONNAME_PREFERENCES , N_("Preferences..."), NULL, N_("Configure HomeBank"), G_CALLBACK (ui_mainwindow_action_preferences) },
213
214 /* ManageMenu */
215 { "Currency" , ICONNAME_HB_CURRENCY , N_("Currencies...") , NULL, N_("Configure the currencies"), G_CALLBACK (ui_mainwindow_action_defcurrency) },
216 { "Account" , ICONNAME_HB_ACCOUNT , N_("Acc_ounts...") , NULL, N_("Configure the accounts"), G_CALLBACK (ui_mainwindow_action_defaccount) },
217 { "Payee" , ICONNAME_HB_PAYEE , N_("_Payees...") , NULL, N_("Configure the payees"), G_CALLBACK (ui_mainwindow_action_defpayee) },
218 { "Category" , ICONNAME_HB_CATEGORY , N_("Categories...") , NULL, N_("Configure the categories"), G_CALLBACK (ui_mainwindow_action_defcategory) },
219 { "Archive" , ICONNAME_HB_ARCHIVE , N_("Scheduled/Template...") , NULL, N_("Configure the scheduled/template transactions"), G_CALLBACK (ui_mainwindow_action_defarchive) },
220 { "Budget" , ICONNAME_HB_BUDGET , N_("Budget...") , NULL, N_("Configure the budget"), G_CALLBACK (ui_mainwindow_action_defbudget) },
221 { "BudgetTabview", ICONNAME_HB_BUDGET , N_("Budget (tab view)...") , NULL, N_("View the budget"), G_CALLBACK (ui_mainwindow_action_defbudget_tabview) },
222 { "Assign" , ICONNAME_HB_ASSIGN , N_("Assignments..."), NULL, N_("Configure the automatic assignments"), G_CALLBACK (ui_mainwindow_action_defassign) },
223
224 /* TxnMenu */
225 { "AddTxn" , ICONNAME_HB_OPE_ADD , N_("Add...") , NULL, N_("Add transactions"), G_CALLBACK (ui_mainwindow_action_addtransactions) },
226 { "ShowTxn" , ICONNAME_HB_OPE_SHOW , N_("Show...") , NULL, N_("Shows selected account transactions"), G_CALLBACK (ui_mainwindow_action_showtransactions) },
227 { "ShowAllTxn" , ICONNAME_HB_OPE_SHOW , N_("Show all...") , NULL, N_("Shows all account transactions"), G_CALLBACK (ui_mainwindow_action_showalltransactions) },
228 { "Scheduler" , NULL , N_("Set scheduler...") , NULL, N_("Configure the transaction scheduler"), G_CALLBACK (ui_mainwindow_action_properties) },
229 { "AddScheduled", NULL , N_("Post scheduled"), NULL, N_("Post pending scheduled transactions"), G_CALLBACK (ui_mainwindow_action_checkscheduled) },
230
231 /* ReportMenu */
232 { "RStatistics" , ICONNAME_HB_REP_STATS , N_("_Statistics...") , NULL, N_("Open the Statistics report"), G_CALLBACK (ui_mainwindow_action_statistic) },
233 { "RTrendTime" , ICONNAME_HB_REP_TIME , N_("_Trend Time...") , NULL, N_("Open the Trend Time report"), G_CALLBACK (ui_mainwindow_action_trendtime) },
234 { "RBudget" , ICONNAME_HB_REP_BUDGET , N_("B_udget...") , NULL, N_("Open the Budget report"), G_CALLBACK (ui_mainwindow_action_budget) },
235 { "RBalance" , ICONNAME_HB_REP_BALANCE, N_("Balance...") , NULL, N_("Open the Balance report"), G_CALLBACK (ui_mainwindow_action_balance) },
236 { "RVehiculeCost", ICONNAME_HB_REP_CAR , N_("_Vehicle cost...") , NULL, N_("Open the Vehicle cost report"), G_CALLBACK (ui_mainwindow_action_vehiclecost) },
237
238 /* Tools */
239 { "Welcome" , NULL , N_("Show welcome dialog...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_help_welcome) },
240 { "FileStats" , NULL , N_("File statistics...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_file_statistics) },
241 { "Anonymize" , NULL , N_("Anonymize...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_anonymize) },
242
243 /* HelpMenu */
244 { "Contents" , ICONNAME_HELP , N_("_Contents") , "F1", N_("Documentation about HomeBank"), G_CALLBACK (ui_mainwindow_action_help) },
245 { "Online" , "lpi-help" , N_("Get Help Online...") , NULL, N_("Connect to the LaunchPad website for online help"), G_CALLBACK (ui_mainwindow_action_help_online) },
246
247 { "Updates" , NULL , N_("Check for updates...") , NULL, N_("Visit HomeBank website to check for update"), G_CALLBACK (ui_mainwindow_action_help_updates) },
248 { "ReleaseNotes", NULL , N_("Release Notes") , NULL, N_("Display the release notes"), G_CALLBACK (ui_mainwindow_action_help_releasenotes) },
249 { "Problem" , "lpi-bug" , N_("Report a Problem...") , NULL, N_("Connect to the LaunchPad website to help fix problems"), G_CALLBACK (ui_mainwindow_action_help_problem) },
250 { "Translate" , "lpi-translate" , N_("Translate this Application..."), NULL, N_("Connect to the LaunchPad website to help translate this application"), G_CALLBACK (ui_mainwindow_action_help_translate) },
251
252 { "About" , ICONNAME_ABOUT , N_("_About") , NULL, N_("About HomeBank") ,G_CALLBACK (ui_mainwindow_action_about) },
253
254};
255static guint n_entries = G_N_ELEMENTS (entries);
256
257
258static GtkToggleActionEntry toggle_entries[] = {
259/* name , icon-name, label, accelerator, tooltip, callback, is_active */
260 { "Toolbar" , NULL , N_("_Toolbar") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_toggle_toolbar), TRUE },
261 { "Spending" , NULL , N_("_Top spending") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_toggle_topspending), TRUE },
262 { "Upcoming" , NULL , N_("_Scheduled list") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_toggle_upcoming), TRUE },
263 { "AsMinor" , NULL , N_("Euro minor"), "<control>M", NULL, G_CALLBACK (ui_mainwindow_action_toggle_minor), FALSE },
264};
265
266static guint n_toggle_entries = G_N_ELEMENTS (toggle_entries);
267
268
269static const gchar *ui_info =
270"<ui>"
271
272" <menubar name='MenuBar'>"
273" <menu action='FileMenu'>"
274" <menuitem action='New'/>"
275" <menuitem action='Open'/>"
276" <menuitem action='RecentMenu'/>"
277" <separator/>"
278" <menuitem action='Save'/>"
279" <menuitem action='SaveAs'/>"
280" <separator/>"
281" <menuitem action='Import'/>"
282/*" <menu action='ImportMenu'>"
283" <menuitem action='ImportQIF'/>"
284" <menuitem action='ImportOFX'/>"
285" <menuitem action='ImportCSV'/>"
286" </menu>"*/
287" <menuitem action='ExportQIF'/>"
288// future: print to come here
289" <separator/>"
290" <menuitem action='Revert'/>"
291" <menuitem action='OpenBak'/>"
292" <separator/>"
293" <menuitem action='Properties'/>"
294" <separator/>"
295" <menuitem action='Close'/>"
296" <menuitem action='Quit'/>"
297" </menu>"
298" <menu action='EditMenu'>"
299" <menuitem action='Preferences'/>"
300" </menu>"
301" <menu action='ViewMenu'>"
302" <menuitem action='Toolbar'/>"
303" <separator/>"
304" <menuitem action='Spending'/>"
305" <menuitem action='Upcoming'/>"
306" <separator/>"
307" <menuitem action='AsMinor'/>"
308" </menu>"
309" <menu action='ManageMenu'>"
310" <menuitem action='Account'/>"
311" <menuitem action='Payee'/>"
312" <menuitem action='Category'/>"
313" <menuitem action='Archive'/>"
314" <menuitem action='Budget'/>"
315" <menuitem action='BudgetTabview'/>"
316" <menuitem action='Assign'/>"
317" <menuitem action='Currency'/>"
318" </menu>"
319" <menu action='TxnMenu'>"
320" <menuitem action='AddTxn'/>"
321" <menuitem action='ShowTxn'/>"
322" <menuitem action='ShowAllTxn'/>"
323" <separator/>"
324" <menuitem action='Scheduler'/>"
325" <menuitem action='AddScheduled'/>"
326" </menu>"
327" <menu action='ReportMenu'>"
328" <menuitem action='RStatistics'/>"
329" <menuitem action='RTrendTime'/>"
330" <menuitem action='RBalance'/>"
331" <menuitem action='RBudget'/>"
332" <menuitem action='RVehiculeCost'/>"
333" </menu>"
334" <menu action='ToolsMenu'>"
335" <menuitem action='Welcome'/>"
336" <menuitem action='FileStats'/>"
337" <separator/>"
338" <menuitem action='Anonymize'/>"
339" </menu>"
340" <menu action='HelpMenu'>"
341" <menuitem action='Contents'/>"
342" <menuitem action='Online'/>"
343" <separator/>"
344" <menuitem action='Updates'/>"
345" <menuitem action='ReleaseNotes'/>"
346" <menuitem action='Problem'/>"
347" <menuitem action='Translate'/>"
348" <separator/>"
349" <menuitem action='About'/>"
350" </menu>"
351" </menubar>"
352
353" <toolbar name='ToolBar'>"
354" <toolitem action='New'/>"
355// here Open + recent is coded
356" <toolitem action='Save'/>"
357" <separator/>"
358" <toolitem action='Account'/>"
359" <toolitem action='Payee'/>"
360" <toolitem action='Category'/>"
361" <toolitem action='Archive'/>"
362" <toolitem action='Budget'/>"
363" <toolitem action='Assign'/>"
364" <toolitem action='Currency'/>"
365" <separator/>"
366" <toolitem action='ShowTxn'/>"
367" <toolitem action='AddTxn'/>"
368" <separator/>"
369" <toolitem action='RStatistics'/>"
370" <toolitem action='RTrendTime'/>"
371" <toolitem action='RBalance'/>"
372" <toolitem action='RBudget'/>"
373" <toolitem action='RVehiculeCost'/>"
374" </toolbar>"
375
376"</ui>";
377
378
379
380/* TODO: a bouger */
381
382
383/*
384**
385*/
386void ui_mainwindow_revert(GtkWidget *widget, gpointer user_data)
387{
388//struct hbfile_data *data;
389gchar *basename;
390gchar *title;
391gchar *secondtext;
392gint result;
393
394 DB( g_print("\n[ui-mainwindow] revert\n") );
395
396 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
397
398 basename = g_path_get_basename(GLOBALS->xhb_filepath);
399 title = g_strdup_printf (
400 _("Revert unsaved changes to file '%s'?"), basename);
401
402 secondtext =
403 _("- Changes made to the file will be permanently lost\n"
404 "- File will be reloaded from the last save (.xhb~)");
405
406 result = ui_dialog_msg_confirm_alert(
407 GTK_WINDOW(GLOBALS->mainwindow),
408 title,
409 secondtext,
410 _("_Revert")
411 );
412
413 g_free(title);
414 g_free(basename);
415
416 if( result == GTK_RESPONSE_OK )
417 {
418 DB( g_print(" - should revert\n") );
419
420 hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb~"));
421 ui_mainwindow_open_internal(widget, NULL);
422 hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb"));
423 }
424
425}
426
427
428static void
429activate_url (GtkAboutDialog *about,
430 const gchar *link,
431 gpointer data)
432{
433 DB( g_print("activate url %s\n", link) );
434
435 homebank_util_url_show (link);
436}
437
438static void hbfile_about(void)
439{
440GtkWidget *dialog;
441GdkPixbuf *pixbuf;
442gchar *pathfilename;
443gchar *version;
444
445 static const gchar *artists[] = {
446 "Maxime DOYEN",
447 NULL
448 };
449
450 static const gchar *authors[] = {
451 "Lead developer:\n" \
452 "Maxime DOYEN",
453 "\nContributor:\n" \
454 "Ga\xc3\xabtan LORIDANT (Maths formulas for charts)\n",
455 NULL
456 };
457
458/*
459 const gchar *documenters[] = {
460 "Maxime DOYEN",
461 NULL
462 };
463*/
464
465 static const gchar *copyright = "Copyright \xc2\xa9 1995-2018 - Maxime DOYEN";
466
467
468
469 version = g_strdup_printf (PACKAGE_VERSION "\n<small>Running against GTK+ %d.%d.%d</small>",
470 gtk_get_major_version (),
471 gtk_get_minor_version (),
472 gtk_get_micro_version ());
473
474 dialog = gtk_about_dialog_new();
475
476 gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(GLOBALS->mainwindow));
477 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
478
479 gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG(dialog), g_get_application_name ());
480 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), version);
481 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), copyright);
482 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), _("Free, easy, personal accounting for everyone"));
483 gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG(dialog), GTK_LICENSE_GPL_2_0);
484
485 //gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(dialog), );
486 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "http://homebank.free.fr");
487 gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), "Visit the HomeBank website");
488
489 gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(dialog), "homebank");
490
491 pathfilename = g_build_filename(homebank_app_get_images_dir(), "splash.png", NULL);
492 pixbuf = gdk_pixbuf_new_from_file(pathfilename, NULL);
493 g_free(pathfilename);
494
495 if( pixbuf )
496 {
497 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf);
498 g_object_unref (pixbuf);
499 }
500
501 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog), authors);
502 gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(dialog), artists);
503 //gtk_about_dialog_set_documenters(GTK_ABOUT_DIALOG(dialog), );
504 //gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(dialog), );
505
506 g_signal_connect (dialog, "activate-link", G_CALLBACK (activate_url), NULL);
507
508 gtk_dialog_run (GTK_DIALOG (dialog));
509
510 gtk_widget_destroy (dialog);
511
512 g_free(version);
513
514}
515
516
517/* hbfile action functions -------------------- */
518static void ui_mainwindow_action_new(void)
519{
520GtkWidget *widget = GLOBALS->mainwindow;
521
522 if( ui_dialog_msg_savechanges(widget,NULL) == TRUE )
523 {
524 //clear all, and init GLOBALS->xhb_filepath to default
525 ui_mainwindow_clear(widget, GINT_TO_POINTER(TRUE)); // GPOINTER_TO_INT(
526 ui_mainwindow_update(widget, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL));
527
528 ui_start_assistant();
529 //ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
530 //ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL);
531 //ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL);
532 }
533}
534
535static void ui_mainwindow_action_open(void)
536{
537 ui_mainwindow_open(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE));
538}
539
540static void ui_mainwindow_action_openbak(void)
541{
542 ui_mainwindow_open(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE));
543}
544
545static void ui_mainwindow_action_save(void)
546{
547 ui_mainwindow_save(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE));
548}
549
550static void ui_mainwindow_action_saveas(void)
551{
552 ui_mainwindow_save(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE));
553}
554
555static void ui_mainwindow_action_revert(void)
556{
557 ui_mainwindow_revert(GLOBALS->mainwindow, NULL);
558}
559
560static void ui_mainwindow_action_close(void)
561{
562GtkWidget *widget = GLOBALS->mainwindow;
563
564 if( ui_dialog_msg_savechanges(widget,NULL) == TRUE )
565 {
566 //clear all, and init GLOBALS->xhb_filepath to default
567 ui_mainwindow_clear(widget, GINT_TO_POINTER(TRUE));
568 ui_mainwindow_update(widget, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_REFRESHALL));
569 }
570
571}
572
573
574static void ui_mainwindow_action_quit(void)
575{
576gboolean result;
577
578 //emulate the wm close button
579 g_signal_emit_by_name(GLOBALS->mainwindow, "delete-event", NULL, &result);
580}
581
582
583static void ui_mainwindow_action_file_statistics(void)
584{
585 ui_dialog_file_statistics();
586}
587
588
589static void ui_mainwindow_action_properties(void)
590{
591 create_defhbfile_dialog();
592 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL));
593}
594
595static void ui_mainwindow_action_anonymize(void)
596{
597gint result;
598gchar *title;
599gchar *secondtext;
600
601 title = _("Are you sure you want to anonymize the file?");
602
603 secondtext =
604 _("Proceeding will anonymize any text, \n"
605 "like 'account x', 'payee y', 'memo z', ...");
606
607 result = ui_dialog_msg_confirm_alert(
608 GTK_WINDOW(GLOBALS->mainwindow),
609 title,
610 secondtext,
611 _("_Anonymize")
612 );
613
614 //#1707201
615 //if( result == GTK_RESPONSE_CANCEL )
616 // return;
617 if( result == GTK_RESPONSE_OK )
618 {
619 hbfile_anonymize();
620 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL));
621 }
622}
623
624
625static void ui_mainwindow_action_defcurrency(void)
626{
627 ui_cur_manage_dialog();
628 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL));
629}
630
631
632static void ui_mainwindow_action_defaccount(void)
633{
634 ui_acc_manage_dialog();
635
636 //our global list has changed, so update the treeview
637 //todo: optimize this, should not call compute balance here
638 account_compute_balances ();
639 ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
640
641 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE));
642}
643
644static void ui_mainwindow_action_defpayee(void)
645{
646 ui_pay_manage_dialog();
647 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
648}
649
650static void ui_mainwindow_action_defcategory(void)
651{
652 ui_cat_manage_dialog();
653 //todo:why refresh upcoming here??
654 //ui_mainwindow_populate_upcoming(GLOBALS->mainwindow, NULL);
655 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL));
656}
657
658
659static void ui_mainwindow_defarchive(Archive *arc)
660{
661struct hbfile_data *data;
662GtkTreeModel *model;
663
664 data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
665
666 // upcoming list have direct pointer to the arc (which may have changed)
667 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc));
668 gtk_list_store_clear (GTK_LIST_STORE(model));
669
670 ui_arc_manage_dialog(arc);
671
672 ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL);
673
674 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
675}
676
677
678static void ui_mainwindow_action_defarchive(void)
679{
680 ui_mainwindow_defarchive(NULL);
681}
682
683
684static void ui_mainwindow_action_defbudget(void)
685{
686 ui_bud_manage_dialog();
687 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
688}
689
690static void ui_mainwindow_action_defbudget_tabview(void)
691{
692 ui_bud_tabview_manage_dialog();
693 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
694}
695
696
697static void ui_mainwindow_action_defassign(void)
698{
699
700 ui_asg_manage_dialog();
701
702 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE));
703}
704
705
706static void ui_mainwindow_action_preferences(void)
707{
708struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
709
710 defpref_dialog_new();
711 if(!PREFS->euro_active)
712 {
713 GtkToggleAction *action = (GtkToggleAction *)gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/AsMinor");
714
715 gtk_toggle_action_set_active(action, FALSE);
716 ui_mainwindow_action_toggle_minor(action);
717 }
718 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL+UF_REFRESHALL));
719}
720
721/* display action */
722
723static void ui_mainwindow_action_toggle_toolbar(GtkToggleAction *action)
724{
725//struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
726
727 PREFS->wal_toolbar = gtk_toggle_action_get_active(action);
728 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL));
729}
730
731static void ui_mainwindow_action_toggle_upcoming(GtkToggleAction *action)
732{
733//struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
734
735 PREFS->wal_upcoming = gtk_toggle_action_get_active(action);
736 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL));
737}
738
739static void ui_mainwindow_action_toggle_topspending(GtkToggleAction *action)
740{
741//struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
742
743 PREFS->wal_spending = gtk_toggle_action_get_active(action);
744 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL));
745}
746
747static void ui_mainwindow_action_toggle_minor(GtkToggleAction *action)
748{
749struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
750
751 GLOBALS->minor = gtk_toggle_action_get_active(action);
752
753 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_acc));
754 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_upc));
755
756 // top spending
757 gtk_chart_show_minor(GTK_CHART(data->RE_pie), GLOBALS->minor);
758
759 ui_panel_topspending_update(data->window, data);
760
761}
762
763static void ui_mainwindow_action_showtransactions(void)
764{
765struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
766GtkWidget *window;
767
768 //todo:change this
769 if( data->acc )
770 {
771 if( data->acc->window == NULL )
772 {
773 window = register_panel_window_new(data->acc);
774 register_panel_window_init(window, NULL);
775 }
776 else
777 {
778 if(GTK_IS_WINDOW(data->acc->window))
779 gtk_window_present(GTK_WINDOW(data->acc->window));
780
781 }
782 }
783}
784
785
786static void ui_mainwindow_action_showalltransactions(void)
787{
788GtkWidget *window;
789
790 if( GLOBALS->alltxnwindow == NULL )
791 {
792 window = register_panel_window_new(NULL);
793 register_panel_window_init(window, NULL);
794 }
795 else
796 {
797 if(GTK_IS_WINDOW(GLOBALS->alltxnwindow))
798 gtk_window_present(GTK_WINDOW(GLOBALS->alltxnwindow));
799 }
800
801}
802
803
804static void ui_mainwindow_action_addtransactions(void)
805{
806 ui_mainwindow_addtransactions(GLOBALS->mainwindow, NULL);
807}
808
809static void ui_mainwindow_action_checkscheduled(void)
810{
811 ui_mainwindow_scheduled_postall(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE));
812}
813
814static void ui_mainwindow_action_statistic(void)
815{
816 ui_repdist_window_new();
817}
818
819static void ui_mainwindow_action_trendtime(void)
820{
821struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
822
823 ui_reptime_window_new(data->acc != NULL ? data->acc->key : 0);
824}
825
826static void ui_mainwindow_action_budget(void)
827{
828 repbudget_window_new();
829}
830
831static void ui_mainwindow_action_balance(void)
832{
833struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data");
834
835 repbalance_window_new(data->acc != NULL ? data->acc->key : 0);
836}
837
838static void ui_mainwindow_action_vehiclecost(void)
839{
840 repcost_window_new();
841}
842
843static void ui_mainwindow_action_import(GtkAction *action)
844{
845/*const gchar *name;
846gint filetype = FILETYPE_UNKNOWN;
847
848 name = gtk_action_get_name(action);
849
850 if( g_str_has_suffix (name, "QIF"))
851 filetype= FILETYPE_QIF;
852 else
853 if( g_str_has_suffix (name, "OFX"))
854 filetype= FILETYPE_OFX;
855 else
856 if( g_str_has_suffix (name, "CSV"))
857 filetype= FILETYPE_CSV_HB;*/
858
859 //DB( g_print("action %s type=%d\n", name, filetype) );
860
861 ui_import_assistant_new(NULL);
862
863}
864
865
866static void ui_mainwindow_action_about(void)
867{
868 hbfile_about();
869
870
871}
872
873
874static void ui_mainwindow_action_export(void)
875{
876gchar *filename;
877
878 if( ui_file_chooser_qif(NULL, &filename) == TRUE )
879 {
880 hb_export_qif_account_all(filename);
881 g_free( filename );
882 }
883}
884
885
886static void ui_mainwindow_action_help(void)
887{
888gchar *link;
889
890 link = g_build_filename("file:///", homebank_app_get_help_dir(), HOMEBANK_URL_HELP, NULL );
891 homebank_util_url_show (link);
892 g_free(link);
893}
894
895
896static void ui_mainwindow_action_help_releasenotes(void)
897{
898gchar *link;
899
900 #ifdef G_OS_WIN32
901 link = g_build_filename("file:///", homebank_app_get_datas_dir(), "ChangeLog.txt", NULL );
902 #else
903 link = g_build_filename("file:///", homebank_app_get_datas_dir(), "ChangeLog", NULL );
904 #endif
905 homebank_util_url_show (link);
906 g_free(link);
907}
908
909
910//todo: move this to a ui-assist-welcome.c
911
912static void ui_mainwindow_action_help_welcome1 (GtkButton *button, gpointer user_data)
913{
914 gtk_dialog_response (GTK_DIALOG(user_data), 1);
915}
916
917static void ui_mainwindow_action_help_welcome2 (GtkButton *button, gpointer user_data)
918{
919 gtk_dialog_response (GTK_DIALOG(user_data), 2);
920}
921
922static void ui_mainwindow_action_help_welcome3 (GtkButton *button, gpointer user_data)
923{
924 gtk_dialog_response (GTK_DIALOG(user_data), 3);
925}
926
927static void ui_mainwindow_action_help_welcome4 (GtkButton *button, gpointer user_data)
928{
929 gtk_dialog_response (GTK_DIALOG(user_data), 4);
930}
931
932static void ui_mainwindow_action_help_welcome5 (GtkButton *button, gpointer user_data)
933{
934 gtk_dialog_response (GTK_DIALOG(user_data), 5);
935}
936
937void ui_mainwindow_action_help_welcome(void)
938{
939GtkWidget *dialog, *content_area;
940GtkWidget *mainvbox, *widget, *label;
941
942 dialog = gtk_dialog_new_with_buttons (_("Welcome to HomeBank"),
943 GTK_WINDOW(GLOBALS->mainwindow),
944 0,
945 _("_Close"),
946 GTK_RESPONSE_ACCEPT,
947 NULL);
948
949 content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog));
950
951 mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
952 gtk_box_pack_start (GTK_BOX (content_area), mainvbox, FALSE, FALSE, 0);
953 gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM);
954
955 label = make_label (_("HomeBank"), 0, 0);
956 gimp_label_set_attributes(GTK_LABEL(label), PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1);
957 gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0);
958
959 label = make_label (_("Free, easy, personal accounting for everyone"), 0, 0);
960 gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0);
961
962 widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
963 gtk_box_pack_start (GTK_BOX (content_area), widget, FALSE, FALSE, 0);
964
965 mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_MEDIUM);
966 gtk_box_pack_start (GTK_BOX (content_area), mainvbox, TRUE, TRUE, 0);
967 gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM);
968
969 label = make_label (_("What do you want to do:"), 0, 0);
970 gimp_label_set_attributes(GTK_LABEL(label), PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1);
971 gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0);
972
973 widget = gtk_button_new_with_mnemonic(_("Read HomeBank _Manual"));
974 gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0);
975 g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome1), dialog);
976
977 widget = gtk_button_new_with_mnemonic(_("Configure _preferences"));
978 gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0);
979 g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome2), dialog);
980
981 widget = gtk_button_new_with_mnemonic(_("Create a _new file"));
982 gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0);
983 g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome3), dialog);
984
985 widget = gtk_button_new_with_mnemonic(_("_Open an existing file"));
986 gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0);
987 g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome4), dialog);
988
989 widget = gtk_button_new_with_mnemonic(_("Open the _example file"));
990 gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0);
991 g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome5), dialog);
992
993 //connect all our signals
994 g_signal_connect (dialog, "destroy", G_CALLBACK (gtk_widget_destroyed), &dialog);
995
996 gtk_widget_show_all (dialog);
997
998 //wait for the user
999 gint result = gtk_dialog_run (GTK_DIALOG (dialog));
1000
1001 // cleanup and destroy
1002 gtk_widget_destroy (dialog);
1003
1004 // do appropriate action
1005 switch(result)
1006 {
1007 case 1:
1008 ui_mainwindow_action_help();
1009 break;
1010 case 2:
1011 ui_mainwindow_action_preferences();
1012 break;
1013 case 3:
1014 ui_mainwindow_action_new();
1015 break;
1016 case 4:
1017 ui_mainwindow_action_open();
1018 break;
1019 case 5:
1020 hbfile_change_filepath(g_build_filename(homebank_app_get_datas_dir(), "example.xhb", NULL));
1021 ui_mainwindow_open_internal(GLOBALS->mainwindow, NULL);
1022 break;
1023 }
1024
1025}
1026
1027
1028static void ui_mainwindow_action_help_updates(void)
1029{
1030const gchar *link = HOMEBANK_URL_HELP_UPDATES;
1031
1032 homebank_util_url_show (link);
1033}
1034
1035
1036static void ui_mainwindow_action_help_online(void)
1037{
1038const gchar *link = HOMEBANK_URL_HELP_ONLINE;
1039
1040 homebank_util_url_show (link);
1041}
1042
1043
1044static void ui_mainwindow_action_help_translate(void)
1045{
1046const gchar *link = HOMEBANK_URL_HELP_TRANSLATE;
1047
1048 homebank_util_url_show (link);
1049}
1050
1051
1052static void ui_mainwindow_action_help_problem(void)
1053{
1054const gchar *link = HOMEBANK_URL_HELP_PROBLEM;
1055
1056 homebank_util_url_show (link);
1057}
1058
1059
1060/* hbfile functions -------------------- */
1061
1062
1063/*
1064**
1065*/
1066static void ui_mainwindow_selection(GtkTreeSelection *treeselection, gpointer user_data)
1067{
1068 ui_mainwindow_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE));
1069}
1070
1071
1072static void ui_mainwindow_close_openbooks(void)
1073{
1074GList *lacc, *elt;
1075
1076 DB( g_print("\n[ui-mainwindow] close openbooks\n") );
1077
1078 lacc = elt = g_hash_table_get_values(GLOBALS->h_acc);
1079 while (elt != NULL)
1080 {
1081 Account *item = elt->data;
1082
1083 if(item->window)
1084 {
1085 gtk_widget_destroy(GTK_WIDGET(item->window));
1086 item->window = NULL;
1087 }
1088
1089 elt = g_list_next(elt);
1090 }
1091 g_list_free(lacc);
1092
1093}
1094
1095
1096
1097/*
1098**
1099*/
1100void ui_mainwindow_clear(GtkWidget *widget, gpointer user_data)
1101{
1102struct hbfile_data *data;
1103gboolean file_clear = GPOINTER_TO_INT(user_data);
1104
1105 DB( g_print("\n[ui-mainwindow] clear\n") );
1106
1107 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1108
1109 // Close opened account window
1110 // Clear TreeView
1111 ui_mainwindow_close_openbooks();
1112 gtk_tree_store_clear(GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc))));
1113 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc))));
1114 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top))));
1115
1116 data->showall = FALSE;
1117 ui_panel_accounts_setup(data);
1118
1119 hbfile_cleanup(file_clear);
1120 hbfile_setup(file_clear);
1121
1122}
1123
1124
1125/*
1126** add some transactions directly
1127*/
1128void ui_mainwindow_addtransactions(GtkWidget *widget, gpointer user_data)
1129{
1130struct hbfile_data *data;
1131GtkWidget *window;
1132gint result = 1;
1133guint32 date;
1134gint account, count;
1135
1136 DB( g_print("\n[ui-mainwindow] add transactions\n") );
1137
1138 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1139
1140 /* init the transaction */
1141 date = homebank_app_date_get_julian();
1142
1143 //#1656531
1144 account = 0;
1145 if(data->acc != NULL)
1146 account = data->acc->key;
1147
1148 window = create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, FALSE, account);
1149 count = 0;
1150 while(result == HB_RESPONSE_ADD || result == HB_RESPONSE_ADDKEEP)
1151 {
1152 Transaction *ope;
1153
1154 /* fill in the transaction */
1155 if( result == HB_RESPONSE_ADD )
1156 {
1157 ope = da_transaction_malloc();
1158 ope->date = date;
1159 ope->kacc = account;
1160
1161 if( PREFS->heritdate == FALSE ) //fix: 318733
1162 ope->date = GLOBALS->today;
1163
1164 da_transaction_set_default_template(ope);
1165 }
1166
1167 // normally we can't be in addkeep without initialized ope with add
1168
1169 deftransaction_set_transaction(window, ope);
1170
1171 result = gtk_dialog_run (GTK_DIALOG (window));
1172
1173 DB( g_print(" - dialog result is %d\n", result) );
1174
1175 if(result == HB_RESPONSE_ADD || result == HB_RESPONSE_ADDKEEP || result == GTK_RESPONSE_ACCEPT)
1176 {
1177 deftransaction_get(window, NULL);
1178 transaction_add(GTK_WINDOW(GLOBALS->mainwindow), ope);
1179
1180 DB( g_print(" - added 1 transaction to %d\n", ope->kacc) );
1181
1182 ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
1183
1184 count++;
1185 //todo: still usefull ? store last date
1186 date = ope->date;
1187 }
1188
1189 if( result == HB_RESPONSE_ADD )
1190 {
1191 da_transaction_free(ope);
1192 ope = NULL;
1193 }
1194
1195 }
1196
1197
1198 deftransaction_dispose(window, NULL);
1199 gtk_widget_destroy (window);
1200
1201 /* todo optimize this */
1202 if(count > 0)
1203 {
1204 GLOBALS->changes_count += count;
1205 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_REFRESHALL));
1206 }
1207}
1208
1209struct tmptop
1210{
1211 guint32 key;
1212 gdouble value;
1213};
1214
1215
1216#define MAX_TOPSPENDING 10
1217
1218
1219static gint tmptop_compare_func(struct tmptop *tt1, struct tmptop *tt2)
1220{
1221 return tt1->value > tt2->value ? 1 : -1;
1222}
1223
1224
1225static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data)
1226{
1227struct hbfile_data *data;
1228GtkTreeModel *model;
1229gchar *title;
1230gchar strbuffer[G_ASCII_DTOSTR_BUF_SIZE];
1231
1232 DB( g_print("\n[ui-mainwindow] topspending_update\n") );
1233
1234 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1235
1236 hb_strfmon(strbuffer, G_ASCII_DTOSTR_BUF_SIZE-1, data->toptotal, GLOBALS->kcur, GLOBALS->minor);
1237 //hb_label_set_amount(GTK_LABEL(data->TX_topamount), total, GLOBALS->kcur, GLOBALS->minor);
1238 title = g_strdup_printf("%s %s", _("Top spending"), strbuffer);
1239
1240 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top));
1241
1242 gtk_chart_set_color_scheme(GTK_CHART(data->RE_pie), PREFS->report_color_scheme);
1243 gtk_chart_set_currency(GTK_CHART(data->RE_pie), GLOBALS->kcur);
1244 gtk_chart_set_datas(GTK_CHART(data->RE_pie), model, LST_TOPSPEND_AMOUNT, title, NULL);
1245
1246 g_free(title);
1247
1248 //future usage
1249 gchar *fu = _("Top %d spending"); title = fu;
1250}
1251
1252
1253static void ui_mainwindow_populate_topspending(GtkWidget *widget, gpointer user_data)
1254{
1255struct hbfile_data *data;
1256GtkTreeModel *model;
1257GtkTreeIter iter;
1258GList *list;
1259gint type, range;
1260guint n_result, i, n_items;
1261GArray *garray;
1262gdouble total, other;
1263Account *acc;
1264
1265
1266 DB( g_print("\n[ui-mainwindow] populate_topspending\n") );
1267
1268 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1269
1270 type = radio_get_active(GTK_CONTAINER(data->RA_type));
1271 range = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_range));
1272
1273 DB( g_print(" - type=%d, range=%d\n", type, range) );
1274 DB( g_print(" - pref range=%d\n", PREFS->date_range_wal) );
1275
1276 if(range == FLT_RANGE_OTHER)
1277 return;
1278
1279 filter_preset_daterange_set(data->filter, range, 0);
1280
1281
1282 n_result = da_cat_get_max_key() + 1;
1283 total = 0.0;
1284
1285 DB( g_print(" - max key is %d\n", n_result) );
1286
1287 /* allocate some memory */
1288 garray = g_array_sized_new(FALSE, FALSE, sizeof(struct tmptop), n_result);
1289
1290 if(garray)
1291 {
1292 struct tmptop zero = { .key=0, .value=0.0 };
1293 GQueue *txn_queue;
1294
1295 //DB( g_print(" - array length=%d\n", garray->len) );
1296
1297 for(i=0 ; i<n_result ; i++)
1298 {
1299 g_array_append_vals(garray, &zero, 1);
1300 //g_array_insert_vals(garray, i, &zero, 1);
1301
1302 //struct tmptop *tt = &g_array_index (garray, struct tmptop, i);
1303 //DB( g_print("%4d, %4d %f\n", i, tt->key, tt->value) );
1304 }
1305
1306 //DB( g_print("\n - end array length=%d\n", garray->len) );
1307
1308 //todo: not ideal, has ot force to get_acc for each txn below
1309 txn_queue = hbfile_transaction_get_partial(data->filter->mindate, data->filter->maxdate);
1310
1311 /* compute the results */
1312 list = g_queue_peek_head_link(txn_queue);
1313 while (list != NULL)
1314 {
1315 Transaction *ope = list->data;
1316
1317 //DB( g_print(" - eval txn: '%s', cat=%d ==> flt-test=%d\n", ope->memo, ope->kcat, filter_test(data->filter, ope)) );
1318
1319 if( !(ope->paymode == PAYMODE_INTXFER) )
1320 {
1321 guint32 pos = 0;
1322 gdouble trn_amount;
1323
1324 //todo: optimize here
1325 trn_amount = ope->amount;
1326 acc = da_acc_get(ope->kacc);
1327 if(acc)
1328 trn_amount = hb_amount_base(ope->amount, acc->kcur);
1329
1330 if( ope->flags & OF_SPLIT )
1331 {
1332 guint nbsplit = da_splits_length(ope->splits);
1333 Split *split;
1334 struct tmptop *item;
1335
1336 for(i=0;i<nbsplit;i++)
1337 {
1338 split = da_splits_get(ope->splits, i);
1339 pos = category_report_id(split->kcat, type);
1340 if( pos <= garray->len )
1341 {
1342 trn_amount = hb_amount_base(split->amount, acc->kcur);
1343 //trn_amount = split->amount;
1344 //#1297054 if( trn_amount < 0 ) {
1345 item = &g_array_index (garray, struct tmptop, pos);
1346 item->key = pos;
1347 item->value += trn_amount;
1348 //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos) );
1349 //}
1350 }
1351 }
1352 }
1353 else
1354 {
1355 struct tmptop *item;
1356
1357 pos = category_report_id(ope->kcat, type);
1358 if( pos <= garray->len )
1359 {
1360 //#1297054 if( trn_amount < 0 ) {
1361 item = &g_array_index (garray, struct tmptop, pos);
1362 item->key = pos;
1363 item->value += trn_amount;
1364 //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos) );
1365 //}
1366 }
1367 }
1368
1369 }
1370
1371 list = g_list_next(list);
1372 }
1373
1374 g_queue_free (txn_queue);
1375
1376 // we need to sort this and limit before
1377 g_array_sort(garray, (GCompareFunc)tmptop_compare_func);
1378
1379 n_items = MIN(garray->len,MAX_TOPSPENDING);
1380 other = 0;
1381 for(i=0 ; i<garray->len ; i++)
1382 {
1383 struct tmptop *item;
1384
1385 item = &g_array_index (garray, struct tmptop, i);
1386 if(item->value < 0)
1387 {
1388 total += item->value;
1389
1390 if(i >= n_items)
1391 other += item->value;
1392
1393 DB( g_print(" - %d : k='%d' v='%f' t='%f'\n", i, item->key, item->value, total) );
1394
1395 }
1396 }
1397
1398 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top));
1399 gtk_list_store_clear (GTK_LIST_STORE(model));
1400 g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */
1401 gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_top), NULL); /* Detach model from view */
1402
1403 /* insert into the treeview */
1404 for(i=0 ; i<MIN(garray->len,MAX_TOPSPENDING) ; i++)
1405 {
1406 gchar *name;
1407 Category *entry;
1408 struct tmptop *item;
1409 gdouble value;
1410
1411 item = &g_array_index (garray, struct tmptop, i);
1412
1413 if(!item->value) continue;
1414 //#1767659 top spending should restrict to... spending
1415 if(item->value < 0)
1416 {
1417 value = hb_amount_round(item->value, 2);
1418 entry = da_cat_get(item->key);
1419 if(entry == NULL) continue;
1420
1421 name = entry->key == 0 ? _("(no category)") : entry->fullname;
1422
1423 // append test
1424 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
1425 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
1426 LST_TOPSPEND_ID, i,
1427 LST_TOPSPEND_KEY, 0,
1428 LST_TOPSPEND_NAME, name,
1429 LST_TOPSPEND_AMOUNT, value,
1430 //LST_TOPSPEND_RATE, (gint)(((ABS(value)*100)/ABS(total)) + 0.5),
1431 -1);
1432 }
1433 }
1434
1435 // append test
1436 if(ABS(other) > 0)
1437 {
1438 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
1439 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
1440 LST_TOPSPEND_ID, n_items,
1441 LST_TOPSPEND_KEY, 0,
1442 LST_TOPSPEND_NAME, _("Other"),
1443 LST_TOPSPEND_AMOUNT, other,
1444 //LST_TOPSPEND_RATE, (gint)(((ABS(other)*100)/ABS(total)) + 0.5),
1445 -1);
1446 }
1447
1448 /* Re-attach model to view */
1449 gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_top), model);
1450 g_object_unref(model);
1451
1452
1453 // update chart and widgets
1454 {
1455 gchar *daterange;
1456
1457 data->toptotal = total;
1458 ui_panel_topspending_update(widget, data);
1459
1460 daterange = filter_daterange_text_get(data->filter);
1461 gtk_widget_set_tooltip_markup(GTK_WIDGET(data->CY_range), daterange);
1462 g_free(daterange);
1463 }
1464 }
1465
1466 /* free our memory */
1467 g_array_free (garray, TRUE);
1468
1469}
1470
1471
1472/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1473/* scheduled */
1474/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
1475static Archive *
1476ui_mainwindow_scheduled_get_selected_item(GtkTreeView *treeview)
1477{
1478GtkTreeSelection *treeselection;
1479GtkTreeModel *model;
1480GtkTreeIter iter;
1481
1482 treeselection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
1483 if( gtk_tree_selection_get_selected(treeselection, &model, &iter) )
1484 {
1485 Archive *arc;
1486
1487 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPUPC_DATAS, &arc, -1);
1488 return arc;
1489 }
1490
1491 return NULL;
1492}
1493
1494
1495static void ui_mainwindow_scheduled_onRowActivated (GtkTreeView *treeview,
1496 GtkTreePath *path,
1497 GtkTreeViewColumn *col,
1498 gpointer userdata)
1499{
1500//struct hbfile_data *data;
1501Archive *arc;
1502
1503 DB( g_print ("\n[ui-mainwindow] A scheduled row has been double-clicked!\n") );
1504
1505 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(treeview, GTK_TYPE_WINDOW)), "inst_data");
1506
1507 arc = ui_mainwindow_scheduled_get_selected_item(treeview);
1508 ui_mainwindow_defarchive(arc);
1509}
1510
1511
1512static void ui_mainwindow_scheduled_do_post(Archive *arc, gboolean doedit, gpointer user_data)
1513{
1514struct hbfile_data *data = user_data;
1515GtkWidget *window;
1516gint result;
1517Transaction *txn;
1518
1519 window = create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, TRUE, 0);
1520
1521 /* fill in the transaction */
1522 txn = da_transaction_malloc();
1523 da_transaction_init_from_template(txn, arc);
1524 txn->date = scheduled_get_postdate(arc, arc->nextdate);
1525
1526 deftransaction_set_transaction(window, txn);
1527
1528 result = gtk_dialog_run (GTK_DIALOG (window));
1529
1530 DB( g_print(" - dialog result is %d\n", result) );
1531
1532 if(result == HB_RESPONSE_ADD || result == GTK_RESPONSE_ACCEPT)
1533 {
1534 deftransaction_get(window, NULL);
1535 transaction_add(GTK_WINDOW(GLOBALS->mainwindow), txn);
1536 GLOBALS->changes_count++;
1537
1538 scheduled_date_advance(arc);
1539
1540 DB( g_print(" - added 1 transaction to %d\n", txn->kacc) );
1541 }
1542
1543 da_transaction_free(txn);
1544
1545 deftransaction_dispose(window, NULL);
1546 gtk_widget_destroy (window);
1547
1548}
1549
1550
1551static void ui_mainwindow_scheduled_editpost_cb(GtkWidget *widget, gpointer user_data)
1552{
1553struct hbfile_data *data = user_data;
1554
1555 Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc));
1556
1557 if( (arc != NULL) )
1558 {
1559 ui_mainwindow_scheduled_do_post(arc, TRUE, data);
1560 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL));
1561 }
1562}
1563
1564
1565static void ui_mainwindow_scheduled_post_cb(GtkWidget *widget, gpointer user_data)
1566{
1567struct hbfile_data *data = user_data;
1568
1569 DB( g_print("\n[ui-mainwindow] scheduled post\n") );
1570
1571 Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc));
1572
1573 if( (arc != NULL) )
1574 {
1575 if( scheduled_is_postable(arc) )
1576 {
1577 Transaction *txn = da_transaction_malloc ();
1578
1579 da_transaction_init_from_template(txn, arc);
1580 txn->date = scheduled_get_postdate(arc, arc->nextdate);
1581 transaction_add(GTK_WINDOW(GLOBALS->mainwindow), txn);
1582
1583 GLOBALS->changes_count++;
1584 scheduled_date_advance(arc);
1585
1586 da_transaction_free (txn);
1587 }
1588 else
1589 {
1590 ui_mainwindow_scheduled_do_post(arc, FALSE, data);
1591 }
1592
1593 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL));
1594 }
1595}
1596
1597
1598static void ui_mainwindow_scheduled_skip_cb(GtkWidget *widget, gpointer user_data)
1599{
1600struct hbfile_data *data = user_data;
1601
1602 Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc));
1603 if( (arc != NULL) && (arc->flags & OF_AUTO) )
1604 {
1605 GLOBALS->changes_count++;
1606 scheduled_date_advance(arc);
1607
1608 ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL);
1609 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE));
1610 }
1611}
1612
1613
1614
1615static void ui_mainwindow_scheduled_update(GtkWidget *widget, gpointer user_data)
1616{
1617struct hbfile_data *data;
1618//gint filter;
1619
1620 DB( g_print("\n[ui-mainwindow] scheduled update\n") );
1621
1622 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1623
1624 //filter = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_sched_filter));
1625
1626 Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc));
1627
1628 if(arc)
1629 {
1630 DB( g_print("archive is %s\n", arc->memo) );
1631
1632 gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), TRUE);
1633 gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), TRUE);
1634 gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), TRUE);
1635 }
1636 else
1637 {
1638 gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), FALSE);
1639 gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), FALSE);
1640 gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), FALSE);
1641 }
1642
1643}
1644
1645
1646
1647static void ui_mainwindow_scheduled_selection_cb(GtkTreeSelection *treeselection, gpointer user_data)
1648{
1649
1650
1651 ui_mainwindow_scheduled_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE));
1652}
1653
1654
1655
1656/*
1657** called after load, importamiga, on demand
1658*/
1659void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data)
1660{
1661//struct hbfile_data *data;
1662gint count;
1663gint usermode = GPOINTER_TO_INT(user_data);
1664
1665 DB( g_print("\n[ui-mainwindow] check scheduled\n") );
1666
1667 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1668
1669 count = scheduled_post_all_pending();
1670
1671 //inform the user
1672 if(usermode == TRUE)
1673 {
1674 gchar *txt;
1675
1676 //#125534
1677 if( count > 0 )
1678 {
1679 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_REFRESHALL));
1680 }
1681
1682 if(count == 0)
1683 txt = _("No transaction to add");
1684 else
1685 txt = _("transaction added: %d");
1686
1687 ui_dialog_msg_infoerror(GTK_WINDOW(GLOBALS->mainwindow), GTK_MESSAGE_INFO,
1688 _("Check scheduled transactions result"),
1689 txt,
1690 count);
1691 }
1692
1693}
1694
1695
1696static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data)
1697{
1698struct hbfile_data *data;
1699GtkTreeModel *model;
1700GtkTreeIter iter;
1701GList *list;
1702gdouble totexp = 0;
1703gdouble totinc = 0;
1704gint count = 0;
1705gchar buffer[256];
1706guint32 maxpostdate;
1707GDate *date;
1708//Account *acc;
1709
1710 DB( g_print("\n[ui-mainwindow] scheduled populate list\n") );
1711
1712 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1713
1714 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc));
1715 gtk_list_store_clear (GTK_LIST_STORE(model));
1716
1717 homebank_app_date_get_julian();
1718
1719 maxpostdate = scheduled_date_get_post_max();
1720
1721 date = g_date_new_julian (maxpostdate);
1722 g_date_strftime (buffer, 256-1, PREFS->date_format, date);
1723 g_date_free(date);
1724
1725 gtk_label_set_text(GTK_LABEL(data->LB_maxpostdate), buffer);
1726
1727
1728 list = g_list_first(GLOBALS->arc_list);
1729 while (list != NULL)
1730 {
1731 Archive *arc = list->data;
1732 Account *acc;
1733 gdouble inc, exp;
1734 guint nbdays, nblate;
1735
1736 if((arc->flags & OF_AUTO) ) //&& arc->kacc > 0)
1737 {
1738 count++;
1739 nbdays = arc->nextdate - maxpostdate;
1740 nblate = scheduled_get_latepost_count(arc, GLOBALS->today);
1741
1742 DB( g_print(" - append '%s' : %d\n", arc->memo, nbdays) );
1743
1744 if(arc->flags & OF_INCOME)
1745 {
1746 inc = arc->amount;
1747 exp = 0.0;
1748 }
1749 else
1750 {
1751 exp = arc->amount;
1752 inc = 0.0;
1753 }
1754
1755 /* insert normal txn */
1756 acc = da_acc_get(arc->kacc);
1757 if( acc)
1758 {
1759 totinc += hb_amount_base(inc, acc->kcur);
1760 totexp += hb_amount_base(exp, acc->kcur);
1761 }
1762 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
1763 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
1764 LST_DSPUPC_DATAS, arc,
1765 LST_DSPUPC_ACCOUNT, acc,
1766 LST_DSPUPC_MEMO, arc->memo,
1767 LST_DSPUPC_EXPENSE, exp,
1768 LST_DSPUPC_INCOME, inc,
1769 LST_DSPUPC_REMAINING, nbdays,
1770 LST_DSPUPC_NB_LATE, nblate,
1771 -1);
1772
1773 /* insert internal xfer txn : 1378836 */
1774 if(arc->paymode == PAYMODE_INTXFER)
1775 {
1776 acc = da_acc_get(arc->kxferacc);
1777 if( acc)
1778 {
1779 totinc += hb_amount_base(-inc, acc->kcur);
1780 totexp += hb_amount_base(-exp, acc->kcur);
1781 }
1782 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
1783 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
1784 LST_DSPUPC_DATAS, arc,
1785 LST_DSPUPC_ACCOUNT, acc,
1786 LST_DSPUPC_MEMO, arc->memo,
1787 LST_DSPUPC_EXPENSE, -inc,
1788 LST_DSPUPC_INCOME, -exp,
1789 LST_DSPUPC_REMAINING, nbdays,
1790 LST_DSPUPC_NB_LATE, nblate,
1791 -1);
1792 }
1793
1794 }
1795 list = g_list_next(list);
1796 }
1797
1798 // insert total
1799 if(count > 0 )
1800 {
1801 gtk_list_store_append (GTK_LIST_STORE(model), &iter);
1802 gtk_list_store_set (GTK_LIST_STORE(model), &iter,
1803 LST_DSPUPC_DATAS, NULL,
1804 LST_DSPUPC_ACCOUNT, NULL,
1805 LST_DSPUPC_MEMO, _("Total"),
1806 LST_DSPUPC_EXPENSE, totexp,
1807 LST_DSPUPC_INCOME, totinc,
1808 -1);
1809 }
1810
1811 ui_mainwindow_scheduled_update(widget, NULL);
1812
1813}
1814
1815
1816gboolean ui_mainwindow_open_backup_check_confirm(gchar *filepath)
1817{
1818gboolean retval = FALSE;
1819gchar *basename, *secondtext;
1820gboolean result;
1821
1822 basename = g_path_get_basename(filepath);
1823 secondtext = g_strdup_printf (
1824 _("Your are about to open the backup file '%s'.\n\nAre you sure you want to do this ?"), basename);
1825
1826 result = ui_dialog_msg_confirm_alert(
1827 GTK_WINDOW(GLOBALS->mainwindow),
1828 _("Open the backup file ?"),
1829 secondtext,
1830 _("_Open backup")
1831 );
1832
1833 g_free(secondtext);
1834 g_free(basename);
1835
1836 if( result == GTK_RESPONSE_OK )
1837 retval = TRUE;
1838
1839 return retval;
1840}
1841
1842
1843/*
1844**
1845*/
1846void ui_mainwindow_open(GtkWidget *widget, gpointer user_data)
1847{
1848//struct hbfile_data *data;
1849gboolean bakmode = GPOINTER_TO_INT(user_data);;
1850gboolean doopen = TRUE;
1851gchar *filename = NULL;
1852
1853 DB( g_print("\n[ui-mainwindow] open\n") );
1854
1855 //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1856
1857 //#1791554 do ask for save confirm
1858 if( bakmode != TRUE )
1859 doopen = ui_dialog_msg_savechanges(widget,NULL);
1860
1861 if( doopen == TRUE )
1862 {
1863 if( ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_OPEN, &filename, bakmode) == TRUE )
1864 {
1865 //#1710955 test for backup open
1866 if( hbfile_file_isbackup(filename) )
1867 {
1868 if( ui_mainwindow_open_backup_check_confirm(filename) == TRUE )
1869 {
1870 GLOBALS->hbfile_is_bak = TRUE;
1871 }
1872 else
1873 {
1874 g_free(filename);
1875 return;
1876 }
1877 }
1878
1879 hbfile_change_filepath(filename);
1880 ui_mainwindow_open_internal(widget, NULL);
1881 }
1882 }
1883}
1884
1885
1886/*
1887 * open the file stored in GLOBALS->xhb_filepath
1888 */
1889void ui_mainwindow_open_internal(GtkWidget *widget, gpointer user_data)
1890{
1891struct hbfile_data *data;
1892gint r;
1893
1894 DB( g_print("\n[ui-mainwindow] open internal\n") );
1895
1896 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1897
1898 if( GLOBALS->xhb_filepath != NULL )
1899 {
1900 DB( g_print(" - filename: '%s'\n", GLOBALS->xhb_filepath) );
1901
1902 ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE));
1903 GLOBALS->hbfile_is_new = FALSE;
1904
1905 r = homebank_load_xml(GLOBALS->xhb_filepath);
1906 if( r == XML_OK )
1907 {
1908 DB( g_print(" - file loaded ok : rcode=%d\n", r) );
1909
1910 GLOBALS->xhb_timemodified = hbfile_file_get_time_modified(GLOBALS->xhb_filepath);
1911 hbfile_file_hasrevert(GLOBALS->xhb_filepath);
1912
1913 if(PREFS->appendscheduled)
1914 scheduled_post_all_pending();
1915
1916 if(PREFS->do_update_currency)
1917 ui_cur_manage_dialog_update_currencies(GTK_WINDOW(GLOBALS->mainwindow));
1918
1919 homebank_lastopenedfiles_save();
1920
1921 //todo: delete this after computing done at xml read
1922 account_compute_balances();
1923
1924 ui_mainwindow_recent_add(data, GLOBALS->xhb_filepath);
1925 }
1926 else
1927 {
1928 gchar *msg = _("Unknown error");
1929
1930 switch(r)
1931 {
1932 case XML_IO_ERROR:
1933 msg = _("I/O error for file '%s'.");
1934 break;
1935 case XML_FILE_ERROR:
1936 msg = _("The file '%s' is not a valid HomeBank file.");
1937 break;
1938 case XML_VERSION_ERROR:
1939 msg = _("The file '%s' was saved with a higher version of HomeBank\nand cannot be loaded by the current version.");
1940 break;
1941 }
1942
1943 ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR,
1944 _("File error"),
1945 msg,
1946 GLOBALS->xhb_filepath
1947 );
1948
1949 ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE));
1950
1951 }
1952
1953 ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
1954 ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL);
1955 ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL);
1956 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL));
1957 }
1958
1959
1960}
1961
1962
1963/*
1964**
1965*/
1966void ui_mainwindow_save(GtkWidget *widget, gpointer user_data)
1967{
1968struct hbfile_data *data;
1969gboolean saveas = GPOINTER_TO_INT(user_data);
1970gchar *filename = NULL;
1971gint r = XML_UNSET;
1972
1973 DB( g_print("\n[ui-mainwindow] save\n") );
1974
1975 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
1976
1977 if( GLOBALS->hbfile_is_new == TRUE )
1978 saveas = 1;
1979
1980 //#1710955 test for backup open
1981 if( GLOBALS->hbfile_is_bak == TRUE )
1982 {
1983 //todo: later for backup, should also remove datetime and .bak
1984 hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb"));
1985 saveas = 1;
1986 }
1987
1988 if(saveas == 1)
1989 {
1990 if(ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_SAVE, &filename, FALSE) == TRUE)
1991 {
1992 DB( g_print(" + should save as '%s'\n", filename) );
1993 homebank_file_ensure_xhb(filename);
1994 homebank_backup_current_file();
1995 r = homebank_save_xml(GLOBALS->xhb_filepath);
1996 GLOBALS->hbfile_is_new = FALSE;
1997 GLOBALS->hbfile_is_bak = FALSE;
1998 }
1999 else
2000 return;
2001 }
2002 else
2003 {
2004 guint64 time_modified = hbfile_file_get_time_modified (GLOBALS->xhb_filepath);
2005 gint result = GTK_RESPONSE_OK;
2006
2007 DB( g_print(" + should quick save '%s'\n + time: open=%lu :: now=%lu\n", GLOBALS->xhb_filepath, GLOBALS->xhb_timemodified, time_modified) );
2008
2009 if( GLOBALS->xhb_timemodified != time_modified )
2010 {
2011 result = ui_dialog_msg_confirm_alert(
2012 GTK_WINDOW(GLOBALS->mainwindow),
2013 _("The file has been modified since reading it."),
2014 _("If you save it, all the external changes could be lost. Save it anyway?"),
2015 _("S_ave Anyway")
2016 );
2017
2018 if( result != GTK_RESPONSE_OK )
2019 return;
2020 }
2021
2022 DB( g_print(" + saving...\n") );
2023 homebank_file_ensure_xhb(NULL);
2024 homebank_backup_current_file();
2025 r = homebank_save_xml(GLOBALS->xhb_filepath);
2026 }
2027
2028 if(r == XML_OK)
2029 {
2030 DB( g_print(" + OK...\n") );
2031 GLOBALS->changes_count = 0;
2032 GLOBALS->xhb_timemodified = hbfile_file_get_time_modified (GLOBALS->xhb_filepath);
2033 ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL));
2034 }
2035 else
2036 {
2037 gchar *msg = _("I/O error for file '%s'.");
2038
2039 ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR,
2040 _("File error"),
2041 msg,
2042 GLOBALS->xhb_filepath
2043 );
2044 }
2045}
2046
2047
2048static void ui_panel_accounts_expand_all(GtkWidget *widget, gpointer user_data)
2049{
2050struct hbfile_data *data;
2051
2052 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
2053 gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_acc));
2054}
2055
2056
2057static void ui_panel_accounts_collapse_all(GtkWidget *widget, gpointer user_data)
2058{
2059struct hbfile_data *data;
2060
2061 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
2062 gtk_tree_view_collapse_all(GTK_TREE_VIEW(data->LV_acc));
2063}
2064
2065
2066
2067static GHashTable *ui_panel_accounts_groups_get(GList *lacc, gint groupby, gboolean showall)
2068{
2069GHashTable *hash;
2070GList *elt;
2071gchar *groupname;
2072gint nballoc;
2073
2074 DB( g_print("\n[ui-mainwindow] accounts_groups_get\n") );
2075
2076 nballoc = da_acc_length ();
2077
2078 DB( g_print(" %d accounts\n", nballoc) );
2079
2080 hash = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
2081 elt = g_list_first(lacc);
2082 while (elt != NULL)
2083 {
2084 Account *acc = elt->data;
2085 GPtrArray *group;
2086
2087 //#1674045 ony rely on nosummary
2088 //if( showall || !(acc->flags & (AF_CLOSED|AF_NOSUMMARY)) )
2089 if( showall || !(acc->flags & AF_NOSUMMARY) )
2090 {
2091 if( groupby == DSPACC_GROUP_BY_BANK )
2092 {
2093 groupname = _("(no institution)");
2094 if( (acc->bankname != NULL) && strlen(acc->bankname) > 0 )
2095 groupname = acc->bankname;
2096 }
2097 else
2098 {
2099 //pre 5.1.3 historical by type display
2100 groupname = _(CYA_ACC_TYPE[acc->type]);
2101 }
2102
2103 if( g_hash_table_contains(hash, groupname) == FALSE )
2104 {
2105 g_hash_table_insert(hash, g_strdup(groupname), g_ptr_array_sized_new(nballoc) );
2106 //DB( g_print(" - type hash insert '%s' = %d\n", groupname, inserted) );
2107 }
2108
2109 group = g_hash_table_lookup(hash, groupname);
2110 if( group != NULL )
2111 {
2112 g_ptr_array_add(group, (gpointer)acc);
2113 DB( g_print(" -- add '%s' to group '%s'\n", acc->name, groupname) );
2114 }
2115 }
2116 elt = g_list_next(elt);
2117 }
2118
2119 DB( g_print(" end\n") );
2120
2121 return hash;
2122}
2123
2124
2125
2126
2127
2128
2129void ui_mainwindow_populate_accounts(GtkWidget *widget, gpointer user_data)
2130{
2131struct hbfile_data *data;
2132GtkTreeModel *model;
2133GtkTreeIter iter1, child_iter;
2134GList *lacc, *elt;
2135Account *acc;
2136guint j, nbtype;
2137gdouble gtbank, gttoday, gtfuture;
2138
2139GHashTable *h_group;
2140GHashTableIter grp_iter;
2141gpointer key, value;
2142
2143 DB( g_print("\n[ui-mainwindow] populate accounts\n") );
2144
2145 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
2146
2147 /* here we create a count and a list of every account pointer by type */
2148 lacc = elt = g_hash_table_get_values(GLOBALS->h_acc);
2149
2150 h_group = ui_panel_accounts_groups_get(lacc, PREFS->pnl_acc_show_by, data->showall);
2151 g_list_free(lacc);
2152
2153
2154 gtbank = gttoday = gtfuture = 0;
2155
2156 DB( g_print(" - populate listview, %d group(s)\n", g_hash_table_size(h_group)) );
2157
2158 model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc));
2159 gtk_tree_store_clear (GTK_TREE_STORE(model));
2160
2161 nbtype = 0;
2162 g_hash_table_iter_init (&grp_iter, h_group);
2163 while (g_hash_table_iter_next (&grp_iter, &key, &value))
2164 {
2165 GPtrArray *gpa = value;
2166 gdouble tbank, ttoday, tfuture;
2167 gint position;
2168
2169 if(gpa != NULL)
2170 {
2171 nbtype++;
2172 //1: Header: Bank, Cash, ...
2173 DB( g_print(" - add group '%s'\n", (gchar *)key) );
2174
2175 //#1663399 keep type position like in dropdown
2176 position = 0;
2177 if( PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE )
2178 {
2179 gint t = 0;
2180
2181 while(CYA_ACC_TYPE[t] != NULL && t < 15)
2182 {
2183 if( !strcmp(CYA_ACC_TYPE[t], key) )
2184 break;
2185 t++;
2186 }
2187
2188 position = t;
2189 }
2190
2191 gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL);
2192 gtk_tree_store_set (GTK_TREE_STORE(model), &iter1,
2193 LST_DSPACC_POS, position,
2194 LST_DSPACC_DATATYPE, DSPACC_TYPE_HEADER,
2195 LST_DSPACC_NAME, key,
2196 -1);
2197
2198 tbank = ttoday = tfuture = 0;
2199
2200 //2: Accounts for real
2201 for(j=0;j<gpa->len;j++)
2202 {
2203 acc = g_ptr_array_index(gpa, j);
2204
2205 //tbank += acc->bal_bank;
2206 //ttoday += acc->bal_today;
2207 //tfuture += acc->bal_future;
2208 tbank += hb_amount_base(acc->bal_bank, acc->kcur);
2209 ttoday += hb_amount_base(acc->bal_today, acc->kcur);
2210 tfuture += hb_amount_base(acc->bal_future, acc->kcur);
2211
2212 DB( g_print(" - add account '%s' :: %.2f %.2f %.2f\n", acc->name, acc->bal_bank, acc->bal_today, acc->bal_future) );
2213
2214 gtk_tree_store_append (GTK_TREE_STORE(model), &child_iter, &iter1);
2215 gtk_tree_store_set (GTK_TREE_STORE(model), &child_iter,
2216 LST_DSPACC_DATAS, acc,
2217 LST_DSPACC_DATATYPE, DSPACC_TYPE_NORMAL,
2218 LST_DSPACC_BANK, acc->bal_bank,
2219 LST_DSPACC_TODAY, acc->bal_today,
2220 LST_DSPACC_FUTURE, acc->bal_future,
2221 -1);
2222 }
2223
2224 if(gpa->len > 1)
2225 {
2226 DB( g_print(" - group total :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) );
2227
2228 // insert the total line
2229 gtk_tree_store_append (GTK_TREE_STORE(model), &child_iter, &iter1);
2230 gtk_tree_store_set (GTK_TREE_STORE(model), &child_iter,
2231 LST_DSPACC_DATATYPE, DSPACC_TYPE_SUBTOTAL,
2232 LST_DSPACC_NAME, _("Total"),
2233 LST_DSPACC_BANK, tbank,
2234 LST_DSPACC_TODAY, ttoday,
2235 LST_DSPACC_FUTURE, tfuture,
2236 -1);
2237 }
2238
2239 /* set balance to header to display when collasped */
2240 DB( g_print(" - enrich group total header :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) );
2241 gtk_tree_store_set (GTK_TREE_STORE(model), &iter1,
2242 LST_DSPACC_BANK, tbank,
2243 LST_DSPACC_TODAY, ttoday,
2244 LST_DSPACC_FUTURE, tfuture,
2245 -1);
2246
2247 /* add to grand total */
2248 gtbank += tbank;
2249 gttoday += ttoday;
2250 gtfuture += tfuture;
2251
2252 }
2253
2254 }
2255
2256 DB( g_print(" - grand total :: %.2f %.2f %.2f\n", gtbank, gttoday, gtfuture) );
2257
2258 // Grand total
2259 if( nbtype > 1 )
2260 {
2261 gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL);
2262 gtk_tree_store_set (GTK_TREE_STORE(model), &iter1,
2263 LST_DSPACC_DATATYPE, DSPACC_TYPE_SUBTOTAL,
2264 LST_DSPACC_NAME, _("Grand total"),
2265 LST_DSPACC_BANK, gtbank,
2266 LST_DSPACC_TODAY, gttoday,
2267 LST_DSPACC_FUTURE, gtfuture,
2268 -1);
2269 }
2270
2271
2272 gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_acc));
2273
2274 DB( g_print(" - free ressources\n") );
2275
2276 g_hash_table_iter_init (&grp_iter, h_group);
2277 while (g_hash_table_iter_next (&grp_iter, &key, &value))
2278 {
2279 g_ptr_array_free (value, TRUE);
2280 }
2281 g_hash_table_destroy (h_group);
2282
2283}
2284
2285
2286void ui_mainwindow_update(GtkWidget *widget, gpointer user_data)
2287{
2288struct hbfile_data *data;
2289gint flags;
2290
2291 DB( g_print("\n[ui-mainwindow] update %p\n", user_data) );
2292
2293 data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data");
2294 //data = INST_DATA(widget);
2295
2296 flags = GPOINTER_TO_INT(user_data);
2297
2298 /* set window title */
2299 if(flags & UF_TITLE)
2300 {
2301 gchar *basename;
2302 gchar *changed;
2303
2304 DB( g_print(" 1: wintitle %p\n", data->wintitle) );
2305
2306 basename = g_path_get_basename(GLOBALS->xhb_filepath);
2307
2308 DB( g_print(" global changes: %d\n", GLOBALS->changes_count) );
2309
2310 g_free(data->wintitle);
2311
2312 changed = (GLOBALS->changes_count > 0) ? "*" : "";
2313
2314#if MYDEBUG == 1
2315 data->wintitle = g_strdup_printf("%s%s (%d)- %s - " PROGNAME, changed, basename, GLOBALS->changes_count, GLOBALS->owner);
2316#else
2317 data->wintitle = g_strdup_printf("%s%s - %s - " PROGNAME, changed, basename, GLOBALS->owner);
2318#endif
2319
2320 gtk_window_set_title (GTK_WINDOW (gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), data->wintitle);
2321
2322 g_free(basename);
2323 }
2324
2325 /* update disabled things */
2326 if(flags & UF_SENSITIVE)
2327 {
2328 GtkTreeSelection *selection;
2329 GtkTreeModel *model;
2330 GtkTreeIter iter;
2331 GtkTreePath *path;
2332 gboolean active,sensitive;
2333
2334 DB( g_print(" 2: disabled, opelist count\n") );
2335
2336 //#1656531
2337 data->acc = NULL;
2338
2339 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_acc));
2340 active = gtk_tree_selection_get_selected(selection, &model, &iter);
2341 if(active)
2342 {
2343 Account *acc;
2344 gint depth;
2345
2346 path = gtk_tree_model_get_path(model, &iter);
2347 depth = gtk_tree_path_get_depth(path);
2348
2349 if( depth > 1 )
2350 {
2351 DB( g_print(" depth is %d\n", depth) );
2352
2353 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPACC_DATAS, &acc, -1);
2354 data->acc = acc;
2355 }
2356 else
2357 active = FALSE;
2358 }
2359
2360 DB( g_print(" changes %d - new %d\n", GLOBALS->changes_count, GLOBALS->hbfile_is_new) );
2361
2362 // save
2363 sensitive = (GLOBALS->changes_count != 0 ) ? TRUE : FALSE;
2364 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Save"), sensitive);
2365
2366 // backup
2367 sensitive = ( (GLOBALS->changes_count != 0) && GLOBALS->xhb_hasrevert ) ? TRUE : FALSE;
2368 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Revert"), sensitive);
2369 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/OpenBak"), sensitive);
2370
2371 // define off ?
2372 sensitive = GLOBALS->define_off == 0 ? TRUE : FALSE;
2373 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Account"), sensitive);
2374 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Payee"), sensitive);
2375 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Category"), sensitive);
2376 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Budget"), sensitive);
2377 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/EditMenu/Preferences"), sensitive);
2378
2379 // empty account list: disable Archives, Edit, Filter, Add, Statistics, Overdrawn, Car Cost
2380 sensitive = da_acc_length() > 0 ? TRUE : FALSE;
2381 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Close"), sensitive);
2382 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Archive"), sensitive);
2383 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/AddTxn"), sensitive);
2384 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/ShowTxn"), sensitive);
2385 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RStatistics"), sensitive);
2386 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RTrendTime"), sensitive);
2387 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RBudget"), sensitive);
2388 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RBalance"), sensitive);
2389 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RVehiculeCost"), sensitive);
2390
2391 // empty category list: disable Budget
2392 sensitive = da_cat_length() > 1 ? TRUE : FALSE;
2393 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Budget"), sensitive);
2394
2395 //#1501129 no need to disable, P & C can be created from assign dialog
2396 //sensitive = ((da_cat_length() > 1) || (da_pay_length() > 1)) ? TRUE : FALSE;
2397 //gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Assign"), sensitive);
2398
2399 // empty archive list: disable scheduled check
2400 sensitive = g_list_length(GLOBALS->arc_list) > 0 ? TRUE : FALSE;
2401 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/AddScheduled"), sensitive);
2402
2403 // no active account: disable Edit, Over
2404 sensitive = (active == TRUE ) ? TRUE : FALSE;
2405 if(data->acc && data->acc->window != NULL)
2406 sensitive = FALSE;
2407 gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/ShowTxn"), sensitive);
2408 }
2409
2410 /* update toolbar, list */
2411 if(flags & UF_VISUAL)
2412 {
2413 DB( g_print(" 8: visual\n") );
2414
2415 if(PREFS->toolbar_style == 0)
2416 gtk_toolbar_unset_style(GTK_TOOLBAR(data->toolbar));
2417 else
2418 gtk_toolbar_set_style(GTK_TOOLBAR(data->toolbar), PREFS->toolbar_style-1);
2419
2420 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (data->LV_acc), PREFS->grid_lines);
2421 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_acc));
2422
2423 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (data->LV_upc), PREFS->grid_lines);
2424 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_upc));
2425
2426 DB( g_print(" - show toolbar=%d\n", PREFS->wal_toolbar) );
2427 if(PREFS->wal_toolbar)
2428 gtk_widget_show(GTK_WIDGET(data->toolbar));
2429 else
2430 gtk_widget_hide(GTK_WIDGET(data->toolbar));
2431
2432
2433 DB( g_print(" - show top_spending=%d\n", PREFS->wal_spending) );
2434
2435 gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_range), PREFS->date_range_wal);
2436
2437 if(PREFS->wal_spending)
2438 gtk_widget_show(GTK_WIDGET(data->GR_top));
2439 else
2440 gtk_widget_hide(GTK_WIDGET(data->GR_top));
2441
2442
2443
2444 DB( g_print(" - show upcoming=%d\n", PREFS->wal_upcoming) );
2445 if(PREFS->wal_upcoming)
2446 gtk_widget_show(GTK_WIDGET(data->GR_upc));
2447 else
2448 gtk_widget_hide(GTK_WIDGET(data->GR_upc));
2449
2450 DB( g_print(" minor %d\n", PREFS->euro_active) );
2451 gtk_action_set_visible(gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/AsMinor"), PREFS->euro_active);
2452 }
2453
2454 /* update balances */
2455 if(flags & UF_BALANCE)
2456 {
2457
2458 DB( g_print(" 4: balances\n") );
2459
2460 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_acc));
2461
2462 //minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor));
2463
2464 /*
2465 hb-label_set_colvalue(GTK_LABEL(data->TX_balance[0]), data->bank, minor);
2466 hb-label_set_colvalue(GTK_LABEL(data->TX_balance[1]), data->today, minor);
2467 hb-label_set_colvalue(GTK_LABEL(data->TX_balance[2]), data->future, minor);
2468 */
2469 }
2470
2471 if(flags & UF_REFRESHALL)
2472 {
2473 DB( g_print(" 16: refreshall\n") );
2474
2475 ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
2476 ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL);
2477 ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL);
2478 }
2479
2480
2481}
2482
2483
2484
2485static void
2486 ui_mainwindow_onRowActivated (GtkTreeView *treeview,
2487 GtkTreePath *path,
2488 GtkTreeViewColumn *col,
2489 gpointer userdata)
2490 {
2491 GtkTreeModel *model;
2492 GtkTreeIter iter;
2493
2494 DB( g_print ("\n[ui-mainwindow] A row has been double-clicked!\n") );
2495
2496 model = gtk_tree_view_get_model(treeview);
2497
2498 if (gtk_tree_model_get_iter(model, &iter, path))
2499 {
2500 Account *acc;
2501
2502 gtk_tree_model_get(model, &iter, LST_DSPACC_DATAS, &acc, -1);
2503
2504 if( acc != NULL )
2505 {
2506
2507 DB( g_print ("Double-clicked row contains name %s\n", acc->name) );
2508
2509 ui_mainwindow_action_showtransactions();
2510
2511 //g_free(name);
2512 }
2513 }
2514 }
2515
2516
2517static void ui_mainwindow_destroy(GtkTreeView *treeview, gpointer user_data)
2518{
2519 DB( g_print("\n[ui-mainwindow] destroy\n") );
2520
2521}
2522
2523
2524/*
2525**
2526*/
2527static gboolean ui_mainwindow_dispose(GtkWidget *widget, GdkEvent *event, gpointer user_data)
2528{
2529struct hbfile_data *data = user_data;
2530struct WinGeometry *wg;
2531gboolean retval = FALSE;
2532
2533 DB( g_print("\n[ui-mainwindow] delete-event\n") );
2534
2535 //store position and size
2536 wg = &PREFS->wal_wg;
2537 gtk_window_get_position(GTK_WINDOW(widget), &wg->l, &wg->t);
2538 gtk_window_get_size(GTK_WINDOW(widget), &wg->w, &wg->h);
2539 GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(widget));
2540 GdkWindowState state = gdk_window_get_state(gdk_window);
2541 wg->s = (state & GDK_WINDOW_STATE_MAXIMIZED) ? 1 : 0;
2542
2543 DB( g_print(" window: l=%d, t=%d, w=%d, h=%d s=%d, state=%d\n", wg->l, wg->t, wg->w, wg->h, wg->s, state & GDK_WINDOW_STATE_MAXIMIZED) );
2544
2545 PREFS->wal_vpaned = gtk_paned_get_position(GTK_PANED(data->vpaned));
2546 PREFS->wal_hpaned = gtk_paned_get_position(GTK_PANED(data->hpaned));
2547
2548 DB( g_print(" - vpaned=%d hpaned=%d\n", PREFS->wal_vpaned, PREFS->wal_hpaned) );
2549
2550 //todo
2551 if(ui_dialog_msg_savechanges(widget, NULL) == FALSE)
2552 {
2553 retval = TRUE;
2554 }
2555 else
2556 {
2557 //todo: retval is useless and below should move to destroy
2558 retval = TRUE;
2559 gtk_widget_destroy(data->LV_top);
2560
2561 g_free(data->wintitle);
2562 da_filter_free(data->filter);
2563 g_free(user_data);
2564
2565 gtk_main_quit();
2566 }
2567
2568 //TRUE:stop other handlers from being invoked for the event | FALSE: propagate
2569 return retval;
2570}
2571
2572
2573static void ui_mainwindow_recent_chooser_item_activated_cb (GtkRecentChooser *chooser, struct hbfile_data *data)
2574{
2575 gchar *uri, *path;
2576 GError *error = NULL;
2577
2578 uri = gtk_recent_chooser_get_current_uri (chooser);
2579
2580 path = g_filename_from_uri (uri, NULL, NULL);
2581 if (error)
2582 {
2583 g_warning ("Could not convert uri \"%s\" to a local path: %s", uri, error->message);
2584 g_error_free (error);
2585 return;
2586 }
2587
2588 if( ui_dialog_msg_savechanges(data->window, NULL) == TRUE )
2589 {
2590
2591 //todo: FixMe
2592 /*
2593 if (! load)
2594 {
2595 gpw_recent_remove (gpw, path);
2596 }
2597 */
2598
2599 hbfile_change_filepath(path);
2600 ui_mainwindow_open_internal(data->window, NULL);
2601 }
2602 else
2603 {
2604 g_free (path);
2605 }
2606 g_free (uri);
2607}
2608
2609
2610void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path)
2611{
2612 GtkRecentData *recent_data;
2613 gchar *uri;
2614 GError *error = NULL;
2615
2616 DB( g_print("\n[ui-mainwindow] recent_add\n") );
2617
2618 DB( g_print(" - file has .xhb suffix = %d\n", g_str_has_suffix (path, ".xhb") ) );
2619
2620 if( g_str_has_suffix (path, ".xhb") == FALSE ) //ignore reverted file
2621 return;
2622
2623 uri = g_filename_to_uri (path, NULL, &error);
2624 if (error)
2625 {
2626 g_warning ("Could not convert uri \"%s\" to a local path: %s", uri, error->message);
2627 g_error_free (error);
2628 return;
2629 }
2630
2631 recent_data = g_slice_new (GtkRecentData);
2632
2633 recent_data->display_name = NULL;
2634 recent_data->description = NULL;
2635 recent_data->mime_type = "application/x-homebank";
2636 recent_data->app_name = (gchar *) g_get_application_name ();
2637 recent_data->app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL);
2638 recent_data->groups = NULL;
2639 recent_data->is_private = FALSE;
2640
2641 if (!gtk_recent_manager_add_full (data->recent_manager,
2642 uri,
2643 recent_data))
2644 {
2645 g_warning ("Unable to add '%s' to the list of recently used documents", uri);
2646 }
2647
2648 g_free (uri);
2649 g_free (recent_data->app_exec);
2650 g_slice_free (GtkRecentData, recent_data);
2651
2652}
2653
2654
2655
2656
2657
2658enum
2659{
2660 TARGET_URI_LIST
2661};
2662
2663static GtkTargetEntry drop_types[] =
2664{
2665 {"text/uri-list", 0, TARGET_URI_LIST}
2666};
2667
2668static void ui_mainwindow_drag_data_received (GtkWidget *widget,
2669 GdkDragContext *context,
2670 gint x, gint y,
2671 GtkSelectionData *selection_data,
2672 guint info, guint time, GtkWindow *window)
2673{
2674gchar **uris, **str;
2675gchar *newseldata;
2676gint n_uris, filetype, slen;
2677GError *error = NULL;
2678
2679 if (info != TARGET_URI_LIST)
2680 return;
2681
2682 DB( g_print("\n[ui-mainwindow] drag_data_received\n") );
2683
2684 /* On MS-Windows, it looks like `selection_data->data' is not NULL terminated. */
2685 slen = gtk_selection_data_get_length(selection_data);
2686 newseldata = g_new (gchar, slen + 1);
2687 memcpy (newseldata, gtk_selection_data_get_data(selection_data), slen);
2688 newseldata[slen] = 0;
2689 //DB( g_print(" - seldata ='%s'\n", gtk_selection_data_get_data(selection_data) ) );
2690 //DB( g_print(" - newseldata ='%s'\n", newseldata ) );
2691
2692 uris = g_uri_list_extract_uris (newseldata);
2693 n_uris = g_strv_length(uris);
2694 DB( g_print(" - dragged %d files (len=%d)\n", n_uris, slen ) );
2695
2696 g_free(newseldata);
2697
2698 //single file: check for xhb
2699 if(n_uris == 1)
2700 {
2701 filetype = hb_filename_type_get_by_extension(*uris);
2702
2703 DB( g_print(" - filetype is homebank (%d)\n", filetype) );
2704
2705 if( filetype == FILETYPE_HOMEBANK )
2706 {
2707 gchar *path = g_filename_from_uri (*uris, NULL, &error);
2708
2709 if( path != NULL )
2710 {
2711 DB( g_print(" - path is '%s'\n", path) );
2712 hbfile_change_filepath(g_strdup(path));
2713 ui_mainwindow_open_internal(GTK_WIDGET(window), NULL);
2714 goto end_drop;
2715 }
2716 else
2717 {
2718 g_warning ("Could not convert uri to local path: %s", error->message);
2719 g_error_free (error);
2720 }
2721 g_free (path);
2722 }
2723 /* we no more manage error here
2724 ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_ERROR,
2725 _("File error"),
2726 _("The file %s is not a valid HomeBank file."),
2727 path);
2728 */
2729 }
2730
2731 //collect known filetype to import
2732 DB( g_print(" - collect %d files\n", n_uris) );
2733
2734 gchar **paths = g_new (gchar *, n_uris + 1);
2735 slen = 0;
2736 for (str = uris; *str; str++)
2737 {
2738 filetype = hb_filename_type_get_by_extension(*str);
2739 if( filetype != FILETYPE_HOMEBANK && filetype != FILETYPE_UNKNOWN )
2740 {
2741 gchar *path = g_filename_from_uri (*str, NULL, NULL);
2742
2743 if( path != NULL )
2744 {
2745 DB( g_print(" - append %d '%s'\n", slen, path ) );
2746 paths[slen++] = path;
2747 }
2748 }
2749 }
2750 paths[slen] = NULL;
2751
2752 if( slen > 0 )
2753 {
2754 ui_import_assistant_new( paths );
2755 }
2756
2757
2758end_drop:
2759 g_strfreev (uris);
2760}
2761
2762
2763static GtkWidget *ui_mainwindow_create_recent_chooser_menu (GtkRecentManager *manager)
2764{
2765GtkWidget *recent_menu;
2766GtkRecentFilter *filter;
2767
2768 recent_menu = gtk_recent_chooser_menu_new_for_manager (manager);
2769 gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (recent_menu), FALSE);
2770 gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (recent_menu), GTK_RECENT_SORT_MRU);
2771 //todo: add a user pref for this
2772 gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER (recent_menu), 10);
2773 gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER (recent_menu), FALSE);
2774 //gtk_recent_chooser_menu_set_show_numbers (GTK_RECENT_CHOOSER_MENU (recent_menu), TRUE);
2775
2776 filter = gtk_recent_filter_new ();
2777 //gtk_recent_filter_add_application (filter, g_get_application_name());
2778 gtk_recent_filter_add_pattern (filter, "*.[Xx][Hh][Bb]");
2779 gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (recent_menu), filter);
2780
2781 return recent_menu;
2782}
2783
2784
2785static void ui_mainwindow_create_menu_bar_and_toolbar(struct hbfile_data *data, GtkWidget *mainvbox)
2786{
2787GtkUIManager *manager;
2788GtkActionGroup *actions;
2789GtkAction *action;
2790GError *error = NULL;
2791
2792 manager = gtk_ui_manager_new ();
2793 data->manager = manager;
2794
2795 gtk_window_add_accel_group (GTK_WINDOW (data->window),
2796 gtk_ui_manager_get_accel_group(manager));
2797
2798 actions = gtk_action_group_new ("MainWindow");
2799 gtk_action_group_set_translation_domain(actions, GETTEXT_PACKAGE);
2800
2801 gtk_action_group_add_actions (actions,
2802 entries,
2803 n_entries,
2804 NULL);
2805
2806 gtk_action_group_add_toggle_actions (actions,
2807 toggle_entries,
2808 n_toggle_entries,
2809 NULL);
2810
2811 gtk_ui_manager_insert_action_group (data->manager, actions, 0);
2812 g_object_unref (actions);
2813 data->actions = actions;
2814
2815 /* set short labels to use in the toolbar */
2816 action = gtk_action_group_get_action(actions, "Open");
2817 g_object_set(action, "short_label", _("Open"), NULL);
2818
2819 //action = gtk_action_group_get_action(action_group, "Save");
2820 //g_object_set(action, "is_important", TRUE, NULL);
2821
2822 action = gtk_action_group_get_action(actions, "Account");
2823 g_object_set(action, "short_label", _("Account"), NULL);
2824
2825 action = gtk_action_group_get_action(actions, "Payee");
2826 g_object_set(action, "short_label", _("Payee"), NULL);
2827
2828 action = gtk_action_group_get_action(actions, "Category");
2829 g_object_set(action, "short_label", _("Category"), NULL);
2830
2831 action = gtk_action_group_get_action(actions, "Archive");
2832 //TRANSLATORS: an archive is stored transaction buffers (kind of bookmark to prefill manual insertion)
2833 g_object_set(action, "short_label", _("Archive"), NULL);
2834
2835 action = gtk_action_group_get_action(actions, "Budget");
2836 g_object_set(action, "short_label", _("Budget"), NULL);
2837
2838 action = gtk_action_group_get_action(actions, "ShowTxn");
2839 g_object_set(action, "short_label", _("Show"), NULL);
2840
2841 action = gtk_action_group_get_action(actions, "AddTxn");
2842 g_object_set(action, "is_important", TRUE, "short_label", _("Add"), NULL);
2843
2844 action = gtk_action_group_get_action(actions, "RStatistics");
2845 g_object_set(action, "short_label", _("Statistics"), NULL);
2846
2847 action = gtk_action_group_get_action(actions, "RBudget");
2848 g_object_set(action, "short_label", _("Budget"), NULL);
2849
2850 action = gtk_action_group_get_action(actions, "RBalance");
2851 g_object_set(action, "short_label", _("Balance"), NULL);
2852
2853 action = gtk_action_group_get_action(actions, "RVehiculeCost");
2854 g_object_set(action, "short_label", _("Vehicle cost"), NULL);
2855
2856 /* now load the UI definition */
2857 gtk_ui_manager_add_ui_from_string (data->manager, ui_info, -1, &error);
2858 if (error != NULL)
2859 {
2860 g_message ("Building menus failed: %s", error->message);
2861 g_error_free (error);
2862 }
2863
2864
2865 data->recent_manager = gtk_recent_manager_get_default ();
2866
2867 data->menubar = gtk_ui_manager_get_widget (manager, "/MenuBar");
2868 gtk_box_pack_start (GTK_BOX (mainvbox),
2869 data->menubar,
2870 FALSE,
2871 FALSE,
2872 0);
2873
2874 /* recent files menu */
2875 data->recent_menu = ui_mainwindow_create_recent_chooser_menu (data->recent_manager);
2876
2877 g_signal_connect (data->recent_menu,
2878 "item-activated",
2879 G_CALLBACK (ui_mainwindow_recent_chooser_item_activated_cb),
2880 data);
2881
2882 GtkWidget *widget = gtk_ui_manager_get_widget (data->manager, "/MenuBar/FileMenu/RecentMenu");
2883 gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), data->recent_menu);
2884
2885
2886 data->toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar");
2887 gtk_box_pack_start (GTK_BOX (mainvbox),
2888 data->toolbar,
2889 FALSE,
2890 FALSE,
2891 0);
2892
2893 /* add the custom Open button to the toolbar */
2894 GtkWidget *image = gtk_image_new_from_icon_name (ICONNAME_HB_FILE_OPEN, GTK_ICON_SIZE_BUTTON);
2895 GtkToolItem *open_button = gtk_menu_tool_button_new(image, _("_Open"));
2896 gtk_tool_item_set_tooltip_text (open_button, _("Open a file"));
2897
2898 GtkWidget *recent_menu = ui_mainwindow_create_recent_chooser_menu (data->recent_manager);
2899 gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (open_button), recent_menu);
2900 gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (open_button), _("Open a recently used file"));
2901
2902 g_signal_connect (recent_menu,
2903 "item-activated",
2904 G_CALLBACK (ui_mainwindow_recent_chooser_item_activated_cb),
2905 data);
2906
2907 action = gtk_action_group_get_action (data->actions, "Open");
2908 g_object_set (action, "short_label", _("Open"), NULL);
2909 //gtk_action_connect_proxy (action, GTK_WIDGET (open_button));
2910 gtk_activatable_set_related_action (GTK_ACTIVATABLE (open_button), action);
2911
2912 gtk_toolbar_insert (GTK_TOOLBAR (data->toolbar), open_button, 1);
2913
2914}
2915
2916
2917/* Callback function for the undo action */
2918/*static void
2919activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data)
2920{
2921 g_print ("Action %s activated\n", g_action_get_name (G_ACTION (action)));
2922}*/
2923
2924static void
2925activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data)
2926{
2927struct hbfile_data *data = user_data;
2928 GVariant *old_state, *new_state;
2929
2930 old_state = g_action_get_state (G_ACTION (action));
2931 new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state));
2932
2933 DB( g_print ("Toggle action %s activated, state changes from %d to %d\n",
2934 g_action_get_name (G_ACTION (action)),
2935 g_variant_get_boolean (old_state),
2936 g_variant_get_boolean (new_state)) );
2937
2938 data->showall = g_variant_get_boolean (new_state);
2939 ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
2940
2941 g_simple_action_set_state (action, new_state);
2942 g_variant_unref (old_state);
2943}
2944
2945static void
2946activate_radio (GSimpleAction *action, GVariant *parameter, gpointer user_data)
2947{
2948//struct hbfile_data *data = user_data;
2949GVariant *old_state, *new_state;
2950
2951 old_state = g_action_get_state (G_ACTION (action));
2952 new_state = g_variant_new_string (g_variant_get_string (parameter, NULL));
2953
2954 DB( g_print ("Radio action %s activated, state changes from %s to %s\n",
2955 g_action_get_name (G_ACTION (action)),
2956 g_variant_get_string (old_state, NULL),
2957 g_variant_get_string (new_state, NULL)) );
2958
2959 PREFS->pnl_acc_show_by = DSPACC_GROUP_BY_TYPE;
2960 if( !strcmp("bank", g_variant_get_string(new_state, NULL)) )
2961 PREFS->pnl_acc_show_by = DSPACC_GROUP_BY_BANK;
2962
2963 ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL);
2964
2965 g_simple_action_set_state (action, new_state);
2966 g_variant_unref (old_state);
2967}
2968
2969
2970static const GActionEntry actions[] = {
2971// name, function(), type, state,
2972// { "paste", activate_action, NULL, NULL, NULL, {0,0,0} },
2973 { "showall", activate_toggle, NULL, "false" , NULL, {0,0,0} },
2974 { "groupby", activate_radio , "s", "'type'", NULL, {0,0,0} }
2975};
2976
2977
2978static void ui_panel_accounts_setup(struct hbfile_data *data)
2979{
2980GAction *action;
2981GVariant *new_state;
2982
2983 if( !G_IS_SIMPLE_ACTION_GROUP(data->action_group_acc) )
2984 return;
2985
2986 action = g_action_map_lookup_action (G_ACTION_MAP (data->action_group_acc), "showall");
2987 if( action )
2988 {
2989 new_state = g_variant_new_boolean (data->showall);
2990 g_simple_action_set_state (G_SIMPLE_ACTION(action), new_state);
2991 }
2992
2993 action = g_action_map_lookup_action (G_ACTION_MAP (data->action_group_acc), "groupby");
2994 if( action )
2995 {
2996 const gchar *value = (PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE) ? "type" : "bank";
2997 new_state = g_variant_new_string (value);
2998 g_simple_action_set_state (G_SIMPLE_ACTION (action), new_state);
2999 }
3000
3001}
3002
3003
3004static GtkWidget *ui_mainwindow_create_youraccounts(struct hbfile_data *data)
3005{
3006GtkWidget *panel, *label, *widget, *sw, *tbar, *hbox, *image;
3007GtkToolItem *toolitem;
3008
3009 panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
3010 gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL);
3011
3012 sw = gtk_scrolled_window_new (NULL, NULL);
3013 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN);
3014 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3015 gtk_box_pack_start (GTK_BOX (panel), sw, TRUE, TRUE, 0);
3016 widget = (GtkWidget *)create_list_account();
3017 data->LV_acc = widget;
3018 gtk_container_add (GTK_CONTAINER (sw), widget);
3019
3020 //list toolbar
3021 tbar = gtk_toolbar_new();
3022 gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU);
3023 gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS);
3024 gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR);
3025 gtk_box_pack_start (GTK_BOX (panel), tbar, FALSE, FALSE, 0);
3026
3027 label = make_label_group(_("Your accounts"));
3028 toolitem = gtk_tool_item_new();
3029 gtk_container_add (GTK_CONTAINER(toolitem), label);
3030 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3031
3032 toolitem = gtk_separator_tool_item_new ();
3033 gtk_tool_item_set_expand (toolitem, TRUE);
3034 gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
3035 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3036
3037 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
3038 toolitem = gtk_tool_item_new();
3039 gtk_container_add (GTK_CONTAINER(toolitem), hbox);
3040 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3041
3042 widget = make_image_button(ICONNAME_HB_BUTTON_EXPAND, _("Expand all"));
3043 data->BT_expandall = widget;
3044 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
3045
3046 widget = make_image_button(ICONNAME_HB_BUTTON_COLLAPSE, _("Collapse all"));
3047 data->BT_collapseall = widget;
3048 gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
3049
3050 toolitem = gtk_separator_tool_item_new ();
3051 gtk_tool_item_set_expand (toolitem, FALSE);
3052 gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
3053 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3054
3055
3056 //gmenu test (see test folder into gtk)
3057GMenu *menu, *section;
3058
3059 menu = g_menu_new ();
3060 //g_menu_append (menumodel, "About", "actions.undo");
3061 //g_menu_append (menumodel, "Test", "actions.redo");
3062 section = g_menu_new ();
3063 g_menu_append (section, _("Show all"), "actions.showall");
3064 g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
3065 g_object_unref (section);
3066
3067 section = g_menu_new ();
3068 g_menu_append (section, _("By type"), "actions.groupby::type");
3069 g_menu_append (section, _("By institition"), "actions.groupby::bank");
3070 g_menu_append_section(menu, NULL, G_MENU_MODEL(section));
3071 g_object_unref (section);
3072
3073
3074 GSimpleActionGroup *group = g_simple_action_group_new ();
3075 data->action_group_acc = group;
3076 g_action_map_add_action_entries (G_ACTION_MAP (group), actions, G_N_ELEMENTS (actions), data);
3077
3078
3079 widget = gtk_menu_button_new();
3080 gtk_menu_button_set_direction (GTK_MENU_BUTTON(widget), GTK_ARROW_UP);
3081 gtk_widget_set_halign (widget, GTK_ALIGN_END);
3082 image = gtk_image_new_from_icon_name (ICONNAME_EMBLEM_SYSTEM, GTK_ICON_SIZE_MENU);
3083 g_object_set (widget, "image", image, NULL);
3084
3085 toolitem = gtk_tool_item_new();
3086 gtk_container_add (GTK_CONTAINER(toolitem), widget);
3087 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3088
3089 gtk_widget_insert_action_group (widget, "actions", G_ACTION_GROUP(group));
3090 gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (widget), G_MENU_MODEL (menu));
3091
3092 return panel;
3093}
3094
3095
3096static GtkWidget *ui_mainwindow_create_topspending(struct hbfile_data *data)
3097{
3098GtkWidget *panel, *hbox, *tbar;
3099GtkWidget *label, *widget;
3100GtkToolItem *toolitem;
3101
3102 widget = (GtkWidget *)create_list_topspending();
3103 data->LV_top = widget;
3104
3105 panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
3106 gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL);
3107 data->GR_top = panel;
3108
3109 /* chart + listview */
3110 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
3111 gtk_box_pack_start (GTK_BOX (panel), hbox, TRUE, TRUE, 0);
3112
3113 widget = gtk_chart_new(CHART_TYPE_PIE);
3114 data->RE_pie = widget;
3115 gtk_chart_set_minor_prefs(GTK_CHART(widget), PREFS->euro_value, PREFS->minor_cur.symbol);
3116 gtk_chart_show_legend(GTK_CHART(data->RE_pie), TRUE, TRUE);
3117 gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
3118
3119 //list toolbar
3120 tbar = gtk_toolbar_new();
3121 gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU);
3122 gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS);
3123 gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR);
3124 gtk_box_pack_start (GTK_BOX (panel), tbar, FALSE, FALSE, 0);
3125
3126 label = make_label_group(_("Where your money goes"));
3127 toolitem = gtk_tool_item_new();
3128 gtk_container_add (GTK_CONTAINER(toolitem), label);
3129 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3130
3131 toolitem = gtk_separator_tool_item_new ();
3132 gtk_tool_item_set_expand (toolitem, TRUE);
3133 gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
3134 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3135
3136 /* total + date range */
3137 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL);
3138 toolitem = gtk_tool_item_new();
3139 gtk_container_add (GTK_CONTAINER(toolitem), hbox);
3140 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3141
3142 data->CY_range = make_daterange(label, FALSE);
3143 gtk_box_pack_end (GTK_BOX (hbox), data->CY_range, FALSE, FALSE, 0);
3144
3145 widget = make_radio(CYA_CATSUBCAT, TRUE, GTK_ORIENTATION_HORIZONTAL);
3146 data->RA_type = widget;
3147 gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0);
3148
3149 return panel;
3150}
3151
3152
3153static GtkWidget *ui_mainwindow_scheduled_create(struct hbfile_data *data)
3154{
3155GtkWidget *panel, *hbox, *vbox, *bbox, *sw, *tbar;
3156GtkWidget *label, *widget;
3157GtkToolItem *toolitem;
3158
3159 panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
3160 gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL);
3161 data->GR_upc = panel;
3162
3163 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
3164 //gtk_widget_set_margin_top(GTK_WIDGET(vbox), 0);
3165 //gtk_widget_set_margin_bottom(GTK_WIDGET(vbox), SPACING_SMALL);
3166 //gtk_widget_set_margin_start(GTK_WIDGET(vbox), 2*SPACING_SMALL);
3167 //gtk_widget_set_margin_end(GTK_WIDGET(vbox), SPACING_SMALL);
3168 gtk_box_pack_start (GTK_BOX (panel), vbox, TRUE, TRUE, 0);
3169
3170 sw = gtk_scrolled_window_new (NULL, NULL);
3171 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN);
3172 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3173 gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
3174
3175 widget = (GtkWidget *)create_list_upcoming();
3176 data->LV_upc = widget;
3177 gtk_container_add (GTK_CONTAINER (sw), widget);
3178
3179 tbar = gtk_toolbar_new();
3180 gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU);
3181 gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS);
3182 gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR);
3183 gtk_box_pack_start (GTK_BOX (vbox), tbar, FALSE, FALSE, 0);
3184
3185 label = make_label_group(_("Scheduled transactions"));
3186 toolitem = gtk_tool_item_new();
3187 gtk_container_add (GTK_CONTAINER(toolitem), label);
3188 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3189
3190 toolitem = gtk_separator_tool_item_new ();
3191 gtk_tool_item_set_expand (toolitem, FALSE);
3192 gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
3193 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3194
3195
3196 bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
3197 toolitem = gtk_tool_item_new();
3198 gtk_container_add (GTK_CONTAINER(toolitem), bbox);
3199 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3200
3201 widget = gtk_button_new_with_label(_("Skip"));
3202 data->BT_sched_skip = widget;
3203 gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0);
3204
3205 widget = gtk_button_new_with_label(_("Edit & Post"));
3206 data->BT_sched_editpost = widget;
3207 gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0);
3208
3209 //TRANSLATORS: Posting a scheduled transaction is the action to materialize it into its target account.
3210 //TRANSLATORS: Before that action the automated transaction occurrence is pending and not yet really existing.
3211 widget = gtk_button_new_with_label (_("Post"));
3212 data->BT_sched_post = widget;
3213 gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0);
3214
3215 toolitem = gtk_separator_tool_item_new ();
3216 gtk_tool_item_set_expand (toolitem, FALSE);
3217 gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE);
3218 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3219
3220 hbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
3221 gtk_widget_set_valign (hbox, GTK_ALIGN_CENTER);
3222 toolitem = gtk_tool_item_new();
3223 gtk_container_add (GTK_CONTAINER(toolitem), hbox);
3224 gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1);
3225
3226 label = make_label(_("maximum post date"), 0.0, 0.7);
3227 gtk_widget_set_halign (label, GTK_ALIGN_CENTER);
3228 gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1);
3229 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
3230
3231 label = make_label(NULL, 0.0, 0.7);
3232 data->LB_maxpostdate = label;
3233 gtk_widget_set_halign (label, GTK_ALIGN_CENTER);
3234 gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1);
3235 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
3236
3237 return panel;
3238}
3239
3240
3241/*
3242** the window creation
3243*/
3244GtkWidget *create_hbfile_window(GtkWidget *do_widget)
3245{
3246struct hbfile_data *data;
3247struct WinGeometry *wg;
3248GtkWidget *mainvbox, *vbox, *vpaned, *hpaned;
3249GtkWidget *widget;
3250GtkWidget *window;
3251GtkAction *action;
3252
3253 DB( g_print("\n[ui-mainwindow] create main window\n") );
3254
3255 data = g_malloc0(sizeof(struct hbfile_data));
3256 if(!data) return NULL;
3257
3258 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3259
3260 //store our window private data
3261 g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)data);
3262 DB( g_print(" - new window=%p, inst_data=%p\n", window, data) );
3263
3264 // this is our mainwindow, so store it to GLOBALS data
3265 data->window = window;
3266 GLOBALS->mainwindow = window;
3267
3268 mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
3269 gtk_container_add (GTK_CONTAINER (window), mainvbox);
3270
3271 ui_mainwindow_create_menu_bar_and_toolbar (data, mainvbox);
3272
3273#if HB_UNSTABLE_SHOW == TRUE
3274GtkWidget *bar, *label;
3275
3276 bar = gtk_info_bar_new ();
3277 gtk_box_pack_start (GTK_BOX (mainvbox), bar, FALSE, FALSE, 0);
3278 gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_WARNING);
3279 label = make_label(NULL, 0.5, 0.5);
3280 gtk_label_set_markup (GTK_LABEL(label), "Unstable Development Version");
3281 gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label, FALSE, FALSE, 0);
3282#endif
3283
3284 /* Add the main area */
3285 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
3286 //gtk_container_set_border_width (GTK_CONTAINER(vbox), SPACING_MEDIUM);
3287 gtk_box_pack_start (GTK_BOX (mainvbox), vbox, TRUE, TRUE, 0);
3288
3289 vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
3290 data->vpaned = vpaned;
3291 gtk_box_pack_start (GTK_BOX (vbox), vpaned, TRUE, TRUE, 0);
3292
3293 hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
3294 data->hpaned = hpaned;
3295 gtk_paned_pack1 (GTK_PANED(vpaned), hpaned, FALSE, FALSE);
3296
3297 widget = ui_mainwindow_scheduled_create(data);
3298 gtk_paned_pack2 (GTK_PANED(vpaned), widget, TRUE, FALSE);
3299
3300 widget = ui_mainwindow_create_youraccounts(data);
3301 //gtk_widget_set_size_request (widget, 100, -1);
3302 gtk_paned_pack1 (GTK_PANED(hpaned), widget, FALSE, FALSE);
3303
3304 widget = ui_mainwindow_create_topspending(data);
3305 //gtk_widget_set_size_request (widget, -1, 100);
3306 gtk_paned_pack2 (GTK_PANED(hpaned), widget, TRUE, FALSE);
3307
3308
3309 //setup, init and show window
3310 wg = &PREFS->wal_wg;
3311 if(wg->s == 0)
3312 {
3313 gtk_window_move(GTK_WINDOW(window), wg->l, wg->t);
3314 gtk_window_resize(GTK_WINDOW(window), wg->w, wg->h);
3315 }
3316 else
3317 gtk_window_maximize(GTK_WINDOW(window));
3318
3319 gtk_widget_show_all (window);
3320
3321 //#1662197/1660910 moved after resize/show
3322 DB( g_print(" - vpaned=%d hpaned=%d\n", PREFS->wal_vpaned, PREFS->wal_hpaned) );
3323
3324 if(PREFS->wal_hpaned > 0)
3325 gtk_paned_set_position(GTK_PANED(data->hpaned), PREFS->wal_hpaned);
3326 if(PREFS->wal_vpaned > 0)
3327 gtk_paned_set_position(GTK_PANED(data->vpaned), PREFS->wal_vpaned);
3328
3329 //todo: move this elsewhere
3330 DB( g_print(" - setup stuff\n") );
3331
3332 data->filter = da_filter_malloc();
3333 filter_default_all_set(data->filter);
3334 gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_range), PREFS->date_range_wal);
3335
3336 action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Toolbar");
3337 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_toolbar);
3338 action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Spending");
3339 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_spending);
3340 action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Upcoming");
3341 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_upcoming);
3342
3343 /* Drag and drop support, set targets to NULL because we add the
3344 default uri_targets below */
3345
3346 /* support for opening a file by dragging onto the project window */
3347 gtk_drag_dest_set (GTK_WIDGET (window),
3348 GTK_DEST_DEFAULT_ALL,
3349 drop_types,
3350 G_N_ELEMENTS (drop_types),
3351 GDK_ACTION_COPY);
3352
3353 g_signal_connect (G_OBJECT (window), "drag-data-received",
3354 G_CALLBACK (ui_mainwindow_drag_data_received), window);
3355
3356
3357
3358 //connect all our signals
3359 DB( g_print(" - connect signals\n") );
3360
3361
3362 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_acc)), "changed", G_CALLBACK (ui_mainwindow_selection), NULL);
3363 g_signal_connect (GTK_TREE_VIEW(data->LV_acc ), "row-activated", G_CALLBACK (ui_mainwindow_onRowActivated), GINT_TO_POINTER(2));
3364 g_signal_connect (G_OBJECT (data->BT_expandall ), "clicked" , G_CALLBACK (ui_panel_accounts_expand_all), NULL);
3365 g_signal_connect (G_OBJECT (data->BT_collapseall), "clicked" , G_CALLBACK (ui_panel_accounts_collapse_all), NULL);
3366
3367 g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_upc)), "changed", G_CALLBACK (ui_mainwindow_scheduled_selection_cb), NULL);
3368 g_signal_connect (GTK_TREE_VIEW(data->LV_upc), "row-activated", G_CALLBACK (ui_mainwindow_scheduled_onRowActivated), NULL);
3369 g_signal_connect (G_OBJECT (data->BT_sched_skip), "clicked", G_CALLBACK (ui_mainwindow_scheduled_skip_cb), data);
3370 g_signal_connect (G_OBJECT (data->BT_sched_editpost), "clicked", G_CALLBACK (ui_mainwindow_scheduled_editpost_cb), data);
3371 g_signal_connect (G_OBJECT (data->BT_sched_post), "clicked", G_CALLBACK (ui_mainwindow_scheduled_post_cb), data);
3372
3373 widget = radio_get_nth_widget(GTK_CONTAINER(data->RA_type), 1);
3374 if(widget)
3375 g_signal_connect (widget, "toggled", G_CALLBACK (ui_mainwindow_populate_topspending), &data);
3376
3377 g_signal_connect (data->CY_range, "changed", G_CALLBACK (ui_mainwindow_populate_topspending), NULL);
3378
3379
3380 /* GtkWindow events */
3381 g_signal_connect (window, "delete-event", G_CALLBACK (ui_mainwindow_dispose), (gpointer)data);
3382 g_signal_connect (window, "destroy", G_CALLBACK (ui_mainwindow_destroy), NULL);
3383
3384 //gtk_action_group_set_sensitive(data->actions, FALSE);
3385
3386 return window;
3387}
3388
03389
=== added file 'src/ui-budget-tabview.c'
--- src/ui-budget-tabview.c 1970-01-01 00:00:00 +0000
+++ src/ui-budget-tabview.c 2019-09-17 21:50:17 +0000
@@ -0,0 +1,2916 @@
1/* HomeBank -- Free, easy, personal accounting for everyone.
2 * Copyright (C) 2018-2019 Adrien Dorsaz <adrien@adorsaz.ch>
3 *
4 * This file is part of HomeBank.
5 *
6 * HomeBank is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * HomeBank is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21#include "homebank.h"
22#include "hb-misc.h"
23#include "dsp_mainwindow.h"
24#include "hb-category.h"
25#include "ui-budget-tabview.h"
26
27/****************************************************************************/
28/* Implementation notes */
29/****************************************************************************/
30/*
31 * This dialog allows user to manage its budget within a GtkTreeView.
32 *
33 * The view rows are separated in three main tree roots:
34 * - Income: contains all Homebank categories of income type (see GF_INCOME)
35 * - Expense: contains all Homebank categories of expense type
36 * - Total: contains 3 sub-rows:
37 * - Income: sum all amounts of the Income root
38 * - Expense: sum all amounts of the Expense root
39 * - Summary: difference between the two above sub-rows
40 *
41 * The view columns contain:
42 * - Category: Homebank categories organised in hierarchy
43 * according to the main tree roots above and the categories hierarchy
44 *
45 * - Annual Total: sum all amounts of the year for the category
46 *
47 * - Monthly Average: average of the amounts for the category
48 *
49 * - Monthly: set the monthly amount when the Same flag is active
50 * - That column contains a toggle check box to enable or not monthly values
51 * Check it to disable the GF_CUSTOM flag of Homebank categories
52 * "Does this category has same amount planned every month ?"
53 *
54 * - 12 columns for each month of the year containing their specific amount
55 *
56 * The dialog shows 3 radio buttons on top to choose between 3 viewing modes:
57 * - Summary: show Homebank categories with budget set or set with GF_FORCED
58 * - Expense: show all available Homebank categories of expense type
59 * - Income: show all available Homebank categories of income type
60 *
61 */
62
63/****************************************************************************/
64/* Debug macros */
65/****************************************************************************/
66#define MYDEBUG 0
67
68#if MYDEBUG
69#define DB(x) (x);
70#else
71#define DB(x);
72#endif
73
74/* Global data */
75extern struct HomeBank *GLOBALS;
76extern struct Preferences *PREFS;
77
78static gchar *UI_BUD_TABVIEW_MONTHS[] = {
79 N_("Jan"), N_("Feb"), N_("Mar"),
80 N_("Apr"), N_("May"), N_("Jun"),
81 N_("Jul"), N_("Aug"), N_("Sept"),
82 N_("Oct"), N_("Nov"), N_("Dec"),
83 NULL};