diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index 15185b297..8032c27d2 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -157,7 +157,7 @@ void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow, const QS QCoreApplication::processEvents(QEventLoop::AllEvents, 10); - Q_FOREACH (AutoTypeAction* action, actions) { + for (AutoTypeAction* action : asConst(actions)) { if (m_plugin->activeWindow() != window) { qWarning("Active window changed, interrupting auto-type."); break; @@ -187,8 +187,9 @@ void AutoType::performGlobalAutoType(const QList& dbList) QList entryList; QHash sequenceHash; - Q_FOREACH (Database* db, dbList) { - Q_FOREACH (Entry* entry, db->rootGroup()->entriesRecursive()) { + for (Database* db : dbList) { + const QList dbEntries = db->rootGroup()->entriesRecursive(); + for (Entry* entry : dbEntries) { QString sequence = autoTypeSequence(entry, windowTitle); if (!sequence.isEmpty()) { entryList << entry; @@ -300,7 +301,7 @@ bool AutoType::parseActions(const QString& sequence, const Entry* entry, QList AutoType::createActionFromTemplate(const QString& tmpl, c } - QString placeholder = QString("{%1}").arg(tmplName); - QString resolved = entry->resolvePlaceholders(placeholder); + const QString placeholder = QString("{%1}").arg(tmplName); + const QString resolved = entry->resolvePlaceholders(placeholder); if (placeholder != resolved) { - Q_FOREACH (const QChar& ch, resolved) { + for (const QChar& ch : resolved) { if (ch == '\n') { list.append(new AutoTypeKey(Qt::Key_Enter)); } @@ -511,7 +512,8 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl QString sequence; if (!windowTitle.isEmpty()) { bool match = false; - Q_FOREACH (const AutoTypeAssociations::Association& assoc, entry->autoTypeAssociations()->getAll()) { + const QList assocList = entry->autoTypeAssociations()->getAll(); + for (const AutoTypeAssociations::Association& assoc : assocList) { if (windowMatches(windowTitle, assoc.window)) { if (!assoc.sequence.isEmpty()) { sequence = assoc.sequence; diff --git a/src/autotype/WildcardMatcher.cpp b/src/autotype/WildcardMatcher.cpp index 3d7cc7511..ad83f9b0a 100644 --- a/src/autotype/WildcardMatcher.cpp +++ b/src/autotype/WildcardMatcher.cpp @@ -70,7 +70,7 @@ bool WildcardMatcher::startOrEndDoesNotMatch(const QStringList& parts) bool WildcardMatcher::partsMatch(const QStringList& parts) { int index = 0; - Q_FOREACH (const QString& part, parts) { + for (const QString& part : parts) { int matchIndex = getMatchIndex(part, index); if (noMatchFound(matchIndex)) { return false; diff --git a/src/autotype/xcb/AutoTypeXCB.cpp b/src/autotype/xcb/AutoTypeXCB.cpp index 40acaf663..23a211d37 100644 --- a/src/autotype/xcb/AutoTypeXCB.cpp +++ b/src/autotype/xcb/AutoTypeXCB.cpp @@ -344,7 +344,7 @@ QList AutoTypePlatformX11::widgetsToX11Windows(const QWidgetList& widget { QList windows; - Q_FOREACH (const QWidget* widget, widgetList) { + for (const QWidget* widget : widgetList) { windows.append(widget->effectiveWinId()); } @@ -384,14 +384,22 @@ bool AutoTypePlatformX11::isTopLevelWindow(Window window) int format; unsigned long nitems; unsigned long after; - unsigned char* data = nullptr; - int retVal = XGetWindowProperty(m_dpy, window, m_atomWmState, 0, 0, False, AnyPropertyType, &type, &format, + unsigned char* data = Q_NULLPTR; + int retVal = XGetWindowProperty(m_dpy, window, m_atomWmState, 0, 2, False, m_atomWmState, &type, &format, &nitems, &after, &data); - if (data) { + + bool result = false; + + if (retVal == 0 && data) { + if (type == m_atomWmState && format == 32 && nitems > 0) { + qint32 state = static_cast(*data); + result = (state != WithdrawnState); + } + XFree(data); } - return (retVal == 0) && type; + return result; } KeySym AutoTypePlatformX11::charToKeySym(const QChar& ch) diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 6f9423570..9e01d3bc0 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -91,13 +91,15 @@ Entry* Database::resolveEntry(const Uuid& uuid) Entry* Database::recFindEntry(const Uuid& uuid, Group* group) { - Q_FOREACH (Entry* entry, group->entries()) { + const QList entryList = group->entries(); + for (Entry* entry : entryList) { if (entry->uuid() == uuid) { return entry; } } - Q_FOREACH (Group* child, group->children()) { + const QList children = group->children(); + for (Group* child : children) { Entry* result = recFindEntry(uuid, child); if (result) { return result; @@ -118,7 +120,8 @@ Group* Database::recFindGroup(const Uuid& uuid, Group* group) return group; } - Q_FOREACH (Group* child, group->children()) { + const QList children = group->children(); + for (Group* child : children) { Group* result = recFindGroup(uuid, child); if (result) { return result; diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 2fd52d0b0..d90a33fe8 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -371,7 +371,6 @@ const QList& Entry::historyItems() const void Entry::addHistoryItem(Entry* entry) { Q_ASSERT(!entry->parent()); - Q_ASSERT(entry->uuid() == uuid()); m_history.append(entry); Q_EMIT modified(); @@ -383,7 +382,7 @@ void Entry::removeHistoryItems(const QList& historyEntries) return; } - Q_FOREACH (Entry* entry, historyEntries) { + for (Entry* entry : historyEntries) { Q_ASSERT(!entry->parent()); Q_ASSERT(entry->uuid() == uuid()); Q_ASSERT(m_history.contains(entry)); @@ -432,8 +431,8 @@ void Entry::truncateHistory() if (size <= histMaxSize) { size += historyItem->attributes()->attributesSize(); - QSet newAttachments = historyItem->attachments()->values().toSet() - foundAttachements; - Q_FOREACH (const QByteArray& attachment, newAttachments) { + const QSet newAttachments = historyItem->attachments()->values().toSet() - foundAttachements; + for (const QByteArray& attachment : newAttachments) { size += attachment.size(); } foundAttachements += newAttachments; @@ -462,7 +461,7 @@ Entry* Entry::clone(CloneFlags flags) const entry->m_attachments->copyDataFrom(m_attachments); entry->m_autoTypeAssociations->copyDataFrom(this->m_autoTypeAssociations); if (flags & CloneIncludeHistory) { - Q_FOREACH (Entry* historyItem, m_history) { + for (Entry* historyItem : m_history) { Entry* historyItemClone = historyItem->clone(flags & ~CloneIncludeHistory & ~CloneNewUuid); historyItemClone->setUpdateTimeinfo(false); historyItemClone->setUuid(entry->uuid()); @@ -509,7 +508,7 @@ void Entry::beginUpdate() m_modifiedSinceBegin = false; } -void Entry::endUpdate() +bool Entry::endUpdate() { Q_ASSERT(m_tmpHistoryItem); if (m_modifiedSinceBegin) { @@ -522,6 +521,8 @@ void Entry::endUpdate() } m_tmpHistoryItem = nullptr; + + return m_modifiedSinceBegin; } void Entry::updateModifiedSinceBegin() diff --git a/src/core/Entry.h b/src/core/Entry.h index cd7c7b779..0b4d4829f 100644 --- a/src/core/Entry.h +++ b/src/core/Entry.h @@ -133,7 +133,7 @@ public: * if the entry has been changed. */ void beginUpdate(); - void endUpdate(); + bool endUpdate(); Group* group(); const Group* group() const; diff --git a/src/core/EntryAttributes.cpp b/src/core/EntryAttributes.cpp index 08fd2f9c3..195a8f14a 100644 --- a/src/core/EntryAttributes.cpp +++ b/src/core/EntryAttributes.cpp @@ -44,7 +44,8 @@ bool EntryAttributes::hasKey(const QString& key) const QList EntryAttributes::customKeys() { QList customKeys; - Q_FOREACH (const QString& key, keys()) { + const QList keyList = keys(); + for (const QString& key : keyList) { if (!isDefaultAttribute(key)) { customKeys.append(key); } @@ -167,14 +168,16 @@ void EntryAttributes::copyCustomKeysFrom(const EntryAttributes* other) Q_EMIT aboutToBeReset(); // remove all non-default keys - Q_FOREACH (const QString& key, keys()) { + const QList keyList = keys(); + for (const QString& key : keyList) { if (!isDefaultAttribute(key)) { m_attributes.remove(key); m_protectedAttributes.remove(key); } } - Q_FOREACH (const QString& key, other->keys()) { + const QList otherKeyList = other->keys(); + for (const QString& key : otherKeyList) { if (!isDefaultAttribute(key)) { m_attributes.insert(key, other->value(key)); if (other->isProtected(key)) { @@ -194,7 +197,8 @@ bool EntryAttributes::areCustomKeysDifferent(const EntryAttributes* other) return true; } - Q_FOREACH (const QString& key, keys()) { + const QList keyList = keys(); + for (const QString& key : keyList) { if (isDefaultAttribute(key)) { continue; } @@ -239,7 +243,7 @@ void EntryAttributes::clear() m_attributes.clear(); m_protectedAttributes.clear(); - Q_FOREACH (const QString& key, DefaultAttributes) { + for (const QString& key : DefaultAttributes) { m_attributes.insert(key, ""); } diff --git a/src/core/EntrySearcher.cpp b/src/core/EntrySearcher.cpp index 05c4c5892..c0360a36c 100644 --- a/src/core/EntrySearcher.cpp +++ b/src/core/EntrySearcher.cpp @@ -34,10 +34,13 @@ QList EntrySearcher::searchEntries(const QString& searchTerm, const Grou { QList searchResult; - Q_FOREACH (Entry* entry, group->entries()) { - searchResult.append(matchEntry(searchTerm, entry, caseSensitivity)); + const QList entryList = group->entries(); + for (Entry* entry : entryList) { + searchResult.append(matchEntry(searchTerm, entry, caseSensitivity)); } - Q_FOREACH (Group* childGroup, group->children()) { + + const QList children = group->children(); + for (Group* childGroup : children) { if (childGroup->searchingEnabled() != Group::Disable) { searchResult.append(searchEntries(searchTerm, childGroup, caseSensitivity)); } @@ -49,8 +52,8 @@ QList EntrySearcher::searchEntries(const QString& searchTerm, const Grou QList EntrySearcher::matchEntry(const QString& searchTerm, Entry* entry, Qt::CaseSensitivity caseSensitivity) { - QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts); - Q_FOREACH (const QString& word, wordList) { + const QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts); + for (const QString& word : wordList) { if (!wordMatch(word, entry, caseSensitivity)) { return QList(); } diff --git a/src/core/FilePath.cpp b/src/core/FilePath.cpp index 497568ad1..06208b7c9 100644 --- a/src/core/FilePath.cpp +++ b/src/core/FilePath.cpp @@ -22,6 +22,7 @@ #include #include "config-keepassx.h" +#include "core/Global.h" FilePath* FilePath::m_instance(nullptr); @@ -40,7 +41,8 @@ QString FilePath::pluginPath(const QString& name) QStringList pluginPaths; QDir buildDir(QCoreApplication::applicationDirPath() + "/autotype"); - Q_FOREACH (const QString& dir, buildDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + const QStringList buildDirEntryList = buildDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString& dir : buildDirEntryList) { pluginPaths << QCoreApplication::applicationDirPath() + "/autotype/" + dir; } @@ -68,10 +70,10 @@ QString FilePath::pluginPath(const QString& name) QStringList dirFilter; dirFilter << QString("*%1*").arg(name); - Q_FOREACH (const QString& path, pluginPaths) { - QStringList fileCandidates = QDir(path).entryList(dirFilter, QDir::Files); + for (const QString& path : asConst(pluginPaths)) { + const QStringList fileCandidates = QDir(path).entryList(dirFilter, QDir::Files); - Q_FOREACH (const QString& file, fileCandidates) { + for (const QString& file : fileCandidates) { QString filePath = path + "/" + file; if (QLibrary::isLibrary(filePath)) { @@ -103,10 +105,9 @@ QIcon FilePath::icon(const QString& category, const QString& name, bool fromThem } if (icon.isNull()) { - QList pngSizes; - pngSizes << 16 << 22 << 24 << 32 << 48 << 64 << 128; + const QList pngSizes = { 16, 22, 24, 32, 48, 64, 128 }; QString filename; - Q_FOREACH (int size, pngSizes) { + for (int size : pngSizes) { filename = QString("%1/icons/application/%2x%2/%3.png").arg(m_dataPath, QString::number(size), combinedName); if (QFile::exists(filename)) { @@ -148,10 +149,9 @@ QIcon FilePath::onOffIcon(const QString& category, const QString& name) stateName = "on"; } - QList pngSizes; - pngSizes << 16 << 22 << 24 << 32 << 48 << 64 << 128; + const QList pngSizes = { 16, 22, 24, 32, 48, 64, 128 }; QString filename; - Q_FOREACH (int size, pngSizes) { + for (int size : pngSizes) { filename = QString("%1/icons/application/%2x%2/%3-%4.png").arg(m_dataPath, QString::number(size), combinedName, stateName); if (QFile::exists(filename)) { diff --git a/src/core/Global.h b/src/core/Global.h index 14281eeec..bd6a73356 100644 --- a/src/core/Global.h +++ b/src/core/Global.h @@ -36,4 +36,13 @@ #define QUINT32_MAX 4294967295U #endif +template struct AddConst { typedef const T Type; }; + +// this adds const to non-const objects (like std::as_const) +template +constexpr typename AddConst::Type& asConst(T &t) noexcept { return t; } +// prevent rvalue arguments: +template +void asConst(const T&&) = delete; + #endif // KEEPASSX_GLOBAL_H diff --git a/src/core/Group.cpp b/src/core/Group.cpp index 2b9e9bcff..325ef9467 100644 --- a/src/core/Group.cpp +++ b/src/core/Group.cpp @@ -18,6 +18,7 @@ #include "Group.h" #include "core/Config.h" +#include "core/Global.h" #include "core/DatabaseIcons.h" #include "core/Metadata.h" @@ -37,13 +38,13 @@ Group::~Group() { // Destroy entries and children manually so DeletedObjects can be added // to database. - QList entries = m_entries; - Q_FOREACH (Entry* entry, entries) { + const QList entries = m_entries; + for (Entry* entry : entries) { delete entry; } - QList children = m_children; - Q_FOREACH (Group* group, children) { + const QList children = m_children; + for (Group* group : children) { delete group; } @@ -427,12 +428,12 @@ QList Group::entriesRecursive(bool includeHistoryItems) const entryList.append(m_entries); if (includeHistoryItems) { - Q_FOREACH (Entry* entry, m_entries) { + for (Entry* entry : m_entries) { entryList.append(entry->historyItems()); } } - Q_FOREACH (Group* group, m_children) { + for (Group* group : m_children) { entryList.append(group->entriesRecursive(includeHistoryItems)); } @@ -446,7 +447,7 @@ QList Group::groupsRecursive(bool includeSelf) const groupList.append(this); } - Q_FOREACH (const Group* group, m_children) { + for (const Group* group : m_children) { groupList.append(group->groupsRecursive(true)); } @@ -460,7 +461,7 @@ QList Group::groupsRecursive(bool includeSelf) groupList.append(this); } - Q_FOREACH (Group* group, m_children) { + for (Group* group : asConst(m_children)) { groupList.append(group->groupsRecursive(true)); } @@ -475,13 +476,14 @@ QSet Group::customIconsRecursive() const result.insert(iconUuid()); } - Q_FOREACH (Entry* entry, entriesRecursive(true)) { + const QList entryList = entriesRecursive(true); + for (Entry* entry : entryList) { if (!entry->iconUuid().isNull()) { result.insert(entry->iconUuid()); } } - Q_FOREACH (Group* group, m_children) { + for (Group* group : m_children) { result.unite(group->customIconsRecursive()); } @@ -497,13 +499,15 @@ Group* Group::clone(Entry::CloneFlags entryFlags) const clonedGroup->setUuid(Uuid::random()); clonedGroup->m_data = m_data; - Q_FOREACH (Entry* entry, entries()) { + const QList entryList = entries(); + for (Entry* entry : entryList) { Entry* clonedEntry = entry->clone(entryFlags); clonedEntry->setGroup(clonedGroup); } - Q_FOREACH (Group* groupChild, children()) { - Group* clonedGroupChild = groupChild->clone(); + const QList childrenGroups = children(); + for (Group* groupChild : childrenGroups) { + Group* clonedGroupChild = groupChild->clone(entryFlags); clonedGroupChild->setParent(clonedGroup); } @@ -569,7 +573,7 @@ void Group::recSetDatabase(Database* db) disconnect(SIGNAL(modified()), m_db); } - Q_FOREACH (Entry* entry, m_entries) { + for (Entry* entry : asConst(m_entries)) { if (m_db) { entry->disconnect(m_db); } @@ -591,7 +595,7 @@ void Group::recSetDatabase(Database* db) m_db = db; - Q_FOREACH (Group* group, m_children) { + for (Group* group : asConst(m_children)) { group->recSetDatabase(db); } } @@ -609,11 +613,11 @@ void Group::cleanupParent() void Group::recCreateDelObjects() { if (m_db) { - Q_FOREACH (Entry* entry, m_entries) { + for (Entry* entry : asConst(m_entries)) { m_db->addDeletedObject(entry->uuid()); } - Q_FOREACH (Group* group, m_children) { + for (Group* group : asConst(m_children)) { group->recCreateDelObjects(); } m_db->addDeletedObject(m_uuid); diff --git a/src/core/Metadata.cpp b/src/core/Metadata.cpp index a50c6ef45..e908fbb24 100644 --- a/src/core/Metadata.cpp +++ b/src/core/Metadata.cpp @@ -218,7 +218,7 @@ QHash Metadata::customIconsScaledPixmaps() const { QHash result; - Q_FOREACH (const Uuid& uuid, m_customIconsOrder) { + for (const Uuid& uuid : m_customIconsOrder) { result.insert(uuid, customIconScaledPixmap(uuid)); } @@ -427,7 +427,7 @@ void Metadata::removeCustomIcon(const Uuid& uuid) void Metadata::copyCustomIcons(const QSet& iconList, const Metadata* otherMetadata) { - Q_FOREACH (const Uuid& uuid, iconList) { + for (const Uuid& uuid : iconList) { Q_ASSERT(otherMetadata->containsCustomIcon(uuid)); if (!containsCustomIcon(uuid) && otherMetadata->containsCustomIcon(uuid)) { diff --git a/src/core/PasswordGenerator.cpp b/src/core/PasswordGenerator.cpp index 52f124786..f5b7123ca 100644 --- a/src/core/PasswordGenerator.cpp +++ b/src/core/PasswordGenerator.cpp @@ -45,11 +45,11 @@ QString PasswordGenerator::generatePassword() const { Q_ASSERT(isValid()); - QVector groups = passwordGroups(); + const QVector groups = passwordGroups(); QVector passwordChars; - Q_FOREACH (const PasswordGroup& group, groups) { - Q_FOREACH (QChar ch, group) { + for (const PasswordGroup& group : groups) { + for (QChar ch : group) { passwordChars.append(ch); } } diff --git a/src/core/SignalMultiplexer.cpp b/src/core/SignalMultiplexer.cpp index ebf38bf64..7b5fab93b 100644 --- a/src/core/SignalMultiplexer.cpp +++ b/src/core/SignalMultiplexer.cpp @@ -17,6 +17,8 @@ #include "SignalMultiplexer.h" +#include "core/Global.h" + SignalMultiplexer::SignalMultiplexer() { } @@ -45,7 +47,7 @@ void SignalMultiplexer::setCurrentObject(QObject* object) } if (m_currentObject) { - Q_FOREACH (const Connection& con, m_connections) { + for (const Connection& con : asConst(m_connections)) { disconnect(con); } } @@ -53,7 +55,7 @@ void SignalMultiplexer::setCurrentObject(QObject* object) m_currentObject = object; if (object) { - Q_FOREACH (const Connection& con, m_connections) { + for (const Connection& con : asConst(m_connections)) { connect(con); } } diff --git a/src/core/Tools.cpp b/src/core/Tools.cpp index 06eb73d1a..bc63bf139 100644 --- a/src/core/Tools.cpp +++ b/src/core/Tools.cpp @@ -71,7 +71,9 @@ bool hasChild(const QObject* parent, const QObject* child) if (!parent || !child) { return false; } - Q_FOREACH (QObject* c, parent->children()) { + + const QObjectList children = parent->children(); + for (QObject* c : children) { if (child == c || hasChild(c, child)) { return true; } @@ -120,10 +122,10 @@ bool readAllFromDevice(QIODevice* device, QByteArray& data) QString imageReaderFilter() { - QList formats = QImageReader::supportedImageFormats(); + const QList formats = QImageReader::supportedImageFormats(); QStringList formatsStringList; - Q_FOREACH (const QByteArray& format, formats) { + for (const QByteArray& format : formats) { for (int i = 0; i < format.size(); i++) { if (!QChar(format.at(i)).isLetterOrNumber()) { continue; @@ -138,7 +140,7 @@ QString imageReaderFilter() bool isHex(const QByteArray& ba) { - Q_FOREACH (char c, ba) { + for (char c : ba) { if ( !( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) ) { return false; } diff --git a/src/core/Translator.cpp b/src/core/Translator.cpp index ed63693cb..713727ea1 100644 --- a/src/core/Translator.cpp +++ b/src/core/Translator.cpp @@ -49,18 +49,20 @@ void Translator::installTranslator() QList > Translator::availableLanguages() { - QStringList paths; + const QStringList paths = { #ifdef QT_DEBUG - paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR)); + QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR), #endif - paths.append(filePath()->dataPath("translations")); + filePath()->dataPath("translations") + }; QList > languages; languages.append(QPair("system", "System default")); QRegExp regExp("keepassx_([a-zA-Z_]+)\\.qm", Qt::CaseInsensitive, QRegExp::RegExp2); - Q_FOREACH (const QString& path, paths) { - Q_FOREACH (const QString& filename, QDir(path).entryList()) { + for (const QString& path : paths) { + const QStringList fileList = QDir(path).entryList(); + for (const QString& filename : fileList) { if (regExp.exactMatch(filename)) { QString langcode = regExp.cap(1); if (langcode == "en_plurals") { @@ -85,13 +87,14 @@ QList > Translator::availableLanguages() bool Translator::installTranslator(const QString& language) { - QStringList paths; + const QStringList paths = { #ifdef QT_DEBUG - paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR)); + QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR), #endif - paths.append(filePath()->dataPath("translations")); + filePath()->dataPath("translations") + }; - Q_FOREACH (const QString& path, paths) { + for (const QString& path : paths) { if (installTranslator(language, path)) { return true; } @@ -116,7 +119,7 @@ bool Translator::installTranslator(const QString& language, const QString& path) bool Translator::installQtTranslator(const QString& language) { QTranslator* qtTranslator = new QTranslator(qApp); - if (qtTranslator->load(QString("%1/qt_%2").arg(QLibraryInfo::location(QLibraryInfo::TranslationsPath), language))) { + if (qtTranslator->load(QString("%1/qtbase_%2").arg(QLibraryInfo::location(QLibraryInfo::TranslationsPath), language))) { QCoreApplication::installTranslator(qtTranslator); return true; } diff --git a/src/crypto/Crypto.cpp b/src/crypto/Crypto.cpp index 1ff6fdedf..4669de69a 100644 --- a/src/crypto/Crypto.cpp +++ b/src/crypto/Crypto.cpp @@ -90,13 +90,11 @@ bool Crypto::checkAlgorithms() qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); return false; } -#ifdef GCRYPT_HAS_SALSA20 if (gcry_cipher_algo_info(GCRY_CIPHER_SALSA20, GCRYCTL_TEST_ALGO, nullptr, nullptr) != 0) { m_errorStr = "GCRY_CIPHER_SALSA20 not found."; qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); return false; } -#endif if (gcry_md_test_algo(GCRY_MD_SHA256) != 0) { m_errorStr = "GCRY_MD_SHA256 not found."; qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr)); diff --git a/src/format/CsvExporter.cpp b/src/format/CsvExporter.cpp index 11378642f..c444afe23 100644 --- a/src/format/CsvExporter.cpp +++ b/src/format/CsvExporter.cpp @@ -64,7 +64,8 @@ bool CsvExporter::writeGroup(QIODevice* device, const Group* group, QString grou } groupPath.append(group->name()); - Q_FOREACH (const Entry* entry, group->entries()) { + const QList entryList = group->entries(); + for (const Entry* entry : entryList) { QString line; addColumn(line, groupPath); @@ -82,7 +83,8 @@ bool CsvExporter::writeGroup(QIODevice* device, const Group* group, QString grou } } - Q_FOREACH (const Group* child, group->children()) { + const QList children = group->children(); + for (const Group* child : children) { if (!writeGroup(device, child, groupPath)) { return false; } diff --git a/src/format/KeePass1Reader.cpp b/src/format/KeePass1Reader.cpp index 27c6d1469..4747d7f87 100644 --- a/src/format/KeePass1Reader.cpp +++ b/src/format/KeePass1Reader.cpp @@ -195,7 +195,7 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor return nullptr; } - Q_FOREACH (Entry* entry, entries) { + for (Entry* entry : asConst(entries)) { if (isMetaStream(entry)) { parseMetaStream(entry); @@ -215,7 +215,8 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor db->rootGroup()->setName(tr("Root")); - Q_FOREACH (Group* group, db->rootGroup()->children()) { + const QList children = db->rootGroup()->children(); + for (Group* group : children) { if (group->name() == "Backup") { group->setSearchingEnabled(Group::Disable); group->setAutoTypeEnabled(Group::Disable); @@ -225,11 +226,12 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor Q_ASSERT(m_tmpParent->children().isEmpty()); Q_ASSERT(m_tmpParent->entries().isEmpty()); - Q_FOREACH (Group* group, groups) { + for (Group* group : asConst(groups)) { group->setUpdateTimeinfo(true); } - Q_FOREACH (Entry* entry, m_db->rootGroup()->entriesRecursive()) { + const QList dbEntries = m_db->rootGroup()->entriesRecursive(); + for (Entry* entry : dbEntries) { entry->setUpdateTimeinfo(true); } @@ -298,15 +300,14 @@ QString KeePass1Reader::errorString() SymmetricCipherStream* KeePass1Reader::testKeys(const QString& password, const QByteArray& keyfileData, qint64 contentPos) { - QList encodings; - encodings << Windows1252 << Latin1 << UTF8; + const QList encodings = { Windows1252, Latin1, UTF8 }; QScopedPointer cipherStream; QByteArray passwordData; QTextCodec* codec = QTextCodec::codecForName("Windows-1252"); QByteArray passwordDataCorrect = codec->fromUnicode(password); - Q_FOREACH (PasswordEncoding encoding, encodings) { + for (PasswordEncoding encoding : encodings) { if (encoding == Windows1252) { passwordData = passwordDataCorrect; } @@ -727,7 +728,8 @@ void KeePass1Reader::parseNotes(const QString& rawNotes, Entry* entry) QStringList notes; bool lastLineAutoType = false; - Q_FOREACH (QString line, rawNotes.split("\n")) { + const QStringList rawNotesLines = rawNotes.split("\n"); + for (QString line : rawNotesLines) { line.remove("\r"); if (sequenceRegexp.exactMatch(line)) { @@ -769,8 +771,9 @@ void KeePass1Reader::parseNotes(const QString& rawNotes, Entry* entry) i.next(); QString sequence = sequences.value(i.key()); + const QStringList windowList = i.value(); - Q_FOREACH (const QString& window, i.value()) { + for (const QString& window : windowList) { AutoTypeAssociations::Association assoc; assoc.window = window; assoc.sequence = sequence; diff --git a/src/format/KeePass2Reader.cpp b/src/format/KeePass2Reader.cpp index b0247f788..b45cefa6c 100644 --- a/src/format/KeePass2Reader.cpp +++ b/src/format/KeePass2Reader.cpp @@ -192,7 +192,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke QByteArray headerHash = CryptoHash::hash(headerStream.storedData(), CryptoHash::Sha256); if (headerHash != xmlReader.headerHash()) { raiseError("Header doesn't match hash"); - return nullptr; + return Q_NULLPTR; } } diff --git a/src/format/KeePass2XmlReader.cpp b/src/format/KeePass2XmlReader.cpp index 40087a633..f70672592 100644 --- a/src/format/KeePass2XmlReader.cpp +++ b/src/format/KeePass2XmlReader.cpp @@ -86,17 +86,17 @@ void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Ra } } - QSet poolKeys = m_binaryPool.keys().toSet(); - QSet entryKeys = m_binaryMap.keys().toSet(); - QSet unmappedKeys = entryKeys - poolKeys; - QSet unusedKeys = poolKeys - entryKeys; + const QSet poolKeys = m_binaryPool.keys().toSet(); + const QSet entryKeys = m_binaryMap.keys().toSet(); + const QSet unmappedKeys = entryKeys - poolKeys; + const QSet unusedKeys = poolKeys - entryKeys; if (!unmappedKeys.isEmpty()) { raiseError("Unmapped keys left."); } if (!m_xml.error()) { - Q_FOREACH (const QString& key, unusedKeys) { + for (const QString& key : unusedKeys) { qWarning("KeePass2XmlReader::readDatabase: found unused key \"%s\"", qPrintable(key)); } } @@ -118,7 +118,8 @@ void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Ra for (iEntry = m_entries.constBegin(); iEntry != m_entries.constEnd(); ++iEntry) { iEntry.value()->setUpdateTimeinfo(true); - Q_FOREACH (Entry* histEntry, iEntry.value()->historyItems()) { + const QList historyItems = iEntry.value()->historyItems(); + for (Entry* histEntry : historyItems) { histEntry->setUpdateTimeinfo(true); } } @@ -614,11 +615,11 @@ Group* KeePass2XmlReader::parseGroup() raiseError("No group uuid found"); } - Q_FOREACH (Group* child, children) { + for (Group* child : asConst(children)) { child->setParent(group); } - Q_FOREACH (Entry* entry, entries) { + for (Entry* entry : asConst(entries)) { entry->setGroup(group); } @@ -777,11 +778,18 @@ Entry* KeePass2XmlReader::parseEntry(bool history) raiseError("No entry uuid found"); } - Q_FOREACH (Entry* historyItem, historyItems) { + for (Entry* historyItem : asConst(historyItems)) { + if (historyItem->uuid() != entry->uuid()) { + if (m_strictMode) { + raiseError("History element with different uuid"); + } else { + historyItem->setUuid(entry->uuid()); + } + } entry->addHistoryItem(historyItem); } - Q_FOREACH (const StringPair& ref, binaryRefs) { + for (const StringPair& ref : asConst(binaryRefs)) { m_binaryMap.insertMulti(ref.first, qMakePair(entry, ref.second)); } diff --git a/src/format/KeePass2XmlWriter.cpp b/src/format/KeePass2XmlWriter.cpp index 7fd03cc07..6c92c4b39 100644 --- a/src/format/KeePass2XmlWriter.cpp +++ b/src/format/KeePass2XmlWriter.cpp @@ -82,11 +82,12 @@ QString KeePass2XmlWriter::errorString() void KeePass2XmlWriter::generateIdMap() { - QList allEntries = m_db->rootGroup()->entriesRecursive(true); + const QList allEntries = m_db->rootGroup()->entriesRecursive(true); int nextId = 0; - Q_FOREACH (Entry* entry, allEntries) { - Q_FOREACH (const QString& key, entry->attachments()->keys()) { + for (Entry* entry : allEntries) { + const QList attachmentKeys = entry->attachments()->keys(); + for (const QString& key : attachmentKeys) { QByteArray data = entry->attachments()->value(key); if (!m_idMap.contains(data)) { m_idMap.insert(data, nextId++); @@ -149,7 +150,8 @@ void KeePass2XmlWriter::writeCustomIcons() { m_xml.writeStartElement("CustomIcons"); - Q_FOREACH (const Uuid& uuid, m_meta->customIconsOrder()) { + const QList customIconsOrder = m_meta->customIconsOrder(); + for (const Uuid& uuid : customIconsOrder) { writeIcon(uuid, m_meta->customIcon(uuid)); } @@ -220,7 +222,8 @@ void KeePass2XmlWriter::writeCustomData() m_xml.writeStartElement("CustomData"); QHash customFields = m_meta->customFields(); - Q_FOREACH (const QString& key, customFields.keys()) { + const QList keyList = customFields.keys(); + for (const QString& key : keyList) { writeCustomDataItem(key, customFields.value(key)); } @@ -273,11 +276,13 @@ void KeePass2XmlWriter::writeGroup(const Group* group) writeUuid("LastTopVisibleEntry", group->lastTopVisibleEntry()); - Q_FOREACH (const Entry* entry, group->entries()) { + const QList entryList = group->entries(); + for (const Entry* entry : entryList) { writeEntry(entry); } - Q_FOREACH (const Group* child, group->children()) { + const QList children = group->children(); + for (const Group* child : children) { writeGroup(child); } @@ -303,7 +308,8 @@ void KeePass2XmlWriter::writeDeletedObjects() { m_xml.writeStartElement("DeletedObjects"); - Q_FOREACH (const DeletedObject& delObj, m_db->deletedObjects()) { + const QList delObjList = m_db->deletedObjects(); + for (const DeletedObject& delObj : delObjList) { writeDeletedObject(delObj); } @@ -337,7 +343,8 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry) writeString("Tags", entry->tags()); writeTimes(entry->timeInfo()); - Q_FOREACH (const QString& key, entry->attributes()->keys()) { + const QList attributesKeyList = entry->attributes()->keys(); + for (const QString& key : attributesKeyList) { m_xml.writeStartElement("String"); bool protect = ( ((key == "Title") && m_meta->protectTitle()) || @@ -379,7 +386,8 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry) m_xml.writeEndElement(); } - Q_FOREACH (const QString& key, entry->attachments()->keys()) { + const QList attachmentsKeyList = entry->attachments()->keys(); + for (const QString& key : attachmentsKeyList) { m_xml.writeStartElement("Binary"); writeString("Key", key); @@ -408,7 +416,8 @@ void KeePass2XmlWriter::writeAutoType(const Entry* entry) writeNumber("DataTransferObfuscation", entry->autoTypeObfuscation()); writeString("DefaultSequence", entry->defaultAutoTypeSequence()); - Q_FOREACH (const AutoTypeAssociations::Association& assoc, entry->autoTypeAssociations()->getAll()) { + const QList autoTypeAssociations = entry->autoTypeAssociations()->getAll(); + for (const AutoTypeAssociations::Association& assoc : autoTypeAssociations) { writeAutoTypeAssoc(assoc); } @@ -430,7 +439,7 @@ void KeePass2XmlWriter::writeEntryHistory(const Entry* entry) m_xml.writeStartElement("History"); const QList& historyItems = entry->historyItems(); - Q_FOREACH (const Entry* item, historyItems) { + for (const Entry* item : historyItems) { writeEntry(item); } diff --git a/src/gui/DatabaseSettingsWidget.cpp b/src/gui/DatabaseSettingsWidget.cpp index d4ca8ddba..b0759bf3a 100644 --- a/src/gui/DatabaseSettingsWidget.cpp +++ b/src/gui/DatabaseSettingsWidget.cpp @@ -139,8 +139,8 @@ void DatabaseSettingsWidget::transformRoundsBenchmark() void DatabaseSettingsWidget::truncateHistories() { - QList allEntries = m_db->rootGroup()->entriesRecursive(false); - Q_FOREACH (Entry* entry, allEntries) { + const QList allEntries = m_db->rootGroup()->entriesRecursive(false); + for (Entry* entry : allEntries) { entry->truncateHistory(); } } diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 78a3a12a1..1abb6b452 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -223,7 +223,7 @@ bool DatabaseTabWidget::closeDatabase(Database* db) if (dbName.right(1) == "*") { dbName.chop(1); } - if (dbStruct.dbWidget->isInEditMode() && db->hasKey()) { + if (dbStruct.dbWidget->isInEditMode() && db->hasKey() && dbStruct.dbWidget->isEditWidgetModified()) { QMessageBox::StandardButton result = MessageBox::question( this, tr("Close?"), @@ -296,7 +296,7 @@ bool DatabaseTabWidget::saveDatabase(Database* db) DatabaseManagerStruct& dbStruct = m_dbList[db]; if (dbStruct.saveToFilename) { - QSaveFile saveFile(dbStruct.filePath); + QSaveFile saveFile(dbStruct.canonicalFilePath); if (saveFile.open(QIODevice::WriteOnly)) { m_writer.writeDatabase(&saveFile, db); if (m_writer.hasError()) { @@ -310,6 +310,11 @@ bool DatabaseTabWidget::saveDatabase(Database* db) return false; } } + else { + MessageBox::critical(this, tr("Error"), tr("Writing the database failed.") + "\n\n" + + saveFile.errorString()); + return false; + } dbStruct.modified = false; updateTabName(db); @@ -386,6 +391,9 @@ bool DatabaseTabWidget::saveDatabaseAs(Database* db) return false; } + // refresh fileinfo since the file didn't exist before + fileInfo.refresh(); + dbStruct.modified = false; dbStruct.saveToFilename = true; dbStruct.readOnly = false; @@ -649,7 +657,7 @@ void DatabaseTabWidget::lockDatabases() // show the correct tab widget before we are asking questions about it setCurrentWidget(dbWidget); - if (mode == DatabaseWidget::EditMode) { + if (mode == DatabaseWidget::EditMode && dbWidget->isEditWidgetModified()) { QMessageBox::StandardButton result = MessageBox::question( this, tr("Lock database"), diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 3bca6fa31..120379171 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -194,6 +194,18 @@ bool DatabaseWidget::isInEditMode() const return currentMode() == DatabaseWidget::EditMode; } +bool DatabaseWidget::isEditWidgetModified() const +{ + if (currentWidget() == m_editEntryWidget) { + return m_editEntryWidget->hasBeenModified(); + } + else { + // other edit widget don't have a hasBeenModified() method yet + // assume that they already have been modified + return true; + } +} + QList DatabaseWidget::splitterSizes() const { return m_splitter->sizes(); @@ -311,7 +323,7 @@ void DatabaseWidget::deleteEntries() // get all entry pointers as the indexes change when removing multiple entries QList selectedEntries; - Q_FOREACH (const QModelIndex& index, selected) { + for (const QModelIndex& index : selected) { selectedEntries.append(m_entryView->entryFromIndex(index)); } @@ -335,23 +347,33 @@ void DatabaseWidget::deleteEntries() } if (result == QMessageBox::Yes) { - Q_FOREACH (Entry* entry, selectedEntries) { + for (Entry* entry : asConst(selectedEntries)) { delete entry; } } } else { - if (selected.size() > 1) { - QMessageBox::StandardButton result = MessageBox::question( + QMessageBox::StandardButton result; + + if (selected.size() == 1) { + result = MessageBox::question( + this, tr("Move entry to recycle bin?"), + tr("Do you really want to move entry \"%1\" to the recycle bin?") + .arg(selectedEntries.first()->title()), + QMessageBox::Yes | QMessageBox::No); + } + else { + result = MessageBox::question( this, tr("Move entries to recycle bin?"), tr("Do you really want to move %n entry(s) to the recycle bin?", 0, selected.size()), QMessageBox::Yes | QMessageBox::No); - if (result == QMessageBox::No) { - return; - } } - Q_FOREACH (Entry* entry, selectedEntries) { + if (result == QMessageBox::No) { + return; + } + + for (Entry* entry : asConst(selectedEntries)) { m_db->recycleEntry(entry); } } @@ -493,7 +515,9 @@ void DatabaseWidget::deleteGroup() } bool inRecylceBin = Tools::hasChild(m_db->metadata()->recycleBin(), currentGroup); - if (inRecylceBin || !m_db->metadata()->recycleBinEnabled()) { + bool isRecycleBin = (currentGroup == m_db->metadata()->recycleBin()); + bool isRecycleBinSubgroup = Tools::hasChild(currentGroup, m_db->metadata()->recycleBin()); + if (inRecylceBin || isRecycleBin || isRecycleBinSubgroup || !m_db->metadata()->recycleBinEnabled()) { QMessageBox::StandardButton result = MessageBox::question( this, tr("Delete group?"), tr("Do you really want to delete the group \"%1\" for good?") @@ -659,8 +683,8 @@ void DatabaseWidget::unlockDatabase(bool accepted) replaceDatabase(static_cast(sender())->database()); - QList groups = m_db->rootGroup()->groupsRecursive(true); - Q_FOREACH (Group* group, groups) { + const QList groups = m_db->rootGroup()->groupsRecursive(true); + for (Group* group : groups) { if (group->uuid() == m_groupBeforeLock) { m_groupView->setCurrentGroup(group); break; @@ -871,8 +895,7 @@ bool DatabaseWidget::dbHasKey() const bool DatabaseWidget::canDeleteCurrentGroup() const { bool isRootGroup = m_db->rootGroup() == m_groupView->currentGroup(); - bool isRecycleBin = m_db->metadata()->recycleBin() == m_groupView->currentGroup(); - return !isRootGroup && !isRecycleBin; + return !isRootGroup; } bool DatabaseWidget::isInSearchMode() const diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index 38a685cc6..e49ee86f5 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -74,6 +74,7 @@ public: QStringList customEntryAttributes() const; bool isGroupSelected() const; bool isInEditMode() const; + bool isEditWidgetModified() const; QList splitterSizes() const; void setSplitterSizes(const QList& sizes); QList entryHeaderViewSizes() const; diff --git a/src/gui/DatabaseWidgetStateSync.cpp b/src/gui/DatabaseWidgetStateSync.cpp index 430380c5a..f2359fe03 100644 --- a/src/gui/DatabaseWidgetStateSync.cpp +++ b/src/gui/DatabaseWidgetStateSync.cpp @@ -124,10 +124,10 @@ void DatabaseWidgetStateSync::updateColumnSizes() QList DatabaseWidgetStateSync::variantToIntList(const QVariant& variant) { - QVariantList list = variant.toList(); + const QVariantList list = variant.toList(); QList result; - Q_FOREACH (const QVariant& var, list) { + for (const QVariant& var : list) { bool ok; int size = var.toInt(&ok); if (ok) { @@ -146,7 +146,7 @@ QVariant DatabaseWidgetStateSync::intListToVariant(const QList& list) { QVariantList result; - Q_FOREACH (int value, list) { + for (int value : list) { result.append(value); } diff --git a/src/gui/EditWidgetIcons.cpp b/src/gui/EditWidgetIcons.cpp index 3d3565c5a..ba1d9b231 100644 --- a/src/gui/EditWidgetIcons.cpp +++ b/src/gui/EditWidgetIcons.cpp @@ -19,6 +19,7 @@ #include "ui_EditWidgetIcons.h" #include +#include #include "core/Group.h" #include "core/Metadata.h" @@ -60,11 +61,8 @@ EditWidgetIcons::~EditWidgetIcons() { } -IconStruct EditWidgetIcons::save() +IconStruct EditWidgetIcons::state() const { - Q_ASSERT(m_database); - Q_ASSERT(!m_currentUuid.isNull()); - IconStruct iconStruct; if (m_ui->defaultIconsRadio->isChecked()) { QModelIndex index = m_ui->defaultIconsView->currentIndex(); @@ -85,9 +83,13 @@ IconStruct EditWidgetIcons::save() } } + return iconStruct; +} + +void EditWidgetIcons::reset() +{ m_database = nullptr; m_currentUuid = Uuid(); - return iconStruct; } void EditWidgetIcons::load(Uuid currentUuid, Database* database, IconStruct iconStruct) @@ -129,7 +131,10 @@ void EditWidgetIcons::addCustomIcon() QString filename = QFileDialog::getOpenFileName( this, tr("Select Image"), "", filter); if (!filename.isEmpty()) { - QImage image(filename); + QImageReader imageReader(filename); + // detect from content, otherwise reading fails if file extension is wrong + imageReader.setDecideFormatFromContent(true); + QImage image = imageReader.read(); if (!image.isNull()) { Uuid uuid = Uuid::random(); m_database->metadata()->addCustomIconScaled(uuid, image); @@ -139,7 +144,8 @@ void EditWidgetIcons::addCustomIcon() m_ui->customIconsView->setCurrentIndex(index); } else { - // TODO: show error + MessageBox::critical(this, tr("Error"), + tr("Can't read icon:").append("\n").append(imageReader.errorString())); } } } @@ -153,10 +159,10 @@ void EditWidgetIcons::removeCustomIcon() Uuid iconUuid = m_customIconModel->uuidFromIndex(index); int iconUsedCount = 0; - QList allEntries = m_database->rootGroup()->entriesRecursive(true); + const QList allEntries = m_database->rootGroup()->entriesRecursive(true); QList historyEntriesWithSameIcon; - Q_FOREACH (Entry* entry, allEntries) { + for (Entry* entry : allEntries) { bool isHistoryEntry = !entry->group(); if (iconUuid == entry->iconUuid()) { if (isHistoryEntry) { @@ -168,15 +174,15 @@ void EditWidgetIcons::removeCustomIcon() } } - QList allGroups = m_database->rootGroup()->groupsRecursive(true); - Q_FOREACH (const Group* group, allGroups) { + const QList allGroups = m_database->rootGroup()->groupsRecursive(true); + for (const Group* group : allGroups) { if (iconUuid == group->iconUuid() && m_currentUuid != group->uuid()) { iconUsedCount++; } } if (iconUsedCount == 0) { - Q_FOREACH (Entry* entry, historyEntriesWithSameIcon) { + for (Entry* entry : asConst(historyEntriesWithSameIcon)) { entry->setUpdateTimeinfo(false); entry->setIcon(0); entry->setUpdateTimeinfo(true); diff --git a/src/gui/EditWidgetIcons.h b/src/gui/EditWidgetIcons.h index f3f3f11c5..db58801fa 100644 --- a/src/gui/EditWidgetIcons.h +++ b/src/gui/EditWidgetIcons.h @@ -46,7 +46,8 @@ public: explicit EditWidgetIcons(QWidget* parent = nullptr); ~EditWidgetIcons(); - IconStruct save(); + IconStruct state() const; + void reset(); void load(Uuid currentUuid, Database* database, IconStruct iconStruct); private Q_SLOTS: diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 24e526615..6dccf1dc3 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -269,8 +269,8 @@ void MainWindow::updateLastDatabasesMenu() { m_ui->menuRecentDatabases->clear(); - QStringList lastDatabases = config()->get("LastDatabases", QVariant()).toStringList(); - Q_FOREACH (const QString& database, lastDatabases) { + const QStringList lastDatabases = config()->get("LastDatabases", QVariant()).toStringList(); + for (const QString& database : lastDatabases) { QAction* action = m_ui->menuRecentDatabases->addAction(database); action->setData(database); m_lastDatabasesActions->addAction(action); @@ -295,7 +295,8 @@ void MainWindow::updateCopyAttributesMenu() delete actions[i]; } - Q_FOREACH (const QString& key, dbWidget->customEntryAttributes()) { + const QStringList customEntryAttributes = dbWidget->customEntryAttributes(); + for (const QString& key : customEntryAttributes) { QAction* action = m_ui->menuEntryCopyAttribute->addAction(key); m_copyAdditionalAttributeActions->addAction(action); } @@ -372,12 +373,14 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) break; } case DatabaseWidget::EditMode: - case DatabaseWidget::LockedMode: - Q_FOREACH (QAction* action, m_ui->menuEntries->actions()) { + case DatabaseWidget::LockedMode: { + const QList entryActions = m_ui->menuEntries->actions(); + for (QAction* action : entryActions) { action->setEnabled(false); } - Q_FOREACH (QAction* action, m_ui->menuGroups->actions()) { + const QList groupActions = m_ui->menuGroups->actions(); + for (QAction* action : groupActions) { action->setEnabled(false); } m_ui->actionEntryCopyTitle->setEnabled(false); @@ -394,17 +397,20 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) m_ui->actionDatabaseSaveAs->setEnabled(false); m_ui->actionExportCsv->setEnabled(false); break; + } default: Q_ASSERT(false); } m_ui->actionDatabaseClose->setEnabled(true); } else { - Q_FOREACH (QAction* action, m_ui->menuEntries->actions()) { + const QList entryActions = m_ui->menuEntries->actions(); + for (QAction* action : entryActions) { action->setEnabled(false); } - Q_FOREACH (QAction* action, m_ui->menuGroups->actions()) { + const QList groupActions = m_ui->menuGroups->actions(); + for (QAction* action : groupActions) { action->setEnabled(false); } m_ui->actionEntryCopyTitle->setEnabled(false); diff --git a/src/gui/PasswordComboBox.cpp b/src/gui/PasswordComboBox.cpp index e1218505d..1f6c068f1 100644 --- a/src/gui/PasswordComboBox.cpp +++ b/src/gui/PasswordComboBox.cpp @@ -49,7 +49,7 @@ void PasswordComboBox::setEcho(bool echo) // Qt on Mac OS doesn't seem to know the generic monospace family (tested with 4.8.6) setStyleSheet("QComboBox { font-family: monospace,Menlo,Monaco; }"); #else - setStyleSheet("QComboBox { font-family: monospace,Courier; }"); + setStyleSheet("QComboBox { font-family: monospace,Courier New; }"); #endif } else { diff --git a/src/gui/PasswordEdit.cpp b/src/gui/PasswordEdit.cpp index e5bbf6b34..3fd5d478c 100644 --- a/src/gui/PasswordEdit.cpp +++ b/src/gui/PasswordEdit.cpp @@ -58,7 +58,7 @@ void PasswordEdit::updateStylesheet() // Qt on Mac OS doesn't seem to know the generic monospace family (tested with 4.8.6) stylesheet.append("font-family: monospace,Menlo,Monaco; "); #else - stylesheet.append("font-family: monospace; "); + stylesheet.append("font-family: monospace,Courier New; "); #endif } diff --git a/src/gui/PasswordGeneratorWidget.cpp b/src/gui/PasswordGeneratorWidget.cpp index d6fb12bea..95efa5b2b 100644 --- a/src/gui/PasswordGeneratorWidget.cpp +++ b/src/gui/PasswordGeneratorWidget.cpp @@ -88,6 +88,14 @@ void PasswordGeneratorWidget::reset() updateGenerator(); } +void PasswordGeneratorWidget::regeneratePassword() +{ + if (m_generator->isValid()) { + QString password = m_generator->generatePassword(); + m_ui->editNewPassword->setEditText(password); + } +} + void PasswordGeneratorWidget::updateApplyEnabled(const QString& password) { m_ui->buttonApply->setEnabled(!password.isEmpty()); @@ -111,6 +119,10 @@ void PasswordGeneratorWidget::sliderMoved() void PasswordGeneratorWidget::spinBoxChanged() { + if (m_updatingSpinBox) { + return; + } + // Interlock so that we don't update twice - this causes issues as the spinbox can go higher than slider m_updatingSpinBox = true; @@ -161,12 +173,39 @@ PasswordGenerator::GeneratorFlags PasswordGeneratorWidget::generatorFlags() void PasswordGeneratorWidget::updateGenerator() { - m_generator->setLength(m_ui->spinBoxLength->value()); - m_generator->setCharClasses(charClasses()); - m_generator->setFlags(generatorFlags()); + PasswordGenerator::CharClasses classes = charClasses(); + PasswordGenerator::GeneratorFlags flags = generatorFlags(); - if (m_generator->isValid()) { - QString password = m_generator->generatePassword(); - m_ui->editNewPassword->setEditText(password); + int minLength = 0; + if (flags.testFlag(PasswordGenerator::CharFromEveryGroup)) { + if (classes.testFlag(PasswordGenerator::LowerLetters)) { + minLength++; + } + if (classes.testFlag(PasswordGenerator::UpperLetters)) { + minLength++; + } + if (classes.testFlag(PasswordGenerator::Numbers)) { + minLength++; + } + if (classes.testFlag(PasswordGenerator::SpecialCharacters)) { + minLength++; + } } + minLength = qMax(minLength, 1); + + if (m_ui->spinBoxLength->value() < minLength) { + m_updatingSpinBox = true; + m_ui->spinBoxLength->setValue(minLength); + m_ui->sliderLength->setValue(minLength); + m_updatingSpinBox = false; + } + + m_ui->spinBoxLength->setMinimum(minLength); + m_ui->sliderLength->setMinimum(minLength); + + m_generator->setLength(m_ui->spinBoxLength->value()); + m_generator->setCharClasses(classes); + m_generator->setFlags(flags); + + regeneratePassword(); } diff --git a/src/gui/PasswordGeneratorWidget.h b/src/gui/PasswordGeneratorWidget.h index cfb21bbec..46ef08c3b 100644 --- a/src/gui/PasswordGeneratorWidget.h +++ b/src/gui/PasswordGeneratorWidget.h @@ -38,6 +38,7 @@ public: ~PasswordGeneratorWidget(); void loadSettings(); void reset(); + void regeneratePassword(); Q_SIGNALS: void newPassword(const QString& password); diff --git a/src/gui/entry/EditEntryWidget.cpp b/src/gui/entry/EditEntryWidget.cpp index 5ad612cfc..77f68c927 100644 --- a/src/gui/entry/EditEntryWidget.cpp +++ b/src/gui/entry/EditEntryWidget.cpp @@ -414,55 +414,60 @@ void EditEntryWidget::saveEntry() // we don't want to create a new history item, if only the history has changed m_entry->removeHistoryItems(m_historyModel->deletedEntries()); + m_autoTypeAssoc->removeEmpty(); + if (!m_create) { m_entry->beginUpdate(); } - m_entry->setTitle(m_mainUi->titleEdit->text()); - m_entry->setUsername(m_mainUi->usernameEdit->text()); - m_entry->setUrl(m_mainUi->urlEdit->text()); - m_entry->setPassword(m_mainUi->passwordEdit->text()); - m_entry->setExpires(m_mainUi->expireCheck->isChecked()); - m_entry->setExpiryTime(m_mainUi->expireDatePicker->dateTime().toUTC()); - - m_entry->setNotes(m_mainUi->notesEdit->toPlainText()); - - m_entry->attributes()->copyCustomKeysFrom(m_entryAttributes); - m_entry->attachments()->copyDataFrom(m_entryAttachments); - - IconStruct iconStruct = m_iconsWidget->save(); - - if (iconStruct.number < 0) { - m_entry->setIcon(Entry::DefaultIconNumber); - } - else if (iconStruct.uuid.isNull()) { - m_entry->setIcon(iconStruct.number); - } - else { - m_entry->setIcon(iconStruct.uuid); - } - - m_entry->setAutoTypeEnabled(m_autoTypeUi->enableButton->isChecked()); - if (m_autoTypeUi->inheritSequenceButton->isChecked()) { - m_entry->setDefaultAutoTypeSequence(QString()); - } - else { - m_entry->setDefaultAutoTypeSequence(m_autoTypeUi->sequenceEdit->text()); - } - - m_autoTypeAssoc->removeEmpty(); - m_entry->autoTypeAssociations()->copyDataFrom(m_autoTypeAssoc); + updateEntryData(m_entry); if (!m_create) { m_entry->endUpdate(); } - clear(); Q_EMIT editFinished(true); } +void EditEntryWidget::updateEntryData(Entry* entry) const +{ + entry->setTitle(m_mainUi->titleEdit->text()); + entry->setUsername(m_mainUi->usernameEdit->text()); + entry->setUrl(m_mainUi->urlEdit->text()); + entry->setPassword(m_mainUi->passwordEdit->text()); + entry->setExpires(m_mainUi->expireCheck->isChecked()); + entry->setExpiryTime(m_mainUi->expireDatePicker->dateTime().toUTC()); + + entry->setNotes(m_mainUi->notesEdit->toPlainText()); + + entry->attributes()->copyCustomKeysFrom(m_entryAttributes); + entry->attachments()->copyDataFrom(m_entryAttachments); + + IconStruct iconStruct = m_iconsWidget->state(); + + if (iconStruct.number < 0) { + entry->setIcon(Entry::DefaultIconNumber); + } + else if (iconStruct.uuid.isNull()) { + entry->setIcon(iconStruct.number); + } + else { + entry->setIcon(iconStruct.uuid); + } + + entry->setAutoTypeEnabled(m_autoTypeUi->enableButton->isChecked()); + if (m_autoTypeUi->inheritSequenceButton->isChecked()) { + entry->setDefaultAutoTypeSequence(QString()); + } + else { + entry->setDefaultAutoTypeSequence(m_autoTypeUi->sequenceEdit->text()); + } + + entry->autoTypeAssociations()->copyDataFrom(m_autoTypeAssoc); +} + void EditEntryWidget::cancel() { if (m_history) { @@ -489,10 +494,28 @@ void EditEntryWidget::clear() m_entryAttachments->clear(); m_autoTypeAssoc->clear(); m_historyModel->clear(); + m_iconsWidget->reset(); +} + +bool EditEntryWidget::hasBeenModified() const +{ + // entry has been modified if a history item is to be deleted + if (!m_historyModel->deletedEntries().isEmpty()) { + return true; + } + + // check if updating the entry would modify it + QScopedPointer entry(new Entry()); + entry->copyDataFrom(m_entry); + + entry->beginUpdate(); + updateEntryData(entry.data()); + return entry->endUpdate(); } void EditEntryWidget::togglePasswordGeneratorButton(bool checked) { + m_mainUi->passwordGenerator->regeneratePassword(); m_mainUi->passwordGenerator->setVisible(checked); } diff --git a/src/gui/entry/EditEntryWidget.h b/src/gui/entry/EditEntryWidget.h index 3c66b2a57..c8045d93c 100644 --- a/src/gui/entry/EditEntryWidget.h +++ b/src/gui/entry/EditEntryWidget.h @@ -61,6 +61,7 @@ public: void createPresetsMenu(QMenu* expirePresetsMenu); QString entryTitle() const; void clear(); + bool hasBeenModified() const; Q_SIGNALS: void editFinished(bool accepted); @@ -107,6 +108,7 @@ private: bool passwordsEqual(); void setForms(const Entry* entry, bool restore = false); QMenu* createPresetsMenu(); + void updateEntryData(Entry* entry) const; Entry* m_entry; Database* m_database; diff --git a/src/gui/entry/EntryAttributesModel.cpp b/src/gui/entry/EntryAttributesModel.cpp index 297740c3c..b22380ae8 100644 --- a/src/gui/entry/EntryAttributesModel.cpp +++ b/src/gui/entry/EntryAttributesModel.cpp @@ -232,7 +232,8 @@ void EntryAttributesModel::updateAttributes() { m_attributes.clear(); - Q_FOREACH (const QString& key, m_entryAttributes->keys()) { + const QList attributesKeyList = m_entryAttributes->keys(); + for (const QString& key : attributesKeyList) { if (!EntryAttributes::isDefaultAttribute(key)) { m_attributes.append(key); } diff --git a/src/gui/entry/EntryHistoryModel.cpp b/src/gui/entry/EntryHistoryModel.cpp index 58aa49a69..ca21055c6 100644 --- a/src/gui/entry/EntryHistoryModel.cpp +++ b/src/gui/entry/EntryHistoryModel.cpp @@ -18,6 +18,7 @@ #include "EntryHistoryModel.h" #include "core/Entry.h" +#include "core/Global.h" EntryHistoryModel::EntryHistoryModel(QObject* parent) : QAbstractTableModel(parent) @@ -136,7 +137,7 @@ void EntryHistoryModel::deleteAll() beginRemoveRows(QModelIndex(), 0, m_historyEntries.size() - 1); - Q_FOREACH (Entry* entry, m_historyEntries) { + for (Entry* entry : asConst(m_historyEntries)) { m_deletedHistoryEntries << entry; } m_historyEntries.clear(); diff --git a/src/gui/entry/EntryModel.cpp b/src/gui/entry/EntryModel.cpp index efb64deac..d606a777e 100644 --- a/src/gui/entry/EntryModel.cpp +++ b/src/gui/entry/EntryModel.cpp @@ -22,6 +22,7 @@ #include "core/DatabaseIcons.h" #include "core/Entry.h" +#include "core/Global.h" #include "core/Group.h" #include "core/Metadata.h" @@ -78,13 +79,14 @@ void EntryModel::setEntryList(const QList& entries) QSet databases; - Q_FOREACH (Entry* entry, m_entries) { + for (Entry* entry : asConst(m_entries)) { databases.insert(entry->group()->database()); } - Q_FOREACH (Database* db, databases) { + for (Database* db : asConst(databases)) { Q_ASSERT(db); - Q_FOREACH (const Group* group, db->rootGroup()->groupsRecursive(true)) { + const QList groupList = db->rootGroup()->groupsRecursive(true); + for (const Group* group : groupList) { m_allGroups.append(group); } @@ -93,7 +95,7 @@ void EntryModel::setEntryList(const QList& entries) } } - Q_FOREACH (const Group* group, m_allGroups) { + for (const Group* group : asConst(m_allGroups)) { makeConnections(group); } @@ -224,7 +226,7 @@ QMimeData* EntryModel::mimeData(const QModelIndexList& indexes) const QSet seenEntries; - Q_FOREACH (const QModelIndex& index, indexes) { + for (const QModelIndex& index : indexes) { if (!index.isValid()) { continue; } @@ -301,7 +303,7 @@ void EntryModel::severConnections() disconnect(m_group, nullptr, this, nullptr); } - Q_FOREACH (const Group* group, m_allGroups) { + for (const Group* group : asConst(m_allGroups)) { disconnect(group, nullptr, this, nullptr); } } diff --git a/src/gui/group/EditGroupWidget.cpp b/src/gui/group/EditGroupWidget.cpp index 7fdec89a2..a5b426b92 100644 --- a/src/gui/group/EditGroupWidget.cpp +++ b/src/gui/group/EditGroupWidget.cpp @@ -113,7 +113,7 @@ void EditGroupWidget::save() m_group->setDefaultAutoTypeSequence(m_mainUi->autoTypeSequenceCustomEdit->text()); } - IconStruct iconStruct = m_editGroupWidgetIcons->save(); + IconStruct iconStruct = m_editGroupWidgetIcons->state(); if (iconStruct.number < 0) { m_group->setIcon(Group::DefaultIconNumber); @@ -144,6 +144,7 @@ void EditGroupWidget::clear() { m_group = nullptr; m_database = nullptr; + m_editGroupWidgetIcons->reset(); } void EditGroupWidget::addTriStateItems(QComboBox* comboBox, bool inheritDefault) diff --git a/src/gui/group/GroupModel.cpp b/src/gui/group/GroupModel.cpp index fc6d83eae..5aafc1a79 100644 --- a/src/gui/group/GroupModel.cpp +++ b/src/gui/group/GroupModel.cpp @@ -338,7 +338,7 @@ QMimeData* GroupModel::mimeData(const QModelIndexList& indexes) const QSet seenGroups; - Q_FOREACH (const QModelIndex& index, indexes) { + for (const QModelIndex& index : indexes) { if (!index.isValid()) { continue; } diff --git a/src/gui/group/GroupView.cpp b/src/gui/group/GroupView.cpp index 1f94dc0fc..31f5639fc 100644 --- a/src/gui/group/GroupView.cpp +++ b/src/gui/group/GroupView.cpp @@ -98,7 +98,8 @@ void GroupView::recInitExpanded(Group* group) expandGroup(group, group->isExpanded()); m_updatingExpanded = false; - Q_FOREACH (Group* child, group->children()) { + const QList children = group->children(); + for (Group* child : children) { recInitExpanded(child); } } diff --git a/src/keys/CompositeKey.cpp b/src/keys/CompositeKey.cpp index d38f466fd..16b48592e 100644 --- a/src/keys/CompositeKey.cpp +++ b/src/keys/CompositeKey.cpp @@ -21,6 +21,7 @@ #include #include +#include "core/Global.h" #include "crypto/CryptoHash.h" #include "crypto/SymmetricCipher.h" @@ -63,7 +64,7 @@ CompositeKey& CompositeKey::operator=(const CompositeKey& key) clear(); - Q_FOREACH (const Key* subKey, key.m_keys) { + for (const Key* subKey : asConst(key.m_keys)) { addKey(*subKey); } @@ -74,7 +75,7 @@ QByteArray CompositeKey::rawKey() const { CryptoHash cryptoHash(CryptoHash::Sha256); - Q_FOREACH (const Key* key, m_keys) { + for (const Key* key : m_keys) { cryptoHash.addData(key->rawKey()); } diff --git a/src/main.cpp b/src/main.cpp index b185f78b4..655fb91ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,8 +95,8 @@ int main(int argc, char** argv) } if (config()->get("OpenPreviousDatabasesOnStartup").toBool()) { - QStringList filenames = config()->get("LastOpenedDatabases").toStringList(); - Q_FOREACH (const QString& filename, filenames) { + const QStringList filenames = config()->get("LastOpenedDatabases").toStringList(); + for (const QString& filename : filenames) { if (!filename.isEmpty() && QFile::exists(filename)) { mainWindow.openDatabase(filename, QString(), QString()); } diff --git a/tests/TestGroup.cpp b/tests/TestGroup.cpp index 13ce82ea5..a923776de 100644 --- a/tests/TestGroup.cpp +++ b/tests/TestGroup.cpp @@ -385,7 +385,12 @@ void TestGroup::testClone() QVERIFY(clonedSubGroupEntry->uuid() != subGroupEntry->uuid()); QCOMPARE(clonedSubGroupEntry->title(), QString("SubGroupEntry")); + Group* clonedGroupKeepUuid = originalGroup->clone(Entry::CloneNoFlags); + QCOMPARE(clonedGroupKeepUuid->entries().at(0)->uuid(), originalGroupEntry->uuid()); + QCOMPARE(clonedGroupKeepUuid->children().at(0)->entries().at(0)->uuid(), subGroupEntry->uuid()); + delete clonedGroup; + delete clonedGroupKeepUuid; delete db; } diff --git a/tests/TestKeePass2Writer.cpp b/tests/TestKeePass2Writer.cpp index 60b7b90eb..9f0c87be7 100644 --- a/tests/TestKeePass2Writer.cpp +++ b/tests/TestKeePass2Writer.cpp @@ -18,6 +18,7 @@ #include "TestKeePass2Writer.h" #include +#include #include #include "config-keepassx-tests.h" diff --git a/tests/TestKeePass2XmlReader.cpp b/tests/TestKeePass2XmlReader.cpp index f04c54806..495b39acf 100644 --- a/tests/TestKeePass2XmlReader.cpp +++ b/tests/TestKeePass2XmlReader.cpp @@ -406,6 +406,8 @@ void TestKeePass2XmlReader::testBroken_data() QTest::newRow("BrokenGroupReference (not strict)") << "BrokenGroupReference" << false << false; QTest::newRow("BrokenDeletedObjects (strict)") << "BrokenDeletedObjects" << true << true; QTest::newRow("BrokenDeletedObjects (not strict)") << "BrokenDeletedObjects" << false << false; + QTest::newRow("BrokenDifferentEntryHistoryUuid (strict)") << "BrokenDifferentEntryHistoryUuid" << true << true; + QTest::newRow("BrokenDifferentEntryHistoryUuid (not strict)") << "BrokenDifferentEntryHistoryUuid" << false << false; } void TestKeePass2XmlReader::testEmptyUuids() @@ -486,6 +488,32 @@ void TestKeePass2XmlReader::testInvalidXmlChars() QCOMPARE(strToBytes(attrRead->value("SurrogateValid2")), strToBytes(strSurrogateValid2)); } +void TestKeePass2XmlReader::testRepairUuidHistoryItem() +{ + KeePass2XmlReader reader; + QString xmlFile = QString("%1/%2.xml").arg(KEEPASSX_TEST_DATA_DIR, "BrokenDifferentEntryHistoryUuid"); + QVERIFY(QFile::exists(xmlFile)); + QScopedPointer db(reader.readDatabase(xmlFile)); + if (reader.hasError()) { + qWarning("Database read error: %s", qPrintable(reader.errorString())); + } + QVERIFY(!reader.hasError()); + + + + QList entries = db.data()->rootGroup()->entries(); + QCOMPARE(entries.size(), 1); + Entry* entry = entries.at(0); + + QList historyItems = entry->historyItems(); + QCOMPARE(historyItems.size(), 1); + Entry* historyItem = historyItems.at(0); + + QVERIFY(!entry->uuid().isNull()); + QVERIFY(!historyItem->uuid().isNull()); + QCOMPARE(historyItem->uuid(), entry->uuid()); +} + void TestKeePass2XmlReader::cleanupTestCase() { delete m_db; diff --git a/tests/TestKeePass2XmlReader.h b/tests/TestKeePass2XmlReader.h index b9be7b553..ff83e2597 100644 --- a/tests/TestKeePass2XmlReader.h +++ b/tests/TestKeePass2XmlReader.h @@ -43,6 +43,7 @@ private Q_SLOTS: void testBroken_data(); void testEmptyUuids(); void testInvalidXmlChars(); + void testRepairUuidHistoryItem(); void cleanupTestCase(); private: diff --git a/tests/data/BrokenDifferentEntryHistoryUuid.xml b/tests/data/BrokenDifferentEntryHistoryUuid.xml new file mode 100644 index 000000000..c07f03aa7 --- /dev/null +++ b/tests/data/BrokenDifferentEntryHistoryUuid.xml @@ -0,0 +1,17 @@ + + + + + lmU+9n0aeESKZvcEze+bRg== + Test + + MTExMTExMTExMTExMTExMQ== + + + MjIyMjIyMjIyMjIyMjIyMg== + + + + + + diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index 1585c8a6b..90d7fc2b0 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -240,6 +240,7 @@ void TestGui::testSearch() QVERIFY(entryDeleteWidget->isEnabled()); QVERIFY(!m_db->metadata()->recycleBin()); + MessageBox::setNextAnswer(QMessageBox::Yes); QTest::mouseClick(entryDeleteWidget, Qt::LeftButton); QCOMPARE(entryView->model()->rowCount(), 3);