CMake generator: Integrate warnings in confirmation dialog

Task-number: QDS-5856
Change-Id: If95515ee0921598623a024fd7bd8fe8ef3482aa9
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Tapani Mattila
2021-12-27 12:18:58 +02:00
parent 72c3d675a0
commit 85dab69262
6 changed files with 133 additions and 66 deletions

View File

@@ -33,7 +33,7 @@ CheckableFileTreeItem::CheckableFileTreeItem(const FilePath &filePath)
:QStandardItem(filePath.toString()) :QStandardItem(filePath.toString())
{ {
Qt::ItemFlags itemFlags = flags(); Qt::ItemFlags itemFlags = flags();
if (isFile()) if (!isDir())
itemFlags |= Qt::ItemIsUserCheckable; itemFlags |= Qt::ItemIsUserCheckable;
itemFlags &= ~(Qt::ItemIsEditable | Qt::ItemIsSelectable); itemFlags &= ~(Qt::ItemIsEditable | Qt::ItemIsSelectable);
setFlags(itemFlags); setFlags(itemFlags);

View File

@@ -27,6 +27,8 @@
#include "cmakegeneratordialogtreemodel.h" #include "cmakegeneratordialogtreemodel.h"
#include "generatecmakelistsconstants.h" #include "generatecmakelistsconstants.h"
#include <utils/utilsicons.h>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QPushButton> #include <QPushButton>
#include <QLayout> #include <QLayout>
@@ -39,8 +41,15 @@ namespace QmlDesigner {
namespace GenerateCmake { namespace GenerateCmake {
CmakeGeneratorDialog::CmakeGeneratorDialog(const FilePath &rootDir, const FilePaths &files) CmakeGeneratorDialog::CmakeGeneratorDialog(const FilePath &rootDir, const FilePaths &files)
: QDialog() : QDialog(),
m_rootDir(rootDir),
m_files(files)
{ {
setWindowTitle(QCoreApplication::translate("QmlDesigner::GenerateCmake",
"Select Files to Generate"));
m_model = new CMakeGeneratorDialogTreeModel(rootDir, files, this);
QVBoxLayout *layout = new QVBoxLayout(this); QVBoxLayout *layout = new QVBoxLayout(this);
setLayout(layout); setLayout(layout);
@@ -51,16 +60,20 @@ CmakeGeneratorDialog::CmakeGeneratorDialog(const FilePath &rootDir, const FilePa
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
connect(m_model, &CMakeGeneratorDialogTreeModel::checkedStateChanged, this, &CmakeGeneratorDialog::refreshNotificationText);
m_model = new CMakeGeneratorDialogTreeModel(rootDir, files, this);
QTreeView *tree = new QTreeView(this); QTreeView *tree = new QTreeView(this);
tree->setModel(m_model); tree->setModel(m_model);
tree->expandAll(); tree->expandAll();
tree->setHeaderHidden(true); tree->setHeaderHidden(true);
tree->setItemsExpandable(false);
layout->addWidget(tree); m_notifications = new QTextEdit(this);
m_warningIcon = Utils::Icons::WARNING.pixmap();
refreshNotificationText();
layout->addWidget(tree, 2);
layout->addWidget(m_notifications, 1);
layout->addWidget(buttons); layout->addWidget(buttons);
} }
@@ -76,5 +89,47 @@ FilePaths CmakeGeneratorDialog::getFilePaths()
return paths; return paths;
} }
const QString FILE_CREATE_NOTIFICATION = QCoreApplication::translate("QmlDesigner::GenerateCmake",
"File %1 will be created.\n");
const QString FILE_OVERWRITE_NOTIFICATION = QCoreApplication::translate("QmlDesigner::GenerateCmake",
"File %1 will be overwritten.\n");
void CmakeGeneratorDialog::refreshNotificationText()
{
QTextDocument *document = m_notifications->document();
document->clear();
document->addResource(QTextDocument::ImageResource, QUrl("cmakegendialog://warningicon"), m_warningIcon);
QTextCursor cursor = m_notifications->textCursor();
QTextImageFormat iformat;
iformat.setName("cmakegendialog://warningicon");
QList<CheckableFileTreeItem*> nodes = m_model->items();
for (CheckableFileTreeItem *node : nodes) {
if (!m_files.contains(node->toFilePath()))
continue;
if (!node->toFilePath().exists() && node->isChecked()) {
QString relativePath = QString(node->toFilePath().toString()).remove(m_rootDir.toString()+'/');
cursor.insertText(QString(FILE_CREATE_NOTIFICATION).arg(relativePath));
}
}
if (!document->toPlainText().isEmpty())
cursor.insertBlock();
for (CheckableFileTreeItem *node : nodes) {
if (!m_files.contains(node->toFilePath()))
continue;
if (node->toFilePath().exists() && node->isChecked()) {
QString relativePath = node->toFilePath().relativePath(m_rootDir).toString();
cursor.insertImage(iformat);
cursor.insertText(QString(FILE_OVERWRITE_NOTIFICATION).arg(relativePath));
}
}
}
} }
} }

