GnuCash 2.4.99
dialog-price-edit-db.c
00001 /********************************************************************\
00002  * dialog-price-editor.c -- price selector dialog                   *
00003  * Copyright (C) 2001 Gnumatic, Inc.                                *
00004  * Author: Dave Peticolas <dave@krondo.com>                         *
00005  * Copyright (C) 2003,2005 David Hampton                            *
00006  * Copyright (C) 2011 Robert Fewell                                 *
00007  *                                                                  *
00008  * This program is free software; you can redistribute it and/or    *
00009  * modify it under the terms of the GNU General Public License as   *
00010  * published by the Free Software Foundation; either version 2 of   *
00011  * the License, or (at your option) any later version.              *
00012  *                                                                  *
00013  * This program is distributed in the hope that it will be useful,  *
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00016  * GNU General Public License for more details.                     *
00017  *                                                                  *
00018  * You should have received a copy of the GNU General Public License*
00019  * along with this program; if not, contact:                        *
00020  *                                                                  *
00021  * Free Software Foundation           Voice:  +1-617-542-5942       *
00022  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00023  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00024 \********************************************************************/
00025 
00026 #include "config.h"
00027 
00028 #include <gtk/gtk.h>
00029 #include <glib/gi18n.h>
00030 #include <libguile.h>
00031 #include "guile-mappings.h"
00032 #include <time.h>
00033 
00034 #include "dialog-utils.h"
00035 #include "gnc-amount-edit.h"
00036 #include "gnc-commodity-edit.h"
00037 #include "gnc-general-select.h"
00038 #include "gnc-component-manager.h"
00039 #include "gnc-currency-edit.h"
00040 #include "gnc-date-edit.h"
00041 #include "gnc-engine.h"
00042 #include "gnc-gui-query.h"
00043 #include "gnc-pricedb.h"
00044 #include "gnc-session.h"
00045 #include "gnc-tree-view-price.h"
00046 #include "gnc-ui.h"
00047 #include "gnc-ui-util.h"
00048 #include "guile-util.h"
00049 #include "engine-helpers.h"
00050 #include "swig-runtime.h"
00051 
00052 
00053 #define DIALOG_PRICE_DB_CM_CLASS "dialog-price-edit-db"
00054 #define GCONF_SECTION "dialogs/edit_prices"
00055 
00056 /* This static indicates the debugging module that this .o belongs to.  */
00057 static QofLogModule log_module = GNC_MOD_GUI;
00058 
00059 
00060 void gnc_prices_dialog_window_destroy_cb (GtkObject *object, gpointer data);
00061 void gnc_prices_dialog_close_cb (GtkDialog *dialog, gpointer data);
00062 void gnc_prices_dialog_response (GtkDialog *dialog, gint response_id, gpointer data);
00063 void gnc_prices_dialog_edit_clicked (GtkWidget *widget, gpointer data);
00064 void gnc_prices_dialog_remove_clicked (GtkWidget *widget, gpointer data);
00065 void gnc_prices_dialog_remove_old_clicked (GtkWidget *widget, gpointer data);
00066 void gnc_prices_dialog_add_clicked (GtkWidget *widget, gpointer data);
00067 void gnc_prices_dialog_get_quotes_clicked (GtkWidget *widget, gpointer data);
00068 
00069 
00070 typedef struct
00071 {
00072     GtkWidget * dialog;
00073     QofSession *session;
00074     QofBook *book;
00075     GNCPriceDB *price_db;
00076 
00077     GncTreeViewPrice * price_tree;
00078 
00079     GtkWidget * edit_button;
00080     GtkWidget * remove_button;
00081 } PricesDialog;
00082 
00083 
00084 void
00085 gnc_prices_dialog_window_destroy_cb (GtkObject *object, gpointer data)
00086 {
00087     PricesDialog *pdb_dialog = data;
00088 
00089     ENTER(" ");
00090     gnc_unregister_gui_component_by_data (DIALOG_PRICE_DB_CM_CLASS, pdb_dialog);
00091 
00092     if (pdb_dialog->dialog)
00093     {
00094         gtk_widget_destroy(pdb_dialog->dialog);
00095         pdb_dialog->dialog = NULL;
00096     }
00097 
00098     g_free (pdb_dialog);
00099     LEAVE(" ");
00100 }
00101 
00102 
00103 void
00104 gnc_prices_dialog_close_cb (GtkDialog *dialog, gpointer data)
00105 {
00106     PricesDialog *pdb_dialog = data;
00107 
00108     ENTER(" ");
00109     gnc_close_gui_component_by_data (DIALOG_PRICE_DB_CM_CLASS, pdb_dialog);
00110     LEAVE(" ");
00111 }
00112 
00113 
00114 void
00115 gnc_prices_dialog_response (GtkDialog *dialog, gint response_id, gpointer data)
00116 {
00117     PricesDialog *pdb_dialog = data;
00118 
00119     ENTER(" ");
00120     gnc_close_gui_component_by_data (DIALOG_PRICE_DB_CM_CLASS, pdb_dialog);
00121     LEAVE(" ");
00122 }
00123 
00124 
00125 void
00126 gnc_prices_dialog_edit_clicked (GtkWidget *widget, gpointer data)
00127 {
00128     PricesDialog *pdb_dialog = data;
00129     GList *price_list;
00130 
00131     ENTER(" ");
00132     price_list = gnc_tree_view_price_get_selected_prices(pdb_dialog->price_tree);
00133     if (!price_list)
00134     {
00135         LEAVE("no price selected");
00136         return;
00137     }
00138     if (g_list_next(price_list))
00139     {
00140         g_list_free(price_list);
00141         LEAVE("too many prices selected");
00142         return;
00143     }
00144 
00145     gnc_price_edit_dialog (pdb_dialog->dialog, pdb_dialog->session,
00146                            price_list->data, GNC_PRICE_EDIT);
00147     g_list_free(price_list);
00148     LEAVE(" ");
00149 }
00150 
00151 
00152 static void
00153 remove_helper(GNCPrice *price, GNCPriceDB *pdb)
00154 {
00155     gnc_pricedb_remove_price (pdb, price);
00156 }
00157 
00158 
00159 void
00160 gnc_prices_dialog_remove_clicked (GtkWidget *widget, gpointer data)
00161 {
00162     PricesDialog *pdb_dialog = data;
00163     GList *price_list;
00164     gint length, response;
00165     GtkWidget *dialog;
00166 
00167     ENTER(" ");
00168     price_list = gnc_tree_view_price_get_selected_prices(pdb_dialog->price_tree);
00169     if (!price_list)
00170     {
00171         LEAVE("no price selected");
00172         return;
00173     }
00174 
00175     length = g_list_length(price_list);
00176     if (length > 1)
00177     {
00178         gchar *message;
00179 
00180         message = g_strdup_printf
00181                   (/* Translators: %d is the number of prices. This
00182           is a ngettext(3) message. */
00183                       ngettext("Are you sure you want to delete the %d selected price?",
00184                                "Are you sure you want to delete the %d selected prices?",
00185                                length),
00186                       length);
00187         dialog = gtk_message_dialog_new(GTK_WINDOW(pdb_dialog->dialog),
00188                                         GTK_DIALOG_DESTROY_WITH_PARENT,
00189                                         GTK_MESSAGE_QUESTION,
00190                                         GTK_BUTTONS_NONE,
00191                                         "%s", _("Delete prices?"));
00192         gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
00193                 "%s", message);
00194         g_free(message);
00195         gtk_dialog_add_buttons(GTK_DIALOG(dialog),
00196                                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
00197                                GTK_STOCK_DELETE, GTK_RESPONSE_YES,
00198                                (gchar *)NULL);
00199         gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
00200         response = gnc_dialog_run(GTK_DIALOG(dialog), "pricedb_remove_multiple");
00201         gtk_widget_destroy(dialog);
00202     }
00203     else
00204     {
00205         response = GTK_RESPONSE_YES;
00206     }
00207 
00208     if (response == GTK_RESPONSE_YES)
00209     {
00210         g_list_foreach(price_list, (GFunc)remove_helper, pdb_dialog->price_db);
00211     }
00212     g_list_free(price_list);
00213     LEAVE(" ");
00214 }
00215 
00216 
00217 void
00218 gnc_prices_dialog_remove_old_clicked (GtkWidget *widget, gpointer data)
00219 {
00220     PricesDialog *pdb_dialog = data;
00221     GtkBuilder *builder;
00222     GtkWidget *dialog, *button, *date, *label, *box;
00223     gint result;
00224     gboolean delete_user, delete_last;
00225 
00226     ENTER(" ");
00227     builder = gtk_builder_new();
00228     gnc_builder_add_from_file (builder, "dialog-price.glade", "Deletion Date");
00229 
00230     dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Deletion Date"));
00231 
00232     box = GTK_WIDGET(gtk_builder_get_object (builder, "date_hbox"));
00233     date = gnc_date_edit_new (time (NULL), FALSE, FALSE);
00234 
00235     gtk_box_pack_start (GTK_BOX (box), date, TRUE, TRUE, 0);
00236     gtk_widget_show (date);
00237     gtk_entry_set_activates_default(GTK_ENTRY(GNC_DATE_EDIT(date)->date_entry), TRUE);
00238     label = GTK_WIDGET(gtk_builder_get_object (builder, "date_label"));
00239     gnc_date_make_mnemonic_target (GNC_DATE_EDIT(date), label);
00240 
00241     gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, pdb_dialog);
00242 
00243     gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (pdb_dialog->dialog));
00244 
00245     result = gtk_dialog_run (GTK_DIALOG (dialog));
00246     if (result == GTK_RESPONSE_OK)
00247     {
00248         Timespec ts;
00249 
00250         DEBUG("deleting prices");
00251         ts.tv_sec = gnc_date_edit_get_date (GNC_DATE_EDIT (date));
00252         ts.tv_nsec = 0;
00253 
00254         button = GTK_WIDGET(gtk_builder_get_object (builder, "delete_manual"));
00255         delete_user = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
00256         button = GTK_WIDGET(gtk_builder_get_object (builder, "delete_last"));
00257         delete_last = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
00258 
00259         gnc_pricedb_remove_old_prices(pdb_dialog->price_db, ts,
00260                                       delete_user, delete_last);
00261     }
00262 
00263     gtk_widget_destroy(dialog);
00264     LEAVE(" ");
00265 }
00266 
00267 
00268 void
00269 gnc_prices_dialog_add_clicked (GtkWidget *widget, gpointer data)
00270 {
00271     PricesDialog *pdb_dialog = data;
00272     GNCPrice *price = NULL;
00273     GList *price_list;
00274 
00275     ENTER(" ");
00276     price_list = gnc_tree_view_price_get_selected_prices(pdb_dialog->price_tree);
00277     if (price_list)
00278     {
00279         price = price_list->data;
00280         g_list_free(price_list);
00281     }
00282     gnc_price_edit_dialog (pdb_dialog->dialog, pdb_dialog->session,
00283                            price, GNC_PRICE_NEW);
00284     LEAVE(" ");
00285 }
00286 
00287 
00288 void
00289 gnc_prices_dialog_get_quotes_clicked (GtkWidget *widget, gpointer data)
00290 {
00291     PricesDialog *pdb_dialog = data;
00292     SCM quotes_func;
00293     SCM book_scm;
00294     SCM scm_window;
00295 
00296     ENTER(" ");
00297     quotes_func = scm_c_eval_string ("gnc:book-add-quotes");
00298     if (!scm_is_procedure (quotes_func))
00299     {
00300         LEAVE(" no procedure");
00301         return;
00302     }
00303 
00304     book_scm = gnc_book_to_scm (pdb_dialog->book);
00305     if (scm_is_true (scm_not (book_scm)))
00306     {
00307         LEAVE("no book");
00308         return;
00309     }
00310 
00311     scm_window =  SWIG_NewPointerObj(pdb_dialog->dialog,
00312                                      SWIG_TypeQuery("_p_GtkWidget"), 0);
00313 
00314     gnc_set_busy_cursor (NULL, TRUE);
00315     scm_call_2 (quotes_func, scm_window, book_scm);
00316     gnc_unset_busy_cursor (NULL);
00317 
00318     /* Without this, the summary bar on the accounts tab
00319      * won't reflect the new prices (bug #522095). */
00320     gnc_gui_refresh_all ();
00321 
00322     LEAVE(" ");
00323 }
00324 
00325 
00326 static void
00327 gnc_prices_dialog_selection_changed (GtkTreeSelection *treeselection,
00328                                      gpointer data)
00329 {
00330     PricesDialog *pdb_dialog = data;
00331     GList *price_list;
00332     gint length;
00333 
00334     ENTER(" ");
00335     price_list = gnc_tree_view_price_get_selected_prices(pdb_dialog->price_tree);
00336     length = g_list_length(price_list);
00337 
00338     gtk_widget_set_sensitive (pdb_dialog->edit_button,
00339                               length == 1);
00340     gtk_widget_set_sensitive (pdb_dialog->remove_button,
00341                               length >= 1);
00342     LEAVE("%d prices selected", length);
00343 }
00344 
00345 
00346 static gboolean
00347 gnc_price_dialog_filter_ns_func (gnc_commodity_namespace *namespace,
00348                                  gpointer data)
00349 {
00350     PricesDialog *pdb_dialog = data;
00351     const gchar *name;
00352     static GList *cm_list;
00353     GList *item;
00354 
00355     /* Never show the template list */
00356     name = gnc_commodity_namespace_get_name (namespace);
00357     if (safe_strcmp (name, "template") == 0)
00358         return FALSE;
00359 
00360     /* See if this namespace has commodities */
00361     cm_list = gnc_commodity_namespace_get_commodity_list(namespace);
00362     for (item = cm_list; item; item = g_list_next(item))
00363     {
00364 
00365         /* For each commodity, see if there are prices */
00366         if (gnc_pricedb_has_prices(pdb_dialog->price_db, item->data, NULL))
00367         {
00368             return TRUE;
00369         }
00370     }
00371 
00372     //  printf("Namespace %s not visible\n", name);
00373     return FALSE;
00374 }
00375 
00376 
00377 static gboolean
00378 gnc_price_dialog_filter_cm_func (gnc_commodity *commodity,
00379                                  gpointer data)
00380 {
00381     PricesDialog *pdb_dialog = data;
00382 
00383     /* Show any commodity that has prices */
00384     return gnc_pricedb_has_prices(pdb_dialog->price_db, commodity, NULL);
00385 }
00386 
00387 
00388 static void
00389 row_activated_cb (GtkTreeView *view, GtkTreePath *path,
00390                   GtkTreeViewColumn *column, gpointer data)
00391 {
00392     GtkTreeModel *model;
00393     GtkTreeIter iter;
00394 
00395     g_return_if_fail(view);
00396 
00397     model = gtk_tree_view_get_model(view);
00398     if (gtk_tree_model_get_iter(model, &iter, path))
00399     {
00400         if (gtk_tree_model_iter_has_child(model, &iter))
00401         {
00402             /* There are children, so it's not a price.
00403              * Just expand or collapse the row. */
00404             if (gtk_tree_view_row_expanded(view, path))
00405                 gtk_tree_view_collapse_row(view, path);
00406             else
00407                 gtk_tree_view_expand_row(view, path, FALSE);
00408         }
00409         else
00410             /* It's a price, so click the Edit button. */
00411             gnc_prices_dialog_edit_clicked(GTK_WIDGET(view), data);
00412     }
00413 }
00414 
00415 
00416 static void
00417 gnc_prices_dialog_create (GtkWidget * parent, PricesDialog *pdb_dialog)
00418 {
00419     GtkWidget *dialog, *scrolled_window;
00420     GtkBuilder *builder;
00421     GtkTreeView *view;
00422     GtkTreeSelection *selection;
00423 
00424     ENTER(" ");
00425     builder = gtk_builder_new();
00426     gnc_builder_add_from_file (builder, "dialog-price.glade", "Prices Dialog");
00427 
00428     dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Prices Dialog"));
00429     pdb_dialog->dialog = dialog;
00430 
00431     pdb_dialog->session = gnc_get_current_session();
00432     pdb_dialog->book = qof_session_get_book(pdb_dialog->session);
00433     pdb_dialog->price_db = gnc_pricedb_get_db(pdb_dialog->book);
00434 
00435     /* parent */
00436     if (parent != NULL)
00437         gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent));
00438 
00439     /* default to 'close' button */
00440     gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
00441 
00442     /* price tree */
00443     scrolled_window = GTK_WIDGET(gtk_builder_get_object (builder, "price_list_window"));
00444     view = gnc_tree_view_price_new(pdb_dialog->book,
00445                                    "gconf-section", GCONF_SECTION,
00446                                    "show-column-menu", TRUE,
00447                                    NULL);
00448     pdb_dialog->price_tree = GNC_TREE_VIEW_PRICE(view);
00449     gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET(view));
00450     gnc_tree_view_price_set_filter (pdb_dialog->price_tree,
00451                                     gnc_price_dialog_filter_ns_func,
00452                                     gnc_price_dialog_filter_cm_func,
00453                                     NULL,
00454                                     pdb_dialog, NULL);
00455 
00456     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
00457     gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
00458     g_signal_connect (G_OBJECT (selection), "changed",
00459                       G_CALLBACK (gnc_prices_dialog_selection_changed), pdb_dialog);
00460 
00461     g_signal_connect (G_OBJECT (view), "row-activated",
00462                       G_CALLBACK (row_activated_cb), pdb_dialog);
00463 
00464     /* buttons */
00465     {
00466         GtkWidget *button;
00467 
00468         button = GTK_WIDGET(gtk_builder_get_object (builder, "edit_button"));
00469         pdb_dialog->edit_button = button;
00470 
00471         button = GTK_WIDGET(gtk_builder_get_object (builder, "remove_button"));
00472         pdb_dialog->remove_button = button;
00473 
00474         if (!gnc_quote_source_fq_installed())
00475         {
00476             button = GTK_WIDGET(gtk_builder_get_object (builder, "get_quotes_button"));
00477             gtk_widget_set_sensitive(button, FALSE);
00478         }
00479     }
00480 
00481     gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, pdb_dialog);
00482 
00483     g_object_unref(G_OBJECT(builder));
00484 
00485     gnc_restore_window_size(GCONF_SECTION, GTK_WINDOW(pdb_dialog->dialog));
00486     LEAVE(" ");
00487 }
00488 
00489 
00490 static void
00491 close_handler (gpointer user_data)
00492 {
00493     PricesDialog *pdb_dialog = user_data;
00494 
00495     ENTER(" ");
00496     gnc_save_window_size(GCONF_SECTION, GTK_WINDOW(pdb_dialog->dialog));
00497 
00498     gtk_widget_destroy (GTK_WIDGET (pdb_dialog->dialog));
00499     LEAVE(" ");
00500 }
00501 
00502 
00503 static void
00504 refresh_handler (GHashTable *changes, gpointer user_data)
00505 {
00506     ENTER(" ");
00507     LEAVE(" ");
00508 }
00509 
00510 
00511 static gboolean
00512 show_handler (const char *class, gint component_id,
00513               gpointer user_data, gpointer iter_data)
00514 {
00515     PricesDialog *pdb_dialog = user_data;
00516 
00517     ENTER(" ");
00518     if (!pdb_dialog)
00519     {
00520         LEAVE("no data strucure");
00521         return(FALSE);
00522     }
00523 
00524     gtk_window_present (GTK_WINDOW(pdb_dialog->dialog));
00525     LEAVE(" ");
00526     return(TRUE);
00527 }
00528 
00529 
00530 /********************************************************************\
00531  * gnc_prices_dialog                                                *
00532  *   opens up a window showing all price information                *
00533  *                                                                  *
00534  * Args:   parent  - the parent of the window to be created         *
00535  * Return: nothing                                                  *
00536 \********************************************************************/
00537 void
00538 gnc_prices_dialog (GtkWidget * parent)
00539 {
00540     PricesDialog *pdb_dialog;
00541     gint component_id;
00542 
00543     ENTER(" ");
00544     if (gnc_forall_gui_components (DIALOG_PRICE_DB_CM_CLASS, show_handler, NULL))
00545     {
00546         LEAVE("existing dialog raised");
00547         return;
00548     }
00549 
00550     pdb_dialog = g_new0 (PricesDialog, 1);
00551 
00552     gnc_prices_dialog_create (parent, pdb_dialog);
00553 
00554     component_id = gnc_register_gui_component (DIALOG_PRICE_DB_CM_CLASS,
00555                    refresh_handler, close_handler,
00556                    pdb_dialog);
00557     gnc_gui_component_set_session (component_id, pdb_dialog->session);
00558 
00559     gtk_widget_grab_focus (GTK_WIDGET(pdb_dialog->price_tree));
00560 
00561     gtk_widget_show (pdb_dialog->dialog);
00562     LEAVE(" ");
00563 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines