/* $Id: appointment.c,v 1.29 2016/12/04 15:22:16 tom Exp $ */ #include #ifdef HAVE_XCURSES char *XCursesProgramName = "appointmentBook"; #endif /* * Create definitions. */ #define MAX_MARKERS 2000 /* * */ static chtype GPAppointmentAttributes[] = { A_BLINK, A_BOLD, A_REVERSE, A_UNDERLINE }; /* * */ typedef enum { vBirthday, vAnniversary, vAppointment, vOther } EAppointmentType; /* * */ struct AppointmentMarker { EAppointmentType type; char *description; int day; int month; int year; }; /* * */ struct AppointmentInfo { struct AppointmentMarker appointment[MAX_MARKERS]; int appointmentCount; }; /* * Declare local function prototypes. */ static BINDFN_PROTO (createCalendarMarkCB); static BINDFN_PROTO (removeCalendarMarkCB); static BINDFN_PROTO (displayCalendarMarkCB); static BINDFN_PROTO (accelerateToDateCB); void readAppointmentFile (char *filename, struct AppointmentInfo *appInfo); void saveAppointmentFile (char *filename, struct AppointmentInfo *appInfo); /* * This program demonstrates the Cdk calendar widget. */ int main (int argc, char **argv) { /* *INDENT-EQLS* */ CDKSCREEN *cdkscreen = 0; CDKCALENDAR *calendar = 0; const char *title = "CDK Appointment Book\n<#HL(30)>\n"; char *filename = 0; struct tm *dateInfo = 0; time_t clck = 0; struct AppointmentInfo appointmentInfo; int day, month, year, x; /* * Get the current dates and set the default values for * the day/month/year values for the calendar. */ /* *INDENT-EQLS* */ time (&clck); dateInfo = gmtime (&clck); day = dateInfo->tm_mday; month = dateInfo->tm_mon + 1; year = dateInfo->tm_year + 1900; /* Check the command line for options. */ while (1) { int ret; /* Are there any more command line options to parse. */ if ((ret = getopt (argc, argv, "d:m:y:t:f:")) == -1) { break; } switch (ret) { case 'd': day = atoi (optarg); break; case 'm': month = atoi (optarg); break; case 'y': year = atoi (optarg); break; case 't': title = copyChar (optarg); break; case 'f': filename = copyChar (optarg); break; } } /* Create the appointment book filename. */ if (filename == 0) { char temp[1000]; char *home = getenv ("HOME"); if (home != 0) { sprintf (temp, "%.*s/.appointment", (int)sizeof (temp) - 20, home); } else { strcpy (temp, ".appointment"); } filename = copyChar (temp); } /* Read the appointment book information. */ readAppointmentFile (filename, &appointmentInfo); cdkscreen = initCDKScreen (NULL); /* Start CDK Colors. */ initCDKColor (); /* Create the calendar widget. */ calendar = newCDKCalendar (cdkscreen, CENTER, CENTER, title, day, month, year, A_NORMAL, A_NORMAL, A_NORMAL, A_REVERSE, TRUE, FALSE); /* Is the widget null? */ if (calendar == 0) { /* Clean up the memory. */ destroyCDKScreen (cdkscreen); /* End curses... */ endCDK (); /* Spit out a message. */ printf ("Cannot create the calendar. Is the window too small?\n"); ExitProgram (EXIT_FAILURE); } /* Create a key binding to mark days on the calendar. */ bindCDKObject (vCALENDAR, calendar, 'm', createCalendarMarkCB, &appointmentInfo); bindCDKObject (vCALENDAR, calendar, 'M', createCalendarMarkCB, &appointmentInfo); bindCDKObject (vCALENDAR, calendar, 'r', removeCalendarMarkCB, &appointmentInfo); bindCDKObject (vCALENDAR, calendar, 'R', removeCalendarMarkCB, &appointmentInfo); bindCDKObject (vCALENDAR, calendar, '?', displayCalendarMarkCB, &appointmentInfo); bindCDKObject (vCALENDAR, calendar, 'j', accelerateToDateCB, &appointmentInfo); bindCDKObject (vCALENDAR, calendar, 'J', accelerateToDateCB, &appointmentInfo); /* Set all the appointments read from the file. */ for (x = 0; x < appointmentInfo.appointmentCount; x++) { chtype marker = GPAppointmentAttributes[appointmentInfo.appointment[x].type]; setCDKCalendarMarker (calendar, appointmentInfo.appointment[x].day, appointmentInfo.appointment[x].month, appointmentInfo.appointment[x].year, marker); } /* Draw the calendar widget. */ drawCDKCalendar (calendar, ObjOf (calendar)->box); /* Let the user play with the widget. */ activateCDKCalendar (calendar, 0); /* Save the appointment information. */ saveAppointmentFile (filename, &appointmentInfo); free (filename); /* Clean up and exit. */ destroyCDKCalendar (calendar); destroyCDKScreen (cdkscreen); endCDK (); ExitProgram (EXIT_SUCCESS); } /* * This reads a given appointment file. */ void readAppointmentFile (char *filename, struct AppointmentInfo *appInfo) { /* *INDENT-EQLS* */ int appointments = 0; int linesRead = 0; char **lines = 0; int x; /* Read the appointment file. */ linesRead = CDKreadFile (filename, &lines); if (linesRead == -1) { appInfo->appointmentCount = 0; return; } /* Split each line up and create an appointment. */ for (x = 0; x < linesRead; x++) { char **temp = CDKsplitString (lines[x], CTRL ('V')); int segments = (int)CDKcountStrings ((CDK_CSTRING2)temp); /* * A valid line has 5 elements: * Day, Month, Year, Type, Description. */ if (segments == 5) { int eType = atoi (temp[3]); /* *INDENT-EQLS* */ appInfo->appointment[appointments].day = atoi (temp[0]); appInfo->appointment[appointments].month = atoi (temp[1]); appInfo->appointment[appointments].year = atoi (temp[2]); appInfo->appointment[appointments].type = (EAppointmentType) eType; appInfo->appointment[appointments].description = copyChar (temp[4]); appointments++; } CDKfreeStrings (temp); } CDKfreeStrings (lines); /* Keep the amount of appointments read. */ appInfo->appointmentCount = appointments; } /* * This saves a given appointment file. */ void saveAppointmentFile (char *filename, struct AppointmentInfo *appInfo) { /* Declare local variables. */ FILE *fd; int x; /* Can we open the file? */ if ((fd = fopen (filename, "w")) == 0) { return; } /* Start writing. */ for (x = 0; x < appInfo->appointmentCount; x++) { if (appInfo->appointment[x].description != 0) { fprintf (fd, "%d%c%d%c%d%c%d%c%s\n", appInfo->appointment[x].day, CTRL ('V'), appInfo->appointment[x].month, CTRL ('V'), appInfo->appointment[x].year, CTRL ('V'), (int)appInfo->appointment[x].type, CTRL ('V'), appInfo->appointment[x].description); freeChar (appInfo->appointment[x].description); } } fclose (fd); } /* * This adds a marker to the calendar. */ static int createCalendarMarkCB (EObjectType objectType GCC_UNUSED, void *object, void *clientData, chtype key GCC_UNUSED) { /* *INDENT-EQLS* */ CDKCALENDAR *calendar = (CDKCALENDAR *)object; CDKENTRY *entry = 0; CDKITEMLIST *itemlist = 0; const char *items[] = { "Birthday", "Anniversary", "Appointment", "Other" }; char *description = 0; struct AppointmentInfo *appointmentInfo = (struct AppointmentInfo *)clientData; int current = appointmentInfo->appointmentCount; chtype marker; int selection; /* Create the itemlist widget. */ itemlist = newCDKItemlist (ScreenOf (calendar), CENTER, CENTER, 0, "Select Appointment Type: ", (CDK_CSTRING2)items, 4, 0, TRUE, FALSE); /* Get the appointment tye from the user. */ selection = activateCDKItemlist (itemlist, 0); /* They hit escape, kill the itemlist widget and leave. */ if (selection == -1) { destroyCDKItemlist (itemlist); drawCDKCalendar (calendar, ObjOf (calendar)->box); return (FALSE); } /* Destroy the itemlist and set the marker. */ destroyCDKItemlist (itemlist); drawCDKCalendar (calendar, ObjOf (calendar)->box); marker = GPAppointmentAttributes[selection]; /* Create the entry field for the description. */ entry = newCDKEntry (ScreenOf (calendar), CENTER, CENTER, "Enter a description of the appointment.", "Description: ", A_NORMAL, (chtype)'.', vMIXED, 40, 1, 512, TRUE, FALSE); /* Get the description. */ description = activateCDKEntry (entry, 0); if (description == 0) { destroyCDKEntry (entry); drawCDKCalendar (calendar, ObjOf (calendar)->box); return (FALSE); } /* Destroy the entry and set the marker. */ description = copyChar (entry->info); destroyCDKEntry (entry); drawCDKCalendar (calendar, ObjOf (calendar)->box); /* Set the marker. */ setCDKCalendarMarker (calendar, calendar->day, calendar->month, calendar->year, marker); /* Keep the marker. */ appointmentInfo->appointment[current].day = calendar->day; appointmentInfo->appointment[current].month = calendar->month; appointmentInfo->appointment[current].year = calendar->year; appointmentInfo->appointment[current].type = (EAppointmentType) selection; appointmentInfo->appointment[current].description = description; appointmentInfo->appointmentCount++; /* Redraw the calendar. */ drawCDKCalendar (calendar, ObjOf (calendar)->box); return (FALSE); } /* * This removes a marker from the calendar. */ static int removeCalendarMarkCB (EObjectType objectType GCC_UNUSED, void *object, void *clientData, chtype key GCC_UNUSED) { CDKCALENDAR *calendar = (CDKCALENDAR *)object; struct AppointmentInfo *appointmentInfo = (struct AppointmentInfo *)clientData; int x; /* Look for the marker in the list. */ for (x = 0; x < appointmentInfo->appointmentCount; x++) { if ((appointmentInfo->appointment[x].day == calendar->day) && (appointmentInfo->appointment[x].month == calendar->month) && (appointmentInfo->appointment[x].year == calendar->year)) { freeChar (appointmentInfo->appointment[x].description); appointmentInfo->appointment[x].description = 0; break; } } /* Remove the marker from the calendar. */ removeCDKCalendarMarker (calendar, calendar->day, calendar->month, calendar->year); /* Redraw the calendar. */ drawCDKCalendar (calendar, ObjOf (calendar)->box); return (FALSE); } /* * This displays the marker(s) on the given day. */ static int displayCalendarMarkCB (EObjectType objectType GCC_UNUSED, void *object, void *clientData, chtype key GCC_UNUSED) { /* *INDENT-EQLS* */ CDKCALENDAR *calendar = (CDKCALENDAR *)object; CDKLABEL *label = 0; struct AppointmentInfo *appointmentInfo = (struct AppointmentInfo *)clientData; int found = 0; int mesgLines = 0; const char *type = 0; char *mesg[10], temp[256]; int x; /* Look for the marker in the list. */ for (x = 0; x < appointmentInfo->appointmentCount; x++) { /* Get the day month year. */ /* *INDENT-EQLS* */ int day = appointmentInfo->appointment[x].day; int month = appointmentInfo->appointment[x].month; int year = appointmentInfo->appointment[x].year; /* Determine the appointment type. */ if (appointmentInfo->appointment[x].type == vBirthday) { type = "Birthday"; } else if (appointmentInfo->appointment[x].type == vAnniversary) { type = "Anniversary"; } else if (appointmentInfo->appointment[x].type == vAppointment) { type = "Appointment"; } else { type = "Other"; } /* Find the marker by the day/month/year. */ if ((day == calendar->day) && (month == calendar->month) && (year == calendar->year) && (appointmentInfo->appointment[x].description != 0)) { /* Create the message for the label widget. */ sprintf (temp, "Appointment Date: %02d/%02d/%d", day, month, year); mesg[mesgLines++] = copyChar (temp); mesg[mesgLines++] = copyChar (" "); mesg[mesgLines++] = copyChar ("<#HL(35)>"); sprintf (temp, " Appointment Type: %s", type); mesg[mesgLines++] = copyChar (temp); mesg[mesgLines++] = copyChar (" Description :"); sprintf (temp, " %s", appointmentInfo->appointment[x].description); mesg[mesgLines++] = copyChar (temp); mesg[mesgLines++] = copyChar ("<#HL(35)>"); mesg[mesgLines++] = copyChar (" "); mesg[mesgLines++] = copyChar ("Press space to continue."); found = 1; break; } } /* If we didn't find the marker, create a different message. */ if (found == 0) { sprintf (temp, "There is no appointment for %02d/%02d/%d", calendar->day, calendar->month, calendar->year); mesg[mesgLines++] = copyChar (temp); mesg[mesgLines++] = copyChar ("<#HL(30)>"); mesg[mesgLines++] = copyChar ("Press space to continue."); } /* Create the label widget. */ label = newCDKLabel (ScreenOf (calendar), CENTER, CENTER, (CDK_CSTRING2)mesg, mesgLines, TRUE, FALSE); drawCDKLabel (label, ObjOf (label)->box); waitCDKLabel (label, ' '); destroyCDKLabel (label); /* Clean up the memory used. */ for (x = 0; x < mesgLines; x++) { freeChar (mesg[x]); } /* Redraw the calendar widget. */ drawCDKCalendar (calendar, ObjOf (calendar)->box); return (FALSE); } /* * This allows the user to accelerate to a given date. */ static int accelerateToDateCB (EObjectType objectType GCC_UNUSED, void *object GCC_UNUSED, void *clientData GCC_UNUSED, chtype key GCC_UNUSED) { return (FALSE); }