Merge lp:~adorsaz/homebank/adv-budget-with-categories into lp:homebank/5.2.x
- adv-budget-with-categories
- Merge into 5.2.x
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Maxime DOYEN | ||||
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 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Maxime DOYEN | Needs Fixing | ||
Review via email: mp+362864@code.launchpad.net |
Commit message
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
Maxime DOYEN (mdoyen) wrote : | # |
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_
- dialog: top radio button should be Summary(or Synthesis)
- 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) ?
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
-
rename ui-adv-budget to ui-budget-tabview
- 106. By Adrien Dorsaz
-
replace all `adv_budget` (and similar) prefix in symbols with `bud_tabview`
- 107. By Adrien Dorsaz
-
ui-budget-tabview: by default build tabview in read-only mode
- 108. By Adrien Dorsaz
-
ui-budget-tabview: reorder and rename top radio buttons
- 109. By Adrien Dorsaz
-
ui-budget-tabview: add empty last column to follow the window expension
- 110. By Adrien Dorsaz
-
ui-budget-tabview: on model toggle, reset scroll to top and unselect rows
- 111. By Adrien Dorsaz
-
budget-tabview: center title columns and hide tree lines
That's to be coherent with others tree view style
- 112. By Adrien Dorsaz
-
budget-tabview: place total column on second position
- 113. By Adrien Dorsaz
-
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
-
ui-budget-tabview: add monthly average column
- 115. By Adrien Dorsaz
-
ui-budget-tabview: display category name with normal weight within Summary
- 116. By Adrien Dorsaz
-
ui-budget-tabview: edit mode is able to clear inputs
- 117. By Adrien Dorsaz
-
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
-
ui-budget-tabview: adjust documentation, adjust symbols with `_`
- 119. By Adrien Dorsaz
-
ui-budget-tabview: refactor merge dialog and avoid select merge source as target
- 120. By Adrien Dorsaz
-
ui-budget-tabview: refactor category_add to use the get_selected_
category - 121. By Adrien Dorsaz
-
ui-budget-tabview: hide amount if equals 0.0 (which allow to remove sensitive workaround)
- 122. By Adrien Dorsaz
-
ui-budget-tabview: use fg colors defined by user for debit/credit
- 123. By Adrien Dorsaz
-
ui-budget-tabview: monthly average uses homebank round helper
- 124. By Adrien Dorsaz
-
ui-budget-tabview: remove the useless right margin to align with the search entry above
- 125. By Adrien Dorsaz
-
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_
- 126. By Adrien Dorsaz
-
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
-
ui-budget-tabview: edit mode: add dialog show available parents according to current view mode (Summary, Expense, Income)
- 128. By Adrien Dorsaz
-
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
1 | === modified file 'src/Makefile.am' |
2 | --- src/Makefile.am 2019-04-11 20:36:11 +0000 |
3 | +++ src/Makefile.am 2019-09-17 21:50:17 +0000 |
4 | @@ -106,6 +106,8 @@ |
5 | ui-assist-start.h \ |
6 | ui-budget.c \ |
7 | ui-budget.h \ |
8 | + ui-budget-tabview.c \ |
9 | + ui-budget-tabview.h \ |
10 | ui-category.c \ |
11 | ui-category.h \ |
12 | ui-currency.c \ |
13 | |
14 | === modified file 'src/Makefile.in' |
15 | --- src/Makefile.in 2019-04-11 20:36:11 +0000 |
16 | +++ src/Makefile.in 2019-09-17 21:50:17 +0000 |
17 | @@ -119,12 +119,21 @@ |
18 | rep-vehicle.$(OBJEXT) ui-account.$(OBJEXT) \ |
19 | ui-archive.$(OBJEXT) ui-assign.$(OBJEXT) \ |
20 | ui-assist-import.$(OBJEXT) ui-assist-start.$(OBJEXT) \ |
21 | +<<<<<<< TREE |
22 | ui-budget.$(OBJEXT) ui-category.$(OBJEXT) \ |
23 | ui-currency.$(OBJEXT) ui-dialogs.$(OBJEXT) ui-filter.$(OBJEXT) \ |
24 | ui-hbfile.$(OBJEXT) ui-payee.$(OBJEXT) ui-pref.$(OBJEXT) \ |
25 | ui-split.$(OBJEXT) ui-tag.$(OBJEXT) ui-transaction.$(OBJEXT) \ |
26 | ui-txn-multi.$(OBJEXT) ui-widgets-data.$(OBJEXT) \ |
27 | ui-widgets.$(OBJEXT) |
28 | +======= |
29 | + ui-budget.$(OBJEXT) ui-budget-tabview.$(OBJEXT) \ |
30 | + ui-category.$(OBJEXT) ui-currency.$(OBJEXT) \ |
31 | + ui-dialogs.$(OBJEXT) ui-filter.$(OBJEXT) ui-hbfile.$(OBJEXT) \ |
32 | + ui-payee.$(OBJEXT) ui-pref.$(OBJEXT) ui-split.$(OBJEXT) \ |
33 | + ui-transaction.$(OBJEXT) ui-txn-multi.$(OBJEXT) \ |
34 | + ui-widgets.$(OBJEXT) |
35 | +>>>>>>> MERGE-SOURCE |
36 | homebank_OBJECTS = $(am_homebank_OBJECTS) |
37 | am__DEPENDENCIES_1 = |
38 | homebank_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) |
39 | @@ -441,6 +450,8 @@ |
40 | ui-assist-start.h \ |
41 | ui-budget.c \ |
42 | ui-budget.h \ |
43 | + ui-budget-tabview.c \ |
44 | + ui-budget-tabview.h \ |
45 | ui-category.c \ |
46 | ui-category.h \ |
47 | ui-currency.c \ |
48 | @@ -561,6 +572,7 @@ |
49 | distclean-compile: |
50 | -rm -f *.tab.c |
51 | |
52 | +<<<<<<< TREE |
53 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp-account.Po@am__quote@ # am--include-marker |
54 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp-mainwindow.Po@am__quote@ # am--include-marker |
55 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-chart-colors.Po@am__quote@ # am--include-marker |
56 | @@ -627,6 +639,64 @@ |
57 | @echo '# dummy' >$@-t && $(am__mv) $@-t $@ |
58 | |
59 | am--depfiles: $(am__depfiles_remade) |
60 | +======= |
61 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp_account.Po@am__quote@ |
62 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsp_mainwindow.Po@am__quote@ |
63 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-chart-colors.Po@am__quote@ |
64 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-chart-stack.Po@am__quote@ |
65 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-chart.Po@am__quote@ |
66 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk-dateentry.Po@am__quote@ |
67 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-account.Po@am__quote@ |
68 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-archive.Po@am__quote@ |
69 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-assign.Po@am__quote@ |
70 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-category.Po@am__quote@ |
71 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-currency.Po@am__quote@ |
72 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-encoding.Po@am__quote@ |
73 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-export.Po@am__quote@ |
74 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-filter.Po@am__quote@ |
75 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-hbfile.Po@am__quote@ |
76 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-import-csv.Po@am__quote@ |
77 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-import-ofx.Po@am__quote@ |
78 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-import-qif.Po@am__quote@ |
79 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-import.Po@am__quote@ |
80 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-misc.Po@am__quote@ |
81 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-payee.Po@am__quote@ |
82 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-preferences.Po@am__quote@ |
83 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-report.Po@am__quote@ |
84 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-split.Po@am__quote@ |
85 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-tag.Po@am__quote@ |
86 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-transaction.Po@am__quote@ |
87 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hb-xml.Po@am__quote@ |
88 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/homebank.Po@am__quote@ |
89 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/language.Po@am__quote@ |
90 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list_account.Po@am__quote@ |
91 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list_operation.Po@am__quote@ |
92 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list_topspending.Po@am__quote@ |
93 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list_upcoming.Po@am__quote@ |
94 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rep_balance.Po@am__quote@ |
95 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rep_budget.Po@am__quote@ |
96 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rep_stats.Po@am__quote@ |
97 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rep_time.Po@am__quote@ |
98 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rep_vehicle.Po@am__quote@ |
99 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-account.Po@am__quote@ |
100 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-archive.Po@am__quote@ |
101 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-assign.Po@am__quote@ |
102 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-assist-import.Po@am__quote@ |
103 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-assist-start.Po@am__quote@ |
104 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-budget-tabview.Po@am__quote@ |
105 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-budget.Po@am__quote@ |
106 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-category.Po@am__quote@ |
107 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-currency.Po@am__quote@ |
108 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-dialogs.Po@am__quote@ |
109 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-filter.Po@am__quote@ |
110 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-hbfile.Po@am__quote@ |
111 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-payee.Po@am__quote@ |
112 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-pref.Po@am__quote@ |
113 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-split.Po@am__quote@ |
114 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-transaction.Po@am__quote@ |
115 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-txn-multi.Po@am__quote@ |
116 | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ui-widgets.Po@am__quote@ |
117 | +>>>>>>> MERGE-SOURCE |
118 | |
119 | .c.o: |
120 | @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< |
121 | |
122 | === added file 'src/dsp_mainwindow.c.OTHER' |
123 | --- src/dsp_mainwindow.c.OTHER 1970-01-01 00:00:00 +0000 |
124 | +++ src/dsp_mainwindow.c.OTHER 2019-09-17 21:50:17 +0000 |
125 | @@ -0,0 +1,3388 @@ |
126 | +/* HomeBank -- Free, easy, personal accounting for everyone. |
127 | + * Copyright (C) 1995-2018 Maxime DOYEN |
128 | + * |
129 | + * This file is part of HomeBank. |
130 | + * |
131 | + * HomeBank is free software; you can redistribute it and/or modify |
132 | + * it under the terms of the GNU General Public License as published by |
133 | + * the Free Software Foundation; either version 2 of the License, or |
134 | + * (at your option) any later version. |
135 | + * |
136 | + * HomeBank is distributed in the hope that it will be useful, |
137 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
138 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
139 | + * GNU General Public License for more details. |
140 | + * |
141 | + * You should have received a copy of the GNU General Public License |
142 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
143 | + */ |
144 | + |
145 | + |
146 | +#include "homebank.h" |
147 | + |
148 | +#include "dsp_mainwindow.h" |
149 | + |
150 | +#include "list_account.h" |
151 | +#include "list_upcoming.h" |
152 | +#include "list_topspending.h" |
153 | + |
154 | +#include "dsp_account.h" |
155 | +#include "ui-assist-import.h" |
156 | +#include "ui-assist-start.h" |
157 | +#include "ui-account.h" |
158 | +#include "ui-currency.h" |
159 | +#include "ui-payee.h" |
160 | +#include "ui-category.h" |
161 | +#include "ui-archive.h" |
162 | +#include "ui-assign.h" |
163 | +#include "ui-budget.h" |
164 | +#include "ui-budget-tabview.h" |
165 | +#include "ui-pref.h" |
166 | +#include "ui-hbfile.h" |
167 | +#include "ui-transaction.h" |
168 | + |
169 | +#include "rep_balance.h" |
170 | +#include "rep_budget.h" |
171 | +#include "rep_stats.h" |
172 | +#include "rep_time.h" |
173 | +#include "rep_vehicle.h" |
174 | + |
175 | +#include "gtk-chart.h" |
176 | + |
177 | +//old url prior 2018 |
178 | +//#define HOMEBANK_URL_HELP "http://homebank.free.fr/help/" |
179 | +//#define HOMEBANK_URL_HELP_ONLINE "https://launchpad.net/homebank/+addquestion" |
180 | +//#define HOMEBANK_URL_HELP_PROBLEM "https://launchpad.net/homebank/+filebug" |
181 | +//#define HOMEBANK_URL_HELP_TRANSLATE "https://launchpad.net/homebank/+translations" |
182 | + |
183 | +#define HOMEBANK_URL_HELP "index.html" |
184 | +#define HOMEBANK_URL_HELP_ONLINE "http://homebank.free.fr/support.php" |
185 | +#define HOMEBANK_URL_HELP_UPDATES "http://homebank.free.fr/downloads.php" |
186 | +#define HOMEBANK_URL_HELP_PROBLEM "http://homebank.free.fr/development.php#bug" |
187 | +#define HOMEBANK_URL_HELP_TRANSLATE "http://homebank.free.fr/development.php#translate" |
188 | + |
189 | + |
190 | +/****************************************************************************/ |
191 | +/* Debug macros */ |
192 | +/****************************************************************************/ |
193 | +#define MYDEBUG 0 |
194 | + |
195 | +#if MYDEBUG |
196 | +#define DB(x) (x); |
197 | +#else |
198 | +#define DB(x); |
199 | +#endif |
200 | + |
201 | +/* our global datas */ |
202 | +extern struct HomeBank *GLOBALS; |
203 | +extern struct Preferences *PREFS; |
204 | +extern gchar *homebank_pixmaps_dir; |
205 | + |
206 | + |
207 | +/* our functions prototype */ |
208 | +static void ui_mainwindow_action_new(void); |
209 | +static void ui_mainwindow_action_open(void); |
210 | +static void ui_mainwindow_action_save(void); |
211 | +static void ui_mainwindow_action_saveas(void); |
212 | +static void ui_mainwindow_action_revert(void); |
213 | +static void ui_mainwindow_action_openbak(void); |
214 | +static void ui_mainwindow_action_properties(void); |
215 | +static void ui_mainwindow_action_close(void); |
216 | +static void ui_mainwindow_action_quit(void); |
217 | + |
218 | +static void ui_mainwindow_action_defcurrency(void); |
219 | +static void ui_mainwindow_action_defaccount(void); |
220 | +static void ui_mainwindow_action_defpayee(void); |
221 | +static void ui_mainwindow_action_defcategory(void); |
222 | +static void ui_mainwindow_action_defarchive(void); |
223 | +static void ui_mainwindow_action_defbudget(void); |
224 | +static void ui_mainwindow_action_defbudget_tabview(void); |
225 | +static void ui_mainwindow_action_defassign(void); |
226 | +static void ui_mainwindow_action_preferences(void); |
227 | + |
228 | +static void ui_mainwindow_action_toggle_toolbar(GtkToggleAction *action); |
229 | +static void ui_mainwindow_action_toggle_upcoming(GtkToggleAction *action); |
230 | +static void ui_mainwindow_action_toggle_topspending(GtkToggleAction *action); |
231 | +static void ui_mainwindow_action_toggle_minor(GtkToggleAction *action); |
232 | + |
233 | +static void ui_mainwindow_action_showtransactions(void); |
234 | +static void ui_mainwindow_action_showalltransactions(void); |
235 | + |
236 | +static void ui_mainwindow_action_addtransactions(void); |
237 | +static void ui_mainwindow_action_checkscheduled(void); |
238 | + |
239 | +static void ui_mainwindow_action_statistic(void); |
240 | +static void ui_mainwindow_action_trendtime(void); |
241 | +static void ui_mainwindow_action_budget(void); |
242 | +static void ui_mainwindow_action_balance(void); |
243 | +static void ui_mainwindow_action_vehiclecost(void); |
244 | + |
245 | +static void ui_mainwindow_action_import(GtkAction *action); |
246 | +static void ui_mainwindow_action_export(void); |
247 | +static void ui_mainwindow_action_anonymize(void); |
248 | +static void ui_mainwindow_action_file_statistics(void); |
249 | + |
250 | +static void ui_mainwindow_action_help(void); |
251 | +void ui_mainwindow_action_help_welcome(void); |
252 | +static void ui_mainwindow_action_help_online(void); |
253 | +static void ui_mainwindow_action_help_updates(void); |
254 | +static void ui_mainwindow_action_help_releasenotes(void); |
255 | +static void ui_mainwindow_action_help_translate(void); |
256 | +static void ui_mainwindow_action_help_problem(void); |
257 | +static void ui_mainwindow_action_about(void); |
258 | + |
259 | + |
260 | +static GtkWidget *ui_mainwindow_create_recent_chooser_menu (GtkRecentManager *manager); |
261 | + |
262 | +static void ui_mainwindow_populate_topspending(GtkWidget *widget, gpointer user_data); |
263 | + |
264 | +void ui_mainwindow_open(GtkWidget *widget, gpointer user_data); |
265 | + |
266 | +void ui_mainwindow_save(GtkWidget *widget, gpointer user_data); |
267 | +void ui_mainwindow_revert(GtkWidget *widget, gpointer user_data); |
268 | +void ui_mainwindow_action(GtkWidget *widget, gpointer user_data); |
269 | +void ui_mainwindow_toggle_minor(GtkWidget *widget, gpointer user_data); |
270 | +void ui_mainwindow_clear(GtkWidget *widget, gpointer user_data); |
271 | + |
272 | +gboolean ui_dialog_msg_savechanges(GtkWidget *widget, gpointer user_data); |
273 | + |
274 | +void ui_mainwindow_update(GtkWidget *widget, gpointer user_data); |
275 | +void ui_mainwindow_addtransactions(GtkWidget *widget, gpointer user_data); |
276 | +void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path); |
277 | + |
278 | +static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data); |
279 | + |
280 | +static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data); |
281 | +void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data); |
282 | + |
283 | +void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path); |
284 | + |
285 | +static void ui_panel_accounts_setup(struct hbfile_data *data); |
286 | + |
287 | +extern gchar *CYA_ACC_TYPE[]; |
288 | + |
289 | +gchar *CYA_CATSUBCAT[] = { |
290 | + N_("Category"), |
291 | + N_("Subcategory"), |
292 | + NULL |
293 | +}; |
294 | + |
295 | + |
296 | +static GtkActionEntry entries[] = { |
297 | + |
298 | + /* name, icon-name, label */ |
299 | + |
300 | + { "FileMenu" , NULL, N_("_File"), NULL, NULL, NULL }, |
301 | + //{ "ImportMenu" , NULL, N_("_Import"), NULL, NULL, NULL }, |
302 | + { "RecentMenu" , NULL, N_("Open _Recent"), NULL, NULL, NULL }, |
303 | + { "EditMenu" , NULL, N_("_Edit"), NULL, NULL, NULL }, |
304 | + { "ViewMenu" , NULL, N_("_View"), NULL, NULL, NULL }, |
305 | + { "ManageMenu" , NULL, N_("_Manage"), NULL, NULL, NULL }, |
306 | + { "TxnMenu" , NULL, N_("_Transactions"), NULL, NULL, NULL }, |
307 | + { "ReportMenu" , NULL, N_("_Reports"), NULL, NULL, NULL }, |
308 | + { "ToolsMenu" , NULL, N_("_Tools"), NULL, NULL, NULL }, |
309 | + { "HelpMenu" , NULL, N_("_Help"), NULL, NULL, NULL }, |
310 | + |
311 | +// { "Import" , NULL, N_("Import") }, |
312 | +// { "Export" , NULL, N_("Export to") }, |
313 | + /* name, icon-name, label, accelerator, tooltip */ |
314 | + |
315 | + /* FileMenu */ |
316 | + { "New" , ICONNAME_HB_FILE_NEW , N_("_New") , "<control>N", N_("Create a new file"), G_CALLBACK (ui_mainwindow_action_new) }, |
317 | + { "Open" , ICONNAME_HB_FILE_OPEN , N_("_Open...") , "<control>O", N_("Open a file"), G_CALLBACK (ui_mainwindow_action_open) }, |
318 | + { "Save" , ICONNAME_HB_FILE_SAVE , N_("_Save") , "<control>S", N_("Save the current file"), G_CALLBACK (ui_mainwindow_action_save) }, |
319 | + { "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) }, |
320 | + |
321 | + { "Revert" , ICONNAME_REVERT , N_("Revert") , NULL, N_("Revert to a saved version of this file"), G_CALLBACK (ui_mainwindow_action_revert) }, |
322 | + { "OpenBak" , NULL , N_("Restore backup") , NULL, N_("Restore from a backup file"), G_CALLBACK (ui_mainwindow_action_openbak) }, |
323 | + |
324 | + { "Properties" , ICONNAME_PROPERTIES , N_("Properties..."), NULL, N_("Configure the file"), G_CALLBACK (ui_mainwindow_action_properties) }, |
325 | + { "Close" , ICONNAME_CLOSE , N_("_Close") , "<control>W", N_("Close the current file"), G_CALLBACK (ui_mainwindow_action_close) }, |
326 | + { "Quit" , ICONNAME_QUIT , N_("_Quit") , "<control>Q", N_("Quit HomeBank"), G_CALLBACK (ui_mainwindow_action_quit) }, |
327 | + |
328 | + /* Exchange */ |
329 | + { "Import" , ICONNAME_HB_FILE_IMPORT , N_("Import...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, |
330 | + //{ "ImportQIF" , ICONNAME_HB_FILE_IMPORT , N_("QIF file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, |
331 | + //{ "ImportOFX" , ICONNAME_HB_FILE_IMPORT , N_("OFX/QFX file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, |
332 | + //{ "ImportCSV" , ICONNAME_HB_FILE_IMPORT , N_("CSV file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, |
333 | + |
334 | + { "ExportQIF" , ICONNAME_HB_FILE_EXPORT , N_("Export as QIF...") , NULL, N_("Export all account in a QIF file"), G_CALLBACK (ui_mainwindow_action_export) }, |
335 | + |
336 | + /* EditMenu */ |
337 | + { "Preferences", ICONNAME_PREFERENCES , N_("Preferences..."), NULL, N_("Configure HomeBank"), G_CALLBACK (ui_mainwindow_action_preferences) }, |
338 | + |
339 | + /* ManageMenu */ |
340 | + { "Currency" , ICONNAME_HB_CURRENCY , N_("Currencies...") , NULL, N_("Configure the currencies"), G_CALLBACK (ui_mainwindow_action_defcurrency) }, |
341 | + { "Account" , ICONNAME_HB_ACCOUNT , N_("Acc_ounts...") , NULL, N_("Configure the accounts"), G_CALLBACK (ui_mainwindow_action_defaccount) }, |
342 | + { "Payee" , ICONNAME_HB_PAYEE , N_("_Payees...") , NULL, N_("Configure the payees"), G_CALLBACK (ui_mainwindow_action_defpayee) }, |
343 | + { "Category" , ICONNAME_HB_CATEGORY , N_("Categories...") , NULL, N_("Configure the categories"), G_CALLBACK (ui_mainwindow_action_defcategory) }, |
344 | + { "Archive" , ICONNAME_HB_ARCHIVE , N_("Scheduled/Template...") , NULL, N_("Configure the scheduled/template transactions"), G_CALLBACK (ui_mainwindow_action_defarchive) }, |
345 | + { "Budget" , ICONNAME_HB_BUDGET , N_("Budget...") , NULL, N_("Configure the budget"), G_CALLBACK (ui_mainwindow_action_defbudget) }, |
346 | + { "BudgetTabview", ICONNAME_HB_BUDGET , N_("Budget (tab view)...") , NULL, N_("View the budget"), G_CALLBACK (ui_mainwindow_action_defbudget_tabview) }, |
347 | + { "Assign" , ICONNAME_HB_ASSIGN , N_("Assignments..."), NULL, N_("Configure the automatic assignments"), G_CALLBACK (ui_mainwindow_action_defassign) }, |
348 | + |
349 | + /* TxnMenu */ |
350 | + { "AddTxn" , ICONNAME_HB_OPE_ADD , N_("Add...") , NULL, N_("Add transactions"), G_CALLBACK (ui_mainwindow_action_addtransactions) }, |
351 | + { "ShowTxn" , ICONNAME_HB_OPE_SHOW , N_("Show...") , NULL, N_("Shows selected account transactions"), G_CALLBACK (ui_mainwindow_action_showtransactions) }, |
352 | + { "ShowAllTxn" , ICONNAME_HB_OPE_SHOW , N_("Show all...") , NULL, N_("Shows all account transactions"), G_CALLBACK (ui_mainwindow_action_showalltransactions) }, |
353 | + { "Scheduler" , NULL , N_("Set scheduler...") , NULL, N_("Configure the transaction scheduler"), G_CALLBACK (ui_mainwindow_action_properties) }, |
354 | + { "AddScheduled", NULL , N_("Post scheduled"), NULL, N_("Post pending scheduled transactions"), G_CALLBACK (ui_mainwindow_action_checkscheduled) }, |
355 | + |
356 | + /* ReportMenu */ |
357 | + { "RStatistics" , ICONNAME_HB_REP_STATS , N_("_Statistics...") , NULL, N_("Open the Statistics report"), G_CALLBACK (ui_mainwindow_action_statistic) }, |
358 | + { "RTrendTime" , ICONNAME_HB_REP_TIME , N_("_Trend Time...") , NULL, N_("Open the Trend Time report"), G_CALLBACK (ui_mainwindow_action_trendtime) }, |
359 | + { "RBudget" , ICONNAME_HB_REP_BUDGET , N_("B_udget...") , NULL, N_("Open the Budget report"), G_CALLBACK (ui_mainwindow_action_budget) }, |
360 | + { "RBalance" , ICONNAME_HB_REP_BALANCE, N_("Balance...") , NULL, N_("Open the Balance report"), G_CALLBACK (ui_mainwindow_action_balance) }, |
361 | + { "RVehiculeCost", ICONNAME_HB_REP_CAR , N_("_Vehicle cost...") , NULL, N_("Open the Vehicle cost report"), G_CALLBACK (ui_mainwindow_action_vehiclecost) }, |
362 | + |
363 | + /* Tools */ |
364 | + { "Welcome" , NULL , N_("Show welcome dialog...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_help_welcome) }, |
365 | + { "FileStats" , NULL , N_("File statistics...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_file_statistics) }, |
366 | + { "Anonymize" , NULL , N_("Anonymize...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_anonymize) }, |
367 | + |
368 | + /* HelpMenu */ |
369 | + { "Contents" , ICONNAME_HELP , N_("_Contents") , "F1", N_("Documentation about HomeBank"), G_CALLBACK (ui_mainwindow_action_help) }, |
370 | + { "Online" , "lpi-help" , N_("Get Help Online...") , NULL, N_("Connect to the LaunchPad website for online help"), G_CALLBACK (ui_mainwindow_action_help_online) }, |
371 | + |
372 | + { "Updates" , NULL , N_("Check for updates...") , NULL, N_("Visit HomeBank website to check for update"), G_CALLBACK (ui_mainwindow_action_help_updates) }, |
373 | + { "ReleaseNotes", NULL , N_("Release Notes") , NULL, N_("Display the release notes"), G_CALLBACK (ui_mainwindow_action_help_releasenotes) }, |
374 | + { "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) }, |
375 | + { "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) }, |
376 | + |
377 | + { "About" , ICONNAME_ABOUT , N_("_About") , NULL, N_("About HomeBank") ,G_CALLBACK (ui_mainwindow_action_about) }, |
378 | + |
379 | +}; |
380 | +static guint n_entries = G_N_ELEMENTS (entries); |
381 | + |
382 | + |
383 | +static GtkToggleActionEntry toggle_entries[] = { |
384 | +/* name , icon-name, label, accelerator, tooltip, callback, is_active */ |
385 | + { "Toolbar" , NULL , N_("_Toolbar") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_toggle_toolbar), TRUE }, |
386 | + { "Spending" , NULL , N_("_Top spending") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_toggle_topspending), TRUE }, |
387 | + { "Upcoming" , NULL , N_("_Scheduled list") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_toggle_upcoming), TRUE }, |
388 | + { "AsMinor" , NULL , N_("Euro minor"), "<control>M", NULL, G_CALLBACK (ui_mainwindow_action_toggle_minor), FALSE }, |
389 | +}; |
390 | + |
391 | +static guint n_toggle_entries = G_N_ELEMENTS (toggle_entries); |
392 | + |
393 | + |
394 | +static const gchar *ui_info = |
395 | +"<ui>" |
396 | + |
397 | +" <menubar name='MenuBar'>" |
398 | +" <menu action='FileMenu'>" |
399 | +" <menuitem action='New'/>" |
400 | +" <menuitem action='Open'/>" |
401 | +" <menuitem action='RecentMenu'/>" |
402 | +" <separator/>" |
403 | +" <menuitem action='Save'/>" |
404 | +" <menuitem action='SaveAs'/>" |
405 | +" <separator/>" |
406 | +" <menuitem action='Import'/>" |
407 | +/*" <menu action='ImportMenu'>" |
408 | +" <menuitem action='ImportQIF'/>" |
409 | +" <menuitem action='ImportOFX'/>" |
410 | +" <menuitem action='ImportCSV'/>" |
411 | +" </menu>"*/ |
412 | +" <menuitem action='ExportQIF'/>" |
413 | +// future: print to come here |
414 | +" <separator/>" |
415 | +" <menuitem action='Revert'/>" |
416 | +" <menuitem action='OpenBak'/>" |
417 | +" <separator/>" |
418 | +" <menuitem action='Properties'/>" |
419 | +" <separator/>" |
420 | +" <menuitem action='Close'/>" |
421 | +" <menuitem action='Quit'/>" |
422 | +" </menu>" |
423 | +" <menu action='EditMenu'>" |
424 | +" <menuitem action='Preferences'/>" |
425 | +" </menu>" |
426 | +" <menu action='ViewMenu'>" |
427 | +" <menuitem action='Toolbar'/>" |
428 | +" <separator/>" |
429 | +" <menuitem action='Spending'/>" |
430 | +" <menuitem action='Upcoming'/>" |
431 | +" <separator/>" |
432 | +" <menuitem action='AsMinor'/>" |
433 | +" </menu>" |
434 | +" <menu action='ManageMenu'>" |
435 | +" <menuitem action='Account'/>" |
436 | +" <menuitem action='Payee'/>" |
437 | +" <menuitem action='Category'/>" |
438 | +" <menuitem action='Archive'/>" |
439 | +" <menuitem action='Budget'/>" |
440 | +" <menuitem action='BudgetTabview'/>" |
441 | +" <menuitem action='Assign'/>" |
442 | +" <menuitem action='Currency'/>" |
443 | +" </menu>" |
444 | +" <menu action='TxnMenu'>" |
445 | +" <menuitem action='AddTxn'/>" |
446 | +" <menuitem action='ShowTxn'/>" |
447 | +" <menuitem action='ShowAllTxn'/>" |
448 | +" <separator/>" |
449 | +" <menuitem action='Scheduler'/>" |
450 | +" <menuitem action='AddScheduled'/>" |
451 | +" </menu>" |
452 | +" <menu action='ReportMenu'>" |
453 | +" <menuitem action='RStatistics'/>" |
454 | +" <menuitem action='RTrendTime'/>" |
455 | +" <menuitem action='RBalance'/>" |
456 | +" <menuitem action='RBudget'/>" |
457 | +" <menuitem action='RVehiculeCost'/>" |
458 | +" </menu>" |
459 | +" <menu action='ToolsMenu'>" |
460 | +" <menuitem action='Welcome'/>" |
461 | +" <menuitem action='FileStats'/>" |
462 | +" <separator/>" |
463 | +" <menuitem action='Anonymize'/>" |
464 | +" </menu>" |
465 | +" <menu action='HelpMenu'>" |
466 | +" <menuitem action='Contents'/>" |
467 | +" <menuitem action='Online'/>" |
468 | +" <separator/>" |
469 | +" <menuitem action='Updates'/>" |
470 | +" <menuitem action='ReleaseNotes'/>" |
471 | +" <menuitem action='Problem'/>" |
472 | +" <menuitem action='Translate'/>" |
473 | +" <separator/>" |
474 | +" <menuitem action='About'/>" |
475 | +" </menu>" |
476 | +" </menubar>" |
477 | + |
478 | +" <toolbar name='ToolBar'>" |
479 | +" <toolitem action='New'/>" |
480 | +// here Open + recent is coded |
481 | +" <toolitem action='Save'/>" |
482 | +" <separator/>" |
483 | +" <toolitem action='Account'/>" |
484 | +" <toolitem action='Payee'/>" |
485 | +" <toolitem action='Category'/>" |
486 | +" <toolitem action='Archive'/>" |
487 | +" <toolitem action='Budget'/>" |
488 | +" <toolitem action='Assign'/>" |
489 | +" <toolitem action='Currency'/>" |
490 | +" <separator/>" |
491 | +" <toolitem action='ShowTxn'/>" |
492 | +" <toolitem action='AddTxn'/>" |
493 | +" <separator/>" |
494 | +" <toolitem action='RStatistics'/>" |
495 | +" <toolitem action='RTrendTime'/>" |
496 | +" <toolitem action='RBalance'/>" |
497 | +" <toolitem action='RBudget'/>" |
498 | +" <toolitem action='RVehiculeCost'/>" |
499 | +" </toolbar>" |
500 | + |
501 | +"</ui>"; |
502 | + |
503 | + |
504 | + |
505 | +/* TODO: a bouger */ |
506 | + |
507 | + |
508 | +/* |
509 | +** |
510 | +*/ |
511 | +void ui_mainwindow_revert(GtkWidget *widget, gpointer user_data) |
512 | +{ |
513 | +//struct hbfile_data *data; |
514 | +gchar *basename; |
515 | +gchar *title; |
516 | +gchar *secondtext; |
517 | +gint result; |
518 | + |
519 | + DB( g_print("\n[ui-mainwindow] revert\n") ); |
520 | + |
521 | + //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
522 | + |
523 | + basename = g_path_get_basename(GLOBALS->xhb_filepath); |
524 | + title = g_strdup_printf ( |
525 | + _("Revert unsaved changes to file '%s'?"), basename); |
526 | + |
527 | + secondtext = |
528 | + _("- Changes made to the file will be permanently lost\n" |
529 | + "- File will be reloaded from the last save (.xhb~)"); |
530 | + |
531 | + result = ui_dialog_msg_confirm_alert( |
532 | + GTK_WINDOW(GLOBALS->mainwindow), |
533 | + title, |
534 | + secondtext, |
535 | + _("_Revert") |
536 | + ); |
537 | + |
538 | + g_free(title); |
539 | + g_free(basename); |
540 | + |
541 | + if( result == GTK_RESPONSE_OK ) |
542 | + { |
543 | + DB( g_print(" - should revert\n") ); |
544 | + |
545 | + hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb~")); |
546 | + ui_mainwindow_open_internal(widget, NULL); |
547 | + hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb")); |
548 | + } |
549 | + |
550 | +} |
551 | + |
552 | + |
553 | +static void |
554 | +activate_url (GtkAboutDialog *about, |
555 | + const gchar *link, |
556 | + gpointer data) |
557 | +{ |
558 | + DB( g_print("activate url %s\n", link) ); |
559 | + |
560 | + homebank_util_url_show (link); |
561 | +} |
562 | + |
563 | +static void hbfile_about(void) |
564 | +{ |
565 | +GtkWidget *dialog; |
566 | +GdkPixbuf *pixbuf; |
567 | +gchar *pathfilename; |
568 | +gchar *version; |
569 | + |
570 | + static const gchar *artists[] = { |
571 | + "Maxime DOYEN", |
572 | + NULL |
573 | + }; |
574 | + |
575 | + static const gchar *authors[] = { |
576 | + "Lead developer:\n" \ |
577 | + "Maxime DOYEN", |
578 | + "\nContributor:\n" \ |
579 | + "Ga\xc3\xabtan LORIDANT (Maths formulas for charts)\n", |
580 | + NULL |
581 | + }; |
582 | + |
583 | +/* |
584 | + const gchar *documenters[] = { |
585 | + "Maxime DOYEN", |
586 | + NULL |
587 | + }; |
588 | +*/ |
589 | + |
590 | + static const gchar *copyright = "Copyright \xc2\xa9 1995-2018 - Maxime DOYEN"; |
591 | + |
592 | + |
593 | + |
594 | + version = g_strdup_printf (PACKAGE_VERSION "\n<small>Running against GTK+ %d.%d.%d</small>", |
595 | + gtk_get_major_version (), |
596 | + gtk_get_minor_version (), |
597 | + gtk_get_micro_version ()); |
598 | + |
599 | + dialog = gtk_about_dialog_new(); |
600 | + |
601 | + gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(GLOBALS->mainwindow)); |
602 | + gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); |
603 | + |
604 | + gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG(dialog), g_get_application_name ()); |
605 | + gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), version); |
606 | + gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), copyright); |
607 | + gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), _("Free, easy, personal accounting for everyone")); |
608 | + gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG(dialog), GTK_LICENSE_GPL_2_0); |
609 | + |
610 | + //gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(dialog), ); |
611 | + gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "http://homebank.free.fr"); |
612 | + gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), "Visit the HomeBank website"); |
613 | + |
614 | + gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(dialog), "homebank"); |
615 | + |
616 | + pathfilename = g_build_filename(homebank_app_get_images_dir(), "splash.png", NULL); |
617 | + pixbuf = gdk_pixbuf_new_from_file(pathfilename, NULL); |
618 | + g_free(pathfilename); |
619 | + |
620 | + if( pixbuf ) |
621 | + { |
622 | + gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf); |
623 | + g_object_unref (pixbuf); |
624 | + } |
625 | + |
626 | + gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog), authors); |
627 | + gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(dialog), artists); |
628 | + //gtk_about_dialog_set_documenters(GTK_ABOUT_DIALOG(dialog), ); |
629 | + //gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(dialog), ); |
630 | + |
631 | + g_signal_connect (dialog, "activate-link", G_CALLBACK (activate_url), NULL); |
632 | + |
633 | + gtk_dialog_run (GTK_DIALOG (dialog)); |
634 | + |
635 | + gtk_widget_destroy (dialog); |
636 | + |
637 | + g_free(version); |
638 | + |
639 | +} |
640 | + |
641 | + |
642 | +/* hbfile action functions -------------------- */ |
643 | +static void ui_mainwindow_action_new(void) |
644 | +{ |
645 | +GtkWidget *widget = GLOBALS->mainwindow; |
646 | + |
647 | + if( ui_dialog_msg_savechanges(widget,NULL) == TRUE ) |
648 | + { |
649 | + //clear all, and init GLOBALS->xhb_filepath to default |
650 | + ui_mainwindow_clear(widget, GINT_TO_POINTER(TRUE)); // GPOINTER_TO_INT( |
651 | + ui_mainwindow_update(widget, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); |
652 | + |
653 | + ui_start_assistant(); |
654 | + //ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); |
655 | + //ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); |
656 | + //ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL); |
657 | + } |
658 | +} |
659 | + |
660 | +static void ui_mainwindow_action_open(void) |
661 | +{ |
662 | + ui_mainwindow_open(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE)); |
663 | +} |
664 | + |
665 | +static void ui_mainwindow_action_openbak(void) |
666 | +{ |
667 | + ui_mainwindow_open(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE)); |
668 | +} |
669 | + |
670 | +static void ui_mainwindow_action_save(void) |
671 | +{ |
672 | + ui_mainwindow_save(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE)); |
673 | +} |
674 | + |
675 | +static void ui_mainwindow_action_saveas(void) |
676 | +{ |
677 | + ui_mainwindow_save(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE)); |
678 | +} |
679 | + |
680 | +static void ui_mainwindow_action_revert(void) |
681 | +{ |
682 | + ui_mainwindow_revert(GLOBALS->mainwindow, NULL); |
683 | +} |
684 | + |
685 | +static void ui_mainwindow_action_close(void) |
686 | +{ |
687 | +GtkWidget *widget = GLOBALS->mainwindow; |
688 | + |
689 | + if( ui_dialog_msg_savechanges(widget,NULL) == TRUE ) |
690 | + { |
691 | + //clear all, and init GLOBALS->xhb_filepath to default |
692 | + ui_mainwindow_clear(widget, GINT_TO_POINTER(TRUE)); |
693 | + ui_mainwindow_update(widget, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_REFRESHALL)); |
694 | + } |
695 | + |
696 | +} |
697 | + |
698 | + |
699 | +static void ui_mainwindow_action_quit(void) |
700 | +{ |
701 | +gboolean result; |
702 | + |
703 | + //emulate the wm close button |
704 | + g_signal_emit_by_name(GLOBALS->mainwindow, "delete-event", NULL, &result); |
705 | +} |
706 | + |
707 | + |
708 | +static void ui_mainwindow_action_file_statistics(void) |
709 | +{ |
710 | + ui_dialog_file_statistics(); |
711 | +} |
712 | + |
713 | + |
714 | +static void ui_mainwindow_action_properties(void) |
715 | +{ |
716 | + create_defhbfile_dialog(); |
717 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); |
718 | +} |
719 | + |
720 | +static void ui_mainwindow_action_anonymize(void) |
721 | +{ |
722 | +gint result; |
723 | +gchar *title; |
724 | +gchar *secondtext; |
725 | + |
726 | + title = _("Are you sure you want to anonymize the file?"); |
727 | + |
728 | + secondtext = |
729 | + _("Proceeding will anonymize any text, \n" |
730 | + "like 'account x', 'payee y', 'memo z', ..."); |
731 | + |
732 | + result = ui_dialog_msg_confirm_alert( |
733 | + GTK_WINDOW(GLOBALS->mainwindow), |
734 | + title, |
735 | + secondtext, |
736 | + _("_Anonymize") |
737 | + ); |
738 | + |
739 | + //#1707201 |
740 | + //if( result == GTK_RESPONSE_CANCEL ) |
741 | + // return; |
742 | + if( result == GTK_RESPONSE_OK ) |
743 | + { |
744 | + hbfile_anonymize(); |
745 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); |
746 | + } |
747 | +} |
748 | + |
749 | + |
750 | +static void ui_mainwindow_action_defcurrency(void) |
751 | +{ |
752 | + ui_cur_manage_dialog(); |
753 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); |
754 | +} |
755 | + |
756 | + |
757 | +static void ui_mainwindow_action_defaccount(void) |
758 | +{ |
759 | + ui_acc_manage_dialog(); |
760 | + |
761 | + //our global list has changed, so update the treeview |
762 | + //todo: optimize this, should not call compute balance here |
763 | + account_compute_balances (); |
764 | + ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); |
765 | + |
766 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE)); |
767 | +} |
768 | + |
769 | +static void ui_mainwindow_action_defpayee(void) |
770 | +{ |
771 | + ui_pay_manage_dialog(); |
772 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); |
773 | +} |
774 | + |
775 | +static void ui_mainwindow_action_defcategory(void) |
776 | +{ |
777 | + ui_cat_manage_dialog(); |
778 | + //todo:why refresh upcoming here?? |
779 | + //ui_mainwindow_populate_upcoming(GLOBALS->mainwindow, NULL); |
780 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); |
781 | +} |
782 | + |
783 | + |
784 | +static void ui_mainwindow_defarchive(Archive *arc) |
785 | +{ |
786 | +struct hbfile_data *data; |
787 | +GtkTreeModel *model; |
788 | + |
789 | + data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); |
790 | + |
791 | + // upcoming list have direct pointer to the arc (which may have changed) |
792 | + model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc)); |
793 | + gtk_list_store_clear (GTK_LIST_STORE(model)); |
794 | + |
795 | + ui_arc_manage_dialog(arc); |
796 | + |
797 | + ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); |
798 | + |
799 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); |
800 | +} |
801 | + |
802 | + |
803 | +static void ui_mainwindow_action_defarchive(void) |
804 | +{ |
805 | + ui_mainwindow_defarchive(NULL); |
806 | +} |
807 | + |
808 | + |
809 | +static void ui_mainwindow_action_defbudget(void) |
810 | +{ |
811 | + ui_bud_manage_dialog(); |
812 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); |
813 | +} |
814 | + |
815 | +static void ui_mainwindow_action_defbudget_tabview(void) |
816 | +{ |
817 | + ui_bud_tabview_manage_dialog(); |
818 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); |
819 | +} |
820 | + |
821 | + |
822 | +static void ui_mainwindow_action_defassign(void) |
823 | +{ |
824 | + |
825 | + ui_asg_manage_dialog(); |
826 | + |
827 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); |
828 | +} |
829 | + |
830 | + |
831 | +static void ui_mainwindow_action_preferences(void) |
832 | +{ |
833 | +struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); |
834 | + |
835 | + defpref_dialog_new(); |
836 | + if(!PREFS->euro_active) |
837 | + { |
838 | + GtkToggleAction *action = (GtkToggleAction *)gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/AsMinor"); |
839 | + |
840 | + gtk_toggle_action_set_active(action, FALSE); |
841 | + ui_mainwindow_action_toggle_minor(action); |
842 | + } |
843 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL+UF_REFRESHALL)); |
844 | +} |
845 | + |
846 | +/* display action */ |
847 | + |
848 | +static void ui_mainwindow_action_toggle_toolbar(GtkToggleAction *action) |
849 | +{ |
850 | +//struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); |
851 | + |
852 | + PREFS->wal_toolbar = gtk_toggle_action_get_active(action); |
853 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL)); |
854 | +} |
855 | + |
856 | +static void ui_mainwindow_action_toggle_upcoming(GtkToggleAction *action) |
857 | +{ |
858 | +//struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); |
859 | + |
860 | + PREFS->wal_upcoming = gtk_toggle_action_get_active(action); |
861 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL)); |
862 | +} |
863 | + |
864 | +static void ui_mainwindow_action_toggle_topspending(GtkToggleAction *action) |
865 | +{ |
866 | +//struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); |
867 | + |
868 | + PREFS->wal_spending = gtk_toggle_action_get_active(action); |
869 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL)); |
870 | +} |
871 | + |
872 | +static void ui_mainwindow_action_toggle_minor(GtkToggleAction *action) |
873 | +{ |
874 | +struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); |
875 | + |
876 | + GLOBALS->minor = gtk_toggle_action_get_active(action); |
877 | + |
878 | + gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_acc)); |
879 | + gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_upc)); |
880 | + |
881 | + // top spending |
882 | + gtk_chart_show_minor(GTK_CHART(data->RE_pie), GLOBALS->minor); |
883 | + |
884 | + ui_panel_topspending_update(data->window, data); |
885 | + |
886 | +} |
887 | + |
888 | +static void ui_mainwindow_action_showtransactions(void) |
889 | +{ |
890 | +struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); |
891 | +GtkWidget *window; |
892 | + |
893 | + //todo:change this |
894 | + if( data->acc ) |
895 | + { |
896 | + if( data->acc->window == NULL ) |
897 | + { |
898 | + window = register_panel_window_new(data->acc); |
899 | + register_panel_window_init(window, NULL); |
900 | + } |
901 | + else |
902 | + { |
903 | + if(GTK_IS_WINDOW(data->acc->window)) |
904 | + gtk_window_present(GTK_WINDOW(data->acc->window)); |
905 | + |
906 | + } |
907 | + } |
908 | +} |
909 | + |
910 | + |
911 | +static void ui_mainwindow_action_showalltransactions(void) |
912 | +{ |
913 | +GtkWidget *window; |
914 | + |
915 | + if( GLOBALS->alltxnwindow == NULL ) |
916 | + { |
917 | + window = register_panel_window_new(NULL); |
918 | + register_panel_window_init(window, NULL); |
919 | + } |
920 | + else |
921 | + { |
922 | + if(GTK_IS_WINDOW(GLOBALS->alltxnwindow)) |
923 | + gtk_window_present(GTK_WINDOW(GLOBALS->alltxnwindow)); |
924 | + } |
925 | + |
926 | +} |
927 | + |
928 | + |
929 | +static void ui_mainwindow_action_addtransactions(void) |
930 | +{ |
931 | + ui_mainwindow_addtransactions(GLOBALS->mainwindow, NULL); |
932 | +} |
933 | + |
934 | +static void ui_mainwindow_action_checkscheduled(void) |
935 | +{ |
936 | + ui_mainwindow_scheduled_postall(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE)); |
937 | +} |
938 | + |
939 | +static void ui_mainwindow_action_statistic(void) |
940 | +{ |
941 | + ui_repdist_window_new(); |
942 | +} |
943 | + |
944 | +static void ui_mainwindow_action_trendtime(void) |
945 | +{ |
946 | +struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); |
947 | + |
948 | + ui_reptime_window_new(data->acc != NULL ? data->acc->key : 0); |
949 | +} |
950 | + |
951 | +static void ui_mainwindow_action_budget(void) |
952 | +{ |
953 | + repbudget_window_new(); |
954 | +} |
955 | + |
956 | +static void ui_mainwindow_action_balance(void) |
957 | +{ |
958 | +struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); |
959 | + |
960 | + repbalance_window_new(data->acc != NULL ? data->acc->key : 0); |
961 | +} |
962 | + |
963 | +static void ui_mainwindow_action_vehiclecost(void) |
964 | +{ |
965 | + repcost_window_new(); |
966 | +} |
967 | + |
968 | +static void ui_mainwindow_action_import(GtkAction *action) |
969 | +{ |
970 | +/*const gchar *name; |
971 | +gint filetype = FILETYPE_UNKNOWN; |
972 | + |
973 | + name = gtk_action_get_name(action); |
974 | + |
975 | + if( g_str_has_suffix (name, "QIF")) |
976 | + filetype= FILETYPE_QIF; |
977 | + else |
978 | + if( g_str_has_suffix (name, "OFX")) |
979 | + filetype= FILETYPE_OFX; |
980 | + else |
981 | + if( g_str_has_suffix (name, "CSV")) |
982 | + filetype= FILETYPE_CSV_HB;*/ |
983 | + |
984 | + //DB( g_print("action %s type=%d\n", name, filetype) ); |
985 | + |
986 | + ui_import_assistant_new(NULL); |
987 | + |
988 | +} |
989 | + |
990 | + |
991 | +static void ui_mainwindow_action_about(void) |
992 | +{ |
993 | + hbfile_about(); |
994 | + |
995 | + |
996 | +} |
997 | + |
998 | + |
999 | +static void ui_mainwindow_action_export(void) |
1000 | +{ |
1001 | +gchar *filename; |
1002 | + |
1003 | + if( ui_file_chooser_qif(NULL, &filename) == TRUE ) |
1004 | + { |
1005 | + hb_export_qif_account_all(filename); |
1006 | + g_free( filename ); |
1007 | + } |
1008 | +} |
1009 | + |
1010 | + |
1011 | +static void ui_mainwindow_action_help(void) |
1012 | +{ |
1013 | +gchar *link; |
1014 | + |
1015 | + link = g_build_filename("file:///", homebank_app_get_help_dir(), HOMEBANK_URL_HELP, NULL ); |
1016 | + homebank_util_url_show (link); |
1017 | + g_free(link); |
1018 | +} |
1019 | + |
1020 | + |
1021 | +static void ui_mainwindow_action_help_releasenotes(void) |
1022 | +{ |
1023 | +gchar *link; |
1024 | + |
1025 | + #ifdef G_OS_WIN32 |
1026 | + link = g_build_filename("file:///", homebank_app_get_datas_dir(), "ChangeLog.txt", NULL ); |
1027 | + #else |
1028 | + link = g_build_filename("file:///", homebank_app_get_datas_dir(), "ChangeLog", NULL ); |
1029 | + #endif |
1030 | + homebank_util_url_show (link); |
1031 | + g_free(link); |
1032 | +} |
1033 | + |
1034 | + |
1035 | +//todo: move this to a ui-assist-welcome.c |
1036 | + |
1037 | +static void ui_mainwindow_action_help_welcome1 (GtkButton *button, gpointer user_data) |
1038 | +{ |
1039 | + gtk_dialog_response (GTK_DIALOG(user_data), 1); |
1040 | +} |
1041 | + |
1042 | +static void ui_mainwindow_action_help_welcome2 (GtkButton *button, gpointer user_data) |
1043 | +{ |
1044 | + gtk_dialog_response (GTK_DIALOG(user_data), 2); |
1045 | +} |
1046 | + |
1047 | +static void ui_mainwindow_action_help_welcome3 (GtkButton *button, gpointer user_data) |
1048 | +{ |
1049 | + gtk_dialog_response (GTK_DIALOG(user_data), 3); |
1050 | +} |
1051 | + |
1052 | +static void ui_mainwindow_action_help_welcome4 (GtkButton *button, gpointer user_data) |
1053 | +{ |
1054 | + gtk_dialog_response (GTK_DIALOG(user_data), 4); |
1055 | +} |
1056 | + |
1057 | +static void ui_mainwindow_action_help_welcome5 (GtkButton *button, gpointer user_data) |
1058 | +{ |
1059 | + gtk_dialog_response (GTK_DIALOG(user_data), 5); |
1060 | +} |
1061 | + |
1062 | +void ui_mainwindow_action_help_welcome(void) |
1063 | +{ |
1064 | +GtkWidget *dialog, *content_area; |
1065 | +GtkWidget *mainvbox, *widget, *label; |
1066 | + |
1067 | + dialog = gtk_dialog_new_with_buttons (_("Welcome to HomeBank"), |
1068 | + GTK_WINDOW(GLOBALS->mainwindow), |
1069 | + 0, |
1070 | + _("_Close"), |
1071 | + GTK_RESPONSE_ACCEPT, |
1072 | + NULL); |
1073 | + |
1074 | + content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog)); |
1075 | + |
1076 | + mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); |
1077 | + gtk_box_pack_start (GTK_BOX (content_area), mainvbox, FALSE, FALSE, 0); |
1078 | + gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM); |
1079 | + |
1080 | + label = make_label (_("HomeBank"), 0, 0); |
1081 | + gimp_label_set_attributes(GTK_LABEL(label), PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1); |
1082 | + gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0); |
1083 | + |
1084 | + label = make_label (_("Free, easy, personal accounting for everyone"), 0, 0); |
1085 | + gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0); |
1086 | + |
1087 | + widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); |
1088 | + gtk_box_pack_start (GTK_BOX (content_area), widget, FALSE, FALSE, 0); |
1089 | + |
1090 | + mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_MEDIUM); |
1091 | + gtk_box_pack_start (GTK_BOX (content_area), mainvbox, TRUE, TRUE, 0); |
1092 | + gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM); |
1093 | + |
1094 | + label = make_label (_("What do you want to do:"), 0, 0); |
1095 | + gimp_label_set_attributes(GTK_LABEL(label), PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1); |
1096 | + gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0); |
1097 | + |
1098 | + widget = gtk_button_new_with_mnemonic(_("Read HomeBank _Manual")); |
1099 | + gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); |
1100 | + g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome1), dialog); |
1101 | + |
1102 | + widget = gtk_button_new_with_mnemonic(_("Configure _preferences")); |
1103 | + gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); |
1104 | + g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome2), dialog); |
1105 | + |
1106 | + widget = gtk_button_new_with_mnemonic(_("Create a _new file")); |
1107 | + gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); |
1108 | + g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome3), dialog); |
1109 | + |
1110 | + widget = gtk_button_new_with_mnemonic(_("_Open an existing file")); |
1111 | + gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); |
1112 | + g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome4), dialog); |
1113 | + |
1114 | + widget = gtk_button_new_with_mnemonic(_("Open the _example file")); |
1115 | + gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); |
1116 | + g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome5), dialog); |
1117 | + |
1118 | + //connect all our signals |
1119 | + g_signal_connect (dialog, "destroy", G_CALLBACK (gtk_widget_destroyed), &dialog); |
1120 | + |
1121 | + gtk_widget_show_all (dialog); |
1122 | + |
1123 | + //wait for the user |
1124 | + gint result = gtk_dialog_run (GTK_DIALOG (dialog)); |
1125 | + |
1126 | + // cleanup and destroy |
1127 | + gtk_widget_destroy (dialog); |
1128 | + |
1129 | + // do appropriate action |
1130 | + switch(result) |
1131 | + { |
1132 | + case 1: |
1133 | + ui_mainwindow_action_help(); |
1134 | + break; |
1135 | + case 2: |
1136 | + ui_mainwindow_action_preferences(); |
1137 | + break; |
1138 | + case 3: |
1139 | + ui_mainwindow_action_new(); |
1140 | + break; |
1141 | + case 4: |
1142 | + ui_mainwindow_action_open(); |
1143 | + break; |
1144 | + case 5: |
1145 | + hbfile_change_filepath(g_build_filename(homebank_app_get_datas_dir(), "example.xhb", NULL)); |
1146 | + ui_mainwindow_open_internal(GLOBALS->mainwindow, NULL); |
1147 | + break; |
1148 | + } |
1149 | + |
1150 | +} |
1151 | + |
1152 | + |
1153 | +static void ui_mainwindow_action_help_updates(void) |
1154 | +{ |
1155 | +const gchar *link = HOMEBANK_URL_HELP_UPDATES; |
1156 | + |
1157 | + homebank_util_url_show (link); |
1158 | +} |
1159 | + |
1160 | + |
1161 | +static void ui_mainwindow_action_help_online(void) |
1162 | +{ |
1163 | +const gchar *link = HOMEBANK_URL_HELP_ONLINE; |
1164 | + |
1165 | + homebank_util_url_show (link); |
1166 | +} |
1167 | + |
1168 | + |
1169 | +static void ui_mainwindow_action_help_translate(void) |
1170 | +{ |
1171 | +const gchar *link = HOMEBANK_URL_HELP_TRANSLATE; |
1172 | + |
1173 | + homebank_util_url_show (link); |
1174 | +} |
1175 | + |
1176 | + |
1177 | +static void ui_mainwindow_action_help_problem(void) |
1178 | +{ |
1179 | +const gchar *link = HOMEBANK_URL_HELP_PROBLEM; |
1180 | + |
1181 | + homebank_util_url_show (link); |
1182 | +} |
1183 | + |
1184 | + |
1185 | +/* hbfile functions -------------------- */ |
1186 | + |
1187 | + |
1188 | +/* |
1189 | +** |
1190 | +*/ |
1191 | +static void ui_mainwindow_selection(GtkTreeSelection *treeselection, gpointer user_data) |
1192 | +{ |
1193 | + ui_mainwindow_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE)); |
1194 | +} |
1195 | + |
1196 | + |
1197 | +static void ui_mainwindow_close_openbooks(void) |
1198 | +{ |
1199 | +GList *lacc, *elt; |
1200 | + |
1201 | + DB( g_print("\n[ui-mainwindow] close openbooks\n") ); |
1202 | + |
1203 | + lacc = elt = g_hash_table_get_values(GLOBALS->h_acc); |
1204 | + while (elt != NULL) |
1205 | + { |
1206 | + Account *item = elt->data; |
1207 | + |
1208 | + if(item->window) |
1209 | + { |
1210 | + gtk_widget_destroy(GTK_WIDGET(item->window)); |
1211 | + item->window = NULL; |
1212 | + } |
1213 | + |
1214 | + elt = g_list_next(elt); |
1215 | + } |
1216 | + g_list_free(lacc); |
1217 | + |
1218 | +} |
1219 | + |
1220 | + |
1221 | + |
1222 | +/* |
1223 | +** |
1224 | +*/ |
1225 | +void ui_mainwindow_clear(GtkWidget *widget, gpointer user_data) |
1226 | +{ |
1227 | +struct hbfile_data *data; |
1228 | +gboolean file_clear = GPOINTER_TO_INT(user_data); |
1229 | + |
1230 | + DB( g_print("\n[ui-mainwindow] clear\n") ); |
1231 | + |
1232 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
1233 | + |
1234 | + // Close opened account window |
1235 | + // Clear TreeView |
1236 | + ui_mainwindow_close_openbooks(); |
1237 | + gtk_tree_store_clear(GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc)))); |
1238 | + gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc)))); |
1239 | + gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top)))); |
1240 | + |
1241 | + data->showall = FALSE; |
1242 | + ui_panel_accounts_setup(data); |
1243 | + |
1244 | + hbfile_cleanup(file_clear); |
1245 | + hbfile_setup(file_clear); |
1246 | + |
1247 | +} |
1248 | + |
1249 | + |
1250 | +/* |
1251 | +** add some transactions directly |
1252 | +*/ |
1253 | +void ui_mainwindow_addtransactions(GtkWidget *widget, gpointer user_data) |
1254 | +{ |
1255 | +struct hbfile_data *data; |
1256 | +GtkWidget *window; |
1257 | +gint result = 1; |
1258 | +guint32 date; |
1259 | +gint account, count; |
1260 | + |
1261 | + DB( g_print("\n[ui-mainwindow] add transactions\n") ); |
1262 | + |
1263 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
1264 | + |
1265 | + /* init the transaction */ |
1266 | + date = homebank_app_date_get_julian(); |
1267 | + |
1268 | + //#1656531 |
1269 | + account = 0; |
1270 | + if(data->acc != NULL) |
1271 | + account = data->acc->key; |
1272 | + |
1273 | + window = create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, FALSE, account); |
1274 | + count = 0; |
1275 | + while(result == HB_RESPONSE_ADD || result == HB_RESPONSE_ADDKEEP) |
1276 | + { |
1277 | + Transaction *ope; |
1278 | + |
1279 | + /* fill in the transaction */ |
1280 | + if( result == HB_RESPONSE_ADD ) |
1281 | + { |
1282 | + ope = da_transaction_malloc(); |
1283 | + ope->date = date; |
1284 | + ope->kacc = account; |
1285 | + |
1286 | + if( PREFS->heritdate == FALSE ) //fix: 318733 |
1287 | + ope->date = GLOBALS->today; |
1288 | + |
1289 | + da_transaction_set_default_template(ope); |
1290 | + } |
1291 | + |
1292 | + // normally we can't be in addkeep without initialized ope with add |
1293 | + |
1294 | + deftransaction_set_transaction(window, ope); |
1295 | + |
1296 | + result = gtk_dialog_run (GTK_DIALOG (window)); |
1297 | + |
1298 | + DB( g_print(" - dialog result is %d\n", result) ); |
1299 | + |
1300 | + if(result == HB_RESPONSE_ADD || result == HB_RESPONSE_ADDKEEP || result == GTK_RESPONSE_ACCEPT) |
1301 | + { |
1302 | + deftransaction_get(window, NULL); |
1303 | + transaction_add(GTK_WINDOW(GLOBALS->mainwindow), ope); |
1304 | + |
1305 | + DB( g_print(" - added 1 transaction to %d\n", ope->kacc) ); |
1306 | + |
1307 | + ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); |
1308 | + |
1309 | + count++; |
1310 | + //todo: still usefull ? store last date |
1311 | + date = ope->date; |
1312 | + } |
1313 | + |
1314 | + if( result == HB_RESPONSE_ADD ) |
1315 | + { |
1316 | + da_transaction_free(ope); |
1317 | + ope = NULL; |
1318 | + } |
1319 | + |
1320 | + } |
1321 | + |
1322 | + |
1323 | + deftransaction_dispose(window, NULL); |
1324 | + gtk_widget_destroy (window); |
1325 | + |
1326 | + /* todo optimize this */ |
1327 | + if(count > 0) |
1328 | + { |
1329 | + GLOBALS->changes_count += count; |
1330 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_REFRESHALL)); |
1331 | + } |
1332 | +} |
1333 | + |
1334 | +struct tmptop |
1335 | +{ |
1336 | + guint32 key; |
1337 | + gdouble value; |
1338 | +}; |
1339 | + |
1340 | + |
1341 | +#define MAX_TOPSPENDING 10 |
1342 | + |
1343 | + |
1344 | +static gint tmptop_compare_func(struct tmptop *tt1, struct tmptop *tt2) |
1345 | +{ |
1346 | + return tt1->value > tt2->value ? 1 : -1; |
1347 | +} |
1348 | + |
1349 | + |
1350 | +static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data) |
1351 | +{ |
1352 | +struct hbfile_data *data; |
1353 | +GtkTreeModel *model; |
1354 | +gchar *title; |
1355 | +gchar strbuffer[G_ASCII_DTOSTR_BUF_SIZE]; |
1356 | + |
1357 | + DB( g_print("\n[ui-mainwindow] topspending_update\n") ); |
1358 | + |
1359 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
1360 | + |
1361 | + hb_strfmon(strbuffer, G_ASCII_DTOSTR_BUF_SIZE-1, data->toptotal, GLOBALS->kcur, GLOBALS->minor); |
1362 | + //hb_label_set_amount(GTK_LABEL(data->TX_topamount), total, GLOBALS->kcur, GLOBALS->minor); |
1363 | + title = g_strdup_printf("%s %s", _("Top spending"), strbuffer); |
1364 | + |
1365 | + model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top)); |
1366 | + |
1367 | + gtk_chart_set_color_scheme(GTK_CHART(data->RE_pie), PREFS->report_color_scheme); |
1368 | + gtk_chart_set_currency(GTK_CHART(data->RE_pie), GLOBALS->kcur); |
1369 | + gtk_chart_set_datas(GTK_CHART(data->RE_pie), model, LST_TOPSPEND_AMOUNT, title, NULL); |
1370 | + |
1371 | + g_free(title); |
1372 | + |
1373 | + //future usage |
1374 | + gchar *fu = _("Top %d spending"); title = fu; |
1375 | +} |
1376 | + |
1377 | + |
1378 | +static void ui_mainwindow_populate_topspending(GtkWidget *widget, gpointer user_data) |
1379 | +{ |
1380 | +struct hbfile_data *data; |
1381 | +GtkTreeModel *model; |
1382 | +GtkTreeIter iter; |
1383 | +GList *list; |
1384 | +gint type, range; |
1385 | +guint n_result, i, n_items; |
1386 | +GArray *garray; |
1387 | +gdouble total, other; |
1388 | +Account *acc; |
1389 | + |
1390 | + |
1391 | + DB( g_print("\n[ui-mainwindow] populate_topspending\n") ); |
1392 | + |
1393 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
1394 | + |
1395 | + type = radio_get_active(GTK_CONTAINER(data->RA_type)); |
1396 | + range = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_range)); |
1397 | + |
1398 | + DB( g_print(" - type=%d, range=%d\n", type, range) ); |
1399 | + DB( g_print(" - pref range=%d\n", PREFS->date_range_wal) ); |
1400 | + |
1401 | + if(range == FLT_RANGE_OTHER) |
1402 | + return; |
1403 | + |
1404 | + filter_preset_daterange_set(data->filter, range, 0); |
1405 | + |
1406 | + |
1407 | + n_result = da_cat_get_max_key() + 1; |
1408 | + total = 0.0; |
1409 | + |
1410 | + DB( g_print(" - max key is %d\n", n_result) ); |
1411 | + |
1412 | + /* allocate some memory */ |
1413 | + garray = g_array_sized_new(FALSE, FALSE, sizeof(struct tmptop), n_result); |
1414 | + |
1415 | + if(garray) |
1416 | + { |
1417 | + struct tmptop zero = { .key=0, .value=0.0 }; |
1418 | + GQueue *txn_queue; |
1419 | + |
1420 | + //DB( g_print(" - array length=%d\n", garray->len) ); |
1421 | + |
1422 | + for(i=0 ; i<n_result ; i++) |
1423 | + { |
1424 | + g_array_append_vals(garray, &zero, 1); |
1425 | + //g_array_insert_vals(garray, i, &zero, 1); |
1426 | + |
1427 | + //struct tmptop *tt = &g_array_index (garray, struct tmptop, i); |
1428 | + //DB( g_print("%4d, %4d %f\n", i, tt->key, tt->value) ); |
1429 | + } |
1430 | + |
1431 | + //DB( g_print("\n - end array length=%d\n", garray->len) ); |
1432 | + |
1433 | + //todo: not ideal, has ot force to get_acc for each txn below |
1434 | + txn_queue = hbfile_transaction_get_partial(data->filter->mindate, data->filter->maxdate); |
1435 | + |
1436 | + /* compute the results */ |
1437 | + list = g_queue_peek_head_link(txn_queue); |
1438 | + while (list != NULL) |
1439 | + { |
1440 | + Transaction *ope = list->data; |
1441 | + |
1442 | + //DB( g_print(" - eval txn: '%s', cat=%d ==> flt-test=%d\n", ope->memo, ope->kcat, filter_test(data->filter, ope)) ); |
1443 | + |
1444 | + if( !(ope->paymode == PAYMODE_INTXFER) ) |
1445 | + { |
1446 | + guint32 pos = 0; |
1447 | + gdouble trn_amount; |
1448 | + |
1449 | + //todo: optimize here |
1450 | + trn_amount = ope->amount; |
1451 | + acc = da_acc_get(ope->kacc); |
1452 | + if(acc) |
1453 | + trn_amount = hb_amount_base(ope->amount, acc->kcur); |
1454 | + |
1455 | + if( ope->flags & OF_SPLIT ) |
1456 | + { |
1457 | + guint nbsplit = da_splits_length(ope->splits); |
1458 | + Split *split; |
1459 | + struct tmptop *item; |
1460 | + |
1461 | + for(i=0;i<nbsplit;i++) |
1462 | + { |
1463 | + split = da_splits_get(ope->splits, i); |
1464 | + pos = category_report_id(split->kcat, type); |
1465 | + if( pos <= garray->len ) |
1466 | + { |
1467 | + trn_amount = hb_amount_base(split->amount, acc->kcur); |
1468 | + //trn_amount = split->amount; |
1469 | + //#1297054 if( trn_amount < 0 ) { |
1470 | + item = &g_array_index (garray, struct tmptop, pos); |
1471 | + item->key = pos; |
1472 | + item->value += trn_amount; |
1473 | + //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos) ); |
1474 | + //} |
1475 | + } |
1476 | + } |
1477 | + } |
1478 | + else |
1479 | + { |
1480 | + struct tmptop *item; |
1481 | + |
1482 | + pos = category_report_id(ope->kcat, type); |
1483 | + if( pos <= garray->len ) |
1484 | + { |
1485 | + //#1297054 if( trn_amount < 0 ) { |
1486 | + item = &g_array_index (garray, struct tmptop, pos); |
1487 | + item->key = pos; |
1488 | + item->value += trn_amount; |
1489 | + //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos) ); |
1490 | + //} |
1491 | + } |
1492 | + } |
1493 | + |
1494 | + } |
1495 | + |
1496 | + list = g_list_next(list); |
1497 | + } |
1498 | + |
1499 | + g_queue_free (txn_queue); |
1500 | + |
1501 | + // we need to sort this and limit before |
1502 | + g_array_sort(garray, (GCompareFunc)tmptop_compare_func); |
1503 | + |
1504 | + n_items = MIN(garray->len,MAX_TOPSPENDING); |
1505 | + other = 0; |
1506 | + for(i=0 ; i<garray->len ; i++) |
1507 | + { |
1508 | + struct tmptop *item; |
1509 | + |
1510 | + item = &g_array_index (garray, struct tmptop, i); |
1511 | + if(item->value < 0) |
1512 | + { |
1513 | + total += item->value; |
1514 | + |
1515 | + if(i >= n_items) |
1516 | + other += item->value; |
1517 | + |
1518 | + DB( g_print(" - %d : k='%d' v='%f' t='%f'\n", i, item->key, item->value, total) ); |
1519 | + |
1520 | + } |
1521 | + } |
1522 | + |
1523 | + model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top)); |
1524 | + gtk_list_store_clear (GTK_LIST_STORE(model)); |
1525 | + g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */ |
1526 | + gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_top), NULL); /* Detach model from view */ |
1527 | + |
1528 | + /* insert into the treeview */ |
1529 | + for(i=0 ; i<MIN(garray->len,MAX_TOPSPENDING) ; i++) |
1530 | + { |
1531 | + gchar *name; |
1532 | + Category *entry; |
1533 | + struct tmptop *item; |
1534 | + gdouble value; |
1535 | + |
1536 | + item = &g_array_index (garray, struct tmptop, i); |
1537 | + |
1538 | + if(!item->value) continue; |
1539 | + //#1767659 top spending should restrict to... spending |
1540 | + if(item->value < 0) |
1541 | + { |
1542 | + value = hb_amount_round(item->value, 2); |
1543 | + entry = da_cat_get(item->key); |
1544 | + if(entry == NULL) continue; |
1545 | + |
1546 | + name = entry->key == 0 ? _("(no category)") : entry->fullname; |
1547 | + |
1548 | + // append test |
1549 | + gtk_list_store_append (GTK_LIST_STORE(model), &iter); |
1550 | + gtk_list_store_set (GTK_LIST_STORE(model), &iter, |
1551 | + LST_TOPSPEND_ID, i, |
1552 | + LST_TOPSPEND_KEY, 0, |
1553 | + LST_TOPSPEND_NAME, name, |
1554 | + LST_TOPSPEND_AMOUNT, value, |
1555 | + //LST_TOPSPEND_RATE, (gint)(((ABS(value)*100)/ABS(total)) + 0.5), |
1556 | + -1); |
1557 | + } |
1558 | + } |
1559 | + |
1560 | + // append test |
1561 | + if(ABS(other) > 0) |
1562 | + { |
1563 | + gtk_list_store_append (GTK_LIST_STORE(model), &iter); |
1564 | + gtk_list_store_set (GTK_LIST_STORE(model), &iter, |
1565 | + LST_TOPSPEND_ID, n_items, |
1566 | + LST_TOPSPEND_KEY, 0, |
1567 | + LST_TOPSPEND_NAME, _("Other"), |
1568 | + LST_TOPSPEND_AMOUNT, other, |
1569 | + //LST_TOPSPEND_RATE, (gint)(((ABS(other)*100)/ABS(total)) + 0.5), |
1570 | + -1); |
1571 | + } |
1572 | + |
1573 | + /* Re-attach model to view */ |
1574 | + gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_top), model); |
1575 | + g_object_unref(model); |
1576 | + |
1577 | + |
1578 | + // update chart and widgets |
1579 | + { |
1580 | + gchar *daterange; |
1581 | + |
1582 | + data->toptotal = total; |
1583 | + ui_panel_topspending_update(widget, data); |
1584 | + |
1585 | + daterange = filter_daterange_text_get(data->filter); |
1586 | + gtk_widget_set_tooltip_markup(GTK_WIDGET(data->CY_range), daterange); |
1587 | + g_free(daterange); |
1588 | + } |
1589 | + } |
1590 | + |
1591 | + /* free our memory */ |
1592 | + g_array_free (garray, TRUE); |
1593 | + |
1594 | +} |
1595 | + |
1596 | + |
1597 | +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ |
1598 | +/* scheduled */ |
1599 | +/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ |
1600 | +static Archive * |
1601 | +ui_mainwindow_scheduled_get_selected_item(GtkTreeView *treeview) |
1602 | +{ |
1603 | +GtkTreeSelection *treeselection; |
1604 | +GtkTreeModel *model; |
1605 | +GtkTreeIter iter; |
1606 | + |
1607 | + treeselection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); |
1608 | + if( gtk_tree_selection_get_selected(treeselection, &model, &iter) ) |
1609 | + { |
1610 | + Archive *arc; |
1611 | + |
1612 | + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPUPC_DATAS, &arc, -1); |
1613 | + return arc; |
1614 | + } |
1615 | + |
1616 | + return NULL; |
1617 | +} |
1618 | + |
1619 | + |
1620 | +static void ui_mainwindow_scheduled_onRowActivated (GtkTreeView *treeview, |
1621 | + GtkTreePath *path, |
1622 | + GtkTreeViewColumn *col, |
1623 | + gpointer userdata) |
1624 | +{ |
1625 | +//struct hbfile_data *data; |
1626 | +Archive *arc; |
1627 | + |
1628 | + DB( g_print ("\n[ui-mainwindow] A scheduled row has been double-clicked!\n") ); |
1629 | + |
1630 | + //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(treeview, GTK_TYPE_WINDOW)), "inst_data"); |
1631 | + |
1632 | + arc = ui_mainwindow_scheduled_get_selected_item(treeview); |
1633 | + ui_mainwindow_defarchive(arc); |
1634 | +} |
1635 | + |
1636 | + |
1637 | +static void ui_mainwindow_scheduled_do_post(Archive *arc, gboolean doedit, gpointer user_data) |
1638 | +{ |
1639 | +struct hbfile_data *data = user_data; |
1640 | +GtkWidget *window; |
1641 | +gint result; |
1642 | +Transaction *txn; |
1643 | + |
1644 | + window = create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, TRUE, 0); |
1645 | + |
1646 | + /* fill in the transaction */ |
1647 | + txn = da_transaction_malloc(); |
1648 | + da_transaction_init_from_template(txn, arc); |
1649 | + txn->date = scheduled_get_postdate(arc, arc->nextdate); |
1650 | + |
1651 | + deftransaction_set_transaction(window, txn); |
1652 | + |
1653 | + result = gtk_dialog_run (GTK_DIALOG (window)); |
1654 | + |
1655 | + DB( g_print(" - dialog result is %d\n", result) ); |
1656 | + |
1657 | + if(result == HB_RESPONSE_ADD || result == GTK_RESPONSE_ACCEPT) |
1658 | + { |
1659 | + deftransaction_get(window, NULL); |
1660 | + transaction_add(GTK_WINDOW(GLOBALS->mainwindow), txn); |
1661 | + GLOBALS->changes_count++; |
1662 | + |
1663 | + scheduled_date_advance(arc); |
1664 | + |
1665 | + DB( g_print(" - added 1 transaction to %d\n", txn->kacc) ); |
1666 | + } |
1667 | + |
1668 | + da_transaction_free(txn); |
1669 | + |
1670 | + deftransaction_dispose(window, NULL); |
1671 | + gtk_widget_destroy (window); |
1672 | + |
1673 | +} |
1674 | + |
1675 | + |
1676 | +static void ui_mainwindow_scheduled_editpost_cb(GtkWidget *widget, gpointer user_data) |
1677 | +{ |
1678 | +struct hbfile_data *data = user_data; |
1679 | + |
1680 | + Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); |
1681 | + |
1682 | + if( (arc != NULL) ) |
1683 | + { |
1684 | + ui_mainwindow_scheduled_do_post(arc, TRUE, data); |
1685 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL)); |
1686 | + } |
1687 | +} |
1688 | + |
1689 | + |
1690 | +static void ui_mainwindow_scheduled_post_cb(GtkWidget *widget, gpointer user_data) |
1691 | +{ |
1692 | +struct hbfile_data *data = user_data; |
1693 | + |
1694 | + DB( g_print("\n[ui-mainwindow] scheduled post\n") ); |
1695 | + |
1696 | + Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); |
1697 | + |
1698 | + if( (arc != NULL) ) |
1699 | + { |
1700 | + if( scheduled_is_postable(arc) ) |
1701 | + { |
1702 | + Transaction *txn = da_transaction_malloc (); |
1703 | + |
1704 | + da_transaction_init_from_template(txn, arc); |
1705 | + txn->date = scheduled_get_postdate(arc, arc->nextdate); |
1706 | + transaction_add(GTK_WINDOW(GLOBALS->mainwindow), txn); |
1707 | + |
1708 | + GLOBALS->changes_count++; |
1709 | + scheduled_date_advance(arc); |
1710 | + |
1711 | + da_transaction_free (txn); |
1712 | + } |
1713 | + else |
1714 | + { |
1715 | + ui_mainwindow_scheduled_do_post(arc, FALSE, data); |
1716 | + } |
1717 | + |
1718 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL)); |
1719 | + } |
1720 | +} |
1721 | + |
1722 | + |
1723 | +static void ui_mainwindow_scheduled_skip_cb(GtkWidget *widget, gpointer user_data) |
1724 | +{ |
1725 | +struct hbfile_data *data = user_data; |
1726 | + |
1727 | + Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); |
1728 | + if( (arc != NULL) && (arc->flags & OF_AUTO) ) |
1729 | + { |
1730 | + GLOBALS->changes_count++; |
1731 | + scheduled_date_advance(arc); |
1732 | + |
1733 | + ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); |
1734 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE)); |
1735 | + } |
1736 | +} |
1737 | + |
1738 | + |
1739 | + |
1740 | +static void ui_mainwindow_scheduled_update(GtkWidget *widget, gpointer user_data) |
1741 | +{ |
1742 | +struct hbfile_data *data; |
1743 | +//gint filter; |
1744 | + |
1745 | + DB( g_print("\n[ui-mainwindow] scheduled update\n") ); |
1746 | + |
1747 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
1748 | + |
1749 | + //filter = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_sched_filter)); |
1750 | + |
1751 | + Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); |
1752 | + |
1753 | + if(arc) |
1754 | + { |
1755 | + DB( g_print("archive is %s\n", arc->memo) ); |
1756 | + |
1757 | + gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), TRUE); |
1758 | + gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), TRUE); |
1759 | + gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), TRUE); |
1760 | + } |
1761 | + else |
1762 | + { |
1763 | + gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), FALSE); |
1764 | + gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), FALSE); |
1765 | + gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), FALSE); |
1766 | + } |
1767 | + |
1768 | +} |
1769 | + |
1770 | + |
1771 | + |
1772 | +static void ui_mainwindow_scheduled_selection_cb(GtkTreeSelection *treeselection, gpointer user_data) |
1773 | +{ |
1774 | + |
1775 | + |
1776 | + ui_mainwindow_scheduled_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE)); |
1777 | +} |
1778 | + |
1779 | + |
1780 | + |
1781 | +/* |
1782 | +** called after load, importamiga, on demand |
1783 | +*/ |
1784 | +void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data) |
1785 | +{ |
1786 | +//struct hbfile_data *data; |
1787 | +gint count; |
1788 | +gint usermode = GPOINTER_TO_INT(user_data); |
1789 | + |
1790 | + DB( g_print("\n[ui-mainwindow] check scheduled\n") ); |
1791 | + |
1792 | + //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
1793 | + |
1794 | + count = scheduled_post_all_pending(); |
1795 | + |
1796 | + //inform the user |
1797 | + if(usermode == TRUE) |
1798 | + { |
1799 | + gchar *txt; |
1800 | + |
1801 | + //#125534 |
1802 | + if( count > 0 ) |
1803 | + { |
1804 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_REFRESHALL)); |
1805 | + } |
1806 | + |
1807 | + if(count == 0) |
1808 | + txt = _("No transaction to add"); |
1809 | + else |
1810 | + txt = _("transaction added: %d"); |
1811 | + |
1812 | + ui_dialog_msg_infoerror(GTK_WINDOW(GLOBALS->mainwindow), GTK_MESSAGE_INFO, |
1813 | + _("Check scheduled transactions result"), |
1814 | + txt, |
1815 | + count); |
1816 | + } |
1817 | + |
1818 | +} |
1819 | + |
1820 | + |
1821 | +static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data) |
1822 | +{ |
1823 | +struct hbfile_data *data; |
1824 | +GtkTreeModel *model; |
1825 | +GtkTreeIter iter; |
1826 | +GList *list; |
1827 | +gdouble totexp = 0; |
1828 | +gdouble totinc = 0; |
1829 | +gint count = 0; |
1830 | +gchar buffer[256]; |
1831 | +guint32 maxpostdate; |
1832 | +GDate *date; |
1833 | +//Account *acc; |
1834 | + |
1835 | + DB( g_print("\n[ui-mainwindow] scheduled populate list\n") ); |
1836 | + |
1837 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
1838 | + |
1839 | + model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc)); |
1840 | + gtk_list_store_clear (GTK_LIST_STORE(model)); |
1841 | + |
1842 | + homebank_app_date_get_julian(); |
1843 | + |
1844 | + maxpostdate = scheduled_date_get_post_max(); |
1845 | + |
1846 | + date = g_date_new_julian (maxpostdate); |
1847 | + g_date_strftime (buffer, 256-1, PREFS->date_format, date); |
1848 | + g_date_free(date); |
1849 | + |
1850 | + gtk_label_set_text(GTK_LABEL(data->LB_maxpostdate), buffer); |
1851 | + |
1852 | + |
1853 | + list = g_list_first(GLOBALS->arc_list); |
1854 | + while (list != NULL) |
1855 | + { |
1856 | + Archive *arc = list->data; |
1857 | + Account *acc; |
1858 | + gdouble inc, exp; |
1859 | + guint nbdays, nblate; |
1860 | + |
1861 | + if((arc->flags & OF_AUTO) ) //&& arc->kacc > 0) |
1862 | + { |
1863 | + count++; |
1864 | + nbdays = arc->nextdate - maxpostdate; |
1865 | + nblate = scheduled_get_latepost_count(arc, GLOBALS->today); |
1866 | + |
1867 | + DB( g_print(" - append '%s' : %d\n", arc->memo, nbdays) ); |
1868 | + |
1869 | + if(arc->flags & OF_INCOME) |
1870 | + { |
1871 | + inc = arc->amount; |
1872 | + exp = 0.0; |
1873 | + } |
1874 | + else |
1875 | + { |
1876 | + exp = arc->amount; |
1877 | + inc = 0.0; |
1878 | + } |
1879 | + |
1880 | + /* insert normal txn */ |
1881 | + acc = da_acc_get(arc->kacc); |
1882 | + if( acc) |
1883 | + { |
1884 | + totinc += hb_amount_base(inc, acc->kcur); |
1885 | + totexp += hb_amount_base(exp, acc->kcur); |
1886 | + } |
1887 | + gtk_list_store_append (GTK_LIST_STORE(model), &iter); |
1888 | + gtk_list_store_set (GTK_LIST_STORE(model), &iter, |
1889 | + LST_DSPUPC_DATAS, arc, |
1890 | + LST_DSPUPC_ACCOUNT, acc, |
1891 | + LST_DSPUPC_MEMO, arc->memo, |
1892 | + LST_DSPUPC_EXPENSE, exp, |
1893 | + LST_DSPUPC_INCOME, inc, |
1894 | + LST_DSPUPC_REMAINING, nbdays, |
1895 | + LST_DSPUPC_NB_LATE, nblate, |
1896 | + -1); |
1897 | + |
1898 | + /* insert internal xfer txn : 1378836 */ |
1899 | + if(arc->paymode == PAYMODE_INTXFER) |
1900 | + { |
1901 | + acc = da_acc_get(arc->kxferacc); |
1902 | + if( acc) |
1903 | + { |
1904 | + totinc += hb_amount_base(-inc, acc->kcur); |
1905 | + totexp += hb_amount_base(-exp, acc->kcur); |
1906 | + } |
1907 | + gtk_list_store_append (GTK_LIST_STORE(model), &iter); |
1908 | + gtk_list_store_set (GTK_LIST_STORE(model), &iter, |
1909 | + LST_DSPUPC_DATAS, arc, |
1910 | + LST_DSPUPC_ACCOUNT, acc, |
1911 | + LST_DSPUPC_MEMO, arc->memo, |
1912 | + LST_DSPUPC_EXPENSE, -inc, |
1913 | + LST_DSPUPC_INCOME, -exp, |
1914 | + LST_DSPUPC_REMAINING, nbdays, |
1915 | + LST_DSPUPC_NB_LATE, nblate, |
1916 | + -1); |
1917 | + } |
1918 | + |
1919 | + } |
1920 | + list = g_list_next(list); |
1921 | + } |
1922 | + |
1923 | + // insert total |
1924 | + if(count > 0 ) |
1925 | + { |
1926 | + gtk_list_store_append (GTK_LIST_STORE(model), &iter); |
1927 | + gtk_list_store_set (GTK_LIST_STORE(model), &iter, |
1928 | + LST_DSPUPC_DATAS, NULL, |
1929 | + LST_DSPUPC_ACCOUNT, NULL, |
1930 | + LST_DSPUPC_MEMO, _("Total"), |
1931 | + LST_DSPUPC_EXPENSE, totexp, |
1932 | + LST_DSPUPC_INCOME, totinc, |
1933 | + -1); |
1934 | + } |
1935 | + |
1936 | + ui_mainwindow_scheduled_update(widget, NULL); |
1937 | + |
1938 | +} |
1939 | + |
1940 | + |
1941 | +gboolean ui_mainwindow_open_backup_check_confirm(gchar *filepath) |
1942 | +{ |
1943 | +gboolean retval = FALSE; |
1944 | +gchar *basename, *secondtext; |
1945 | +gboolean result; |
1946 | + |
1947 | + basename = g_path_get_basename(filepath); |
1948 | + secondtext = g_strdup_printf ( |
1949 | + _("Your are about to open the backup file '%s'.\n\nAre you sure you want to do this ?"), basename); |
1950 | + |
1951 | + result = ui_dialog_msg_confirm_alert( |
1952 | + GTK_WINDOW(GLOBALS->mainwindow), |
1953 | + _("Open the backup file ?"), |
1954 | + secondtext, |
1955 | + _("_Open backup") |
1956 | + ); |
1957 | + |
1958 | + g_free(secondtext); |
1959 | + g_free(basename); |
1960 | + |
1961 | + if( result == GTK_RESPONSE_OK ) |
1962 | + retval = TRUE; |
1963 | + |
1964 | + return retval; |
1965 | +} |
1966 | + |
1967 | + |
1968 | +/* |
1969 | +** |
1970 | +*/ |
1971 | +void ui_mainwindow_open(GtkWidget *widget, gpointer user_data) |
1972 | +{ |
1973 | +//struct hbfile_data *data; |
1974 | +gboolean bakmode = GPOINTER_TO_INT(user_data);; |
1975 | +gboolean doopen = TRUE; |
1976 | +gchar *filename = NULL; |
1977 | + |
1978 | + DB( g_print("\n[ui-mainwindow] open\n") ); |
1979 | + |
1980 | + //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
1981 | + |
1982 | + //#1791554 do ask for save confirm |
1983 | + if( bakmode != TRUE ) |
1984 | + doopen = ui_dialog_msg_savechanges(widget,NULL); |
1985 | + |
1986 | + if( doopen == TRUE ) |
1987 | + { |
1988 | + if( ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_OPEN, &filename, bakmode) == TRUE ) |
1989 | + { |
1990 | + //#1710955 test for backup open |
1991 | + if( hbfile_file_isbackup(filename) ) |
1992 | + { |
1993 | + if( ui_mainwindow_open_backup_check_confirm(filename) == TRUE ) |
1994 | + { |
1995 | + GLOBALS->hbfile_is_bak = TRUE; |
1996 | + } |
1997 | + else |
1998 | + { |
1999 | + g_free(filename); |
2000 | + return; |
2001 | + } |
2002 | + } |
2003 | + |
2004 | + hbfile_change_filepath(filename); |
2005 | + ui_mainwindow_open_internal(widget, NULL); |
2006 | + } |
2007 | + } |
2008 | +} |
2009 | + |
2010 | + |
2011 | +/* |
2012 | + * open the file stored in GLOBALS->xhb_filepath |
2013 | + */ |
2014 | +void ui_mainwindow_open_internal(GtkWidget *widget, gpointer user_data) |
2015 | +{ |
2016 | +struct hbfile_data *data; |
2017 | +gint r; |
2018 | + |
2019 | + DB( g_print("\n[ui-mainwindow] open internal\n") ); |
2020 | + |
2021 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
2022 | + |
2023 | + if( GLOBALS->xhb_filepath != NULL ) |
2024 | + { |
2025 | + DB( g_print(" - filename: '%s'\n", GLOBALS->xhb_filepath) ); |
2026 | + |
2027 | + ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE)); |
2028 | + GLOBALS->hbfile_is_new = FALSE; |
2029 | + |
2030 | + r = homebank_load_xml(GLOBALS->xhb_filepath); |
2031 | + if( r == XML_OK ) |
2032 | + { |
2033 | + DB( g_print(" - file loaded ok : rcode=%d\n", r) ); |
2034 | + |
2035 | + GLOBALS->xhb_timemodified = hbfile_file_get_time_modified(GLOBALS->xhb_filepath); |
2036 | + hbfile_file_hasrevert(GLOBALS->xhb_filepath); |
2037 | + |
2038 | + if(PREFS->appendscheduled) |
2039 | + scheduled_post_all_pending(); |
2040 | + |
2041 | + if(PREFS->do_update_currency) |
2042 | + ui_cur_manage_dialog_update_currencies(GTK_WINDOW(GLOBALS->mainwindow)); |
2043 | + |
2044 | + homebank_lastopenedfiles_save(); |
2045 | + |
2046 | + //todo: delete this after computing done at xml read |
2047 | + account_compute_balances(); |
2048 | + |
2049 | + ui_mainwindow_recent_add(data, GLOBALS->xhb_filepath); |
2050 | + } |
2051 | + else |
2052 | + { |
2053 | + gchar *msg = _("Unknown error"); |
2054 | + |
2055 | + switch(r) |
2056 | + { |
2057 | + case XML_IO_ERROR: |
2058 | + msg = _("I/O error for file '%s'."); |
2059 | + break; |
2060 | + case XML_FILE_ERROR: |
2061 | + msg = _("The file '%s' is not a valid HomeBank file."); |
2062 | + break; |
2063 | + case XML_VERSION_ERROR: |
2064 | + msg = _("The file '%s' was saved with a higher version of HomeBank\nand cannot be loaded by the current version."); |
2065 | + break; |
2066 | + } |
2067 | + |
2068 | + ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR, |
2069 | + _("File error"), |
2070 | + msg, |
2071 | + GLOBALS->xhb_filepath |
2072 | + ); |
2073 | + |
2074 | + ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE)); |
2075 | + |
2076 | + } |
2077 | + |
2078 | + ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); |
2079 | + ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); |
2080 | + ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL); |
2081 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL)); |
2082 | + } |
2083 | + |
2084 | + |
2085 | +} |
2086 | + |
2087 | + |
2088 | +/* |
2089 | +** |
2090 | +*/ |
2091 | +void ui_mainwindow_save(GtkWidget *widget, gpointer user_data) |
2092 | +{ |
2093 | +struct hbfile_data *data; |
2094 | +gboolean saveas = GPOINTER_TO_INT(user_data); |
2095 | +gchar *filename = NULL; |
2096 | +gint r = XML_UNSET; |
2097 | + |
2098 | + DB( g_print("\n[ui-mainwindow] save\n") ); |
2099 | + |
2100 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
2101 | + |
2102 | + if( GLOBALS->hbfile_is_new == TRUE ) |
2103 | + saveas = 1; |
2104 | + |
2105 | + //#1710955 test for backup open |
2106 | + if( GLOBALS->hbfile_is_bak == TRUE ) |
2107 | + { |
2108 | + //todo: later for backup, should also remove datetime and .bak |
2109 | + hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb")); |
2110 | + saveas = 1; |
2111 | + } |
2112 | + |
2113 | + if(saveas == 1) |
2114 | + { |
2115 | + if(ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_SAVE, &filename, FALSE) == TRUE) |
2116 | + { |
2117 | + DB( g_print(" + should save as '%s'\n", filename) ); |
2118 | + homebank_file_ensure_xhb(filename); |
2119 | + homebank_backup_current_file(); |
2120 | + r = homebank_save_xml(GLOBALS->xhb_filepath); |
2121 | + GLOBALS->hbfile_is_new = FALSE; |
2122 | + GLOBALS->hbfile_is_bak = FALSE; |
2123 | + } |
2124 | + else |
2125 | + return; |
2126 | + } |
2127 | + else |
2128 | + { |
2129 | + guint64 time_modified = hbfile_file_get_time_modified (GLOBALS->xhb_filepath); |
2130 | + gint result = GTK_RESPONSE_OK; |
2131 | + |
2132 | + DB( g_print(" + should quick save '%s'\n + time: open=%lu :: now=%lu\n", GLOBALS->xhb_filepath, GLOBALS->xhb_timemodified, time_modified) ); |
2133 | + |
2134 | + if( GLOBALS->xhb_timemodified != time_modified ) |
2135 | + { |
2136 | + result = ui_dialog_msg_confirm_alert( |
2137 | + GTK_WINDOW(GLOBALS->mainwindow), |
2138 | + _("The file has been modified since reading it."), |
2139 | + _("If you save it, all the external changes could be lost. Save it anyway?"), |
2140 | + _("S_ave Anyway") |
2141 | + ); |
2142 | + |
2143 | + if( result != GTK_RESPONSE_OK ) |
2144 | + return; |
2145 | + } |
2146 | + |
2147 | + DB( g_print(" + saving...\n") ); |
2148 | + homebank_file_ensure_xhb(NULL); |
2149 | + homebank_backup_current_file(); |
2150 | + r = homebank_save_xml(GLOBALS->xhb_filepath); |
2151 | + } |
2152 | + |
2153 | + if(r == XML_OK) |
2154 | + { |
2155 | + DB( g_print(" + OK...\n") ); |
2156 | + GLOBALS->changes_count = 0; |
2157 | + GLOBALS->xhb_timemodified = hbfile_file_get_time_modified (GLOBALS->xhb_filepath); |
2158 | + ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL)); |
2159 | + } |
2160 | + else |
2161 | + { |
2162 | + gchar *msg = _("I/O error for file '%s'."); |
2163 | + |
2164 | + ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR, |
2165 | + _("File error"), |
2166 | + msg, |
2167 | + GLOBALS->xhb_filepath |
2168 | + ); |
2169 | + } |
2170 | +} |
2171 | + |
2172 | + |
2173 | +static void ui_panel_accounts_expand_all(GtkWidget *widget, gpointer user_data) |
2174 | +{ |
2175 | +struct hbfile_data *data; |
2176 | + |
2177 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
2178 | + gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_acc)); |
2179 | +} |
2180 | + |
2181 | + |
2182 | +static void ui_panel_accounts_collapse_all(GtkWidget *widget, gpointer user_data) |
2183 | +{ |
2184 | +struct hbfile_data *data; |
2185 | + |
2186 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
2187 | + gtk_tree_view_collapse_all(GTK_TREE_VIEW(data->LV_acc)); |
2188 | +} |
2189 | + |
2190 | + |
2191 | + |
2192 | +static GHashTable *ui_panel_accounts_groups_get(GList *lacc, gint groupby, gboolean showall) |
2193 | +{ |
2194 | +GHashTable *hash; |
2195 | +GList *elt; |
2196 | +gchar *groupname; |
2197 | +gint nballoc; |
2198 | + |
2199 | + DB( g_print("\n[ui-mainwindow] accounts_groups_get\n") ); |
2200 | + |
2201 | + nballoc = da_acc_length (); |
2202 | + |
2203 | + DB( g_print(" %d accounts\n", nballoc) ); |
2204 | + |
2205 | + hash = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); |
2206 | + elt = g_list_first(lacc); |
2207 | + while (elt != NULL) |
2208 | + { |
2209 | + Account *acc = elt->data; |
2210 | + GPtrArray *group; |
2211 | + |
2212 | + //#1674045 ony rely on nosummary |
2213 | + //if( showall || !(acc->flags & (AF_CLOSED|AF_NOSUMMARY)) ) |
2214 | + if( showall || !(acc->flags & AF_NOSUMMARY) ) |
2215 | + { |
2216 | + if( groupby == DSPACC_GROUP_BY_BANK ) |
2217 | + { |
2218 | + groupname = _("(no institution)"); |
2219 | + if( (acc->bankname != NULL) && strlen(acc->bankname) > 0 ) |
2220 | + groupname = acc->bankname; |
2221 | + } |
2222 | + else |
2223 | + { |
2224 | + //pre 5.1.3 historical by type display |
2225 | + groupname = _(CYA_ACC_TYPE[acc->type]); |
2226 | + } |
2227 | + |
2228 | + if( g_hash_table_contains(hash, groupname) == FALSE ) |
2229 | + { |
2230 | + g_hash_table_insert(hash, g_strdup(groupname), g_ptr_array_sized_new(nballoc) ); |
2231 | + //DB( g_print(" - type hash insert '%s' = %d\n", groupname, inserted) ); |
2232 | + } |
2233 | + |
2234 | + group = g_hash_table_lookup(hash, groupname); |
2235 | + if( group != NULL ) |
2236 | + { |
2237 | + g_ptr_array_add(group, (gpointer)acc); |
2238 | + DB( g_print(" -- add '%s' to group '%s'\n", acc->name, groupname) ); |
2239 | + } |
2240 | + } |
2241 | + elt = g_list_next(elt); |
2242 | + } |
2243 | + |
2244 | + DB( g_print(" end\n") ); |
2245 | + |
2246 | + return hash; |
2247 | +} |
2248 | + |
2249 | + |
2250 | + |
2251 | + |
2252 | + |
2253 | + |
2254 | +void ui_mainwindow_populate_accounts(GtkWidget *widget, gpointer user_data) |
2255 | +{ |
2256 | +struct hbfile_data *data; |
2257 | +GtkTreeModel *model; |
2258 | +GtkTreeIter iter1, child_iter; |
2259 | +GList *lacc, *elt; |
2260 | +Account *acc; |
2261 | +guint j, nbtype; |
2262 | +gdouble gtbank, gttoday, gtfuture; |
2263 | + |
2264 | +GHashTable *h_group; |
2265 | +GHashTableIter grp_iter; |
2266 | +gpointer key, value; |
2267 | + |
2268 | + DB( g_print("\n[ui-mainwindow] populate accounts\n") ); |
2269 | + |
2270 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
2271 | + |
2272 | + /* here we create a count and a list of every account pointer by type */ |
2273 | + lacc = elt = g_hash_table_get_values(GLOBALS->h_acc); |
2274 | + |
2275 | + h_group = ui_panel_accounts_groups_get(lacc, PREFS->pnl_acc_show_by, data->showall); |
2276 | + g_list_free(lacc); |
2277 | + |
2278 | + |
2279 | + gtbank = gttoday = gtfuture = 0; |
2280 | + |
2281 | + DB( g_print(" - populate listview, %d group(s)\n", g_hash_table_size(h_group)) ); |
2282 | + |
2283 | + model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc)); |
2284 | + gtk_tree_store_clear (GTK_TREE_STORE(model)); |
2285 | + |
2286 | + nbtype = 0; |
2287 | + g_hash_table_iter_init (&grp_iter, h_group); |
2288 | + while (g_hash_table_iter_next (&grp_iter, &key, &value)) |
2289 | + { |
2290 | + GPtrArray *gpa = value; |
2291 | + gdouble tbank, ttoday, tfuture; |
2292 | + gint position; |
2293 | + |
2294 | + if(gpa != NULL) |
2295 | + { |
2296 | + nbtype++; |
2297 | + //1: Header: Bank, Cash, ... |
2298 | + DB( g_print(" - add group '%s'\n", (gchar *)key) ); |
2299 | + |
2300 | + //#1663399 keep type position like in dropdown |
2301 | + position = 0; |
2302 | + if( PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE ) |
2303 | + { |
2304 | + gint t = 0; |
2305 | + |
2306 | + while(CYA_ACC_TYPE[t] != NULL && t < 15) |
2307 | + { |
2308 | + if( !strcmp(CYA_ACC_TYPE[t], key) ) |
2309 | + break; |
2310 | + t++; |
2311 | + } |
2312 | + |
2313 | + position = t; |
2314 | + } |
2315 | + |
2316 | + gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL); |
2317 | + gtk_tree_store_set (GTK_TREE_STORE(model), &iter1, |
2318 | + LST_DSPACC_POS, position, |
2319 | + LST_DSPACC_DATATYPE, DSPACC_TYPE_HEADER, |
2320 | + LST_DSPACC_NAME, key, |
2321 | + -1); |
2322 | + |
2323 | + tbank = ttoday = tfuture = 0; |
2324 | + |
2325 | + //2: Accounts for real |
2326 | + for(j=0;j<gpa->len;j++) |
2327 | + { |
2328 | + acc = g_ptr_array_index(gpa, j); |
2329 | + |
2330 | + //tbank += acc->bal_bank; |
2331 | + //ttoday += acc->bal_today; |
2332 | + //tfuture += acc->bal_future; |
2333 | + tbank += hb_amount_base(acc->bal_bank, acc->kcur); |
2334 | + ttoday += hb_amount_base(acc->bal_today, acc->kcur); |
2335 | + tfuture += hb_amount_base(acc->bal_future, acc->kcur); |
2336 | + |
2337 | + DB( g_print(" - add account '%s' :: %.2f %.2f %.2f\n", acc->name, acc->bal_bank, acc->bal_today, acc->bal_future) ); |
2338 | + |
2339 | + gtk_tree_store_append (GTK_TREE_STORE(model), &child_iter, &iter1); |
2340 | + gtk_tree_store_set (GTK_TREE_STORE(model), &child_iter, |
2341 | + LST_DSPACC_DATAS, acc, |
2342 | + LST_DSPACC_DATATYPE, DSPACC_TYPE_NORMAL, |
2343 | + LST_DSPACC_BANK, acc->bal_bank, |
2344 | + LST_DSPACC_TODAY, acc->bal_today, |
2345 | + LST_DSPACC_FUTURE, acc->bal_future, |
2346 | + -1); |
2347 | + } |
2348 | + |
2349 | + if(gpa->len > 1) |
2350 | + { |
2351 | + DB( g_print(" - group total :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) ); |
2352 | + |
2353 | + // insert the total line |
2354 | + gtk_tree_store_append (GTK_TREE_STORE(model), &child_iter, &iter1); |
2355 | + gtk_tree_store_set (GTK_TREE_STORE(model), &child_iter, |
2356 | + LST_DSPACC_DATATYPE, DSPACC_TYPE_SUBTOTAL, |
2357 | + LST_DSPACC_NAME, _("Total"), |
2358 | + LST_DSPACC_BANK, tbank, |
2359 | + LST_DSPACC_TODAY, ttoday, |
2360 | + LST_DSPACC_FUTURE, tfuture, |
2361 | + -1); |
2362 | + } |
2363 | + |
2364 | + /* set balance to header to display when collasped */ |
2365 | + DB( g_print(" - enrich group total header :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) ); |
2366 | + gtk_tree_store_set (GTK_TREE_STORE(model), &iter1, |
2367 | + LST_DSPACC_BANK, tbank, |
2368 | + LST_DSPACC_TODAY, ttoday, |
2369 | + LST_DSPACC_FUTURE, tfuture, |
2370 | + -1); |
2371 | + |
2372 | + /* add to grand total */ |
2373 | + gtbank += tbank; |
2374 | + gttoday += ttoday; |
2375 | + gtfuture += tfuture; |
2376 | + |
2377 | + } |
2378 | + |
2379 | + } |
2380 | + |
2381 | + DB( g_print(" - grand total :: %.2f %.2f %.2f\n", gtbank, gttoday, gtfuture) ); |
2382 | + |
2383 | + // Grand total |
2384 | + if( nbtype > 1 ) |
2385 | + { |
2386 | + gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL); |
2387 | + gtk_tree_store_set (GTK_TREE_STORE(model), &iter1, |
2388 | + LST_DSPACC_DATATYPE, DSPACC_TYPE_SUBTOTAL, |
2389 | + LST_DSPACC_NAME, _("Grand total"), |
2390 | + LST_DSPACC_BANK, gtbank, |
2391 | + LST_DSPACC_TODAY, gttoday, |
2392 | + LST_DSPACC_FUTURE, gtfuture, |
2393 | + -1); |
2394 | + } |
2395 | + |
2396 | + |
2397 | + gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_acc)); |
2398 | + |
2399 | + DB( g_print(" - free ressources\n") ); |
2400 | + |
2401 | + g_hash_table_iter_init (&grp_iter, h_group); |
2402 | + while (g_hash_table_iter_next (&grp_iter, &key, &value)) |
2403 | + { |
2404 | + g_ptr_array_free (value, TRUE); |
2405 | + } |
2406 | + g_hash_table_destroy (h_group); |
2407 | + |
2408 | +} |
2409 | + |
2410 | + |
2411 | +void ui_mainwindow_update(GtkWidget *widget, gpointer user_data) |
2412 | +{ |
2413 | +struct hbfile_data *data; |
2414 | +gint flags; |
2415 | + |
2416 | + DB( g_print("\n[ui-mainwindow] update %p\n", user_data) ); |
2417 | + |
2418 | + data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); |
2419 | + //data = INST_DATA(widget); |
2420 | + |
2421 | + flags = GPOINTER_TO_INT(user_data); |
2422 | + |
2423 | + /* set window title */ |
2424 | + if(flags & UF_TITLE) |
2425 | + { |
2426 | + gchar *basename; |
2427 | + gchar *changed; |
2428 | + |
2429 | + DB( g_print(" 1: wintitle %p\n", data->wintitle) ); |
2430 | + |
2431 | + basename = g_path_get_basename(GLOBALS->xhb_filepath); |
2432 | + |
2433 | + DB( g_print(" global changes: %d\n", GLOBALS->changes_count) ); |
2434 | + |
2435 | + g_free(data->wintitle); |
2436 | + |
2437 | + changed = (GLOBALS->changes_count > 0) ? "*" : ""; |
2438 | + |
2439 | +#if MYDEBUG == 1 |
2440 | + data->wintitle = g_strdup_printf("%s%s (%d)- %s - " PROGNAME, changed, basename, GLOBALS->changes_count, GLOBALS->owner); |
2441 | +#else |
2442 | + data->wintitle = g_strdup_printf("%s%s - %s - " PROGNAME, changed, basename, GLOBALS->owner); |
2443 | +#endif |
2444 | + |
2445 | + gtk_window_set_title (GTK_WINDOW (gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), data->wintitle); |
2446 | + |
2447 | + g_free(basename); |
2448 | + } |
2449 | + |
2450 | + /* update disabled things */ |
2451 | + if(flags & UF_SENSITIVE) |
2452 | + { |
2453 | + GtkTreeSelection *selection; |
2454 | + GtkTreeModel *model; |
2455 | + GtkTreeIter iter; |
2456 | + GtkTreePath *path; |
2457 | + gboolean active,sensitive; |
2458 | + |
2459 | + DB( g_print(" 2: disabled, opelist count\n") ); |
2460 | + |
2461 | + //#1656531 |
2462 | + data->acc = NULL; |
2463 | + |
2464 | + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_acc)); |
2465 | + active = gtk_tree_selection_get_selected(selection, &model, &iter); |
2466 | + if(active) |
2467 | + { |
2468 | + Account *acc; |
2469 | + gint depth; |
2470 | + |
2471 | + path = gtk_tree_model_get_path(model, &iter); |
2472 | + depth = gtk_tree_path_get_depth(path); |
2473 | + |
2474 | + if( depth > 1 ) |
2475 | + { |
2476 | + DB( g_print(" depth is %d\n", depth) ); |
2477 | + |
2478 | + gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPACC_DATAS, &acc, -1); |
2479 | + data->acc = acc; |
2480 | + } |
2481 | + else |
2482 | + active = FALSE; |
2483 | + } |
2484 | + |
2485 | + DB( g_print(" changes %d - new %d\n", GLOBALS->changes_count, GLOBALS->hbfile_is_new) ); |
2486 | + |
2487 | + // save |
2488 | + sensitive = (GLOBALS->changes_count != 0 ) ? TRUE : FALSE; |
2489 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Save"), sensitive); |
2490 | + |
2491 | + // backup |
2492 | + sensitive = ( (GLOBALS->changes_count != 0) && GLOBALS->xhb_hasrevert ) ? TRUE : FALSE; |
2493 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Revert"), sensitive); |
2494 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/OpenBak"), sensitive); |
2495 | + |
2496 | + // define off ? |
2497 | + sensitive = GLOBALS->define_off == 0 ? TRUE : FALSE; |
2498 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Account"), sensitive); |
2499 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Payee"), sensitive); |
2500 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Category"), sensitive); |
2501 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Budget"), sensitive); |
2502 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/EditMenu/Preferences"), sensitive); |
2503 | + |
2504 | + // empty account list: disable Archives, Edit, Filter, Add, Statistics, Overdrawn, Car Cost |
2505 | + sensitive = da_acc_length() > 0 ? TRUE : FALSE; |
2506 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Close"), sensitive); |
2507 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Archive"), sensitive); |
2508 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/AddTxn"), sensitive); |
2509 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/ShowTxn"), sensitive); |
2510 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RStatistics"), sensitive); |
2511 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RTrendTime"), sensitive); |
2512 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RBudget"), sensitive); |
2513 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RBalance"), sensitive); |
2514 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RVehiculeCost"), sensitive); |
2515 | + |
2516 | + // empty category list: disable Budget |
2517 | + sensitive = da_cat_length() > 1 ? TRUE : FALSE; |
2518 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Budget"), sensitive); |
2519 | + |
2520 | + //#1501129 no need to disable, P & C can be created from assign dialog |
2521 | + //sensitive = ((da_cat_length() > 1) || (da_pay_length() > 1)) ? TRUE : FALSE; |
2522 | + //gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Assign"), sensitive); |
2523 | + |
2524 | + // empty archive list: disable scheduled check |
2525 | + sensitive = g_list_length(GLOBALS->arc_list) > 0 ? TRUE : FALSE; |
2526 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/AddScheduled"), sensitive); |
2527 | + |
2528 | + // no active account: disable Edit, Over |
2529 | + sensitive = (active == TRUE ) ? TRUE : FALSE; |
2530 | + if(data->acc && data->acc->window != NULL) |
2531 | + sensitive = FALSE; |
2532 | + gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/ShowTxn"), sensitive); |
2533 | + } |
2534 | + |
2535 | + /* update toolbar, list */ |
2536 | + if(flags & UF_VISUAL) |
2537 | + { |
2538 | + DB( g_print(" 8: visual\n") ); |
2539 | + |
2540 | + if(PREFS->toolbar_style == 0) |
2541 | + gtk_toolbar_unset_style(GTK_TOOLBAR(data->toolbar)); |
2542 | + else |
2543 | + gtk_toolbar_set_style(GTK_TOOLBAR(data->toolbar), PREFS->toolbar_style-1); |
2544 | + |
2545 | + gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (data->LV_acc), PREFS->grid_lines); |
2546 | + gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_acc)); |
2547 | + |
2548 | + gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (data->LV_upc), PREFS->grid_lines); |
2549 | + gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_upc)); |
2550 | + |
2551 | + DB( g_print(" - show toolbar=%d\n", PREFS->wal_toolbar) ); |
2552 | + if(PREFS->wal_toolbar) |
2553 | + gtk_widget_show(GTK_WIDGET(data->toolbar)); |
2554 | + else |
2555 | + gtk_widget_hide(GTK_WIDGET(data->toolbar)); |
2556 | + |
2557 | + |
2558 | + DB( g_print(" - show top_spending=%d\n", PREFS->wal_spending) ); |
2559 | + |
2560 | + gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_range), PREFS->date_range_wal); |
2561 | + |
2562 | + if(PREFS->wal_spending) |
2563 | + gtk_widget_show(GTK_WIDGET(data->GR_top)); |
2564 | + else |
2565 | + gtk_widget_hide(GTK_WIDGET(data->GR_top)); |
2566 | + |
2567 | + |
2568 | + |
2569 | + DB( g_print(" - show upcoming=%d\n", PREFS->wal_upcoming) ); |
2570 | + if(PREFS->wal_upcoming) |
2571 | + gtk_widget_show(GTK_WIDGET(data->GR_upc)); |
2572 | + else |
2573 | + gtk_widget_hide(GTK_WIDGET(data->GR_upc)); |
2574 | + |
2575 | + DB( g_print(" minor %d\n", PREFS->euro_active) ); |
2576 | + gtk_action_set_visible(gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/AsMinor"), PREFS->euro_active); |
2577 | + } |
2578 | + |
2579 | + /* update balances */ |
2580 | + if(flags & UF_BALANCE) |
2581 | + { |
2582 | + |
2583 | + DB( g_print(" 4: balances\n") ); |
2584 | + |
2585 | + gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_acc)); |
2586 | + |
2587 | + //minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor)); |
2588 | + |
2589 | + /* |
2590 | + hb-label_set_colvalue(GTK_LABEL(data->TX_balance[0]), data->bank, minor); |
2591 | + hb-label_set_colvalue(GTK_LABEL(data->TX_balance[1]), data->today, minor); |
2592 | + hb-label_set_colvalue(GTK_LABEL(data->TX_balance[2]), data->future, minor); |
2593 | + */ |
2594 | + } |
2595 | + |
2596 | + if(flags & UF_REFRESHALL) |
2597 | + { |
2598 | + DB( g_print(" 16: refreshall\n") ); |
2599 | + |
2600 | + ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); |
2601 | + ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL); |
2602 | + ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); |
2603 | + } |
2604 | + |
2605 | + |
2606 | +} |
2607 | + |
2608 | + |
2609 | + |
2610 | +static void |
2611 | + ui_mainwindow_onRowActivated (GtkTreeView *treeview, |
2612 | + GtkTreePath *path, |
2613 | + GtkTreeViewColumn *col, |
2614 | + gpointer userdata) |
2615 | + { |
2616 | + GtkTreeModel *model; |
2617 | + GtkTreeIter iter; |
2618 | + |
2619 | + DB( g_print ("\n[ui-mainwindow] A row has been double-clicked!\n") ); |
2620 | + |
2621 | + model = gtk_tree_view_get_model(treeview); |
2622 | + |
2623 | + if (gtk_tree_model_get_iter(model, &iter, path)) |
2624 | + { |
2625 | + Account *acc; |
2626 | + |
2627 | + gtk_tree_model_get(model, &iter, LST_DSPACC_DATAS, &acc, -1); |
2628 | + |
2629 | + if( acc != NULL ) |
2630 | + { |
2631 | + |
2632 | + DB( g_print ("Double-clicked row contains name %s\n", acc->name) ); |
2633 | + |
2634 | + ui_mainwindow_action_showtransactions(); |
2635 | + |
2636 | + //g_free(name); |
2637 | + } |
2638 | + } |
2639 | + } |
2640 | + |
2641 | + |
2642 | +static void ui_mainwindow_destroy(GtkTreeView *treeview, gpointer user_data) |
2643 | +{ |
2644 | + DB( g_print("\n[ui-mainwindow] destroy\n") ); |
2645 | + |
2646 | +} |
2647 | + |
2648 | + |
2649 | +/* |
2650 | +** |
2651 | +*/ |
2652 | +static gboolean ui_mainwindow_dispose(GtkWidget *widget, GdkEvent *event, gpointer user_data) |
2653 | +{ |
2654 | +struct hbfile_data *data = user_data; |
2655 | +struct WinGeometry *wg; |
2656 | +gboolean retval = FALSE; |
2657 | + |
2658 | + DB( g_print("\n[ui-mainwindow] delete-event\n") ); |
2659 | + |
2660 | + //store position and size |
2661 | + wg = &PREFS->wal_wg; |
2662 | + gtk_window_get_position(GTK_WINDOW(widget), &wg->l, &wg->t); |
2663 | + gtk_window_get_size(GTK_WINDOW(widget), &wg->w, &wg->h); |
2664 | + GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(widget)); |
2665 | + GdkWindowState state = gdk_window_get_state(gdk_window); |
2666 | + wg->s = (state & GDK_WINDOW_STATE_MAXIMIZED) ? 1 : 0; |
2667 | + |
2668 | + 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) ); |
2669 | + |
2670 | + PREFS->wal_vpaned = gtk_paned_get_position(GTK_PANED(data->vpaned)); |
2671 | + PREFS->wal_hpaned = gtk_paned_get_position(GTK_PANED(data->hpaned)); |
2672 | + |
2673 | + DB( g_print(" - vpaned=%d hpaned=%d\n", PREFS->wal_vpaned, PREFS->wal_hpaned) ); |
2674 | + |
2675 | + //todo |
2676 | + if(ui_dialog_msg_savechanges(widget, NULL) == FALSE) |
2677 | + { |
2678 | + retval = TRUE; |
2679 | + } |
2680 | + else |
2681 | + { |
2682 | + //todo: retval is useless and below should move to destroy |
2683 | + retval = TRUE; |
2684 | + gtk_widget_destroy(data->LV_top); |
2685 | + |
2686 | + g_free(data->wintitle); |
2687 | + da_filter_free(data->filter); |
2688 | + g_free(user_data); |
2689 | + |
2690 | + gtk_main_quit(); |
2691 | + } |
2692 | + |
2693 | + //TRUE:stop other handlers from being invoked for the event | FALSE: propagate |
2694 | + return retval; |
2695 | +} |
2696 | + |
2697 | + |
2698 | +static void ui_mainwindow_recent_chooser_item_activated_cb (GtkRecentChooser *chooser, struct hbfile_data *data) |
2699 | +{ |
2700 | + gchar *uri, *path; |
2701 | + GError *error = NULL; |
2702 | + |
2703 | + uri = gtk_recent_chooser_get_current_uri (chooser); |
2704 | + |
2705 | + path = g_filename_from_uri (uri, NULL, NULL); |
2706 | + if (error) |
2707 | + { |
2708 | + g_warning ("Could not convert uri \"%s\" to a local path: %s", uri, error->message); |
2709 | + g_error_free (error); |
2710 | + return; |
2711 | + } |
2712 | + |
2713 | + if( ui_dialog_msg_savechanges(data->window, NULL) == TRUE ) |
2714 | + { |
2715 | + |
2716 | + //todo: FixMe |
2717 | + /* |
2718 | + if (! load) |
2719 | + { |
2720 | + gpw_recent_remove (gpw, path); |
2721 | + } |
2722 | + */ |
2723 | + |
2724 | + hbfile_change_filepath(path); |
2725 | + ui_mainwindow_open_internal(data->window, NULL); |
2726 | + } |
2727 | + else |
2728 | + { |
2729 | + g_free (path); |
2730 | + } |
2731 | + g_free (uri); |
2732 | +} |
2733 | + |
2734 | + |
2735 | +void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path) |
2736 | +{ |
2737 | + GtkRecentData *recent_data; |
2738 | + gchar *uri; |
2739 | + GError *error = NULL; |
2740 | + |
2741 | + DB( g_print("\n[ui-mainwindow] recent_add\n") ); |
2742 | + |
2743 | + DB( g_print(" - file has .xhb suffix = %d\n", g_str_has_suffix (path, ".xhb") ) ); |
2744 | + |
2745 | + if( g_str_has_suffix (path, ".xhb") == FALSE ) //ignore reverted file |
2746 | + return; |
2747 | + |
2748 | + uri = g_filename_to_uri (path, NULL, &error); |
2749 | + if (error) |
2750 | + { |
2751 | + g_warning ("Could not convert uri \"%s\" to a local path: %s", uri, error->message); |
2752 | + g_error_free (error); |
2753 | + return; |
2754 | + } |
2755 | + |
2756 | + recent_data = g_slice_new (GtkRecentData); |
2757 | + |
2758 | + recent_data->display_name = NULL; |
2759 | + recent_data->description = NULL; |
2760 | + recent_data->mime_type = "application/x-homebank"; |
2761 | + recent_data->app_name = (gchar *) g_get_application_name (); |
2762 | + recent_data->app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL); |
2763 | + recent_data->groups = NULL; |
2764 | + recent_data->is_private = FALSE; |
2765 | + |
2766 | + if (!gtk_recent_manager_add_full (data->recent_manager, |
2767 | + uri, |
2768 | + recent_data)) |
2769 | + { |
2770 | + g_warning ("Unable to add '%s' to the list of recently used documents", uri); |
2771 | + } |
2772 | + |
2773 | + g_free (uri); |
2774 | + g_free (recent_data->app_exec); |
2775 | + g_slice_free (GtkRecentData, recent_data); |
2776 | + |
2777 | +} |
2778 | + |
2779 | + |
2780 | + |
2781 | + |
2782 | + |
2783 | +enum |
2784 | +{ |
2785 | + TARGET_URI_LIST |
2786 | +}; |
2787 | + |
2788 | +static GtkTargetEntry drop_types[] = |
2789 | +{ |
2790 | + {"text/uri-list", 0, TARGET_URI_LIST} |
2791 | +}; |
2792 | + |
2793 | +static void ui_mainwindow_drag_data_received (GtkWidget *widget, |
2794 | + GdkDragContext *context, |
2795 | + gint x, gint y, |
2796 | + GtkSelectionData *selection_data, |
2797 | + guint info, guint time, GtkWindow *window) |
2798 | +{ |
2799 | +gchar **uris, **str; |
2800 | +gchar *newseldata; |
2801 | +gint n_uris, filetype, slen; |
2802 | +GError *error = NULL; |
2803 | + |
2804 | + if (info != TARGET_URI_LIST) |
2805 | + return; |
2806 | + |
2807 | + DB( g_print("\n[ui-mainwindow] drag_data_received\n") ); |
2808 | + |
2809 | + /* On MS-Windows, it looks like `selection_data->data' is not NULL terminated. */ |
2810 | + slen = gtk_selection_data_get_length(selection_data); |
2811 | + newseldata = g_new (gchar, slen + 1); |
2812 | + memcpy (newseldata, gtk_selection_data_get_data(selection_data), slen); |
2813 | + newseldata[slen] = 0; |
2814 | + //DB( g_print(" - seldata ='%s'\n", gtk_selection_data_get_data(selection_data) ) ); |
2815 | + //DB( g_print(" - newseldata ='%s'\n", newseldata ) ); |
2816 | + |
2817 | + uris = g_uri_list_extract_uris (newseldata); |
2818 | + n_uris = g_strv_length(uris); |
2819 | + DB( g_print(" - dragged %d files (len=%d)\n", n_uris, slen ) ); |
2820 | + |
2821 | + g_free(newseldata); |
2822 | + |
2823 | + //single file: check for xhb |
2824 | + if(n_uris == 1) |
2825 | + { |
2826 | + filetype = hb_filename_type_get_by_extension(*uris); |
2827 | + |
2828 | + DB( g_print(" - filetype is homebank (%d)\n", filetype) ); |
2829 | + |
2830 | + if( filetype == FILETYPE_HOMEBANK ) |
2831 | + { |
2832 | + gchar *path = g_filename_from_uri (*uris, NULL, &error); |
2833 | + |
2834 | + if( path != NULL ) |
2835 | + { |
2836 | + DB( g_print(" - path is '%s'\n", path) ); |
2837 | + hbfile_change_filepath(g_strdup(path)); |
2838 | + ui_mainwindow_open_internal(GTK_WIDGET(window), NULL); |
2839 | + goto end_drop; |
2840 | + } |
2841 | + else |
2842 | + { |
2843 | + g_warning ("Could not convert uri to local path: %s", error->message); |
2844 | + g_error_free (error); |
2845 | + } |
2846 | + g_free (path); |
2847 | + } |
2848 | + /* we no more manage error here |
2849 | + ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_ERROR, |
2850 | + _("File error"), |
2851 | + _("The file %s is not a valid HomeBank file."), |
2852 | + path); |
2853 | + */ |
2854 | + } |
2855 | + |
2856 | + //collect known filetype to import |
2857 | + DB( g_print(" - collect %d files\n", n_uris) ); |
2858 | + |
2859 | + gchar **paths = g_new (gchar *, n_uris + 1); |
2860 | + slen = 0; |
2861 | + for (str = uris; *str; str++) |
2862 | + { |
2863 | + filetype = hb_filename_type_get_by_extension(*str); |
2864 | + if( filetype != FILETYPE_HOMEBANK && filetype != FILETYPE_UNKNOWN ) |
2865 | + { |
2866 | + gchar *path = g_filename_from_uri (*str, NULL, NULL); |
2867 | + |
2868 | + if( path != NULL ) |
2869 | + { |
2870 | + DB( g_print(" - append %d '%s'\n", slen, path ) ); |
2871 | + paths[slen++] = path; |
2872 | + } |
2873 | + } |
2874 | + } |
2875 | + paths[slen] = NULL; |
2876 | + |
2877 | + if( slen > 0 ) |
2878 | + { |
2879 | + ui_import_assistant_new( paths ); |
2880 | + } |
2881 | + |
2882 | + |
2883 | +end_drop: |
2884 | + g_strfreev (uris); |
2885 | +} |
2886 | + |
2887 | + |
2888 | +static GtkWidget *ui_mainwindow_create_recent_chooser_menu (GtkRecentManager *manager) |
2889 | +{ |
2890 | +GtkWidget *recent_menu; |
2891 | +GtkRecentFilter *filter; |
2892 | + |
2893 | + recent_menu = gtk_recent_chooser_menu_new_for_manager (manager); |
2894 | + gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (recent_menu), FALSE); |
2895 | + gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (recent_menu), GTK_RECENT_SORT_MRU); |
2896 | + //todo: add a user pref for this |
2897 | + gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER (recent_menu), 10); |
2898 | + gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER (recent_menu), FALSE); |
2899 | + //gtk_recent_chooser_menu_set_show_numbers (GTK_RECENT_CHOOSER_MENU (recent_menu), TRUE); |
2900 | + |
2901 | + filter = gtk_recent_filter_new (); |
2902 | + //gtk_recent_filter_add_application (filter, g_get_application_name()); |
2903 | + gtk_recent_filter_add_pattern (filter, "*.[Xx][Hh][Bb]"); |
2904 | + gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (recent_menu), filter); |
2905 | + |
2906 | + return recent_menu; |
2907 | +} |
2908 | + |
2909 | + |
2910 | +static void ui_mainwindow_create_menu_bar_and_toolbar(struct hbfile_data *data, GtkWidget *mainvbox) |
2911 | +{ |
2912 | +GtkUIManager *manager; |
2913 | +GtkActionGroup *actions; |
2914 | +GtkAction *action; |
2915 | +GError *error = NULL; |
2916 | + |
2917 | + manager = gtk_ui_manager_new (); |
2918 | + data->manager = manager; |
2919 | + |
2920 | + gtk_window_add_accel_group (GTK_WINDOW (data->window), |
2921 | + gtk_ui_manager_get_accel_group(manager)); |
2922 | + |
2923 | + actions = gtk_action_group_new ("MainWindow"); |
2924 | + gtk_action_group_set_translation_domain(actions, GETTEXT_PACKAGE); |
2925 | + |
2926 | + gtk_action_group_add_actions (actions, |
2927 | + entries, |
2928 | + n_entries, |
2929 | + NULL); |
2930 | + |
2931 | + gtk_action_group_add_toggle_actions (actions, |
2932 | + toggle_entries, |
2933 | + n_toggle_entries, |
2934 | + NULL); |
2935 | + |
2936 | + gtk_ui_manager_insert_action_group (data->manager, actions, 0); |
2937 | + g_object_unref (actions); |
2938 | + data->actions = actions; |
2939 | + |
2940 | + /* set short labels to use in the toolbar */ |
2941 | + action = gtk_action_group_get_action(actions, "Open"); |
2942 | + g_object_set(action, "short_label", _("Open"), NULL); |
2943 | + |
2944 | + //action = gtk_action_group_get_action(action_group, "Save"); |
2945 | + //g_object_set(action, "is_important", TRUE, NULL); |
2946 | + |
2947 | + action = gtk_action_group_get_action(actions, "Account"); |
2948 | + g_object_set(action, "short_label", _("Account"), NULL); |
2949 | + |
2950 | + action = gtk_action_group_get_action(actions, "Payee"); |
2951 | + g_object_set(action, "short_label", _("Payee"), NULL); |
2952 | + |
2953 | + action = gtk_action_group_get_action(actions, "Category"); |
2954 | + g_object_set(action, "short_label", _("Category"), NULL); |
2955 | + |
2956 | + action = gtk_action_group_get_action(actions, "Archive"); |
2957 | + //TRANSLATORS: an archive is stored transaction buffers (kind of bookmark to prefill manual insertion) |
2958 | + g_object_set(action, "short_label", _("Archive"), NULL); |
2959 | + |
2960 | + action = gtk_action_group_get_action(actions, "Budget"); |
2961 | + g_object_set(action, "short_label", _("Budget"), NULL); |
2962 | + |
2963 | + action = gtk_action_group_get_action(actions, "ShowTxn"); |
2964 | + g_object_set(action, "short_label", _("Show"), NULL); |
2965 | + |
2966 | + action = gtk_action_group_get_action(actions, "AddTxn"); |
2967 | + g_object_set(action, "is_important", TRUE, "short_label", _("Add"), NULL); |
2968 | + |
2969 | + action = gtk_action_group_get_action(actions, "RStatistics"); |
2970 | + g_object_set(action, "short_label", _("Statistics"), NULL); |
2971 | + |
2972 | + action = gtk_action_group_get_action(actions, "RBudget"); |
2973 | + g_object_set(action, "short_label", _("Budget"), NULL); |
2974 | + |
2975 | + action = gtk_action_group_get_action(actions, "RBalance"); |
2976 | + g_object_set(action, "short_label", _("Balance"), NULL); |
2977 | + |
2978 | + action = gtk_action_group_get_action(actions, "RVehiculeCost"); |
2979 | + g_object_set(action, "short_label", _("Vehicle cost"), NULL); |
2980 | + |
2981 | + /* now load the UI definition */ |
2982 | + gtk_ui_manager_add_ui_from_string (data->manager, ui_info, -1, &error); |
2983 | + if (error != NULL) |
2984 | + { |
2985 | + g_message ("Building menus failed: %s", error->message); |
2986 | + g_error_free (error); |
2987 | + } |
2988 | + |
2989 | + |
2990 | + data->recent_manager = gtk_recent_manager_get_default (); |
2991 | + |
2992 | + data->menubar = gtk_ui_manager_get_widget (manager, "/MenuBar"); |
2993 | + gtk_box_pack_start (GTK_BOX (mainvbox), |
2994 | + data->menubar, |
2995 | + FALSE, |
2996 | + FALSE, |
2997 | + 0); |
2998 | + |
2999 | + /* recent files menu */ |
3000 | + data->recent_menu = ui_mainwindow_create_recent_chooser_menu (data->recent_manager); |
3001 | + |
3002 | + g_signal_connect (data->recent_menu, |
3003 | + "item-activated", |
3004 | + G_CALLBACK (ui_mainwindow_recent_chooser_item_activated_cb), |
3005 | + data); |
3006 | + |
3007 | + GtkWidget *widget = gtk_ui_manager_get_widget (data->manager, "/MenuBar/FileMenu/RecentMenu"); |
3008 | + gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), data->recent_menu); |
3009 | + |
3010 | + |
3011 | + data->toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar"); |
3012 | + gtk_box_pack_start (GTK_BOX (mainvbox), |
3013 | + data->toolbar, |
3014 | + FALSE, |
3015 | + FALSE, |
3016 | + 0); |
3017 | + |
3018 | + /* add the custom Open button to the toolbar */ |
3019 | + GtkWidget *image = gtk_image_new_from_icon_name (ICONNAME_HB_FILE_OPEN, GTK_ICON_SIZE_BUTTON); |
3020 | + GtkToolItem *open_button = gtk_menu_tool_button_new(image, _("_Open")); |
3021 | + gtk_tool_item_set_tooltip_text (open_button, _("Open a file")); |
3022 | + |
3023 | + GtkWidget *recent_menu = ui_mainwindow_create_recent_chooser_menu (data->recent_manager); |
3024 | + gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (open_button), recent_menu); |
3025 | + gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (open_button), _("Open a recently used file")); |
3026 | + |
3027 | + g_signal_connect (recent_menu, |
3028 | + "item-activated", |
3029 | + G_CALLBACK (ui_mainwindow_recent_chooser_item_activated_cb), |
3030 | + data); |
3031 | + |
3032 | + action = gtk_action_group_get_action (data->actions, "Open"); |
3033 | + g_object_set (action, "short_label", _("Open"), NULL); |
3034 | + //gtk_action_connect_proxy (action, GTK_WIDGET (open_button)); |
3035 | + gtk_activatable_set_related_action (GTK_ACTIVATABLE (open_button), action); |
3036 | + |
3037 | + gtk_toolbar_insert (GTK_TOOLBAR (data->toolbar), open_button, 1); |
3038 | + |
3039 | +} |
3040 | + |
3041 | + |
3042 | +/* Callback function for the undo action */ |
3043 | +/*static void |
3044 | +activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) |
3045 | +{ |
3046 | + g_print ("Action %s activated\n", g_action_get_name (G_ACTION (action))); |
3047 | +}*/ |
3048 | + |
3049 | +static void |
3050 | +activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data) |
3051 | +{ |
3052 | +struct hbfile_data *data = user_data; |
3053 | + GVariant *old_state, *new_state; |
3054 | + |
3055 | + old_state = g_action_get_state (G_ACTION (action)); |
3056 | + new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state)); |
3057 | + |
3058 | + DB( g_print ("Toggle action %s activated, state changes from %d to %d\n", |
3059 | + g_action_get_name (G_ACTION (action)), |
3060 | + g_variant_get_boolean (old_state), |
3061 | + g_variant_get_boolean (new_state)) ); |
3062 | + |
3063 | + data->showall = g_variant_get_boolean (new_state); |
3064 | + ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); |
3065 | + |
3066 | + g_simple_action_set_state (action, new_state); |
3067 | + g_variant_unref (old_state); |
3068 | +} |
3069 | + |
3070 | +static void |
3071 | +activate_radio (GSimpleAction *action, GVariant *parameter, gpointer user_data) |
3072 | +{ |
3073 | +//struct hbfile_data *data = user_data; |
3074 | +GVariant *old_state, *new_state; |
3075 | + |
3076 | + old_state = g_action_get_state (G_ACTION (action)); |
3077 | + new_state = g_variant_new_string (g_variant_get_string (parameter, NULL)); |
3078 | + |
3079 | + DB( g_print ("Radio action %s activated, state changes from %s to %s\n", |
3080 | + g_action_get_name (G_ACTION (action)), |
3081 | + g_variant_get_string (old_state, NULL), |
3082 | + g_variant_get_string (new_state, NULL)) ); |
3083 | + |
3084 | + PREFS->pnl_acc_show_by = DSPACC_GROUP_BY_TYPE; |
3085 | + if( !strcmp("bank", g_variant_get_string(new_state, NULL)) ) |
3086 | + PREFS->pnl_acc_show_by = DSPACC_GROUP_BY_BANK; |
3087 | + |
3088 | + ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); |
3089 | + |
3090 | + g_simple_action_set_state (action, new_state); |
3091 | + g_variant_unref (old_state); |
3092 | +} |
3093 | + |
3094 | + |
3095 | +static const GActionEntry actions[] = { |
3096 | +// name, function(), type, state, |
3097 | +// { "paste", activate_action, NULL, NULL, NULL, {0,0,0} }, |
3098 | + { "showall", activate_toggle, NULL, "false" , NULL, {0,0,0} }, |
3099 | + { "groupby", activate_radio , "s", "'type'", NULL, {0,0,0} } |
3100 | +}; |
3101 | + |
3102 | + |
3103 | +static void ui_panel_accounts_setup(struct hbfile_data *data) |
3104 | +{ |
3105 | +GAction *action; |
3106 | +GVariant *new_state; |
3107 | + |
3108 | + if( !G_IS_SIMPLE_ACTION_GROUP(data->action_group_acc) ) |
3109 | + return; |
3110 | + |
3111 | + action = g_action_map_lookup_action (G_ACTION_MAP (data->action_group_acc), "showall"); |
3112 | + if( action ) |
3113 | + { |
3114 | + new_state = g_variant_new_boolean (data->showall); |
3115 | + g_simple_action_set_state (G_SIMPLE_ACTION(action), new_state); |
3116 | + } |
3117 | + |
3118 | + action = g_action_map_lookup_action (G_ACTION_MAP (data->action_group_acc), "groupby"); |
3119 | + if( action ) |
3120 | + { |
3121 | + const gchar *value = (PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE) ? "type" : "bank"; |
3122 | + new_state = g_variant_new_string (value); |
3123 | + g_simple_action_set_state (G_SIMPLE_ACTION (action), new_state); |
3124 | + } |
3125 | + |
3126 | +} |
3127 | + |
3128 | + |
3129 | +static GtkWidget *ui_mainwindow_create_youraccounts(struct hbfile_data *data) |
3130 | +{ |
3131 | +GtkWidget *panel, *label, *widget, *sw, *tbar, *hbox, *image; |
3132 | +GtkToolItem *toolitem; |
3133 | + |
3134 | + panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); |
3135 | + gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL); |
3136 | + |
3137 | + sw = gtk_scrolled_window_new (NULL, NULL); |
3138 | + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); |
3139 | + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
3140 | + gtk_box_pack_start (GTK_BOX (panel), sw, TRUE, TRUE, 0); |
3141 | + widget = (GtkWidget *)create_list_account(); |
3142 | + data->LV_acc = widget; |
3143 | + gtk_container_add (GTK_CONTAINER (sw), widget); |
3144 | + |
3145 | + //list toolbar |
3146 | + tbar = gtk_toolbar_new(); |
3147 | + gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU); |
3148 | + gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS); |
3149 | + gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR); |
3150 | + gtk_box_pack_start (GTK_BOX (panel), tbar, FALSE, FALSE, 0); |
3151 | + |
3152 | + label = make_label_group(_("Your accounts")); |
3153 | + toolitem = gtk_tool_item_new(); |
3154 | + gtk_container_add (GTK_CONTAINER(toolitem), label); |
3155 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3156 | + |
3157 | + toolitem = gtk_separator_tool_item_new (); |
3158 | + gtk_tool_item_set_expand (toolitem, TRUE); |
3159 | + gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); |
3160 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3161 | + |
3162 | + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); |
3163 | + toolitem = gtk_tool_item_new(); |
3164 | + gtk_container_add (GTK_CONTAINER(toolitem), hbox); |
3165 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3166 | + |
3167 | + widget = make_image_button(ICONNAME_HB_BUTTON_EXPAND, _("Expand all")); |
3168 | + data->BT_expandall = widget; |
3169 | + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); |
3170 | + |
3171 | + widget = make_image_button(ICONNAME_HB_BUTTON_COLLAPSE, _("Collapse all")); |
3172 | + data->BT_collapseall = widget; |
3173 | + gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); |
3174 | + |
3175 | + toolitem = gtk_separator_tool_item_new (); |
3176 | + gtk_tool_item_set_expand (toolitem, FALSE); |
3177 | + gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); |
3178 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3179 | + |
3180 | + |
3181 | + //gmenu test (see test folder into gtk) |
3182 | +GMenu *menu, *section; |
3183 | + |
3184 | + menu = g_menu_new (); |
3185 | + //g_menu_append (menumodel, "About", "actions.undo"); |
3186 | + //g_menu_append (menumodel, "Test", "actions.redo"); |
3187 | + section = g_menu_new (); |
3188 | + g_menu_append (section, _("Show all"), "actions.showall"); |
3189 | + g_menu_append_section(menu, NULL, G_MENU_MODEL(section)); |
3190 | + g_object_unref (section); |
3191 | + |
3192 | + section = g_menu_new (); |
3193 | + g_menu_append (section, _("By type"), "actions.groupby::type"); |
3194 | + g_menu_append (section, _("By institition"), "actions.groupby::bank"); |
3195 | + g_menu_append_section(menu, NULL, G_MENU_MODEL(section)); |
3196 | + g_object_unref (section); |
3197 | + |
3198 | + |
3199 | + GSimpleActionGroup *group = g_simple_action_group_new (); |
3200 | + data->action_group_acc = group; |
3201 | + g_action_map_add_action_entries (G_ACTION_MAP (group), actions, G_N_ELEMENTS (actions), data); |
3202 | + |
3203 | + |
3204 | + widget = gtk_menu_button_new(); |
3205 | + gtk_menu_button_set_direction (GTK_MENU_BUTTON(widget), GTK_ARROW_UP); |
3206 | + gtk_widget_set_halign (widget, GTK_ALIGN_END); |
3207 | + image = gtk_image_new_from_icon_name (ICONNAME_EMBLEM_SYSTEM, GTK_ICON_SIZE_MENU); |
3208 | + g_object_set (widget, "image", image, NULL); |
3209 | + |
3210 | + toolitem = gtk_tool_item_new(); |
3211 | + gtk_container_add (GTK_CONTAINER(toolitem), widget); |
3212 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3213 | + |
3214 | + gtk_widget_insert_action_group (widget, "actions", G_ACTION_GROUP(group)); |
3215 | + gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (widget), G_MENU_MODEL (menu)); |
3216 | + |
3217 | + return panel; |
3218 | +} |
3219 | + |
3220 | + |
3221 | +static GtkWidget *ui_mainwindow_create_topspending(struct hbfile_data *data) |
3222 | +{ |
3223 | +GtkWidget *panel, *hbox, *tbar; |
3224 | +GtkWidget *label, *widget; |
3225 | +GtkToolItem *toolitem; |
3226 | + |
3227 | + widget = (GtkWidget *)create_list_topspending(); |
3228 | + data->LV_top = widget; |
3229 | + |
3230 | + panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); |
3231 | + gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL); |
3232 | + data->GR_top = panel; |
3233 | + |
3234 | + /* chart + listview */ |
3235 | + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); |
3236 | + gtk_box_pack_start (GTK_BOX (panel), hbox, TRUE, TRUE, 0); |
3237 | + |
3238 | + widget = gtk_chart_new(CHART_TYPE_PIE); |
3239 | + data->RE_pie = widget; |
3240 | + gtk_chart_set_minor_prefs(GTK_CHART(widget), PREFS->euro_value, PREFS->minor_cur.symbol); |
3241 | + gtk_chart_show_legend(GTK_CHART(data->RE_pie), TRUE, TRUE); |
3242 | + gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0); |
3243 | + |
3244 | + //list toolbar |
3245 | + tbar = gtk_toolbar_new(); |
3246 | + gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU); |
3247 | + gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS); |
3248 | + gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR); |
3249 | + gtk_box_pack_start (GTK_BOX (panel), tbar, FALSE, FALSE, 0); |
3250 | + |
3251 | + label = make_label_group(_("Where your money goes")); |
3252 | + toolitem = gtk_tool_item_new(); |
3253 | + gtk_container_add (GTK_CONTAINER(toolitem), label); |
3254 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3255 | + |
3256 | + toolitem = gtk_separator_tool_item_new (); |
3257 | + gtk_tool_item_set_expand (toolitem, TRUE); |
3258 | + gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); |
3259 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3260 | + |
3261 | + /* total + date range */ |
3262 | + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL); |
3263 | + toolitem = gtk_tool_item_new(); |
3264 | + gtk_container_add (GTK_CONTAINER(toolitem), hbox); |
3265 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3266 | + |
3267 | + data->CY_range = make_daterange(label, FALSE); |
3268 | + gtk_box_pack_end (GTK_BOX (hbox), data->CY_range, FALSE, FALSE, 0); |
3269 | + |
3270 | + widget = make_radio(CYA_CATSUBCAT, TRUE, GTK_ORIENTATION_HORIZONTAL); |
3271 | + data->RA_type = widget; |
3272 | + gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0); |
3273 | + |
3274 | + return panel; |
3275 | +} |
3276 | + |
3277 | + |
3278 | +static GtkWidget *ui_mainwindow_scheduled_create(struct hbfile_data *data) |
3279 | +{ |
3280 | +GtkWidget *panel, *hbox, *vbox, *bbox, *sw, *tbar; |
3281 | +GtkWidget *label, *widget; |
3282 | +GtkToolItem *toolitem; |
3283 | + |
3284 | + panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); |
3285 | + gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL); |
3286 | + data->GR_upc = panel; |
3287 | + |
3288 | + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); |
3289 | + //gtk_widget_set_margin_top(GTK_WIDGET(vbox), 0); |
3290 | + //gtk_widget_set_margin_bottom(GTK_WIDGET(vbox), SPACING_SMALL); |
3291 | + //gtk_widget_set_margin_start(GTK_WIDGET(vbox), 2*SPACING_SMALL); |
3292 | + //gtk_widget_set_margin_end(GTK_WIDGET(vbox), SPACING_SMALL); |
3293 | + gtk_box_pack_start (GTK_BOX (panel), vbox, TRUE, TRUE, 0); |
3294 | + |
3295 | + sw = gtk_scrolled_window_new (NULL, NULL); |
3296 | + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); |
3297 | + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
3298 | + gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); |
3299 | + |
3300 | + widget = (GtkWidget *)create_list_upcoming(); |
3301 | + data->LV_upc = widget; |
3302 | + gtk_container_add (GTK_CONTAINER (sw), widget); |
3303 | + |
3304 | + tbar = gtk_toolbar_new(); |
3305 | + gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU); |
3306 | + gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS); |
3307 | + gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR); |
3308 | + gtk_box_pack_start (GTK_BOX (vbox), tbar, FALSE, FALSE, 0); |
3309 | + |
3310 | + label = make_label_group(_("Scheduled transactions")); |
3311 | + toolitem = gtk_tool_item_new(); |
3312 | + gtk_container_add (GTK_CONTAINER(toolitem), label); |
3313 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3314 | + |
3315 | + toolitem = gtk_separator_tool_item_new (); |
3316 | + gtk_tool_item_set_expand (toolitem, FALSE); |
3317 | + gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); |
3318 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3319 | + |
3320 | + |
3321 | + bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); |
3322 | + toolitem = gtk_tool_item_new(); |
3323 | + gtk_container_add (GTK_CONTAINER(toolitem), bbox); |
3324 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3325 | + |
3326 | + widget = gtk_button_new_with_label(_("Skip")); |
3327 | + data->BT_sched_skip = widget; |
3328 | + gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0); |
3329 | + |
3330 | + widget = gtk_button_new_with_label(_("Edit & Post")); |
3331 | + data->BT_sched_editpost = widget; |
3332 | + gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0); |
3333 | + |
3334 | + //TRANSLATORS: Posting a scheduled transaction is the action to materialize it into its target account. |
3335 | + //TRANSLATORS: Before that action the automated transaction occurrence is pending and not yet really existing. |
3336 | + widget = gtk_button_new_with_label (_("Post")); |
3337 | + data->BT_sched_post = widget; |
3338 | + gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0); |
3339 | + |
3340 | + toolitem = gtk_separator_tool_item_new (); |
3341 | + gtk_tool_item_set_expand (toolitem, FALSE); |
3342 | + gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); |
3343 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3344 | + |
3345 | + hbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); |
3346 | + gtk_widget_set_valign (hbox, GTK_ALIGN_CENTER); |
3347 | + toolitem = gtk_tool_item_new(); |
3348 | + gtk_container_add (GTK_CONTAINER(toolitem), hbox); |
3349 | + gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); |
3350 | + |
3351 | + label = make_label(_("maximum post date"), 0.0, 0.7); |
3352 | + gtk_widget_set_halign (label, GTK_ALIGN_CENTER); |
3353 | + gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); |
3354 | + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); |
3355 | + |
3356 | + label = make_label(NULL, 0.0, 0.7); |
3357 | + data->LB_maxpostdate = label; |
3358 | + gtk_widget_set_halign (label, GTK_ALIGN_CENTER); |
3359 | + gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); |
3360 | + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); |
3361 | + |
3362 | + return panel; |
3363 | +} |
3364 | + |
3365 | + |
3366 | +/* |
3367 | +** the window creation |
3368 | +*/ |
3369 | +GtkWidget *create_hbfile_window(GtkWidget *do_widget) |
3370 | +{ |
3371 | +struct hbfile_data *data; |
3372 | +struct WinGeometry *wg; |
3373 | +GtkWidget *mainvbox, *vbox, *vpaned, *hpaned; |
3374 | +GtkWidget *widget; |
3375 | +GtkWidget *window; |
3376 | +GtkAction *action; |
3377 | + |
3378 | + DB( g_print("\n[ui-mainwindow] create main window\n") ); |
3379 | + |
3380 | + data = g_malloc0(sizeof(struct hbfile_data)); |
3381 | + if(!data) return NULL; |
3382 | + |
3383 | + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); |
3384 | + |
3385 | + //store our window private data |
3386 | + g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)data); |
3387 | + DB( g_print(" - new window=%p, inst_data=%p\n", window, data) ); |
3388 | + |
3389 | + // this is our mainwindow, so store it to GLOBALS data |
3390 | + data->window = window; |
3391 | + GLOBALS->mainwindow = window; |
3392 | + |
3393 | + mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); |
3394 | + gtk_container_add (GTK_CONTAINER (window), mainvbox); |
3395 | + |
3396 | + ui_mainwindow_create_menu_bar_and_toolbar (data, mainvbox); |
3397 | + |
3398 | +#if HB_UNSTABLE_SHOW == TRUE |
3399 | +GtkWidget *bar, *label; |
3400 | + |
3401 | + bar = gtk_info_bar_new (); |
3402 | + gtk_box_pack_start (GTK_BOX (mainvbox), bar, FALSE, FALSE, 0); |
3403 | + gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_WARNING); |
3404 | + label = make_label(NULL, 0.5, 0.5); |
3405 | + gtk_label_set_markup (GTK_LABEL(label), "Unstable Development Version"); |
3406 | + gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label, FALSE, FALSE, 0); |
3407 | +#endif |
3408 | + |
3409 | + /* Add the main area */ |
3410 | + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); |
3411 | + //gtk_container_set_border_width (GTK_CONTAINER(vbox), SPACING_MEDIUM); |
3412 | + gtk_box_pack_start (GTK_BOX (mainvbox), vbox, TRUE, TRUE, 0); |
3413 | + |
3414 | + vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL); |
3415 | + data->vpaned = vpaned; |
3416 | + gtk_box_pack_start (GTK_BOX (vbox), vpaned, TRUE, TRUE, 0); |
3417 | + |
3418 | + hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); |
3419 | + data->hpaned = hpaned; |
3420 | + gtk_paned_pack1 (GTK_PANED(vpaned), hpaned, FALSE, FALSE); |
3421 | + |
3422 | + widget = ui_mainwindow_scheduled_create(data); |
3423 | + gtk_paned_pack2 (GTK_PANED(vpaned), widget, TRUE, FALSE); |
3424 | + |
3425 | + widget = ui_mainwindow_create_youraccounts(data); |
3426 | + //gtk_widget_set_size_request (widget, 100, -1); |
3427 | + gtk_paned_pack1 (GTK_PANED(hpaned), widget, FALSE, FALSE); |
3428 | + |
3429 | + widget = ui_mainwindow_create_topspending(data); |
3430 | + //gtk_widget_set_size_request (widget, -1, 100); |
3431 | + gtk_paned_pack2 (GTK_PANED(hpaned), widget, TRUE, FALSE); |
3432 | + |
3433 | + |
3434 | + //setup, init and show window |
3435 | + wg = &PREFS->wal_wg; |
3436 | + if(wg->s == 0) |
3437 | + { |
3438 | + gtk_window_move(GTK_WINDOW(window), wg->l, wg->t); |
3439 | + gtk_window_resize(GTK_WINDOW(window), wg->w, wg->h); |
3440 | + } |
3441 | + else |
3442 | + gtk_window_maximize(GTK_WINDOW(window)); |
3443 | + |
3444 | + gtk_widget_show_all (window); |
3445 | + |
3446 | + //#1662197/1660910 moved after resize/show |
3447 | + DB( g_print(" - vpaned=%d hpaned=%d\n", PREFS->wal_vpaned, PREFS->wal_hpaned) ); |
3448 | + |
3449 | + if(PREFS->wal_hpaned > 0) |
3450 | + gtk_paned_set_position(GTK_PANED(data->hpaned), PREFS->wal_hpaned); |
3451 | + if(PREFS->wal_vpaned > 0) |
3452 | + gtk_paned_set_position(GTK_PANED(data->vpaned), PREFS->wal_vpaned); |
3453 | + |
3454 | + //todo: move this elsewhere |
3455 | + DB( g_print(" - setup stuff\n") ); |
3456 | + |
3457 | + data->filter = da_filter_malloc(); |
3458 | + filter_default_all_set(data->filter); |
3459 | + gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_range), PREFS->date_range_wal); |
3460 | + |
3461 | + action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Toolbar"); |
3462 | + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_toolbar); |
3463 | + action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Spending"); |
3464 | + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_spending); |
3465 | + action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Upcoming"); |
3466 | + gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_upcoming); |
3467 | + |
3468 | + /* Drag and drop support, set targets to NULL because we add the |
3469 | + default uri_targets below */ |
3470 | + |
3471 | + /* support for opening a file by dragging onto the project window */ |
3472 | + gtk_drag_dest_set (GTK_WIDGET (window), |
3473 | + GTK_DEST_DEFAULT_ALL, |
3474 | + drop_types, |
3475 | + G_N_ELEMENTS (drop_types), |
3476 | + GDK_ACTION_COPY); |
3477 | + |
3478 | + g_signal_connect (G_OBJECT (window), "drag-data-received", |
3479 | + G_CALLBACK (ui_mainwindow_drag_data_received), window); |
3480 | + |
3481 | + |
3482 | + |
3483 | + //connect all our signals |
3484 | + DB( g_print(" - connect signals\n") ); |
3485 | + |
3486 | + |
3487 | + g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_acc)), "changed", G_CALLBACK (ui_mainwindow_selection), NULL); |
3488 | + g_signal_connect (GTK_TREE_VIEW(data->LV_acc ), "row-activated", G_CALLBACK (ui_mainwindow_onRowActivated), GINT_TO_POINTER(2)); |
3489 | + g_signal_connect (G_OBJECT (data->BT_expandall ), "clicked" , G_CALLBACK (ui_panel_accounts_expand_all), NULL); |
3490 | + g_signal_connect (G_OBJECT (data->BT_collapseall), "clicked" , G_CALLBACK (ui_panel_accounts_collapse_all), NULL); |
3491 | + |
3492 | + g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_upc)), "changed", G_CALLBACK (ui_mainwindow_scheduled_selection_cb), NULL); |
3493 | + g_signal_connect (GTK_TREE_VIEW(data->LV_upc), "row-activated", G_CALLBACK (ui_mainwindow_scheduled_onRowActivated), NULL); |
3494 | + g_signal_connect (G_OBJECT (data->BT_sched_skip), "clicked", G_CALLBACK (ui_mainwindow_scheduled_skip_cb), data); |
3495 | + g_signal_connect (G_OBJECT (data->BT_sched_editpost), "clicked", G_CALLBACK (ui_mainwindow_scheduled_editpost_cb), data); |
3496 | + g_signal_connect (G_OBJECT (data->BT_sched_post), "clicked", G_CALLBACK (ui_mainwindow_scheduled_post_cb), data); |
3497 | + |
3498 | + widget = radio_get_nth_widget(GTK_CONTAINER(data->RA_type), 1); |
3499 | + if(widget) |
3500 | + g_signal_connect (widget, "toggled", G_CALLBACK (ui_mainwindow_populate_topspending), &data); |
3501 | + |
3502 | + g_signal_connect (data->CY_range, "changed", G_CALLBACK (ui_mainwindow_populate_topspending), NULL); |
3503 | + |
3504 | + |
3505 | + /* GtkWindow events */ |
3506 | + g_signal_connect (window, "delete-event", G_CALLBACK (ui_mainwindow_dispose), (gpointer)data); |
3507 | + g_signal_connect (window, "destroy", G_CALLBACK (ui_mainwindow_destroy), NULL); |
3508 | + |
3509 | + //gtk_action_group_set_sensitive(data->actions, FALSE); |
3510 | + |
3511 | + return window; |
3512 | +} |
3513 | + |
3514 | |
3515 | === added file 'src/ui-budget-tabview.c' |
3516 | --- src/ui-budget-tabview.c 1970-01-01 00:00:00 +0000 |
3517 | +++ src/ui-budget-tabview.c 2019-09-17 21:50:17 +0000 |
3518 | @@ -0,0 +1,2916 @@ |
3519 | +/* HomeBank -- Free, easy, personal accounting for everyone. |
3520 | + * Copyright (C) 2018-2019 Adrien Dorsaz <adrien@adorsaz.ch> |
3521 | + * |
3522 | + * This file is part of HomeBank. |
3523 | + * |
3524 | + * HomeBank is free software; you can redistribute it and/or modify |
3525 | + * it under the terms of the GNU General Public License as published by |
3526 | + * the Free Software Foundation; either version 2 of the License, or |
3527 | + * (at your option) any later version. |
3528 | + * |
3529 | + * HomeBank is distributed in the hope that it will be useful, |
3530 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3531 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3532 | + * GNU General Public License for more details. |
3533 | + * |
3534 | + * You should have received a copy of the GNU General Public License |
3535 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3536 | + */ |
3537 | + |
3538 | + |
3539 | +#include "homebank.h" |
3540 | +#include "hb-misc.h" |
3541 | +#include "dsp_mainwindow.h" |
3542 | +#include "hb-category.h" |
3543 | +#include "ui-budget-tabview.h" |
3544 | + |
3545 | +/****************************************************************************/ |
3546 | +/* Implementation notes */ |
3547 | +/****************************************************************************/ |
3548 | +/* |
3549 | + * This dialog allows user to manage its budget within a GtkTreeView. |
3550 | + * |
3551 | + * The view rows are separated in three main tree roots: |
3552 | + * - Income: contains all Homebank categories of income type (see GF_INCOME) |
3553 | + * - Expense: contains all Homebank categories of expense type |
3554 | + * - Total: contains 3 sub-rows: |
3555 | + * - Income: sum all amounts of the Income root |
3556 | + * - Expense: sum all amounts of the Expense root |
3557 | + * - Summary: difference between the two above sub-rows |
3558 | + * |
3559 | + * The view columns contain: |
3560 | + * - Category: Homebank categories organised in hierarchy |
3561 | + * according to the main tree roots above and the categories hierarchy |
3562 | + * |
3563 | + * - Annual Total: sum all amounts of the year for the category |
3564 | + * |
3565 | + * - Monthly Average: average of the amounts for the category |
3566 | + * |
3567 | + * - Monthly: set the monthly amount when the Same flag is active |
3568 | + * - That column contains a toggle check box to enable or not monthly values |
3569 | + * Check it to disable the GF_CUSTOM flag of Homebank categories |
3570 | + * "Does this category has same amount planned every month ?" |
3571 | + * |
3572 | + * - 12 columns for each month of the year containing their specific amount |
3573 | + * |
3574 | + * The dialog shows 3 radio buttons on top to choose between 3 viewing modes: |
3575 | + * - Summary: show Homebank categories with budget set or set with GF_FORCED |
3576 | + * - Expense: show all available Homebank categories of expense type |
3577 | + * - Income: show all available Homebank categories of income type |
3578 | + * |
3579 | + */ |
3580 | + |
3581 | +/****************************************************************************/ |
3582 | +/* Debug macros */ |
3583 | +/****************************************************************************/ |
3584 | +#define MYDEBUG 0 |
3585 | + |
3586 | +#if MYDEBUG |
3587 | +#define DB(x) (x); |
3588 | +#else |
3589 | +#define DB(x); |
3590 | +#endif |
3591 | + |
3592 | +/* Global data */ |
3593 | +extern struct HomeBank *GLOBALS; |
3594 | +extern struct Preferences *PREFS; |
3595 | + |
3596 | +static gchar *UI_BUD_TABVIEW_MONTHS[] = { |
3597 | + N_("Jan"), N_("Feb"), N_("Mar"), |
3598 | + N_("Apr"), N_("May"), N_("Jun"), |
3599 | + N_("Jul"), N_("Aug"), N_("Sept"), |
3600 | + N_("Oct"), N_("Nov"), N_("Dec"), |
3601 | + NULL}; |
3602 | + |
3603 | +/* The different view mode available */ |
3604 | +static gchar *UI_BUD_TABVIEW_VIEW_MODE[] = { |
3605 | + N_("Summary"), |
3606 | + N_("Expense"), |
3607 | + N_("Income"), |
3608 | + NULL |
3609 | +}; |
3610 | + |
3611 | +/* These values has to correspond to UI_BUD_TABVIEW_VIEW_MODE[] */ |
3612 | +enum ui_bud_tabview_view_mode |
3613 | +{ |
3614 | + UI_BUD_TABVIEW_VIEW_SUMMARY = 0, |
3615 | + UI_BUD_TABVIEW_VIEW_EXPENSE, |
3616 | + UI_BUD_TABVIEW_VIEW_INCOME |
3617 | +}; |
3618 | +typedef enum ui_bud_tabview_view_mode ui_bud_tabview_view_mode_t; |
3619 | + |
3620 | +/* These values corresponds to the return of category_type_get from hb-category */ |
3621 | +enum ui_bud_tabview_cat_type |
3622 | +{ |
3623 | + UI_BUD_TABVIEW_CAT_TYPE_EXPENSE = -1, |
3624 | + UI_BUD_TABVIEW_CAT_TYPE_NONE = 0, // Not real category type: used to retrieve tree roots |
3625 | + UI_BUD_TABVIEW_CAT_TYPE_INCOME = 1 |
3626 | +}; |
3627 | +typedef enum ui_bud_tabview_cat_type ui_bud_tabview_cat_type_t; |
3628 | + |
3629 | +/* enum for the Budget Tree Store model */ |
3630 | +enum ui_bud_tabview_store |
3631 | +{ |
3632 | + UI_BUD_TABVIEW_CATEGORY_KEY = 0, |
3633 | + UI_BUD_TABVIEW_CATEGORY_NAME, |
3634 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, |
3635 | + UI_BUD_TABVIEW_CATEGORY_TYPE, |
3636 | + UI_BUD_TABVIEW_IS_ROOT, // To retrieve easier the 3 main tree roots |
3637 | + UI_BUD_TABVIEW_IS_TOTAL, // To retrieve rows inside the Total root |
3638 | + UI_BUD_TABVIEW_IS_CHILD_HEADER, // The row corresponds to the head child which is shown before the separator |
3639 | + UI_BUD_TABVIEW_IS_SEPARATOR, // Row to just display a separator in Tree View |
3640 | + UI_BUD_TABVIEW_IS_MONITORING_FORCED, |
3641 | + UI_BUD_TABVIEW_IS_SAME_AMOUNT, |
3642 | + UI_BUD_TABVIEW_IS_SUB_CATEGORY, |
3643 | + UI_BUD_TABVIEW_HAS_BUDGET, |
3644 | + UI_BUD_TABVIEW_SAME_AMOUNT, |
3645 | + UI_BUD_TABVIEW_JANUARY, |
3646 | + UI_BUD_TABVIEW_FEBRUARY, |
3647 | + UI_BUD_TABVIEW_MARCH, |
3648 | + UI_BUD_TABVIEW_APRIL, |
3649 | + UI_BUD_TABVIEW_MAY, |
3650 | + UI_BUD_TABVIEW_JUNE, |
3651 | + UI_BUD_TABVIEW_JULY, |
3652 | + UI_BUD_TABVIEW_AUGUST, |
3653 | + UI_BUD_TABVIEW_SEPTEMBER, |
3654 | + UI_BUD_TABVIEW_OCTOBER, |
3655 | + UI_BUD_TABVIEW_NOVEMBER, |
3656 | + UI_BUD_TABVIEW_DECEMBER, |
3657 | + UI_BUD_TABVIEW_NUMBER_COLOMNS |
3658 | +}; |
3659 | +typedef enum ui_bud_tabview_store ui_bud_tabview_store_t; |
3660 | + |
3661 | +// Retrieve a row iterator according to specific criterias |
3662 | +const struct ui_bud_tabview_search_criteria |
3663 | +{ |
3664 | + // Search by non-zero category key |
3665 | + guint32 row_category_key; |
3666 | + // Search by other criterias |
3667 | + ui_bud_tabview_cat_type_t row_category_type; |
3668 | + gboolean row_is_root; |
3669 | + gboolean row_is_total; |
3670 | + // Found iterator, NULL if not found |
3671 | + GtkTreeIter *iterator; |
3672 | +} ui_bud_tabview_search_criteria_default = {0, UI_BUD_TABVIEW_CAT_TYPE_NONE, FALSE, FALSE, NULL} ; |
3673 | +typedef struct ui_bud_tabview_search_criteria ui_bud_tabview_search_criteria_t; |
3674 | + |
3675 | +/* |
3676 | + * Local headers |
3677 | + **/ |
3678 | + |
3679 | +// GtkTreeStore model |
3680 | +static gboolean ui_bud_tabview_model_search_iterator (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, ui_bud_tabview_search_criteria_t *search); |
3681 | +static void ui_bud_tabview_model_add_category_with_lineage(GtkTreeStore *budget, GtkTreeIter *balanceIter, guint32 *key_category); |
3682 | +static void ui_bud_tabview_model_collapse (GtkTreeView *view); |
3683 | +static void ui_bud_tabview_model_insert_roots(GtkTreeStore* budget); |
3684 | +static void ui_bud_tabview_model_update_monthly_total(GtkTreeStore* budget); |
3685 | +static gboolean ui_bud_tabview_model_row_filter (GtkTreeModel *model, GtkTreeIter *iter, gpointer data); |
3686 | +#if HB_BUD_TABVIEW_EDIT_ENABLE |
3687 | +static gboolean ui_bud_tabview_model_row_merge_filter_with_headers (GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data); |
3688 | +static gboolean ui_bud_tabview_model_row_filter_parents (GtkTreeModel *model, GtkTreeIter *iter, gpointer data); |
3689 | +#endif |
3690 | +static gint ui_bud_tabview_model_row_sort (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data); |
3691 | +static GtkTreeModel * ui_bud_tabview_model_new (); |
3692 | + |
3693 | +// GtkTreeView widget |
3694 | +static void ui_bud_tabview_view_display_category_name (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data); |
3695 | +static void ui_bud_tabview_view_display_amount (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data); |
3696 | +static void ui_bud_tabview_view_display_is_same_amount (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data); |
3697 | +static void ui_bud_tabview_view_display_annual_total (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data); |
3698 | +static void ui_bud_tabview_view_display_monthly_average(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data); |
3699 | +static void ui_bud_tabview_view_toggle (gpointer user_data, ui_bud_tabview_view_mode_t view_mode); |
3700 | +static gboolean ui_bud_tabview_view_search (GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer data); |
3701 | +#if HB_BUD_TABVIEW_EDIT_ENABLE |
3702 | +static gboolean ui_bud_tabview_view_separator (GtkTreeModel *model, GtkTreeIter *iter, gpointer data); |
3703 | +static void ui_bud_tabview_view_on_select(GtkTreeSelection *treeselection, gpointer user_data); |
3704 | +#endif |
3705 | +static GtkWidget *ui_bud_tabview_view_new (gpointer user_data); |
3706 | + |
3707 | +// UI actions |
3708 | +#if HB_BUD_TABVIEW_EDIT_ENABLE |
3709 | +static void ui_bud_tabview_cell_update_category(GtkCellRendererText *renderer, gchar *filter_path, gchar *new_text, gpointer user_data); |
3710 | +static void ui_bud_tabview_cell_update_amount(GtkCellRendererText *renderer, gchar *filter_path, gchar *new_text, gpointer user_data); |
3711 | +static void ui_bud_tabview_cell_update_is_same_amount(GtkCellRendererText *renderer, gchar *filter_path, gpointer user_data); |
3712 | +#endif |
3713 | +static void ui_bud_tabview_view_update_mode (GtkToggleButton *button, gpointer user_data); |
3714 | +static void ui_bud_tabview_view_expand (GtkButton *button, gpointer user_data); |
3715 | +static void ui_bud_tabview_view_collapse (GtkButton *button, gpointer user_data); |
3716 | +#if HB_BUD_TABVIEW_EDIT_ENABLE |
3717 | +static gboolean ui_bud_tabview_get_selected_category (GtkTreeModel **budget, GtkTreeIter *iter, Category **category, ui_bud_tabview_data_t *data); |
3718 | +static gboolean ui_bud_tabview_get_selected_root_iter (GtkTreeModel **budget, GtkTreeIter *iter, ui_bud_tabview_data_t *data); |
3719 | +static void ui_bud_tabview_category_add_full_filled (GtkWidget *source, gpointer user_data); |
3720 | +static void ui_bud_tabview_category_add (GtkButton *button, gpointer user_data); |
3721 | +static void ui_bud_tabview_category_delete (GtkButton *button, gpointer user_data); |
3722 | +static void ui_bud_tabview_category_merge_full_filled (GtkWidget *source, gpointer user_data); |
3723 | +static void ui_bud_tabview_category_merge (GtkButton *button, gpointer user_data); |
3724 | +static void ui_bud_tabview_category_reset (GtkButton *button, gpointer user_data); |
3725 | +#endif |
3726 | +static gboolean ui_bud_tabview_on_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data); |
3727 | +static void ui_bud_tabview_dialog_close(ui_bud_tabview_data_t *data, gint response); |
3728 | + |
3729 | +/** |
3730 | + * GtkTreeStore model |
3731 | + **/ |
3732 | + |
3733 | +// Look for category by deterministic characteristics |
3734 | +// Only categories with specific characteristics can be easily found |
3735 | +// like roots, total rows and categories with real key id |
3736 | +// You are responsible to g_free iterator |
3737 | +static gboolean ui_bud_tabview_model_search_iterator (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, ui_bud_tabview_search_criteria_t *search) |
3738 | +{ |
3739 | +guint32 category_key; |
3740 | +ui_bud_tabview_cat_type_t category_type; |
3741 | +gboolean is_found = FALSE, is_root, is_total, is_separator; |
3742 | + |
3743 | + search->iterator = NULL; |
3744 | + |
3745 | + gtk_tree_model_get (model, iter, |
3746 | + UI_BUD_TABVIEW_CATEGORY_KEY, &category_key, |
3747 | + UI_BUD_TABVIEW_CATEGORY_TYPE, &category_type, |
3748 | + UI_BUD_TABVIEW_IS_ROOT, &is_root, |
3749 | + UI_BUD_TABVIEW_IS_TOTAL, &is_total, |
3750 | + UI_BUD_TABVIEW_IS_SEPARATOR, &is_separator, |
3751 | + -1); |
3752 | + |
3753 | + if (search->row_category_key > 0 // Look for iter of real category row |
3754 | + && category_key == search->row_category_key |
3755 | + && !(is_total) |
3756 | + && !(is_root) |
3757 | + ) |
3758 | + { |
3759 | + DB(g_print("\tFound row with key %d\n", category_key)); |
3760 | + is_found = TRUE; |
3761 | + } |
3762 | + else if (search->row_category_key == 0 // Look for iter of fake category row |
3763 | + && is_root == search->row_is_root |
3764 | + && is_total == search->row_is_total |
3765 | + && category_type == search->row_category_type |
3766 | + && !is_separator |
3767 | + ) |
3768 | + { |
3769 | + DB(g_print("\tFound row with is_root = %d, is_total %d, type = %d\n", is_root, is_total, category_type)); |
3770 | + is_found = TRUE; |
3771 | + } |
3772 | + |
3773 | + // If found, save result to struct |
3774 | + if (is_found) |
3775 | + { |
3776 | + search->iterator = g_malloc0(sizeof(GtkTreeIter)); |
3777 | + *search->iterator = *iter; |
3778 | + } |
3779 | + |
3780 | + return is_found; |
3781 | +} |
3782 | + |
3783 | +/* Recursive function which add a new row in the budget model with all its ancestors */ |
3784 | +static void ui_bud_tabview_model_add_category_with_lineage(GtkTreeStore *budget, GtkTreeIter *balanceIter, guint32 *key_category) |
3785 | +{ |
3786 | +GtkTreeIter child; |
3787 | +GtkTreeIter *parent; |
3788 | +Category *bdg_category; |
3789 | +gboolean cat_is_same_amount; |
3790 | +ui_bud_tabview_search_criteria_t parent_search = ui_bud_tabview_search_criteria_default; |
3791 | + |
3792 | + bdg_category = da_cat_get(*key_category); |
3793 | + |
3794 | + if (bdg_category == NULL) |
3795 | + { |
3796 | + return; |
3797 | + } |
3798 | + |
3799 | + cat_is_same_amount = (! (bdg_category->flags & GF_CUSTOM)); |
3800 | + |
3801 | + /* Check if parent category already exists */ |
3802 | + parent_search.row_category_key = bdg_category->parent; |
3803 | + |
3804 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
3805 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
3806 | + &parent_search); |
3807 | + |
3808 | + if (bdg_category->parent == 0) |
3809 | + { |
3810 | + // If we are one of the oldest parent, stop recursion |
3811 | + gtk_tree_store_insert ( |
3812 | + budget, |
3813 | + &child, |
3814 | + balanceIter, |
3815 | + -1); |
3816 | + } |
3817 | + else |
3818 | + { |
3819 | + if (parent_search.iterator) |
3820 | + { |
3821 | + DB(g_print("\tRecursion optimisation: parent key %d already exists\n", parent_search.row_category_key)); |
3822 | + // If parent already exists, stop recursion |
3823 | + parent = parent_search.iterator; |
3824 | + } |
3825 | + else |
3826 | + { |
3827 | + // Parent has not been found, ask to create it first |
3828 | + ui_bud_tabview_model_add_category_with_lineage(budget, balanceIter, &(bdg_category->parent)); |
3829 | + |
3830 | + // Now, we are sure parent exists, look for it again |
3831 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
3832 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
3833 | + &parent_search); |
3834 | + |
3835 | + parent = parent_search.iterator; |
3836 | + } |
3837 | + |
3838 | + gtk_tree_store_insert ( |
3839 | + budget, |
3840 | + &child, |
3841 | + parent, |
3842 | + -1); |
3843 | + } |
3844 | + |
3845 | + DB(g_print("insert new category %s (key: %d, type: %d)\n", |
3846 | + bdg_category->name, bdg_category->key, category_type_get (bdg_category))); |
3847 | + |
3848 | + gtk_tree_store_set( |
3849 | + budget, |
3850 | + &child, |
3851 | + UI_BUD_TABVIEW_CATEGORY_KEY, bdg_category->key, |
3852 | + UI_BUD_TABVIEW_CATEGORY_NAME, bdg_category->name, |
3853 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, bdg_category->fullname, |
3854 | + UI_BUD_TABVIEW_CATEGORY_TYPE, category_type_get (bdg_category), |
3855 | + UI_BUD_TABVIEW_IS_MONITORING_FORCED, (bdg_category->flags & GF_FORCED), |
3856 | + UI_BUD_TABVIEW_IS_ROOT, FALSE, |
3857 | + UI_BUD_TABVIEW_IS_SAME_AMOUNT, cat_is_same_amount, |
3858 | + UI_BUD_TABVIEW_IS_TOTAL, FALSE, |
3859 | + UI_BUD_TABVIEW_IS_SUB_CATEGORY, bdg_category->parent != 0, |
3860 | + UI_BUD_TABVIEW_HAS_BUDGET, (bdg_category->flags & GF_BUDGET), |
3861 | + UI_BUD_TABVIEW_SAME_AMOUNT, bdg_category->budget[0], |
3862 | + UI_BUD_TABVIEW_JANUARY, bdg_category->budget[1], |
3863 | + UI_BUD_TABVIEW_FEBRUARY, bdg_category->budget[2], |
3864 | + UI_BUD_TABVIEW_MARCH, bdg_category->budget[3], |
3865 | + UI_BUD_TABVIEW_APRIL, bdg_category->budget[4], |
3866 | + UI_BUD_TABVIEW_MAY, bdg_category->budget[5], |
3867 | + UI_BUD_TABVIEW_JUNE, bdg_category->budget[6], |
3868 | + UI_BUD_TABVIEW_JULY, bdg_category->budget[7], |
3869 | + UI_BUD_TABVIEW_AUGUST, bdg_category->budget[8], |
3870 | + UI_BUD_TABVIEW_SEPTEMBER, bdg_category->budget[9], |
3871 | + UI_BUD_TABVIEW_OCTOBER, bdg_category->budget[10], |
3872 | + UI_BUD_TABVIEW_NOVEMBER, bdg_category->budget[11], |
3873 | + UI_BUD_TABVIEW_DECEMBER, bdg_category->budget[12], |
3874 | + -1); |
3875 | + |
3876 | + // Always add child header and separator |
3877 | + parent = gtk_tree_iter_copy(&child); |
3878 | + gtk_tree_store_insert_with_values( |
3879 | + budget, |
3880 | + &child, |
3881 | + parent, |
3882 | + -1, |
3883 | + UI_BUD_TABVIEW_CATEGORY_KEY, bdg_category->key, |
3884 | + UI_BUD_TABVIEW_CATEGORY_NAME, bdg_category->name, |
3885 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, bdg_category->fullname, |
3886 | + UI_BUD_TABVIEW_CATEGORY_TYPE, category_type_get (bdg_category), |
3887 | + UI_BUD_TABVIEW_IS_CHILD_HEADER, TRUE, |
3888 | + -1); |
3889 | + |
3890 | + gtk_tree_store_insert_with_values( |
3891 | + budget, |
3892 | + &child, |
3893 | + parent, |
3894 | + -1, |
3895 | + UI_BUD_TABVIEW_CATEGORY_KEY, bdg_category->key, |
3896 | + UI_BUD_TABVIEW_CATEGORY_TYPE, category_type_get (bdg_category), |
3897 | + UI_BUD_TABVIEW_IS_SEPARATOR, TRUE, |
3898 | + -1); |
3899 | + |
3900 | + gtk_tree_iter_free(parent); |
3901 | + |
3902 | + g_free(parent_search.iterator); |
3903 | + |
3904 | + return; |
3905 | +} |
3906 | + |
3907 | +// Collapse all categories except root |
3908 | +static void ui_bud_tabview_model_collapse (GtkTreeView *view) |
3909 | +{ |
3910 | +GtkTreeModel *budget; |
3911 | +GtkTreePath *path; |
3912 | +ui_bud_tabview_search_criteria_t root_search = ui_bud_tabview_search_criteria_default; |
3913 | + |
3914 | + budget = gtk_tree_view_get_model (view); |
3915 | + |
3916 | + gtk_tree_view_collapse_all(view); |
3917 | + |
3918 | + // Keep root categories expanded |
3919 | + |
3920 | + // Retrieve income root |
3921 | + root_search.row_is_root = TRUE; |
3922 | + root_search.row_is_total = FALSE; |
3923 | + root_search.row_category_type = UI_BUD_TABVIEW_CAT_TYPE_INCOME; |
3924 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
3925 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
3926 | + &root_search); |
3927 | + |
3928 | + if (root_search.iterator != NULL) |
3929 | + { |
3930 | + path = gtk_tree_model_get_path(budget, root_search.iterator); |
3931 | + gtk_tree_view_expand_row(view, path, FALSE); |
3932 | + } |
3933 | + |
3934 | + // Retrieve expense root |
3935 | + root_search.row_is_root = TRUE; |
3936 | + root_search.row_is_total = FALSE; |
3937 | + root_search.row_category_type = UI_BUD_TABVIEW_CAT_TYPE_EXPENSE; |
3938 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
3939 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
3940 | + &root_search); |
3941 | + |
3942 | + if (root_search.iterator != NULL) |
3943 | + { |
3944 | + path = gtk_tree_model_get_path(budget, root_search.iterator); |
3945 | + gtk_tree_view_expand_row(view, path, FALSE); |
3946 | + } |
3947 | + |
3948 | + // Retrieve total root |
3949 | + root_search.row_is_root = TRUE; |
3950 | + root_search.row_is_total = FALSE; |
3951 | + root_search.row_category_type = UI_BUD_TABVIEW_CAT_TYPE_NONE; |
3952 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
3953 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
3954 | + &root_search); |
3955 | + |
3956 | + if (root_search.iterator != NULL) |
3957 | + { |
3958 | + path = gtk_tree_model_get_path(budget, root_search.iterator); |
3959 | + gtk_tree_view_expand_row(view, path, FALSE); |
3960 | + } |
3961 | + |
3962 | + g_free(root_search.iterator); |
3963 | + |
3964 | + return; |
3965 | +} |
3966 | + |
3967 | +// Create tree roots for the store |
3968 | +static void ui_bud_tabview_model_insert_roots(GtkTreeStore* budget) |
3969 | +{ |
3970 | +GtkTreeIter iter, root; |
3971 | + |
3972 | + gtk_tree_store_insert_with_values ( |
3973 | + budget, |
3974 | + &root, |
3975 | + NULL, |
3976 | + -1, |
3977 | + UI_BUD_TABVIEW_CATEGORY_NAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_INCOME]), |
3978 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_INCOME]), |
3979 | + UI_BUD_TABVIEW_CATEGORY_TYPE, UI_BUD_TABVIEW_CAT_TYPE_INCOME, |
3980 | + UI_BUD_TABVIEW_IS_ROOT, TRUE, |
3981 | + UI_BUD_TABVIEW_IS_TOTAL, FALSE, |
3982 | + -1); |
3983 | + |
3984 | + // For add category dialog: copy of the root to be able to select it |
3985 | + gtk_tree_store_insert_with_values ( |
3986 | + budget, |
3987 | + &iter, |
3988 | + &root, |
3989 | + -1, |
3990 | + UI_BUD_TABVIEW_CATEGORY_NAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_INCOME]), |
3991 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_INCOME]), |
3992 | + UI_BUD_TABVIEW_CATEGORY_TYPE, UI_BUD_TABVIEW_CAT_TYPE_INCOME, |
3993 | + UI_BUD_TABVIEW_CATEGORY_KEY, 0, |
3994 | + UI_BUD_TABVIEW_IS_ROOT, FALSE, |
3995 | + UI_BUD_TABVIEW_IS_TOTAL, FALSE, |
3996 | + UI_BUD_TABVIEW_IS_CHILD_HEADER, TRUE, |
3997 | + -1); |
3998 | + |
3999 | + // For add category dialog: add a separator to distinguish root with children |
4000 | + gtk_tree_store_insert_with_values ( |
4001 | + budget, |
4002 | + &iter, |
4003 | + &root, |
4004 | + -1, |
4005 | + UI_BUD_TABVIEW_IS_SEPARATOR, TRUE, |
4006 | + UI_BUD_TABVIEW_CATEGORY_TYPE, UI_BUD_TABVIEW_CAT_TYPE_INCOME, |
4007 | + -1); |
4008 | + |
4009 | + gtk_tree_store_insert_with_values ( |
4010 | + budget, |
4011 | + &root, |
4012 | + NULL, |
4013 | + -1, |
4014 | + UI_BUD_TABVIEW_CATEGORY_NAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_EXPENSE]), |
4015 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_EXPENSE]), |
4016 | + UI_BUD_TABVIEW_CATEGORY_TYPE, UI_BUD_TABVIEW_CAT_TYPE_EXPENSE, |
4017 | + UI_BUD_TABVIEW_IS_ROOT, TRUE, |
4018 | + UI_BUD_TABVIEW_IS_TOTAL, FALSE, |
4019 | + -1); |
4020 | + |
4021 | + // For add category dialog: copy of the root to be able to select it |
4022 | + gtk_tree_store_insert_with_values ( |
4023 | + budget, |
4024 | + &iter, |
4025 | + &root, |
4026 | + -1, |
4027 | + UI_BUD_TABVIEW_CATEGORY_NAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_EXPENSE]), |
4028 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_EXPENSE]), |
4029 | + UI_BUD_TABVIEW_CATEGORY_TYPE, UI_BUD_TABVIEW_CAT_TYPE_EXPENSE, |
4030 | + UI_BUD_TABVIEW_CATEGORY_KEY, 0, |
4031 | + UI_BUD_TABVIEW_IS_ROOT, FALSE, |
4032 | + UI_BUD_TABVIEW_IS_TOTAL, FALSE, |
4033 | + UI_BUD_TABVIEW_IS_CHILD_HEADER, TRUE, |
4034 | + -1); |
4035 | + |
4036 | + // For add category dialog: add a separator to distinguish root with children |
4037 | + gtk_tree_store_insert_with_values ( |
4038 | + budget, |
4039 | + &iter, |
4040 | + &root, |
4041 | + -1, |
4042 | + UI_BUD_TABVIEW_IS_SEPARATOR, TRUE, |
4043 | + UI_BUD_TABVIEW_CATEGORY_TYPE, UI_BUD_TABVIEW_CAT_TYPE_EXPENSE, |
4044 | + -1); |
4045 | + |
4046 | + gtk_tree_store_insert_with_values ( |
4047 | + budget, |
4048 | + &root, |
4049 | + NULL, |
4050 | + -1, |
4051 | + UI_BUD_TABVIEW_CATEGORY_NAME, _("Totals"), |
4052 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, _("Totals"), |
4053 | + UI_BUD_TABVIEW_CATEGORY_TYPE, UI_BUD_TABVIEW_CAT_TYPE_NONE, |
4054 | + UI_BUD_TABVIEW_IS_ROOT, TRUE, |
4055 | + UI_BUD_TABVIEW_IS_TOTAL, FALSE, |
4056 | + -1); |
4057 | + |
4058 | + return; |
4059 | +} |
4060 | + |
4061 | +// Update (or insert) total rows for a budget according to the view mode |
4062 | +// This function will is used to initiate model and to refresh it after change by user |
4063 | +static void ui_bud_tabview_model_update_monthly_total(GtkTreeStore* budget) |
4064 | +{ |
4065 | +ui_bud_tabview_search_criteria_t root_search = ui_bud_tabview_search_criteria_default; |
4066 | +GtkTreeIter total_root, child; |
4067 | +double total_income[12] = {0}, total_expense[12] = {0}; |
4068 | +gboolean cat_is_same_amount; |
4069 | +int n_category; |
4070 | + |
4071 | + // Go through all categories to compute totals |
4072 | + n_category = da_cat_get_max_key(); |
4073 | + |
4074 | + for(guint32 i=1; i<=n_category; ++i) |
4075 | + { |
4076 | + Category *bdg_category; |
4077 | + gboolean cat_is_income; |
4078 | + |
4079 | + bdg_category = da_cat_get(i); |
4080 | + |
4081 | + if (bdg_category == NULL) |
4082 | + { |
4083 | + continue; |
4084 | + } |
4085 | + |
4086 | + cat_is_income = (category_type_get (bdg_category) == 1); |
4087 | + cat_is_same_amount = (! (bdg_category->flags & GF_CUSTOM)); |
4088 | + |
4089 | + for (gint j=0; j<=11; ++j) |
4090 | + { |
4091 | + if (cat_is_income) |
4092 | + { |
4093 | + if (cat_is_same_amount) |
4094 | + { |
4095 | + total_income[j] += bdg_category->budget[0]; |
4096 | + } |
4097 | + else |
4098 | + { |
4099 | + total_income[j] += bdg_category->budget[j+1]; |
4100 | + } |
4101 | + } |
4102 | + else |
4103 | + { |
4104 | + if (cat_is_same_amount) |
4105 | + { |
4106 | + total_expense[j] += bdg_category->budget[0]; |
4107 | + } |
4108 | + else |
4109 | + { |
4110 | + total_expense[j] += bdg_category->budget[j+1]; |
4111 | + } |
4112 | + } |
4113 | + } |
4114 | + } |
4115 | + |
4116 | + // Retrieve total root and insert required total rows |
4117 | + root_search.row_is_root = TRUE; |
4118 | + root_search.row_is_total = FALSE; |
4119 | + root_search.row_category_type = UI_BUD_TABVIEW_CAT_TYPE_NONE; |
4120 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
4121 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
4122 | + &root_search); |
4123 | + |
4124 | + if (!root_search.iterator) |
4125 | + { |
4126 | + return; |
4127 | + } |
4128 | + |
4129 | + total_root = *root_search.iterator; |
4130 | + |
4131 | + // Retrieve and set totals |
4132 | + root_search.row_is_root = FALSE; |
4133 | + root_search.row_is_total = TRUE; |
4134 | + |
4135 | + // First, look for Incomes |
4136 | + root_search.row_category_type = UI_BUD_TABVIEW_CAT_TYPE_INCOME; |
4137 | + |
4138 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
4139 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
4140 | + &root_search); |
4141 | + |
4142 | + if (root_search.iterator) |
4143 | + { |
4144 | + child = *root_search.iterator; |
4145 | + } |
4146 | + else |
4147 | + { |
4148 | + gtk_tree_store_insert(budget, &child, &total_root, -1); |
4149 | + } |
4150 | + |
4151 | + gtk_tree_store_set ( |
4152 | + budget, |
4153 | + &child, |
4154 | + UI_BUD_TABVIEW_CATEGORY_NAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_INCOME]), |
4155 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_INCOME]), |
4156 | + UI_BUD_TABVIEW_CATEGORY_TYPE, UI_BUD_TABVIEW_CAT_TYPE_INCOME, |
4157 | + UI_BUD_TABVIEW_IS_TOTAL, TRUE, |
4158 | + UI_BUD_TABVIEW_JANUARY, total_income[0], |
4159 | + UI_BUD_TABVIEW_FEBRUARY, total_income[1], |
4160 | + UI_BUD_TABVIEW_MARCH, total_income[2], |
4161 | + UI_BUD_TABVIEW_APRIL, total_income[3], |
4162 | + UI_BUD_TABVIEW_MAY, total_income[4], |
4163 | + UI_BUD_TABVIEW_JUNE, total_income[5], |
4164 | + UI_BUD_TABVIEW_JULY, total_income[6], |
4165 | + UI_BUD_TABVIEW_AUGUST, total_income[7], |
4166 | + UI_BUD_TABVIEW_SEPTEMBER, total_income[8], |
4167 | + UI_BUD_TABVIEW_OCTOBER, total_income[9], |
4168 | + UI_BUD_TABVIEW_NOVEMBER, total_income[10], |
4169 | + UI_BUD_TABVIEW_DECEMBER, total_income[11], |
4170 | + -1); |
4171 | + |
4172 | + // Then look for Expenses |
4173 | + root_search.row_category_type = UI_BUD_TABVIEW_CAT_TYPE_EXPENSE; |
4174 | + |
4175 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
4176 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
4177 | + &root_search); |
4178 | + |
4179 | + if (root_search.iterator) |
4180 | + { |
4181 | + child = *root_search.iterator; |
4182 | + } |
4183 | + else |
4184 | + { |
4185 | + gtk_tree_store_insert(budget, &child, &total_root, -1); |
4186 | + } |
4187 | + |
4188 | + gtk_tree_store_set ( |
4189 | + budget, |
4190 | + &child, |
4191 | + UI_BUD_TABVIEW_CATEGORY_NAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_EXPENSE]), |
4192 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_EXPENSE]), |
4193 | + UI_BUD_TABVIEW_CATEGORY_TYPE, UI_BUD_TABVIEW_CAT_TYPE_EXPENSE, |
4194 | + UI_BUD_TABVIEW_IS_TOTAL, TRUE, |
4195 | + UI_BUD_TABVIEW_JANUARY, total_expense[0], |
4196 | + UI_BUD_TABVIEW_FEBRUARY, total_expense[1], |
4197 | + UI_BUD_TABVIEW_MARCH, total_expense[2], |
4198 | + UI_BUD_TABVIEW_APRIL, total_expense[3], |
4199 | + UI_BUD_TABVIEW_MAY, total_expense[4], |
4200 | + UI_BUD_TABVIEW_JUNE, total_expense[5], |
4201 | + UI_BUD_TABVIEW_JULY, total_expense[6], |
4202 | + UI_BUD_TABVIEW_AUGUST, total_expense[7], |
4203 | + UI_BUD_TABVIEW_SEPTEMBER, total_expense[8], |
4204 | + UI_BUD_TABVIEW_OCTOBER, total_expense[9], |
4205 | + UI_BUD_TABVIEW_NOVEMBER, total_expense[10], |
4206 | + UI_BUD_TABVIEW_DECEMBER, total_expense[11], |
4207 | + -1); |
4208 | + |
4209 | + // Finally, set Balance total row |
4210 | + root_search.row_category_type = UI_BUD_TABVIEW_CAT_TYPE_NONE; |
4211 | + |
4212 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
4213 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
4214 | + &root_search); |
4215 | + |
4216 | + if (root_search.iterator) |
4217 | + { |
4218 | + child = *root_search.iterator; |
4219 | + } |
4220 | + else |
4221 | + { |
4222 | + gtk_tree_store_insert(budget, &child, &total_root, -1); |
4223 | + } |
4224 | + |
4225 | + gtk_tree_store_set ( |
4226 | + budget, |
4227 | + &child, |
4228 | + UI_BUD_TABVIEW_CATEGORY_NAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_SUMMARY]), |
4229 | + UI_BUD_TABVIEW_CATEGORY_FULLNAME, _(UI_BUD_TABVIEW_VIEW_MODE[UI_BUD_TABVIEW_VIEW_SUMMARY]), |
4230 | + UI_BUD_TABVIEW_CATEGORY_TYPE, UI_BUD_TABVIEW_CAT_TYPE_NONE, |
4231 | + UI_BUD_TABVIEW_IS_TOTAL, TRUE, |
4232 | + UI_BUD_TABVIEW_JANUARY, total_income[0] + total_expense[0], |
4233 | + UI_BUD_TABVIEW_FEBRUARY, total_income[1] + total_expense[1], |
4234 | + UI_BUD_TABVIEW_MARCH, total_income[2] + total_expense[2], |
4235 | + UI_BUD_TABVIEW_APRIL, total_income[3] + total_expense[3], |
4236 | + UI_BUD_TABVIEW_MAY, total_income[4] + total_expense[4], |
4237 | + UI_BUD_TABVIEW_JUNE, total_income[5] + total_expense[5], |
4238 | + UI_BUD_TABVIEW_JULY, total_income[6] + total_expense[6], |
4239 | + UI_BUD_TABVIEW_AUGUST, total_income[7] + total_expense[7], |
4240 | + UI_BUD_TABVIEW_SEPTEMBER, total_income[8] + total_expense[8], |
4241 | + UI_BUD_TABVIEW_OCTOBER, total_income[9] + total_expense[9], |
4242 | + UI_BUD_TABVIEW_NOVEMBER, total_income[10] + total_expense[10], |
4243 | + UI_BUD_TABVIEW_DECEMBER, total_income[11] + total_expense[11], |
4244 | + -1); |
4245 | + |
4246 | + g_free(root_search.iterator); |
4247 | + |
4248 | + return; |
4249 | +} |
4250 | + |
4251 | +// Filter shown rows according to VIEW mode |
4252 | +static gboolean ui_bud_tabview_model_row_filter (GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) |
4253 | +{ |
4254 | +gboolean is_visible, is_root, is_total, is_separator, is_childheader; |
4255 | +ui_bud_tabview_data_t* data; |
4256 | +ui_bud_tabview_view_mode_t view_mode; |
4257 | +guint32 category_key; |
4258 | +ui_bud_tabview_cat_type_t category_type; |
4259 | +Category *bdg_category; |
4260 | + |
4261 | + is_visible = TRUE; |
4262 | + data = user_data; |
4263 | + view_mode = radio_get_active(GTK_CONTAINER(data->RA_mode)); |
4264 | + |
4265 | + gtk_tree_model_get(model, iter, |
4266 | + UI_BUD_TABVIEW_IS_ROOT, &is_root, |
4267 | + UI_BUD_TABVIEW_IS_TOTAL, &is_total, |
4268 | + UI_BUD_TABVIEW_IS_SEPARATOR, &is_separator, |
4269 | + UI_BUD_TABVIEW_IS_CHILD_HEADER, &is_childheader, |
4270 | + UI_BUD_TABVIEW_CATEGORY_KEY, &category_key, |
4271 | + UI_BUD_TABVIEW_CATEGORY_TYPE, &category_type, |
4272 | + -1); |
4273 | + |
4274 | + // On specific mode, hide categories of opposite type |
4275 | + if (!is_total |
4276 | + && category_type == UI_BUD_TABVIEW_CAT_TYPE_INCOME |
4277 | + && view_mode == UI_BUD_TABVIEW_VIEW_EXPENSE) |
4278 | + { |
4279 | + is_visible = FALSE; |
4280 | + } |
4281 | + |
4282 | + if (!is_total |
4283 | + && category_type == UI_BUD_TABVIEW_CAT_TYPE_EXPENSE |
4284 | + && view_mode == UI_BUD_TABVIEW_VIEW_INCOME) |
4285 | + { |
4286 | + is_visible = FALSE; |
4287 | + } |
4288 | + |
4289 | + // Hide fake first child root used for add dialog |
4290 | + if (is_childheader |
4291 | + || is_separator) |
4292 | + { |
4293 | + is_visible = FALSE; |
4294 | + } |
4295 | + |
4296 | + // On balance mode, hide not forced empty categories |
4297 | + if (!is_total |
4298 | + && !is_root |
4299 | + && !is_childheader |
4300 | + && !is_separator |
4301 | + && view_mode == UI_BUD_TABVIEW_VIEW_SUMMARY) |
4302 | + { |
4303 | + bdg_category = da_cat_get(category_key); |
4304 | + |
4305 | + if (bdg_category != NULL) |
4306 | + { |
4307 | + // Either the category has some budget, or its display is forced |
4308 | + is_visible = (bdg_category->flags & (GF_BUDGET|GF_FORCED)); |
4309 | + |
4310 | + // Force display if one of its children should be displayed |
4311 | + if (!is_visible) |
4312 | + { |
4313 | + GtkTreeIter child; |
4314 | + Category *subcat; |
4315 | + guint32 subcat_key; |
4316 | + gint child_id=0; |
4317 | + |
4318 | + while (gtk_tree_model_iter_nth_child(model, |
4319 | + &child, |
4320 | + iter, |
4321 | + child_id)) |
4322 | + { |
4323 | + gtk_tree_model_get(model, &child, |
4324 | + UI_BUD_TABVIEW_CATEGORY_KEY, &subcat_key, |
4325 | + -1); |
4326 | + |
4327 | + if (subcat_key != 0) |
4328 | + { |
4329 | + subcat = da_cat_get (subcat_key); |
4330 | + |
4331 | + if (subcat != NULL) |
4332 | + { |
4333 | + is_visible = (subcat->flags & (GF_BUDGET|GF_FORCED)); |
4334 | + } |
4335 | + } |
4336 | + |
4337 | + // Stop loop on first visible children |
4338 | + if (is_visible) |
4339 | + { |
4340 | + break; |
4341 | + } |
4342 | + |
4343 | + ++child_id; |
4344 | + } |
4345 | + } |
4346 | + } |
4347 | + } |
4348 | + |
4349 | + return is_visible; |
4350 | +} |
4351 | + |
4352 | +#if HB_BUD_TABVIEW_EDIT_ENABLE |
4353 | +// Filter rows to show only parent categories |
4354 | +static gboolean ui_bud_tabview_model_row_filter_parents (GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) |
4355 | +{ |
4356 | +ui_bud_tabview_data_t *data = user_data; |
4357 | +gboolean is_visible, is_root, is_total, is_separator, is_childheader; |
4358 | +Category *bdg_category; |
4359 | +guint32 category_key; |
4360 | +ui_bud_tabview_cat_type_t category_type; |
4361 | +ui_bud_tabview_view_mode_t view_mode = UI_BUD_TABVIEW_VIEW_SUMMARY; |
4362 | + |
4363 | + view_mode = radio_get_active(GTK_CONTAINER(data->RA_mode)); |
4364 | + |
4365 | + is_visible = TRUE; |
4366 | + |
4367 | + gtk_tree_model_get(model, iter, |
4368 | + UI_BUD_TABVIEW_CATEGORY_KEY, &category_key, |
4369 | + UI_BUD_TABVIEW_CATEGORY_TYPE, &category_type, |
4370 | + UI_BUD_TABVIEW_IS_ROOT, &is_root, |
4371 | + UI_BUD_TABVIEW_IS_TOTAL, &is_total, |
4372 | + UI_BUD_TABVIEW_IS_CHILD_HEADER, &is_childheader, |
4373 | + UI_BUD_TABVIEW_IS_SEPARATOR, &is_separator, |
4374 | + -1); |
4375 | + |
4376 | + // Show root according to view_mode |
4377 | + if (is_root) |
4378 | + { |
4379 | + // Always hide total root |
4380 | + if(category_type == UI_BUD_TABVIEW_CAT_TYPE_NONE) |
4381 | + { |
4382 | + is_visible = FALSE; |
4383 | + } |
4384 | + else if(view_mode == UI_BUD_TABVIEW_VIEW_EXPENSE && category_type == UI_BUD_TABVIEW_CAT_TYPE_INCOME) |
4385 | + { |
4386 | + is_visible = FALSE; |
4387 | + } |
4388 | + else if(view_mode == UI_BUD_TABVIEW_VIEW_INCOME && category_type == UI_BUD_TABVIEW_CAT_TYPE_EXPENSE) |
4389 | + { |
4390 | + is_visible = FALSE; |
4391 | + } |
4392 | + } |
4393 | + |
4394 | + // Hide Total rows |
4395 | + if (is_total) { |
4396 | + is_visible = FALSE; |
4397 | + } |
4398 | + |
4399 | + if (category_key > 0 && (is_separator || is_childheader)) |
4400 | + { |
4401 | + is_visible = FALSE; |
4402 | + } |
4403 | + else if (category_key > 0) |
4404 | + { |
4405 | + // Hide rows according to currently view mode |
4406 | + if(view_mode == UI_BUD_TABVIEW_VIEW_EXPENSE && category_type == UI_BUD_TABVIEW_CAT_TYPE_INCOME) |
4407 | + { |
4408 | + is_visible = FALSE; |
4409 | + } |
4410 | + else if(view_mode == UI_BUD_TABVIEW_VIEW_INCOME && category_type == UI_BUD_TABVIEW_CAT_TYPE_EXPENSE) |
4411 | + { |
4412 | + is_visible = FALSE; |
4413 | + } |
4414 | + else |
4415 | + { |
4416 | + // Show categories without parents |
4417 | + bdg_category = da_cat_get(category_key); |
4418 | + |
4419 | + if (bdg_category != NULL) |
4420 | + { |
4421 | + if (bdg_category->parent > 0) |
4422 | + { |
4423 | + is_visible = FALSE; |
4424 | + } |
4425 | + } |
4426 | + } |
4427 | + } |
4428 | + |
4429 | + return is_visible; |
4430 | +} |
4431 | + |
4432 | +// Filter rows to show only mergeable categories |
4433 | +static gboolean ui_bud_tabview_model_row_merge_filter_with_headers (GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) |
4434 | +{ |
4435 | +ui_bud_tabview_data_t *data = user_data; |
4436 | +gboolean is_visible, is_root, is_total, is_separator, is_childheader; |
4437 | +guint32 category_key; |
4438 | +ui_bud_tabview_cat_type_t category_type; |
4439 | + |
4440 | + is_visible = TRUE; |
4441 | + |
4442 | + gtk_tree_model_get(model, iter, |
4443 | + UI_BUD_TABVIEW_CATEGORY_KEY, &category_key, |
4444 | + UI_BUD_TABVIEW_CATEGORY_TYPE, &category_type, |
4445 | + UI_BUD_TABVIEW_IS_ROOT, &is_root, |
4446 | + UI_BUD_TABVIEW_IS_TOTAL, &is_total, |
4447 | + UI_BUD_TABVIEW_IS_CHILD_HEADER, &is_childheader, |
4448 | + UI_BUD_TABVIEW_IS_SEPARATOR, &is_separator, |
4449 | + -1); |
4450 | + |
4451 | + // Hide source merge row |
4452 | + if (data->MERGE_source_category_key == category_key) |
4453 | + { |
4454 | + is_visible = FALSE; |
4455 | + } |
4456 | + |
4457 | + // Hide Total root |
4458 | + if (is_root |
4459 | + && category_type == UI_BUD_TABVIEW_CAT_TYPE_NONE ) |
4460 | + { |
4461 | + is_visible = FALSE; |
4462 | + } |
4463 | + |
4464 | + // Hide Total rows |
4465 | + if (is_total) |
4466 | + { |
4467 | + is_visible = FALSE; |
4468 | + } |
4469 | + |
4470 | + if ((is_separator || is_childheader)) |
4471 | + { |
4472 | + GtkTreeIter parent; |
4473 | + gtk_tree_model_iter_parent(model, &parent, iter); |
4474 | + |
4475 | + // Show child header and separator if parent has more than 2 children |
4476 | + is_visible = (gtk_tree_model_iter_n_children(model, &parent) > 2); |
4477 | + } |
4478 | + |
4479 | + return is_visible; |
4480 | +} |
4481 | +#endif |
4482 | + |
4483 | +static gint ui_bud_tabview_model_row_sort (GtkTreeModel *model, GtkTreeIter *cat_a, GtkTreeIter *cat_b, gpointer user_data) |
4484 | +{ |
4485 | +const gchar* cat_a_name; |
4486 | +const gchar* cat_b_name; |
4487 | +ui_bud_tabview_cat_type_t cat_a_type, cat_b_type; |
4488 | +guint32 cat_a_key, cat_b_key; |
4489 | +gboolean cat_a_is_childheader, cat_a_is_separator, cat_b_is_childheader, cat_b_is_separator; |
4490 | +gint order = 0; |
4491 | + |
4492 | + gtk_tree_model_get(model, cat_a, |
4493 | + UI_BUD_TABVIEW_CATEGORY_NAME, &cat_a_name, |
4494 | + UI_BUD_TABVIEW_CATEGORY_TYPE, &cat_a_type, |
4495 | + UI_BUD_TABVIEW_CATEGORY_KEY, &cat_a_key, |
4496 | + UI_BUD_TABVIEW_IS_CHILD_HEADER, &cat_a_is_childheader, |
4497 | + UI_BUD_TABVIEW_IS_SEPARATOR, &cat_a_is_separator, |
4498 | + -1); |
4499 | + |
4500 | + gtk_tree_model_get(model, cat_b, |
4501 | + UI_BUD_TABVIEW_CATEGORY_NAME, &cat_b_name, |
4502 | + UI_BUD_TABVIEW_CATEGORY_TYPE, &cat_b_type, |
4503 | + UI_BUD_TABVIEW_CATEGORY_KEY, &cat_b_key, |
4504 | + UI_BUD_TABVIEW_IS_CHILD_HEADER, &cat_b_is_childheader, |
4505 | + UI_BUD_TABVIEW_IS_SEPARATOR, &cat_b_is_separator, |
4506 | + -1); |
4507 | + |
4508 | + // Sort first by category type |
4509 | + if (cat_a_type != cat_b_type) |
4510 | + { |
4511 | + switch (cat_a_type) |
4512 | + { |
4513 | + case UI_BUD_TABVIEW_CAT_TYPE_INCOME: |
4514 | + order = -1; |
4515 | + break; |
4516 | + case UI_BUD_TABVIEW_CAT_TYPE_EXPENSE: |
4517 | + order = 0; |
4518 | + break; |
4519 | + case UI_BUD_TABVIEW_CAT_TYPE_NONE: |
4520 | + order = 1; |
4521 | + break; |
4522 | + } |
4523 | + } |
4524 | + else |
4525 | + { |
4526 | + // On standard categories, just order by name |
4527 | + if (!cat_a_is_childheader && !cat_a_is_separator |
4528 | + && !cat_b_is_childheader && !cat_b_is_separator) |
4529 | + { |
4530 | + order = g_utf8_collate(g_utf8_casefold(cat_a_name, -1), |
4531 | + g_utf8_casefold(cat_b_name, -1) |
4532 | + ); |
4533 | + } |
4534 | + // Otherwise, fake categories have to be first (header and separator) |
4535 | + else if (cat_a_is_childheader || cat_a_is_separator) |
4536 | + { |
4537 | + if (!cat_b_is_separator && !cat_b_is_childheader) |
4538 | + { |
4539 | + order = -1; |
4540 | + } |
4541 | + // When both are fake, header has to be first |
4542 | + else |
4543 | + { |
4544 | + order = (cat_a_is_childheader ? -1 : 1); |
4545 | + } |
4546 | + } |
4547 | + else |
4548 | + { |
4549 | + // Same idea for fake categories when cat_b is fake, but |
4550 | + // with reversed result, because sort function return |
4551 | + // result according to cat_a |
4552 | + |
4553 | + if (!cat_a_is_separator && !cat_a_is_childheader) |
4554 | + { |
4555 | + order = 1; |
4556 | + } |
4557 | + else |
4558 | + { |
4559 | + order = (cat_b_is_childheader ? 1 : -1); |
4560 | + } |
4561 | + } |
4562 | + } |
4563 | + |
4564 | + return order; |
4565 | +} |
4566 | + |
4567 | +// the budget model creation |
4568 | +static GtkTreeModel * ui_bud_tabview_model_new () |
4569 | +{ |
4570 | +GtkTreeStore *budget; |
4571 | +GtkTreeIter *iter_income, *iter_expense; |
4572 | +guint32 n_category; |
4573 | +ui_bud_tabview_search_criteria_t root_search = ui_bud_tabview_search_criteria_default; |
4574 | + |
4575 | + // Create Tree Store |
4576 | + budget = gtk_tree_store_new ( UI_BUD_TABVIEW_NUMBER_COLOMNS, |
4577 | + G_TYPE_UINT, // UI_BUD_TABVIEW_CATEGORY_KEY |
4578 | + G_TYPE_STRING, // UI_BUD_TABVIEW_CATEGORY_NAME |
4579 | + G_TYPE_STRING, // UI_BUD_TABVIEW_CATEGORY_FULLNAME |
4580 | + G_TYPE_INT, // UI_BUD_TABVIEW_CATEGORY_TYPE |
4581 | + G_TYPE_BOOLEAN, // UI_BUD_TABVIEW_IS_ROOT |
4582 | + G_TYPE_BOOLEAN, // UI_BUD_TABVIEW_IS_TOTAL |
4583 | + G_TYPE_BOOLEAN, // UI_BUD_TABVIEW_IS_CHILD_HEADER |
4584 | + G_TYPE_BOOLEAN, // UI_BUD_TABVIEW_IS_SEPARATOR |
4585 | + G_TYPE_BOOLEAN, // UI_BUD_TABVIEW_IS_MONITORING_FORCED |
4586 | + G_TYPE_BOOLEAN, // UI_BUD_TABVIEW_IS_SAME_AMOUNT |
4587 | + G_TYPE_BOOLEAN, // UI_BUD_TABVIEW_IS_SUB_CATEGORY |
4588 | + G_TYPE_BOOLEAN, // UI_BUD_TABVIEW_HAS_BUDGET |
4589 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_SAME_AMOUNT |
4590 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_JANUARY |
4591 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_FEBRUARY |
4592 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_MARCH |
4593 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_APRIL |
4594 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_MAY |
4595 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_JUNE |
4596 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_JULY |
4597 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_AUGUST |
4598 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_SEPTEMBER |
4599 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_OCTOBER |
4600 | + G_TYPE_DOUBLE, // UI_BUD_TABVIEW_NOVEMBER |
4601 | + G_TYPE_DOUBLE // UI_BUD_TABVIEW_DECEMBER |
4602 | + ); |
4603 | + |
4604 | + // Populate the store |
4605 | + |
4606 | + /* Create tree roots */ |
4607 | + ui_bud_tabview_model_insert_roots (budget); |
4608 | + |
4609 | + // Retrieve required root |
4610 | + root_search.row_is_root = TRUE; |
4611 | + root_search.row_is_total = FALSE; |
4612 | + |
4613 | + root_search.row_category_type = UI_BUD_TABVIEW_CAT_TYPE_INCOME; |
4614 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
4615 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
4616 | + &root_search); |
4617 | + iter_income = root_search.iterator; |
4618 | + |
4619 | + root_search.row_category_type = UI_BUD_TABVIEW_CAT_TYPE_EXPENSE; |
4620 | + gtk_tree_model_foreach(GTK_TREE_MODEL(budget), |
4621 | + (GtkTreeModelForeachFunc) ui_bud_tabview_model_search_iterator, |
4622 | + &root_search); |
4623 | + iter_expense = root_search.iterator; |
4624 | + |
4625 | + /* Create rows for real categories */ |
4626 | + n_category = da_cat_get_max_key(); |
4627 | + |
4628 | + for(guint32 i=1; i<=n_category; ++i) |
4629 | + { |
4630 | + Category *bdg_category; |
4631 | + gboolean cat_is_income; |
4632 | + |
4633 | + bdg_category = da_cat_get(i); |
4634 | + |
4635 | + if (bdg_category == NULL) |
4636 | + { |
4637 | + continue; |
4638 | + } |
4639 | + |
4640 | + cat_is_income = (category_type_get (bdg_category) == 1); |
4641 | + |
4642 | + DB(g_print(" category %d:'%s' isincome=%d, issub=%d hasbudget=%d parent=%d\n", |
4643 | + bdg_category->key, bdg_category->name, |
4644 | + cat_is_income, (bdg_category->flags & GF_SUB), |
4645 | + (bdg_category->flags & GF_BUDGET), bdg_category->parent)); |
4646 | + |
4647 | + // Compute totals and initiate category in right tree root |
4648 | + if (cat_is_income) |
4649 | + { |
4650 | + ui_bud_tabview_model_add_category_with_lineage(budget, iter_income, &(bdg_category->key)); |
4651 | + } |
4652 | + else if (!cat_is_income) |
4653 | + { |
4654 | + ui_bud_tabview_model_add_category_with_lineage(budget, iter_expense, &(bdg_category->key)); |
4655 | + } |
4656 | + } |
4657 | + |
4658 | + /* Create rows for total root */ |
4659 | + ui_bud_tabview_model_update_monthly_total(GTK_TREE_STORE(budget)); |
4660 | + |
4661 | + /* Sort categories on same node level */ |
4662 | + gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(budget), |
4663 | + UI_BUD_TABVIEW_CATEGORY_NAME, ui_bud_tabview_model_row_sort, |
4664 | + NULL, NULL); |
4665 | + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (budget), |
4666 | + UI_BUD_TABVIEW_CATEGORY_NAME, GTK_SORT_ASCENDING); |
4667 | + |
4668 | + g_free(root_search.iterator); |
4669 | + |
4670 | + return GTK_TREE_MODEL(budget); |
4671 | +} |
4672 | + |
4673 | +/** |
4674 | + * GtkTreeView functions |
4675 | + **/ |
4676 | + |
4677 | +// Display category name in bold if it has budget |
4678 | +static void ui_bud_tabview_view_display_category_name (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) |
4679 | +{ |
4680 | +ui_bud_tabview_data_t *data = user_data; |
4681 | +gboolean has_budget, is_sub_category; |
4682 | +PangoWeight weight = PANGO_WEIGHT_NORMAL; |
4683 | +ui_bud_tabview_view_mode_t view_mode = UI_BUD_TABVIEW_VIEW_SUMMARY; |
4684 | + |
4685 | + gtk_tree_model_get(model, iter, |
4686 | + UI_BUD_TABVIEW_IS_SUB_CATEGORY, &is_sub_category, |
4687 | + UI_BUD_TABVIEW_HAS_BUDGET, &has_budget, |
4688 | + -1); |
4689 | + |
4690 | + view_mode = radio_get_active(GTK_CONTAINER(data->RA_mode)); |
4691 | + |
4692 | + if (view_mode != UI_BUD_TABVIEW_VIEW_SUMMARY && has_budget) |
4693 | + { |
4694 | + weight = PANGO_WEIGHT_BOLD; |
4695 | + } |
4696 | + |
4697 | + g_object_set(renderer, |
4698 | + "style", is_sub_category ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL, |
4699 | + "weight", weight, |
4700 | + NULL); |
4701 | +} |
4702 | + |
4703 | +// to enable or not edition on month columns |
4704 | +static void ui_bud_tabview_view_display_amount (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) |
4705 | +{ |
4706 | +GtkAdjustment *adjustment; |
4707 | +gboolean is_same_amount, is_root, is_total, is_visible, is_editable; |
4708 | +ui_bud_tabview_cat_type_t row_category_type; |
4709 | +gdouble amount = 0.0; |
4710 | +gchar *text; |
4711 | +gchar *fgcolor; |
4712 | +const ui_bud_tabview_store_t column_id = GPOINTER_TO_INT(user_data); |
4713 | + |
4714 | + gtk_tree_model_get(model, iter, |
4715 | + UI_BUD_TABVIEW_CATEGORY_TYPE, &row_category_type, |
4716 | + UI_BUD_TABVIEW_IS_ROOT, &is_root, |
4717 | + UI_BUD_TABVIEW_IS_SAME_AMOUNT, &is_same_amount, |
4718 | + UI_BUD_TABVIEW_IS_TOTAL, &is_total, |
4719 | + -1); |
4720 | + |
4721 | + // Text to display |
4722 | + if (is_same_amount) |
4723 | + { |
4724 | + gtk_tree_model_get(model, iter, UI_BUD_TABVIEW_SAME_AMOUNT, &amount, -1); |
4725 | + } |
4726 | + else if (column_id >= UI_BUD_TABVIEW_JANUARY && column_id <= UI_BUD_TABVIEW_DECEMBER) |
4727 | + { |
4728 | + gtk_tree_model_get(model, iter, column_id, &amount, -1); |
4729 | + } |
4730 | + |
4731 | + text = g_strdup_printf("%.2f", amount); |
4732 | + fgcolor = get_normal_color_amount(amount); |
4733 | + |
4734 | + // Default styling values |
4735 | + is_visible = TRUE; |
4736 | + is_editable = FALSE; |
4737 | + |
4738 | + if (is_root) |
4739 | + { |
4740 | + is_visible = FALSE; |
4741 | + is_editable = FALSE; |
4742 | + } |
4743 | + else if (is_total) |
4744 | + { |
4745 | + is_visible = TRUE; |
4746 | + is_editable = FALSE; |
4747 | + |
4748 | + if (column_id == UI_BUD_TABVIEW_SAME_AMOUNT) |
4749 | + { |
4750 | + is_visible = FALSE; |
4751 | + } |
4752 | + } |
4753 | + else if (is_same_amount) |
4754 | + { |
4755 | + is_visible = TRUE; |
4756 | + is_editable = FALSE; |
4757 | + |
4758 | + if (column_id == UI_BUD_TABVIEW_SAME_AMOUNT) |
4759 | + { |
4760 | + is_editable = TRUE; |
4761 | + } |
4762 | + } |
4763 | + else if (! is_same_amount) |
4764 | + { |
4765 | + is_visible = TRUE; |
4766 | + is_editable = TRUE; |
4767 | + |
4768 | + if (column_id == UI_BUD_TABVIEW_SAME_AMOUNT) |
4769 | + { |
4770 | + is_editable = FALSE; |
4771 | + } |
4772 | + } |
4773 | + |
4774 | + // Finally, visibility depends on set amount |
4775 | +#if !HB_BUD_TABVIEW_EDIT_ENABLE |
4776 | + is_visible = (is_visible && amount != 0.0); |
4777 | + is_editable = FALSE; |
4778 | +#else |
4779 | + is_visible = (is_visible && (is_editable || amount != 0.0)); |
4780 | +#endif |
4781 | + |
4782 | + adjustment = gtk_adjustment_new( |
4783 | + 0.0, // initial-value |
4784 | + -G_MAXDOUBLE, // minmal-value |
4785 | + G_MAXDOUBLE, // maximal-value |
4786 | + 0.5, // step increment |
4787 | + 10, // page increment |
4788 | + 0); // page size (0 because irrelevant for GtkSpinButton) |
4789 | + |
4790 | + g_object_set(renderer, |
4791 | + "text", text, |
4792 | + "visible", is_visible, |
4793 | + "editable", is_editable, |
4794 | + "foreground", fgcolor, |
4795 | + "xalign", 1.0, |
4796 | + "adjustment", adjustment, |
4797 | + "digits", 2, |
4798 | + NULL); |
4799 | + |
4800 | + g_free(text); |
4801 | +} |
4802 | + |
4803 | +// to enable or not edition on month columns |
4804 | +static void ui_bud_tabview_view_display_is_same_amount (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) |
4805 | +{ |
4806 | +gboolean is_same_amount, is_root, is_total, is_visible, is_sensitive; |
4807 | + |
4808 | + gtk_tree_model_get(model, iter, |
4809 | + UI_BUD_TABVIEW_IS_ROOT, &is_root, |
4810 | + UI_BUD_TABVIEW_IS_SAME_AMOUNT, &is_same_amount, |
4811 | + UI_BUD_TABVIEW_IS_TOTAL, &is_total, |
4812 | + -1); |
4813 | + |
4814 | + // Default values |
4815 | + is_visible = TRUE; |
4816 | + is_sensitive = TRUE; |
4817 | + |
4818 | + if (is_root || is_total) |
4819 | + { |
4820 | + is_visible = FALSE; |
4821 | + is_sensitive = FALSE; |
4822 | + } |
4823 | + |
4824 | + g_object_set(renderer, |
4825 | + "activatable", TRUE, |
4826 | + "active", is_same_amount, |
4827 | + "visible", is_visible, |
4828 | + "sensitive", is_sensitive, |
4829 | + NULL); |
4830 | +} |
4831 | + |
4832 | +// Compute dynamically the annual total |
4833 | +static void ui_bud_tabview_view_display_annual_total (GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) |
4834 | +{ |
4835 | +gboolean is_same_amount = FALSE, is_total = FALSE, is_root = FALSE; |
4836 | +gdouble amount = 0.0; |
4837 | +gdouble total = 0.0; |
4838 | +gchar *text; |
4839 | +gchar *fgcolor; |
4840 | +gboolean is_visible = TRUE; |
4841 | + |
4842 | + gtk_tree_model_get(model, iter, |
4843 | + UI_BUD_TABVIEW_IS_ROOT, &is_root, |
4844 | + UI_BUD_TABVIEW_IS_SAME_AMOUNT, &is_same_amount, |
4845 | + UI_BUD_TABVIEW_SAME_AMOUNT, &amount, |
4846 | + UI_BUD_TABVIEW_IS_TOTAL, &is_total, |
4847 | + -1); |
4848 | + |
4849 | + if (is_same_amount) |
4850 | + { |
4851 | + total = 12.0 * amount; |
4852 | + } |
4853 | + else |
4854 | + { |
4855 | + for (int i = UI_BUD_TABVIEW_JANUARY ; i <= UI_BUD_TABVIEW_DECEMBER ; ++i) |
4856 | + { |
4857 | + gtk_tree_model_get(model, iter, i, &amount, -1); |
4858 | + total += amount; |
4859 | + } |
4860 | + } |
4861 | + |
4862 | + text = g_strdup_printf("%.2f", total); |
4863 | + fgcolor = get_normal_color_amount(total); |
4864 | + |
4865 | + if (is_root) |
4866 | + { |
4867 | + is_visible = FALSE; |
4868 | + } |
4869 | + |
4870 | + // Finally, visibility depends on set amount |
4871 | + is_visible = (is_visible && amount != 0.0); |
4872 | + |
4873 | + g_object_set(renderer, |
4874 | + "text", text, |
4875 | + "foreground", fgcolor, |
4876 | + "visible", is_visible, |
4877 | + "xalign", 1.0, |
4878 | + NULL); |
4879 | + |
4880 | + g_free(text); |
4881 | +} |
4882 | + |
4883 | +// Compute monthly average |
4884 | +static void ui_bud_tabview_view_display_monthly_average(GtkTreeViewColumn *col, GtkCellRenderer *renderer, GtkTreeModel *model, GtkTreeIter *iter, gpointer user_data) |
4885 | +{ |
4886 | +gboolean is_same_amount = FALSE, is_total = FALSE, is_root = FALSE; |
4887 | +gdouble amount = 0.0; |
4888 | +gdouble average = 0.0; |
4889 | +gchar *text; |
4890 | +gchar *fgcolor; |
4891 | +gboolean is_visible = TRUE; |
4892 | + |
4893 | + gtk_tree_model_get(model, iter, |
4894 | + UI_BUD_TABVIEW_IS_ROOT, &is_root, |
4895 | + UI_BUD_TABVIEW_IS_SAME_AMOUNT, &is_same_amount, |
4896 | + UI_BUD_TABVIEW_SAME_AMOUNT, &amount, |
4897 | + UI_BUD_TABVIEW_IS_TOTAL, &is_total, |
4898 | + -1); |
4899 | + |
4900 | + if (is_same_amount) |
4901 | + { |
4902 | + average = amount; |
4903 | + } |
4904 | + else |
4905 | + { |
4906 | + for (int i = UI_BUD_TABVIEW_JANUARY ; i <= UI_BUD_TABVIEW_DECEMBER ; ++i) |
4907 | + { |
4908 | + gtk_tree_model_get(model, iter, i, &amount, -1); |
4909 | + average += amount; |
4910 | + } |
4911 | + average = hb_amount_round(average / 12.0, 2); |
4912 | + } |
4913 | + |
4914 | + text = g_strdup_printf("%.2f", average); |
4915 | + fgcolor = get_normal_color_amount(average); |
4916 | + |
4917 | + if (is_root) |
4918 | + { |
4919 | + is_visible = FALSE; |
4920 | + } |
4921 | + |
4922 | + // Finally, visibility depends on set amount |
4923 | + is_visible = (is_visible && average != 0.0); |
4924 | + |
4925 | + g_object_set(renderer, |
4926 | + "text", text, |
4927 | + "foreground", fgcolor, |
4928 | + "visible", is_visible, |
4929 | + "xalign", 1.0, |
4930 | + NULL); |
4931 | + |
4932 | + g_free(text); |
4933 | +} |
4934 | + |
4935 | +// When view mode is toggled: |
4936 | +// - recreate the view to update columns rendering |
4937 | +static void ui_bud_tabview_view_toggle (gpointer user_data, ui_bud_tabview_view_mode_t view_mode) |
4938 | +{ |
4939 | +ui_bud_tabview_data_t *data = user_data; |
4940 | +GtkTreeModel *budget; |
4941 | +GtkWidget *view; |
4942 | +GtkTreePath* firstRow; |
4943 | + |
4944 | + view = data->TV_budget; |
4945 | + |
4946 | + budget = gtk_tree_view_get_model(GTK_TREE_VIEW(view)); |
4947 | + |
4948 | + gtk_tree_model_filter_refilter(GTK_TREE_MODEL_FILTER(budget)); |
4949 | + |
4950 | + if (data->TV_is_expanded) |
4951 | + { |
4952 | + gtk_tree_view_expand_all(GTK_TREE_VIEW(view)); |
4953 | + } |
4954 | + else |
4955 | + { |
4956 | + ui_bud_tabview_model_collapse(GTK_TREE_VIEW(view)); |
4957 | + } |
4958 | + |
4959 | + gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(GTK_TREE_VIEW(view))); |
4960 | + |
4961 | + firstRow = gtk_tree_path_new_from_string("0"); |
4962 | + gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view), firstRow, data->TVC_category, TRUE, 0, 0); |
4963 | + |
4964 | + DB(g_print("[ui_bud_tabview] : button state changed to: %d\n", view_mode)); |
4965 | + |
4966 | + return; |
4967 | +} |
4968 | + |
4969 | +static gboolean ui_bud_tabview_view_search (GtkTreeModel *filter, gint column, const gchar *key, GtkTreeIter *filter_iter, gpointer data) |
4970 | +{ |
4971 | +gboolean is_matching = FALSE, is_root, is_total; |
4972 | +GtkTreeModel *budget; |
4973 | +GtkTreeIter iter; |
4974 | +gchar *category_name; |
4975 | + |
4976 | + budget = gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(filter)); |
4977 | + gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER(filter), |
4978 | + &iter, |
4979 | + filter_iter); |
4980 | + |
4981 | + gtk_tree_model_get(budget, &iter, |
4982 | + UI_BUD_TABVIEW_CATEGORY_NAME, &category_name, |
4983 | + UI_BUD_TABVIEW_IS_ROOT, &is_root, |
4984 | + UI_BUD_TABVIEW_IS_TOTAL, &is_total, |
4985 | + -1); |
4986 | + |
4987 | + if (!is_root && !is_total |
4988 | + && g_strstr_len(g_utf8_casefold(category_name, -1), -1, |
4989 | + g_utf8_casefold(key, -1))) |
4990 | + { |
4991 | + is_matching = TRUE; |
4992 | + } |
4993 | + |
4994 | + // GtkTreeViewSearchEqualFunc has to return FALSE only if iter matches. |
4995 | + return !is_matching; |
4996 | +} |
4997 | + |
4998 | +#if HB_BUD_TABVIEW_EDIT_ENABLE |
4999 | +static gboolean ui_bud_tabview_view_separator (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) |
5000 | +{ |
merged this code with my local trunk for review