CMake generator: Make file picker a treeview

Task-number: QDS-5836
Change-Id: Ib261ac8750baae7ce55d9c990b5dadb26fc6ac03
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Tapani Mattila
2021-12-21 20:04:32 +02:00
parent b9798f35e6
commit 72c3d675a0
10 changed files with 345 additions and 189 deletions

View File

@@ -27,11 +27,12 @@ add_qtc_plugin(QmlDesigner
designmodewidget.cpp designmodewidget.h
documentmanager.cpp documentmanager.h
documentwarningwidget.cpp documentwarningwidget.h
cmakegeneratordialog.h cmakegeneratordialog.cpp
checkablefiletreeitem.cpp checkablefiletreeitem.h
cmakegeneratordialog.cpp cmakegeneratordialog.h
cmakegeneratordialogtreemodel.cpp cmakegeneratordialogtreemodel.h
generateresource.cpp generateresource.h
generatecmakelists.cpp generatecmakelists.h
generatecmakelistsconstants.h
checkablefilelistmodel.cpp checkablefilelistmodel.h
openuiqmlfiledialog.cpp openuiqmlfiledialog.h openuiqmlfiledialog.ui
qmldesignerconstants.h
qmldesignericons.h

View File

@@ -1,111 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Tooling
**
** 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 "checkablefilelistmodel.h"
using namespace Utils;
namespace QmlDesigner {
CheckableFileListModel::CheckableFileListModel(const FilePath &rootDir, const FilePaths &files, bool checkedByDefault, QObject *parent)
:QStandardItemModel(parent),
rootDir(rootDir)
{
for (const FilePath &file: files) {
appendRow(new CheckableStandardItem(file.toString(), checkedByDefault));
}
}
QList<CheckableStandardItem*> CheckableFileListModel::checkedItems() const
{
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
QList<QStandardItem*> allItems = findItems("*", Qt::MatchWildcard);
#else
QList<QStandardItem*> allItems = findItems(".*", Qt::MatchRegularExpression);
#endif
QList<CheckableStandardItem*> checkedItems;
for (QStandardItem *standardItem : allItems) {
CheckableStandardItem *item = static_cast<CheckableStandardItem*>(standardItem);
if (item->isChecked())
checkedItems.append(item);
}
return checkedItems;
}
QVariant CheckableFileListModel::data(const QModelIndex &index, int role) const
{
if (index.isValid()) {
if (role == Qt::CheckStateRole) {
CheckableStandardItem *item = static_cast<CheckableStandardItem*>(QStandardItemModel::item(index.row()));
return item->isChecked() ? Qt::Checked : Qt::Unchecked;
}
else if (role == Qt::DisplayRole) {
QVariant data = QStandardItemModel::data(index, role);
FilePath fullPath = FilePath::fromString(data.toString());
FilePath relativePath = fullPath.relativeChildPath(rootDir);
return QVariant(relativePath.toString());
}
}
return QStandardItemModel::data(index, role);
}
bool CheckableFileListModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::CheckStateRole)
{
CheckableStandardItem *item = static_cast<CheckableStandardItem*>(QStandardItemModel::item(index.row()));
item->setChecked(value.value<bool>());
return true;
}
return QStandardItemModel::setData(index, value, role);
}
CheckableStandardItem::CheckableStandardItem(const QString &text, bool checked)
:QStandardItem(text),
checked(checked)
{
setFlags(flags() |= Qt::ItemIsUserCheckable);
}
void CheckableStandardItem::setChecked(bool checked)
{
this->checked = checked;
}
bool CheckableStandardItem::isChecked() const
{
return this->checked;
}
int CheckableStandardItem::type() const
{
return QStandardItem::UserType + 0x74d4f1;
}
} //QmlDesigner

View File

@@ -0,0 +1,67 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Tooling
**
** 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 "checkablefiletreeitem.h"
using namespace Utils;
namespace QmlDesigner {
CheckableFileTreeItem::CheckableFileTreeItem(const FilePath &filePath)
:QStandardItem(filePath.toString())
{
Qt::ItemFlags itemFlags = flags();
if (isFile())
itemFlags |= Qt::ItemIsUserCheckable;
itemFlags &= ~(Qt::ItemIsEditable | Qt::ItemIsSelectable);
setFlags(itemFlags);
}
const FilePath CheckableFileTreeItem::toFilePath() const
{
return FilePath::fromString(text());
}
bool CheckableFileTreeItem::isFile() const
{
return FilePath::fromString(text()).isFile();
}
bool CheckableFileTreeItem::isDir() const
{
return FilePath::fromString(text()).isDir();
}
void CheckableFileTreeItem::setChecked(bool checked)
{
this->checked = checked;
}
bool CheckableFileTreeItem::isChecked() const
{
return this->checked;
}
} //QmlDesigner

