~ubuntu-branches/ubuntu/gutsy/kdebase-workspace/gutsy-backports

« back to all changes in this revision

Viewing changes to kcontrol/kfontinst/kcmfontinst/DuplicatesDialog.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2007-09-05 20:45:14 UTC
  • Revision ID: james.westby@ubuntu.com-20070905204514-632hhspl0nvrc84i
Tags: upstream-3.93.0
ImportĀ upstreamĀ versionĀ 3.93.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * KFontInst - KDE Font Installer
 
3
 *
 
4
 * Copyright 2003-2007 Craig Drummond <craig@kde.org>
 
5
 *
 
6
 * ----
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public
 
10
 * License version 2 as published by the Free Software Foundation.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; see the file COPYING.  If not, write to
 
19
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
20
 * Boston, MA 02110-1301, USA.
 
21
 */
 
22
 
 
23
#include "DuplicatesDialog.h"
 
24
#include "Misc.h"
 
25
#include "Fc.h"
 
26
#include "JobRunner.h"
 
27
#include "FontList.h"
 
28
#include <kglobal.h>
 
29
#include <kiconloader.h>
 
30
#include <klocale.h>
 
31
#include <kmessagebox.h>
 
32
#include <kdesu/su.h>
 
33
#include <kfileitem.h>
 
34
#include <kpropertiesdialog.h>
 
35
#include <kshell.h>
 
36
#include <QLabel>
 
37
#include <QTimer>
 
38
#include <QGridLayout>
 
39
#include <QDir>
 
40
#include <QFileInfoList>
 
41
#include <QFileInfo>
 
42
#include <QHeaderView>
 
43
#include <QDateTime>
 
44
#include <QMenu>
 
45
#include <QContextMenuEvent>
 
46
#include <QAction>
 
47
#include <QApplication>
 
48
#include <QDesktopWidget>
 
49
#include <QProcess>
 
50
 
 
51
namespace KFI
 
