File indexing completed on 2024-04-21 15:02:25
0001 /* 0002 SPDX-FileCopyrightText: 2016 Dan Leinir Turthra Jensen <admin@leinir.dk> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "quickengine.h" 0008 #include "quicksettings.h" 0009 0010 #if KNEWSTUFFQUICK_BUILD_DEPRECATED_SINCE(5, 81) 0011 #include <KAuthorized> 0012 #endif 0013 #include <KLocalizedString> 0014 0015 #include "categoriesmodel.h" 0016 #include "quickquestionlistener.h" 0017 #include "searchpresetmodel.h" 0018 0019 #include "engine.h" 0020 0021 class EnginePrivate 0022 { 0023 public: 0024 EnginePrivate() 0025 : engine(nullptr) 0026 , categoriesModel(nullptr) 0027 , searchPresetModel(nullptr) 0028 { 0029 } 0030 KNSCore::Engine *engine; 0031 bool isLoading{false}; 0032 bool isValid{false}; 0033 CategoriesModel *categoriesModel; 0034 SearchPresetModel *searchPresetModel; 0035 QString configFile; 0036 0037 #if KNEWSTUFF_BUILD_DEPRECATED_SINCE(5, 82) 0038 KNSCore::EntryInternal::List changedEntries; 0039 static KNSCore::EntryWrapper *getChangedEntry(QQmlListProperty<KNSCore::EntryWrapper> *property, int i) 0040 { 0041 KNSCore::EntryWrapper *entry{nullptr}; 0042 if (property) { 0043 auto d = static_cast<EnginePrivate *>(property->data); 0044 if (d) { 0045 if (i >= 0 && i < d->changedEntries.count()) { 0046 // Lifetime management for these objects should be done by the consumer, 0047 // but are also parented for auto-delete on application shutdown 0048 entry = new KNSCore::EntryWrapper(d->changedEntries[i], property->object); 0049 } 0050 } 0051 } 0052 return entry; 0053 } 0054 static int getChangedEntriesCount(QQmlListProperty<KNSCore::EntryWrapper> *property) 0055 { 0056 int count{0}; 0057 if (property) { 0058 auto d = static_cast<EnginePrivate *>(property->data); 0059 if (d) { 0060 count = d->changedEntries.count(); 0061 } 0062 } 0063 return count; 0064 } 0065 #endif 0066 }; 0067 0068 Engine::Engine(QObject *parent) 0069 : QObject(parent) 0070 , d(new EnginePrivate) 0071 { 0072 } 0073 0074 Engine::~Engine() = default; 0075 0076 #if KNEWSTUFFQUICK_BUILD_DEPRECATED_SINCE(5, 81) 0077 bool Engine::allowedByKiosk() const 0078 { 0079 return KAuthorized::authorize(KAuthorized::GHNS); 0080 } 0081 #endif 0082 0083 QString Engine::configFile() const 0084 { 0085 return d->configFile; 0086 } 0087 0088 void Engine::setConfigFile(const QString &newFile) 0089 { 0090 if (d->configFile != newFile) { 0091 d->isLoading = true; 0092 Q_EMIT isLoadingChanged(); 0093 d->configFile = newFile; 0094 Q_EMIT configFileChanged(); 0095 0096 if (KNewStuffQuick::Settings::instance()->allowedByKiosk()) { 0097 if (!d->engine) { 0098 d->engine = new KNSCore::Engine(this); 0099 connect(d->engine, &KNSCore::Engine::signalProvidersLoaded, this, [=]() { 0100 d->isLoading = false; 0101 Q_EMIT isLoadingChanged(); 0102 }); 0103 connect(d->engine, &KNSCore::Engine::signalMessage, this, &Engine::message); 0104 connect(d->engine, &KNSCore::Engine::busyStateChanged, this, [this]() { 0105 if (!d->engine->busyState()) { 0106 idleMessage(QString()); 0107 } else { 0108 busyMessage(d->engine->busyMessage()); 0109 } 0110 }); 0111 connect(d->engine, 0112 &KNSCore::Engine::signalErrorCode, 0113 this, 0114 [=](const KNSCore::ErrorCode &theErrorCode, const QString &message, const QVariant &metadata) { 0115 Q_EMIT errorCode(static_cast<ErrorCode>(theErrorCode), message, metadata); 0116 if (theErrorCode == KNSCore::ProviderError) { 0117 // This means loading the providers file failed entirely and we cannot complete the 0118 // initialisation. It also means the engine is done loading, but that nothing will 0119 // work, and we need to inform the user of this. 0120 d->isLoading = false; 0121 Q_EMIT isLoadingChanged(); 0122 } 0123 Q_EMIT errorMessage(message); 0124 }); 0125 connect(d->engine, 0126 &KNSCore::Engine::signalEntryEvent, 0127 this, 0128 [this](const KNSCore::EntryInternal &entry, KNSCore::EntryInternal::EntryEvent event) { 0129 KNSCore::EntryWrapper *wrappedEntry = new KNSCore::EntryWrapper(entry, this); 0130 // Just forward the event but not do anything more 0131 if (event != KNSCore::EntryInternal::StatusChangedEvent) { 0132 Q_EMIT entryEvent(wrappedEntry, (EntryEvent)event); 0133 return; 0134 } 0135 0136 // We do not want to emit the entries changed signal for intermediate changed 0137 // this would cause the KCMs to reload their view unnecessarily, BUG: 431568 0138 if (entry.status() == KNS3::Entry::Installing || entry.status() == KNS3::Entry::Updating) { 0139 return; 0140 } 0141 Q_EMIT entryEvent(wrappedEntry, (EntryEvent)event); 0142 #if KNEWSTUFF_BUILD_DEPRECATED_SINCE(5, 82) 0143 if (d->changedEntries.contains(entry)) { 0144 d->changedEntries.removeAll(entry); 0145 } 0146 d->changedEntries << entry; 0147 Q_EMIT changedEntriesChanged(); 0148 #endif 0149 }); 0150 Q_EMIT engineChanged(); 0151 KNewStuffQuick::QuickQuestionListener::instance(); 0152 d->categoriesModel = new CategoriesModel(this); 0153 Q_EMIT categoriesChanged(); 0154 d->searchPresetModel = new SearchPresetModel(this); 0155 Q_EMIT searchPresetModelChanged(); 0156 // And finally, let's just make sure we don't miss out the various things here getting changed 0157 // In other words, when we're asked to reset the view, actually do that 0158 connect(d->engine, &KNSCore::Engine::signalResetView, this, &Engine::categoriesFilterChanged); 0159 connect(d->engine, &KNSCore::Engine::signalResetView, this, &Engine::filterChanged); 0160 connect(d->engine, &KNSCore::Engine::signalResetView, this, &Engine::sortOrderChanged); 0161 connect(d->engine, &KNSCore::Engine::signalResetView, this, &Engine::searchTermChanged); 0162 Q_EMIT categoriesFilterChanged(); 0163 Q_EMIT filterChanged(); 0164 Q_EMIT sortOrderChanged(); 0165 Q_EMIT searchTermChanged(); 0166 } 0167 d->isValid = d->engine->init(d->configFile); 0168 Q_EMIT engineInitialized(); 0169 } else { 0170 // This is not an error message in the proper sense, and the message is not intended to look like an error (as there is really 0171 // nothing the user can do to fix it, and we just tell them so they're not wondering what's wrong) 0172 Q_EMIT message( 0173 i18nc("An informational message which is shown to inform the user they are not authorized to use GetHotNewStuff functionality", 0174 "You are not authorized to Get Hot New Stuff. If you think this is in error, please contact the person in charge of your permissions.")); 0175 } 0176 } 0177 } 0178 0179 QObject *Engine::engine() const 0180 { 0181 return d->engine; 0182 } 0183 0184 bool Engine::isLoading() const 0185 { 0186 return d->isLoading; 0187 } 0188 0189 bool Engine::hasAdoptionCommand() const 0190 { 0191 if (d->engine) { 0192 return d->engine->hasAdoptionCommand(); 0193 } 0194 return false; 0195 } 0196 0197 QString Engine::name() const 0198 { 0199 if (d->engine) { 0200 return d->engine->name(); 0201 } 0202 return QString{}; 0203 } 0204 0205 QObject *Engine::categories() const 0206 { 0207 return d->categoriesModel; 0208 } 0209 0210 QStringList Engine::categoriesFilter() const 0211 { 0212 if (d->engine) { 0213 return d->engine->categoriesFilter(); 0214 } 0215 return QStringList{}; 0216 } 0217 0218 void Engine::setCategoriesFilter(const QStringList &newCategoriesFilter) 0219 { 0220 if (d->engine) { 0221 // This ensures that if we somehow end up with any empty entries (such as the default 0222 // option in the categories dropdowns), our list will remain empty. 0223 QStringList filter{newCategoriesFilter}; 0224 filter.removeAll({}); 0225 if (d->engine->categoriesFilter() != filter) { 0226 d->engine->setCategoriesFilter(filter); 0227 Q_EMIT categoriesFilterChanged(); 0228 } 0229 } 0230 } 0231 0232 void Engine::resetCategoriesFilter() 0233 { 0234 if (d->engine) { 0235 d->engine->setCategoriesFilter(d->engine->categories()); 0236 } 0237 } 0238 0239 int Engine::filter() const 0240 { 0241 if (d->engine) { 0242 return d->engine->filter(); 0243 } 0244 return 0; 0245 } 0246 0247 void Engine::setFilter(int newFilter) 0248 { 0249 if (d->engine && d->engine->filter() != newFilter) { 0250 d->engine->setFilter(static_cast<KNSCore::Provider::Filter>(newFilter)); 0251 Q_EMIT filterChanged(); 0252 } 0253 } 0254 0255 int Engine::sortOrder() const 0256 { 0257 if (d->engine) { 0258 return d->engine->sortMode(); 0259 } 0260 return 0; 0261 } 0262 0263 void Engine::setSortOrder(int newSortOrder) 0264 { 0265 if (d->engine && d->engine->sortMode() != newSortOrder) { 0266 d->engine->setSortMode(static_cast<KNSCore::Provider::SortMode>(newSortOrder)); 0267 Q_EMIT sortOrderChanged(); 0268 } 0269 } 0270 0271 QString Engine::searchTerm() const 0272 { 0273 if (d->engine) { 0274 return d->engine->searchTerm(); 0275 } 0276 return QString{}; 0277 } 0278 0279 void Engine::setSearchTerm(const QString &newSearchTerm) 0280 { 0281 if (d->engine && d->isValid && d->engine->searchTerm() != newSearchTerm) { 0282 d->engine->setSearchTerm(newSearchTerm); 0283 Q_EMIT searchTermChanged(); 0284 } 0285 } 0286 0287 QObject *Engine::searchPresetModel() const 0288 { 0289 return d->searchPresetModel; 0290 } 0291 0292 void Engine::resetSearchTerm() 0293 { 0294 setSearchTerm(QString{}); 0295 } 0296 0297 #if KNEWSTUFF_BUILD_DEPRECATED_SINCE(5, 82) 0298 QQmlListProperty<KNSCore::EntryWrapper> Engine::changedEntries() 0299 { 0300 return QQmlListProperty<KNSCore::EntryWrapper>(this, d.get(), &EnginePrivate::getChangedEntriesCount, &EnginePrivate::getChangedEntry); 0301 } 0302 0303 int Engine::changedEntriesCount() const 0304 { 0305 return d->changedEntries.count(); 0306 } 0307 0308 void Engine::resetChangedEntries() 0309 { 0310 if (!d->changedEntries.isEmpty()) { 0311 d->changedEntries.clear(); 0312 Q_EMIT changedEntriesChanged(); 0313 } 0314 } 0315 #endif 0316 0317 bool Engine::isValid() 0318 { 0319 return d->isValid; 0320 } 0321 0322 #include "moc_quickengine.cpp"