View File

@@ -23,43 +23,31 @@
**
****************************************************************************/
#ifndef CHECKABLEFILELISTMODEL_H
#define CHECKABLEFILELISTMODEL_H
#ifndef CHECKABLEFILETREEITEM_H
#define CHECKABLEFILETREEITEM_H
#include <utils/fileutils.h>
#include <QStandardItemModel>
#include <QStandardItem>
namespace QmlDesigner {
class CheckableStandardItem : public QStandardItem
class CheckableFileTreeItem : public QStandardItem
{
public:
explicit CheckableStandardItem(const QString &text = QString(), bool checked = false);
explicit CheckableFileTreeItem(const Utils::FilePath &text = Utils::FilePath());
const Utils::FilePath toFilePath() const;
bool isFile() const;
bool isDir() const;
bool isChecked() const;
void setChecked(bool checked);
int type() const;
private:
bool checked;
};
class CheckableFileListModel : public QStandardItemModel
{
public:
CheckableFileListModel(const Utils::FilePath &rootDir,
const Utils::FilePaths &files,
bool checkedByDefault = false,
QObject *parent = nullptr);
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
QList<CheckableStandardItem*> checkedItems() const;
protected:
Utils::FilePath rootDir;
};
} //QmlDesigner
Q_DECLARE_METATYPE(QmlDesigner::CheckableStandardItem)
#endif // CHECKABLEFILELISTMODEL_H
#endif // CHECKABLEFILETREEITEM_H

View File

@@ -24,13 +24,14 @@
****************************************************************************/
#include "cmakegeneratordialog.h"
#include "cmakegeneratordialogtreemodel.h"
#include "generatecmakelistsconstants.h"
#include <QDialogButtonBox>
#include <QPushButton>
#include <QLayout>
#include <QLabel>
#include <QListView>
#include <QTreeView>
using namespace Utils;
@@ -51,12 +52,15 @@ CmakeGeneratorDialog::CmakeGeneratorDialog(const FilePath &rootDir, const FilePa
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
model = new CMakeGeneratorDialogModel(rootDir, files, this);
m_model = new CMakeGeneratorDialogTreeModel(rootDir, files, this);
QListView *list = new QListView(this);
list->setModel(model);
QTreeView *tree = new QTreeView(this);
tree->setModel(m_model);
tree->expandAll();
tree->setHeaderHidden(true);
tree->setItemsExpandable(false);
layout->addWidget(list);
layout->addWidget(tree);
layout->addWidget(buttons);
}
@@ -64,44 +68,13 @@ FilePaths CmakeGeneratorDialog::getFilePaths()
{
FilePaths paths;
QList<CheckableStandardItem*> items = model->checkedItems();
for (CheckableStandardItem *item: items) {
QList<CheckableFileTreeItem*> items = m_model->checkedItems();
for (CheckableFileTreeItem *item: items) {
paths.append(FilePath::fromString(item->text()));
}
return paths;
}
CMakeGeneratorDialogModel::CMakeGeneratorDialogModel(const Utils::FilePath &rootDir, const Utils::FilePaths &files, QObject *parent)
:CheckableFileListModel(rootDir, files, parent)
{
for (int i=0; i<rowCount(); i++) {
CheckableStandardItem *item = static_cast<CheckableStandardItem*>(QStandardItemModel::item(i));
item->setChecked(CMakeGeneratorDialogModel::checkedByDefault(FilePath::fromString(item->text())));
}
}
bool CMakeGeneratorDialogModel::checkedByDefault(const FilePath &path) const
{
if (path.exists()) {
QString relativePath = path.relativeChildPath(rootDir).toString();
if (relativePath.compare(QmlDesigner::GenerateCmake::Constants::FILENAME_CMAKELISTS) == 0)
return false;
if (relativePath.endsWith(QmlDesigner::GenerateCmake::Constants::FILENAME_CMAKELISTS)
&& relativePath.length() > QString(QmlDesigner::GenerateCmake::Constants::FILENAME_CMAKELISTS).length())
return true;
if (relativePath.compare(QmlDesigner::GenerateCmake::Constants::FILENAME_MODULES) == 0)
return true;
if (relativePath.compare(
FilePath::fromString(QmlDesigner::GenerateCmake::Constants::DIRNAME_CPP)
.pathAppended(QmlDesigner::GenerateCmake::Constants::FILENAME_MAINCPP_HEADER)
.toString())
== 0)
return true;
}
return !path.exists();
}
}
}

View File

