/* HomeBank -- Free, easy, personal accounting for everyone. * Copyright (C) 1995-2018 Maxime DOYEN * * This file is part of HomeBank. * * HomeBank is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * HomeBank is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "homebank.h" #include "dsp_mainwindow.h" #include "list_account.h" #include "list_upcoming.h" #include "list_topspending.h" #include "dsp_account.h" #include "ui-assist-import.h" #include "ui-assist-start.h" #include "ui-account.h" #include "ui-currency.h" #include "ui-payee.h" #include "ui-category.h" #include "ui-archive.h" #include "ui-assign.h" #include "ui-budget.h" #include "ui-pref.h" #include "ui-hbfile.h" #include "ui-transaction.h" #include "rep_balance.h" #include "rep_budget.h" #include "rep_stats.h" #include "rep_time.h" #include "rep_vehicle.h" #include "gtk-chart.h" //old url prior 2018 //#define HOMEBANK_URL_HELP "http://homebank.free.fr/help/" //#define HOMEBANK_URL_HELP_ONLINE "https://launchpad.net/homebank/+addquestion" //#define HOMEBANK_URL_HELP_PROBLEM "https://launchpad.net/homebank/+filebug" //#define HOMEBANK_URL_HELP_TRANSLATE "https://launchpad.net/homebank/+translations" #define HOMEBANK_URL_HELP "index.html" #define HOMEBANK_URL_HELP_ONLINE "http://homebank.free.fr/support.php" #define HOMEBANK_URL_HELP_UPDATES "http://homebank.free.fr/downloads.php" #define HOMEBANK_URL_HELP_PROBLEM "http://homebank.free.fr/development.php#bug" #define HOMEBANK_URL_HELP_TRANSLATE "http://homebank.free.fr/development.php#translate" /****************************************************************************/ /* Debug macros */ /****************************************************************************/ #define MYDEBUG 0 #if MYDEBUG #define DB(x) (x); #else #define DB(x); #endif /* our global datas */ extern struct HomeBank *GLOBALS; extern struct Preferences *PREFS; extern gchar *homebank_pixmaps_dir; /* our functions prototype */ static void ui_mainwindow_action_new(void); static void ui_mainwindow_action_open(void); static void ui_mainwindow_action_save(void); static void ui_mainwindow_action_saveas(void); static void ui_mainwindow_action_revert(void); static void ui_mainwindow_action_properties(void); static void ui_mainwindow_action_close(void); static void ui_mainwindow_action_quit(void); static void ui_mainwindow_action_defcurrency(void); static void ui_mainwindow_action_defaccount(void); static void ui_mainwindow_action_defpayee(void); static void ui_mainwindow_action_defcategory(void); static void ui_mainwindow_action_defarchive(void); static void ui_mainwindow_action_defbudget(void); static void ui_mainwindow_action_defassign(void); static void ui_mainwindow_action_preferences(void); static void ui_mainwindow_action_toggle_toolbar(GtkToggleAction *action); static void ui_mainwindow_action_toggle_upcoming(GtkToggleAction *action); static void ui_mainwindow_action_toggle_topspending(GtkToggleAction *action); static void ui_mainwindow_action_toggle_minor(GtkToggleAction *action); static void ui_mainwindow_action_showtransactions(void); static void ui_mainwindow_action_addtransactions(void); static void ui_mainwindow_action_checkscheduled(void); static void ui_mainwindow_action_statistic(void); static void ui_mainwindow_action_trendtime(void); static void ui_mainwindow_action_budget(void); static void ui_mainwindow_action_balance(void); static void ui_mainwindow_action_vehiclecost(void); static void ui_mainwindow_action_import(GtkAction *action); static void ui_mainwindow_action_export(void); static void ui_mainwindow_action_anonymize(void); static void ui_mainwindow_action_file_statistics(void); static void ui_mainwindow_action_help(void); void ui_mainwindow_action_help_welcome(void); static void ui_mainwindow_action_help_online(void); static void ui_mainwindow_action_help_updates(void); static void ui_mainwindow_action_help_releasenotes(void); static void ui_mainwindow_action_help_translate(void); static void ui_mainwindow_action_help_problem(void); static void ui_mainwindow_action_about(void); static GtkWidget *ui_mainwindow_create_recent_chooser_menu (GtkRecentManager *manager); static void ui_mainwindow_populate_topspending(GtkWidget *widget, gpointer user_data); void ui_mainwindow_open(GtkWidget *widget, gpointer user_data); void ui_mainwindow_save(GtkWidget *widget, gpointer user_data); void ui_mainwindow_revert(GtkWidget *widget, gpointer user_data); void ui_mainwindow_action(GtkWidget *widget, gpointer user_data); void ui_mainwindow_toggle_minor(GtkWidget *widget, gpointer user_data); void ui_mainwindow_clear(GtkWidget *widget, gpointer user_data); gboolean ui_dialog_msg_savechanges(GtkWidget *widget, gpointer user_data); void ui_mainwindow_update(GtkWidget *widget, gpointer user_data); void ui_mainwindow_addtransactions(GtkWidget *widget, gpointer user_data); void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path); static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data); static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data); void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data); void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path); static void ui_panel_accounts_setup(struct hbfile_data *data); extern gchar *CYA_ACC_TYPE[]; gchar *CYA_CATSUBCAT[] = { N_("Category"), N_("Subcategory"), NULL }; static GtkActionEntry entries[] = { /* name, icon-name, label */ { "FileMenu" , NULL, N_("_File"), NULL, NULL, NULL }, { "ImportMenu" , NULL, N_("_Import"), NULL, NULL, NULL }, { "EditMenu" , NULL, N_("_Edit"), NULL, NULL, NULL }, { "ViewMenu" , NULL, N_("_View"), NULL, NULL, NULL }, { "ManageMenu" , NULL, N_("_Manage"), NULL, NULL, NULL }, { "TxnMenu" , NULL, N_("_Transactions"), NULL, NULL, NULL }, { "ReportMenu" , NULL, N_("_Reports"), NULL, NULL, NULL }, { "ToolsMenu" , NULL, N_("_Tools"), NULL, NULL, NULL }, { "HelpMenu" , NULL, N_("_Help"), NULL, NULL, NULL }, // { "Import" , NULL, N_("Import") }, // { "Export" , NULL, N_("Export to") }, /* name, icon-name, label, accelerator, tooltip */ /* FileMenu */ { "New" , ICONNAME_NEW , N_("_New") , "N", N_("Create a new file"), G_CALLBACK (ui_mainwindow_action_new) }, { "Open" , ICONNAME_OPEN , N_("_Open...") , "O", N_("Open a file"), G_CALLBACK (ui_mainwindow_action_open) }, { "Save" , ICONNAME_SAVE , N_("_Save") , "S", N_("Save the current file"), G_CALLBACK (ui_mainwindow_action_save) }, { "SaveAs" , ICONNAME_SAVE_AS , N_("Save _As...") , "S", N_("Save the current file with a different name"), G_CALLBACK (ui_mainwindow_action_saveas) }, { "Revert" , ICONNAME_REVERT , N_("Revert") , NULL, N_("Revert to a saved version of this file"), G_CALLBACK (ui_mainwindow_action_revert) }, { "Properties" , ICONNAME_PROPERTIES , N_("Properties..."), NULL, N_("Configure the file"), G_CALLBACK (ui_mainwindow_action_properties) }, { "Close" , ICONNAME_CLOSE , N_("_Close") , "W", N_("Close the current file"), G_CALLBACK (ui_mainwindow_action_close) }, { "Quit" , ICONNAME_QUIT , N_("_Quit") , "Q", N_("Quit HomeBank"), G_CALLBACK (ui_mainwindow_action_quit) }, /* Exchange */ { "ImportQIF" , ICONNAME_HB_FILE_IMPORT , N_("QIF file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, { "ImportOFX" , ICONNAME_HB_FILE_IMPORT , N_("OFX/QFX file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, { "ImportCSV" , ICONNAME_HB_FILE_IMPORT , N_("CSV file...") , NULL, N_("Open the import assistant"), G_CALLBACK (ui_mainwindow_action_import) }, { "ExportQIF" , ICONNAME_HB_FILE_EXPORT , N_("Export QIF file...") , NULL, N_("Export all account in a QIF file"), G_CALLBACK (ui_mainwindow_action_export) }, /* EditMenu */ { "Preferences", ICONNAME_PREFERENCES , N_("Preferences..."), NULL, N_("Configure HomeBank"), G_CALLBACK (ui_mainwindow_action_preferences) }, /* ManageMenu */ { "Currency" , ICONNAME_HB_CURRENCY , N_("Currencies...") , NULL, N_("Configure the currencies"), G_CALLBACK (ui_mainwindow_action_defcurrency) }, { "Account" , ICONNAME_HB_ACCOUNT , N_("Acc_ounts...") , NULL, N_("Configure the accounts"), G_CALLBACK (ui_mainwindow_action_defaccount) }, { "Payee" , ICONNAME_HB_PAYEE , N_("_Payees...") , NULL, N_("Configure the payees"), G_CALLBACK (ui_mainwindow_action_defpayee) }, { "Category" , ICONNAME_HB_CATEGORY , N_("Categories...") , NULL, N_("Configure the categories"), G_CALLBACK (ui_mainwindow_action_defcategory) }, { "Archive" , ICONNAME_HB_ARCHIVE , N_("Scheduled/Template...") , NULL, N_("Configure the scheduled/template transactions"), G_CALLBACK (ui_mainwindow_action_defarchive) }, { "Budget" , ICONNAME_HB_BUDGET , N_("Budget...") , NULL, N_("Configure the budget"), G_CALLBACK (ui_mainwindow_action_defbudget) }, { "Assign" , ICONNAME_HB_ASSIGN , N_("Assignments..."), NULL, N_("Configure the automatic assignments"), G_CALLBACK (ui_mainwindow_action_defassign) }, /* TxnMenu */ { "ShowOpe" , ICONNAME_HB_OPE_SHOW , N_("Show...") , NULL, N_("Shows selected account transactions"), G_CALLBACK (ui_mainwindow_action_showtransactions) }, { "AddOpe" , ICONNAME_HB_OPE_ADD , N_("Add...") , NULL, N_("Add transactions"), G_CALLBACK (ui_mainwindow_action_addtransactions) }, { "Scheduler" , NULL , N_("Set scheduler...") , NULL, N_("Configure the transaction scheduler"), G_CALLBACK (ui_mainwindow_action_properties) }, { "AddScheduled", NULL , N_("Post scheduled"), NULL, N_("Post pending scheduled transactions"), G_CALLBACK (ui_mainwindow_action_checkscheduled) }, /* ReportMenu */ { "RStatistics" , ICONNAME_HB_REP_STATS , N_("_Statistics...") , NULL, N_("Open the Statistics report"), G_CALLBACK (ui_mainwindow_action_statistic) }, { "RTrendTime" , ICONNAME_HB_REP_TIME , N_("_Trend Time...") , NULL, N_("Open the Trend Time report"), G_CALLBACK (ui_mainwindow_action_trendtime) }, { "RBudget" , ICONNAME_HB_REP_BUDGET , N_("B_udget...") , NULL, N_("Open the Budget report"), G_CALLBACK (ui_mainwindow_action_budget) }, { "RBalance" , ICONNAME_HB_REP_BALANCE, N_("Balance...") , NULL, N_("Open the Balance report"), G_CALLBACK (ui_mainwindow_action_balance) }, { "RVehiculeCost", ICONNAME_HB_REP_CAR , N_("_Vehicle cost...") , NULL, N_("Open the Vehicle cost report"), G_CALLBACK (ui_mainwindow_action_vehiclecost) }, /* Tools */ { "Welcome" , NULL , N_("Show welcome dialog...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_help_welcome) }, { "FileStats" , NULL , N_("File statistics...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_file_statistics) }, { "Anonymize" , NULL , N_("Anonymize...") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_anonymize) }, /* HelpMenu */ { "Contents" , ICONNAME_HELP , N_("_Contents") , "F1", N_("Documentation about HomeBank"), G_CALLBACK (ui_mainwindow_action_help) }, { "Online" , "lpi-help" , N_("Get Help Online...") , NULL, N_("Connect to the LaunchPad website for online help"), G_CALLBACK (ui_mainwindow_action_help_online) }, { "Updates" , NULL , N_("Check for updates...") , NULL, N_("Visit HomeBank website to check for update"), G_CALLBACK (ui_mainwindow_action_help_updates) }, { "ReleaseNotes", NULL , N_("Release Notes") , NULL, N_("Display the release notes"), G_CALLBACK (ui_mainwindow_action_help_releasenotes) }, { "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) }, { "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) }, { "About" , ICONNAME_ABOUT , N_("_About") , NULL, N_("About HomeBank") ,G_CALLBACK (ui_mainwindow_action_about) }, }; static guint n_entries = G_N_ELEMENTS (entries); static GtkToggleActionEntry toggle_entries[] = { /* name , icon-name, label, accelerator, tooltip, callback, is_active */ { "Toolbar" , NULL , N_("_Toolbar") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_toggle_toolbar), TRUE }, { "Spending" , NULL , N_("_Top spending") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_toggle_topspending), TRUE }, { "Upcoming" , NULL , N_("_Scheduled list") , NULL, NULL, G_CALLBACK (ui_mainwindow_action_toggle_upcoming), TRUE }, { "AsMinor" , NULL , N_("Euro minor"), "M", NULL, G_CALLBACK (ui_mainwindow_action_toggle_minor), FALSE }, }; static guint n_toggle_entries = G_N_ELEMENTS (toggle_entries); static const gchar *ui_info = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " //" " // print to come here " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " // here Open + recent is coded " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; /* TODO: a bouger */ /* ** */ void ui_mainwindow_revert(GtkWidget *widget, gpointer user_data) { //struct hbfile_data *data; gchar *basename; gchar *title; gchar *secondtext; gint result; DB( g_print("\n[ui-mainwindow] revert\n") ); //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); basename = g_path_get_basename(GLOBALS->xhb_filepath); title = g_strdup_printf ( _("Revert unsaved changes to file '%s'?"), basename); secondtext = _("- Changes made to the file will be permanently lost\n" "- File will be reloaded from the last save (.xhb~)"); result = ui_dialog_msg_confirm_alert( GTK_WINDOW(GLOBALS->mainwindow), title, secondtext, _("_Revert") ); g_free(title); g_free(basename); if( result == GTK_RESPONSE_OK ) { DB( g_print(" - should revert\n") ); hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb~")); ui_mainwindow_open_internal(widget, NULL); hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb")); } } static void activate_url (GtkAboutDialog *about, const gchar *link, gpointer data) { DB( g_print("activate url %s\n", link) ); homebank_util_url_show (link); } static void hbfile_about(void) { GtkWidget *dialog; GdkPixbuf *pixbuf; gchar *pathfilename; gchar *version; static const gchar *artists[] = { "Maxime DOYEN", NULL }; static const gchar *authors[] = { "Lead developer:\n" \ "Maxime DOYEN", "\nContributor:\n" \ "Ga\xc3\xabtan LORIDANT (Maths formulas for charts)\n", NULL }; /* const gchar *documenters[] = { "Maxime DOYEN", NULL }; */ static const gchar *copyright = "Copyright \xc2\xa9 1995-2018 - Maxime DOYEN"; version = g_strdup_printf (PACKAGE_VERSION "\nRunning against GTK+ %d.%d.%d", gtk_get_major_version (), gtk_get_minor_version (), gtk_get_micro_version ()); dialog = gtk_about_dialog_new(); gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(GLOBALS->mainwindow)); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG(dialog), g_get_application_name ()); gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), version); gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), copyright); gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), _("Free, easy, personal accounting for everyone")); gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG(dialog), GTK_LICENSE_GPL_2_0); //gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(dialog), ); gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "http://homebank.free.fr"); gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), "Visit the HomeBank website"); gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(dialog), "homebank"); pathfilename = g_build_filename(homebank_app_get_images_dir(), "splash.png", NULL); pixbuf = gdk_pixbuf_new_from_file(pathfilename, NULL); g_free(pathfilename); if( pixbuf ) { gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf); g_object_unref (pixbuf); } gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog), authors); gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(dialog), artists); //gtk_about_dialog_set_documenters(GTK_ABOUT_DIALOG(dialog), ); //gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(dialog), ); g_signal_connect (dialog, "activate-link", G_CALLBACK (activate_url), NULL); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_free(version); } /* hbfile action functions -------------------- */ static void ui_mainwindow_action_new(void) { GtkWidget *widget = GLOBALS->mainwindow; if( ui_dialog_msg_savechanges(widget,NULL) == TRUE ) { //clear all, and init GLOBALS->xhb_filepath to default ui_mainwindow_clear(widget, GINT_TO_POINTER(TRUE)); // GPOINTER_TO_INT( ui_mainwindow_update(widget, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); ui_start_assistant(); //ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); //ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); //ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL); } } static void ui_mainwindow_action_open(void) { ui_mainwindow_open(GLOBALS->mainwindow, NULL); } static void ui_mainwindow_action_save(void) { ui_mainwindow_save(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE)); } static void ui_mainwindow_action_saveas(void) { ui_mainwindow_save(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE)); } static void ui_mainwindow_action_revert(void) { ui_mainwindow_revert(GLOBALS->mainwindow, NULL); } static void ui_mainwindow_action_close(void) { GtkWidget *widget = GLOBALS->mainwindow; if( ui_dialog_msg_savechanges(widget,NULL) == TRUE ) { //clear all, and init GLOBALS->xhb_filepath to default ui_mainwindow_clear(widget, GINT_TO_POINTER(TRUE)); ui_mainwindow_update(widget, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_REFRESHALL)); } } static void ui_mainwindow_action_quit(void) { gboolean result; //emulate the wm close button g_signal_emit_by_name(GLOBALS->mainwindow, "delete-event", NULL, &result); } static void ui_mainwindow_action_file_statistics(void) { ui_dialog_file_statistics(); } static void ui_mainwindow_action_properties(void) { create_defhbfile_dialog(); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); } static void ui_mainwindow_action_anonymize(void) { gint result; gchar *title; gchar *secondtext; title = _("Are you sure you want to anonymize the file?"); secondtext = _("Proceeding will anonymize any text, \n" "like 'account x', 'payee y', 'memo z', ..."); result = ui_dialog_msg_confirm_alert( GTK_WINDOW(GLOBALS->mainwindow), title, secondtext, _("_Anonymize") ); //#1707201 //if( result == GTK_RESPONSE_CANCEL ) // return; if( result == GTK_RESPONSE_OK ) { hbfile_anonymize(); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); } } static void ui_mainwindow_action_defcurrency(void) { ui_cur_manage_dialog(); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_REFRESHALL)); } static void ui_mainwindow_action_defaccount(void) { ui_acc_manage_dialog(); //our global list has changed, so update the treeview //todo: optimize this, should not call compute balance here account_compute_balances (); ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE)); } static void ui_mainwindow_action_defpayee(void) { ui_pay_manage_dialog(); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); } static void ui_mainwindow_action_defcategory(void) { ui_cat_manage_dialog(); //todo:why refresh upcoming here?? //ui_mainwindow_populate_upcoming(GLOBALS->mainwindow, NULL); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); } static void ui_mainwindow_defarchive(Archive *arc) { struct hbfile_data *data; GtkTreeModel *model; data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); // upcoming list have direct pointer to the arc (which may have changed) model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc)); gtk_list_store_clear (GTK_LIST_STORE(model)); ui_arc_manage_dialog(arc); ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); } static void ui_mainwindow_action_defarchive(void) { ui_mainwindow_defarchive(NULL); } static void ui_mainwindow_action_defbudget(void) { ui_bud_manage_dialog(); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); } static void ui_mainwindow_action_defassign(void) { ui_asg_manage_dialog(); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE)); } static void ui_mainwindow_action_preferences(void) { struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); defpref_dialog_new(); if(!PREFS->euro_active) { GtkToggleAction *action = (GtkToggleAction *)gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/AsMinor"); gtk_toggle_action_set_active(action, FALSE); ui_mainwindow_action_toggle_minor(action); } ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL+UF_REFRESHALL)); } /* display action */ static void ui_mainwindow_action_toggle_toolbar(GtkToggleAction *action) { //struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); PREFS->wal_toolbar = gtk_toggle_action_get_active(action); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL)); } static void ui_mainwindow_action_toggle_upcoming(GtkToggleAction *action) { //struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); PREFS->wal_upcoming = gtk_toggle_action_get_active(action); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL)); } static void ui_mainwindow_action_toggle_topspending(GtkToggleAction *action) { //struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); PREFS->wal_spending = gtk_toggle_action_get_active(action); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_VISUAL)); } static void ui_mainwindow_action_toggle_minor(GtkToggleAction *action) { struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); GLOBALS->minor = gtk_toggle_action_get_active(action); gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_acc)); gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_upc)); // top spending gtk_chart_show_minor(GTK_CHART(data->RE_pie), GLOBALS->minor); ui_panel_topspending_update(data->window, data); } static void ui_mainwindow_action_showtransactions(void) { struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); GtkWidget *window; //todo:change this if( data->acc ) { if( data->acc->window == NULL ) { window = register_panel_window_new(data->acc->key, data->acc); register_panel_window_init(window, NULL); } else { if(GTK_IS_WINDOW(data->acc->window)) gtk_window_present(data->acc->window); } } } static void ui_mainwindow_action_addtransactions(void) { ui_mainwindow_addtransactions(GLOBALS->mainwindow, NULL); } static void ui_mainwindow_action_checkscheduled(void) { ui_mainwindow_scheduled_postall(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE)); } static void ui_mainwindow_action_statistic(void) { ui_repdist_window_new(); } static void ui_mainwindow_action_trendtime(void) { struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); ui_reptime_window_new(data->acc != NULL ? data->acc->key : 0); } static void ui_mainwindow_action_budget(void) { repbudget_window_new(); } static void ui_mainwindow_action_balance(void) { struct hbfile_data *data = g_object_get_data(G_OBJECT(GLOBALS->mainwindow), "inst_data"); repbalance_window_new(data->acc != NULL ? data->acc->key : 0); } static void ui_mainwindow_action_vehiclecost(void) { repcost_window_new(); } static void ui_mainwindow_action_import(GtkAction *action) { const gchar *name; gint filetype = FILETYPE_UNKNOW; name = gtk_action_get_name(action); if( g_str_has_suffix (name, "QIF")) filetype= FILETYPE_QIF; else if( g_str_has_suffix (name, "OFX")) filetype= FILETYPE_OFX; else if( g_str_has_suffix (name, "CSV")) filetype= FILETYPE_CSV_HB; DB( g_print("action %s type=%d\n", name, filetype) ); ui_import_assistant_new(filetype); } static void ui_mainwindow_action_about(void) { hbfile_about(); } static void ui_mainwindow_action_export(void) { gchar *filename; if( ui_file_chooser_qif(NULL, &filename) == TRUE ) { hb_export_qif_account_all(filename); g_free( filename ); } } static void ui_mainwindow_action_help(void) { gchar *link; link = g_build_filename("file:///", homebank_app_get_help_dir(), HOMEBANK_URL_HELP, NULL ); homebank_util_url_show (link); g_free(link); } static void ui_mainwindow_action_help_releasenotes(void) { gchar *link; #ifdef G_OS_WIN32 link = g_build_filename("file:///", homebank_app_get_datas_dir(), "ChangeLog.txt", NULL ); #else link = g_build_filename("file:///", homebank_app_get_datas_dir(), "ChangeLog", NULL ); #endif homebank_util_url_show (link); g_free(link); } //todo: move this to a ui-assist-welcome.c static void ui_mainwindow_action_help_welcome1 (GtkButton *button, gpointer user_data) { gtk_dialog_response (GTK_DIALOG(user_data), 1); } static void ui_mainwindow_action_help_welcome2 (GtkButton *button, gpointer user_data) { gtk_dialog_response (GTK_DIALOG(user_data), 2); } static void ui_mainwindow_action_help_welcome3 (GtkButton *button, gpointer user_data) { gtk_dialog_response (GTK_DIALOG(user_data), 3); } static void ui_mainwindow_action_help_welcome4 (GtkButton *button, gpointer user_data) { gtk_dialog_response (GTK_DIALOG(user_data), 4); } static void ui_mainwindow_action_help_welcome5 (GtkButton *button, gpointer user_data) { gtk_dialog_response (GTK_DIALOG(user_data), 5); } void ui_mainwindow_action_help_welcome(void) { GtkWidget *dialog, *content_area; GtkWidget *mainvbox, *widget, *label; dialog = gtk_dialog_new_with_buttons (_("Welcome to HomeBank"), GTK_WINDOW(GLOBALS->mainwindow), 0, _("_Close"), GTK_RESPONSE_ACCEPT, NULL); content_area = gtk_dialog_get_content_area(GTK_DIALOG (dialog)); mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_box_pack_start (GTK_BOX (content_area), mainvbox, FALSE, FALSE, 0); gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM); label = make_label (_("HomeBank"), 0, 0); gimp_label_set_attributes(GTK_LABEL(label), PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1); gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0); label = make_label (_("Free, easy, personal accounting for everyone"), 0, 0); gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0); widget = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); gtk_box_pack_start (GTK_BOX (content_area), widget, FALSE, FALSE, 0); mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, SPACING_MEDIUM); gtk_box_pack_start (GTK_BOX (content_area), mainvbox, TRUE, TRUE, 0); gtk_container_set_border_width (GTK_CONTAINER(mainvbox), SPACING_MEDIUM); label = make_label (_("What do you want to do:"), 0, 0); gimp_label_set_attributes(GTK_LABEL(label), PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD, -1); gtk_box_pack_start (GTK_BOX (mainvbox), label, FALSE, FALSE, 0); widget = gtk_button_new_with_mnemonic(_("Read HomeBank _Manual")); gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome1), dialog); widget = gtk_button_new_with_mnemonic(_("Configure _preferences")); gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome2), dialog); widget = gtk_button_new_with_mnemonic(_("Create a _new file")); gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome3), dialog); widget = gtk_button_new_with_mnemonic(_("_Open an existing file")); gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome4), dialog); widget = gtk_button_new_with_mnemonic(_("Open the _example file")); gtk_box_pack_start (GTK_BOX (mainvbox), widget, FALSE, FALSE, 0); g_signal_connect (widget, "clicked", G_CALLBACK (ui_mainwindow_action_help_welcome5), dialog); //connect all our signals g_signal_connect (dialog, "destroy", G_CALLBACK (gtk_widget_destroyed), &dialog); gtk_widget_show_all (dialog); //wait for the user gint result = gtk_dialog_run (GTK_DIALOG (dialog)); // cleanup and destroy gtk_widget_destroy (dialog); // do appropriate action switch(result) { case 1: ui_mainwindow_action_help(); break; case 2: ui_mainwindow_action_preferences(); break; case 3: ui_mainwindow_action_new(); break; case 4: ui_mainwindow_action_open(); break; case 5: hbfile_change_filepath(g_build_filename(homebank_app_get_datas_dir(), "example.xhb", NULL)); ui_mainwindow_open_internal(GLOBALS->mainwindow, NULL); break; } } static void ui_mainwindow_action_help_updates(void) { const gchar *link = HOMEBANK_URL_HELP_UPDATES; homebank_util_url_show (link); } static void ui_mainwindow_action_help_online(void) { const gchar *link = HOMEBANK_URL_HELP_ONLINE; homebank_util_url_show (link); } static void ui_mainwindow_action_help_translate(void) { const gchar *link = HOMEBANK_URL_HELP_TRANSLATE; homebank_util_url_show (link); } static void ui_mainwindow_action_help_problem(void) { const gchar *link = HOMEBANK_URL_HELP_PROBLEM; homebank_util_url_show (link); } /* hbfile functions -------------------- */ /* ** */ static void ui_mainwindow_selection(GtkTreeSelection *treeselection, gpointer user_data) { ui_mainwindow_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE)); } static void ui_mainwindow_close_openbooks(void) { GList *lacc, *elt; DB( g_print("\n[ui-mainwindow] close openbooks\n") ); lacc = elt = g_hash_table_get_values(GLOBALS->h_acc); while (elt != NULL) { Account *item = elt->data; if(item->window) { gtk_widget_destroy(GTK_WIDGET(item->window)); item->window = NULL; } elt = g_list_next(elt); } g_list_free(lacc); } /* ** */ void ui_mainwindow_clear(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; gboolean file_clear = GPOINTER_TO_INT(user_data); DB( g_print("\n[ui-mainwindow] clear\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); // Close opened account window // Clear TreeView ui_mainwindow_close_openbooks(); gtk_tree_store_clear(GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc)))); gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc)))); gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top)))); data->showall = FALSE; ui_panel_accounts_setup(data); hbfile_cleanup(file_clear); hbfile_setup(file_clear); } /* ** add some transactions directly */ void ui_mainwindow_addtransactions(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; GtkWidget *window; gint result = 1; guint32 date; gint account, count; DB( g_print("\n[ui-mainwindow] add transactions\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); /* init the transaction */ date = homebank_app_date_get_julian(); //#1656531 account = 0; if(data->acc != NULL) account = data->acc->key; window = create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, FALSE); count = 0; while(result == GTK_RESPONSE_ADD || result == GTK_RESPONSE_ADDKEEP) { Transaction *ope; /* fill in the transaction */ if( result == GTK_RESPONSE_ADD ) { ope = da_transaction_malloc(); ope->date = date; ope->kacc = account; if( PREFS->heritdate == FALSE ) //fix: 318733 ope->date = GLOBALS->today; } // normally we can't be in addkeep without initialized ope with add deftransaction_set_transaction(window, ope); result = gtk_dialog_run (GTK_DIALOG (window)); DB( g_print(" - dialog result is %d\n", result) ); if(result == GTK_RESPONSE_ADD || result == GTK_RESPONSE_ADDKEEP || result == GTK_RESPONSE_ACCEPT) { deftransaction_get(window, NULL); transaction_add(ope); DB( g_print(" - added 1 transaction to %d\n", ope->kacc) ); ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); count++; //todo: still usefull ? store last date date = ope->date; } if( result == GTK_RESPONSE_ADD ) { da_transaction_free(ope); ope = NULL; } } deftransaction_dispose(window, NULL); gtk_widget_destroy (window); /* todo optimize this */ if(count > 0) { GLOBALS->changes_count += count; ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_BALANCE+UF_REFRESHALL)); } } struct tmptop { guint32 key; gdouble value; }; #define MAX_TOPSPENDING 10 static gint tmptop_compare_func(struct tmptop *tt1, struct tmptop *tt2) { return tt1->value > tt2->value ? 1 : -1; } static void ui_panel_topspending_update(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; GtkTreeModel *model; gchar *title; gchar strbuffer[G_ASCII_DTOSTR_BUF_SIZE]; DB( g_print("\n[ui-mainwindow] topspending_update\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); hb_strfmon(strbuffer, G_ASCII_DTOSTR_BUF_SIZE-1, data->toptotal, GLOBALS->kcur, GLOBALS->minor); //hb_label_set_amount(GTK_LABEL(data->TX_topamount), total, GLOBALS->kcur, GLOBALS->minor); title = g_strdup_printf("%s %s", _("Top spending"), strbuffer); model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top)); gtk_chart_set_color_scheme(GTK_CHART(data->RE_pie), PREFS->report_color_scheme); gtk_chart_set_currency(GTK_CHART(data->RE_pie), GLOBALS->kcur); gtk_chart_set_datas(GTK_CHART(data->RE_pie), model, LST_TOPSPEND_AMOUNT, title, NULL); g_free(title); //future usage gchar *fu = _("Top %d spending"); title = fu; } static void ui_mainwindow_populate_topspending(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; GtkTreeModel *model; GtkTreeIter iter; GList *list; gint type, range; guint n_result, i, n_items; GArray *garray; gdouble total, other; Account *acc; DB( g_print("\n[ui-mainwindow] populate_topspending\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); type = radio_get_active(GTK_CONTAINER(data->RA_type)); range = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_range)); DB( g_print(" - type=%d, range=%d\n", type, range) ); DB( g_print(" - pref range=%d\n", PREFS->date_range_wal) ); if(range == FLT_RANGE_OTHER) return; filter_preset_daterange_set(data->filter, range, 0); n_result = da_cat_get_max_key() + 1; total = 0.0; DB( g_print(" - max key is %d\n", n_result) ); /* allocate some memory */ garray = g_array_sized_new(FALSE, FALSE, sizeof(struct tmptop), n_result); if(garray) { struct tmptop zero = { .key=0, .value=0.0 }; GQueue *txn_queue; //DB( g_print(" - array length=%d\n", garray->len) ); for(i=0 ; ikey, tt->value) ); } //DB( g_print("\n - end array length=%d\n", garray->len) ); //todo: not ideal, has ot force to get_acc for each txn below txn_queue = hbfile_transaction_get_partial(data->filter->mindate, data->filter->maxdate); /* compute the results */ list = g_queue_peek_head_link(txn_queue); while (list != NULL) { Transaction *ope = list->data; //DB( g_print(" - eval txn: '%s', cat=%d ==> flt-test=%d\n", ope->memo, ope->kcat, filter_test(data->filter, ope)) ); if( !(ope->paymode == PAYMODE_INTXFER) ) { guint32 pos = 0; gdouble trn_amount; //todo: optimize here trn_amount = ope->amount; acc = da_acc_get(ope->kacc); if(acc) trn_amount = hb_amount_base(ope->amount, acc->kcur); if( ope->flags & OF_SPLIT ) { guint nbsplit = da_splits_count(ope->splits); Split *split; struct tmptop *item; for(i=0;isplits[i]; pos = category_report_id(split->kcat, type); trn_amount = hb_amount_base(split->amount, acc->kcur); //trn_amount = split->amount; //#1297054 if( trn_amount < 0 ) { item = &g_array_index (garray, struct tmptop, pos); item->key = pos; item->value += trn_amount; //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos) ); //} } } else { struct tmptop *item; pos = category_report_id(ope->kcat, type); //#1297054 if( trn_amount < 0 ) { item = &g_array_index (garray, struct tmptop, pos); item->key = pos; item->value += trn_amount; //DB( g_print(" - stored %.2f to item %d\n", trn_amount, pos) ); //} } } list = g_list_next(list); } g_queue_free (txn_queue); // we need to sort this and limit before g_array_sort(garray, (GCompareFunc)tmptop_compare_func); n_items = MIN(garray->len,MAX_TOPSPENDING); other = 0; for(i=0 ; ilen ; i++) { struct tmptop *item; item = &g_array_index (garray, struct tmptop, i); if(item->value < 0) { total += item->value; if(i >= n_items) other += item->value; DB( g_print(" - %d : k='%d' v='%f' t='%f'\n", i, item->key, item->value, total) ); } } model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_top)); gtk_list_store_clear (GTK_LIST_STORE(model)); g_object_ref(model); /* Make sure the model stays with us after the tree view unrefs it */ gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_top), NULL); /* Detach model from view */ /* insert into the treeview */ for(i=0 ; ilen,MAX_TOPSPENDING) ; i++) { gchar *name; Category *entry; struct tmptop *item; gdouble value; item = &g_array_index (garray, struct tmptop, i); if(!item->value) continue; value = hb_amount_round(item->value, 2); entry = da_cat_get(item->key); if(entry == NULL) continue; name = entry->key == 0 ? _("(no category)") : da_cat_get_fullname(entry); // append test gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_TOPSPEND_ID, i, LST_TOPSPEND_KEY, 0, LST_TOPSPEND_NAME, name, LST_TOPSPEND_AMOUNT, value, //LST_TOPSPEND_RATE, (gint)(((ABS(value)*100)/ABS(total)) + 0.5), -1); } // append test if(ABS(other) > 0) { gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_TOPSPEND_ID, n_items, LST_TOPSPEND_KEY, 0, LST_TOPSPEND_NAME, _("Other"), LST_TOPSPEND_AMOUNT, other, //LST_TOPSPEND_RATE, (gint)(((ABS(other)*100)/ABS(total)) + 0.5), -1); } /* Re-attach model to view */ gtk_tree_view_set_model(GTK_TREE_VIEW(data->LV_top), model); g_object_unref(model); // update chart and widgets { gchar *daterange; data->toptotal = total; ui_panel_topspending_update(widget, data); daterange = filter_daterange_text_get(data->filter); gtk_widget_set_tooltip_markup(GTK_WIDGET(data->CY_range), daterange); g_free(daterange); } } /* free our memory */ g_array_free (garray, TRUE); } /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ /* scheduled */ /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ static Archive * ui_mainwindow_scheduled_get_selected_item(GtkTreeView *treeview) { GtkTreeSelection *treeselection; GtkTreeModel *model; GtkTreeIter iter; treeselection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); if( gtk_tree_selection_get_selected(treeselection, &model, &iter) ) { Archive *arc; gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPUPC_DATAS, &arc, -1); return arc; } return NULL; } static void ui_mainwindow_scheduled_onRowActivated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata) { //struct hbfile_data *data; Archive *arc; DB( g_print ("\n[ui-mainwindow] A scheduled row has been double-clicked!\n") ); //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(treeview, GTK_TYPE_WINDOW)), "inst_data"); arc = ui_mainwindow_scheduled_get_selected_item(treeview); ui_mainwindow_defarchive(arc); } static void ui_mainwindow_scheduled_do_post(Archive *arc, gboolean doedit, gpointer user_data) { struct hbfile_data *data = user_data; GtkWidget *window; gint result; Transaction *txn; window = create_deftransaction_window(GTK_WINDOW(data->window), TRANSACTION_EDIT_ADD, TRUE); /* fill in the transaction */ txn = da_transaction_malloc(); da_transaction_init_from_template(txn, arc); txn->date = scheduled_get_postdate(arc, arc->nextdate); deftransaction_set_transaction(window, txn); result = gtk_dialog_run (GTK_DIALOG (window)); DB( g_print(" - dialog result is %d\n", result) ); if(result == GTK_RESPONSE_ADD || result == GTK_RESPONSE_ACCEPT) { deftransaction_get(window, NULL); transaction_add(txn); GLOBALS->changes_count++; scheduled_date_advance(arc); DB( g_print(" - added 1 transaction to %d\n", txn->kacc) ); } da_transaction_free(txn); deftransaction_dispose(window, NULL); gtk_widget_destroy (window); } static void ui_mainwindow_scheduled_editpost_cb(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data = user_data; Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); if( (arc != NULL) ) { ui_mainwindow_scheduled_do_post(arc, TRUE, data); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL)); } } static void ui_mainwindow_scheduled_post_cb(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data = user_data; DB( g_print("\n[ui-mainwindow] scheduled post\n") ); Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); if( (arc != NULL) ) { if( scheduled_is_postable(arc) ) { Transaction *txn = da_transaction_malloc (); da_transaction_init_from_template(txn, arc); txn->date = scheduled_get_postdate(arc, arc->nextdate); transaction_add(txn); GLOBALS->changes_count++; scheduled_date_advance(arc); da_transaction_free (txn); } else { ui_mainwindow_scheduled_do_post(arc, FALSE, data); } ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE|UF_REFRESHALL)); } } static void ui_mainwindow_scheduled_skip_cb(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data = user_data; Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); if( (arc != NULL) && (arc->flags & OF_AUTO) ) { GLOBALS->changes_count++; scheduled_date_advance(arc); ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_SENSITIVE)); } } static void ui_mainwindow_scheduled_update(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; //gint filter; DB( g_print("\n[ui-mainwindow] scheduled update\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); //filter = gtk_combo_box_get_active(GTK_COMBO_BOX(data->CY_sched_filter)); Archive *arc = ui_mainwindow_scheduled_get_selected_item(GTK_TREE_VIEW(data->LV_upc)); if(arc) { DB( g_print("archive is %s\n", arc->memo) ); gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), TRUE); } else { gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_skip), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_post), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(data->BT_sched_editpost), FALSE); } } static void ui_mainwindow_scheduled_selection_cb(GtkTreeSelection *treeselection, gpointer user_data) { ui_mainwindow_scheduled_update(GTK_WIDGET(gtk_tree_selection_get_tree_view (treeselection)), GINT_TO_POINTER(UF_SENSITIVE)); } /* ** called after load, importamiga, on demand */ void ui_mainwindow_scheduled_postall(GtkWidget *widget, gpointer user_data) { //struct hbfile_data *data; gint count; gint usermode = GPOINTER_TO_INT(user_data); DB( g_print("\n[ui-mainwindow] check scheduled\n") ); //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); count = scheduled_post_all_pending(); //inform the user if(usermode == TRUE) { gchar *txt; //#125534 if( count > 0 ) { ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_REFRESHALL)); } if(count == 0) txt = _("No transaction to add"); else txt = _("transaction added: %d"); ui_dialog_msg_infoerror(GTK_WINDOW(GLOBALS->mainwindow), GTK_MESSAGE_INFO, _("Check scheduled transactions result"), txt, count); } } static void ui_mainwindow_scheduled_populate(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; GtkTreeModel *model; GtkTreeIter iter; GList *list; gdouble totexp = 0; gdouble totinc = 0; gint count = 0; gchar buffer[256]; guint32 maxpostdate; GDate *date; //Account *acc; DB( g_print("\n[ui-mainwindow] scheduled populate list\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_upc)); gtk_list_store_clear (GTK_LIST_STORE(model)); homebank_app_date_get_julian(); maxpostdate = scheduled_date_get_post_max(); date = g_date_new_julian (maxpostdate); g_date_strftime (buffer, 256-1, PREFS->date_format, date); g_date_free(date); gtk_label_set_text(GTK_LABEL(data->LB_maxpostdate), buffer); list = g_list_first(GLOBALS->arc_list); while (list != NULL) { Archive *arc = list->data; Account *acc; gdouble inc, exp; guint nbdays, nblate; if((arc->flags & OF_AUTO) ) //&& arc->kacc > 0) { count++; nbdays = arc->nextdate - maxpostdate; nblate = scheduled_get_latepost_count(arc, GLOBALS->today); DB( g_print(" - append '%s' : %d\n", arc->memo, nbdays) ); if(arc->flags & OF_INCOME) { inc = arc->amount; exp = 0.0; } else { exp = arc->amount; inc = 0.0; } /* insert normal txn */ acc = da_acc_get(arc->kacc); if( acc) { totinc += hb_amount_base(inc, acc->kcur); totexp += hb_amount_base(exp, acc->kcur); } gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_DSPUPC_DATAS, arc, LST_DSPUPC_ACCOUNT, acc, LST_DSPUPC_MEMO, arc->memo, LST_DSPUPC_EXPENSE, exp, LST_DSPUPC_INCOME, inc, LST_DSPUPC_REMAINING, nbdays, LST_DSPUPC_NB_LATE, nblate, -1); /* insert internal xfer txn : 1378836 */ if(arc->paymode == PAYMODE_INTXFER) { acc = da_acc_get(arc->kxferacc); if( acc) { totinc += hb_amount_base(-inc, acc->kcur); totexp += hb_amount_base(-exp, acc->kcur); } gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_DSPUPC_DATAS, arc, LST_DSPUPC_ACCOUNT, acc, LST_DSPUPC_MEMO, arc->memo, LST_DSPUPC_EXPENSE, -inc, LST_DSPUPC_INCOME, -exp, LST_DSPUPC_REMAINING, nbdays, LST_DSPUPC_NB_LATE, nblate, -1); } } list = g_list_next(list); } // insert total if(count > 0 ) { gtk_list_store_append (GTK_LIST_STORE(model), &iter); gtk_list_store_set (GTK_LIST_STORE(model), &iter, LST_DSPUPC_DATAS, NULL, LST_DSPUPC_ACCOUNT, NULL, LST_DSPUPC_MEMO, _("Total"), LST_DSPUPC_EXPENSE, totexp, LST_DSPUPC_INCOME, totinc, -1); } ui_mainwindow_scheduled_update(widget, NULL); } gboolean ui_mainwindow_open_backup_check_confirm(gchar *filepath) { gboolean retval = FALSE; gchar *basename, *secondtext; gboolean result; basename = g_path_get_basename(filepath); secondtext = g_strdup_printf ( _("Your are about to open the backup file '%s'.\n\nAre you sure you want to do this ?"), basename); result = ui_dialog_msg_confirm_alert( GTK_WINDOW(GLOBALS->mainwindow), _("Open a backup file ?"), secondtext, _("_Open backup") ); g_free(secondtext); g_free(basename); if( result == GTK_RESPONSE_OK ) retval = TRUE; return retval; } /* ** */ void ui_mainwindow_open(GtkWidget *widget, gpointer user_data) { //struct hbfile_data *data; gchar *filename = NULL; DB( g_print("\n[ui-mainwindow] open\n") ); //data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); if( ui_dialog_msg_savechanges(widget,NULL) == TRUE ) { if( ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_OPEN, &filename) == TRUE ) { //#1710955 test for backup open if( hbfile_file_isbackup(filename) ) { if( ui_mainwindow_open_backup_check_confirm(filename) == TRUE ) { GLOBALS->hbfile_is_bak = TRUE; } else { g_free(filename); return; } } hbfile_change_filepath(filename); ui_mainwindow_open_internal(widget, NULL); } } } /* * open the file stored in GLOBALS->xhb_filepath */ void ui_mainwindow_open_internal(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; gint r; DB( g_print("\n[ui-mainwindow] open internal\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); if( GLOBALS->xhb_filepath != NULL ) { DB( g_print(" - filename: '%s'\n", GLOBALS->xhb_filepath) ); ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(FALSE)); GLOBALS->hbfile_is_new = FALSE; r = homebank_load_xml(GLOBALS->xhb_filepath); if( r == XML_OK ) { DB( g_print(" - file loaded ok : rcode=%d\n", r) ); hbfile_file_hasbackup(GLOBALS->xhb_filepath); if(PREFS->appendscheduled) scheduled_post_all_pending(); if(PREFS->do_update_currency) ui_cur_manage_dialog_update_currencies(GTK_WINDOW(GLOBALS->mainwindow)); homebank_lastopenedfiles_save(); //todo: delete this after computing done at xml read account_compute_balances(); ui_mainwindow_recent_add(data, GLOBALS->xhb_filepath); } else { gchar *msg = _("Unknow error"); switch(r) { case XML_IO_ERROR: msg = _("I/O error for file '%s'."); break; case XML_FILE_ERROR: msg = _("The file '%s' is not a valid HomeBank file."); break; case XML_VERSION_ERROR: msg = _("The file '%s' was saved with a higher version of HomeBank\nand cannot be loaded by the current version."); break; } ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR, _("File error"), msg, GLOBALS->xhb_filepath ); ui_mainwindow_clear(GLOBALS->mainwindow, GINT_TO_POINTER(TRUE)); } ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL); ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL)); } } /* ** */ void ui_mainwindow_save(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; gboolean saveas = GPOINTER_TO_INT(user_data); gchar *filename = NULL; gint r = XML_UNSET; DB( g_print("\n[ui-mainwindow] save\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); if( GLOBALS->hbfile_is_new == TRUE ) saveas = 1; //#1710955 test for backup open if( GLOBALS->hbfile_is_bak == TRUE ) { //todo: later for backup, should also remove datetime and .bak hbfile_change_filepath(hb_filename_new_with_extension(GLOBALS->xhb_filepath, "xhb")); saveas = 1; } if(saveas == 1) { if(ui_file_chooser_xhb(GTK_FILE_CHOOSER_ACTION_SAVE, &filename) == TRUE) { DB( g_print(" + should save as '%s'\n", filename) ); homebank_file_ensure_xhb(filename); homebank_backup_current_file(); r = homebank_save_xml(GLOBALS->xhb_filepath); GLOBALS->hbfile_is_new = FALSE; GLOBALS->hbfile_is_bak = FALSE; } else return; } else { DB( g_print(" + should quick save %s\n", GLOBALS->xhb_filepath) ); homebank_file_ensure_xhb(NULL); homebank_backup_current_file(); r = homebank_save_xml(GLOBALS->xhb_filepath); } if(r == XML_OK) { GLOBALS->changes_count = 0; ui_mainwindow_update(GLOBALS->mainwindow, GINT_TO_POINTER(UF_TITLE+UF_SENSITIVE+UF_VISUAL)); } else { gchar *msg = _("I/O error for file '%s'."); ui_dialog_msg_infoerror(GTK_WINDOW(data->window), GTK_MESSAGE_ERROR, _("File error"), msg, GLOBALS->xhb_filepath ); } } static void ui_panel_accounts_expand_all(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_acc)); } static void ui_panel_accounts_collapse_all(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); gtk_tree_view_collapse_all(GTK_TREE_VIEW(data->LV_acc)); } static GHashTable *ui_panel_accounts_groups_get(GList *lacc, gint groupby, gboolean showall) { GHashTable *hash; GList *elt; gchar *groupname; gint nballoc; DB( g_print("\n[ui-mainwindow] accounts_groups_get\n") ); nballoc = da_acc_length (); DB( g_print(" %d accounts\n", nballoc) ); hash = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); elt = g_list_first(lacc); while (elt != NULL) { Account *acc = elt->data; GPtrArray *group; //#1674045 ony rely on nosummary //if( showall || !(acc->flags & (AF_CLOSED|AF_NOSUMMARY)) ) if( showall || !(acc->flags & AF_NOSUMMARY) ) { if( groupby == DSPACC_GROUP_BY_BANK ) { groupname = _("(no institution)"); if( (acc->bankname != NULL) && strlen(acc->bankname) > 0 ) groupname = acc->bankname; } else { //pre 5.1.3 historical by type display groupname = _(CYA_ACC_TYPE[acc->type]); } if( g_hash_table_contains(hash, groupname) == FALSE ) { g_hash_table_insert(hash, g_strdup(groupname), g_ptr_array_sized_new(nballoc) ); //DB( g_print(" - type hash insert '%s' = %d\n", groupname, inserted) ); } group = g_hash_table_lookup(hash, groupname); if( group != NULL ) { g_ptr_array_add(group, (gpointer)acc); DB( g_print(" -- add '%s' to group '%s'\n", acc->name, groupname) ); } } elt = g_list_next(elt); } return hash; } void ui_mainwindow_populate_accounts(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; GtkTreeModel *model; GtkTreeIter iter1, child_iter; GList *lacc, *elt; Account *acc; guint j, nbtype; gdouble gtbank, gttoday, gtfuture; GHashTable *h_group; GHashTableIter grp_iter; gpointer key, value; DB( g_print("\n[ui-mainwindow] populate accounts\n") ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); /* here we create a count and a list of every account pointer by type */ lacc = elt = g_hash_table_get_values(GLOBALS->h_acc); h_group = ui_panel_accounts_groups_get(lacc, PREFS->pnl_acc_show_by, data->showall); g_list_free(lacc); gtbank = gttoday = gtfuture = 0; DB( g_print(" - populate listview, %d group(s)\n", g_hash_table_size(h_group)) ); model = gtk_tree_view_get_model(GTK_TREE_VIEW(data->LV_acc)); gtk_tree_store_clear (GTK_TREE_STORE(model)); nbtype = 0; g_hash_table_iter_init (&grp_iter, h_group); while (g_hash_table_iter_next (&grp_iter, &key, &value)) { GPtrArray *gpa = value; gdouble tbank, ttoday, tfuture; gint position; if(gpa != NULL) { nbtype++; //1: Header: Bank, Cash, ... DB( g_print(" - add group '%s'\n", (gchar *)key) ); //#1663399 keep type position like in dropdown position = 0; if( PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE ) { gint t = 0; while(CYA_ACC_TYPE[t] != NULL && t < 15) { if( !strcmp(CYA_ACC_TYPE[t], key) ) break; t++; } position = t; } gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL); gtk_tree_store_set (GTK_TREE_STORE(model), &iter1, LST_DSPACC_POS, position, LST_DSPACC_DATATYPE, DSPACC_TYPE_HEADER, LST_DSPACC_NAME, key, -1); tbank = ttoday = tfuture = 0; //2: Accounts for real for(j=0;jlen;j++) { acc = g_ptr_array_index(gpa, j); //tbank += acc->bal_bank; //ttoday += acc->bal_today; //tfuture += acc->bal_future; tbank += hb_amount_base(acc->bal_bank, acc->kcur); ttoday += hb_amount_base(acc->bal_today, acc->kcur); tfuture += hb_amount_base(acc->bal_future, acc->kcur); DB( g_print(" - add account '%s' :: %.2f %.2f %.2f\n", acc->name, acc->bal_bank, acc->bal_today, acc->bal_future) ); gtk_tree_store_append (GTK_TREE_STORE(model), &child_iter, &iter1); gtk_tree_store_set (GTK_TREE_STORE(model), &child_iter, LST_DSPACC_DATAS, acc, LST_DSPACC_DATATYPE, DSPACC_TYPE_NORMAL, LST_DSPACC_BANK, acc->bal_bank, LST_DSPACC_TODAY, acc->bal_today, LST_DSPACC_FUTURE, acc->bal_future, -1); } if(gpa->len > 1) { DB( g_print(" - group total :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) ); // insert the total line gtk_tree_store_append (GTK_TREE_STORE(model), &child_iter, &iter1); gtk_tree_store_set (GTK_TREE_STORE(model), &child_iter, LST_DSPACC_DATATYPE, DSPACC_TYPE_SUBTOTAL, LST_DSPACC_NAME, _("Total"), LST_DSPACC_BANK, tbank, LST_DSPACC_TODAY, ttoday, LST_DSPACC_FUTURE, tfuture, -1); } /* set balance to header to display when collasped */ DB( g_print(" - enrich group total header :: %.2f %.2f %.2f\n", tbank, ttoday, tfuture) ); gtk_tree_store_set (GTK_TREE_STORE(model), &iter1, LST_DSPACC_BANK, tbank, LST_DSPACC_TODAY, ttoday, LST_DSPACC_FUTURE, tfuture, -1); /* add to grand total */ gtbank += tbank; gttoday += ttoday; gtfuture += tfuture; } } DB( g_print(" - grand total :: %.2f %.2f %.2f\n", gtbank, gttoday, gtfuture) ); // Grand total if( nbtype > 1 ) { gtk_tree_store_append (GTK_TREE_STORE(model), &iter1, NULL); gtk_tree_store_set (GTK_TREE_STORE(model), &iter1, LST_DSPACC_DATATYPE, DSPACC_TYPE_SUBTOTAL, LST_DSPACC_NAME, _("Grand total"), LST_DSPACC_BANK, gtbank, LST_DSPACC_TODAY, gttoday, LST_DSPACC_FUTURE, gtfuture, -1); } gtk_tree_view_expand_all(GTK_TREE_VIEW(data->LV_acc)); DB( g_print(" - free ressources\n") ); g_hash_table_iter_init (&grp_iter, h_group); while (g_hash_table_iter_next (&grp_iter, &key, &value)) { g_ptr_array_free (value, TRUE); } g_hash_table_destroy (h_group); } void ui_mainwindow_update(GtkWidget *widget, gpointer user_data) { struct hbfile_data *data; gint flags; DB( g_print("\n[ui-mainwindow] update %p\n", user_data) ); data = g_object_get_data(G_OBJECT(gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), "inst_data"); //data = INST_DATA(widget); flags = GPOINTER_TO_INT(user_data); /* set window title */ if(flags & UF_TITLE) { gchar *basename; gchar *changed; DB( g_print(" 1: wintitle %p\n", data->wintitle) ); basename = g_path_get_basename(GLOBALS->xhb_filepath); DB( g_print(" global changes: %d\n", GLOBALS->changes_count) ); g_free(data->wintitle); changed = (GLOBALS->changes_count > 0) ? "*" : ""; data->wintitle = g_strdup_printf("%s%s - %s - " PROGNAME, changed, basename, GLOBALS->owner); gtk_window_set_title (GTK_WINDOW (gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW)), data->wintitle); g_free(basename); } /* update disabled things */ if(flags & UF_SENSITIVE) { GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; gboolean active,sensitive; DB( g_print(" 2: disabled, opelist count\n") ); //#1656531 data->acc = NULL; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_acc)); active = gtk_tree_selection_get_selected(selection, &model, &iter); if(active) { Account *acc; gint depth; path = gtk_tree_model_get_path(model, &iter); depth = gtk_tree_path_get_depth(path); if( depth > 1 ) { DB( g_print(" depth is %d\n", depth) ); gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, LST_DSPACC_DATAS, &acc, -1); data->acc = acc; } else active = FALSE; } // no change: disable save DB( g_print(" changes %d - new %d\n", GLOBALS->changes_count, GLOBALS->hbfile_is_new) ); sensitive = (GLOBALS->changes_count != 0 ) ? TRUE : FALSE; //gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/SaveAs"), sensitive); //if(sensitive == TRUE && GLOBALS->hbfile_is_new == TRUE) sensitive = FALSE; gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Save"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Revert"), GLOBALS->xhb_hasbak); // define off ? sensitive = GLOBALS->define_off == 0 ? TRUE : FALSE; gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Account"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Payee"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Category"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Budget"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/EditMenu/Preferences"), sensitive); // empty account list: disable Import, Archives, Edit, Filter, Add, Statistics, Overdrawn, Car Cost sensitive = da_acc_length() > 0 ? TRUE : FALSE; //gtk_action_set_sensitive(gtk_ui_manager_get_action(data-data->manager, "/MenuBar/FileMenu/Import"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/FileMenu/Close"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Archive"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/AddOpe"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/ShowOpe"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RStatistics"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RTrendTime"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RBudget"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RBalance"), sensitive); gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ReportMenu/RVehiculeCost"), sensitive); // empty category list: disable Budget sensitive = da_cat_length() > 1 ? TRUE : FALSE; gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Budget"), sensitive); //#1501129 no need to disable, P & C can be created from assign dialog //sensitive = ((da_cat_length() > 1) || (da_pay_length() > 1)) ? TRUE : FALSE; //gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/ManageMenu/Assign"), sensitive); // empty archive list: disable scheduled check sensitive = g_list_length(GLOBALS->arc_list) > 0 ? TRUE : FALSE; gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/AddScheduled"), sensitive); // no active account: disable Edit, Over sensitive = (active == TRUE ) ? TRUE : FALSE; if(data->acc && data->acc->window != NULL) sensitive = FALSE; gtk_action_set_sensitive(gtk_ui_manager_get_action(data->manager, "/MenuBar/TxnMenu/ShowOpe"), sensitive); } /* update toolbar, list */ if(flags & UF_VISUAL) { DB( g_print(" 8: visual\n") ); if(PREFS->toolbar_style == 0) gtk_toolbar_unset_style(GTK_TOOLBAR(data->toolbar)); else gtk_toolbar_set_style(GTK_TOOLBAR(data->toolbar), PREFS->toolbar_style-1); gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (data->LV_acc), PREFS->grid_lines); gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_acc)); gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (data->LV_upc), PREFS->grid_lines); gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_upc)); DB( g_print(" - show toolbar=%d\n", PREFS->wal_toolbar) ); if(PREFS->wal_toolbar) gtk_widget_show(GTK_WIDGET(data->toolbar)); else gtk_widget_hide(GTK_WIDGET(data->toolbar)); DB( g_print(" - show top_spending=%d\n", PREFS->wal_spending) ); gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_range), PREFS->date_range_wal); if(PREFS->wal_spending) gtk_widget_show(GTK_WIDGET(data->GR_top)); else gtk_widget_hide(GTK_WIDGET(data->GR_top)); DB( g_print(" - show upcoming=%d\n", PREFS->wal_upcoming) ); if(PREFS->wal_upcoming) gtk_widget_show(GTK_WIDGET(data->GR_upc)); else gtk_widget_hide(GTK_WIDGET(data->GR_upc)); DB( g_print(" minor %d\n", PREFS->euro_active) ); gtk_action_set_visible(gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/AsMinor"), PREFS->euro_active); } /* update balances */ if(flags & UF_BALANCE) { DB( g_print(" 4: balances\n") ); gtk_tree_view_columns_autosize (GTK_TREE_VIEW(data->LV_acc)); //minor = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->CM_minor)); /* hb-label_set_colvalue(GTK_LABEL(data->TX_balance[0]), data->bank, minor); hb-label_set_colvalue(GTK_LABEL(data->TX_balance[1]), data->today, minor); hb-label_set_colvalue(GTK_LABEL(data->TX_balance[2]), data->future, minor); */ } if(flags & UF_REFRESHALL) { DB( g_print(" 16: refreshall\n") ); ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); ui_mainwindow_populate_topspending(GLOBALS->mainwindow, NULL); ui_mainwindow_scheduled_populate(GLOBALS->mainwindow, NULL); } } static void ui_mainwindow_onRowActivated (GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer userdata) { GtkTreeModel *model; GtkTreeIter iter; DB( g_print ("\n[ui-mainwindow] A row has been double-clicked!\n") ); model = gtk_tree_view_get_model(treeview); if (gtk_tree_model_get_iter(model, &iter, path)) { Account *acc; gtk_tree_model_get(model, &iter, LST_DSPACC_DATAS, &acc, -1); if( acc != NULL ) { DB( g_print ("Double-clicked row contains name %s\n", acc->name) ); ui_mainwindow_action_showtransactions(); //g_free(name); } } } static void ui_mainwindow_destroy(GtkTreeView *treeview, gpointer user_data) { DB( g_print("\n[ui-mainwindow] destroy\n") ); } /* ** */ static gboolean ui_mainwindow_dispose(GtkWidget *widget, GdkEvent *event, gpointer user_data) { struct hbfile_data *data = user_data; struct WinGeometry *wg; gboolean retval = FALSE; DB( g_print("\n[ui-mainwindow] delete-event\n") ); //store position and size wg = &PREFS->wal_wg; gtk_window_get_position(GTK_WINDOW(widget), &wg->l, &wg->t); gtk_window_get_size(GTK_WINDOW(widget), &wg->w, &wg->h); GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(widget)); GdkWindowState state = gdk_window_get_state(gdk_window); wg->s = (state & GDK_WINDOW_STATE_MAXIMIZED) ? 1 : 0; 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) ); PREFS->wal_vpaned = gtk_paned_get_position(GTK_PANED(data->vpaned)); PREFS->wal_hpaned = gtk_paned_get_position(GTK_PANED(data->hpaned)); DB( g_print(" - vpaned=%d hpaned=%d\n", PREFS->wal_vpaned, PREFS->wal_hpaned) ); //todo if(ui_dialog_msg_savechanges(widget, NULL) == FALSE) { retval = TRUE; } else { //todo: retval is useless and below should move to destroy retval = TRUE; gtk_widget_destroy(data->LV_top); g_free(data->wintitle); da_filter_free(data->filter); g_free(user_data); gtk_main_quit(); } //TRUE:stop other handlers from being invoked for the event | FALSE: propagate return retval; } static void ui_mainwindow_recent_chooser_item_activated_cb (GtkRecentChooser *chooser, struct hbfile_data *data) { gchar *uri, *path; GError *error = NULL; uri = gtk_recent_chooser_get_current_uri (chooser); path = g_filename_from_uri (uri, NULL, NULL); if (error) { g_warning ("Could not convert uri \"%s\" to a local path: %s", uri, error->message); g_error_free (error); return; } if( ui_dialog_msg_savechanges(data->window, NULL) == TRUE ) { //todo: FixMe /* if (! load) { gpw_recent_remove (gpw, path); } */ hbfile_change_filepath(path); ui_mainwindow_open_internal(data->window, NULL); } else { g_free (path); } g_free (uri); } static void ui_mainwindow_window_screen_changed_cb (GtkWidget *widget, GdkScreen *old_screen, struct hbfile_data *data) { DB( g_print("\n[ui-mainwindow] screen_changed_cb\n") ); data->recent_manager = gtk_recent_manager_get_default (); gtk_menu_detach (GTK_MENU (data->recent_menu)); g_object_unref (G_OBJECT (data->recent_menu)); data->recent_menu = ui_mainwindow_create_recent_chooser_menu (data->recent_manager); g_signal_connect (data->recent_menu, "item-activated", G_CALLBACK (ui_mainwindow_recent_chooser_item_activated_cb), data); //menu_item = gtk_ui_manager_get_widget (data->manager, "/MenuBar/FileMenu/OpenRecent"); //gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), data->recent_menu); } void ui_mainwindow_recent_add (struct hbfile_data *data, const gchar *path) { GtkRecentData *recent_data; gchar *uri; GError *error = NULL; DB( g_print("\n[ui-mainwindow] recent_add\n") ); DB( g_print(" - file has .xhb suffix = %d\n", g_str_has_suffix (path, ".xhb") ) ); if( g_str_has_suffix (path, ".xhb") == FALSE ) //ignore reverted file return; uri = g_filename_to_uri (path, NULL, &error); if (error) { g_warning ("Could not convert uri \"%s\" to a local path: %s", uri, error->message); g_error_free (error); return; } recent_data = g_slice_new (GtkRecentData); recent_data->display_name = NULL; recent_data->description = NULL; recent_data->mime_type = "application/x-homebank"; recent_data->app_name = (gchar *) g_get_application_name (); recent_data->app_exec = g_strjoin (" ", g_get_prgname (), "%u", NULL); recent_data->groups = NULL; recent_data->is_private = FALSE; if (!gtk_recent_manager_add_full (data->recent_manager, uri, recent_data)) { g_warning ("Unable to add '%s' to the list of recently used documents", uri); } g_free (uri); g_free (recent_data->app_exec); g_slice_free (GtkRecentData, recent_data); } enum { TARGET_URI_LIST }; static GtkTargetEntry drop_types[] = { {"text/uri-list", 0, TARGET_URI_LIST} }; static void ui_mainwindow_drag_data_received (GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time, GtkWindow *window) { gchar **uris, **str; gchar *newseldata; gint filetype, slen; if (info != TARGET_URI_LIST) return; DB( g_print("\n[ui-mainwindow] drag_data_received\n") ); /* On MS-Windows, it looks like `selection_data->data' is not NULL terminated. */ slen = gtk_selection_data_get_length(selection_data); newseldata = g_new (gchar, slen + 1); memcpy (newseldata, gtk_selection_data_get_data(selection_data), slen); newseldata[slen] = 0; uris = g_uri_list_extract_uris (newseldata); DB( g_print(" - dragged %d %d files\n", slen, g_strv_length(uris) ) ); str = uris; //for (str = uris; *str; str++) if( *str ) { GError *error = NULL; gchar *path = g_filename_from_uri (*str, NULL, &error); if (path) { filetype = homebank_alienfile_recognize(path); DB( g_print(" - dragged %s, type is %d\n", path, filetype ) ); if( filetype == FILETYPE_HOMEBANK) { hbfile_change_filepath(g_strdup(path)); ui_mainwindow_open_internal(GTK_WIDGET(window), NULL); } else { //todo: future here to implement import for other filetype // ui_import_assistant_new(); // + write a method into assistant to catch other filename ui_dialog_msg_infoerror(GTK_WINDOW(window), GTK_MESSAGE_ERROR, _("File error"), _("The file %s is not a valid HomeBank file."), path ); } } else { g_warning ("Could not convert uri to local path: %s", error->message); g_error_free (error); } g_free (path); } g_strfreev (uris); g_free(newseldata); } static GtkWidget *ui_mainwindow_create_recent_chooser_menu (GtkRecentManager *manager) { GtkWidget *toolbar_recent_menu; GtkRecentFilter *filter; toolbar_recent_menu = gtk_recent_chooser_menu_new_for_manager (manager); gtk_recent_chooser_set_local_only (GTK_RECENT_CHOOSER (toolbar_recent_menu), FALSE); gtk_recent_chooser_set_sort_type (GTK_RECENT_CHOOSER (toolbar_recent_menu), GTK_RECENT_SORT_MRU); //todo: add a user pref for this gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER (toolbar_recent_menu), 10); //gtk_recent_chooser_set_show_icons (GTK_RECENT_CHOOSER (toolbar_recent_menu), FALSE); //gtk_recent_chooser_menu_set_show_numbers (GTK_RECENT_CHOOSER_MENU (toolbar_recent_menu), TRUE); filter = gtk_recent_filter_new (); //gtk_recent_filter_add_application (filter, g_get_application_name()); gtk_recent_filter_add_pattern (filter, "*.[Xx][Hh][Bb]"); gtk_recent_chooser_set_filter (GTK_RECENT_CHOOSER (toolbar_recent_menu), filter); return toolbar_recent_menu; } static void ui_mainwindow_create_menu_bar_and_toolbar(struct hbfile_data *data, GtkWidget *mainvbox) { GtkUIManager *manager; GtkActionGroup *actions; GtkAction *action; GError *error = NULL; manager = gtk_ui_manager_new (); data->manager = manager; gtk_window_add_accel_group (GTK_WINDOW (data->window), gtk_ui_manager_get_accel_group(manager)); actions = gtk_action_group_new ("MainWindow"); gtk_action_group_set_translation_domain(actions, GETTEXT_PACKAGE); gtk_action_group_add_actions (actions, entries, n_entries, NULL); gtk_action_group_add_toggle_actions (actions, toggle_entries, n_toggle_entries, NULL); gtk_ui_manager_insert_action_group (data->manager, actions, 0); g_object_unref (actions); data->actions = actions; /* set short labels to use in the toolbar */ action = gtk_action_group_get_action(actions, "Open"); g_object_set(action, "short_label", _("Open"), NULL); //action = gtk_action_group_get_action(action_group, "Save"); //g_object_set(action, "is_important", TRUE, NULL); action = gtk_action_group_get_action(actions, "Account"); g_object_set(action, "short_label", _("Account"), NULL); action = gtk_action_group_get_action(actions, "Payee"); g_object_set(action, "short_label", _("Payee"), NULL); action = gtk_action_group_get_action(actions, "Category"); g_object_set(action, "short_label", _("Category"), NULL); action = gtk_action_group_get_action(actions, "Archive"); //TRANSLATORS: an archive is stored transaction buffers (kind of bookmark to prefill manual insertion) g_object_set(action, "short_label", _("Archive"), NULL); action = gtk_action_group_get_action(actions, "Budget"); g_object_set(action, "short_label", _("Budget"), NULL); action = gtk_action_group_get_action(actions, "ShowOpe"); g_object_set(action, "short_label", _("Show"), NULL); action = gtk_action_group_get_action(actions, "AddOpe"); g_object_set(action, "is_important", TRUE, "short_label", _("Add"), NULL); action = gtk_action_group_get_action(actions, "RStatistics"); g_object_set(action, "short_label", _("Statistics"), NULL); action = gtk_action_group_get_action(actions, "RBudget"); g_object_set(action, "short_label", _("Budget"), NULL); action = gtk_action_group_get_action(actions, "RBalance"); g_object_set(action, "short_label", _("Balance"), NULL); action = gtk_action_group_get_action(actions, "RVehiculeCost"); g_object_set(action, "short_label", _("Vehicle cost"), NULL); /* now load the UI definition */ gtk_ui_manager_add_ui_from_string (data->manager, ui_info, -1, &error); if (error != NULL) { g_message ("Building menus failed: %s", error->message); g_error_free (error); } //todo: this generate a warning data->menubar = gtk_ui_manager_get_widget (manager, "/MenuBar"); gtk_box_pack_start (GTK_BOX (mainvbox), data->menubar, FALSE, FALSE, 0); data->toolbar = gtk_ui_manager_get_widget (manager, "/ToolBar"); gtk_box_pack_start (GTK_BOX (mainvbox), data->toolbar, FALSE, FALSE, 0); /* recent files menu */ data->recent_manager = gtk_recent_manager_get_default (); data->recent_menu = ui_mainwindow_create_recent_chooser_menu (data->recent_manager); g_signal_connect (data->recent_menu, "item-activated", G_CALLBACK (ui_mainwindow_recent_chooser_item_activated_cb), data); /* widget = gtk_ui_manager_get_widget (data->manager, "/MenuBar/FileMenu/OpenRecent"); gtk_menu_item_set_submenu (GTK_MENU_ITEM (widget), data->recent_menu); */ /* test */ /* add the custom Open button to the toolbar */ GtkWidget *image = gtk_image_new_from_icon_name (ICONNAME_OPEN, GTK_ICON_SIZE_BUTTON); GtkToolItem *open_button = gtk_menu_tool_button_new(image, _("_Open")); gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (open_button), data->recent_menu); gtk_tool_item_set_tooltip_text (open_button, _("Open a file")); gtk_menu_tool_button_set_arrow_tooltip_text (GTK_MENU_TOOL_BUTTON (open_button), _("Open a recently used file")); action = gtk_action_group_get_action (data->actions, "Open"); g_object_set (action, "short_label", _("Open"), NULL); //gtk_action_connect_proxy (action, GTK_WIDGET (open_button)); gtk_activatable_set_related_action (GTK_ACTIVATABLE (open_button), action); gtk_toolbar_insert (GTK_TOOLBAR (data->toolbar), open_button, 1); /* end test */ } /* Callback function for the undo action */ /*static void activate_action (GSimpleAction *action, GVariant *parameter, gpointer user_data) { g_print ("Action %s activated\n", g_action_get_name (G_ACTION (action))); }*/ static void activate_toggle (GSimpleAction *action, GVariant *parameter, gpointer user_data) { struct hbfile_data *data = user_data; GVariant *old_state, *new_state; old_state = g_action_get_state (G_ACTION (action)); new_state = g_variant_new_boolean (!g_variant_get_boolean (old_state)); DB( g_print ("Toggle action %s activated, state changes from %d to %d\n", g_action_get_name (G_ACTION (action)), g_variant_get_boolean (old_state), g_variant_get_boolean (new_state)) ); data->showall = g_variant_get_boolean (new_state); ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); g_simple_action_set_state (action, new_state); g_variant_unref (old_state); } static void activate_radio (GSimpleAction *action, GVariant *parameter, gpointer user_data) { //struct hbfile_data *data = user_data; GVariant *old_state, *new_state; old_state = g_action_get_state (G_ACTION (action)); new_state = g_variant_new_string (g_variant_get_string (parameter, NULL)); DB( g_print ("Radio action %s activated, state changes from %s to %s\n", g_action_get_name (G_ACTION (action)), g_variant_get_string (old_state, NULL), g_variant_get_string (new_state, NULL)) ); PREFS->pnl_acc_show_by = DSPACC_GROUP_BY_TYPE; if( !strcmp("bank", g_variant_get_string(new_state, NULL)) ) PREFS->pnl_acc_show_by = DSPACC_GROUP_BY_BANK; ui_mainwindow_populate_accounts(GLOBALS->mainwindow, NULL); g_simple_action_set_state (action, new_state); g_variant_unref (old_state); } static const GActionEntry actions[] = { // { "paste", activate_action, NULL, NULL, NULL, {0,0,0} }, { "showall", activate_toggle, NULL, "false" , NULL, {0,0,0} }, { "groupby", activate_radio , "s", "'type'", NULL, {0,0,0} } }; static void ui_panel_accounts_setup(struct hbfile_data *data) { GAction *action; GVariant *new_state; if( !G_IS_SIMPLE_ACTION_GROUP(data->action_group_acc) ) return; action = g_action_map_lookup_action (G_ACTION_MAP (data->action_group_acc), "showall"); if( action ) { new_state = g_variant_new_boolean (data->showall); g_simple_action_set_state (G_SIMPLE_ACTION(action), new_state); } action = g_action_map_lookup_action (G_ACTION_MAP (data->action_group_acc), "groupby"); if( action ) { const gchar *value = (PREFS->pnl_acc_show_by == DSPACC_GROUP_BY_TYPE) ? "type" : "bank"; new_state = g_variant_new_string (value); g_simple_action_set_state (G_SIMPLE_ACTION (action), new_state); } } static GtkWidget *ui_mainwindow_create_youraccounts(struct hbfile_data *data) { GtkWidget *panel, *label, *widget, *sw, *tbar, *hbox, *image; GtkToolItem *toolitem; panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL); sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (panel), sw, TRUE, TRUE, 0); widget = (GtkWidget *)create_list_account(); data->LV_acc = widget; gtk_container_add (GTK_CONTAINER (sw), widget); //list toolbar tbar = gtk_toolbar_new(); gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU); gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS); gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR); gtk_box_pack_start (GTK_BOX (panel), tbar, FALSE, FALSE, 0); label = make_label_group(_("Your accounts")); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), label); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); toolitem = gtk_separator_tool_item_new (); gtk_tool_item_set_expand (toolitem, TRUE); gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), hbox); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); widget = make_image_button(ICONNAME_HB_BUTTON_EXPAND, _("Expand all")); data->BT_expandall = widget; gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); widget = make_image_button(ICONNAME_HB_BUTTON_COLLAPSE, _("Collapse all")); data->BT_collapseall = widget; gtk_box_pack_start (GTK_BOX (hbox), widget, FALSE, FALSE, 0); toolitem = gtk_separator_tool_item_new (); gtk_tool_item_set_expand (toolitem, FALSE); gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); //gmenu test (see test folder into gtk) GMenu *menu, *section; menu = g_menu_new (); //g_menu_append (menumodel, "About", "actions.undo"); //g_menu_append (menumodel, "Test", "actions.redo"); section = g_menu_new (); g_menu_append (section, _("Show all"), "actions.showall"); g_menu_append_section(menu, NULL, G_MENU_MODEL(section)); g_object_unref (section); section = g_menu_new (); g_menu_append (section, _("By type"), "actions.groupby::type"); g_menu_append (section, _("By institition"), "actions.groupby::bank"); g_menu_append_section(menu, NULL, G_MENU_MODEL(section)); g_object_unref (section); GSimpleActionGroup *group = g_simple_action_group_new (); data->action_group_acc = group; g_action_map_add_action_entries (G_ACTION_MAP (group), actions, G_N_ELEMENTS (actions), data); widget = gtk_menu_button_new(); gtk_menu_button_set_direction (GTK_MENU_BUTTON(widget), GTK_ARROW_UP); gtk_widget_set_halign (widget, GTK_ALIGN_END); image = gtk_image_new_from_icon_name (ICONNAME_EMBLEM_SYSTEM, GTK_ICON_SIZE_MENU); g_object_set (widget, "image", image, NULL); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), widget); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); gtk_widget_insert_action_group (widget, "actions", G_ACTION_GROUP(group)); gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (widget), G_MENU_MODEL (menu)); return panel; } static GtkWidget *ui_mainwindow_create_topspending(struct hbfile_data *data) { GtkWidget *panel, *hbox, *tbar; GtkWidget *label, *widget; GtkToolItem *toolitem; widget = (GtkWidget *)create_list_topspending(); data->LV_top = widget; panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL); data->GR_top = panel; /* chart + listview */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start (GTK_BOX (panel), hbox, TRUE, TRUE, 0); widget = gtk_chart_new(CHART_TYPE_PIE); data->RE_pie = widget; gtk_chart_set_minor_prefs(GTK_CHART(widget), PREFS->euro_value, PREFS->minor_cur.symbol); gtk_chart_show_legend(GTK_CHART(data->RE_pie), TRUE, TRUE); gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0); //list toolbar tbar = gtk_toolbar_new(); gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU); gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS); gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR); gtk_box_pack_start (GTK_BOX (panel), tbar, FALSE, FALSE, 0); label = make_label_group(_("Where your money goes")); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), label); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); toolitem = gtk_separator_tool_item_new (); gtk_tool_item_set_expand (toolitem, TRUE); gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); /* total + date range */ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, SPACING_SMALL); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), hbox); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); data->CY_range = make_daterange(label, FALSE); gtk_box_pack_end (GTK_BOX (hbox), data->CY_range, FALSE, FALSE, 0); widget = make_radio(CYA_CATSUBCAT, TRUE, GTK_ORIENTATION_HORIZONTAL); data->RA_type = widget; gtk_box_pack_end (GTK_BOX (hbox), widget, FALSE, FALSE, 0); return panel; } static GtkWidget *ui_mainwindow_scheduled_create(struct hbfile_data *data) { GtkWidget *panel, *hbox, *vbox, *bbox, *sw, *tbar; GtkWidget *label, *widget; GtkToolItem *toolitem; panel = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_set_border_width(GTK_CONTAINER(panel), SPACING_SMALL); data->GR_upc = panel; vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); //gtk_widget_set_margin_top(GTK_WIDGET(vbox), 0); //gtk_widget_set_margin_bottom(GTK_WIDGET(vbox), SPACING_SMALL); //gtk_widget_set_margin_start(GTK_WIDGET(vbox), 2*SPACING_SMALL); //gtk_widget_set_margin_end(GTK_WIDGET(vbox), SPACING_SMALL); gtk_box_pack_start (GTK_BOX (panel), vbox, TRUE, TRUE, 0); sw = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0); widget = (GtkWidget *)create_list_upcoming(); data->LV_upc = widget; gtk_container_add (GTK_CONTAINER (sw), widget); tbar = gtk_toolbar_new(); gtk_toolbar_set_icon_size (GTK_TOOLBAR(tbar), GTK_ICON_SIZE_MENU); gtk_toolbar_set_style(GTK_TOOLBAR(tbar), GTK_TOOLBAR_ICONS); gtk_style_context_add_class (gtk_widget_get_style_context (tbar), GTK_STYLE_CLASS_INLINE_TOOLBAR); gtk_box_pack_start (GTK_BOX (vbox), tbar, FALSE, FALSE, 0); label = make_label_group(_("Scheduled transactions")); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), label); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); toolitem = gtk_separator_tool_item_new (); gtk_tool_item_set_expand (toolitem, FALSE); gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), bbox); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); widget = gtk_button_new_with_label(_("Skip")); data->BT_sched_skip = widget; gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0); widget = gtk_button_new_with_label(_("Edit & Post")); data->BT_sched_editpost = widget; gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0); //TRANSLATORS: Posting a scheduled transaction is the action to materialize it into its target account. //TRANSLATORS: Before that action the automated transaction occurrence is pending and not yet really existing. widget = gtk_button_new_with_label (_("Post")); data->BT_sched_post = widget; gtk_box_pack_start (GTK_BOX (bbox), widget, FALSE, FALSE, 0); toolitem = gtk_separator_tool_item_new (); gtk_tool_item_set_expand (toolitem, FALSE); gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(toolitem), FALSE); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); hbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_set_valign (hbox, GTK_ALIGN_CENTER); toolitem = gtk_tool_item_new(); gtk_container_add (GTK_CONTAINER(toolitem), hbox); gtk_toolbar_insert(GTK_TOOLBAR(tbar), GTK_TOOL_ITEM(toolitem), -1); label = make_label(_("maximum post date"), 0.0, 0.7); gtk_widget_set_halign (label, GTK_ALIGN_CENTER); gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); label = make_label(NULL, 0.0, 0.7); data->LB_maxpostdate = label; gtk_widget_set_halign (label, GTK_ALIGN_CENTER); gimp_label_set_attributes (GTK_LABEL (label), PANGO_ATTR_SCALE, PANGO_SCALE_SMALL, -1); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); return panel; } /* ** the window creation */ GtkWidget *create_hbfile_window(GtkWidget *do_widget) { struct hbfile_data *data; struct WinGeometry *wg; GtkWidget *mainvbox, *vbox, *vpaned, *hpaned; GtkWidget *widget; GtkWidget *window; GtkAction *action; DB( g_print("\n[ui-mainwindow] create main window\n") ); data = g_malloc0(sizeof(struct hbfile_data)); if(!data) return NULL; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); //store our window private data g_object_set_data(G_OBJECT(window), "inst_data", (gpointer)data); DB( g_print(" - new window=%p, inst_data=%p\n", window, data) ); // this is our mainwindow, so store it to GLOBALS data data->window = window; GLOBALS->mainwindow = window; mainvbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_add (GTK_CONTAINER (window), mainvbox); ui_mainwindow_create_menu_bar_and_toolbar (data, mainvbox); #if HB_UNSTABLE_SHOW == TRUE GtkWidget *bar, *label; bar = gtk_info_bar_new (); gtk_box_pack_start (GTK_BOX (mainvbox), bar, FALSE, FALSE, 0); gtk_info_bar_set_message_type (GTK_INFO_BAR (bar), GTK_MESSAGE_WARNING); label = make_label(NULL, 0.5, 0.5); gtk_label_set_markup (GTK_LABEL(label), "Unstable Development Version"); gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (GTK_INFO_BAR (bar))), label, FALSE, FALSE, 0); #endif /* Add the main area */ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); //gtk_container_set_border_width (GTK_CONTAINER(vbox), SPACING_MEDIUM); gtk_box_pack_start (GTK_BOX (mainvbox), vbox, TRUE, TRUE, 0); vpaned = gtk_paned_new(GTK_ORIENTATION_VERTICAL); data->vpaned = vpaned; gtk_box_pack_start (GTK_BOX (vbox), vpaned, TRUE, TRUE, 0); hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); data->hpaned = hpaned; gtk_paned_pack1 (GTK_PANED(vpaned), hpaned, FALSE, FALSE); widget = ui_mainwindow_scheduled_create(data); gtk_paned_pack2 (GTK_PANED(vpaned), widget, TRUE, FALSE); widget = ui_mainwindow_create_youraccounts(data); //gtk_widget_set_size_request (widget, 100, -1); gtk_paned_pack1 (GTK_PANED(hpaned), widget, FALSE, FALSE); widget = ui_mainwindow_create_topspending(data); //gtk_widget_set_size_request (widget, -1, 100); gtk_paned_pack2 (GTK_PANED(hpaned), widget, TRUE, FALSE); //setup, init and show window wg = &PREFS->wal_wg; if(wg->s == 0) { gtk_window_move(GTK_WINDOW(window), wg->l, wg->t); gtk_window_resize(GTK_WINDOW(window), wg->w, wg->h); } else gtk_window_maximize(GTK_WINDOW(window)); gtk_widget_show_all (window); //#1662197/1660910 moved after resize/show DB( g_print(" - vpaned=%d hpaned=%d\n", PREFS->wal_vpaned, PREFS->wal_hpaned) ); if(PREFS->wal_hpaned > 0) gtk_paned_set_position(GTK_PANED(data->hpaned), PREFS->wal_hpaned); if(PREFS->wal_vpaned > 0) gtk_paned_set_position(GTK_PANED(data->vpaned), PREFS->wal_vpaned); //todo: move this elsewhere DB( g_print(" - setup stuff\n") ); data->filter = da_filter_malloc(); filter_default_all_set(data->filter); gtk_combo_box_set_active(GTK_COMBO_BOX(data->CY_range), PREFS->date_range_wal); action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Toolbar"); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_toolbar); action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Spending"); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_spending); action = gtk_ui_manager_get_action(data->manager, "/MenuBar/ViewMenu/Upcoming"); gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(action), PREFS->wal_upcoming); /* Drag and drop support, set targets to NULL because we add the default uri_targets below */ /* support for opening a file by dragging onto the project window */ gtk_drag_dest_set (GTK_WIDGET (window), GTK_DEST_DEFAULT_ALL, drop_types, G_N_ELEMENTS (drop_types), GDK_ACTION_COPY); g_signal_connect (G_OBJECT (window), "drag-data-received", G_CALLBACK (ui_mainwindow_drag_data_received), window); //connect all our signals DB( g_print(" - connect signals\n") ); g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_acc)), "changed", G_CALLBACK (ui_mainwindow_selection), NULL); g_signal_connect (GTK_TREE_VIEW(data->LV_acc ), "row-activated", G_CALLBACK (ui_mainwindow_onRowActivated), GINT_TO_POINTER(2)); g_signal_connect (G_OBJECT (data->BT_expandall ), "clicked" , G_CALLBACK (ui_panel_accounts_expand_all), NULL); g_signal_connect (G_OBJECT (data->BT_collapseall), "clicked" , G_CALLBACK (ui_panel_accounts_collapse_all), NULL); g_signal_connect (gtk_tree_view_get_selection(GTK_TREE_VIEW(data->LV_upc)), "changed", G_CALLBACK (ui_mainwindow_scheduled_selection_cb), NULL); g_signal_connect (GTK_TREE_VIEW(data->LV_upc), "row-activated", G_CALLBACK (ui_mainwindow_scheduled_onRowActivated), NULL); g_signal_connect (G_OBJECT (data->BT_sched_skip), "clicked", G_CALLBACK (ui_mainwindow_scheduled_skip_cb), data); g_signal_connect (G_OBJECT (data->BT_sched_editpost), "clicked", G_CALLBACK (ui_mainwindow_scheduled_editpost_cb), data); g_signal_connect (G_OBJECT (data->BT_sched_post), "clicked", G_CALLBACK (ui_mainwindow_scheduled_post_cb), data); widget = radio_get_nth_widget(GTK_CONTAINER(data->RA_type), 1); if(widget) g_signal_connect (widget, "toggled", G_CALLBACK (ui_mainwindow_populate_topspending), &data); g_signal_connect (data->CY_range, "changed", G_CALLBACK (ui_mainwindow_populate_topspending), NULL); /* GtkWindow events */ g_signal_connect (window, "delete-event", G_CALLBACK (ui_mainwindow_dispose), (gpointer)data); g_signal_connect (window, "destroy", G_CALLBACK (ui_mainwindow_destroy), NULL); g_signal_connect (window, "screen-changed", G_CALLBACK (ui_mainwindow_window_screen_changed_cb), data); //gtk_action_group_set_sensitive(data->actions, FALSE); return window; }