QmlDesigner: Block modifying imports when editing in-file subcomponent

Adding import statements fails silently when editing in-file
subcomponent, and removing them can crash creator, so block various
cases in component library, navigator, and 3D edit view that do this.

Fixes: QDS-5353
Change-Id: Ide5429cd97d2bf78f884b14e83cdffd10399f929
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Miikka Heikkinen
2021-11-02 15:05:11 +02:00
parent 69c8be67ae
commit 590d01e8a9
9 changed files with 57 additions and 19 deletions

View File

@@ -116,7 +116,7 @@ Item {
text: qsTr("Remove Module")
visible: itemsView.currentCategory === null
height: visible ? implicitHeight : 0
enabled: itemsView.importToRemove !== ""
enabled: itemsView.importToRemove !== "" && !rootView.subCompEditMode
onTriggered: rootView.removeImport(itemsView.importToRemove)
}

View File

@@ -93,8 +93,10 @@ Item {
anchors.topMargin: 1
width: 24
height: 24
color: mouseArea.containsMouse ? StudioTheme.Values.themeControlBackgroundHover
: StudioTheme.Values.themeControlBackground
color: mouseArea.containsMouse && enabled
? StudioTheme.Values.themeControlBackgroundHover
: StudioTheme.Values.themeControlBackground
enabled: index !== 0 || !rootView.subCompEditMode
Label { // + sign
text: StudioTheme.Constants.plus

View File

@@ -33,6 +33,7 @@
#include <designeractionmanager.h>
#include <designersettings.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
#include <viewmanager.h>
#include <qmldesignericons.h>
#include <designmodecontext.h>
@@ -370,7 +371,8 @@ QVector<Edit3DAction *> Edit3DView::rightActions() const
void Edit3DView::addQuick3DImport()
{
if (model()) {
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
if (document && !document->inFileComponentModelActive() && model()) {
const QList<Import> imports = model()->possibleImports();
for (const auto &import : imports) {
if (import.url() == "QtQuick3D") {

View File

@@ -210,6 +210,11 @@ bool DesignDocument::pasteSVG()
return true;
}
bool DesignDocument::inFileComponentModelActive() const
{
return !m_inFileComponentModel.isNull();
}
QList<DocumentMessage> DesignDocument::qmlParseWarnings() const
{
return m_rewriterView->warnings();

View File

@@ -76,6 +76,7 @@ public:
Model *currentModel() const;
Model *documentModel() const;
bool inFileComponentModelActive() const;
void contextHelp(const Core::IContext::HelpCallback &callback) const;
QList<DocumentMessage> qmlParseWarnings() const;

View File

@@ -354,7 +354,8 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
beginResetModel();
clearSections();
Utils::FilePath qmlFileName = QmlDesignerPlugin::instance()->currentDesignDocument()->fileName();
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
Utils::FilePath qmlFileName = document->fileName();
ProjectExplorer::Project *project = ProjectExplorer::SessionManager::projectForFile(qmlFileName);
QString projectName = project ? project->displayName() : "";
@@ -398,6 +399,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
itemLibImport->setImportExpanded(loadExpandedState(itemLibImport->importUrl()));
}
const bool blockNewImports = document->inFileComponentModelActive();
const QList<ItemLibraryEntry> itemLibEntries = itemLibraryInfo->entries();
for (const ItemLibraryEntry &entry : itemLibEntries) {
NodeMetaInfo metaInfo = model->metaInfo(entry.typeName());
@@ -429,7 +431,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
bool hasImport = model->hasImport(import, true, true);
bool isImportPossible = false;
if (!hasImport)
isImportPossible = model->isImportPossible(import, true, true);
isImportPossible = !blockNewImports && model->isImportPossible(import, true, true);
bool isUsable = (valid && (isItem || forceVisibility))
&& (entry.requiredImport().isEmpty() || hasImport);
if (!blocked && (isUsable || isImportPossible)) {

View File

@@ -400,6 +400,17 @@ void ItemLibraryWidget::setModel(Model *model)
return;
setItemLibraryInfo(model->metaInfo().itemLibraryInfo());
if (DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument()) {
const bool subCompEditMode = document->inFileComponentModelActive();
if (m_subCompEditMode != subCompEditMode) {
m_subCompEditMode = subCompEditMode;
// Switch out of module add panel if it's active
if (m_subCompEditMode && m_stackedWidget->currentIndex() == 2)
m_stackedWidget->setCurrentIndex(0);
emit subCompEditModeChanged();
}
}
}
void ItemLibraryWidget::handleTabChanged(int index)
@@ -545,6 +556,11 @@ QPair<QString, QByteArray> ItemLibraryWidget::getAssetTypeAndData(const QString
return {};
}
bool ItemLibraryWidget::subCompEditMode() const
{
return m_subCompEditMode;
}
void ItemLibraryWidget::setFlowMode(bool b)
{
m_itemLibraryModel->setFlowMode(b);

View File

@@ -71,6 +71,8 @@ class ItemLibraryWidget : public QFrame
Q_OBJECT
public:
Q_PROPERTY(bool subCompEditMode READ subCompEditMode NOTIFY subCompEditModeChanged)
ItemLibraryWidget(AsynchronousImageCache &imageCache,
AsynchronousImageCache &asynchronousFontImageCache,
SynchronousImageCache &synchronousFontImageCache);
@@ -94,6 +96,8 @@ public:
inline static bool isHorizontalLayout = false;
bool subCompEditMode() const;
Q_INVOKABLE void startDragAndDrop(const QVariant &itemLibEntry, const QPointF &mousePos);
Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos);
Q_INVOKABLE void removeImport(const QString &importUrl);
@@ -108,7 +112,8 @@ public:
Q_INVOKABLE QSet<QString> supportedDropSuffixes();
signals:
void itemActivated(const QString& itemName);
void itemActivated(const QString &itemName);
void subCompEditModeChanged();
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
@@ -152,6 +157,7 @@ private:
bool m_updateRetry = false;
QString m_filterText;
QPoint m_dragStartPoint;
bool m_subCompEditMode = false;
inline static int HORIZONTAL_LAYOUT_WIDTH_LIMIT = 600;
};

View File

@@ -551,20 +551,24 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData,
QList<ModelNode> addedNodes;
ModelNode currNode;
QSet<QString> neededImports;
for (const QString &assetPath : assetsPaths) {
QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first;
if (assetType == "application/vnd.bauhaus.libraryresource.shader")
neededImports.insert("QtQuick3D");
else if (assetType == "application/vnd.bauhaus.libraryresource.sound")
neededImports.insert("QtMultimedia");
// Adding required imports is skipped if we are editing in-file subcomponent
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
if (document && !document->inFileComponentModelActive()) {
QSet<QString> neededImports;
for (const QString &assetPath : assetsPaths) {
QString assetType = ItemLibraryWidget::getAssetTypeAndData(assetPath).first;
if (assetType == "application/vnd.bauhaus.libraryresource.shader")
neededImports.insert("QtQuick3D");
else if (assetType == "application/vnd.bauhaus.libraryresource.sound")
neededImports.insert("QtMultimedia");
if (neededImports.size() == 2)
break;
};
if (neededImports.size() == 2)
break;
};
for (const QString &import : std::as_const(neededImports))
addImport(import);
for (const QString &import : std::as_const(neededImports))
addImport(import);
}
m_view->executeInTransaction("NavigatorTreeModel::dropMimeData", [&] {
for (const QString &assetPath : assetsPaths) {