From 00aafa69f5a478749f796fca20b5a71a6d5d1b49 Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Sun, 1 Jan 2012 21:52:54 +0100 Subject: [PATCH] Store database icons as QImage instead of QIcon. This has the advantage that they can be used without a running X server. Add methods to retrieve QPixmaps that are converted from the stored QImages and cached by QPixmapCache. --- src/core/Database.h | 1 - src/core/DatabaseIcons.cpp | 55 ++++++++++++++++++++++---------- src/core/DatabaseIcons.h | 25 ++++++++------- src/core/Entry.cpp | 25 +++++++++++++-- src/core/Entry.h | 8 +++-- src/core/Group.cpp | 26 +++++++++++++-- src/core/Group.h | 8 +++-- src/core/Metadata.cpp | 6 ++-- src/core/Metadata.h | 10 +++--- src/format/KeePass2XmlReader.cpp | 8 ++--- src/format/KeePass2XmlWriter.cpp | 9 +++--- src/format/KeePass2XmlWriter.h | 4 +-- src/gui/EntryModel.cpp | 2 +- src/gui/GroupModel.cpp | 2 +- tests/TestKeePass2XmlReader.cpp | 8 +++-- 15 files changed, 137 insertions(+), 60 deletions(-) diff --git a/src/core/Database.h b/src/core/Database.h index dc7fa3bbb..63ec1372e 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -20,7 +20,6 @@ #include #include -#include #include "core/Uuid.h" #include "keys/CompositeKey.h" diff --git a/src/core/DatabaseIcons.cpp b/src/core/DatabaseIcons.cpp index 6e5c942f0..e43c03921 100644 --- a/src/core/DatabaseIcons.cpp +++ b/src/core/DatabaseIcons.cpp @@ -19,20 +19,40 @@ #include "core/DataPath.h" -DatabaseIcons* DatabaseIcons::m_instance(0); - -QIcon DatabaseIcons::icon(int index) +QImage DatabaseIcons::icon(int index) { if (index < 0 || index >= iconCount()) { qWarning("DatabaseIcons::icon: invalid icon index %d", index); - return QIcon(); + return QImage(); } - if (!m_instance) { - m_instance = new DatabaseIcons(); + if (!m_iconCache[index].isNull()) { + return m_iconCache[index]; + } + else { + QString iconPath = QString("icons/database/").append(m_indexToName.at(index)); + QImage icon(DataPath::getPath(iconPath)); + + m_iconCache[index] = icon; + return icon; + } +} + +QPixmap DatabaseIcons::iconPixmap(int index) +{ + if (index < 0 || index >= iconCount()) { + qWarning("DatabaseIcons::iconPixmap: invalid icon index %d", index); + return QPixmap(); } - return m_instance->getIconInternal(index); + QPixmap pixmap; + + if (!QPixmapCache::find(m_pixmapCacheKeys[index], &pixmap)) { + pixmap = QPixmap::fromImage(icon(index)); + m_pixmapCacheKeys[index] = QPixmapCache::insert(pixmap); + } + + return pixmap; } int DatabaseIcons::iconCount() @@ -42,6 +62,7 @@ int DatabaseIcons::iconCount() DatabaseIcons::DatabaseIcons() { + m_indexToName.reserve(iconCount()); m_indexToName.append("C00_Password.png"); m_indexToName.append("C01_Package_Network.png"); m_indexToName.append("C02_MessageBox_Warning.png"); @@ -113,18 +134,20 @@ DatabaseIcons::DatabaseIcons() m_indexToName.append("C68_BlackBerry.png"); Q_ASSERT(m_indexToName.size() == iconCount()); + + m_iconCache.reserve(iconCount()); + m_iconCache.resize(iconCount()); + m_pixmapCacheKeys.reserve(iconCount()); + m_pixmapCacheKeys.resize(iconCount()); } -QIcon DatabaseIcons::getIconInternal(int index) +DatabaseIcons* databaseIcons() { - if (m_iconCache.contains(index)) { - return m_iconCache.value(index); - } - else { - QString iconPath = QString("icons/database/").append(m_indexToName.at(index)); - QIcon icon(DataPath::getPath(iconPath)); + static DatabaseIcons* instance(0); - m_iconCache.insert(index, icon); - return icon; + if (!instance) { + instance = new DatabaseIcons(); } + + return instance; } diff --git a/src/core/DatabaseIcons.h b/src/core/DatabaseIcons.h index 76ca84d60..fc9a88001 100644 --- a/src/core/DatabaseIcons.h +++ b/src/core/DatabaseIcons.h @@ -18,25 +18,28 @@ #ifndef KEEPASSX_DATABASEICONS_H #define KEEPASSX_DATABASEICONS_H -#include -#include +#include +#include +#include +#include class DatabaseIcons { public: - static QIcon icon(int index); - static int iconCount(); - -private: - static DatabaseIcons* m_instance; + QImage icon(int index); + QPixmap iconPixmap(int index); + int iconCount(); private: DatabaseIcons(); - QIcon getIconInternal(int index); - bool m_initalized; - QList m_indexToName; - QHash m_iconCache; + QVector m_indexToName; + QVector m_iconCache; + QVector m_pixmapCacheKeys; + + friend DatabaseIcons* databaseIcons(); }; +DatabaseIcons* databaseIcons(); + #endif // KEEPASSX_DATABASEICONS_H diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 0d7c1848d..bf0387023 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -52,10 +52,10 @@ Uuid Entry::uuid() const return m_uuid; } -QIcon Entry::icon() const +QImage Entry::icon() const { if (m_customIcon.isNull()) { - return DatabaseIcons::icon(m_iconNumber); + return databaseIcons()->icon(m_iconNumber); } else { // TODO check if m_db is 0 @@ -63,6 +63,23 @@ QIcon Entry::icon() const } } +QPixmap Entry::iconPixmap() const +{ + if (m_customIcon.isNull()) { + return databaseIcons()->iconPixmap(m_iconNumber); + } + else { + QPixmap pixmap; + if (!QPixmapCache::find(m_pixmapCacheKey, &pixmap)) { + // TODO check if m_db is 0 + pixmap = QPixmap::fromImage(m_db->metadata()->customIcon(m_customIcon)); + *const_cast(&m_pixmapCacheKey) = QPixmapCache::insert(pixmap); + } + + return pixmap; + } +} + int Entry::iconNumber() const { return m_iconNumber; @@ -176,6 +193,8 @@ void Entry::setIcon(int iconNumber) m_iconNumber = iconNumber; m_customIcon = Uuid(); + + m_pixmapCacheKey = QPixmapCache::Key(); } void Entry::setIcon(const Uuid& uuid) @@ -184,6 +203,8 @@ void Entry::setIcon(const Uuid& uuid) m_iconNumber = 0; m_customIcon = uuid; + + m_pixmapCacheKey = QPixmapCache::Key(); } void Entry::setForegroundColor(const QColor& color) diff --git a/src/core/Entry.h b/src/core/Entry.h index 319b0da04..0e2e64e95 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -23,7 +23,9 @@ #include #include #include -#include +#include +#include +#include #include "core/TimeInfo.h" #include "core/Uuid.h" @@ -45,7 +47,8 @@ public: Entry(); ~Entry(); Uuid uuid() const; - QIcon icon() const; + QImage icon() const; + QPixmap iconPixmap() const; int iconNumber() const; Uuid iconUuid() const; QColor foregroundColor() const; @@ -125,6 +128,7 @@ private: QList m_history; QPointer m_group; const Database* m_db; + QPixmapCache::Key m_pixmapCacheKey; const static QStringList m_defaultAttibutes; }; diff --git a/src/core/Group.cpp b/src/core/Group.cpp index e5732c8f1..8ed4a17cc 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -55,16 +55,34 @@ QString Group::notes() const return m_notes; } -QIcon Group::icon() const +QImage Group::icon() const { if (m_customIcon.isNull()) { - return DatabaseIcons::icon(m_iconNumber); + return databaseIcons()->icon(m_iconNumber); } else { + // TODO check if m_db is 0 return m_db->metadata()->customIcon(m_customIcon); } } +QPixmap Group::iconPixmap() const +{ + if (m_customIcon.isNull()) { + return databaseIcons()->iconPixmap(m_iconNumber); + } + else { + QPixmap pixmap; + if (!QPixmapCache::find(m_pixmapCacheKey, &pixmap)) { + // TODO check if m_db is 0 + pixmap = QPixmap::fromImage(m_db->metadata()->customIcon(m_customIcon)); + *const_cast(&m_pixmapCacheKey) = QPixmapCache::insert(pixmap); + } + + return pixmap; + } +} + int Group::iconNumber() const { return m_iconNumber; @@ -129,6 +147,8 @@ void Group::setIcon(int iconNumber) m_iconNumber = iconNumber; m_customIcon = Uuid(); + m_pixmapCacheKey = QPixmapCache::Key(); + Q_EMIT dataChanged(this); } @@ -139,6 +159,8 @@ void Group::setIcon(const Uuid& uuid) m_iconNumber = 0; m_customIcon = uuid; + m_pixmapCacheKey = QPixmapCache::Key(); + Q_EMIT dataChanged(this); } diff --git a/src/core/Group.h b/src/core/Group.h index 64734a7ad..18387edf2 100644 --- a/src/core/Group.h +++ b/src/core/Group.h @@ -19,7 +19,9 @@ #define KEEPASSX_GROUP_H #include -#include +#include +#include +#include #include "core/Database.h" #include "core/Entry.h" @@ -38,7 +40,8 @@ public: Uuid uuid() const; QString name() const; QString notes() const; - QIcon icon() const; + QImage icon() const; + QPixmap iconPixmap() const; int iconNumber() const; Uuid iconUuid() const; TimeInfo timeInfo() const; @@ -109,6 +112,7 @@ private: QList m_entries; QPointer m_parent; + QPixmapCache::Key m_pixmapCacheKey; friend void Database::setRootGroup(Group* group); friend Entry::~Entry(); diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp index 9a75dd3a4..0b9382a4b 100644 --- a/src/core/Metadata.cpp +++ b/src/core/Metadata.cpp @@ -120,12 +120,12 @@ bool Metadata::autoEnableVisualHiding() const return m_autoEnableVisualHiding; } -QIcon Metadata::customIcon(const Uuid& uuid) const +QImage Metadata::customIcon(const Uuid& uuid) const { return m_customIcons.value(uuid); } -QHash Metadata::customIcons() const +QHash Metadata::customIcons() const { return m_customIcons; } @@ -257,7 +257,7 @@ void Metadata::setAutoEnableVisualHiding(bool value) m_autoEnableVisualHiding = value; } -void Metadata::addCustomIcon(const Uuid& uuid, const QIcon& icon) +void Metadata::addCustomIcon(const Uuid& uuid, const QImage& icon) { Q_ASSERT(!uuid.isNull()); Q_ASSERT(!m_customIcons.contains(uuid)); diff --git a/src/core/Metadata.h b/src/core/Metadata.h index 2aa70da36..178eaf9ca 100644 --- a/src/core/Metadata.h +++ b/src/core/Metadata.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include "core/Uuid.h" @@ -48,8 +48,8 @@ public: bool protectUrl() const; bool protectNotes() const; bool autoEnableVisualHiding() const; - QIcon customIcon(const Uuid& uuid) const; - QHash customIcons() const; + QImage customIcon(const Uuid& uuid) const; + QHash customIcons() const; bool recycleBinEnabled() const; const Group* recycleBin() const; QDateTime recycleBinChanged() const; @@ -76,7 +76,7 @@ public: void setProtectUrl(bool value); void setProtectNotes(bool value); void setAutoEnableVisualHiding(bool value); - void addCustomIcon(const Uuid& uuid, const QIcon& icon); + void addCustomIcon(const Uuid& uuid, const QImage& icon); void removeCustomIcon(const Uuid& uuid); void setRecycleBinEnabled(bool value); void setRecycleBin(Group* group); @@ -113,7 +113,7 @@ private: bool m_protectNotes; bool m_autoEnableVisualHiding; - QHash m_customIcons; + QHash m_customIcons; bool m_recycleBinEnabled; Group* m_recycleBin; diff --git a/src/format/KeePass2XmlReader.cpp b/src/format/KeePass2XmlReader.cpp index af3b7d450..275c7413c 100644 --- a/src/format/KeePass2XmlReader.cpp +++ b/src/format/KeePass2XmlReader.cpp @@ -227,9 +227,9 @@ void KeePass2XmlReader::parseIcon() uuid = readUuid(); } else if (m_xml.name() == "Data") { - QPixmap pixmap; - pixmap.loadFromData(readBinary()); - m_meta->addCustomIcon(uuid, QIcon(pixmap)); + QImage icon; + icon.loadFromData(readBinary()); + m_meta->addCustomIcon(uuid, icon); } else { skipCurrentElement(); @@ -318,7 +318,7 @@ Group* KeePass2XmlReader::parseGroup() raiseError(); } else { - if (iconId >= DatabaseIcons::iconCount()) { + if (iconId >= databaseIcons()->iconCount()) { qWarning("KeePass2XmlReader::parseGroup: icon id \"%d\" not supported", iconId); } group->setIcon(iconId); diff --git a/src/format/KeePass2XmlWriter.cpp b/src/format/KeePass2XmlWriter.cpp index e95d70fa3..075c9d710 100644 --- a/src/format/KeePass2XmlWriter.cpp +++ b/src/format/KeePass2XmlWriter.cpp @@ -107,7 +107,7 @@ void KeePass2XmlWriter::writeCustomIcons() { m_xml.writeStartElement("CustomIcons"); - QHash customIcons = m_meta->customIcons(); + QHash customIcons = m_meta->customIcons(); Q_FOREACH (const Uuid& uuid, customIcons.keys()) { writeIcon(uuid, customIcons.value(uuid)); } @@ -115,18 +115,17 @@ void KeePass2XmlWriter::writeCustomIcons() m_xml.writeEndElement(); } -void KeePass2XmlWriter::writeIcon(const Uuid& uuid, const QIcon& icon) +void KeePass2XmlWriter::writeIcon(const Uuid& uuid, const QImage& icon) { m_xml.writeStartElement("Icon"); writeUuid("UUID", uuid); - QPixmap pixmap = icon.pixmap(16, 16); - QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); - pixmap.save(&buffer, "PNG"); + // TODO check !icon.save() + icon.save(&buffer, "PNG"); buffer.close(); writeBinary("Data", ba); diff --git a/src/format/KeePass2XmlWriter.h b/src/format/KeePass2XmlWriter.h index 34e699b26..044f2fd90 100644 --- a/src/format/KeePass2XmlWriter.h +++ b/src/format/KeePass2XmlWriter.h @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "core/Database.h" #include "core/Entry.h" @@ -46,7 +46,7 @@ private: void writeMetadata(); void writeMemoryProtection(); void writeCustomIcons(); - void writeIcon(const Uuid& uuid, const QIcon& icon); + void writeIcon(const Uuid& uuid, const QImage& icon); void writeCustomData(); void writeCustomDataItem(const QString& key, const QString& value); void writeRoot(); diff --git a/src/gui/EntryModel.cpp b/src/gui/EntryModel.cpp index 2308dd97e..f1f744f37 100644 --- a/src/gui/EntryModel.cpp +++ b/src/gui/EntryModel.cpp @@ -85,7 +85,7 @@ QVariant EntryModel::data(const QModelIndex& index, int role) const } } else if ((role == Qt::DecorationRole) && (index.column() == 0)) { - return entry->icon(); + return entry->iconPixmap(); } return QVariant(); diff --git a/src/gui/GroupModel.cpp b/src/gui/GroupModel.cpp index 7b135c29f..2209d75f5 100644 --- a/src/gui/GroupModel.cpp +++ b/src/gui/GroupModel.cpp @@ -109,7 +109,7 @@ QVariant GroupModel::data(const QModelIndex& index, int role) const return group->name(); } else if (role == Qt::DecorationRole) { - return group->icon(); + return group->iconPixmap(); } else { return QVariant(); diff --git a/tests/TestKeePass2XmlReader.cpp b/tests/TestKeePass2XmlReader.cpp index c63f1253f..cac8cb314 100644 --- a/tests/TestKeePass2XmlReader.cpp +++ b/tests/TestKeePass2XmlReader.cpp @@ -105,11 +105,13 @@ void TestKeePass2XmlReader::testCustomIcons() QCOMPARE(m_db->metadata()->customIcons().size(), 1); Uuid uuid = Uuid::fromBase64("++vyI+daLk6omox4a6kQGA=="); QVERIFY(m_db->metadata()->customIcons().contains(uuid)); - QIcon icon = m_db->metadata()->customIcon(uuid); - QImage img = icon.pixmap(16, 16).toImage(); + QImage icon = m_db->metadata()->customIcon(uuid); + QCOMPARE(icon.width(), 16); + QCOMPARE(icon.height(), 16); + for (int x=0; x<16; x++) { for (int y=0; y<16; y++) { - QRgb rgb = img.pixel(x, y); + QRgb rgb = icon.pixel(x, y); QCOMPARE(qRed(rgb), 128); QCOMPARE(qGreen(rgb), 0); QCOMPARE(qBlue(rgb), 128);