diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index 5beb9c80a35..b1914350d3e 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -325,6 +325,21 @@ static bool isValidExampleOrDemo(ExampleItem *item) return ok || debugExamples(); } +// ordered list of "known" categories +// TODO this should be defined in the manifest +Q_GLOBAL_STATIC_WITH_ARGS(QStringList, + defaultOrder, + {QStringList() << "Application Examples" + << "Desktop" + << "Mobile" + << "Embedded" + << "Graphics" + << "Input/Output" + << "Connectivity" + << "Networking" + << "Positioning & Location" + << "Internationalization"}); + void ExamplesViewController::updateExamples() { QString examplesInstallPath; @@ -366,9 +381,10 @@ void ExamplesViewController::updateExamples() } } - const bool sortIntoCategories = qtVersion >= *minQtVersionForCategories; + const bool sortIntoCategories = !m_isExamples || qtVersion >= *minQtVersionForCategories; + const QStringList order = m_isExamples ? *defaultOrder : QStringList(); const QList>> sections - = getCategories(items, sortIntoCategories); + = getCategories(items, sortIntoCategories, order, m_isExamples); for (int i = 0; i < sections.size(); ++i) { m_view->addSection(sections.at(i).first, static_container_cast(sections.at(i).second)); diff --git a/src/plugins/qtsupport/examplesparser.cpp b/src/plugins/qtsupport/examplesparser.cpp index d115dcf3fe0..f961846e1d7 100644 --- a/src/plugins/qtsupport/examplesparser.cpp +++ b/src/plugins/qtsupport/examplesparser.cpp @@ -215,7 +215,8 @@ static QList parseTutorials(QXmlStreamReader *reader, const FileP QXmlStreamAttributes attributes = reader->attributes(); item->name = attributes.value(QLatin1String("name")).toString(); const QString projectPath = attributes.value(QLatin1String("projectPath")).toString(); - item->projectPath = projectsOffset / projectPath; + item->projectPath = projectPath.isEmpty() ? FilePath() + : projectsOffset / projectPath; item->hasSourceCode = !projectPath.isEmpty(); item->imageUrl = Utils::StyleHelper::dpiSpecificImageFile( attributes.value(QLatin1String("imageUrl")).toString()); @@ -239,6 +240,8 @@ static QList parseTutorials(QXmlStreamReader *reader, const FileP } else if (reader->name() == QLatin1String("tags")) { item->tags = reader->readElementText(QXmlStreamReader::ErrorOnUnexpectedElement) .split(QLatin1Char(',')); + } else if (reader->name() == QLatin1String("meta")) { + item->metaData = parseMeta(reader); } break; case QXmlStreamReader::EndElement: @@ -301,21 +304,6 @@ expected_str> parseExamples(const QByteArray &manifestData, return items; } -// ordered list of "known" categories -// TODO this should be defined in the manifest -Q_GLOBAL_STATIC_WITH_ARGS(QList, - defaultOrder, - {QStringList() << "Application Examples" - << "Desktop" - << "Mobile" - << "Embedded" - << "Graphics" - << "Input/Output" - << "Connectivity" - << "Networking" - << "Positioning & Location" - << "Internationalization"}); - static bool sortByHighlightedAndName(ExampleItem *first, ExampleItem *second) { if (first->isHighlighted && !second->isHighlighted) @@ -326,7 +314,9 @@ static bool sortByHighlightedAndName(ExampleItem *first, ExampleItem *second) } QList>> getCategories(const QList &items, - bool sortIntoCategories) + bool sortIntoCategories, + const QStringList &defaultOrder, + bool restrictRows) { static const QString otherDisplayName = Tr::tr("Other", "Category for all other examples"); const bool useCategories = sortIntoCategories @@ -365,14 +355,17 @@ QList>> getCategories(const QList< } else { // All original items have been copied into a category or other, delete. qDeleteAll(items); - static const int defaultOrderSize = defaultOrder->size(); + static const int defaultOrderSize = defaultOrder.size(); int index = 0; const auto end = categoryMap.constKeyValueEnd(); for (auto it = categoryMap.constKeyValueBegin(); it != end; ++it) { // order "known" categories as wanted, others come afterwards - const int defaultIndex = defaultOrder->indexOf(it->first); + const int defaultIndex = defaultOrder.indexOf(it->first); const int priority = defaultIndex >= 0 ? defaultIndex : (index + defaultOrderSize); - categories.append({{it->first, priority, /*maxRows=*/index == 0 ? 2 : 1}, it->second}); + const std::optional maxRows = restrictRows + ? std::make_optional(index == 0 ? 2 : 1) + : std::nullopt; + categories.append({{it->first, priority, maxRows}, it->second}); ++index; } if (!other.isEmpty()) diff --git a/src/plugins/qtsupport/examplesparser.h b/src/plugins/qtsupport/examplesparser.h index 54efaf58875..d57e7a536ad 100644 --- a/src/plugins/qtsupport/examplesparser.h +++ b/src/plugins/qtsupport/examplesparser.h @@ -45,7 +45,10 @@ QTSUPPORT_TEST_EXPORT Utils::expected_str> parseExamples( bool examples); QTSUPPORT_TEST_EXPORT QList>> getCategories( - const QList &items, bool sortIntoCategories); + const QList &items, + bool sortIntoCategories, + const QStringList &defaultOrder, + bool restrictRows); } // namespace QtSupport::Internal diff --git a/src/plugins/qtsupport/qtcreator_tutorials.xml b/src/plugins/qtsupport/qtcreator_tutorials.xml index 5f56f7501b7..f374f1b6301 100644 --- a/src/plugins/qtsupport/qtcreator_tutorials.xml +++ b/src/plugins/qtsupport/qtcreator_tutorials.xml @@ -1,196 +1,337 @@ - + qt creator,build,compile,help + + Help + - + qt creator,qt designer,widgets,c++,text,help + + Help + - + qt,qt creator,qt designer,widgets,c++,help + + Help + - + qt creator,qt quick,qml,states,transitions,help + + Help + - + qt creator,qml,android,ios,controls,help + + Help + - + qt quick,controls,tumbler,help + + Help + - + qt creator,learning,ui,welcome,2023 + + Learning + - + qt creator,learning,projects,qt widgets,2023 + + Learning + - + qt creator,learning,qt designer,coding,2023 + + Learning + - + qt creator,learning,debugging,2023 + + Learning + - + qt creator,embedded,device creation,video,2021 + + Online + - + qt creator,SCXML,video + + Online + - + qt creator,qt quick,c++,video + + Online + - + qt creator,video + + Online + - + qt creator,video,2018 + + Online + - + qt creator,qt quick,controls,video,2018 + + Online + - + - qt creator,debugging,2021 + qt creator,debugging,video,2021 + + Online + - + - qt creator,qt linguist,translation,2021 + qt creator,qt linguist,translation,video,2021 + + Online + - + qt,installation,online installer,modules,video,2021 + + Online + - + - embedded,installation,device creation,2021 + embedded,installation,device creation,video,2021 + + Online + - + - qt creator,widgets,2021 + qt creator,widgets,video,2021 + + Online + - + qt quick,widgets,ui,video,2021 + + Online + - + qt,mcus,video,STM32H750B-DISCOVERY,2021 + + Online + - + qtformcus,mcus,qt,video,NXP IMXRT1050-EVKB,2020 + + Online + - + qtformcus,mcus,qt,video,2021 + + Online + - + qt creator,wizard,talk,2015 + + Talk + - + qt creator,configuration,talk,2013 + + Talk + - + qt creator,plugins,talk,2019 + + Talk + - + - qt quick,qt creator,qml profiler,talk,2014 + qt quick,qt creator,qml profiler,talk,2014 + + Talk + - + qt creator,cpu usage analyzer,perf,embedded,device creation,talk,2015 + + Talk + - + qt creator,scxml,talk,2016 + + Talk + - + qt creator,qbs,qemu,talk,2015 + + Talk + - + qt creator,ios,talk,2016 + + Talk + - + qt creator,baremetal,talk,2013 + + Talk + - + qt quick,ui,widgets,talk,2016 + + Talk + - + qt creator,talk,2019 + + Talk + - + qt creator,webassembly,emscripten,talk,2019 + + Talk + - + qt,qt quick,screen resolution,ui,talk,2016 + + Talk + - + qt designer,widgets,ui,talk,2019 + + Talk + - + android,ios,talk,2017 + + Talk + - + qt creator,qml profiler,ctf viewer,lttng,talk,2019 + + Talk + - + android,ios,qt quick,controls,talk,2017 + + Talk + - + qt creator,kits,yocto,embedded,talk,2019 + + Talk + - + qt creator,plugins,video,2021 + + Talk + - + android,talk,2021 + + Talk + - + qt quick,controls,styling,ui,talk,2021 + + Talk + - + qt,c++,qml,talk,2021 + + Talk + diff --git a/tests/auto/examples/tst_examples.cpp b/tests/auto/examples/tst_examples.cpp index d6639663adf..e01336d65a8 100644 --- a/tests/auto/examples/tst_examples.cpp +++ b/tests/auto/examples/tst_examples.cpp @@ -140,6 +140,27 @@ void tst_Examples::parsing_data() << FilePath("examples") << QString() << FilePaths() << FilePath() << FilePaths() << Example << /*hasSourceCode=*/false << false << /*isHighlighted=*/true << "" << "" << QStringList() << MetaData() << QStringList{"Featured"}; + + QTest::addRow("tutorial with category") + << QByteArray(R"raw( + + + + qt creator,build,compile,help + + Help + + + +)raw") << /*isExamples=*/false + << "A tutorial" + << "A dummy tutorial." + << ":qtsupport/images/icons/tutorialicon.png" + << QStringList{"qt creator", "build", "compile", "help"} << FilePath() + << "qthelp://org.qt-project.qtcreator/doc/dummytutorial.html" << FilePaths() << FilePath() + << FilePaths() << Tutorial << /*hasSourceCode=*/false << /*isVideo=*/false + << /*isHighlighted=*/false << QString() << QString() << QStringList() + << MetaData({{"category", {"Help"}}}) << QStringList("Help"); } void tst_Examples::parsing() @@ -175,8 +196,8 @@ void tst_Examples::parsing() QCOMPARE(item.platforms, expected.platforms); QCOMPARE(item.metaData, expected.metaData); - const QList>> resultCategories = getCategories(*result, - true); + const QList>> resultCategories + = getCategories(*result, true, {}, true); QCOMPARE(resultCategories.size(), categories.size()); for (int i = 0; i < resultCategories.size(); ++i) { QCOMPARE(resultCategories.at(i).first.name, categories.at(i));