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 "qimpenprefbase.h"
00023 #include "qimpensetup.h"
00024
00025 #include <qpe/qpeapplication.h>
00026 #include <qpe/config.h>
00027
00028 #include <qcombobox.h>
00029 #include <qlistbox.h>
00030 #include <qlabel.h>
00031 #include <qpushbutton.h>
00032 #include <qlayout.h>
00033 #include <qpixmap.h>
00034 #include <qbuttongroup.h>
00035 #include <qslider.h>
00036 #include <qtabwidget.h>
00037 #include <qdir.h>
00038 #include <qmessagebox.h>
00039 #include <opie2/odebug.h>
00040
00041
00042
00043 static const char * const left_xpm[] = {
00044 "16 16 2 1",
00045 " c None",
00046 ". c #000000",
00047 " ",
00048 " ",
00049 " ",
00050 " . ",
00051 " .. ",
00052 " ... ",
00053 " .... ",
00054 " ..... ",
00055 " ...... ",
00056 " ..... ",
00057 " .... ",
00058 " ... ",
00059 " .. ",
00060 " . ",
00061 " ",
00062 " "};
00063
00064
00065
00066 static const char * const right_xpm[] = {
00067 "16 16 2 1",
00068 " c None",
00069 ". c #000000",
00070 " ",
00071 " ",
00072 " ",
00073 " . ",
00074 " .. ",
00075 " ... ",
00076 " .... ",
00077 " ..... ",
00078 " ...... ",
00079 " ..... ",
00080 " .... ",
00081 " ... ",
00082 " .. ",
00083 " . ",
00084 " ",
00085 " "};
00086
00087
00088
00089 QIMPenSetup::QIMPenSetup( QIMPenProfile *p, QWidget *parent,
00090 const char *name, bool modal, int WFlags )
00091 : QDialog( parent, name, modal, WFlags ), profileCombo(0), profile(p)
00092 {
00093 setCaption( tr("Setup Handwriting Input") );
00094
00095 QVBoxLayout *vb = new QVBoxLayout( this );
00096
00097 #define MULTIPROFILE
00098 #ifdef MULTIPROFILE
00099 profileList.setAutoDelete( true );
00100 QHBoxLayout *hb = new QHBoxLayout( vb );
00101 hb->setMargin( 6 );
00102 QLabel *l = new QLabel( tr("Character Profile:"), this );
00103 hb->addWidget( l );
00104 profileCombo = new QComboBox( this );
00105 connect( profileCombo, SIGNAL(activated(const QString&)),
00106 this, SLOT(selectProfile(const QString&)) );
00107 hb->addWidget( profileCombo );
00108 #else
00109 profileList.append( profile );
00110 #endif
00111
00112 owarn << "profiles: " << profileList.count() << oendl;
00113
00114 QTabWidget *tw = new QTabWidget( this );
00115 vb->addWidget( tw );
00116
00117 pref = new QIMPenPrefBase( this );
00118 tw->addTab( pref, tr("Preferences") );
00119
00120 pref->inputStyle->setExclusive( TRUE );
00121
00122 style = profile->style() == QIMPenProfile::ToggleCases ? 1 : 0;
00123 pref->inputStyle->setButton( style );
00124 connect( pref->inputStyle, SIGNAL(clicked(int)),
00125 this, SLOT(styleClicked(int)) );
00126 pref->inputStyle->setEnabled( profile->canSelectStyle() );
00127
00128 multiTimeout = profile->multiStrokeTimeout();
00129 pref->multiStrokeSlider->setValue( multiTimeout );
00130 multiTimeoutChanged( multiTimeout );
00131 connect( pref->multiStrokeSlider, SIGNAL(valueChanged(int)),
00132 this, SLOT(multiTimeoutChanged(int)) );
00133
00134 edit = new QIMPenEdit( p, tw );
00135 tw->addTab( edit, tr("Customize") );
00136 #ifdef MULTIPROFILE
00137 loadProfiles();
00138 #endif
00139
00140 }
00141
00142 void QIMPenSetup::loadProfiles()
00143 {
00144 QString path = QPEApplication::qpeDir() + "etc/qimpen";
00145 QDir dir( path, "*.conf" );
00146 QStringList list = dir.entryList();
00147 QStringList::Iterator it;
00148 for ( it = list.begin(); it != list.end(); ++it ) {
00149 QIMPenProfile *p = new QIMPenProfile( path + "/" + *it );
00150 profileList.append( p );
00151 profileCombo->insertItem( p->name() );
00152 if ( p->name() == profile->name() ) {
00153 profileCombo->setCurrentItem( profileCombo->count()-1 );
00154 profile = p;
00155 edit->setProfile( profile );
00156 }
00157 }
00158 }
00159
00160 void QIMPenSetup::styleClicked( int id )
00161 {
00162 style = id;
00163 }
00164
00165 void QIMPenSetup::multiTimeoutChanged( int v )
00166 {
00167 multiTimeout = v;
00168 pref->multiStrokeLabel->setText( tr("%1 ms").arg(v) );
00169 }
00170
00171 void QIMPenSetup::selectProfile( const QString &p )
00172 {
00173 if ( p == profile->name() )
00174 return;
00175
00176 profile->setStyle( style ? QIMPenProfile::ToggleCases : QIMPenProfile::BothCases );
00177 profile->setMultiStrokeTimeout( multiTimeout );
00178
00179 for ( int i = 0; i < (int)profileList.count(); i++ ) {
00180 if ( profileList.at(i)->name() == p ) {
00181 profile = profileList.at(i);
00182 style = profile->style() == QIMPenProfile::ToggleCases ? 1 : 0;
00183 pref->inputStyle->setButton( style );
00184 pref->inputStyle->setEnabled( profile->canSelectStyle() );
00185 multiTimeout = profile->multiStrokeTimeout();
00186 pref->multiStrokeSlider->setValue( multiTimeout );
00187 multiTimeoutChanged( multiTimeout );
00188 edit->setProfile( profile );
00189 break;
00190 }
00191 }
00192 }
00193
00194 void QIMPenSetup::accept()
00195 {
00196 profile->setStyle( style ? QIMPenProfile::ToggleCases : QIMPenProfile::BothCases );
00197 profile->setMultiStrokeTimeout( multiTimeout );
00198
00199 if ( profileCombo ) {
00200 Config config( "handwriting" );
00201 config.setGroup( "Settings" );
00202 config.writeEntry( "Profile", profileCombo->currentText() );
00203 }
00204
00205 bool ok = TRUE;
00206 for ( int i = 0; i < (int)profileList.count(); i++ ) {
00207 QIMPenProfile *prof = profileList.at(i);
00208 QIMPenCharSetIterator it(prof->charSets());
00209 for ( ; it.current(); ++it ) {
00210 if ( !(it.current()->save( QIMPenCharSet::User )) ) {
00211 ok = FALSE;
00212 break;
00213 }
00214 }
00215 }
00216 if ( !ok ) {
00217 if ( QMessageBox::critical( 0, tr( "Out of space" ),
00218 tr("Unable to save information.\n"
00219 "Free up some space\n"
00220 "and try again.\n"
00221 "\nQuit anyway?"),
00222 QMessageBox::Yes|QMessageBox::Escape,
00223 QMessageBox::No|QMessageBox::Default )
00224 != QMessageBox::No ) {
00225 QDialog::accept();
00226 }
00227 } else {
00228 QDialog::accept();
00229 }
00230 }
00231
00232
00233
00234 QIMPenInputCharDlg::QIMPenInputCharDlg( QWidget *parent, const char *name,
00235 bool modal, int WFlags)
00236 : QDialog( parent, name, modal, WFlags )
00237 {
00238 setCaption( tr("Enter new character") );
00239 uni = 0;
00240
00241 QVBoxLayout *vb = new QVBoxLayout( this, 10 );
00242
00243 QHBoxLayout *hb = new QHBoxLayout();
00244 vb->addLayout( hb );
00245
00246 QLabel *label = new QLabel( tr("Character:"), this );
00247 hb->addWidget( label );
00248
00249 QComboBox *cb = new QComboBox( TRUE, this );
00250 connect( cb, SIGNAL(activated(int)), SLOT(setSpecial(int)) );
00251 connect( cb, SIGNAL(textChanged(const QString&)),
00252 SLOT(setCharacter(const QString&)) );
00253 addSpecial( cb );
00254 cb->setEditText( "" );
00255 hb->addWidget( cb );
00256
00257 hb = new QHBoxLayout();
00258 vb->addLayout( hb );
00259
00260 QPushButton *pb = new QPushButton( "OK", this );
00261 connect( pb, SIGNAL(clicked()), SLOT(accept()));
00262 hb->addWidget( pb );
00263 pb = new QPushButton( "Cancel", this );
00264 connect( pb, SIGNAL(clicked()), SLOT(reject()));
00265 hb->addWidget( pb );
00266
00267 cb->setFocus();
00268 }
00269
00270 void QIMPenInputCharDlg::addSpecial( QComboBox *cb )
00271 {
00272 int i = 0;
00273 while ( qimpen_specialKeys[i].code != Key_unknown ) {
00274 cb->insertItem( qimpen_specialKeys[i].name );
00275 i++;
00276 }
00277 }
00278
00279 void QIMPenInputCharDlg::setSpecial( int sp )
00280 {
00281 uni = qimpen_specialKeys[sp].code << 16;
00282 }
00283
00284 void QIMPenInputCharDlg::setCharacter( const QString &string )
00285 {
00286 uni = string[0].unicode();
00287 }
00288
00289
00290
00291 class CharListItem : public QListBoxText
00292 {
00293 public:
00294 CharListItem( const QString &text, uint c )
00295 : QListBoxText( text )
00296 {
00297 _code = c;
00298 }
00299
00300 uint code() const { return _code; }
00301
00302 protected:
00303 uint _code;
00304 };
00305
00313 QIMPenEdit::QIMPenEdit( QIMPenProfile *p, QWidget *parent,
00314 const char *name )
00315 : QWidget( parent, name ), profile(p)
00316 {
00317 currentChar = 0;
00318 currentCode = 0;
00319 inputChar = new QIMPenChar();
00320
00321 QVBoxLayout *tvb = new QVBoxLayout( this, 5 );
00322
00323 QGridLayout *gl = new QGridLayout( tvb, 4, 2 );
00324 gl->setRowStretch( 1, 1 );
00325 gl->addRowSpacing( 2, 35 );
00326 gl->addRowSpacing( 3, 35 );
00327
00328 charSetCombo = new QComboBox( this );
00329 gl->addMultiCellWidget( charSetCombo, 0, 0, 0, 1 );
00330 connect( charSetCombo, SIGNAL(activated(int)), SLOT(selectCharSetVisible(int)));
00331 QIMPenCharSetIterator it( profile->charSets() );
00332 for ( ; it.current(); ++it ) {
00333 charSetCombo->insertItem( it.current()->description() );
00334 }
00335
00336 charList = new QListBox( this );
00337 charList->setMinimumHeight( charList->sizeHint().height() );
00338 connect( charList, SIGNAL(highlighted(int)), SLOT(selectChar(int)) );
00339 gl->addWidget( charList, 1, 0 );
00340
00341 pw = new QIMPenWidget( this );
00342 pw->setFixedHeight( 75 );
00343 gl->addMultiCellWidget( pw, 2, 3, 0, 0 );
00344 connect( pw, SIGNAL(stroke(QIMPenStroke*)),
00345 SLOT(newStroke(QIMPenStroke*)) );
00346
00347 QVBoxLayout *vb = new QVBoxLayout();
00348 gl->addLayout( vb, 1, 1 );
00349 newBtn = new QPushButton( tr("New..."), this );
00350 connect( newBtn, SIGNAL(clicked()), SLOT(addNewChar()) );
00351 vb->addWidget( newBtn );
00352
00353 addBtn = new QPushButton( tr("Add"), this );
00354 connect( addBtn, SIGNAL(clicked()), SLOT(addChar()) );
00355 vb->addWidget( addBtn );
00356
00357 removeBtn = new QPushButton( tr("Remove"), this );
00358 connect( removeBtn, SIGNAL(clicked()), SLOT(removeChar()) );
00359 vb->addWidget( removeBtn );
00360
00361 QPushButton *pb = new QPushButton( tr("Default"), this );
00362 connect( pb, SIGNAL(clicked()), SLOT(defaultChars()) );
00363 vb->addWidget( pb );
00364
00365 QHBoxLayout *hb = new QHBoxLayout();
00366 gl->addLayout( hb, 2, 1 );
00367 prevBtn = new QPushButton( this );
00368 prevBtn->setPixmap( QPixmap( (const char **)left_xpm ) );
00369 connect( prevBtn, SIGNAL(clicked()), SLOT(prevChar()));
00370 hb->addWidget( prevBtn );
00371
00372 nextBtn = new QPushButton( this );
00373 nextBtn->setPixmap( QPixmap( (const char **)right_xpm ) );
00374 connect( nextBtn, SIGNAL(clicked()), SLOT(nextChar()));
00375 hb->addWidget( nextBtn );
00376
00377 pb = new QPushButton( tr("Clear"), this );
00378 connect( pb, SIGNAL(clicked()), SLOT(clearChar()) );
00379 gl->addWidget( pb, 3, 1 );
00380
00381
00382 #if !defined(Q_WS_QWS)
00383 hb = new QHBoxLayout( tvb );
00384 pb = new QPushButton( tr("OK"), this );
00385 connect( pb, SIGNAL(clicked()), SLOT(accept()) );
00386 hb->addWidget( pb );
00387
00388 pb = new QPushButton( tr("Cancel"), this );
00389 connect( pb, SIGNAL(clicked()), SLOT(reject()) );
00390 hb->addWidget( pb );
00391 #endif
00392 selectCharSetVisible( 0 );
00393 charList->setFocus();
00394
00395 resize( minimumSize() );
00396 enableButtons();
00397 }
00398
00399 void QIMPenEdit::setProfile( QIMPenProfile *p )
00400 {
00401 profile = p;
00402 charSetCombo->clear();
00403 QIMPenCharSetIterator it( profile->charSets() );
00404 for ( ; it.current(); ++it ) {
00405 if ( ! it.current()->hidden() )
00406 charSetCombo->insertItem( it.current()->description() );
00407 }
00408 selectCharSetVisible( 0 );
00409 charList->setFocus();
00410 enableButtons();
00411 }
00412
00413 void QIMPenEdit::selectCharSet( QIMPenCharSet *c )
00414 {
00415 int i = 0;
00416 QIMPenCharSetIterator it( profile->charSets() );
00417 for ( ; it.current(); ++it, i++ ) {
00418 if ( it.current() == c ) {
00419 charSetCombo->setCurrentItem( i );
00420 selectCharSet( i );
00421 }
00422 }
00423 }
00424
00425
00430 void QIMPenEdit::fillCharList()
00431 {
00432 charList->clear();
00433 QIMPenCharIterator it( currentSet->characters() );
00434 CharListItem *li = 0;
00435 for ( ; it.current(); ++it ) {
00436 uint ch = it.current()->character();
00437 QString n = it.current()->name();
00438 if ( !n.isEmpty() )
00439 li = new CharListItem( n, ch );
00440 if ( li ) {
00441 CharListItem *i = (CharListItem *)charList->findItem( li->text() );
00442 if ( !i || i->code() != ch ) {
00443 charList->insertItem( li );
00444 } else {
00445 delete li;
00446 li = 0;
00447 }
00448 }
00449 }
00450 currentChar = 0;
00451 }
00452
00453 void QIMPenEdit::enableButtons()
00454 {
00455 bool add = !inputChar->isEmpty();
00456 newBtn->setEnabled( add );
00457 addBtn->setEnabled( add );
00458 removeBtn->setEnabled( currentChar );
00459 }
00460
00465 QIMPenChar *QIMPenEdit::findPrev()
00466 {
00467 if ( !currentChar )
00468 return 0;
00469 QIMPenCharIterator it( currentSet->characters() );
00470 bool found = FALSE;
00471 for ( it.toLast(); it.current(); --it ) {
00472 if ( !found && it.current() == currentChar )
00473 found = TRUE;
00474 else if ( found && it.current()->character() == currentCode &&
00475 !it.current()->testFlag( QIMPenChar::Deleted ) ) {
00476 return it.current();
00477 }
00478 }
00479
00480 return 0;
00481 }
00482
00487 QIMPenChar *QIMPenEdit::findNext()
00488 {
00489 if ( !currentChar )
00490 return 0;
00491 QIMPenCharIterator it( currentSet->characters() );
00492 bool found = FALSE;
00493 for ( ; it.current(); ++it ) {
00494 if ( !found && it.current() == currentChar )
00495 found = TRUE;
00496 else if ( found && it.current()->character() == currentCode &&
00497 !it.current()->testFlag( QIMPenChar::Deleted ) ) {
00498 return it.current();
00499 }
00500 }
00501
00502 return 0;
00503 }
00504
00505 void QIMPenEdit::setCurrentChar( QIMPenChar *pc )
00506 {
00507 currentChar = pc;
00508 pw->showCharacter( currentChar );
00509 if ( currentChar ) {
00510 prevBtn->setEnabled( findPrev() != 0 );
00511 nextBtn->setEnabled( findNext() != 0 );
00512 }
00513 }
00514
00515 void QIMPenEdit::prevChar()
00516 {
00517 QIMPenChar *pc = findPrev();
00518 if ( pc )
00519 setCurrentChar( pc );
00520 }
00521
00522 void QIMPenEdit::nextChar()
00523 {
00524 QIMPenChar *pc = findNext();
00525 if ( pc )
00526 setCurrentChar( pc );
00527 }
00528
00529 void QIMPenEdit::clearChar()
00530 {
00531 inputChar->clear();
00532 pw->clear();
00533 enableButtons();
00534 }
00535
00536 void QIMPenEdit::selectChar( int i )
00537 {
00538 currentChar = 0;
00539 currentCode = ((CharListItem *)charList->item(i))->code();
00540 QIMPenCharIterator it(currentSet->characters() );
00541 for ( ; it.current(); ++it ) {
00542 if ( it.current()->character() == currentCode &&
00543 !it.current()->testFlag( QIMPenChar::Deleted ) ) {
00544 setCurrentChar( it.current() );
00545 break;
00546 }
00547 }
00548 if ( !it.current() )
00549 setCurrentChar( 0 );
00550 inputChar->clear();
00551 }
00552
00553 void QIMPenEdit::selectCharSetVisible( int c )
00554 {
00555 int i = 0;
00556 QIMPenCharSetIterator it( profile->charSets() );
00557 for ( ; it.current(); ++it, i++ ) {
00558 if ( charSetCombo->text( c ) == it.current()->description() ) {
00559 selectCharSet( i );
00560 }
00561 }
00562 }
00563
00564 void QIMPenEdit::selectCharSet( int i )
00565 {
00566 if ( currentSet )
00567 pw->removeCharSet( 0 );
00568 currentSet = profile->charSets().at( i );
00569 fillCharList();
00570 pw->insertCharSet( currentSet );
00571 inputChar->clear();
00572 if ( charList->count() ) {
00573 charList->setSelected( 0, TRUE );
00574 selectChar(0);
00575 }
00576 }
00577
00578 void QIMPenEdit::addChar()
00579 {
00580 if ( !inputChar->isEmpty() ) {
00581 QIMPenChar *pc = new QIMPenChar( *inputChar );
00582 pc->setCharacter( currentCode );
00583
00584
00585
00586
00587 QIMPenCharIterator it(currentSet->characters() );
00588 QIMPenChar *sc = 0;
00589 while ( (sc = it.current()) != 0 ) {
00590 ++it;
00591 if ( sc->character() == currentCode &&
00592 sc->testFlag( QIMPenChar::System ) &&
00593 !sc->testFlag( QIMPenChar::Deleted ) ) {
00594 QIMPenChar *cc = new QIMPenChar( *sc );
00595 cc->clearFlag( QIMPenChar::System );
00596 currentSet->addChar( cc );
00597 sc->setFlag( QIMPenChar::Deleted );
00598 }
00599 }
00600
00601 currentSet->addChar( pc );
00602 setCurrentChar( pc );
00603 inputChar->clear();
00604 }
00605 }
00606
00607 void QIMPenEdit::addNewChar()
00608 {
00609 if ( !inputChar->isEmpty() ) {
00610 QIMPenInputCharDlg dlg( 0, 0, TRUE );
00611 if ( dlg.exec() ) {
00612 currentCode = dlg.unicode();
00613 addChar();
00614 fillCharList();
00615 for ( unsigned int i = 0; i < charList->count(); i++ ) {
00616 CharListItem *li = (CharListItem *)charList->item(i);
00617 if ( li->code() == dlg.unicode() ) {
00618 charList->setSelected( i, TRUE );
00619 break;
00620 }
00621 }
00622 }
00623 }
00624 }
00625
00626 void QIMPenEdit::removeChar()
00627 {
00628 if ( currentChar ) {
00629 QIMPenChar *pc = findPrev();
00630 if ( !pc ) pc = findNext();
00631 if ( currentChar->testFlag( QIMPenChar::System ) )
00632 currentChar->setFlag( QIMPenChar::Deleted );
00633 else
00634 currentSet->removeChar( currentChar );
00635 setCurrentChar( pc );
00636 }
00637 }
00638
00639 void QIMPenEdit::defaultChars()
00640 {
00641 if ( currentCode ) {
00642 currentChar = 0;
00643 bool haveSystem = FALSE;
00644 QIMPenCharIterator it(currentSet->characters() );
00645 for ( ; it.current(); ++it ) {
00646 if ( it.current()->character() == currentCode &&
00647 it.current()->testFlag( QIMPenChar::System ) ) {
00648 haveSystem = TRUE;
00649 break;
00650 }
00651 }
00652 if ( haveSystem ) {
00653 it.toFirst();
00654 while ( it.current() ) {
00655 QIMPenChar *pc = it.current();
00656 ++it;
00657 if ( pc->character() == currentCode ) {
00658 if ( pc->testFlag( QIMPenChar::System ) ) {
00659 pc->clearFlag( QIMPenChar::Deleted );
00660 if ( !currentChar )
00661 currentChar = pc;
00662 } else {
00663 currentSet->removeChar( pc );
00664 }
00665 }
00666 }
00667 setCurrentChar( currentChar );
00668 }
00669 }
00670 }
00671
00672 void QIMPenEdit::newStroke( QIMPenStroke *st )
00673 {
00674 inputChar->addStroke( st );
00675 enableButtons();
00676 }
00677