Implement new item library UI

- Create a new header qml widget.
- Move tabs and filtering search to the header widget.
- Add imports/assets using a new "+" button on the tabs.
- Remove import flow tag view (still some remainings to be removed in another commit).
- Change layout from grid to vbox.
- Rename some classes and variables to make them clearer.
- New "Add Library" view that replaces the QML imports view (older QML imports classes removed).
- Enable Search in the "add import" view.
- Hide category header if only 1 category is under an import.
- Assorted relevant fixes, tweaks, and clean ups.

Task-number: QDS-3589
Change-Id: I710aed50858b32e024200911c6a21fd963e1b692
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Henning Gründl <henning.gruendl@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Mahmoud Badri
2021-02-04 16:18:45 +02:00
parent 60f1e23ff2
commit 151184a609
55 changed files with 1372 additions and 1357 deletions

View File

@@ -27,38 +27,61 @@ import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuickDesignerTheme 1.0
import HelperWidgets 2.0
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
/* The view displaying the item grid.
The following Qml context properties have to be set:
- listmodel itemLibraryModel
- ItemLibraryModel listmodel
- int itemLibraryIconWidth
- int itemLibraryIconHeight
itemLibraryModel has to have the following structure:
itemLibraryModel structure:
ListModel {
ListElement {
int sectionLibId
string sectionName
list sectionEntries: [
ListElement {
int itemLibId
string itemName
pixmap itemPixmap
},
...
itemLibraryModel [
ItemLibraryImport {
string importName
string importUrl
bool importVisible
bool importUsed
bool importExpanded
list categoryModel [
ItemLibraryCategory {
string categoryName
bool categoryVisible
bool categoryExpanded
list itemModel [
ItemLibraryItem {
string itemName
string itemLibraryIconPath
bool itemVisible
string componentPath
var itemLibraryEntry
},
... more items
]
},
... more categories
]
},
... more imports
]
}
...
}
*/
ScrollView {
id: itemsView
property string importToRemove: ""
// called from C++ to close context menu on focus out
function closeContextMenu()
{
contextMenu.close()
}
Item {
id: styleConstants
property int textWidth: 58
@@ -72,22 +95,61 @@ ScrollView {
property int cellWidth: textWidth + 2 * cellHorizontalMargin
property int cellHeight: itemLibraryIconHeight + textHeight +
2 * cellVerticalMargin + cellVerticalSpacing
StudioControls.Menu {
id: contextMenu
StudioControls.MenuItem {
text: qsTr("Remove Library")
enabled: importToRemove !== ""
&& importToRemove !== "QtQuick"
onTriggered: rootView.removeImport(importToRemove)
}
}
}
Column {
id: column
spacing: 2
Repeater {
model: itemLibraryModel // to be set in Qml context
delegate: Section {
width: itemsView.width -
(itemsView.verticalScrollBarVisible ? StudioTheme.Values.scrollBarThickness : 0)
caption: sectionName // to be set by model
visible: sectionVisible
topPadding: 2
leftPadding: 2
rightPadding: 1
expanded: sectionExpanded
onExpandedChanged: itemLibraryModel.setExpanded(expanded, sectionName);
(itemsView.verticalScrollBarVisible ? itemsView.verticalThickness : 0)
caption: importName
visible: importVisible
sectionHeight: 30
sectionFontSize: 15
showArrow: categoryModel.rowCount() > 0
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
expanded: importExpanded
onExpandedChanged: itemLibraryModel.setExpanded(expanded, importUrl);
onShowContextMenu: {
importToRemove = importUsed ? "" : importUrl
contextMenu.popup()
}
Column {
spacing: 2
Repeater {
model: categoryModel
delegate: Section {
width: itemsView.width -
(itemsView.verticalScrollBarVisible ? itemsView.verticalThickness : 0)
sectionBackgroundColor: "transparent"
showTopSeparator: index > 0
hideHeader: categoryModel.rowCount() <= 1
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
caption: categoryName + " (" + itemModel.rowCount() + ")"
visible: categoryVisible
expanded: categoryExpanded
onExpandedChanged: itemLibraryModel.setExpanded(expanded, categoryName);
Grid {
id: itemGrid
@@ -95,7 +157,7 @@ ScrollView {
property int flexibleWidth: (parent.width - styleConstants.cellWidth * columns) / columns
Repeater {
model: sectionEntries
model: itemModel
delegate: ItemDelegate {
visible: itemVisible
width: styleConstants.cellWidth + itemGrid.flexibleWidth
@@ -106,5 +168,8 @@ ScrollView {
}
}
}
}
}
}
}

View File

@@ -32,8 +32,9 @@ Flickable {
property alias horizontalThickness: horizontalScrollBar.height
property alias verticalThickness: verticalScrollBar.width
property bool bothVisible: verticalScrollBar.scrollBarVisible
&& horizontalScrollBar.scrollBarVisible
property bool verticalScrollBarVisible: verticalScrollBar.scrollBarVisible
property bool horizontalScrollBarVisible: horizontalScrollBar.scrollBarVisible
property bool bothVisible: verticalScrollBarVisible && horizontalScrollBarVisible
contentWidth: areaItem.childrenRect.width
contentHeight: areaItem.childrenRect.height

View File

@@ -32,6 +32,12 @@ import StudioTheme 1.0 as StudioTheme
Item {
id: section
property alias caption: label.text
property alias sectionHeight: header.height
property alias sectionBackgroundColor: header.color
property alias sectionFontSize: label.font.pixelSize
property alias showTopSeparator: topSeparator.visible
property alias showArrow: arrow.visible
property int leftPadding: 8
property int topPadding: 4
property int rightPadding: 0
@@ -42,9 +48,18 @@ Item {
property bool expanded: true
property int level: 0
property int levelShift: 10
property bool hideHeader: false
onHideHeaderChanged:
{
header.visible = !hideHeader
header.height = hideHeader ? 0 : 20
}
clip: true
signal showContextMenu()
Rectangle {
id: header
height: 20
@@ -80,12 +95,28 @@ Item {
MouseArea {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.LeftButton) {
section.animationDuration = 120
section.expanded = !section.expanded
} else {
section.showContextMenu()
}
}
}
}
Rectangle {
id: topSeparator
height: 1
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 5 + leftPadding
anchors.leftMargin: 5 - leftPadding
visible: false
color: "#666666"
}
default property alias __content: row.children

View File

@@ -285,16 +285,6 @@ extend_qtc_plugin(QmlDesigner
transitiontool.cpp transitiontool.h
)
extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/importmanager
SOURCES
importlabel.cpp importlabel.h
importmanager.qrc
importmanagercombobox.cpp importmanagercombobox.h
importmanagerview.cpp importmanagerview.h
importswidget.cpp importswidget.h
)
extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/integration
PUBLIC_INCLUDES components/integration
@@ -316,14 +306,17 @@ extend_qtc_plugin(QmlDesigner
itemlibraryitem.cpp itemlibraryitem.h
itemlibrarymodel.cpp itemlibrarymodel.h
itemlibraryresourceview.cpp itemlibraryresourceview.h
itemlibrarysection.cpp itemlibrarysection.h
itemlibrarysectionmodel.cpp itemlibrarysectionmodel.h
itemlibrarycategory.cpp itemlibrarycategory.h
itemlibraryitemsmodel.cpp itemlibraryitemsmodel.h
itemlibraryview.cpp itemlibraryview.h
itemlibrarywidget.cpp itemlibrarywidget.h
itemlibraryassetimportdialog.cpp itemlibraryassetimportdialog.h
itemlibraryassetimportdialog.ui
itemlibraryassetimporter.cpp itemlibraryassetimporter.h
itemlibraryiconimageprovider.cpp itemlibraryiconimageprovider.h
itemLibraryimport.cpp itemLibraryimport.h
itemLibrarycategoriesmodel.cpp itemLibrarycategoriesmodel.h
itemlibraryaddimportmodel.cpp itemlibraryaddimportmodel.h
)
extend_qtc_plugin(QmlDesigner

View File

@@ -1,78 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "importlabel.h"
#include <utils/utilsicons.h>
#include <QHBoxLayout>
#include <QPushButton>
#include <QIcon>
namespace QmlDesigner {
ImportLabel::ImportLabel(QWidget *parent) :
QWidget(parent)
{
auto layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
m_removeButton = new QPushButton(this);
m_removeButton->setIcon(Utils::Icons::CLOSE_TOOLBAR.icon());
m_removeButton->setFlat(true);
m_removeButton->setMaximumWidth(20);
m_removeButton->setMaximumHeight(20);
m_removeButton->setFocusPolicy(Qt::NoFocus);
m_removeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
m_removeButton->setToolTip(tr("Remove Import"));
connect(m_removeButton, &QAbstractButton::clicked, this, [this] { emit removeImport(m_import); });
layout->addWidget(m_removeButton);
m_importLabel = new QLabel(this);
layout->addWidget(m_importLabel);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}
void ImportLabel::setImport(const Import &import)
{
m_importLabel->setText(import.toString(false));
m_import = import;
}
const Import ImportLabel::import() const
{
return m_import;
}
void ImportLabel::setReadOnly(bool readOnly) const
{
m_removeButton->setDisabled(readOnly);
m_removeButton->setIcon(readOnly ? QIcon()
: Utils::Icons::CLOSE_TOOLBAR.icon());
}
} // namespace QmlDesigner

View File

@@ -1,54 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QLabel>
#include <QPushButton>
#include <import.h>
namespace QmlDesigner {
class ImportLabel : public QWidget
{
Q_OBJECT
public:
explicit ImportLabel(QWidget *parent = nullptr);
void setImport(const Import &import);
const Import import() const;
void setReadOnly(bool) const;
signals:
void removeImport(const Import &import);
private:
Import m_import;
QLabel *m_importLabel;
QPushButton *m_removeButton;
};
}

View File

@@ -1,87 +0,0 @@
QPushButton, QComboBox[editable="false"],
QComboBox[editable="true"] {
background-color: creatorTheme.QmlDesigner_BackgroundColorDarkAlternate;
border-width: 3;
font-size: creatorTheme.captionFontPixelSize;
}
QPushButton:hover, QComboBox[editable="false"]:hover,
QComboBox[editable="true"]:hover, QMenuBar::item:hover {
background-color: creatorTheme.QmlDesigner_BackgroundColorDarkAlternate;
border-width: 3;
}
QPushButton:pressed, QComboBox[editable="false"]:on,
QComboBox[editable="true"]:on, QMenuBar::item:on {
background-color: creatorTheme.QmlDesigner_BackgroundColorDarkAlternate;
border-width: 3;
}
QComboBox
{
font-size: creatorTheme.captionFontPixelSize;
color: white;
min-width: 60px;
}
QComboBox[editable="false"] {
padding-left: 16px;
padding-right: 0px;
spacing: 2px;
}
QFontComboBox {
padding-left: 16px;
}
QComboBox[editable="false"]::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 12px;
border-left-style: solid;
border-left-color: black;
border-left-width: 0px;
}
QComboBox[editable="false"]::down-arrow {
subcontrol-origin: content;
subcontrol-position: center;
position: relative;
right: 3px;
}
QComboBox[editable="false"]::down-arrow:on {
position: relative;
top: 1px;
}
QComboBox[editable="true"] {
padding-right: 10px;
}
QComboBox[editable="true"]::drop-down {
subcontrol-origin: border;
subcontrol-position: top right;
width: 13px;
position: absolute;
top: 2px;
bottom: 2px;
right: 2px;
}
QComboBox[editable="true"]::drop-down,
QComboBox[editable="true"]::drop-down:hover,
QComboBox[editable="true"]::drop-down:on {
border-width: 0px;
border-left-width: 3px;
}
QComboBox[editable="true"]::down-arrow:on {
position: relative;
top: 1px;
left: 1px;
}
QComboBox::disabled {
color: gray;
}

View File

@@ -1,16 +0,0 @@
VPATH += $$PWD
HEADERS += importmanagerview.h \
components/importmanager/importlabel.h \
components/importmanager/importmanagercombobox.h
HEADERS += importswidget.h
SOURCES += importmanagerview.cpp \
components/importmanager/importlabel.cpp \
components/importmanager/importmanagercombobox.cpp
SOURCES += components/importmanager/importswidget.cpp
RESOURCES += \
components/importmanager/importmanager.qrc

View File

@@ -1,5 +0,0 @@
<RCC>
<qresource prefix="/importmanager">
<file>importmanager.css</file>
</qresource>
</RCC>

View File

@@ -1,58 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "importmanagercombobox.h"
#include <utils/fileutils.h>
#include <QStyle>
#include <QStyleFactory>
#include <QStylePainter>
ImportManagerComboBox::ImportManagerComboBox(QWidget *parent) :
QComboBox(parent)
{
QStyle *style = QStyleFactory::create("fusion");
setStyle(style);
setStyleSheet(QString::fromUtf8(Utils::FileReader::fetchQrc(QLatin1String(":/importmanager/importmanager.css"))));
setToolTip(tr("Add new import"));
}
void ImportManagerComboBox::paintEvent(QPaintEvent *)
{
QStylePainter painter(this);
painter.setPen(palette().color(QPalette::Text));
// draw the combobox frame, focusrect and selected etc.
QStyleOptionComboBox opt;
initStyleOption(&opt);
opt.currentText = tr("<Add Import>");
painter.drawComplexControl(QStyle::CC_ComboBox, opt);
// draw the icon and text
painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
}

View File

@@ -1,38 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QComboBox>
class ImportManagerComboBox : public QComboBox
{
Q_OBJECT
public:
explicit ImportManagerComboBox(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *e) override;
};

View File

@@ -1,142 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "importmanagerview.h"
#include "importswidget.h"
#include <rewritingexception.h>
#include <qmldesignerplugin.h>
#include <qmldesignerconstants.h>
namespace QmlDesigner {
ImportManagerView::ImportManagerView(QObject *parent)
: AbstractView(parent)
{
}
ImportManagerView::~ImportManagerView() = default;
bool ImportManagerView::hasWidget() const
{
return true;
}
WidgetInfo ImportManagerView::widgetInfo()
{
if (m_importsWidget == nullptr) {
m_importsWidget = new ImportsWidget;
connect(m_importsWidget.data(), &ImportsWidget::removeImport, this, &ImportManagerView::removeImport);
connect(m_importsWidget.data(), &ImportsWidget::addImport, this, &ImportManagerView::addImport);
if (model())
m_importsWidget->setImports(model()->imports());
}
return createWidgetInfo(m_importsWidget, nullptr, QLatin1String("ImportManager"), WidgetInfo::LeftPane, 1, tr("Import Manager"));
}
void ImportManagerView::modelAttached(Model *model)
{
AbstractView::modelAttached(model);
if (m_importsWidget) {
m_importsWidget->setImports(model->imports());
m_importsWidget->setPossibleImports(model->possibleImports());
m_importsWidget->setUsedImports(model->usedImports());
}
}
void ImportManagerView::modelAboutToBeDetached(Model *model)
{
if (m_importsWidget) {
m_importsWidget->removeImports();
m_importsWidget->removePossibleImports();
m_importsWidget->removeUsedImports();
}
AbstractView::modelAboutToBeDetached(model);
}
void ImportManagerView::importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports)
{
Q_UNUSED(addedImports);
Q_UNUSED(removedImports);
if (m_importsWidget) {
m_importsWidget->setImports(model()->imports());
// setImports recreates labels, so we need to update used imports, as it is not guaranteed
// usedImportsChanged notification will come after this.
m_importsWidget->setUsedImports(model()->usedImports());
// setPossibleImports done in response to possibleImportsChanged comes before importsChanged,
// which causes incorrect "already used" filtering to be applied to possible imports list,
// so update the possible imports list here, too.
m_importsWidget->setPossibleImports(model()->possibleImports());
}
}
void ImportManagerView::possibleImportsChanged(const QList<Import> &/*possibleImports*/)
{
if (m_importsWidget)
m_importsWidget->setPossibleImports(model()->possibleImports());
}
void ImportManagerView::usedImportsChanged(const QList<Import> &/*usedImports*/)
{
if (m_importsWidget)
m_importsWidget->setUsedImports(model()->usedImports());
}
void ImportManagerView::removeImport(const Import &import)
{
try {
if (model())
model()->changeImports({}, {import});
}
catch (const RewritingException &e) {
e.showException();
}
}
void ImportManagerView::addImport(const Import &import)
{
if (import.isLibraryImport()
&& (import.url().startsWith("QtQuick")
|| import.url().startsWith("SimulinkConnector"))) {
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_IMPORT_ADDED
+ import.toImportString());
}
try {
if (model())
model()->changeImports({import}, {});
}
catch (const RewritingException &e) {
e.showException();
}
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
}
} // namespace QmlDesigner

View File

@@ -1,192 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "importswidget.h"
#include "importlabel.h"
#include "importmanagercombobox.h"
#include <designdocument.h>
#include <qmldesignerplugin.h>
#include <designermcumanager.h>
#include <utils/algorithm.h>
#include <QVBoxLayout>
#include <QComboBox>
namespace QmlDesigner {
ImportsWidget::ImportsWidget(QWidget *parent) :
QWidget(parent)
{
setWindowTitle(tr("Import Manager"));
m_addImportComboBox = new ImportManagerComboBox(this);
connect(m_addImportComboBox, QOverload<int>::of(&QComboBox::activated),
this, &ImportsWidget::addSelectedImport);
}
void ImportsWidget::removeImports()
{
qDeleteAll(m_importLabels);
m_importLabels.clear();
updateLayout();
}
static bool isImportAlreadyUsed(const Import &import, QList<ImportLabel *> importLabels)
{
foreach (ImportLabel *importLabel, importLabels) {
if (importLabel->import() == import)
return true;
}
return false;
}
static bool importLess(const Import &firstImport, const Import &secondImport)
{
if (firstImport.url() == secondImport.url())
return firstImport.toString() < secondImport.toString();
if (firstImport.url() == "QtQuick")
return true;
if (secondImport.url() == "QtQuick")
return false;
if (firstImport.isLibraryImport() && secondImport.isFileImport())
return false;
if (firstImport.isFileImport() && secondImport.isLibraryImport())
return true;
if (firstImport.isFileImport() && secondImport.isFileImport())
return QString::localeAwareCompare(firstImport.file(), secondImport.file()) < 0;
if (firstImport.isLibraryImport() && secondImport.isLibraryImport())
return QString::localeAwareCompare(firstImport.url(), secondImport.url()) < 0;
return false;
}
void ImportsWidget::setPossibleImports(QList<Import> possibleImports)
{
Utils::sort(possibleImports, importLess);
m_addImportComboBox->clear();
const DesignerMcuManager &mcuManager = DesignerMcuManager::instance();
const bool isQtForMCUs = mcuManager.isMCUProject();
QList<Import> filteredImports;
const QStringList mcuAllowedList = mcuManager.allowedImports();
const QStringList mcuBannedList = mcuManager.bannedImports();
if (isQtForMCUs) {
filteredImports = Utils::filtered(possibleImports,
[mcuAllowedList, mcuBannedList](const Import &import) {
return (mcuAllowedList.contains(import.url())
|| !import.url().startsWith("Qt"))
&& !mcuBannedList.contains(import.url());
});
} else {
filteredImports = possibleImports;
}
for (const Import &possibleImport : filteredImports) {
if (!isImportAlreadyUsed(possibleImport, m_importLabels))
m_addImportComboBox->addItem(possibleImport.toString(true), QVariant::fromValue(possibleImport));
}
}
void ImportsWidget::removePossibleImports()
{
m_addImportComboBox->clear();
}
void ImportsWidget::setUsedImports(const QList<Import> &usedImports)
{
const QStringList excludeList = {"SimulinkConnector"};
// exclude imports in the excludeList from being readonly (i.e. always enable their x button)
QList<Import> filteredImports = Utils::filtered(usedImports, [excludeList](const Import &import) {
return !excludeList.contains(import.url());
});
foreach (ImportLabel *importLabel, m_importLabels)
importLabel->setReadOnly(filteredImports.contains(importLabel->import()));
}
void ImportsWidget::removeUsedImports()
{
foreach (ImportLabel *importLabel, m_importLabels)
importLabel->setEnabled(true);
}
void ImportsWidget::setImports(const QList<Import> &imports)
{
qDeleteAll(m_importLabels);
m_importLabels.clear();
QList<Import> sortedImports = imports;
Utils::sort(sortedImports, importLess);
foreach (const Import &import, sortedImports) {
auto importLabel = new ImportLabel(this);
importLabel->setImport(import);
m_importLabels.append(importLabel);
connect(importLabel, &ImportLabel::removeImport, this, &ImportsWidget::removeImport);
}
updateLayout();
}
void ImportsWidget::updateLayout()
{
delete layout();
auto layout = new QVBoxLayout(this);
layout->setSpacing(0);
layout->addWidget(m_addImportComboBox);
foreach (ImportLabel *importLabel, m_importLabels)
layout->addWidget(importLabel);
layout->addStretch();
}
void ImportsWidget::addSelectedImport(int addImportComboBoxIndex)
{
Import selectedImport = m_addImportComboBox->itemData(addImportComboBoxIndex).value<Import>();
if (selectedImport.isEmpty())
return;
emit addImport(selectedImport);
}
} // namespace QmlDesigner

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

View File

@@ -7,9 +7,12 @@ HEADERS += itemlibraryview.h \
itemlibrarymodel.h \
itemlibraryresourceview.h \
itemlibraryimageprovider.h \
itemlibrarysectionmodel.h \
itemlibraryitem.h \
itemlibrarysection.h \
itemlibrarycategory.h \
itemlibraryitemsmodel.h \
itemlibraryimport.h \
itemlibrarycategoriesmodel.h \
itemlibraryaddimportmodel.h \
itemlibraryassetimportdialog.h \
itemlibraryassetimporter.h \
customfilesystemmodel.h
@@ -20,9 +23,12 @@ SOURCES += itemlibraryview.cpp \
itemlibrarymodel.cpp \
itemlibraryresourceview.cpp \
itemlibraryimageprovider.cpp \
itemlibrarysectionmodel.cpp \
itemlibraryitem.cpp \
itemlibrarysection.cpp \
itemlibrarycategory.cpp \
itemlibraryitemsmodel.cpp \
itemlibraryimport.cpp \
itemlibrarycategoriesmodel.cpp \
itemlibraryaddimportmodel.cpp \
itemlibraryassetimportdialog.cpp \
itemlibraryassetimporter.cpp \
customfilesystemmodel.cpp

View File

@@ -29,5 +29,17 @@
<file>images/asset_sound_192.png</file>
<file>images/asset_sound_256.png</file>
<file>images/asset_sound_384.png</file>
<file>images/tab_icon.png</file>
<file>images/tab_icon@2x.png</file>
<file>images/x.png</file>
<file>images/x@2x.png</file>
<file>images/add.png</file>
<file>images/add@2x.png</file>
<file>images/add_unselected.png</file>
<file>images/add_unselected@2x.png</file>
<file>images/down.png</file>
<file>images/down@2x.png</file>
<file>qml/libraryheader.qml</file>
<file>qml/addimport.qml</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,156 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "itemlibraryaddimportmodel.h"
#include <designermcumanager.h>
#include <utils/algorithm.h>
#include <QDebug>
#include <QVariant>
#include <QMetaProperty>
namespace QmlDesigner {
ItemLibraryAddImportModel::ItemLibraryAddImportModel(QObject *parent)
: QAbstractListModel(parent)
{
// add role names
m_roleNames.insert(Qt::UserRole + 1, "importUrl");
m_roleNames.insert(Qt::UserRole + 2, "importVisible");
}
ItemLibraryAddImportModel::~ItemLibraryAddImportModel()
{
}
int ItemLibraryAddImportModel::rowCount(const QModelIndex & /*parent*/) const
{
return m_importList.count();
}
QVariant ItemLibraryAddImportModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= m_importList.count())
return {};
QString importUrl = m_importList[index.row()].url();
if (m_roleNames[role] == "importUrl")
return importUrl;
if (m_roleNames[role] == "importVisible")
return m_searchText.isEmpty() || m_importFilterList.contains(importUrl);
qWarning() << Q_FUNC_INFO << "invalid role requested";
return {};
}
QHash<int, QByteArray> ItemLibraryAddImportModel::roleNames() const
{
return m_roleNames;
}
void ItemLibraryAddImportModel::update(const QList<Import> &possibleImports)
{
beginResetModel();
m_importList.clear();
const DesignerMcuManager &mcuManager = DesignerMcuManager::instance();
const bool isQtForMCUs = mcuManager.isMCUProject();
QList<Import> filteredImports;
const QStringList mcuAllowedList = mcuManager.allowedImports();
const QStringList mcuBannedList = mcuManager.bannedImports();
if (isQtForMCUs) {
filteredImports = Utils::filtered(possibleImports,
[&](const Import &import) {
return (mcuAllowedList.contains(import.url())
|| !import.url().startsWith("Qt"))
&& !mcuBannedList.contains(import.url());
});
} else {
filteredImports = possibleImports;
}
Utils::sort(filteredImports, [](const Import &firstImport, const Import &secondImport) {
if (firstImport.url() == secondImport.url())
return firstImport.toString() < secondImport.toString();
if (firstImport.url() == "QtQuick")
return true;
if (secondImport.url() == "QtQuick")
return false;
if (firstImport.isLibraryImport() && secondImport.isFileImport())
return false;
if (firstImport.isFileImport() && secondImport.isLibraryImport())
return true;
if (firstImport.isFileImport() && secondImport.isFileImport())
return QString::localeAwareCompare(firstImport.file(), secondImport.file()) < 0;
if (firstImport.isLibraryImport() && secondImport.isLibraryImport())
return QString::localeAwareCompare(firstImport.url(), secondImport.url()) < 0;
return false;
});
// create import sections
for (const Import &import : std::as_const(filteredImports)) {
if (import.isLibraryImport())
m_importList.append(import);
}
endResetModel();
}
void ItemLibraryAddImportModel::setSearchText(const QString &searchText)
{
QString lowerSearchText = searchText.toLower();
if (m_searchText != lowerSearchText) {
beginResetModel();
m_searchText = lowerSearchText;
for (const Import &import : std::as_const(m_importList)) {
if (import.url().toLower().contains(lowerSearchText))
m_importFilterList.insert(import.url());
else
m_importFilterList.remove(import.url());
}
endResetModel();
}
}
Import ItemLibraryAddImportModel::getImportAt(int index) const
{
return m_importList.at(index);
}
} // namespace QmlDesigner

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,46 +25,36 @@
#pragma once
#include <QAbstractListModel>
#include <import.h>
#include <QWidget>
QT_BEGIN_NAMESPACE
class QComboBox;
QT_END_NAMESPACE
#include <QSet>
namespace QmlDesigner {
class ImportLabel;
class ItemLibraryEntry;
class ImportsWidget : public QWidget
class ItemLibraryAddImportModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit ImportsWidget(QWidget *parent = nullptr);
explicit ItemLibraryAddImportModel(QObject *parent = nullptr);
~ItemLibraryAddImportModel() override;
void setImports(const QList<Import> &imports);
void removeImports();
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
void setPossibleImports(QList<Import> possibleImports);
void removePossibleImports();
void setUsedImports(const QList<Import> &possibleImports);
void removeUsedImports();
signals:
void removeImport(const Import &import);
void addImport(const Import &import);
protected:
void updateLayout();
void update(const QList<Import> &possibleImports);
void setSearchText(const QString &searchText);
Import getImportAt(int index) const;
private:
void addSelectedImport(int addImportComboBoxIndex);
private:
QList<ImportLabel*> m_importLabels;
QComboBox *m_addImportComboBox;
QString m_searchText;
QList<Import> m_importList;
QSet<QString> m_importFilterList;
QHash<int, QByteArray> m_roleNames;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,114 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "itemlibrarycategoriesmodel.h"
#include "itemlibrarycategory.h"
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <QVariant>
#include <QMetaProperty>
#include <QMetaObject>
namespace QmlDesigner {
ItemLibraryCategoriesModel::ItemLibraryCategoriesModel(QObject *parent) :
QAbstractListModel(parent)
{
addRoleNames();
}
ItemLibraryCategoriesModel::~ItemLibraryCategoriesModel()
{
}
int ItemLibraryCategoriesModel::rowCount(const QModelIndex &) const
{
return m_categoryList.count();
}
QVariant ItemLibraryCategoriesModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= m_categoryList.count()) {
qWarning() << Q_FUNC_INFO << "invalid index requested";
return {};
}
if (m_roleNames.contains(role)) {
QVariant value = m_categoryList.at(index.row())->property(m_roleNames.value(role));
if (auto model = qobject_cast<ItemLibraryItemsModel *>(value.value<QObject *>()))
return QVariant::fromValue(model);
return value;
}
qWarning() << Q_FUNC_INFO << "invalid role requested";
return {};
}
QHash<int, QByteArray> ItemLibraryCategoriesModel::roleNames() const
{
return m_roleNames;
}
void ItemLibraryCategoriesModel::addCategory(ItemLibraryCategory *category)
{
m_categoryList.append(category);
category->setVisible(true);
}
const QList<QPointer<ItemLibraryCategory>> &ItemLibraryCategoriesModel::categorySections() const
{
return m_categoryList;
}
void ItemLibraryCategoriesModel::sortCategorySections()
{
auto categorySort = [](ItemLibraryCategory *first, ItemLibraryCategory *second) {
return QString::localeAwareCompare(first->sortingName(), second->sortingName()) < 0;
};
std::sort(m_categoryList.begin(), m_categoryList.end(), categorySort);
}
void ItemLibraryCategoriesModel::resetModel()
{
beginResetModel();
endResetModel();
}
void ItemLibraryCategoriesModel::addRoleNames()
{
int role = 0;
const QMetaObject meta = ItemLibraryCategory::staticMetaObject;
for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i)
m_roleNames.insert(role++, meta.property(i).name());
}
} // namespace QmlDesigner

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,37 +25,39 @@
#pragma once
#include <abstractview.h>
#include "itemlibrarymodel.h"
#include <QObject>
#include <QPointer>
namespace QmlDesigner {
class ImportsWidget;
class ItemLibraryCategory;
class ImportManagerView : public AbstractView
class ItemLibraryCategoriesModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit ImportManagerView(QObject *parent = nullptr);
~ImportManagerView() override;
ItemLibraryCategoriesModel(QObject *parent = nullptr);
~ItemLibraryCategoriesModel() override;
bool hasWidget() const override;
WidgetInfo widgetInfo() override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
void addCategory(ItemLibraryCategory *category);
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
void possibleImportsChanged(const QList<Import> &possibleImports) override;
void usedImportsChanged(const QList<Import> &usedImports) override;
const QList<QPointer<ItemLibraryCategory>> &categorySections() const;
void sortCategorySections();
void resetModel();
private:
void removeImport(const Import &import);
void addImport(const Import &import);
void addRoleNames();
private:
QPointer<ImportsWidget> m_importsWidget;
QList<QPointer<ItemLibraryCategory>> m_categoryList;
QHash<int, QByteArray> m_roleNames;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "itemlibrarycategory.h"
#include "itemlibraryitem.h"
namespace QmlDesigner {
ItemLibraryCategory::ItemLibraryCategory(const QString &groupName, QObject *parent)
: QObject(parent),
m_name(groupName)
{
}
QString ItemLibraryCategory::categoryName() const
{
return m_name;
}
bool ItemLibraryCategory::categoryExpanded() const
{
return m_categoryExpanded;
}
QString ItemLibraryCategory::sortingName() const
{
return categoryName();
}
void ItemLibraryCategory::addItem(ItemLibraryItem *itemEntry)
{
m_itemModel.addItem(itemEntry);
}
QObject *ItemLibraryCategory::itemModel()
{
return &m_itemModel;
}
bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool *changed)
{
bool hasVisibleItems = false;
*changed = false;
for (const auto &item : m_itemModel.items()) {
bool itemVisible = item->itemName().toLower().contains(searchText)
|| item->typeName().toLower().contains(searchText);
bool itemChanged = item->setVisible(itemVisible);
*changed |= itemChanged;
if (itemVisible)
hasVisibleItems = true;
}
return hasVisibleItems;
}
bool ItemLibraryCategory::setVisible(bool isVisible)
{
if (isVisible != m_isVisible) {
m_isVisible = isVisible;
return true;
}
return false;
}
bool ItemLibraryCategory::isVisible() const
{
return m_isVisible;
}
void ItemLibraryCategory::sortItems()
{
m_itemModel.sortItems();
}
void ItemLibraryCategory::setExpanded(bool expanded)
{
m_categoryExpanded = expanded;
}
} // namespace QmlDesigner

View File

@@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
@@ -25,47 +25,49 @@
#pragma once
#include "itemlibrarysectionmodel.h"
#include "itemlibraryitemsmodel.h"
namespace QmlDesigner {
class ItemLibrarySection: public QObject {
class ItemLibraryItem;
class ItemLibraryCategory : public QObject
{
Q_OBJECT
Q_PROPERTY(QObject* sectionEntries READ sectionEntries NOTIFY sectionEntriesChanged FINAL)
Q_PROPERTY(QString sectionName READ sectionName FINAL)
Q_PROPERTY(bool sectionVisible READ isVisible NOTIFY visibilityChanged FINAL)
Q_PROPERTY(bool sectionExpanded READ sectionExpanded FINAL)
Q_PROPERTY(QString categoryName READ categoryName FINAL)
Q_PROPERTY(bool categoryVisible READ isVisible NOTIFY visibilityChanged FINAL)
Q_PROPERTY(bool categoryExpanded READ categoryExpanded FINAL)
Q_PROPERTY(QObject *itemModel READ itemModel NOTIFY itemModelChanged FINAL)
public:
ItemLibrarySection(const QString &sectionName, QObject *parent = nullptr);
ItemLibraryCategory(const QString &groupName, QObject *parent = nullptr);
QString sectionName() const;
bool sectionExpanded() const;
QString categoryName() const;
bool categoryExpanded() const;
QString sortingName() const;
void addSectionEntry(ItemLibraryItem *sectionEntry);
QObject *sectionEntries();
void addItem(ItemLibraryItem *item);
QObject *itemModel();
bool updateSectionVisibility(const QString &searchText, bool *changed);
bool updateItemVisibility(const QString &searchText, bool *changed);
bool setVisible(bool isVisible);
bool isVisible() const;
void sortItems();
void setSectionExpanded(bool expanded);
void setExpanded(bool expanded);
signals:
void sectionEntriesChanged();
void itemModelChanged();
void visibilityChanged();
private:
ItemLibrarySectionModel m_sectionEntries;
ItemLibraryItemsModel m_itemModel;
QString m_name;
bool m_sectionExpanded;
bool m_isVisible;
bool m_categoryExpanded = true;
bool m_isVisible = true;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,153 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "itemlibraryimport.h"
#include "itemlibrarycategory.h"
namespace QmlDesigner {
ItemLibraryImport::ItemLibraryImport(const Import &import, QObject *parent)
: QObject(parent),
m_import(import)
{
}
QString ItemLibraryImport::importName() const
{
if (importUrl().isEmpty())
return userComponentsTitle();
if (importUrl() == "QtQuick")
return tr("Default Components");
return importUrl().replace('.', ' ');
}
QString ItemLibraryImport::importUrl() const
{
return m_import.url();
}
bool ItemLibraryImport::importExpanded() const
{
return m_importExpanded;
}
QString ItemLibraryImport::sortingName() const
{
if (importName() == userComponentsTitle()) // user components always come first
return "_";
return importName();
}
void ItemLibraryImport::addCategory(ItemLibraryCategory *category)
{
m_categoryModel.addCategory(category);
}
QObject *ItemLibraryImport::categoryModel()
{
return &m_categoryModel;
}
bool ItemLibraryImport::updateCategoryVisibility(const QString &searchText, bool *changed)
{
bool hasVisibleItems = false;
*changed = false;
for (const auto &category : m_categoryModel.categorySections()) {
bool categoryChanged = false;
hasVisibleItems = category->updateItemVisibility(searchText, &categoryChanged);
categoryChanged |= category->setVisible(hasVisibleItems);
*changed |= categoryChanged;
*changed |= hasVisibleItems;
}
if (*changed)
m_categoryModel.resetModel();
return hasVisibleItems;
}
Import ItemLibraryImport::importEntry() const
{
return m_import;
}
bool ItemLibraryImport::setVisible(bool isVisible)
{
if (isVisible != m_isVisible) {
m_isVisible = isVisible;
return true;
}
return false;
}
bool ItemLibraryImport::isVisible() const
{
return m_isVisible;
}
void ItemLibraryImport::setImportUsed(bool importUsed)
{
m_importUsed = importUsed;
}
bool ItemLibraryImport::isImportUsed() const
{
return m_importUsed;
}
void ItemLibraryImport::sortCategorySections()
{
m_categoryModel.sortCategorySections();
}
void ItemLibraryImport::setExpanded(bool expanded)
{
m_importExpanded = expanded;
}
ItemLibraryCategory *ItemLibraryImport::getCategorySection(const QString &categoryName) const
{
for (ItemLibraryCategory *catSec : std::as_const(m_categoryModel.categorySections())) {
if (catSec->categoryName() == categoryName)
return catSec;
}
return nullptr;
}
// static
QString ItemLibraryImport::userComponentsTitle()
{
return tr("My Components");
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,81 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "itemlibrarycategoriesmodel.h"
#include "import.h"
namespace QmlDesigner {
class ItemLibraryCategory;
class ItemLibraryImport : public QObject
{
Q_OBJECT
Q_PROPERTY(QString importName READ importName FINAL)
Q_PROPERTY(QString importUrl READ importUrl FINAL)
Q_PROPERTY(bool importVisible READ isVisible NOTIFY visibilityChanged FINAL)
Q_PROPERTY(bool importUsed READ isImportUsed NOTIFY importUsedChanged FINAL)
Q_PROPERTY(bool importExpanded READ importExpanded FINAL)
Q_PROPERTY(QObject *categoryModel READ categoryModel NOTIFY categoryModelChanged FINAL)
public:
ItemLibraryImport(const Import &import, QObject *parent = nullptr);
QString importName() const;
QString importUrl() const;
bool importExpanded() const;
QString sortingName() const;
Import importEntry() const;
bool isVisible() const;
bool isImportUsed() const;
ItemLibraryCategory *getCategorySection(const QString &categoryName) const;
void addCategory(ItemLibraryCategory *category);
QObject *categoryModel();
bool updateCategoryVisibility(const QString &searchText, bool *changed);
bool setVisible(bool isVisible);
void setImportUsed(bool importUsed);
void sortCategorySections();
void setExpanded(bool expanded);
static QString userComponentsTitle();
signals:
void categoryModelChanged();
void visibilityChanged();
void importUsedChanged();
private:
Import m_import;
bool m_importExpanded = true;
bool m_isVisible = true;
bool m_importUsed = false;
ItemLibraryCategoriesModel m_categoryModel;
};
} // namespace QmlDesigner

View File

@@ -27,9 +27,9 @@
namespace QmlDesigner {
ItemLibraryItem::ItemLibraryItem(QObject *parent)
ItemLibraryItem::ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, QObject *parent)
: QObject(parent),
m_isVisible(true)
m_itemLibraryEntry(itemLibraryEntry)
{
}
@@ -77,11 +77,6 @@ bool ItemLibraryItem::isVisible() const
return m_isVisible;
}
void ItemLibraryItem::setItemLibraryEntry(const ItemLibraryEntry &itemLibraryEntry)
{
m_itemLibraryEntry = itemLibraryEntry;
}
QVariant ItemLibraryItem::itemLibraryEntry() const
{
return QVariant::fromValue(m_itemLibraryEntry);

View File

@@ -34,8 +34,8 @@
namespace QmlDesigner {
class ItemLibraryItem: public QObject {
class ItemLibraryItem: public QObject
{
Q_OBJECT
Q_PROPERTY(QVariant itemLibraryEntry READ itemLibraryEntry FINAL)
@@ -45,7 +45,7 @@ class ItemLibraryItem: public QObject {
Q_PROPERTY(QString componentPath READ componentPath FINAL)
public:
ItemLibraryItem(QObject *parent);
ItemLibraryItem(const ItemLibraryEntry &itemLibraryEntry, QObject *parent);
~ItemLibraryItem() override;
QString itemName() const;
@@ -56,7 +56,6 @@ public:
bool setVisible(bool isVisible);
bool isVisible() const;
void setItemLibraryEntry(const ItemLibraryEntry &itemLibraryEntry);
QVariant itemLibraryEntry() const;
signals:
@@ -64,7 +63,7 @@ signals:
private:
ItemLibraryEntry m_itemLibraryEntry;
bool m_isVisible;
bool m_isVisible = true;
};
} // namespace QmlDesigner

View File

@@ -23,70 +23,62 @@
**
****************************************************************************/
#include "itemlibrarysectionmodel.h"
#include "itemlibraryitemsmodel.h"
#include "itemlibraryitem.h"
#include <utils/qtcassert.h>
#include <QDebug>
#include <QMetaProperty>
namespace QmlDesigner {
ItemLibrarySectionModel::ItemLibrarySectionModel(QObject *parent) :
ItemLibraryItemsModel::ItemLibraryItemsModel(QObject *parent) :
QAbstractListModel(parent)
{
addRoleNames();
}
ItemLibrarySectionModel::~ItemLibrarySectionModel()
ItemLibraryItemsModel::~ItemLibraryItemsModel()
{
}
int ItemLibrarySectionModel::rowCount(const QModelIndex &) const
int ItemLibraryItemsModel::rowCount(const QModelIndex &) const
{
return m_itemList.count();
}
QVariant ItemLibrarySectionModel::data(const QModelIndex &index, int role) const
QVariant ItemLibraryItemsModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() + 1 > m_itemList.count()) {
if (!index.isValid() || index.row() >= m_itemList.count()) {
qDebug() << Q_FUNC_INFO << "invalid index requested";
return QVariant();
return {};
}
if (m_roleNames.contains(role)) {
QVariant value = m_itemList.at(index.row())->property(m_roleNames.value(role));
if (auto model = qobject_cast<ItemLibrarySectionModel *>(value.value<QObject*>()))
return QVariant::fromValue(model);
if (m_roleNames.contains(role))
return m_itemList.at(index.row())->property(m_roleNames.value(role));
}
qWarning() << Q_FUNC_INFO << "invalid role requested";
return QVariant();
return {};
}
QHash<int, QByteArray> ItemLibrarySectionModel::roleNames() const
QHash<int, QByteArray> ItemLibraryItemsModel::roleNames() const
{
return m_roleNames;
}
void ItemLibrarySectionModel::addItem(ItemLibraryItem *element)
void ItemLibraryItemsModel::addItem(ItemLibraryItem *element)
{
m_itemList.append(element);
element->setVisible(true);
}
const QList<QPointer<ItemLibraryItem>> &ItemLibrarySectionModel::items() const
const QList<QPointer<ItemLibraryItem>> &ItemLibraryItemsModel::items() const
{
return m_itemList;
}
void ItemLibrarySectionModel::sortItems()
void ItemLibraryItemsModel::sortItems()
{
int nullPointerSectionCount = m_itemList.removeAll(QPointer<ItemLibraryItem>());
QTC_ASSERT(nullPointerSectionCount == 0,;);
@@ -97,20 +89,18 @@ void ItemLibrarySectionModel::sortItems()
std::sort(m_itemList.begin(), m_itemList.end(), itemSort);
}
void ItemLibrarySectionModel::resetModel()
void ItemLibraryItemsModel::resetModel()
{
beginResetModel();
endResetModel();
}
void ItemLibrarySectionModel::addRoleNames()
void ItemLibraryItemsModel::addRoleNames()
{
int role = 0;
for (int propertyIndex = 0; propertyIndex < ItemLibraryItem::staticMetaObject.propertyCount(); ++propertyIndex) {
QMetaProperty property = ItemLibraryItem::staticMetaObject.property(propertyIndex);
m_roleNames.insert(role, property.name());
++role;
}
const QMetaObject meta = ItemLibraryItem::staticMetaObject;
for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i)
m_roleNames.insert(role++, meta.property(i).name());
}
} // namespace QmlDesigner

View File

@@ -25,8 +25,7 @@
#pragma once
#include "itemlibrarymodel.h"
#include <QAbstractListModel>
#include <QObject>
#include <QPointer>
@@ -34,13 +33,13 @@ namespace QmlDesigner {
class ItemLibraryItem;
class ItemLibrarySectionModel: public QAbstractListModel {
class ItemLibraryItemsModel : public QAbstractListModel
{
Q_OBJECT
public:
ItemLibrarySectionModel(QObject *parent = nullptr);
~ItemLibrarySectionModel() override;
ItemLibraryItemsModel(QObject *parent = nullptr);
~ItemLibraryItemsModel() override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
@@ -48,19 +47,16 @@ public:
void addItem(ItemLibraryItem *item);
const QList<QPointer<ItemLibraryItem> > &items() const;
const QList<QPointer<ItemLibraryItem>> &items() const;
void sortItems();
void resetModel();
private: // functions
private:
void addRoleNames();
private: // variables
QList<QPointer<ItemLibraryItem>> m_itemList;
QHash<int, QByteArray> m_roleNames;
};
} // namespace QmlDesigner
QML_DECLARE_TYPE(QmlDesigner::ItemLibrarySectionModel)

View File

@@ -24,17 +24,16 @@
****************************************************************************/
#include "itemlibrarymodel.h"
#include "itemlibraryinfo.h"
#include "itemlibrarysection.h"
#include "itemlibrarycategoriesmodel.h"
#include "itemlibraryimport.h"
#include "itemlibrarycategory.h"
#include "itemlibraryitem.h"
#include "itemlibrarysection.h"
#include "itemlibraryinfo.h"
#include <model.h>
#include <nodehints.h>
#include <nodemetainfo.h>
#include <designdocument.h>
#include <qmldesignerplugin.h>
#include <designermcumanager.h>
#include <utils/algorithm.h>
@@ -44,29 +43,18 @@
#include <QMetaProperty>
#include <QLoggingCategory>
#include <QMimeData>
#include <QPainter>
#include <QPen>
#include <qdebug.h>
static Q_LOGGING_CATEGORY(itemlibraryPopulate, "qtc.itemlibrary.populate", QtWarningMsg)
static bool inline registerItemLibrarySortedModel() {
qmlRegisterAnonymousType<QmlDesigner::ItemLibrarySectionModel>("ItemLibrarySectionModel", 1);
return true;
}
namespace QmlDesigner {
static QHash<QString, bool> collapsedStateHash;
void ItemLibraryModel::setExpanded(bool expanded, const QString &section)
// sectionName can be an import or category section
void ItemLibraryModel::setExpanded(bool expanded, const QString &sectionName)
{
if (collapsedStateHash.contains(section))
collapsedStateHash.remove(section);
collapsedStateHash.insert(sectionName, expanded);
}
if (!expanded) //default is true
collapsedStateHash.insert(section, expanded);
bool ItemLibraryModel::sectionExpanded(const QString &sectionName) const
{
return collapsedStateHash.value(sectionName, true);
}
void ItemLibraryModel::setFlowMode(bool b)
@@ -89,32 +77,27 @@ ItemLibraryModel::~ItemLibraryModel()
int ItemLibraryModel::rowCount(const QModelIndex & /*parent*/) const
{
return m_sections.count();
return m_importList.count();
}
QVariant ItemLibraryModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() +1 > m_sections.count())
return QVariant();
if (!index.isValid() || index.row() +1 > m_importList.count())
return {};
if (m_roleNames.contains(role)) {
QVariant value = m_sections.at(index.row())->property(m_roleNames.value(role));
QVariant value = m_importList.at(index.row())->property(m_roleNames.value(role));
auto model = qobject_cast<ItemLibrarySectionModel *>(value.value<QObject*>());
auto model = qobject_cast<ItemLibraryCategoriesModel *>(value.value<QObject *>());
if (model)
return QVariant::fromValue(model);
auto model2 = qobject_cast<ItemLibraryModel *>(value.value<QObject*>());
if (model2)
return QVariant::fromValue(model2);
return value;
}
qWarning() << Q_FUNC_INFO << "invalid role requested";
return QVariant();
return {};
}
QHash<int, QByteArray> ItemLibraryModel::roleNames() const
@@ -127,19 +110,15 @@ QString ItemLibraryModel::searchText() const
return m_searchText;
}
void ItemLibraryModel::setSearchText(const QString &searchText)
{
QString lowerSearchText = searchText.toLower();
if (m_searchText != lowerSearchText) {
m_searchText = lowerSearchText;
emit searchTextChanged();
bool changed = false;
updateVisibility(&changed);
if (changed)
emit dataChanged(QModelIndex(), QModelIndex());
}
}
@@ -153,14 +132,6 @@ Import entryToImport(const ItemLibraryEntry &entry)
}
bool sectionExapanded(const QString &sectionName)
{
if (collapsedStateHash.contains(sectionName))
return collapsedStateHash.value(sectionName);
return true;
}
void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
{
if (!model)
@@ -169,32 +140,24 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
beginResetModel();
clearSections();
QStringList imports;
foreach (const Import &import, model->imports())
if (import.isLibraryImport())
imports << import.url() + QLatin1Char(' ') + import.version();
qCInfo(itemlibraryPopulate) << Q_FUNC_INFO;
foreach (ItemLibraryEntry entry, itemLibraryInfo->entries()) {
qCInfo(itemlibraryPopulate) << entry.typeName() << entry.majorVersion() << entry.minorVersion();
// create import sections
for (const Import &import : model->imports()) {
if (import.isLibraryImport()) {
ItemLibraryImport *itemLibImport = new ItemLibraryImport(import, this);
m_importList.append(itemLibImport);
itemLibImport->setExpanded(sectionExpanded(import.url()));
}
}
const QList<ItemLibraryEntry> itemLibEntries = itemLibraryInfo->entries();
for (const ItemLibraryEntry &entry : itemLibEntries) {
NodeMetaInfo metaInfo = model->metaInfo(entry.typeName());
qCInfo(itemlibraryPopulate) << "valid: " << metaInfo.isValid() << metaInfo.majorVersion() << metaInfo.minorVersion();
bool valid = metaInfo.isValid() && metaInfo.majorVersion() == entry.majorVersion();
bool isItem = valid && metaInfo.isSubclassOf("QtQuick.Item");
qCInfo(itemlibraryPopulate) << "isItem: " << isItem;
qCInfo(itemlibraryPopulate) << "required import: " << entry.requiredImport() << entryToImport(entry).toImportString();
bool forceVisiblity = valid && NodeHints::fromItemLibraryEntry(entry).visibleInLibrary();
if (m_flowMode && metaInfo.isValid()) {
isItem = metaInfo.isSubclassOf("FlowView.FlowItem")
|| metaInfo.isSubclassOf("FlowView.FlowWildcard")
|| metaInfo.isSubclassOf("FlowView.FlowDecision");
@@ -202,7 +165,6 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
}
const DesignerMcuManager &mcuManager = DesignerMcuManager::instance();
if (mcuManager.isMCUProject()) {
const QSet<QString> blockTypes = mcuManager.bannedItems();
@@ -210,22 +172,44 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
valid = false;
}
if (valid && (isItem || forceVisiblity) //We can change if the navigator does support pure QObjects
if (valid && (isItem || forceVisiblity) // We can change if the navigator does support pure QObjects
&& (entry.requiredImport().isEmpty()
|| model->hasImport(entryToImport(entry), true, true))) {
QString itemSectionName = entry.category();
qCInfo(itemlibraryPopulate) << "Adding:" << entry.typeName() << "to:" << entry.category();
ItemLibrarySection *sectionModel = sectionByName(itemSectionName);
if (sectionModel == nullptr) {
sectionModel = new ItemLibrarySection(itemSectionName, this);
m_sections.append(sectionModel);
sectionModel->setSectionExpanded(sectionExapanded(itemSectionName));
ItemLibraryImport *importSection = nullptr;
QString catName = entry.category();
if (catName == ItemLibraryImport::userComponentsTitle()) {
// create an import section for user components
importSection = importByUrl(ItemLibraryImport::userComponentsTitle());
if (!importSection) {
importSection = new ItemLibraryImport({}, this);
m_importList.append(importSection);
importSection->setExpanded(sectionExpanded(catName));
}
} else {
if (catName.startsWith("Qt Quick - "))
catName = catName.mid(11); // remove "Qt Quick - "
importSection = importByUrl(entry.requiredImport());
}
auto item = new ItemLibraryItem(sectionModel);
item->setItemLibraryEntry(entry);
sectionModel->addSectionEntry(item);
if (!importSection) { // should not happen, but just in case
qWarning() << __FUNCTION__ << "No import section found! skipping entry: " << entry.name();
continue;
}
// get or create category section
ItemLibraryCategory *categorySection = importSection->getCategorySection(catName);
if (!categorySection) {
categorySection = new ItemLibraryCategory(catName, importSection);
importSection->addCategory(categorySection);
categorySection->setExpanded(sectionExpanded(categorySection->categoryName()));
}
// create item
auto item = new ItemLibraryItem(entry, categorySection);
categorySection->addItem(item);
}
}
@@ -251,67 +235,68 @@ QMimeData *ItemLibraryModel::getMimeData(const ItemLibraryEntry &itemLibraryEntr
void ItemLibraryModel::clearSections()
{
qDeleteAll(m_sections);
m_sections.clear();
qDeleteAll(m_importList);
m_importList.clear();
}
void ItemLibraryModel::registerQmlTypes()
{
qmlRegisterAnonymousType<QmlDesigner::ItemLibrarySectionModel>("ItemLibrarySectionModel", 1);
qmlRegisterAnonymousType<QmlDesigner::ItemLibraryModel>("ItemLibraryModel", 1);
}
ItemLibrarySection *ItemLibraryModel::sectionByName(const QString &sectionName)
ItemLibraryImport *ItemLibraryModel::importByUrl(const QString &importUrl) const
{
foreach (ItemLibrarySection *itemLibrarySection, m_sections) {
if (itemLibrarySection->sectionName() == sectionName)
return itemLibrarySection;
for (ItemLibraryImport *itemLibraryImport : std::as_const(m_importList)) {
if (itemLibraryImport->importUrl() == importUrl
|| (importUrl.isEmpty() && itemLibraryImport->importUrl() == "QtQuick")
|| (importUrl == ItemLibraryImport::userComponentsTitle()
&& itemLibraryImport->importName() == ItemLibraryImport::userComponentsTitle())) {
return itemLibraryImport;
}
}
return nullptr;
}
void ItemLibraryModel::updateUsedImports(const QList<Import> &usedImports)
{
// imports in the excludeList are not marked used and thus can always be removed even when in use.
const QList<QString> excludeList = {"SimulinkConnector"};
for (ItemLibraryImport *importSection : std::as_const(m_importList)) {
if (!excludeList.contains(importSection->importUrl()))
importSection->setImportUsed(usedImports.contains(importSection->importEntry()));
}
}
void ItemLibraryModel::updateVisibility(bool *changed)
{
foreach (ItemLibrarySection *itemLibrarySection, m_sections) {
QString sectionSearchText = m_searchText;
for (ItemLibraryImport *import : std::as_const(m_importList)) {
bool categoryChanged = false;
import->updateCategoryVisibility(m_searchText, &categoryChanged);
bool sectionChanged = false;
bool sectionVisibility = itemLibrarySection->updateSectionVisibility(sectionSearchText,
&sectionChanged);
*changed |= sectionChanged;
*changed |= itemLibrarySection->setVisible(sectionVisibility);
*changed |= categoryChanged;
}
}
void ItemLibraryModel::addRoleNames()
{
int role = 0;
for (int propertyIndex = 0; propertyIndex < ItemLibrarySection::staticMetaObject.propertyCount(); ++propertyIndex) {
QMetaProperty property = ItemLibrarySection::staticMetaObject.property(propertyIndex);
m_roleNames.insert(role, property.name());
++role;
}
const QMetaObject meta = ItemLibraryImport::staticMetaObject;
for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i)
m_roleNames.insert(role++, meta.property(i).name());
}
void ItemLibraryModel::sortSections()
{
int nullPointerSectionCount = m_sections.removeAll(QPointer<ItemLibrarySection>());
QTC_ASSERT(nullPointerSectionCount == 0,;);
auto sectionSort = [](ItemLibrarySection *first, ItemLibrarySection *second) {
auto sectionSort = [](ItemLibraryImport *first, ItemLibraryImport *second) {
return QString::localeAwareCompare(first->sortingName(), second->sortingName()) < 0;
};
std::sort(m_sections.begin(), m_sections.end(), sectionSort);
std::sort(m_importList.begin(), m_importList.end(), sectionSort);
for (const auto &itemLibrarySection : qAsConst(m_sections))
itemLibrarySection->sortItems();
}
void registerQmlTypes()
{
registerItemLibrarySortedModel();
for (ItemLibraryImport *itemLibImport : qAsConst(m_importList))
itemLibImport->sortCategorySections();
}
} // namespace QmlDesigner

View File

@@ -25,10 +25,9 @@
#pragma once
#include <QMap>
#include <QIcon>
#include <QAbstractListModel>
#include <QtQml/qqml.h>
#include <import.h>
QT_FORWARD_DECLARE_CLASS(QMimeData)
@@ -37,12 +36,11 @@ namespace QmlDesigner {
class ItemLibraryInfo;
class ItemLibraryEntry;
class Model;
class ItemLibrarySection;
class ItemLibraryModel: public QAbstractListModel {
class ItemLibraryImport;
class ItemLibraryModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QString searchText READ searchText WRITE setSearchText NOTIFY searchTextChanged)
public:
explicit ItemLibraryModel(QObject *parent = nullptr);
@@ -53,39 +51,34 @@ public:
QHash<int, QByteArray> roleNames() const override;
QString searchText() const;
ItemLibraryImport *importByUrl(const QString &importName) const;
void update(ItemLibraryInfo *itemLibraryInfo, Model *model);
void updateUsedImports(const QList<Import> &usedImports);
QMimeData *getMimeData(const ItemLibraryEntry &itemLibraryEntry);
static void registerQmlTypes();
void setSearchText(const QString &searchText);
void setFlowMode(bool);
static void registerQmlTypes();
Q_INVOKABLE void setExpanded(bool, const QString &section);
void setFlowMode(bool);
signals:
void qmlModelChanged();
void searchTextChanged();
private: // functions
ItemLibrarySection *sectionByName(const QString &sectionName);
private:
void updateVisibility(bool *changed);
void addRoleNames();
void sortSections();
void clearSections();
bool sectionExpanded(const QString &sectionName) const;
private: // variables
QList<QPointer<ItemLibrarySection>> m_sections;
QList<QPointer<ItemLibraryImport>> m_importList;
QHash<int, QByteArray> m_roleNames;
QString m_searchText;
bool m_flowMode = false;
QHash<QString, bool> collapsedStateHash;
};
} // namespace QmlDesigner
QML_DECLARE_TYPE(QmlDesigner::ItemLibraryModel)

View File

@@ -1,121 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "itemlibrarysection.h"
#include "itemlibraryitem.h"
namespace QmlDesigner {
ItemLibrarySection::ItemLibrarySection(const QString &sectionName, QObject *parent)
: QObject(parent),
m_sectionEntries(parent),
m_name(sectionName),
m_sectionExpanded(true),
m_isVisible(true)
{
}
QString ItemLibrarySection::sectionName() const
{
return m_name;
}
bool ItemLibrarySection::sectionExpanded() const
{
return m_sectionExpanded;
}
QString ItemLibrarySection::sortingName() const
{
if (sectionName() == QStringLiteral("My QML Components")) //Qml Components always come first
return QStringLiteral("aaaa");
return sectionName();
}
void ItemLibrarySection::addSectionEntry(ItemLibraryItem *sectionEntry)
{
m_sectionEntries.addItem(sectionEntry);
}
QObject *ItemLibrarySection::sectionEntries()
{
return &m_sectionEntries;
}
bool ItemLibrarySection::updateSectionVisibility(const QString &searchText, bool *changed)
{
bool haveVisibleItems = false;
*changed = false;
for (const auto &itemLibraryItem : m_sectionEntries.items()) {
bool itemVisible = itemLibraryItem->itemName().toLower().contains(searchText)
|| itemLibraryItem->typeName().toLower().contains(searchText);
bool itemChanged = itemLibraryItem->setVisible(itemVisible);
*changed |= itemChanged;
if (itemVisible)
haveVisibleItems = true;
}
if (*changed)
m_sectionEntries.resetModel();
return haveVisibleItems;
}
bool ItemLibrarySection::setVisible(bool isVisible)
{
if (isVisible != m_isVisible) {
m_isVisible = isVisible;
return true;
}
return false;
}
bool ItemLibrarySection::isVisible() const
{
return m_isVisible;
}
void ItemLibrarySection::sortItems()
{
m_sectionEntries.sortItems();
}
void ItemLibrarySection::setSectionExpanded(bool expanded)
{
m_sectionExpanded = expanded;
}
} // namespace QmlDesigner

View File

@@ -37,7 +37,6 @@
#include <imagecache/imagecachestorage.h>
#include <imagecache/timestampprovider.h>
#include <import.h>
#include <importmanagerview.h>
#include <nodelistproperty.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/project.h>
@@ -80,8 +79,7 @@ public:
};
ItemLibraryView::ItemLibraryView(QObject* parent)
: AbstractView(parent),
m_importManagerView(new ImportManagerView(this))
: AbstractView(parent)
{
m_imageCacheData = std::make_unique<ImageCacheData>();
@@ -123,7 +121,6 @@ WidgetInfo ItemLibraryView::widgetInfo()
m_widget = new ItemLibraryWidget{m_imageCacheData->cache,
m_imageCacheData->asynchronousFontImageCache,
m_imageCacheData->synchronousFontImageCache};
m_widget->setImportsWidget(m_importManagerView->widgetInfo().widget);
}
return createWidgetInfo(m_widget.data(),
@@ -141,7 +138,6 @@ void ItemLibraryView::modelAttached(Model *model)
m_widget->clearSearchFilter();
m_widget->setModel(model);
updateImports();
model->attachView(m_importManagerView);
m_hasErrors = !rewriterView()->errors().isEmpty();
m_widget->setFlowMode(QmlItemNode(rootModelNode()).isFlowView());
setResourcePath(DocumentManager::currentResourcePath().toFileInfo().absoluteFilePath());
@@ -149,8 +145,6 @@ void ItemLibraryView::modelAttached(Model *model)
void ItemLibraryView::modelAboutToBeDetached(Model *model)
{
model->detachView(m_importManagerView);
AbstractView::modelAboutToBeDetached(model);
m_widget->setModel(nullptr);
@@ -189,6 +183,16 @@ void ItemLibraryView::importsChanged(const QList<Import> &addedImports, const QL
}
}
void ItemLibraryView::possibleImportsChanged(const QList<Import> &possibleImports)
{
m_widget->updatePossibleImports(possibleImports);
}
void ItemLibraryView::usedImportsChanged(const QList<Import> &usedImports)
{
m_widget->updateUsedImports(usedImports);
}
void ItemLibraryView::setResourcePath(const QString &resourcePath)
{
if (m_widget.isNull())

View File

@@ -33,7 +33,6 @@
namespace QmlDesigner {
class ItemLibraryWidget;
class ImportManagerView;
class ImageCacheData;
class AsynchronousImageCache;
@@ -52,6 +51,8 @@ public:
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
void possibleImportsChanged(const QList<Import> &possibleImports) override;
void usedImportsChanged(const QList<Import> &usedImports) override;
void documentMessagesChanged(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings) override;
void updateImport3DSupport(const QVariantMap &supportMap) override;
@@ -65,7 +66,6 @@ protected:
private:
std::unique_ptr<ImageCacheData> m_imageCacheData;
QPointer<ItemLibraryWidget> m_widget;
ImportManagerView *m_importManagerView;
bool m_hasErrors = false;
QVariantMap m_importableExtensions3DMap;
QVariantMap m_importOptions3DMap;

View File

@@ -27,6 +27,7 @@
#include "customfilesystemmodel.h"
#include "itemlibraryiconimageprovider.h"
#include "itemlibraryimport.h"
#include <theme.h>
@@ -35,6 +36,7 @@
#include <itemlibraryimageprovider.h>
#include <itemlibraryinfo.h>
#include <itemlibrarymodel.h>
#include <itemlibraryaddimportmodel.h>
#include <metainfo.h>
#include <model.h>
#include <rewritingexception.h>
@@ -57,7 +59,7 @@
#include <QFileDialog>
#include <QFileInfo>
#include <QFileSystemModel>
#include <QGridLayout>
#include <QVBoxLayout>
#include <QImageReader>
#include <QMenu>
#include <QMimeData>
@@ -77,16 +79,28 @@ static QString propertyEditorResourcesPath() {
return Core::ICore::resourcePath() + QStringLiteral("/qmldesigner/propertyEditorQmlSources");
}
bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::FocusOut) {
if (obj == m_itemViewQuickWidget.data())
QMetaObject::invokeMethod(m_itemViewQuickWidget->rootObject(), "closeContextMenu");
}
return QObject::eventFilter(obj, event);
}
ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
AsynchronousImageCache &asynchronousFontImageCache,
SynchronousImageCache &synchronousFontImageCache)
: m_itemIconSize(24, 24)
, m_itemLibraryModel(new ItemLibraryModel(this))
, m_itemLibraryAddImportModel(new ItemLibraryAddImportModel(this))
, m_resourcesFileSystemModel{new CustomFileSystemModel(synchronousFontImageCache, this)}
, m_headerWidget(new QQuickWidget(this))
, m_addImportWidget(new QQuickWidget(this))
, m_itemViewQuickWidget(new QQuickWidget(this))
, m_resourcesView(new ItemLibraryResourceView(asynchronousFontImageCache, this))
, m_importTagsWidget(new QWidget(this))
, m_addResourcesWidget(new QWidget(this))
, m_imageCache{imageCache}
, m_filterFlag(QtBasic)
{
m_compressionTimer.setInterval(200);
m_compressionTimer.setSingleShot(true);
@@ -94,11 +108,33 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
setWindowTitle(tr("Library", "Title of library view"));
/* create Items view and its model */
m_itemViewQuickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
// create header widget
m_headerWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_headerWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
Theme::setupTheme(m_headerWidget->engine());
m_headerWidget->setSource(QUrl("qrc:/ItemLibrary/qml/libraryheader.qml"));
QObject::connect(m_headerWidget->rootObject(), SIGNAL(tabChanged(int)), this,
SLOT(handleTabChanged(int)));
QObject::connect(m_headerWidget->rootObject(), SIGNAL(filterChanged(QString)), this,
SLOT(handleFilterChanged(QString)));
QObject::connect(m_headerWidget->rootObject(), SIGNAL(addLibraryClicked()), this,
SLOT(handleAddLibrary()));
QObject::connect(m_headerWidget->rootObject(), SIGNAL(addAssetClicked()), this,
SLOT(handleAddAsset()));
// create add imports widget
m_addImportWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_addImportWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
Theme::setupTheme(m_addImportWidget->engine());
m_addImportWidget->setSource(QUrl("qrc:/ItemLibrary/qml/addimport.qml"));
m_addImportWidget->rootContext()->setContextProperty(
"addImportModel", QVariant::fromValue(m_itemLibraryAddImportModel.data()));
QObject::connect(m_addImportWidget->rootObject(), SIGNAL(addImport(int)), this,
SLOT(handleAddImport(int)));
// set up Item Library view and model
m_itemViewQuickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_itemViewQuickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
m_itemLibraryModel = new ItemLibraryModel(this);
m_itemViewQuickWidget->rootContext()->setContextProperties(QVector<QQmlContext::PropertyPair>{
{{"itemLibraryModel"}, QVariant::fromValue(m_itemLibraryModel.data())},
@@ -111,66 +147,30 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
m_previewTooltipBackend = std::make_unique<PreviewTooltipBackend>(m_imageCache);
m_itemViewQuickWidget->rootContext()->setContextProperty("tooltipBackend",
m_previewTooltipBackend.get());
m_itemViewQuickWidget->setClearColor(
Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate));
/* create Resources view and its model */
m_resourcesFileSystemModel = new CustomFileSystemModel(synchronousFontImageCache, this);
m_resourcesView->setModel(m_resourcesFileSystemModel.data());
/* create image provider for loading item icons */
m_itemViewQuickWidget->engine()->addImageProvider(QStringLiteral("qmldesigner_itemlibrary"), new Internal::ItemLibraryImageProvider);
m_itemViewQuickWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_ButtonColor));
m_itemViewQuickWidget->engine()->addImageProvider(QStringLiteral("qmldesigner_itemlibrary"),
new Internal::ItemLibraryImageProvider);
Theme::setupTheme(m_itemViewQuickWidget->engine());
m_itemViewQuickWidget->installEventFilter(this);
/* other widgets */
auto tabBar = new QTabBar(this);
tabBar->addTab(tr("QML Types", "Title of library QML types view"));
tabBar->addTab(tr("Assets", "Title of library assets view"));
tabBar->addTab(tr("QML Imports", "Title of QML imports view"));
tabBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
connect(tabBar, &QTabBar::currentChanged, this, &ItemLibraryWidget::setCurrentIndexOfStackedWidget);
connect(tabBar, &QTabBar::currentChanged, this, &ItemLibraryWidget::updateSearch);
m_filterLineEdit = new Utils::FancyLineEdit(this);
m_filterLineEdit->setObjectName(QStringLiteral("itemLibrarySearchInput"));
m_filterLineEdit->setPlaceholderText(tr("<Filter>", "Library search input hint text"));
m_filterLineEdit->setDragEnabled(false);
m_filterLineEdit->setMinimumWidth(75);
m_filterLineEdit->setTextMargins(0, 0, 20, 0);
m_filterLineEdit->setFiltering(true);
QWidget *lineEditFrame = new QWidget(this);
lineEditFrame->setObjectName(QStringLiteral("itemLibrarySearchInputFrame"));
auto lineEditLayout = new QGridLayout(lineEditFrame);
lineEditLayout->setContentsMargins(2, 2, 2, 2);
lineEditLayout->setSpacing(0);
lineEditLayout->addItem(new QSpacerItem(5, 3, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, 0, 1, 3);
lineEditLayout->addItem(new QSpacerItem(5, 5, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 0);
lineEditLayout->addWidget(m_filterLineEdit.data(), 1, 1, 1, 1);
lineEditLayout->addItem(new QSpacerItem(5, 5, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 2);
connect(m_filterLineEdit.data(), &Utils::FancyLineEdit::filterChanged, this, &ItemLibraryWidget::setSearchFilter);
// connect Resources view and its model
m_resourcesView->setModel(m_resourcesFileSystemModel.data());
m_stackedWidget = new QStackedWidget(this);
m_stackedWidget->addWidget(m_itemViewQuickWidget.data());
m_stackedWidget->addWidget(m_resourcesView.data());
m_stackedWidget->addWidget(m_addImportWidget.data());
m_stackedWidget->setMinimumHeight(30);
m_stackedWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
QWidget *spacer = new QWidget(this);
spacer->setObjectName(QStringLiteral("itemLibrarySearchInputSpacer"));
spacer->setFixedHeight(4);
auto layout = new QGridLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
auto layout = new QVBoxLayout(this);
layout->setContentsMargins({});
layout->setSpacing(0);
layout->addWidget(tabBar, 0, 0, 1, 1);
layout->addWidget(spacer, 1, 0);
layout->addWidget(lineEditFrame, 2, 0, 1, 1);
layout->addWidget(m_importTagsWidget.data(), 3, 0, 1, 1);
layout->addWidget(m_addResourcesWidget.data(), 4, 0, 1, 1);
layout->addWidget(m_stackedWidget.data(), 5, 0, 1, 1);
layout->addWidget(m_headerWidget.data());
layout->addWidget(m_stackedWidget.data());
setSearchFilter(QString());
updateSearch();
/* style sheets */
setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/stylesheet.css")))));
@@ -181,25 +181,6 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache,
connect(&m_compressionTimer, &QTimer::timeout, this, &ItemLibraryWidget::updateModel);
auto flowLayout = new Utils::FlowLayout(m_importTagsWidget.data());
flowLayout->setContentsMargins(4, 4, 4, 4);
m_addResourcesWidget->setVisible(false);
flowLayout = new Utils::FlowLayout(m_addResourcesWidget.data());
flowLayout->setContentsMargins(4, 4, 4, 4);
auto button = new QToolButton(m_addResourcesWidget.data());
auto font = button->font();
font.setPixelSize(Theme::instance()->smallFontPixelSize());
button->setFont(font);
button->setIcon(Utils::Icons::PLUS.icon());
button->setText(tr("Add New Assets..."));
button->setToolTip(tr("Add new assets to project."));
button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
flowLayout->addWidget(button);
connect(button, &QToolButton::clicked, [this]() {
addResources({});
});
const auto dropSupport = new Utils::DropSupport(
m_resourcesView.data(), [this](QDropEvent *event, Utils::DropSupport *) {
// Accept supported file types
@@ -250,35 +231,43 @@ void ItemLibraryWidget::setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo)
delayedUpdateModel();
}
void ItemLibraryWidget::updateImports()
{
if (m_model)
setupImportTagWidget();
}
void ItemLibraryWidget::setImportsWidget(QWidget *importsWidget)
{
m_stackedWidget->addWidget(importsWidget);
}
QList<QToolButton *> ItemLibraryWidget::createToolBarWidgets()
{
// TODO: implement
QList<QToolButton *> buttons;
return buttons;
}
void ItemLibraryWidget::setSearchFilter(const QString &searchFilter)
void ItemLibraryWidget::handleFilterChanged(const QString &filterText)
{
if (m_stackedWidget->currentIndex() == 0) {
m_itemLibraryModel->setSearchText(searchFilter);
m_itemViewQuickWidget->update();
} else {
QStringList nameFilterList;
m_filterText = filterText;
m_resourcesFileSystemModel->setSearchFilter(searchFilter);
m_resourcesFileSystemModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
m_resourcesView->scrollToTop();
updateSearch();
}
void ItemLibraryWidget::handleAddLibrary()
{
QMetaObject::invokeMethod(m_headerWidget->rootObject(), "setTab", Q_ARG(QVariant, 0));
handleTabChanged(2);
}
void ItemLibraryWidget::handleAddAsset()
{
addResources({});
}
void ItemLibraryWidget::handleAddImport(int index)
{
Import import = m_itemLibraryAddImportModel->getImportAt(index);
if (import.isLibraryImport() && (import.url().startsWith("QtQuick")
|| import.url().startsWith("SimulinkConnector"))) {
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_IMPORT_ADDED
+ import.toImportString());
}
m_model->changeImports({import}, {});
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
m_stackedWidget->setCurrentIndex(0); // switch to the Components Library after import is added
}
void ItemLibraryWidget::delayedUpdateModel()
@@ -299,24 +288,10 @@ void ItemLibraryWidget::setModel(Model *model)
setItemLibraryInfo(model->metaInfo().itemLibraryInfo());
}
void ItemLibraryWidget::setCurrentIndexOfStackedWidget(int index)
void ItemLibraryWidget::handleTabChanged(int index)
{
if (index == 2) {
m_filterLineEdit->setVisible(false);
m_importTagsWidget->setVisible(true);
m_addResourcesWidget->setVisible(false);
}
if (index == 1) {
m_filterLineEdit->setVisible(true);
m_importTagsWidget->setVisible(false);
m_addResourcesWidget->setVisible(true);
} else {
m_filterLineEdit->setVisible(true);
m_importTagsWidget->setVisible(true);
m_addResourcesWidget->setVisible(false);
}
m_stackedWidget->setCurrentIndex(index);
updateSearch();
}
QString ItemLibraryWidget::qmlSourcesPath()
@@ -326,55 +301,18 @@ QString ItemLibraryWidget::qmlSourcesPath()
void ItemLibraryWidget::clearSearchFilter()
{
m_filterLineEdit->clear();
QMetaObject::invokeMethod(m_headerWidget->rootObject(), "clearSearchFilter");
}
void ItemLibraryWidget::reloadQmlSource()
{
QString itemLibraryQmlFilePath = qmlSourcesPath() + QStringLiteral("/ItemsView.qml");
QTC_ASSERT(QFileInfo::exists(itemLibraryQmlFilePath), return);
m_itemViewQuickWidget->engine()->clearComponentCache();
m_itemViewQuickWidget->setSource(QUrl::fromLocalFile(itemLibraryQmlFilePath));
}
void ItemLibraryWidget::setupImportTagWidget()
{
QTC_ASSERT(m_model, return);
const DesignerMcuManager &mcuManager = DesignerMcuManager::instance();
const bool isQtForMCUs = mcuManager.isMCUProject();
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(Theme::instance()->smallFontPixelSize());
button->setFont(font);
button->setIcon(Utils::Icons::PLUS.icon());
button->setText(import);
button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
button->setToolTip(tr("Add import %1").arg(import));
connect(button, &QToolButton::clicked, this, [this, import]() {
addPossibleImport(import);
});
return button;
};
if (!isQtForMCUs) {
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()
{
QTC_ASSERT(m_itemLibraryModel, return);
@@ -392,13 +330,31 @@ void ItemLibraryWidget::updateModel()
} else {
m_updateRetry = false;
}
updateImports();
updateSearch();
}
void ItemLibraryWidget::updatePossibleImports(const QList<Import> &possibleImports)
{
m_itemLibraryAddImportModel->update(possibleImports);
}
void ItemLibraryWidget::updateUsedImports(const QList<Import> &usedImports)
{
m_itemLibraryModel->updateUsedImports(usedImports);
}
void ItemLibraryWidget::updateSearch()
{
setSearchFilter(m_filterLineEdit->text());
if (m_stackedWidget->currentIndex() == 0) { // Item Library tab selected
m_itemLibraryModel->setSearchText(m_filterText);
m_itemViewQuickWidget->update();
} else if (m_stackedWidget->currentIndex() == 1) { // Assets tab selected
m_resourcesFileSystemModel->setSearchFilter(m_filterText);
m_resourcesFileSystemModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
m_resourcesView->scrollToTop();
} else if (m_stackedWidget->currentIndex() == 2) { // QML imports tab selected
m_itemLibraryAddImportModel->setSearchText(m_filterText);
}
}
void ItemLibraryWidget::setResourcePath(const QString &resourcePath)
@@ -436,52 +392,13 @@ void ItemLibraryWidget::setFlowMode(bool b)
m_itemLibraryModel->setFlowMode(b);
}
void ItemLibraryWidget::removeImport(const QString &name)
void ItemLibraryWidget::removeImport(const QString &importUrl)
{
QTC_ASSERT(m_model, return);
QList<Import> toBeRemovedImportList;
foreach (const Import &import, m_model->imports())
if (import.isLibraryImport() && import.url().compare(name, Qt::CaseInsensitive) == 0)
toBeRemovedImportList.append(import);
m_model->changeImports({}, toBeRemovedImportList);
}
void ItemLibraryWidget::addImport(const QString &name, const QString &version)
{
QTC_ASSERT(m_model, return);
m_model->changeImports({Import::createLibraryImport(name, version)}, {});
}
void ItemLibraryWidget::addPossibleImport(const QString &name)
{
QTC_ASSERT(m_model, return);
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_IMPORT_ADDED_FLOWTAG
+ name);
const Import import = m_model->highestPossibleImport(name);
try {
QList<Import> addedImports = {Import::createLibraryImport(name, import.version())};
// Special case for adding an import for 3D asset - also add QtQuick3D import
const QString asset3DPrefix = QLatin1String(Constants::QUICK_3D_ASSETS_FOLDER + 1)
+ QLatin1Char('.');
if (name.startsWith(asset3DPrefix)) {
const QString q3Dlib = QLatin1String(Constants::QT_QUICK_3D_MODULE_NAME);
Import q3DImport = m_model->highestPossibleImport(q3Dlib);
if (q3DImport.url() == q3Dlib)
addedImports.prepend(Import::createLibraryImport(q3Dlib, q3DImport.version()));
}
RewriterTransaction transaction
= m_model->rewriterView()->beginRewriterTransaction(
QByteArrayLiteral("ItemLibraryWidget::addPossibleImport"));
m_model->changeImports(addedImports, {});
transaction.commit();
}
catch (const RewritingException &e) {
e.showException();
}
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManager();
ItemLibraryImport *importSection = m_itemLibraryModel->importByUrl(importUrl);
if (importSection)
m_model->changeImports({}, {importSection->importEntry()});
}
void ItemLibraryWidget::addResources(const QStringList &files)
@@ -534,8 +451,12 @@ void ItemLibraryWidget::addResources(const QStringList &files)
currentDir,
filters.join(";;"));
if (!fileNames.isEmpty())
if (!fileNames.isEmpty()) {
lastDir = QFileInfo(fileNames.first()).absolutePath();
// switch to assets view after an asset is added
m_stackedWidget->setCurrentIndex(1);
QMetaObject::invokeMethod(m_headerWidget->rootObject(), "setTab", Q_ARG(QVariant, 1));
}
}
QMultiMap<QString, QString> partitionedFileNames;

View File

@@ -27,6 +27,7 @@
#include "itemlibraryinfo.h"
#include "itemlibraryresourceview.h"
#include "import.h"
#include <utils/fancylineedit.h>
#include <utils/dropsupport.h>
@@ -55,6 +56,7 @@ class CustomFileSystemModel;
class ItemLibraryModel;
class ItemLibraryAddImportModel;
class ItemLibraryResourceView;
class SynchronousImageCache;
class AsynchronousImageCache;
@@ -64,11 +66,6 @@ class ItemLibraryWidget : public QFrame
{
Q_OBJECT
enum FilterChangeFlag {
QtBasic = 0x0,
Meego = 0x1
};
public:
ItemLibraryWidget(AsynchronousImageCache &imageCache,
AsynchronousImageCache &asynchronousFontImageCache,
@@ -78,38 +75,33 @@ public:
void setItemLibraryInfo(ItemLibraryInfo *itemLibraryInfo);
QList<QToolButton *> createToolBarWidgets();
void updateImports();
void setImportsWidget(QWidget *importsWidget);
static QString qmlSourcesPath();
void clearSearchFilter();
void setSearchFilter(const QString &searchFilter);
void delayedUpdateModel();
void updateModel();
void updateSearch();
void updatePossibleImports(const QList<Import> &possibleImports);
void updateUsedImports(const QList<Import> &usedImports);
void setResourcePath(const QString &resourcePath);
void setModel(Model *model);
void setFlowMode(bool b);
Q_INVOKABLE void startDragAndDrop(QQuickItem *mouseArea, QVariant itemLibId);
void setFlowMode(bool b);
Q_INVOKABLE void removeImport(const QString &importUrl);
signals:
void itemActivated(const QString& itemName);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
private:
void setCurrentIndexOfStackedWidget(int index);
void reloadQmlSource();
void setupImportTagWidget();
void removeImport(const QString &name);
void addImport(const QString &name, const QString &version);
void addPossibleImport(const QString &name);
void addResources(const QStringList &files);
void importDroppedFiles(const QList<Utils::DropSupport::FileSpec> &files);
void updateSearch();
QTimer m_compressionTimer;
QSize m_itemIconSize;
@@ -117,23 +109,30 @@ private:
QPointer<ItemLibraryInfo> m_itemLibraryInfo;
QPointer<ItemLibraryModel> m_itemLibraryModel;
QPointer<ItemLibraryAddImportModel> m_itemLibraryAddImportModel;
QPointer<CustomFileSystemModel> m_resourcesFileSystemModel;
QPointer<QStackedWidget> m_stackedWidget;
QPointer<Utils::FancyLineEdit> m_filterLineEdit;
QScopedPointer<QQuickWidget> m_headerWidget;
QScopedPointer<QQuickWidget> m_addImportWidget;
QScopedPointer<QQuickWidget> m_itemViewQuickWidget;
QScopedPointer<ItemLibraryResourceView> m_resourcesView;
QScopedPointer<QWidget> m_importTagsWidget;
QScopedPointer<QWidget> m_addResourcesWidget;
std::unique_ptr<PreviewTooltipBackend> m_previewTooltipBackend;
QShortcut *m_qmlSourceUpdateShortcut;
AsynchronousImageCache &m_imageCache;
QPointer<Model> m_model;
FilterChangeFlag m_filterFlag;
ItemLibraryEntry m_currentitemLibraryEntry;
bool m_updateRetry = false;
QString m_filterText;
private slots:
void handleTabChanged(int index);
void handleFilterChanged(const QString &filterText);
void handleAddLibrary();
void handleAddAsset();
void handleAddImport(int index);
};
}

View File

@@ -0,0 +1,86 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuickDesignerTheme 1.0
Column {
id: root
signal addImport(int index)
Text {
id: header
text: qsTr("Select a Library to add")
color: "#ffffff"
font.pixelSize: 16
width: parent.width
height: 50
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
ScrollView { // ListView not used because of QTBUG-52941
id: listView
width: parent.width
height: parent.height - header.height
clip: true
Column {
spacing: 2
Repeater {
model: addImportModel
delegate: Rectangle {
width: listView.width
height: 25
color: mouseArea.containsMouse ? Qt.lighter(Theme.qmlDesignerButtonColor(), 1.3)
: Theme.qmlDesignerButtonColor()
visible: importVisible
Text {
text: importUrl
color: Theme.color(Theme.PanelTextColorLight)
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 10
anchors.rightMargin: 10
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: addImport(index)
}
}
}
}
}
}

View File

@@ -0,0 +1,157 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuickDesignerTheme 1.0
Item {
id: root
width: 200
height: 75
signal tabChanged(int index)
signal filterChanged(string filterText)
signal addLibraryClicked()
signal addAssetClicked()
function setTab(index)
{
tabBar.setCurrentIndex(index);
}
function clearSearchFilter()
{
searchFilterText.text = "";
}
Column {
anchors.left: parent.left
anchors.right: parent.right
spacing: 10
TabBar {
id: tabBar
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 5
anchors.rightMargin: 5
spacing: 40
background: Rectangle {
color: Theme.color(Theme.QmlDesigner_BackgroundColorDarkAlternate)
}
Repeater {
model: [{title: qsTr("Components"), addToolTip: qsTr("Add Library")},
{title: qsTr("Assets"), addToolTip: qsTr("Add new assets to project.")}]
TabButton {
contentItem: Text { // TabButton text
text: modelData.title
font.pixelSize: 13
font.bold: true
color: tabBar.currentIndex === index ? "#0094ce" : "#dadada"
anchors.bottomMargin: 2
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignBottom
elide: Text.ElideRight
}
background: Item { // TabButton background
Rectangle { // + button
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: 2
anchors.bottomMargin: 2
width: img.width + 10
height: img.height + 10
color: mouseArea.containsMouse ? "#353535" : "#262626"
ToolTip.delay: 500
ToolTip.text: modelData.addToolTip
ToolTip.visible: mouseArea.containsMouse
Image {
id: img
source: tabBar.currentIndex === index ? "../images/add.png"
: "../images/add_unselected.png"
anchors.centerIn: parent
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: index == 0 ? addLibraryClicked() : addAssetClicked()
}
}
Rectangle { // bottom strip
anchors.bottom: parent.bottom
width: parent.width
height: 2
color: tabBar.currentIndex === index ? "#0094ce" : "#a8a8a8"
}
}
onClicked: tabChanged(index)
}
}
}
TextField { // filter
id: searchFilterText
placeholderText: qsTr("Search")
placeholderTextColor: "#a8a8a8"
color: "#dadada"
selectedTextColor: "#0094ce"
background: Rectangle {
color: "#111111"
border.color: "#666666"
}
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 5
anchors.rightMargin: 5
selectByMouse: true
onTextChanged: filterChanged(text)
Image { // clear text button
source: "../images/x.png"
anchors.right: parent.right
anchors.rightMargin: 5
anchors.verticalCenter: parent.verticalCenter
visible: searchFilterText.text !== ""
MouseArea {
anchors.fill: parent
onClicked: searchFilterText.text = ""
}
}
}
}
}

View File

@@ -26,17 +26,6 @@ QGraphicsView {
background-color: creatorTheme.QmlDesigner_BackgroundColorDarkAlternate;
}
QLineEdit#itemLibrarySearchInput
{
color: creatorTheme.PanelTextColorLight;
font-size: creatorTheme.smallFontPixelSize;
border: 1px solid creatorTheme.QmlDesigner_BackgroundColorDarker;
border-width: 1;
max-height: 20px;
min-height: 20px;
background-color: creatorTheme.FancyToolButtonSelectedColor;
}
QTreeView {
color: creatorTheme.PanelTextColorLight;
selection-color: creatorTheme.PanelTextColorLight;
@@ -76,11 +65,7 @@ QTabBar::tab {
border-image: none;
background-color: creatorTheme.QmlDesigner_TabDark;
color: creatorTheme.QmlDesigner_TabLight;
margin-top: 0x;
margin-bottom: 0px;
margin-left: 0px;
margin-right: 0px;
margin: 0px;
font: bold;
font-size: creatorTheme.captionFontPixelSize;
}
@@ -90,7 +75,3 @@ QTabBar::tab:selected {
background-color: creatorTheme.QmlDesigner_TabLight;
color: creatorTheme.QmlDesigner_TabDark;
}
QWidget#itemLibrarySearchInputSpacer {
background-color: creatorTheme.QmlDesigner_TabLight;
}

View File

@@ -18,7 +18,6 @@ QtcProduct {
"../components/debugview",
"../components/edit3d",
"../components/formeditor",
"../components/importmanager",
"../components/integration",
"../components/itemlibrary",
"../components/navigator",

View File

@@ -344,6 +344,7 @@ QStringList ItemLibraryInfo::blacklistImports() const
return list;
}
// TODO: remove this and its dependencies, as flow tags are removed
QStringList ItemLibraryInfo::showTagsForImports() const
{
auto list = m_showTagsForImports;

View File

@@ -25,6 +25,7 @@
#include "subcomponentmanager.h"
#include <itemlibraryimport.h>
#include <qmldesignerconstants.h>
#include "model.h"
@@ -336,7 +337,7 @@ void SubComponentManager::registerQmlFile(const QFileInfo &fileInfo, const QStri
ItemLibraryEntry itemLibraryEntry;
itemLibraryEntry.setType(componentName.toUtf8());
itemLibraryEntry.setName(baseComponentName);
itemLibraryEntry.setCategory(tr("My QML Components"));
itemLibraryEntry.setCategory(ItemLibraryImport::userComponentsTitle());
itemLibraryEntry.setCustomComponentSource(fileInfo.absoluteFilePath());
if (!qualifier.isEmpty()) {
itemLibraryEntry.setRequiredImport(fixedQualifier);

View File

@@ -1024,8 +1024,6 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH
collectLinkErrors(&errors, ctxt);
setupImports(m_document, differenceHandler);
if (!justSanityCheck)
setupPossibleImports(snapshot, m_vContext);
qCInfo(rewriterBenchmark) << "imports setup:" << time.elapsed();

View File

@@ -37,7 +37,6 @@
#include <designmodewidget.h>
#include <edit3dview.h>
#include <formeditorview.h>
#include <importmanagerview.h>
#include <itemlibraryview.h>
#include <navigatorview.h>
#include <nodeinstanceview.h>

View File

@@ -23,7 +23,6 @@ INCLUDEPATH *= \
$$PWD/designercore/include \
$$PWD/components/integration \
$$PWD/components/componentcore \
$$PWD/components/importmanager \
$$PWD/components/itemlibrary \
$$PWD/components/edit3d \
$$PWD/components/formeditor \

View File

@@ -22,7 +22,6 @@ include(components/navigator/navigator.pri)
include(components/stateseditor/stateseditor.pri)
include(components/resources/resources.pri)
include(components/debugview/debugview.pri)
include(components/importmanager/importmanager.pri)
include(components/sourcetool/sourcetool.pri)
include(components/colortool/colortool.pri)
include(components/texttool/texttool.pri)

View File

@@ -49,7 +49,6 @@ Project {
"components/curveeditor",
"components/connectioneditor",
"components/debugview",
"components/importmanager",
"components/integration",
"components/propertyeditor",
"components/edit3d",
@@ -594,16 +593,6 @@ Project {
"formeditor/formeditortoolbutton.h",
"formeditor/transitiontool.cpp",
"formeditor/transitiontool.h",
"importmanager/importlabel.cpp",
"importmanager/importlabel.h",
"importmanager/importmanagercombobox.cpp",
"importmanager/importmanagercombobox.h",
"importmanager/importmanager.css",
"importmanager/importmanager.qrc",
"importmanager/importmanagerview.cpp",
"importmanager/importmanagerview.h",
"importmanager/importswidget.cpp",
"importmanager/importswidget.h",
"integration/componentaction.cpp",
"integration/componentaction.h",
"integration/componentview.cpp",