@@ -27,7 +27,7 @@
#ifndef CMAKEGENERATORDIALOG_H
#define CMAKEGENERATORDIALOG_H
#include "checkablefilelistmodel.h"
#include "cmakegeneratordialogtreemodel.h"
#include <utils/fileutils.h>
@@ -37,14 +37,6 @@
namespace QmlDesigner {
namespace GenerateCmake {
class CMakeGeneratorDialogModel : public CheckableFileListModel
{
public:
CMakeGeneratorDialogModel(const Utils::FilePath &rootDir, const Utils::FilePaths &files, QObject *parent = nullptr);
protected:
virtual bool checkedByDefault(const Utils::FilePath &file) const;
};
class CmakeGeneratorDialog : public QDialog
{
public:
@@ -52,7 +44,7 @@ public:
Utils::FilePaths getFilePaths();
private:
CheckableFileListModel *model;
CMakeGeneratorDialogTreeModel *m_model;
};
}

View File

@@ -0,0 +1,175 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Tooling
**
** 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 "cmakegeneratordialogtreemodel.h"
#include "generatecmakelistsconstants.h"
#include "checkablefiletreeitem.h"
using namespace Utils;
namespace QmlDesigner {
namespace GenerateCmake {
CMakeGeneratorDialogTreeModel::CMakeGeneratorDialogTreeModel(const FilePath &rootDir,
const FilePaths &files, QObject *parent)
:QStandardItemModel(parent),
rootDir(rootDir),
m_icons(new QFileIconProvider())
{
createNodes(files, invisibleRootItem());
}
CMakeGeneratorDialogTreeModel::~CMakeGeneratorDialogTreeModel()
{
delete m_icons;
}
QVariant CMakeGeneratorDialogTreeModel::data(const QModelIndex &index, int role) const
{
if (index.isValid()) {
const CheckableFileTreeItem *node = constNodeForIndex(index);
if (role == Qt::CheckStateRole) {
if (node->isFile())
return node->isChecked() ? Qt::Checked : Qt::Unchecked;
return {};
}
else if (role == Qt::DisplayRole) {
FilePath fullPath = node->toFilePath();
return QVariant(fullPath.fileName());
}
else if (role == Qt::DecorationRole) {
if (!node->isFile())
return m_icons->icon(QFileIconProvider::Folder);
}
}
return QStandardItemModel::data(index, role);
}
bool CMakeGeneratorDialogTreeModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid()) {
CheckableFileTreeItem *node = nodeForIndex(index);
if (role == Qt::CheckStateRole) {
node->setChecked(value.value<bool>());
return true;
}
}
return QStandardItemModel::setData(index, value, role);;
}
const QList<CheckableFileTreeItem*> CMakeGeneratorDialogTreeModel::checkedItems() const
{
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
QList<QStandardItem*> allItems = findItems("*", Qt::MatchWildcard);
#else
QList<QStandardItem*> allItems = findItems(".*", Qt::MatchRegularExpression);
#endif
QList<CheckableFileTreeItem*> checkedItems;
for (QStandardItem *standardItem : allItems) {
CheckableFileTreeItem *item = static_cast<CheckableFileTreeItem*>(standardItem);
if (item->isChecked())
checkedItems.append(item);
}
return checkedItems;
}
bool CMakeGeneratorDialogTreeModel::checkedByDefault(const Utils::FilePath &file) const
{
if (file.exists()) {
QString relativePath = file.relativeChildPath(rootDir).toString();
if (relativePath.compare(QmlDesigner::GenerateCmake::Constants::FILENAME_CMAKELISTS) == 0)
return false;
if (relativePath.endsWith(QmlDesigner::GenerateCmake::Constants::FILENAME_CMAKELISTS)
&& relativePath.length() > QString(QmlDesigner::GenerateCmake::Constants::FILENAME_CMAKELISTS).length())
return true;
if (relativePath.compare(QmlDesigner::GenerateCmake::Constants::FILENAME_MODULES) == 0)
return true;
if (relativePath.compare(
FilePath::fromString(QmlDesigner::GenerateCmake::Constants::DIRNAME_CPP)
.pathAppended(QmlDesigner::GenerateCmake::Constants::FILENAME_MAINCPP_HEADER)
.toString())
== 0)
return true;
}
return !file.exists();
}
void CMakeGeneratorDialogTreeModel::createNodes(const FilePaths &candidates, QStandardItem *parent)
{
if (!parent)
return;
CheckableFileTreeItem *checkParent = dynamic_cast<CheckableFileTreeItem*>(parent);
FilePath thisDir = (parent == invisibleRootItem()) ? rootDir : checkParent->toFilePath();
for (const FilePath &file : candidates) {
if (file.parentDir() == thisDir) {
CheckableFileTreeItem *fileNode = new CheckableFileTreeItem(file);
fileNode->setChecked(checkedByDefault(file));
parent->appendRow(fileNode);
}
}
FilePaths directSubDirs;
for (const FilePath &file : candidates) {
FilePath dir = file.parentDir();
if (dir.parentDir() == thisDir && !directSubDirs.contains(dir))
directSubDirs.append(dir);
}
for (const FilePath &subDir : directSubDirs) {
CheckableFileTreeItem *dirNode = new CheckableFileTreeItem(subDir);
parent->appendRow(dirNode);
FilePaths subDirCandidates;
for (const FilePath &file : candidates)
if (file.isChildOf(subDir))
subDirCandidates.append(file);
createNodes(subDirCandidates, dirNode);
}
}
const CheckableFileTreeItem* CMakeGeneratorDialogTreeModel::constNodeForIndex(const QModelIndex &index) const
{
const QStandardItem *parent = static_cast<const QStandardItem*>(index.constInternalPointer());
const QStandardItem *item = parent->child(index.row(), index.column());
return static_cast<const CheckableFileTreeItem*>(item);
}
CheckableFileTreeItem* CMakeGeneratorDialogTreeModel::nodeForIndex(const QModelIndex &index)
{
QStandardItem *parent = static_cast<QStandardItem*>(index.internalPointer());
QStandardItem *item = parent->child(index.row(), index.column());
return static_cast<CheckableFileTreeItem*>(item);
}
} //GenerateCmake
} //QmlDesigner

