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

global.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 #define QTOPIA_INTERNAL_LANGLIST
00021 #include <qpe/qpedebug.h>
00022 #include <qpe/global.h>
00023 #include <qpe/qdawg.h>
00024 #include <qpe/qpeapplication.h>
00025 #include <qpe/resource.h>
00026 #include <qpe/storage.h>
00027 #include <qpe/applnk.h>
00028 #include <qpe/qcopenvelope_qws.h>
00029 #include <qpe/config.h>
00030 
00031 #include <qlabel.h>
00032 #include <qtimer.h>
00033 #include <qmap.h>
00034 #include <qdict.h>
00035 #include <qdir.h>
00036 #include <qmessagebox.h>
00037 #include <qregexp.h>
00038 
00039 #include <stdlib.h>
00040 #include <sys/stat.h>
00041 #include <sys/wait.h>
00042 #include <sys/types.h>
00043 #include <fcntl.h>
00044 #include <unistd.h>
00045 #include <errno.h>
00046 
00047 #include <qwindowsystem_qws.h> // for qwsServer
00048 #include <qdatetime.h>
00049 
00050 
00051 //#include "quickexec_p.h"
00052 
00053 class Emitter : public QObject {
00054     Q_OBJECT
00055 public:
00056     Emitter( QWidget* receiver, const QString& document )
00057     {
00058     connect(this, SIGNAL(setDocument(const QString&)),
00059         receiver, SLOT(setDocument(const QString&)));
00060     emit setDocument(document);
00061     disconnect(this, SIGNAL(setDocument(const QString&)),
00062            receiver, SLOT(setDocument(const QString&)));
00063     }
00064 
00065 signals:
00066     void setDocument(const QString&);
00067 };
00068 
00069 
00070 class StartingAppList : public QObject {
00071     Q_OBJECT
00072 public:
00073     static void add( const QString& name );
00074     static bool isStarting( const QString name );
00075 private slots:
00076     void handleNewChannel( const QString &);
00077 private:
00078     StartingAppList( QObject *parent=0, const char* name=0 ) ;
00079 
00080     QDict<QTime> dict;
00081     static StartingAppList *appl;
00082 };
00083 
00084 StartingAppList* StartingAppList::appl = 0;
00085 
00086 StartingAppList::StartingAppList( QObject *parent, const char* name )
00087     :QObject( parent, name )
00088 {
00089 #if QT_VERSION >= 232 && defined(QWS)
00090     connect( qwsServer, SIGNAL( newChannel(const QString&)),
00091          this, SLOT( handleNewChannel(const QString&)) );
00092 #endif
00093     dict.setAutoDelete( TRUE );
00094 }
00095 
00096 void StartingAppList::add( const QString& name )
00097 {
00098 #if QT_VERSION >= 232  && !defined(QT_NO_COP)
00099     if ( !appl )
00100     appl = new StartingAppList;
00101     QTime *t = new QTime;
00102     t->start();
00103     appl->dict.insert( "QPE/Application/" + name, t );
00104 #endif
00105 }
00106 
00107 bool StartingAppList::isStarting( const QString name )
00108 {
00109 #if QT_VERSION >= 232  && !defined(QT_NO_COP)
00110     if ( appl ) {
00111     QTime *t  = appl->dict.find( "QPE/Application/" + name );
00112     if ( !t )
00113         return FALSE;
00114     if ( t->elapsed() > 10000 ) {
00115         // timeout in case of crash or something
00116         appl->dict.remove( "QPE/Application/" + name );
00117         return FALSE;
00118     }
00119     return TRUE;
00120     }
00121 #endif
00122     return FALSE;
00123 }
00124 
00125 void StartingAppList::handleNewChannel( const QString & name )
00126 {
00127 #if QT_VERSION >= 232  && !defined(QT_NO_COP)
00128     dict.remove( name );
00129 #endif
00130 }
00131 
00132 static bool docDirCreated = FALSE;
00133 static QDawg* fixed_dawg = 0;
00134 static QDict<QDawg> *named_dawg = 0;
00135 
00136 static QString qpeDir()
00137 {
00138     QString dir = getenv("OPIEDIR");
00139     if ( dir.isEmpty() ) dir = "..";
00140     return dir;
00141 }
00142 
00143 static QString dictDir()
00144 {
00145     return qpeDir() + "/etc/dict";
00146 }
00147 
00206 Global::Global()
00207 {
00208 }
00209 
00216 const QDawg& Global::fixedDawg()
00217 {
00218     if ( !fixed_dawg ) {
00219     if ( !docDirCreated )
00220         createDocDir();
00221 
00222     fixed_dawg = new QDawg;
00223     QString dawgfilename = dictDir() + "/dawg";
00224     QString words_lang;
00225     QStringList langs = Global::languageList();
00226     for (QStringList::ConstIterator it = langs.begin(); it!=langs.end(); ++it) {
00227         QString lang = *it;
00228         words_lang = dictDir() + "/words." + lang;
00229         QString dawgfilename_lang = dawgfilename + "." + lang;
00230         if ( QFile::exists(dawgfilename_lang) ||
00231          QFile::exists(words_lang) ) {
00232         dawgfilename = dawgfilename_lang;
00233         break;
00234         }
00235     }
00236     QFile dawgfile(dawgfilename);
00237 
00238     if ( !dawgfile.exists() ) {
00239         QString fn = dictDir() + "/words";
00240         if ( QFile::exists(words_lang) )
00241         fn = words_lang;
00242         QFile in(fn);
00243         if ( in.open(IO_ReadOnly) ) {
00244         fixed_dawg->createFromWords(&in);
00245         dawgfile.open(IO_WriteOnly);
00246         fixed_dawg->write(&dawgfile);
00247         dawgfile.close();
00248         }
00249     } else {
00250         fixed_dawg->readFile(dawgfilename);
00251     }
00252     }
00253 
00254     return *fixed_dawg;
00255 }
00256 
00263 const QDawg& Global::addedDawg()
00264 {
00265     return dawg("local");
00266 }
00267 
00274 const QDawg& Global::dawg(const QString& name)
00275 {
00276     createDocDir();
00277     if ( !named_dawg )
00278     named_dawg = new QDict<QDawg>;
00279     QDawg* r = named_dawg->find(name);
00280     if ( !r ) {
00281     r = new QDawg;
00282     named_dawg->insert(name,r);
00283     QString dawgfilename = applicationFileName("Dictionary", name ) + ".dawg";
00284     QFile dawgfile(dawgfilename);
00285     if ( dawgfile.open(IO_ReadOnly) )
00286         r->readFile(dawgfilename);
00287     }
00288     return *r;
00289 }
00290 
00299 void Global::addWords(const QStringList& wordlist)
00300 {
00301     addWords("local",wordlist);
00302 }
00303 
00312 void Global::addWords(const QString& dictname, const QStringList& wordlist)
00313 {
00314     QDawg& d = (QDawg&)dawg(dictname);
00315     QStringList all = d.allWords() + wordlist;
00316     d.createFromWords(all);
00317 
00318     QString dawgfilename = applicationFileName("Dictionary", dictname) + ".dawg";
00319     QFile dawgfile(dawgfilename);
00320     if ( dawgfile.open(IO_WriteOnly) ) {
00321     d.write(&dawgfile);
00322     dawgfile.close();
00323     }
00324 
00325     // #### Re-read the dawg here if we use mmap().
00326 
00327     // #### Signal other processes to re-read.
00328 }
00329 
00330 
00338 QString Global::applicationFileName(const QString& appname, const QString& filename)
00339 {
00340     QDir d;
00341     QString r = getenv("HOME");
00342     r += "/Applications/";
00343     if ( !QFile::exists( r ) )
00344     if ( d.mkdir(r) == false )
00345         return QString::null;
00346     r += appname;
00347     if ( !QFile::exists( r ) )
00348     if ( d.mkdir(r) == false )
00349         return QString::null;
00350     r += "/"; r += filename;
00351     return r;
00352 }
00353 
00357 void Global::createDocDir()
00358 {
00359     if ( !docDirCreated ) {
00360     docDirCreated = TRUE;
00361     mkdir( QPEApplication::documentDir().latin1(), 0755 );
00362     }
00363 }
00364 
00365 
00370 void Global::statusMessage(const QString& message)
00371 {
00372 #if !defined(QT_NO_COP)
00373     QCopEnvelope e( "QPE/TaskBar", "message(QString)" );
00374     e << message;
00375 #endif
00376 }
00377 
00381 void Global::applyStyle()
00382 {
00383 #if !defined(QT_NO_COP)
00384     QCopChannel::send( "QPE/System", "applyStyle()" );
00385 #else
00386     ((QPEApplication *)qApp)->applyStyle(); // apply without needing QCop for floppy version
00387 #endif
00388 }
00389 
00393 QWidget *Global::shutdown( bool )
00394 {
00395 #if !defined(QT_NO_COP)
00396     QCopChannel::send( "QPE/System", "shutdown()" );
00397 #endif
00398     return 0;
00399 }
00400 
00404 QWidget *Global::restart( bool )
00405 {
00406 #if !defined(QT_NO_COP)
00407     QCopChannel::send( "QPE/System", "restart()" );
00408 #endif
00409     return 0;
00410 }
00411 
00422 void Global::showInputMethod()
00423 {
00424 #if !defined(QT_NO_COP)
00425     QCopChannel::send( "QPE/TaskBar", "showInputMethod()" );
00426 #endif
00427 }
00428 
00437 void Global::hideInputMethod()
00438 {
00439 #if !defined(QT_NO_COP)
00440     QCopChannel::send( "QPE/TaskBar", "hideInputMethod()" );
00441 #endif
00442 }
00443 
00444 
00448 bool Global::isBuiltinCommand( const QString &name )
00449 {
00450     if(!builtin)
00451     return FALSE; // yes, it can happen
00452     for (int i = 0; builtin[i].file; i++) {
00453     if ( builtin[i].file == name ) {
00454         return TRUE;
00455     }
00456     }
00457     return FALSE;
00458 }
00459 
00460 Global::Command* Global::builtin=0;
00461 QGuardedPtr<QWidget> *Global::running=0;
00462 
00472 void Global::setBuiltinCommands( Command* list )
00473 {
00474     if ( running )
00475     delete [] running;
00476 
00477     builtin = list;
00478     int count = 0;
00479     if (!builtin)
00480     return;
00481     while ( builtin[count].file )
00482     count++;
00483 
00484     running = new QGuardedPtr<QWidget> [ count ];
00485 }
00486 
00490 void Global::setDocument( QWidget* receiver, const QString& document )
00491 {
00492     Emitter emitter(receiver,document);
00493 }
00494 
00498 bool Global::terminateBuiltin( const QString& n )
00499 {
00500     if (!builtin)
00501     return FALSE;
00502     for (int i = 0; builtin[i].file; i++) {
00503     if ( builtin[i].file == n ) {
00504         delete running[i];
00505         return TRUE;
00506     }
00507     }
00508     return FALSE;
00509 }
00510 
00514 void Global::terminate( const AppLnk* app )
00515 {
00516     //if ( terminateBuiltin(app->exec()) ) return; // maybe? haven't tried this
00517 
00518 #ifndef QT_NO_COP
00519     QCString channel = "QPE/Application/" + app->exec().utf8();
00520     if ( QCopChannel::isRegistered(channel) ) {
00521     QCopEnvelope e(channel, "quit()");
00522     }
00523 #endif
00524 }
00525 
00533 void Global::invoke(const QString &c)
00534 {
00535     // Convert the command line in to a list of arguments
00536     QStringList list = QStringList::split(QRegExp("  *"),c);
00537 
00538 #if !defined(QT_NO_COP)
00539     QString ap=list[0];
00540     // see if the application is already running
00541     // XXX should lock file /tmp/qcop-msg-ap
00542     if ( QCopChannel::isRegistered( ("QPE/Application/" + ap).latin1() ) ) {
00543     // If the channel is already register, the app is already running, so show it.
00544     { QCopEnvelope env( ("QPE/Application/" + ap).latin1(), "raise()" ); }
00545 
00546     //QCopEnvelope e("QPE/System", "notBusy(QString)" );
00547     //e << ap;
00548     return;
00549     }
00550     // XXX should unlock file /tmp/qcop-msg-ap
00551     //see if it is being started
00552     if ( StartingAppList::isStarting( ap ) ) {
00553         // FIXME take it out for now, since it leads to a much to short showing of wait if
00554         // some entry is clicked.
00555         // Real cause is that ::execute is called twice for document tab. But it would need some larger changes
00556         // to fix that, and with future syncs with qtopia 1.6 it will change anyway big time since somebody there
00557         // had the idea that an apploader belongs to the launcher ...
00558     //QCopEnvelope e("QPE/System", "notBusy(QString)" );
00559     //e << ap;
00560     return;
00561     }
00562 
00563 #endif
00564 
00565 #ifdef QT_NO_QWS_MULTIPROCESS
00566     QMessageBox::warning( 0, "Error", "Could not find the application " + c, "Ok", 0, 0, 0, 1 );
00567 #else
00568 
00569     QStrList slist;
00570     unsigned int j;
00571     for ( j = 0; j < list.count(); j++ )
00572     slist.append( list[j].utf8() );
00573 
00574     const char **args = new const char *[slist.count() + 1];
00575     for ( j = 0; j < slist.count(); j++ )
00576     args[j] = slist.at(j);
00577     args[j] = NULL;
00578 
00579 #if !defined(QT_NO_COP)
00580     // an attempt to show a wait...
00581     // more logic should be used, but this will be fine for the moment...
00582     QCopEnvelope ( "QPE/System", "busy()" );
00583 #endif
00584 
00585 #ifdef HAVE_QUICKEXEC
00586 #ifdef Q_OS_MACX
00587     QString libexe = qpeDir()+"/binlib/lib"+args[0] + ".dylib";
00588 #else
00589     QString libexe = qpeDir()+"/binlib/lib"+args[0] + ".so";
00590 #endif
00591     qDebug("libfile = %s", libexe.latin1() );
00592     if ( QFile::exists( libexe ) ) {
00593     qDebug("calling quickexec %s", libexe.latin1() );
00594     quickexecv( libexe.utf8().data(), (const char **)args );
00595     } else
00596 #endif
00597     {
00598         bool success = false;
00599         int pfd [2];
00600         if ( ::pipe ( pfd ) < 0 )
00601             pfd [0] = pfd [1] = -1;
00602 
00603         pid_t pid = ::fork ( );
00604 
00605         if ( pid == 0 ) { // child
00606             for ( int fd = 3; fd < 100; fd++ ) {
00607                 if ( fd != pfd [1] )
00608                     ::close ( fd );
00609             }
00610             ::setpgid ( ::getpid ( ), ::getppid ( ));
00611 
00612             // Closing of fd[1] indicates that the execvp succeeded!
00613             if ( pfd [1] >= 0 )
00614                 ::fcntl ( pfd [1], F_SETFD, FD_CLOEXEC );
00615 
00616             // Try bindir first, so that foo/bar works too
00617             ::execv ( qpeDir ( ) + "/bin/" + args [0], (char * const *) args );
00618             ::execvp ( args [0], (char * const *) args );
00619 
00620             char resultByte = 1;
00621             if ( pfd [1] >= 0 )
00622                 ::write ( pfd [1], &resultByte, 1 );
00623             ::_exit ( -1 );
00624         }
00625         else if ( pid > 0 ) {
00626             success = true;
00627 
00628             if ( pfd [1] >= 0 )
00629                 ::close ( pfd [1] );
00630             if ( pfd [0] >= 0 ) {
00631                 while ( true ) {
00632                     char resultByte;
00633                     int n = ::read ( pfd [0], &resultByte, 1 );
00634                     if ( n == 1 ) {
00635                         success = false;
00636                         break;
00637                     }
00638                     if (( n == -1 ) && (( errno == ECHILD ) || ( errno == EINTR )))
00639                         continue;
00640 
00641                     break; // success
00642                 }
00643                 ::close ( pfd [0] );
00644             }
00645         }
00646         if ( success )
00647             StartingAppList::add( list[0] );
00648         else
00649             QMessageBox::warning( 0, "Error", "Could not start the application " + c, "Ok", 0, 0, 0, 1 );
00650     }
00651 #endif //QT_NO_QWS_MULTIPROCESS
00652 }
00653 
00654 
00662 void Global::execute( const QString &c, const QString& document )
00663 {
00664     // ask the server to do the work
00665 #if !defined(QT_NO_COP)
00666     if ( document.isNull() ) {
00667         QCopEnvelope e( "QPE/System", "execute(QString)" );
00668         e << c;
00669     } else {
00670         QCopEnvelope e( "QPE/System", "execute(QString,QString)" );
00671         e << c << document;
00672     }
00673 #endif
00674     return;
00675 }
00676 
00683 QString Global::shellQuote(const QString& s)
00684 {
00685     QString r="\"";
00686     for (int i=0; i<(int)s.length(); i++) {
00687     char c = s[i].latin1();
00688     switch (c) {
00689         case '\\': case '"': case '$':
00690         r+="\\";
00691     }
00692     r += s[i];
00693     }
00694     r += "\"";
00695     return r;
00696 }
00697 
00704 QString Global::stringQuote(const QString& s)
00705 {
00706     QString r="\"";
00707     for (int i=0; i<(int)s.length(); i++) {
00708     char c = s[i].latin1();
00709     switch (c) {
00710         case '\\': case '"':
00711         r+="\\";
00712     }
00713     r += s[i];
00714     }
00715     r += "\"";
00716     return r;
00717 }
00718 
00724 void Global::findDocuments(DocLnkSet* folder, const QString &mimefilter)
00725 {
00726     QString homedocs = QString(getenv("HOME")) + "/Documents";
00727     DocLnkSet d(homedocs,mimefilter);
00728     folder->appendFrom(d);
00743     StorageInfo storage;
00744     const QList<FileSystem> &fs = storage.fileSystems();
00745     QListIterator<FileSystem> it ( fs );
00746     for ( ; it.current(); ++it ) {
00747       if ( (*it)->isRemovable() ) { // let's find out  if we should search on it
00748         // this is a candidate look at the cf and see if we should search on it
00749         QString path = (*it)->path();
00750         Config conf((*it)->path() + "/.opiestorage.cf", Config::File );
00751         conf.setGroup("main");
00752         if (!conf.readBoolEntry("check",true)) {
00753             continue;
00754         }
00755         conf.setGroup("subdirs");
00756         if (conf.readBoolEntry("wholemedia",true)) {
00757             DocLnkSet ide( path,mimefilter);
00758             folder->appendFrom(ide);
00759         } else {
00760             QStringList subDirs = conf.readListEntry("subdirs",':');
00761             if (subDirs.isEmpty()) {
00762                 subDirs.append("Documents");
00763             }
00764             for (unsigned c = 0; c < subDirs.count();++c) {
00765                 DocLnkSet ide( path+"/"+subDirs[c], mimefilter );
00766                 folder->appendFrom(ide);
00767             }
00768         }
00769       } else if ( (*it)->disk() == "/dev/mtdblock6" || (*it)->disk() == "tmpfs" ) {
00770     QString path = (*it)->path() + "/Documents";
00771     DocLnkSet ide( path, mimefilter );
00772     folder->appendFrom(ide);
00773       }
00774     }
00775 }
00776 
00777 QStringList Global::languageList()
00778 {
00779     QString lang = getenv("LANG");
00780     QStringList langs;
00781     langs.append(lang);
00782     int i  = lang.find(".");
00783     if ( i > 0 )
00784     lang = lang.left( i );
00785     i = lang.find( "_" );
00786     if ( i > 0 )
00787     langs.append(lang.left(i));
00788     return langs;
00789 }
00790 
00791 QStringList Global::helpPath()
00792 {
00793     QString qpeDir = QPEApplication::qpeDir();
00794     QStringList path;
00795     QStringList langs = Global::languageList();
00796     for (QStringList::ConstIterator it = langs.fromLast(); it!=langs.end(); --it) {
00797     QString lang = *it;
00798     if ( !lang.isEmpty() )
00799         path += qpeDir + "/help/" + lang + "/html";
00800     }
00801     path += qpeDir + "/pics";
00802     path += qpeDir + "/help/html";
00803     /* we even put english into the en dir so try it as fallback as well for opie */
00804     path += qpeDir + "/help/en/html";
00805     path += qpeDir + "/docs";
00806 
00807 
00808     return path;
00809 }
00810 
00811 
00812 #include "global.moc"

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