52
{
 
53
 
 
54
enum EDialogColumns
 
55
{
 
56
    COL_FILE,
 
57
    COL_TRASH,
 
58
    COL_SIZE,
 
59
    COL_DATE,
 
60
    COL_LINK
 
61
};
 
62
 
 
63
CDuplicatesDialog::CDuplicatesDialog(QWidget *parent, CJobRunner *jr, CFontList *fl)
 
64
                 : CActionDialog(parent),
 
65
                   itsModifiedSys(false),
 
66
                   itsModifiedUser(false),
 
67
                   itsRunner(jr),
 
68
                   itsFontList(fl)
 
69
{
 
70
    setCaption(i18n("Duplicate Fonts"));
 
71
    setButtons(KDialog::Ok|KDialog::Cancel);
 
72
    enableButtonOk(false);
 
73
 
 
74
    QFrame *page = new QFrame(this);
 
75
    setMainWidget(page);
 
76
 
 
77
    QGridLayout *layout=new QGridLayout(page);
 
78
    layout->setMargin(0);
 
79
    layout->setSpacing(KDialog::spacingHint());
 
80
    itsLabel=new QLabel(page);
 
81
    itsView=new CFontFileListView(page);
 
82
    itsView->hide();
 
83
    layout->addWidget(itsPixmapLabel, 0, 0);
 
84
    layout->addWidget(itsLabel, 0, 1);
 
85
    itsLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
 
86
    layout->addWidget(itsView, 1, 0, 1, 2);
 
87
    itsFontFileList=new CFontFileList(this);
 
88
    connect(itsFontFileList, SIGNAL(finished()), SLOT(scanFinished()));
 
89
    connect(itsView, SIGNAL(haveDeletions(bool)), SLOT(enableButtonOk(bool)));
 
90
}
 
91
 
 
92
int CDuplicatesDialog::exec()
 
93
{
 
94
    itsModifiedSys=itsModifiedUser=false;
 
95
    itsLabel->setText(i18n("Scanning for duplicate fonts. Please wait..."));
 
96
    itsFontFileList->start();
 
97
    return CActionDialog::exec();
 
98
}
 
99
 
 
100
void CDuplicatesDialog::scanFinished()
 
101
{
 
102
    stopAnimation();
 
103
 
 
104
    if(itsFontFileList->wasTerminated())
 
105
    {
 
106
        itsFontFileList->wait();
 
107
        reject();
 
108
    }
 
109
    else
 
110
    {
 
111
        CFontFileList::TFontMap duplicates;
 
112
 
 
113
        itsFontFileList->getDuplicateFonts(duplicates);
 
114
 
 
115
        if(0==duplicates.count())
 
116
            itsLabel->setText(i18n("No duplicate fonts found."));
 
117
        else
 
118
        {
 
119
            QSize sizeB4(size());
 
120
 
 
121
            itsLabel->setText(i18n("%1 duplicate fonts found.", duplicates.count()));
 
122
            itsView->show();
 
123
 
 
124
            CFontFileList::TFontMap::ConstIterator it(duplicates.begin()),
 
125
                                                   end(duplicates.end());
 
126
            QFont                                  boldFont(font());
 
127
 
 
128
            boldFont.setBold(true);
 
129
 
 
130
            for(; it!=end; ++it)
 
131
            {
 
132
                QStringList details;
 
133
 
 
134
                details << FC::createName(it.key().family, it.key().styleInfo);
 
135
 
 
136
                QTreeWidgetItem *top=new QTreeWidgetItem(itsView, details);
 
137
 
 
138
                QStringList::ConstIterator fit((*it).begin()),
 
139
                                           fend((*it).end());
 
140
                int                        tt(0),
 
141
                                           t1(0);
 
142
 
 
143
                for(; fit!=fend; ++fit)
 
144
                {
 
145
                    QFileInfo info(*fit);
 
146
                    details.clear();
 
147
                    details.append(*fit);
 
148
                    details.append("");
 
149
                    details.append(KGlobal::locale()->formatByteSize(info.size()));
 
150
                    details.append(KGlobal::locale()->formatDateTime(info.created()));
 
151
                    if(info.isSymLink())
 
152
                        details.append(info.readLink());
 
153
                    new QTreeWidgetItem(top, details);
 
154
                    if(Misc::checkExt(*fit, "pfa") || Misc::checkExt(*fit, "pfb"))
 
155
                        t1++;
 
156
                    else
 
157
                        tt++;
 
158
                }
 
159
                top->setExpanded(true);
 
160
                top->setData(COL_FILE, Qt::DecorationRole,
 
161
                             QVariant(SmallIcon(t1>tt ? "font-type1" : "font-truetype")));
 
162
                top->setFont(COL_FILE, boldFont);
 
163
            }
 
164
            itsView->setSortingEnabled(true);
 
165
            itsView->header()->resizeSections(QHeaderView::ResizeToContents);
 
166
 
 
167
            int width=(KDialog::marginHint()+itsView->frameWidth()+8)*2;
 
168
 
 
169
            for(int i=0; i<itsView->header()->count(); ++i)
 
170
                width+=itsView->header()->sectionSize(i);
 
171
 
 
172
            width=qMin(QApplication::desktop()->screenGeometry(this).width(), width);
 
173
            resize(width, height());
 
174
            QSize sizeNow(size());
 
175
            if(sizeNow.width()>sizeB4.width())
 
176
            {
 
177
                int xmod=(sizeNow.width()-sizeB4.width())/2,
 
178
                    ymod=(sizeNow.height()-sizeB4.height())/2;
 
179
 
 
180
                move(pos().x()-xmod, pos().y()-ymod);
 
181
            }
 
182
        }
 
183
    }
 
184
}
 
185
 
 
186
enum EStatus
 
187
{
 
188
    STATUS_NO_FILES,
 
189
    STATUS_ALL_REMOVED,
 
190
    STATUS_ERROR,
 
191
    STATUS_USER_CANCELLED
 
192
};
 
193
 
 
194
void CDuplicatesDialog::slotButtonClicked(int button)
 
195
{
 
196
    switch(button)
 
197
    {
 
198
        case KDialog::Ok:
 
199
        {
 
200
            switch(deleteFiles())
 
201
            {
 
202
                case STATUS_NO_FILES:
 
203
                case STATUS_ALL_REMOVED:
 
204
                    accept();
 
205
                    break;
 
206
                case STATUS_ERROR:
 
207
                {
 
208
                    QList<QString> files=itsView->getMarkedFiles().toList();
 
209
 
 
210
                    if(1==files.count())
 
211
                        KMessageBox::error(this, i18n("Could not delete:\n%1", files.first()));
 
212
                    else
 
213
                        KMessageBox::errorList(this, i18n("Could not delete the following files:"), files);
 
214
                    break;
 
215
                }
 
216
                default:
 
217
                case STATUS_USER_CANCELLED:
 
218
                    break;
 
219
            }
 
220
            break;
 
221
        }
 
222
        case KDialog::Cancel:
 
223
            if(!itsFontFileList->wasTerminated())
 
224
            {
 
225
                if(itsFontFileList->isRunning())
 
226
                {
 
227
                    if(KMessageBox::Yes==KMessageBox::warningYesNo(this, i18n("Abort font scan?")))
 
228
                    {
 
229
                        itsLabel->setText("Aborting...");
 
230
 
 
231
                        if(itsFontFileList->isRunning())
 
232
                            itsFontFileList->terminate();
 
233
                        else
 
234
                            reject();
 
235
                    }
 
236
                }
 
237
                else
 
238
                    reject();
 
239
            }
 
240
            break;
 
241
        default:
 
242
            break;
 
243
    }
 
244
}
 
245
 
 
246
int CDuplicatesDialog::deleteFiles()
 
247
{
 
248
    QSet<QString> files(itsView->getMarkedFiles());
 
249
 
 
250
    if(!files.count())
 
251
        return STATUS_NO_FILES;
 
252
 
 
253
    if(1==files.count()
 
254
       ? KMessageBox::Yes==KMessageBox::warningYesNo(this,
 
255
                           i18n("Are you sure you wish to delete:\n%1", files.toList().first()))
 
256
       : KMessageBox::Yes==KMessageBox::warningYesNoList(this,
 
257
                           i18n("Are you sure you wish to delete:"), files.toList()))
 
258
    {
 
259
        QSet<QString> removed;
 
260
 
 
261
        if(!Misc::root())
 
262
        {
 
263
            QSet<QString>                sys,
 
264
                                         user;
 
265
            QSet<QString>::ConstIterator it(files.begin()),
 
266
                                         end(files.end());
 
267
            QString                      home(Misc::dirSyntax(QDir::homePath()));
 
268
 
 
269
            for(; it!=end; ++it)
 
270
                if(Misc::root() || 0==(*it).indexOf(home))
 
271
                    user.insert(*it);
 
272
                else
 
273
                    sys.insert(*it);
 
274
 
 
275
            if(user.count())
 
276
                removed=deleteFiles(user);
 
277
            if(sys.count() && itsRunner->getAdminPasswd(this))
 
278
            {
 
279
                static const int constSysDelFiles=16; // Number of files to rm -f in one go...
 
280
 
 
281
                QSet<QString>::ConstIterator it(files.begin()),
 
282
                                             end(files.end());
 
283
                QStringList                  delFiles;
 
284
 
 
285
                for(; it!=end; ++it)
 
286
                {
 
287
                    delFiles.append(*it);
 
288
 
 
289
                    if(constSysDelFiles==delFiles.size())
 
290
                    {
 
291
                        removed+=deleteSysFiles(delFiles);
 
292
                        delFiles.clear();
 
293
                    }
 
294
                }
 
295
 
 
296
                if(delFiles.count())
 
297
                    removed+=deleteSysFiles(delFiles);
 
298
            }
 
299
        }
 
300
        else
 
301
            removed=deleteFiles(files);
 
302
 
 
303
        itsView->removeFiles(removed);
 
304
        return 0==itsView->getMarkedFiles().count() ? STATUS_ALL_REMOVED : STATUS_ERROR;
 
305
    }
 
306
    return STATUS_USER_CANCELLED;
 
307
}
 
308
 
 
309
QSet<QString> CDuplicatesDialog::deleteFiles(const QSet<QString> &files)
 
310
{
 
311
    QSet<QString>                removed;
 
312
    QSet<QString>::ConstIterator it(files.begin()),
 
313
                                 end(files.end());
 
314
 
 
315
    for(; it!=end; ++it)
 
316
        if(0==::unlink(QFile::encodeName(*it).data()) || !Misc::fExists(*it))
 
317
            removed.insert(*it);
 
318
 
 
319
    if(removed.count())
 
320
        itsModifiedUser=true;
 
321
 
 
322
    return removed;
 
323
}
 
324
 
 
325
QSet<QString> CDuplicatesDialog::deleteSysFiles(const QStringList &files)
 
326
{
 
327
    QSet<QString> removed;
 
328
 
 
329
    if(files.count())
 
330
    {
 
331
        QByteArray cmd("rm -f");
 
332
        QStringList::ConstIterator it(files.begin()),
 
333
                                   end(files.end());
 
334
 
 
335
        for(; it!=end; ++it)
 
336
        {
 
337
            cmd+=' ';
 
338
            cmd+=QFile::encodeName(KShell::quoteArg(*it));
 
339
        }
 
340
 
 
341
        SuProcess proc(KFI_SYS_USER);
 
342
 
 
343
        proc.setCommand(cmd);
 
344
        proc.exec(itsRunner->adminPasswd().toLocal8Bit());
 
345
 
 
346
        for(it=files.begin(); it!=end; ++it)
 
347
            if(!Misc::fExists(*it))
 
348
                removed.insert(*it);
 
349
    }
 
350
 
 
351
    if(removed.count())
 
352
        itsModifiedSys=true;
 
353
    return removed;
 
354
}
 
355
 
 
356
static uint qHash(const CFontFileList::TFile &key)
 
357
{
 
358
    return qHash(key.name.toLower());
 
359
}
 
360
 
 
361
CFontFileList::CFontFileList(CDuplicatesDialog *parent)
 
362
             : QThread(parent),
 
363
               itsTerminated(false)
 
364
{
 
365
}
 
366
 
 
367
void CFontFileList::start()
 
368
{
 
369
    if(!isRunning())
 
370
    {
 
371
        itsTerminated=false;
 
372
        QThread::start();
 
373
    }
 
374
}
 
375
 
 
376
void CFontFileList::terminate()
 
377
{
 
378
    itsTerminated=true;
 
379
}
 
380
 
 
381
void CFontFileList::getDuplicateFonts(TFontMap &map)
 
382
{
 
383
    map=itsMap;
 
384
 
 
385
    if(map.count())
 
386
    {
 
387
        TFontMap::Iterator it(map.begin()),
 
388
                           end(map.end());
 
389
 
 
390
        // Now re-iterate, and remove any entries that only have 1 file...
 
391
        for(it=map.begin(); it!=end; )
 
392
            if((*it).count()<2)
 
393
                it=map.erase(it);
 
394
            else
 
395
                ++it;
 
396
    }
 
397
}
 
398
 
 
399
void CFontFileList::run()
 
400
{
 
401
    const QList<CFamilyItem *>          &families(((CDuplicatesDialog *)parent())->fontList()->families());
 
402
    QList<CFamilyItem *>::ConstIterator it(families.begin()),
 
403
                                        end(families.end());
 
404
 
 
405
    for(; it!=end; ++it)
 
406
    {
 
407
        QList<CFontItem *>::ConstIterator fontIt((*it)->fonts().begin()),
 
408
                                          fontEnd((*it)->fonts().end());
 
409
 
 
410
        for(; fontIt!=fontEnd; ++fontIt)
 
411
            if(!(*fontIt)->isBitmap())
 
412
            {
 
413
                Misc::TFont                              font((*fontIt)->family(), (*fontIt)->styleInfo());
 
414
                CDisabledFonts::TFileList::ConstIterator fileIt((*fontIt)->files().begin()),
 
415
                                                         fileEnd((*fontIt)->files().end());
 
416
 
 
417
                for(; fileIt!=fileEnd; ++fileIt)
 
418
                    if(!Misc::isMetrics(*fileIt))
 
419
                        itsMap[font].append(*fileIt);
 
420
            }
 
421
    }
 
422
 
 
423
    // if we have 2 fonts: /wibble/a.ttf and /wibble/a.TTF fontconfig only returns the 1st, so we
 
424
    // now iterate over fontconfig's list, and look for other matching fonts...
 
425
    if(itsMap.count() && !itsTerminated)
 
426
    {
 
427
        // Create a map of folder -> set<files>
 
428
        TFontMap::Iterator           it(itsMap.begin()),
 
429
                                     end(itsMap.end());
 
430
        QHash<QString, QSet<TFile> > folderMap;
 
431
 
 
432
        for(int n=0; it!=end && !itsTerminated; ++it)
 
433
        {
 
434
            QStringList           add;
 
435
            QStringList::Iterator fIt((*it).begin()),
 
436
                                  fEnd((*it).end());
 
437
 
 
438
            for(; fIt!=fEnd && !itsTerminated; ++fIt, ++n)
 
439
                folderMap[Misc::getDir(*fIt)].insert(TFile(Misc::getFile(*fIt), it));
 
440
        }
 
441
 
 
442
        // Go through our folder map, and check for file duplicates...
 
443
        QHash<QString, QSet<TFile> >::Iterator folderIt(folderMap.begin()),
 
444
                                               folderEnd(folderMap.end());
 
445
 
 
446
        for(; folderIt!=folderEnd && !itsTerminated; ++folderIt)
 
447
            fileDuplicates(folderIt.key(), *folderIt);
 
448
    }
 
449
 
 
450
    emit finished();
 
451
}
 
452
 
 
453
void CFontFileList::fileDuplicates(const QString &folder, const QSet<TFile> &files)
 
454
{
 
455
    QDir                       dir(folder);
 
456
    QStringList                nameFilters;
 
457
    QSet<TFile>::ConstIterator it(files.begin()),
 
458
                               end(files.end());
 
459
 
 
460
    // Filter the QDir to look for filenames matching (caselessly) to those in
 
461
    // files...
 
462
    for(; it!=end; ++it)
 
463
        nameFilters.append((*it).name);
 
464
 
 
465
    dir.setFilter(QDir::Files|QDir::Hidden);
 
466
    dir.setNameFilters(nameFilters);
 
467
 
 
468
    QFileInfoList list(dir.entryInfoList());
 
469
 
 
470
    for (int i = 0; i < list.size() && !itsTerminated; ++i)
 
471
    {
 
472
        QFileInfo fileInfo(list.at(i));
 
473
 
 
474
        // Check if this file is already know about - this will do a case-sensitive comparison
 
475
        if(!files.contains(TFile(fileInfo.fileName())))
 
476
        {
 
477
            // OK, not found - this means its a duplicate, but different case. So, find the
 
478
            // FontMap iterator, and update its list of files.
 
479
            QSet<TFile>::ConstIterator entry=files.find(TFile(fileInfo.fileName(), true));
 
480
 
 
481
            if(entry!=files.end())
 
482
                (*((*entry).it)).append(fileInfo.absoluteFilePath());
 
483
        }
 
484
    }
 
485
}
 
486
 
 
487
inline void markItem(QTreeWidgetItem *item)
 
488
{
 
489
    item->setData(COL_TRASH, Qt::DecorationRole, QVariant(SmallIcon("list-remove")));
 
490
}
 
491
 
 
492
inline void unmarkItem(QTreeWidgetItem *item)
 
493
{
 
494
    item->setData(COL_TRASH, Qt::DecorationRole, QVariant());
 
495
}
 
496
 
 
497
inline bool isMarked(QTreeWidgetItem *item)
 
498
{
 
499
    return item->data(COL_TRASH, Qt::DecorationRole).isValid();
 
500
}
 
501
 
 
502
CFontFileListView::CFontFileListView(QWidget *parent)
 
503
                 : QTreeWidget(parent)
 
504
{
 
505
    QStringList headers;
 
506
    headers.append(i18n("Font/File"));
 
507
    headers.append("");
 
508
    headers.append(i18n("Size"));
 
509
    headers.append(i18n("Date"));
 
510
    headers.append(i18n("Links To"));
 
511
    setHeaderLabels(headers);
 
512
    headerItem()->setData(COL_TRASH, Qt::DecorationRole, QVariant(SmallIcon("edit-trash")));
 
513
    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
 
514
    setSelectionMode(ExtendedSelection);
 
515
    sortByColumn(COL_FILE, Qt::AscendingOrder);
 
516
    setSelectionBehavior(SelectRows);
 
517
    setSortingEnabled(true);
 
518
    setAllColumnsShowFocus(true);
 
519
    setAlternatingRowColors(true);
 
520
 
 
521
    itsMenu=new QMenu(this);
 
522
    itsMenu->addAction(KIcon("kfontview"), i18n("Open in Font Viewer..."),
 
523
                       this, SLOT(openViewer()));
 
524
    itsMenu->addAction(KIcon("document-properties"), i18n("Properties..."),
 
525
                       this, SLOT(properties()));
 
526
    itsMenu->addSeparator();
 
527
    itsUnMarkAct=itsMenu->addAction(i18n("Unmark for deletion..."),
 
528
                                    this, SLOT(unmark()));
 
529
    itsMarkAct=itsMenu->addAction(KIcon("edit-delete"), i18n("Mark for deletion..."),
 
530
                                  this, SLOT(mark()));
 
531
 
 
532
    connect(this, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged()));
 
533
    connect(this, SIGNAL(itemClicked(QTreeWidgetItem *, int)), SLOT(clicked(QTreeWidgetItem *, int)));
 
534
}
 
