ui: added automatic include path detection for C/C++ Source Groups

This commit is contained in:
mlangkabel
2018-01-09 12:13:16 +01:00
parent 978cf4f4ed
commit 686ba504c2
35 changed files with 877 additions and 248 deletions
+2
View File
@@ -225,6 +225,8 @@ add_files(
qt/window/QtLicenseWindow.h
qt/window/QtMainWindow.cpp
qt/window/QtMainWindow.h
qt/window/QtPathListDialog.cpp
qt/window/QtPathListDialog.h
qt/window/QtPreferencesWindow.cpp
qt/window/QtPreferencesWindow.h
qt/window/QtSelectPathsDialog.cpp
+5
View File
@@ -29,6 +29,11 @@ void QtProgressBar::showProgress(size_t percent)
update();
}
size_t QtProgressBar::getProgress() const
{
return m_percent;
}
void QtProgressBar::showUnknownProgressAnimated()
{
start();
+1
View File
@@ -17,6 +17,7 @@ public:
QtProgressBar(QWidget* parent = nullptr);
void showProgress(size_t percent);
size_t getProgress() const;
void showUnknownProgressAnimated();
+14 -2
View File
@@ -58,11 +58,10 @@ void QtDialogView::hideUnknownProgressDialog()
void QtDialogView::showProgressDialog(const std::string& title, const std::string& message, int progress)
{
MessageStatus(title + ": " + message + " [" + std::to_string(progress) + "%]", false, true).dispatch();
m_onQtThread(
[=]()
{
bool sendStatusMessage = true;
QtIndexingDialog* window = dynamic_cast<QtIndexingDialog*>(m_windowStack.getTopWindow());
if (!window || window->getType() != QtIndexingDialog::DIALOG_PROGRESS)
{
@@ -71,6 +70,19 @@ void QtDialogView::showProgressDialog(const std::string& title, const std::strin
window = createWindow<QtIndexingDialog>();
window->setupProgress();
}
else
{
sendStatusMessage = (
window->getTitle() != title ||
window->getMessage() != message ||
window->getProgress() != progress
);
}
if (sendStatusMessage)
{
MessageStatus(title + ": " + message + " [" + std::to_string(progress) + "%]", false, true).dispatch();
}
window->updateTitle(title.c_str());
window->updateMessage(message.c_str());
+16 -2
View File
@@ -273,15 +273,29 @@ void QtIndexingDialog::updateMessage(QString message)
}
}
void QtIndexingDialog::updateProgress(int progress)
std::string QtIndexingDialog::getMessage() const
{
int percent = std::min(std::max(progress, 0), 100);
if (m_messageLabel)
{
return m_messageLabel->text().toStdString();
}
return "";
}
void QtIndexingDialog::updateProgress(size_t progress)
{
size_t percent = std::min<size_t>(std::max<size_t>(progress, 0), 100);
m_progressBar->showProgress(percent);
m_percentLabel->setText(QString::number(percent) + "% Progress");
setGeometries();
}
size_t QtIndexingDialog::getProgress() const
{
return m_progressBar->getProgress();
}
void QtIndexingDialog::updateIndexingProgress(size_t fileCount, size_t totalFileCount, std::string sourcePath)
{
updateMessage(QString::number(fileCount) + "/" + QString::number(totalFileCount) + " File" + (totalFileCount > 1 ? "s" : ""));
+3 -1
View File
@@ -48,7 +48,9 @@ public:
void setupProgress();
void updateMessage(QString message);
void updateProgress(int progress);
std::string getMessage() const;
void updateProgress(size_t progress);
size_t getProgress() const;
void updateIndexingProgress(size_t fileCount, size_t totalFileCount, std::string sourcePath);
void updateErrorCount(size_t errorCount, size_t fatalCount);
@@ -0,0 +1,57 @@
#include "qt/window/QtPathListDialog.h"
#include <QLabel>
#include "qt/element/QtDirectoryListBox.h"
QtPathListDialog::QtPathListDialog(const QString& title, const QString& description, QWidget* parent)
: QtWindow(parent)
, m_title(title)
, m_description(description)
{
}
QSize QtPathListDialog::sizeHint() const
{
return QSize(550, 550);
}
void QtPathListDialog::setRelativeRootDirectory(const FilePath& dir)
{
m_pathList->setRelativeRootDirectory(dir);
}
void QtPathListDialog::setPaths(const std::vector<FilePath>& paths, bool readOnly)
{
m_pathList->setList(paths, readOnly);
}
std::vector<FilePath> QtPathListDialog::getPaths()
{
return m_pathList->getList();
}
void QtPathListDialog::populateWindow(QWidget* widget)
{
QVBoxLayout* layout = new QVBoxLayout();
layout->setContentsMargins(0, 0, 0, 0);
QLabel* description = new QLabel(m_description);
description->setObjectName("description");
description->setWordWrap(true);
layout->addWidget(description);
m_pathList = new QtDirectoryListBox(this, m_title);
layout->addWidget(m_pathList);
widget->setLayout(layout);
}
void QtPathListDialog::windowReady()
{
updateNextButton("Save");
updateCloseButton("Cancel");
setPreviousVisible(false);
updateTitle(m_title);
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef QT_PATH_LIST_DIALOG_H
#define QT_PATH_LIST_DIALOG_H
#include "qt/window/QtWindow.h"
class FilePath;
class QtDirectoryListBox;
class QtPathListDialog
: public QtWindow
{
Q_OBJECT
public:
QtPathListDialog(const QString& title, const QString& description, QWidget* parent = 0);
QSize sizeHint() const override;
void setRelativeRootDirectory(const FilePath& dir);
void setPaths(const std::vector<FilePath>& paths, bool readOnly = false);
std::vector<FilePath> getPaths();
protected:
void populateWindow(QWidget* widget) override;
void windowReady() override;
QString m_title;
QString m_description;
private:
QtDirectoryListBox* m_pathList;
};
#endif // QT_PATH_LIST_DIALOG_H
-1
View File
@@ -28,7 +28,6 @@ protected:
QString m_description;
private:
QPlainTextEdit* m_text;
};
+9
View File
@@ -213,6 +213,15 @@ void QtWindow::updateTitle(QString title)
}
}
std::string QtWindow::getTitle() const
{
if (m_title)
{
return m_title->text().toStdString();
}
return "";
}
void QtWindow::updateSubTitle(QString subTitle)
{
if (m_subTitle)
+1
View File
@@ -35,6 +35,7 @@ public:
void moveToCenter();
void updateTitle(QString title);
std::string getTitle() const;
void updateSubTitle(QString subTitle);
void updateNextButton(QString text);
@@ -9,10 +9,11 @@
#include "Application.h"
#include "component/view/DialogView.h"
#include "data/indexer/IndexerCommandCxxCdb.h"
#include "project/IncludeDirective.h"
#include "project/IncludeValidation.h"
#include "utility/IncludeDirective.h"
#include "utility/IncludeProcessing.h"
#include "qt/element/QtDirectoryListBox.h"
#include "qt/view/QtDialogView.h"
#include "qt/window/QtPathListDialog.h"
#include "qt/window/QtSelectPathsDialog.h"
#include "settings/ApplicationSettings.h"
#include "settings/SourceGroupSettingsCxxCdb.h"
@@ -23,6 +24,7 @@
#include "utility/utility.h"
#include "utility/utilityFile.h"
#include "utility/utilityPathDetection.h"
#include "utility/utilityString.h"
QtProjectWizzardContentPaths::QtProjectWizzardContentPaths(
std::shared_ptr<SourceGroupSettings> settings, QtProjectWizzardWindow* window
@@ -429,6 +431,8 @@ QtProjectWizzardContentPathsHeaderSearch::QtProjectWizzardContentPathsHeaderSear
: QtProjectWizzardContentPaths(settings, window)
, m_showValidationResultFunctor(std::bind(
&QtProjectWizzardContentPathsHeaderSearch::showValidationResult, this, std::placeholders::_1))
, m_showDetectedIncludesResultFunctor(std::bind(
&QtProjectWizzardContentPathsHeaderSearch::showDetectedIncludesResult, this, std::placeholders::_1))
, m_isCdb(isCDB)
{
setTitleString(m_isCdb ? "Additional Include Paths" : "Include Paths");
@@ -454,11 +458,18 @@ void QtProjectWizzardContentPathsHeaderSearch::populate(QGridLayout* layout, int
if (!m_isCdb)
{
QPushButton* button = new QPushButton("validate include directives");
button->setObjectName("windowButton");
connect(button, &QPushButton::clicked, this, &QtProjectWizzardContentPathsHeaderSearch::validateButtonClicked);
layout->addWidget(button, row, QtProjectWizzardWindow::BACK_COL, Qt::AlignRight | Qt::AlignTop);
{
QPushButton* detectionButton = new QPushButton("auto-detect");
detectionButton->setObjectName("windowButton");
connect(detectionButton, &QPushButton::clicked, this, &QtProjectWizzardContentPathsHeaderSearch::detectIncludesButtonClicked);
layout->addWidget(detectionButton, row, QtProjectWizzardWindow::BACK_COL, Qt::AlignLeft | Qt::AlignTop);
}
{
QPushButton* validateionButton = new QPushButton("validate include directives");
validateionButton->setObjectName("windowButton");
connect(validateionButton, &QPushButton::clicked, this, &QtProjectWizzardContentPathsHeaderSearch::validateIncludesButtonClicked);
layout->addWidget(validateionButton, row, QtProjectWizzardWindow::BACK_COL, Qt::AlignRight | Qt::AlignTop);
}
row++;
}
}
@@ -486,7 +497,30 @@ bool QtProjectWizzardContentPathsHeaderSearch::isScrollAble() const
return true;
}
void QtProjectWizzardContentPathsHeaderSearch::validateButtonClicked()
void QtProjectWizzardContentPathsHeaderSearch::detectIncludesButtonClicked()
{
m_window->saveContent();
m_pathsDialog = std::make_shared<QtPathListDialog>(
"Detect Include Paths",
"<p>Automatically search the paths provided below for additional include paths that "
"can be used to resolve include directives within your source code.</p>"
"<p>The indexed paths will be searched by default but you can add further paths if required.</p>"
);
m_pathsDialog->setup();
m_pathsDialog->updateNextButton("Next");
m_pathsDialog->setCloseVisible(true);
m_pathsDialog->setRelativeRootDirectory(m_settings->getProjectDirectoryPath());
m_pathsDialog->setPaths(m_settings->getSourcePaths(), true);
m_pathsDialog->showWindow();
connect(m_pathsDialog.get(), &QtPathListDialog::finished, this, &QtProjectWizzardContentPathsHeaderSearch::finishedSelectDetectIncludesRootPathsDialog);
connect(m_pathsDialog.get(), &QtPathListDialog::canceled, this, &QtProjectWizzardContentPathsHeaderSearch::closedPathsDialog);
}
void QtProjectWizzardContentPathsHeaderSearch::validateIncludesButtonClicked()
{
// TODO: regard Force Includes here, too!
m_window->saveContent();
@@ -497,7 +531,7 @@ void QtProjectWizzardContentPathsHeaderSearch::validateButtonClicked()
{
std::shared_ptr<DialogView> dialogView = Application::getInstance()->getDialogView();
std::vector<FilePath> sourceFilePaths;
std::set<FilePath> sourceFilePaths;
std::vector<FilePath> indexedFilePaths;
std::vector<FilePath> headerSearchPaths;
@@ -514,7 +548,7 @@ void QtProjectWizzardContentPathsHeaderSearch::validateButtonClicked()
m_settings->getExcludePathsExpandedAndAbsolute(),
m_settings->getSourceExtensions()
);
sourceFilePaths = utility::toVector(fileManager.getAllSourceFilePaths());
sourceFilePaths = fileManager.getAllSourceFilePaths();
headerSearchPaths = ApplicationSettings::getInstance()->getHeaderSearchPathsExpanded();
@@ -531,10 +565,10 @@ void QtProjectWizzardContentPathsHeaderSearch::validateButtonClicked()
dialogView->hideProgressDialog();
});
unresolvedIncludes = IncludeValidation::getUnresolvedIncludeDirectives(
unresolvedIncludes = IncludeProcessing::getUnresolvedIncludeDirectives(
sourceFilePaths,
indexedFilePaths,
headerSearchPaths,
utility::toSet(indexedFilePaths),
utility::toSet(headerSearchPaths),
log2(sourceFilePaths.size()),
[&](const float progress)
{
@@ -549,6 +583,147 @@ void QtProjectWizzardContentPathsHeaderSearch::validateButtonClicked()
}).detach();
}
void QtProjectWizzardContentPathsHeaderSearch::finishedSelectDetectIncludesRootPathsDialog()
{
// TODO: regard Force Includes here, too!
const std::vector<FilePath> searchedPaths = m_settings->makePathsExpandedAndAbsolute(m_pathsDialog->getPaths());
closedPathsDialog();
std::thread([=]()
{
std::set<FilePath> detectedHeaderSearchPaths;
{
std::shared_ptr<QtDialogView> dialogView = std::dynamic_pointer_cast<QtDialogView>(Application::getInstance()->getDialogView());
std::set<FilePath> sourceFilePaths;
{
dialogView->setParentWindow(m_window);
dialogView->showUnknownProgressDialog("Processing", "Gathering Source Files");
ScopedFunctor dialogHider([&dialogView]() {
dialogView->hideUnknownProgressDialog();
});
FileManager fileManager;
fileManager.update(
m_settings->getSourcePathsExpandedAndAbsolute(),
m_settings->getExcludePathsExpandedAndAbsolute(),
m_settings->getSourceExtensions()
);
sourceFilePaths = fileManager.getAllSourceFilePaths();
}
{
dialogView->setParentWindow(m_window);
ScopedFunctor dialogHider([&dialogView]() {
dialogView->hideProgressDialog();
});
detectedHeaderSearchPaths = IncludeProcessing::getHeaderSearchDirectories(
sourceFilePaths,
utility::toSet(searchedPaths),
log2(sourceFilePaths.size()),
[&](const float progress)
{
Application::getInstance()->getDialogView()->showProgressDialog(
"Processing", std::to_string(int(progress * sourceFilePaths.size())) + " Files", int(progress * 100.0f)
);
}
);
}
}
m_showDetectedIncludesResultFunctor(detectedHeaderSearchPaths);
}).detach();
}
void QtProjectWizzardContentPathsHeaderSearch::finishedAcceptDetectedIncludePathsDialog()
{
const std::vector<std::string> detectedPaths = utility::splitToVector(m_filesDialog->getText(), "\n");
closedFilesDialog();
std::vector<std::string> headerSearchPaths = m_list->getStringList();
headerSearchPaths.reserve(headerSearchPaths.size() + detectedPaths.size());
for (const std::string& detectedPath : detectedPaths)
{
if (!detectedPath.empty())
{
headerSearchPaths.push_back(detectedPath);
}
}
m_list->setStringList(headerSearchPaths);
}
void QtProjectWizzardContentPathsHeaderSearch::closedPathsDialog()
{
m_pathsDialog->hide();
m_pathsDialog.reset();
window()->raise();
}
void QtProjectWizzardContentPathsHeaderSearch::showDetectedIncludesResult(const std::set<FilePath>& detectedHeaderSearchPaths)
{
const std::set<FilePath> headerSearchPaths = utility::toSet(m_settings->makePathsExpandedAndAbsolute(m_list->getList()));
std::vector<FilePath> additionalHeaderSearchPaths;
for (const FilePath& detectedHeaderSearchPath : detectedHeaderSearchPaths)
{
if (headerSearchPaths.find(detectedHeaderSearchPath) == headerSearchPaths.end())
{
additionalHeaderSearchPaths.push_back(detectedHeaderSearchPath);
}
}
if (additionalHeaderSearchPaths.empty())
{
QMessageBox msgBox;
msgBox.setText("<p>No additional include paths have been detected while searching the provided paths.</p>");
msgBox.exec();
}
else
{
std::string detailedText = "";
FilePath relativeRoot = m_list->getRelativeRootDirectory();
for (const FilePath& path : additionalHeaderSearchPaths)
{
if (!relativeRoot.empty())
{
const FilePath relPath = path.getRelativeTo(relativeRoot);
if (relPath.str().size() < path.str().size())
{
detailedText += relPath.str() + "\n";
continue;
}
}
detailedText += path.str() + "\n";
}
m_filesDialog = std::make_shared<QtTextEditDialog>(
"Detected Include Paths",
(
"<p>The following <b>" + std::to_string(additionalHeaderSearchPaths.size()) + "</b> include paths have been "
"detected and will be added to the include paths that are already defined by this Source Group.<b>"
).c_str()
);
m_filesDialog->setup();
m_filesDialog->setCloseVisible(true);
m_filesDialog->updateNextButton("Finish");
m_filesDialog->setReadOnly(true);
m_filesDialog->setText(detailedText);
m_filesDialog->showWindow();
connect(m_filesDialog.get(), &QtTextEditDialog::finished, this, &QtProjectWizzardContentPathsHeaderSearch::finishedAcceptDetectedIncludePathsDialog);
connect(m_filesDialog.get(), &QtTextEditDialog::canceled, this, &QtProjectWizzardContentPathsHeaderSearch::closedFilesDialog);
}
}
void QtProjectWizzardContentPathsHeaderSearch::showValidationResult(const std::vector<IncludeDirective>& unresolvedIncludes)
{
if (unresolvedIncludes.empty())
@@ -1,6 +1,8 @@
#ifndef QT_PROJECT_WIZZARD_CONTENT_PATHS_H
#define QT_PROJECT_WIZZARD_CONTENT_PATHS_H
#include <set>
#include "qt/window/project_wizzard/QtProjectWizzardContent.h"
#include "utility/path_detector/CombinedPathDetector.h"
@@ -9,6 +11,7 @@ class QCheckBox;
class QComboBox;
class QPushButton;
class QtDirectoryListBox;
class QtPathListDialog;
class SourceGroupSettings;
class SourceGroupSettingsCxxCdb;
@@ -119,12 +122,19 @@ public:
virtual bool isScrollAble() const override;
private slots:
void validateButtonClicked();
void detectIncludesButtonClicked();
void validateIncludesButtonClicked();
void finishedSelectDetectIncludesRootPathsDialog();
void finishedAcceptDetectedIncludePathsDialog();
void closedPathsDialog();
private:
void showDetectedIncludesResult(const std::set<FilePath>& detectedHeaderSearchPaths);
void showValidationResult(const std::vector<IncludeDirective>& unresolvedIncludes);
QtThreadedFunctor<std::set<FilePath>> m_showDetectedIncludesResultFunctor;
QtThreadedFunctor<std::vector<IncludeDirective>> m_showValidationResultFunctor;
std::shared_ptr<QtPathListDialog> m_pathsDialog;
const bool m_isCdb;
};