diff --git a/cmake/QtCreatorAPI.cmake b/cmake/QtCreatorAPI.cmake index 1cb69ebdc28..c417d3ab9eb 100644 --- a/cmake/QtCreatorAPI.cmake +++ b/cmake/QtCreatorAPI.cmake @@ -219,10 +219,11 @@ function(add_qtc_library name) endif() qtc_output_binary_dir(_output_binary_dir) + string(REGEX MATCH "^[0-9]*" IDE_VERSION_MAJOR ${IDE_VERSION}) set_target_properties(${name} PROPERTIES SOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}" VERSION "${IDE_VERSION}" - SOVERSION "${PROJECT_VERSION_MAJOR}" + SOVERSION "${IDE_VERSION_MAJOR}" MACHO_CURRENT_VERSION ${IDE_VERSION} MACHO_COMPATIBILITY_VERSION ${IDE_VERSION_COMPAT} CXX_EXTENSIONS OFF @@ -240,7 +241,7 @@ function(add_qtc_library name) if (WIN32 AND library_type STREQUAL "SHARED" AND NOT _arg_UNVERSIONED) # Match qmake naming scheme e.g. Library4.dll set_target_properties(${name} PROPERTIES - SUFFIX "${PROJECT_VERSION_MAJOR}${CMAKE_SHARED_LIBRARY_SUFFIX}" + SUFFIX "${IDE_VERSION_MAJOR}${CMAKE_SHARED_LIBRARY_SUFFIX}" PREFIX "" ) endif() @@ -491,8 +492,9 @@ function(add_qtc_plugin target_name) if (WIN32) # Match qmake naming scheme e.g. Plugin4.dll + string(REGEX MATCH "^[0-9]*" IDE_VERSION_MAJOR ${IDE_VERSION}) set_target_properties(${target_name} PROPERTIES - SUFFIX "${PROJECT_VERSION_MAJOR}${CMAKE_SHARED_LIBRARY_SUFFIX}" + SUFFIX "${IDE_VERSION_MAJOR}${CMAKE_SHARED_LIBRARY_SUFFIX}" PREFIX "" ) endif() diff --git a/doc/qtcreator/images/qtcreator-type-hierarchy-view.png b/doc/qtcreator/images/qtcreator-type-hierarchy-view.png new file mode 100644 index 00000000000..d8ad0649588 Binary files /dev/null and b/doc/qtcreator/images/qtcreator-type-hierarchy-view.png differ diff --git a/doc/qtcreator/src/howto/creator-views.qdoc b/doc/qtcreator/src/howto/creator-views.qdoc index fcbab35d6b2..b74b22b5764 100644 --- a/doc/qtcreator/src/howto/creator-views.qdoc +++ b/doc/qtcreator/src/howto/creator-views.qdoc @@ -327,8 +327,19 @@ \section1 Viewing Type Hierarchy - To view the base classes of a class, right-click the class and select - \uicontrol {Open Type Hierarchy} or press \key {Ctrl+Shift+T}. + To view the base classes and derived classes of a class, right-click the + class in the code editor and select \uicontrol {Open Type Hierarchy} or + press \key {Ctrl+Shift+T}. + + \image qtcreator-type-hierarchy-view.png "Type Hierarchy view" + + To navigate in the type hierarchy, double-click a class or select it, + and then select \uicontrol {Open Type Hierarchy} in the context menu. + The previous class is highlighted in the view. + + The definition of the selected class is opened in the code editor. You + can also select \uicontrol {Open in Editor} in the context menu to open + it. \section1 Viewing Include Hierarchy diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt index eb3c779b400..b1e61d596ef 100644 --- a/share/CMakeLists.txt +++ b/share/CMakeLists.txt @@ -6,6 +6,6 @@ if (NOT APPLE AND NOT WIN32) applications metainfo DESTINATION - share + ${CMAKE_INSTALL_DATAROOTDIR} ) endif() diff --git a/src/libs/cplusplus/FindUsages.cpp b/src/libs/cplusplus/FindUsages.cpp index f495f36e59d..b0835b7c0ae 100644 --- a/src/libs/cplusplus/FindUsages.cpp +++ b/src/libs/cplusplus/FindUsages.cpp @@ -229,7 +229,8 @@ public: } if (const auto declarator = (*it)->asDeclarator()) { if (containsToken(declarator->core_declarator)) { - if (declarator->initializer && (!declarator->postfix_declarator_list + if (declarator->initializer && declarator->equal_token + && (!declarator->postfix_declarator_list || !declarator->postfix_declarator_list->value || !declarator->postfix_declarator_list->value->asFunctionDeclarator())) { return Usage::Type::Initialization; diff --git a/src/libs/sqlite/utf8string.h b/src/libs/sqlite/utf8string.h index 6e8e469595f..0c6a1fb3341 100644 --- a/src/libs/sqlite/utf8string.h +++ b/src/libs/sqlite/utf8string.h @@ -268,6 +268,13 @@ public: return second == first; } + friend bool operator!=(const Utf8String &first, const char *second) + { + return first.byteArray != second; + } + + friend bool operator!=(const char *first, const Utf8String &second) { return second != first; } + friend bool operator==(const Utf8String &first, const QString &second) { return first.byteArray == second.toUtf8(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index e29d54dba97..d4d2f0d2675 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -68,8 +68,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -707,6 +709,23 @@ bool CMakeBuildSettingsWidget::eventFilter(QObject *target, QEvent *event) if ((action = createForceAction(ConfigModel::DataItem::STRING, idx))) menu->addAction(action); + auto copy = new QAction(tr("Copy"), this); + menu->addAction(copy); + connect(copy, &QAction::triggered, this, [this] { + const QModelIndexList selectedIndexes = m_configView->selectionModel()->selectedIndexes(); + + const QModelIndexList validIndexes = Utils::filtered(selectedIndexes, [](const QModelIndex &index) { + return index.isValid() && index.flags().testFlag(Qt::ItemIsSelectable); + }); + + const QStringList variableList = Utils::transform(validIndexes, [this](const QModelIndex &index) { + return ConfigModel::dataItemFromIndex(index) + .toCMakeConfigItem().toArgument(m_buildConfiguration->macroExpander()); + }); + + QApplication::clipboard()->setText(variableList.join('\n'), QClipboard::Clipboard); + }); + menu->move(e->globalPos()); menu->show(); diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index 4fa34cba606..002a2b82623 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -71,7 +72,9 @@ CMakeProjectNode::CMakeProjectNode(const Utils::FilePath &directory) : ProjectExplorer::ProjectNode(directory) { setPriority(Node::DefaultProjectPriority + 1000); - setIcon(QIcon(":/projectexplorer/images/projectexplorer.png")); // TODO: Use proper icon! + static const QIcon productIcon = Core::FileIconProvider::directoryIcon( + ProjectExplorer::Constants::FILEOVERLAY_PRODUCT); + setIcon(productIcon); setListInProject(false); } diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index 74b12c7d742..70f0fa3960a 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -83,6 +83,35 @@ public: } } + CMakeConfigItem toCMakeConfigItem() const { + CMakeConfigItem cmi; + cmi.key = key.toUtf8(); + cmi.value = value.toUtf8(); + switch (type) { + case DataItem::BOOLEAN: + cmi.type = CMakeConfigItem::BOOL; + break; + case DataItem::FILE: + cmi.type = CMakeConfigItem::FILEPATH; + break; + case DataItem::DIRECTORY: + cmi.type = CMakeConfigItem::PATH; + break; + case DataItem::STRING: + cmi.type = CMakeConfigItem::STRING; + break; + case DataItem::UNKNOWN: + cmi.type = CMakeConfigItem::INTERNAL; + break; + } + cmi.isUnset = isUnset; + cmi.isAdvanced = isAdvanced; + cmi.values = values; + cmi.documentation = description.toUtf8(); + + return cmi; + } + enum Type { BOOLEAN, FILE, DIRECTORY, STRING, UNKNOWN}; QString key; diff --git a/src/plugins/coreplugin/find/searchresultwindow.cpp b/src/plugins/coreplugin/find/searchresultwindow.cpp index 0d1d49524e3..af87935623f 100644 --- a/src/plugins/coreplugin/find/searchresultwindow.cpp +++ b/src/plugins/coreplugin/find/searchresultwindow.cpp @@ -814,7 +814,7 @@ void SearchResult::setAdditionalReplaceWidget(QWidget *widget) */ void SearchResult::addResult(const SearchResultItem &item) { - m_widget->addResults({item}, AddSorted); + m_widget->addResults({item}, AddOrdered); } /*! diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index cac88d51be9..9f7b9274e70 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -796,6 +796,14 @@ void MainWindow::registerDefaultActions() // mhelp->addAction(cmd, Constants::G_HELP_ABOUT); // tmpaction->setEnabled(true); // connect(tmpaction, &QAction::triggered, qApp, &QApplication::aboutQt); + + // Contact + tmpaction = new QAction(tr("Contact..."), this); + cmd = ActionManager::registerAction(tmpaction, "QtCreator.Contact"); + mhelp->addAction(cmd, Constants::G_HELP_ABOUT); + tmpaction->setEnabled(true); + connect(tmpaction, &QAction::triggered, this, &MainWindow::contact); + // About sep if (!HostOsInfo::isMacHost()) { // doesn't have the "About" actions in the Help menu tmpaction = new QAction(this); @@ -1237,6 +1245,33 @@ void MainWindow::aboutPlugins() dialog.exec(); } +void MainWindow::contact() +{ + QMessageBox dlg(QMessageBox::Information, tr("Contact"), + tr("

