Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

qimpeninput.cpp

Go to the documentation of this file.
00001 /**********************************************************************
00002 ** Copyright (C) 2000-2002 Trolltech AS.  All rights reserved.
00003 **
00004 ** This file is part of the Qtopia Environment.
00005 **
00006 ** This file may be distributed and/or modified under the terms of the
00007 ** GNU General Public License version 2 as published by the Free Software
00008 ** Foundation and appearing in the file LICENSE.GPL included in the
00009 ** packaging of this file.
00010 **
00011 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00012 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00013 **
00014 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
00015 **
00016 ** Contact info@trolltech.com if any conditions of this licensing are
00017 ** not clear to you.
00018 **
00019 **********************************************************************/
00020 
00021 #include "qimpenwidget.h"
00022 #include "qimpensetup.h"
00023 #include "qimpeninput.h"
00024 #include "qimpencombining.h"
00025 #include "qimpenwordpick.h"
00026 #include "qimpenmatch.h"
00027 #include "qimpenhelp.h"
00028 
00029 #include <qpe/qpeapplication.h>
00030 #include <qpe/qdawg.h>
00031 #include <qpe/config.h>
00032 #include <qpe/global.h>
00033 
00034 #include <qlayout.h>
00035 #include <qpushbutton.h>
00036 #include <qlabel.h>
00037 #include <qtimer.h>
00038 #include <qdir.h>
00039 #include <opie2/odebug.h>
00040 
00041 #include <limits.h>
00042 
00043 // We'll use little pixmaps for the buttons to save screen space.
00044 
00045 /* XPM */
00046 static const char * const pen_xpm[] = {
00047 "12 12 4 1",
00048 "       c None",
00049 ".      c #000000",
00050 "+      c #FFFFFF",
00051 "@      c #808080",
00052 "         .  ",
00053 "        .+. ",
00054 "       ..@@.",
00055 "      .+@.. ",
00056 "     .+@@.  ",
00057 "    .+@@.   ",
00058 "   .+@@.    ",
00059 "  .@.@.     ",
00060 "  .@@.      ",
00061 " ....       ",
00062 " ..         ",
00063 "            "};
00064 
00065 
00066 /* XPM */
00067 static char * bs_xpm[] = {
00068 "12 12 5 1",
00069 "       c None",
00070 ".      c #333333",
00071 "+      c #000000",
00072 "@      c #FFFFFF",
00073 "#      c #666666",
00074 "            ",
00075 "            ",
00076 "            ",
00077 "    .       ",
00078 "   ++       ",
00079 "  +@#+++++. ",
00080 " +@@@@@@@@+ ",
00081 "  +@#+++++. ",
00082 "   ++       ",
00083 "    .       ",
00084 "            ",
00085 "            "};
00086 
00087 
00088 /* XPM */
00089 static char * enter_xpm[] = {
00090 "12 12 5 1",
00091 "       c None",
00092 ".      c #333333",
00093 "+      c #000000",
00094 "@      c #FFFFFF",
00095 "#      c #666666",
00096 "            ",
00097 "        .+. ",
00098 "        +@+ ",
00099 "    .   +@+ ",
00100 "   ++   +@+ ",
00101 "  +@#++++@+ ",
00102 " +@@@@@@@@+ ",
00103 "  +@#+++++. ",
00104 "   ++       ",
00105 "    .       ",
00106 "            ",
00107 "            "};
00108 
00109 
00110 
00111 /* XPM */
00112 static char * help_xpm[] = {
00113 "12 12 5 1",
00114 "       c None",
00115 ".      c #000000",
00116 "+      c #FFFFFF",
00117 "@      c #666666",
00118 "#      c #333333",
00119 "            ",
00120 "    ...     ",
00121 "   .+++.    ",
00122 "  .+..@+.   ",
00123 "  #.# .+.   ",
00124 "      .+.   ",
00125 "     .+.    ",
00126 "    .+.     ",
00127 "    .+.     ",
00128 "    #.#     ",
00129 "    .+.     ",
00130 "    #.#     "};
00131 
00132 
00138 QIMPenInput::QIMPenInput( QWidget *parent, const char *name, WFlags wf )
00139     : QFrame( parent, name, wf ), helpDlg(0), profile(0)
00140 {
00141     setFrameStyle( Box | Plain );
00142 
00143     profileList.setAutoDelete( true );
00144 
00145     matcher = new QIMPenMatch( this );
00146     connect( matcher, SIGNAL(keypress(uint)), this, SLOT(keypress(uint)) );
00147     connect( matcher, SIGNAL(erase()), this, SLOT(erase()) );
00148 
00149     QGridLayout *gl = new QGridLayout( this, 5, 2, 1, 0 );
00150     gl->setColStretch( 0, 1 );
00151 
00152     wordPicker = new QIMPenWordPick( this );
00153     connect( wordPicker, SIGNAL(wordClicked(const QString&)),
00154              this, SLOT(wordPicked(const QString&)) );
00155     connect( matcher, SIGNAL(matchedCharacters(const QIMPenCharMatchList&)),
00156              this, SLOT(matchedCharacters(const QIMPenCharMatchList&)) );
00157     connect( matcher, SIGNAL(matchedWords(const QIMPenMatch::MatchWordList&)),
00158              wordPicker, SLOT(setWords(const QIMPenMatch::MatchWordList&)) );
00159     QFont f("smallsmooth",9);
00160     QFontInfo fi( f );
00161     wordPicker->setFont( f );
00162     wordPicker->setBackgroundColor( white );
00163     gl->addMultiCellWidget( wordPicker, 0, 0, 0, 1 );
00164     if ( !Global::fixedDawg().root() || !matcher->isWordMatchingEnabled() )
00165         wordPicker->hide();
00166 
00167     pw = new QIMPenWidget( this );
00168     gl->addMultiCellWidget( pw, 1, 4, 0, 0 );
00169 
00170     int bh = pw->sizeHint().height()/4;
00171 
00172     QPushButton *b = new QPushButton( this );
00173     b->setFocusPolicy( NoFocus );
00174     b->setPixmap( QPixmap( (const char **)bs_xpm ) );
00175     b->setFixedHeight(pw->sizeHint().height()-3*bh); // left-over space goes here
00176     b->setAutoRepeat( TRUE );
00177     gl->addWidget( b, 1, 1 );
00178     connect( b, SIGNAL(clicked()), SLOT(backspace()));
00179 
00180     b = new QPushButton( this );
00181     b->setFocusPolicy( NoFocus );
00182     b->setPixmap( QPixmap( (const char **)enter_xpm ) );
00183     b->setFixedHeight(bh);
00184     b->setAutoRepeat( TRUE );
00185     gl->addWidget( b, 2, 1 );
00186     connect( b, SIGNAL(clicked()), SLOT(enter()));
00187 
00188     helpBtn = new QPushButton( this );
00189     helpBtn->setFocusPolicy( NoFocus );
00190     helpBtn->setPixmap( QPixmap( (const char **)help_xpm ) );
00191     helpBtn->setFixedHeight(bh);
00192     gl->addWidget( helpBtn, 3, 1 );
00193     connect( helpBtn, SIGNAL(clicked()), SLOT(help()));
00194 
00195     QPixmap pm( (const char **)pen_xpm );
00196     setupBtn = new QPushButton( this );
00197     setupBtn->setFocusPolicy( NoFocus );
00198     setupBtn->setPixmap( pm );
00199     setupBtn->setFixedHeight(bh);
00200     gl->addWidget( setupBtn, 4, 1 );
00201     connect( setupBtn, SIGNAL(clicked()), SLOT(setup()));
00202 
00203     connect( matcher, SIGNAL(removeStroke()), pw, SLOT(removeStroke()) );
00204     connect( pw, SIGNAL(changeCharSet(QIMPenCharSet*)),
00205              matcher, SLOT(setCharSet(QIMPenCharSet*)) );
00206     connect( pw, SIGNAL(changeCharSet(int)),
00207              this, SLOT(selectCharSet(int)) );
00208     connect( pw, SIGNAL(beginStroke()),
00209              matcher, SLOT(beginStroke()) );
00210     connect( pw, SIGNAL(stroke(QIMPenStroke*)),
00211              this, SLOT(strokeEntered(QIMPenStroke*)) );
00212     connect( pw, SIGNAL(stroke(QIMPenStroke*)),
00213              matcher, SLOT(strokeEntered(QIMPenStroke*)) );
00214 
00215     shortcutCharSet = 0;
00216     currCharSet = 0;
00217     setupDlg = 0;
00218     profile = 0;
00219     mode = Normal;
00220 
00221     loadProfiles();
00222 }
00223 
00224 QIMPenInput::~QIMPenInput()
00225 {
00226     delete (HandwritingHelp*) helpDlg;
00227 }
00228 
00229 QSize QIMPenInput::sizeHint() const
00230 {
00231     int fw = frameWidth();
00232     int ps = wordPicker->isHidden() ? 0 : wordPicker->sizeHint().height();
00233     return pw->sizeHint() + QSize( fw*2, fw*2+ps );
00234 }
00235 
00236 void QIMPenInput::loadProfiles()
00237 {
00238     profileList.clear();
00239     profile = 0;
00240     delete shortcutCharSet;
00241     shortcutCharSet = new QIMPenCharSet();
00242     shortcutCharSet->setTitle( tr("Shortcut") );
00243     QString path = QPEApplication::qpeDir() + "etc/qimpen";
00244     QDir dir( path, "*.conf" );
00245     QStringList list = dir.entryList();
00246     QStringList::Iterator it;
00247     for ( it = list.begin(); it != list.end(); ++it ) {
00248         QIMPenProfile *p = new QIMPenProfile( path + "/" + *it );
00249         profileList.append( p );
00250         if ( p->shortcut() ) {
00251             QIMPenCharIterator it( p->shortcut()->characters() );
00252             for ( ; it.current(); ++it ) {
00253                 shortcutCharSet->addChar( new QIMPenChar(*it.current()) );
00254             }
00255         }
00256     }
00257 
00258     Config config( "handwriting" );
00259     config.setGroup( "Settings" );
00260     QString prof = config.readEntry( "Profile", "Default" );
00261     selectProfile( prof );
00262 }
00263 
00264 void QIMPenInput::selectProfile( const QString &name )
00265 {
00266     QListIterator<QIMPenProfile> it( profileList );
00267     for ( ; it.current(); ++it ) {
00268         if ( it.current()->name() == name ) {
00269             profile = it.current();
00270             break;
00271         }
00272     }
00273 
00274     if ( !it.current() )
00275         return;
00276 
00277     pw->clearCharSets();
00278     baseSets.clear();
00279 
00280     matcher->setMultiStrokeTimeout( profile->multiStrokeTimeout() );
00281     matcher->setWordMatchingEnabled( profile->matchWords() );
00282 
00283     if ( !Global::fixedDawg().root() || !matcher->isWordMatchingEnabled() )
00284         wordPicker->hide();
00285     else
00286         wordPicker->show();
00287 
00288     if ( profile->uppercase() && profile->style() == QIMPenProfile::BothCases ) {
00289         baseSets.append( profile->uppercase() );
00290         pw->insertCharSet( profile->uppercase() );
00291     }
00292 
00293     if ( profile->lowercase() ) {
00294         baseSets.append( profile->lowercase() );
00295         pw->insertCharSet( profile->lowercase(), profile->style() == QIMPenProfile::BothCases ? 1 : 2 );
00296     }
00297 
00298     if ( profile->numeric() ) {
00299         baseSets.append( profile->numeric() );
00300         pw->insertCharSet( profile->numeric() );
00301     }
00302 
00303     if ( helpDlg )
00304         delete (HandwritingHelp*) helpDlg;
00305 }
00306 
00307 void QIMPenInput::wordPicked( const QString &w )
00308 {
00309     int bs = matcher->word().length();
00310     for ( int i = 0; i < bs; i++ )
00311         keypress( Qt::Key_Backspace << 16 );
00312 
00313     for ( unsigned int i = 0; i < w.length(); i++ )
00314         keypress( w[i].unicode() );
00315 
00316     matcher->resetState();
00317     wordPicker->clear();
00318 }
00319 
00320 void QIMPenInput::selectCharSet( int idx )
00321 {
00322     if ( mode == Switch ) {
00323         //odebug << "Switch back to normal" << oendl;
00324         pw->changeCharSet( baseSets.at(currCharSet), currCharSet );
00325         mode = Normal;
00326     }
00327     currCharSet = idx;
00328 }
00329 
00330 void QIMPenInput::beginStroke()
00331 {
00332 }
00333 
00334 void QIMPenInput::strokeEntered( QIMPenStroke * )
00335 {
00336     pw->greyStroke();
00337 }
00338 
00339 void QIMPenInput::erase()
00340 {
00341     keypress( Qt::Key_Backspace << 16 );
00342 }
00343 
00344 void QIMPenInput::matchedCharacters( const QIMPenCharMatchList &cl )
00345 {
00346     const QIMPenChar *ch = cl.first().penChar;
00347     int scan = ch->character() >> 16;
00348 
00349     if ( scan < QIMPenChar::ModeBase )
00350         return;
00351 
00352     // We matched a special character...
00353 
00354     switch ( scan ) {
00355         case QIMPenChar::Caps:
00356             if ( profile->style() == QIMPenProfile::ToggleCases ) {
00357 //              odebug << "Caps" << oendl;
00358 //              
00359                 if ( mode == SwitchLock ) {
00360 //                  odebug << "Switch to normal" << oendl;
00361                     pw->changeCharSet( profile->lowercase(), currCharSet );
00362                     mode = Switch;
00363                 } else {
00364 //                  odebug << "Switch to upper" << oendl;
00365                     pw->changeCharSet( profile->uppercase(), currCharSet );
00366                     mode = Switch;
00367                 }
00368             }
00369             break;
00370         case QIMPenChar::CapsLock:
00371             if ( profile->style() == QIMPenProfile::ToggleCases ) {
00372 //              odebug << "CapsLock" << oendl;
00373                 if ( mode == Switch &&
00374                      baseSets.at(currCharSet) == profile->uppercase() ) {
00375 //                  odebug << "Switch to normal" << oendl;
00376                     pw->changeCharSet( profile->lowercase(), currCharSet );
00377                     // change our base set back to lower.
00378                     baseSets.remove( currCharSet );
00379                     baseSets.insert( currCharSet, profile->lowercase() );
00380                     mode = Normal;
00381                 } else {                
00382 //                  odebug << "Switch to caps lock" << oendl;
00383                     pw->changeCharSet( profile->uppercase(), currCharSet );
00384                     // change our base set to upper.
00385                     baseSets.remove( currCharSet );
00386                     baseSets.insert( currCharSet, profile->uppercase() );
00387                     mode = SwitchLock;
00388                 }
00389             }
00390             break;
00391         case QIMPenChar::Punctuation:
00392             if ( profile->punctuation() ) {
00393                 //odebug << "Switch to punctuation" << oendl;
00394                 pw->changeCharSet( profile->punctuation(), currCharSet );
00395                 mode = Switch;
00396             }
00397             break;
00398         case QIMPenChar::Symbol:
00399             if ( profile->symbol() ) {
00400                 //odebug << "Switch to symbol" << oendl ;
00401                 pw->changeCharSet( profile->symbol(), currCharSet );
00402                 mode = Switch;
00403             }
00404             break;
00405         case QIMPenChar::Shortcut:
00406             if ( shortcutCharSet ) {
00407                 pw->changeCharSet( shortcutCharSet, currCharSet );
00408                 mode = Switch;
00409             }
00410             break;
00411         case QIMPenChar::Extended:
00412             handleExtended( ch->data() );
00413             break;
00414     }
00415 }
00416 
00417 void QIMPenInput::keypress( uint scan_uni )
00418 {
00419     int scan = scan_uni >> 16;
00420     if ( !scan ) {
00421         if ( scan_uni >= 'a' && scan_uni <= 'z' ) {
00422             scan = Qt::Key_A + scan_uni - 'a';
00423         } else if ( scan_uni >= 'A' && scan_uni <= 'Z' ) {
00424             scan = Qt::Key_A + scan_uni - 'A';
00425         } else if ( scan_uni == ' ' ) {
00426             scan = Qt::Key_Space;
00427         }
00428     }
00429 
00430     switch ( scan ) {
00431         case Key_Tab:
00432             scan_uni = 9;
00433             break;
00434         case Key_Return:
00435             scan_uni = 13;
00436             break;
00437         case Key_Backspace:
00438             scan_uni = 8;
00439             break;
00440         case Key_Escape:
00441             scan_uni = 27;
00442             break;
00443         default:
00444             break;
00445     }
00446 
00447     if ( mode == Switch ) {
00448 //      odebug << "Switch back to normal" << oendl ;
00449         pw->changeCharSet( baseSets.at(currCharSet), currCharSet );
00450         if ( baseSets.at(currCharSet) == profile->uppercase() )
00451             mode = SwitchLock;
00452         else
00453             mode = Normal;
00454     }
00455 
00456     emit key( scan_uni&0xffff, scan, 0, true, false );
00457     emit key( scan_uni&0xffff, scan, 0, false, false );
00458 }
00459 
00460 void QIMPenInput::handleExtended( const QString &ex )
00461 {
00462     if ( ex.find( "Select" ) == 0 ) {
00463         QString set = ex.mid( 7 );
00464         odebug << "Select new profile: " << set.latin1() << oendl;
00465         selectProfile( set );
00466     }
00467 }
00468 
00469 void QIMPenInput::help()
00470 {
00471     if ( helpDlg )
00472         delete (HandwritingHelp*) helpDlg;
00473     helpDlg = new HandwritingHelp( profile, 0, 0, WDestructiveClose );
00474     helpDlg->showMaximized();
00475     helpDlg->show();
00476     helpDlg->raise();
00477 }
00478 
00482 void QIMPenInput::setup()
00483 {
00484     if ( !setupDlg ) {
00485         // We are working with our copy of the char sets here.
00486         setupDlg = new QIMPenSetup( profile, 0, 0, TRUE );
00487         setupDlg->editor()->selectCharSet( profile->charSets().at(1) ); // lower case? This is crap.
00488         if ( qApp->desktop()->width() < 640 )
00489             setupDlg->showMaximized();
00490         Global::hideInputMethod();
00491         setupDlg->exec();
00492         loadProfiles();
00493         delete setupDlg;
00494         setupDlg = 0;
00495         Global::showInputMethod();
00496     } else {
00497         setupDlg->raise();
00498     }
00499 }
00500 
00501 void QIMPenInput::backspace()
00502 {
00503     keypress( Qt::Key_Backspace << 16 );
00504     matcher->backspace();
00505 }
00506 
00507 void QIMPenInput::enter()
00508 {
00509     keypress( Qt::Key_Return << 16 );
00510     matcher->resetState();
00511 }
00512 
00513 
00514 void QIMPenInput::resetState()
00515 {
00516     matcher->resetState();
00517 }

Generated on Sat Nov 5 16:16:01 2005 for OPIE by  doxygen 1.4.2