Commit 2c684ecd authored by Nicolas Fella's avatar Nicolas Fella
Browse files

Lazily load file entry icons

Summary:
Building the icons datastructure is the most significant bottleneck when opening large archives. Knowing all the icons at loading time is unnecessary since most elements won't be visible anyway.
This patch moves the icon storing into the Entry class where it is lazily determined the first time it is accessed. This improves the initial archive loading time significantly.

Test Plan: It's hard to give exact numbers, but my main test archive (the Android NDK) went from ~3 seconds to load to "pretty much instant"

Reviewers: #ark, elvisangelaccio

Reviewed By: #ark, elvisangelaccio

Subscribers: broulik, kde-utils-devel

Tags: #ark

Differential Revision: https://phabricator.kde.org/D26357
parent 4dfbd053
......@@ -25,6 +25,8 @@
#include "archiveentry.h"
#include <QMimeDatabase>
namespace Kerfuffle {
Archive::Entry::Entry(QObject *parent, const QString &fullPath, const QString &rootNode)
: QObject(parent)
......@@ -201,6 +203,22 @@ void Archive::Entry::countChildren(uint &dirs, uint &files) const
}
}
QIcon Archive::Entry::icon() const
{
if (m_icon.isNull()) {
QMimeDatabase db;
if (m_isDirectory) {
static QIcon directoryIcon = QIcon::fromTheme(db.mimeTypeForName(QStringLiteral("inode/directory")).iconName());
m_icon = directoryIcon;
} else {
m_icon = QIcon::fromTheme(db.mimeTypeForFile(m_name, QMimeDatabase::MatchMode::MatchExtension).iconName());
}
}
return m_icon;
}
bool Archive::Entry::operator==(const Archive::Entry &right) const
{
return m_fullPath == right.m_fullPath;
......
......@@ -29,7 +29,7 @@
#include "archive_kerfuffle.h"
#include <QDateTime>
#include <QIcon>
namespace Kerfuffle {
......@@ -94,6 +94,7 @@ public:
int row() const;
Entry *find(const QString &name) const;
Entry *findByPath(const QStringList & pieces, int index = 0) const;
QIcon icon() const;
/**
* Fills @p dirs and @p files with the number of directories and files
......@@ -128,6 +129,7 @@ private:
bool m_isDirectory;
bool m_isExecutable;
bool m_isPasswordProtected;
mutable QIcon m_icon;
};
QDebug KERFUFFLE_EXPORT operator<<(QDebug d, const Kerfuffle::Archive::Entry &entry);
......
......@@ -131,9 +131,9 @@ QVariant ArchiveModel::data(const QModelIndex &index, int role) const
}
case Qt::DecorationRole:
if (index.column() == 0) {
const Archive::Entry *e = static_cast<Archive::Entry*>(index.internalPointer());
Archive::Entry *e = static_cast<Archive::Entry*>(index.internalPointer());
QIcon::Mode mode = (filesToMove.contains(e->fullPath())) ? QIcon::Disabled : QIcon::Normal;
return m_entryIcons.value(e->fullPath(NoTrailingSlash)).pixmap(QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize), mode);
return e->icon().pixmap(QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize), mode);
}
return QVariant();
case Qt::FontRole: {
......@@ -454,7 +454,6 @@ void ArchiveModel::slotEntryRemoved(const QString & path)
Q_UNUSED(index);
beginRemoveRows(indexForEntry(parent), entry->row(), entry->row());
m_entryIcons.remove(parent->entries().at(entry->row())->fullPath(NoTrailingSlash));
parent->removeEntryAt(entry->row());
endRemoveRows();
}
......@@ -589,14 +588,6 @@ void ArchiveModel::insertEntry(Archive::Entry *entry, InsertBehaviour behaviour)
if (behaviour == NotifyViews) {
endInsertRows();
}
// Save an icon for each newly added entry.
QMimeDatabase db;
QIcon icon;
entry->isDir()
? icon = QIcon::fromTheme(db.mimeTypeForName(QStringLiteral("inode/directory")).iconName())
: icon = QIcon::fromTheme(db.mimeTypeForFile(entry->fullPath()).iconName());
m_entryIcons.insert(entry->fullPath(NoTrailingSlash), icon);
}
Kerfuffle::Archive* ArchiveModel::archive() const
......@@ -839,11 +830,6 @@ QMap<QString, Archive::Entry*> ArchiveModel::entryMap(const QVector<Archive::Ent
return map;
}
const QHash<QString, QIcon> ArchiveModel::entryIcons() const
{
return m_entryIcons;
}
void ArchiveModel::slotCleanupEmptyDirs()
{
QList<QPersistentModelIndex> queue;
......@@ -874,7 +860,6 @@ void ArchiveModel::slotCleanupEmptyDirs()
Archive::Entry *rawEntry = static_cast<Archive::Entry*>(node.internalPointer());
qCDebug(ARK) << "Delete with parent entries " << rawEntry->getParent()->entries() << " and row " << rawEntry->row();
beginRemoveRows(parent(node), rawEntry->row(), rawEntry->row());
m_entryIcons.remove(rawEntry->getParent()->entries().at(rawEntry->row())->fullPath(NoTrailingSlash));
rawEntry->getParent()->removeEntryAt(rawEntry->row());
endRemoveRows();
}
......
......@@ -134,8 +134,6 @@ public:
static QMap<QString, Archive::Entry*> entryMap(const QVector<Archive::Entry*> &entries);
const QHash<QString, QIcon> entryIcons() const;
QMap<QString, Kerfuffle::Archive::Entry*> filesToMove;
QMap<QString, Kerfuffle::Archive::Entry*> filesToCopy;
......
......@@ -31,7 +31,7 @@
using namespace Kerfuffle;
OverwriteDialog::OverwriteDialog(QWidget *parent, const QList<const Archive::Entry*> &entries, const QHash<QString, QIcon> &icons, bool error)
OverwriteDialog::OverwriteDialog(QWidget *parent, const QList<const Archive::Entry*> &entries, bool error)
: QDialog(parent)
, m_buttonBox(QDialogButtonBox::Cancel, Qt::Horizontal)
{
......@@ -54,7 +54,7 @@ OverwriteDialog::OverwriteDialog(QWidget *parent, const QList<const Archive::Ent
connect(&m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
for (const Archive::Entry *entry : entries) {
QListWidgetItem *item = new QListWidgetItem(icons.value(entry->fullPath(NoTrailingSlash)), entry->fullPath(NoTrailingSlash));
QListWidgetItem *item = new QListWidgetItem(entry->icon(), entry->fullPath(NoTrailingSlash));
m_entriesList.addItem(item);
}
......
......@@ -43,7 +43,7 @@ class OverwriteDialog : public QDialog
{
Q_OBJECT
public:
explicit OverwriteDialog(QWidget *parent, const QList<const Kerfuffle::Archive::Entry*> &entries, const QHash<QString, QIcon> &icons, bool error = false);
explicit OverwriteDialog(QWidget *parent, const QList<const Kerfuffle::Archive::Entry*> &entries, bool error = false);
~OverwriteDialog() override;
private:
......
......@@ -1299,7 +1299,7 @@ void Part::slotAddFiles(const QStringList& filesToAdd, const Archive::Entry *des
bool error = m_model->conflictingEntries(conflictingEntries, withChildPaths, true);
if (conflictingEntries.count() > 0) {
QPointer<OverwriteDialog> overwriteDialog = new OverwriteDialog(widget(), conflictingEntries, m_model->entryIcons(), error);
QPointer<OverwriteDialog> overwriteDialog = new OverwriteDialog(widget(), conflictingEntries, error);
int ret = overwriteDialog->exec();
delete overwriteDialog;
if (ret == QDialog::Rejected) {
......@@ -1515,7 +1515,7 @@ void Part::slotPasteFiles(QVector<Kerfuffle::Archive::Entry*> &files, Kerfuffle:
bool error = m_model->conflictingEntries(conflictingEntries, newPaths, false);
if (conflictingEntries.count() != 0) {
QPointer<OverwriteDialog> overwriteDialog = new OverwriteDialog(widget(), conflictingEntries, m_model->entryIcons(), error);
QPointer<OverwriteDialog> overwriteDialog = new OverwriteDialog(widget(), conflictingEntries, error);
int ret = overwriteDialog->exec();
delete overwriteDialog;
if (ret == QDialog::Rejected) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment