diff --git a/shell/watcheddocumentset.cpp b/shell/watcheddocumentset.cpp index cbe2b2207..6572087f7 100644 --- a/shell/watcheddocumentset.cpp +++ b/shell/watcheddocumentset.cpp @@ -1,359 +1,361 @@ /* * KDevelop Problem Reporter * * Copyright 2010 Dmitry Risenberg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library 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 "watcheddocumentset.h" #include #include #include #include #include #include +#include #include #include #include namespace KDevelop { enum ActionFlag { DoUpdate = 1, DoEmit = 2 }; Q_DECLARE_FLAGS(ActionFlags, ActionFlag); Q_DECLARE_OPERATORS_FOR_FLAGS(ActionFlags); class WatchedDocumentSetPrivate : public QObject { Q_OBJECT public: using DocumentSet = WatchedDocumentSet::DocumentSet; explicit WatchedDocumentSetPrivate(WatchedDocumentSet* documentSet) : m_documentSet(documentSet) , m_showImports(false) { connect(DUChain::self(), &DUChain::updateReady, this, &WatchedDocumentSetPrivate::updateReady); } inline bool showImports() const { return m_showImports; } void setShowImports(bool showImports) { if (m_showImports == showImports) return; DocumentSet oldImports = m_imports; m_showImports = showImports; updateImports(); if (m_imports != oldImports) emit m_documentSet->changed(); } inline const DocumentSet& documents() const { return m_documents; } inline const DocumentSet& imports() const { return m_imports; } inline void doUpdate(ActionFlags flags) { if (flags.testFlag(DoUpdate)) updateImports(); if (flags.testFlag(DoEmit)) emit m_documentSet->changed(); } void setDocuments(const DocumentSet& docs, ActionFlags flags = nullptr) { m_documents = docs; doUpdate(flags); } void addDocument(const IndexedString& doc, ActionFlags flags = nullptr) { if (m_documents.contains(doc)) return; m_documents.insert(doc); doUpdate(flags); } void delDocument(const IndexedString& doc, ActionFlags flags = nullptr) { if (!m_documents.contains(doc)) return; m_documents.remove(doc); doUpdate(flags); } void updateImports() { if (!m_showImports) { if (!m_imports.isEmpty()) { m_imports.clear(); return; } return; } getImportsFromDUChain(); } private: void getImportsFromDU(TopDUContext* context, QSet& visitedContexts) { if (!context || visitedContexts.contains(context)) return; visitedContexts.insert(context); foreach (const DUContext::Import& ctx, context->importedParentContexts()) { TopDUContext* topCtx = dynamic_cast(ctx.context(nullptr)); if (topCtx) getImportsFromDU(topCtx, visitedContexts); } } void getImportsFromDUChain() { + KDevelop::DUChainReadLocker lock; QSet visitedContexts; m_imports.clear(); foreach (const IndexedString& doc, m_documents) { TopDUContext* ctx = DUChain::self()->chainForDocument(doc); getImportsFromDU(ctx, visitedContexts); visitedContexts.remove(ctx); } foreach (TopDUContext* ctx, visitedContexts) { m_imports.insert(ctx->url()); } } void updateReady(const IndexedString& doc, const ReferencedTopDUContext&) { if (!m_showImports || !m_documents.contains(doc)) return; DocumentSet oldImports = m_imports; updateImports(); if (m_imports != oldImports) emit m_documentSet->changed(); } WatchedDocumentSet* m_documentSet; DocumentSet m_documents; DocumentSet m_imports; bool m_showImports; }; WatchedDocumentSet::WatchedDocumentSet(QObject* parent) : QObject(parent) , d(new WatchedDocumentSetPrivate(this)) { } WatchedDocumentSet::~WatchedDocumentSet() { } bool WatchedDocumentSet::showImports() const { return d->showImports(); } void WatchedDocumentSet::setShowImports(bool showImports) { d->setShowImports(showImports); } void WatchedDocumentSet::setCurrentDocument(const IndexedString&) { } WatchedDocumentSet::DocumentSet WatchedDocumentSet::get() const { return d->documents(); } WatchedDocumentSet::DocumentSet WatchedDocumentSet::getImports() const { return d->imports(); } CurrentDocumentSet::CurrentDocumentSet(const IndexedString& document, QObject* parent) : WatchedDocumentSet(parent) { d->setDocuments({document}, DoUpdate); } void CurrentDocumentSet::setCurrentDocument(const IndexedString& url) { d->setDocuments({url}, DoUpdate | DoEmit); } ProblemScope CurrentDocumentSet::getScope() const { return CurrentDocument; } OpenDocumentSet::OpenDocumentSet(QObject* parent) : WatchedDocumentSet(parent) { foreach (IDocument* doc, ICore::self()->documentController()->openDocuments()) { d->addDocument(IndexedString(doc->url())); } d->updateImports(); connect(ICore::self()->documentController(), &IDocumentController::documentClosed, this, &OpenDocumentSet::documentClosed); connect(ICore::self()->documentController(), &IDocumentController::textDocumentCreated, this, &OpenDocumentSet::documentCreated); } void OpenDocumentSet::documentClosed(IDocument* doc) { d->delDocument(IndexedString(doc->url()), DoUpdate | DoEmit); } void OpenDocumentSet::documentCreated(IDocument* doc) { d->addDocument(IndexedString(doc->url()), DoUpdate | DoEmit); } ProblemScope OpenDocumentSet::getScope() const { return OpenDocuments; } ProjectSet::ProjectSet(QObject* parent) : WatchedDocumentSet(parent) { } void ProjectSet::fileAdded(ProjectFileItem* file) { d->addDocument(IndexedString(file->indexedPath()), DoUpdate | DoEmit); } void ProjectSet::fileRemoved(ProjectFileItem* file) { d->delDocument(IndexedString(file->indexedPath()), DoUpdate | DoEmit); } void ProjectSet::fileRenamed(const Path& oldFile, ProjectFileItem* newFile) { d->delDocument(IndexedString(oldFile.pathOrUrl())); d->addDocument(IndexedString(newFile->indexedPath()), DoUpdate | DoEmit); } void ProjectSet::trackProjectFiles(const IProject* project) { if (project) { // The implementation should derive from QObject somehow QObject* fileManager = dynamic_cast(project->projectFileManager()); if (fileManager) { // can't use new signal/slot syntax here, IProjectFileManager is no a QObject connect(fileManager, SIGNAL(fileAdded(ProjectFileItem*)), this, SLOT(fileAdded(ProjectFileItem*))); connect(fileManager, SIGNAL(fileRemoved(ProjectFileItem*)), this, SLOT(fileRemoved(ProjectFileItem*))); connect(fileManager, SIGNAL(fileRenamed(Path,ProjectFileItem*)), this, SLOT(fileRenamed(Path,ProjectFileItem*))); } } } CurrentProjectSet::CurrentProjectSet(const IndexedString& document, QObject* parent) : ProjectSet(parent) , m_currentProject(nullptr) { setCurrentDocumentInternal(document); } void CurrentProjectSet::setCurrentDocument(const IndexedString& url) { setCurrentDocumentInternal(url); } void CurrentProjectSet::setCurrentDocumentInternal(const IndexedString& url) { IProject* projectForUrl = ICore::self()->projectController()->findProjectForUrl(url.toUrl()); if (projectForUrl && projectForUrl != m_currentProject) { m_currentProject = projectForUrl; d->setDocuments(m_currentProject->fileSet()); d->addDocument(IndexedString(m_currentProject->path().toLocalFile()), DoUpdate | DoEmit); trackProjectFiles(m_currentProject); } } ProblemScope CurrentProjectSet::getScope() const { return CurrentProject; } AllProjectSet::AllProjectSet(QObject* parent) : ProjectSet(parent) { foreach(const IProject* project, ICore::self()->projectController()->projects()) { foreach (const IndexedString &indexedString, project->fileSet()) { d->addDocument(indexedString); } d->addDocument(IndexedString(project->path().toLocalFile())); trackProjectFiles(project); } d->updateImports(); emit changed(); } ProblemScope AllProjectSet::getScope() const { return AllProjects; } BypassSet::BypassSet(QObject* parent) : WatchedDocumentSet(parent) { } ProblemScope BypassSet::getScope() const { return BypassScopeFilter; } } #include "watcheddocumentset.moc" diff --git a/util/environmentselectionwidget.cpp b/util/environmentselectionwidget.cpp index 4a7d15b98..e2fd7d9e7 100644 --- a/util/environmentselectionwidget.cpp +++ b/util/environmentselectionwidget.cpp @@ -1,105 +1,98 @@ /* This file is part of KDevelop Copyright 2007 Dukju Ahn This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "environmentselectionwidget.h" #include "environmentgrouplist.h" #include "environmentselectionmodel.h" #include +#include #include #include namespace KDevelop { struct EnvironmentSelectionWidgetPrivate { KComboBox* comboBox; EnvironmentSelectionModel* model; EnvironmentSelectionWidget* owner; explicit EnvironmentSelectionWidgetPrivate( EnvironmentSelectionWidget* _owner ) : comboBox( new KComboBox( _owner ) ) , model( new EnvironmentSelectionModel( _owner ) ) , owner( _owner ) { comboBox->setModel( model ); comboBox->setEditable( false ); } }; EnvironmentSelectionWidget::EnvironmentSelectionWidget( QWidget *parent ) : QWidget( parent ), d( new EnvironmentSelectionWidgetPrivate( this ) ) { - // Taken from kdelibs/kdeui/dialogs/kconfigdialogmanager.cpp (no idea whether this is documented) - // Commits d44186bce4670d2985fb6aba8dba59bbd2c4c77a and 8edc1932ecc62370d9a31836dfa9b2bd0175a293 - // introduced a regression in kdelibs to fix problems running some apps against Qt4.8. Unfortunately - // this fix breaks exactly our use-case, which is to store the text-value in kconfig instead of - // the index even though the combobox is editable. Since that change the special combobox-code in - // kconfigdialogmanager.cpp is run before check a user-property and hence our user-property is - // ignored. Setting this special kcfg_property to the name of our user-property again overrides - // the hardcoded combobox-behaviour - until the next one breaks things in kdelibs :| - setProperty("kcfg_property", QByteArray("currentProfile")); + KConfigDialogManager::changedMap()->insert("KDevelop::EnvironmentSelectionWidget", SIGNAL(currentProfileChanged(QString))); setLayout( new QHBoxLayout( this ) ); layout()->addWidget( d->comboBox ); layout()->setMargin( 0 ); setCurrentProfile( QString() ); // select the default profile connect(d->comboBox, &QComboBox::currentTextChanged, this, &EnvironmentSelectionWidget::currentProfileChanged); } EnvironmentSelectionWidget::~EnvironmentSelectionWidget() { delete d; } QString EnvironmentSelectionWidget::currentProfile() const { return d->model->index( d->comboBox->currentIndex(), 0 ).data( Qt::EditRole ).toString(); } void EnvironmentSelectionWidget::setCurrentProfile( const QString& profile ) { d->comboBox->setCurrentIndex( d->comboBox->findData( profile, Qt::EditRole ) ); emit currentProfileChanged(profile); } void EnvironmentSelectionWidget::reconfigure() { QString selectedProfile = currentProfile(); d->model->reload(); setCurrentProfile( d->model->reloadSelectedItem( selectedProfile ) ); } QString EnvironmentSelectionWidget::effectiveProfileName() const { return d->model->index( d->comboBox->currentIndex(), 0 ).data( EnvironmentSelectionModel::EffectiveNameRole ).toString(); } EnvironmentGroupList EnvironmentSelectionWidget::environment() const { return d->model->environment(); } }