rendered paste body////////////////////////////////////////////////////////////////////////// @file main.cc/// @author Kevin P. Rowe/// @date May 13, 2011/// @version 0.99/// @brief Main application./// @details Contains basically two compilation paths, one for curses/// interface, and one for standard C++ I/O if curses is not found or/// specifically disabled. Configure with --disable-curses to force/// curses support off. The program loads a data file (defaults to:/// "data/friendFile") into memory and displays information about a/// people and their birthdays. The data file should be in the following/// format:/// @code/// Kevin Rowe/// 111-555-1212/// 5/21/// Someone Else/// 222-555-1212/// 4/1/// @endcode////// @note The date is in format 'mm/dd' for the birthday. Make sure you/// use a forward slash ('/') for the separator.///////////////////////////////////////////////////////////////////////#include <iostream>#include <fstream>#include <sstream>#include <string>#include <cstring>#include "config.h"#include "node.h"#include "bdaybook.h"#ifdef HAVE_CURSES_H#include <curses.h>#undef clear#endif#ifdef HAVE_NCURSES_H#include <ncurses.h>#undef clear#endif#if defined( HAVE_CURSES_H ) || defined( HAVE_NCURSES_H )#define USE_CURSES 1#else#define USE_CURSES 0#endifusing namespace std;/// The createNode function./// Creates a new dynamic node of type @e bdayNode and returns a/// pointer to it./// @param name string name of person/// @param phone string phone number/// @param month int numeric month/// @param day int numeric day/// @return pointer to new bdayNode objectbdayNodePtr createNode( string name, string phone, int month , int day );/// printMenu function. Convenience function to save space. Prints menu/// using stdout.void printMenu();/// addNode function. Convenience function to save space. Gets input/// from stdin, creates a bdayNode object and adds it to BDayList @e l.void addNode( BDayList &l );#if defined( HAVE_CURSES_H ) || defined( HAVE_NCURSES_H )/// genCursesMenu function. Creates the curses menu on curses window/// @e scr. Uses color if available./// @todo Do screen bounds checking to make sure menu fits on screen/// properly.void genCursesMenu( WINDOW *scr );/// create_newwin function. Creates a new curses window with dimensions/// given and prints a border around it./// @return pointer to new WINDOW objectWINDOW *create_newwin( int, int, int, int );/// destroy_win function. Destroys window object @e local_win./// @note This does not clear window content, please do that before/// calling this function.void destroy_win(WINDOW *local_win);#endifint main( int argc, char *argv[] ){ // Some initial main variables. They are reused in various places, // however their names always coincide with their use. string filename = "data/friendFile"; // default file to load string name, phone, date; stringstream inDate; int month, day, found; BDayList list; bdayNodePtr newNode; char choice; int cchoice; if ( argc > 1 ) // Allow specifying a different filename on command // line. { if ( !strcmp( "-f", argv[1])) { filename = argv[2]; } } fstream file; file.open( filename.c_str(), fstream::in ); if ( file.fail() ) { cout << "Error opening file \"" << filename << "\"!" << endl; return 1; } while ( file.good() ) // Load in the main DB file { getline( file, name ); getline( file, phone ); getline( file, date ); inDate.str( date ); inDate >> month; inDate.ignore( 1, '/' ); inDate >> day; if ( !file.eof() ) { newNode = createNode( name, phone, month, day ); list.insert( newNode ); } inDate.clear(); } file.close(); list.sort(); bool loopVar = true; bool *map;#if USE_CURSES // Do some curses initialization stuff if it's enabled initscr(); noecho(); cbreak(); nonl(); intrflush( stdscr, FALSE ); keypad( stdscr, TRUE ); int pminrow = 0; int pmincol = 0; int sminrow = 2; int smaxrow = LINES - 2; int smincol = 0; int smaxcol = COLS - 3; char inName[30]; char inPhone[20]; char winDate[11]; bool monthMode = false; int setMonth; string fName, fPhone; stringstream fBirthday; WINDOW *popupWin, *mainPad, *rightWin;#endif while ( loopVar ) // Main application loop {#if USE_CURSES // Curses I/O if enabled // Curses window pointers mainPad = newpad( list.getSize(), 44 ); if (has_colors()) { start_color(); init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); init_pair(3, COLOR_YELLOW, COLOR_BLACK); init_pair(4, COLOR_BLUE, COLOR_BLACK); init_pair(5, COLOR_CYAN, COLOR_BLACK); init_pair(6, COLOR_MAGENTA, COLOR_BLACK); init_pair(7, COLOR_WHITE, COLOR_BLACK); } genCursesMenu( stdscr ); if( has_colors() ) attron( A_BOLD | COLOR_PAIR(4)); else attron( A_BOLD ); mvprintw( 1, 2, "Name:" ); mvprintw( 1, 21, "Phone num:" ); mvprintw( 1, 35, "Birthday:" ); if( has_colors() ) attroff( A_BOLD | COLOR_PAIR(4)); else attroff( A_BOLD ); list.sort(); for ( int i = 0; i < list.getSize(); i++ ) { if ( list[i].month == setMonth && monthMode ) { wattron( mainPad, A_BOLD | A_STANDOUT ); if ( has_colors() ) wattron( mainPad, COLOR_PAIR(1)); mvwprintw( mainPad, i, 0, " "); } mvwprintw( mainPad, i, 1, "%s", list[i].name.c_str() ); mvwprintw( mainPad, i, 20, "%s", list[i].phone.c_str() ); mvwprintw( mainPad, i, 37, "%d/%d", list[i].month, list[i].day ); if ( list[i].month == setMonth && monthMode ) { wattroff( mainPad, A_BOLD | A_STANDOUT ); if ( has_colors() ) wattroff( mainPad, COLOR_PAIR(1)); } } rightWin = create_newwin( 10, 30, (LINES - 10) / 2, ((COLS + ( COLS/2 ) - 30 )/2) ); mvwprintw( rightWin, 1, 2, "File: %s", filename.c_str()); mvwprintw( rightWin, 3, 2, "Records: %d", list.getSize()); if ( fName.size() > 0 ) { wattron( rightWin, A_BOLD ); mvwprintw( rightWin, 5, 2, "Record Search: " ); mvwprintw( rightWin, 6, 4, "Name:" ); mvwprintw( rightWin, 7, 4, "Phone:"); mvwprintw( rightWin, 8, 4, "Birthday:"); wattroff( rightWin, A_BOLD ); mvwprintw( rightWin, 6, 10, "%s", fName.c_str() ); mvwprintw( rightWin, 7, 11, "%s", fPhone.c_str() ); mvwprintw( rightWin, 8, 14, "%s", (fBirthday.str()).c_str() ); } wrefresh( rightWin ); prefresh( mainPad, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol ); refresh(); cchoice = getch(); switch( cchoice ) { case KEY_F(5): // F5 Key - Add New Record // Create popup Window to get user input for name popupWin = create_newwin( 3, 35, (LINES - 5)/2, (COLS - 35)/2 ); wbkgd( popupWin, A_STANDOUT ); mvwprintw( popupWin, 1, 2, "Enter name: "); wrefresh( popupWin ); // Get user input echo(); wgetnstr( popupWin, inName, 25 ); noecho(); // Clear and destroy popup window werase( popupWin ); destroy_win( popupWin ); // Create another popup for second input popupWin = create_newwin( 3, 51, (LINES - 5)/2, (COLS - 51)/2 ); wbkgd( popupWin, A_STANDOUT ); mvwprintw( popupWin, 1, 2, "Enter phone num. ( 123-456-7890 ): "); wrefresh( popupWin ); // Get input echo(); wgetnstr( popupWin, inPhone, 15 ); noecho(); // Clear and destroy popup window werase( popupWin ); destroy_win( popupWin ); // Create another popup popupWin = create_newwin( 3, 34, (LINES - 5)/2, (COLS - 34)/2 ); wbkgd( popupWin, A_STANDOUT ); mvwprintw( popupWin, 1, 2, "Enter birthdate (mm/dd): "); wrefresh( popupWin ); // Get input echo(); wgetnstr( popupWin, winDate, 10 ); noecho(); // Clear and destroy window werase( popupWin ); destroy_win( popupWin ); // Convert c-strings to strings and such name = inName; phone = inPhone; inDate.str( winDate ); inDate >> month; inDate.ignore( 1, '/' ); inDate >> day; // Create and insert node into linked list newNode = createNode( name, phone, month, day ); list.insert( newNode ); // Stringstreams don't clear themselves so we need this inDate.clear(); break; case KEY_F(6): // F6 - Delete a record // Create new popup win for user input popupWin = create_newwin( 3, 43, (LINES - 5)/2, (COLS - 43)/2 ); wbkgd( popupWin, A_STANDOUT ); mvwprintw( popupWin, 1, 2, "Enter name to delete: "); wrefresh( popupWin ); // Get input echo(); wgetnstr( popupWin, inName, 19 ); noecho(); // Clear and destroy popup werase( popupWin ); destroy_win( popupWin ); // C-string to string name = inName; // If found, then remove, otherwise make another // popup that says it was not found. if ( list.findByName( name ) != -1 ) list.remove( list.findByName( name )); else { popupWin = create_newwin( 3, 19, (LINES - 5)/2, (COLS - 43)/2 ); wbkgd( popupWin, A_STANDOUT ); mvwprintw( popupWin, 1, 2, "Name not found!"); wrefresh( popupWin ); getch(); // wait for key press // erase and destroy popup werase( popupWin ); destroy_win( popupWin ); } break; case KEY_F(7): // F7 - Find a specific name // Create new popup win for user input popupWin = create_newwin( 3, 43, (LINES - 5)/2, (COLS - 43)/2 ); wbkgd( popupWin, A_STANDOUT ); mvwprintw( popupWin, 1, 2, "Enter name to find: "); wrefresh( popupWin ); // Get input echo(); wgetnstr( popupWin, inName, 19 ); noecho(); // Clear and destroy popup werase( popupWin ); destroy_win( popupWin ); // C-string to string name = inName; // If found, then remove, otherwise make another // popup that says it was not found. if ( list.findByName( name ) != -1 ) { fName = list[list.findByName( name )].name; fPhone = list[list.findByName( name )].phone; fBirthday.str(""); fBirthday.clear(); fBirthday << list[list.findByName(name)].month << '/' << list[list.findByName(name)].day; } else { popupWin = create_newwin( 3, 19, (LINES - 5)/2, (COLS - 43)/2 ); wbkgd( popupWin, A_STANDOUT ); mvwprintw( popupWin, 1, 2, "Name not found!"); wrefresh( popupWin ); getch(); // wait for key press // erase and destroy popup werase( popupWin ); destroy_win( popupWin ); } break; case KEY_F(8): // F8 - List highlight month // Create new popup win for user input popupWin = create_newwin( 3, 39, (LINES - 5)/2, (COLS - 39)/2 ); wbkgd( popupWin, A_STANDOUT ); mvwprintw( popupWin, 1, 2, "Enter month to highlight (1-12): "); wrefresh( popupWin ); // Get input echo(); wgetnstr( popupWin, winDate, 4 ); noecho(); // Clear and destroy popup werase( popupWin ); destroy_win( popupWin ); // Quick string to int conversion inDate.str( winDate ); inDate >> setMonth; inDate.clear(); // If month is between 1-12 inclusive, turn on // month highlight mode. if ( setMonth > 0 && setMonth < 13 ) monthMode = true; else { popupWin = create_newwin( 3, 18, (LINES - 5)/2, (COLS - 18)/2 ); wbkgd( popupWin, A_STANDOUT ); mvwprintw( popupWin, 1, 2, "Invalid Entry!" ); getch(); werase( popupWin ); destroy_win( popupWin ); } break; case KEY_F(9): // F9 - Exit loopVar = false; break; case KEY_UP: // Up arrow key - Scroll up if ( pminrow > 0 ) pminrow--; break; case KEY_DOWN: // Down arrow key - Scroll down if ( pminrow <= list.getSize() - smaxrow ) pminrow++; break; default: break; } wclear( mainPad ); delwin( mainPad ); werase( rightWin ); destroy_win( rightWin ); refresh();#else // Standard I/O if compiled without Curses support printMenu(); cout << "Enter a menu option: "; cin.get( choice ); cin.ignore( 1, '\n' ); switch( choice ) { case 'A': case 'a': addNode( list ); list.sort(); break; case 'D': case 'd': cout << "* Enter a name to delete: "; getline( cin, name ); if ( list.findByName( name ) != -1 ) list.remove( list.findByName( name )); else cout << "* Record not found!" << endl; break; case 'P': case 'p': list.output( cout ); break; case 'M': case 'm': cout << "* Enter month to list ( numeric 1-12 ): "; cin >> month; cin.ignore( 1, '\n'); map = list.findByMonth( month ); for ( int i = 0; i < list.getSize(); i++ ) { if ( map[i] ) { cout << "Name: " << list[i].name << endl << "Phone Num.: " << list[i].phone << endl << "Birthday: " << list[i].month << '/' << list[i].day << endl << endl; } } break; case 'F': case 'f': cout << "Enter name to search for: "; getline( cin, name ); found = list.findByName( name ); if ( found != -1 ) { cout << "Name: " << list[found].name << endl << "Phone Num.: " << list[found].phone << endl << "Birthday: " << list[found].month << '/' << list[found].day << endl << endl; } else cout << endl << "* Name not found" << endl; break; case 'Q': case 'q': loopVar = false; break; default: cout << "* Invalid choice!" << endl; break; } // End switch#endif // END USE_CURSES } // End While#if USE_CURSES endwin();#endif file.open( filename.c_str(), fstream::out ); if ( file.fail() ) { cout << "Error opening file for writing!" << endl; } else { list.output( file ); file.close(); } return 0;}bdayNodePtr createNode( string name, string phone, int month, int day ){ bdayNodePtr node = new bdayNode; node->name = name; node->phone = phone; node->month = month; node->day = day; node->next = NULL; return node;}void printMenu() { cout << "----------Birthday DB Main Menu----------" << endl << endl << "\ta. Add new record" << endl << "\td. Delete a record" << endl << "\tp. View all records" << endl << "\tm. Find all records in a month" << endl << "\tf. Find a record by name" << endl << "\tq. Save and quit" << endl << endl;}#if defined( HAVE_CURSES_H ) || defined( HAVE_NCURSES_H )void genCursesMenu( WINDOW *win ){ int row, col; curs_set( 0 ); if ( has_colors() ) { attron( A_BOLD | COLOR_PAIR(1) ); mvprintw( 0, (COLS - 21)/2, "Birthday DB Main Menu" ); attron( A_BOLD | COLOR_PAIR(2) ); } else attron( A_BOLD ); mvprintw( LINES - 1, (COLS - 77)/2, "F5" ); getyx( stdscr, row, col ); mvprintw( LINES - 1, col + 9, "F6" ); getyx( stdscr, row, col ); mvprintw( LINES - 1, col + 9, "F7" ); getyx( stdscr, row, col ); mvprintw( LINES - 1, col + 10, "F8" ); getyx( stdscr, row, col ); mvprintw( LINES - 1, col + 16, "F9" ); if ( has_colors() ) { attroff( A_BOLD | COLOR_PAIR(2) ); attron( COLOR_PAIR(4) ); } else attroff( A_BOLD ); mvprintw( LINES - 1, (COLS - 81)/2, "|"); getyx( stdscr, row, col ); mvprintw( LINES - 1, col + 4, "- Add |"); getyx( stdscr, row, col ); mvprintw( LINES - 1, col + 4,"- Del |"); getyx( stdscr, row, col ); mvprintw( LINES - 1, col + 4, "- Find |"); getyx( stdscr, row, col ); mvprintw( LINES - 1, col + 4, "- Find/Month |" ); getyx( stdscr, row, col ); mvprintw( LINES - 1, col + 4, "- Quit |" ); refresh(); if ( has_colors() ) attroff( COLOR_PAIR(4) );}WINDOW *create_newwin(int height, int width, int starty, int startx){ WINDOW *local_win; local_win = newwin(height, width, starty, startx); box(local_win, 0 , 0); wrefresh(local_win); return local_win;}void destroy_win(WINDOW *local_win){ wbkgd( local_win, A_NORMAL ); wborder(local_win, ' ', ' ', ' ',' ',' ',' ',' ',' '); wrefresh(local_win); delwin(local_win);}#endifvoid addNode( BDayList &l ){ string name, phone, date; stringstream inDate; int month, day; cout << "Enter name: "; getline( cin, name ); cout << "Enter phone number (In the following format: 123-456-7890): "; getline( cin, phone ); cout << "Enter birthday ( mm/dd ): "; getline( cin, date ); inDate.str( date ); inDate >> month; inDate.ignore( 1, '/' ); inDate >> day; bdayNodePtr newNode = createNode( name, phone, month, day ); l.insert( newNode );}