Branch data Line data Source code
1 : : /********************************************************************\
2 : : * top-level.c -- Gnome GUI main for GnuCash *
3 : : * Copyright (C) 1997 Robin D. Clark *
4 : : * Copyright (C) 1998-2000 Linas Vepstas *
5 : : * *
6 : : * This program is free software; you can redistribute it and/or *
7 : : * modify it under the terms of the GNU General Public License as *
8 : : * published by the Free Software Foundation; either version 2 of *
9 : : * the License, or (at your option) any later version. *
10 : : * *
11 : : * This program is distributed in the hope that it will be useful, *
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 : : * GNU General Public License for more details. *
15 : : * *
16 : : * You should have received a copy of the GNU General Public License*
17 : : * along with this program; if not, contact: *
18 : : * *
19 : : * Free Software Foundation Voice: +1-617-542-5942 *
20 : : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 : : * Boston, MA 02110-1301, USA gnu@gnu.org *
22 : : * *
23 : : \********************************************************************/
24 : :
25 : : #include <config.h>
26 : :
27 : : #include <gtk/gtk.h>
28 : : #include <glib/gi18n.h>
29 : : #include <stdlib.h>
30 : :
31 : : #include "TransLog.h"
32 : : #include "business-options-gnome.h"
33 : : #include "business-urls.h"
34 : : #include "combocell.h"
35 : : #include "dialog-account.h"
36 : : #include "dialog-doclink.h"
37 : : #include "dialog-commodity.h"
38 : : #include "dialog-invoice.h"
39 : : #include "dialog-preferences.h"
40 : : #include "dialog-sx-editor.h"
41 : : #include "dialog-transfer.h"
42 : : #include "dialog-totd.h"
43 : : #include "assistant-hierarchy.h"
44 : : #include "file-utils.h"
45 : : #include "gnc-component-manager.h"
46 : : #include "gnc-engine.h"
47 : : #include "gnc-file.h"
48 : : #include "gnc-hooks.h"
49 : : #include "gncInvoice.h"
50 : : #include "gfec.h"
51 : : #include "gnc-main-window.h"
52 : : #include "gnc-menu-extensions.h"
53 : : #include "gnc-plugin-menu-additions.h" /* FIXME Remove this line*/
54 : : #include "gnc-plugin-account-tree.h" /* FIXME Remove this line*/
55 : : #include "gnc-plugin-basic-commands.h" /* FIXME Remove this line*/
56 : : #include "gnc-plugin-file-history.h" /* FIXME Remove this line*/
57 : : #include "gnc-plugin-register.h" /* FIXME Remove this line*/
58 : : #include "gnc-plugin-budget.h"
59 : : #include "gnc-plugin-business.h"
60 : : #include "gnc-plugin-page-register.h"
61 : : #include "gnc-plugin-manager.h" /* FIXME Remove this line*/
62 : : #include "gnc-html.h"
63 : : #include "gnc-gnome-utils.h"
64 : : #include "gnc-report.h"
65 : : #include "gnc-split-reg.h"
66 : : #include "gnc-state.h"
67 : : #include "gnc-ui.h"
68 : : #include "gnc-ui-util.h"
69 : : #include "gnucash-color.h"
70 : : #include "gnucash-sheet.h"
71 : : #include "gnucash-style.h"
72 : : #include "search-core-type.h"
73 : : #include "search-owner.h"
74 : : #include "top-level.h"
75 : : #include "window-report.h"
76 : : #include "gnc-window.h"
77 : : #include "gnc-gkeyfile-utils.h"
78 : :
79 : :
80 : : /** GLOBALS *********************************************************/
81 : : /* This static indicates the debugging module that this .o belongs to. */
82 : : static QofLogModule log_module = GNC_MOD_GUI;
83 : :
84 : : /* ============================================================== */
85 : : /* HTML Handler for reports. */
86 : :
87 : : static gboolean
88 : 0 : validate_type(const char *url_type, const char *location,
89 : : const char *entity_type, GNCURLResult *result,
90 : : GncGUID *guid, QofInstance **entity)
91 : : {
92 : : QofCollection *col;
93 : 0 : QofBook * book = gnc_get_current_book();
94 : 0 : if (!string_to_guid (location + strlen(url_type), guid))
95 : : {
96 : 0 : result->error_message = g_strdup_printf (_("Bad URL: %s"), location);
97 : 0 : return FALSE;
98 : : }
99 : 0 : col = qof_book_get_collection (book, entity_type);
100 : 0 : *entity = qof_collection_lookup_entity (col, guid);
101 : 0 : if (NULL == *entity)
102 : : {
103 : 0 : result->error_message = g_strdup_printf (_("Entity Not Found: %s"),
104 : : location);
105 : 0 : return FALSE;
106 : : }
107 : :
108 : 0 : return TRUE;
109 : : }
110 : :
111 : :
112 : : static gboolean
113 : 0 : gnc_html_register_url_cb (const char *location, const char *label,
114 : : gboolean new_window, GNCURLResult *result)
115 : : {
116 : 0 : GncPluginPage *page = NULL;
117 : 0 : GNCSplitReg * gsr = NULL;
118 : 0 : Split * split = NULL;
119 : 0 : Account * account = NULL;
120 : : Transaction * trans;
121 : : GncInvoice * invoice;
122 : : GList * node;
123 : : GncGUID guid;
124 : 0 : QofInstance * entity = NULL;
125 : :
126 : 0 : g_return_val_if_fail (location != NULL, FALSE);
127 : 0 : g_return_val_if_fail (result != NULL, FALSE);
128 : :
129 : 0 : result->load_to_stream = FALSE;
130 : :
131 : : /* href="gnc-register:account=My Bank Account" */
132 : 0 : if (strncmp("account=", location, 8) == 0)
133 : : {
134 : 0 : account = gnc_account_lookup_by_full_name (gnc_get_current_root_account (),
135 : 0 : location + 8);
136 : : }
137 : :
138 : : /* href="gnc-register:guid=12345678901234567890123456789012" */
139 : 0 : else if (strncmp ("acct-guid=", location, strlen ("acct-guid=")) == 0)
140 : : {
141 : 0 : if (!validate_type("acct-guid=", location, GNC_ID_ACCOUNT, result, &guid, &entity))
142 : 0 : return FALSE;
143 : :
144 : 0 : account = GNC_ACCOUNT(entity);
145 : : }
146 : :
147 : 0 : else if (strncmp ("trans-guid=", location, strlen ("trans-guid=")) == 0)
148 : : {
149 : 0 : if (!validate_type("trans-guid=", location, GNC_ID_TRANS, result, &guid, &entity))
150 : 0 : return FALSE;
151 : :
152 : 0 : trans = (Transaction *) entity;
153 : :
154 : 0 : for (node = xaccTransGetSplitList (trans); node; node = node->next)
155 : : {
156 : 0 : split = node->data;
157 : 0 : account = xaccSplitGetAccount(split);
158 : 0 : if (account) break;
159 : : }
160 : :
161 : 0 : if (!account)
162 : : {
163 : 0 : result->error_message =
164 : 0 : g_strdup_printf (_("Transaction with no Accounts: %s"), location);
165 : 0 : return FALSE;
166 : : }
167 : : }
168 : :
169 : 0 : else if (strncmp ("trans-doclink-guid=", location,
170 : : strlen ("trans-doclink-guid=")) == 0)
171 : : {
172 : 0 : if (!validate_type("trans-doclink-guid=", location, GNC_ID_TRANS,
173 : : result, &guid, &entity))
174 : 0 : return FALSE;
175 : :
176 : 0 : trans = (Transaction *) entity;
177 : 0 : gnc_doclink_open_uri (gnc_ui_get_gtk_window (GTK_WIDGET (result->parent)),
178 : 0 : xaccTransGetDocLink (trans));
179 : 0 : return TRUE;
180 : : }
181 : :
182 : 0 : else if (strncmp ("invoice-doclink-guid=", location,
183 : : strlen ("invoice-doclink-guid=")) == 0)
184 : : {
185 : 0 : if (!validate_type("invoice-doclink-guid=", location, GNC_ID_INVOICE,
186 : : result, &guid, &entity))
187 : 0 : return FALSE;
188 : :
189 : 0 : invoice = (GncInvoice *) entity;
190 : 0 : gnc_doclink_open_uri (gnc_ui_get_gtk_window (GTK_WIDGET (result->parent)),
191 : 0 : gncInvoiceGetDocLink (invoice));
192 : 0 : return TRUE;
193 : : }
194 : :
195 : 0 : else if (strncmp ("split-guid=", location, strlen ("split-guid=")) == 0)
196 : : {
197 : 0 : if (!validate_type("split-guid=", location, GNC_ID_SPLIT, result, &guid, &entity))
198 : 0 : return FALSE;
199 : :
200 : 0 : split = (Split *) entity;
201 : 0 : account = xaccSplitGetAccount(split);
202 : : }
203 : :
204 : : else
205 : : {
206 : 0 : result->error_message =
207 : 0 : g_strdup_printf (_("Unsupported entity type: %s"), location);
208 : 0 : return FALSE;
209 : : }
210 : :
211 : 0 : page = gnc_plugin_page_register_new (account, FALSE);
212 : 0 : gnc_main_window_open_page (GNC_MAIN_WINDOW (result->parent), page);
213 : 0 : if (split)
214 : : {
215 : 0 : gsr = gnc_plugin_page_register_get_gsr (page);
216 : :
217 : : /* Test for visibility of split */
218 : 0 : if (gnc_split_reg_clear_filter_for_split (gsr, split))
219 : 0 : gnc_plugin_page_register_clear_current_filter (page);
220 : :
221 : 0 : gnc_split_reg_jump_to_split (gsr, split);
222 : : }
223 : 0 : return TRUE;
224 : : }
225 : :
226 : : /* ============================================================== */
227 : :
228 : : static gboolean
229 : 0 : gnc_html_price_url_cb (const char *location, const char *label,
230 : : gboolean new_window, GNCURLResult *result)
231 : : {
232 : : GncGUID guid;
233 : 0 : QofInstance * entity = NULL;
234 : :
235 : 0 : g_return_val_if_fail (location != NULL, FALSE);
236 : 0 : g_return_val_if_fail (result != NULL, FALSE);
237 : :
238 : 0 : result->load_to_stream = FALSE;
239 : :
240 : : /* href="gnc-register:guid=12345678901234567890123456789012" */
241 : 0 : if (strncmp ("price-guid=", location, strlen ("price-guid=")) == 0)
242 : : {
243 : 0 : if (!validate_type("price-guid=", location, GNC_ID_PRICE, result, &guid, &entity))
244 : 0 : return FALSE;
245 : :
246 : 0 : if (!gnc_price_edit_by_guid (GTK_WIDGET (result->parent), &guid))
247 : : {
248 : 0 : result->error_message = g_strdup_printf (_("No such price: %s"),
249 : : location);
250 : 0 : return FALSE;
251 : : }
252 : : }
253 : : else
254 : : {
255 : 0 : result->error_message = g_strdup_printf (_("Badly formed URL %s"),
256 : : location);
257 : 0 : return FALSE;
258 : : }
259 : :
260 : 0 : return TRUE;
261 : : }
262 : :
263 : : /** Restore all persistent program state. This function finds the
264 : : * "new" state file associated with the current session. It then
265 : : * iterates through this state information, calling a helper function
266 : : * to recreate each open window.
267 : : *
268 : : * @note The name of the state file is based on the name of the data
269 : : * file, not the path name of the data file. If there are multiple
270 : : * data files with the same name, the state files will be suffixed
271 : : * with a number. E.G. test_account, test_account_2, test_account_3,
272 : : * etc.
273 : : *
274 : : * @param session A pointer to the current session.
275 : : *
276 : : * @param unused An unused pointer. */
277 : : static void
278 : 0 : gnc_restore_all_state (gpointer session, gpointer unused)
279 : : {
280 : 0 : GKeyFile *keyfile = NULL;
281 : 0 : gchar *file_guid = NULL;
282 : 0 : GError *error = NULL;
283 : :
284 : 0 : keyfile = gnc_state_load (session);
285 : :
286 : : #ifdef DEBUG
287 : : /* Debugging: dump a copy to the trace log */
288 : : {
289 : : gchar *file_data;
290 : : gsize file_length;
291 : 0 : file_data = g_key_file_to_data(keyfile, &file_length, NULL);
292 : 0 : DEBUG("=== File Data Read===\n%s\n=== File End ===\n", file_data);
293 : 0 : g_free(file_data);
294 : : }
295 : : #endif
296 : :
297 : : /* If no state file was found, keyfile will be empty
298 : : * In that case, let's load the default state */
299 : 0 : if (!g_key_file_has_group (keyfile, STATE_FILE_TOP))
300 : : {
301 : 0 : gnc_main_window_restore_default_state(NULL);
302 : 0 : LEAVE("no state file");
303 : 0 : goto cleanup;
304 : : }
305 : :
306 : : /* report any other keyfile read error as a warning
307 : : * but still load default state */
308 : 0 : file_guid = g_key_file_get_string(keyfile, STATE_FILE_TOP,
309 : : STATE_FILE_BOOK_GUID, &error);
310 : 0 : if (error)
311 : : {
312 : 0 : gnc_main_window_restore_default_state(NULL);
313 : 0 : g_warning("error reading group %s key %s: %s",
314 : : STATE_FILE_TOP, STATE_FILE_BOOK_GUID, error->message);
315 : 0 : LEAVE("no guid in state file");
316 : 0 : goto cleanup;
317 : : }
318 : :
319 : 0 : gnc_main_window_restore_all_windows(keyfile);
320 : :
321 : : /* Clean up */
322 : 0 : LEAVE("ok");
323 : 0 : cleanup:
324 : 0 : if (error)
325 : 0 : g_error_free(error);
326 : 0 : if (file_guid)
327 : 0 : g_free(file_guid);
328 : :
329 : 0 : gnc_totd_dialog_reparent ();
330 : 0 : }
331 : :
332 : :
333 : : /** Save all persistent program state to disk. This function finds the
334 : : * name of the "new" state file associated with a specific book guid.
335 : : * It saves some top level data, then iterates through the list of
336 : : * open windows calling a helper function to save each window.
337 : : *
338 : : * @note The name of the state file is based on the name of the data
339 : : * file, not the path name of the data file. If there are multiple
340 : : * data files with the same name, the state files will be suffixed
341 : : * with a number. E.G. test_account, test_account_2, test_account_3,
342 : : * etc.
343 : : *
344 : : * @param session The QofSession whose state should be saved.
345 : : *
346 : : * @param unused */
347 : : static void
348 : 0 : gnc_save_all_state (gpointer session, gpointer unused)
349 : : {
350 : : QofBook *book;
351 : : gchar guid_string[GUID_ENCODING_LENGTH+1];
352 : : const GncGUID *guid;
353 : 0 : GKeyFile *keyfile = NULL;
354 : :
355 : 0 : keyfile = gnc_state_get_current ();
356 : 0 : if (keyfile)
357 : : {
358 : : /* Remove existing Window and Page groups from the keyfile
359 : : * They will be regenerated.
360 : : */
361 : : gsize num_groups, curr;
362 : 0 : gchar **groups = g_key_file_get_groups (keyfile, &num_groups);
363 : 0 : for (curr=0; curr < num_groups; curr++)
364 : : {
365 : 0 : if (g_str_has_prefix (groups[curr], "Window ") ||
366 : 0 : g_str_has_prefix (groups[curr], "Page "))
367 : : {
368 : 0 : DEBUG ("Removing state group %s", groups[curr]);
369 : 0 : g_key_file_remove_group (keyfile, groups[curr], NULL);
370 : : }
371 : : }
372 : 0 : g_strfreev (groups);
373 : : }
374 : :
375 : : /* Store the book's GncGUID in the top level group */
376 : 0 : book = qof_session_get_book(session);
377 : 0 : if (!book)
378 : : {
379 : 0 : PERR("Session has no book!");
380 : 0 : return;
381 : : }
382 : 0 : guid = qof_entity_get_guid(QOF_INSTANCE(book));
383 : 0 : guid_to_string_buff(guid, guid_string);
384 : 0 : g_key_file_set_string(keyfile, STATE_FILE_TOP, STATE_FILE_BOOK_GUID,
385 : : guid_string);
386 : :
387 : 0 : gnc_main_window_save_all_windows(keyfile);
388 : :
389 : : #ifdef DEBUG
390 : : /* Debugging: dump a copy to the trace log */
391 : : {
392 : : gchar *file_data;
393 : : gsize file_length;
394 : 0 : file_data = g_key_file_to_data(keyfile, &file_length, NULL);
395 : 0 : DEBUG("=== File Data Written===\n%s\n=== File End ===\n", file_data);
396 : 0 : g_free(file_data);
397 : : }
398 : : #endif
399 : 0 : LEAVE("");
400 : : }
401 : :
402 : : void
403 : 0 : gnc_main_gui_init (void)
404 : : {
405 : 0 : ENTER(" ");
406 : :
407 : 0 : if (!gnucash_style_init())
408 : 0 : gnc_shutdown(1);
409 : 0 : gnucash_color_init();
410 : :
411 : 0 : gnc_html_register_url_handler (URL_TYPE_REGISTER,
412 : : gnc_html_register_url_cb);
413 : :
414 : 0 : gnc_html_register_url_handler (URL_TYPE_PRICE,
415 : : gnc_html_price_url_cb);
416 : :
417 : : /* Register the Owner search type */
418 : 0 : gnc_search_core_register_type (GNC_OWNER_MODULE_NAME,
419 : : (GNCSearchCoreNew) gnc_search_owner_new);
420 : 0 : gnc_business_urls_initialize ();
421 : 0 : gnc_business_options_gnome_initialize ();
422 : :
423 : : /* FIXME Remove this test code */
424 : 0 : gnc_plugin_manager_add_plugin (
425 : : gnc_plugin_manager_get (), gnc_plugin_account_tree_new ());
426 : 0 : gnc_plugin_manager_add_plugin (
427 : : gnc_plugin_manager_get (), gnc_plugin_basic_commands_new ());
428 : 0 : gnc_plugin_manager_add_plugin (
429 : : gnc_plugin_manager_get (), gnc_plugin_file_history_new ());
430 : 0 : gnc_plugin_manager_add_plugin (
431 : : gnc_plugin_manager_get (), gnc_plugin_menu_additions_new ());
432 : 0 : gnc_plugin_manager_add_plugin (
433 : : gnc_plugin_manager_get (), gnc_plugin_register_new ());
434 : 0 : gnc_plugin_manager_add_plugin (
435 : : gnc_plugin_manager_get (), gnc_plugin_business_new ());
436 : : /* I'm not sure why the FIXME note says to remove this. Maybe
437 : : each module should be adding its own plugin to the manager?
438 : : Anyway... Oh, maybe... nah */
439 : 0 : gnc_plugin_manager_add_plugin (gnc_plugin_manager_get (),
440 : : gnc_plugin_budget_new ());
441 : 0 : gnc_ui_hierarchy_assistant_initialize();
442 : :
443 : : /* Run the ui startup hooks. */
444 : 0 : gnc_hook_run(HOOK_UI_STARTUP, NULL);
445 : :
446 : 0 : gnc_hook_add_dangler(HOOK_BOOK_OPENED,
447 : : gnc_restore_all_state, NULL, NULL);
448 : 0 : gnc_hook_add_dangler(HOOK_BOOK_CLOSED,
449 : : gnc_save_all_state, NULL, NULL);
450 : 0 : gnc_hook_add_dangler(HOOK_BOOK_CLOSED,
451 : : (GFunc)gnc_reports_flush_global, NULL, NULL);
452 : 0 : gnc_hook_add_dangler(HOOK_BOOK_OPENED,
453 : : (GFunc)gnc_invoice_remind_bills_due_cb, NULL, NULL);
454 : 0 : gnc_hook_add_dangler(HOOK_BOOK_OPENED,
455 : : (GFunc)gnc_invoice_remind_invoices_due_cb, NULL, NULL);
456 : :
457 : 0 : gnc_ui_sx_initialize();
458 : :
459 : : /* Add to preferences under Business */
460 : : /* The parameters are; glade file, items to add from glade file - last being the dialog, preference tab name */
461 : 0 : gnc_preferences_add_page("business-prefs.glade", "liststore_printinvoice,days_in_adj,cust_days_in_adj,business_prefs",
462 : 0 : _("Business"));
463 : :
464 : 0 : LEAVE(" ");
465 : 0 : return;
466 : : }
467 : :
468 : : /****************** END OF FILE **********************/
|