sort.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *            sort.c
00003  *
00004  *  Sun Sep 24 12:13:51 2006
00005  *  Copyright  2006-2007  Neil Williams
00006  *  linux@codehelp.co.uk
00007  ****************************************************************************/
00013 /*
00014     This package is free software; you can redistribute it and/or modify
00015     it under the terms of the GNU General Public License as published by
00016     the Free Software Foundation; either version 3 of the License, or
00017     (at your option) any later version.
00018 
00019     This program is distributed in the hope that it will be useful,
00020     but WITHOUT ANY WARRANTY; without even the implied warranty of
00021     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022     GNU General Public License for more details.
00023 
00024     You should have received a copy of the GNU General Public License
00025     along with this program.  If not, see <http://www.gnu.org/licenses/>.
00026 */
00027 
00028 #include "config.h"
00029 
00030 #include <math.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <glib.h>
00034 #include <gtk/gtk.h>
00035 #include <glib/gi18n.h>
00036 #include <gtkextra/gtksheet.h>
00037 #include "types.h"
00038 #include "dim_list_menu.h"
00039 #include "edit.h"
00040 #include "main.h"
00041 #include "dialog_initial.h"
00042 
00043 #define FROM_LIST_WIDTH   180
00044 #define FROM_LIST_HEIGHT  180
00045 
00046 typedef struct
00047 {
00048     union
00049     {
00050         gdouble number;
00051         gchar *string;
00052     } level[MAX_SORT_NESTING];
00053     gint old_row;
00054 } QlSortRow;
00055 
00056 QlSortRow *big_array;
00057 
00058 QlSortInfo * curr_sort;
00059 QlSortInfo * edit_sort;
00060 
00061 enum {
00062     SORT_COL,
00063     FROM_COL,
00064 };
00065 
00066 typedef enum 
00067 {
00068     QL_SORT_NONE,
00069     QL_SORT_ADD,
00070     QL_SORT_EDIT,
00071     QL_SORT_APPLY,
00072     QL_SORT_DELETE
00073 } QlSortType;
00074 
00075 QlSortType select_mode;
00076 
00077 /* how many sort levels there are */
00078 gint levels;
00079 gint level_type[MAX_SORT_NESTING + 1];
00080 /* +1 or -1 */
00081 gint level_ascending[MAX_SORT_NESTING + 1];
00082 gint level_formatting[MAX_SORT_NESTING + 1];
00083 
00084 /*  User clicked ascending at some level */
00085 static void
00086 ascending_clicked (GtkObject G_GNUC_UNUSED * object, gpointer entry)
00087 {
00088     gint level = GPOINTER_TO_INT (entry);
00089     edit_sort->line[level].ascending = TRUE;
00090 }
00091 
00092 /*  User clicked ascending at some level */
00093 static void
00094 descending_clicked (GtkObject G_GNUC_UNUSED * object, gpointer entry)
00095 {
00096     gint level = GPOINTER_TO_INT (entry);
00097     edit_sort->line[level].ascending = FALSE;
00098 }
00099 
00100 /*  User clicked to change a field at some level */
00101 static void
00102 field_change (GtkObject * object, gpointer G_GNUC_UNUSED entry)
00103 {
00104     gint iselect, level, fieldx;
00105 
00106     iselect = gtk_combo_box_get_active (GTK_COMBO_BOX (object));
00107     level = iselect / 100;
00108     fieldx = iselect % 100;
00109     edit_sort->line[level].field = fieldx;
00110 }
00111 
00112 /* Build the field button for the sort dialog box  */
00113 static GtkWidget *
00114 field_menu (QlTabData * tab, gint level)
00115 {
00116     GtkWidget *temp_box, *ascend_button, *descend_button;
00117     GtkWidget *menu, *menu_item, *name_label;
00118     gint ret_value, fieldx;
00119     GtkComboBox *field_box;
00120 
00121     menu = gtk_menu_new ();
00122     menu_item = gtk_menu_item_new_with_label (_("-Unused-"));
00123     gtk_widget_show (menu_item);
00124     ret_value = level * 100;
00125     g_signal_connect (GTK_OBJECT (menu_item),
00126         "select", G_CALLBACK (field_change), &ret_value);
00127     gtk_menu_attach (GTK_MENU (menu), menu_item, 0, 1, 0, 1);
00128 
00129     /* add the individual fields to the menu */
00130     field_box = GTK_COMBO_BOX (gtk_combo_box_new_text ());
00132     for (fieldx = 0; fieldx <= tab->file->last_field; fieldx++)
00133     {
00134         QlFieldInfo * field;
00135         ret_value = level * 100 + fieldx + 1;
00136         field = ql_get_fieldinfo (tab, fieldx);
00137         gtk_combo_box_insert_text (field_box, ret_value,
00138             field->name);
00139     }
00140     gtk_widget_show (GTK_WIDGET (field_box));
00141     g_signal_connect (GTK_OBJECT (field_box),
00142         "changed", G_CALLBACK (field_change), NULL);
00143     if (edit_sort->line[level].field >= 0)
00144         gtk_combo_box_set_active (field_box, edit_sort->line[level].field);
00145     /* Pack Widgets into boxes */
00146     temp_box = gtk_hbox_new (FALSE, 5);
00147 
00148     /* now ascending and descending buttons */
00149     /* ad_vbox = gtk_vbox_new (FALSE, 5); */
00150     ascend_button = gtk_radio_button_new_with_label 
00151         (NULL, _("Ascending"));
00152     descend_button =
00153         gtk_radio_button_new_with_label (gtk_radio_button_get_group
00154         (GTK_RADIO_BUTTON (ascend_button)), _("Descending"));
00155     if (edit_sort->line[level].ascending)
00156         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ascend_button),
00157             1);
00158     else
00159         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (descend_button),
00160             1);
00161 
00162     /* Callbacks for radio buttons */
00163     g_signal_connect (GTK_OBJECT (ascend_button), "clicked",
00164         G_CALLBACK (ascending_clicked), GINT_TO_POINTER (level));
00165     g_signal_connect (GTK_OBJECT (descend_button), "clicked",
00166         G_CALLBACK (descending_clicked), GINT_TO_POINTER (level));
00167 
00168     gtk_box_pack_end (GTK_BOX (temp_box), descend_button, FALSE, FALSE, 0);
00169     gtk_box_pack_end (GTK_BOX (temp_box), ascend_button, FALSE, FALSE, 0);
00170     gtk_box_pack_end (GTK_BOX (temp_box), GTK_WIDGET (field_box),
00171         FALSE, FALSE, 0);
00172 
00173     /* now right justify the name label */
00174     if (level)
00175         name_label = gtk_label_new (_("then on: "));
00176     else
00177         name_label = gtk_label_new (_("Primary sort on: "));
00178     gtk_box_pack_end (GTK_BOX (temp_box), name_label, FALSE, FALSE, 0);
00179 
00180     return (temp_box);
00181 }                               /* end of field_menu () */
00182 
00183 /*  This routine compares two big_array elements to return hi, low, equal
00184 and is full of bugs.
00185 */
00186 static gint
00187 sort_compare (gconstpointer fir, gconstpointer sec)
00188 {
00189     gchar *local_string1;
00190     gchar *local_string2;
00191     gdouble local_double1;
00192     gdouble local_double2;
00193     gint levelx;
00194     gint temp_return;
00195     gdouble temp_double;
00196     QlSortRow *first = (QlSortRow *) (fir), *second = (QlSortRow *) (sec);
00197     for (levelx = 0; levelx < levels; levelx++)
00198     {
00199         if (level_type[levelx] == FIELD_TYPE_TEXT)
00200         {
00201             local_string1 = first->level[levelx].string;
00202             local_string2 = second->level[levelx].string;
00203             if (!local_string1)
00204             {
00205                 if (!local_string2)
00206                     continue;   /* they are equal */
00207                 return (level_ascending[levelx]);   /* left is less than right */
00208             }
00209             /* first is not zero, maybe second is */
00210             if (!local_string2)
00211                 return (-level_ascending[levelx]);
00212 
00213             temp_return = strcmp (local_string1, local_string2);
00214             if (temp_return)
00215                 return (level_ascending[levelx] * temp_return);
00216         }
00217 
00218         else
00219         {                       /* all numeric types */
00220             local_double1 = first->level[levelx].number;
00221             local_double2 = second->level[levelx].number;
00222             if ((glong)local_double1 == (glong)HUGE_VAL)
00223             {
00224                 if ((glong)local_double2 == (glong)HUGE_VAL)
00225                     continue;   /* they are equal */
00226                 return (level_ascending[levelx]);   /* left is less than right */
00227             }
00228             /* first is not zero, maybe second is */
00229             if ((glong)local_double2 == (glong)HUGE_VAL)
00230                 return (-level_ascending[levelx]);
00231             temp_double = first->level[levelx].number -
00232                 second->level[levelx].number;
00233             if (temp_double > 0)
00234                 return (level_ascending[levelx]);
00235             if (temp_double < 0)
00236                 return (-level_ascending[levelx]);
00237         }
00238     }
00239 
00240     /* got through everything.  They must be equal */
00241     return 0;
00242 }
00243 
00244 /* 1.  Build an array of elements to sort
00245   2.  Sort them
00246   3.  Copy the sorted rows to the end of the sheet
00247   4.  Delete the original sorted rows  */
00248 static void
00249 do_the_nasty_sort (QlTabData * tab)
00250 {
00251     gint fieldx;
00252     gint rows, rowx, fromrow, torow;
00253     gboolean visible, hold_visible;
00254     gint colx;
00255     gint levelx;
00256     gint local_last_field;
00257     gchar *text;
00258     gchar *hold1row[MAX_FIELDS + 2];
00259 
00260     for (fieldx = 0; fieldx < MAX_FIELDS; fieldx++)
00261         hold1row[fieldx] = NULL;
00262     local_last_field = tab->file->last_field;
00263     /* omits last row, which is blank */
00264     rows = tab->file->last_row;
00265     levels = curr_sort->line_ct;
00266     if (rows < 2)
00267         return;
00268     for (levelx = 0; levelx < levels; levelx++)
00269     {
00270         QlFieldInfo * field;
00271         fieldx = curr_sort->line[levelx].field;
00272         field = ql_get_fieldinfo (tab, fieldx);
00273         curr_sort->line[levelx].column = field->sheet_column;
00274         level_type[levelx] = field->type;
00275         level_formatting[levelx] = field->formatting;
00276         if (curr_sort->line[levelx].ascending)
00277             level_ascending[levelx] = 1;
00278         else
00279             level_ascending[levelx] = -1;
00280     }
00281 
00282     /* go get enough storage to sort this mess */
00283     big_array = (QlSortRow *) g_malloc (rows * sizeof (QlSortRow));
00284 
00285     /* Start the big loop to build array that qsort will sort */
00286     for (rowx = 0; rowx < rows; rowx++)
00287     {
00288         big_array[rowx].old_row = rowx;
00289         for (levelx = 0; levelx < levels; levelx++)
00290         {
00291             text = gtk_sheet_cell_get_text (tab->view->sheet, rowx,
00292                 curr_sort->line[levelx].column);
00293             if (text)
00294                 switch (level_type[levelx])
00295                 {
00296                 case FIELD_TYPE_TEXT:
00297                     big_array[rowx].level[levelx].string = text;
00298                     break;
00299                 default:
00300                     big_array[rowx].level[levelx].number =
00301                         qls2d (text, level_type[levelx],
00302                         level_formatting[levelx]);
00303                     break;
00304                 }
00305             else
00306             {
00307                 if (level_type[levelx] == FIELD_TYPE_TEXT)
00308                     big_array[rowx].level[levelx].string = NULL;
00309                 else
00310                     big_array[rowx].level[levelx].number = HUGE_VAL;
00311             }
00312         }
00313     }                           /* end of building array of pointers */
00314 
00315     /* this is sure easy.  sort them */
00316     qsort (big_array, (size_t) rows, sizeof (QlSortRow), sort_compare);
00317 
00318     /* rows are rearranged.  move them in sheet */
00319     big_draw_start (tab);
00320 
00321     /* the plan is to move aside one row, then move in the row that goes 
00322        there, then move in the next row into the vacated position, and so on */
00323     for (rowx = 0; rowx < rows; rowx++)
00324     {
00325         if (big_array[rowx].old_row < 0)    /* already moved */
00326             continue;
00327         if (rowx == big_array[rowx].old_row)    /* this row doesn't move */
00328             continue;
00329 
00330         /* save this first row */
00331         hold_visible = row_is_visible (tab, rowx);
00332         for (colx = 0; colx <= local_last_field; colx++)
00333         {
00334             text = g_strdup (gtk_sheet_cell_get_text 
00335                 (tab->view->sheet, rowx, colx));
00336             if (text)
00337             {
00338                 hold1row[colx] = text;
00339                 gtk_sheet_cell_clear (tab->view->sheet, rowx,
00340                     colx);
00341             }
00342         }
00343         torow = rowx;
00344         fromrow = big_array[rowx].old_row;
00345         big_array[rowx].old_row = -1;
00346 
00347         /* copy row that goes here from where it is now */
00348         do
00349         {
00350             visible = row_is_visible (tab, fromrow);
00351             gtk_sheet_row_set_visibility (tab->view->sheet,
00352                 torow, visible);
00353             for (colx = 0; colx <= local_last_field; colx++)
00354             {
00355                 text = g_strdup (gtk_sheet_cell_get_text 
00356                     (tab->view->sheet, fromrow, colx));
00357                 if (text)
00358                 {
00359                     gtk_sheet_set_cell_text (tab->view->sheet,
00360                         torow, colx, text);
00361                     gtk_sheet_cell_clear (tab->view->sheet,
00362                         fromrow, colx);
00363                 }
00364                 g_free (text);
00365             }
00366             torow = fromrow;
00367             fromrow = big_array[fromrow].old_row;
00368             big_array[torow].old_row = -1;
00369         }
00370         while (big_array[fromrow].old_row >= 0);
00371 
00372         /* got to the end of a chain, put back the stored row */
00373         gtk_sheet_row_set_visibility (tab->view->sheet,
00374             torow, hold_visible);
00375         for (colx = 0; colx <= local_last_field; colx++)
00376         {
00377             if (hold1row[colx])
00378             {
00379                 gtk_sheet_set_cell_text (tab->view->sheet, torow,
00380                     colx, hold1row[colx]);
00381                 g_free (hold1row[colx]);
00382                 hold1row[colx] = NULL;
00383             }
00384         }
00385     }                           /* end of big looop to move all rows */
00386     g_free (big_array);
00387     big_draw_end (tab);
00388     front_is_changed (tab);
00389 }                               /* end of do_the_nasty_sort () */
00390 
00391 /*  User clicked OK to finish editing a sort layout.  What we do now
00392   depends on how we got here.*/
00393 static void
00394 ok_clicked (GtkWidget * w, gpointer G_GNUC_UNUSED entry)
00395 {
00396     gchar *text;
00397     gint sortx;
00398     gboolean gotone;
00399     QlContext * qlc;
00400     QlTabData * tab;
00401 
00402     qlc = ql_get_context (GTK_WIDGET(w));
00403     tab = ql_get_tabdata (qlc);
00404     /* save the changed name */
00405     text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tab->view->entry1)));
00406     if (check_entry (tab, text))
00407         return;
00408     front_is_changed (tab);
00409     strcpy (edit_sort->name, text);
00410 
00411     /* check to see if even one field.  Don't start moving until we
00412        get past this point */
00413     gotone = FALSE;
00414     for (sortx = 0; sortx < MAX_SORT_NESTING; sortx++)
00415         if (edit_sort->line[sortx].field > 0)
00416             gotone = TRUE;
00417 
00418     if (!gotone)
00419     {
00420         level2_error (tab, _("You must specify at least one column "
00421                 "on which to sort."));
00422         return;
00423     }
00424 
00425     /* there is at least one field.  Now clean up and convert all back to valid
00426        values. */
00427     edit_sort->line_ct = 0;
00428     for (sortx = 0; sortx < MAX_SORT_NESTING; sortx++)
00429         if (edit_sort->line[sortx].field-- > 0)
00430             edit_sort->line[edit_sort->line_ct++] = edit_sort->line[sortx];
00431 
00432     curr_sort = edit_sort;
00433     do_the_nasty_sort (tab);
00434 
00435     if (select_mode == QL_SORT_ADD)
00436         tab->file->sort_ct++;
00437     tab->file->sort_ptr = curr_sort;
00438     dim_list_sort_menu (tab->qlc);
00439 }
00440 
00441 /* User clicked OK to select a specific sort layout.  What we do now
00442   depends on how we got here.*/
00443 static void
00444 select_ok (GtkButton * button, gpointer data)
00445 {
00446     GtkTreeSelection *selection;
00447     GtkTreeIter iter;
00448     GtkTreeModel *model;
00449     gchar * sort_name;
00450     gint reportx;
00451     QlContext * qlc;
00452     QlTabData * tab;
00453 
00454     qlc = ql_get_context (GTK_WIDGET(button));
00455     tab = ql_get_tabdata (qlc);
00456     selection = GTK_TREE_SELECTION (data);
00457     if (gtk_tree_selection_get_selected (selection, &model, &iter))
00458     {
00459         reportx = -1;
00460         gtk_tree_model_get (model, &iter, SORT_COL, 
00461             &sort_name, -1);
00462         for (reportx = 0; reportx <= tab->file->report_ct; reportx++)
00463         {
00464             if (0 == strcmp (tab->file->sorts[reportx].name, sort_name))
00465             {
00466                 tab->file->sort_ptr = &tab->file->sorts[reportx];
00467                 curr_sort = &tab->file->sorts[reportx];
00468             }
00469         }
00470         if (tab->file->report_no < 0)
00471             return;
00472         do_the_nasty_sort (tab);
00473 //      gtk_widget_destroy (dialog1_win);
00474         dim_list_sort_menu (tab->qlc);
00475     }
00476 }
00477 
00478 static void
00479 build_select_box (QlTabData * tab)
00480 {
00481     gint sortx;
00482     guint width;
00483     GtkWidget *top_vbox;
00484     GtkWidget *hbox2;           /* treeview and header */
00485     GtkWidget *scrwin_from, * ok_button;
00486     GtkTreeStore * treestore;
00487     GtkTreeIter parent_iter, child_iter;
00488     GtkCellRenderer *renderer;
00489     GtkTreeViewColumn *column;
00490     GtkTreeView * treeview;
00491     GtkTreeModel * model;
00492     GtkTreeSortable * sort;
00493     GtkTreeSelection * bselect;
00494     GtkWidget *hbox6;           /* same as action area */
00495     GtkWidget *cancel_button;
00496     GtkWidget * select_dlg;
00497 
00498     select_dlg = gtk_dialog_new ();
00499     gtk_window_set_modal (GTK_WINDOW (select_dlg), TRUE);
00500     gtk_window_set_position (GTK_WINDOW (select_dlg), GTK_WIN_POS_CENTER);
00501     gtk_window_set_resizable (GTK_WINDOW (select_dlg), TRUE);
00502     gtk_container_set_border_width (GTK_CONTAINER (select_dlg), 5);
00503     width = 0;
00504     gtk_window_set_title (GTK_WINDOW (select_dlg), _("Select a sort"));
00505     top_vbox = GTK_DIALOG (select_dlg)->vbox;
00506     gtk_box_set_spacing (GTK_BOX (top_vbox), 10);
00507     hbox6 = GTK_DIALOG (select_dlg)->action_area;
00508 
00509     hbox2 = gtk_hbox_new (FALSE, 5);
00510     gtk_box_pack_start (GTK_BOX (top_vbox), hbox2, TRUE, TRUE, 0);
00511 
00512     /* The sort names tree */
00513     treeview = GTK_TREE_VIEW (gtk_tree_view_new ());
00514     model = gtk_tree_view_get_model (treeview);
00515     treestore = gtk_tree_store_new (SINGLE_COL, G_TYPE_STRING);
00516     sort = GTK_TREE_SORTABLE (treestore);
00517     gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), 
00518         GTK_TREE_MODEL (sort));
00519     gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
00520     gtk_tree_view_set_reorderable (GTK_TREE_VIEW (treeview), TRUE);
00521     gtk_tree_store_append (treestore, &parent_iter, NULL);
00522     gtk_tree_store_set (treestore, &parent_iter, SORT_COL, 
00523         _("Available sort patterns"), -1);
00524     renderer = gtk_cell_renderer_text_new ();
00525     column = gtk_tree_view_column_new_with_attributes
00526         (_("Sort Name"), renderer, "text", SORT_COL, NULL);
00527     gtk_tree_view_column_set_sort_column_id (column, SORT_COL);
00528     gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
00529     bselect = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
00530     gtk_tree_selection_set_mode (bselect, GTK_SELECTION_SINGLE);
00531 
00532     scrwin_from = gtk_scrolled_window_new (NULL, NULL);
00533     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrwin_from),
00534         GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
00535     gtk_container_set_border_width (GTK_CONTAINER (scrwin_from), 5);
00536     gtk_box_pack_start (GTK_BOX (hbox2), scrwin_from, TRUE, TRUE, 0);
00537     gtk_container_add (GTK_CONTAINER (scrwin_from), 
00538         GTK_WIDGET(treeview));
00539 
00540     ok_button = gtk_button_new_from_stock (GTK_STOCK_OK);
00541     gtk_box_pack_start (GTK_BOX (hbox6), ok_button, TRUE, TRUE, 0);
00542     g_signal_connect (GTK_OBJECT (ok_button), "clicked",
00543         G_CALLBACK (select_ok), bselect);
00544 
00545     cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
00546     gtk_box_pack_start (GTK_BOX (hbox6), cancel_button, TRUE, TRUE, 0);
00547     g_signal_connect (GTK_OBJECT (cancel_button), "clicked",
00548         G_CALLBACK (close_dlg), select_dlg);
00549     g_signal_connect (GTK_OBJECT (select_dlg), "delete_event", 
00550         G_CALLBACK (close_dlg), select_dlg);
00551 
00552     /* now populate the tree of sort names */
00553     for (sortx = 0; sortx < tab->file->sort_ct; sortx++)
00554     {
00555         gtk_tree_store_append (treestore, &child_iter, &parent_iter);
00556         gtk_tree_store_set (treestore, &child_iter, SORT_COL, 
00557             tab->file->sorts[sortx].name, -1);
00558         width = (strlen(tab->file->sorts[sortx].name) > width) ? 
00559             strlen(tab->file->sorts[sortx].name) : width;
00560     }
00561     gtk_widget_set_size_request (GTK_WIDGET(treeview), 
00562         width + 200, 200);
00563     gtk_tree_view_expand_all (GTK_TREE_VIEW(treeview));
00564     gtk_widget_show_all (select_dlg);
00565 }                               /* End of build_select_box */
00566 
00567 static void
00568 display_edit_window (QlTabData * tab)
00569 {
00570     GtkWidget *ok_button,
00571         *cancel_button, * edit_win,
00572         *top_box, *button_box, *temp_box, *hbox1, *name_label;
00573     gint sortx;
00574 
00575     /* let's clean up the sort rules for display purposes.
00576        Even when there may be only two lines, all six display. 
00577        For that reason, add 1 to all entries so that 0 displays 
00578        as None and 1 displays field 0 */
00579     for (sortx = 0; sortx < MAX_SORT_NESTING; sortx++)
00580     {
00581         if (sortx < edit_sort->line_ct)
00582             edit_sort->line[sortx].field++;
00583         else
00584         {
00585             edit_sort->line[sortx].field = 0;
00586             edit_sort->line[sortx].ascending = TRUE;
00587         }
00588     }
00589 
00590     edit_win = gtk_dialog_new ();
00591     gtk_window_set_modal (GTK_WINDOW (edit_win), TRUE);
00592     gtk_window_set_position (GTK_WINDOW (edit_win), GTK_WIN_POS_CENTER);
00593     gtk_window_set_resizable (GTK_WINDOW (edit_win), TRUE);
00594     gtk_container_set_border_width (GTK_CONTAINER (edit_win), 5);
00595 
00596     gtk_window_set_title (GTK_WINDOW (edit_win),
00597         _("Add or edit sort rules"));
00598     top_box = GTK_DIALOG (edit_win)->vbox;
00599     button_box = GTK_DIALOG (edit_win)->action_area;
00600     gtk_box_set_spacing (GTK_BOX (top_box), 5);
00601     g_signal_connect (GTK_OBJECT (edit_win),
00602         "delete_event", G_CALLBACK (gtk_widget_destroy), edit_win);
00603     /* Show and allow changes to sort name */
00604     hbox1 = gtk_hbox_new (FALSE, 5);
00605     name_label = gtk_label_new (_("Sort Name"));
00606     gtk_box_pack_start (GTK_BOX (hbox1), name_label, FALSE, FALSE, 0);
00607 
00608     tab->view->entry1 = gtk_entry_new ();
00609     gtk_box_pack_start (GTK_BOX (hbox1), tab->view->entry1, TRUE, TRUE, 0);
00610     gtk_box_pack_start (GTK_BOX (top_box), hbox1, FALSE, FALSE, 0);
00611     gtk_entry_set_text (GTK_ENTRY (tab->view->entry1), edit_sort->name);
00612 
00613     /* make six entries for levels of sorting */
00614     for (sortx = 0; sortx < MAX_SORT_NESTING; sortx++)
00615     {
00616         temp_box = field_menu (tab, sortx);
00617         gtk_container_add (GTK_CONTAINER (top_box), temp_box);
00618     }
00619 
00620     ok_button = gtk_button_new_from_stock (GTK_STOCK_OK);
00621     g_signal_connect (GTK_OBJECT (ok_button),
00622         "clicked", G_CALLBACK (ok_clicked), edit_win);
00623 
00624     cancel_button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
00625     g_signal_connect (GTK_OBJECT (cancel_button),
00626         "clicked", G_CALLBACK (close_dlg), edit_win);
00627 
00628     gtk_container_add (GTK_CONTAINER (button_box), ok_button);
00629     gtk_container_add (GTK_CONTAINER (button_box), cancel_button);
00630     gtk_widget_show_all (edit_win);
00631 }                               /* end of display_edit_window */
00632 
00633 /*  Add a new sort to the file */
00634 void
00635 sort_add (GtkAction G_GNUC_UNUSED * a, gpointer data)
00636 {
00637     QlContext * qlc;
00638     QlTabData * tab;
00639 
00640     qlc = ql_get_context (GTK_WIDGET(data));
00641     tab = ql_get_tabdata (qlc);
00642     CHECK_CHANGED(tab);
00643     edit_sort = g_new0(QlSortInfo, 1);
00644     edit_sort->name = g_strdup(_("Untitled sort"));
00645     select_mode = QL_SORT_ADD;
00646     tab->file->sort_ptr = &tab->file->sorts[tab->file->sort_ct];
00647     display_edit_window (tab);
00648 }
00649 
00650 /* Called by report.  Just sort the file */
00651 void
00652 sort_do_it (QlTabData * tab, gint sortno)
00653 {
00654     g_return_if_fail (tab);
00655     CHECK_CHANGED(tab);
00656     curr_sort = &tab->file->sorts[sortno];
00657     do_the_nasty_sort (tab);
00658 }
00659 
00660 void
00661 sort_by_column (GtkAction G_GNUC_UNUSED * w, gpointer data)
00662 {
00663     GtkSheetRange range;
00664     QlContext * qlc;
00665     QlTabData * tab;
00666 
00667     qlc = ql_get_context (GTK_WIDGET(data));
00668     tab = ql_get_tabdata (qlc);
00669 //  CHECK_CHANGED(tab);
00670     curr_sort = g_new0 (QlSortInfo, 1);
00671     curr_sort->line_ct = 1;
00672     curr_sort->line[0].field = tab->file->col_to_field[tab->view->sel_range.col0];
00673     curr_sort->line[0].ascending = TRUE;
00674     do_the_nasty_sort (tab);
00675     range.col0 = range.coli = tab->view->sel_range.col0;
00676     range.row0 = range.rowi = 0;
00677     gtk_sheet_select_range (tab->view->sheet, &range);
00678 }
00679 
00680 void
00681 sort_delete (GtkAction G_GNUC_UNUSED * w, gpointer data)
00682 {
00683     QlContext * qlc;
00684     QlTabData * tab;
00685 
00686     qlc = ql_get_context (GTK_WIDGET(data));
00687     tab = ql_get_tabdata (qlc);
00688     CHECK_CHANGED(tab);
00689     select_mode = QL_SORT_DELETE;
00690     build_select_box (tab);
00691 }
00692 
00693 void
00694 sort_edit (GtkAction G_GNUC_UNUSED * w, gpointer data)
00695 {
00696     QlContext * qlc;
00697     QlTabData * tab;
00698 
00699     qlc = ql_get_context (GTK_WIDGET(data));
00700     tab = ql_get_tabdata (qlc);
00701     CHECK_CHANGED(tab);
00702     select_mode = QL_SORT_EDIT;
00703     build_select_box (tab);
00704 }
00705 
00706 void
00707 sort_apply (GtkWidget G_GNUC_UNUSED * w, gpointer data)
00708 {
00709     QlContext * qlc;
00710     QlTabData * tab;
00711 
00712     qlc = ql_get_context (GTK_WIDGET(data));
00713     tab = ql_get_tabdata (qlc);
00714     CHECK_CHANGED(tab);
00715     select_mode = QL_SORT_APPLY;
00716     build_select_box (tab);
00717 }

Generated on Mon Jan 28 22:02:10 2008 for quicklist by  doxygen 1.5.4