QmlDesigner: Add tags for important imports

This makes the relevant imports a lot more discoverable.

Change-Id: Ide0396cf844c071aaee050a8993eb06a9c544daf
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Thomas Hartmann
2018-01-13 16:21:07 +01:00
parent f00b805da1
commit 59a01d9a1d
4 changed files with 125 additions and 31 deletions

View File

@@ -29,32 +29,38 @@
#include <theme.h> #include <theme.h>
#include <itemlibrarymodel.h>
#include <itemlibraryimageprovider.h>
#include <itemlibraryinfo.h>
#include <metainfo.h>
#include <model.h>
#include <rewritingexception.h>
#include <qmldesignerplugin.h>
#include <utils/flowlayout.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <utils/stylehelper.h> #include <utils/stylehelper.h>
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <coreplugin/coreconstants.h> #include <coreplugin/coreconstants.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include "itemlibrarymodel.h"
#include "itemlibraryimageprovider.h"
#include <model.h>
#include <metainfo.h>
#include "rewritingexception.h"
#include <QApplication>
#include <QDrag> #include <QDrag>
#include <QFileInfo> #include <QFileInfo>
#include <QFileSystemModel> #include <QFileSystemModel>
#include <QStackedWidget>
#include <QGridLayout> #include <QGridLayout>
#include <QTabBar>
#include <QImageReader> #include <QImageReader>
#include <QMenu>
#include <QMimeData> #include <QMimeData>
#include <QMouseEvent> #include <QMouseEvent>
#include <QWheelEvent>
#include <QMenu>
#include <QApplication>
#include <QTimer>
#include <QShortcut> #include <QShortcut>
#include <QStackedWidget>
#include <QTabBar>
#include <QTimer>
#include <QToolButton>
#include <QWheelEvent>
#include <QQmlContext> #include <QQmlContext>
#include <QQuickItem> #include <QQuickItem>
@@ -69,6 +75,7 @@ ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
m_itemIconSize(24, 24), m_itemIconSize(24, 24),
m_itemViewQuickWidget(new QQuickWidget), m_itemViewQuickWidget(new QQuickWidget),
m_resourcesView(new ItemLibraryResourceView(this)), m_resourcesView(new ItemLibraryResourceView(this)),
m_importTagsWidget(new QWidget(this)),
m_filterFlag(QtBasic) m_filterFlag(QtBasic)
{ {
m_compressionTimer.setInterval(200); m_compressionTimer.setInterval(200);
@@ -126,7 +133,6 @@ ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
lineEditLayout->addItem(new QSpacerItem(5, 5, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 2); lineEditLayout->addItem(new QSpacerItem(5, 5, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 2);
connect(m_filterLineEdit.data(), &Utils::FancyLineEdit::filterChanged, this, &ItemLibraryWidget::setSearchFilter); connect(m_filterLineEdit.data(), &Utils::FancyLineEdit::filterChanged, this, &ItemLibraryWidget::setSearchFilter);
m_stackedWidget = new QStackedWidget(this); m_stackedWidget = new QStackedWidget(this);
m_stackedWidget->addWidget(m_itemViewQuickWidget.data()); m_stackedWidget->addWidget(m_itemViewQuickWidget.data());
m_stackedWidget->addWidget(m_resourcesView.data()); m_stackedWidget->addWidget(m_resourcesView.data());
@@ -141,7 +147,8 @@ ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
layout->addWidget(tabBar, 0, 0, 1, 1); layout->addWidget(tabBar, 0, 0, 1, 1);
layout->addWidget(spacer, 1, 0); layout->addWidget(spacer, 1, 0);
layout->addWidget(lineEditFrame, 2, 0, 1, 1); layout->addWidget(lineEditFrame, 2, 0, 1, 1);
layout->addWidget(m_stackedWidget.data(), 3, 0, 1, 1); layout->addWidget(m_importTagsWidget.data(), 3, 0, 1, 1);
layout->addWidget(m_stackedWidget.data(), 4, 0, 1, 1);
setSearchFilter(QString()); setSearchFilter(QString());
@@ -154,6 +161,9 @@ ItemLibraryWidget::ItemLibraryWidget(QWidget *parent) :
connect(&m_compressionTimer, &QTimer::timeout, this, &ItemLibraryWidget::updateModel); connect(&m_compressionTimer, &QTimer::timeout, this, &ItemLibraryWidget::updateModel);
auto *flowLayout = new Utils::FlowLayout(m_importTagsWidget.data());
flowLayout->setMargin(4);
// init the first load of the QML UI elements // init the first load of the QML UI elements
reloadQmlSource(); reloadQmlSource();
} }
@@ -175,12 +185,8 @@ void ItemLibraryWidget::setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo)
void ItemLibraryWidget::updateImports() void ItemLibraryWidget::updateImports()
{ {
if (m_model) { if (m_model)
QStringList imports; setupImportTagWidget();
foreach (const Import &import, m_model->imports())
if (import.isLibraryImport())
imports << import.url();
}
} }
void ItemLibraryWidget::setImportsWidget(QWidget *importsWidget) void ItemLibraryWidget::setImportsWidget(QWidget *importsWidget)
@@ -223,10 +229,16 @@ void ItemLibraryWidget::setModel(Model *model)
void ItemLibraryWidget::setCurrentIndexOfStackedWidget(int index) void ItemLibraryWidget::setCurrentIndexOfStackedWidget(int index)
{ {
if (index == 2) if (index == 2) {
m_filterLineEdit->setVisible(false); m_filterLineEdit->setVisible(false);
else m_importTagsWidget->setVisible(true);
} if (index == 1) {
m_filterLineEdit->setVisible(true); m_filterLineEdit->setVisible(true);
m_importTagsWidget->setVisible(false);
} else {
m_filterLineEdit->setVisible(true);
m_importTagsWidget->setVisible(true);
}
m_stackedWidget->setCurrentIndex(index); m_stackedWidget->setCurrentIndex(index);
} }
@@ -249,6 +261,38 @@ void ItemLibraryWidget::reloadQmlSource()
m_itemViewQuickWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlFilePath)); m_itemViewQuickWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlFilePath));
} }
void ItemLibraryWidget::setupImportTagWidget()
{
QTC_ASSERT(m_model, return);
const QStringList imports = m_model->metaInfo().itemLibraryInfo()->showTagsForImports();
qDeleteAll(m_importTagsWidget->findChildren<QWidget*>("", Qt::FindDirectChildrenOnly));
auto *flowLayout = m_importTagsWidget->layout();
auto createButton = [this](const QString &import) {
auto button = new QToolButton(m_importTagsWidget.data());
auto font = button->font();
font.setPixelSize(9);
button->setFont(font);
button->setIcon(Utils::Icons::PLUS.icon());
button->setText(import);
button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
connect(button, &QToolButton::clicked, this, [this, import]() {
addPossibleImport(import);
});
return button;
};
for (const QString &importPath : imports) {
const Import import = Import::createLibraryImport(importPath);
if (!m_model->hasImport(import, true, true)
&& m_model->isImportPossible(import, true, true))
flowLayout->addWidget(createButton(importPath));
}
}
void ItemLibraryWidget::updateModel() void ItemLibraryWidget::updateModel()
{ {
m_itemLibraryModel->update(m_itemLibraryInfo.data(), m_model.data()); m_itemLibraryModel->update(m_itemLibraryInfo.data(), m_model.data());
@@ -293,8 +337,7 @@ void ItemLibraryWidget::startDragAndDrop(QQuickItem *mouseArea, QVariant itemLib
void ItemLibraryWidget::removeImport(const QString &name) void ItemLibraryWidget::removeImport(const QString &name)
{ {
if (!m_model) QTC_ASSERT(m_model, return);
return;
QList<Import> toBeRemovedImportList; QList<Import> toBeRemovedImportList;
foreach (const Import &import, m_model->imports()) foreach (const Import &import, m_model->imports())
@@ -306,9 +349,21 @@ void ItemLibraryWidget::removeImport(const QString &name)
void ItemLibraryWidget::addImport(const QString &name, const QString &version) void ItemLibraryWidget::addImport(const QString &name, const QString &version)
{ {
if (!m_model) QTC_ASSERT(m_model, return);
return;
m_model->changeImports({Import::createLibraryImport(name, version)}, {}); m_model->changeImports({Import::createLibraryImport(name, version)}, {});
} }
void ItemLibraryWidget::addPossibleImport(const QString &name)
{
QTC_ASSERT(m_model, return);
const Import import = m_model->highestPossibleImport(name);
try {
m_model->changeImports({Import::createLibraryImport(name, import.version())}, {});
}
catch (const RewritingException &e) {
e.showException();
}
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
}
} }

View File

@@ -86,18 +86,17 @@ public:
Q_INVOKABLE void startDragAndDrop(QQuickItem *mouseArea, QVariant itemLibId); Q_INVOKABLE void startDragAndDrop(QQuickItem *mouseArea, QVariant itemLibId);
protected:
void removeImport(const QString &name);
void addImport(const QString &name, const QString &version);
signals: signals:
void itemActivated(const QString& itemName); void itemActivated(const QString& itemName);
private: private:
void setCurrentIndexOfStackedWidget(int index); void setCurrentIndexOfStackedWidget(int index);
void reloadQmlSource(); void reloadQmlSource();
void setupImportTagWidget();
void removeImport(const QString &name);
void addImport(const QString &name, const QString &version);
void addPossibleImport(const QString &name);
private:
QTimer m_compressionTimer; QTimer m_compressionTimer;
QSize m_itemIconSize; QSize m_itemIconSize;
@@ -111,6 +110,8 @@ private:
QPointer<Utils::FancyLineEdit> m_filterLineEdit; QPointer<Utils::FancyLineEdit> m_filterLineEdit;
QScopedPointer<QQuickWidget> m_itemViewQuickWidget; QScopedPointer<QQuickWidget> m_itemViewQuickWidget;
QScopedPointer<ItemLibraryResourceView> m_resourcesView; QScopedPointer<ItemLibraryResourceView> m_resourcesView;
QScopedPointer<QWidget> m_importTagsWidget;
QShortcut *m_qmlSourceUpdateShortcut; QShortcut *m_qmlSourceUpdateShortcut;
QPointer<Model> m_model; QPointer<Model> m_model;

View File

@@ -99,8 +99,10 @@ public:
void setPossibleImports(const QList<Import> &possibleImports); void setPossibleImports(const QList<Import> &possibleImports);
void setUsedImports(const QList<Import> &usedImports); void setUsedImports(const QList<Import> &usedImports);
bool hasImport(const Import &import, bool ignoreAlias = true, bool allowHigherVersion = false); bool hasImport(const Import &import, bool ignoreAlias = true, bool allowHigherVersion = false);
bool isImportPossible(const Import &import, bool ignoreAlias = true, bool allowHigherVersion = false);
QString pathForImport(const Import &import); QString pathForImport(const Import &import);
QStringList importPaths() const; QStringList importPaths() const;
Import highestPossibleImport(const QString &importPath);
RewriterView *rewriterView() const; RewriterView *rewriterView() const;
void setRewriterView(RewriterView *rewriterView); void setRewriterView(RewriterView *rewriterView);

View File

@@ -1874,6 +1874,8 @@ void Model::setUsedImports(const QList<Import> &usedImports)
static bool compareVersions(const QString &version1, const QString &version2, bool allowHigherVersion) static bool compareVersions(const QString &version1, const QString &version2, bool allowHigherVersion)
{ {
if (version2.isEmpty())
return true;
if (version1 == version2) if (version1 == version2)
return true; return true;
if (!allowHigherVersion) if (!allowHigherVersion)
@@ -1921,6 +1923,26 @@ bool Model::hasImport(const Import &import, bool ignoreAlias, bool allowHigherVe
return false; return false;
} }
bool Model::isImportPossible(const Import &import, bool ignoreAlias, bool allowHigherVersion)
{
if (imports().contains(import))
return true;
if (!ignoreAlias)
return false;
const auto importList = possibleImports();
for (const Import &possibleImport : importList) {
if (possibleImport.isFileImport() && import.isFileImport())
if (possibleImport.file() == import.file())
return true;
if (possibleImport.isLibraryImport() && import.isLibraryImport())
if (possibleImport.url() == import.url() && compareVersions(possibleImport.version(), import.version(), allowHigherVersion))
return true;
}
return false;
}
QString Model::pathForImport(const Import &import) QString Model::pathForImport(const Import &import)
{ {
if (!rewriterView()) if (!rewriterView())
@@ -1944,6 +1966,20 @@ QStringList Model::importPaths() const
return importPathList; return importPathList;
} }
Import Model::highestPossibleImport(const QString &importPath)
{
Import candidate;
for (const Import &import : possibleImports()) {
if (import.url() == importPath) {
if (candidate.isEmpty() || compareVersions(import.version(), candidate.version(), true))
candidate = import;
}
}
return candidate;
}
RewriterView *Model::rewriterView() const RewriterView *Model::rewriterView() const
{ {
return d->rewriterView(); return d->rewriterView();