presage  0.8.7
presageDemo.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************
00003  *  Presage, an extensible predictive text entry system
00004  *  ---------------------------------------------------
00005  *
00006  *  Copyright (C) 2008  Matteo Vescovi <matteo.vescovi@yahoo.co.uk>
00007 
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 2 of the License, or
00011     (at your option) any later version.
00012 
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017 
00018     You should have received a copy of the GNU General Public License along
00019     with this program; if not, write to the Free Software Foundation, Inc.,
00020     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00021                                                                              *
00022                                                                 **********(*)*/
00023 
00024 
00025 #include "presage.h"
00026 
00027 #ifdef HAVE_CONFIG_H
00028 # include "config.h"
00029 #endif
00030 
00031 /* Solaris 10 needs to have NOMACROS defined to avoid conflict between
00032    curses and standard template library code.
00033  */
00034 #ifndef NOMACROS
00035 # define NOMACROS
00036 # include <curses.h>
00037 # undef NOMACROS
00038 #else
00039 # include <curses.h>
00040 #endif
00041 
00042 #ifdef HAVE_STDLIB_H
00043 # include <stdlib.h>
00044 #endif
00045 
00046 #include <getopt.h>
00047 
00048 #include <iostream>
00049 #include <sstream>
00050 #include <list>
00051 
00052 const char PROGRAM_NAME[] = "presage_demo";
00053 
00054 // prototypes
00055 //
00056 void parseCommandLineArgs(int argc, char** argv);
00057 void printUsage();
00058 void printVersion();
00059 
00060 void disclaimer();
00061 
00062 void draw_title_win(WINDOW*);
00063 void draw_context_win(WINDOW*, std::string);
00064 void draw_function_keys(WINDOW*);
00065 void draw_previous_suggestions(std::vector<std::string>, bool, const int, int);
00066 size_t getGreatestSuggestionLength(std::vector< std::string > suggestions);
00067 
00068 // globals
00069 std::string       suggestions;
00070 std::string       config;
00071 std::stringstream buffer;    // text buffer, a real application would
00072                              // use something a little more
00073                              // sophisticated than a stringstream
00074 
00086 class PresageDemoCallback : public PresageCallback {
00087 public:
00088     PresageDemoCallback(std::stringstream& buffer) : m_buffer(buffer) { }
00089 
00090     std::string get_past_stream() const { return m_buffer.str(); }
00091     std::string get_future_stream() const { return empty; }
00092 
00093 private:
00094     std::stringstream& m_buffer;
00095     const std::string empty;
00096 
00097 };
00098 
00114 int main(int argc, char** argv)
00115 {
00116     parseCommandLineArgs(argc, argv);
00117 
00118     // magic starts here
00119     PresageCallback* callback = new PresageDemoCallback(buffer); 
00120     Presage presage(callback, config);
00121 
00122     // configuration variable may be read and written programmatically
00123     if (suggestions.empty()) {
00124         suggestions = presage.config("Presage.Selector.SUGGESTIONS");
00125     } else {
00126         presage.config("Presage.Selector.SUGGESTIONS", suggestions);
00127     }
00128 
00129     // curses 
00130     initscr();
00131     noecho();
00132     cbreak();
00133     keypad(stdscr, TRUE);
00134     clear();
00135     refresh();
00136 
00137     disclaimer();
00138 
00139     // curses title window
00140     const int TITLE_WIN_HEIGHT  = 6;
00141     const int TITLE_WIN_WIDTH   = COLS;
00142     const int TITLE_WIN_BEGIN_Y = 0;
00143     const int TITLE_WIN_BEGIN_X = 0;
00144     WINDOW* title_win = newwin(TITLE_WIN_HEIGHT, TITLE_WIN_WIDTH, TITLE_WIN_BEGIN_Y, TITLE_WIN_BEGIN_X);
00145     draw_title_win(title_win);
00146 
00147     // curses context window
00148     const int CONTEXT_WIN_HEIGHT  = 5;
00149     const int CONTEXT_WIN_WIDTH   = COLS;
00150     const int CONTEXT_WIN_BEGIN_Y = TITLE_WIN_BEGIN_Y + TITLE_WIN_HEIGHT + 1;
00151     const int CONTEXT_WIN_BEGIN_X = 0;
00152     WINDOW* context_win = newwin(CONTEXT_WIN_HEIGHT, CONTEXT_WIN_WIDTH, CONTEXT_WIN_BEGIN_Y, CONTEXT_WIN_BEGIN_X);
00153     draw_context_win(context_win, std::string(""));
00154 
00155     // curses function keys window
00156     const int FUNCTION_WIN_HEIGHT  = atoi(suggestions.c_str()) + 2;
00157     const int FUNCTION_WIN_WIDTH   = 4;
00158     const int FUNCTION_WIN_BEGIN_Y = CONTEXT_WIN_BEGIN_Y + CONTEXT_WIN_HEIGHT + 1;
00159     const int FUNCTION_WIN_BEGIN_X = 0;
00160     WINDOW* function_win = newwin(FUNCTION_WIN_HEIGHT, FUNCTION_WIN_WIDTH, FUNCTION_WIN_BEGIN_Y, FUNCTION_WIN_BEGIN_X);
00161     draw_function_keys(function_win);
00162 
00163     mvprintw(LINES - 1, 0, "Press F12 to quit.");
00164     refresh();
00165 
00166 
00167     std::vector<std::string> words;
00168     unsigned int c = ' ';
00169     do {
00170         size_t size = words.size();
00171         if ((KEY_F0 < c) && (c <= KEY_F(size)) && (c - KEY_F0 <= size)) {
00172             // prediction was successful. user pressed the function
00173             // key corresponding to desired token. selecting
00174             // suggestion.
00175             std::string message = "Last selected word: " + words[c - KEY_F0 - 1];
00176             mvprintw(LINES - 3, 0, message.c_str());
00177             clrtoeol();
00178             move(LINES, COLS);
00179 
00180             // update buffer with prediction completion
00181             buffer << presage.completion(words[c - KEY_F0 - 1]);
00182             // ask presage to predict next token
00183             words = presage.predict();
00184 
00185         } else {
00186             // prediction unsuccessful. get next character from user
00187             // and elaborate a new prediction.
00188             buffer << static_cast<char>(c);
00189             words = presage.predict();
00190 
00191             // refresh curses screen
00192             refresh();
00193         }
00194         draw_context_win(context_win, presage.context());
00195         draw_previous_suggestions(words,
00196                                   presage.context_change(),
00197                                   CONTEXT_WIN_BEGIN_Y + CONTEXT_WIN_HEIGHT + 1,
00198                                   FUNCTION_WIN_BEGIN_X + FUNCTION_WIN_WIDTH + 1 );
00199         c = getch();
00200 
00201     } while( c != KEY_F(12) );
00202 
00203     delwin(title_win);
00204     delwin(context_win);
00205     delwin(function_win);
00206     endwin();
00207 
00208     return 0;
00209 }
00210 
00211 
00212 void draw_context_win(WINDOW* win, std::string str)
00213 {
00214     wclear( win );
00215     box( win, 0, 0 );
00216     mvwprintw( win, 1, 1, str.c_str() );
00217     wrefresh( win );
00218 }
00219 
00220 
00221 void drawMsgWin( WINDOW* win, std::vector<std::string> words )
00222 {
00223     wclear( win );
00224     box( win, 0, 0 );
00225         
00226     int i = 1;
00227     std::vector<std::string>::const_iterator j = words.begin();
00228     while( j != words.end() ) {
00229         mvwprintw( win, i, 1, j->c_str() );
00230         i++;
00231         j++;
00232     }
00233 
00234     wrefresh( win );
00235 }
00236 
00237 void draw_function_keys(WINDOW* win)
00238 {
00239     wclear(win);
00240     box(win, 0, 0);
00241     for (int i = 1; i <= atoi(suggestions.c_str()); i++) {
00242         std::stringstream ss;
00243         ss << 'F' << i;
00244         mvwprintw(win, i, 1, ss.str().c_str());
00245     }
00246     wrefresh(win);
00247 }
00248 
00249 void draw_previous_suggestions(std::vector<std::string> words, bool contextChange,
00250                                const int starty, int startx)
00251 {
00252     static std::list< std::vector<std::string> > previousSuggestions;
00253     static std::vector< WINDOW* > windows;
00254 
00255     // clear out existing windows
00256     for (std::vector< WINDOW* >::iterator winit = windows.begin();
00257          winit != windows.end();
00258          winit++) {
00259         wclear(*winit);
00260         wrefresh(*winit);
00261         delwin(*winit);
00262     }
00263     windows.clear();
00264 
00265     if (contextChange) {
00266         // insert a context change marker in the list of previous
00267         // suggestions
00268         // 
00269         std::vector< std::string > marker;
00270         for (int i = 0; i < atoi(suggestions.c_str()); i++) {
00271             marker.push_back("|");
00272         }
00273         previousSuggestions.insert(previousSuggestions.begin(), marker);
00274     }
00275 
00276     previousSuggestions.insert(previousSuggestions.begin(), words);
00277 
00278     for (std::list< std::vector<std::string> >::const_iterator listit = previousSuggestions.begin();
00279          (listit != previousSuggestions.end() && startx < COLS); // don't draw window off the screen
00280          listit++) {
00281 
00282         int height = listit->size() + 2;
00283         int width = getGreatestSuggestionLength(*listit) + 2;
00284 
00285         WINDOW* win = newwin(height, width, starty, startx);
00286         wclear(win);
00287         box(win, 0, 0);
00288 
00289         int line = 1;
00290         for (std::vector<std::string>::const_iterator strit = listit->begin();
00291              strit != listit->end();
00292              strit++) {
00293             
00294             mvwprintw(win, line, 1, strit->c_str());
00295             line++;
00296         }
00297 
00298         wrefresh(win);
00299         windows.push_back(win);
00300         startx += width + 2;
00301     }
00302 }
00303 
00304 size_t getGreatestSuggestionLength(std::vector< std::string > suggestions)
00305 {
00306     size_t result = 0;
00307     for (std::vector< std::string >::const_iterator it = suggestions.begin();
00308          it != suggestions.end();
00309          it++) {
00310         if (it->size() > result) {
00311             result = it->size();
00312         }
00313     }
00314     return result;
00315 }
00316 
00317 void disclaimer()
00318 {
00319     int topBottomBorder = (LINES/8);
00320     int borderWinHeight = 15;
00321     int borderWinWidth  = 70;
00322     int sideBorder      = (COLS - borderWinWidth) / 2;
00323     WINDOW* borderWin     = newwin(borderWinHeight, borderWinWidth, topBottomBorder, sideBorder);
00324     WINDOW* disclaimerWin = newwin(borderWinHeight-2, borderWinWidth-2, topBottomBorder+1, sideBorder+1);
00325     box(borderWin, 0, 0);
00326     wrefresh(borderWin);
00327     wprintw(disclaimerWin,
00328             "Presage Demo\n"
00329             "------------\n"
00330             "This program is intended as a demonstration of Presage ONLY.\n"
00331             "\n"
00332             "The Presage project aims to provide an intelligent predictive\n"
00333             "text entry platform.\n"
00334             "\n"
00335             "Its intent is NOT to provide a predictive text entry user interface.\n"
00336             "Think of Presage as the predictive backend that sits behind a\n"
00337             "shiny user interface and does all the predictive heavy lifting.\n"
00338         );
00339     mvwprintw(disclaimerWin, (borderWinHeight-2)-1, 1, "Press any key to continue...");
00340     wrefresh(disclaimerWin);
00341 
00342     getch();
00343 
00344     delwin(disclaimerWin);
00345     delwin(borderWin);
00346 
00347     clear();
00348     refresh();
00349 }
00350 
00351 void draw_title_win(WINDOW* title_win)
00352 {
00353     wclear(title_win);
00354     box(title_win, 0, 0);
00355     mvwprintw(title_win, 1, 1, "Presage Demo ", VERSION);
00356     mvwprintw(title_win, 2, 1, "Copyright (C) Matteo Vescovi");
00357     mvwprintw(title_win, 3, 1, "This is free software; see the source for copying conditions.  There is NO");
00358     mvwprintw(title_win, 4, 1, "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
00359     wrefresh(title_win);
00360 }
00361 
00362 void parseCommandLineArgs(int argc, char* argv[])
00363 {
00364     int next_option;
00365         
00366     // getopt structures
00367     const char* const short_options = "c:s:hv";
00368 
00369     const struct option long_options[] = {
00370         { "config",       required_argument, 0, 'c' },
00371         { "suggestions",  required_argument, 0, 's' },
00372         { "help",         no_argument,       0, 'h' },
00373         { "version",      no_argument,       0, 'v' },
00374         { 0, 0, 0, 0 }
00375     };
00376 
00377     do {
00378         next_option = getopt_long( argc, argv, 
00379                                    short_options, long_options, NULL );
00380                 
00381         switch( next_option ) {
00382         case 'c': // --config or -c option
00383             config = optarg;
00384             break;
00385         case 's': // --suggestions or -s option
00386             suggestions = optarg;
00387             break;
00388         case 'h': // --help or -h option
00389             printUsage();
00390             exit (0);
00391             break;
00392         case 'v': // --version or -v option
00393             printVersion();
00394             exit (0);
00395             break;
00396         case '?': // unknown option
00397             printUsage();
00398             exit (0);
00399             break;
00400         case -1:
00401             break;
00402         default:
00403             abort();
00404         }
00405 
00406     } while( next_option != -1 );
00407 }
00408 
00409 void printVersion()
00410 {
00411     std::cout << PROGRAM_NAME << " (" << PACKAGE << ") version " << VERSION << std::endl
00412               << "Copyright (C) 2004 Matteo Vescovi." << std::endl
00413               << "This is free software; see the source for copying conditions.  There is NO" << std::endl
00414               << "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE," << std::endl
00415               << "to the extent permitted by law." << std::endl;
00416 }
00417 
00418 void printUsage()
00419 {
00420     std::cout << "Usage: " << PROGRAM_NAME << " [OPTION]..." << std::endl
00421               << std::endl
00422               << "Begin typing. presage will attempt to predict the desired word." << std::endl
00423               << "After each keystroke, presage will return a number of predictions." << std::endl
00424               << "If the desired word appears in the prediction list, select it by pressing the" << std::endl
00425               << "corresponding function key." << std::endl
00426               << std::endl
00427               << "  -c, --config CONFIG  use config file CONFIG" << std::endl
00428               << "  -s, --suggestions N  set prediction size to N suggestions" << std::endl
00429               << "  -h, --help           display this help and exit" << std::endl
00430               << "  -v, --version        output version information and exit" << std::endl
00431               << std::endl
00432               << "Direct your bug reports to: " << PACKAGE_BUGREPORT << std::endl;
00433 }