View File

@@ -32,6 +32,7 @@
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <QDialog> #include <QDialog>
#include <QTextEdit>
namespace QmlDesigner { namespace QmlDesigner {
@@ -39,12 +40,21 @@ namespace GenerateCmake {
class CmakeGeneratorDialog : public QDialog class CmakeGeneratorDialog : public QDialog
{ {
Q_OBJECT
public: public:
CmakeGeneratorDialog(const Utils::FilePath &rootDir, const Utils::FilePaths &files); CmakeGeneratorDialog(const Utils::FilePath &rootDir, const Utils::FilePaths &files);
Utils::FilePaths getFilePaths(); Utils::FilePaths getFilePaths();
public slots:
void refreshNotificationText();
private: private:
CMakeGeneratorDialogTreeModel *m_model; CMakeGeneratorDialogTreeModel *m_model;
QTextEdit *m_notifications;
QVariant m_warningIcon;
Utils::FilePath m_rootDir;
Utils::FilePaths m_files;
}; };
} }

View File

@@ -27,6 +27,8 @@
#include "generatecmakelistsconstants.h" #include "generatecmakelistsconstants.h"
#include "checkablefiletreeitem.h" #include "checkablefiletreeitem.h"
#include <utils/utilsicons.h>
using namespace Utils; using namespace Utils;
namespace QmlDesigner { namespace QmlDesigner {
@@ -51,7 +53,7 @@ QVariant CMakeGeneratorDialogTreeModel::data(const QModelIndex &index, int role)
if (index.isValid()) { if (index.isValid()) {
const CheckableFileTreeItem *node = constNodeForIndex(index); const CheckableFileTreeItem *node = constNodeForIndex(index);
if (role == Qt::CheckStateRole) { if (role == Qt::CheckStateRole) {
if (node->isFile()) if (!node->isDir())
return node->isChecked() ? Qt::Checked : Qt::Unchecked; return node->isChecked() ? Qt::Checked : Qt::Unchecked;
return {}; return {};
} }
@@ -60,8 +62,20 @@ QVariant CMakeGeneratorDialogTreeModel::data(const QModelIndex &index, int role)
return QVariant(fullPath.fileName()); return QVariant(fullPath.fileName());
} }
else if (role == Qt::DecorationRole) { else if (role == Qt::DecorationRole) {
if (!node->isFile()) if (node->isFile())
return Utils::Icons::WARNING.icon();
if (node->isDir())
return m_icons->icon(QFileIconProvider::Folder); return m_icons->icon(QFileIconProvider::Folder);
else
return Utils::Icons::NEWFILE.icon();
}
else if (role == Qt::ToolTipRole) {
if (node->isFile())
return QCoreApplication::translate("QmlDesigner::GenerateCmake",
"This file already exists and will be overwritten.");
if (!node->toFilePath().exists())
return QCoreApplication::translate("QmlDesigner::GenerateCmake",
"This file or folder will be created.");
} }
} }
@@ -74,6 +88,7 @@ bool CMakeGeneratorDialogTreeModel::setData(const QModelIndex &index, const QVar
CheckableFileTreeItem *node = nodeForIndex(index); CheckableFileTreeItem *node = nodeForIndex(index);
if (role == Qt::CheckStateRole) { if (role == Qt::CheckStateRole) {
node->setChecked(value.value<bool>()); node->setChecked(value.value<bool>());
emit checkedStateChanged(node);
return true; return true;
} }
} }
@@ -81,17 +96,26 @@ bool CMakeGeneratorDialogTreeModel::setData(const QModelIndex &index, const QVar
return QStandardItemModel::setData(index, value, role);; return QStandardItemModel::setData(index, value, role);;
} }
const QList<CheckableFileTreeItem*> CMakeGeneratorDialogTreeModel::items() const
{
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
QList<QStandardItem*> standardItems = findItems("*", Qt::MatchWildcard | Qt::MatchRecursive);
#else
QList<QStandardItem*> standardItems = findItems(".*", Qt::MatchRegularExpression | Qt::MatchRecursive);
#endif
QList<CheckableFileTreeItem*> checkableItems;
for (QStandardItem *item : standardItems)
checkableItems.append(static_cast<CheckableFileTreeItem*>(item));
return checkableItems;
}
const QList<CheckableFileTreeItem*> CMakeGeneratorDialogTreeModel::checkedItems() const const QList<CheckableFileTreeItem*> CMakeGeneratorDialogTreeModel::checkedItems() const
{ {
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) QList<CheckableFileTreeItem*> allItems = items();
QList<QStandardItem*> allItems = findItems("*", Qt::MatchWildcard);
#else
QList<QStandardItem*> allItems = findItems(".*", Qt::MatchRegularExpression);
#endif
QList<CheckableFileTreeItem*> checkedItems; QList<CheckableFileTreeItem*> checkedItems;
for (QStandardItem *standardItem : allItems) { for (CheckableFileTreeItem *item : allItems) {
CheckableFileTreeItem *item = static_cast<CheckableFileTreeItem*>(standardItem);
if (item->isChecked()) if (item->isChecked())
checkedItems.append(item); checkedItems.append(item);
} }
@@ -133,6 +157,8 @@ void CMakeGeneratorDialogTreeModel::createNodes(const FilePaths &candidates, QSt
if (file.parentDir() == thisDir) { if (file.parentDir() == thisDir) {
CheckableFileTreeItem *fileNode = new CheckableFileTreeItem(file); CheckableFileTreeItem *fileNode = new CheckableFileTreeItem(file);
fileNode->setChecked(checkedByDefault(file)); fileNode->setChecked(checkedByDefault(file));
if (!file.exists())
fileNode->setChecked(true);
parent->appendRow(fileNode); parent->appendRow(fileNode);
} }
} }

