summaryrefslogtreecommitdiff
path: root/core/launcher/documentlist.cpp
Unidiff
Diffstat (limited to 'core/launcher/documentlist.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/documentlist.cpp646
1 files changed, 646 insertions, 0 deletions
diff --git a/core/launcher/documentlist.cpp b/core/launcher/documentlist.cpp
new file mode 100644
index 0000000..033dd10
--- a/dev/null
+++ b/core/launcher/documentlist.cpp
@@ -0,0 +1,646 @@
1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3**
4** This file is part of the 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#include "documentlist.h"
21#include "serverinterface.h"
22
23#include <qtopia/mimetype.h>
24#include <qtopia/resource.h>
25#include <qtopia/global.h>
26#include <qtopia/categories.h>
27#include <qtopia/qpeapplication.h>
28#include <qtopia/applnk.h>
29#include <qtopia/storage.h>
30#ifdef Q_WS_QWS
31#include <qtopia/qcopenvelope_qws.h>
32#endif
33
34#include <qtimer.h>
35#include <qfileinfo.h>
36#include <qtextstream.h>
37#include <qfile.h>
38#include <qdir.h>
39#include <qpainter.h>
40#include <qimage.h>
41#include <qcopchannel_qws.h>
42#include <qlistview.h>
43#include <qlist.h>
44#include <qpixmap.h>
45
46
47AppLnkSet *DocumentList::appLnkSet = 0;
48
49static const int MAX_SEARCH_DEPTH = 10;
50
51
52class DocumentListPrivate : public QObject {
53 Q_OBJECT
54public:
55 DocumentListPrivate( ServerInterface *gui );
56 ~DocumentListPrivate();
57
58 void initialize();
59
60 const QString nextFile();
61 const DocLnk *iterate();
62 bool store( DocLnk* dl );
63 void estimatedPercentScanned();
64
65 DocLnkSet dls;
66 QDict<void> reference;
67 QDictIterator<void> *dit;
68 enum { Find, RemoveKnownFiles, MakeUnknownFiles, Done } state;
69
70 QStringList docPaths;
71 unsigned int docPathsSearched;
72
73 int searchDepth;
74 QDir *listDirs[MAX_SEARCH_DEPTH];
75 const QFileInfoList *lists[MAX_SEARCH_DEPTH];
76 unsigned int listPositions[MAX_SEARCH_DEPTH];
77
78 StorageInfo *storage;
79
80 int tid;
81
82 ServerInterface *serverGui;
83
84 bool needToSendAllDocLinks;
85 bool sendAppLnks;
86 bool sendDocLnks;
87 bool scanDocs;
88};
89
90
91DocumentList::DocumentList( ServerInterface *serverGui, bool scanDocs,
92 QObject *parent, const char *name )
93 : QObject( parent, name )
94{
95 appLnkSet = new AppLnkSet( MimeType::appsFolderName() );
96 d = new DocumentListPrivate( serverGui );
97 d->scanDocs = scanDocs;
98 d->needToSendAllDocLinks = false;
99
100 QTimer::singleShot( 10, this, SLOT( startInitialScan() ) );
101}
102
103void DocumentList::startInitialScan()
104{
105 reloadAppLnks();
106 reloadDocLnks();
107}
108
109DocumentList::~DocumentList()
110{
111 delete appLnkSet;
112 delete d;
113}
114
115
116void DocumentList::add( const DocLnk& doc )
117{
118 if ( d->serverGui && QFile::exists( doc.file() ) )
119 d->serverGui->documentAdded( doc );
120}
121
122
123void DocumentList::start()
124{
125 resume();
126}
127
128
129void DocumentList::pause()
130{
131 //qDebug("pause %i", d->tid);
132 killTimer( d->tid );
133 d->tid = 0;
134}
135
136
137void DocumentList::resume()
138{
139 if ( d->tid == 0 ) {
140 d->tid = startTimer( 0 );
141 //qDebug("resumed %i", d->tid);
142 }
143}
144
145/*
146void DocumentList::resend()
147{
148 // Re-emits all the added items to the list (firstly letting everyone know to
149 // clear what they have as it is being sent again)
150 pause();
151 emit allRemoved();
152 QTimer::singleShot( 5, this, SLOT( resendWorker() ) );
153}
154
155
156void DocumentList::resendWorker()
157{
158 const QList<DocLnk> &list = d->dls.children();
159 for ( QListIterator<DocLnk> it( list ); it.current(); ++it )
160 add( *(*it) );
161 resume();
162}
163*/
164
165void DocumentList::rescan()
166{
167 //qDebug("rescan");
168 pause();
169 d->initialize();
170 resume();
171}
172
173
174void DocumentList::timerEvent( QTimerEvent *te )
175{
176 if ( te->timerId() == d->tid ) {
177 // Do 3 at a time
178 for (int i = 0; i < 3; i++ ) {
179 const DocLnk *lnk = d->iterate();
180 if ( lnk ) {
181 add( *lnk );
182 } else {
183 // stop when done
184 pause();
185 if ( d->serverGui )
186 d->serverGui->documentScanningProgress( 100 );
187 if ( d->needToSendAllDocLinks )
188 sendAllDocLinks();
189 break;
190 }
191 }
192 }
193}
194
195
196void DocumentList::reloadAppLnks()
197{
198 if ( d->sendAppLnks && d->serverGui ) {
199 d->serverGui->applicationScanningProgress( 0 );
200 d->serverGui->allApplicationsRemoved();
201 }
202
203 delete appLnkSet;
204 appLnkSet = new AppLnkSet( MimeType::appsFolderName() );
205
206 if ( d->sendAppLnks && d->serverGui ) {
207 static QStringList prevTypeList;
208 QStringList types = appLnkSet->types();
209 for ( QStringList::Iterator ittypes=types.begin(); ittypes!=types.end(); ++ittypes) {
210 if ( !(*ittypes).isEmpty() ) {
211 if ( !prevTypeList.contains(*ittypes) ) {
212 QString name = appLnkSet->typeName(*ittypes);
213 QPixmap pm = appLnkSet->typePixmap(*ittypes);
214 QPixmap bgPm = appLnkSet->typeBigPixmap(*ittypes);
215
216 if (pm.isNull()) {
217 QImage img( Resource::loadImage( "UnknownDocument" ) );
218 pm = img.smoothScale( AppLnk::smallIconSize(), AppLnk::smallIconSize() );
219 bgPm = img.smoothScale( AppLnk::bigIconSize(), AppLnk::bigIconSize() );
220 }
221
222 //qDebug("adding type %s", (*ittypes).latin1());
223
224 // ### our current launcher expects docs tab to be last
225 d->serverGui->typeAdded( *ittypes, name.isNull() ? (*ittypes) : name, pm, bgPm );
226 }
227 prevTypeList.remove(*ittypes);
228 }
229 }
230 for ( QStringList::Iterator ittypes=prevTypeList.begin(); ittypes!=prevTypeList.end(); ++ittypes) {
231 //qDebug("removing type %s", (*ittypes).latin1());
232 d->serverGui->typeRemoved(*ittypes);
233 }
234 prevTypeList = types;
235 }
236
237 QListIterator<AppLnk> itapp( appLnkSet->children() );
238 AppLnk* l;
239 while ( (l=itapp.current()) ) {
240 ++itapp;
241 if ( d->sendAppLnks && d->serverGui )
242 d->serverGui->applicationAdded( l->type(), *l );
243 }
244
245 if ( d->sendAppLnks && d->serverGui )
246 d->serverGui->applicationScanningProgress( 100 );
247}
248
249void DocumentList::reloadDocLnks()
250{
251 if ( !d->scanDocs )
252 return;
253
254 if ( d->sendDocLnks && d->serverGui ) {
255 d->serverGui->documentScanningProgress( 0 );
256 d->serverGui->allDocumentsRemoved();
257 }
258
259 rescan();
260}
261
262void DocumentList::linkChanged( QString arg )
263{
264 //qDebug( "linkchanged( %s )", arg.latin1() );
265
266 if ( arg.isNull() || Global::isAppLnkFileName( arg ) ) {
267 reloadAppLnks();
268 } else {
269
270 const QList<DocLnk> &list = d->dls.children();
271 QListIterator<DocLnk> it( list );
272 while ( it.current() ) {
273 DocLnk *doc = it.current();
274 ++it;
275 if ( ( doc->linkFileKnown() && doc->linkFile() == arg )
276 || ( doc->fileKnown() && doc->file() == arg ) ) {
277 //qDebug( "found old link" );
278 DocLnk* dl = new DocLnk( arg );
279 // add new one if it exists and matches the mimetype
280 if ( d->store( dl ) ) {
281 // Existing link has been changed, send old link ref and a ref
282 // to the new link
283 //qDebug( "change case" );
284 if ( d->serverGui )
285 d->serverGui->documentChanged( *doc, *dl );
286
287 } else {
288 // Link has been removed or doesn't match the mimetypes any more
289 // so we aren't interested in it, so take it away from the list
290 //qDebug( "removal case" );
291 if ( d->serverGui )
292 d->serverGui->documentRemoved( *doc );
293
294 }
295 d->dls.remove( doc ); // remove old link from docLnkSet
296 delete doc;
297 return;
298 }
299 }
300 // Didn't find existing link, must be new
301 DocLnk* dl = new DocLnk( arg );
302 if ( d->store( dl ) ) {
303 // Add if it's a link we are interested in
304 //qDebug( "add case" );
305 add( *dl );
306 }
307
308 }
309}
310
311void DocumentList::restoreDone()
312{
313 reloadAppLnks();
314 reloadDocLnks();
315}
316
317void DocumentList::storageChanged()
318{
319 // ### can implement better
320 reloadAppLnks();
321 reloadDocLnks();
322 // ### Optimization opportunity
323 // Could be a bit more intelligent and somehow work out which
324 // mtab entry has changed and then only scan that and add and remove
325 // links appropriately.
326// rescan();
327}
328
329void DocumentList::sendAllDocLinks()
330{
331 if ( d->tid != 0 ) {
332 // We are in the middle of scanning, set a flag so
333 // we do this when we finish our scanning
334 d->needToSendAllDocLinks = true;
335 return;
336 }
337
338 QString contents;
339 Categories cats;
340 for ( QListIterator<DocLnk> it( d->dls.children() ); it.current(); ++it ) {
341 DocLnk *doc = it.current();
342 QFileInfo fi( doc->file() );
343 if ( !fi.exists() )
344 continue;
345
346 bool fake = !doc->linkFileKnown();
347 if ( !fake ) {
348 QFile f( doc->linkFile() );
349 if ( f.open( IO_ReadOnly ) ) {
350 QTextStream ts( &f );
351 ts.setEncoding( QTextStream::UnicodeUTF8 );
352 contents += ts.read();
353 f.close();
354 } else
355 fake = TRUE;
356 }
357 if (fake) {
358 contents += "[Desktop Entry]\n"; // No tr
359 contents += "Categories = " + // No tr
360 cats.labels("Document View",doc->categories()).join(";") + "\n"; // No tr
361 contents += "Name = "+doc->name()+"\n"; // No tr
362 contents += "Type = "+doc->type()+"\n"; // No tr
363 }
364 contents += "File = "+doc->file()+"\n"; // No tr // (resolves path)
365 contents += QString("Size = %1\n").arg( fi.size() ); // No tr
366 }
367
368 //qDebug( "sending length %d", contents.length() );
369#ifndef QT_NO_COP
370 QCopEnvelope e( "QPE/Desktop", "docLinks(QString)" );
371 e << contents;
372#endif
373 //qDebug( "================ \n\n%s\n\n===============", contents.latin1() );
374
375 d->needToSendAllDocLinks = false;
376}
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401DocumentListPrivate::DocumentListPrivate( ServerInterface *gui )
402{
403 storage = new StorageInfo( this );
404 serverGui = gui;
405 if ( serverGui ) {
406 sendAppLnks = serverGui->requiresApplications();
407 sendDocLnks = serverGui->requiresDocuments();
408 } else {
409 sendAppLnks = false;
410 sendDocLnks = false;
411 }
412 for ( int i = 0; i < MAX_SEARCH_DEPTH; i++ ) {
413 listDirs[i] = 0;
414 lists[i] = 0;
415 listPositions[i] = 0;
416 }
417 initialize();
418 tid = 0;
419}
420
421
422void DocumentListPrivate::initialize()
423{
424 // Reset
425 dls.clear();
426 docPaths.clear();
427 reference.clear();
428
429 QDir docDir( QPEApplication::documentDir() );
430 if ( docDir.exists() )
431 docPaths += QPEApplication::documentDir();
432 int i = 1;
433 const QList<FileSystem> &fs = storage->fileSystems();
434 QListIterator<FileSystem> it( fs );
435 for ( ; it.current(); ++it )
436 if ( (*it)->isRemovable() ) {
437 docPaths += (*it)->path();
438 i++;
439 }
440
441 for ( int i = 0; i < MAX_SEARCH_DEPTH; i++ ) {
442 if ( listDirs[i] ) {
443 delete listDirs[i];
444 listDirs[i] = 0;
445 }
446 lists[i] = 0;
447 listPositions[i] = 0;
448 }
449
450 docPathsSearched = 0;
451 searchDepth = -1;
452 state = Find;
453 dit = 0;
454}
455
456
457DocumentListPrivate::~DocumentListPrivate()
458{
459 for ( int i = 0; i < MAX_SEARCH_DEPTH; i++ )
460 if ( listDirs[i] )
461 delete listDirs[i];
462 delete dit;
463}
464
465
466void DocumentListPrivate::estimatedPercentScanned()
467{
468 double overallProgress = 0.0;
469 double levelWeight = 75.0;
470
471 int topCount = docPaths.count();
472 if ( topCount > 1 ) {
473 levelWeight = levelWeight / topCount;
474 overallProgress += (docPathsSearched - 1) * levelWeight;
475 }
476
477 for ( int d = 0; d <= searchDepth; d++ ) {
478 if ( listDirs[d] ) {
479 int items = lists[d]->count();
480 if ( items > 1 ) {
481 levelWeight = levelWeight / items;
482 // Take in to account "." and ".."
483 overallProgress += (listPositions[d] - 3) * levelWeight;
484 }
485 } else {
486 break;
487 }
488 }
489
490 // qDebug( "overallProgress: %f", overallProgress );
491
492 if ( serverGui )
493 serverGui->documentScanningProgress( (int)overallProgress );
494}
495
496
497const QString DocumentListPrivate::nextFile()
498{
499 while ( TRUE ) {
500 while ( searchDepth < 0 ) {
501 // go to next base path
502 if ( docPathsSearched >= docPaths.count() ) {
503 // end of base paths
504 return QString::null;
505 } else {
506 QDir dir( docPaths[docPathsSearched] );
507 // qDebug("now using base path: %s", docPaths[docPathsSearched].latin1() );
508 docPathsSearched++;
509 if ( !dir.exists( ".Qtopia-ignore" ) ) {
510 listDirs[0] = new QDir( dir );
511 lists[0] = listDirs[0]->entryInfoList();
512 listPositions[0] = 0;
513 searchDepth = 0;
514 }
515 }
516 }
517
518 const QFileInfoList *fil = lists[searchDepth];
519 QFileInfoList *fl = (QFileInfoList *)fil;
520 unsigned int pos = listPositions[searchDepth];
521
522 if ( pos >= fl->count() ) {
523 // go up a depth
524 delete listDirs[searchDepth];
525 listDirs[searchDepth] = 0;
526 lists[searchDepth] = 0;
527 listPositions[searchDepth] = 0;
528 searchDepth--;
529 } else {
530 const QFileInfo *fi = fl->at(pos);
531 listPositions[searchDepth]++;
532 QString bn = fi->fileName();
533 if ( bn[0] != '.' ) {
534 if ( fi->isDir() ) {
535 if ( bn != "CVS" && bn != "Qtopia" && bn != "QtPalmtop" ) {
536 // go down a depth
537 QDir dir( fi->filePath() );
538 // qDebug("now going in to path: %s", bn.latin1() );
539 if ( !dir.exists( ".Qtopia-ignore" ) ) {
540 if ( searchDepth < MAX_SEARCH_DEPTH - 1) {
541 searchDepth++;
542 listDirs[searchDepth] = new QDir( dir );
543 lists[searchDepth] = listDirs[searchDepth]->entryInfoList();
544 listPositions[searchDepth] = 0;
545 }
546 }
547 }
548 } else {
549 estimatedPercentScanned();
550 return fl->at(pos)->filePath();
551 }
552 }
553 }
554 }
555
556 return QString::null;
557}
558
559
560bool DocumentListPrivate::store( DocLnk* dl )
561{
562 // if ( dl->fileKnown() && !dl->file().isEmpty() ) {
563 if ( dl && dl->fileKnown() ) {
564 dls.add( dl ); // store
565 return TRUE;
566 }
567
568 // don't store - delete
569 delete dl;
570 return FALSE;
571}
572
573
574 #define MAGIC_NUMBER((void*)2)
575
576const DocLnk *DocumentListPrivate::iterate()
577{
578 if ( state == Find ) {
579 //qDebug("state Find");
580 QString file = nextFile();
581 while ( !file.isNull() ) {
582 if ( file.right(8) == ".desktop" ) { // No tr
583 DocLnk* dl = new DocLnk( file );
584 if ( store(dl) )
585 return dl;
586 } else {
587 reference.insert( file, MAGIC_NUMBER );
588 }
589 file = nextFile();
590 }
591 state = RemoveKnownFiles;
592
593 if ( serverGui )
594 serverGui->documentScanningProgress( 75 );
595 }
596
597 static int iterationI;
598 static int iterationCount;
599
600 if ( state == RemoveKnownFiles ) {
601 //qDebug("state RemoveKnownFiles");
602 const QList<DocLnk> &list = dls.children();
603 for ( QListIterator<DocLnk> it( list ); it.current(); ++it ) {
604 reference.remove( (*it)->file() );
605 // ### does this need to be deleted?
606 }
607 dit = new QDictIterator<void>(reference);
608 state = MakeUnknownFiles;
609
610 iterationI = 0;
611 iterationCount = dit->count();
612 }
613
614 if ( state == MakeUnknownFiles ) {
615 //qDebug("state MakeUnknownFiles");
616 for (void* c; (c=dit->current()); ++(*dit) ) {
617 if ( c == MAGIC_NUMBER ) {
618 DocLnk* dl = new DocLnk;
619 QFileInfo fi( dit->currentKey() );
620 dl->setFile( fi.filePath() );
621 dl->setName( fi.baseName() );
622 if ( store(dl) ) {
623 ++*dit;
624 iterationI++;
625 if ( serverGui )
626 serverGui->documentScanningProgress( 75 + (25*iterationI)/iterationCount );
627 return dl;
628 }
629 }
630 iterationI++;
631 }
632
633 delete dit;
634 dit = 0;
635 state = Done;
636 }
637
638 //qDebug("state Done");
639 return NULL;
640}
641
642
643#include "documentlist.moc"
644
645
646