00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
00044
00045
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
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
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
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);
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
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
00353
00354 switch ( scan ) {
00355 case QIMPenChar::Caps:
00356 if ( profile->style() == QIMPenProfile::ToggleCases ) {
00357
00358
00359 if ( mode == SwitchLock ) {
00360
00361 pw->changeCharSet( profile->lowercase(), currCharSet );
00362 mode = Switch;
00363 } else {
00364
00365 pw->changeCharSet( profile->uppercase(), currCharSet );
00366 mode = Switch;
00367 }
00368 }
00369 break;
00370 case QIMPenChar::CapsLock:
00371 if ( profile->style() == QIMPenProfile::ToggleCases ) {
00372
00373 if ( mode == Switch &&
00374 baseSets.at(currCharSet) == profile->uppercase() ) {
00375
00376 pw->changeCharSet( profile->lowercase(), currCharSet );
00377
00378 baseSets.remove( currCharSet );
00379 baseSets.insert( currCharSet, profile->lowercase() );
00380 mode = Normal;
00381 } else {
00382
00383 pw->changeCharSet( profile->uppercase(), currCharSet );
00384
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
00394 pw->changeCharSet( profile->punctuation(), currCharSet );
00395 mode = Switch;
00396 }
00397 break;
00398 case QIMPenChar::Symbol:
00399 if ( profile->symbol() ) {
00400
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
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
00486 setupDlg = new QIMPenSetup( profile, 0, 0, TRUE );
00487 setupDlg->editor()->selectCharSet( profile->charSets().at(1) );
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 }