View File

@@ -38,6 +38,8 @@ namespace GenerateCmake {
class CMakeGeneratorDialogTreeModel : public QStandardItemModel class CMakeGeneratorDialogTreeModel : public QStandardItemModel
{ {
Q_OBJECT
public: public:
CMakeGeneratorDialogTreeModel(const Utils::FilePath &rootDir, CMakeGeneratorDialogTreeModel(const Utils::FilePath &rootDir,
const Utils::FilePaths &files, QObject *parent = nullptr); const Utils::FilePaths &files, QObject *parent = nullptr);
@@ -46,10 +48,14 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role); bool setData(const QModelIndex &index, const QVariant &value, int role);
const QList<CheckableFileTreeItem*> items() const;
const QList<CheckableFileTreeItem*> checkedItems() const; const QList<CheckableFileTreeItem*> checkedItems() const;
const CheckableFileTreeItem* constNodeForIndex(const QModelIndex &index) const; const CheckableFileTreeItem* constNodeForIndex(const QModelIndex &index) const;
CheckableFileTreeItem* nodeForIndex(const QModelIndex &index); CheckableFileTreeItem* nodeForIndex(const QModelIndex &index);
signals:
void checkedStateChanged(CheckableFileTreeItem *item);
protected: protected:
bool checkedByDefault(const Utils::FilePath &file) const; bool checkedByDefault(const Utils::FilePath &file) const;
Utils::FilePath rootDir; Utils::FilePath rootDir;

View File

@@ -166,67 +166,35 @@ void removeUnconfirmedQueuedFiles(const Utils::FilePaths confirmedFiles)
const QString WARNING_MISSING_STRUCTURE_FATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake", const QString WARNING_MISSING_STRUCTURE_FATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake",
"The project is not properly structured for automatically generating CMake files.\n\nAborting process.\n\nThe following files or directories are missing:\n\n%1"); "The project is not properly structured for automatically generating CMake files.\n\nAborting process.\n\nThe following files or directories are missing:\n\n%1");
const QString WARNING_MISSING_STRUCTURE_NONFATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake", //const QString WARNING_MISSING_STRUCTURE_NONFATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake",
"The project is not properly structured for automatically generating CMake files.\n\nThe following files or directories are missing and may be created:\n\n%1"); // "The project is not properly structured for automatically generating CMake files.\n\nThe following files or directories are missing and may be created:\n\n%1");
const QString WARNING_TITLE_FATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake", const QString WARNING_TITLE_FATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake",
"Cannot Generate CMake Files"); "Cannot Generate CMake Files");
const QString WARNING_TITLE_NONFATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake", //const QString WARNING_TITLE_NONFATAL = QCoreApplication::translate("QmlDesigner::GenerateCmake",
"Problems with Generating CMake Files"); // "Problems with Generating CMake Files");
void showProjectDirErrorDialog(int error) void showProjectDirErrorDialog(int error)
{ {
QString fatalList;
QString nonFatalList;
if (error & MissingContentDir)
fatalList.append(QString(DIRNAME_CONTENT) + "\n");
if (error & MissingAppMainQml)
fatalList.append(QString(DIRNAME_CONTENT)
+ QDir::separator()
+ QString(FILENAME_APPMAINQML)
+ "\n");
if (error & MissingCppDir)
fatalList.append(QString(DIRNAME_CPP) + "\n");
if (error & MissingImportDir)
fatalList.append(QString(DIRNAME_IMPORT) + "\n");
if (error & MissingAssetImportDir)
nonFatalList.append(QString(DIRNAME_ASSET) + "\n");
if (error & MissingMainCMake)
nonFatalList.append(QString(FILENAME_CMAKELISTS) + "\n");
if (error & MissingQmlModules)
nonFatalList.append(QString(FILENAME_MODULES) + "\n");
if (error & MissingMainQml)
nonFatalList.append(QString(FILENAME_MAINQML) + "\n");
if (error & MissingMainCpp)
nonFatalList.append(QString(DIRNAME_CPP)
+ QDir::separator()
+ QString(FILENAME_MAINCPP)
+ "\n");
if (error & MissingMainCppHeader)
nonFatalList.append(QString(DIRNAME_CPP)
+ QDir::separator()
+ QString(FILENAME_MAINCPP_HEADER)
+ "\n");
if (error & MissingEnvHeader)
nonFatalList.append(QString(DIRNAME_CPP)
+ QDir::separator()
+ QString(FILENAME_ENV_HEADER)
+ "\n");
bool isFatal = isErrorFatal(error); bool isFatal = isErrorFatal(error);
if (isFatal) { if (isFatal) {
QString fatalList;
if (error & MissingContentDir)
fatalList.append(QString(DIRNAME_CONTENT) + "\n");
if (error & MissingAppMainQml)
fatalList.append(QString(DIRNAME_CONTENT)
+ QDir::separator()
+ QString(FILENAME_APPMAINQML)
+ "\n");
if (error & MissingCppDir)
fatalList.append(QString(DIRNAME_CPP) + "\n");
if (error & MissingImportDir)
fatalList.append(QString(DIRNAME_IMPORT) + "\n");
QMessageBox::critical(nullptr, QMessageBox::critical(nullptr,
WARNING_TITLE_FATAL, WARNING_TITLE_FATAL,
WARNING_MISSING_STRUCTURE_FATAL.arg(fatalList + nonFatalList)); WARNING_MISSING_STRUCTURE_FATAL.arg(fatalList));
}
else {
QMessageBox::warning(nullptr,
WARNING_TITLE_NONFATAL,
WARNING_MISSING_STRUCTURE_NONFATAL.arg(nonFatalList));
} }
} }
@@ -237,6 +205,8 @@ bool showConfirmationDialog(const Utils::FilePath &rootDir)
files.append(file.filePath); files.append(file.filePath);
CmakeGeneratorDialog dialog(rootDir, files); CmakeGeneratorDialog dialog(rootDir, files);
dialog.setMinimumWidth(600);
dialog.setMinimumHeight(640);
if (dialog.exec()) { if (dialog.exec()) {
Utils::FilePaths confirmedFiles = dialog.getFilePaths(); Utils::FilePaths confirmedFiles = dialog.getFilePaths();
removeUnconfirmedQueuedFiles(confirmedFiles); removeUnconfirmedQueuedFiles(confirmedFiles);