summaryrefslogtreecommitdiff
path: root/library/applnk.cpp
Unidiff
Diffstat (limited to 'library/applnk.cpp') (more/less context) (ignore 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 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20
21#include "applnk.h"
22
23#include <qpe/qpeapplication.h>
24#include <qpe/categories.h>
25#include <qpe/categoryselect.h>
26#include <qpe/qcopenvelope_qws.h>
27#include <qpe/global.h>
28#include <qpe/mimetype.h>
29#include <qpe/config.h>
30#include <qpe/storage.h>
31#include <qpe/resource.h>
32
33#include <qdict.h>
34#include <qdir.h>
35#include <qregexp.h>
36
37#ifdef Q_WS_QWS
38#include <qgfx_qws.h>
39#endif
40
41#include <stdlib.h>
42
43int AppLnk::lastId = 5000;
44
45static int smallSize = 14;
46static int bigSize = 32;
47
48static QString safeFileName(const QString& n)
49{
50 QString safename=n;
51 safename.replace(QRegExp("[^0-9A-Za-z.]"),"_");
52 safename.replace(QRegExp("^[^A-Za-z]*"),"");
53 if ( safename.isEmpty() )
54 safename = "_";
55 return safename;
56}
57
58
59class AppLnkPrivate
60{
61public:
62 QArray<int> mCat;
63};
64
65/*!
66 \class AppLnk applnk.h
67 \brief The AppLnk class represents an application available on the system.
68
69 Information about applications are stored in Qtopia as ".desktop" files.
70 When read, these files are stored as AppLnk objects.
71*/
72
73/*!
74 Sets the size used for small icons to \a small pixels.
75 Only affects AppLnk objects created after the call.
76*/
77void AppLnk::setSmallIconSize(int small)
78{
79 smallSize = small;
80}
81
82/*!
83 Returns the size used for small icons.
84*/
85int AppLnk::smallIconSize()
86{
87 return smallSize;
88}
89
90
91/*!
92 Sets the size used for large icons to \a big pixels.
93 Only affects AppLnk objects created after the call.
94*/
95void AppLnk::setBigIconSize(int big)
96{
97 bigSize = big;
98}
99
100/*!
101 Returns the size used for large icons.
102*/
103int AppLnk::bigIconSize()
104{
105 return bigSize;
106}
107
108
109/*!
110 \fn QString AppLnk::name() const
111
112 Returns the Name property.
113*/
114/*!
115 \fn QString AppLnk::exec() const
116
117 Returns the Exec property. This is the executable program associated
118 with the AppLnk.
119*/
120/*!
121 \fn QString AppLnk::rotation() const
122
123 Returns the Rotation property.
124*/
125/*!
126 \fn QString AppLnk::comment() const
127
128 Returns the Comment property.
129*/
130/*!
131 \fn QStringList AppLnk::mimeTypes() const
132
133 Returns the MimeTypes property. This is the list of MIME types
134 that the application can view or edit.
135*/
136/*!
137 \fn const QArray<int>& AppLnk::categories() const
138
139 Returns the Categories property.
140*/
141
142const QArray<int>& AppLnk::categories() const
143{
144 return d->mCat;
145}
146
147/*!
148 \fn int AppLnk::id() const
149
150 Returns the id of the AppLnk. If the AppLnk is not in an AppLnkSet,
151 this value is 0, otherwise it is a value that is unique for the
152 duration of the current process.
153*/
154
155/*!
156 \fn bool AppLnk::isValid() const
157
158 Returns whether this AppLnk is valid.
159*/
160
161/*!
162 Creates an invalid AppLnk.
163
164 \sa isValid()
165*/
166AppLnk::AppLnk()
167{
168 mId = 0;
169 d = new AppLnkPrivate();
170}
171
172/*!
173 Loads \a file as an AppLnk.
174*/
175AppLnk::AppLnk( const QString &file )
176{
177 QStringList sl;
178 d = new AppLnkPrivate();
179 if ( !file.isNull() ) {
180 Config config( file, Config::File );
181
182 if ( config.isValid() ) {
183 config.setGroup( "Desktop Entry" );
184
185 mName = config.readEntry( "Name", file );
186 mExec = config.readEntry( "Exec" );
187 mType = config.readEntry( "Type", QString::null );
188 mIconFile = config.readEntry( "Icon", QString::null );
189 mRotation = config.readEntry( "Rotation", "" );
190 mComment = config.readEntry( "Comment", QString::null );
191 mMimeTypes = config.readListEntry( "MimeType", ';' );
192 mMimeTypeIcons = config.readListEntry( "MimeTypeIcons", ';' );
193 mLinkFile = file;
194 mFile = config.readEntry("File", QString::null);
195 sl = config.readListEntry("Categories", ';');
196 }
197 }
198 // let's try our darndest to create categories...
199 Categories cat( 0 );
200 cat.load( categoryFileName() );
201 d->mCat.resize( sl.count() );
202 int i;
203 QStringList::Iterator it;
204 for ( i = 0, it = sl.begin(); it != sl.end();
205 ++it, i++ ) {
206
207 bool number;
208 int id = (*it).toInt( &number );
209 if ( !number ) {
210 // convert from old school...
211 id = cat.id( "Document Viewer", *it );
212 if ( id == 0 )
213 id = cat.addCategory( "Document Viewer", *it );
214 }
215 d->mCat[i] = id;
216 }
217 mId = 0;
218}
219
220/*!
221 Returns a small pixmap associated with the application.
222*/
223const QPixmap& AppLnk::pixmap() const
224{
225 if ( mPixmap.isNull() ) {
226 AppLnk* that = (AppLnk*)this;
227 if ( mIconFile.isEmpty() ) {
228 MimeType mt(type());
229 that->mPixmap = mt.pixmap();
230 if ( that->mPixmap.isNull() )
231 that->mPixmap = Resource::loadPixmap("UnknownDocument-14");
232 return that->mPixmap;
233 }
234 QImage unscaledIcon = Resource::loadImage( that->mIconFile );
235 that->mPixmap.convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
236 that->mBigPixmap.convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
237 return that->mPixmap;
238 }
239 return mPixmap;
240}
241
242/*!
243 Returns a large pixmap associated with the application.
244*/
245const QPixmap& AppLnk::bigPixmap() const
246{
247 if ( mBigPixmap.isNull() ) {
248 AppLnk* that = (AppLnk*)this;
249 if ( mIconFile.isEmpty() ) {
250 MimeType mt(type());
251 that->mBigPixmap = mt.bigPixmap();
252 if ( that->mBigPixmap.isNull() )
253 that->mBigPixmap = Resource::loadPixmap("UnknownDocument");
254 return that->mBigPixmap;
255 }
256 QImage unscaledIcon = Resource::loadImage( that->mIconFile );
257 that->mPixmap.convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
258 that->mBigPixmap.convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
259 return that->mBigPixmap;
260 }
261 return mBigPixmap;
262}
263
264/*!
265 Returns the type of the application.
266*/
267QString AppLnk::type() const
268{
269 if ( mType.isNull() ) {
270 AppLnk* that = (AppLnk*)this;
271 MimeType mt(file());
272 that->mType = mt.id();
273 return that->mType;
274 }
275 return mType;
276}
277
278/*!
279 Returns the file associated with the AppLnk.
280
281 \sa exec()
282*/
283QString AppLnk::file() const
284{
285 if ( mFile.isNull() ) {
286 AppLnk* that = (AppLnk*)this;
287 if ( !mLinkFile.isEmpty() ) {
288 that->mFile =
289 mLinkFile.right(8)==".desktop" // 8 = strlen(".desktop")
290 ? mLinkFile.left(mLinkFile.length()-8) : mLinkFile;
291 } else if ( mType.contains('/') ) {
292 that->mFile =
293 QString(getenv("HOME"))+"/Documents/"+mType+"/"+safeFileName(that->mName);
294 if ( QFile::exists(that->mFile) || QFile::exists(that->mFile+".desktop") ) {
295 int n=1;
296 QString nn;
297 while (QFile::exists((nn=(that->mFile+"_"+QString::number(n))))
298 || QFile::exists(nn+".desktop"))
299 n++;
300 that->mFile = nn;
301 }
302 that->mLinkFile = that->mFile+".desktop";
303 }
304 return that->mFile;
305 }
306 return mFile;
307}
308
309/*!
310 Returns the desktop file coresponding to this AppLnk.
311
312 \sa file(), exec()
313*/
314QString AppLnk::linkFile() const
315{
316 if ( mLinkFile.isNull() ) {
317 AppLnk* that = (AppLnk*)this;
318 if ( type().contains('/') ) {
319 StorageInfo storage;
320 const FileSystem *fs = storage.fileSystemOf( that->mFile );
321 // qDebug("creating lnkFile for %s", mFile.latin1() );
322 // if ( fs )
323 // qDebug("fs is %s", fs->path().latin1() );
324 if ( fs && fs->isRemovable() ) {
325 // qDebug("isRemovable");
326 that->mLinkFile = fs->path();
327 } else
328 that->mLinkFile = getenv( "HOME" );
329 that->mLinkFile += "/Documents/"+type()+"/"+safeFileName(that->mName);
330 if ( QFile::exists(that->mLinkFile+".desktop") ) {
331 int n=1;
332 QString nn;
333 while (QFile::exists((nn=that->mLinkFile+"_"+QString::number(n))+".desktop"))
334 n++;
335 that->mLinkFile = nn;
336 }
337 that->mLinkFile += ".desktop";
338 // qDebug("file is %s", mLinkFile.latin1() );
339 }
340 return that->mLinkFile;
341 }
342 return mLinkFile;
343}
344
345/*!
346 Copies \a copy.
347*/
348AppLnk::AppLnk( const AppLnk &copy )
349{
350 mName = copy.mName;
351 mPixmap = copy.mPixmap;
352 mBigPixmap = copy.mBigPixmap;
353 mExec = copy.mExec;
354 mType = copy.mType;
355 mRotation = copy.mRotation;
356 mComment = copy.mComment;
357 mFile = copy.mFile;
358 mLinkFile = copy.mLinkFile;
359 mIconFile = copy.mIconFile;
360 mMimeTypes = copy.mMimeTypes;
361 mMimeTypeIcons = copy.mMimeTypeIcons;
362 mId = 0;
363 d = new AppLnkPrivate();
364 d->mCat = copy.d->mCat;
365}
366
367/*!
368 Destroys the AppLnk. Note that if the AppLnk is current a member of
369 an AppLnkSet, this will produce a run-time warning.
370
371 \sa AppLnkSet::add(), AppLnkSet::remove()
372*/
373AppLnk::~AppLnk()
374{
375 if ( mId )
376 qWarning("Deleting AppLnk that is in an AppLnkSet");
377 if ( d )
378 delete d;
379}
380
381/*!
382 Executes the application associated with this AppLnk.
383*/
384void AppLnk::execute() const
385{
386 execute(QStringList());
387}
388
389/*!
390 Executes the application associated with this AppLnk, with
391 \a args as arguments.
392*/
393void AppLnk::execute(const QStringList& args) const
394{
395#ifdef Q_WS_QWS
396 if ( !mRotation.isEmpty() ) {
397 // ######## this will only work in the server
398 int rot = QPEApplication::defaultRotation();
399 rot = (rot+mRotation.toInt())%360;
400 QCString old = getenv("QWS_DISPLAY");
401 setenv("QWS_DISPLAY", QString("Transformed:Rot%1:0").arg(rot), 1);
402 invoke(args);
403 setenv("QWS_DISPLAY", old.data(), 1);
404 } else
405#endif
406 invoke(args);
407}
408
409/*!
410 Invokes the application associated with this AppLnk, with
411 \a args as arguments. Rotation is not taken into account by
412 this function, you should not call it directly.
413
414 \sa execute()
415*/
416void AppLnk::invoke(const QStringList& args) const
417{
418 Global::execute( exec(), args[0] );
419}
420
421/*!
422 Sets the Exec property to \a exec.
423
424 \sa exec()
425*/
426void AppLnk::setExec( const QString& exec )
427{
428 mExec = exec;
429}
430
431/*!
432 Sets the Name property to \a docname.
433
434 \sa name()
435*/
436void AppLnk::setName( const QString& docname )
437{
438 mName = docname;
439}
440
441/*!
442 Sets the File property to \a filename.
443
444 \sa file()
445*/
446void AppLnk::setFile( const QString& filename )
447{
448 mFile = filename;
449}
450
451/*!
452 Sets the LinkFile property to \a filename.
453
454 \sa linkFile()
455*/
456void AppLnk::setLinkFile( const QString& filename )
457{
458 mLinkFile = filename;
459}
460
461/*!
462 Sets the Comment property to \a comment.
463
464 \sa comment()
465*/
466void AppLnk::setComment( const QString& comment )
467{
468 mComment = comment;
469}
470
471/*!
472 Sets the Type property to \a type.
473
474 \sa type()
475*/
476void AppLnk::setType( const QString& type )
477{
478 mType = type;
479}
480
481/*!
482 Sets the Icon property to \a iconname.
483
484 \sa pixmap(), bigPixmap()
485*/
486void AppLnk::setIcon( const QString& iconname )
487{
488 mIconFile = iconname;
489 QImage unscaledIcon = Resource::loadImage( mIconFile );
490 mPixmap.convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
491 mBigPixmap.convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
492}
493
494/*!
495 Sets the Categories property to \a c.
496
497 \sa categories()
498*/
499void AppLnk::setCategories( const QArray<int>& c )
500{
501 d->mCat = c;
502}
503
504/*!
505 \fn QStringList AppLnk::mimeTypeIcons() const
506
507 Returns the MimeTypeIcons property of the AppLnk.
508*/
509
510/*!
511 Attempts to ensure that the link file for this AppLnk exists, including
512 creating any required directories. Returns TRUE if successful.
513*/
514bool AppLnk::ensureLinkExists() const
515{
516 QString lf = linkFile();
517 if ( !QFile::exists(lf) ) {
518 // May need to create directories
519 QFileInfo fi(lf);
520 if ( system(("mkdir -p "+fi.dirPath(TRUE))) )
521 return FALSE;
522 }
523 return TRUE;
524}
525
526/*!
527 Commits the AppLnk to disk. Returns whether the operation succeeded.
528
529 The "linkChanged(QString)" message is sent to the
530 "QPE/System" QCop channel as a result.
531*/
532bool AppLnk::writeLink() const
533{
534 // Only re-writes settable parts
535 QString lf = linkFile();
536 if ( !ensureLinkExists() )
537 return FALSE;
538 Config config( lf, Config::File );
539 config.setGroup("Desktop Entry");
540 config.writeEntry("Name",mName);
541 if ( !mIconFile.isNull() ) config.writeEntry("Icon",mIconFile);
542 config.writeEntry("Type",type());
543 if ( !mComment.isNull() ) config.writeEntry("Comment",mComment);
544 config.writeEntry("File",file());
545 // write out the id...
546 int i;
547 QStringList sl;
548 for ( i = 0; i < int(d->mCat.count()); i++ ) {
549 sl.append( QString::number( d->mCat[i] ) );
550 }
551 config.writeEntry( "Categories", sl, ';' );
552
553 QCopEnvelope e("QPE/System", "linkChanged(QString)");
554 e << lf;
555
556 return TRUE;
557}
558
559/*!
560 Sets the property named \a key to \a value.
561*/
562void AppLnk::setProperty(const QString& key, const QString& value)
563{
564 if ( ensureLinkExists() ) {
565 Config cfg(linkFile(), Config::File);
566 cfg.writeEntry(key,value);
567 }
568}
569
570/*!
571 Returns the property named \a key.
572*/
573QString AppLnk::property(const QString& key) const
574{
575 QString lf = linkFile();
576 if ( !QFile::exists(lf) )
577 return QString::null;
578 Config cfg(lf, Config::File);
579 return cfg.readEntry(key);
580}
581
582
583/*!
584 Deletes both the linkFile() and file() associated with this AppLnk.
585*/
586void AppLnk::removeFiles()
587{
588 bool valid = isValid();
589 if ( !valid || QFile::remove(linkFile()) ) {
590 if ( QFile::remove(file()) ) {
591 QCopEnvelope e("QPE/System", "linkChanged(QString)");
592 e << linkFile();
593 } else if ( valid ) {
594 // restore link
595 writeLink();
596 }
597 }
598}
599
600/*!
601 Delete the linkFile(), leaving any file() untouched.
602*/
603void AppLnk::removeLinkFile()
604{
605 if ( isValid() && QFile::remove(linkFile()) ) {
606 QCopEnvelope e("QPE/System", "linkChanged(QString)");
607 e << linkFile();
608 }
609}
610
611class AppLnkSetPrivate {
612public:
613 AppLnkSetPrivate()
614 {
615 typPix.setAutoDelete(TRUE);
616 typPixBig.setAutoDelete(TRUE);
617 typName.setAutoDelete(TRUE);
618 }
619
620 QDict<QPixmap> typPix;
621 QDict<QPixmap> typPixBig;
622 QDict<QString> typName;
623};
624
625/*!
626 \class AppLnkSet applnk.h
627 \brief The AppLnkSet class is a set of AppLnk objects.
628*/
629
630/*!
631 \fn QStringList AppLnkSet::types() const
632
633 Returns the list of types in the set.
634
635 \sa AppLnk::type(), typeName(), typePixmap(), typeBigPixmap()
636*/
637
638/*!
639 \fn const QList<AppLnk>& AppLnkSet::children() const
640
641 Returns the members of the set.
642*/
643
644/*!
645 Constructs an empty AppLnkSet.
646*/
647AppLnkSet::AppLnkSet() :
648 d(new AppLnkSetPrivate)
649{
650}
651
652/*!
653 Constructs an AppLnkSet that contains AppLnk objects representing
654 all the files in a \a directory (recursively).
655
656 The directories may contain ".directory" files which overrides
657 any AppLnk::type() value of AppLnk objects found in the directory.
658 This allows simple localization of application types.
659*/
660AppLnkSet::AppLnkSet( const QString &directory ) :
661 d(new AppLnkSetPrivate)
662{
663 QDir dir( directory );
664 mFile = directory;
665 findChildren(directory,QString::null,QString::null);
666}
667
668/*!
669 Detaches all AppLnk objects from the set. The set become empty
670 and the call becomes responsible for deleting the AppLnk objects.
671*/
672void AppLnkSet::detachChildren()
673{
674 QListIterator<AppLnk> it( mApps );
675 for ( ; it.current(); ) {
676 AppLnk* a = *it;
677 ++it;
678 a->mId = 0;
679 }
680 mApps.clear();
681}
682
683/*!
684 Destroys the set, deleting all AppLnk objects it contains.
685
686 \sa detachChildren()
687*/
688AppLnkSet::~AppLnkSet()
689{
690 QListIterator<AppLnk> it( mApps );
691 for ( ; it.current(); ) {
692 AppLnk* a = *it;
693 ++it;
694 a->mId = 0;
695 delete a;
696 }
697 delete d;
698}
699
700void AppLnkSet::findChildren(const QString &dr, const QString& typ, const QString& typName, int depth)
701{
702 depth++;
703 if ( depth > 10 )
704 return;
705
706 QDir dir( dr );
707 QString typNameLocal = typName;
708
709 if ( dir.exists( ".directory" ) ) {
710 Config config( dr + "/.directory", Config::File );
711 config.setGroup( "Desktop Entry" );
712 typNameLocal = config.readEntry( "Name", typNameLocal );
713 if ( !typ.isEmpty() ) {
714 QString iconFile = config.readEntry( "Icon", "AppsIcon" );
715 QImage unscaledIcon = Resource::loadImage( iconFile );
716 QPixmap pm, bpm;
717 pm.convertFromImage( unscaledIcon.smoothScale( smallSize, smallSize ) );
718 bpm.convertFromImage( unscaledIcon.smoothScale( bigSize, bigSize ) );
719 d->typPix.insert(typ, new QPixmap(pm));
720 d->typPixBig.insert(typ, new QPixmap(bpm));
721 d->typName.insert(typ, new QString(typNameLocal));
722 }
723 }
724
725 const QFileInfoList *list = dir.entryInfoList();
726 if ( list ) {
727 QFileInfo* fi;
728 bool cadded=FALSE;
729 for ( QFileInfoListIterator it(*list); (fi=*it); ++it ) {
730 QString bn = fi->fileName();
731 if ( bn[0] != '.' && bn != "CVS" ) {
732 if ( fi->isDir() ) {
733 QString c = typ.isNull() ? bn : typ+"/"+bn;
734 QString d = typNameLocal.isNull() ? bn : typNameLocal+"/"+bn;
735 findChildren(fi->filePath(), c, d, depth );
736 } else {
737 if ( fi->extension(FALSE) == "desktop" ) {
738 AppLnk* app = new AppLnk( fi->filePath() );
739#ifdef QT_NO_QWS_MULTIPROCESS
740 if ( !Global::isBuiltinCommand( app->exec() ) )
741 delete app;
742 else
743#endif
744 {
745 if ( !typ.isEmpty() ) {
746 if ( !cadded ) {
747 typs.append(typ);
748 cadded = TRUE;
749 }
750 app->setType(typ);
751 }
752 add(app);
753 }
754 }
755 }
756 }
757 }
758 }
759}
760
761/*!
762 Adds \a f to the set. The set takes over responsibility for deleting \a f.
763
764 \sa remove()
765*/
766void AppLnkSet::add( AppLnk *f )
767{
768 if ( f->mId == 0 ) {
769 AppLnk::lastId++;
770 f->mId = AppLnk::lastId;
771 mApps.append( f );
772 } else {
773 qWarning("Attempt to add an AppLnk twice");
774 }
775}
776
777/*!
778 Removes \a f to the set, returning whether \a f was in the set.
779 The caller becomes responsible for deleting \a f.
780
781 \sa add()
782*/
783bool AppLnkSet::remove( AppLnk *f )
784{
785 if ( mApps.remove( f ) ) {
786 f->mId = 0;
787 return TRUE;
788 }
789 return FALSE;
790}
791
792/*!
793 Returns the localized name for type \a t.
794*/
795QString AppLnkSet::typeName( const QString& t ) const
796{
797 QString *st = d->typName.find(t);
798 return st ? *st : QString::null;
799}
800
801/*!
802 Returns the small pixmap associated with type \a t.
803*/
804QPixmap AppLnkSet::typePixmap( const QString& t ) const
805{
806 QPixmap *pm = d->typPix.find(t);
807 return pm ? *pm : QPixmap();
808}
809
810/*!
811 Returns the large pixmap associated with type \a t.
812*/
813QPixmap AppLnkSet::typeBigPixmap( const QString& t ) const
814{
815 QPixmap *pm = d->typPixBig.find(t);
816 return pm ? *pm : QPixmap();
817}
818
819/*!
820 Returns the AppLnk with the given \a id.
821*/
822const AppLnk *AppLnkSet::find( int id ) const
823{
824 QListIterator<AppLnk> it( children() );
825
826 for ( ; it.current(); ++it ) {
827 const AppLnk *app = it.current();
828 if ( app->id() == id )
829 return app;
830 }
831
832 return 0;
833}
834
835/*!
836 Returns the AppLnk with the given \a exec attribute.
837*/
838const AppLnk *AppLnkSet::findExec( const QString& exec ) const
839{
840 QListIterator<AppLnk> it( children() );
841
842 for ( ; it.current(); ++it ) {
843 const AppLnk *app = it.current();
844 if ( app->exec() == exec )
845 return app;
846 }
847
848 return 0;
849}
850
851/*!
852 \class DocLnkSet applnk.h
853 \brief The DocLnkSet class is a set of DocLnk objects.
854*/
855
856/*!
857 \fn const QList<DocLnk>& DocLnkSet::children() const
858
859 Returns the members of the set.
860*/
861
862/*!
863 Constructs an empty DocLnkSet.
864
865 \sa appendFrom()
866*/
867DocLnkSet::DocLnkSet()
868{
869}
870
871/*!
872 Constructs an DocLnkSet that contains DocLnk objects representing
873 all the files in a \a directory (recursively).
874
875 If \a mimefilter is not null,
876 only documents with a MIME type matching \a mimefilter are selected.
877 The value may contain multiple wild-card patterns separated by ";",
878 such as "*o/mpeg;audio/x-wav".
879*/
880DocLnkSet::DocLnkSet( const QString &directory, const QString& mimefilter ) :
881 AppLnkSet()
882{
883 QDir dir( directory );
884 mFile = dir.dirName();
885 QDict<void> reference;
886
887 QStringList subFilter = QStringList::split(";", mimefilter);
888 QValueList<QRegExp> mimeFilters;
889 for( QStringList::Iterator it = subFilter.begin(); it != subFilter.end(); ++ it )
890 mimeFilters.append( QRegExp(*it, FALSE, TRUE) );
891
892 findChildren(directory, mimeFilters, reference);
893
894 const QList<DocLnk> &list = children();
895 for ( QListIterator<DocLnk> it( list ); it.current(); ++it ) {
896 reference.remove( (*it)->file() );
897 }
898
899 for ( QDictIterator<void> dit(reference); dit.current(); ++dit ) {
900 if ( dit.current() == (void*)2 ) {
901 // Unreferenced, make an unwritten link
902 DocLnk* dl = new DocLnk;
903 QFileInfo fi( dit.currentKey() );
904 dl->setFile(fi.filePath());
905 dl->setName(fi.baseName());
906 // #### default to current path?
907 // dl->setCategories( ... );
908 bool match = mimefilter.isNull();
909 if ( !match )
910 for( QValueList<QRegExp>::Iterator it = mimeFilters.begin(); it != mimeFilters.end() && !match; ++ it )
911 if ( (*it).match(dl->type()) >= 0 )
912 match = TRUE;
913 if ( match /* && dl->type() != "application/octet-stream" */
914 && !!dl->exec() )
915 add(dl);
916 else
917 delete dl;
918 }
919 }
920}
921
922// other becomes empty
923/*!
924 Transfers all DocLnk objects from \a other to this set. \a other becomes
925 empty.
926*/
927void DocLnkSet::appendFrom( DocLnkSet& other )
928{
929 if ( &other == this )
930 return;
931 QListIterator<AppLnk> it( other.mApps );
932 for ( ; it.current(); ) {
933 mApps.append(*it);
934 ++it;
935 }
936 other.mApps.clear();
937}
938
939void DocLnkSet::findChildren(const QString &dr, const QValueList<QRegExp> &mimeFilters, QDict<void> &reference, int depth)
940{
941 depth++;
942 if ( depth > 10 )
943 return;
944
945 QDir dir( dr );
946
947 const QFileInfoList *list = dir.entryInfoList();
948 if ( list ) {
949 QFileInfo* fi;
950 for ( QFileInfoListIterator it(*list); (fi=*it); ++it ) {
951 QString bn = fi->fileName();
952 if ( bn[0] != '.' && bn != "CVS" ) {
953 if ( fi->isDir() ) {
954 findChildren(fi->filePath(), mimeFilters, reference, depth);
955 } else {
956 if ( fi->extension(FALSE) == "desktop" ) {
957 DocLnk* dl = new DocLnk( fi->filePath() );
958 QFileInfo fi2(dl->file());
959 bool match = FALSE;
960 if ( !fi2.exists() ) {
961 dir.remove( dl->file() );
962 }
963 if ( mimeFilters.count() == 0 ) {
964 add( dl );
965 match = TRUE;
966 } else {
967 for( QValueList<QRegExp>::ConstIterator it = mimeFilters.begin(); it != mimeFilters.end(); ++ it ) {
968 if ( (*it).match(dl->type()) >= 0 ) {
969 add(dl);
970 match = TRUE;
971 }
972 }
973 }
974 if ( !match )
975 delete dl;
976 } else {
977 if ( !reference.find(fi->fileName()) )
978 reference.insert(fi->filePath(), (void*)2);
979 }
980 }
981 }
982 }
983 }
984}
985
986/*!
987 \class DocLnk applnk.h
988 \brief The DocLnk class represents loaded document references.
989*/
990
991/*!
992 \fn DocLnk::DocLnk( const DocLnk &o )
993
994 Copies \a o.
995*/
996
997/*!
998 Constructs a DocLnk from a valid .desktop \a file or a new .desktop
999 \a file for other files.
1000*/
1001DocLnk::DocLnk( const QString &file ) :
1002 AppLnk(file)
1003{
1004 init(file);
1005}
1006
1007/*!
1008 Constructs a DocLnk from a valid .desktop \a file or a new .desktop
1009 \a file for other files. If \a may_be_desktopfile is TRUE, then \a file
1010 is first attempted to be read as a .desktop file.
1011*/
1012DocLnk::DocLnk( const QString &file, bool may_be_desktopfile ) :
1013 AppLnk(may_be_desktopfile ? file : QString::null)
1014{
1015 init(file);
1016}
1017
1018void DocLnk::init(const QString &file)
1019{
1020 if ( isValid() ) {
1021#ifndef FORCED_DIR_STRUCTURE_WAY
1022 if ( mType.isNull() )
1023 // try to infer it
1024#endif
1025 {
1026 int s0 = file.findRev('/');
1027 if ( s0 > 0 ) {
1028 int s1 = file.findRev('/',s0-1);
1029 if ( s1 > 0 ) {
1030 int s2 = file.findRev('/',s1-1);
1031 if ( s2 > 0 ) {
1032 mType = file.mid(s2+1,s0-s2-1);
1033 }
1034 }
1035 }
1036 }
1037 } else if ( QFile::exists(file) ) {
1038 QString n = file;
1039 n.replace(QRegExp("\\..*"),"");
1040 n.replace(QRegExp(".*/"),"");
1041 setName( n );
1042 setFile( file );
1043 }
1044 MimeType mt(mType);
1045 if( mt.application() )
1046 mExec = mt.application()->exec();
1047}
1048
1049/*!
1050 Constructs an invalid DocLnk.
1051*/
1052DocLnk::DocLnk()
1053{
1054}
1055
1056/*!
1057 Destroys the DocLnk. As with AppLnk objects, a run-time error
1058 occurs if the DocLnk is a member of a DocLnkSet (or AppLnkSet).
1059*/
1060DocLnk::~DocLnk()
1061{
1062}
1063
1064/*!
1065 \reimp
1066*/
1067QString DocLnk::exec() const
1068{
1069 MimeType mt(type());
1070 const AppLnk* app = mt.application();
1071 if ( app )
1072 return app->exec();
1073 else
1074 return QString::null;
1075}
1076
1077/*!
1078 \reimp
1079*/
1080void DocLnk::invoke(const QStringList& args) const
1081{
1082 MimeType mt(type());
1083 const AppLnk* app = mt.application();
1084 if ( app ) {
1085 QStringList a = args;
1086 if ( QFile::exists( linkFile() ) )
1087 a.append(linkFile());
1088 else
1089 a.append(file());
1090 app->execute(a);
1091 }
1092}
1093