mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-24 19:02:51 +00:00
673 lines
20 KiB
C++
673 lines
20 KiB
C++
/*
|
|
* KFontInst - KDE Font Installer
|
|
*
|
|
* Copyright 2003-2007 Craig Drummond <craig@kde.org>
|
|
*
|
|
* ----
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "DuplicatesDialog.h"
|
|
#include "ActionLabel.h"
|
|
#include "Misc.h"
|
|
#include "Fc.h"
|
|
#include "FcEngine.h"
|
|
#include "FontList.h"
|
|
#include "JobRunner.h"
|
|
#include <KGlobal>
|
|
#include <KIconLoader>
|
|
#include <KLocale>
|
|
#include <KMessageBox>
|
|
#include <KFileItem>
|
|
#include <KPropertiesDialog>
|
|
#include <KShell>
|
|
#include <KStandardDirs>
|
|
#include <QtGui/QLabel>
|
|
#include <QtCore/QTimer>
|
|
#include <QtGui/QGridLayout>
|
|
#include <QtCore/QDir>
|
|
#include <QtCore/qfileinfo.h>
|
|
#include <QtCore/QFileInfo>
|
|
#include <QtGui/QHeaderView>
|
|
#include <QtCore/QDateTime>
|
|
#include <QtGui/QMenu>
|
|
#include <QtGui/qevent.h>
|
|
#include <QtGui/QAction>
|
|
#include <QtGui/QApplication>
|
|
#include <QtGui/QDesktopWidget>
|
|
#include <QtCore/QProcess>
|
|
|
|
namespace KFI
|
|
{
|
|
|
|
enum EDialogColumns
|
|
{
|
|
COL_FILE,
|
|
COL_TRASH,
|
|
COL_SIZE,
|
|
COL_DATE,
|
|
COL_LINK
|
|
};
|
|
|
|
CDuplicatesDialog::CDuplicatesDialog(QWidget *parent, CFontList *fl)
|
|
: KDialog(parent),
|
|
itsFontList(fl)
|
|
{
|
|
setCaption(i18n("Duplicate Fonts"));
|
|
setButtons(Cancel);
|
|
setModal(true);
|
|
|
|
QFrame *page = new QFrame(this);
|
|
setMainWidget(page);
|
|
|
|
QGridLayout *layout=new QGridLayout(page);
|
|
layout->setMargin(0);
|
|
layout->setSpacing(KDialog::spacingHint());
|
|
itsLabel=new QLabel(page);
|
|
itsView=new CFontFileListView(page);
|
|
itsView->hide();
|
|
layout->addWidget(itsActionLabel = new CActionLabel(this), 0, 0);
|
|
layout->addWidget(itsLabel, 0, 1);
|
|
itsLabel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
|
|
layout->addWidget(itsView, 1, 0, 1, 2);
|
|
itsFontFileList=new CFontFileList(this);
|
|
connect(itsFontFileList, SIGNAL(finished()), SLOT(scanFinished()));
|
|
connect(itsView, SIGNAL(haveDeletions(bool)), SLOT(enableButtonOk(bool)));
|
|
}
|
|
|
|
int CDuplicatesDialog::exec()
|
|
{
|
|
itsActionLabel->startAnimation();
|
|
itsLabel->setText(i18n("Scanning for duplicate fonts. Please wait..."));
|
|
itsFontFileList->start();
|
|
return KDialog::exec();
|
|
}
|
|
|
|
void CDuplicatesDialog::scanFinished()
|
|
{
|
|
itsActionLabel->stopAnimation();
|
|
|
|
if(itsFontFileList->wasTerminated())
|
|
{
|
|
itsFontFileList->wait();
|
|
reject();
|
|
}
|
|
else
|
|
{
|
|
CFontFileList::TFontMap duplicates;
|
|
|
|
itsFontFileList->getDuplicateFonts(duplicates);
|
|
|
|
if(0==duplicates.count())
|
|
{
|
|
setButtons(Close);
|
|
itsLabel->setText(i18n("No duplicate fonts found."));
|
|
}
|
|
else
|
|
{
|
|
QSize sizeB4(size());
|
|
|
|
setButtons(Ok|Close);
|
|
setButtonText(Ok, i18n("Delete Marked Files"));
|
|
enableButtonOk(false);
|
|
itsLabel->setText(i18np("%1 duplicate font found.", "%1 duplicate fonts found.", duplicates.count()));
|
|
itsView->show();
|
|
|
|
CFontFileList::TFontMap::ConstIterator it(duplicates.begin()),
|
|
end(duplicates.end());
|
|
QFont boldFont(font());
|
|
|
|
boldFont.setBold(true);
|
|
|
|
for(; it!=end; ++it)
|
|
{
|
|
QStringList details;
|
|
|
|
details << FC::createName(it.key().family, it.key().styleInfo);
|
|
|
|
CFontFileListView::StyleItem *top=new CFontFileListView::StyleItem(itsView, details,
|
|
it.key().family, it.key().styleInfo);
|
|
|
|
QSet<QString>::ConstIterator fit((*it).begin()),
|
|
fend((*it).end());
|
|
int tt(0),
|
|
t1(0);
|
|
|
|
for(; fit!=fend; ++fit)
|
|
{
|
|
QFileInfo info(*fit);
|
|
details.clear();
|
|
details.append(*fit);
|
|
details.append("");
|
|
details.append(KGlobal::locale()->formatByteSize(info.size()));
|
|
details.append(KGlobal::locale()->formatDateTime(info.created()));
|
|
if(info.isSymLink())
|
|
details.append(info.readLink());
|
|
new QTreeWidgetItem(top, details);
|
|
if(Misc::checkExt(*fit, "pfa") || Misc::checkExt(*fit, "pfb"))
|
|
t1++;
|
|
else
|
|
tt++;
|
|
}
|
|
top->setData(COL_FILE, Qt::DecorationRole,
|
|
QVariant(SmallIcon(t1>tt ? "application-x-font-type1" : "application-x-font-ttf")));
|
|
top->setFont(COL_FILE, boldFont);
|
|
}
|
|
|
|
QTreeWidgetItem *item=0L;
|
|
for(int i=0; (item=itsView->topLevelItem(i)); ++i)
|
|
item->setExpanded(true);
|
|
|
|
itsView->setSortingEnabled(true);
|
|
itsView->header()->resizeSections(QHeaderView::ResizeToContents);
|
|
|
|
int width=(KDialog::marginHint()+itsView->frameWidth()+8)*2;
|
|
|
|
for(int i=0; i<itsView->header()->count(); ++i)
|
|
width+=itsView->header()->sectionSize(i);
|
|
|
|
width=qMin(QApplication::desktop()->screenGeometry(this).width(), width);
|
|
resize(width, height());
|
|
QSize sizeNow(size());
|
|
if(sizeNow.width()>sizeB4.width())
|
|
{
|
|
int xmod=(sizeNow.width()-sizeB4.width())/2,
|
|
ymod=(sizeNow.height()-sizeB4.height())/2;
|
|
|
|
move(pos().x()-xmod, pos().y()-ymod);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
enum EStatus
|
|
{
|
|
STATUS_NO_FILES,
|
|
STATUS_ALL_REMOVED,
|
|
STATUS_ERROR,
|
|
STATUS_USER_CANCELLED
|
|
};
|
|
|
|
void CDuplicatesDialog::slotButtonClicked(int button)
|
|
{
|
|
switch(button)
|
|
{
|
|
case KDialog::Ok:
|
|
{
|
|
QSet<QString> files=itsView->getMarkedFiles();
|
|
int fCount=files.count();
|
|
|
|
if(1==fCount
|
|
? KMessageBox::Yes==KMessageBox::warningYesNo(this,
|
|
i18n("Are you sure you wish to delete:\n%1", files.toList().first()))
|
|
: KMessageBox::Yes==KMessageBox::warningYesNoList(this,
|
|
i18n("Are you sure you wish to delete:"), files.toList()))
|
|
{
|
|
itsFontList->setSlowUpdates(true);
|
|
|
|
CJobRunner runner(this);
|
|
|
|
connect(&runner, SIGNAL(configuring()), itsFontList, SLOT(unsetSlowUpdates()));
|
|
runner.exec(CJobRunner::CMD_REMOVE_FILE, itsView->getMarkedItems(), false);
|
|
itsFontList->setSlowUpdates(false);
|
|
itsView->removeFiles();
|
|
files=itsView->getMarkedFiles();
|
|
if(fCount!=files.count())
|
|
CFcEngine::setDirty();
|
|
if(0==files.count())
|
|
accept();
|
|
}
|
|
break;
|
|
}
|
|
case KDialog::Cancel:
|
|
case KDialog::Close:
|
|
if(!itsFontFileList->wasTerminated())
|
|
{
|
|
if(itsFontFileList->isRunning())
|
|
{
|
|
if(KMessageBox::Yes==KMessageBox::warningYesNo(this, i18n("Cancel font scan?")))
|
|
{
|
|
itsLabel->setText(i18n("Canceling..."));
|
|
|
|
if(itsFontFileList->isRunning())
|
|
itsFontFileList->terminate();
|
|
else
|
|
reject();
|
|
}
|
|
}
|
|
else
|
|
reject();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static uint qHash(const CFontFileList::TFile &key)
|
|
{
|
|
return qHash(key.name.toLower());
|
|
}
|
|
|
|
CFontFileList::CFontFileList(CDuplicatesDialog *parent)
|
|
: QThread(parent),
|
|
itsTerminated(false)
|
|
{
|
|
}
|
|
|
|
void CFontFileList::start()
|
|
{
|
|
if(!isRunning())
|
|
{
|
|
itsTerminated=false;
|
|
QThread::start();
|
|
}
|
|
}
|
|
|
|
void CFontFileList::terminate()
|
|
{
|
|
itsTerminated=true;
|
|
}
|
|
|
|
void CFontFileList::getDuplicateFonts(TFontMap &map)
|
|
{
|
|
map=itsMap;
|
|
|
|
if(map.count())
|
|
{
|
|
TFontMap::Iterator it(map.begin()),
|
|
end(map.end());
|
|
|
|
// Now re-iterate, and remove any entries that only have 1 file...
|
|
for(it=map.begin(); it!=end; )
|
|
if((*it).count()<2)
|
|
it=map.erase(it);
|
|
else
|
|
++it;
|
|
}
|
|
}
|
|
|
|
void CFontFileList::run()
|
|
{
|
|
const QList<CFamilyItem *> &families(((CDuplicatesDialog *)parent())->fontList()->families());
|
|
QList<CFamilyItem *>::ConstIterator it(families.begin()),
|
|
end(families.end());
|
|
|
|
for(; it!=end; ++it)
|
|
{
|
|
QList<CFontItem *>::ConstIterator fontIt((*it)->fonts().begin()),
|
|
fontEnd((*it)->fonts().end());
|
|
|
|
for(; fontIt!=fontEnd; ++fontIt)
|
|
if(!(*fontIt)->isBitmap())
|
|
{
|
|
Misc::TFont font((*fontIt)->family(), (*fontIt)->styleInfo());
|
|
FileCont::ConstIterator fileIt((*fontIt)->files().begin()),
|
|
fileEnd((*fontIt)->files().end());
|
|
|
|
for(; fileIt!=fileEnd; ++fileIt)
|
|
if(!Misc::isMetrics((*fileIt).path()) && !Misc::isBitmap((*fileIt).path()))
|
|
itsMap[font].insert((*fileIt).path());
|
|
}
|
|
}
|
|
|
|
// if we have 2 fonts: /wibble/a.ttf and /wibble/a.TTF fontconfig only returns the 1st, so we
|
|
// now iterate over fontconfig's list, and look for other matching fonts...
|
|
if(itsMap.count() && !itsTerminated)
|
|
{
|
|
// Create a map of folder -> set<files>
|
|
TFontMap::Iterator it(itsMap.begin()),
|
|
end(itsMap.end());
|
|
QHash<QString, QSet<TFile> > folderMap;
|
|
|
|
for(int n=0; it!=end && !itsTerminated; ++it)
|
|
{
|
|
QStringList add;
|
|
QSet<QString>::const_iterator fIt((*it).begin()),
|
|
fEnd((*it).end());
|
|
|
|
for(; fIt!=fEnd && !itsTerminated; ++fIt, ++n)
|
|
folderMap[Misc::getDir(*fIt)].insert(TFile(Misc::getFile(*fIt), it));
|
|
}
|
|
|
|
// Go through our folder map, and check for file duplicates...
|
|
QHash<QString, QSet<TFile> >::Iterator folderIt(folderMap.begin()),
|
|
folderEnd(folderMap.end());
|
|
|
|
for(; folderIt!=folderEnd && !itsTerminated; ++folderIt)
|
|
fileDuplicates(folderIt.key(), *folderIt);
|
|
}
|
|
|
|
emit finished();
|
|
}
|
|
|
|
void CFontFileList::fileDuplicates(const QString &folder, const QSet<TFile> &files)
|
|
{
|
|
QDir dir(folder);
|
|
|
|
dir.setFilter(QDir::Files|QDir::Hidden);
|
|
|
|
QFileInfoList list(dir.entryInfoList());
|
|
|
|
for (int i = 0; i < list.size() && !itsTerminated; ++i)
|
|
{
|
|
QFileInfo fileInfo(list.at(i));
|
|
|
|
// Check if this file is already know about - this will do a case-sensitive comparison
|
|
if(!files.contains(TFile(fileInfo.fileName())))
|
|
{
|
|
// OK, not found - this means it is a duplicate, but different case. So, find the
|
|
// FontMap iterator, and update its list of files.
|
|
QSet<TFile>::ConstIterator entry=files.find(TFile(fileInfo.fileName(), true));
|
|
|
|
if(entry!=files.end())
|
|
(*((*entry).it)).insert(fileInfo.absoluteFilePath());
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void markItem(QTreeWidgetItem *item)
|
|
{
|
|
item->setData(COL_TRASH, Qt::DecorationRole, QVariant(SmallIcon("list-remove")));
|
|
}
|
|
|
|
inline void unmarkItem(QTreeWidgetItem *item)
|
|
{
|
|
item->setData(COL_TRASH, Qt::DecorationRole, QVariant());
|
|
}
|
|
|
|
inline bool isMarked(QTreeWidgetItem *item)
|
|
{
|
|
return item->data(COL_TRASH, Qt::DecorationRole).isValid();
|
|
}
|
|
|
|
CFontFileListView::CFontFileListView(QWidget *parent)
|
|
: QTreeWidget(parent)
|
|
{
|
|
QStringList headers;
|
|
headers.append(i18n("Font/File"));
|
|
headers.append("");
|
|
headers.append(i18n("Size"));
|
|
headers.append(i18n("Date"));
|
|
headers.append(i18n("Links To"));
|
|
setHeaderLabels(headers);
|
|
headerItem()->setData(COL_TRASH, Qt::DecorationRole, QVariant(SmallIcon("user-trash")));
|
|
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
|
setSelectionMode(ExtendedSelection);
|
|
sortByColumn(COL_FILE, Qt::AscendingOrder);
|
|
setSelectionBehavior(SelectRows);
|
|
setSortingEnabled(true);
|
|
setAllColumnsShowFocus(true);
|
|
setAlternatingRowColors(true);
|
|
|
|
itsMenu=new QMenu(this);
|
|
if(!Misc::app(KFI_VIEWER).isEmpty())
|
|
itsMenu->addAction(KIcon("kfontview"), i18n("Open in Font Viewer"),
|
|
this, SLOT(openViewer()));
|
|
itsMenu->addAction(KIcon("document-properties"), i18n("Properties"),
|
|
this, SLOT(properties()));
|
|
itsMenu->addSeparator();
|
|
itsUnMarkAct=itsMenu->addAction(i18n("Unmark for Deletion"),
|
|
this, SLOT(unmark()));
|
|
itsMarkAct=itsMenu->addAction(KIcon("edit-delete"), i18n("Mark for Deletion"),
|
|
this, SLOT(mark()));
|
|
|
|
connect(this, SIGNAL(itemSelectionChanged()), SLOT(selectedChanged()));
|
|
connect(this, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SLOT(clicked(QTreeWidgetItem*,int)));
|
|
}
|
|
|
|
QSet<QString> CFontFileListView::getMarkedFiles()
|
|
{
|
|
QTreeWidgetItem *root=invisibleRootItem();
|
|
QSet<QString> files;
|
|
|
|
for(int t=0; t<root->childCount(); ++t)
|
|
{
|
|
QList<QTreeWidgetItem *> removeFiles;
|
|
QTreeWidgetItem *font=root->child(t);
|
|
|
|
for(int c=0; c<font->childCount(); ++c)
|
|
{
|
|
QTreeWidgetItem *file=font->child(c);
|
|
|
|
if(isMarked(file))
|
|
files.insert(file->text(0));
|
|
}
|
|
}
|
|
|
|
return files;
|
|
}
|
|
|
|
CJobRunner::ItemList CFontFileListView::getMarkedItems()
|
|
{
|
|
QTreeWidgetItem *root=invisibleRootItem();
|
|
CJobRunner::ItemList items;
|
|
QString home(Misc::dirSyntax(QDir::homePath()));
|
|
|
|
for(int t=0; t<root->childCount(); ++t)
|
|
{
|
|
QList<QTreeWidgetItem *> removeFiles;
|
|
StyleItem *style=(StyleItem *)root->child(t);
|
|
|
|
for(int c=0; c<style->childCount(); ++c)
|
|
{
|
|
QTreeWidgetItem *file=style->child(c);
|
|
|
|
if(isMarked(file))
|
|
items.append(CJobRunner::Item(file->text(0), style->family(), style->value(), 0!=file->text(0).indexOf(home)));
|
|
}
|
|
}
|
|
|
|
return items;
|
|
}
|
|
|
|
void CFontFileListView::removeFiles()
|
|
{
|
|
QTreeWidgetItem *root=invisibleRootItem();
|
|
QList<QTreeWidgetItem *> removeFonts;
|
|
|
|
for(int t=0; t<root->childCount(); ++t)
|
|
{
|
|
QList<QTreeWidgetItem *> removeFiles;
|
|
QTreeWidgetItem *font=root->child(t);
|
|
|
|
for(int c=0; c<font->childCount(); ++c)
|
|
{
|
|
QTreeWidgetItem *file=font->child(c);
|
|
|
|
if(!Misc::fExists(file->text(0)))
|
|
removeFiles.append(file);
|
|
}
|
|
|
|
QList<QTreeWidgetItem *>::ConstIterator it(removeFiles.begin()),
|
|
end(removeFiles.end());
|
|
|
|
for(; it!=end; ++it)
|
|
delete (*it);
|
|
if(0==font->childCount())
|
|
removeFonts.append(font);
|
|
}
|
|
|
|
QList<QTreeWidgetItem *>::ConstIterator it(removeFonts.begin()),
|
|
end(removeFonts.end());
|
|
for(; it!=end; ++it)
|
|
delete (*it);
|
|
}
|
|
|
|
void CFontFileListView::openViewer()
|
|
{
|
|
// Number of fonts user has selected, before we ask if they really want to view them all...
|
|
static const int constMaxBeforePrompt=10;
|
|
|
|
QList<QTreeWidgetItem *> items(selectedItems());
|
|
QSet<QString> files;
|
|
|
|
foreach(QTreeWidgetItem *item, items)
|
|
if(item->parent()) // Then it is a file, not font name :-)
|
|
files.insert(item->text(0));
|
|
|
|
if(files.count() &&
|
|
(files.count()<constMaxBeforePrompt ||
|
|
KMessageBox::Yes==KMessageBox::questionYesNo(this, i18np("Open font in font viewer?",
|
|
"Open all %1 fonts in font viewer?",
|
|
files.count()))))
|
|
{
|
|
QSet<QString>::ConstIterator it(files.begin()),
|
|
end(files.end());
|
|
|
|
for(; it!=end; ++it)
|
|
{
|
|
QStringList args;
|
|
|
|
args << (*it);
|
|
|
|
QProcess::startDetached(Misc::app(KFI_VIEWER), args);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CFontFileListView::properties()
|
|
{
|
|
QList<QTreeWidgetItem *> items(selectedItems());
|
|
KFileItemList files;
|
|
|
|
foreach(QTreeWidgetItem *item, items)
|
|
if(item->parent())
|
|
files.append(KFileItem(KUrl::fromPath(item->text(0)),
|
|
KMimeType::findByPath(item->text(0))->name(),
|
|
item->text(COL_LINK).isEmpty() ? S_IFREG : S_IFLNK));
|
|
|
|
if(files.count())
|
|
{
|
|
KPropertiesDialog dlg(files, this);
|
|
dlg.exec();
|
|
}
|
|
}
|
|
|
|
void CFontFileListView::mark()
|
|
{
|
|
QList<QTreeWidgetItem *> items(selectedItems());
|
|
|
|
foreach(QTreeWidgetItem *item, items) {
|
|
if(item->parent())
|
|
markItem(item);
|
|
}
|
|
checkFiles();
|
|
}
|
|
|
|
void CFontFileListView::unmark()
|
|
{
|
|
QList<QTreeWidgetItem *> items(selectedItems());
|
|
|
|
foreach(QTreeWidgetItem *item, items) {
|
|
if(item->parent())
|
|
unmarkItem(item);
|
|
}
|
|
checkFiles();
|
|
}
|
|
|
|
void CFontFileListView::selectedChanged()
|
|
{
|
|
QList<QTreeWidgetItem *> items(selectedItems());
|
|
|
|
foreach(QTreeWidgetItem *item, items) {
|
|
if(!item->parent() && item->isSelected())
|
|
item->setSelected(false);
|
|
}
|
|
}
|
|
|
|
void CFontFileListView::clicked(QTreeWidgetItem *item, int col)
|
|
{
|
|
if(item && COL_TRASH==col && item->parent())
|
|
{
|
|
if(isMarked(item))
|
|
unmarkItem(item);
|
|
else
|
|
markItem(item);
|
|
checkFiles();
|
|
}
|
|
}
|
|
|
|
void CFontFileListView::contextMenuEvent(QContextMenuEvent *ev)
|
|
{
|
|
QTreeWidgetItem *item(itemAt(ev->pos()));
|
|
|
|
if(item && item->parent())
|
|
{
|
|
if(!item->isSelected())
|
|
item->setSelected(true);
|
|
|
|
bool haveUnmarked(false),
|
|
haveMarked(false);
|
|
|
|
QList<QTreeWidgetItem *> items(selectedItems());
|
|
|
|
foreach(QTreeWidgetItem *it, items)
|
|
{
|
|
if(it->parent() && it->isSelected())
|
|
{
|
|
if(isMarked(it))
|
|
haveMarked=true;
|
|
else
|
|
haveUnmarked=true;
|
|
}
|
|
|
|
if(haveUnmarked && haveMarked)
|
|
break;
|
|
|
|
}
|
|
|
|
itsMarkAct->setEnabled(haveUnmarked);
|
|
itsUnMarkAct->setEnabled(haveMarked);
|
|
itsMenu->popup(ev->globalPos());
|
|
}
|
|
}
|
|
|
|
void CFontFileListView::checkFiles()
|
|
{
|
|
// Need to check that if we mark a file that is linked to, then we also need
|
|
// to mark the sym link.
|
|
QSet<QString> marked(getMarkedFiles());
|
|
|
|
if(marked.count())
|
|
{
|
|
QTreeWidgetItem *root=invisibleRootItem();
|
|
|
|
for(int t=0; t<root->childCount(); ++t)
|
|
{
|
|
QTreeWidgetItem *font=root->child(t);
|
|
|
|
for(int c=0; c<font->childCount(); ++c)
|
|
{
|
|
QTreeWidgetItem *file=font->child(c);
|
|
QString link(font->child(c)->text(COL_LINK));
|
|
|
|
if(!link.isEmpty() && marked.contains(link))
|
|
if(!isMarked(file))
|
|
markItem(file);
|
|
}
|
|
}
|
|
|
|
emit haveDeletions(true);
|
|
}
|
|
else
|
|
emit haveDeletions(false);
|
|
}
|
|
|
|
}
|
|
|
|
#include "moc_DuplicatesDialog.cpp"
|