"Fossies" - the Fresh Open Source Software Archive

Member "jpilot-2_0_1/todo_gui.c" (3 Apr 2021, 105064 Bytes) of package /linux/privat/jpilot-2_0_1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*******************************************************************************
    2  * todo_gui.c
    3  * A module of J-Pilot http://jpilot.org
    4  *
    5  * Copyright (C) 1999-2014 by Judd Montgomery
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of the GNU General Public License as published by
    9  * the Free Software Foundation; version 2 of the License.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  * GNU General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU General Public License
   17  * along with this program; if not, write to the Free Software
   18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   19  ******************************************************************************/
   20 
   21 /********************************* Includes ***********************************/
   22 #include "config.h"
   23 #include <stdlib.h>
   24 #include <string.h>
   25 #include <time.h>
   26 #include <sys/stat.h>
   27 #include <unistd.h>
   28 #include <gtk/gtk.h>
   29 #include <gdk/gdkkeysyms.h>
   30 #include <pi-dlp.h>
   31 #include <slcurses.h>
   32 
   33 #include "todo.h"
   34 #include "i18n.h"
   35 #include "utils.h"
   36 #include "log.h"
   37 #include "prefs.h"
   38 #include "password.h"
   39 #include "print.h"
   40 #include "export.h"
   41 #include "stock_buttons.h"
   42 
   43 /********************************* Constants **********************************/
   44 #define TODO_MAX_COLUMN_LEN 80
   45 #define MAX_RADIO_BUTTON_LEN 100
   46 
   47 #define NUM_TODO_PRIORITIES 5
   48 #define NUM_TODO_CAT_ITEMS 16
   49 #define NUM_TODO_CSV_FIELDS 8
   50 #define CONNECT_SIGNALS 400
   51 #define DISCONNECT_SIGNALS 401
   52 
   53 /* RFCs use CRLF for Internet newline */
   54 #define CRLF "\x0D\x0A"
   55 
   56 /******************************* Global vars **********************************/
   57 /* Keeps track of whether code is using ToDo, or Tasks database
   58  * 0 is ToDo, 1 is Tasks */
   59 static long todo_version = 0;
   60 
   61 extern GtkWidget *glob_date_label;
   62 extern int glob_date_timer_tag;
   63 
   64 static GtkWidget *treeView;
   65 static GtkTreeSelection *treeSelection;
   66 static GtkListStore *listStore;
   67 static GtkWidget *todo_desc, *todo_note;
   68 static GObject *todo_desc_buffer, *todo_note_buffer;
   69 static GtkWidget *todo_completed_checkbox;
   70 static GtkWidget *private_checkbox;
   71 static struct tm due_date;
   72 static GtkWidget *due_date_button;
   73 static GtkWidget *todo_no_due_date_checkbox;
   74 static GtkWidget *radio_button_todo[NUM_TODO_PRIORITIES];
   75 static GtkWidget *new_record_button;
   76 static GtkWidget *apply_record_button;
   77 static GtkWidget *add_record_button;
   78 static GtkWidget *delete_record_button;
   79 static GtkWidget *undelete_record_button;
   80 static GtkWidget *copy_record_button;
   81 static GtkWidget *cancel_record_button;
   82 static GtkWidget *category_menu1;
   83 static GtkWidget *category_menu2;
   84 static GtkWidget *pane;
   85 static GtkWidget *note_pane;
   86 
   87 static ToDoList *glob_todo_list = NULL;
   88 static ToDoList *export_todo_list = NULL;
   89 
   90 static struct sorted_cats sort_l[NUM_TODO_CAT_ITEMS];
   91 
   92 static struct ToDoAppInfo todo_app_info;
   93 static int todo_category = CATEGORY_ALL;
   94 static int column_selected;
   95 static int row_selected;
   96 static int record_changed;
   97 
   98 /****************************** Prototypes ************************************/
   99 static int todo_clear_details(void);
  100 
  101 static int todo_redraw(void);
  102 
  103 static int todo_find(void);
  104 
  105 static void cb_add_new_record(GtkWidget *widget, gpointer data);
  106 
  107 static void connect_changed_signals(int con_or_dis);
  108 
  109 
  110 void addNewRecordToDataStructure(MyToDo *mtodo, gpointer data);
  111 
  112 void deleteTodo(MyToDo *mtodo, gpointer data);
  113 
  114 void undeleteTodo(MyToDo *mtodo, gpointer data);
  115 
  116 int printTodo(MyToDo *mtodo, gpointer data);
  117 
  118 
  119 
  120 gboolean printRecord(GtkTreeModel *model,
  121                      GtkTreePath *path,
  122                      GtkTreeIter *iter,
  123                      gpointer data);
  124 
  125 
  126 
  127 
  128 
  129 gboolean
  130 findRecord(GtkTreeModel *model,
  131            GtkTreePath *path,
  132            GtkTreeIter *iter,
  133            gpointer data);
  134 
  135 gboolean
  136 selectRecordByRow(GtkTreeModel *model,
  137                   GtkTreePath *path,
  138                   GtkTreeIter *iter,
  139                   gpointer data);
  140 
  141 gint compareNoteColumn(GtkTreeModel *model, GtkTreeIter *left, GtkTreeIter *right);
  142 
  143 gint compareCheckColumn(GtkTreeModel *model, GtkTreeIter *left, GtkTreeIter *right);
  144 
  145 
  146 /****************************** Main Code *************************************/
  147 /* Called once on initialization of GUI */
  148 static void init(void) {
  149     time_t ltime;
  150     struct tm *now;
  151     long ivalue;
  152 
  153     time(&ltime);
  154     now = localtime(&ltime);
  155 
  156     memcpy(&due_date, now, sizeof(struct tm));
  157 
  158     get_pref(PREF_TODO_DAYS_TILL_DUE, &ivalue, NULL);
  159     add_days_to_date(&due_date, (int) ivalue);
  160 
  161     row_selected = 0;
  162     column_selected = 0;
  163 
  164     record_changed = CLEAR_FLAG;
  165 }
  166 
  167 static void update_due_button(GtkWidget *button, struct tm *t) {
  168     const char *short_date;
  169     char str[255];
  170 
  171     if (t) {
  172         get_pref(PREF_SHORTDATE, NULL, &short_date);
  173         strftime(str, sizeof(str), short_date, t);
  174 
  175         gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(button))), str);
  176     } else {
  177         gtk_label_set_text(GTK_LABEL(gtk_bin_get_child(GTK_BIN(button))), _("No Date"));
  178     }
  179 }
  180 
  181 static void cb_cal_dialog(GtkWidget *widget,
  182                           gpointer data) {
  183     long fdow;
  184     int r = 0;
  185     struct tm t;
  186     GtkWidget *Pcheck_button;
  187     GtkWidget *Pbutton;
  188 
  189     Pcheck_button = todo_no_due_date_checkbox;
  190     memcpy(&t, &due_date, sizeof(t));
  191     Pbutton = due_date_button;
  192 
  193     get_pref(PREF_FDOW, &fdow, NULL);
  194 
  195     r = cal_dialog(GTK_WINDOW(gtk_widget_get_toplevel(widget)), _("Due Date"), (int) fdow,
  196                    &(t.tm_mon),
  197                    &(t.tm_mday),
  198                    &(t.tm_year));
  199 
  200     if (r == CAL_DONE) {
  201         mktime(&t);
  202         memcpy(&due_date, &t, sizeof(due_date));
  203         if (Pcheck_button) {
  204             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Pcheck_button), FALSE);
  205             /* The above call sets due_date forward by n days, so we correct it */
  206             memcpy(&due_date, &t, sizeof(due_date));
  207             update_due_button(Pbutton, &t);
  208         }
  209         if (Pbutton) {
  210             update_due_button(Pbutton, &t);
  211         }
  212     }
  213 }
  214 
  215 int printTodo(MyToDo *mtodo, gpointer data) {
  216     long this_many;
  217     ToDoList *todo_list;
  218     ToDoList todo_list1;
  219 
  220     get_pref(PREF_PRINT_THIS_MANY, &this_many, NULL);
  221 
  222     todo_list = NULL;
  223     if (this_many == 1) {
  224         if (mtodo < (MyToDo *) LIST_MIN_DATA) {
  225             return EXIT_FAILURE;
  226         }
  227         memcpy(&(todo_list1.mtodo), mtodo, sizeof(MyToDo));
  228         todo_list1.next = NULL;
  229         todo_list = &todo_list1;
  230     }
  231     if (this_many == 2) {
  232         get_todos2(&todo_list, SORT_ASCENDING, 2, 2, 2, 2, todo_category);
  233     }
  234     if (this_many == 3) {
  235         get_todos2(&todo_list, SORT_ASCENDING, 2, 2, 2, 2, CATEGORY_ALL);
  236     }
  237 
  238     print_todos(todo_list, PN);
  239 
  240     if ((this_many == 2) || (this_many == 3)) {
  241         free_ToDoList(&todo_list);
  242     }
  243 
  244     return EXIT_SUCCESS;
  245 }
  246 
  247 int todo_print(void) {
  248     gtk_tree_model_foreach(GTK_TREE_MODEL(listStore), printRecord, NULL);
  249     return EXIT_SUCCESS;
  250 
  251 }
  252 
  253 static void set_new_button_to(int new_state) {
  254     jp_logf(JP_LOG_DEBUG, "set_new_button_to new %d old %d\n", new_state, record_changed);
  255 
  256     if (record_changed == new_state) {
  257         return;
  258     }
  259 
  260     switch (new_state) {
  261         case MODIFY_FLAG:
  262             gtk_widget_show(cancel_record_button);
  263             gtk_widget_show(copy_record_button);
  264             gtk_widget_show(apply_record_button);
  265 
  266             gtk_widget_hide(add_record_button);
  267             gtk_widget_hide(delete_record_button);
  268             gtk_widget_hide(new_record_button);
  269             gtk_widget_hide(undelete_record_button);
  270 
  271             break;
  272         case NEW_FLAG:
  273             gtk_widget_show(cancel_record_button);
  274             gtk_widget_show(add_record_button);
  275 
  276             gtk_widget_hide(apply_record_button);
  277             gtk_widget_hide(copy_record_button);
  278             gtk_widget_hide(delete_record_button);
  279             gtk_widget_hide(new_record_button);
  280             gtk_widget_hide(undelete_record_button);
  281 
  282             break;
  283         case CLEAR_FLAG:
  284             gtk_widget_show(delete_record_button);
  285             gtk_widget_show(copy_record_button);
  286             gtk_widget_show(new_record_button);
  287 
  288             gtk_widget_hide(add_record_button);
  289             gtk_widget_hide(apply_record_button);
  290             gtk_widget_hide(cancel_record_button);
  291             gtk_widget_hide(undelete_record_button);
  292 
  293             break;
  294         case UNDELETE_FLAG:
  295             gtk_widget_show(undelete_record_button);
  296             gtk_widget_show(copy_record_button);
  297             gtk_widget_show(new_record_button);
  298 
  299             gtk_widget_hide(add_record_button);
  300             gtk_widget_hide(apply_record_button);
  301             gtk_widget_hide(cancel_record_button);
  302             gtk_widget_hide(delete_record_button);
  303             break;
  304 
  305         default:
  306             return;
  307     }
  308 
  309     record_changed = new_state;
  310 }
  311 
  312 static void cb_record_changed(GtkWidget *widget,
  313                               gpointer data) {
  314     jp_logf(JP_LOG_DEBUG, "cb_record_changed\n");
  315     if (record_changed == CLEAR_FLAG) {
  316         connect_changed_signals(DISCONNECT_SIGNALS);
  317         if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(listStore), NULL) > 0) {
  318             set_new_button_to(MODIFY_FLAG);
  319         } else {
  320             set_new_button_to(NEW_FLAG);
  321         }
  322     } else if (record_changed == UNDELETE_FLAG) {
  323         jp_logf(JP_LOG_INFO | JP_LOG_GUI,
  324                 _("This record is deleted.\n"
  325                   "Undelete it or copy it to make changes.\n"));
  326     }
  327 }
  328 
  329 static void connect_changed_signals(int con_or_dis) {
  330     int i;
  331     static int connected = 0;
  332 
  333     /* CONNECT */
  334     if ((con_or_dis == CONNECT_SIGNALS) && (!connected)) {
  335         connected = 1;
  336 
  337 
  338         if (category_menu2) {
  339             g_signal_connect(G_OBJECT(category_menu2), "changed", G_CALLBACK(cb_record_changed), NULL);
  340         }
  341         for (i = 0; i < NUM_TODO_PRIORITIES; i++) {
  342             if (radio_button_todo[i]) {
  343                 g_signal_connect(G_OBJECT(radio_button_todo[i]), "toggled",
  344                                  G_CALLBACK(cb_record_changed), NULL);
  345             }
  346         }
  347         g_signal_connect(todo_desc_buffer, "changed",
  348                          G_CALLBACK(cb_record_changed), NULL);
  349         g_signal_connect(todo_note_buffer, "changed",
  350                          G_CALLBACK(cb_record_changed), NULL);
  351 
  352         g_signal_connect(G_OBJECT(todo_completed_checkbox), "toggled",
  353                          G_CALLBACK(cb_record_changed), NULL);
  354         g_signal_connect(G_OBJECT(private_checkbox), "toggled",
  355                          G_CALLBACK(cb_record_changed), NULL);
  356         g_signal_connect(G_OBJECT(todo_no_due_date_checkbox), "toggled",
  357                          G_CALLBACK(cb_record_changed), NULL);
  358         g_signal_connect(G_OBJECT(due_date_button), "pressed",
  359                          G_CALLBACK(cb_record_changed), NULL);
  360     }
  361 
  362     /* DISCONNECT */
  363     if ((con_or_dis == DISCONNECT_SIGNALS) && (connected)) {
  364         connected = 0;
  365         if (category_menu2) {
  366             g_signal_handlers_disconnect_by_func(G_OBJECT(category_menu2), G_CALLBACK(cb_record_changed), NULL);
  367         }
  368         for (i = 0; i < NUM_TODO_PRIORITIES; i++) {
  369             g_signal_handlers_disconnect_by_func(G_OBJECT(radio_button_todo[i]),
  370                                                  G_CALLBACK(cb_record_changed), NULL);
  371         }
  372         g_signal_handlers_disconnect_by_func(todo_desc_buffer,
  373                                              G_CALLBACK(cb_record_changed), NULL);
  374         g_signal_handlers_disconnect_by_func(todo_note_buffer,
  375                                              G_CALLBACK(cb_record_changed), NULL);
  376 
  377         g_signal_handlers_disconnect_by_func(G_OBJECT(todo_completed_checkbox),
  378                                              G_CALLBACK(cb_record_changed), NULL);
  379         g_signal_handlers_disconnect_by_func(G_OBJECT(private_checkbox),
  380                                              G_CALLBACK(cb_record_changed), NULL);
  381         g_signal_handlers_disconnect_by_func(G_OBJECT(todo_no_due_date_checkbox),
  382                                              G_CALLBACK(cb_record_changed), NULL);
  383         g_signal_handlers_disconnect_by_func(G_OBJECT(due_date_button),
  384                                              G_CALLBACK(cb_record_changed), NULL);
  385     }
  386 }
  387 
  388 
  389 static int todo_to_text(struct ToDo *todo, char *text, int len) {
  390     char yes[] = "Yes";
  391     char no[] = "No";
  392     char empty[] = "";
  393     char *complete;
  394     char *description;
  395     char *note;
  396     char due[20];
  397     const char *short_date;
  398 
  399     if (todo->indefinite) {
  400         strcpy(due, "Never");
  401     } else {
  402         get_pref(PREF_SHORTDATE, NULL, &short_date);
  403         strftime(due, sizeof(due), short_date, &(todo->due));
  404     }
  405     complete = todo->complete ? yes : no;
  406     description = todo->description ? todo->description : empty;
  407     note = todo->note ? todo->note : empty;
  408     g_snprintf(text, (gulong) len, "Due: %s\nPriority: %d\nComplete: %s\n\
  409 Description: %s\nNote: %s\n", due, todo->priority, complete,
  410                description, note);
  411     return EXIT_SUCCESS;
  412 }
  413 
  414 /*
  415  * Start Import Code
  416  */
  417 static int cb_todo_import(GtkWidget *parent_window,
  418                           const char *file_path, int type) {
  419     FILE *in;
  420     char text[65536];
  421     char description[65536];
  422     char note[65536];
  423     struct ToDo new_todo;
  424     unsigned char attrib;
  425     int i, ret, index;
  426     int import_all;
  427     ToDoList *todolist;
  428     ToDoList *temp_todolist;
  429     struct CategoryAppInfo cai;
  430     char old_cat_name[32];
  431     int suggested_cat_num;
  432     int new_cat_num;
  433     int priv, indefinite, priority, completed;
  434     int year, month, day;
  435 
  436     in = fopen(file_path, "r");
  437     if (!in) {
  438         jp_logf(JP_LOG_WARN, _("Unable to open file: %s\n"), file_path);
  439         return EXIT_FAILURE;
  440     }
  441 
  442     /* CSV */
  443     if (type == IMPORT_TYPE_CSV) {
  444         jp_logf(JP_LOG_DEBUG, "Todo import CSV [%s]\n", file_path);
  445         /* Get the first line containing the format and check for reasonableness */
  446         if (fgets(text, sizeof(text), in) == NULL) {
  447             jp_logf(JP_LOG_WARN, "fgets failed %s %d\n", __FILE__, __LINE__);
  448         }
  449         ret = verify_csv_header(text, NUM_TODO_CSV_FIELDS, file_path);
  450         if (EXIT_FAILURE == ret) return EXIT_FAILURE;
  451 
  452         import_all = FALSE;
  453         while (1) {
  454             /* Read the category field */
  455             ret = read_csv_field(in, text, sizeof(text));
  456             if (feof(in)) break;
  457 #ifdef JPILOT_DEBUG
  458             printf("category is [%s]\n", text);
  459 #endif
  460             g_strlcpy(old_cat_name, text, 16);
  461             attrib = 0;
  462             /* Figure out what the best category number is */
  463             suggested_cat_num = 0;
  464             for (i = 0; i < NUM_TODO_CAT_ITEMS; i++) {
  465                 if (todo_app_info.category.name[i][0] == '\0') continue;
  466                 if (!strcmp(todo_app_info.category.name[i], old_cat_name)) {
  467                     suggested_cat_num = i;
  468                     break;
  469                 }
  470             }
  471 
  472             /* Read the private field */
  473             ret = read_csv_field(in, text, sizeof(text));
  474 #ifdef JPILOT_DEBUG
  475             printf("private is [%s]\n", text);
  476 #endif
  477             sscanf(text, "%d", &priv);
  478 
  479             /* Read the indefinite field */
  480             ret = read_csv_field(in, text, sizeof(text));
  481 #ifdef JPILOT_DEBUG
  482             printf("indefinite is [%s]\n", text);
  483 #endif
  484             sscanf(text, "%d", &indefinite);
  485 
  486             /* Read the Due Date field */
  487             ret = read_csv_field(in, text, sizeof(text));
  488 #ifdef JPILOT_DEBUG
  489             printf("due date is [%s]\n", text);
  490 #endif
  491             sscanf(text, "%d/%d/%d", &year, &month, &day);
  492 
  493             /* Read the Priority field */
  494             ret = read_csv_field(in, text, sizeof(text));
  495 #ifdef JPILOT_DEBUG
  496             printf("priority is [%s]\n", text);
  497 #endif
  498             sscanf(text, "%d", &priority);
  499 
  500             /* Read the Completed field */
  501             ret = read_csv_field(in, text, sizeof(text));
  502 #ifdef JPILOT_DEBUG
  503             printf("completed is [%s]\n", text);
  504 #endif
  505             sscanf(text, "%d", &completed);
  506 
  507             /* Read the Description field */
  508             ret = read_csv_field(in, description, sizeof(text));
  509 #ifdef JPILOT_DEBUG
  510             printf("todo description [%s]\n", description);
  511 #endif
  512 
  513             /* Read the Note field */
  514             ret = read_csv_field(in, note, sizeof(text));
  515 #ifdef JPILOT_DEBUG
  516             printf("todo note [%s]\n", note);
  517 #endif
  518 
  519             new_todo.indefinite = indefinite;
  520             memset(&(new_todo.due), 0, sizeof(new_todo.due));
  521             new_todo.due.tm_year = year - 1900;
  522             new_todo.due.tm_mon = month - 1;
  523             new_todo.due.tm_mday = day;
  524             new_todo.priority = priority;
  525             new_todo.complete = completed;
  526             new_todo.description = description;
  527             new_todo.note = note;
  528 
  529             todo_to_text(&new_todo, text, sizeof(text));
  530             if (!import_all) {
  531                 ret = import_record_ask(parent_window, pane,
  532                                         text,
  533                                         &(todo_app_info.category),
  534                                         old_cat_name,
  535                                         priv,
  536                                         suggested_cat_num,
  537                                         &new_cat_num);
  538             } else {
  539                 new_cat_num = suggested_cat_num;
  540             }
  541             if (ret == DIALOG_SAID_IMPORT_QUIT) break;
  542             if (ret == DIALOG_SAID_IMPORT_SKIP) continue;
  543             if (ret == DIALOG_SAID_IMPORT_ALL) import_all = TRUE;
  544 
  545             attrib = (unsigned char) ((new_cat_num & 0x0F) | (priv ? dlpRecAttrSecret : 0));
  546             if ((ret == DIALOG_SAID_IMPORT_YES) || (import_all)) {
  547                 pc_todo_write(&new_todo, NEW_PC_REC, attrib, NULL);
  548             }
  549         }
  550     }
  551 
  552     /* Palm Desktop DAT format */
  553     if (type == IMPORT_TYPE_DAT) {
  554         jp_logf(JP_LOG_DEBUG, "Todo import DAT [%s]\n", file_path);
  555         if (dat_check_if_dat_file(in) != DAT_TODO_FILE) {
  556             jp_logf(JP_LOG_WARN, _("File doesn't appear to be todo.dat format\n"));
  557             fclose(in);
  558             return EXIT_FAILURE;
  559         }
  560         todolist = NULL;
  561         dat_get_todos(in, &todolist, &cai);
  562         import_all = FALSE;
  563         for (temp_todolist = todolist; temp_todolist; temp_todolist = temp_todolist->next) {
  564             index = temp_todolist->mtodo.unique_id - 1;
  565             if (index < 0) {
  566                 g_strlcpy(old_cat_name, _("Unfiled"), 16);
  567                 index = 0;
  568             } else {
  569                 g_strlcpy(old_cat_name, cai.name[index], 16);
  570             }
  571             /* Figure out what category it was in the dat file */
  572             index = temp_todolist->mtodo.unique_id - 1;
  573             suggested_cat_num = 0;
  574             if (index > -1) {
  575                 for (i = 0; i < NUM_TODO_CAT_ITEMS; i++) {
  576                     if (todo_app_info.category.name[i][0] == '\0') continue;
  577                     if (!strcmp(todo_app_info.category.name[i], old_cat_name)) {
  578                         suggested_cat_num = i;
  579                         break;
  580                     }
  581                 }
  582             }
  583 
  584             ret = 0;
  585             todo_to_text(&(temp_todolist->mtodo.todo), text, sizeof(text));
  586             if (!import_all) {
  587                 ret = import_record_ask(parent_window, pane,
  588                                         text,
  589                                         &(todo_app_info.category),
  590                                         old_cat_name,
  591                                         (temp_todolist->mtodo.attrib & 0x10),
  592                                         suggested_cat_num,
  593                                         &new_cat_num);
  594             } else {
  595                 new_cat_num = suggested_cat_num;
  596             }
  597             if (ret == DIALOG_SAID_IMPORT_QUIT) break;
  598             if (ret == DIALOG_SAID_IMPORT_SKIP) continue;
  599             if (ret == DIALOG_SAID_IMPORT_ALL) import_all = TRUE;
  600 
  601             attrib = (unsigned char) ((new_cat_num & 0x0F) |
  602                                       ((temp_todolist->mtodo.attrib & 0x10) ? dlpRecAttrSecret : 0));
  603             if ((ret == DIALOG_SAID_IMPORT_YES) || (import_all)) {
  604                 pc_todo_write(&(temp_todolist->mtodo.todo), NEW_PC_REC,
  605                               attrib, NULL);
  606             }
  607         }
  608         free_ToDoList(&todolist);
  609     }
  610 
  611     todo_refresh();
  612     fclose(in);
  613     return EXIT_SUCCESS;
  614 }
  615 
  616 int todo_import(GtkWidget *window) {
  617     char *type_desc[] = {
  618             N_("CSV (Comma Separated Values)"),
  619             N_("DAT/TDA (Palm Archive Formats)"),
  620             NULL
  621     };
  622     int type_int[] = {
  623             IMPORT_TYPE_CSV,
  624             IMPORT_TYPE_DAT,
  625             0
  626     };
  627 
  628     /* Hide ABA import of TaskDB until file format has been decoded */
  629     /* FIXME: Uncomment when support for Tasks has been added
  630     if (todo_version==1) {
  631        type_desc[1] = NULL;
  632        type_int[1] = 0;
  633     }
  634     */
  635 
  636     import_gui(window, pane, type_desc, type_int, cb_todo_import);
  637     return EXIT_SUCCESS;
  638 }
  639 /*
  640  * End Import Code
  641  */
  642 
  643 /*
  644  * Start Export code
  645  */
  646 
  647 
  648 
  649 static void cb_todo_export_ok(GtkWidget *export_window, GtkWidget *treeView,
  650                               int type, const char *filename) {
  651     MyToDo *mtodo;
  652     GList *list, *temp_list;
  653     FILE *out;
  654     struct stat statb;
  655     int i, r;
  656     const char *short_date = NULL;
  657     time_t ltime;
  658     struct tm *now = NULL;
  659     char *button_text[] = {N_("OK")};
  660     char *button_overwrite_text[] = {N_("No"), N_("Yes")};
  661     char text[1024];
  662     char date_string[1024];
  663     char str1[256], str2[256];
  664     char pref_time[40];
  665     char csv_text[65550];
  666     char *p;
  667     gchar *end;
  668     char username[256];
  669     char hostname[256];
  670     const char *svalue;
  671     long userid = -1;
  672     long char_set;
  673     char *utf;
  674 
  675     /* Open file for export, including corner cases where file exists or
  676      * can't be opened */
  677     if (!stat(filename, &statb)) {
  678         if (S_ISDIR(statb.st_mode)) {
  679             g_snprintf(text, sizeof(text), _("%s is a directory"), filename);
  680             dialog_generic(GTK_WINDOW(export_window),
  681                            _("Error Opening File"),
  682                            DIALOG_ERROR, text, 1, button_text);
  683             return;
  684         }
  685         g_snprintf(text, sizeof(text), _("Do you want to overwrite file %s?"), filename);
  686         r = dialog_generic(GTK_WINDOW(export_window),
  687                            _("Overwrite File?"),
  688                            DIALOG_QUESTION, text, 2, button_overwrite_text);
  689         if (r != DIALOG_SAID_2) {
  690             return;
  691         }
  692     }
  693 
  694     out = fopen(filename, "w");
  695     if (!out) {
  696         g_snprintf(text, sizeof(text), _("Error opening file: %s"), filename);
  697         dialog_generic(GTK_WINDOW(export_window),
  698                        _("Error Opening File"),
  699                        DIALOG_ERROR, text, 1, button_text);
  700         return;
  701     }
  702 
  703     /* Write a header for TEXT file */
  704     if (type == EXPORT_TYPE_TEXT) {
  705         get_pref(PREF_SHORTDATE, NULL, &short_date);
  706         get_pref_time_no_secs(pref_time);
  707         time(&ltime);
  708         now = localtime(&ltime);
  709         strftime(str1, sizeof(str1), short_date, now);
  710         strftime(str2, sizeof(str2), pref_time, now);
  711         g_snprintf(date_string, sizeof(date_string), "%s %s", str1, str2);
  712         fprintf(out, _("ToDo exported from %s %s on %s\n\n"),
  713                 PN, VERSION, date_string);
  714     }
  715 
  716     /* Write a header to the CSV file */
  717     if (type == EXPORT_TYPE_CSV) {
  718         fprintf(out,
  719                 "CSV todo version "VERSION": Category, Private, Indefinite, Due Date, Priority, Completed, ToDo Text, Note\n");
  720     }
  721 
  722     /* Special setup for ICAL export */
  723     if (type == EXPORT_TYPE_ICALENDAR) {
  724         get_pref(PREF_CHAR_SET, &char_set, NULL);
  725         if (char_set < CHAR_SET_UTF) {
  726             jp_logf(JP_LOG_WARN, _("Host character encoding is not UTF-8 based.\n"
  727                                    " Exported ical file may not be standards-compliant\n"));
  728         }
  729 
  730         get_pref(PREF_USER, NULL, &svalue);
  731         /* Convert User Name stored in Palm character set */
  732         g_strlcpy(text, svalue, 128);
  733         text[127] = '\0';
  734         charset_p2j(text, 128, (int) char_set);
  735         str_to_ical_str(username, sizeof(username), text);
  736         get_pref(PREF_USER_ID, &userid, NULL);
  737         gethostname(text, sizeof(hostname));
  738         text[sizeof(hostname) - 1] = '\0';
  739         str_to_ical_str(hostname, sizeof(hostname), text);
  740         time(&ltime);
  741         now = gmtime(&ltime);
  742     }
  743 
  744     get_pref(PREF_CHAR_SET, &char_set, NULL);
  745     GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView));
  746     GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeView));
  747     list = gtk_tree_selection_get_selected_rows(selection, &model);
  748 
  749 
  750     for (i = 0, temp_list = list; temp_list; temp_list = temp_list->next, i++) {
  751         GtkTreePath *path = temp_list->data;
  752         GtkTreeIter iter;
  753         if (gtk_tree_model_get_iter(model, &iter, path)) {
  754             gtk_tree_model_get(model, &iter, TODO_DATA_COLUMN_ENUM, &mtodo, -1);
  755             if (!mtodo) {
  756                 continue;
  757                 jp_logf(JP_LOG_WARN, _("Can't export todo %d\n"), (long) temp_list->data + 1);
  758             }
  759             switch (type) {
  760                 case EXPORT_TYPE_CSV:
  761                     utf = charset_p2newj(todo_app_info.category.name[mtodo->attrib & 0x0F], 16, (int) char_set);
  762                     str_to_csv_str(csv_text, utf);
  763                     fprintf(out, "\"%s\",", csv_text);
  764                     g_free(utf);
  765                     fprintf(out, "\"%s\",", (mtodo->attrib & dlpRecAttrSecret) ? "1" : "0");
  766                     fprintf(out, "\"%s\",", mtodo->todo.indefinite ? "1" : "0");
  767                     if (mtodo->todo.indefinite) {
  768                         fprintf(out, "\"\",");
  769                     } else {
  770                         strftime(text, sizeof(text), "%Y/%02m/%02d", &(mtodo->todo.due));
  771                         fprintf(out, "\"%s\",", text);
  772                     }
  773                     fprintf(out, "\"%d\",", mtodo->todo.priority);
  774                     fprintf(out, "\"%s\",", mtodo->todo.complete ? "1" : "0");
  775                     if (mtodo->todo.description) {
  776                         str_to_csv_str(csv_text, mtodo->todo.description);
  777                         fprintf(out, "\"%s\",", csv_text);
  778                     } else {
  779                         fprintf(out, "\"\",");
  780                     }
  781                     if (mtodo->todo.note) {
  782                         str_to_csv_str(csv_text, mtodo->todo.note);
  783                         fprintf(out, "\"%s\"\n", csv_text);
  784                     } else {
  785                         fprintf(out, "\"\",");
  786                     }
  787                     break;
  788 
  789                 case EXPORT_TYPE_TEXT:
  790                     utf = charset_p2newj(todo_app_info.category.name[mtodo->attrib & 0x0F], 16, (int) char_set);
  791                     fprintf(out, _("Category: %s\n"), utf);
  792                     g_free(utf);
  793 
  794                     fprintf(out, _("Private: %s\n"),
  795                             (mtodo->attrib & dlpRecAttrSecret) ? _("Yes") : _("No"));
  796                     if (mtodo->todo.indefinite) {
  797                         fprintf(out, _("Due Date: None\n"));
  798                     } else {
  799                         strftime(text, sizeof(text), short_date, &(mtodo->todo.due));
  800                         fprintf(out, _("Due Date: %s\n"), text);
  801                     }
  802                     fprintf(out, _("Priority: %d\n"), mtodo->todo.priority);
  803                     fprintf(out, _("Completed: %s\n"), mtodo->todo.complete ? _("Yes") : _("No"));
  804                     if (mtodo->todo.description) {
  805                         fprintf(out, _("Description: %s\n"), mtodo->todo.description);
  806                     }
  807                     if (mtodo->todo.note) {
  808                         fprintf(out, _("Note: %s\n\n"), mtodo->todo.note);
  809                     }
  810                     break;
  811 
  812                 case EXPORT_TYPE_ICALENDAR:
  813                     /* RFC 2445: Internet Calendaring and Scheduling Core
  814                      *           Object Specification */
  815                     if (i == 0) {
  816                         fprintf(out, "BEGIN:VCALENDAR"CRLF);
  817                         fprintf(out, "VERSION:2.0"CRLF);
  818                         fprintf(out, "PRODID:%s"CRLF, FPI_STRING);
  819                     }
  820                     fprintf(out, "BEGIN:VTODO"CRLF);
  821                     if (mtodo->attrib & dlpRecAttrSecret) {
  822                         fprintf(out, "CLASS:PRIVATE"CRLF);
  823                     }
  824                     fprintf(out, "UID:palm-todo-%08x-%08lx-%s@%s"CRLF,
  825                             mtodo->unique_id, userid, username, hostname);
  826                     fprintf(out, "DTSTAMP:%04d%02d%02dT%02d%02d%02dZ"CRLF,
  827                             now->tm_year + 1900,
  828                             now->tm_mon + 1,
  829                             now->tm_mday,
  830                             now->tm_hour,
  831                             now->tm_min,
  832                             now->tm_sec);
  833                     str_to_ical_str(text, sizeof(text),
  834                                     todo_app_info.category.name[mtodo->attrib & 0x0F]);
  835                     fprintf(out, "CATEGORIES:%s"CRLF, text);
  836                     if (mtodo->todo.description) {
  837                         g_strlcpy(str1, mtodo->todo.description, 51);
  838                         /* truncate the string on a UTF-8 character boundary */
  839                         if (char_set > CHAR_SET_UTF) {
  840                             if (!g_utf8_validate(str1, -1, (const gchar **) &end))
  841                                 *end = 0;
  842                         }
  843                     } else {
  844                         /* Handle pathological case with null description. */
  845                         str1[0] = '\0';
  846                     }
  847                     if ((p = strchr(str1, '\n'))) {
  848                         *p = '\0';
  849                     }
  850                     str_to_ical_str(text, sizeof(text), str1);
  851                     fprintf(out, "SUMMARY:%s%s"CRLF, text,
  852                             strlen(str1) > 49 ? "..." : "");
  853                     str_to_ical_str(text, sizeof(text), mtodo->todo.description);
  854                     fprintf(out, "DESCRIPTION:%s", text);
  855                     if (mtodo->todo.note && mtodo->todo.note[0]) {
  856                         str_to_ical_str(text, sizeof(text), mtodo->todo.note);
  857                         fprintf(out, "\\n"CRLF" %s"CRLF, text);
  858                     } else {
  859                         fprintf(out, ""CRLF);
  860                     }
  861                     fprintf(out, "STATUS:%s"CRLF, mtodo->todo.complete ? "COMPLETED" : "NEEDS-ACTION");
  862                     fprintf(out, "PRIORITY:%d"CRLF, mtodo->todo.priority);
  863                     if (!mtodo->todo.indefinite) {
  864                         fprintf(out, "DUE;VALUE=DATE:%04d%02d%02d"CRLF,
  865                                 mtodo->todo.due.tm_year + 1900,
  866                                 mtodo->todo.due.tm_mon + 1,
  867                                 mtodo->todo.due.tm_mday);
  868                     }
  869                     fprintf(out, "END:VTODO"CRLF);
  870                     if (temp_list->next == NULL) {
  871                         fprintf(out, "END:VCALENDAR"CRLF);
  872                     }
  873                     break;
  874                 default:
  875                     jp_logf(JP_LOG_WARN, _("Unknown export type\n"));
  876             }
  877         }
  878     }
  879 
  880     if (out) {
  881         fclose(out);
  882     }
  883 }
  884 
  885 static void cb_todo_update_listStore(GtkWidget *exportTreeView, int category) {
  886     if (exportTreeView == NULL || !GTK_IS_TREE_VIEW(exportTreeView)) {
  887         return;
  888     }
  889     todo_update_liststore(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(exportTreeView))), NULL,
  890                           &export_todo_list, category, FALSE);
  891 }
  892 
  893 static GtkWidget *cb_todo_init_treeView() {
  894     GtkListStore *listStore = gtk_list_store_new(TODO_NUM_COLS, G_TYPE_BOOLEAN, G_TYPE_STRING, GDK_TYPE_PIXBUF,
  895                                                  G_TYPE_STRING,
  896                                                  G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_RGBA, G_TYPE_BOOLEAN,
  897                                                  G_TYPE_STRING, G_TYPE_BOOLEAN);
  898     GtkTreeModel *model = GTK_TREE_MODEL(listStore);
  899     GtkWidget *todo_treeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
  900     GtkCellRenderer *taskRenderer = gtk_cell_renderer_text_new();
  901     // gtk_cell_renderer_set_fixed_size(taskRenderer, -1, 1);
  902 
  903     GtkTreeViewColumn *taskColumn = gtk_tree_view_column_new_with_attributes("Task",
  904                                                                              taskRenderer,
  905                                                                              "text", TODO_TEXT_COLUMN_ENUM,
  906                                                                              "cell-background-rgba",
  907                                                                              TODO_BACKGROUND_COLOR_ENUM,
  908                                                                              "cell-background-set",
  909                                                                              TODO_BACKGROUND_COLOR_ENABLED_ENUM,
  910                                                                              NULL);
  911     gtk_tree_view_column_set_sort_column_id(taskColumn, TODO_TEXT_COLUMN_ENUM);
  912 
  913 
  914     GtkCellRenderer *dateRenderer = gtk_cell_renderer_text_new();
  915     // gtk_cell_renderer_set_fixed_size(dateRenderer, -1, 1);
  916 
  917     GtkTreeViewColumn *dateColumn = gtk_tree_view_column_new_with_attributes("Due",
  918                                                                              dateRenderer,
  919                                                                              "text", TODO_DATE_COLUMN_ENUM,
  920                                                                              "cell-background-rgba",
  921                                                                              TODO_BACKGROUND_COLOR_ENUM,
  922                                                                              "cell-background-set",
  923                                                                              TODO_BACKGROUND_COLOR_ENABLED_ENUM,
  924                                                                              "foreground", TODO_FOREGROUND_COLOR_ENUM,
  925                                                                              "foreground-set",
  926                                                                              TODO_FORGROUND_COLOR_ENABLED_ENUM,
  927                                                                              NULL);
  928     gtk_tree_view_column_set_sort_column_id(dateColumn, TODO_DATE_COLUMN_ENUM);
  929 
  930     GtkCellRenderer *priorityRenderer = gtk_cell_renderer_text_new();
  931     // gtk_cell_renderer_set_fixed_size(priorityRenderer, -1, 1);
  932     GtkTreeViewColumn *priorityColumn = gtk_tree_view_column_new_with_attributes("",
  933                                                                                  priorityRenderer,
  934                                                                                  "text", TODO_PRIORITY_COLUMN_ENUM,
  935                                                                                  "cell-background-rgba",
  936                                                                                  TODO_BACKGROUND_COLOR_ENUM,
  937                                                                                  "cell-background-set",
  938                                                                                  TODO_BACKGROUND_COLOR_ENABLED_ENUM,
  939                                                                                  NULL);
  940     gtk_tree_view_column_set_sort_column_id(priorityColumn, TODO_PRIORITY_COLUMN_ENUM);
  941 
  942     GtkCellRenderer *noteRenderer = gtk_cell_renderer_pixbuf_new();
  943     GtkTreeViewColumn *noteColumn = gtk_tree_view_column_new_with_attributes("",
  944                                                                              noteRenderer,
  945                                                                              "pixbuf", TODO_NOTE_COLUMN_ENUM,
  946                                                                              "cell-background-rgba",
  947                                                                              TODO_BACKGROUND_COLOR_ENUM,
  948                                                                              "cell-background-set",
  949                                                                              TODO_BACKGROUND_COLOR_ENABLED_ENUM,
  950                                                                              NULL);
  951     gtk_tree_view_column_set_sort_column_id(noteColumn, TODO_NOTE_COLUMN_ENUM);
  952 
  953 
  954     GtkCellRenderer *checkRenderer = gtk_cell_renderer_toggle_new();
  955 
  956     GtkTreeViewColumn *checkColumn = gtk_tree_view_column_new_with_attributes("", checkRenderer, "active",
  957                                                                               TODO_CHECK_COLUMN_ENUM,
  958                                                                               "cell-background-rgba",
  959                                                                               TODO_BACKGROUND_COLOR_ENUM,
  960                                                                               "cell-background-set",
  961                                                                               TODO_BACKGROUND_COLOR_ENABLED_ENUM, NULL);
  962     gtk_tree_view_insert_column(GTK_TREE_VIEW (todo_treeView), checkColumn, TODO_CHECK_COLUMN_ENUM);
  963     gtk_tree_view_insert_column(GTK_TREE_VIEW (todo_treeView), priorityColumn, TODO_PRIORITY_COLUMN_ENUM);
  964     gtk_tree_view_insert_column(GTK_TREE_VIEW (todo_treeView), noteColumn, TODO_NOTE_COLUMN_ENUM);
  965     gtk_tree_view_insert_column(GTK_TREE_VIEW (todo_treeView), dateColumn, TODO_DATE_COLUMN_ENUM);
  966     gtk_tree_view_insert_column(GTK_TREE_VIEW (todo_treeView), taskColumn, TODO_TEXT_COLUMN_ENUM);
  967     gtk_tree_view_column_set_clickable(checkColumn, gtk_false());
  968     gtk_tree_view_column_set_clickable(priorityColumn, gtk_false());
  969     gtk_tree_view_column_set_clickable(noteColumn, gtk_false());
  970     gtk_tree_view_column_set_clickable(dateColumn, gtk_false());
  971     gtk_tree_view_column_set_clickable(taskColumn, gtk_false());
  972     gtk_tree_view_column_set_sizing(checkColumn, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
  973     gtk_tree_view_column_set_sizing(dateColumn, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
  974     gtk_tree_view_column_set_sizing(priorityColumn, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
  975     gtk_tree_view_column_set_sizing(noteColumn, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
  976     gtk_tree_view_column_set_sizing(taskColumn, GTK_TREE_VIEW_COLUMN_FIXED);
  977     return GTK_WIDGET(todo_treeView);
  978 }
  979 
  980 static void cb_todo_export_done(GtkWidget *widget, const char *filename) {
  981     free_ToDoList(&export_todo_list);
  982     if (widget != NULL && GTK_IS_TREE_VIEW(widget)) {
  983         gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(widget))));
  984     }
  985 
  986     set_pref(PREF_TODO_EXPORT_FILENAME, 0, filename, TRUE);
  987 }
  988 
  989 int todo_export(GtkWidget *window) {
  990     int w, h, x, y;
  991     char *type_text[] = {N_("Text"),
  992                          N_("CSV"),
  993                          N_("iCalendar"),
  994                          NULL};
  995     int type_int[] = {EXPORT_TYPE_TEXT, EXPORT_TYPE_CSV, EXPORT_TYPE_ICALENDAR};
  996 
  997     w = gdk_window_get_width(gtk_widget_get_window(window));
  998     h = gdk_window_get_height(gtk_widget_get_window(window));
  999     gdk_window_get_root_origin(gtk_widget_get_window(window), &x, &y);
 1000 
 1001     w = gtk_paned_get_position(GTK_PANED(pane));
 1002     x += 40;
 1003 
 1004     export_gui(window,
 1005                w, h, x, y, 5, sort_l,
 1006                PREF_TODO_EXPORT_FILENAME,
 1007                type_text,
 1008                type_int,
 1009                cb_todo_init_treeView,
 1010                cb_todo_update_listStore,
 1011                cb_todo_export_done,
 1012                cb_todo_export_ok
 1013     );
 1014 
 1015     return EXIT_SUCCESS;
 1016 }
 1017 
 1018 /*
 1019  * End Export Code
 1020  */
 1021 
 1022 
 1023 /* Find position of category in sorted category array 
 1024  * via its assigned category number */
 1025 static int find_sort_cat_pos(int cat) {
 1026     int i;
 1027 
 1028     for (i = 0; i < NUM_TODO_CAT_ITEMS; i++) {
 1029         if (sort_l[i].cat_num == cat) {
 1030             return i;
 1031         }
 1032     }
 1033 
 1034     return -1;
 1035 }
 1036 
 1037 /* Find a category's position in the category menu.
 1038  * This is equal to the category number except for the Unfiled category.
 1039  * The Unfiled category is always in the last position which changes as
 1040  * the number of categories changes */
 1041 static int find_menu_cat_pos(int cat) {
 1042     int i;
 1043 
 1044     if (cat != NUM_TODO_CAT_ITEMS - 1) {
 1045         return cat;
 1046     } else { /* Unfiled category */
 1047         /* Count how many category entries are filled */
 1048         for (i = 0; i < NUM_TODO_CAT_ITEMS; i++) {
 1049             if (!sort_l[i].Pcat[0]) {
 1050                 return i;
 1051             }
 1052         }
 1053         return 0;
 1054     }
 1055 }
 1056 
 1057 gboolean deleteRecord(GtkTreeModel *model,
 1058                       GtkTreePath *path,
 1059                       GtkTreeIter *iter,
 1060                       gpointer data) {
 1061     int *i = gtk_tree_path_get_indices(path);
 1062     if (i[0] == row_selected) {
 1063         MyToDo *mytodo = NULL;
 1064         gtk_tree_model_get(model, iter, TODO_DATA_COLUMN_ENUM, &mytodo, -1);
 1065         deleteTodo(mytodo, data);
 1066         return TRUE;
 1067     }
 1068 
 1069     return FALSE;
 1070 
 1071 
 1072 }
 1073 
 1074 void deleteTodo(MyToDo *mtodo, gpointer data) {
 1075 
 1076     int flag;
 1077     int show_priv;
 1078     long char_set;
 1079 
 1080     if (mtodo < (MyToDo *) LIST_MIN_DATA) {
 1081         return;
 1082     }
 1083 
 1084     /* Convert to Palm character set */
 1085     get_pref(PREF_CHAR_SET, &char_set, NULL);
 1086     if (char_set != CHAR_SET_LATIN1) {
 1087         if (mtodo->todo.description)
 1088             charset_j2p(mtodo->todo.description, (int) strlen(mtodo->todo.description) + 1, char_set);
 1089         if (mtodo->todo.note)
 1090             charset_j2p(mtodo->todo.note, (int) strlen(mtodo->todo.note) + 1, char_set);
 1091     }
 1092 
 1093     /* Do masking like Palm OS 3.5 */
 1094     show_priv = show_privates(GET_PRIVATES);
 1095     if ((show_priv != SHOW_PRIVATES) &&
 1096         (mtodo->attrib & dlpRecAttrSecret)) {
 1097         return;
 1098     }
 1099     /* End Masking */
 1100     flag = GPOINTER_TO_INT(data);
 1101     if ((flag == MODIFY_FLAG) || (flag == DELETE_FLAG)) {
 1102         jp_logf(JP_LOG_DEBUG, "calling delete_pc_record\n");
 1103         delete_pc_record(TODO, mtodo, flag);
 1104         if (flag == DELETE_FLAG) {
 1105             /* when we redraw we want to go to the line above the deleted one */
 1106             if (row_selected > 0) {
 1107                 row_selected--;
 1108             }
 1109         }
 1110     }
 1111 
 1112     if (flag == DELETE_FLAG) {
 1113         todo_redraw();
 1114     }
 1115 }
 1116 
 1117 static void cb_delete_todo(GtkWidget *widget,
 1118                            gpointer data) {
 1119     gtk_tree_model_foreach(GTK_TREE_MODEL(listStore), deleteRecord, data);
 1120     return;
 1121 
 1122 }
 1123 
 1124 gboolean undeleteRecord(GtkTreeModel *model,
 1125                         GtkTreePath *path,
 1126                         GtkTreeIter *iter,
 1127                         gpointer data) {
 1128     int *i = gtk_tree_path_get_indices(path);
 1129     if (i[0] == row_selected) {
 1130         MyToDo *mytodo = NULL;
 1131         gtk_tree_model_get(model, iter, TODO_DATA_COLUMN_ENUM, &mytodo, -1);
 1132         undeleteTodo(mytodo, data);
 1133         return TRUE;
 1134     }
 1135 
 1136     return FALSE;
 1137 
 1138 
 1139 }
 1140 
 1141 gboolean printRecord(GtkTreeModel *model,
 1142                      GtkTreePath *path,
 1143                      GtkTreeIter *iter,
 1144                      gpointer data) {
 1145     int *i = gtk_tree_path_get_indices(path);
 1146     if (i[0] == row_selected) {
 1147         MyToDo *mytodo = NULL;
 1148         gtk_tree_model_get(model, iter, TODO_DATA_COLUMN_ENUM, &mytodo, -1);
 1149         printTodo(mytodo, data);
 1150         return TRUE;
 1151     }
 1152 
 1153     return FALSE;
 1154 
 1155 
 1156 }
 1157 
 1158 void undeleteTodo(MyToDo *mtodo, gpointer data) {
 1159     int flag;
 1160     int show_priv;
 1161     if (mtodo < (MyToDo *) LIST_MIN_DATA) {
 1162         return;
 1163     }
 1164 
 1165     /* Do masking like Palm OS 3.5 */
 1166     show_priv = show_privates(GET_PRIVATES);
 1167     if ((show_priv != SHOW_PRIVATES) &&
 1168         (mtodo->attrib & dlpRecAttrSecret)) {
 1169         return;
 1170     }
 1171     /* End Masking */
 1172 
 1173     jp_logf(JP_LOG_DEBUG, "mtodo->unique_id = %d\n", mtodo->unique_id);
 1174     jp_logf(JP_LOG_DEBUG, "mtodo->rt = %d\n", mtodo->rt);
 1175 
 1176     flag = GPOINTER_TO_INT(data);
 1177     if (flag == UNDELETE_FLAG) {
 1178         if (mtodo->rt == DELETED_PALM_REC ||
 1179             mtodo->rt == DELETED_PC_REC) {
 1180             undelete_pc_record(TODO, mtodo, flag);
 1181         }
 1182         /* Possible later addition of undelete for modified records
 1183         else if (mtodo->rt == MODIFIED_PALM_REC)
 1184         {
 1185            cb_add_new_record(widget, GINT_TO_POINTER(COPY_FLAG));
 1186         }
 1187         */
 1188     }
 1189 
 1190     todo_redraw();
 1191 }
 1192 
 1193 static void cb_undelete_todo(GtkWidget *widget,
 1194                              gpointer data) {
 1195 
 1196     gtk_tree_model_foreach(GTK_TREE_MODEL(listStore), undeleteRecord, data);
 1197     return;
 1198 
 1199 }
 1200 
 1201 static void cb_cancel(GtkWidget *widget, gpointer data) {
 1202     set_new_button_to(CLEAR_FLAG);
 1203     todo_refresh();
 1204 }
 1205 
 1206 static void cb_edit_cats(GtkWidget *widget, gpointer data) {
 1207     struct ToDoAppInfo ai;
 1208     char db_name[FILENAME_MAX];
 1209     char pdb_name[FILENAME_MAX];
 1210     char full_name[FILENAME_MAX];
 1211     unsigned char buffer[65536];
 1212     int num;
 1213     size_t size;
 1214     void *buf;
 1215     struct pi_file *pf;
 1216 #ifdef ENABLE_MANANA
 1217     long ivalue;
 1218 #endif
 1219 
 1220     jp_logf(JP_LOG_DEBUG, "cb_edit_cats\n");
 1221 
 1222 #ifdef ENABLE_MANANA
 1223     get_pref(PREF_MANANA_MODE, &ivalue, NULL);
 1224     if (ivalue) {
 1225         strcpy(pdb_name, "MananaDB.pdb");
 1226         strcpy(db_name, "MananaDB");
 1227     } else {
 1228         strcpy(pdb_name, "ToDoDB.pdb");
 1229         strcpy(db_name, "ToDoDB");
 1230     }
 1231 #else
 1232     strcpy(pdb_name, "ToDoDB.pdb");
 1233     strcpy(db_name, "ToDoDB");
 1234 #endif
 1235 
 1236     get_home_file_name(pdb_name, full_name, sizeof(full_name));
 1237 
 1238     buf = NULL;
 1239     memset(&ai, 0, sizeof(ai));
 1240 
 1241     pf = pi_file_open(full_name);
 1242     pi_file_get_app_info(pf, &buf, &size);
 1243 
 1244     num = unpack_ToDoAppInfo(&ai, buf, size);
 1245     if (num <= 0) {
 1246         jp_logf(JP_LOG_WARN, _("Error reading file: %s\n"), pdb_name);
 1247         return;
 1248     }
 1249 
 1250     pi_file_close(pf);
 1251 
 1252     edit_cats(widget, db_name, &(ai.category));
 1253 
 1254     size = (size_t) pack_ToDoAppInfo(&ai, buffer, sizeof(buffer));
 1255 
 1256     pdb_file_write_app_block(db_name, buffer, (int) size);
 1257 
 1258     cb_app_button(NULL, GINT_TO_POINTER(REDRAW));
 1259 }
 1260 
 1261 static void cb_category(GtkComboBox *item, int selection) {
 1262     int b;
 1263     if (!item) return;
 1264     if (gtk_combo_box_get_active(GTK_COMBO_BOX(item)) < 0) {
 1265         return;
 1266     }
 1267     int selectedItem = get_selected_category_from_combo_box(item);
 1268     if (selectedItem == -1) {
 1269         return;
 1270     }
 1271 
 1272     if (todo_category == selectedItem) { return; }
 1273 
 1274     b = dialog_save_changed_record_with_cancel(pane, record_changed);
 1275     if (b == DIALOG_SAID_1) { /* Cancel */
 1276         int index, index2;
 1277 
 1278         if (todo_category == CATEGORY_ALL) {
 1279             index = 0;
 1280             index2 = 0;
 1281         } else {
 1282             index = find_sort_cat_pos(todo_category);
 1283             index2 = find_menu_cat_pos(index) + 1;
 1284             index += 1;
 1285         }
 1286 
 1287         if (index < 0) {
 1288             jp_logf(JP_LOG_WARN, _("Category is not legal\n"));
 1289         } else {
 1290             gtk_combo_box_set_active(GTK_COMBO_BOX(category_menu1), index2);
 1291         }
 1292 
 1293         return;
 1294     }
 1295     if (b == DIALOG_SAID_3) { /* Save */
 1296         cb_add_new_record(NULL, GINT_TO_POINTER(record_changed));
 1297     }
 1298 
 1299     if (selectedItem == CATEGORY_EDIT) {
 1300         cb_edit_cats(GTK_WIDGET(item), NULL);
 1301     } else {
 1302         todo_category = selectedItem;
 1303     }
 1304     row_selected = 0;
 1305     jp_logf(JP_LOG_DEBUG, "todo_category = %d\n", todo_category);
 1306     todo_update_liststore(listStore, category_menu1, &glob_todo_list, todo_category, TRUE);
 1307 }
 1308 
 1309 static void cb_check_button_no_due_date(GtkWidget *widget, gpointer data) {
 1310     long till_due;
 1311     struct tm *now;
 1312     time_t ltime;
 1313 
 1314     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
 1315         update_due_button(due_date_button, NULL);
 1316     } else {
 1317         time(&ltime);
 1318         now = localtime(&ltime);
 1319         memcpy(&due_date, now, sizeof(struct tm));
 1320 
 1321         get_pref(PREF_TODO_DAYS_TILL_DUE, &till_due, NULL);
 1322         add_days_to_date(&due_date, (int) till_due);
 1323 
 1324         update_due_button(due_date_button, &due_date);
 1325     }
 1326 }
 1327 
 1328 static int todo_clear_details(void) {
 1329     time_t ltime;
 1330     struct tm *now;
 1331     int new_cat;
 1332     int sorted_position;
 1333     long default_due, till_due;
 1334 
 1335     time(&ltime);
 1336     now = localtime(&ltime);
 1337 
 1338     /* Need to disconnect these signals first */
 1339     connect_changed_signals(DISCONNECT_SIGNALS);
 1340 
 1341     gtk_widget_freeze_child_notify(todo_desc);
 1342     gtk_widget_freeze_child_notify(todo_note);
 1343 
 1344     gtk_text_buffer_set_text(GTK_TEXT_BUFFER(todo_desc_buffer), "", -1);
 1345     gtk_text_buffer_set_text(GTK_TEXT_BUFFER(todo_note_buffer), "", -1);
 1346 
 1347     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button_todo[0]), TRUE);
 1348 
 1349     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(todo_completed_checkbox), FALSE);
 1350 
 1351     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(private_checkbox), FALSE);
 1352 
 1353     get_pref(PREF_TODO_DAYS_DUE, &default_due, NULL);
 1354     get_pref(PREF_TODO_DAYS_TILL_DUE, &till_due, NULL);
 1355     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(todo_no_due_date_checkbox),
 1356                                  !default_due);
 1357 
 1358     memcpy(&due_date, now, sizeof(struct tm));
 1359 
 1360     if (default_due) {
 1361         add_days_to_date(&due_date, (int) till_due);
 1362         update_due_button(due_date_button, &due_date);
 1363     } else {
 1364         update_due_button(due_date_button, NULL);
 1365     }
 1366 
 1367     gtk_widget_thaw_child_notify(todo_desc);
 1368     gtk_widget_thaw_child_notify(todo_note);
 1369 
 1370     if (todo_category == CATEGORY_ALL) {
 1371         new_cat = 0;
 1372     } else {
 1373         new_cat = todo_category;
 1374     }
 1375     sorted_position = find_sort_cat_pos(new_cat);
 1376     if (sorted_position < 0) {
 1377         jp_logf(JP_LOG_WARN, _("Category is not legal\n"));
 1378     } else {
 1379         gtk_combo_box_set_active(GTK_COMBO_BOX(category_menu2), find_menu_cat_pos(sorted_position));
 1380     }
 1381 
 1382     set_new_button_to(CLEAR_FLAG);
 1383     connect_changed_signals(CONNECT_SIGNALS);
 1384 
 1385     return EXIT_SUCCESS;
 1386 }
 1387 
 1388 static int todo_get_details(struct ToDo *new_todo, unsigned char *attrib) {
 1389     int i;
 1390     GtkTextIter start_iter;
 1391     GtkTextIter end_iter;
 1392 
 1393     new_todo->indefinite = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(todo_no_due_date_checkbox)));
 1394     if (!(new_todo->indefinite)) {
 1395         new_todo->due.tm_mon = due_date.tm_mon;
 1396         new_todo->due.tm_mday = due_date.tm_mday;
 1397         new_todo->due.tm_year = due_date.tm_year;
 1398         jp_logf(JP_LOG_DEBUG, "todo_get_details: setting due date=%d/%d/%d\n", new_todo->due.tm_mon,
 1399                 new_todo->due.tm_mday, new_todo->due.tm_year);
 1400     } else {
 1401         memset(&(new_todo->due), 0, sizeof(new_todo->due));
 1402     }
 1403     new_todo->priority = 1;
 1404     for (i = 0; i < NUM_TODO_PRIORITIES; i++) {
 1405         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_button_todo[i]))) {
 1406             new_todo->priority = i + 1;
 1407             break;
 1408         }
 1409     }
 1410     new_todo->complete = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(todo_completed_checkbox)));
 1411     /* Can there be an entry with no description? */
 1412     /* Yes, but the Palm Pilot gui doesn't allow it to be entered on the Palm, */
 1413     /* it will show it though.  I allow it. */
 1414     gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(todo_desc_buffer),
 1415                                &start_iter, &end_iter);
 1416     new_todo->description = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(todo_desc_buffer),
 1417                                                      &start_iter, &end_iter, TRUE);
 1418     gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(todo_note_buffer),
 1419                                &start_iter, &end_iter);
 1420     new_todo->note = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(todo_note_buffer),
 1421                                               &start_iter, &end_iter, TRUE);
 1422     if (new_todo->note[0] == '\0') {
 1423         free(new_todo->note);
 1424         new_todo->note = NULL;
 1425     }
 1426 
 1427     if (GTK_IS_WIDGET(category_menu2)) {
 1428         *attrib = get_selected_category_from_combo_box(GTK_COMBO_BOX(category_menu2));
 1429     }
 1430     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(private_checkbox))) {
 1431         *attrib |= dlpRecAttrSecret;
 1432     }
 1433 
 1434 #ifdef JPILOT_DEBUG
 1435     jp_logf(JP_LOG_DEBUG, "attrib = %d\n", *attrib);
 1436     jp_logf(JP_LOG_DEBUG, "indefinite=%d\n",new_todo->indefinite);
 1437     if (!new_todo->indefinite) {
 1438        jp_logf(JP_LOG_DEBUG, "due: %d/%d/%d\n",new_todo->due.tm_mon,
 1439                new_todo->due.tm_mday,
 1440                new_todo->due.tm_year);
 1441     }
 1442     jp_logf(JP_LOG_DEBUG, "priority=%d\n",new_todo->priority);
 1443     jp_logf(JP_LOG_DEBUG, "complete=%d\n",new_todo->complete);
 1444     jp_logf(JP_LOG_DEBUG, "description=[%s]\n",new_todo->description);
 1445     jp_logf(JP_LOG_DEBUG, "note=[%s]\n",new_todo->note);
 1446 #endif
 1447 
 1448     return EXIT_SUCCESS;
 1449 }
 1450 
 1451 gboolean
 1452 addNewRecord(GtkTreeModel *model,
 1453              GtkTreePath *path,
 1454              GtkTreeIter *iter,
 1455              gpointer data) {
 1456 
 1457     int *i = gtk_tree_path_get_indices(path);
 1458     if (i[0] == row_selected) {
 1459         MyToDo *mytodo = NULL;
 1460         gtk_tree_model_get(model, iter, TODO_DATA_COLUMN_ENUM, &mytodo, -1);
 1461         addNewRecordToDataStructure(mytodo, data);
 1462         return TRUE;
 1463     }
 1464     return FALSE;
 1465 
 1466 
 1467 }
 1468 
 1469 void addNewRecordToDataStructure(MyToDo *mtodo, gpointer data) {
 1470 
 1471     struct ToDo new_todo;
 1472     unsigned char attrib = 0;
 1473     int flag;
 1474     int show_priv;
 1475     unsigned int unique_id;
 1476     flag = GPOINTER_TO_INT(data);
 1477     unique_id = 0;
 1478 
 1479 
 1480     //while(gtk_tree_path_)
 1481     /* Do masking like Palm OS 3.5 */
 1482     if ((flag == COPY_FLAG) || (flag == MODIFY_FLAG)) {
 1483         show_priv = show_privates(GET_PRIVATES);
 1484         if (mtodo < (MyToDo *) LIST_MIN_DATA) {
 1485             return;
 1486         }
 1487         if ((show_priv != SHOW_PRIVATES) &&
 1488             (mtodo->attrib & dlpRecAttrSecret)) {
 1489             return;
 1490         }
 1491     }
 1492     /* End Masking */
 1493     if (flag == CLEAR_FLAG) {
 1494         /* Clear button was hit */
 1495         todo_clear_details();
 1496         connect_changed_signals(DISCONNECT_SIGNALS);
 1497         set_new_button_to(NEW_FLAG);
 1498         gtk_widget_grab_focus(GTK_WIDGET(todo_desc));
 1499         return;
 1500     }
 1501     if ((flag != NEW_FLAG) && (flag != MODIFY_FLAG) && (flag != COPY_FLAG)) {
 1502         return;
 1503     }
 1504     if (flag == MODIFY_FLAG) {
 1505 
 1506         unique_id = mtodo->unique_id;
 1507         if (mtodo < (MyToDo *) LIST_MIN_DATA) {
 1508             return;
 1509         }
 1510         if ((mtodo->rt == DELETED_PALM_REC) ||
 1511             (mtodo->rt == DELETED_PC_REC) ||
 1512             (mtodo->rt == MODIFIED_PALM_REC)) {
 1513             jp_logf(JP_LOG_INFO, _("You can't modify a record that is deleted\n"));
 1514             return;
 1515         }
 1516     }
 1517     todo_get_details(&new_todo, &attrib);
 1518 
 1519     set_new_button_to(CLEAR_FLAG);
 1520 
 1521     if (flag == MODIFY_FLAG) {
 1522         cb_delete_todo(NULL, data);
 1523         if ((mtodo->rt == PALM_REC) || (mtodo->rt == REPLACEMENT_PALM_REC)) {
 1524             pc_todo_write(&new_todo, REPLACEMENT_PALM_REC, attrib, &unique_id);
 1525         } else {
 1526             unique_id = 0;
 1527             pc_todo_write(&new_todo, NEW_PC_REC, attrib, &unique_id);
 1528         }
 1529     } else {
 1530         unique_id = 0;
 1531         pc_todo_write(&new_todo, NEW_PC_REC, attrib, &unique_id);
 1532     }
 1533     free_ToDo(&new_todo);
 1534 
 1535     /* Don't return to modified record if search gui active */
 1536     if (!glob_find_id) {
 1537         glob_find_id = unique_id;
 1538     }
 1539     todo_redraw();
 1540 
 1541 
 1542     return;
 1543 }
 1544 
 1545 static void cb_add_new_record(GtkWidget *widget, gpointer data) {
 1546     if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(listStore), NULL) != 0) {
 1547         gtk_tree_model_foreach(GTK_TREE_MODEL(listStore), addNewRecord, data);
 1548     } else {
 1549         //no records exist in category yet.
 1550         addNewRecordToDataStructure(NULL, data);
 1551     }
 1552 }
 1553 
 1554 /* Do masking like Palm OS 3.5 */
 1555 static void clear_mytodos(MyToDo *mtodo) {
 1556     mtodo->unique_id = 0;
 1557     mtodo->attrib = (unsigned char) (mtodo->attrib & 0xF8);
 1558     mtodo->todo.complete = 0;
 1559     mtodo->todo.priority = 1;
 1560     mtodo->todo.indefinite = 1;
 1561     if (mtodo->todo.description) {
 1562         free(mtodo->todo.description);
 1563         mtodo->todo.description = strdup("");
 1564     }
 1565     if (mtodo->todo.note) {
 1566         free(mtodo->todo.note);
 1567         mtodo->todo.note = strdup("");
 1568     }
 1569 
 1570     return;
 1571 }
 1572 
 1573 /* End Masking */
 1574 
 1575 
 1576 static gint sortNoteColumn(GtkTreeModel *model,
 1577                            GtkTreeIter *left,
 1578                            GtkTreeIter *right,
 1579                            gpointer columnId) {
 1580     gint sortcol = GPOINTER_TO_INT(columnId);
 1581     gint ret = 0;
 1582     switch (sortcol) {
 1583         case TODO_NOTE_COLUMN_ENUM: {
 1584             ret = compareNoteColumn(model, left, right);
 1585         }
 1586             break;
 1587         default:
 1588             break;
 1589     }
 1590     return ret;
 1591 
 1592 }
 1593 
 1594 gint compareCheckColumn(GtkTreeModel *model, GtkTreeIter *left, GtkTreeIter *right) {
 1595     gint ret;
 1596     gboolean *name1, *name2;
 1597 
 1598     gtk_tree_model_get(GTK_TREE_MODEL(model), left, TODO_CHECK_COLUMN_ENUM, &name1, -1);
 1599     gtk_tree_model_get(GTK_TREE_MODEL(model), right, TODO_CHECK_COLUMN_ENUM, &name2, -1);
 1600     if (!name1 && name2) {
 1601         ret = 1;
 1602     } else if (name1 && !name2) {
 1603         ret = -1;
 1604     } else {
 1605         ret = 0;
 1606     }
 1607     return ret;
 1608 }
 1609 
 1610 gint compareNoteColumn(GtkTreeModel *model, GtkTreeIter *left, GtkTreeIter *right) {
 1611     gint ret;
 1612     GdkPixbuf *note1, *note2;
 1613 
 1614     gtk_tree_model_get(GTK_TREE_MODEL(model), left, TODO_NOTE_COLUMN_ENUM, &note1, -1);
 1615     gtk_tree_model_get(GTK_TREE_MODEL(model), right, TODO_NOTE_COLUMN_ENUM, &note2, -1);
 1616 
 1617     if (note1 == NULL && note2 == NULL) {
 1618         ret = 0;
 1619     } else if (note1 == NULL && note2 != NULL) {
 1620         ret = -1;
 1621     } else if (note1 != NULL && note2 == NULL) {
 1622         ret = 1;
 1623     } else {
 1624         ret = 0;
 1625     }
 1626     return ret;
 1627 }
 1628 
 1629 
 1630 static void column_clicked_cb(GtkTreeViewColumn *column) {
 1631     column_selected = gtk_tree_view_column_get_sort_column_id(column);
 1632 
 1633 }
 1634 
 1635 static void checkedCallBack(GtkCellRendererToggle *renderer, gchar *path, GtkListStore *model) {
 1636     GtkTreeIter iter;
 1637     gboolean active;
 1638     MyToDo *mtodo;
 1639     active = gtk_cell_renderer_toggle_get_active(renderer);
 1640 
 1641     gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL (model), &iter, path);
 1642     gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, TODO_DATA_COLUMN_ENUM, &mtodo, -1);
 1643     if (active) {
 1644         // gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), 0, 0);
 1645         gtk_list_store_set(GTK_LIST_STORE (model), &iter, TODO_CHECK_COLUMN_ENUM, FALSE, -1);
 1646         mtodo->todo.complete = 0;
 1647     } else {
 1648         // gtk_cell_renderer_set_alignment(GTK_CELL_RENDERER(renderer), 0.5, 0.5);
 1649         gtk_list_store_set(GTK_LIST_STORE (model), &iter, TODO_CHECK_COLUMN_ENUM, TRUE, -1);
 1650         mtodo->todo.complete = 1;
 1651     }
 1652 }
 1653 
 1654 
 1655 static gboolean handleRowSelection(GtkTreeSelection *selection,
 1656                                    GtkTreeModel *model,
 1657                                    GtkTreePath *path,
 1658                                    gboolean path_currently_selected,
 1659                                    gpointer userdata) {
 1660     GtkTreeIter iter;
 1661 
 1662     struct ToDo *todo;
 1663     MyToDo *mtodo;
 1664     int b;
 1665     int index, sorted_position;
 1666     //unsigned int unique_id = 0;
 1667     time_t ltime;
 1668     struct tm *now;
 1669 
 1670     if ((gtk_tree_model_get_iter(model, &iter, path)) && (!path_currently_selected)) {
 1671 
 1672         int *i = gtk_tree_path_get_indices(path);
 1673         row_selected = i[0];
 1674         gtk_tree_model_get(model, &iter, TODO_DATA_COLUMN_ENUM, &mtodo, -1);
 1675         if ((record_changed == MODIFY_FLAG) || (record_changed == NEW_FLAG)) {
 1676             //if (mtodo != NULL) {
 1677             //    unique_id = mtodo->unique_id;
 1678             //}
 1679             // We need to turn this "scroll with mouse held down" thing off
 1680             button_set_for_motion(0);
 1681             b = dialog_save_changed_record_with_cancel(pane, record_changed);
 1682             if (b == DIALOG_SAID_1) { /* Cancel */
 1683                 return TRUE;
 1684             }
 1685             if (b == DIALOG_SAID_3) { /* Save */
 1686                 cb_add_new_record(NULL, GINT_TO_POINTER(record_changed));
 1687             }
 1688             set_new_button_to(CLEAR_FLAG);
 1689 
 1690             return TRUE;
 1691         }
 1692         time(&ltime);
 1693         now = localtime(&ltime);
 1694         if (mtodo == NULL) {
 1695             return TRUE;
 1696         }
 1697         if (mtodo->rt == DELETED_PALM_REC ||
 1698             (mtodo->rt == DELETED_PC_REC))
 1699             /* Possible later addition of undelete code for modified deleted records
 1700                || mtodo->rt == MODIFIED_PALM_REC
 1701             */
 1702         {
 1703             set_new_button_to(UNDELETE_FLAG);
 1704         } else {
 1705             set_new_button_to(CLEAR_FLAG);
 1706         }
 1707         connect_changed_signals(DISCONNECT_SIGNALS);
 1708         //Not sure this is really needed as about 10 lines up does the same check.
 1709         if (mtodo == NULL) {
 1710             return TRUE;
 1711         }
 1712         todo = &(mtodo->todo);
 1713         gtk_widget_freeze_child_notify(todo_desc);
 1714         gtk_widget_freeze_child_notify(todo_note);
 1715         gtk_text_buffer_set_text(GTK_TEXT_BUFFER(todo_desc_buffer), "", -1);
 1716         gtk_text_buffer_set_text(GTK_TEXT_BUFFER(todo_note_buffer), "", -1);
 1717         index = mtodo->attrib & 0x0F;
 1718         sorted_position = find_sort_cat_pos(index);
 1719         int pos = findSortedPostion(sorted_position, GTK_COMBO_BOX(category_menu2));
 1720         if (pos != sorted_position && index != 0) {
 1721             /* Illegal category */
 1722             jp_logf(JP_LOG_DEBUG, "Category is not legal\n");
 1723             index = sorted_position = 0;
 1724             sorted_position = find_sort_cat_pos(index);
 1725         }
 1726         if (sorted_position < 0) {
 1727             jp_logf(JP_LOG_WARN, _("Category is not legal\n"));
 1728         }
 1729         gtk_combo_box_set_active(GTK_COMBO_BOX(category_menu2), find_menu_cat_pos(sorted_position));
 1730 
 1731         if (todo->description) {
 1732             if (todo->description[0]) {
 1733                 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(todo_desc_buffer), todo->description, -1);
 1734             }
 1735         }
 1736 
 1737         if (todo->note) {
 1738             if (todo->note[0]) {
 1739                 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(todo_note_buffer), todo->note, -1);
 1740             }
 1741         }
 1742 
 1743         if ((todo->priority < 1) || (todo->priority > 5)) {
 1744             jp_logf(JP_LOG_WARN, _("Priority out of range\n"));
 1745         } else {
 1746             gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_button_todo[todo->priority - 1]), TRUE);
 1747         }
 1748 
 1749         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(todo_completed_checkbox), todo->complete);
 1750 
 1751         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(private_checkbox),
 1752                                      mtodo->attrib & dlpRecAttrSecret);
 1753 
 1754         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(todo_no_due_date_checkbox),
 1755                                      todo->indefinite);
 1756         if (!todo->indefinite) {
 1757             update_due_button(due_date_button, &(todo->due));
 1758             due_date.tm_mon = todo->due.tm_mon;
 1759             due_date.tm_mday = todo->due.tm_mday;
 1760             due_date.tm_year = todo->due.tm_year;
 1761         } else {
 1762             update_due_button(due_date_button, NULL);
 1763             due_date.tm_mon = now->tm_mon;
 1764             due_date.tm_mday = now->tm_mday;
 1765             due_date.tm_year = now->tm_year;
 1766         }
 1767 
 1768         gtk_widget_thaw_child_notify(todo_desc);
 1769         gtk_widget_thaw_child_notify(todo_note);
 1770         /* If they have clicked on the checkmark box then do a modify */
 1771         /* if (column == 0) {
 1772              gtk_signal_emit_by_name(G_OBJECT(todo_completed_checkbox), "clicked");
 1773              gtk_signal_emit_by_name(G_OBJECT(apply_record_button), "clicked");
 1774          }*/
 1775         connect_changed_signals(CONNECT_SIGNALS);
 1776         return TRUE;
 1777     }
 1778     // gtk_tree_model_get(model, &iter, TODO_TEXT_COLUMN_ENUM, &name, -1);
 1779 
 1780 
 1781     return TRUE; /* allow selection state to change */
 1782 }
 1783 
 1784 static gboolean cb_key_pressed_left_side(GtkWidget *widget,
 1785                                          GdkEventKey *event,
 1786                                          gpointer next_widget) {
 1787     GtkTextBuffer *text_buffer;
 1788     GtkTextIter iter;
 1789 
 1790     if (event->keyval == GDK_KEY_Return) {
 1791         g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event");
 1792         gtk_widget_grab_focus(GTK_WIDGET(next_widget));
 1793         /* Position cursor at start of text */
 1794         text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(next_widget));
 1795         gtk_text_buffer_get_start_iter(text_buffer, &iter);
 1796         gtk_text_buffer_place_cursor(text_buffer, &iter);
 1797         return TRUE;
 1798     }
 1799 
 1800     return FALSE;
 1801 }
 1802 
 1803 static gboolean cb_key_pressed_right_side(GtkWidget *widget,
 1804                                           GdkEventKey *event,
 1805                                           gpointer data) {
 1806     if ((event->keyval == GDK_KEY_Return) && (event->state & GDK_SHIFT_MASK)) {
 1807         g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event");
 1808         gtk_widget_grab_focus(GTK_WIDGET(treeView));
 1809         return TRUE;
 1810     }
 1811     /* Call external editor for note text */
 1812     if (data != NULL &&
 1813         (event->keyval == GDK_KEY_e) && (event->state & GDK_CONTROL_MASK)) {
 1814         g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event");
 1815 
 1816         /* Get current text and place in temporary file */
 1817         GtkTextIter start_iter;
 1818         GtkTextIter end_iter;
 1819         char *text_out;
 1820 
 1821         gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(todo_note_buffer),
 1822                                    &start_iter, &end_iter);
 1823         text_out = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(todo_note_buffer),
 1824                                             &start_iter, &end_iter, TRUE);
 1825 
 1826 
 1827         char tmp_fname[] = "jpilot.XXXXXX";
 1828         int tmpfd = mkstemp(tmp_fname);
 1829         if (tmpfd < 0) {
 1830             jp_logf(JP_LOG_WARN, _("Could not get temporary file name\n"));
 1831             if (text_out)
 1832                 free(text_out);
 1833             return TRUE;
 1834         }
 1835 
 1836         FILE *fptr = fdopen(tmpfd, "w");
 1837         if (!fptr) {
 1838             jp_logf(JP_LOG_WARN, _("Could not open temporary file for external editor\n"));
 1839             if (text_out)
 1840                 free(text_out);
 1841             return TRUE;
 1842         }
 1843         fwrite(text_out, strlen(text_out), 1, fptr);
 1844         fwrite("\n", 1, 1, fptr);
 1845         fclose(fptr);
 1846 
 1847         /* Call external editor */
 1848         char command[1024];
 1849         const char *ext_editor;
 1850 
 1851         get_pref(PREF_EXTERNAL_EDITOR, NULL, &ext_editor);
 1852         if (!ext_editor) {
 1853             jp_logf(JP_LOG_INFO, "External Editor command empty\n");
 1854             if (text_out)
 1855                 free(text_out);
 1856             return TRUE;
 1857         }
 1858 
 1859         if ((strlen(ext_editor) + strlen(tmp_fname) + 1) > sizeof(command)) {
 1860             jp_logf(JP_LOG_WARN, _("External editor command too long to execute\n"));
 1861             if (text_out)
 1862                 free(text_out);
 1863             return TRUE;
 1864         }
 1865         g_snprintf(command, sizeof(command), "%s %s", ext_editor, tmp_fname);
 1866 
 1867         /* jp_logf(JP_LOG_STDOUT|JP_LOG_FILE, _("executing command = [%s]\n"), command); */
 1868         if (system(command) == -1) {
 1869             /* Read data back from temporary file into memo */
 1870             char text_in[0xFFFF];
 1871             size_t bytes_read;
 1872 
 1873             fptr = fopen(tmp_fname, "rb");
 1874             if (!fptr) {
 1875                 jp_logf(JP_LOG_WARN, _("Could not open temporary file from external editor\n"));
 1876                 return TRUE;
 1877             }
 1878             bytes_read = fread(text_in, 1, 0xFFFF, fptr);
 1879             fclose(fptr);
 1880             unlink(tmp_fname);
 1881 
 1882             text_in[--bytes_read] = '\0';  /* Strip final newline */
 1883             /* Only update text if it has changed */
 1884             if (strcmp(text_out, text_in)) {
 1885                 gtk_text_buffer_set_text(GTK_TEXT_BUFFER(todo_note_buffer),
 1886                                          text_in, -1);
 1887             }
 1888         }
 1889 
 1890         if (text_out)
 1891             free(text_out);
 1892 
 1893         return TRUE;
 1894     }   /* End of external editor if */
 1895 
 1896     return FALSE;
 1897 }
 1898 
 1899 void todo_liststore_clear(GtkListStore *pListStore) {
 1900     gtk_list_store_clear(pListStore);
 1901 
 1902 }
 1903 
 1904 static gboolean cb_key_pressed_tab(GtkWidget *widget,
 1905                                    GdkEventKey *event,
 1906                                    gpointer next_widget) {
 1907     GtkTextIter cursor_pos_iter;
 1908     GtkTextBuffer *text_buffer;
 1909 
 1910     if (event->keyval == GDK_KEY_Tab) {
 1911         /* See if they are at the end of the text */
 1912         text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget));
 1913         gtk_text_buffer_get_iter_at_mark(text_buffer, &cursor_pos_iter, gtk_text_buffer_get_insert(text_buffer));
 1914         if (gtk_text_iter_is_end(&cursor_pos_iter)) {
 1915             g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event");
 1916             gtk_widget_grab_focus(GTK_WIDGET(next_widget));
 1917             return TRUE;
 1918         }
 1919     }
 1920     return FALSE;
 1921 }
 1922 
 1923 static gboolean cb_key_pressed_shift_tab(GtkWidget *widget,
 1924                                          GdkEventKey *event,
 1925                                          gpointer next_widget) {
 1926     if (event->keyval == GDK_KEY_ISO_Left_Tab) {
 1927         g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event");
 1928         gtk_widget_grab_focus(GTK_WIDGET(next_widget));
 1929         return TRUE;
 1930     }
 1931     return FALSE;
 1932 }
 1933 
 1934 /* This redraws the treeView and goes back to the same line number */
 1935 static int todo_redraw(void) {
 1936     todo_update_liststore(listStore, category_menu1, &glob_todo_list, todo_category, TRUE);
 1937     return EXIT_SUCCESS;
 1938 }
 1939 
 1940 int todo_cycle_cat(void) {
 1941     int b;
 1942     int i, new_cat;
 1943 
 1944     b = dialog_save_changed_record(pane, record_changed);
 1945     if (b == DIALOG_SAID_2) {
 1946         cb_add_new_record(NULL, GINT_TO_POINTER(record_changed));
 1947     }
 1948 
 1949     if (todo_category == CATEGORY_ALL) {
 1950         new_cat = -1;
 1951     } else {
 1952         new_cat = find_sort_cat_pos(todo_category);
 1953     }
 1954 
 1955     for (i = 0; i < NUM_TODO_CAT_ITEMS; i++) {
 1956         new_cat++;
 1957         if (new_cat >= NUM_TODO_CAT_ITEMS) {
 1958             todo_category = CATEGORY_ALL;
 1959             break;
 1960         }
 1961         if ((sort_l[new_cat].Pcat) && (sort_l[new_cat].Pcat[0])) {
 1962             todo_category = sort_l[new_cat].cat_num;
 1963             break;
 1964         }
 1965     }
 1966 
 1967     row_selected = 0;
 1968 
 1969     return EXIT_SUCCESS;
 1970 }
 1971 
 1972 int todo_refresh(void) {
 1973     int index, index2;
 1974 
 1975     if (glob_find_id) {
 1976         todo_category = CATEGORY_ALL;
 1977     }
 1978     if (todo_category == CATEGORY_ALL) {
 1979         index = 0;
 1980         index2 = 0;
 1981     } else {
 1982         index = find_sort_cat_pos(todo_category);
 1983         index2 = find_menu_cat_pos(index) + 1;
 1984         index += 1;
 1985     }
 1986     todo_update_liststore(listStore, category_menu1, &glob_todo_list, todo_category, TRUE);
 1987     if (index < 0) {
 1988         jp_logf(JP_LOG_WARN, _("Category is not legal\n"));
 1989     } else {
 1990         gtk_combo_box_set_active(GTK_COMBO_BOX(category_menu1), index2);
 1991     }
 1992 
 1993     return EXIT_SUCCESS;
 1994 }
 1995 
 1996 void todo_update_liststore(GtkListStore *pListStore, GtkWidget *tooltip_widget,
 1997                            ToDoList **todo_list, int category, int main) {
 1998     GtkTreeIter iter;
 1999     int num_entries, entries_shown;
 2000     char str[50];
 2001     GdkPixbuf *pixbuf_note;
 2002     GdkPixbuf *pixbuf_check;
 2003     GdkPixbuf *pixbuf_checked;
 2004     gboolean checkColumnDisplay = gtk_true();
 2005     GdkPixbuf *noteColumnDisplay;
 2006     ToDoList *temp_todo;
 2007     char dateDisplay[50];
 2008     char priorityDisplay[50];
 2009     char descriptionDisplay[TODO_MAX_COLUMN_LEN + 2];
 2010     const char *svalue;
 2011     long hide_completed, hide_not_due;
 2012     long show_tooltips;
 2013     int show_priv;
 2014     time_t ltime;
 2015     struct tm *now, *due;
 2016     int comp_now, comp_due;
 2017 
 2018     free_ToDoList(todo_list);
 2019 
 2020     /* Need to get all records including private ones for the tooltips calculation */
 2021     num_entries = get_todos2(todo_list, SORT_ASCENDING, 2, 2, 1, 1, CATEGORY_ALL);
 2022 
 2023     /* Start by clearing existing entry if in main window */
 2024     if (main) {
 2025         todo_clear_details();
 2026         GtkTreeSelection *treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView));
 2027         gtk_tree_selection_set_select_function(treeSelection, NULL, NULL, NULL);
 2028     }
 2029     todo_liststore_clear(pListStore);
 2030 
 2031 
 2032     /* Collect preferences and constant pixmaps for loop */
 2033     get_pref(PREF_TODO_HIDE_COMPLETED, &hide_completed, NULL);
 2034     get_pref(PREF_TODO_HIDE_NOT_DUE, &hide_not_due, NULL);
 2035     show_priv = show_privates(GET_PRIVATES);
 2036     get_pixbufs(PIXMAP_NOTE, &pixbuf_note);
 2037     get_pixbufs(PIXMAP_BOX_CHECK, &pixbuf_check);
 2038     get_pixbufs(PIXMAP_BOX_CHECKED, &pixbuf_checked);
 2039 /*#ifdef __APPLE__
 2040     mask_note = NULL;
 2041    mask_check = NULL;
 2042    mask_checked = NULL;
 2043 #endif
 2044  */
 2045     /* Current time used for calculating overdue items */
 2046     time(&ltime);
 2047     now = localtime(&ltime);
 2048     comp_now = now->tm_year * 380 + now->tm_mon * 31 + now->tm_mday - 1;
 2049 
 2050     entries_shown = 0;
 2051     for (temp_todo = *todo_list; temp_todo; temp_todo = temp_todo->next) {
 2052 
 2053         if (((temp_todo->mtodo.attrib & 0x0F) != category) &&
 2054             category != CATEGORY_ALL) {
 2055             continue;
 2056         }
 2057 
 2058         /* Do masking like Palm OS 3.5 */
 2059         if ((show_priv == MASK_PRIVATES) &&
 2060             (temp_todo->mtodo.attrib & dlpRecAttrSecret)) {
 2061             gtk_list_store_append(pListStore, &iter);
 2062             gtk_list_store_set(pListStore, &iter,
 2063                                TODO_CHECK_COLUMN_ENUM, "---",
 2064                                TODO_PRIORITY_COLUMN_ENUM, "---",
 2065                                TODO_TEXT_COLUMN_ENUM, "--------------------",
 2066                                TODO_DATE_COLUMN_ENUM, "----------",
 2067                                TODO_DATA_COLUMN_ENUM, &(temp_todo->mtodo),
 2068                                -1);
 2069             clear_mytodos(&temp_todo->mtodo);
 2070             entries_shown++;
 2071             continue;
 2072         }
 2073         /* End Masking */
 2074 
 2075         /* Allow a record found through search window to temporarily be
 2076            displayed even if it would normally be hidden by option settings */
 2077         if (!glob_find_id || (glob_find_id != temp_todo->mtodo.unique_id)) {
 2078             /* Hide the completed records if need be */
 2079             if (hide_completed && temp_todo->mtodo.todo.complete) {
 2080                 continue;
 2081             }
 2082 
 2083             /* Hide the not due yet records if need be */
 2084             if ((hide_not_due) && (!(temp_todo->mtodo.todo.indefinite))) {
 2085                 due = &(temp_todo->mtodo.todo.due);
 2086                 comp_due = due->tm_year * 380 + due->tm_mon * 31 + due->tm_mday - 1;
 2087                 if (comp_due > comp_now) {
 2088                     continue;
 2089                 }
 2090             }
 2091         }
 2092 
 2093         /* Hide the private records if need be */
 2094         if ((show_priv != SHOW_PRIVATES) &&
 2095             (temp_todo->mtodo.attrib & dlpRecAttrSecret)) {
 2096             continue;
 2097         }
 2098 
 2099 
 2100 
 2101         /* Put a checkbox or checked checkbox pixmap up */
 2102         if (temp_todo->mtodo.todo.complete > 0) {
 2103             checkColumnDisplay = TRUE;
 2104         } else {
 2105             checkColumnDisplay = FALSE;
 2106         }
 2107 
 2108         /* Print the priority number */
 2109         sprintf(priorityDisplay, "%d", temp_todo->mtodo.todo.priority);
 2110 
 2111         /* Put a note pixmap up */
 2112         if (temp_todo->mtodo.todo.note[0]) {
 2113             noteColumnDisplay = pixbuf_note;
 2114         } else {
 2115             noteColumnDisplay = NULL;
 2116         }
 2117 
 2118         /* Print the due date */
 2119         if (!temp_todo->mtodo.todo.indefinite) {
 2120             get_pref(PREF_SHORTDATE, NULL, &svalue);
 2121             strftime(dateDisplay, sizeof(dateDisplay), svalue, &(temp_todo->mtodo.todo.due));
 2122         } else {
 2123             sprintf(dateDisplay, _("No date"));
 2124         }
 2125 
 2126         /* Print the todo text */
 2127         lstrncpy_remove_cr_lfs(descriptionDisplay, temp_todo->mtodo.todo.description, TODO_MAX_COLUMN_LEN);
 2128         gtk_list_store_append(pListStore, &iter);
 2129 
 2130         GdkRGBA bgColor;
 2131         gboolean showBgColor = FALSE;
 2132         GdkRGBA fgColor;
 2133         gboolean showFgColor = FALSE;
 2134         switch (temp_todo->mtodo.rt) {
 2135             case NEW_PC_REC:
 2136             case REPLACEMENT_PALM_REC:
 2137 
 2138                 bgColor = get_color(LIST_NEW_RED, LIST_NEW_GREEN, LIST_NEW_BLUE);
 2139                 showBgColor = TRUE;
 2140                 break;
 2141             case DELETED_PALM_REC:
 2142             case DELETED_PC_REC:
 2143 
 2144                 bgColor = get_color(LIST_DEL_RED, LIST_DEL_GREEN, LIST_DEL_BLUE);
 2145                 showBgColor = TRUE;
 2146                 break;
 2147             case MODIFIED_PALM_REC:
 2148 
 2149                 bgColor = get_color(LIST_MOD_RED, LIST_MOD_GREEN, LIST_MOD_BLUE);
 2150                 showBgColor = TRUE;
 2151                 break;
 2152             default:
 2153                 if (temp_todo->mtodo.attrib & dlpRecAttrSecret) {
 2154 
 2155                     bgColor = get_color(LIST_PRIVATE_RED, LIST_PRIVATE_GREEN, LIST_PRIVATE_BLUE);
 2156                     showBgColor = TRUE;
 2157                 } else {
 2158                     showBgColor = FALSE;
 2159                 }
 2160         }
 2161 
 2162         if (!(temp_todo->mtodo.todo.indefinite)) {
 2163             due = &(temp_todo->mtodo.todo.due);
 2164             comp_due = due->tm_year * 380 + due->tm_mon * 31 + due->tm_mday - 1;
 2165 
 2166             if (comp_due < comp_now) {
 2167                 fgColor = get_color(LIST_OVERDUE_RED, LIST_OVERDUE_GREEN, LIST_OVERDUE_BLUE);
 2168 
 2169             } else if (comp_due == comp_now) {
 2170                 fgColor = get_color(LIST_DUENOW_RED, LIST_DUENOW_GREEN, LIST_DUENOW_BLUE);
 2171             }
 2172             showFgColor = TRUE;
 2173         }
 2174         gtk_list_store_set(pListStore, &iter,
 2175                            TODO_CHECK_COLUMN_ENUM, checkColumnDisplay,
 2176                            TODO_PRIORITY_COLUMN_ENUM, priorityDisplay,
 2177                            TODO_NOTE_COLUMN_ENUM, noteColumnDisplay,
 2178                            TODO_TEXT_COLUMN_ENUM, descriptionDisplay,
 2179                            TODO_DATE_COLUMN_ENUM, dateDisplay,
 2180                            TODO_DATA_COLUMN_ENUM, &(temp_todo->mtodo),
 2181                            TODO_BACKGROUND_COLOR_ENUM, showBgColor ? &bgColor : NULL,
 2182                            TODO_BACKGROUND_COLOR_ENABLED_ENUM, showBgColor,
 2183                            TODO_FOREGROUND_COLOR_ENUM, showFgColor ? gdk_rgba_to_string(&fgColor) : NULL,
 2184                            TODO_FORGROUND_COLOR_ENABLED_ENUM, showFgColor,
 2185                            -1);
 2186 
 2187         entries_shown++;
 2188     }
 2189     if ((main) && (entries_shown > 0)) {
 2190         // Set callback for a row selected
 2191         gtk_tree_selection_set_select_function(treeSelection, handleRowSelection, NULL, NULL);
 2192         /* First, select any record being searched for */
 2193         if (glob_find_id) {
 2194             todo_find();
 2195         }
 2196             /* Second, try the currently selected row */
 2197         else if (row_selected < entries_shown) {
 2198             gtk_tree_model_foreach(GTK_TREE_MODEL(pListStore), selectRecordByRow, NULL);
 2199         }
 2200             /* Third, select row 0 if nothing else is possible */
 2201         else {
 2202             row_selected = 0;
 2203             gtk_tree_model_foreach(GTK_TREE_MODEL(pListStore), selectRecordByRow, NULL);
 2204         }
 2205 
 2206     }
 2207     if (tooltip_widget) {
 2208         get_pref(PREF_SHOW_TOOLTIPS, &show_tooltips, NULL);
 2209         if (todo_list == NULL) {
 2210             set_tooltip((int) show_tooltips, tooltip_widget, _("0 records"));
 2211         } else {
 2212             sprintf(str, _("%d of %d records"), entries_shown, num_entries);
 2213             set_tooltip((int) show_tooltips, tooltip_widget, str);
 2214         }
 2215     }
 2216 }
 2217 
 2218 gboolean
 2219 findRecord(GtkTreeModel *model,
 2220            GtkTreePath *path,
 2221            GtkTreeIter *iter,
 2222            gpointer data) {
 2223 
 2224     if (glob_find_id) {
 2225         MyToDo *mytodo = NULL;
 2226 
 2227         gtk_tree_model_get(model, iter, TODO_DATA_COLUMN_ENUM, &mytodo, -1);
 2228         if (mytodo->unique_id == glob_find_id) {
 2229             GtkTreeSelection *selection = NULL;
 2230             selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView));
 2231             gtk_tree_selection_set_select_function(selection, handleRowSelection, NULL, NULL);
 2232             gtk_tree_selection_select_path(selection, path);
 2233             gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(treeView), path,
 2234                                          gtk_tree_view_get_column(GTK_TREE_VIEW(treeView), TODO_TEXT_COLUMN_ENUM),
 2235                                          FALSE, 1.0, 0.0);
 2236             glob_find_id = 0;
 2237             return TRUE;
 2238         }
 2239     }
 2240     return FALSE;
 2241 }
 2242 
 2243 
 2244 gboolean
 2245 selectRecordByRow(GtkTreeModel *model,
 2246                   GtkTreePath *path,
 2247                   GtkTreeIter *iter,
 2248                   gpointer data) {
 2249     int *i = gtk_tree_path_get_indices(path);
 2250     if (i[0] == row_selected) {
 2251         GtkTreeSelection *selection = NULL;
 2252         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView));
 2253         gtk_tree_selection_select_path(selection, path);
 2254         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(treeView), path,
 2255                                      gtk_tree_view_get_column(GTK_TREE_VIEW(treeView), TODO_TEXT_COLUMN_ENUM),
 2256                                      FALSE, 1.0, 0.0);
 2257         return TRUE;
 2258     }
 2259 
 2260     return FALSE;
 2261 }
 2262 
 2263 static int todo_find(void) {
 2264     gtk_tree_model_foreach(GTK_TREE_MODEL(listStore), findRecord, NULL);
 2265     return EXIT_SUCCESS;
 2266 
 2267 }
 2268 
 2269 int todo_gui_cleanup(void) {
 2270     int b;
 2271 
 2272     b = dialog_save_changed_record(pane, record_changed);
 2273     if (b == DIALOG_SAID_2) {
 2274         cb_add_new_record(NULL, GINT_TO_POINTER(record_changed));
 2275     }
 2276     free_ToDoList(&glob_todo_list);
 2277     connect_changed_signals(DISCONNECT_SIGNALS);
 2278     set_pref(PREF_TODO_PANE, gtk_paned_get_position(GTK_PANED(pane)), NULL, TRUE);
 2279     set_pref(PREF_TODO_NOTE_PANE, gtk_paned_get_position(GTK_PANED(note_pane)), NULL, TRUE);
 2280     set_pref(PREF_LAST_TODO_CATEGORY, todo_category, NULL, TRUE);
 2281     set_pref(PREF_TODO_SORT_COLUMN, column_selected, NULL, TRUE);
 2282 
 2283     set_pref(PREF_TODO_SORT_ORDER,
 2284              gtk_tree_view_column_get_sort_order(gtk_tree_view_get_column(GTK_TREE_VIEW(treeView), column_selected)),
 2285              NULL, TRUE);
 2286     GtkTreeSelection *treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView));
 2287     gtk_tree_selection_set_select_function(treeSelection, NULL, NULL, NULL);
 2288     todo_liststore_clear(listStore);
 2289     return EXIT_SUCCESS;
 2290 }
 2291 
 2292 
 2293 /* Main function */
 2294 int todo_gui(GtkWidget *vbox, GtkWidget *hbox) {
 2295     GtkWidget *scrolled_window;
 2296     GtkWidget *pixbufwid;
 2297     GdkPixbuf *pixbuf;
 2298     GtkWidget *vbox1, *vbox2;
 2299     GtkWidget *hbox_temp, *hbox_temp2;
 2300     GtkWidget *vbox_temp;
 2301     GtkWidget *separator;
 2302     GtkWidget *label;
 2303     char str[MAX_RADIO_BUTTON_LEN];
 2304     int i;
 2305     GSList *group;
 2306     long ivalue;
 2307     GtkAccelGroup *accel_group;
 2308     long char_set;
 2309     long show_tooltips;
 2310     char *cat_name;
 2311     get_pref(PREF_TODO_VERSION, &todo_version, NULL);
 2312     init();
 2313     get_todo_app_info(&todo_app_info);
 2314     /* Initialize categories */
 2315     get_pref(PREF_CHAR_SET, &char_set, NULL);
 2316     for (i = 1; i < NUM_TODO_CAT_ITEMS; i++) {
 2317         cat_name = charset_p2newj(todo_app_info.category.name[i], 31, (int) char_set);
 2318         strcpy(sort_l[i - 1].Pcat, cat_name);
 2319         free(cat_name);
 2320         sort_l[i - 1].cat_num = i;
 2321     }
 2322     /* put reserved 'Unfiled' category at end of list */
 2323     cat_name = charset_p2newj(todo_app_info.category.name[0], 31, (int) char_set);
 2324     strcpy(sort_l[NUM_TODO_CAT_ITEMS - 1].Pcat, cat_name);
 2325     free(cat_name);
 2326     sort_l[NUM_TODO_CAT_ITEMS - 1].cat_num = 0;
 2327 
 2328     qsort(sort_l, NUM_TODO_CAT_ITEMS - 1, sizeof(struct sorted_cats), cat_compare);
 2329 
 2330 #ifdef JPILOT_DEBUG
 2331     for (i=0; i<NUM_TODO_CAT_ITEMS; i++) {
 2332        printf("cat %d [%s]\n", sort_l[i].cat_num, sort_l[i].Pcat);
 2333     }
 2334 #endif
 2335 
 2336     get_pref(PREF_LAST_TODO_CATEGORY, &ivalue, NULL);
 2337     todo_category = (int) ivalue;
 2338 
 2339     if ((todo_category != CATEGORY_ALL)
 2340         && (todo_app_info.category.name[todo_category][0] == '\0')) {
 2341         todo_category = CATEGORY_ALL;
 2342     }
 2343 
 2344     /* Create basic GUI with left and right boxes and sliding pane */
 2345     accel_group = gtk_accel_group_new();
 2346     gtk_window_add_accel_group(GTK_WINDOW(gtk_widget_get_toplevel(vbox)),
 2347                                accel_group);
 2348     get_pref(PREF_SHOW_TOOLTIPS, &show_tooltips, NULL);
 2349 
 2350     pane = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
 2351     get_pref(PREF_TODO_PANE, &ivalue, NULL);
 2352     gtk_paned_set_position(GTK_PANED(pane), (gint) ivalue);
 2353 
 2354     gtk_box_pack_start(GTK_BOX(hbox), pane, TRUE, TRUE, 5);
 2355 
 2356     vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
 2357     vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
 2358 
 2359     gtk_paned_pack1(GTK_PANED(pane), vbox1, TRUE, FALSE);
 2360     gtk_paned_pack2(GTK_PANED(pane), vbox2, TRUE, FALSE);
 2361 
 2362     /* Left side of GUI */
 2363 
 2364     /* Separator */
 2365     separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
 2366     gtk_box_pack_start(GTK_BOX(vbox1), separator, FALSE, FALSE, 5);
 2367 
 2368     //time(&ltime);
 2369     //now = localtime(&ltime);
 2370 
 2371     /* Make the 'Today is:' label */
 2372     glob_date_label = gtk_label_new(" ");
 2373     gtk_box_pack_start(GTK_BOX(vbox1), glob_date_label, FALSE, FALSE, 0);
 2374     timeout_date(NULL);
 2375     glob_date_timer_tag = g_timeout_add(CLOCK_TICK, timeout_sync_up, NULL);
 2376 
 2377     /* Separator */
 2378     separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
 2379     gtk_box_pack_start(GTK_BOX(vbox1), separator, FALSE, FALSE, 5);
 2380 
 2381     /* Left-side Category box */
 2382     hbox_temp = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
 2383     gtk_box_pack_start(GTK_BOX(vbox1), hbox_temp, FALSE, FALSE, 0);
 2384 
 2385     /* Left-side Category menu */
 2386     make_category_menu(&category_menu1,
 2387                        sort_l, cb_category, TRUE, TRUE);
 2388     gtk_box_pack_start(GTK_BOX(hbox_temp), category_menu1, TRUE, TRUE, 0);
 2389 
 2390     /* Todo list scrolled window */
 2391     scrolled_window = gtk_scrolled_window_new(NULL, NULL);
 2392     gtk_container_set_border_width(GTK_CONTAINER(scrolled_window), 0);
 2393     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
 2394                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 2395     //gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), (GtkShadowType) GTK_TYPE_SHADOW_TYPE);
 2396     gtk_box_pack_start(GTK_BOX(vbox1), scrolled_window, TRUE, TRUE, 0);
 2397     //
 2398     listStore = gtk_list_store_new(TODO_NUM_COLS, G_TYPE_BOOLEAN, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING,
 2399                                    G_TYPE_STRING, G_TYPE_POINTER, GDK_TYPE_RGBA, G_TYPE_BOOLEAN, G_TYPE_STRING,
 2400                                    G_TYPE_BOOLEAN);
 2401     GtkTreeSortable *sortable;
 2402     sortable = GTK_TREE_SORTABLE(listStore);
 2403     gtk_tree_sortable_set_sort_func(sortable, TODO_NOTE_COLUMN_ENUM, sortNoteColumn,
 2404                                     GINT_TO_POINTER(TODO_NOTE_COLUMN_ENUM), NULL);
 2405     GtkTreeModel *model = GTK_TREE_MODEL(listStore);
 2406     treeView = gtk_tree_view_new_with_model(model);
 2407 
 2408     GtkCellRenderer *taskRenderer = gtk_cell_renderer_text_new();
 2409     // gtk_cell_renderer_set_fixed_size(taskRenderer, -1, 1);
 2410 
 2411     GtkTreeViewColumn *taskColumn = gtk_tree_view_column_new_with_attributes("Task",
 2412                                                                              taskRenderer,
 2413                                                                              "text", TODO_TEXT_COLUMN_ENUM,
 2414                                                                              "cell-background-rgba",
 2415                                                                              TODO_BACKGROUND_COLOR_ENUM,
 2416                                                                              "cell-background-set",
 2417                                                                              TODO_BACKGROUND_COLOR_ENABLED_ENUM,
 2418                                                                              NULL);
 2419     gtk_tree_view_column_set_sort_column_id(taskColumn, TODO_TEXT_COLUMN_ENUM);
 2420 
 2421 
 2422     GtkCellRenderer *dateRenderer = gtk_cell_renderer_text_new();
 2423     // gtk_cell_renderer_set_fixed_size(dateRenderer, -1, 1);
 2424 
 2425     GtkTreeViewColumn *dateColumn = gtk_tree_view_column_new_with_attributes("Due",
 2426                                                                              dateRenderer,
 2427                                                                              "text", TODO_DATE_COLUMN_ENUM,
 2428                                                                              "cell-background-rgba",
 2429                                                                              TODO_BACKGROUND_COLOR_ENUM,
 2430                                                                              "cell-background-set",
 2431                                                                              TODO_BACKGROUND_COLOR_ENABLED_ENUM,
 2432                                                                              "foreground", TODO_FOREGROUND_COLOR_ENUM,
 2433                                                                              "foreground-set",
 2434                                                                              TODO_FORGROUND_COLOR_ENABLED_ENUM,
 2435                                                                              NULL);
 2436     gtk_tree_view_column_set_sort_column_id(dateColumn, TODO_DATE_COLUMN_ENUM);
 2437 
 2438     GtkCellRenderer *priorityRenderer = gtk_cell_renderer_text_new();
 2439     // gtk_cell_renderer_set_fixed_size(priorityRenderer, -1, 1);
 2440     GtkTreeViewColumn *priorityColumn = gtk_tree_view_column_new_with_attributes("",
 2441                                                                                  priorityRenderer,
 2442                                                                                  "text", TODO_PRIORITY_COLUMN_ENUM,
 2443                                                                                  "cell-background-rgba",
 2444                                                                                  TODO_BACKGROUND_COLOR_ENUM,
 2445                                                                                  "cell-background-set",
 2446                                                                                  TODO_BACKGROUND_COLOR_ENABLED_ENUM,
 2447                                                                                  NULL);
 2448     gtk_tree_view_column_set_sort_column_id(priorityColumn, TODO_PRIORITY_COLUMN_ENUM);
 2449 
 2450     GtkCellRenderer *noteRenderer = gtk_cell_renderer_pixbuf_new();
 2451     gtk_cell_renderer_set_alignment(noteRenderer,0,0);
 2452     gtk_cell_renderer_set_padding(noteRenderer,4,0);
 2453 
 2454     GtkTreeViewColumn *noteColumn = gtk_tree_view_column_new_with_attributes("",
 2455                                                                              noteRenderer,
 2456                                                                              "pixbuf", TODO_NOTE_COLUMN_ENUM,
 2457                                                                              "cell-background-rgba",
 2458                                                                              TODO_BACKGROUND_COLOR_ENUM,
 2459                                                                              "cell-background-set",
 2460                                                                              TODO_BACKGROUND_COLOR_ENABLED_ENUM,
 2461                                                                              NULL);
 2462     gtk_tree_view_column_set_sort_column_id(noteColumn, TODO_NOTE_COLUMN_ENUM);
 2463 
 2464 
 2465     GtkCellRenderer *checkRenderer = gtk_cell_renderer_toggle_new();
 2466     gtk_cell_renderer_set_alignment(checkRenderer,0,0);
 2467     gtk_cell_renderer_set_padding(checkRenderer,4,0);
 2468     GtkTreeViewColumn *checkColumn = gtk_tree_view_column_new_with_attributes("", checkRenderer, "active",
 2469                                                                               TODO_CHECK_COLUMN_ENUM,
 2470                                                                               "cell-background-rgba",
 2471                                                                               TODO_BACKGROUND_COLOR_ENUM,
 2472                                                                               "cell-background-set",
 2473                                                                               TODO_BACKGROUND_COLOR_ENABLED_ENUM, NULL);
 2474     // FIXME, this doesn't mark the record changed and toggle the right side toggle button
 2475       g_signal_connect (checkRenderer, "toggled",
 2476                       G_CALLBACK(checkedCallBack),
 2477                       listStore);
 2478     gtk_tree_view_column_set_sort_column_id(checkColumn, TODO_CHECK_COLUMN_ENUM);
 2479     gtk_tree_view_insert_column(GTK_TREE_VIEW (treeView), checkColumn, TODO_CHECK_COLUMN_ENUM);
 2480     gtk_tree_view_insert_column(GTK_TREE_VIEW (treeView), priorityColumn, TODO_PRIORITY_COLUMN_ENUM);
 2481     gtk_tree_view_insert_column(GTK_TREE_VIEW (treeView), noteColumn, TODO_NOTE_COLUMN_ENUM);
 2482     gtk_tree_view_insert_column(GTK_TREE_VIEW (treeView), dateColumn, TODO_DATE_COLUMN_ENUM);
 2483     gtk_tree_view_insert_column(GTK_TREE_VIEW (treeView), taskColumn, TODO_TEXT_COLUMN_ENUM);
 2484     gtk_tree_view_column_set_clickable(checkColumn, gtk_true());
 2485     gtk_tree_view_column_set_clickable(priorityColumn, gtk_true());
 2486     gtk_tree_view_column_set_clickable(noteColumn, gtk_true());
 2487     gtk_tree_view_column_set_clickable(dateColumn, gtk_true());
 2488     gtk_tree_view_column_set_clickable(taskColumn, gtk_true());
 2489     gtk_tree_view_column_set_sizing(checkColumn, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
 2490     gtk_tree_view_column_set_sizing(dateColumn, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
 2491     gtk_tree_view_column_set_sizing(priorityColumn, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
 2492     gtk_tree_view_column_set_sizing(noteColumn, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
 2493     gtk_tree_view_column_set_sizing(taskColumn, GTK_TREE_VIEW_COLUMN_FIXED);
 2494     gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView)),
 2495                                 GTK_SELECTION_BROWSE);
 2496 
 2497 
 2498     /* Put pretty pictures in the treeView column headings */
 2499     get_pixbufs(PIXMAP_NOTE, &pixbuf);
 2500     pixbufwid = gtk_image_new_from_pixbuf(pixbuf);
 2501     gtk_widget_show(GTK_WIDGET(pixbufwid));
 2502     gtk_tree_view_column_set_widget(noteColumn, pixbufwid);
 2503     gtk_tree_view_column_set_alignment(noteColumn, GTK_JUSTIFY_LEFT);
 2504 
 2505 
 2506     get_pixbufs(PIXMAP_BOX_CHECKED, &pixbuf);
 2507     pixbufwid = gtk_image_new_from_pixbuf(pixbuf);
 2508     gtk_widget_show(GTK_WIDGET(pixbufwid));
 2509     gtk_tree_view_column_set_widget(checkColumn, pixbufwid);
 2510 
 2511     gtk_tree_view_column_set_alignment(checkColumn, GTK_JUSTIFY_LEFT);
 2512 
 2513     // register function to handle column header clicks..
 2514     g_signal_connect (taskColumn, "clicked", G_CALLBACK(column_clicked_cb), NULL);
 2515     g_signal_connect (noteColumn, "clicked", G_CALLBACK(column_clicked_cb), NULL);
 2516     g_signal_connect (checkColumn, "clicked", G_CALLBACK(column_clicked_cb), NULL);
 2517     g_signal_connect (priorityColumn, "clicked", G_CALLBACK(column_clicked_cb), NULL);
 2518     g_signal_connect (dateColumn, "clicked", G_CALLBACK(column_clicked_cb), NULL);
 2519     treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeView));
 2520 
 2521     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(scrolled_window),
 2522                                     GTK_POLICY_NEVER,
 2523                                     GTK_POLICY_AUTOMATIC);
 2524 
 2525     gtk_tree_selection_set_select_function(treeSelection, handleRowSelection, NULL, NULL);
 2526     gtk_widget_set_events(treeView, GDK_BUTTON1_MOTION_MASK);
 2527     g_signal_connect (G_OBJECT(treeView), "motion_notify_event",
 2528                       G_CALLBACK(motion_notify_event), NULL);
 2529     g_signal_connect (G_OBJECT(treeView), "button-press-event",
 2530                       G_CALLBACK(button_pressed_for_motion), NULL);
 2531     g_signal_connect (G_OBJECT(treeView), "button-release-event",
 2532                       G_CALLBACK(button_released_for_motion), NULL);
 2533     /* Restore previous sorting configuration */
 2534     get_pref(PREF_TODO_SORT_COLUMN, &ivalue, NULL);
 2535     column_selected = (int) ivalue;
 2536 
 2537     for (int x = 0; x < TODO_NUM_COLS - 5; x++) {
 2538         gtk_tree_view_column_set_sort_indicator(gtk_tree_view_get_column(GTK_TREE_VIEW(treeView), x), gtk_false());
 2539     }
 2540     gtk_tree_view_column_set_sort_indicator(gtk_tree_view_get_column(GTK_TREE_VIEW(treeView), column_selected),
 2541                                             gtk_true());
 2542     gtk_tree_view_columns_autosize(GTK_TREE_VIEW(treeView));
 2543 
 2544     get_pref(PREF_TODO_SORT_ORDER, &ivalue, NULL);
 2545     gtk_tree_sortable_set_sort_column_id(sortable, column_selected, (GtkSortType) ivalue);
 2546 
 2547 
 2548     g_object_unref(model);
 2549     gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(treeView));
 2550     /* Right side of GUI */
 2551 
 2552     hbox_temp = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3);
 2553     gtk_box_pack_start(GTK_BOX(vbox2), hbox_temp, FALSE, FALSE, 0);
 2554 
 2555     /* Cancel button */
 2556     CREATE_BUTTON(cancel_record_button, _("Cancel"), CANCEL, _("Cancel the modifications"), GDK_KEY_Escape, 0, "ESC")
 2557     g_signal_connect(G_OBJECT(cancel_record_button), "clicked",
 2558                      G_CALLBACK(cb_cancel), NULL);
 2559 
 2560     /* Delete button */
 2561     CREATE_BUTTON(delete_record_button, _("Delete"), DELETE, _("Delete the selected record"), GDK_d, GDK_CONTROL_MASK,
 2562                   "Ctrl+D")
 2563     g_signal_connect(G_OBJECT(delete_record_button), "clicked",
 2564                      G_CALLBACK(cb_delete_todo),
 2565                      GINT_TO_POINTER(DELETE_FLAG));
 2566 
 2567     /* Undelete Button */
 2568     CREATE_BUTTON(undelete_record_button, _("Undelete"), UNDELETE, _("Undelete the selected record"), 0, 0, "")
 2569     g_signal_connect(G_OBJECT(undelete_record_button), "clicked",
 2570                      G_CALLBACK(cb_undelete_todo),
 2571                      GINT_TO_POINTER(UNDELETE_FLAG));
 2572 
 2573     /* Copy button */
 2574     CREATE_BUTTON(copy_record_button, _("Copy"), COPY, _("Copy the selected record"), GDK_c,
 2575                   GDK_CONTROL_MASK | GDK_SHIFT_MASK, "Ctrl+Shift+C")
 2576     g_signal_connect(G_OBJECT(copy_record_button), "clicked",
 2577                      G_CALLBACK(cb_add_new_record),
 2578                      GINT_TO_POINTER(COPY_FLAG));
 2579 
 2580     /* New button */
 2581     CREATE_BUTTON(new_record_button, _("New Record"), NEW, _("Add a new record"), GDK_n, GDK_CONTROL_MASK, "Ctrl+N")
 2582     g_signal_connect(G_OBJECT(new_record_button), "clicked",
 2583                      G_CALLBACK(cb_add_new_record),
 2584                      GINT_TO_POINTER(CLEAR_FLAG));
 2585 
 2586     /* "Add Record" button */
 2587     CREATE_BUTTON(add_record_button, _("Add Record"), ADD, _("Add the new record"), GDK_KEY_Return, GDK_CONTROL_MASK,
 2588                   "Ctrl+Enter")
 2589     g_signal_connect(G_OBJECT(add_record_button), "clicked",
 2590                      G_CALLBACK(cb_add_new_record),
 2591                      GINT_TO_POINTER(NEW_FLAG));
 2592 #ifndef ENABLE_STOCK_BUTTONS
 2593     gtk_widget_set_name(GTK_WIDGET(GTK_LABEL(gtk_bin_get_child(GTK_BIN(add_record_button)))),
 2594                         "label_high");
 2595 #endif
 2596 
 2597     /* "Apply Changes" button */
 2598     CREATE_BUTTON(apply_record_button, _("Apply Changes"), APPLY, _("Commit the modifications"), GDK_KEY_Return,
 2599                   GDK_CONTROL_MASK, "Ctrl+Enter")
 2600     g_signal_connect(G_OBJECT(apply_record_button), "clicked",
 2601                      G_CALLBACK(cb_add_new_record),
 2602                      GINT_TO_POINTER(MODIFY_FLAG));
 2603 #ifndef ENABLE_STOCK_BUTTONS
 2604     gtk_widget_set_name(GTK_WIDGET(GTK_LABEL(gtk_bin_get_child(GTK_BIN(apply_record_button)))),
 2605                         "label_high");
 2606 #endif
 2607 
 2608     /* Separator */
 2609     separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
 2610     gtk_box_pack_start(GTK_BOX(vbox2), separator, FALSE, FALSE, 5);
 2611 
 2612     hbox_temp = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
 2613     gtk_box_pack_start(GTK_BOX(vbox2), hbox_temp, FALSE, FALSE, 0);
 2614 
 2615     /* Right-side Category menu */
 2616 
 2617     make_category_menu(&category_menu2,
 2618                        sort_l, NULL, FALSE, FALSE);
 2619     gtk_box_pack_start(GTK_BOX(hbox_temp), category_menu2, TRUE, TRUE, 0);
 2620 
 2621     /* Private checkbox */
 2622     private_checkbox = gtk_check_button_new_with_label(_("Private"));
 2623     gtk_box_pack_end(GTK_BOX(hbox_temp), private_checkbox, FALSE, FALSE, 0);
 2624 
 2625     /* Completed checkbox */
 2626     todo_completed_checkbox = gtk_check_button_new_with_label(_("Completed"));
 2627     gtk_box_pack_start(GTK_BOX(vbox2), todo_completed_checkbox, FALSE, FALSE, 0);
 2628 
 2629     /* Priority radio buttons */
 2630     hbox_temp = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
 2631     gtk_box_pack_start(GTK_BOX(vbox2), hbox_temp, FALSE, FALSE, 0);
 2632 
 2633     label = gtk_label_new(_("Priority:"));
 2634     gtk_box_pack_start(GTK_BOX(hbox_temp), label, FALSE, FALSE, 2);
 2635     set_tooltip((int) show_tooltips, label, _("Set priority   Alt+#"));
 2636 
 2637     group = NULL;
 2638     for (i = 0; i < NUM_TODO_PRIORITIES; i++) {
 2639         sprintf(str, "%d", i + 1);
 2640         radio_button_todo[i] = gtk_radio_button_new_with_label(group, str);
 2641         group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio_button_todo[i]));
 2642         gtk_widget_add_accelerator(radio_button_todo[i], "clicked", accel_group,
 2643                                    (guint) GDK_KEY_1 + i, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
 2644         gtk_box_pack_start(GTK_BOX(hbox_temp),
 2645                            radio_button_todo[i], FALSE, FALSE, 0);
 2646     }
 2647 
 2648     /* "Date Due:" label */
 2649     hbox_temp = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
 2650     gtk_box_pack_start(GTK_BOX(vbox2), hbox_temp, FALSE, FALSE, 0);
 2651 
 2652     /* Spacer to line up */
 2653     hbox_temp2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
 2654     gtk_box_pack_start(GTK_BOX(hbox_temp), hbox_temp2, FALSE, FALSE, 1);
 2655 
 2656     label = gtk_label_new(_("Date Due:"));
 2657     gtk_box_pack_start(GTK_BOX(hbox_temp), label, FALSE, FALSE, 0);
 2658 
 2659     /* "Date Due" button */
 2660     due_date_button = gtk_button_new_with_label("");
 2661     gtk_box_pack_start(GTK_BOX(hbox_temp), due_date_button, FALSE, FALSE, 5);
 2662     g_signal_connect(G_OBJECT(due_date_button), "clicked",
 2663                      G_CALLBACK(cb_cal_dialog), NULL);
 2664 
 2665     /* "No Date" check box */
 2666     todo_no_due_date_checkbox = gtk_check_button_new_with_label(_("No Date"));
 2667     g_signal_connect(G_OBJECT(todo_no_due_date_checkbox), "clicked",
 2668                      G_CALLBACK(cb_check_button_no_due_date), NULL);
 2669     gtk_box_pack_start(GTK_BOX(hbox_temp), todo_no_due_date_checkbox, FALSE, FALSE, 0);
 2670 
 2671     note_pane = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
 2672     get_pref(PREF_TODO_NOTE_PANE, &ivalue, NULL);
 2673     gtk_paned_set_position(GTK_PANED(note_pane), (gint) ivalue);
 2674     gtk_box_pack_start(GTK_BOX(vbox2), note_pane, TRUE, TRUE, 0);
 2675 
 2676     /* Description text box */
 2677     hbox_temp = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
 2678     gtk_paned_pack1(GTK_PANED(note_pane), hbox_temp, TRUE, FALSE);
 2679 
 2680     todo_desc = gtk_text_view_new();
 2681     todo_desc_buffer = G_OBJECT(gtk_text_view_get_buffer(GTK_TEXT_VIEW(todo_desc)));
 2682     gtk_text_view_set_editable(GTK_TEXT_VIEW(todo_desc), TRUE);
 2683     gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(todo_desc), GTK_WRAP_WORD);
 2684 
 2685     scrolled_window = gtk_scrolled_window_new(NULL, NULL);
 2686     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
 2687                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 2688     gtk_container_set_border_width(GTK_CONTAINER(scrolled_window), 1);
 2689     gtk_container_add(GTK_CONTAINER(scrolled_window), todo_desc);
 2690     gtk_box_pack_start(GTK_BOX(hbox_temp), scrolled_window, TRUE, TRUE, 0);
 2691     /* Note text box */
 2692     vbox_temp = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
 2693     gtk_paned_pack2(GTK_PANED(note_pane), vbox_temp, TRUE, FALSE);
 2694 
 2695     label = gtk_label_new(_("Note"));
 2696     gtk_box_pack_start(GTK_BOX(vbox_temp), label, FALSE, FALSE, 0);
 2697 
 2698     todo_note = gtk_text_view_new();
 2699     todo_note_buffer = G_OBJECT(gtk_text_view_get_buffer(GTK_TEXT_VIEW(todo_note)));
 2700     gtk_text_view_set_editable(GTK_TEXT_VIEW(todo_note), TRUE);
 2701     gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(todo_note), GTK_WRAP_WORD);
 2702 
 2703     scrolled_window = gtk_scrolled_window_new(NULL, NULL);
 2704     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
 2705                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 2706     gtk_container_set_border_width(GTK_CONTAINER(scrolled_window), 1);
 2707     gtk_container_add(GTK_CONTAINER(scrolled_window), todo_note);
 2708     gtk_box_pack_start(GTK_BOX(vbox_temp), scrolled_window, TRUE, TRUE, 0);
 2709 
 2710     /* Capture the TAB key to change focus with it */
 2711     g_signal_connect(G_OBJECT(todo_desc), "key_press_event",
 2712                      G_CALLBACK(cb_key_pressed_tab), todo_note);
 2713 
 2714     g_signal_connect(G_OBJECT(todo_note), "key_press_event",
 2715                      G_CALLBACK(cb_key_pressed_shift_tab), todo_desc);
 2716 
 2717     /* Capture the Enter & Shift-Enter key combinations to move back and
 2718      * forth between the left- and right-hand sides of the display. */
 2719     g_signal_connect(G_OBJECT(treeView), "key_press_event",
 2720                      G_CALLBACK(cb_key_pressed_left_side), todo_desc);
 2721 
 2722     g_signal_connect(G_OBJECT(todo_desc), "key_press_event",
 2723                      G_CALLBACK(cb_key_pressed_right_side), NULL);
 2724 
 2725     g_signal_connect(G_OBJECT(todo_note), "key_press_event",
 2726                      G_CALLBACK(cb_key_pressed_right_side),
 2727                      GINT_TO_POINTER(1));
 2728 
 2729     /**********************************************************************/
 2730 
 2731     gtk_widget_show_all(vbox);
 2732     gtk_widget_show_all(hbox);
 2733 
 2734     gtk_widget_hide(add_record_button);
 2735     gtk_widget_hide(apply_record_button);
 2736     gtk_widget_hide(undelete_record_button);
 2737     gtk_widget_hide(cancel_record_button);
 2738 
 2739     todo_refresh();
 2740 
 2741     return EXIT_SUCCESS;
 2742 }
 2743