535
 
 
536
QSet<QString> CFontFileListView::getMarkedFiles()
 
537
{
 
538
    QTreeWidgetItem *root=invisibleRootItem();
 
539
    QSet<QString>   files;
 
540
 
 
541
    for(int t=0; t<root->childCount(); ++t)
 
542
    {
 
543
        QList<QTreeWidgetItem *> removeFiles;
 
544
        QTreeWidgetItem          *font=root->child(t);
 
545
 
 
546
        for(int c=0; c<font->childCount(); ++c)
 
547
        {
 
548
            QTreeWidgetItem *file=font->child(c);
 
549
 
 
550
            if(isMarked(file))
 
551
                files.insert(file->text(0));
 
552
        }
 
553
    }
 
554
 
 
555
    return files;
 
556
}
 
557
 
 
558
void CFontFileListView::removeFiles(const QSet<QString> &files)
 
559
{
 
560
    QTreeWidgetItem          *root=invisibleRootItem();
 
561
    QList<QTreeWidgetItem *> removeFonts;
 
562
 
 
563
    for(int t=0; t<root->childCount(); ++t)
 
564
    {
 
565
        QList<QTreeWidgetItem *> removeFiles;
 
566
        QTreeWidgetItem          *font=root->child(t);
 
567
 
 
568
        for(int c=0; c<font->childCount(); ++c)
 
569
        {
 
570
            QTreeWidgetItem *file=font->child(c);
 
571
 
 
572
            if(files.contains(file->text(0)))
 
573
                removeFiles.append(file);
 
574
        }
 
575
 
 
576
        QList<QTreeWidgetItem *>::ConstIterator it(removeFiles.begin()),
 
577
                                                end(removeFiles.end());
 
578
 
 
579
        for(; it!=end; ++it)
 
580
            delete (*it);
 
581
        if(0==font->childCount())
 
582
            removeFonts.append(font);
 
583
    }
 
584
 
 
585
    QList<QTreeWidgetItem *>::ConstIterator it(removeFonts.begin()),
 
586
                                            end(removeFonts.end());
 
587
    for(; it!=end; ++it)
 
588
        delete (*it);
 
589
}
 
