-rw-r--r-- | library/applnk.cpp | 1093 |
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 | |||
43 | int AppLnk::lastId = 5000; | ||
44 | |||
45 | static int smallSize = 14; | ||
46 | static int bigSize = 32; | ||
47 | |||
48 | static 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 | |||
59 | class AppLnkPrivate | ||
60 | { | ||
61 | public: | ||
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 | */ | ||
77 | void AppLnk::setSmallIconSize(int small) | ||
78 | { | ||
79 | smallSize = small; | ||
80 | } | ||
81 | |||
82 | /*! | ||
83 | Returns the size used for small icons. | ||
84 | */ | ||
85 | int 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 | */ | ||
95 | void AppLnk::setBigIconSize(int big) | ||
96 | { | ||
97 | bigSize = big; | ||
98 | } | ||
99 | |||
100 | /*! | ||
101 | Returns the size used for large icons. | ||
102 | */ | ||
103 | int 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 | |||
142 | const 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 | */ | ||
166 | AppLnk::AppLnk() | ||
167 | { | ||
168 | mId = 0; | ||
169 | d = new AppLnkPrivate(); | ||
170 | } | ||
171 | |||
172 | /*! | ||
173 | Loads \a file as an AppLnk. | ||
174 | */ | ||
175 | AppLnk::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 | */ | ||
223 | const 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 | */ | ||
245 | const 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 | */ | ||
267 | QString 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 | */ | ||
283 | QString 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 | */ | ||
314 | QString 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 | */ | ||
348 | AppLnk::AppLnk( const AppLnk © ) | ||
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 | */ | ||
373 | AppLnk::~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 | */ | ||
384 | void 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 | */ | ||
393 | void 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 | */ | ||
416 | void 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 | */ | ||
426 | void 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 | */ | ||
436 | void 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 | */ | ||
446 | void 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 | */ | ||
456 | void 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 | */ | ||
466 | void 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 | */ | ||
476 | void 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 | */ | ||
486 | void 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 | */ | ||
499 | void 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 | */ | ||
514 | bool 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 | */ | ||
532 | bool 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 | */ | ||
562 | void 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 | */ | ||
573 | QString 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 | */ | ||
586 | void 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 | */ | ||
603 | void AppLnk::removeLinkFile() | ||
604 | { | ||
605 | if ( isValid() && QFile::remove(linkFile()) ) { | ||
606 | QCopEnvelope e("QPE/System", "linkChanged(QString)"); | ||
607 | e << linkFile(); | ||
608 | } | ||
609 | } | ||
610 | |||
611 | class AppLnkSetPrivate { | ||
612 | public: | ||
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 | */ | ||
647 | AppLnkSet::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 | */ | ||
660 | AppLnkSet::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 | */ | ||
672 | void 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 | */ | ||
688 | AppLnkSet::~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 | |||
700 | void 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 | */ | ||
766 | void 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 | */ | ||
783 | bool 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 | */ | ||
795 | QString 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 | */ | ||
804 | QPixmap 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 | */ | ||
813 | QPixmap 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 | */ | ||
822 | const 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 | */ | ||
838 | const 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 | */ | ||
867 | DocLnkSet::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 | */ | ||
880 | DocLnkSet::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 | */ | ||
927 | void 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 | |||
939 | void 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 | */ | ||
1001 | DocLnk::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 | */ | ||
1012 | DocLnk::DocLnk( const QString &file, bool may_be_desktopfile ) : | ||
1013 | AppLnk(may_be_desktopfile ? file : QString::null) | ||
1014 | { | ||
1015 | init(file); | ||
1016 | } | ||
1017 | |||
1018 | void 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 | */ | ||
1052 | DocLnk::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 | */ | ||
1060 | DocLnk::~DocLnk() | ||
1061 | { | ||
1062 | } | ||
1063 | |||
1064 | /*! | ||
1065 | \reimp | ||
1066 | */ | ||
1067 | QString 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 | */ | ||
1080 | void 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 | |||