00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #define QTOPIA_INTERNAL_LANGLIST
00022 #include "inputmethods.h"
00023
00024
00025 #include <opie2/odebug.h>
00026 #include <qpe/config.h>
00027 #include <qpe/global.h>
00028 #include <qpe/qpeapplication.h>
00029 using namespace Opie::Core;
00030
00031
00032 #include <qpopupmenu.h>
00033 #include <qtoolbutton.h>
00034 #include <qwidgetstack.h>
00035 #include <qlayout.h>
00036 #include <qdir.h>
00037 #include <qtl.h>
00038 #ifdef Q_WS_QWS
00039 #include <qwindowsystem_qws.h>
00040 #include <qwsevent_qws.h>
00041 #include <qcopchannel_qws.h>
00042 #endif
00043
00044
00045 #include <stdlib.h>
00046
00047
00048 static const char * tri_xpm[]={
00049 "9 9 2 1",
00050 "a c #000000",
00051 ". c None",
00052 ".........",
00053 ".........",
00054 ".........",
00055 "....a....",
00056 "...aaa...",
00057 "..aaaaa..",
00058 ".aaaaaaa.",
00059 ".........",
00060 "........."};
00061
00062 int InputMethod::operator <(const InputMethod& o) const
00063 {
00064 return name() < o.name();
00065 }
00066 int InputMethod::operator >(const InputMethod& o) const
00067 {
00068 return name() > o.name();
00069 }
00070 int InputMethod::operator <=(const InputMethod& o) const
00071 {
00072 return name() <= o.name();
00073 }
00074
00075
00076
00077
00078
00079
00080 class IMToolButton : public QToolButton
00081 {
00082 public:
00083 IMToolButton::IMToolButton( QWidget *parent ) : QToolButton( parent )
00084 { setWFlags( WStyle_Tool );
00085 setBackgroundOrigin( ParentOrigin );
00086 setBackgroundMode( PaletteBackground );
00087 }
00088 };
00089
00090
00091 InputMethods::InputMethods( QWidget *parent ) :
00092 QWidget( parent, "InputMethods", WStyle_Tool | WStyle_Customize ),
00093 mkeyboard(0), imethod(0)
00094 {
00095 readConfig();
00096
00097 setBackgroundOrigin( ParentOrigin );
00098 setBackgroundMode( PaletteBackground );
00099 QHBoxLayout *hbox = new QHBoxLayout( this );
00100
00101 kbdButton = new IMToolButton( this);
00102 kbdButton->setFocusPolicy(NoFocus);
00103 kbdButton->setToggleButton( TRUE );
00104 if (parent->sizeHint().height() > 0)
00105 kbdButton->setFixedHeight( parent->sizeHint().height() );
00106 kbdButton->setFixedWidth( 32 );
00107 kbdButton->setAutoRaise( TRUE );
00108 kbdButton->setUsesBigPixmap( TRUE );
00109 hbox->addWidget( kbdButton );
00110 connect( kbdButton, SIGNAL(toggled(bool)), this, SLOT(showKbd(bool)) );
00111
00112 kbdChoice = new IMToolButton( this );
00113 kbdChoice->setFocusPolicy(NoFocus);
00114 kbdChoice->setPixmap( QPixmap( (const char **)tri_xpm ) );
00115 if (parent->sizeHint().height() > 0)
00116 kbdChoice->setFixedHeight( parent->sizeHint().height() );
00117 kbdChoice->setFixedWidth( 13 );
00118 kbdChoice->setAutoRaise( TRUE );
00119 hbox->addWidget( kbdChoice );
00120 connect( kbdChoice, SIGNAL(clicked()), this, SLOT(chooseKbd()) );
00121
00122 connect( (QPEApplication*)qApp, SIGNAL(clientMoused()),
00123 this, SLOT(resetStates()) );
00124
00125
00126 imButton = new QWidgetStack( this );
00127 imButton->setFocusPolicy(NoFocus);
00128 if (parent->sizeHint().height() > 0)
00129 imButton->setFixedHeight( parent->sizeHint().height() );
00130 hbox->addWidget(imButton);
00131
00132 imChoice = new QToolButton( this );
00133 imChoice->setFocusPolicy(NoFocus);
00134 imChoice->setPixmap( QPixmap( (const char **)tri_xpm ) );
00135 if (parent->sizeHint().height() > 0)
00136 imChoice->setFixedHeight( parent->sizeHint().height() );
00137 imChoice->setFixedWidth( 13 );
00138 imChoice->setAutoRaise( TRUE );
00139 hbox->addWidget( imChoice );
00140 connect( imChoice, SIGNAL(clicked()), this, SLOT(chooseIm()) );
00141
00142 loadInputMethods();
00143
00144 QCopChannel *channel = new QCopChannel( "QPE/IME", this );
00145 connect( channel, SIGNAL(received(const QCString&,const QByteArray&)),
00146 this, SLOT(qcopReceive(const QCString&,const QByteArray&)) );
00147 }
00148
00149 InputMethods::~InputMethods()
00150 {
00151 Config cfg("qpe");
00152 cfg.setGroup("InputMethod");
00153 if (imethod)
00154 cfg.writeEntry("im", imethod->name() );
00155 if (mkeyboard)
00156 cfg.writeEntry("current", mkeyboard->name() );
00157
00158 unloadInputMethods();
00159 }
00160
00161 void InputMethods::hideInputMethod()
00162 {
00163 kbdButton->setOn( FALSE );
00164 }
00165
00166 void InputMethods::showInputMethod()
00167 {
00168 kbdButton->setOn( TRUE );
00169 }
00170
00171 void InputMethods::showInputMethod(const QString& name)
00172 {
00173 int i = 0;
00174 QValueList<InputMethod>::Iterator it;
00175 InputMethod *im = 0;
00176 for ( it = inputMethodList.begin(); it != inputMethodList.end(); ++it, i++ ) {
00177 QString lname = (*it).libName.mid((*it).libName.findRev('/') + 1);
00178 if ( (*it).name() == name || lname == name ) {
00179 im = &(*it);
00180 break;
00181 }
00182 }
00183 if ( im )
00184 chooseKeyboard(im);
00185 }
00186
00187 void InputMethods::resetStates()
00188 {
00189 if ( mkeyboard && !mkeyboard->newIM )
00190 mkeyboard->interface->resetState();
00191 }
00192
00193 QRect InputMethods::inputRect() const
00194 {
00195 if ( !mkeyboard || !mkeyboard->widget || !mkeyboard->widget->isVisible() )
00196 return QRect();
00197 else
00198 return mkeyboard->widget->geometry();
00199 }
00200
00201 void InputMethods::unloadInputMethods()
00202 {
00203 unloadMethod( inputMethodList );
00204 unloadMethod( inputModifierList );
00205 inputMethodList.clear();
00206 inputModifierList.clear();
00207
00208 }
00209
00210 void InputMethods::unloadMethod( QValueList<InputMethod>& list ) {
00211 QValueList<InputMethod>::Iterator it;
00212
00213 for (it = list.begin(); it != list.end(); ++it )
00214 (*it).releaseInterface();
00215
00216 }
00217
00218
00219 QStringList InputMethods::plugins()const {
00220 QString path = QPEApplication::qpeDir() + "plugins/inputmethods";
00221 #ifdef Q_OS_MACX
00222 QDir dir( path, "lib*.dylib" );
00223 #else
00224 QDir dir( path, "lib*.so" );
00225 #endif
00226 return dir.entryList();
00227 }
00228
00229 void InputMethods::installTranslator( const QString& type ) {
00230 QStringList langs = Global::languageList();
00231 QStringList::ConstIterator lit;
00232 for ( lit= langs.begin(); lit!=langs.end(); ++lit) {
00233 QString lang = *lit;
00234 QTranslator * trans = new QTranslator(qApp);
00235
00236 QString tfn = QPEApplication::qpeDir()+"i18n/"+lang+"/"+type+".qm";
00237
00238 if ( trans->load( tfn ))
00239 qApp->installTranslator( trans );
00240 else
00241 delete trans;
00242 }
00243 }
00244
00245 void InputMethods::setPreferedHandlers() {
00246 Config cfg("qpe");
00247 cfg.setGroup("InputMethod");
00248 QString current = cfg.readEntry("current");
00249 QString im = cfg.readEntry("im");
00250
00251 QValueList<InputMethod>::Iterator it;
00252 if (!inputModifierList.isEmpty() && !im.isEmpty() ) {
00253 for (it = inputModifierList.begin(); it != inputModifierList.end(); ++it )
00254 if ( (*it).name() == im ) {
00255 imethod = &(*it); break;
00256 }
00257
00258 }
00259 if (!inputMethodList.isEmpty() && !current.isEmpty() ) {
00260 for (it = inputMethodList.begin(); it != inputMethodList.end(); ++it )
00261 if ( (*it).name() == current ) {
00262 owarn << "preferred keyboard is " << current << "" << oendl;
00263 mkeyboard = &(*it);
00264 kbdButton->setPixmap( *mkeyboard->icon() );
00265 break;
00266 }
00267 }
00268
00269 }
00270
00271 void InputMethods::loadInputMethods()
00272 {
00273 #ifndef QT_NO_COMPONENT
00274 hideInputMethod();
00275 mkeyboard = 0;
00276
00277 unloadInputMethods();
00278
00279 QString path = QPEApplication::qpeDir() + "plugins/inputmethods";
00280 QStringList list = plugins();
00281 QStringList::Iterator it;
00282 for ( it = list.begin(); it != list.end(); ++it ) {
00283 InputMethodInterface *iface = 0;
00284 ExtInputMethodInterface *eface = 0;
00285 QLibrary *lib = new QLibrary( path + "/" + *it );
00286
00287 if ( lib->queryInterface( IID_InputMethod, (QUnknownInterface**)&iface ) == QS_OK ) {
00288 InputMethod input;
00289 input.newIM = FALSE;
00290 input.library = lib;
00291 input.libName = *it;
00292 input.interface = iface;
00293 input.widget = input.interface->inputMethod( 0, inputWidgetStyle );
00294 input.interface->onKeyPress( this, SLOT(sendKey(ushort,ushort,ushort,bool,bool)) );
00295 inputMethodList.append( input );
00296 } else if ( lib->queryInterface( IID_ExtInputMethod, (QUnknownInterface**)&eface ) == QS_OK ) {
00297 InputMethod input;
00298 input.newIM = TRUE;
00299 input.library = lib;
00300 input.libName = *it;
00301 input.extInterface = eface;
00302 input.widget = input.extInterface->keyboardWidget( 0, inputWidgetStyle );
00303
00304 if (input.widget) {
00305
00306 inputMethodList.append( input );
00307 } else {
00308
00309 input.widget = input.extInterface->statusWidget( 0, 0 );
00310 if (input.widget) {
00311
00312 inputModifierList.append( input );
00313 imButton->addWidget(input.widget, inputModifierList.count());
00314 }
00315 }
00316 }else{
00317 delete lib;
00318 lib = 0l;
00319 }
00320 installTranslator( (*it).left( (*it).find(".") ) );
00321 }
00322 qHeapSort( inputMethodList );
00323 #endif
00324
00325 QWSServer::setCurrentInputMethod( 0 );
00326
00327
00328 setPreferedHandlers();
00329 if ( !inputModifierList.isEmpty() ) {
00330 if (!imethod)
00331 imethod = &inputModifierList[0];
00332 imButton->raiseWidget(imethod->widget);
00333 QWSServer::setCurrentInputMethod( imethod->extInterface->inputMethod() );
00334 } else {
00335 imethod = 0;
00336 }
00337
00338
00339
00340 updateKeyboards(imethod);
00341
00342 if ( !inputModifierList.isEmpty() )
00343 imButton->show();
00344 else
00345 imButton->hide();
00346
00347 if ( inputModifierList.count() > 1 )
00348 imChoice->show();
00349 else
00350 imChoice->hide();
00351 }
00352
00353 void InputMethods::chooseKbd()
00354 {
00355 QPopupMenu pop( this );
00356 pop.setFocusPolicy( NoFocus );
00357
00358 QString imname;
00359 if (imethod)
00360 imname = imethod->libName.mid(imethod->libName.findRev('/') + 1);
00361
00362 int i = 0;
00363 int firstDepKbd = 0;
00364
00365 QValueList<InputMethod>::Iterator it;
00366 for ( it = inputMethodList.begin(); it != inputMethodList.end(); ++it, i++ ) {
00367
00368 if (!(*it).newIM || (*it).extInterface->compatible().count() == 0 ) {
00369 pop.insertItem( (*it).name(), i, firstDepKbd);
00370 if ( mkeyboard == &(*it) )
00371 pop.setItemChecked( i, TRUE );
00372
00373 firstDepKbd++;
00374 } else if ( (*it).extInterface->compatible().contains(imname)) {
00375
00376 if (firstDepKbd == i)
00377 pop.insertSeparator();
00378 pop.insertItem( (*it).name(), i, -1);
00379 if ( mkeyboard == &(*it) )
00380 pop.setItemChecked( i, TRUE );
00381 }
00382 }
00383
00384 QPoint pt = mapToGlobal(kbdChoice->geometry().topRight());
00385 QSize s = pop.sizeHint();
00386 pt.ry() -= s.height();
00387 pt.rx() -= s.width();
00388 i = pop.exec( pt );
00389 if ( i == -1 )
00390 return;
00391 InputMethod *im = &inputMethodList[i];
00392 chooseKeyboard(im);
00393 }
00394
00395 void InputMethods::chooseIm()
00396 {
00397 QPopupMenu pop( this );
00398
00399 int i = 0;
00400 QValueList<InputMethod>::Iterator it;
00401 for ( it = inputModifierList.begin(); it != inputModifierList.end(); ++it, i++ ) {
00402 pop.insertItem( (*it).name(), i );
00403 if ( imethod == &(*it) )
00404 pop.setItemChecked( i, TRUE );
00405 }
00406
00407 QPoint pt = mapToGlobal(imChoice->geometry().topRight());
00408 QSize s = pop.sizeHint();
00409 pt.ry() -= s.height();
00410 pt.rx() -= s.width();
00411 i = pop.exec( pt );
00412 if ( i == -1 )
00413 return;
00414 InputMethod *im = &inputModifierList[i];
00415
00416 chooseMethod(im);
00417 }
00418
00419 void InputMethods::chooseKeyboard(InputMethod* im)
00420 {
00421 if ( im != mkeyboard ) {
00422 if ( mkeyboard && mkeyboard->widget->isVisible() )
00423 mkeyboard->widget->hide();
00424 mkeyboard = im;
00425 kbdButton->setPixmap( *mkeyboard->icon() );
00426 }
00427 if ( !kbdButton->isOn() )
00428 kbdButton->setOn( TRUE );
00429 else
00430 showKbd( TRUE );
00431 }
00432
00433 static bool keyboardCompatible(InputMethod *keyb, const QString &imname )
00434 {
00435 if ( !keyb || !keyb->newIM || !keyb->extInterface->compatible().count() )
00436 return TRUE;
00437
00438 if ( keyb->extInterface->compatible().contains(imname) )
00439 return TRUE;
00440
00441 return FALSE;
00442 }
00443
00444
00445 void InputMethods::updateKeyboards(InputMethod *im )
00446 {
00447 uint count;
00448
00449 if ( im ) {
00450 QString imname = im->libName.mid(im->libName.findRev('/') + 1);
00451
00452 if ( mkeyboard && !keyboardCompatible(mkeyboard, imname) ) {
00453 kbdButton->setOn( FALSE );
00454 showKbd( FALSE );
00455 mkeyboard = 0;
00456 }
00457
00458 count = 0;
00459
00460 QValueList<InputMethod>::Iterator it;
00461 for ( it = inputMethodList.begin(); it != inputMethodList.end(); ++it ) {
00462 if ( keyboardCompatible( &(*it), imname ) ) {
00463 if ( !mkeyboard ) {
00464 mkeyboard = &(*it);
00465 kbdButton->setPixmap( *mkeyboard->icon() );
00466 }
00467
00468 count++;
00469 }
00470 }
00471 } else {
00472 count = inputMethodList.count();
00473 if ( count && !mkeyboard ) {
00474 mkeyboard = &inputMethodList[0];
00475 kbdButton->setPixmap( *mkeyboard->icon() );
00476 } else if (!count){
00477 mkeyboard = 0;
00478 }
00479 }
00480
00481 if ( count > 1 )
00482 kbdChoice->show();
00483 else
00484 kbdChoice->hide();
00485
00486 if ( count )
00487 kbdButton->show();
00488 else
00489 kbdButton->hide();
00490 }
00491
00492 void InputMethods::chooseMethod(InputMethod* im)
00493 {
00494 if ( im != imethod ) {
00495 updateKeyboards( im );
00496
00497 Config cfg("qpe");
00498 cfg.setGroup("InputMethod");
00499 if (im )
00500 cfg.writeEntry("im", im->name() );
00501 if (mkeyboard)
00502 cfg.writeEntry("current", mkeyboard->name() );
00503
00504 QWSServer::setCurrentInputMethod( 0 );
00505 imethod = im;
00506 if ( imethod && imethod->newIM )
00507 QWSServer::setCurrentInputMethod( imethod->extInterface->inputMethod() );
00508 else
00509 QWSServer::setCurrentInputMethod( 0 );
00510
00511 if ( im )
00512 imButton->raiseWidget(im->widget);
00513 else
00514 imButton->hide();
00515 }
00516 }
00517
00518 void InputMethods::qcopReceive( const QCString &msg, const QByteArray &data )
00519 {
00520 if ( imethod && imethod->newIM )
00521 imethod->extInterface->qcopReceive( msg, data );
00522 }
00523
00524
00525 void InputMethods::showKbd( bool on )
00526 {
00527 if ( !mkeyboard )
00528 return;
00529
00530 if ( on )
00531 {
00532 mkeyboard->resetState();
00533
00534 int height = QMIN( mkeyboard->widget->sizeHint().height(), 134 );
00535 int width = static_cast<int>( qApp->desktop()->width() * (inputWidgetWidth*0.01) );
00536 int left = 0;
00537 int top = mapToGlobal( QPoint() ).y() - height;
00538
00539 if ( inputWidgetStyle & QWidget::WStyle_DialogBorder )
00540 {
00541 odebug << "InputMethods: reading geometry." << oendl;
00542 Config cfg( "Launcher" );
00543 cfg.setGroup( "InputMethods" );
00544 int l = cfg.readNumEntry( "absX", -1 );
00545 int t = cfg.readNumEntry( "absY", -1 );
00546 int w = cfg.readNumEntry( "absWidth", -1 );
00547 int h = cfg.readNumEntry( "absHeight", -1 );
00548
00549 if ( l > -1 && t > -1 && w > -1 && h > -1 )
00550 {
00551 odebug << "InputMethods: config values ( " << l << ", " << t << ", " << w << ", " << h << " ) are ok." << oendl;
00552 left = l;
00553 top = t;
00554 width = w;
00555 height = h;
00556 }
00557 else
00558 {
00559 odebug << "InputMethods: config values are new or not ok." << oendl;
00560 }
00561 }
00562 else
00563 {
00564 odebug << "InputMethods: no floating selected." << oendl;
00565 }
00566 mkeyboard->widget->resize( width, height );
00567 mkeyboard->widget->move( left, top );
00568 mkeyboard->widget->show();
00569 mkeyboard->widget->installEventFilter( this );
00570 }
00571 else
00572 {
00573 if ( inputWidgetStyle & QWidget::WStyle_DialogBorder )
00574 {
00575 QPoint pos = mkeyboard->widget->pos();
00576 QSize siz = mkeyboard->widget->size();
00577 odebug << "InputMethods: saving geometry." << oendl;
00578 Config cfg( "Launcher" );
00579 cfg.setGroup( "InputMethods" );
00580 cfg.writeEntry( "absX", pos.x() );
00581 cfg.writeEntry( "absY", pos.y() );
00582 cfg.writeEntry( "absWidth", siz.width() );
00583 cfg.writeEntry( "absHeight", siz.height() );
00584 cfg.write();
00585 mkeyboard->widget->removeEventFilter( this );
00586 }
00587 mkeyboard->widget->hide();
00588 }
00589
00590 emit inputToggled( on );
00591 }
00592
00593 bool InputMethods::shown() const
00594 {
00595 return mkeyboard && mkeyboard->widget->isVisible();
00596 }
00597
00598 QString InputMethods::currentShown() const
00599 {
00600 return mkeyboard && mkeyboard->widget->isVisible()
00601 ? mkeyboard->name() : QString::null;
00602 }
00603
00604 void InputMethods::sendKey( ushort unicode, ushort scancode, ushort mod, bool press, bool repeat )
00605 {
00606 #if defined(Q_WS_QWS)
00607 QWSServer::sendKeyEvent( unicode, scancode, mod, press, repeat );
00608 #endif
00609 }
00610
00611 bool InputMethods::eventFilter( QObject* , QEvent* e )
00612 {
00613 if ( e->type() == QEvent::Close )
00614 {
00615 ( (QCloseEvent*) e )->ignore();
00616 showKbd( false );
00617 kbdButton->setOn( false );
00618 return true;
00619 }
00620 return false;
00621 }
00622
00623 void InputMethods::readConfig() {
00624 Config cfg( "Launcher" );
00625 cfg.setGroup( "InputMethods" );
00626
00627 inputWidgetStyle = QWidget::WStyle_Customize | QWidget::WStyle_StaysOnTop | QWidget::WGroupLeader | QWidget::WStyle_Tool;
00628 inputWidgetStyle |= cfg.readBoolEntry( "Float", false ) ?
00629 QWidget::WStyle_DialogBorder : 0;
00630 inputWidgetWidth = cfg.readNumEntry( "Width", 100 );
00631 }