View File

@@ -0,0 +1,67 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Tooling
**
** 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.
**
****************************************************************************/
#ifndef CMAKEGENERATORDIALOGTREEMODEL_H
#define CMAKEGENERATORDIALOGTREEMODEL_H
#include "checkablefiletreeitem.h"
#include <QFileIconProvider>
#include <QStandardItemModel>
#include <utils/fileutils.h>
namespace QmlDesigner {
namespace GenerateCmake {
class CMakeGeneratorDialogTreeModel : public QStandardItemModel
{
public:
CMakeGeneratorDialogTreeModel(const Utils::FilePath &rootDir,
const Utils::FilePaths &files, QObject *parent = nullptr);
~CMakeGeneratorDialogTreeModel();
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
const QList<CheckableFileTreeItem*> checkedItems() const;
const CheckableFileTreeItem* constNodeForIndex(const QModelIndex &index) const;
CheckableFileTreeItem* nodeForIndex(const QModelIndex &index);
protected:
bool checkedByDefault(const Utils::FilePath &file) const;
Utils::FilePath rootDir;
private:
void createNodes(const Utils::FilePaths &candidates, QStandardItem *parent);
QFileIconProvider* m_icons;
};
} //GenerateCmake
} //QmlDesigner
#endif // CMAKEGENERATORDIALOGTREEMODEL_H

View File

@@ -8,8 +8,9 @@ HEADERS += $$PWD/qmldesignerconstants.h \
$$PWD/generateresource.h \
$$PWD/generatecmakelists.h \
$$PWD/generatecmakelistsconstants.h \
$$PWD/checkablefilelistmodel.h \
$$PWD/checkablefiletreeitem.h \
$$PWD/cmakegeneratordialog.h \
$$PWD/cmakegeneratordialogtreemodel.h \
$$PWD/settingspage.h \
$$PWD/designmodecontext.h \
$$PWD/documentmanager.h \
@@ -27,8 +28,9 @@ SOURCES += $$PWD/qmldesignerplugin.cpp \
$$PWD/editorproxy.cpp \
$$PWD/generateresource.cpp \
$$PWD/generatecmakelists.cpp \
$$PWD/checkablefilelistmodel.cpp \
$$PWD/checkablefiletreeitem.cpp \
$$PWD/cmakegeneratordialog.cpp \
$$PWD/cmakegeneratordialogtreemodel.cpp \
$$PWD/settingspage.cpp \
$$PWD/designmodecontext.cpp \
$$PWD/documentmanager.cpp \

View File

@@ -1018,8 +1018,10 @@ Project {
"generatecmakelists.cpp",
"generatecmakelists.h",
"generatecmakelistsconstants.h",
"checkablefilelistmodel.cpp",
"checkablefilelistmodel.h",
"checkablefiletreeitem.cpp",
"checkablefiletreeitem.h",
"cmakegeneratordialogtreemodel.cpp",
"cmakegeneratordialogtreemodel.h",
"cmakegeneratordialog.cpp",
"cmakegeneratordialog.h",
"designersettings.cpp",