summaryrefslogtreecommitdiff
path: root/library/applnk.cpp
authorkergoth <kergoth>2002-01-25 22:14:26 (UTC)
committer kergoth <kergoth>2002-01-25 22:14:26 (UTC)
commit15318cad33835e4e2dc620d033e43cd930676cdd (patch) (side-by-side diff)
treec2fa0399a2c47fda8e2cd0092c73a809d17f68eb /library/applnk.cpp
downloadopie-15318cad33835e4e2dc620d033e43cd930676cdd.zip
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.gz
opie-15318cad33835e4e2dc620d033e43cd930676cdd.tar.bz2
Initial revision
Diffstat (limited to 'library/applnk.cpp') (more/less context) (show whitespace changes)
-rw-r--r--library/applnk.cpp1093
1 files changed, 1093 insertions, 0 deletions
diff --git a/library/applnk.cpp b/library/applnk.cpp
new file mode 100644
index 0000000..2af6cf4
--- a/dev/null
+++ b/library/applnk.cpp
@@ -0,0 +1,1093 @@
+/**********************************************************************
+** Copyright (C) 2000 Trolltech AS. All rights reserved.
+**
+** This file is part of Qtopia Environment.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "applnk.h"
+
+#include <qpe/qpeapplication.h>
+#include <qpe/categories.h>
+#include <qpe/categoryselect.h>
+#include <qpe/qcopenvelope_qws.h>
+#include <qpe/global.h>
+#include <qpe/mimetype.h>
+#include <qpe/config.h>
+#include <qpe/storage.h>
+#include <qpe/resource.h>
+
+#include <qdict.h>
+#include <qdir.h>
+#include <qregexp.h>
+
+#ifdef Q_WS_QWS
+#include <qgfx_qws.h>
+#endif
+
+#include <stdlib.h>
+
+int AppLnk::lastId = 5000;
+
+static int smallSize = 14;
+static int bigSize = 32;
+
+static QString safeFileName(const QString& n)
+{
+ QString safename=n;
+ safename.replace(QRegExp("[^0-9A-Za-z.]"),"_");
+ safename.replace(QRegExp("^[^A-Za-z]*"),"");
+ if ( safename.isEmpty() )
+ safename = "_";
+ return safename;
+}
+
+
+class AppLnkPrivate
+{
+public:
+ QArray<int> mCat;
+};
+
+/*!
+ \class AppLnk applnk.h
+ \brief The AppLnk class represents an application available on the system.
+
+ Information about applications are stored in Qtopia as ".desktop" files.
+ When read, these files are stored as AppLnk objects.
+*/
+
+/*!
+ Sets the size used for small icons to \a small pixels.
+ Only affects AppLnk objects created after the call.
+*/
+void AppLnk::setSmallIconSize(int small)
+{
+ smallSize = small;
+}
+
+/*!
+ Returns the size used for small icons.
+*/
+int AppLnk::smallIconSize()
+{
+ return smallSize;
+}
+
+
+/*!
+ Sets the size used for large icons to \a big pixels.
+ Only affects AppLnk objects created after the call.
+*/
+void AppLnk::setBigIconSize(int big)
+{
+ bigSize = big;
+}
+
+/*!
+ Returns the size used for large icons.
+*/
+int AppLnk::bigIconSize()
+{
+ return bigSize;
+}
+
+
+/*!
+ \fn QString AppLnk::name() const
+
+ Returns the Name property.
+*/
+/*!
+ \fn QString AppLnk::exec() const
+
+ Returns the Exec property. This is the executable program associated
+ with the AppLnk.
+*/
+/*!
+ \fn QString AppLnk::rotation() const
+
+ Returns the Rotation property.
+*/
+/*!
+ \fn QString AppLnk::comment() const
+
+ Returns the Comment property.
+*/
+/*!
+ \fn QStringList AppLnk::mimeTypes() const
+
+ Returns the MimeTypes property. This is the list of MIME types
+ that the application can view or edit.
+*/
+/*!
+ \fn const QArray<int>& AppLnk::categories() const
+
+ Returns the Categories property.
+*/
+
+const QArray<int>& AppLnk::categories() const
+{
+ return d->mCat;
+}
+
+/*!
+ \fn int AppLnk::id() const
+
+ Returns the id of the AppLnk. If the AppLnk is not in an AppLnkSet,
+ this value is 0, otherwise it is a value that is unique for the
+ duration of the current process.
+*/
+
+/*!
+ \fn bool AppLnk::isValid() const
+
+ Returns whether this AppLnk is valid.
+*/
+
+/*!
+ Creates an invalid AppLnk.
+
+ \sa isValid()
+*/
+AppLnk::AppLnk()
+{
+ mId = 0;
+ d = new AppLnkPrivate();
+}
+
+/*!
+ Loads \a file as an AppLnk.
+*/
+AppLnk::AppLnk( const QString &file )
+{
+ QStringList sl;
+ d = new AppLnkPrivate();
+ if ( !file.isNull() ) {
+ Config config( file, Config::File );
+
+ if ( config.isValid() ) {
+ config.setGroup( "Desktop Entry" );
+
+ mName = config.readEntry( "Name", file );
+ mExec = config.readEntry( "Exec" );
+ mType = config.readEntry( "Type", QString::null );
+ mIconFile = config.readEntry( "Icon", QString::null );
+ mRotation = config.readEntry( "Rotation", "" );
+ mComment = config.readEntry( "Comment", QString::null );
+ mMimeTypes = config.readListEntry( "MimeType", ';' );
+ mMimeTypeIcons = config.readListEntry( "MimeTypeIcons", ';' );
+ mLinkFile = file;
+ mFile = config.readEntry("File", QString::null);
+ sl = config.readListEntry("Categories", ';');
+ }
+ }
+ // let's try our darndest to create categories...
+ Categories cat( 0 );
+ cat.load( categoryFileName() );
+ d->mCat.resize( sl.count() );
+ int i;
+ QStringList::Iterator it;
+ for ( i = 0, it = sl.begin(); it != sl.end();
+ ++it, i++ ) {
+
+ bool number;
+ int id = (*it).toInt( &number );
+ if ( !number ) {
+ // convert from old school...
+ id = cat.id( "Document Viewer", *it );
+ if ( id == 0 )
+ id = cat.addCategory( "Document Viewer", *it );
+ }
+ d->mCat[i] = id;
+ }
+ mId = 0;
+}
+
+/*!
+ Returns a small pixmap associated with the application.
+*/
+const QPixmap& AppLnk::pixmap() const
+{
+ if ( mPixmap.isNull() ) {
+ AppLnk* that = (AppLnk*)this;
+ if ( mIconFile.isEmpty() ) {
+ MimeType mt(type());
+ that->mPixmap = mt.pixmap();
+ if ( that->mPixmap.isNull() )
+ that->mPixmap = Resource::loadPixmap("UnknownDocument-14");
+ return that->mPixmap;
+ }
+ QImage unscaledIcon = Resource::loadImage( that->mIconFile );
+ that->mPixmap.convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
+ that->mBigPixmap.convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
+ return that->mPixmap;
+ }
+ return mPixmap;
+}
+
+/*!
+ Returns a large pixmap associated with the application.
+*/
+const QPixmap& AppLnk::bigPixmap() const
+{
+ if ( mBigPixmap.isNull() ) {
+ AppLnk* that = (AppLnk*)this;
+ if ( mIconFile.isEmpty() ) {
+ MimeType mt(type());
+ that->mBigPixmap = mt.bigPixmap();
+ if ( that->mBigPixmap.isNull() )
+ that->mBigPixmap = Resource::loadPixmap("UnknownDocument");
+ return that->mBigPixmap;
+ }
+ QImage unscaledIcon = Resource::loadImage( that->mIconFile );
+ that->mPixmap.convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
+ that->mBigPixmap.convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
+ return that->mBigPixmap;
+ }
+ return mBigPixmap;
+}
+
+/*!
+ Returns the type of the application.
+*/
+QString AppLnk::type() const
+{
+ if ( mType.isNull() ) {
+ AppLnk* that = (AppLnk*)this;
+ MimeType mt(file());
+ that->mType = mt.id();
+ return that->mType;
+ }
+ return mType;
+}
+
+/*!
+ Returns the file associated with the AppLnk.
+
+ \sa exec()
+*/
+QString AppLnk::file() const
+{
+ if ( mFile.isNull() ) {
+ AppLnk* that = (AppLnk*)this;
+ if ( !mLinkFile.isEmpty() ) {
+ that->mFile =
+ mLinkFile.right(8)==".desktop" // 8 = strlen(".desktop")
+ ? mLinkFile.left(mLinkFile.length()-8) : mLinkFile;
+ } else if ( mType.contains('/') ) {
+ that->mFile =
+ QString(getenv("HOME"))+"/Documents/"+mType+"/"+safeFileName(that->mName);
+ if ( QFile::exists(that->mFile) || QFile::exists(that->mFile+".desktop") ) {
+ int n=1;
+ QString nn;
+ while (QFile::exists((nn=(that->mFile+"_"+QString::number(n))))
+ || QFile::exists(nn+".desktop"))
+ n++;
+ that->mFile = nn;
+ }
+ that->mLinkFile = that->mFile+".desktop";
+ }
+ return that->mFile;
+ }
+ return mFile;
+}
+
+/*!
+ Returns the desktop file coresponding to this AppLnk.
+
+ \sa file(), exec()
+*/
+QString AppLnk::linkFile() const
+{
+ if ( mLinkFile.isNull() ) {
+ AppLnk* that = (AppLnk*)this;
+ if ( type().contains('/') ) {
+ StorageInfo storage;
+ const FileSystem *fs = storage.fileSystemOf( that->mFile );
+// qDebug("creating lnkFile for %s", mFile.latin1() );
+// if ( fs )
+// qDebug("fs is %s", fs->path().latin1() );
+ if ( fs && fs->isRemovable() ) {
+// qDebug("isRemovable");
+ that->mLinkFile = fs->path();
+ } else
+ that->mLinkFile = getenv( "HOME" );
+ that->mLinkFile += "/Documents/"+type()+"/"+safeFileName(that->mName);
+ if ( QFile::exists(that->mLinkFile+".desktop") ) {
+ int n=1;
+ QString nn;
+ while (QFile::exists((nn=that->mLinkFile+"_"+QString::number(n))+".desktop"))
+ n++;
+ that->mLinkFile = nn;
+ }
+ that->mLinkFile += ".desktop";
+// qDebug("file is %s", mLinkFile.latin1() );
+ }
+ return that->mLinkFile;
+ }
+ return mLinkFile;
+}
+
+/*!
+ Copies \a copy.
+*/
+AppLnk::AppLnk( const AppLnk &copy )
+{
+ mName = copy.mName;
+ mPixmap = copy.mPixmap;
+ mBigPixmap = copy.mBigPixmap;
+ mExec = copy.mExec;
+ mType = copy.mType;
+ mRotation = copy.mRotation;
+ mComment = copy.mComment;
+ mFile = copy.mFile;
+ mLinkFile = copy.mLinkFile;
+ mIconFile = copy.mIconFile;
+ mMimeTypes = copy.mMimeTypes;
+ mMimeTypeIcons = copy.mMimeTypeIcons;
+ mId = 0;
+ d = new AppLnkPrivate();
+ d->mCat = copy.d->mCat;
+}
+
+/*!
+ Destroys the AppLnk. Note that if the AppLnk is current a member of
+ an AppLnkSet, this will produce a run-time warning.
+
+ \sa AppLnkSet::add(), AppLnkSet::remove()
+*/
+AppLnk::~AppLnk()
+{
+ if ( mId )
+ qWarning("Deleting AppLnk that is in an AppLnkSet");
+ if ( d )
+ delete d;
+}
+
+/*!
+ Executes the application associated with this AppLnk.
+*/
+void AppLnk::execute() const
+{
+ execute(QStringList());
+}
+
+/*!
+ Executes the application associated with this AppLnk, with
+ \a args as arguments.
+*/
+void AppLnk::execute(const QStringList& args) const
+{
+#ifdef Q_WS_QWS
+ if ( !mRotation.isEmpty() ) {
+ // ######## this will only work in the server
+ int rot = QPEApplication::defaultRotation();
+ rot = (rot+mRotation.toInt())%360;
+ QCString old = getenv("QWS_DISPLAY");
+ setenv("QWS_DISPLAY", QString("Transformed:Rot%1:0").arg(rot), 1);
+ invoke(args);
+ setenv("QWS_DISPLAY", old.data(), 1);
+ } else
+#endif
+ invoke(args);
+}
+
+/*!
+ Invokes the application associated with this AppLnk, with
+ \a args as arguments. Rotation is not taken into account by
+ this function, you should not call it directly.
+
+ \sa execute()
+*/
+void AppLnk::invoke(const QStringList& args) const
+{
+ Global::execute( exec(), args[0] );
+}
+
+/*!
+ Sets the Exec property to \a exec.
+
+ \sa exec()
+*/
+void AppLnk::setExec( const QString& exec )
+{
+ mExec = exec;
+}
+
+/*!
+ Sets the Name property to \a docname.
+
+ \sa name()
+*/
+void AppLnk::setName( const QString& docname )
+{
+ mName = docname;
+}
+
+/*!
+ Sets the File property to \a filename.
+
+ \sa file()
+*/
+void AppLnk::setFile( const QString& filename )
+{
+ mFile = filename;
+}
+
+/*!
+ Sets the LinkFile property to \a filename.
+
+ \sa linkFile()
+*/
+void AppLnk::setLinkFile( const QString& filename )
+{
+ mLinkFile = filename;
+}
+
+/*!
+ Sets the Comment property to \a comment.
+
+ \sa comment()
+*/
+void AppLnk::setComment( const QString& comment )
+{
+ mComment = comment;
+}
+
+/*!
+ Sets the Type property to \a type.
+
+ \sa type()
+*/
+void AppLnk::setType( const QString& type )
+{
+ mType = type;
+}
+
+/*!
+ Sets the Icon property to \a iconname.
+
+ \sa pixmap(), bigPixmap()
+*/
+void AppLnk::setIcon( const QString& iconname )
+{
+ mIconFile = iconname;
+ QImage unscaledIcon = Resource::loadImage( mIconFile );
+ mPixmap.convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
+ mBigPixmap.convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
+}
+
+/*!
+ Sets the Categories property to \a c.
+
+ \sa categories()
+*/
+void AppLnk::setCategories( const QArray<int>& c )
+{
+ d->mCat = c;
+}
+
+/*!
+ \fn QStringList AppLnk::mimeTypeIcons() const
+
+ Returns the MimeTypeIcons property of the AppLnk.
+*/
+
+/*!
+ Attempts to ensure that the link file for this AppLnk exists, including
+ creating any required directories. Returns TRUE if successful.
+*/
+bool AppLnk::ensureLinkExists() const
+{
+ QString lf = linkFile();
+ if ( !QFile::exists(lf) ) {
+ // May need to create directories
+ QFileInfo fi(lf);
+ if ( system(("mkdir -p "+fi.dirPath(TRUE))) )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*!
+ Commits the AppLnk to disk. Returns whether the operation succeeded.
+
+ The "linkChanged(QString)" message is sent to the
+ "QPE/System" QCop channel as a result.
+*/
+bool AppLnk::writeLink() const
+{
+ // Only re-writes settable parts
+ QString lf = linkFile();
+ if ( !ensureLinkExists() )
+ return FALSE;
+ Config config( lf, Config::File );
+ config.setGroup("Desktop Entry");
+ config.writeEntry("Name",mName);
+ if ( !mIconFile.isNull() ) config.writeEntry("Icon",mIconFile);
+ config.writeEntry("Type",type());
+ if ( !mComment.isNull() ) config.writeEntry("Comment",mComment);
+ config.writeEntry("File",file());
+ // write out the id...
+ int i;
+ QStringList sl;
+ for ( i = 0; i < int(d->mCat.count()); i++ ) {
+ sl.append( QString::number( d->mCat[i] ) );
+ }
+ config.writeEntry( "Categories", sl, ';' );
+
+ QCopEnvelope e("QPE/System", "linkChanged(QString)");
+ e << lf;
+
+ return TRUE;
+}
+
+/*!
+ Sets the property named \a key to \a value.
+*/
+void AppLnk::setProperty(const QString& key, const QString& value)
+{
+ if ( ensureLinkExists() ) {
+ Config cfg(linkFile(), Config::File);
+ cfg.writeEntry(key,value);
+ }
+}
+
+/*!
+ Returns the property named \a key.
+*/
+QString AppLnk::property(const QString& key) const
+{
+ QString lf = linkFile();
+ if ( !QFile::exists(lf) )
+ return QString::null;
+ Config cfg(lf, Config::File);
+ return cfg.readEntry(key);
+}
+
+
+/*!
+ Deletes both the linkFile() and file() associated with this AppLnk.
+*/
+void AppLnk::removeFiles()
+{
+ bool valid = isValid();
+ if ( !valid || QFile::remove(linkFile()) ) {
+ if ( QFile::remove(file()) ) {
+ QCopEnvelope e("QPE/System", "linkChanged(QString)");
+ e << linkFile();
+ } else if ( valid ) {
+ // restore link
+ writeLink();
+ }
+ }
+}
+
+/*!
+ Delete the linkFile(), leaving any file() untouched.
+*/
+void AppLnk::removeLinkFile()
+{
+ if ( isValid() && QFile::remove(linkFile()) ) {
+ QCopEnvelope e("QPE/System", "linkChanged(QString)");
+ e << linkFile();
+ }
+}
+
+class AppLnkSetPrivate {
+public:
+ AppLnkSetPrivate()
+ {
+ typPix.setAutoDelete(TRUE);
+ typPixBig.setAutoDelete(TRUE);
+ typName.setAutoDelete(TRUE);
+ }
+
+ QDict<QPixmap> typPix;
+ QDict<QPixmap> typPixBig;
+ QDict<QString> typName;
+};
+
+/*!
+ \class AppLnkSet applnk.h
+ \brief The AppLnkSet class is a set of AppLnk objects.
+*/
+
+/*!
+ \fn QStringList AppLnkSet::types() const
+
+ Returns the list of types in the set.
+
+ \sa AppLnk::type(), typeName(), typePixmap(), typeBigPixmap()
+*/
+
+/*!
+ \fn const QList<AppLnk>& AppLnkSet::children() const
+
+ Returns the members of the set.
+*/
+
+/*!
+ Constructs an empty AppLnkSet.
+*/
+AppLnkSet::AppLnkSet() :
+ d(new AppLnkSetPrivate)
+{
+}
+
+/*!
+ Constructs an AppLnkSet that contains AppLnk objects representing
+ all the files in a \a directory (recursively).
+
+ The directories may contain ".directory" files which overrides
+ any AppLnk::type() value of AppLnk objects found in the directory.
+ This allows simple localization of application types.
+*/
+AppLnkSet::AppLnkSet( const QString &directory ) :
+ d(new AppLnkSetPrivate)
+{
+ QDir dir( directory );
+ mFile = directory;
+ findChildren(directory,QString::null,QString::null);
+}
+
+/*!
+ Detaches all AppLnk objects from the set. The set become empty
+ and the call becomes responsible for deleting the AppLnk objects.
+*/
+void AppLnkSet::detachChildren()
+{
+ QListIterator<AppLnk> it( mApps );
+ for ( ; it.current(); ) {
+ AppLnk* a = *it;
+ ++it;
+ a->mId = 0;
+ }
+ mApps.clear();
+}
+
+/*!
+ Destroys the set, deleting all AppLnk objects it contains.
+
+ \sa detachChildren()
+*/
+AppLnkSet::~AppLnkSet()
+{
+ QListIterator<AppLnk> it( mApps );
+ for ( ; it.current(); ) {
+ AppLnk* a = *it;
+ ++it;
+ a->mId = 0;
+ delete a;
+ }
+ delete d;
+}
+
+void AppLnkSet::findChildren(const QString &dr, const QString& typ, const QString& typName, int depth)
+{
+ depth++;
+ if ( depth > 10 )
+ return;
+
+ QDir dir( dr );
+ QString typNameLocal = typName;
+
+ if ( dir.exists( ".directory" ) ) {
+ Config config( dr + "/.directory", Config::File );
+ config.setGroup( "Desktop Entry" );
+ typNameLocal = config.readEntry( "Name", typNameLocal );
+ if ( !typ.isEmpty() ) {
+ QString iconFile = config.readEntry( "Icon", "AppsIcon" );
+ QImage unscaledIcon = Resource::loadImage( iconFile );
+ QPixmap pm, bpm;
+ pm.convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
+ bpm.convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
+ d->typPix.insert(typ, new QPixmap(pm));
+ d->typPixBig.insert(typ, new QPixmap(bpm));
+ d->typName.insert(typ, new QString(typNameLocal));
+ }
+ }
+
+ const QFileInfoList *list = dir.entryInfoList();
+ if ( list ) {
+ QFileInfo* fi;
+ bool cadded=FALSE;
+ for ( QFileInfoListIterator it(*list); (fi=*it); ++it ) {
+ QString bn = fi->fileName();
+ if ( bn[0] != '.' && bn != "CVS" ) {
+ if ( fi->isDir() ) {
+ QString c = typ.isNull() ? bn : typ+"/"+bn;
+ QString d = typNameLocal.isNull() ? bn : typNameLocal+"/"+bn;
+ findChildren(fi->filePath(), c, d, depth );
+ } else {
+ if ( fi->extension(FALSE) == "desktop" ) {
+ AppLnk* app = new AppLnk( fi->filePath() );
+#ifdef QT_NO_QWS_MULTIPROCESS
+ if ( !Global::isBuiltinCommand( app->exec() ) )
+ delete app;
+ else
+#endif
+ {
+ if ( !typ.isEmpty() ) {
+ if ( !cadded ) {
+ typs.append(typ);
+ cadded = TRUE;
+ }
+ app->setType(typ);
+ }
+ add(app);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/*!
+ Adds \a f to the set. The set takes over responsibility for deleting \a f.
+
+ \sa remove()
+*/
+void AppLnkSet::add( AppLnk *f )
+{
+ if ( f->mId == 0 ) {
+ AppLnk::lastId++;
+ f->mId = AppLnk::lastId;
+ mApps.append( f );
+ } else {
+ qWarning("Attempt to add an AppLnk twice");
+ }
+}
+
+/*!
+ Removes \a f to the set, returning whether \a f was in the set.
+ The caller becomes responsible for deleting \a f.
+
+ \sa add()
+*/
+bool AppLnkSet::remove( AppLnk *f )
+{
+ if ( mApps.remove( f ) ) {
+ f->mId = 0;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*!
+ Returns the localized name for type \a t.
+*/
+QString AppLnkSet::typeName( const QString& t ) const
+{
+ QString *st = d->typName.find(t);
+ return st ? *st : QString::null;
+}
+
+/*!
+ Returns the small pixmap associated with type \a t.
+*/
+QPixmap AppLnkSet::typePixmap( const QString& t ) const
+{
+ QPixmap *pm = d->typPix.find(t);
+ return pm ? *pm : QPixmap();
+}
+
+/*!
+ Returns the large pixmap associated with type \a t.
+*/
+QPixmap AppLnkSet::typeBigPixmap( const QString& t ) const
+{
+ QPixmap *pm = d->typPixBig.find(t);
+ return pm ? *pm : QPixmap();
+}
+
+/*!
+ Returns the AppLnk with the given \a id.
+*/
+const AppLnk *AppLnkSet::find( int id ) const
+{
+ QListIterator<AppLnk> it( children() );
+
+ for ( ; it.current(); ++it ) {
+ const AppLnk *app = it.current();
+ if ( app->id() == id )
+ return app;
+ }
+
+ return 0;
+}
+
+/*!
+ Returns the AppLnk with the given \a exec attribute.
+*/
+const AppLnk *AppLnkSet::findExec( const QString& exec ) const
+{
+ QListIterator<AppLnk> it( children() );
+
+ for ( ; it.current(); ++it ) {
+ const AppLnk *app = it.current();
+ if ( app->exec() == exec )
+ return app;
+ }
+
+ return 0;
+}
+
+/*!
+ \class DocLnkSet applnk.h
+ \brief The DocLnkSet class is a set of DocLnk objects.
+*/
+
+/*!
+ \fn const QList<DocLnk>& DocLnkSet::children() const
+
+ Returns the members of the set.
+*/
+
+/*!
+ Constructs an empty DocLnkSet.
+
+ \sa appendFrom()
+*/
+DocLnkSet::DocLnkSet()
+{
+}
+
+/*!
+ Constructs an DocLnkSet that contains DocLnk objects representing
+ all the files in a \a directory (recursively).
+
+ If \a mimefilter is not null,
+ only documents with a MIME type matching \a mimefilter are selected.
+ The value may contain multiple wild-card patterns separated by ";",
+ such as "*o/mpeg;audio/x-wav".
+*/
+DocLnkSet::DocLnkSet( const QString &directory, const QString& mimefilter ) :
+ AppLnkSet()
+{
+ QDir dir( directory );
+ mFile = dir.dirName();
+ QDict<void> reference;
+
+ QStringList subFilter = QStringList::split(";", mimefilter);
+ QValueList<QRegExp> mimeFilters;
+ for( QStringList::Iterator it = subFilter.begin(); it != subFilter.end(); ++ it )
+ mimeFilters.append( QRegExp(*it, FALSE, TRUE) );
+
+ findChildren(directory, mimeFilters, reference);
+
+ const QList<DocLnk> &list = children();
+ for ( QListIterator<DocLnk> it( list ); it.current(); ++it ) {
+ reference.remove( (*it)->file() );
+ }
+
+ for ( QDictIterator<void> dit(reference); dit.current(); ++dit ) {
+ if ( dit.current() == (void*)2 ) {
+ // Unreferenced, make an unwritten link
+ DocLnk* dl = new DocLnk;
+ QFileInfo fi( dit.currentKey() );
+ dl->setFile(fi.filePath());
+ dl->setName(fi.baseName());
+ // #### default to current path?
+ // dl->setCategories( ... );
+ bool match = mimefilter.isNull();
+ if ( !match )
+ for( QValueList<QRegExp>::Iterator it = mimeFilters.begin(); it != mimeFilters.end() && !match; ++ it )
+ if ( (*it).match(dl->type()) >= 0 )
+ match = TRUE;
+ if ( match /* && dl->type() != "application/octet-stream" */
+ && !!dl->exec() )
+ add(dl);
+ else
+ delete dl;
+ }
+ }
+}
+
+// other becomes empty
+/*!
+ Transfers all DocLnk objects from \a other to this set. \a other becomes
+ empty.
+*/
+void DocLnkSet::appendFrom( DocLnkSet& other )
+{
+ if ( &other == this )
+ return;
+ QListIterator<AppLnk> it( other.mApps );
+ for ( ; it.current(); ) {
+ mApps.append(*it);
+ ++it;
+ }
+ other.mApps.clear();
+}
+
+void DocLnkSet::findChildren(const QString &dr, const QValueList<QRegExp> &mimeFilters, QDict<void> &reference, int depth)
+{
+ depth++;
+ if ( depth > 10 )
+ return;
+
+ QDir dir( dr );
+
+ const QFileInfoList *list = dir.entryInfoList();
+ if ( list ) {
+ QFileInfo* fi;
+ for ( QFileInfoListIterator it(*list); (fi=*it); ++it ) {
+ QString bn = fi->fileName();
+ if ( bn[0] != '.' && bn != "CVS" ) {
+ if ( fi->isDir() ) {
+ findChildren(fi->filePath(), mimeFilters, reference, depth);
+ } else {
+ if ( fi->extension(FALSE) == "desktop" ) {
+ DocLnk* dl = new DocLnk( fi->filePath() );
+ QFileInfo fi2(dl->file());
+ bool match = FALSE;
+ if ( !fi2.exists() ) {
+ dir.remove( dl->file() );
+ }
+ if ( mimeFilters.count() == 0 ) {
+ add( dl );
+ match = TRUE;
+ } else {
+ for( QValueList<QRegExp>::ConstIterator it = mimeFilters.begin(); it != mimeFilters.end(); ++ it ) {
+ if ( (*it).match(dl->type()) >= 0 ) {
+ add(dl);
+ match = TRUE;
+ }
+ }
+ }
+ if ( !match )
+ delete dl;
+ } else {
+ if ( !reference.find(fi->fileName()) )
+ reference.insert(fi->filePath(), (void*)2);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*!
+ \class DocLnk applnk.h
+ \brief The DocLnk class represents loaded document references.
+*/
+
+/*!
+ \fn DocLnk::DocLnk( const DocLnk &o )
+
+ Copies \a o.
+*/
+
+/*!
+ Constructs a DocLnk from a valid .desktop \a file or a new .desktop
+ \a file for other files.
+*/
+DocLnk::DocLnk( const QString &file ) :
+ AppLnk(file)
+{
+ init(file);
+}
+
+/*!
+ Constructs a DocLnk from a valid .desktop \a file or a new .desktop
+ \a file for other files. If \a may_be_desktopfile is TRUE, then \a file
+ is first attempted to be read as a .desktop file.
+*/
+DocLnk::DocLnk( const QString &file, bool may_be_desktopfile ) :
+ AppLnk(may_be_desktopfile ? file : QString::null)
+{
+ init(file);
+}
+
+void DocLnk::init(const QString &file)
+{
+ if ( isValid() ) {
+#ifndef FORCED_DIR_STRUCTURE_WAY
+ if ( mType.isNull() )
+ // try to infer it
+#endif
+ {
+ int s0 = file.findRev('/');
+ if ( s0 > 0 ) {
+ int s1 = file.findRev('/',s0-1);
+ if ( s1 > 0 ) {
+ int s2 = file.findRev('/',s1-1);
+ if ( s2 > 0 ) {
+ mType = file.mid(s2+1,s0-s2-1);
+ }
+ }
+ }
+ }
+ } else if ( QFile::exists(file) ) {
+ QString n = file;
+ n.replace(QRegExp("\\..*"),"");
+ n.replace(QRegExp(".*/"),"");
+ setName( n );
+ setFile( file );
+ }
+ MimeType mt(mType);
+ if( mt.application() )
+ mExec = mt.application()->exec();
+}
+
+/*!
+ Constructs an invalid DocLnk.
+*/
+DocLnk::DocLnk()
+{
+}
+
+/*!
+ Destroys the DocLnk. As with AppLnk objects, a run-time error
+ occurs if the DocLnk is a member of a DocLnkSet (or AppLnkSet).
+*/
+DocLnk::~DocLnk()
+{
+}
+
+/*!
+ \reimp
+*/
+QString DocLnk::exec() const
+{
+ MimeType mt(type());
+ const AppLnk* app = mt.application();
+ if ( app )
+ return app->exec();
+ else
+ return QString::null;
+}
+
+/*!
+ \reimp
+*/
+void DocLnk::invoke(const QStringList& args) const
+{
+ MimeType mt(type());
+ const AppLnk* app = mt.application();
+ if ( app ) {
+ QStringList a = args;
+ if ( QFile::exists( linkFile() ) )
+ a.append(linkFile());
+ else
+ a.append(file());
+ app->execute(a);
+ }
+}
+