Merge remote-tracking branch 'origin/4.15'

Change-Id: Ifae18bacb0c4bdb1e0516c9f92c0fd16150e35e6
This commit is contained in:
Eike Ziller
2021-03-01 09:56:20 +01:00
43 changed files with 443 additions and 73 deletions

View File

@@ -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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -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

View File

@@ -6,6 +6,6 @@ if (NOT APPLE AND NOT WIN32)
applications
metainfo
DESTINATION
share
${CMAKE_INSTALL_DATAROOTDIR}
)
endif()

View File

@@ -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;

View File

@@ -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();

View File

@@ -68,8 +68,10 @@
#include <utils/stringutils.h>
#include <utils/variablechooser.h>
#include <QApplication>
#include <QBoxLayout>
#include <QCheckBox>
#include <QClipboard>
#include <QDialog>
#include <QDialogButtonBox>
#include <QDir>
@@ -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();

View File

@@ -31,6 +31,7 @@
#include <android/androidconstants.h>
#include <coreplugin/fileiconprovider.h>
#include <ios/iosconstants.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/target.h>
#include <utils/qtcassert.h>
@@ -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);
}

View File

@@ -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;

View File

@@ -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);
}
/*!

View File

@@ -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("<p>Qt Creator developers can be reached at the Qt Creator mailing list:</p>"
"%1"
"<p>or the #qt-creator channel on FreeNode IRC:</p>"
"%2"
"<p>Our bug tracker is located at %3.</p>"
"<p>Please use %4 for bigger chunks of text.</p>")
.arg("<p>&nbsp;&nbsp;&nbsp;&nbsp;"
"<a href=\"https://lists.qt-project.org/listinfo/qt-creator\">"
"mailto:qt-creator@qt-project.org"
"</a></p>")
.arg("<p>&nbsp;&nbsp;&nbsp;&nbsp;"
"<a href=\"https://irc.freenode.org\">"
"irc://freenode.org/qt-creator"
"</a></p>")
.arg("<a href=\"https://bugreports.qt.io/projects/QTCREATORBUG\">"
"https://bugreports.qt.io"
"</a>")
.arg("<a href=\"https://pastebin.com\">"
"https://pastebin.com"
"</a>"),
QMessageBox::Ok, this);
dlg.exec();
}
QPrinter *MainWindow::printer() const
{
if (!m_printer)

View File

@@ -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);

View File

@@ -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;

View File

@@ -91,7 +91,6 @@ public slots:
void setWordWrapEnabled(bool wrap);
protected:
bool isScrollbarAtBottom() const;
virtual void handleLink(const QPoint &pos);
private:

View File

@@ -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"),

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 782 B

View File

@@ -8,7 +8,6 @@
<file>images/mode_project@2x.png</file>
<file>images/mode_project_mask.png</file>
<file>images/mode_project_mask@2x.png</file>
<file>images/projectexplorer.png</file>
<file>images/buildhammerhandle.png</file>
<file>images/buildhammerhandle@2x.png</file>
<file>images/buildhammerhead.png</file>

View File

@@ -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);

View File

@@ -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");

View File

@@ -1412,6 +1412,17 @@ void DesignerActionManager::createDefaultDesignerActions()
66,
&openSignalDialog,
&singleSelectionAndHasSlotTrigger));
addDesignerAction(new ModelNodeContextMenuAction(
update3DAssetCommandId,
update3DAssetDisplayName,
{},
rootCategory,
QKeySequence(),
priorityGenericToolBar,
&updateImported3DAsset,
&selectionIsImported3DAsset,
&selectionIsImported3DAsset));
}
void DesignerActionManager::createDefaultAddResourceHandler()

View File

@@ -31,6 +31,7 @@
#include <bindingproperty.h>
#include <nodeproperty.h>
#include <qmldesignerplugin.h>
#include <qmldesignerconstants.h>
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

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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 <projectexplorer/project.h>
#include <projectexplorer/session.h>
#include <coreplugin/icore.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtCore/qloggingcategory.h>
#include <QtCore/qtimer.h>
#include <QtCore/qjsonarray.h>
#include <QtWidgets/qpushbutton.h>
#include <QtWidgets/qgridlayout.h>
#include <QtWidgets/qlabel.h>
#include <QtWidgets/qcheckbox.h>
#include <QtWidgets/qspinbox.h>
#include <QtWidgets/qscrollbar.h>
#include <QtWidgets/qtabbar.h>
#include <QtWidgets/qscrollarea.h>
#include <QFileInfo>
#include <QDir>
#include <QLoggingCategory>
#include <QTimer>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QPushButton>
#include <QGridLayout>
#include <QLabel>
#include <QCheckBox>
#include <QSpinBox>
#include <QScrollBar>
#include <QTabBar>
#include <QScrollArea>
#include <QMessageBox>
#include <QFileDialog>
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<QString> &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<QVariantMap>(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<QString> 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<QWidget *>(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);
}
}

View File

@@ -25,9 +25,11 @@
#pragma once
#include "itemlibraryassetimporter.h"
#include "modelnode.h"
#include <QtWidgets/qdialog.h>
#include <QtCore/qjsonobject.h>
#include <QDialog>
#include <QJsonObject>
#include <QSet>
namespace Utils {
class OutputFormatter;
@@ -49,9 +51,15 @@ public:
const QString &defaulTargetDirectory,
const QVariantMap &supportedExts,
const QVariantMap &supportedOpts,
const QJsonObject &defaultOpts,
const QSet<QString> &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<QString, int> m_extToImportOptionsMap;
int m_optionsHeight = 0;
int m_optionsRows = 0;
QSet<QString> m_preselectedFilesForOverwrite;
};
}

View File

@@ -33,16 +33,19 @@
#include "rewritertransaction.h"
#include "rewritingexception.h"
#include <utils/algorithm.h>
#include <QApplication>
#include <QDir>
#include <QDirIterator>
#include <QSaveFile>
#include <QFile>
#include <QLoggingCategory>
#include <QTemporaryDir>
#include <QApplication>
#include <QMessageBox>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLoggingCategory>
#include <QMessageBox>
#include <QPushButton>
#include <QSaveFile>
#include <QTemporaryDir>
namespace
{
@@ -64,7 +67,8 @@ ItemLibraryAssetImporter::~ItemLibraryAssetImporter() {
void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles,
const QString &importPath,
const QVector<QJsonObject> &options,
const QHash<QString, int> &extToImportOptionsMap)
const QHash<QString, int> &extToImportOptionsMap,
const QSet<QString> &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<QJsonObject> &options,
const QHash<QString, int> &extToImportOptionsMap)
const QHash<QString, int> &extToImportOptionsMap,
const QSet<QString> &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<QString> &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<QWidget *>(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);
}

View File

@@ -54,7 +54,8 @@ public:
void importQuick3D(const QStringList &inputFiles, const QString &importPath,
const QVector<QJsonObject> &options,
const QHash<QString, int> &extToImportOptionsMap);
const QHash<QString, int> &extToImportOptionsMap,
const QSet<QString> &preselectedFilesForOverwrite);
bool isImporting() const;
void cancelImport();
@@ -91,8 +92,10 @@ private:
void notifyFinished();
void reset();
void parseFiles(const QStringList &filePaths, const QVector<QJsonObject> &options,
const QHash<QString, int> &extToImportOptionsMap);
bool preParseQuick3DAsset(const QString &file, ParseData &pd);
const QHash<QString, int> &extToImportOptionsMap,
const QSet<QString> &preselectedFilesForOverwrite);
bool preParseQuick3DAsset(const QString &file, ParseData &pd,
const QSet<QString> &preselectedFilesForOverwrite);
void postParseQuick3DAsset(const ParseData &pd);
void copyImportedFiles();

View File

@@ -48,6 +48,7 @@
#include <utils/algorithm.h>
#include <qmldesignerplugin.h>
#include <qmlitemnode.h>
#include <qmldesignerconstants.h>
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<QVariantMap>(supportMap.value("options"));
}
void ItemLibraryView::customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data)
{
if (identifier == "UpdateImported3DAsset" && nodeList.size() > 0) {
ItemLibraryAssetImportDialog::updateImport(nodeList[0], m_importableExtensions3DMap,
m_importOptions3DMap);
} else {
AbstractView::customNotification(view, identifier, nodeList, data);
}
}
} // namespace QmlDesigner

View File

@@ -55,6 +55,8 @@ public:
void usedImportsChanged(const QList<Import> &usedImports) override;
void documentMessagesChanged(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings) override;
void updateImport3DSupport(const QVariantMap &supportMap) override;
void customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void setResourcePath(const QString &resourcePath);

View File

@@ -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());
}
}

View File

@@ -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

View File

@@ -41,6 +41,8 @@
#include <QPair>
#include <QVBoxLayout>
#include <algorithm>
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);

View File

@@ -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,

View File

@@ -9333,6 +9333,28 @@
style="fill:none;stroke:#1986a0;stroke-opacity:1"
id="path5210-3" />
</g>
<g
id="src/plugins/projectexplorer/images/fileoverlay_product"
transform="translate(160)">
<use
x="0"
y="0"
xlink:href="#transparentBackgroundRect"
id="use2479-2"
width="100%"
transform="translate(80,68)"
height="100%" />
<path
id="path2592"
style="fill:#6300aa;stroke:#ffffff;stroke-width:2;stroke-linejoin:round;stroke-opacity:0.75;paint-order:stroke fill"
d="m 73.99414,527.11523 -1.03125,0.42579 0.22852,1.06445 -0.58399,0.58789 -1.0664,-0.22852 -0.42579,1.0293 0.91407,0.5918 v 0.82812 l -0.91407,0.5918 0.42579,1.03125 1.06445,-0.22852 0.58789,0.58399 -0.22852,1.0664 1.0293,0.42579 0.5918,-0.91407 h 0.82812 l 0.5918,0.91407 1.03125,-0.42579 -0.22852,-1.06445 0.58399,-0.58789 1.0664,0.22852 0.42579,-1.0293 -0.91407,-0.5918 v -0.82812 l 0.91407,-0.5918 -0.42579,-1.03125 -1.06445,0.22852 -0.58789,-0.58399 0.22852,-1.0664 -1.0293,-0.42579 -0.5918,0.91407 h -0.82812 z" />
<circle
style="fill:none;stroke:#ffffff"
id="path2669"
cx="75"
cy="531"
r="1.5" />
</g>
<g
id="src/libs/utils/images/filesave">
<rect

Before

Width:  |  Height:  |  Size: 380 KiB

After

Width:  |  Height:  |  Size: 381 KiB

View File

@@ -2021,7 +2021,7 @@ void tst_FindUsages::writableRefs()
struct S {
S() : value2(value) {}
static int value;
int value2;
int value2 : 2;
static void *p;
static const void *p2;
struct Nested {

View File

@@ -66,10 +66,12 @@ def startQC(additionalParameters=None, withPreparedSettingsPath=True, closeLinkT
appWithOptions.extend(('-platform', 'windows:dialogs=none'))
test.log("Starting now: %s" % ' '.join(appWithOptions))
appContext = startApplication(' '.join(appWithOptions))
if closeLinkToQt:
clickButton(waitForObject(":*Qt Creator.Do Not Show Again_QToolButton"))
if cancelTour:
clickButton(waitForObject(":*Qt Creator.Do Not Show Again_QToolButton"))
if closeLinkToQt or cancelTour:
progressBarWait(3000) # wait for the "Updating documentation" progress bar
if closeLinkToQt:
clickButton(waitForObject(":*Qt Creator.Do Not Show Again_QToolButton"))
if cancelTour:
clickButton(waitForObject(":*Qt Creator.Do Not Show Again_QToolButton"))
return appContext;
def startedWithoutPluginError():