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

startmenu.cpp

Go to the documentation of this file.
00001 /*
00002                              This file is part of the Opie Project
00003               =.             (C) 2000-2002 Trolltech AS
00004             .=l.             (C) 2002-2005 The Opie Team <opie-devel@handhelds.org>
00005            .>+-=
00006  _;:,     .>    :=|.         This program is free software; you can
00007 .> <`_,   >  .   <=          redistribute it and/or  modify it under
00008     :`=1 )Y*s>-.--   :       the terms of the GNU Library General Public
00009 .="- .-=="i,     .._         License as published by the Free Software
00010  - .   .-<_>     .<>         Foundation; version 2 of the License.
00011      ._= =}       :
00012     .%`+i>       _;_.
00013     .i_,=:_.      -<s.       This program is distributed in the hope that
00014      +  .  -:.       =       it will be useful,  but WITHOUT ANY WARRANTY;
00015     : ..    .:,     . . .    without even the implied warranty of
00016     =_        +     =;=|`    MERCHANTABILITY or FITNESS FOR A
00017   _.=:.       :    :=>`:     PARTICULAR PURPOSE. See the GNU
00018 ..}^=.=       =       ;      Library General Public License for more
00019 ++=   -.     .`     .:       details.
00020     :     =  ...= . :.=-
00021  -.   .:....=;==+<;          You should have received a copy of the GNU
00022   -_. . .   )=.  =           Library General Public License along with
00023     --        :-=`           this library; see the file COPYING.LIB.
00024                              If not, write to the Free Software Foundation,
00025                              Inc., 59 Temple Place - Suite 330,
00026                              Boston, MA 02111-1307, USA.
00027 */
00028 // TODO. During startup
00029 // Launcher::typeAdded
00030 // is called for each new tab and calls then each time the refresh of startmenu
00031 // suboptimal
00032 
00033 #define INCLUDE_MENUITEM_DEF
00034 
00035 #include "startmenu.h"
00036 
00037 /* OPIE */
00038 #include <opie2/oresource.h>
00039 using namespace Opie::Core;
00040 #include <qtopia/qpeapplication.h>
00041 #include <qtopia/config.h>
00042 #include <qtopia/mimetype.h>
00043 #include <qtopia/qlibrary.h>
00044 
00045 #define APPLNK_ID_OFFSET 250
00046 #define NO_ID -1
00047 
00048 
00049 void StartPopupMenu::keyPressEvent( QKeyEvent *e )
00050 {
00051     if ( e->key() == Key_F33 || e->key() == Key_Space ) {
00052         // "OK" button, little hacky
00053             QKeyEvent ke(QEvent::KeyPress, Key_Enter, 13, 0);
00054             QPopupMenu::keyPressEvent( &ke );
00055     } else {
00056             QPopupMenu::keyPressEvent( e );
00057     }
00058 }
00059 
00060 //---------------------------------------------------------------------------
00061 
00062 StartMenu::StartMenu(QWidget *parent) : QLabel( parent )
00063 {
00064     startButtonPixmap = "go"; // No tr
00065 
00066     int sz = AppLnk::smallIconSize()+3;
00067     QPixmap pm;
00068     pm.convertFromImage(OResource::loadImage( startButtonPixmap, OResource::NoScale ).smoothScale( sz,sz) );
00069     setPixmap(pm);
00070     setFocusPolicy( NoFocus );
00071 
00072     useWidePopupMenu = true;
00073     launchMenu = 0;
00074     currentItem = 0;
00075     refreshMenu();
00076 }
00077 
00078 
00079 void StartMenu::mousePressEvent( QMouseEvent * )
00080 {
00081     launch();
00082 }
00083 
00084 
00085 StartMenu::~StartMenu()
00086 {
00087     clearApplets();
00088 }
00089 
00090 void StartMenu::createMenu()
00091 {
00092     clearApplets();
00093     delete launchMenu;
00094 
00095     launchMenu = new StartPopupMenu( this );
00096     loadMenu( launchMenu );
00097     loadApplets();
00098 
00099     bool result = currentItem || menuApplets.count();
00100     if ( result )
00101             connect( launchMenu, SIGNAL(activated(int)), SLOT(itemSelected(int)) );
00102 }
00103 
00104 void StartMenu::refreshMenu()
00105 {
00106     Config cfg( "StartMenu" );
00107     cfg.setGroup( "Menu" );
00108     bool ltabs = cfg.readBoolEntry( "LauncherTabs", TRUE );
00109     bool lot = cfg.readBoolEntry( "LauncherOther", TRUE );
00110     useWidePopupMenu = cfg.readBoolEntry(  "LauncherSubPopup",  TRUE );
00111 
00112     if ( launchMenu && !(ltabs || lot) ) return; // nothing to do
00113 
00114         createMenu();
00115 }
00116 
00117 void StartMenu::itemSelected( int id )
00118 {
00119     if ( id == NO_ID ) return;
00120 
00121     if ( id < 0 ) {
00122         MenuApplet *applet = menuApplets.find( id );
00123         if ( applet ) {
00124             applet->iface->activated();
00125         }
00126     } else if ( id >= APPLNK_ID_OFFSET ) {
00127         AppLnk * appLnk = appLnks.find( id );
00128         if ( appLnk ) {
00129                     appLnk->execute();
00130         }
00131     } else {
00132         QString *tabName = tabNames.find( id );
00133         if ( tabName ) {
00134                 emit tabSelected( *tabName );
00135             }
00136     }
00137 }
00138 
00139 void StartMenu::createAppEntry( QPopupMenu *menu, QDir dir, QString file )
00140 {
00141     if ( file.right(8) == ".desktop" ) {
00142                 AppLnk* applnk = new AppLnk( dir.path() + "/" + file );
00143         if ( !applnk->isValid() ) {
00144             delete applnk;
00145             return;
00146         }
00147 
00148             if ( applnk->type() == "Separator" ) { // No tr
00149                     menu->insertSeparator();
00150                 delete applnk;
00151         } else {
00152             QPixmap pixmap = OResource::loadPixmap( applnk->icon(), OResource::SmallIcon );
00153                 // Insert items ordered lexically
00154                 int current, left = 0, right = currentItem;
00155                 while( left != right ) {
00156                     current = ( left + right ) / 2;
00157                     if ( menu->text(menu->idAt( ( current ) ) ) < applnk->name() )
00158                         left = ++current;
00159                     else
00160                         right = current;
00161                 }
00162 
00163                 menu->insertItem( pixmap, applnk->name(),
00164                               currentItem + APPLNK_ID_OFFSET, current );
00165                 appLnks.insert( currentItem + APPLNK_ID_OFFSET, applnk );
00166                 currentItem++;
00167                 }
00168     }
00169 
00170 }
00171 
00172 void StartMenu::createDirEntry( QPopupMenu *menu, QDir dir, QString file, bool lot )
00173 {
00174     // do some sanity checks and collect information
00175 
00176     if ( file == "." || file == ".." ) return;
00177 
00178     Config cfg( dir.path() + "/" + file + "/.directory", Config::File );
00179     if ( !cfg.isValid() ) return;
00180 
00181         QString name = cfg.readEntry( "Name" );
00182     QString icon = cfg.readEntry( "Icon" );
00183         if ( !name || !icon ) return;
00184 
00185     QDir subdir = QDir( dir );
00186     subdir.cd( file );
00187     subdir.setFilter( QDir::Files );
00188     subdir.setNameFilter( "*.desktop" );
00189     // we don' t show the menu if there are no entries
00190     // perhaps one should check if there exist subsubdirs with entries...
00191     if ( subdir.entryList().isEmpty() ) return;
00192 
00193     // checks were ok
00194 
00195     QPixmap pixmap = OResource::loadPixmap( icon, OResource::SmallIcon );
00196         if ( useWidePopupMenu ) {
00197         // generate submenu
00198         QPopupMenu *submenu = new QPopupMenu( menu );
00199         connect( submenu,  SIGNAL(activated(int)), SLOT(itemSelected(int)) );
00200         menu->insertItem( pixmap, name, submenu, NO_ID );
00201 
00202         // ltabs is true cause else we wouldn't stuck around..
00203         createMenuEntries( submenu, subdir, true, lot );
00204     } else {
00205         // no submenus - just bring corresponding tab to front
00206         menu->insertItem( pixmap, name, currentItem );
00207         tabNames.insert( currentItem, new QString( file ) );
00208         currentItem++;
00209     }
00210 }
00211 
00212 void StartMenu::createMenuEntries( QPopupMenu *menu, QDir dir, bool ltabs, bool lot )
00213 {
00214     if ( lot ) {
00215         dir.setFilter( QDir::Files );
00216         dir.setNameFilter( "*.desktop" );
00217         QStringList files = dir.entryList();
00218         files.sort();
00219 
00220         for ( QStringList::Iterator it = files.begin(); it != files.end(); it++ ) {
00221             createAppEntry( menu, dir, *it );
00222         }
00223     }
00224     if ( ltabs ) {
00225         dir.setNameFilter( "*" );
00226         dir.setFilter( QDir::Dirs );
00227         QStringList dirs = dir.entryList();
00228         dirs.sort();
00229 
00230         for ( QStringList::Iterator it = dirs.begin(); it != dirs.end(); it++ ) {
00231             createDirEntry( menu, dir, *it, lot );
00232         }
00233     }
00234 }
00235 
00236 bool StartMenu::loadMenu( QPopupMenu *menu )
00237 {
00238     Config cfg("StartMenu");
00239     cfg.setGroup("Menu");
00240 
00241     bool ltabs = cfg.readBoolEntry("LauncherTabs", TRUE);
00242     bool lot = cfg.readBoolEntry("LauncherOther", TRUE);
00243     useWidePopupMenu = cfg.readBoolEntry(  "LauncherSubPopup",  TRUE );
00244     bool sepfirst = !ltabs && !lot;
00245 
00246     currentItem = 0;
00247         launchMenu->clear();
00248 
00249     appLnks.setAutoDelete( true );
00250     tabNames.setAutoDelete( true );
00251     appLnks.clear();
00252     tabNames.clear();
00253     appLnks.setAutoDelete( false );
00254     tabNames.setAutoDelete( false );
00255 
00256     QDir dir( MimeType::appsFolderName(), QString::null, QDir::Name );
00257     createMenuEntries( menu, dir, ltabs, lot );
00258 
00259         if ( !menu->count() ) sepfirst = TRUE;
00260 
00261     launchMenu->setName( sepfirst ? "accessories" : "accessories_need_sep" ); // No tr
00262 
00263     return currentItem;
00264 }
00265 
00266 
00267 void StartMenu::launch()
00268 {
00269     int y = mapToGlobal( QPoint() ).y() - launchMenu->sizeHint().height();
00270 
00271     if ( launchMenu->isVisible() )
00272         launchMenu->hide();
00273     else
00274         launchMenu->popup( QPoint( 1, y ) );
00275 }
00276 
00277 
00278 
00279 
00280 static int compareAppletPositions(const void *b, const void *a)
00281 {
00282     const MenuApplet* aa = *(const MenuApplet**)a;
00283     const MenuApplet* ab = *(const MenuApplet**)b;
00284     int d = aa->iface->position() - ab->iface->position();
00285     if ( d ) return d;
00286     return QString::compare(aa->library->library(),ab->library->library());
00287 }
00288 
00289 void StartMenu::clearApplets()
00290 {
00291     if ( launchMenu )
00292         launchMenu-> hide();
00293 
00294     for ( QIntDictIterator<MenuApplet> it( menuApplets ); it.current(); ++it ) {
00295         MenuApplet *applet = it.current();
00296         if ( launchMenu ) {
00297                 launchMenu->removeItem( applet-> id );
00298                 delete applet->popup;
00299         }
00300 
00301         applet->iface->release();
00302         applet->library->unload();
00303         delete applet-> library;
00304     }
00305     menuApplets.clear();
00306 }
00307 
00308 
00309 
00310 
00311 void StartMenu::loadApplets()
00312 {
00313     Config cfg( "StartMenu" );
00314     cfg.setGroup( "Applets" );
00315 
00316     // SafeMode causes too much problems, so we disable it for now --
00317     // maybe we should reenable it for OPIE 1.0 - sandman 26.09.02
00318     // removed in the remerge PluginManager could handle it
00319     // we don't currently use it -zecke
00320 
00321     QStringList exclude = cfg.readListEntry( "ExcludeApplets", ',' );
00322 
00323     QString lang = getenv( "LANG" );
00324     QString path = QPEApplication::qpeDir() + "plugins/applets";
00325     QDir dir( path, "lib*.so" );
00326     QStringList list = dir.entryList();
00327     QStringList::Iterator it;
00328     int napplets = 0;
00329     MenuApplet* *xapplets = new MenuApplet*[list.count()];
00330     for ( it = list.begin(); it != list.end(); ++it ) {
00331         if ( exclude.find( *it ) != exclude.end() )
00332             continue;
00333         MenuAppletInterface *iface = 0;
00334         QLibrary *lib = new QLibrary( path + "/" + *it );
00335         if (( lib->queryInterface( IID_MenuApplet, (QUnknownInterface**)&iface ) == QS_OK ) && iface ) {
00336             MenuApplet *applet = new MenuApplet;
00337             xapplets[napplets++] = applet;
00338             applet->library = lib;
00339             applet->iface = iface;
00340 
00341             QTranslator *trans = new QTranslator(qApp);
00342             QString type = (*it).left( (*it).find(".") );
00343             QString tfn = QPEApplication::qpeDir()+"i18n/"+lang+"/"+type+".qm";
00344             if ( trans->load( tfn ))
00345                 qApp->installTranslator( trans );
00346             else
00347                 delete trans;
00348         } else {
00349             exclude += *it;
00350             delete lib;
00351         }
00352     }
00353     cfg.writeEntry( "ExcludeApplets", exclude, ',' );
00354     qsort(xapplets, napplets, sizeof(menuApplets[0]), compareAppletPositions);
00355 
00356 
00357     while ( napplets-- ) {
00358         MenuApplet *applet = xapplets[napplets];
00359         applet->popup = applet->iface->popup( this );
00360 
00361         // menuApplets got an id < -1
00362         menuApplets.insert( -( currentItem + 2 ), new MenuApplet( *applet ) );
00363         currentItem++;
00364     }
00365     delete [] xapplets;
00366 
00367     addApplets( launchMenu );
00368 }
00369 
00370 
00371 /*
00372  * Launcher calls loadMenu too often fix that
00373  */
00374 void StartMenu::addApplets(QPopupMenu* pop) {
00375     QIntDict<MenuApplet> dict;
00376     if( pop-> count ( ))
00377         pop-> insertSeparator ( );
00378 
00379     for ( QIntDictIterator<MenuApplet> it( menuApplets ); it.current(); ++it ) {
00380         MenuApplet *applet = it.current();
00381         if ( applet->popup )
00382             applet->id = pop->insertItem( applet->iface->icon(),
00383                                           applet->iface->text(), applet->popup );
00384         else
00385             applet->id = pop->insertItem( applet->iface->icon(),
00386                                           applet->iface->text() );
00387 
00388 
00389         dict.insert( applet->id, new MenuApplet( *applet ) );
00390     }
00391     /* need to update the key */
00392     menuApplets.setAutoDelete( true );
00393     menuApplets.clear();
00394     menuApplets.setAutoDelete( false );
00395     menuApplets = dict;
00396 }

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