590
 
 
591
void CFontFileListView::openViewer()
 
592
{
 
593
    // Number of fonts user has selected, before we ask if they really want to view them all...
 
594
    static const int constMaxBeforePrompt=10;
 
595
 
 
596
    QList<QTreeWidgetItem *> items(selectedItems());
 
597
    QTreeWidgetItem          *item;
 
598
    QSet<QString>            files;
 
599
 
 
600
    foreach(item, items)
 
601
        if(item->parent()) // Then its a file, not font name :-)
 
602
            files.insert(item->text(0));
 
603
 
 
604
    if(files.count() &&
 
605
       (files.count()<constMaxBeforePrompt ||
 
606
        KMessageBox::Yes==KMessageBox::questionYesNo(this, i18n("Open all %1 fonts in font viewer?", files.count()))))
 
607
    {
 
608
         QSet<QString>::ConstIterator it(files.begin()),
 
609
                                      end(files.end());
 
610
 
 
611
        for(; it!=end; ++it)
 
612
        {
 
613
            QStringList args;
 
614
 
 
615
            args << (*it);
 
616
 
 
617
            QProcess::startDetached(KFI_VIEWER, args);
 
618
        }
 
619
    }
 
620
}
 
621
 
 
622
void CFontFileListView::properties()
 
623
{
 
624
    QList<QTreeWidgetItem *> items(selectedItems());
 
625
    QTreeWidgetItem          *item;
 
626
    KFileItemList            files;
 
627
 
 
628
    foreach(item, items)
 
629
        if(item->parent())
 
630
            files.append(new KFileItem(KUrl::fromPath(item->text(0)),
 
631
                                       KMimeType::findByPath(item->text(0))->name(),
 
632
                                       item->text(COL_LINK).isEmpty() ? S_IFREG : S_IFLNK));
 
633
 
 
634
    if(files.count())
 
635
    {
 
636
        KPropertiesDialog dlg(files, this);
 
637
        dlg.exec();
 
638
 
 
639
        KFileItemList::ConstIterator it(files.begin()),
 
640
                                     end(files.end());
 
641
 
 
642
        for(; it!=end; ++it)
 
643
            delete (*it);
 
644
    }
 
645
}
 
