Qtopia library API Documentation

global.cpp

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 
00030 #include <qfile.h>
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 #include <qfile.h>
00051 
00052 namespace {
00053   // checks if the storage should be searched
00054   bool checkStorage(const QString &path ){ // this is a small Config replacement cause config is too limited -zecke
00055     QFile file(path );
00056     if(!file.open(IO_ReadOnly ) )
00057        return true;
00058 
00059     QByteArray array = file.readAll();
00060     QStringList list = QStringList::split('\n', QString( array ) );
00061     for(QStringList::Iterator it = list.begin(); it != list.end(); ++it ){
00062       if( (*it).startsWith("autocheck = 0" ) ){
00063     return false;
00064       }else if( (*it).startsWith("autocheck = 1" ) ){
00065     return true;
00066       }
00067     }
00068     return true;
00069   }
00070 }
00071 
00072 //#include "quickexec_p.h"
00073 
00074 class Emitter : public QObject {
00075     Q_OBJECT
00076 public:
00077     Emitter( QWidget* receiver, const QString& document )
00078     {
00079     connect(this, SIGNAL(setDocument(const QString&)),
00080         receiver, SLOT(setDocument(const QString&)));
00081     emit setDocument(document);
00082     disconnect(this, SIGNAL(setDocument(const QString&)),
00083            receiver, SLOT(setDocument(const QString&)));
00084     }
00085 
00086 signals:
00087     void setDocument(const QString&);
00088 };
00089 
00090 
00091 class StartingAppList : public QObject {
00092     Q_OBJECT
00093 public:
00094     static void add( const QString& name );
00095     static bool isStarting( const QString name );
00096 private slots:
00097     void handleNewChannel( const QString &);
00098 private:
00099     StartingAppList( QObject *parent=0, const char* name=0 ) ;
00100 
00101     QDict<QTime> dict;
00102     static StartingAppList *appl;
00103 };
00104 
00105 StartingAppList* StartingAppList::appl = 0;
00106 
00107 StartingAppList::StartingAppList( QObject *parent, const char* name )
00108     :QObject( parent, name )
00109 {
00110 #if QT_VERSION >= 232 && defined(QWS)
00111     connect( qwsServer, SIGNAL( newChannel(const QString&)),
00112          this, SLOT( handleNewChannel(const QString&)) );
00113 #endif
00114     dict.setAutoDelete( TRUE );
00115 }
00116 
00117 void StartingAppList::add( const QString& name )
00118 {
00119 #if QT_VERSION >= 232  && !defined(QT_NO_COP)
00120     if ( !appl )
00121     appl = new StartingAppList;
00122     QTime *t = new QTime;
00123     t->start();
00124     appl->dict.insert( "QPE/Application/" + name, t );
00125 #endif
00126 }
00127 
00128 bool StartingAppList::isStarting( const QString name )
00129 {
00130 #if QT_VERSION >= 232  && !defined(QT_NO_COP)
00131     if ( appl ) {
00132     QTime *t  = appl->dict.find( "QPE/Application/" + name );
00133     if ( !t )
00134         return FALSE;
00135     if ( t->elapsed() > 10000 ) {
00136         // timeout in case of crash or something
00137         appl->dict.remove( "QPE/Application/" + name );
00138         return FALSE;
00139     }
00140     return TRUE;
00141     }
00142 #endif
00143     return FALSE;
00144 }
00145 
00146 void StartingAppList::handleNewChannel( const QString & name )
00147 {
00148 #if QT_VERSION >= 232  && !defined(QT_NO_COP)
00149     dict.remove( name );
00150 #endif
00151 }
00152 
00153 static bool docDirCreated = FALSE;
00154 static QDawg* fixed_dawg = 0;
00155 static QDict<QDawg> *named_dawg = 0;
00156 
00157 static QString qpeDir()
00158 {
00159     QString dir = getenv("OPIEDIR");
00160     if ( dir.isEmpty() ) dir = "..";
00161     return dir;
00162 }
00163 
00164 static QString dictDir()
00165 {
00166     return qpeDir() + "/etc/dict";
00167 }
00168 
00227 Global::Global()
00228 {
00229 }
00230 
00237 const QDawg& Global::fixedDawg()
00238 {
00239     if ( !fixed_dawg ) {
00240     if ( !docDirCreated )
00241         createDocDir();
00242 
00243     fixed_dawg = new QDawg;
00244     QString dawgfilename = dictDir() + "/dawg";
00245     QString words_lang;
00246     QStringList langs = Global::languageList();
00247     for (QStringList::ConstIterator it = langs.begin(); it!=langs.end(); ++it) {
00248         QString lang = *it;
00249         words_lang = dictDir() + "/words." + lang;
00250         QString dawgfilename_lang = dawgfilename + "." + lang;
00251         if ( QFile::exists(dawgfilename_lang) ||
00252          QFile::exists(words_lang) ) {
00253         dawgfilename = dawgfilename_lang;
00254         break;
00255         }
00256     }
00257     QFile dawgfile(dawgfilename);
00258 
00259     if ( !dawgfile.exists() ) {
00260         QString fn = dictDir() + "/words";
00261         if ( QFile::exists(words_lang) )
00262         fn = words_lang;
00263         QFile in(fn);
00264         if ( in.open(IO_ReadOnly) ) {
00265         fixed_dawg->createFromWords(&in);
00266         dawgfile.open(IO_WriteOnly);
00267         fixed_dawg->write(&dawgfile);
00268         dawgfile.close();
00269         }
00270     } else {
00271         fixed_dawg->readFile(dawgfilename);
00272     }
00273     }
00274 
00275     return *fixed_dawg;
00276 }
00277 
00284 const QDawg& Global::addedDawg()
00285 {
00286     return dawg("local");
00287 }
00288 
00295 const QDawg& Global::dawg(const QString& name)
00296 {
00297     createDocDir();
00298     if ( !named_dawg )
00299     named_dawg = new QDict<QDawg>;
00300     QDawg* r = named_dawg->find(name);
00301     if ( !r ) {
00302     r = new QDawg;
00303     named_dawg->insert(name,r);
00304     QString dawgfilename = applicationFileName("Dictionary", name ) + ".dawg";
00305     QFile dawgfile(dawgfilename);
00306     if ( dawgfile.open(IO_ReadOnly) )
00307         r->readFile(dawgfilename);
00308     }
00309     return *r;
00310 }
00311 
00320 void Global::addWords(const QStringList& wordlist)
00321 {
00322     addWords("local",wordlist);
00323 }
00324 
00333 void Global::addWords(const QString& dictname, const QStringList& wordlist)
00334 {
00335     QDawg& d = (QDawg&)dawg(dictname);
00336     QStringList all = d.allWords() + wordlist;
00337     d.createFromWords(all);
00338 
00339     QString dawgfilename = applicationFileName("Dictionary", dictname) + ".dawg";
00340     QFile dawgfile(dawgfilename);
00341     if ( dawgfile.open(IO_WriteOnly) ) {
00342     d.write(&dawgfile);
00343     dawgfile.close();
00344     }
00345 
00346     // #### Re-read the dawg here if we use mmap().
00347 
00348     // #### Signal other processes to re-read.
00349 }
00350 
00351 
00359 QString Global::applicationFileName(const QString& appname, const QString& filename)
00360 {
00361     QDir d;
00362     QString r = getenv("HOME");
00363     r += "/Applications/";
00364     if ( !QFile::exists( r ) )
00365     if ( d.mkdir(r) == false )
00366         return QString::null;
00367     r += appname;
00368     if ( !QFile::exists( r ) )
00369     if ( d.mkdir(r) == false )
00370         return QString::null;
00371     r += "/"; r += filename;
00372     return r;
00373 }
00374 
00378 void Global::createDocDir()
00379 {
00380     if ( !docDirCreated ) {
00381     docDirCreated = TRUE;
00382     mkdir( QPEApplication::documentDir().latin1(), 0755 );
00383     }
00384 }
00385 
00386 
00391 void Global::statusMessage(const QString& message)
00392 {
00393 #if !defined(QT_NO_COP)
00394     QCopEnvelope e( "QPE/TaskBar", "message(QString)" );
00395     e << message;
00396 #endif
00397 }
00398 
00402 void Global::applyStyle()
00403 {
00404 #if !defined(QT_NO_COP)
00405     QCopChannel::send( "QPE/System", "applyStyle()" );
00406 #else
00407     ((QPEApplication *)qApp)->applyStyle(); // apply without needing QCop for floppy version
00408 #endif
00409 }
00410 
00414 QWidget *Global::shutdown( bool )
00415 {
00416 #if !defined(QT_NO_COP)
00417     QCopChannel::send( "QPE/System", "shutdown()" );
00418 #endif
00419     return 0;
00420 }
00421 
00425 QWidget *Global::restart( bool )
00426 {
00427 #if !defined(QT_NO_COP)
00428     QCopChannel::send( "QPE/System", "restart()" );
00429 #endif
00430     return 0;
00431 }
00432 
00443 void Global::showInputMethod()
00444 {
00445 #if !defined(QT_NO_COP)
00446     QCopChannel::send( "QPE/TaskBar", "showInputMethod()" );
00447 #endif
00448 }
00449 
00458 void Global::hideInputMethod()
00459 {
00460 #if !defined(QT_NO_COP)
00461     QCopChannel::send( "QPE/TaskBar", "hideInputMethod()" );
00462 #endif
00463 }
00464 
00465 
00469 bool Global::isBuiltinCommand( const QString &name )
00470 {
00471     if(!builtin)
00472     return FALSE; // yes, it can happen
00473     for (int i = 0; builtin[i].file; i++) {
00474     if ( builtin[i].file == name ) {
00475         return TRUE;
00476     }
00477     }
00478     return FALSE;
00479 }
00480 
00481 Global::Command* Global::builtin=0;
00482 QGuardedPtr<QWidget> *Global::running=0;
00483 
00493 void Global::setBuiltinCommands( Command* list )
00494 {
00495     if ( running )
00496     delete [] running;
00497 
00498     builtin = list;
00499     int count = 0;
00500     if (!builtin)
00501     return;
00502     while ( builtin[count].file )
00503     count++;
00504 
00505     running = new QGuardedPtr<QWidget> [ count ];
00506 }
00507 
00511 void Global::setDocument( QWidget* receiver, const QString& document )
00512 {
00513     Emitter emitter(receiver,document);
00514 }
00515 
00519 bool Global::terminateBuiltin( const QString& n )
00520 {
00521     if (!builtin)
00522     return FALSE;
00523     for (int i = 0; builtin[i].file; i++) {
00524     if ( builtin[i].file == n ) {
00525         delete running[i];
00526         return TRUE;
00527     }
00528     }
00529     return FALSE;
00530 }
00531 
00535 void Global::terminate( const AppLnk* app )
00536 {
00537     //if ( terminateBuiltin(app->exec()) ) return; // maybe? haven't tried this
00538 
00539 #ifndef QT_NO_COP
00540     QCString channel = "QPE/Application/" + app->exec().utf8();
00541     if ( QCopChannel::isRegistered(channel) ) {
00542     QCopEnvelope e(channel, "quit()");
00543     }
00544 #endif
00545 }
00546 
00554 void Global::invoke(const QString &c)
00555 {
00556     // Convert the command line in to a list of arguments
00557     QStringList list = QStringList::split(QRegExp("  *"),c);
00558 
00559 #if !defined(QT_NO_COP)
00560     QString ap=list[0];
00561     // see if the application is already running
00562     // XXX should lock file /tmp/qcop-msg-ap
00563     if ( QCopChannel::isRegistered( ("QPE/Application/" + ap).latin1() ) ) {
00564     // If the channel is already register, the app is already running, so show it.
00565     { QCopEnvelope env( ("QPE/Application/" + ap).latin1(), "raise()" ); }
00566 
00567     //QCopEnvelope e("QPE/System", "notBusy(QString)" );
00568     //e << ap;
00569     return;
00570     }
00571     // XXX should unlock file /tmp/qcop-msg-ap
00572     //see if it is being started
00573     if ( StartingAppList::isStarting( ap ) ) {
00574         // FIXME take it out for now, since it leads to a much to short showing of wait if
00575         // some entry is clicked.
00576         // Real cause is that ::execute is called twice for document tab. But it would need some larger changes
00577         // to fix that, and with future syncs with qtopia 1.6 it will change anyway big time since somebody there
00578         // had the idea that an apploader belongs to the launcher ...
00579     //QCopEnvelope e("QPE/System", "notBusy(QString)" );
00580     //e << ap;
00581     return;
00582     }
00583 
00584 #endif
00585 
00586 #ifdef QT_NO_QWS_MULTIPROCESS
00587     QMessageBox::warning( 0, "Error", "Could not find the application " + c, "Ok", 0, 0, 0, 1 );
00588 #else
00589 
00590     QStrList slist;
00591     unsigned int j;
00592     for ( j = 0; j < list.count(); j++ )
00593     slist.append( list[j].utf8() );
00594 
00595     const char **args = new (const char *)[slist.count() + 1];
00596     for ( j = 0; j < slist.count(); j++ )
00597     args[j] = slist.at(j);
00598     args[j] = NULL;
00599 
00600 #if !defined(QT_NO_COP)
00601     // an attempt to show a wait...
00602     // more logic should be used, but this will be fine for the moment...
00603     QCopEnvelope ( "QPE/System", "busy()" );
00604 #endif
00605 
00606 #ifdef HAVE_QUICKEXEC
00607 #ifdef Q_OS_MACX
00608     QString libexe = qpeDir()+"/binlib/lib"+args[0] + ".dylib";
00609 #else
00610     QString libexe = qpeDir()+"/binlib/lib"+args[0] + ".so";
00611 #endif
00612     qDebug("libfile = %s", libexe.latin1() );
00613     if ( QFile::exists( libexe ) ) {
00614     qDebug("calling quickexec %s", libexe.latin1() );
00615     quickexecv( libexe.utf8().data(), (const char **)args );
00616     } else
00617 #endif
00618     {
00619         bool success = false;
00620         int pfd [2];
00621         if ( ::pipe ( pfd ) < 0 )
00622             pfd [0] = pfd [1] = -1;
00623 
00624         pid_t pid = ::fork ( );
00625 
00626         if ( pid == 0 ) { // child
00627             for ( int fd = 3; fd < 100; fd++ ) {
00628                 if ( fd != pfd [1] )
00629                     ::close ( fd );
00630             }
00631             ::setpgid ( ::getpid ( ), ::getppid ( ));
00632 
00633             // Closing of fd[1] indicates that the execvp succeeded!
00634             if ( pfd [1] >= 0 )
00635                 ::fcntl ( pfd [1], F_SETFD, FD_CLOEXEC );
00636 
00637             // Try bindir first, so that foo/bar works too
00638             ::execv ( qpeDir ( ) + "/bin/" + args [0], (char * const *) args );
00639             ::execvp ( args [0], (char * const *) args );
00640 
00641             char resultByte = 1;
00642             if ( pfd [1] >= 0 )
00643                 ::write ( pfd [1], &resultByte, 1 );
00644             ::_exit ( -1 );
00645         }
00646         else if ( pid > 0 ) {
00647             success = true;
00648 
00649             if ( pfd [1] >= 0 )
00650                 ::close ( pfd [1] );
00651             if ( pfd [0] >= 0 ) {
00652                 while ( true ) {
00653                     char resultByte;
00654                     int n = ::read ( pfd [0], &resultByte, 1 );
00655                     if ( n == 1 ) {
00656                         success = false;
00657                         break;
00658                     }
00659                     if (( n == -1 ) && (( errno == ECHILD ) || ( errno == EINTR )))
00660                         continue;
00661 
00662                     break; // success
00663                 }
00664                 ::close ( pfd [0] );
00665             }
00666         }
00667         if ( success )
00668             StartingAppList::add( list[0] );
00669         else
00670             QMessageBox::warning( 0, "Error", "Could not start the application " + c, "Ok", 0, 0, 0, 1 );
00671     }
00672 #endif //QT_NO_QWS_MULTIPROCESS
00673 }
00674 
00675 
00683 void Global::execute( const QString &c, const QString& document )
00684 {
00685     // ask the server to do the work
00686 #if !defined(QT_NO_COP)
00687     if ( document.isNull() ) {
00688         QCopEnvelope e( "QPE/System", "execute(QString)" );
00689         e << c;
00690     } else {
00691         QCopEnvelope e( "QPE/System", "execute(QString,QString)" );
00692         e << c << document;
00693     }
00694 #endif
00695     return;
00696 }
00697 
00704 QString Global::shellQuote(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 '"': case '$':
00711         r+="\\";
00712     }
00713     r += s[i];
00714     }
00715     r += "\"";
00716     return r;
00717 }
00718 
00725 QString Global::stringQuote(const QString& s)
00726 {
00727     QString r="\"";
00728     for (int i=0; i<(int)s.length(); i++) {
00729     char c = s[i].latin1();
00730     switch (c) {
00731         case '\\': case '"':
00732         r+="\\";
00733     }
00734     r += s[i];
00735     }
00736     r += "\"";
00737     return r;
00738 }
00739 
00745 void Global::findDocuments(DocLnkSet* folder, const QString &mimefilter)
00746 {
00747     QString homedocs = QString(getenv("HOME")) + "/Documents";
00748     DocLnkSet d(homedocs,mimefilter);
00749     folder->appendFrom(d);
00764     StorageInfo storage;
00765     const QList<FileSystem> &fs = storage.fileSystems();
00766     QListIterator<FileSystem> it ( fs );
00767     for ( ; it.current(); ++it ) {
00768       if ( (*it)->isRemovable() ) { // let's find out  if we should search on it
00769     // this is a candidate look at the cf and see if we should search on it
00770     QString path = (*it)->path();
00771     if( !checkStorage((*it)->path() + "/.opiestorage.cf" ) )
00772       continue;
00773     DocLnkSet ide( path, mimefilter );
00774     folder->appendFrom(ide);
00775       } else if ( (*it)->disk() == "/dev/mtdblock6" || (*it)->disk() == "tmpfs" ) {
00776     QString path = (*it)->path() + "/Documents";
00777     DocLnkSet ide( path, mimefilter );
00778     folder->appendFrom(ide);
00779       }
00780     }
00781 }
00782 
00783 QStringList Global::languageList()
00784 {
00785     QString lang = getenv("LANG");
00786     QStringList langs;
00787     langs.append(lang);
00788     int i  = lang.find(".");
00789     if ( i > 0 )
00790     lang = lang.left( i );
00791     i = lang.find( "_" );
00792     if ( i > 0 )
00793     langs.append(lang.left(i));
00794     return langs;
00795 }
00796 
00797 QStringList Global::helpPath()
00798 {
00799     QString qpeDir = QPEApplication::qpeDir();
00800     QStringList path;
00801     QStringList langs = Global::languageList();
00802     for (QStringList::ConstIterator it = langs.fromLast(); it!=langs.end(); --it) {
00803     QString lang = *it;
00804     if ( !lang.isEmpty() )
00805         path += qpeDir + "/help/" + lang + "/html";
00806     }
00807     path += qpeDir + "/pics";
00808     path += qpeDir + "/help/html";
00809     /* we even put english into the en dir so try it as fallback as well for opie */
00810     path += qpeDir + "/help/en/html";
00811     path += qpeDir + "/docs";
00812 
00813 
00814     return path;
00815 }
00816 
00817 
00818 #include "global.moc"
KDE Logo
This file is part of the documentation for OPIE Version 1.5.5.
Documentation copyright © 1997-2003 the KDE developers. 2003 OPIE developers
Generated on Tue Feb 10 20:24:05 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2001