"Fossies" - the Fresh Open Source Software Archive

Member "jpilot-2_0_1/monthview_gui.c" (3 Apr 2021, 18343 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. For more information about "monthview_gui.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.8.2_vs_2_0_1.

    1 /*******************************************************************************
    2  * monthview_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 <gtk/gtk.h>
   26 #include <gdk/gdkkeysyms.h>
   27 
   28 #include <pi-calendar.h>
   29 
   30 #include "utils.h"
   31 #include "i18n.h"
   32 #include "prefs.h"
   33 #include "log.h"
   34 #include "datebook.h"
   35 #include "calendar.h"
   36 #include "print.h"
   37 #include "jpilot.h"
   38 
   39 /******************************* Global vars **********************************/
   40 extern int datebk_category;
   41 extern int glob_app;
   42 
   43 GtkWidget *monthview_window=NULL;
   44 static char      glob_str_dow[7][32];
   45 static GObject   *all_appts_buffer;
   46 static GtkWidget *month_month_label;
   47 static int glob_offset;
   48 static struct tm glob_month_date;
   49 
   50 /*
   51  * The calendar display is 6 rows and 7 columns
   52  * and contains this data.
   53  */
   54 typedef struct {
   55    GtkWidget *label;
   56    GtkWidget *tv;
   57    GObject   *buffer;
   58 } c_day;
   59 
   60 static c_day glob_days[42];
   61 
   62 /****************************** Prototypes ************************************/
   63 static int display_months_appts(struct tm *glob_month_date);
   64 static void set_day_labels(void);
   65 
   66 /****************************** Main Code *************************************/
   67 static gboolean cb_destroy(GtkWidget *widget)
   68 {
   69    int n;
   70    GString *gstr;
   71    GtkWidget *text;
   72    /* FIXME: Do we need to do free buffers?  If so do for all_appts_buffer; */
   73 
   74    monthview_window = NULL;
   75 
   76    for (n=0; n<4; n++) {
   77       text = glob_days[n].tv;
   78       gstr =  g_object_get_data(G_OBJECT(text), "gstr");
   79       if (gstr) {
   80          g_string_free(gstr, TRUE);
   81          g_object_set_data(G_OBJECT(text), "gstr", NULL);
   82       }
   83    }
   84    return FALSE;
   85 }
   86 
   87 void cb_monthview_quit(GtkWidget *widget, gpointer data)
   88 {
   89    int w, h;
   90 
   91    w = gdk_window_get_width(gtk_widget_get_window(monthview_window));
   92    h = gdk_window_get_height(gtk_widget_get_window(monthview_window));
   93    set_pref(PREF_MONTHVIEW_WIDTH, w, NULL, FALSE);
   94    set_pref(PREF_MONTHVIEW_HEIGHT, h, NULL, FALSE);
   95 
   96    gtk_widget_destroy(monthview_window);
   97 }
   98 
   99 static void cb_month_move(GtkWidget *widget, gpointer data)
  100 {
  101    if (GPOINTER_TO_INT(data)==-1) {
  102       glob_month_date.tm_mday=15;
  103       sub_days_from_date(&glob_month_date, 30);
  104    }
  105    if (GPOINTER_TO_INT(data)==1) {
  106       glob_month_date.tm_mday=15;
  107       add_days_to_date(&glob_month_date, 30);
  108    }
  109    set_day_labels();
  110    display_months_appts(&glob_month_date);
  111 }
  112 
  113 static void cb_month_print(GtkWidget *widget, gpointer data)
  114 {
  115    long paper_size;
  116 
  117    jp_logf(JP_LOG_DEBUG, "cb_month_print called\n");
  118    if (print_gui(monthview_window, DATEBOOK, 3, 0x04) == DIALOG_SAID_PRINT) {
  119       get_pref(PREF_PAPER_SIZE, &paper_size, NULL);
  120       if (paper_size==1) {
  121          print_months_appts(&glob_month_date, PAPER_A4);
  122       } else {
  123          print_months_appts(&glob_month_date, PAPER_Letter);
  124       }
  125    }
  126 }
  127 
  128 static void cb_enter_notify(GtkWidget *widget, GdkEvent *event, gpointer data)
  129 {
  130    static int prev_day=-1;
  131    GtkWidget *textview;
  132    GString *gstr;
  133    
  134    if (prev_day==GPOINTER_TO_INT(data)+1-glob_offset) {
  135       return;
  136    }
  137    prev_day = GPOINTER_TO_INT(data)+1-glob_offset;
  138 
  139    textview = gtk_bin_get_child(GTK_BIN(widget));
  140    gstr =  g_object_get_data(G_OBJECT(textview), "gstr");
  141    if (gstr) {
  142       gtk_text_buffer_set_text(GTK_TEXT_BUFFER(all_appts_buffer), gstr->str, -1);
  143    } else {
  144       gtk_text_buffer_set_text(GTK_TEXT_BUFFER(all_appts_buffer), "", -1);
  145    }
  146 }
  147 
  148 /* Called when a day is clicked on in the month view */
  149 static void cb_enter_selected_day(GtkWidget *widget, 
  150                                   GdkEvent  *event, 
  151                                   gpointer   data)
  152 {
  153    int day = GPOINTER_TO_INT(data) + 1 - glob_offset;
  154 
  155    if (glob_app != DATEBOOK)
  156       return;
  157 
  158    /* Redisplay the day view based on the date the user clicked on */
  159    datebook_gui_setdate(glob_month_date.tm_year, glob_month_date.tm_mon, day);
  160 }
  161 
  162 /*
  163  * Relabel shown day labels according to the month.
  164  * Also, set a global offset for indexing day 1.
  165  */
  166 static void set_day_labels(void)
  167 {
  168    int n;
  169    int dow, ndim;
  170    int now_today;
  171    long fdow;
  172    char str[64];
  173    int d;
  174    GtkWidget *text;
  175    char *markup_str;
  176 
  177    /* Determine today for highlighting */
  178    now_today = get_highlighted_today(&glob_month_date);
  179 
  180    get_month_info(glob_month_date.tm_mon, 1, glob_month_date.tm_year, &dow, &ndim);
  181 
  182    get_pref(PREF_FDOW, &fdow, NULL);
  183 
  184    glob_offset = (7+dow-fdow)%7;
  185 
  186    d = 1 - glob_offset;
  187 
  188    for (n=0; n<42; n++, d++) {
  189       text = glob_days[n].tv;
  190       /* Clear the calendar day entry */
  191       gtk_text_buffer_set_text(GTK_TEXT_BUFFER(glob_days[n].buffer), "", -1);
  192       if ((d<1) || (d>ndim)) {
  193          str[0]='\0';
  194          gtk_widget_set_sensitive(glob_days[n].tv, FALSE);
  195       } else {
  196          snprintf(str, sizeof(str), "%d - %s", d, glob_str_dow[n%7]);
  197          str[sizeof(str)-1]='\0';
  198          gtk_widget_set_sensitive(glob_days[n].tv, TRUE);
  199       }
  200 
  201       if (d == now_today)
  202       {
  203          /* Make today's text bold */
  204          markup_str = g_markup_printf_escaped("<b>%s</b>", str);
  205          gtk_widget_set_name(text, "today");
  206       } else {
  207          markup_str = g_markup_printf_escaped("%s", str);
  208          gtk_widget_set_name(text, "");
  209       }
  210       gtk_label_set_markup(GTK_LABEL(glob_days[n].label), markup_str);
  211       g_free(markup_str);
  212    }
  213 }
  214 
  215 static void create_month_boxes_texts(GtkWidget *grid)
  216 {
  217     int x, y;
  218     int count;
  219     GtkWidget *vbox;
  220     GtkWidget *tv;
  221     GtkWidget *label;
  222     GtkWidget *event_box;
  223 
  224     count = 0;
  225     /* 6 Rows of 7 days for a month */
  226     for (y=0; y<6; y++) {
  227         for (x=0; x<7; x++, count++) {
  228             /* Day of month labels */
  229             /* label variable only used to save some typing */
  230             label = glob_days[count].label = gtk_label_new("");
  231             gtk_widget_set_halign(GTK_WIDGET(label), GTK_ALIGN_START);
  232             vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  233             gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(vbox), x, y, 1, 1);
  234             gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
  235 
  236             /* tv variable only used to save some typing */
  237             tv = glob_days[count].tv = gtk_text_view_new();
  238             glob_days[count].buffer = G_OBJECT(gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv)));
  239             gtk_widget_set_halign(tv, GTK_ALIGN_FILL);
  240             gtk_widget_set_valign(tv, GTK_ALIGN_FILL);
  241             gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(tv), FALSE);
  242             gtk_text_view_set_editable(GTK_TEXT_VIEW(tv), FALSE);
  243             gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tv), GTK_WRAP_CHAR);
  244 
  245             /* textview widget does not support window events such as
  246              * enter_notify.  The widget must be wrapped in an event box
  247              * in order to work correctly. */
  248             event_box = gtk_event_box_new();
  249             gtk_widget_set_halign(event_box, GTK_ALIGN_FILL);
  250             gtk_widget_set_valign(event_box, GTK_ALIGN_FILL);
  251 
  252             /* Use a scrolled window to keep the main window from expanding */
  253             GtkWidget *scrolled = gtk_scrolled_window_new(NULL, NULL);
  254             gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
  255 
  256             gtk_container_add(GTK_CONTAINER(scrolled), tv);
  257 
  258             gtk_container_add(GTK_CONTAINER(event_box), scrolled);
  259 
  260             g_signal_connect(G_OBJECT(event_box), "enter_notify_event",
  261                              G_CALLBACK(cb_enter_notify), GINT_TO_POINTER(count));
  262             g_signal_connect(G_OBJECT(tv), "button_release_event",
  263                              G_CALLBACK(cb_enter_selected_day),
  264                              GINT_TO_POINTER(count));
  265 
  266             gtk_box_pack_start(GTK_BOX(vbox), event_box, TRUE, TRUE, 2);
  267         }
  268     }
  269 
  270     /* Draw the text viewer at the botton */
  271     tv = gtk_text_view_new();
  272     all_appts_buffer = G_OBJECT(gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv)));
  273     gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(tv), FALSE);
  274     gtk_text_view_set_editable(GTK_TEXT_VIEW(tv), FALSE);
  275     gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tv), GTK_WRAP_WORD);
  276     gtk_widget_set_size_request(GTK_WIDGET(tv), 10, 10);
  277     gtk_grid_attach(GTK_GRID(grid), GTK_WIDGET(tv), 0, y, 7, 1);
  278 }
  279 
  280 static int display_months_appts(struct tm *date_in)
  281 {
  282    CalendarEventList *ce_list;
  283    CalendarEventList *temp_cel;
  284    struct tm date;
  285    char desc[100];
  286    char datef[20];
  287    char str[64];
  288    int dow;
  289    int ndim;
  290    int n;
  291    int mask;
  292    int num_shown;
  293 #ifdef ENABLE_DATEBK
  294    int ret;
  295    int cat_bit;
  296    int db3_type;
  297    long use_db3_tags;
  298    struct db4_struct db4;
  299 #endif
  300    GString *gstr;
  301    GtkWidget *temp_text;
  302    long datebook_version;
  303 
  304    ce_list = NULL;
  305    mask=0;
  306 
  307    get_pref(PREF_DATEBOOK_VERSION, &datebook_version, NULL);
  308 
  309    /* Clear all of the boxes */
  310    for (n=0; n<42; n++) {
  311       temp_text = glob_days[n].tv;
  312       gstr =  g_object_get_data(G_OBJECT(temp_text), "gstr");
  313       if (gstr) {
  314          g_string_free(gstr, TRUE);
  315          g_object_set_data(G_OBJECT(temp_text), "gstr", NULL);
  316       }
  317    }
  318 
  319    /* Set month name label */
  320    jp_strftime(str, sizeof(str), "%B %Y", date_in);
  321    gtk_label_set_text(GTK_LABEL(month_month_label), str);
  322 
  323    memcpy(&date, date_in, sizeof(struct tm));
  324 
  325    /* Get all of the appointments */
  326    get_days_calendar_events2(&ce_list, NULL, 2, 2, 2, CATEGORY_ALL, NULL);
  327 
  328    get_month_info(date.tm_mon, 1, date.tm_year, &dow, &ndim);
  329 
  330    weed_calendar_event_list(&ce_list, date.tm_mon, date.tm_year, 0, &mask);
  331 
  332    /* Cycle through every day in the selected month, starting at dow (day of week) for the first day */
  333    for (n=dow, date.tm_mday=1; date.tm_mday<=ndim; date.tm_mday++, n++) {
  334       gstr=NULL;
  335 
  336       date.tm_sec=0;
  337       date.tm_min=0;
  338       date.tm_hour=11;
  339       date.tm_isdst=-1;
  340       date.tm_wday=0;
  341       date.tm_yday=1;
  342       mktime(&date);
  343 
  344       /* Clear all of the text buffers */
  345       gtk_text_buffer_set_text(GTK_TEXT_BUFFER(glob_days[n].buffer), "", -1);
  346 
  347       num_shown = 0;
  348       for (temp_cel = ce_list; temp_cel; temp_cel=temp_cel->next) {
  349 #ifdef ENABLE_DATEBK
  350          get_pref(PREF_USE_DB3, &use_db3_tags, NULL);
  351          if (use_db3_tags) {
  352             ret = db3_parse_tag(temp_cel->mcale.cale.note, &db3_type, &db4);
  353             jp_logf(JP_LOG_DEBUG, "category = 0x%x\n, ret=%d", db4.category, ret);
  354             cat_bit=1<<db4.category;
  355             if (!(cat_bit & datebk_category)) {
  356                jp_logf(JP_LOG_DEBUG, "skipping rec not in this category\n");
  357                continue;
  358             }
  359          }
  360 #endif
  361          if (calendar_isApptOnDate(&(temp_cel->mcale.cale), &date)) {
  362             if (num_shown) {
  363                /* Set each text buffer */
  364                gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(glob_days[n].buffer), "\n", -1);
  365                g_string_append(gstr, "\n");
  366             } else {
  367                gstr=g_string_new("");
  368             }
  369             num_shown++;
  370             if (temp_cel->mcale.cale.event) {
  371                strcpy(desc, "*");
  372             } else {
  373                get_pref_time_no_secs(datef);
  374                jp_strftime(desc, sizeof(desc), datef, &(temp_cel->mcale.cale.begin));
  375                strcat(desc, " ");
  376             }
  377             g_string_append(gstr, desc);
  378             g_string_append(gstr, temp_cel->mcale.cale.description);
  379             if (temp_cel->mcale.cale.description) {
  380                strncat(desc, temp_cel->mcale.cale.description, 36);
  381                /* FIXME: This kind of truncation is bad for UTF-8 */ 
  382                desc[35]='\0';
  383             }
  384             /* FIXME: Add location in parentheses (loc) as the Palm does.
  385              * We would need to check strlen, etc., before adding */
  386             remove_cr_lfs(desc);
  387 
  388             /* Append number of anniversary years if enabled & appropriate */
  389             append_anni_years(desc, 35, &date, NULL, &temp_cel->mcale.cale);
  390 
  391             gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(glob_days[n].buffer), desc, -1);
  392          }
  393       }
  394       g_object_set_data(G_OBJECT(glob_days[n].tv), "gstr", gstr);
  395    }
  396    free_CalendarEventList(&ce_list);
  397 
  398    return EXIT_SUCCESS;
  399 }
  400 
  401 void monthview_gui(struct tm *date_in)
  402 {
  403    struct tm date;
  404    GtkWidget *grid1;
  405    GtkWidget *grid2;
  406    GtkWidget *button;
  407    GtkWidget *vbox;
  408    GtkAccelGroup *accel_group;
  409    int i;
  410    char str[64];
  411    long fdow;
  412    char title[200];
  413    long w, h, show_tooltips;
  414 
  415    if (monthview_window) {
  416        /* Delete any existing window to ensure that new window is biased
  417         * around currently selected date and so that the new window
  418         * contents are updated with any changes on the day view. */
  419       gtk_widget_destroy(monthview_window);
  420    }
  421 
  422    memcpy(&glob_month_date, date_in, sizeof(struct tm));
  423 
  424    get_pref(PREF_FDOW, &fdow, NULL);
  425 
  426    get_pref(PREF_MONTHVIEW_WIDTH, &w, NULL);
  427    get_pref(PREF_MONTHVIEW_HEIGHT, &h, NULL);
  428    get_pref(PREF_SHOW_TOOLTIPS, &show_tooltips, NULL);
  429 
  430    g_snprintf(title, sizeof(title), "%s %s", PN, _("Monthly View"));
  431 
  432    monthview_window = gtk_widget_new(GTK_TYPE_WINDOW,
  433                                      "type", GTK_WINDOW_TOPLEVEL,
  434                                      "title", title,
  435                                      NULL);
  436 
  437    gtk_window_set_default_size(GTK_WINDOW(monthview_window), w, h);
  438 
  439    gtk_container_set_border_width(GTK_CONTAINER(monthview_window), 10);
  440 
  441    g_signal_connect(G_OBJECT(monthview_window), "destroy",
  442                     G_CALLBACK(cb_destroy), monthview_window);
  443 
  444    /* Use a grid instead of boxes */
  445    grid1 = gtk_grid_new();
  446    gtk_grid_set_row_spacing(GTK_GRID(grid1), 5);
  447    gtk_grid_set_column_spacing(GTK_GRID(grid1), 5);
  448 
  449    grid2 = gtk_grid_new();
  450    gtk_grid_set_row_spacing(GTK_GRID(grid2), 5);
  451    gtk_grid_set_column_spacing(GTK_GRID(grid2), 5);
  452    gtk_grid_set_row_homogeneous(GTK_GRID(grid2), TRUE);
  453    gtk_grid_set_column_homogeneous(GTK_GRID(grid2), TRUE);
  454    gtk_widget_set_halign(grid2, GTK_ALIGN_FILL);
  455    gtk_widget_set_valign(grid2, GTK_ALIGN_FILL);
  456    gtk_widget_set_hexpand(grid2, TRUE);
  457    gtk_widget_set_vexpand(grid2, TRUE);
  458 
  459    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
  460    gtk_container_add(GTK_CONTAINER(monthview_window), vbox);
  461 
  462    gtk_box_pack_start(GTK_BOX(vbox), grid1, FALSE, FALSE, 0);
  463    gtk_box_pack_start(GTK_BOX(vbox), grid2, TRUE, TRUE, 0);
  464 
  465    /* Make accelerators for some buttons window */
  466    accel_group = gtk_accel_group_new();
  467    gtk_window_add_accel_group(GTK_WINDOW(gtk_widget_get_toplevel(vbox)), accel_group);
  468 
  469    /* Make a left arrow for going back a week */
  470    button = gtk_button_new_with_label("Back");
  471    g_signal_connect(G_OBJECT(button), "clicked",
  472                       G_CALLBACK(cb_month_move),
  473                       GINT_TO_POINTER(-1));
  474    gtk_grid_attach(GTK_GRID(grid1), GTK_WIDGET(button), 0, 0, 1, 1);
  475 
  476    /* Accelerator key for left arrow */
  477    gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel_group, 
  478                               GDK_KEY_Left, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
  479    set_tooltip(show_tooltips, button, _("Last month   Alt+LeftArrow"));
  480 
  481    /* Close button */
  482    button = gtk_button_new_with_label("Close");
  483    g_signal_connect(G_OBJECT(button), "clicked",
  484                       G_CALLBACK(cb_monthview_quit), monthview_window);
  485    /* Closing the window via a delete event uses the same cleanup routine */
  486    g_signal_connect(G_OBJECT(monthview_window), "delete_event",
  487                       G_CALLBACK(cb_monthview_quit), NULL);
  488    gtk_grid_attach(GTK_GRID(grid1), GTK_WIDGET(button), 1, 0, 1, 1);
  489 
  490    /* Print button */
  491    button = gtk_button_new_with_label("Print");
  492    g_signal_connect(G_OBJECT(button), "clicked",
  493                       G_CALLBACK(cb_month_print), monthview_window);
  494    gtk_grid_attach(GTK_GRID(grid1), GTK_WIDGET(button), 2, 0, 1, 1);
  495 
  496    /* Make a right arrow for going forward a week */
  497    button = gtk_button_new_with_label("Forward");
  498    g_signal_connect(G_OBJECT(button), "clicked",
  499                       G_CALLBACK(cb_month_move),
  500                       GINT_TO_POINTER(1));
  501    gtk_grid_attach(GTK_GRID(grid1), GTK_WIDGET(button), 3, 0, 1, 1);
  502 
  503    /* Accelerator key for right arrow */
  504    gtk_widget_add_accelerator(GTK_WIDGET(button), "clicked", accel_group, 
  505                               GDK_KEY_Right, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
  506    set_tooltip(show_tooltips, button, _("Next month   Alt+RightArrow"));
  507 
  508    /* Month name label */
  509    jp_strftime(str, sizeof(str), "%B %Y", &glob_month_date);
  510    month_month_label = gtk_label_new(str);
  511    gtk_grid_attach(GTK_GRID(grid1), GTK_WIDGET(month_month_label), 0, 1, 7, 1);
  512 
  513    /* Use a date that we know is on a Sunday */
  514    memset(&date, 0, sizeof(date));
  515    date.tm_hour=12;
  516    date.tm_mday=3;
  517    date.tm_mon=1;
  518    date.tm_year=80;
  519    mktime(&date);
  520    /* Get to the first day of week.
  521     * 0 for Sunday, 1 for Monday, etc.
  522     * Move the date to the firs day of the week according to settings.
  523     */
  524    if (fdow) add_days_to_date(&date, fdow);
  525 
  526    /* Make strings for the days of the week, i.e. Sunday, Monday... */
  527    for (i=0; i<7; i++) {
  528       jp_strftime(glob_str_dow[i], sizeof(glob_str_dow[i]), "%A", &date);
  529       add_days_to_date(&date, 1);
  530    }
  531 
  532    /* Attach 6 rows of 7 boxes for the calendar text views.
  533     * Also one large text view at the bottom.
  534     */
  535    create_month_boxes_texts(grid2);
  536 
  537    gtk_widget_show_all(monthview_window);
  538 
  539    set_day_labels();
  540 
  541    display_months_appts(&glob_month_date);
  542 }