646
 
 
647
void CFontFileListView::mark()
 
648
{
 
649
    QList<QTreeWidgetItem *> items(selectedItems());
 
650
    QTreeWidgetItem          *item;
 
651
 
 
652
    foreach(item, items)
 
653
        if(item->parent())
 
654
            markItem(item);
 
655
    checkFiles();
 
656
}
 
657
 
 
658
void CFontFileListView::unmark()
 
659
{
 
660
    QList<QTreeWidgetItem *> items(selectedItems());
 
661
    QTreeWidgetItem          *item;
 
662
 
 
663
    foreach(item, items)
 
664
        if(item->parent())
 
665
            unmarkItem(item);
 
666
    checkFiles();
 
667
}
 
668
 
 
669
void CFontFileListView::selectionChanged()
 
670
{
 
671
    QList<QTreeWidgetItem *> items(selectedItems());
 
672
    QTreeWidgetItem          *item;
 
673
 
 
674
    foreach(item, items)
 
675
        if(!item->parent() && item->isSelected())
 
676
            item->setSelected(false);
 
677
}
 
678
 
 
679
void CFontFileListView::clicked(QTreeWidgetItem *item, int col)
 
680
{
 
681
    if(item && COL_TRASH==col && item->parent())
 
682
    {
 
683
        if(isMarked(item))
 
684
            unmarkItem(item);
 
685
        else
 
686
            markItem(item);
 
687
        checkFiles();
 
688
    }
 
689
}
 
