forked from qt-creator/qt-creator
QmlDesigner: Implement hiding component library categories
Task-number: QDS-3822 Change-Id: I4e22385497c4e58725b7f7a62a4e4351d0b78661 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -78,11 +78,14 @@ ScrollView {
|
||||
|
||||
property string importToRemove: ""
|
||||
property string importToAdd: ""
|
||||
property var currentItem: null
|
||||
property var currentCategory: null
|
||||
property var currentImport: null
|
||||
|
||||
// called from C++ to close context menu on focus out
|
||||
function closeContextMenu()
|
||||
{
|
||||
importContextMenu.close()
|
||||
moduleContextMenu.close()
|
||||
itemContextMenu.close()
|
||||
}
|
||||
|
||||
@@ -107,25 +110,73 @@ ScrollView {
|
||||
2 * cellVerticalMargin + cellVerticalSpacing
|
||||
|
||||
StudioControls.Menu {
|
||||
id: importContextMenu
|
||||
id: moduleContextMenu
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Remove Module")
|
||||
visible: currentCategory === null
|
||||
height: visible ? implicitHeight : 0
|
||||
enabled: importToRemove !== ""
|
||||
onTriggered: rootView.removeImport(importToRemove)
|
||||
}
|
||||
|
||||
StudioControls.MenuSeparator {}
|
||||
StudioControls.MenuSeparator {
|
||||
visible: currentCategory === null
|
||||
height: StudioTheme.Values.border
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Expand All")
|
||||
visible: currentCategory === null
|
||||
height: visible ? implicitHeight : 0
|
||||
onTriggered: itemLibraryModel.expandAll()
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Collapse All")
|
||||
visible: currentCategory === null
|
||||
height: visible ? implicitHeight : 0
|
||||
onTriggered: itemLibraryModel.collapseAll()
|
||||
}
|
||||
|
||||
StudioControls.MenuSeparator {
|
||||
visible: currentCategory === null
|
||||
height: StudioTheme.Values.border
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Hide Category")
|
||||
visible: currentCategory
|
||||
height: visible ? implicitHeight : 0
|
||||
onTriggered: {
|
||||
itemLibraryModel.isAnyCategoryHidden = true
|
||||
currentCategory.categoryVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.MenuSeparator {
|
||||
visible: currentCategory
|
||||
height: StudioTheme.Values.border
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Show Module Hidden Categories")
|
||||
enabled: currentImport && !currentImport.importCatVisibleState
|
||||
onTriggered: {
|
||||
currentImport.importCatVisibleState = true
|
||||
if (!itemLibraryModel.getIsAnyCategoryHidden())
|
||||
itemLibraryModel.isAnyCategoryHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.MenuItem {
|
||||
text: qsTr("Show All Hidden Categories")
|
||||
enabled: itemLibraryModel.isAnyCategoryHidden
|
||||
onTriggered: {
|
||||
itemLibraryModel.isAnyCategoryHidden = false
|
||||
itemLibraryModel.showHiddenCategories()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StudioControls.Menu {
|
||||
@@ -166,11 +217,14 @@ ScrollView {
|
||||
}
|
||||
onShowContextMenu: {
|
||||
importToRemove = importRemovable ? importUrl : ""
|
||||
importContextMenu.popup()
|
||||
currentImport = model
|
||||
currentCategory = null
|
||||
moduleContextMenu.popup()
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: 2
|
||||
property var currentImportModel: model // allows accessing the import model from inside the category section
|
||||
Repeater {
|
||||
model: categoryModel
|
||||
delegate: Section {
|
||||
@@ -188,6 +242,11 @@ ScrollView {
|
||||
expanded: categoryExpanded
|
||||
expandOnClick: false
|
||||
onToggleExpand: categoryExpanded = !categoryExpanded
|
||||
onShowContextMenu: {
|
||||
currentCategory = model
|
||||
currentImport = parent.currentImportModel
|
||||
moduleContextMenu.popup()
|
||||
}
|
||||
|
||||
Grid {
|
||||
id: itemGrid
|
||||
|
@@ -75,14 +75,18 @@ QVariant ItemLibraryCategoriesModel::data(const QModelIndex &index, int role) co
|
||||
|
||||
bool ItemLibraryCategoriesModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
// currently only categoryExpanded property is updatable
|
||||
// currently only categoryExpanded and categoryVisible properties is updatable
|
||||
if (index.isValid() && m_roleNames.contains(role)) {
|
||||
QVariant currValue = m_categoryList.at(index.row())->property(m_roleNames.value(role));
|
||||
|
||||
if (currValue != value) {
|
||||
m_categoryList[index.row()]->setProperty(m_roleNames.value(role), value);
|
||||
if (m_roleNames.value(role) == "categoryExpanded") {
|
||||
ItemLibraryModel::saveExpandedState(value.toBool(),
|
||||
m_categoryList[index.row()]->categoryName());
|
||||
} else if (m_roleNames.value(role) == "categoryVisible") {
|
||||
ItemLibraryModel::saveCategoryVisibleState(value.toBool(),
|
||||
m_categoryList[index.row()]->categoryName());
|
||||
}
|
||||
emit dataChanged(index, index, {role});
|
||||
return true;
|
||||
@@ -139,6 +143,17 @@ void ItemLibraryCategoriesModel::resetModel()
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ItemLibraryCategoriesModel::showAllCategories(bool show)
|
||||
{
|
||||
for (const auto &category : std::as_const(m_categoryList)) {
|
||||
if (category->isCategoryVisible() != show) {
|
||||
category->setCategoryVisible(show);
|
||||
ItemLibraryModel::saveCategoryVisibleState(show, category->categoryName());
|
||||
}
|
||||
}
|
||||
emit dataChanged(index(0), index(m_categoryList.size() - 1), {m_roleNames.key("categoryVisible")});
|
||||
}
|
||||
|
||||
void ItemLibraryCategoriesModel::addRoleNames()
|
||||
{
|
||||
int role = 0;
|
||||
|
@@ -54,6 +54,7 @@ public:
|
||||
|
||||
void sortCategorySections();
|
||||
void resetModel();
|
||||
void showAllCategories(bool show = true);
|
||||
|
||||
private:
|
||||
void addRoleNames();
|
||||
|
@@ -87,6 +87,14 @@ bool ItemLibraryCategory::updateItemVisibility(const QString &searchText, bool *
|
||||
return hasVisibleItems;
|
||||
}
|
||||
|
||||
void ItemLibraryCategory::setCategoryVisible(bool isVisible)
|
||||
{
|
||||
if (isVisible != m_isVisible) {
|
||||
m_isVisible = isVisible;
|
||||
emit categoryVisibilityChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ItemLibraryCategory::setVisible(bool isVisible)
|
||||
{
|
||||
if (isVisible != m_isVisible) {
|
||||
@@ -97,7 +105,7 @@ bool ItemLibraryCategory::setVisible(bool isVisible)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ItemLibraryCategory::isVisible() const
|
||||
bool ItemLibraryCategory::isCategoryVisible() const
|
||||
{
|
||||
return m_isVisible;
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ class ItemLibraryCategory : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QString categoryName READ categoryName FINAL)
|
||||
Q_PROPERTY(bool categoryVisible READ isVisible NOTIFY visibilityChanged FINAL)
|
||||
Q_PROPERTY(bool categoryVisible READ isCategoryVisible WRITE setCategoryVisible NOTIFY categoryVisibilityChanged FINAL)
|
||||
Q_PROPERTY(bool categoryExpanded READ categoryExpanded WRITE setExpanded NOTIFY expandedChanged FINAL)
|
||||
Q_PROPERTY(QObject *itemModel READ itemModel NOTIFY itemModelChanged FINAL)
|
||||
|
||||
@@ -52,8 +52,9 @@ public:
|
||||
|
||||
bool updateItemVisibility(const QString &searchText, bool *changed);
|
||||
|
||||
void setCategoryVisible(bool isVisible);
|
||||
bool setVisible(bool isVisible);
|
||||
bool isVisible() const;
|
||||
bool isCategoryVisible() const;
|
||||
|
||||
void sortItems();
|
||||
|
||||
@@ -63,6 +64,7 @@ signals:
|
||||
void itemModelChanged();
|
||||
void visibilityChanged();
|
||||
void expandedChanged();
|
||||
void categoryVisibilityChanged();
|
||||
|
||||
private:
|
||||
ItemLibraryItemsModel m_itemModel;
|
||||
|
@@ -116,6 +116,9 @@ bool ItemLibraryImport::updateCategoryVisibility(const QString &searchText, bool
|
||||
*changed = false;
|
||||
|
||||
for (const auto &category : m_categoryModel.categorySections()) {
|
||||
category->setCategoryVisible(ItemLibraryModel::loadCategoryVisibleState(category->categoryName()));
|
||||
|
||||
if (!searchText.isEmpty() || category->isCategoryVisible()) {
|
||||
bool categoryChanged = false;
|
||||
bool hasVisibleItems = category->updateItemVisibility(searchText, &categoryChanged);
|
||||
categoryChanged |= category->setVisible(hasVisibleItems);
|
||||
@@ -125,10 +128,16 @@ bool ItemLibraryImport::updateCategoryVisibility(const QString &searchText, bool
|
||||
if (hasVisibleItems)
|
||||
hasVisibleCategories = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hasVisibleCategories;
|
||||
}
|
||||
|
||||
void ItemLibraryImport::showAllCategories(bool show)
|
||||
{
|
||||
m_categoryModel.showAllCategories(show);
|
||||
}
|
||||
|
||||
Import ItemLibraryImport::importEntry() const
|
||||
{
|
||||
return m_import;
|
||||
@@ -235,4 +244,22 @@ void ItemLibraryImport::updateRemovable()
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if all categories are visible, otherwise false
|
||||
bool ItemLibraryImport::importCatVisibleState() const
|
||||
{
|
||||
if (m_categoryModel.rowCount() > 0) {
|
||||
for (ItemLibraryCategory *cat : m_categoryModel.categorySections()) {
|
||||
if (!cat->isCategoryVisible())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ItemLibraryImport::setImportCatVisibleState(bool show)
|
||||
{
|
||||
m_categoryModel.showAllCategories(show);
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
@@ -43,6 +43,7 @@ class ItemLibraryImport : public QObject
|
||||
Q_PROPERTY(bool importExpanded READ importExpanded WRITE setImportExpanded NOTIFY importExpandChanged FINAL)
|
||||
Q_PROPERTY(bool importRemovable READ importRemovable NOTIFY importRemovableChanged FINAL)
|
||||
Q_PROPERTY(bool importUnimported READ importUnimported FINAL)
|
||||
Q_PROPERTY(bool importCatVisibleState READ importCatVisibleState WRITE setImportCatVisibleState NOTIFY importCatVisibleStateChanged FINAL)
|
||||
Q_PROPERTY(QObject *categoryModel READ categoryModel NOTIFY categoryModelChanged FINAL)
|
||||
|
||||
public:
|
||||
@@ -64,6 +65,7 @@ public:
|
||||
bool importVisible() const;
|
||||
bool importUsed() const;
|
||||
bool importRemovable() const;
|
||||
bool importCatVisibleState() const;
|
||||
bool hasCategories() const;
|
||||
bool hasSingleCategory() const;
|
||||
ItemLibraryCategory *getCategorySection(const QString &categoryName) const;
|
||||
@@ -75,7 +77,9 @@ public:
|
||||
void setImportUsed(bool importUsed);
|
||||
void sortCategorySections();
|
||||
void setImportExpanded(bool expanded = true);
|
||||
void setImportCatVisibleState(bool show);
|
||||
void expandCategories(bool expand = true);
|
||||
void showAllCategories(bool show = true);
|
||||
|
||||
static QString userComponentsTitle();
|
||||
static QString quick3DAssetsTitle();
|
||||
@@ -89,6 +93,7 @@ signals:
|
||||
void importUsedChanged();
|
||||
void importExpandChanged();
|
||||
void importRemovableChanged();
|
||||
void importCatVisibleStateChanged();
|
||||
|
||||
private:
|
||||
void updateRemovable();
|
||||
|
@@ -59,6 +59,49 @@ bool ItemLibraryModel::loadExpandedState(const QString §ionName)
|
||||
return expandedStateHash.value(sectionName, true);
|
||||
}
|
||||
|
||||
void ItemLibraryModel::saveCategoryVisibleState(bool isVisible, const QString &categoryName)
|
||||
{
|
||||
categoryVisibleStateHash.insert(categoryName, isVisible);
|
||||
}
|
||||
|
||||
bool ItemLibraryModel::loadCategoryVisibleState(const QString &categoryName)
|
||||
{
|
||||
return categoryVisibleStateHash.value(categoryName, true);
|
||||
}
|
||||
|
||||
void ItemLibraryModel::showHiddenCategories()
|
||||
{
|
||||
for (const QPointer<ItemLibraryImport> &import : std::as_const(m_importList)) {
|
||||
if (import->hasCategories())
|
||||
import->showAllCategories(true);
|
||||
}
|
||||
|
||||
categoryVisibleStateHash.clear();
|
||||
}
|
||||
|
||||
bool ItemLibraryModel::getIsAnyCategoryHidden() const
|
||||
{
|
||||
for (const bool &catState : std::as_const(categoryVisibleStateHash)) {
|
||||
if (!catState)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ItemLibraryModel::isAnyCategoryHidden() const
|
||||
{
|
||||
return m_isAnyCategoryHidden;
|
||||
}
|
||||
|
||||
void ItemLibraryModel::setIsAnyCategoryHidden(bool state)
|
||||
{
|
||||
if (state != m_isAnyCategoryHidden) {
|
||||
m_isAnyCategoryHidden = state;
|
||||
emit isAnyCategoryHiddenChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ItemLibraryModel::expandAll()
|
||||
{
|
||||
int i = 0;
|
||||
|
@@ -41,6 +41,7 @@ class ItemLibraryImport;
|
||||
class ItemLibraryModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool isAnyCategoryHidden READ isAnyCategoryHidden WRITE setIsAnyCategoryHidden NOTIFY isAnyCategoryHiddenChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit ItemLibraryModel(QObject *parent = nullptr);
|
||||
@@ -62,15 +63,25 @@ public:
|
||||
void setSearchText(const QString &searchText);
|
||||
void setFlowMode(bool);
|
||||
|
||||
bool isAnyCategoryHidden() const;
|
||||
void setIsAnyCategoryHidden(bool state);
|
||||
|
||||
static void registerQmlTypes();
|
||||
static void saveExpandedState(bool expanded, const QString §ionName);
|
||||
static bool loadExpandedState(const QString §ionName);
|
||||
static void saveCategoryVisibleState(bool isVisible, const QString &categoryName);
|
||||
static bool loadCategoryVisibleState(const QString &categoryName);
|
||||
|
||||
Q_INVOKABLE void expandAll();
|
||||
Q_INVOKABLE void collapseAll();
|
||||
Q_INVOKABLE void showHiddenCategories();
|
||||
Q_INVOKABLE bool getIsAnyCategoryHidden() const;
|
||||
|
||||
Import entryToImport(const ItemLibraryEntry &entry);
|
||||
|
||||
signals:
|
||||
void isAnyCategoryHiddenChanged();
|
||||
|
||||
private:
|
||||
void updateVisibility(bool *changed);
|
||||
void addRoleNames();
|
||||
@@ -82,8 +93,10 @@ private:
|
||||
|
||||
QString m_searchText;
|
||||
bool m_flowMode = false;
|
||||
bool m_isAnyCategoryHidden = false;
|
||||
|
||||
inline static QHash<QString, bool> expandedStateHash;
|
||||
inline static QHash<QString, bool> categoryVisibleStateHash;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
Reference in New Issue
Block a user