presage
0.8.7
|
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 }