diff --git a/languages/plugins/custom-definesandincludes/CMakeLists.txt b/languages/plugins/custom-definesandincludes/CMakeLists.txt index 42c0bc6c8c..909fe08e19 100644 --- a/languages/plugins/custom-definesandincludes/CMakeLists.txt +++ b/languages/plugins/custom-definesandincludes/CMakeLists.txt @@ -1,62 +1,59 @@ add_subdirectory(tests) add_subdirectory(compilerprovider) add_subdirectory(noprojectincludesanddefines) set( kdevdefinesandincludesmanager_SRCS definesandincludesmanager.cpp debugarea.cpp kcm_widget/projectpathsmodel.cpp kcm_widget/definesmodel.cpp kcm_widget/includesmodel.cpp kcm_widget/includeswidget.cpp kcm_widget/defineswidget.cpp kcm_widget/projectpathswidget.cpp kcm_widget/definesandincludesconfigpage.cpp - kcm_widget/compilersmodel.cpp - kcm_widget/compilerswidget.cpp kcm_widget/parserwidget.cpp compilerprovider/icompiler.cpp # TODO: is this really neccessary ) ki18n_wrap_ui(kdevdefinesandincludesmanager_SRCS kcm_widget/batchedit.ui kcm_widget/includeswidget.ui kcm_widget/defineswidget.ui kcm_widget/projectpathswidget.ui - kcm_widget/compilerswidget.ui kcm_widget/parserwidget.ui ) kconfig_add_kcfg_files( kdevdefinesandincludesmanager_SRCS kcm_widget/customdefinesandincludes.kcfgc) kdevplatform_add_plugin(kdevdefinesandincludesmanager JSON kdevdefinesandincludesmanager.json SOURCES ${kdevdefinesandincludesmanager_SRCS}) target_link_libraries( kdevdefinesandincludesmanager LINK_PRIVATE KDev::Project KDev::Util KDev::Language kdevnoprojectincludesanddefines kdevcompilerprovider) option(BUILD_kdev_includepathsconverter "Build utility to modify include paths of a project from command line." ON) if(BUILD_kdev_includepathsconverter) add_executable(kdev_includepathsconverter includepathsconverter.cpp) target_link_libraries(kdev_includepathsconverter LINK_PRIVATE KDev::Project kdevcompilerprovider ) install(TARGETS kdev_includepathsconverter ${INSTALL_TARGETS_DEFAULT_ARGS} ) endif() install(FILES idefinesandincludesmanager.h DESTINATION ${INCLUDE_INSTALL_DIR}/kdevelop/custom-definesandincludes COMPONENT Devel ) add_library(KDev::DefinesAndIncludesManager ALIAS kdevdefinesandincludesmanager) target_include_directories(kdevdefinesandincludesmanager INTERFACE "$" "$" ) set_target_properties(kdevdefinesandincludesmanager PROPERTIES EXPORT_NAME DefinesAndIncludesManager ) install(TARGETS kdevdefinesandincludesmanager EXPORT KDevelopTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/languages/plugins/custom-definesandincludes/compilerprovider/CMakeLists.txt b/languages/plugins/custom-definesandincludes/compilerprovider/CMakeLists.txt index 2782dcd04e..6f26f0b20a 100644 --- a/languages/plugins/custom-definesandincludes/compilerprovider/CMakeLists.txt +++ b/languages/plugins/custom-definesandincludes/compilerprovider/CMakeLists.txt @@ -1,28 +1,34 @@ set( compilerprovider_SRCS compilerprovider.cpp icompiler.cpp gcclikecompiler.cpp msvccompiler.cpp compilerfactories.cpp settingsmanager.cpp ../debugarea.cpp + widget/compilersmodel.cpp + widget/compilerswidget.cpp ) +ki18n_wrap_ui(compilerprovider_SRCS + widget/compilerswidget.ui +) + add_library(kdevcompilerprovider STATIC ${compilerprovider_SRCS}) target_link_libraries( kdevcompilerprovider LINK_PRIVATE KDev::Project KDev::Util KDev::Language ) set_target_properties(kdevcompilerprovider PROPERTIES POSITION_INDEPENDENT_CODE ON) option(BUILD_kdev_msvcdefinehelper "Build the msvcdefinehelper tool for retrieving msvc standard macro definitions" OFF) if(BUILD_kdev_msvcdefinehelper) set(kdevmsvcdefinehelper_SRCS msvcdefinehelper.cpp) add_executable(kdevmsvcdefinehelper ${kdevmsvcdefinehelper_SRCS}) install(TARGETS kdevmsvcdefinehelper RUNTIME DESTINATION bin LIBRARY DESTINATION lib) endif() add_subdirectory(tests) diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/compilersmodel.cpp b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.cpp similarity index 100% rename from languages/plugins/custom-definesandincludes/kcm_widget/compilersmodel.cpp rename to languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.cpp diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/compilersmodel.h b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.h similarity index 100% rename from languages/plugins/custom-definesandincludes/kcm_widget/compilersmodel.h rename to languages/plugins/custom-definesandincludes/compilerprovider/widget/compilersmodel.h diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/compilerswidget.cpp b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.cpp similarity index 82% rename from languages/plugins/custom-definesandincludes/kcm_widget/compilerswidget.cpp rename to languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.cpp index aebbf5a72b..38d78225bd 100644 --- a/languages/plugins/custom-definesandincludes/kcm_widget/compilerswidget.cpp +++ b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.cpp @@ -1,183 +1,242 @@ /* * This file is part of KDevelop * * Copyright 2014 Sergey Kalinichev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "compilerswidget.h" #include #include #include #include #include #include #include "../ui_compilerswidget.h" #include "compilersmodel.h" -#include "debugarea.h" +#include "../../debugarea.h" #include "../compilerprovider/settingsmanager.h" #include "../compilerprovider/compilerprovider.h" using namespace KDevelop; CompilersWidget::CompilersWidget(QWidget* parent) - : QWidget(parent), m_ui(new Ui::CompilersWidget) + : ConfigPage(nullptr, nullptr, parent) + , m_ui(new Ui::CompilersWidget) , m_compilersModel(new CompilersModel(this)) { m_ui->setupUi(this); m_ui->compilers->setModel(m_compilersModel); m_ui->compilers->header()->setSectionResizeMode(QHeaderView::Stretch); m_addMenu = new QMenu(m_ui->addButton); m_mapper = new QSignalMapper(m_addMenu); connect(m_mapper, static_cast(&QSignalMapper::mapped), this, &CompilersWidget::addCompiler); m_addMenu->clear(); auto settings = SettingsManager::globalInstance(); auto provider = settings->provider(); foreach (const auto& factory, provider->compilerFactories()) { QAction* action = new QAction(m_addMenu); action->setText(factory->name()); connect(action, &QAction::triggered, m_mapper, static_cast(&QSignalMapper::map)); m_mapper->setMapping(action, factory->name()); m_addMenu->addAction(action); } m_ui->addButton->setMenu(m_addMenu); connect(m_ui->removeButton, &QPushButton::clicked, this, &CompilersWidget::deleteCompiler); auto delAction = new QAction( i18n("Delete compiler"), this ); delAction->setShortcut( QKeySequence( "Del" ) ); delAction->setShortcutContext( Qt::WidgetWithChildrenShortcut ); m_ui->compilers->addAction( delAction ); connect( delAction, &QAction::triggered, this, &CompilersWidget::deleteCompiler ); connect(m_ui->compilers->selectionModel(), &QItemSelectionModel::currentChanged, this, &CompilersWidget::compilerSelected); connect(m_ui->compilerName, &QLineEdit::editingFinished, this, &CompilersWidget::compilerEdited); connect(m_ui->compilerPath, &QLineEdit::editingFinished, this, &CompilersWidget::compilerEdited); connect(m_ui->compilerSelector, &QPushButton::clicked, this, &CompilersWidget::selectCompilerPathDialog); connect(m_compilersModel, &CompilersModel::compilerChanged, this, &CompilersWidget::compilerChanged); enableItems(false); } void CompilersWidget::setCompilers(const QVector< CompilerPointer >& compilers) { m_compilersModel->setCompilers(compilers); } void CompilersWidget::clear() { m_compilersModel->setCompilers({}); } void CompilersWidget::deleteCompiler() { definesAndIncludesDebug() << "Deleting compiler"; auto selectionModel = m_ui->compilers->selectionModel(); foreach (const QModelIndex& row, selectionModel->selectedIndexes()) { if (row.column() == 1) { //Don't remove the same compiler twice continue; } if(m_compilersModel->removeRows(row.row(), 1, row.parent())) { auto selectedCompiler = selectionModel->selectedIndexes(); compilerSelected(selectedCompiler.isEmpty() ? QModelIndex() : selectedCompiler.first()); } } + + emit changed(); } void CompilersWidget::addCompiler(const QString& factoryName) { auto settings = SettingsManager::globalInstance(); auto provider = settings->provider(); foreach (const auto& factory, provider->compilerFactories()) { if (factoryName == factory->name()) { //add compiler without any information, the user will fill the data in later auto compilerIndex = m_compilersModel->addCompiler(factory->createCompiler(QString(), QString())); m_ui->compilers->selectionModel()->select(compilerIndex, QItemSelectionModel::Clear | QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); compilerSelected(compilerIndex); break; } } + + emit changed(); } QVector< CompilerPointer > CompilersWidget::compilers() const { return m_compilersModel->compilers(); } void CompilersWidget::compilerSelected(const QModelIndex& index) { auto compiler = index.data(CompilersModel::CompilerDataRole); if (compiler.value()) { m_ui->compilerName->setText(compiler.value()->name()); m_ui->compilerPath->setText(compiler.value()->path()); enableItems(true); } else { enableItems(false); } } void CompilersWidget::compilerEdited() { auto indexes = m_ui->compilers->selectionModel()->selectedIndexes(); Q_ASSERT(!indexes.isEmpty()); auto compiler = indexes.first().data(CompilersModel::CompilerDataRole); if (!compiler.value()) { return; } compiler.value()->setName(m_ui->compilerName->text()); compiler.value()->setPath(m_ui->compilerPath->text()); m_compilersModel->updateCompiler(m_ui->compilers->selectionModel()->selection()); + + emit changed(); } void CompilersWidget::selectCompilerPathDialog() { const QString compilerPath = QFileDialog::getOpenFileName(this, tr("Select path to compiler")); if (compilerPath.isEmpty()) return; m_ui->compilerPath->setText(compilerPath); compilerEdited(); } void CompilersWidget::enableItems(bool enable) { m_ui->compilerName->setEnabled(enable); m_ui->compilerPath->setEnabled(enable); m_ui->compilerSelector->setEnabled(enable); if(!enable) { m_ui->compilerName->clear(); m_ui->compilerPath->clear(); } } + +void CompilersWidget::reset() +{ + auto settings = SettingsManager::globalInstance(); + setCompilers(settings->provider()->compilers()); +} + +void CompilersWidget::apply() +{ + auto settings = SettingsManager::globalInstance(); + auto provider = settings->provider(); + + settings->writeUserDefinedCompilers(compilers()); + + const auto& providerCompilers = provider->compilers(); + const auto& widgetCompilers = compilers(); + for (auto compiler: providerCompilers) { + if (!widgetCompilers.contains(compiler)) { + provider->unregisterCompiler(compiler); + } + } + + for (auto compiler: widgetCompilers) { + if (!providerCompilers.contains(compiler)) { + provider->registerCompiler(compiler); + } + } +} + +void CompilersWidget::defaults() +{ +} + +QString CompilersWidget::name() const +{ + return i18n("Compilers"); +} + +QString CompilersWidget::fullName() const +{ + return i18n("Configure Compilers"); +} + +QIcon CompilersWidget::icon() const +{ + return QIcon::fromTheme(QStringLiteral("kdevelop")); +} + +KDevelop::ConfigPage::ConfigPageType CompilersWidget::configPageType() const +{ + return ConfigPage::LanguageConfigPage; +} diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/compilerswidget.h b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.h similarity index 78% rename from languages/plugins/custom-definesandincludes/kcm_widget/compilerswidget.h rename to languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.h index 66db39a443..c776b6bfaf 100644 --- a/languages/plugins/custom-definesandincludes/kcm_widget/compilerswidget.h +++ b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.h @@ -1,71 +1,83 @@ /* * This file is part of KDevelop * * Copyright 2014 Sergey Kalinichev * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef COMPILERWIDGET_H #define COMPILERWIDGET_H #include #include #include +#include + #include "../compilerprovider/icompiler.h" namespace Ui { class CompilersWidget; } class CompilersModel; class QMenu; class QSignalMapper; -class CompilersWidget : public QWidget +class CompilersWidget : public KDevelop::ConfigPage { Q_OBJECT public: - CompilersWidget( QWidget* parent = 0 ); - void setCompilers( const QVector& compilers ); + explicit CompilersWidget(QWidget* parent = 0); + void setCompilers(const QVector& compilers); QVector compilers() const; void clear(); + QString name() const override; + QString fullName() const override; + QIcon icon() const override; + + KDevelop::ConfigPage::ConfigPageType configPageType() const override; + + void apply() override; + void reset() override; + void defaults() override; + private slots: void deleteCompiler(); void addCompiler(const QString& factoryName); void compilerSelected(const QModelIndex& index); void compilerEdited(); void selectCompilerPathDialog(); signals: void compilerChanged(); private: void enableItems(bool enable); Ui::CompilersWidget* m_ui; CompilersModel* m_compilersModel; QMenu *m_addMenu; QSignalMapper *m_mapper; }; #endif diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/compilerswidget.ui b/languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.ui similarity index 100% rename from languages/plugins/custom-definesandincludes/kcm_widget/compilerswidget.ui rename to languages/plugins/custom-definesandincludes/compilerprovider/widget/compilerswidget.ui diff --git a/languages/plugins/custom-definesandincludes/definesandincludesmanager.cpp b/languages/plugins/custom-definesandincludes/definesandincludesmanager.cpp index 8a912cc995..ad7d3e1e25 100644 --- a/languages/plugins/custom-definesandincludes/definesandincludesmanager.cpp +++ b/languages/plugins/custom-definesandincludes/definesandincludesmanager.cpp @@ -1,292 +1,303 @@ /* * This file is part of KDevelop * * Copyright 2014 Sergey Kalinichev * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "definesandincludesmanager.h" #include "kcm_widget/definesandincludesconfigpage.h" #include "compilerprovider/compilerprovider.h" +#include "compilerprovider/widget/compilerswidget.h" #include "noprojectincludesanddefines/noprojectincludepathsmanager.h" #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; namespace { ///@return: The ConfigEntry, with includes/defines from @p paths for all parent folders of @p item. static ConfigEntry findConfigForItem(QList paths, const KDevelop::ProjectBaseItem* item) { ConfigEntry ret; const Path itemPath = item->path(); const Path rootDirectory = item->project()->path(); Path closestPath; std::sort(paths.begin(), paths.end(), [] (const ConfigEntry& lhs, const ConfigEntry& rhs) { // sort in reverse order to do a bottom-up search return lhs.path > rhs.path; }); for (const ConfigEntry & entry : paths) { Path targetDirectory = rootDirectory; // note: a dot represents the project root if (entry.path != ".") { targetDirectory.addPath(entry.path); } if (targetDirectory == itemPath || targetDirectory.isParentOf(itemPath)) { ret.includes += entry.includes; for (auto it = entry.defines.constBegin(); it != entry.defines.constEnd(); it++) { if (!ret.defines.contains(it.key())) { ret.defines[it.key()] = it.value(); } } if (ret.parserArguments.isEmpty() || targetDirectory.segments().size() > closestPath.segments().size()) { ret.parserArguments = entry.parserArguments; closestPath = targetDirectory; } } } ret.includes.removeDuplicates(); Q_ASSERT(!ret.parserArguments.isEmpty()); return ret; } void merge(Defines* target, const Defines& source) { if (target->isEmpty()) { *target = source; return; } for (auto it = source.constBegin(); it != source.constEnd(); ++it) { target->insert(it.key(), it.value()); } } } K_PLUGIN_FACTORY_WITH_JSON(DefinesAndIncludesManagerFactory, "kdevdefinesandincludesmanager.json", registerPlugin(); ) DefinesAndIncludesManager::DefinesAndIncludesManager( QObject* parent, const QVariantList& ) : IPlugin("kdevdefinesandincludesmanager", parent ) , m_settings(SettingsManager::globalInstance()) , m_noProjectIPM(new NoProjectIncludePathsManager()) { KDEV_USE_EXTENSION_INTERFACE(IDefinesAndIncludesManager); registerProvider(m_settings->provider()); } DefinesAndIncludesManager::~DefinesAndIncludesManager() = default; Defines DefinesAndIncludesManager::defines( ProjectBaseItem* item, Type type ) const { Q_ASSERT(QThread::currentThread() == qApp->thread()); if (!item) { return m_settings->provider()->defines(nullptr); } Defines defines; for (auto provider : m_providers) { if (provider->type() & type) { merge(&defines, provider->defines(item)); } } if ( type & ProjectSpecific ) { auto buildManager = item->project()->buildSystemManager(); if ( buildManager ) { merge(&defines, buildManager->defines(item)); } } // Manually set defines have the highest priority and overwrite values of all other types of defines. if (type & UserDefined) { auto cfg = item->project()->projectConfiguration().data(); merge(&defines, findConfigForItem(m_settings->readPaths(cfg), item).defines); } return defines; } Path::List DefinesAndIncludesManager::includes( ProjectBaseItem* item, Type type ) const { Q_ASSERT(QThread::currentThread() == qApp->thread()); if (!item) { return m_settings->provider()->includes(nullptr); } Path::List includes; if (type & UserDefined) { auto cfg = item->project()->projectConfiguration().data(); includes += KDevelop::toPathList(findConfigForItem(m_settings->readPaths(cfg), item).includes); } if ( type & ProjectSpecific ) { auto buildManager = item->project()->buildSystemManager(); if ( buildManager ) { includes += buildManager->includeDirectories(item); } } for (auto provider : m_providers) { if (provider->type() & type) { includes += provider->includes(item); } } return includes; } bool DefinesAndIncludesManager::unregisterProvider(IDefinesAndIncludesManager::Provider* provider) { int idx = m_providers.indexOf(provider); if (idx != -1) { m_providers.remove(idx); return true; } return false; } void DefinesAndIncludesManager::registerProvider(IDefinesAndIncludesManager::Provider* provider) { Q_ASSERT(provider); if (m_providers.contains(provider)) { return; } m_providers.push_back(provider); } Defines DefinesAndIncludesManager::defines(const QString&) const { return m_settings->provider()->defines(nullptr); } Path::List DefinesAndIncludesManager::includes(const QString& path) const { return m_settings->provider()->includes(nullptr) + m_noProjectIPM->includes(path); } void DefinesAndIncludesManager::openConfigurationDialog(const QString& pathToFile) { if (auto project = KDevelop::ICore::self()->projectController()->findProjectForUrl(QUrl::fromLocalFile(pathToFile))) { KDevelop::ICore::self()->projectController()->configureProject(project); } else { m_noProjectIPM->openConfigurationDialog(pathToFile); } } Path::List DefinesAndIncludesManager::includesInBackground(const QString& path) const { Path::List includes; for (auto provider: m_backgroundProviders) { includes += provider->includesInBackground(path); } return includes; } Defines DefinesAndIncludesManager::definesInBackground(const QString& path) const { QHash defines; for (auto provider: m_backgroundProviders) { auto result = provider->definesInBackground(path); for (auto it = result.constBegin(); it != result.constEnd(); it++) { defines[it.key()] = it.value(); } } return defines; } bool DefinesAndIncludesManager::unregisterBackgroundProvider(IDefinesAndIncludesManager::BackgroundProvider* provider) { int idx = m_backgroundProviders.indexOf(provider); if (idx != -1) { m_backgroundProviders.remove(idx); return true; } return false; } void DefinesAndIncludesManager::registerBackgroundProvider(IDefinesAndIncludesManager::BackgroundProvider* provider) { Q_ASSERT(provider); if (m_backgroundProviders.contains(provider)) { return; } m_backgroundProviders.push_back(provider); } QString DefinesAndIncludesManager::parserArguments(KDevelop::ProjectBaseItem* item) const { if(!item){ return m_settings->defaultParserArguments(); } Q_ASSERT(QThread::currentThread() == qApp->thread()); auto cfg = item->project()->projectConfiguration().data(); return findConfigForItem(m_settings->readPaths(cfg), item).parserArguments; } int DefinesAndIncludesManager::perProjectConfigPages() const { return 1; } ConfigPage* DefinesAndIncludesManager::perProjectConfigPage(int number, const ProjectConfigOptions& options, QWidget* parent) { if (number == 0) { return new DefinesAndIncludesConfigPage(this, options, parent); } return nullptr; } +KDevelop::ConfigPage* DefinesAndIncludesManager::configPage(int number, QWidget* parent) +{ + return number == 0 ? new CompilersWidget(parent) : nullptr; +} + +int DefinesAndIncludesManager::configPages() const +{ + return 1; +} + #include "definesandincludesmanager.moc" diff --git a/languages/plugins/custom-definesandincludes/definesandincludesmanager.h b/languages/plugins/custom-definesandincludes/definesandincludesmanager.h index 8c7c92cb13..3e661917e7 100644 --- a/languages/plugins/custom-definesandincludes/definesandincludesmanager.h +++ b/languages/plugins/custom-definesandincludes/definesandincludesmanager.h @@ -1,79 +1,82 @@ /* * This file is part of KDevelop * * Copyright 2014 Sergey Kalinichev * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #ifndef CUSTOMDEFINESANDINCLUDESMANAGER_H #define CUSTOMDEFINESANDINCLUDESMANAGER_H #include #include #include #include #include "idefinesandincludesmanager.h" #include "compilerprovider/settingsmanager.h" class CompilerProvider; class NoProjectIncludePathsManager; /// @brief: Class for retrieving custom defines and includes. class DefinesAndIncludesManager : public KDevelop::IPlugin, public KDevelop::IDefinesAndIncludesManager { Q_OBJECT Q_INTERFACES( KDevelop::IDefinesAndIncludesManager ) public: explicit DefinesAndIncludesManager( QObject* parent, const QVariantList& args = QVariantList() ); ~DefinesAndIncludesManager() override; ///@return list of all custom defines for @p item KDevelop::Defines defines( KDevelop::ProjectBaseItem* item, Type type ) const override; ///@return list of all custom includes for @p item KDevelop::Path::List includes( KDevelop::ProjectBaseItem* item, Type type ) const override; KDevelop::Defines defines( const QString& path ) const override; KDevelop::Path::List includes( const QString& path ) const override; void registerProvider( Provider* provider ) override; bool unregisterProvider( Provider* provider ) override; KDevelop::Path::List includesInBackground( const QString& path ) const override; KDevelop::Defines definesInBackground(const QString& path) const override; void registerBackgroundProvider(BackgroundProvider* provider) override; bool unregisterBackgroundProvider(BackgroundProvider* provider) override; QString parserArguments(KDevelop::ProjectBaseItem* item) const override; void openConfigurationDialog( const QString& pathToFile ) override; int perProjectConfigPages() const override; KDevelop::ConfigPage* perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions& options, QWidget* parent) override; + KDevelop::ConfigPage* configPage(int number, QWidget *parent) override; + int configPages() const override; + private: QVector m_providers; QVector m_backgroundProviders; SettingsManager* m_settings; QScopedPointer m_noProjectIPM; }; #endif // CUSTOMDEFINESANDINCLUDESMANAGER_H diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/definesandincludesconfigpage.cpp b/languages/plugins/custom-definesandincludes/kcm_widget/definesandincludesconfigpage.cpp index 1acd778601..b186c13be7 100644 --- a/languages/plugins/custom-definesandincludes/kcm_widget/definesandincludesconfigpage.cpp +++ b/languages/plugins/custom-definesandincludes/kcm_widget/definesandincludesconfigpage.cpp @@ -1,118 +1,99 @@ /************************************************************************ * * * Copyright 2010 Andreas Pakulat * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 or version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ************************************************************************/ #include #include #include #include #include "projectpathswidget.h" #include "customdefinesandincludes.h" #include "../compilerprovider/compilerprovider.h" #include #include #include #include #include #include #include #include #include #include "definesandincludesconfigpage.h" DefinesAndIncludesConfigPage::DefinesAndIncludesConfigPage(KDevelop::IPlugin* plugin, const KDevelop::ProjectConfigOptions& options, QWidget* parent) : ProjectConfigPage(plugin, options, parent) { QVBoxLayout* layout = new QVBoxLayout( this ); configWidget = new ProjectPathsWidget( this ); configWidget->setProject( project() ); connect(configWidget, &ProjectPathsWidget::changed, this, &DefinesAndIncludesConfigPage::changed); layout->addWidget( configWidget ); } DefinesAndIncludesConfigPage::~DefinesAndIncludesConfigPage() { } void DefinesAndIncludesConfigPage::loadFrom( KConfig* cfg ) { configWidget->clear(); auto settings = SettingsManager::globalInstance(); - auto provider = settings->provider(); - configWidget->setCompilers(provider->compilers()); configWidget->setPaths( settings->readPaths( cfg ) ); } void DefinesAndIncludesConfigPage::saveTo(KConfig* cfg, KDevelop::IProject*) { auto settings = SettingsManager::globalInstance(); settings->writePaths( cfg, configWidget->paths() ); - auto provider = settings->provider(); - settings->writeUserDefinedCompilers(configWidget->compilers()); - - const auto& providerCompilers = provider->compilers(); - const auto& widgetCompilers = configWidget->compilers(); - for (auto compiler: providerCompilers) { - if (!widgetCompilers.contains(compiler)) { - provider->unregisterCompiler(compiler); - } - } - - for (auto compiler: widgetCompilers) { - if (!providerCompilers.contains(compiler)) { - provider->registerCompiler(compiler); - } - } - if ( settings->needToReparseCurrentProject( cfg ) ) { KDevelop::ICore::self()->projectController()->reparseProject(project(), true); } } void DefinesAndIncludesConfigPage::reset() { ProjectConfigPage::reset(); loadFrom(CustomDefinesAndIncludes::self()->config()); } void DefinesAndIncludesConfigPage::apply() { ProjectConfigPage::apply(); saveTo(CustomDefinesAndIncludes::self()->config(), project()); } QString DefinesAndIncludesConfigPage::name() const { return i18n("Language Support"); } QString DefinesAndIncludesConfigPage::fullName() const { return i18n("Configure Language Support"); } QIcon DefinesAndIncludesConfigPage::icon() const { return QIcon::fromTheme("kdevelop"); } diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.cpp b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.cpp index aec83c3929..86f9ca7493 100644 --- a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.cpp +++ b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.cpp @@ -1,327 +1,304 @@ /************************************************************************ * * * Copyright 2010 Andreas Pakulat * * Copyright 2014 Sergey Kalinichev * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ************************************************************************/ #include "projectpathswidget.h" #include #include #include #include #include #include #include #include #include "../compilerprovider/compilerprovider.h" -#include "compilerswidget.h" - #include "ui_projectpathswidget.h" #include "ui_batchedit.h" #include "projectpathsmodel.h" #include "debugarea.h" using namespace KDevelop; namespace { enum PageType { IncludesPage, DefinesPage, - CompilerPage, ParserArgumentsPage }; } ProjectPathsWidget::ProjectPathsWidget( QWidget* parent ) : QWidget(parent), ui(new Ui::ProjectPathsWidget), pathsModel(new ProjectPathsModel(this)) { ui->setupUi( this ); ui->addPath->setIcon(QIcon::fromTheme("list-add")); ui->removePath->setIcon(QIcon::fromTheme("list-remove")); // hack taken from kurlrequester, make the buttons a bit less in height so they better match the url-requester ui->addPath->setFixedHeight( ui->projectPaths->sizeHint().height() ); ui->removePath->setFixedHeight( ui->projectPaths->sizeHint().height() ); connect( ui->addPath, &QPushButton::clicked, this, &ProjectPathsWidget::addProjectPath ); connect( ui->removePath, &QPushButton::clicked, this, &ProjectPathsWidget::deleteProjectPath ); connect( ui->batchEdit, &QPushButton::clicked, this, &ProjectPathsWidget::batchEdit ); ui->projectPaths->setModel( pathsModel ); connect( ui->projectPaths, static_cast(&KComboBox::currentIndexChanged), this, &ProjectPathsWidget::projectPathSelected ); connect( pathsModel, &ProjectPathsModel::dataChanged, this, &ProjectPathsWidget::changed ); connect( pathsModel, &ProjectPathsModel::rowsInserted, this, &ProjectPathsWidget::changed ); connect( pathsModel, &ProjectPathsModel::rowsRemoved, this, &ProjectPathsWidget::changed ); connect( ui->compiler, static_cast(&QComboBox::activated), this, &ProjectPathsWidget::changed ); connect( ui->compiler, static_cast(&QComboBox::activated), this, &ProjectPathsWidget::changeCompilerForPath ); - connect(ui->compilersWidget, &CompilersWidget::compilerChanged, this, &ProjectPathsWidget::changed); - connect( ui->includesWidget, static_cast(&IncludesWidget::includesChanged), this, &ProjectPathsWidget::includesChanged ); connect( ui->definesWidget, static_cast(&DefinesWidget::definesChanged), this, &ProjectPathsWidget::definesChanged ); - connect(ui->compilersWidget, &CompilersWidget::compilerChanged, - this, &ProjectPathsWidget::userDefinedCompilerChanged); - connect(ui->languageParameters, &QTabWidget::currentChanged, this, &ProjectPathsWidget::tabChanged); connect(ui->parserWidget, &ParserWidget::changed, this, &ProjectPathsWidget::parserArgumentsChanged); + + tabChanged(IncludesPage); } QList ProjectPathsWidget::paths() const { return pathsModel->paths(); } void ProjectPathsWidget::setPaths( const QList& paths ) { bool b = blockSignals( true ); clear(); pathsModel->setPaths( paths ); blockSignals( b ); ui->projectPaths->setCurrentIndex(0); // at least a project root item is present projectPathSelected(0); ui->languageParameters->setCurrentIndex(0); updateEnablements(); + + // Set compilers + ui->compiler->clear(); + auto settings = SettingsManager::globalInstance(); + auto compilers = settings->provider()->compilers(); + for (int i = 0 ; i < compilers.count(); ++i) { + Q_ASSERT(compilers[i]); + if (!compilers[i]) { + continue; + } + ui->compiler->addItem(compilers[i]->name()); + QVariant val; val.setValue(compilers[i]); + ui->compiler->setItemData(i, val); + } } void ProjectPathsWidget::definesChanged( const Defines& defines ) { definesAndIncludesDebug() << "defines changed"; updatePathsModel( QVariant::fromValue(defines), ProjectPathsModel::DefinesDataRole ); } void ProjectPathsWidget::includesChanged( const QStringList& includes ) { definesAndIncludesDebug() << "includes changed"; updatePathsModel( includes, ProjectPathsModel::IncludesDataRole ); } void ProjectPathsWidget::parserArgumentsChanged() { updatePathsModel(ui->parserWidget->parserArguments(), ProjectPathsModel::ParserArgumentsRole); } void ProjectPathsWidget::updatePathsModel(const QVariant& newData, int role) { QModelIndex idx = pathsModel->index( ui->projectPaths->currentIndex(), 0, QModelIndex() ); if( idx.isValid() ) { bool b = pathsModel->setData( idx, newData, role ); if( b ) { emit changed(); } } } void ProjectPathsWidget::projectPathSelected( int index ) { if( index < 0 && pathsModel->rowCount() > 0 ) { index = 0; } Q_ASSERT(index >= 0); const QModelIndex midx = pathsModel->index( index, 0 ); ui->includesWidget->setIncludes( pathsModel->data( midx, ProjectPathsModel::IncludesDataRole ).toStringList() ); ui->definesWidget->setDefines( pathsModel->data( midx, ProjectPathsModel::DefinesDataRole ).value() ); Q_ASSERT(pathsModel->data(midx, ProjectPathsModel::CompilerDataRole).value()); ui->compiler->setCurrentText(pathsModel->data(midx, ProjectPathsModel::CompilerDataRole).value()->name()); ui->parserWidget->setParserArguments(pathsModel->data(midx, ProjectPathsModel::ParserArgumentsRole ).toString()); updateEnablements(); } void ProjectPathsWidget::clear() { bool sigDisabled = ui->projectPaths->blockSignals( true ); pathsModel->setPaths( QList() ); ui->includesWidget->clear(); ui->definesWidget->clear(); updateEnablements(); ui->projectPaths->blockSignals( sigDisabled ); } void ProjectPathsWidget::addProjectPath() { const QUrl directory = pathsModel->data(pathsModel->index(0, 0), ProjectPathsModel::FullUrlDataRole).value(); QFileDialog dlg(this, tr("Select Project Path"), directory.toLocalFile()); dlg.setFileMode(QFileDialog::Directory); dlg.setOption(QFileDialog::ShowDirsOnly); dlg.exec(); pathsModel->addPath(dlg.selectedUrls().value(0)); ui->projectPaths->setCurrentIndex(pathsModel->rowCount() - 1); updateEnablements(); } void ProjectPathsWidget::deleteProjectPath() { const QModelIndex idx = pathsModel->index( ui->projectPaths->currentIndex(), 0 ); if( KMessageBox::questionYesNo( this, i18n("Are you sure you want to remove the configuration for the path '%1'?", pathsModel->data( idx, Qt::DisplayRole ).toString() ), "Remove Path Configuration" ) == KMessageBox::Yes ) { pathsModel->removeRows( ui->projectPaths->currentIndex(), 1 ); } updateEnablements(); } void ProjectPathsWidget::setProject(KDevelop::IProject* w_project) { m_project = w_project; pathsModel->setProject( m_project ); ui->includesWidget->setProject( m_project ); } void ProjectPathsWidget::updateEnablements() { // Disable removal of the project root entry which is always first in the list ui->removePath->setEnabled( ui->projectPaths->currentIndex() > 0 ); } void ProjectPathsWidget::batchEdit() { Ui::BatchEdit be; QDialog dialog(this); be.setupUi(&dialog); const int index = qMax(ui->projectPaths->currentIndex(), 0); const QModelIndex midx = pathsModel->index(index, 0); if (!midx.isValid()) { return; } bool includesTab = ui->languageParameters->currentIndex() == 0; if (includesTab) { auto includes = pathsModel->data(midx, ProjectPathsModel::IncludesDataRole).toStringList(); be.textEdit->setPlainText(includes.join("\n")); dialog.setWindowTitle(i18n("Edit include directories/files")); } else { auto defines = pathsModel->data(midx, ProjectPathsModel::DefinesDataRole).value(); for (auto it = defines.constBegin(); it != defines.constEnd(); it++) { be.textEdit->append(it.key() + "=" + it.value()); } dialog.setWindowTitle(i18n("Edit defined macros")); } if (dialog.exec() != QDialog::Accepted) { return; } if (includesTab) { auto includes = be.textEdit->toPlainText().split('\n', QString::SkipEmptyParts); for (auto& s : includes) { s = s.trimmed(); } pathsModel->setData(midx, includes, ProjectPathsModel::IncludesDataRole); } else { auto list = be.textEdit->toPlainText().split('\n', QString::SkipEmptyParts); Defines defines; for (auto& d : list) { //This matches: a=b, a=, a QRegExp r("^([^=]+)(=(.*))?$"); if (!r.exactMatch(d)) { continue; } defines[r.cap(1).trimmed()] = r.cap(3).trimmed(); } pathsModel->setData(midx, QVariant::fromValue(defines), ProjectPathsModel::DefinesDataRole); } projectPathSelected(index); } void ProjectPathsWidget::setCurrentCompiler(const QString& name) { for (int i = 0 ; i < ui->compiler->count(); ++i) { if(ui->compiler->itemText(i) == name) { ui->compiler->setCurrentIndex(i); } } } CompilerPointer ProjectPathsWidget::currentCompiler() const { return ui->compiler->itemData(ui->compiler->currentIndex()).value(); } -void ProjectPathsWidget::setCompilers(const QVector< CompilerPointer >& compilers, bool updateCompilersModel) -{ - ui->compiler->clear(); - for (int i = 0 ; i < compilers.count(); ++i) { - Q_ASSERT(compilers[i]); - if (!compilers[i]) { - continue; - } - ui->compiler->addItem(compilers[i]->name()); - QVariant val; val.setValue(compilers[i]); - ui->compiler->setItemData(i, val); - } - - if (updateCompilersModel) { - ui->compilersWidget->setCompilers(compilers); - } -} - -QVector< CompilerPointer > ProjectPathsWidget::compilers() const -{ - return ui->compilersWidget->compilers(); -} - -void ProjectPathsWidget::userDefinedCompilerChanged() -{ - //TODO: if some compiler was deleted remove it from the pathsModel too. - auto current = currentCompiler()->name(); - setCompilers(ui->compilersWidget->compilers(), false); - setCurrentCompiler(current); -} - void ProjectPathsWidget::tabChanged(int idx) { - if (idx == CompilerPage || idx == ParserArgumentsPage) { + if (idx == ParserArgumentsPage) { ui->batchEdit->setVisible(false); ui->compilerBox->setVisible(true); } else { ui->batchEdit->setVisible(true); ui->compilerBox->setVisible(false); } } void ProjectPathsWidget::changeCompilerForPath() { for (int idx = 0; idx < pathsModel->rowCount(); idx++) { const QModelIndex midx = pathsModel->index(idx, 0); if (pathsModel->data(midx, Qt::DisplayRole) == ui->projectPaths->currentText()) { pathsModel->setData(midx, QVariant::fromValue(currentCompiler()), ProjectPathsModel::CompilerDataRole); break; } } } diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.h b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.h index 0be0ce06a7..91ed084997 100644 --- a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.h +++ b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.h @@ -1,94 +1,88 @@ /************************************************************************ * * * Copyright 2010 Andreas Pakulat * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 or version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see . * ************************************************************************/ #ifndef KDEVELOP_PROJECTMANAGERS_CUSTOM_BUILDSYSTEM_PROJECTPATHSWIDGET_H #define KDEVELOP_PROJECTMANAGERS_CUSTOM_BUILDSYSTEM_PROJECTPATHSWIDGET_H #include #include #include "../compilerprovider/icompiler.h" #include "../compilerprovider/settingsmanager.h" class KUrlRequester; namespace Ui { class ProjectPathsWidget; } namespace KDevelop { class IProject; } class ProjectPathsModel; class QItemSelection; class ProjectPathsWidget : public QWidget { Q_OBJECT public: ProjectPathsWidget( QWidget* parent = 0 ); void setProject(KDevelop::IProject* w_project); void setPaths( const QList& ); QList paths() const; void clear(); - void setCompilers(const QVector& compilers, bool updateCompilersModel = true); - - QVector compilers() const; - signals: void changed(); private: void setCurrentCompiler(const QString& name); CompilerPointer currentCompiler() const; private slots: // Handling of project-path combobox, add and remove buttons void projectPathSelected( int index ); void addProjectPath(); void deleteProjectPath(); void batchEdit(); void tabChanged(int); void changeCompilerForPath(); // Forward includes model changes into the pathsModel void includesChanged( const QStringList& includes ); // Forward defines model changes into the pathsModel void definesChanged( const KDevelop::Defines& defines ); - void userDefinedCompilerChanged(); - void parserArgumentsChanged(); private: Ui::ProjectPathsWidget* ui; ProjectPathsModel* pathsModel; KDevelop::IProject* m_project; // Enables/Disables widgets based on UI state/selection void updateEnablements(); void updatePathsModel( const QVariant& newData, int role ); }; #endif diff --git a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.ui b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.ui index 1ea16a6ade..a66086396e 100644 --- a/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.ui +++ b/languages/plugins/custom-definesandincludes/kcm_widget/projectpathswidget.ui @@ -1,313 +1,274 @@ ProjectPathsWidget 0 0 667 621 9 9 9 9 Configure which macros and include directories/files will be added to the parser during project parsing: Check this if you want the project to be reparsed to apply the changes. Reparse the project true Qt::Horizontal 40 20 0 0 0 0 <html><head/><body><p>Select compiler that will be used to retrieve standard include directories and defined macros.</p></body></html> Compiler for path <html><head/><body><p>Select compiler that will be used to retrieve standard include directories and defined macros.</p></body></html> Edit multiply includes/defines at the same time. &Batch Edit... 0 0 Add a new sub-project path entry. - - + .. false Delete current sub-project path entry. - - + .. true 0 8 - 3 + 0 Includes/Imports 0 0 0 0 0 8 Defines 0 0 0 0 0 0 8 - - - Compilers - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 8 - - - - - - C/C++ parser KComboBox QComboBox
kcombobox.h
DefinesWidget QWidget
kcm_widget/defineswidget.h
IncludesWidget QWidget
kcm_widget/includeswidget.h
- - CompilersWidget - QWidget -
kcm_widget/compilerswidget.h
-
ParserWidget QWidget
kcm_widget/parserwidget.h
1