Qt Creator developers can be reached at the Qt Creator mailing list:

" + "%1" + "

or the #qt-creator channel on FreeNode IRC:

" + "%2" + "

Our bug tracker is located at %3.

" + "

Please use %4 for bigger chunks of text.

") + .arg("

    " + "" + "mailto:qt-creator@qt-project.org" + "

") + .arg("

    " + "" + "irc://freenode.org/qt-creator" + "

") + .arg("" + "https://bugreports.qt.io" + "") + .arg("" + "https://pastebin.com" + ""), + QMessageBox::Ok, this); + dlg.exec(); +} + QPrinter *MainWindow::printer() const { if (!m_printer) diff --git a/src/plugins/coreplugin/mainwindow.h b/src/plugins/coreplugin/mainwindow.h index d9105ba93b3..746dd93fc42 100644 --- a/src/plugins/coreplugin/mainwindow.h +++ b/src/plugins/coreplugin/mainwindow.h @@ -129,6 +129,7 @@ private: static void setFocusToEditor(); void aboutQtCreator(); void aboutPlugins(); + void contact(); void updateFocusWidget(QWidget *old, QWidget *now); NavigationWidget *navigationWidget(Side side) const; void setSidebarVisible(bool visible, Side side); diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp index fb3df944361..2aeb9399bfc 100644 --- a/src/plugins/coreplugin/outputwindow.cpp +++ b/src/plugins/coreplugin/outputwindow.cpp @@ -155,6 +155,8 @@ OutputWindow::OutputWindow(Context context, const QString &settingsKey, QWidget connect(verticalScrollBar(), &QAbstractSlider::sliderMoved, this, &OutputWindow::updateAutoScroll); + connect(verticalScrollBar(), &QAbstractSlider::sliderReleased, + this, &OutputWindow::updateAutoScroll); undoAction->setEnabled(false); redoAction->setEnabled(false); @@ -449,7 +451,7 @@ void OutputWindow::handleOutputChunk(const QString &output, OutputFormat format) void OutputWindow::updateAutoScroll() { - d->scrollToBottom = isScrollbarAtBottom(); + d->scrollToBottom = verticalScrollBar()->value() >= verticalScrollBar()->maximum() - 1; } void OutputWindow::setMaxCharCount(int count) @@ -473,11 +475,6 @@ void OutputWindow::appendMessage(const QString &output, OutputFormat format) d->queueTimer.start(); } -bool OutputWindow::isScrollbarAtBottom() const -{ - return verticalScrollBar()->value() == verticalScrollBar()->maximum(); -} - QMimeData *OutputWindow::createMimeDataFromSelection() const { const auto mimeData = new QMimeData; diff --git a/src/plugins/coreplugin/outputwindow.h b/src/plugins/coreplugin/outputwindow.h index de951ded952..70b216b08c5 100644 --- a/src/plugins/coreplugin/outputwindow.h +++ b/src/plugins/coreplugin/outputwindow.h @@ -91,7 +91,6 @@ public slots: void setWordWrapEnabled(bool wrap); protected: - bool isScrollbarAtBottom() const; virtual void handleLink(const QPoint &pos); private: diff --git a/src/plugins/coreplugin/systemsettings.cpp b/src/plugins/coreplugin/systemsettings.cpp index 8852fb183e0..59fc5e9a6f2 100644 --- a/src/plugins/coreplugin/systemsettings.cpp +++ b/src/plugins/coreplugin/systemsettings.cpp @@ -51,14 +51,14 @@ using namespace Utils; -static const char crashReportingEnabledKey[] = "CrashReportingEnabled"; -static const char showCrashButtonKey[] = "ShowCrashButton"; - namespace Core { namespace Internal { -// TODO: move to somewhere in Utils #ifdef ENABLE_CRASHPAD +const char crashReportingEnabledKey[] = "CrashReportingEnabled"; +const char showCrashButtonKey[] = "ShowCrashButton"; + +// TODO: move to somewhere in Utils static QString formatSize(qint64 size) { QStringList units {QObject::tr("Bytes"), QObject::tr("KB"), QObject::tr("MB"), diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 2c2b80dce1e..656b4d9c0dc 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -853,7 +853,7 @@ void DebuggerEnginePrivate::setupViews() m_perspective->addWindow(m_stackWindow, Perspective::SplitVertical, nullptr); m_perspective->addWindow(m_breakWindow, Perspective::SplitHorizontal, m_stackWindow); - m_perspective->addWindow(m_threadsWindow, Perspective::AddToTab, m_breakWindow,false); + m_perspective->addWindow(m_threadsWindow, Perspective::AddToTab, m_breakWindow); m_perspective->addWindow(m_modulesWindow, Perspective::AddToTab, m_threadsWindow, false); m_perspective->addWindow(m_sourceFilesWindow, Perspective::AddToTab, m_modulesWindow, false); m_perspective->addWindow(m_localsAndInspectorWindow, Perspective::AddToTab, nullptr, true, Qt::RightDockWidgetArea); diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index c14927769a8..72f19334e4e 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -1558,7 +1558,7 @@ void FakeVimPluginPrivate::editorOpened(IEditor *editor) return; // Duplicated editors are not signalled by the EditorManager. Track them nevertheless. - connect(editor, &IEditor::editorDuplicated, this, [this, editor](IEditor *duplicate) { + connect(editor, &IEditor::editorDuplicated, this, [this](IEditor *duplicate) { editorOpened(duplicate); connect(duplicate, &QObject::destroyed, this, [this, duplicate] { m_editorToHandler.remove(duplicate); diff --git a/src/plugins/help/helpwidget.cpp b/src/plugins/help/helpwidget.cpp index a72ff4c6b48..1f235dcce62 100644 --- a/src/plugins/help/helpwidget.cpp +++ b/src/plugins/help/helpwidget.cpp @@ -931,7 +931,10 @@ void HelpWidget::updateCloseButton() { if (supportsPages()) { const bool closeOnReturn = LocalHelpManager::returnOnClose() && m_style == ModeWidget; - m_closeAction->setEnabled(closeOnReturn || m_viewerStack->count() > 1); + const bool hasMultiplePages = m_viewerStack->count() > 1; + m_closeAction->setEnabled(closeOnReturn || hasMultiplePages); + m_gotoPrevious->setEnabled(hasMultiplePages); + m_gotoNext->setEnabled(hasMultiplePages); } } diff --git a/src/plugins/help/openpagesswitcher.cpp b/src/plugins/help/openpagesswitcher.cpp index 20117828a71..5991efd0dda 100644 --- a/src/plugins/help/openpagesswitcher.cpp +++ b/src/plugins/help/openpagesswitcher.cpp @@ -81,7 +81,9 @@ void OpenPagesSwitcher::gotoPreviousPage() void OpenPagesSwitcher::selectAndHide() { setVisible(false); - emit setCurrentPage(m_openPagesWidget->currentIndex()); + QModelIndex index = m_openPagesWidget->currentIndex(); + if (index.isValid()) + emit setCurrentPage(index); } void OpenPagesSwitcher::selectCurrentPage(int index) diff --git a/src/plugins/projectexplorer/images/fileoverlay_product.png b/src/plugins/projectexplorer/images/fileoverlay_product.png index 42fcf5f44c2..b5f3c706666 100644 Binary files a/src/plugins/projectexplorer/images/fileoverlay_product.png and b/src/plugins/projectexplorer/images/fileoverlay_product.png differ diff --git a/src/plugins/projectexplorer/images/fileoverlay_product@2x.png b/src/plugins/projectexplorer/images/fileoverlay_product@2x.png index 49d595f9d92..d80b7ae673a 100644 Binary files a/src/plugins/projectexplorer/images/fileoverlay_product@2x.png and b/src/plugins/projectexplorer/images/fileoverlay_product@2x.png differ diff --git a/src/plugins/projectexplorer/images/projectexplorer.png b/src/plugins/projectexplorer/images/projectexplorer.png deleted file mode 100644 index a84f2536f33..00000000000 Binary files a/src/plugins/projectexplorer/images/projectexplorer.png and /dev/null differ diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc index 32fb160cf63..76a913e8df1 100644 --- a/src/plugins/projectexplorer/projectexplorer.qrc +++ b/src/plugins/projectexplorer/projectexplorer.qrc @@ -8,7 +8,6 @@ images/mode_project@2x.png images/mode_project_mask.png images/mode_project_mask@2x.png - images/projectexplorer.png images/buildhammerhandle.png images/buildhammerhandle@2x.png images/buildhammerhead.png diff --git a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp index 8aa58a13968..b8323bb80d2 100644 --- a/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp +++ b/src/plugins/qmldesigner/components/annotationeditor/annotationcommenttab.cpp @@ -70,7 +70,11 @@ AnnotationCommentTab::AnnotationCommentTab(QWidget *parent) "project type", "project version", "Screen Description", - "Section"}}); + "Section", + "normalcolor", + "focuscolor", + "selectedcolor", + "pressedcolor"}}); connect(ui->titleEdit, &QComboBox::currentTextChanged, this, &AnnotationCommentTab::commentTitleChanged); diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h index ea8bb99f1a1..9477212bb7d 100644 --- a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h +++ b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h @@ -90,6 +90,7 @@ const char fitSelectionToScreenCommandId[] = "FitSelectionToScreen"; const char editAnnotationCommandId[] = "EditAnnotation"; const char openSignalDialogCommandId[] = "OpenSignalDialog"; +const char update3DAssetCommandId[] = "Update3DAsset"; const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection"); const char flowConnectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connect"); @@ -131,6 +132,7 @@ const char moveToComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextM const char editAnnotationDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit Annotation"); const char openSignalDialogDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Open Signal Dialog"); +const char update3DAssetDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Update 3D Asset"); const char setIdDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Id"); diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 02596eaf1f0..cccc108bbb5 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -1412,6 +1412,17 @@ void DesignerActionManager::createDefaultDesignerActions() 66, &openSignalDialog, &singleSelectionAndHasSlotTrigger)); + + addDesignerAction(new ModelNodeContextMenuAction( + update3DAssetCommandId, + update3DAssetDisplayName, + {}, + rootCategory, + QKeySequence(), + priorityGenericToolBar, + &updateImported3DAsset, + &selectionIsImported3DAsset, + &selectionIsImported3DAsset)); } void DesignerActionManager::createDefaultAddResourceHandler() diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp index 195ce608d4c..b7a68890b82 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace QmlDesigner { @@ -99,6 +100,21 @@ bool selectionIsComponent(const SelectionContext &selectionState) && selectionState.currentSingleSelectedNode().isComponent(); } +bool selectionIsImported3DAsset(const SelectionContext &selectionState) +{ + ModelNode node = selectionState.currentSingleSelectedNode(); + if (selectionState.view() && node.isValid() && node.hasMetaInfo()) { + QString fileName = node.metaInfo().componentFileName(); // absolute path + if (fileName.isEmpty()) { + // Node is not a file component, so we have to check if the current doc itself is + fileName = node.model()->fileUrl().toLocalFile(); + } + if (fileName.contains(Constants::QUICK_3D_ASSETS_FOLDER)) + return true; + } + return false; +} + } //SelectionStateFunctors } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h index 37696245849..dc36da3dc6e 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h @@ -109,6 +109,7 @@ bool selectionHasSameParent(const SelectionContext &selectionState); bool selectionIsComponent(const SelectionContext &selectionState); bool singleSelectionItemIsAnchored(const SelectionContext &selectionState); bool singleSelectionItemIsNotAnchored(const SelectionContext &selectionState); +bool selectionIsImported3DAsset(const SelectionContext &selectionState); } // namespace SelectionStateFunctors diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index c13080c8f1f..ebcae41091e 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -1581,6 +1581,15 @@ void openSignalDialog(const SelectionContext &selectionContext) SignalList::showWidget(selectionContext.currentSingleSelectedNode()); } +void updateImported3DAsset(const SelectionContext &selectionContext) +{ + if (selectionContext.view()) { + selectionContext.view()->emitCustomNotification( + "UpdateImported3DAsset", {selectionContext.currentSingleSelectedNode()}); + + } +} + } // namespace ModelNodeOperations } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index 575e62f010a..0e302a3c65a 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -89,6 +89,7 @@ void removeGroup(const SelectionContext &selectionContext); void editAnnotation(const SelectionContext &selectionContext); void openSignalDialog(const SelectionContext &selectionContext); +void updateImported3DAsset(const SelectionContext &selectionContext); // ModelNodePreviewImageOperations QVariant previewImageDataForGenericNode(const ModelNode &modelNode); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp index 0b0c7fef103..5d6054c7b76 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.cpp @@ -28,26 +28,33 @@ #include "qmldesignerplugin.h" #include "qmldesignerconstants.h" #include "model.h" +#include "nodemetainfo.h" +#include "variantproperty.h" #include "utils/outputformatter.h" #include "theme.h" #include #include +#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace QmlDesigner { @@ -70,14 +77,15 @@ static const int rowHeight = 26; } -ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &importFiles, - const QString &defaulTargetDirectory, - const QVariantMap &supportedExts, - const QVariantMap &supportedOpts, - QWidget *parent) : - QDialog(parent) +ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog( + const QStringList &importFiles, const QString &defaulTargetDirectory, + const QVariantMap &supportedExts, const QVariantMap &supportedOpts, + const QJsonObject &defaultOpts, const QSet &preselectedFilesForOverwrite, + QWidget *parent) + : QDialog(parent) , ui(new Ui::ItemLibraryAssetImportDialog) , m_importer(this) + , m_preselectedFilesForOverwrite(preselectedFilesForOverwrite) { setModal(true); ui->setupUi(this); @@ -172,6 +180,16 @@ ItemLibraryAssetImportDialog::ItemLibraryAssetImportDialog(const QStringList &im while (optIt != supportedOpts.constEnd()) { QJsonObject options = QJsonObject::fromVariantMap(qvariant_cast(optIt.value())); m_importOptions << options.value("options").toObject(); + auto it = defaultOpts.constBegin(); + while (it != defaultOpts.constEnd()) { + if (m_importOptions.last().contains(it.key())) { + QJsonObject optObj = m_importOptions.last()[it.key()].toObject(); + QJsonValue value(it.value().toObject()["value"]); + optObj.insert("value", value); + m_importOptions.last().insert(it.key(), optObj); + } + ++it; + } groups << options.value("groups").toObject(); const auto &exts = optIt.key().split(':'); for (const auto &ext : exts) @@ -252,6 +270,125 @@ ItemLibraryAssetImportDialog::~ItemLibraryAssetImportDialog() delete ui; } +void ItemLibraryAssetImportDialog::updateImport(const ModelNode &updateNode, + const QVariantMap &supportedExts, + const QVariantMap &supportedOpts) +{ + QString errorMsg; + const ModelNode &node = updateNode; + if (node.isValid() && node.hasMetaInfo()) { + QString compFileName = node.metaInfo().componentFileName(); // absolute path + bool preselectNodeSource = false; + if (compFileName.isEmpty()) { + // Node is not a file component, so we have to check if the current doc itself is + compFileName = node.model()->fileUrl().toLocalFile(); + preselectNodeSource = true; + } + QFileInfo compFileInfo{compFileName}; + + // Find to top asset folder + const QString assetFolder = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER).mid(1); + const QStringList parts = compFileName.split('/'); + int i = parts.size() - 1; + int previousSize = 0; + for (; i >= 0; --i) { + if (parts[i] == assetFolder) + break; + previousSize = parts[i].size(); + } + if (i >= 0) { + const QString assetPath = compFileName.left(compFileName.lastIndexOf(assetFolder) + + assetFolder.size() + previousSize + 1); + const QDir assetDir(assetPath); + + // Find import options and the original source scene + const QString jsonFileName = assetDir.absoluteFilePath( + Constants::QUICK_3D_ASSET_IMPORT_DATA_NAME); + QFile jsonFile{jsonFileName}; + if (jsonFile.open(QIODevice::ReadOnly)) { + QJsonParseError jsonError; + const QByteArray fileData = jsonFile.readAll(); + auto jsonDocument = QJsonDocument::fromJson(fileData, &jsonError); + jsonFile.close(); + if (jsonError.error == QJsonParseError::NoError) { + QJsonObject jsonObj = jsonDocument.object(); + const QJsonObject options = jsonObj.value( + Constants::QUICK_3D_ASSET_IMPORT_DATA_OPTIONS_KEY).toObject(); + QString sourcePath = jsonObj.value( + Constants::QUICK_3D_ASSET_IMPORT_DATA_SOURCE_KEY).toString(); + if (options.isEmpty() || sourcePath.isEmpty()) { + errorMsg = QCoreApplication::translate( + "ModelNodeOperations", + "Asset import data file '%1' is invalid.").arg(jsonFileName); + } else { + QFileInfo sourceInfo{sourcePath}; + if (!sourceInfo.exists()) { + // Unable to find original scene source, launch file dialog to locate it + QString initialPath; + ProjectExplorer::Project *currentProject + = ProjectExplorer::SessionManager::projectForFile( + Utils::FilePath::fromString(compFileName)); + if (currentProject) + initialPath = currentProject->projectDirectory().toString(); + else + initialPath = compFileInfo.absolutePath(); + QStringList selectedFiles = QFileDialog::getOpenFileNames( + Core::ICore::dialogParent(), + tr("Locate 3D Asset '%1'").arg(sourceInfo.fileName()), + initialPath, sourceInfo.fileName()); + if (!selectedFiles.isEmpty() + && QFileInfo{selectedFiles[0]}.fileName() == sourceInfo.fileName()) { + sourcePath = selectedFiles[0]; + sourceInfo.setFile(sourcePath); + } + } + if (sourceInfo.exists()) { + // In case of a selected node inside an imported component, preselect + // any file pointed to by a "source" property of the node. + QSet preselectedFiles; + if (preselectNodeSource && updateNode.hasProperty("source")) { + QString source = updateNode.variantProperty("source").value().toString(); + if (QFileInfo{source}.isRelative()) + source = QDir{compFileInfo.absolutePath()}.absoluteFilePath(source); + preselectedFiles.insert(source); + } + auto importDlg = new ItemLibraryAssetImportDialog( + {sourceInfo.absoluteFilePath()}, + node.model()->fileUrl().toLocalFile(), + supportedExts, supportedOpts, options, + preselectedFiles, Core::ICore::mainWindow()); + importDlg->show(); + + } else { + errorMsg = QCoreApplication::translate( + "ModelNodeOperations", "Unable to locate source scene '%1'.") + .arg(sourceInfo.fileName()); + } + } + } else { + errorMsg = jsonError.errorString(); + } + } else { + errorMsg = QCoreApplication::translate("ModelNodeOperations", + "Opening asset import data file '%1' failed.") + .arg(jsonFileName); + } + } else { + errorMsg = QCoreApplication::translate("ModelNodeOperations", + "Unable to resolve asset import path."); + } + } + + if (!errorMsg.isEmpty()) { + QMessageBox::warning( + qobject_cast(Core::ICore::dialogParent()), + QCoreApplication::translate("ModelNodeOperations", "Import Update Failed"), + QCoreApplication::translate("ModelNodeOperations", + "Failed to update import.\nError:\n%1").arg(errorMsg), + QMessageBox::Close); + } +} + void ItemLibraryAssetImportDialog::createTab(const QString &tabLabel, int optionsIndex, const QJsonObject &groups) { @@ -610,7 +747,8 @@ void ItemLibraryAssetImportDialog::onImport() if (!m_quick3DFiles.isEmpty()) { m_importer.importQuick3D(m_quick3DFiles, m_quick3DImportPath, - m_importOptions, m_extToImportOptionsMap); + m_importOptions, m_extToImportOptionsMap, + m_preselectedFilesForOverwrite); } } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h index 3d4069986ec..ded5d75703a 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimportdialog.h @@ -25,9 +25,11 @@ #pragma once #include "itemlibraryassetimporter.h" +#include "modelnode.h" -#include -#include +#include +#include +#include namespace Utils { class OutputFormatter; @@ -49,9 +51,15 @@ public: const QString &defaulTargetDirectory, const QVariantMap &supportedExts, const QVariantMap &supportedOpts, + const QJsonObject &defaultOpts, + const QSet &preselectedFilesForOverwrite, QWidget *parent = nullptr); ~ItemLibraryAssetImportDialog(); + static void updateImport(const ModelNode &updateNode, + const QVariantMap &supportedExts, + const QVariantMap &supportedOpts); + protected: void resizeEvent(QResizeEvent *event) override; @@ -82,5 +90,6 @@ private: QHash m_extToImportOptionsMap; int m_optionsHeight = 0; int m_optionsRows = 0; + QSet m_preselectedFilesForOverwrite; }; } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index 69924f20080..b78dcb6eece 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -33,16 +33,19 @@ #include "rewritertransaction.h" #include "rewritingexception.h" +#include + +#include #include #include -#include #include -#include -#include -#include -#include #include +#include +#include +#include #include +#include +#include namespace { @@ -64,7 +67,8 @@ ItemLibraryAssetImporter::~ItemLibraryAssetImporter() { void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles, const QString &importPath, const QVector &options, - const QHash &extToImportOptionsMap) + const QHash &extToImportOptionsMap, + const QSet &preselectedFilesForOverwrite) { if (m_isImporting) cancelImport(); @@ -79,7 +83,7 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles, m_importPath = importPath; - parseFiles(inputFiles, options, extToImportOptionsMap); + parseFiles(inputFiles, options, extToImportOptionsMap, preselectedFilesForOverwrite); if (!isCancelled()) { const auto parseData = m_parseData; @@ -203,7 +207,8 @@ void ItemLibraryAssetImporter::reset() void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, const QVector &options, - const QHash &extToImportOptionsMap) + const QHash &extToImportOptionsMap, + const QSet &preselectedFilesForOverwrite) { if (isCancelled()) return; @@ -219,7 +224,7 @@ void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, int index = extToImportOptionsMap.value(QFileInfo(file).suffix()); ParseData pd; pd.options = options[index]; - if (preParseQuick3DAsset(file, pd)) { + if (preParseQuick3DAsset(file, pd, preselectedFilesForOverwrite)) { pd.importId = ++m_importIdCounter; m_parseData.insert(pd.importId, pd); } @@ -227,7 +232,8 @@ void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, } } -bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseData &pd) +bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseData &pd, + const QSet &preselectedFilesForOverwrite) { pd.targetDir = QDir(m_importPath); pd.outDir = QDir(m_tempDir->path()); @@ -264,7 +270,9 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa pd.assetName = assetDirs[0]; pd.targetDirPath = pd.targetDir.filePath(pd.assetName); } - OverwriteResult result = confirmAssetOverwrite(pd.assetName); + OverwriteResult result = preselectedFilesForOverwrite.isEmpty() + ? confirmAssetOverwrite(pd.assetName) + : OverwriteResult::Update; if (result == OverwriteResult::Skip) { addWarning(tr("Skipped import of existing asset: \"%1\"").arg(pd.assetName)); return false; @@ -282,8 +290,11 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa alwaysOverwrite.insert(iconIt.fileInfo().absoluteFilePath()); } alwaysOverwrite.insert(sourceSceneTargetFilePath(pd)); + alwaysOverwrite.insert(pd.targetDirPath + '/' + Constants::QUICK_3D_ASSET_IMPORT_DATA_NAME); - Internal::AssetImportUpdateDialog dlg {pd.targetDirPath, {}, alwaysOverwrite, + Internal::AssetImportUpdateDialog dlg {pd.targetDirPath, + preselectedFilesForOverwrite, + alwaysOverwrite, qobject_cast(parent())}; int exitVal = dlg.exec(); @@ -291,7 +302,7 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa if (exitVal == QDialog::Accepted) overwriteFiles = dlg.selectedFiles(); if (!overwriteFiles.isEmpty()) { - overwriteFiles.append(QStringList::fromSet(alwaysOverwrite)); + overwriteFiles.append(Utils::toList(alwaysOverwrite)); m_overwrittenImports.insert(pd.targetDirPath, overwriteFiles); } else { addWarning(tr("No files selected for overwrite, skipping import: \"%1\"").arg(pd.assetName)); @@ -421,6 +432,18 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) } } + // Generate import metadata file + const QString sourcePath = pd.sourceInfo.absoluteFilePath(); + QString importDataFileName = outDir.absoluteFilePath(Constants::QUICK_3D_ASSET_IMPORT_DATA_NAME); + QSaveFile importDataFile(importDataFileName); + if (importDataFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + QJsonObject optObj; + optObj.insert(Constants::QUICK_3D_ASSET_IMPORT_DATA_OPTIONS_KEY, pd.options); + optObj.insert(Constants::QUICK_3D_ASSET_IMPORT_DATA_SOURCE_KEY, sourcePath); + importDataFile.write(QJsonDocument{optObj}.toJson()); + importDataFile.commit(); + } + // Gather all generated files QDirIterator dirIt(outDir.path(), QDir::Files, QDirIterator::Subdirectories); while (dirIt.hasNext()) { @@ -429,7 +452,7 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) } // Copy the original asset into a subdirectory - assetFiles.insert(pd.sourceInfo.absoluteFilePath(), sourceSceneTargetFilePath(pd)); + assetFiles.insert(sourcePath, sourceSceneTargetFilePath(pd)); m_importFiles.insert(assetFiles); } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h index 56bd8ec8f29..9abc315fbe0 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h @@ -54,7 +54,8 @@ public: void importQuick3D(const QStringList &inputFiles, const QString &importPath, const QVector &options, - const QHash &extToImportOptionsMap); + const QHash &extToImportOptionsMap, + const QSet &preselectedFilesForOverwrite); bool isImporting() const; void cancelImport(); @@ -91,8 +92,10 @@ private: void notifyFinished(); void reset(); void parseFiles(const QStringList &filePaths, const QVector &options, - const QHash &extToImportOptionsMap); - bool preParseQuick3DAsset(const QString &file, ParseData &pd); + const QHash &extToImportOptionsMap, + const QSet &preselectedFilesForOverwrite); + bool preParseQuick3DAsset(const QString &file, ParseData &pd, + const QSet &preselectedFilesForOverwrite); void postParseQuick3DAsset(const ParseData &pd); void copyImportedFiles(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp index dde17dbad32..151e6c5a596 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp @@ -48,6 +48,7 @@ #include #include #include +#include namespace QmlDesigner { @@ -240,7 +241,7 @@ void ItemLibraryView::updateImport3DSupport(const QVariantMap &supportMap) auto handle3DModel = [this](const QStringList &fileNames, const QString &defaultDir) -> bool { auto importDlg = new ItemLibraryAssetImportDialog(fileNames, defaultDir, m_importableExtensions3DMap, - m_importOptions3DMap, + m_importOptions3DMap, {}, {}, Core::ICore::mainWindow()); importDlg->show(); return true; @@ -263,4 +264,15 @@ void ItemLibraryView::updateImport3DSupport(const QVariantMap &supportMap) m_importOptions3DMap = qvariant_cast(supportMap.value("options")); } +void ItemLibraryView::customNotification(const AbstractView *view, const QString &identifier, + const QList &nodeList, const QList &data) +{ + if (identifier == "UpdateImported3DAsset" && nodeList.size() > 0) { + ItemLibraryAssetImportDialog::updateImport(nodeList[0], m_importableExtensions3DMap, + m_importOptions3DMap); + } else { + AbstractView::customNotification(view, identifier, nodeList, data); + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h index 5668b8fbc61..c9d7841bbd7 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h @@ -55,6 +55,8 @@ public: void usedImportsChanged(const QList &usedImports) override; void documentMessagesChanged(const QList &errors, const QList &warnings) override; void updateImport3DSupport(const QVariantMap &supportMap) override; + void customNotification(const AbstractView *view, const QString &identifier, + const QList &nodeList, const QList &data) override; void setResourcePath(const QString &resourcePath); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index 890629e4fd5..ec78ed97afd 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -144,6 +144,7 @@ void PropertyEditorValue::setValueWithEmit(const QVariant &value) setValue(newValue); m_isBound = false; + m_expression.clear(); emit valueChanged(nameAsQString(), value); emit valueChangedQml(); emit isBoundChanged(); @@ -182,6 +183,7 @@ void PropertyEditorValue::setExpressionWithEmit(const QString &expression) { if ( m_expression != expression) { setExpression(expression); + m_value.clear(); emit expressionChanged(nameAsQString()); } } diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 84985b991f7..937cfc8005f 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -69,6 +69,9 @@ const char QML_DESIGNER_SUBFOLDER[] = "/designer/"; const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets"; const char QUICK_3D_ASSET_LIBRARY_ICON_SUFFIX[] = "_libicon"; const char QUICK_3D_ASSET_ICON_DIR[] = "_icons"; +const char QUICK_3D_ASSET_IMPORT_DATA_NAME[] = "_importdata.json"; +const char QUICK_3D_ASSET_IMPORT_DATA_OPTIONS_KEY[] = "import_options"; +const char QUICK_3D_ASSET_IMPORT_DATA_SOURCE_KEY[] = "source_scene"; const char DEFAULT_ASSET_IMPORT_FOLDER[] = "/asset_imports"; // Menus diff --git a/src/plugins/qtsupport/translationwizardpage.cpp b/src/plugins/qtsupport/translationwizardpage.cpp index 4dc80def5ba..f4c9008ed36 100644 --- a/src/plugins/qtsupport/translationwizardpage.cpp +++ b/src/plugins/qtsupport/translationwizardpage.cpp @@ -41,6 +41,8 @@ #include #include +#include + using namespace Core; using namespace ProjectExplorer; using namespace Utils; @@ -107,6 +109,8 @@ TranslationWizardPage::TranslationWizardPage(const QString &enabledExpr) }); sort(localeStrings, [](const LocalePair &l1, const LocalePair &l2) { return l1.first < l2.first; }); + localeStrings.erase(std::unique(localeStrings.begin(), localeStrings.end()), + localeStrings.end()); for (const LocalePair &lp : qAsConst(localeStrings)) m_languageComboBox.addItem(lp.first, lp.second); formLayout->addRow(tr("Language:"), &m_languageComboBox); diff --git a/src/tools/iconlister/iconlister.cpp b/src/tools/iconlister/iconlister.cpp index b650652c1bc..e8b9d3eb18d 100644 --- a/src/tools/iconlister/iconlister.cpp +++ b/src/tools/iconlister/iconlister.cpp @@ -334,8 +334,6 @@ void IconLister::addProjectExplorerIcons() {QIcon(":/projectexplorer/images/category_buildrun.png"), "category_buildrun.png", prefix, ""}, - {QIcon(":/projectexplorer/images/projectexplorer.png"), "projectexplorer.png", prefix, - ""}, {QIcon(":/projectexplorer/images/session.png"), "session.png", prefix, ""}, {QIcon(":/projectexplorer/images/BuildSettings.png"), "BuildSettings.png", prefix, diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 5152fcc6255..e0bec68332c 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -9333,6 +9333,28 @@ style="fill:none;stroke:#1986a0;stroke-opacity:1" id="path5210-3" /> + + + + +