12#include <QtConcurrent/qtconcurrentrun.h>
13#include <QtCore/qpromise.h>
16#include <QtCore/qdir.h>
17#include <QtCore/qfileinfo.h>
21using namespace Qt::StringLiterals;
28 void init(
const QString &collectionFile);
44 QHelpEngineCore *helpEngineCore)
47 filterEngine =
new QHelpFilterEngine(q);
53 collectionHandler.reset(
new QHelpCollectionHandler(collectionFile, q));
54 QObject::connect(collectionHandler.get(), &QHelpCollectionHandler::error, q,
55 [
this](
const QString &msg) { error = msg; });
56 filterEngine->setCollectionHandler(collectionHandler.get());
67 emit q->setupStarted();
69 collectionHandler->setReadOnly(q->isReadOnly());
70 const bool opened = collectionHandler->openCollectionFile();
74 emit q->setupFinished();
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
128
129
130
131
134
135
136
137
140
141
142
145
146
147
148
149
150
151
152
155
156
157
158
159
162
163
164
165
166QHelpEngineCore::QHelpEngineCore(
const QString &collectionFile, QObject *parent)
168 , d(
new QHelpEngineCorePrivate(collectionFile,
this))
172
173
174#if QT_DEPRECATED_SINCE(6
, 8
)
175QHelpEngineCore::QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate, QObject *parent)
177 , d(helpEngineCorePrivate)
182
183
184QHelpEngineCore::~QHelpEngineCore()
190
191
192
193
194
195
196
197
198QString QHelpEngineCore::collectionFile()
const
200 return d->collectionHandler->collectionFile();
203void QHelpEngineCore::setCollectionFile(
const QString &fileName)
205 if (fileName != collectionFile())
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224bool QHelpEngineCore::isReadOnly()
const
229void QHelpEngineCore::setReadOnly(
bool enable)
231 if (d->readOnly == enable)
234 d->readOnly = enable;
235 d->init(collectionFile());
239
240
241
242
243
244
245
246QHelpFilterEngine *QHelpEngineCore::filterEngine()
const
248 return d->filterEngine;
252
253
254
255
256
257
258
259
260
261
262
263
264
265bool QHelpEngineCore::setupData()
267 d->needsSetup =
true;
272
273
274
275
276
277
278
279bool QHelpEngineCore::copyCollectionFile(
const QString &fileName)
283 return d->collectionHandler->copyCollectionFile(fileName);
287
288
289
290
291
292
293QString QHelpEngineCore::namespaceName(
const QString &documentationFileName)
295 void *pointer =
const_cast<QString *>(&documentationFileName);
296 QHelpDBReader reader(documentationFileName, QHelpGlobal::uniquifyConnectionName(
297 "GetNamespaceName"_L1, pointer),
nullptr);
299 return reader.namespaceName();
304
305
306
307
308
309
310
311
312bool QHelpEngineCore::registerDocumentation(
const QString &documentationFileName)
315 d->needsSetup =
true;
316 return d->collectionHandler->registerDocumentation(documentationFileName);
320
321
322
323
324
325
326bool QHelpEngineCore::unregisterDocumentation(
const QString &namespaceName)
329 d->needsSetup =
true;
330 return d->collectionHandler->unregisterDocumentation(namespaceName);
334
335
336
337
338
339
340QString QHelpEngineCore::documentationFileName(
const QString &namespaceName)
345 const QHelpCollectionHandler::FileInfo fileInfo =
346 d->collectionHandler->registeredDocumentation(namespaceName);
348 if (fileInfo.namespaceName.isEmpty())
351 if (QDir::isAbsolutePath(fileInfo.fileName))
352 return fileInfo.fileName;
354 return QFileInfo(QFileInfo(d->collectionHandler->collectionFile()).absolutePath()
355 + u'/' + fileInfo.fileName).absoluteFilePath();
359
360
361
362QStringList QHelpEngineCore::registeredDocumentations()
const
366 const auto &docList = d->collectionHandler->registeredDocumentations();
368 for (
const QHelpCollectionHandler::FileInfo &info : docList)
369 list.append(info.namespaceName);
374
375
376
377
378
379
380
381
382QStringList QHelpEngineCore::customFilters()
const
386 return d->collectionHandler->customFilters();
390
391
392
393
394
395
396
397
398
399
400
401bool QHelpEngineCore::addCustomFilter(
const QString &filterName,
402 const QStringList &attributes)
405 d->needsSetup =
true;
406 return d->collectionHandler->addCustomFilter(filterName, attributes);
410
411
412
413
414
415
416
417
418
419bool QHelpEngineCore::removeCustomFilter(
const QString &filterName)
422 d->needsSetup =
true;
423 return d->collectionHandler->removeCustomFilter(filterName);
427
428
429
430
431
432
433QStringList QHelpEngineCore::filterAttributes()
const
437 return d->collectionHandler->filterAttributes();
441
442
443
444
445
446
447
448QStringList QHelpEngineCore::filterAttributes(
const QString &filterName)
const
452 return d->collectionHandler->filterAttributes(filterName);
456
457
458
459
460
461
462
463
464
465
466
467
468
469QString QHelpEngineCore::currentFilter()
const
474 if (d->currentFilter.isEmpty()) {
475 const QString &filter =
476 d->collectionHandler->customValue(
"CurrentFilter"_L1, QString()).toString();
477 if (!filter.isEmpty() && d->collectionHandler->customFilters().contains(filter))
478 d->currentFilter = filter;
480 return d->currentFilter;
483void QHelpEngineCore::setCurrentFilter(
const QString &filterName)
485 if (!d->setup() || filterName == d->currentFilter)
487 d->currentFilter = filterName;
488 if (d->autoSaveFilter)
489 d->collectionHandler->setCustomValue(
"CurrentFilter"_L1, d->currentFilter);
490 emit currentFilterChanged(d->currentFilter);
494
495
496
497
498
499
500
501
502QList<QStringList> QHelpEngineCore::filterAttributeSets(
const QString &namespaceName)
const
506 return d->collectionHandler->filterAttributeSets(namespaceName);
510
511
512
513
514
515
516
517
518QList<QUrl> QHelpEngineCore::files(
const QString namespaceName,
519 const QStringList &filterAttributes,
520 const QString &extensionFilter)
527 url.setScheme(
"qthelp"_L1);
528 url.setAuthority(namespaceName);
530 const QStringList &files = d->collectionHandler->files(
531 namespaceName, filterAttributes, extensionFilter);
532 for (
const QString &file : files) {
533 url.setPath(
"/"_L1 + file);
540
541
542
543
544QList<QUrl> QHelpEngineCore::files(
const QString namespaceName,
545 const QString &filterName,
546 const QString &extensionFilter)
553 url.setScheme(
"qthelp"_L1);
554 url.setAuthority(namespaceName);
556 const QStringList &files = d->collectionHandler->files(
557 namespaceName, filterName, extensionFilter);
558 for (
const QString &file : files) {
559 url.setPath(
"/"_L1 + file);
566
567
568
569
570
571
572
573
574
575QUrl QHelpEngineCore::findFile(
const QUrl &url)
const
580 QUrl result = d->usesFilterEngine
581 ? d->collectionHandler->findFile(url, d->filterEngine->activeFilter())
582 : d->collectionHandler->findFile(url, filterAttributes(currentFilter()));
583 if (!result.isEmpty())
586 result = d->usesFilterEngine
587 ? d->collectionHandler->findFile(url, QString())
588 : d->collectionHandler->findFile(url, QStringList());
589 if (!result.isEmpty())
596
597
598
599
600
601QByteArray QHelpEngineCore::fileData(
const QUrl &url)
const
605 return d->collectionHandler->fileData(url);
609
610
611
612
613
614
615QList<QHelpLink> QHelpEngineCore::documentsForIdentifier(
const QString &id)
const
617 return documentsForIdentifier(
618 id, d->usesFilterEngine ? d->filterEngine->activeFilter() : d->currentFilter);
622
623
624
625
626
627
628
629QList<QHelpLink> QHelpEngineCore::documentsForIdentifier(
const QString &id,
const QString &filterName)
const
634 if (d->usesFilterEngine)
635 return d->collectionHandler->documentsForIdentifier(id, filterName);
636 return d->collectionHandler->documentsForIdentifier(id, filterAttributes(filterName));
640
641
642
643
644
645
646QList<QHelpLink> QHelpEngineCore::documentsForKeyword(
const QString &keyword)
const
648 return documentsForKeyword(
649 keyword, d->usesFilterEngine ? d->filterEngine->activeFilter() : d->currentFilter);
653
654
655
656
657
658
659
660QList<QHelpLink> QHelpEngineCore::documentsForKeyword(
const QString &keyword,
const QString &filterName)
const
665 if (d->usesFilterEngine)
666 return d->collectionHandler->documentsForKeyword(keyword, filterName);
667 return d->collectionHandler->documentsForKeyword(keyword, filterAttributes(filterName));
671
672
673
674
675
676
677bool QHelpEngineCore::removeCustomValue(
const QString &key)
680 return d->collectionHandler->removeCustomValue(key);
684
685
686
687
688
689
690QVariant QHelpEngineCore::customValue(
const QString &key,
const QVariant &defaultValue)
const
694 return d->collectionHandler->customValue(key, defaultValue);
698
699
700
701
702
703
704bool QHelpEngineCore::setCustomValue(
const QString &key,
const QVariant &value)
707 return d->collectionHandler->setCustomValue(key, value);
711
712
713
714
715
716
717
718QVariant QHelpEngineCore::metaData(
const QString &documentationFileName,
721 QHelpDBReader reader(documentationFileName,
"GetMetaData"_L1,
nullptr);
724 return reader.metaData(name);
729
730
731QString QHelpEngineCore::error()
const
737
738
739
740
741
742
743
744
745
746
747void QHelpEngineCore::setAutoSaveFilter(
bool save)
749 d->autoSaveFilter = save;
752bool QHelpEngineCore::autoSaveFilter()
const
754 return d->autoSaveFilter;
758
759
760
761
762
763
764
765void QHelpEngineCore::setUsesFilterEngine(
bool uses)
767 d->usesFilterEngine = uses;
771
772
773
774
775
776
777bool QHelpEngineCore::usesFilterEngine()
const
779 return d->usesFilterEngine;
783static QUrl constructUrl(
const QString &namespaceName,
const QString &folderName,
784 const QString &relativePath)
786 const int idx = relativePath.indexOf(u'#');
787 const QString &rp = idx < 0 ? relativePath : relativePath.left(idx);
788 const QString anchor = idx < 0 ? QString() : relativePath.mid(idx + 1);
789 return QHelpCollectionHandler::buildQUrl(namespaceName, folderName, rp, anchor);
792using ContentProviderResult = QList<QHelpCollectionHandler::ContentsData>;
793using ContentProvider = std::function<ContentProviderResult(
const QString &)>;
794using ContentResult = std::shared_ptr<QHelpContentItem>;
797QHelpContentItem *createContentItem(
const QString &name = {},
const QUrl &link = {},
798 QHelpContentItem *parent = {})
800 return new QHelpContentItem(name, link, parent);
803static void requestContentHelper(QPromise<ContentResult> &promise,
const ContentProvider &provider,
804 const QString &collectionFile)
806 ContentResult rootItem(createContentItem());
807 const ContentProviderResult result = provider(collectionFile);
808 for (
const auto &contentsData : result) {
809 const QString namespaceName = contentsData.namespaceName;
810 const QString folderName = contentsData.folderName;
811 for (
const QByteArray &contents : contentsData.contentsList) {
812 if (promise.isCanceled())
815 if (contents.isEmpty())
818 QList<QHelpContentItem *> stack;
819 QDataStream s(contents);
845 }
else if (depth < stack.size()) {
846 stack = stack.sliced(0, depth);
847 }
else if (depth > stack.size()) {
852 QHelpContentItem *substituteItem =
853 stack.isEmpty() ? rootItem.get() : stack.constLast();
854 while (depth > stack.size())
855 stack.append(substituteItem);
858 const QUrl url = constructUrl(namespaceName, folderName, link);
859 QHelpContentItem *parent = stack.isEmpty() ? rootItem.get() : stack.constLast();
860 stack.push_back(createContentItem(title, url, parent));
864 promise.addResult(rootItem);
867static ContentProvider contentProviderFromFilterEngine(
const QString &filter)
869 return [filter](
const QString &collectionFile) -> ContentProviderResult {
870 QHelpCollectionHandler collectionHandler(collectionFile);
871 if (!collectionHandler.openCollectionFile())
873 return collectionHandler.contentsForFilter(filter);
877static ContentProvider contentProviderFromAttributes(
const QStringList &attributes)
879 return [attributes](
const QString &collectionFile) -> ContentProviderResult {
880 QHelpCollectionHandler collectionHandler(collectionFile);
881 if (!collectionHandler.openCollectionFile())
883 return collectionHandler.contentsForFilter(attributes);
887QFuture<ContentResult> QHelpEngineCore::requestContentForCurrentFilter()
const
889 const ContentProvider provider = usesFilterEngine()
890 ? contentProviderFromFilterEngine(filterEngine()->activeFilter())
891 : contentProviderFromAttributes(filterAttributes(d->currentFilter));
892 return QtConcurrent::run(requestContentHelper, provider, collectionFile());
895QFuture<ContentResult> QHelpEngineCore::requestContent(
const QString &filter)
const
897 const ContentProvider provider = usesFilterEngine()
898 ? contentProviderFromFilterEngine(filter)
899 : contentProviderFromAttributes(filterAttributes(filter));
900 return QtConcurrent::run(requestContentHelper, provider, collectionFile());
903using IndexProvider = std::function<QStringList(
const QString &)>;
904using IndexResult = QStringList;
906static IndexProvider indexProviderFromFilterEngine(
const QString &filter)
908 return [filter](
const QString &collectionFile) -> IndexResult {
909 QHelpCollectionHandler collectionHandler(collectionFile);
910 if (!collectionHandler.openCollectionFile())
912 return collectionHandler.indicesForFilter(filter);
916static IndexProvider indexProviderFromAttributes(
const QStringList &attributes)
918 return [attributes](
const QString &collectionFile) -> IndexResult {
919 QHelpCollectionHandler collectionHandler(collectionFile);
920 if (!collectionHandler.openCollectionFile())
922 return collectionHandler.indicesForFilter(attributes);
926QFuture<IndexResult> QHelpEngineCore::requestIndexForCurrentFilter()
const
928 const IndexProvider provider = usesFilterEngine()
929 ? indexProviderFromFilterEngine(filterEngine()->activeFilter())
930 : indexProviderFromAttributes(filterAttributes(d->currentFilter));
931 return QtConcurrent::run(std::move(provider), collectionFile());
934QFuture<IndexResult> QHelpEngineCore::requestIndex(
const QString &filter)
const
936 const IndexProvider provider = usesFilterEngine()
937 ? indexProviderFromFilterEngine(filter)
938 : indexProviderFromAttributes(filterAttributes(filter));
939 return QtConcurrent::run(std::move(provider), collectionFile());
std::unique_ptr< QHelpCollectionHandler > collectionHandler
QHelpFilterEngine * filterEngine
QHelpEngineCorePrivate(const QString &collectionFile, QHelpEngineCore *helpEngineCore)
void init(const QString &collectionFile)
Combined button and popup list for selecting options.