File indexing completed on 2024-04-28 15:40:26
0001 // SPDX-FileCopyrightText: 2023 Jesper K. Pedersen <jesper.pedersen@kdab.com> 0002 // 0003 // SPDX-License-Identifier: GPL-2.0-or-later 0004 0005 #include "AnnotationHandler.h" 0006 #include "Logging.h" 0007 #include "SelectCategoryAndValue.h" 0008 0009 #include <kpabase/SettingsData.h> 0010 0011 #include <KConfigGroup> 0012 #include <KLocalizedString> 0013 #include <KSharedConfig> 0014 #include <QDebug> 0015 #include <QKeyEvent> 0016 #include <QLocale> 0017 #include <qnamespace.h> 0018 0019 namespace Viewer 0020 { 0021 0022 AnnotationHandler::AnnotationHandler(QObject *parent) 0023 : QObject(parent) 0024 { 0025 loadSettings(); 0026 } 0027 0028 namespace 0029 { 0030 bool isKeyboardLetter(const QString &txt) 0031 { 0032 if (txt.isEmpty()) 0033 return false; 0034 0035 #if 0 0036 // See https://www.kdab.com/a-little-hidden-gem-qstringiterator/ for details 0037 // Unfortunately this requires a private header, which our CI doesn't like 0038 QStringIterator i(txt); 0039 char32_t ch = i.next(); 0040 return QChar::isLetter(ch); 0041 #else 0042 return QLocale().toUpper(txt) != txt; 0043 #endif 0044 } 0045 }; 0046 0047 bool AnnotationHandler::handle(QKeyEvent *event) 0048 { 0049 const auto key = event->text().toLower(); 0050 0051 if (key.isEmpty() || !isKeyboardLetter(key) || (event->modifiers() != Qt::KeyboardModifiers() && event->modifiers() != Qt::KeyboardModifiers(Qt::ShiftModifier))) 0052 return false; 0053 0054 if (!m_assignments.contains(key) || event->modifiers().testFlag(Qt::ShiftModifier)) { 0055 const bool assigned = assignKey(key); 0056 if (!assigned) 0057 return false; 0058 } 0059 const auto match = m_assignments.value(key); 0060 0061 Q_EMIT requestToggleCategory(match.category, match.value); 0062 0063 return true; 0064 } 0065 0066 bool AnnotationHandler::assignKey(const QString &key) 0067 { 0068 SelectCategoryAndValue dialog(i18nc("@title", "Assign Macro"), i18n("Select item for macro key <b>%1</b>", key), m_assignments); 0069 connect(&dialog, &SelectCategoryAndValue::helpRequest, this, &AnnotationHandler::requestHelp); 0070 connect(&dialog, &SelectCategoryAndValue::keyRemovalRequested, this, &AnnotationHandler::clearKey); 0071 0072 auto result = dialog.exec(); 0073 if (result == QDialog::Rejected) 0074 return false; 0075 0076 m_assignments[key] = { dialog.category(), dialog.value() }; 0077 qCDebug(ViewerLog) << "Added macro assignment of key" << key << "to:" << m_assignments.value(key); 0078 saveSettings(); 0079 return true; 0080 } 0081 0082 void AnnotationHandler::clearKey(const QString &key) 0083 { 0084 qCDebug(ViewerLog) << "Removed macro assignment of key" << key << "to:" << m_assignments.value(key); 0085 m_assignments.remove(key); 0086 saveSettings(); 0087 } 0088 0089 namespace 0090 { 0091 KConfigGroup configGroup() 0092 { 0093 const auto section = Settings::SettingsData::instance()->groupForDatabase("viewer keybindings"); 0094 return KSharedConfig::openConfig(QString::fromLatin1("kphotoalbumrc"))->group(section); 0095 } 0096 } 0097 0098 void AnnotationHandler::saveSettings() 0099 { 0100 0101 KConfigGroup group = configGroup(); 0102 // delete group so that removed keys are removed: 0103 group.deleteGroup(); 0104 for (auto it = m_assignments.cbegin(); it != m_assignments.cend(); ++it) { 0105 auto subgroup = group.group(it.key()); 0106 const auto item = it.value(); 0107 subgroup.writeEntry("category", item.category); 0108 subgroup.writeEntry("value", item.value); 0109 } 0110 group.sync(); 0111 } 0112 0113 void AnnotationHandler::loadSettings() 0114 { 0115 KConfigGroup group = configGroup(); 0116 const QStringList keys = group.groupList(); 0117 for (const QString &key : keys) { 0118 auto subgroup = group.group(key); 0119 m_assignments[key] = { subgroup.readEntry("category"), subgroup.readEntry("value") }; 0120 } 0121 } 0122 0123 bool AnnotationHandler::askForTagAndInsert() 0124 { 0125 SelectCategoryAndValue dialog(i18n("Tag Item"), i18n("Select tag for image"), m_assignments); 0126 connect(&dialog, &SelectCategoryAndValue::helpRequest, this, &AnnotationHandler::requestHelp); 0127 0128 auto result = dialog.exec(); 0129 if (result == QDialog::Rejected) 0130 return false; 0131 Q_EMIT requestToggleCategory(dialog.category(), dialog.value()); 0132 return true; 0133 } 0134 0135 AnnotationHandler::Assignments AnnotationHandler::assignments() const 0136 { 0137 return m_assignments; 0138 } 0139 0140 QDebug operator<<(QDebug debug, const AnnotationHandler::Assignment &a) 0141 { 0142 QDebugStateSaver saveState(debug); 0143 debug.nospace().noquote() << "\"" << a.category << "/" << a.value << "\""; 0144 return debug; 0145 } 0146 0147 } // namespace Viewer