690
 
 
691
void CFontFileListView::contextMenuEvent(QContextMenuEvent *ev)
 
692
{
 
693
    QTreeWidgetItem *item(itemAt(ev->pos()));
 
694
 
 
695
    if(item && item->parent())
 
696
    {
 
697
        if(!item->isSelected())
 
698
            item->setSelected(true);
 
699
 
 
700
        bool haveUnmarked(false),
 
701
             haveMaked(false);
 
702
 
 
703
        QList<QTreeWidgetItem *> items(selectedItems());
 
704
        QTreeWidgetItem          *item;
 
705
 
 
706
        foreach(item, items)
 
707
        {
 
708
            if(item->parent() && item->isSelected())
 
709
                if(isMarked(item))
 
710
                    haveMaked=true;
 
711
                else
 
712
                    haveUnmarked=true;
 
713
 
 
714
            if(haveUnmarked && haveMaked)
 
715
                break;
 
716
        }
 
717
 
 
718
        itsMarkAct->setEnabled(haveUnmarked);
 
719
        itsUnMarkAct->setEnabled(haveMaked);
 
720
        itsMenu->popup(ev->globalPos());
 
721
    }
 
722
}
 
723
 
 
724
void CFontFileListView::checkFiles()
 
725
{
 
726
    // Need to check that if we mark a file that is linked to, then we also need
 
727
    // to mark the sym link.
 
728
    QSet<QString> marked(getMarkedFiles());
 
729
 
 
730
    if(marked.count())
 
731
    {
 
732
        QTreeWidgetItem *root=invisibleRootItem();
 
733
 
 
734
        for(int t=0; t<root->childCount(); ++t)
 
735
        {
 
736
            QTreeWidgetItem *font=root->child(t);
 
737
 
 
738
            for(int c=0; c<font->childCount(); ++c)
 
739
            {
 
740
                QTreeWidgetItem *file=font->child(c);
 
741
                QString         link(font->child(c)->text(COL_LINK));
 
742
 
 
743
                if(!link.isEmpty() && marked.contains(link))
 
744
                    if(!isMarked(file))
 
745
                        markItem(file);
 
746
            }
 
747
        }
 
748
 
 
749
        emit haveDeletions(true);
 
750
    }
 
751
    else
 
752
        emit haveDeletions(false);
 
753
}
 
754
 
 
755
}
 
756
 
 
757
#include "DuplicatesDialog.moc"