diff --git a/language/codegen/applychangeswidget.cpp b/language/codegen/applychangeswidget.cpp index c6460db12e..d339dfd2f7 100644 --- a/language/codegen/applychangeswidget.cpp +++ b/language/codegen/applychangeswidget.cpp @@ -1,215 +1,215 @@ /* Copyright 2008 Aleix Pol * Copyright 2009 Ramón Zarazúa * * 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 "applychangeswidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "coderepresentation.h" #include #include #include #include #include #include #include #include namespace KDevelop { class ApplyChangesWidgetPrivate { public: ApplyChangesWidgetPrivate(ApplyChangesWidget * p) : parent(p), m_index(0) {} ~ApplyChangesWidgetPrivate() { qDeleteAll(m_temps); } void createEditPart(const KDevelop::IndexedString& url); ApplyChangesWidget * const parent; int m_index; QList m_editParts; QList m_temps; QList m_files; QTabWidget * m_documentTabs; QLabel* m_info; }; ApplyChangesWidget::ApplyChangesWidget(QWidget* parent) : QDialog(parent), d(new ApplyChangesWidgetPrivate(this)) { setSizeGripEnabled(true); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); auto mainLayout = new QVBoxLayout(this); auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &ApplyChangesWidget::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &ApplyChangesWidget::reject); QWidget* w=new QWidget(this); d->m_info=new QLabel(w); d->m_documentTabs = new QTabWidget(w); connect(d->m_documentTabs, &QTabWidget::currentChanged, this, &ApplyChangesWidget::indexChanged); QVBoxLayout* l = new QVBoxLayout(w); l->addWidget(d->m_info); l->addWidget(d->m_documentTabs); mainLayout->addWidget(w); mainLayout->addWidget(buttonBox); resize(QSize(800, 400)); } ApplyChangesWidget::~ApplyChangesWidget() { delete d; } bool ApplyChangesWidget::hasDocuments() const { return d->m_editParts.size() > 0; } KTextEditor::Document* ApplyChangesWidget::document() const { return qobject_cast(d->m_editParts[d->m_index]); } void ApplyChangesWidget::setInformation(const QString & info) { d->m_info->setText(info); } void ApplyChangesWidget::addDocuments(const IndexedString & original) { int idx=d->m_files.indexOf(original); if(idx<0) { QWidget * w = new QWidget; d->m_documentTabs->addTab(w, original.str()); d->m_documentTabs->setCurrentWidget(w); d->m_files.insert(d->m_index, original); d->createEditPart(original); } else { d->m_index=idx; } } bool ApplyChangesWidget::applyAllChanges() { /// @todo implement safeguard in case a file saving fails bool ret = true; for(int i = 0; i < d->m_files.size(); ++i ) if(d->m_editParts[i]->saveAs(d->m_files[i].toUrl())) { IDocument* doc = ICore::self()->documentController()->documentForUrl(d->m_files[i].toUrl()); if(doc && doc->state()==IDocument::Dirty) doc->reload(); } else ret = false; return ret; } } Q_DECLARE_METATYPE(KTextEditor::Range) namespace KDevelop { void ApplyChangesWidgetPrivate::createEditPart(const IndexedString & file) { QWidget * widget = m_documentTabs->currentWidget(); Q_ASSERT(widget); QVBoxLayout *m=new QVBoxLayout(widget); QSplitter *v=new QSplitter(widget); m->addWidget(v); QUrl url = file.toUrl(); QMimeType mimetype = QMimeDatabase().mimeTypeForUrl(url); KParts::ReadWritePart* part=KMimeTypeTrader::self()->createPartInstanceFromQuery(mimetype.name(), widget, widget); KTextEditor::Document* document=qobject_cast(part); Q_ASSERT(document); Q_ASSERT(document->action("file_save")); document->action("file_save")->setEnabled(false); m_editParts.insert(m_index, part); //Open the best code representation, even if it is artificial CodeRepresentation::Ptr repr = createCodeRepresentation(file); if(!repr->fileExists()) { const auto templateName = QDir::tempPath() + QLatin1Char('/') + url.fileName().split('.').last(); QTemporaryFile * temp(new QTemporaryFile(templateName)); temp->open(); temp->write(repr->text().toUtf8()); temp->close(); url = QUrl::fromLocalFile(temp->fileName()); m_temps << temp; } m_editParts[m_index]->openUrl(url); v->addWidget(m_editParts[m_index]->widget()); v->setSizes(QList() << 400 << 100); } void ApplyChangesWidget::indexChanged(int newIndex) { Q_ASSERT(newIndex != -1); d->m_index = newIndex; } void ApplyChangesWidget::updateDiffView(int index) { int prevIndex = d->m_index; d->m_index = index == -1 ? d->m_index : index; d->m_index = prevIndex; } } diff --git a/outputview/outputjob.cpp b/outputview/outputjob.cpp index fe9a984f03..c99e6ebb98 100644 --- a/outputview/outputjob.cpp +++ b/outputview/outputjob.cpp @@ -1,173 +1,175 @@ /* This file is part of KDevelop Copyright 2007-2008 Hamish Rodda 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 "outputjob.h" #include #include #include "interfaces/icore.h" #include "interfaces/iplugincontroller.h" #include "outputview/ioutputview.h" using namespace KDevelop; OutputJob::OutputJob(QObject* parent, OutputJobVerbosity verbosity) : KJob(parent) , m_standardToolView(-1) , m_type(IOutputView::OneView) , m_behaviours(IOutputView::AllowUserClose) , m_killJobOnOutputClose(true) , m_verbosity(verbosity) , m_outputId(-1) , m_outputDelegate(0) { } void OutputJob::startOutput() { IPlugin* i = ICore::self()->pluginController()->pluginForExtension("org.kdevelop.IOutputView"); if( i ) { KDevelop::IOutputView* view = i->extension(); if( view ) { int tvid; if (m_standardToolView != -1) { tvid = view->standardToolView( static_cast(m_standardToolView) ); } else { tvid = view->registerToolView(m_toolTitle, m_type, m_toolIcon); } if (m_title.isEmpty()) m_title = objectName(); m_outputId = view->registerOutputInToolView( tvid, m_title, m_behaviours ); if (!m_outputModel) { m_outputModel = new QStandardItemModel(0); } // Keep the item model around after the job is gone view->setModel(m_outputId, m_outputModel); if (!m_outputDelegate) { m_outputDelegate = new QItemDelegate(0); } view->setDelegate(m_outputId, m_outputDelegate); - if (m_killJobOnOutputClose) + if (m_killJobOnOutputClose) { + // can't use qt5 signal slot syntax here, IOutputView is no a QObject connect(i, SIGNAL(outputRemoved(int,int)), this, SLOT(outputViewRemoved(int,int))); + } if (m_verbosity == OutputJob::Verbose) view->raiseOutput(m_outputId); } } } void OutputJob::outputViewRemoved(int toolViewId, int id) { Q_UNUSED(toolViewId); if (id == m_outputId && m_killJobOnOutputClose) { // Make sure that the job emits result signal as the job // might be used in composite jobs and that one depends // on result being emitted to know whether a subjob // is done. kill( KJob::EmitResult ); } } void KDevelop::OutputJob::setTitle(const QString & title) { m_title = title; if (m_outputId >= 0 && m_standardToolView >= 0) { IPlugin* i = ICore::self()->pluginController()->pluginForExtension("org.kdevelop.IOutputView"); if( i ) { KDevelop::IOutputView* view = i->extension(); if( view ) { view->setTitle(m_outputId, title); } } } } void KDevelop::OutputJob::setViewType(IOutputView::ViewType type) { m_type = type; } void KDevelop::OutputJob::setBehaviours(IOutputView::Behaviours behaviours) { m_behaviours = behaviours; } void KDevelop::OutputJob::setKillJobOnOutputClose(bool killJobOnOutputClose) { m_killJobOnOutputClose = killJobOnOutputClose; } void KDevelop::OutputJob::setModel(QAbstractItemModel * model) { m_outputModel = model; } void KDevelop::OutputJob::setDelegate(QAbstractItemDelegate * delegate) { m_outputDelegate = delegate; } QAbstractItemModel * KDevelop::OutputJob::model() const { return m_outputModel; } void KDevelop::OutputJob::setStandardToolView(IOutputView::StandardToolView standard) { m_standardToolView = standard; } void OutputJob::setToolTitle(const QString& title) { m_toolTitle = title; } void OutputJob::setToolIcon(const QIcon& icon) { m_toolIcon = icon; } int OutputJob::outputId() const { return m_outputId; } OutputJob::OutputJobVerbosity OutputJob::verbosity() const { return m_verbosity; } void OutputJob::setVerbosity(OutputJob::OutputJobVerbosity verbosity) { m_verbosity = verbosity; } diff --git a/plugins/externalscript/editexternalscript.cpp b/plugins/externalscript/editexternalscript.cpp index 3b05f215c5..6c52b06636 100644 --- a/plugins/externalscript/editexternalscript.cpp +++ b/plugins/externalscript/editexternalscript.cpp @@ -1,198 +1,198 @@ /* This plugin is part of KDevelop. Copyright (C) 2010 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "editexternalscript.h" #include "externalscriptitem.h" #include #include #include #include #include #include #include EditExternalScript::EditExternalScript( ExternalScriptItem* item, QWidget* parent, Qt::WindowFlags flags ) : QDialog( parent, flags ), m_item( item ) { setupUi(this); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &EditExternalScript::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &EditExternalScript::reject); shortcutWidget->layout()->setMargin(0); //BEGIN setup tooltips QString tooltip = i18n( "

Defines the command that should be executed when this script is run. Basic shell features of your platform should be available.

\n" "

There are a few placeholders you can use in the command:

\n" "
\n" "
%u
\n" "
Gets replaced by the URL of the active document.
\n" "
%f
\n" "
Gets replaced by the local filepath to the active document.
\n" "
%n
\n" "
Gets replaced by the name of the active document, including its extension.
\n" "
%b
\n" "
Gets replaced by the name of the active document without its extension.
\n" "
%d
\n" "
Gets replaced by the path to the directory of the active document.
\n" "
%p
\n" "
Gets replaced by the URL to the project of the active document.
\n" "
%s
\n" "
Gets replaced with the shell escaped contents of the selection in the active document.
\n" "
%i
\n" "
Gets replaced with the PID of the currently running KDevelop process.
\n" "
\n" "

NOTE: It is your responsibility to prevent running hazardous commands that could lead to data loss.

\n" ); commandEdit->setToolTip( tooltip ); commandLabel->setToolTip( tooltip ); tooltip = i18n( "

Defines what the external script should get as input (via STDIN).

" ); stdinCombo->setToolTip( tooltip ); stdinLabel->setToolTip( tooltip ); tooltip = i18n( "

Defines what should be done with the output (i.e. STDOUT) of the script.

" ); stdoutCombo->setToolTip( tooltip ); stdoutLabel->setToolTip( tooltip ); tooltip = i18n( "

Defines what should be done with the errors (i.e. STDERR) of the script.

" "

Note: if the action is the same as that chosen for the output, the channels will be merged " "and handled together.

" ); stderrCombo->setToolTip( tooltip ); stderrLabel->setToolTip( tooltip ); tooltip = i18n( "

Defines the name of the script. Just for displaying purposes.

" ); nameEdit->setToolTip( tooltip ); nameLabel->setToolTip( tooltip ); tooltip = i18n( "

Defines the shortcut(s) you can use to execute this external script.

" ); shortcutLabel->setToolTip( tooltip ); shortcutWidget->setToolTip( tooltip ); tooltip = i18n( "

Defines whether documents should be saved before the script gets executed.

" ); saveLabel->setToolTip( tooltip ); saveCombo->setToolTip( tooltip ); tooltip = i18n( "

Defines whether the output of the script should be shown in a toolview.

" ); showOutputBox->setToolTip( tooltip ); tooltip = i18n( "

Defines what type of filtering should be applied to the output. E.g. to indicate errors by red text.

" ); outputFilterLabel->setToolTip( tooltip ); outputFilterCombo->setToolTip( tooltip ); //END setup tooltips //BEGIN item to UI copying if ( item->text().isEmpty() ) { setWindowTitle( i18n("Create new external script") ); } else { setWindowTitle( i18n("Edit external script '%1'", item->text()) ); } nameEdit->setText( item->text() ); commandEdit->setText( item->command() ); stdinCombo->setCurrentIndex( item->inputMode() ); stdoutCombo->setCurrentIndex( item->outputMode() ); stderrCombo->setCurrentIndex( item->errorMode() ); saveCombo->setCurrentIndex( item->saveMode() ); shortcutWidget->setShortcut( item->action()->shortcuts() ); showOutputBox->setChecked( item->showOutput() ); outputFilterCombo->setCurrentIndex( item->filterMode() ); //END item to UI copying validate(); nameEdit->setFocus(); - connect(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(save())); - connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(save())); + connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &EditExternalScript::save); + connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &EditExternalScript::save); connect(nameEdit, &QLineEdit::textEdited, this, &EditExternalScript::validate); connect(commandEdit, &QLineEdit::textEdited, this, &EditExternalScript::validate); } EditExternalScript::~EditExternalScript() { } void EditExternalScript::save() { m_item->setText( nameEdit->text() ); m_item->setCommand( commandEdit->text() ); ExternalScriptItem::InputMode inputMode = static_cast( stdinCombo->currentIndex() ); m_item->setInputMode( inputMode ); ExternalScriptItem::OutputMode outputMode = static_cast( stdoutCombo->currentIndex() ); m_item->setOutputMode( outputMode ); ExternalScriptItem::ErrorMode errorMode = static_cast( stderrCombo->currentIndex() ); m_item->setErrorMode( errorMode ); ExternalScriptItem::SaveMode saveMode = static_cast( saveCombo->currentIndex() ); m_item->setSaveMode( saveMode ); m_item->setShowOutput( showOutputBox->isChecked() ); m_item->setFilterMode( outputFilterCombo->currentIndex() ); m_item->action()->setShortcuts( shortcutWidget->shortcut() ); } void EditExternalScript::validate() { bool valid = !nameEdit->text().isEmpty() && !commandEdit->text().isEmpty(); if ( valid ) { KShell::Errors errors = KShell::NoError; KShell::splitArgs( commandEdit->text(), KShell::TildeExpand, &errors ); valid = errors == KShell::NoError; } buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); buttonBox->button(QDialogButtonBox::Apply)->setEnabled(valid); } // kate: indent-mode cstyle; space-indent on; indent-width 2; replace-tabs on; diff --git a/plugins/filetemplates/templateclassassistant.cpp b/plugins/filetemplates/templateclassassistant.cpp index 4e463c0f61..1e569531cc 100644 --- a/plugins/filetemplates/templateclassassistant.cpp +++ b/plugins/filetemplates/templateclassassistant.cpp @@ -1,590 +1,590 @@ /* This file is part of KDevelop Copyright 2012 Miha Čančula 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 "templateclassassistant.h" #include "templateselectionpage.h" #include "templateoptionspage.h" #include "classmemberspage.h" #include "classidentifierpage.h" #include "overridespage.h" #include "licensepage.h" #include "outputpage.h" #include "testcasespage.h" #include "defaultcreateclasshelper.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define REMOVE_PAGE(name) \ if (d->name##Page) \ { \ removePage(d->name##Page); \ d->name##Page = 0; \ d->name##PageWidget = 0; \ } #define ZERO_PAGE(name) \ d->name##Page = 0; \ d->name##PageWidget = 0; using namespace KDevelop; class KDevelop::TemplateClassAssistantPrivate { public: TemplateClassAssistantPrivate(const QUrl& baseUrl); ~TemplateClassAssistantPrivate(); void addFilesToTarget (const QHash& fileUrls); KPageWidgetItem* templateSelectionPage; KPageWidgetItem* classIdentifierPage; KPageWidgetItem* overridesPage; KPageWidgetItem* membersPage; KPageWidgetItem* testCasesPage; KPageWidgetItem* licensePage; KPageWidgetItem* templateOptionsPage; KPageWidgetItem* outputPage; KPageWidgetItem* dummyPage; TemplateSelectionPage* templateSelectionPageWidget; ClassIdentifierPage* classIdentifierPageWidget; OverridesPage* overridesPageWidget; ClassMembersPage* membersPageWidget; TestCasesPage* testCasesPageWidget; LicensePage* licensePageWidget; TemplateOptionsPage* templateOptionsPageWidget; OutputPage* outputPageWidget; QUrl baseUrl; SourceFileTemplate fileTemplate; ICreateClassHelper* helper; TemplateClassGenerator* generator; TemplateRenderer* renderer; QString type; QVariantHash templateOptions; }; TemplateClassAssistantPrivate::TemplateClassAssistantPrivate(const QUrl& baseUrl) : baseUrl(baseUrl) , helper(0) , generator(0) , renderer(0) { } TemplateClassAssistantPrivate::~TemplateClassAssistantPrivate() { delete helper; if (generator) { delete generator; } else { // if we got a generator, it should keep ownership of the renderer // otherwise, we created a templaterenderer on our own delete renderer; } } void TemplateClassAssistantPrivate::addFilesToTarget (const QHash< QString, QUrl >& fileUrls) { // Add the generated files to a target, if one is found QUrl url = baseUrl; if (!url.isValid()) { // This was probably not launched from the project manager view // Still, we try to find the common URL where the generated files are located if (!fileUrls.isEmpty()) { url = fileUrls.constBegin().value().adjusted(QUrl::RemoveFilename); } } qCDebug(PLUGIN_FILETEMPLATES) << "Searching for targets with URL" << url; IProject* project = ICore::self()->projectController()->findProjectForUrl(url); if (!project || !project->buildSystemManager()) { qCDebug(PLUGIN_FILETEMPLATES) << "No suitable project found"; return; } QList items = project->itemsForUrl(url); if (items.isEmpty()) { qCDebug(PLUGIN_FILETEMPLATES) << "No suitable project items found"; return; } QList targets; ProjectTargetItem* target = 0; foreach (ProjectBaseItem* item, items) { if (ProjectTargetItem* target = item->target()) { targets << target; } } if (targets.isEmpty()) { // If no target was explicitly found yet, try all the targets in the current folder foreach (ProjectBaseItem* item, items) { targets << item->targetList(); } } if (targets.isEmpty()) { // If still no targets, we traverse the tree up to the first directory with targets ProjectBaseItem* item = items.first()->parent(); while (targets.isEmpty() && item) { targets = item->targetList(); item = item->parent(); } } if (targets.size() == 1) { qCDebug(PLUGIN_FILETEMPLATES) << "Only one candidate target," << targets.first()->text() << ", using it"; target = targets.first(); } else if (targets.size() > 1) { // More than one candidate target, show the chooser dialog QPointer d = new QDialog; auto mainLayout = new QVBoxLayout(d); mainLayout->addWidget(new QLabel(i18n("Choose one target to add the file or cancel if you do not want to do so."))); QListWidget* targetsWidget = new QListWidget(d); targetsWidget->setSelectionMode(QAbstractItemView::SingleSelection); foreach(ProjectTargetItem* target, targets) { targetsWidget->addItem(target->text()); } targetsWidget->setCurrentRow(0); mainLayout->addWidget(targetsWidget); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - d->connect(buttonBox, SIGNAL(accepted()), d, SLOT(accept())); - d->connect(buttonBox, SIGNAL(rejected()), d, SLOT(reject())); + d->connect(buttonBox, &QDialogButtonBox::accepted, d.data(), &QDialog::accept); + d->connect(buttonBox, &QDialogButtonBox::rejected, d.data(), &QDialog::reject); mainLayout->addWidget(buttonBox); if(d->exec() == QDialog::Accepted) { if (!targetsWidget->selectedItems().isEmpty()) { target = targets[targetsWidget->currentRow()]; } else { qCDebug(PLUGIN_FILETEMPLATES) << "Did not select anything, not adding to a target"; return; } } else { qCDebug(PLUGIN_FILETEMPLATES) << "Canceled select target dialog, not adding to a target"; return; } } else { // No target, not doing anything qCDebug(PLUGIN_FILETEMPLATES) << "No possible targets for URL" << url; return; } Q_ASSERT(target); QList fileItems; foreach (const QUrl &fileUrl, fileUrls) { foreach (ProjectBaseItem* item, project->itemsForUrl(KIO::upUrl(fileUrl))) { if (ProjectFolderItem* folder = item->folder()) { ///FIXME: use Path instead of QUrl in the template class assistant if (ProjectFileItem* file = project->projectFileManager()->addFile(Path(fileUrl), folder)) { fileItems << file; break; } } } } if (!fileItems.isEmpty()) { project->buildSystemManager()->addFilesToTarget(fileItems, target); } } TemplateClassAssistant::TemplateClassAssistant(QWidget* parent, const QUrl& baseUrl) : KAssistantDialog(parent) , d(new TemplateClassAssistantPrivate(baseUrl)) { ZERO_PAGE(templateSelection) ZERO_PAGE(templateOptions) ZERO_PAGE(members) ZERO_PAGE(classIdentifier) ZERO_PAGE(overrides) ZERO_PAGE(license) ZERO_PAGE(output) ZERO_PAGE(testCases) setup(); } TemplateClassAssistant::~TemplateClassAssistant() { delete d; } void TemplateClassAssistant::setup() { if (d->baseUrl.isValid()) { setWindowTitle(xi18n("Create Files from Template in %1", d->baseUrl.toDisplayString())); } else { setWindowTitle(i18n("Create Files from Template")); } d->templateSelectionPageWidget = new TemplateSelectionPage(this); connect(this, &TemplateClassAssistant::accepted, d->templateSelectionPageWidget, &TemplateSelectionPage::saveConfig); d->templateSelectionPage = addPage(d->templateSelectionPageWidget, i18n("Language and Template")); d->templateSelectionPage->setIcon(QIcon::fromTheme("project-development-new-template")); d->dummyPage = addPage(new QWidget(this), QLatin1String("Dummy Page")); // showButton(QDialog::Help, false); } void TemplateClassAssistant::templateChosen(const QString& templateDescription) { d->fileTemplate.setTemplateDescription(templateDescription); d->type = d->fileTemplate.type(); d->generator = 0; if (!d->fileTemplate.isValid()) { return; } qCDebug(PLUGIN_FILETEMPLATES) << "Selected template" << templateDescription << "of type" << d->type; removePage(d->dummyPage); if (d->baseUrl.isValid()) { setWindowTitle(xi18n("Create Files from Template %1 in %2", d->fileTemplate.name(), d->baseUrl.toDisplayString())); } else { setWindowTitle(xi18n("Create Files from Template %1", d->fileTemplate.name())); } if (d->type == "Class") { d->classIdentifierPageWidget = new ClassIdentifierPage(this); d->classIdentifierPage = addPage(d->classIdentifierPageWidget, i18n("Class Basics")); d->classIdentifierPage->setIcon(QIcon::fromTheme("classnew")); connect(d->classIdentifierPageWidget, &ClassIdentifierPage::isValid, this, &TemplateClassAssistant::setCurrentPageValid); setValid(d->classIdentifierPage, false); d->overridesPageWidget = new OverridesPage(this); d->overridesPage = addPage(d->overridesPageWidget, i18n("Override Methods")); d->overridesPage->setIcon(QIcon::fromTheme("code-class")); setValid(d->overridesPage, true); d->membersPageWidget = new ClassMembersPage(this); d->membersPage = addPage(d->membersPageWidget, i18n("Class Members")); d->membersPage->setIcon(QIcon::fromTheme("field")); setValid(d->membersPage, true); d->helper = 0; QString languageName = d->fileTemplate.languageName(); ILanguage* language = ICore::self()->languageController()->language(languageName); if (language && language->languageSupport()) { d->helper = language->languageSupport()->createClassHelper(); } if (!d->helper) { qCDebug(PLUGIN_FILETEMPLATES) << "No class creation helper for language" << languageName; d->helper = new DefaultCreateClassHelper; } d->generator = d->helper->createGenerator(d->baseUrl); Q_ASSERT(d->generator); d->generator->setTemplateDescription(d->fileTemplate); d->renderer = d->generator->renderer(); } else { if (d->type == "Test") { d->testCasesPageWidget = new TestCasesPage(this); d->testCasesPage = addPage(d->testCasesPageWidget, i18n("Test Cases")); connect(d->testCasesPageWidget, &TestCasesPage::isValid, this, &TemplateClassAssistant::setCurrentPageValid); setValid(d->testCasesPage, false); } d->renderer = new TemplateRenderer; d->renderer->setEmptyLinesPolicy(TemplateRenderer::TrimEmptyLines); } d->licensePageWidget = new LicensePage(this); d->licensePage = addPage(d->licensePageWidget, i18n("License")); d->licensePage->setIcon(QIcon::fromTheme("text-x-copying")); setValid(d->licensePage, true); d->outputPageWidget = new OutputPage(this); d->outputPageWidget->prepareForm(d->fileTemplate); d->outputPage = addPage(d->outputPageWidget, i18n("Output")); d->outputPage->setIcon(QIcon::fromTheme("document-save")); connect(d->outputPageWidget, &OutputPage::isValid, this, &TemplateClassAssistant::setCurrentPageValid); setValid(d->outputPage, false); if (d->fileTemplate.hasCustomOptions()) { qCDebug(PLUGIN_FILETEMPLATES) << "Class generator has custom options"; d->templateOptionsPageWidget = new TemplateOptionsPage(this); d->templateOptionsPage = insertPage(d->outputPage, d->templateOptionsPageWidget, i18n("Template Options")); } setCurrentPage(d->templateSelectionPage); } void TemplateClassAssistant::next() { qCDebug(PLUGIN_FILETEMPLATES) << currentPage()->name() << currentPage()->header(); if (currentPage() == d->templateSelectionPage) { // We have chosen the template // Depending on the template's language, we can now create a helper QString description = d->templateSelectionPageWidget->selectedTemplate(); templateChosen(description); if (!d->fileTemplate.isValid()) { return; } } else if (currentPage() == d->classIdentifierPage) { d->generator->setIdentifier(d->classIdentifierPageWidget->identifier()); d->generator->setBaseClasses(d->classIdentifierPageWidget->inheritanceList()); } else if (currentPage() == d->overridesPage) { ClassDescription desc = d->generator->description(); desc.methods.clear(); foreach (const DeclarationPointer& declaration, d->overridesPageWidget->selectedOverrides()) { desc.methods << FunctionDescription(declaration); } d->generator->setDescription(desc); } else if (currentPage() == d->membersPage) { ClassDescription desc = d->generator->description(); desc.members = d->membersPageWidget->members(); d->generator->setDescription(desc); } else if (currentPage() == d->licensePage) { if (d->generator) { d->generator->setLicense(d->licensePageWidget->license()); } else { d->renderer->addVariable("license", d->licensePageWidget->license()); } } else if (d->templateOptionsPage && (currentPage() == d->templateOptionsPage)) { if (d->generator) { d->generator->addVariables(d->templateOptionsPageWidget->templateOptions()); } else { d->renderer->addVariables(d->templateOptionsPageWidget->templateOptions()); } } else if (currentPage() == d->testCasesPage) { d->renderer->addVariable("name", d->testCasesPageWidget->name()); d->renderer->addVariable("testCases", d->testCasesPageWidget->testCases()); } KAssistantDialog::next(); if (currentPage() == d->classIdentifierPage) { d->classIdentifierPageWidget->setInheritanceList(d->fileTemplate.defaultBaseClasses()); } else if (currentPage() == d->membersPage) { d->membersPageWidget->setMembers(d->generator->description().members); } else if (currentPage() == d->overridesPage) { d->overridesPageWidget->clear(); d->overridesPageWidget->addCustomDeclarations(i18n("Default"), d->helper->defaultMethods(d->generator->name())); d->overridesPageWidget->addBaseClasses(d->generator->directBaseClasses(), d->generator->allBaseClasses()); } else if (d->templateOptionsPage && (currentPage() == d->templateOptionsPage)) { d->templateOptionsPageWidget->load(d->fileTemplate, d->renderer); } else if (currentPage() == d->outputPage) { d->outputPageWidget->loadFileTemplate(d->fileTemplate, d->baseUrl, d->renderer); } } void TemplateClassAssistant::back() { KAssistantDialog::back(); if (currentPage() == d->templateSelectionPage) { REMOVE_PAGE(classIdentifier) REMOVE_PAGE(overrides) REMOVE_PAGE(members) REMOVE_PAGE(testCases) REMOVE_PAGE(output) REMOVE_PAGE(templateOptions) REMOVE_PAGE(license) delete d->helper; d->helper = 0; if (d->generator) { delete d->generator; } else { delete d->renderer; } d->generator = 0; d->renderer = 0; if (d->baseUrl.isValid()) { setWindowTitle(xi18n("Create Files from Template in %1", d->baseUrl.toDisplayString())); } else { setWindowTitle(i18n("Create Files from Template")); } d->dummyPage = addPage(new QWidget(this), QLatin1String("Dummy Page")); } } void TemplateClassAssistant::accept() { // next() is not called for the last page (when the user clicks Finish), so we have to set output locations here QHash fileUrls = d->outputPageWidget->fileUrls(); QHash filePositions = d->outputPageWidget->filePositions(); DocumentChangeSet changes; if (d->generator) { QHash::const_iterator it = fileUrls.constBegin(); for (; it != fileUrls.constEnd(); ++it) { d->generator->setFileUrl(it.key(), it.value()); d->generator->setFilePosition(it.key(), filePositions.value(it.key())); } d->generator->addVariables(d->templateOptions); changes = d->generator->generate(); } else { changes = d->renderer->renderFileTemplate(d->fileTemplate, d->baseUrl, fileUrls); } d->addFilesToTarget(fileUrls); changes.applyAllChanges(); // Open the generated files in the editor foreach (const QUrl& url, fileUrls) { ICore::self()->documentController()->openDocument(url); } KAssistantDialog::accept(); } void TemplateClassAssistant::setCurrentPageValid(bool valid) { setValid(currentPage(), valid); } QUrl TemplateClassAssistant::baseUrl() const { return d->baseUrl; } diff --git a/plugins/git/stashmanagerdialog.cpp b/plugins/git/stashmanagerdialog.cpp index 7989bae0fc..1fb939409e 100644 --- a/plugins/git/stashmanagerdialog.cpp +++ b/plugins/git/stashmanagerdialog.cpp @@ -1,153 +1,153 @@ /* * This file is part of KDevelop * Copyright 2010 Aleix Pol Gonzalez * * 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 "stashmanagerdialog.h" #include "ui_stashmanagerdialog.h" #include "gitplugin.h" #include "stashpatchsource.h" #include #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; StashManagerDialog::StashManagerDialog(const QDir& stashed, GitPlugin* plugin, QWidget* parent) : QDialog(parent), m_plugin(plugin), m_dir(stashed) { setWindowTitle(i18n("Stash Manager")); m_mainWidget = new QWidget(this); m_ui = new Ui::StashManager; m_ui->setupUi(m_mainWidget); StashModel* m = new StashModel(stashed, plugin, this); m_ui->stashView->setModel(m); connect(m_ui->show, &QPushButton::clicked, this, &StashManagerDialog::showStash); connect(m_ui->apply, &QPushButton::clicked, this, &StashManagerDialog::applyClicked); connect(m_ui->branch, &QPushButton::clicked, this, &StashManagerDialog::branchClicked); connect(m_ui->pop, &QPushButton::clicked, this, &StashManagerDialog::popClicked); connect(m_ui->drop, &QPushButton::clicked, this, &StashManagerDialog::dropClicked); connect(m, &StashModel::rowsInserted, this, &StashManagerDialog::stashesFound); - connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &StashManagerDialog::reject); m_mainWidget->setEnabled(false); //we won't enable it until we have the model with data and selection } StashManagerDialog::~StashManagerDialog() { delete m_ui; } void StashManagerDialog::stashesFound() { QModelIndex firstIdx=m_ui->stashView->model()->index(0, 0); m_ui->stashView->setCurrentIndex(firstIdx); m_mainWidget->setEnabled(true); } QString StashManagerDialog::selection() const { QModelIndex idx = m_ui->stashView->currentIndex(); Q_ASSERT(idx.isValid()); return idx.data().toString(); } void StashManagerDialog::runStash(const QStringList& arguments) { VcsJob* job = m_plugin->gitStash(m_dir, arguments, OutputJob::Verbose); connect(job, &VcsJob::result, this, &StashManagerDialog::accept); m_mainWidget->setEnabled(false); ICore::self()->runController()->registerJob(job); } void StashManagerDialog::showStash() { IPatchReview * review = ICore::self()->pluginController()->extensionForPlugin(); IPatchSource::Ptr stashPatch(new StashPatchSource(selection(), m_plugin, m_dir)); review->startReview(stashPatch); accept(); } void StashManagerDialog::applyClicked() { runStash(QStringList("apply") << selection()); } void StashManagerDialog::popClicked() { runStash(QStringList("pop") << selection()); } void StashManagerDialog::dropClicked() { QString sel = selection(); int ret = KMessageBox::questionYesNo(this, i18n("Are you sure you want to drop the stash '%1'?", sel)); if(ret == KMessageBox::Yes) runStash(QStringList("drop") << sel); } void StashManagerDialog::branchClicked() { QString branchName = QInputDialog::getText(this, i18n("KDevelop - Git Stash"), i18n("Select a name for the new branch:")); if(!branchName.isEmpty()) runStash(QStringList("branch") << branchName << selection()); } //////////////////StashModel StashModel::StashModel(const QDir& dir, GitPlugin* git, QObject* parent) : QStandardItemModel(parent) { VcsJob* job=git->gitStash(dir, QStringList("list"), OutputJob::Silent); connect(job, &VcsJob::finished, this, &StashModel::stashListReady); ICore::self()->runController()->registerJob(job); } void StashModel::stashListReady(KJob* _job) { DVcsJob* job = qobject_cast(_job); QList< QByteArray > output = job->rawOutput().split('\n'); foreach(const QByteArray& line, output) { QList< QByteArray > fields = line.split(':'); QList elements; foreach(const QByteArray& field, fields) elements += new QStandardItem(QString(field.trimmed())); appendRow(elements); } } diff --git a/plugins/reviewboard/reviewpatchdialog.cpp b/plugins/reviewboard/reviewpatchdialog.cpp index 44800f4a26..ea7d2d7431 100644 --- a/plugins/reviewboard/reviewpatchdialog.cpp +++ b/plugins/reviewboard/reviewpatchdialog.cpp @@ -1,256 +1,256 @@ /* * This file is part of KDevelop * Copyright 2010 Aleix Pol Gonzalez * * 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 "reviewpatchdialog.h" #include #include #include #include #include #include #include "ui_reviewpatch.h" #include "reviewboardjobs.h" #include "debug.h" ReviewPatchDialog::ReviewPatchDialog(const QUrl& dirUrl, QWidget* parent) : QDialog(parent) { m_ui = new Ui::ReviewPatch; QWidget* w = new QWidget(this); m_ui->setupUi(w); - connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &ReviewPatchDialog::accept); + connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &ReviewPatchDialog::reject); connect(m_ui->server, &KUrlRequester::textChanged, this, &ReviewPatchDialog::serverChanged); connect(m_ui->reviewCheckbox, &QCheckBox::stateChanged, this, &ReviewPatchDialog::reviewCheckboxChanged); if (dirUrl.isLocalFile()) { QDir d(dirUrl.toLocalFile()); while(!QFile::exists(d.filePath(".reviewboardrc"))) { if(!d.cdUp()) break; } if(!d.isRoot()) initializeFromRC(d.filePath(".reviewboardrc")); } } ReviewPatchDialog::~ReviewPatchDialog() { delete m_ui; } void ReviewPatchDialog::setBaseDir(const QString& repo) { m_ui->basedir->setText(repo); } void ReviewPatchDialog::setServer(const QUrl& server) { m_ui->server->setUrl(server); } void ReviewPatchDialog::setUsername(const QString& user) { m_ui->username->setText(user); } void ReviewPatchDialog::setRepository(const QString& repo) { m_preferredRepository = repo; } QString ReviewPatchDialog::baseDir() const { return m_ui->basedir->text(); } QUrl ReviewPatchDialog::server() const { QUrl server=m_ui->server->url(); server.setUserName(m_ui->username->text()); server.setPassword(m_ui->password->text()); return server; } QString ReviewPatchDialog::username() const { return m_ui->username->text(); } void ReviewPatchDialog::serverChanged() { m_ui->repositories->clear(); //TODO reviewboards with private repositories don't work. Use user/pass if set. ReviewBoard::ProjectsListRequest* repo = new ReviewBoard::ProjectsListRequest(m_ui->server->url(), this); connect(repo, &ReviewBoard::ProjectsListRequest::finished, this, &ReviewPatchDialog::receivedProjects); repo->start(); } void ReviewPatchDialog::receivedProjects(KJob* job) { // TODO: check error ReviewBoard::ProjectsListRequest* pl=dynamic_cast(job); QVariantList repos = pl->repositories(); // Add default value with no repo selected. m_ui->repositories->addItem(i18n("Repository not selected"), 0); foreach(const QVariant& repo, repos) { QVariantMap repoMap=repo.toMap(); m_ui->repositories->addItem(repoMap["name"].toString(), repoMap["path"]); } connect(m_ui->repositories, static_cast(&QComboBox::currentIndexChanged), this, &ReviewPatchDialog::repositoryChanged); QAbstractItemModel* model = m_ui->repositories->model(); if(!m_preferredRepository.isEmpty()) { QModelIndexList idxs = model->match(model->index(0,0), Qt::UserRole, m_preferredRepository, 1, Qt::MatchExactly); if(idxs.isEmpty()) { idxs = model->match(model->index(0,0), Qt::DisplayRole, QUrl::fromUserInput(m_preferredRepository).fileName(), 1, Qt::MatchExactly); } if(!idxs.isEmpty()) { m_ui->repositories->setCurrentIndex(idxs.first().row()); } else qCDebug(PLUGIN_REVIEWBOARD) << "couldn't fucking find it" << m_preferredRepository; } m_ui->repositoriesBox->setEnabled(job->error()==0); } QString ReviewPatchDialog::repository() const { QComboBox* repositories = m_ui->repositories; if(repositories->currentIndex() != -1) { return repositories->itemData(repositories->currentIndex(), Qt::UserRole).toString(); } return QString(); } void ReviewPatchDialog::repositoryChanged(int index) { m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled((!isUpdateReview() && index > 0) || m_ui->reviews->currentIndex() != -1); } void ReviewPatchDialog::reviewCheckboxChanged(int status) { if (status == Qt::Checked) { m_ui->reviews->setEnabled(true); connect(m_ui->username, &QLineEdit::editingFinished, this, &ReviewPatchDialog::updateReviews); connect(m_ui->password, &QLineEdit::editingFinished, this, &ReviewPatchDialog::updateReviews); connect(m_ui->server, static_cast(&KUrlRequester::returnPressed), this, &ReviewPatchDialog::updateReviews); connect(m_ui->repositories, static_cast(&QComboBox::currentIndexChanged), this, &ReviewPatchDialog::updateReviewsList); } else { m_ui->reviews->setEnabled(false); disconnect(m_ui->username, &QLineEdit::editingFinished, this, &ReviewPatchDialog::updateReviews); disconnect(m_ui->password, &QLineEdit::editingFinished, this, &ReviewPatchDialog::updateReviews); disconnect(m_ui->server, static_cast(&KUrlRequester::returnPressed), this, &ReviewPatchDialog::updateReviews); disconnect(m_ui->repositories, static_cast(&QComboBox::currentIndexChanged), this, &ReviewPatchDialog::updateReviewsList); } updateReviews(); } void ReviewPatchDialog::receivedReviews(KJob* job) { m_reviews.clear(); // TODO: check errors QVariantList reviews = dynamic_cast(job)->reviews(); foreach(const QVariant& review, reviews) { QVariantMap reviewMap = review.toMap(); QVariantMap repoMap = reviewMap["links"].toMap()["repository"].toMap(); m_reviews.insert(repoMap["title"].toString(), qMakePair(reviewMap["summary"].toString(), reviewMap["id"])); } updateReviewsList(); } QString ReviewPatchDialog::review() const { return m_ui->reviews->itemData(m_ui->reviews->currentIndex(), Qt::UserRole).toString(); } void ReviewPatchDialog::updateReviews() { if (isUpdateReview()) { //TODO: reviewboards with private reviews don't work. Use user/pass if set. if (!m_ui->server->text().isEmpty() && !m_ui->username->text().isEmpty()) { ReviewBoard::ReviewListRequest* repo = new ReviewBoard::ReviewListRequest(m_ui->server->url(), username(), "pending", this); connect(repo, &ReviewBoard::ReviewListRequest::finished, this, &ReviewPatchDialog::receivedReviews); repo->start(); } } else { // Clear reviews combobox and enable OK Button if a repository is selected. m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(m_ui->repositories->currentIndex() != -1); } } bool ReviewPatchDialog::isUpdateReview() { return m_ui->reviewCheckbox->checkState() == Qt::Checked; } void ReviewPatchDialog::updateReviewsList() { QString repo = m_ui->repositories->currentText(); QPair kv; m_ui->reviews->clear(); if (m_ui->repositories->currentIndex() < 1) { // Show all Review foreach (const QString& key, m_reviews.uniqueKeys()) { foreach (kv, m_reviews.values(key)) { m_ui->reviews->addItem(kv.first, kv.second); } } } else { // Filter using actual repository. foreach (kv, m_reviews.values(repo)) { m_ui->reviews->addItem(kv.first, kv.second); } } m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(m_ui->reviews->currentIndex() != -1); } void ReviewPatchDialog::initializeFromRC(const QString& filePath) { //The .reviewboardrc files are python files, we'll read and if it doesn't work //Well bad luck. See: http://www.reviewboard.org/docs/rbtools/dev/rbt/configuration/ QRegExp rx("([\\w_]+) *= *[\"'](.*)[\"']"); QFile f(filePath); if(!f.open(QFile::ReadOnly | QFile::Text)) return; QHash values; QTextStream stream(&f); for(; !stream.atEnd(); ) { if(rx.exactMatch(stream.readLine())) { values.insert(rx.cap(1), rx.cap(2)); } } if(values.contains("REVIEWBOARD_URL")) setServer(QUrl(values["REVIEWBOARD_URL"])); if(values.contains("REPOSITORY")) setRepository(values["REPOSITORY"]); qCDebug(PLUGIN_REVIEWBOARD) << "found:" << values; } diff --git a/project/projectfiltermanager.cpp b/project/projectfiltermanager.cpp index 69c77c1265..c813ab69db 100644 --- a/project/projectfiltermanager.cpp +++ b/project/projectfiltermanager.cpp @@ -1,196 +1,197 @@ /* This file is part of KDevelop Copyright 2013 Milian Wolff 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 "projectfiltermanager.h" #include #include #include #include #include #include "interfaces/iprojectfilterprovider.h" #include "interfaces/iprojectfilter.h" #include "interfaces/iprojectfilemanager.h" #include "debug.h" using namespace KDevelop; //BEGIN helper namespace { struct Filter { QSharedPointer filter; // required for bookkeeping IProjectFilterProvider* provider; }; } Q_DECLARE_TYPEINFO(Filter, Q_MOVABLE_TYPE); //END helper //BEGIN private struct ProjectFilterManager::Private { void pluginLoaded(IPlugin* plugin); void unloadingPlugin(IPlugin* plugin); void filterChanged(IProjectFilterProvider* provider, IProject* project); QVector m_filterProvider; QHash > m_filters; ProjectFilterManager* q; }; void ProjectFilterManager::Private::pluginLoaded(IPlugin* plugin) { IProjectFilterProvider* filterProvider = plugin->extension(); if (filterProvider) { m_filterProvider << filterProvider; + // can't use qt5 signal slot syntax here, IProjectFilterProvider is not a QObject QObject::connect(plugin, SIGNAL(filterChanged(KDevelop::IProjectFilterProvider*, KDevelop::IProject*)), q, SLOT(filterChanged(KDevelop::IProjectFilterProvider*, KDevelop::IProject*))); QHash< IProject*, QVector< Filter > >::iterator it = m_filters.begin(); while(it != m_filters.end()) { Filter filter; filter.provider = filterProvider; filter.filter = filterProvider->createFilter(it.key()); it.value().append(filter); ++it; } } } void ProjectFilterManager::Private::unloadingPlugin(IPlugin* plugin) { IProjectFilterProvider* filterProvider = plugin->extension(); if (filterProvider) { int idx = m_filterProvider.indexOf(qobject_cast(plugin)); Q_ASSERT(idx != -1); m_filterProvider.remove(idx); QHash< IProject*, QVector >::iterator filtersIt = m_filters.begin(); while(filtersIt != m_filters.end()) { QVector& filters = filtersIt.value(); QVector::iterator filter = filters.begin(); while(filter != filters.end()) { if ((*filter).provider == filterProvider) { filter = filters.erase(filter); continue; } ++filter; } ++filtersIt; } } } void ProjectFilterManager::Private::filterChanged(IProjectFilterProvider* provider, IProject* project) { if (!m_filters.contains(project)) { return; } QVector< Filter >& filters = m_filters[project]; QVector::iterator it = filters.begin(); while(it != filters.end()) { if (it->provider == provider) { it->filter = provider->createFilter(project); qCDebug(PROJECT) << "project filter changed, reloading" << project->name(); project->projectFileManager()->reload(project->projectItem()); return; } ++it; } Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown provider changed its filter"); } //END private //BEGIN ProjectFilterManager::ProjectFilterManager(QObject* parent) : QObject(parent) , d(new ProjectFilterManager::Private) { d->q = this; connect(ICore::self()->pluginController(), &IPluginController::pluginLoaded, this, [&] (IPlugin* plugin) { d->pluginLoaded(plugin); }); connect(ICore::self()->pluginController(), &IPluginController::unloadingPlugin, this, [&] (IPlugin* plugin) { d->unloadingPlugin(plugin); }); foreach(IPlugin* plugin, ICore::self()->pluginController()->loadedPlugins()) { d->pluginLoaded(plugin); } } ProjectFilterManager::~ProjectFilterManager() { } void ProjectFilterManager::add(IProject* project) { QVector filters; filters.reserve(d->m_filterProvider.size()); foreach(IProjectFilterProvider* provider, d->m_filterProvider) { Filter filter; filter.provider = provider; filter.filter = provider->createFilter(project); filters << filter; } d->m_filters[project] = filters; } void ProjectFilterManager::remove(IProject* project) { d->m_filters.remove(project); } bool ProjectFilterManager::isManaged(IProject* project) const { return d->m_filters.contains(project); } bool ProjectFilterManager::isValid(const Path& path, bool isFolder, IProject* project) const { foreach(const Filter& filter, d->m_filters[project]) { if (!filter.filter->isValid(path, isFolder)) { return false; } } return true; } QVector< QSharedPointer< IProjectFilter > > ProjectFilterManager::filtersForProject(IProject* project) const { QVector< QSharedPointer< IProjectFilter > > ret; QVector< Filter > filters = d->m_filters[project]; ret.reserve(filters.size()); foreach(const Filter& filter, filters) { ret << filter.filter; } return ret; } //END #include "moc_projectfiltermanager.cpp" diff --git a/project/projectitemlineedit.cpp b/project/projectitemlineedit.cpp index 62fc9abac1..85f65e3a35 100644 --- a/project/projectitemlineedit.cpp +++ b/project/projectitemlineedit.cpp @@ -1,243 +1,243 @@ /*************************************************************************** * Copyright 2008 Aleix Pol * * * * 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 Library 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 "projectitemlineedit.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "projectproxymodel.h" #include #include #include #include #include #include #include #include static const QChar sep = '/'; static const QChar escape = '\\'; class ProjectItemCompleter : public QCompleter { Q_OBJECT public: ProjectItemCompleter(QObject* parent=0); QString separator() const { return sep; } QStringList splitPath(const QString &path) const; QString pathFromIndex(const QModelIndex& index) const; void setBaseItem( KDevelop::ProjectBaseItem* item ) { mBase = item; } private: KDevelop::ProjectModel* mModel; KDevelop::ProjectBaseItem* mBase; }; class ProjectItemValidator : public QValidator { Q_OBJECT public: ProjectItemValidator(QObject* parent = 0 ); QValidator::State validate( QString& input, int& pos ) const; void setBaseItem( KDevelop::ProjectBaseItem* item ) { mBase = item; } private: KDevelop::ProjectBaseItem* mBase; }; ProjectItemCompleter::ProjectItemCompleter(QObject* parent) : QCompleter(parent), mModel(KDevelop::ICore::self()->projectController()->projectModel()), mBase( 0 ) { setModel(mModel); setCaseSensitivity( Qt::CaseInsensitive ); } QStringList ProjectItemCompleter::splitPath(const QString& path) const { return joinProjectBasePath( KDevelop::splitWithEscaping( path, sep, escape ), mBase ); } QString ProjectItemCompleter::pathFromIndex(const QModelIndex& index) const { QString postfix; if(mModel->itemFromIndex(index)->folder()) postfix=sep; return KDevelop::joinWithEscaping(removeProjectBasePath( mModel->pathFromIndex(index), mBase ), sep, escape)+postfix; } ProjectItemValidator::ProjectItemValidator(QObject* parent): QValidator(parent), mBase(0) { } QValidator::State ProjectItemValidator::validate(QString& input, int& pos) const { Q_UNUSED( pos ); KDevelop::ProjectModel* model = KDevelop::ICore::self()->projectController()->projectModel(); QStringList path = joinProjectBasePath( KDevelop::splitWithEscaping( input, sep, escape ), mBase ); QModelIndex idx = model->pathToIndex( path ); QValidator::State state = input.isEmpty() ? QValidator::Intermediate : QValidator::Invalid; if( idx.isValid() ) { state = QValidator::Acceptable; } else if( path.count() > 1 ) { // Check beginning of path and if that is ok, then try to find a child QString end = path.takeLast(); idx = model->pathToIndex( path ); if( idx.isValid() ) { for( int i = 0; i < model->rowCount( idx ); i++ ) { if( model->data( model->index( i, 0, idx ) ).toString().startsWith( end, Qt::CaseInsensitive ) ) { state = QValidator::Intermediate; break; } } } } else if( path.count() == 1 ) { // Check for a project whose name beings with the input QString first = path.first(); foreach( KDevelop::IProject* project, KDevelop::ICore::self()->projectController()->projects() ) { if( project->name().startsWith( first, Qt::CaseInsensitive ) ) { state = QValidator::Intermediate; break; } } } return state; } ProjectItemLineEdit::ProjectItemLineEdit(QWidget* parent) : QLineEdit(parent), m_base(0), m_completer( new ProjectItemCompleter( this ) ), m_validator( new ProjectItemValidator( this ) ) { setCompleter( m_completer ); setValidator( m_validator ); setPlaceholderText( i18n("Enter the path to an item from the projects tree" ) ); QAction* selectItemAction = new QAction(QIcon::fromTheme("folder-document"), i18n("Select..."), this); connect(selectItemAction, &QAction::triggered, this, &ProjectItemLineEdit::selectItemDialog); addAction(selectItemAction); setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &ProjectItemLineEdit::customContextMenuRequested, this, &ProjectItemLineEdit::showCtxMenu); } void ProjectItemLineEdit::showCtxMenu(const QPoint& p) { QScopedPointer menu(createStandardContextMenu()); menu->addActions(actions()); menu->exec(mapToGlobal(p)); } bool ProjectItemLineEdit::selectItemDialog() { KDevelop::ProjectModel* model=KDevelop::ICore::self()->projectController()->projectModel(); QWidget* w=new QWidget; w->setLayout(new QVBoxLayout(w)); QTreeView* view = new QTreeView(w); ProjectProxyModel* proxymodel = new ProjectProxyModel(view); proxymodel->setSourceModel(model); view->header()->hide(); view->setModel(proxymodel); view->setSelectionMode(QAbstractItemView::SingleSelection); w->layout()->addWidget(new QLabel(i18n("Select the item you want to get the path from."))); w->layout()->addWidget(view); QDialog dialog; dialog.setWindowTitle(i18n("Select an item...")); QVBoxLayout *mainLayout = new QVBoxLayout(&dialog); mainLayout->addWidget(w); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); mainLayout->addWidget(buttonBox); int res = dialog.exec(); if(res==QDialog::Accepted && view->selectionModel()->hasSelection()) { QModelIndex idx=proxymodel->mapToSource(view->selectionModel()->selectedIndexes().first()); setText(KDevelop::joinWithEscaping(model->pathFromIndex(idx), sep, escape)); selectAll(); return true; } return false; } void ProjectItemLineEdit::setItemPath(const QStringList& list) { setText( KDevelop::joinWithEscaping( removeProjectBasePath( list, m_base ), sep, escape ) ); } QStringList ProjectItemLineEdit::itemPath() const { return joinProjectBasePath( KDevelop::splitWithEscaping( text(), sep, escape ), m_base ); } void ProjectItemLineEdit::setBaseItem(KDevelop::ProjectBaseItem* item) { m_base = item; m_validator->setBaseItem( m_base ); m_completer->setBaseItem( m_base ); } KDevelop::ProjectBaseItem* ProjectItemLineEdit::baseItem() const { return m_base; } KDevelop::ProjectBaseItem* ProjectItemLineEdit::currentItem() const { KDevelop::ProjectModel* model = KDevelop::ICore::self()->projectController()->projectModel(); return model->itemFromIndex(model->pathToIndex(KDevelop::splitWithEscaping(text(),'/', '\\'))); } #include "projectitemlineedit.moc" #include "moc_projectitemlineedit.cpp" diff --git a/shell/environmentconfigurebutton.cpp b/shell/environmentconfigurebutton.cpp index 9572177eec..b28429cc8c 100644 --- a/shell/environmentconfigurebutton.cpp +++ b/shell/environmentconfigurebutton.cpp @@ -1,108 +1,108 @@ /* This file is part of KDevelop Copyright 2010 Milian Wolff 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 "environmentconfigurebutton.h" #include #include #include "settings/environmentpreferences.h" #include #include #include #include #include #include #include #include #include #include namespace KDevelop { class EnvironmentConfigureButtonPrivate { public: EnvironmentConfigureButtonPrivate(EnvironmentConfigureButton* _q) : q(_q), selectionWidget(0) { } void showDialog() { QDialog dlg(qApp->activeWindow()); QString selected; if (selectionWidget) { selected = selectionWidget->effectiveProfileName(); } EnvironmentPreferences prefs(selected, q); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - QObject::connect(buttonBox, SIGNAL(accepted()), &dlg, SLOT(accept())); - QObject::connect(buttonBox, SIGNAL(rejected()), &dlg, SLOT(reject())); + QObject::connect(buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept); + QObject::connect(buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject); auto layout = new QVBoxLayout; layout->addWidget(&prefs); layout->addWidget(buttonBox); dlg.setLayout(layout); dlg.setWindowTitle(prefs.fullName()); dlg.setWindowIcon(prefs.icon()); dlg.resize(480, 320); if (dlg.exec() == QDialog::Accepted) { prefs.apply(); emit q->environmentConfigured(); } } EnvironmentConfigureButton *q; EnvironmentSelectionWidget *selectionWidget; }; EnvironmentConfigureButton::EnvironmentConfigureButton(QWidget* parent) : QPushButton(parent), d(new EnvironmentConfigureButtonPrivate(this)) { setText(QString()); setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); setIcon(QIcon::fromTheme("configure")); setToolTip(i18n("Configure environment variables")); connect(this, &EnvironmentConfigureButton::clicked, this, [&] { d->showDialog(); }); } EnvironmentConfigureButton::~EnvironmentConfigureButton() { delete d; } void EnvironmentConfigureButton::setSelectionWidget(EnvironmentSelectionWidget* widget) { connect(this, &EnvironmentConfigureButton::environmentConfigured, widget, &EnvironmentSelectionWidget::reconfigure); d->selectionWidget = widget; } } #include "moc_environmentconfigurebutton.cpp" diff --git a/shell/launchconfigurationdialog.cpp b/shell/launchconfigurationdialog.cpp index a5620d7318..134ca9f152 100644 --- a/shell/launchconfigurationdialog.cpp +++ b/shell/launchconfigurationdialog.cpp @@ -1,1027 +1,1027 @@ /* This file is part of KDevelop Copyright 2009 Andreas Pakulat 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 "launchconfigurationdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "runcontroller.h" #include "launchconfiguration.h" #include "debug.h" #include #include #include #include #include #include #include #include #include namespace KDevelop { bool launchConfigGreaterThan(KDevelop::LaunchConfigurationType* a, KDevelop::LaunchConfigurationType* b) { return a->name()>b->name(); } //TODO: Maybe use KPageDialog instead, might make the model stuff easier and the default-size stuff as well LaunchConfigurationDialog::LaunchConfigurationDialog(QWidget* parent) : QDialog(parent) , currentPageChanged(false) { setWindowTitle( i18n( "Launch Configurations" ) ); QWidget *mainWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->addWidget(mainWidget); setupUi(mainWidget); mainLayout->setContentsMargins( 0, 0, 0, 0 ); splitter->setSizes(QList() << 260 << 620); addConfig->setIcon( QIcon::fromTheme("list-add") ); addConfig->setEnabled( false ); addConfig->setToolTip(i18nc("@info:tooltip", "Add a new launch configuration.")); deleteConfig->setIcon( QIcon::fromTheme("list-remove") ); deleteConfig->setEnabled( false ); deleteConfig->setToolTip(i18nc("@info:tooltip", "Delete selected launch configuration.")); model = new LaunchConfigurationsModel( tree ); tree->setModel( model ); tree->setExpandsOnDoubleClick( true ); tree->setSelectionBehavior( QAbstractItemView::SelectRows ); tree->setSelectionMode( QAbstractItemView::SingleSelection ); tree->setUniformRowHeights( true ); tree->setItemDelegate( new LaunchConfigurationModelDelegate() ); tree->setColumnHidden(1, true); for(int row=0; rowrowCount(); row++) { tree->setExpanded(model->index(row, 0), true); } tree->setContextMenuPolicy(Qt::CustomContextMenu); connect( tree, &QTreeView::customContextMenuRequested, this, &LaunchConfigurationDialog::doTreeContextMenu ); connect( deleteConfig, &QToolButton::clicked, this, &LaunchConfigurationDialog::deleteConfiguration); connect( model, &LaunchConfigurationsModel::dataChanged, this, &LaunchConfigurationDialog::modelChanged ); connect( tree->selectionModel(), &QItemSelectionModel::selectionChanged, this, &LaunchConfigurationDialog::selectionChanged); QModelIndex idx = model->indexForConfig( Core::self()->runControllerInternal()->defaultLaunch() ); qCDebug(SHELL) << "selecting index:" << idx; if( !idx.isValid() ) { for( int i = 0; i < model->rowCount(); i++ ) { if( model->rowCount( model->index( i, 0, QModelIndex() ) ) > 0 ) { idx = model->index( 1, 0, model->index( i, 0, QModelIndex() ) ); break; } } if( !idx.isValid() ) { idx = model->index( 0, 0, QModelIndex() ); } } tree->selectionModel()->select( QItemSelection( idx, idx ), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); tree->selectionModel()->setCurrentIndex( idx, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); // Unfortunately tree->resizeColumnToContents() only looks at the top-level // items, instead of all open ones. Hence we're calculating it ourselves like // this: // Take the selected index, check if it has childs, if so take the first child // Then count the level by going up, then let the tree calculate the width // for the selected or its first child index and add indentation*level // // If Qt Software ever fixes resizeColumnToContents, the following line // can be enabled and the rest be removed // tree->resizeColumnToContents( 0 ); int level = 0; QModelIndex widthidx = idx; if( model->rowCount( idx ) > 0 ) { widthidx = idx.child( 0, 0 ); } QModelIndex parentidx = widthidx.parent(); while( parentidx.isValid() ) { level++; parentidx = parentidx.parent(); } // make sure the base column width is honored, e.g. when no launch configs exist tree->resizeColumnToContents(0); int width = tree->columnWidth( 0 ); while ( widthidx.isValid() ) { width = qMax( width, level*tree->indentation() + tree->indentation() + tree->sizeHintForIndex( widthidx ).width() ); widthidx = widthidx.parent(); } tree->setColumnWidth( 0, width ); QMenu* m = new QMenu(this); QList types = Core::self()->runController()->launchConfigurationTypes(); std::sort(types.begin(), types.end(), launchConfigGreaterThan); //we want it in reverse order foreach(LaunchConfigurationType* type, types) { connect(type, &LaunchConfigurationType::signalAddLaunchConfiguration, this, &LaunchConfigurationDialog::addConfiguration); QMenu* suggestionsMenu = type->launcherSuggestions(); if(suggestionsMenu) { m->addMenu(suggestionsMenu); } } // Simplify menu structure to get rid of 1-entry levels while (m->actions().count() == 1) { QMenu* subMenu = m->actions().first()->menu(); if (subMenu && subMenu->isEnabled() && subMenu->actions().count()<5) { m = subMenu; } else { break; } } if(!m->isEmpty()) { QAction* separator = new QAction(m); separator->setSeparator(true); m->insertAction(m->actions().first(), separator); } foreach(LaunchConfigurationType* type, types) { QAction* action = new QAction(type->icon(), type->name(), m); action->setProperty("configtype", qVariantFromValue(type)); connect(action, &QAction::triggered, this, &LaunchConfigurationDialog::createEmptyLauncher); if(!m->actions().isEmpty()) m->insertAction(m->actions().first(), action); else m->addAction(action); } addConfig->setMenu(m); connect(debugger, static_cast(&QComboBox::currentIndexChanged), this, &LaunchConfigurationDialog::launchModeChanged); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - connect(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), SLOT(saveConfig()) ); - connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), SLOT(saveConfig()) ); + connect(buttonBox, &QDialogButtonBox::accepted, this, &LaunchConfigurationDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &LaunchConfigurationDialog::reject); + connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, static_cast(&LaunchConfigurationDialog::saveConfig) ); + connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, static_cast(&LaunchConfigurationDialog::saveConfig) ); mainLayout->addWidget(buttonBox); resize( QSize(qMax(700, sizeHint().width()), qMax(500, sizeHint().height())) ); } void LaunchConfigurationDialog::doTreeContextMenu(QPoint point) { if ( ! tree->selectionModel()->selectedRows().isEmpty() ) { QModelIndex selected = tree->selectionModel()->selectedRows().first(); if ( selected.parent().isValid() && ! selected.parent().parent().isValid() ) { // only display the menu if a launch config is clicked QMenu menu; QAction* rename = new QAction(QIcon::fromTheme("edit-rename"), i18n("Rename configuration"), &menu); QAction* delete_ = new QAction(QIcon::fromTheme("edit-delete"), i18n("Delete configuration"), &menu); connect(rename, &QAction::triggered, this, &LaunchConfigurationDialog::renameSelected); connect(delete_, &QAction::triggered, this, &LaunchConfigurationDialog::deleteConfiguration); menu.addAction(rename); menu.addAction(delete_); menu.exec(tree->mapToGlobal(point)); } } } void LaunchConfigurationDialog::renameSelected() { if( !tree->selectionModel()->selectedRows().isEmpty() ) { QModelIndex parent = tree->selectionModel()->selectedRows().first(); if( parent.parent().isValid() ) { parent = parent.parent(); } QModelIndex index = model->index(tree->selectionModel()->selectedRows().first().row(), 0, parent); tree->edit( index ); } } QSize LaunchConfigurationDialog::sizeHint() const { QSize s = QDialog::sizeHint(); return s.expandedTo(QSize(880, 520)); } void LaunchConfigurationDialog::createEmptyLauncher() { QAction* action = qobject_cast(sender()); Q_ASSERT(action); LaunchConfigurationType* type = qobject_cast(action->property("configtype").value()); Q_ASSERT(type); IProject* p = model->projectForIndex(tree->currentIndex()); QPair< QString, QString > launcher( type->launchers().at( 0 )->supportedModes().at(0), type->launchers().at( 0 )->id() ); ILaunchConfiguration* l = ICore::self()->runController()->createLaunchConfiguration(type, launcher, p); addConfiguration(l); } void LaunchConfigurationDialog::selectionChanged(QItemSelection selected, QItemSelection deselected ) { if( !deselected.indexes().isEmpty() ) { LaunchConfiguration* l = model->configForIndex( deselected.indexes().first() ); if( l ) { disconnect(l, &LaunchConfiguration::nameChanged, this, &LaunchConfigurationDialog::updateNameLabel); if( currentPageChanged ) { if( KMessageBox::questionYesNo( this, i18n("Selected Launch Configuration has unsaved changes. Do you want to save it?"), i18n("Unsaved Changes") ) == KMessageBox::Yes ) { saveConfig( deselected.indexes().first() ); } else { LaunchConfigPagesContainer* tab = qobject_cast( stack->currentWidget() ); tab->setLaunchConfiguration( l ); buttonBox->button(QDialogButtonBox::Apply)->setEnabled( false ); currentPageChanged = false; } } } } updateNameLabel(0); for( int i = 1; i < stack->count(); i++ ) { QWidget* w = stack->widget(i); stack->removeWidget(w); delete w; } debugger->clear(); if( !selected.indexes().isEmpty() ) { QModelIndex idx = selected.indexes().first(); LaunchConfiguration* l = model->configForIndex( idx ); ILaunchMode* lm = model->modeForIndex( idx ); if( l ) { updateNameLabel( l ); tree->expand( model->indexForConfig( l ) ); connect( l, &LaunchConfiguration::nameChanged, this, &LaunchConfigurationDialog::updateNameLabel ); if( lm ) { bool b = debugger->blockSignals(true); QList launchers = l->type()->launchers(); for( QList::const_iterator it = launchers.constBegin(); it != launchers.constEnd(); it++ ) { if( ((*it)->supportedModes().contains( lm->id() ) ) ) { debugger->addItem( (*it)->name(), (*it)->id() ); } } debugger->blockSignals(b); debugger->setVisible(debugger->count()>0); debugLabel->setVisible(debugger->count()>0); QVariant currentLaunchMode = idx.sibling(idx.row(), 1).data(Qt::EditRole); debugger->setCurrentIndex(debugger->findData(currentLaunchMode)); ILauncher* launcher = l->type()->launcherForId( currentLaunchMode.toString() ); if( launcher ) { LaunchConfigPagesContainer* tab = launcherWidgets.value( launcher ); if(!tab) { QList pages = launcher->configPages(); if(!pages.isEmpty()) { tab = new LaunchConfigPagesContainer( launcher->configPages(), stack ); connect( tab, &LaunchConfigPagesContainer::changed, this, &LaunchConfigurationDialog::pageChanged ); stack->addWidget( tab ); } } if(tab) { tab->setLaunchConfiguration( l ); stack->setCurrentWidget( tab ); } else { QLabel* label = new QLabel(i18nc("%1 is a launcher name", "No configuration is needed for '%1'", launcher->name()), stack); label->setAlignment(Qt::AlignCenter); QFont font = label->font(); font.setItalic(true); label->setFont(font); stack->addWidget(label); stack->setCurrentWidget(label); } updateNameLabel( l ); addConfig->setEnabled( false ); deleteConfig->setEnabled( false ); } else { addConfig->setEnabled( false ); deleteConfig->setEnabled( false ); stack->setCurrentIndex( 0 ); } } else { //TODO: enable removal button LaunchConfigurationType* type = l->type(); LaunchConfigPagesContainer* tab = typeWidgets.value( type ); if( !tab ) { tab = new LaunchConfigPagesContainer( type->configPages(), stack ); connect( tab, &LaunchConfigPagesContainer::changed, this, &LaunchConfigurationDialog::pageChanged ); stack->addWidget( tab ); } qCDebug(SHELL) << "created pages, setting config up"; tab->setLaunchConfiguration( l ); stack->setCurrentWidget( tab ); addConfig->setEnabled( true ); deleteConfig->setEnabled( true ); debugger->setVisible( false ); debugLabel->setVisible( false ); } } else { addConfig->setEnabled( true ); deleteConfig->setEnabled( false ); stack->setCurrentIndex( 0 ); QLabel* l = new QLabel(i18n("Select a configuration to edit from the left,
" "or click the \"Add New\" button to add a new one.
"), stack); l->setAlignment(Qt::AlignCenter); stack->addWidget(l); stack->setCurrentWidget(l); debugger->setVisible( false ); debugLabel->setVisible( false ); } } else { debugger->setVisible( false ); debugLabel->setVisible( false ); addConfig->setEnabled( false ); deleteConfig->setEnabled( false ); stack->setCurrentIndex( 0 ); } } void LaunchConfigurationDialog::saveConfig( const QModelIndex& idx ) { Q_UNUSED( idx ); LaunchConfigPagesContainer* tab = qobject_cast( stack->currentWidget() ); if( tab ) { tab->save(); buttonBox->button(QDialogButtonBox::Apply)->setEnabled( false ); currentPageChanged = false; } } void LaunchConfigurationDialog::saveConfig() { if( !tree->selectionModel()->selectedRows().isEmpty() ) { saveConfig( tree->selectionModel()->selectedRows().first() ); } } void LaunchConfigurationDialog::pageChanged() { currentPageChanged = true; buttonBox->button(QDialogButtonBox::Apply)->setEnabled( true ); } void LaunchConfigurationDialog::modelChanged(QModelIndex topLeft, QModelIndex bottomRight) { if (tree->selectionModel()) { QModelIndex index = tree->selectionModel()->selectedRows().first(); if (index.row() >= topLeft.row() && index.row() <= bottomRight.row() && bottomRight.column() == 1) selectionChanged(tree->selectionModel()->selection(), tree->selectionModel()->selection()); } } void LaunchConfigurationDialog::deleteConfiguration() { if( !tree->selectionModel()->selectedRows().isEmpty() ) { model->deleteConfiguration( tree->selectionModel()->selectedRows().first() ); tree->resizeColumnToContents( 0 ); } } void LaunchConfigurationDialog::updateNameLabel( LaunchConfiguration* l ) { if( l ) { configName->setText( i18n("Editing %2: %1", l->name(), l->type()->name() ) ); } else { configName->clear(); } } void LaunchConfigurationDialog::createConfiguration() { if( !tree->selectionModel()->selectedRows().isEmpty() ) { QModelIndex idx = tree->selectionModel()->selectedRows().first(); if( idx.parent().isValid() ) { idx = idx.parent(); } model->createConfiguration( idx ); QModelIndex newindex = model->index( model->rowCount( idx ) - 1, 0, idx ); tree->selectionModel()->select( newindex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); tree->selectionModel()->setCurrentIndex( newindex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); tree->edit( newindex ); tree->resizeColumnToContents( 0 ); } } void LaunchConfigurationDialog::addConfiguration(ILaunchConfiguration* _launch) { LaunchConfiguration* launch = dynamic_cast(_launch); Q_ASSERT(launch); int row = launch->project() ? model->findItemForProject(launch->project())->row : 0; QModelIndex idx = model->index(row, 0); model->addConfiguration(launch, idx); QModelIndex newindex = model->index( model->rowCount( idx ) - 1, 0, idx ); tree->selectionModel()->select( newindex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); tree->selectionModel()->setCurrentIndex( newindex, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows ); tree->edit( newindex ); tree->resizeColumnToContents( 0 ); } LaunchConfigurationsModel::LaunchConfigurationsModel(QObject* parent): QAbstractItemModel(parent) { GenericPageItem* global = new GenericPageItem; global->text = i18n("Global"); global->row = 0; topItems << global; foreach( IProject* p, Core::self()->projectController()->projects() ) { ProjectItem* t = new ProjectItem; t->project = p; t->row = topItems.count(); topItems << t; } foreach( LaunchConfiguration* l, Core::self()->runControllerInternal()->launchConfigurationsInternal() ) { addItemForLaunchConfig( l ); } } void LaunchConfigurationsModel::addItemForLaunchConfig( LaunchConfiguration* l ) { LaunchItem* t = new LaunchItem; t->launch = l; TreeItem* parent; if( l->project() ) { parent = findItemForProject( l->project() ); } else { parent = topItems.at(0); } t->parent = parent; t->row = parent->children.count(); parent->children.append( t ); addLaunchModeItemsForLaunchConfig ( t ); } void LaunchConfigurationsModel::addLaunchModeItemsForLaunchConfig ( LaunchItem* t ) { QList items; QSet modes; foreach( ILauncher* launcher, t->launch->type()->launchers() ) { foreach( const QString& mode, launcher->supportedModes() ) { if( !modes.contains( mode ) && launcher->configPages().count() > 0 ) { modes.insert( mode ); LaunchModeItem* lmi = new LaunchModeItem; lmi->mode = Core::self()->runController()->launchModeForId( mode ); lmi->parent = t; lmi->row = t->children.count(); items.append( lmi ); } } } if( !items.isEmpty() ) { QModelIndex p = indexForConfig( t->launch ); beginInsertRows( p, t->children.count(), t->children.count() + items.count() - 1 ); t->children.append( items ); endInsertRows(); } } LaunchConfigurationsModel::ProjectItem* LaunchConfigurationsModel::findItemForProject( IProject* p ) { foreach( TreeItem* t, topItems ) { ProjectItem* pi = dynamic_cast( t ); if( pi && pi->project == p ) { return pi; } } Q_ASSERT(false); return 0; } int LaunchConfigurationsModel::columnCount(const QModelIndex& parent) const { Q_UNUSED( parent ); return 2; } QVariant LaunchConfigurationsModel::data(const QModelIndex& index, int role) const { if( index.isValid() && index.column() >= 0 && index.column() < 2 ) { TreeItem* t = static_cast( index.internalPointer() ); switch( role ) { case Qt::DisplayRole: { LaunchItem* li = dynamic_cast( t ); if( li ) { if( index.column() == 0 ) { return li->launch->name(); } else if( index.column() == 1 ) { return li->launch->type()->name(); } } ProjectItem* pi = dynamic_cast( t ); if( pi && index.column() == 0 ) { return pi->project->name(); } GenericPageItem* gpi = dynamic_cast( t ); if( gpi && index.column() == 0 ) { return gpi->text; } LaunchModeItem* lmi = dynamic_cast( t ); if( lmi ) { if( index.column() == 0 ) { return lmi->mode->name(); } else if( index.column() == 1 ) { LaunchConfiguration* l = configForIndex( index ); return l->type()->launcherForId( l->launcherForMode( lmi->mode->id() ) )->name(); } } break; } case Qt::DecorationRole: { LaunchItem* li = dynamic_cast( t ); if( index.column() == 0 && li ) { return li->launch->type()->icon(); } LaunchModeItem* lmi = dynamic_cast( t ); if( lmi && index.column() == 0 ) { return lmi->mode->icon(); } if ( index.column() == 0 && !index.parent().isValid() ) { if (index.row() == 0) { // global item return QIcon::fromTheme("folder"); } else { // project item return QIcon::fromTheme("folder-development"); } } } case Qt::EditRole: { LaunchItem* li = dynamic_cast( t ); if( li ) { if( index.column() == 0 ) { return li->launch->name(); } else if ( index.column() == 1 ) { return li->launch->type()->id(); } } LaunchModeItem* lmi = dynamic_cast( t ); if( lmi && index.column() == 1 ) { return configForIndex( index )->launcherForMode( lmi->mode->id() ); } break; } default: break; } } return QVariant(); } QModelIndex LaunchConfigurationsModel::index(int row, int column, const QModelIndex& parent) const { if( !hasIndex( row, column, parent ) ) return QModelIndex(); TreeItem* tree; if( !parent.isValid() ) { tree = topItems.at( row ); } else { TreeItem* t = static_cast( parent.internalPointer() ); tree = t->children.at( row ); } if( tree ) { return createIndex( row, column, tree ); } return QModelIndex(); } QModelIndex LaunchConfigurationsModel::parent(const QModelIndex& child) const { if( child.isValid() ) { TreeItem* t = static_cast( child.internalPointer() ); if( t->parent ) { return createIndex( t->parent->row, 0, t->parent ); } } return QModelIndex(); } int LaunchConfigurationsModel::rowCount(const QModelIndex& parent) const { if( parent.column() > 0 ) return 0; if( parent.isValid() ) { TreeItem* t = static_cast( parent.internalPointer() ); return t->children.count(); } else { return topItems.count(); } return 0; } QVariant LaunchConfigurationsModel::headerData(int section, Qt::Orientation orientation, int role) const { if( orientation == Qt::Horizontal && role == Qt::DisplayRole ) { if( section == 0 ) { return i18nc("Name of the Launch Configurations", "Name"); } else if( section == 1 ) { return i18nc("The type of the Launch Configurations (i.e. Python Application, C++ Application)", "Type"); } } return QVariant(); } Qt::ItemFlags LaunchConfigurationsModel::flags(const QModelIndex& index) const { if( index.isValid() && index.column() >= 0 && index.column() < columnCount( QModelIndex() ) ) { TreeItem* t = static_cast( index.internalPointer() ); if( t && ( dynamic_cast( t ) || ( dynamic_cast( t ) && index.column() == 1 ) ) ) { return Qt::ItemFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable ); } else if( t ) { return Qt::ItemFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable ); } } return Qt::NoItemFlags; } bool LaunchConfigurationsModel::setData(const QModelIndex& index, const QVariant& value, int role) { if( index.isValid() && index.parent().isValid() && role == Qt::EditRole ) { if( index.row() >= 0 && index.row() < rowCount( index.parent() ) ) { LaunchItem* t = dynamic_cast( static_cast( index.internalPointer() ) ); if( t ) { if( index.column() == 0 ) { t->launch->setName( value.toString() ); } else if( index.column() == 1 ) { if (t->launch->type()->id() != value.toString()) { t->launch->setType( value.toString() ); QModelIndex p = indexForConfig(t->launch); qCDebug(SHELL) << data(p); beginRemoveRows( p, 0, t->children.count() ); qDeleteAll( t->children ); t->children.clear(); endRemoveRows(); addLaunchModeItemsForLaunchConfig( t ); } } emit dataChanged(index, index); return true; } LaunchModeItem* lmi = dynamic_cast( static_cast( index.internalPointer() ) ); if( lmi ) { if( index.column() == 1 && index.data(Qt::EditRole)!=value) { LaunchConfiguration* l = configForIndex( index ); l->setLauncherForMode( lmi->mode->id(), value.toString() ); emit dataChanged(index, index); return true; } } } } return false; } ILaunchMode* LaunchConfigurationsModel::modeForIndex( const QModelIndex& idx ) const { if( idx.isValid() ) { LaunchModeItem* item = dynamic_cast( static_cast( idx.internalPointer() ) ); if( item ) { return item->mode; } } return 0; } LaunchConfiguration* LaunchConfigurationsModel::configForIndex(const QModelIndex& idx ) const { if( idx.isValid() ) { LaunchItem* item = dynamic_cast( static_cast( idx.internalPointer() ) ); if( item ) { return item->launch; } LaunchModeItem* lmitem = dynamic_cast( static_cast( idx.internalPointer() ) ); if( lmitem ) { return dynamic_cast( lmitem->parent )->launch; } } return 0; } QModelIndex LaunchConfigurationsModel::indexForConfig( LaunchConfiguration* l ) const { if( l ) { TreeItem* tparent = topItems.at( 0 ); if( l->project() ) { foreach( TreeItem* t, topItems ) { ProjectItem* pi = dynamic_cast( t ); if( pi && pi->project == l->project() ) { tparent = t; break; } } } if( tparent ) { foreach( TreeItem* c, tparent->children ) { LaunchItem* li = dynamic_cast( c ); if( li->launch && li->launch == l ) { return index( c->row, 0, index( tparent->row, 0, QModelIndex() ) ); } } } } return QModelIndex(); } void LaunchConfigurationsModel::deleteConfiguration( const QModelIndex& index ) { LaunchItem* t = dynamic_cast( static_cast( index.internalPointer() ) ); if( !t ) return; beginRemoveRows( parent( index ), index.row(), index.row() ); t->parent->children.removeAll( t ); Core::self()->runControllerInternal()->removeLaunchConfiguration( t->launch ); endRemoveRows(); } void LaunchConfigurationsModel::createConfiguration(const QModelIndex& parent ) { if(!Core::self()->runController()->launchConfigurationTypes().isEmpty()) { TreeItem* t = static_cast( parent.internalPointer() ); ProjectItem* ti = dynamic_cast( t ); LaunchConfigurationType* type = Core::self()->runController()->launchConfigurationTypes().at(0); QPair launcher = qMakePair( type->launchers().at( 0 )->supportedModes().at(0), type->launchers().at( 0 )->id() ); IProject* p = ( ti ? ti->project : 0 ); ILaunchConfiguration* l = Core::self()->runController()->createLaunchConfiguration( type, launcher, p ); addConfiguration(l, parent); } } void LaunchConfigurationsModel::addConfiguration(ILaunchConfiguration* l, const QModelIndex& parent) { if( parent.isValid() ) { beginInsertRows( parent, rowCount( parent ), rowCount( parent ) ); addItemForLaunchConfig( dynamic_cast( l ) ); endInsertRows(); } else { delete l; Q_ASSERT(false && "could not add the configuration"); } } IProject* LaunchConfigurationsModel::projectForIndex(const QModelIndex& idx) { if(idx.parent().isValid()) { return projectForIndex(idx.parent()); } else { const ProjectItem* item = dynamic_cast(topItems[idx.row()]); return item ? item->project : 0; } } LaunchConfigPagesContainer::LaunchConfigPagesContainer( const QList& factories, QWidget* parent ) : QWidget(parent) { setLayout( new QVBoxLayout( this ) ); layout()->setContentsMargins( 0, 0, 0, 0 ); QWidget* parentwidget = this; QTabWidget* tab = 0; if( factories.count() > 1 ) { tab = new QTabWidget( this ); parentwidget = tab; layout()->addWidget( tab ); } foreach( LaunchConfigurationPageFactory* fac, factories ) { LaunchConfigurationPage* page = fac->createWidget( parentwidget ); if ( page->layout() ) { page->layout()->setContentsMargins( 0, 0, 0, 0 ); } pages.append( page ); connect( page, &LaunchConfigurationPage::changed, this, &LaunchConfigPagesContainer::changed ); if( tab ) { tab->addTab( page, page->icon(), page->title() ); } else { layout()->addWidget( page ); } } } void LaunchConfigPagesContainer::setLaunchConfiguration( KDevelop::LaunchConfiguration* l ) { config = l; foreach( LaunchConfigurationPage* p, pages ) { p->loadFromConfiguration( config->config(), config->project() ); } } void LaunchConfigPagesContainer::save() { foreach( LaunchConfigurationPage* p, pages ) { p->saveToConfiguration( config->config() ); } config->config().sync(); } QWidget* LaunchConfigurationModelDelegate::createEditor ( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const { const LaunchConfigurationsModel* model = dynamic_cast( index.model() ); ILaunchMode* mode = model->modeForIndex( index ); LaunchConfiguration* config = model->configForIndex( index ); if( index.column() == 1 && mode && config ) { KComboBox* box = new KComboBox( parent ); QList launchers = config->type()->launchers(); for( QList::const_iterator it = launchers.constBegin(); it != launchers.constEnd(); it++ ) { if( ((*it)->supportedModes().contains( mode->id() ) ) ) { box->addItem( (*it)->name(), (*it)->id() ); } } return box; } else if( !mode && config && index.column() == 1 ) { KComboBox* box = new KComboBox( parent ); const QList types = Core::self()->runController()->launchConfigurationTypes(); for( QList::const_iterator it = types.begin(); it != types.end(); it++ ) { box->addItem( (*it)->name(), (*it)->id() ); } return box; } return QStyledItemDelegate::createEditor ( parent, option, index ); } LaunchConfigurationModelDelegate::LaunchConfigurationModelDelegate() { } void LaunchConfigurationModelDelegate::setEditorData ( QWidget* editor, const QModelIndex& index ) const { const LaunchConfigurationsModel* model = dynamic_cast( index.model() ); LaunchConfiguration* config = model->configForIndex( index ); if( index.column() == 1 && config ) { KComboBox* box = qobject_cast( editor ); box->setCurrentIndex( box->findData( index.data( Qt::EditRole ) ) ); } else { QStyledItemDelegate::setEditorData ( editor, index ); } } void LaunchConfigurationModelDelegate::setModelData ( QWidget* editor, QAbstractItemModel* model, const QModelIndex& index ) const { LaunchConfigurationsModel* lmodel = dynamic_cast( model ); LaunchConfiguration* config = lmodel->configForIndex( index ); if( index.column() == 1 && config ) { KComboBox* box = qobject_cast( editor ); lmodel->setData( index, box->itemData( box->currentIndex() ) ); } else { QStyledItemDelegate::setModelData ( editor, model, index ); } } void LaunchConfigurationDialog::launchModeChanged(int item) { QModelIndex index = tree->currentIndex(); if(debugger->isVisible() && item>=0) tree->model()->setData(index.sibling(index.row(), 1), debugger->itemData(item), Qt::EditRole); } } diff --git a/shell/loadedpluginsdialog.cpp b/shell/loadedpluginsdialog.cpp index 12463a0a19..10787a41e8 100644 --- a/shell/loadedpluginsdialog.cpp +++ b/shell/loadedpluginsdialog.cpp @@ -1,312 +1,312 @@ /************************************************************************** * Copyright 2009 Andreas Pakulat * * Copyright 2010 Niko Sams * * * * 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 Library 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 "loadedpluginsdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "plugincontroller.h" #define MARGIN 5 namespace { KPluginInfo pluginInfo(KDevelop::IPlugin* plugin) { return KDevelop::Core::self()->pluginControllerInternal()->pluginInfo(plugin); }; QString displayName(KDevelop::IPlugin* plugin) { const auto name = pluginInfo(plugin).name(); return !name.isEmpty() ? name : plugin->componentName(); } bool sortPlugins(KDevelop::IPlugin* l, KDevelop::IPlugin* r) { return displayName(l) < displayName(r); } } class PluginsModel : public QAbstractListModel { public: enum ExtraRoles { CommentRole = Qt::UserRole+1 }; PluginsModel(QObject* parent = 0) : QAbstractListModel(parent) { m_plugins = KDevelop::Core::self()->pluginControllerInternal()->loadedPlugins(); std::sort(m_plugins.begin(), m_plugins.end(), sortPlugins); } KDevelop::IPlugin *pluginForIndex(const QModelIndex& index) const { if (!index.isValid()) return 0; if (index.parent().isValid()) return 0; if (index.column() != 0) return 0; if (index.row() >= m_plugins.count()) return 0; return m_plugins[index.row()]; } virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const { KDevelop::IPlugin* plugin = pluginForIndex(index); if (!plugin) return QVariant(); switch (role) { case Qt::DisplayRole: return displayName(plugin); case CommentRole: return pluginInfo(plugin).comment(); case Qt::DecorationRole: return pluginInfo(plugin).icon(); default: return QVariant(); }; } virtual int rowCount(const QModelIndex& parent = QModelIndex()) const { if (!parent.isValid()) { return m_plugins.count(); } return 0; } private: QList m_plugins; }; class LoadedPluginsDelegate : public KWidgetItemDelegate { Q_OBJECT public: LoadedPluginsDelegate(QAbstractItemView *itemView, QObject *parent = 0) : KWidgetItemDelegate(itemView, parent) , pushButton(new QPushButton) { pushButton->setIcon(QIcon::fromTheme("dialog-information")); // only for getting size matters } ~LoadedPluginsDelegate() { delete pushButton; } virtual QList createItemWidgets(const QModelIndex &index) const { return QList(); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { int i = 5; int j = 1; QFont font = titleFont(option.font); QFontMetrics fmTitle(font); return QSize(qMax(fmTitle.width(index.model()->data(index, Qt::DisplayRole).toString()), option.fontMetrics.width(index.model()->data(index, PluginsModel::CommentRole).toString())) + KIconLoader::SizeMedium + MARGIN * i + pushButton->sizeHint().width() * j, qMax(KIconLoader::SizeMedium + MARGIN * 2, fmTitle.height() + option.fontMetrics.height() + MARGIN * 2)); } void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { if (!index.isValid()) { return; } painter->save(); QApplication::style()->drawPrimitive(QStyle::PE_PanelItemViewItem, &option, painter, 0); int iconSize = option.rect.height() - MARGIN * 2; QPixmap pixmap = KIconLoader::global()->loadIcon(index.model()->data(index, Qt::DecorationRole).toString(), KIconLoader::Desktop, iconSize, KIconLoader::DefaultState); painter->drawPixmap(QRect(dependantLayoutValue(MARGIN + option.rect.left(), iconSize, option.rect.width()), MARGIN + option.rect.top(), iconSize, iconSize), pixmap, QRect(0, 0, iconSize, iconSize)); QRect contentsRect(dependantLayoutValue(MARGIN * 2 + iconSize + option.rect.left(), option.rect.width() - MARGIN * 3 - iconSize, option.rect.width()), MARGIN + option.rect.top(), option.rect.width() - MARGIN * 3 - iconSize, option.rect.height() - MARGIN * 2); int lessHorizontalSpace = MARGIN * 2 + pushButton->sizeHint().width(); contentsRect.setWidth(contentsRect.width() - lessHorizontalSpace); if (option.state & QStyle::State_Selected) { painter->setPen(option.palette.highlightedText().color()); } if (itemView()->layoutDirection() == Qt::RightToLeft) { contentsRect.translate(lessHorizontalSpace, 0); } painter->save(); painter->save(); QFont font = titleFont(option.font); QFontMetrics fmTitle(font); painter->setFont(font); painter->drawText(contentsRect, Qt::AlignLeft | Qt::AlignTop, fmTitle.elidedText(index.model()->data(index, Qt::DisplayRole).toString(), Qt::ElideRight, contentsRect.width())); painter->restore(); painter->drawText(contentsRect, Qt::AlignLeft | Qt::AlignBottom, option.fontMetrics.elidedText(index.model()->data(index, PluginsModel::CommentRole).toString(), Qt::ElideRight, contentsRect.width())); painter->restore(); painter->restore(); } QList createItemWidgets() const { QPushButton *button = new QPushButton(); button->setIcon(QIcon::fromTheme("dialog-information")); setBlockedEventTypes(button, QList() << QEvent::MouseButtonPress << QEvent::MouseButtonRelease << QEvent::MouseButtonDblClick); connect(button, &QPushButton::clicked, this, &LoadedPluginsDelegate::info); return QList() << button; } void updateItemWidgets(const QList widgets, const QStyleOptionViewItem &option, const QPersistentModelIndex &index) const { Q_UNUSED(index); if ( widgets.isEmpty() ) { qDebug() << "Fixme: missing button?"; return; } QPushButton *aboutPushButton = static_cast(widgets[0]); QSize aboutPushButtonSizeHint = aboutPushButton->sizeHint(); aboutPushButton->resize(aboutPushButtonSizeHint); aboutPushButton->move(dependantLayoutValue(option.rect.width() - MARGIN - aboutPushButtonSizeHint.width(), aboutPushButtonSizeHint.width(), option.rect.width()), option.rect.height() / 2 - aboutPushButtonSizeHint.height() / 2); } int dependantLayoutValue(int value, int width, int totalWidth) const { if (itemView()->layoutDirection() == Qt::LeftToRight) { return value; } return totalWidth - width - value; } QFont titleFont(const QFont &baseFont) const { QFont retFont(baseFont); retFont.setBold(true); return retFont; } private Q_SLOTS: void info() { PluginsModel *m = static_cast(itemView()->model()); KDevelop::IPlugin *p = m->pluginForIndex(focusedIndex()); if (p) { // TODO KF5: Port // const K4AboutData *aboutData = p->componentData().aboutData(); // if (!aboutData->programName().isEmpty()) { // Be sure the about data is not completely empty // KAboutApplicationDialog aboutPlugin(aboutData, itemView()); // aboutPlugin.exec(); // return; // } } } private: QPushButton *pushButton; }; class PluginsView : public QListView { public: PluginsView(QWidget* parent = 0) :QListView(parent) { setModel(new PluginsModel()); setItemDelegate(new LoadedPluginsDelegate(this)); setVerticalScrollMode(QListView::ScrollPerPixel); } virtual ~PluginsView() { // explicitly delete the delegate here since otherwise // we get spammed by warnings that the QPushButton we return // in createItemWidgets is deleted before the delegate // *sigh* - even dfaure says KWidgetItemDelegate is a crude hack delete itemDelegate(); } virtual QSize sizeHint() const { QSize ret = QListView::sizeHint(); ret.setWidth(qMax(ret.width(), sizeHintForColumn(0) + 30)); return ret; } }; LoadedPluginsDialog::LoadedPluginsDialog( QWidget* parent ) : QDialog( parent ) { setWindowTitle(i18n("Loaded Plugins")); QVBoxLayout* vbox = new QVBoxLayout(this); KTitleWidget* title = new KTitleWidget(this); title->setPixmap(QIcon::fromTheme(KAboutData::applicationData().programIconName()), KTitleWidget::ImageLeft); title->setText(i18n("Plugins loaded for %1", KAboutData::applicationData().displayName())); vbox->addWidget(title); vbox->addWidget(new PluginsView()); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &LoadedPluginsDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &LoadedPluginsDialog::reject); buttonBox->button(QDialogButtonBox::Close)->setDefault(true); vbox->addWidget(buttonBox); } #include "moc_loadedpluginsdialog.cpp" #include "loadedpluginsdialog.moc" diff --git a/shell/projectcontroller.cpp b/shell/projectcontroller.cpp index 5543d25672..6eeb434609 100644 --- a/shell/projectcontroller.cpp +++ b/shell/projectcontroller.cpp @@ -1,1184 +1,1184 @@ /* This file is part of KDevelop Copyright 2006 Adam Treat Copyright 2007 Andreas Pakulat 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 "projectcontroller.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "project.h" #include "mainwindow.h" #include "shellextension.h" #include "plugincontroller.h" #include "configdialog.h" #include "uicontroller.h" #include "documentcontroller.h" #include "openprojectdialog.h" #include #include #include #include #include "sessioncontroller.h" #include "session.h" #include "debug.h" #include #include #include #include #include #include namespace KDevelop { class ProjectControllerPrivate { public: QList m_projects; QMap< IProject*, QList > m_projectPlugins; QPointer m_recentAction; Core* m_core; // IProject* m_currentProject; ProjectModel* model; QItemSelectionModel* selectionModel; QPointer m_openProject; QPointer m_fetchProject; QPointer m_closeProject; QPointer m_openConfig; IProjectDialogProvider* dialog; QList m_currentlyOpening; // project-file urls that are being opened IProject* m_configuringProject; ProjectController* q; ProjectBuildSetModel* buildset; bool m_foundProjectFile; //Temporary flag used while searching the hierarchy for a project file bool m_cleaningUp; //Temporary flag enabled while destroying the project-controller QPointer m_changesModel; QHash< IProject*, QPointer > m_parseJobs; // parse jobs that add files from the project to the background parser. ProjectControllerPrivate( ProjectController* p ) : m_core(0), model(0), selectionModel(0), dialog(0), m_configuringProject(0), q(p), buildset(0), m_foundProjectFile(false), m_cleaningUp(false) { } void unloadAllProjectPlugins() { if( m_projects.isEmpty() ) m_core->pluginControllerInternal()->unloadProjectPlugins(); } void projectConfig( QObject * obj ) { if( !obj ) return; Project* proj = qobject_cast(obj); if( !proj ) return; QVector configPages; auto mainWindow = m_core->uiController()->activeMainWindow(); ProjectConfigOptions options; options.developerFile = proj->developerFile(); options.developerTempFile = proj->developerTempFile(); options.projectTempFile = proj->projectTempFile(); options.project = proj; for (IPlugin* plugin : findPluginsForProject(proj)) { for (int i = 0; i < plugin->perProjectConfigPages(); ++i) { configPages.append(plugin->perProjectConfigPage(i, options, mainWindow)); } } Q_ASSERT(!m_configuringProject); m_configuringProject = proj; KDevelop::ConfigDialog cfgDlg(configPages, mainWindow); QObject::connect(&cfgDlg, &ConfigDialog::configSaved, &cfgDlg, [this](ConfigPage* page) { Q_UNUSED(page) Q_ASSERT_X(m_configuringProject, Q_FUNC_INFO, "ConfigDialog signalled project config change, but no project set for configuring!"); emit q->projectConfigurationChanged(m_configuringProject); }); cfgDlg.setWindowTitle(i18n("Configure Project %1", proj->name())); cfgDlg.exec(); proj->projectConfiguration()->sync(); m_configuringProject = nullptr; } void saveListOfOpenedProjects() { auto activeSession = Core::self()->activeSession(); if (!activeSession) { return; } QList openProjects; openProjects.reserve( m_projects.size() ); foreach( IProject* project, m_projects ) { openProjects.append(project->projectFile().toUrl()); } activeSession->setContainedProjects( openProjects ); } // Recursively collects builder dependencies for a project. static void collectBuilders( QList< IProjectBuilder* >& destination, IProjectBuilder* topBuilder, IProject* project ) { QList< IProjectBuilder* > auxBuilders = topBuilder->additionalBuilderPlugins( project ); destination.append( auxBuilders ); foreach( IProjectBuilder* auxBuilder, auxBuilders ) { collectBuilders( destination, auxBuilder, project ); } } QVector findPluginsForProject( IProject* project ) { QList plugins = m_core->pluginController()->loadedPlugins(); QVector projectPlugins; QList buildersForKcm; // Important to also include the "top" builder for the project, so // projects with only one such builder are kept working. Otherwise the project config // dialog is empty for such cases. if( IBuildSystemManager* buildSystemManager = project->buildSystemManager() ) { buildersForKcm << buildSystemManager->builder(); collectBuilders( buildersForKcm, buildSystemManager->builder(), project ); } for(auto plugin : plugins) { const KPluginInfo info = m_core->pluginController()->pluginInfo( plugin ); IProjectFileManager* manager = plugin->extension(); if( manager && manager != project->projectFileManager() ) { // current plugin is a manager but does not apply to given project, skip continue; } IProjectBuilder* builder = plugin->extension(); if ( builder && !buildersForKcm.contains( builder ) ) { continue; } qCDebug(SHELL) << "Using plugin" << info.pluginName() << "for project" << project->name(); projectPlugins << plugin; } return projectPlugins; } void updateActionStates( Context* ctx ) { ProjectItemContext* itemctx = dynamic_cast(ctx); m_openConfig->setEnabled( itemctx && itemctx->items().count() == 1 ); m_closeProject->setEnabled( itemctx && itemctx->items().count() > 0 ); } void openProjectConfig() { ProjectItemContext* ctx = dynamic_cast( Core::self()->selectionController()->currentSelection() ); if( ctx && ctx->items().count() == 1 ) { q->configureProject( ctx->items().at(0)->project() ); } } void closeSelectedProjects() { ProjectItemContext* ctx = dynamic_cast( Core::self()->selectionController()->currentSelection() ); if( ctx && ctx->items().count() > 0 ) { QSet projects; foreach( ProjectBaseItem* item, ctx->items() ) { projects.insert( item->project() ); } foreach( IProject* project, projects ) { q->closeProject( project ); } } } void importProject(const QUrl& url_) { QUrl url(url_); if ( url.isLocalFile() ) { QString path = QFileInfo( url.toLocalFile() ).canonicalFilePath(); if ( !path.isEmpty() ) url.setPath( path ); } if ( !url.isValid() ) { KMessageBox::error(Core::self()->uiControllerInternal()->activeMainWindow(), i18n("Invalid Location: %1", url.toDisplayString(QUrl::PreferLocalFile))); return; } if ( m_currentlyOpening.contains(url)) { qCDebug(SHELL) << "Already opening " << url << ". Aborting."; KPassivePopup::message( i18n( "Project already being opened"), i18n( "Already opening %1, not opening again", url.toDisplayString(QUrl::PreferLocalFile) ), m_core->uiController()->activeMainWindow() ); return; } foreach( IProject* project, m_projects ) { if ( url == project->projectFileUrl() ) { if ( dialog->userWantsReopen() ) { // close first, then open again by falling through q->closeProject(project); } else { // abort return; } } } m_currentlyOpening += url; m_core->pluginControllerInternal()->loadProjectPlugins(); Project* project = new Project(); QObject::connect(project, &Project::aboutToOpen, q, &ProjectController::projectAboutToBeOpened); if ( !project->open( Path(url) ) ) { m_currentlyOpening.removeAll(url); q->abortOpeningProject(project); project->deleteLater(); } } void areaChanged(Sublime::Area* area) { KActionCollection* ac = m_core->uiControllerInternal()->defaultMainWindow()->actionCollection(); ac->action("commit_current_project")->setEnabled(area->objectName() == "code"); ac->action("commit_current_project")->setVisible(area->objectName() == "code"); } }; IProjectDialogProvider::IProjectDialogProvider() {} IProjectDialogProvider::~IProjectDialogProvider() {} ProjectDialogProvider::ProjectDialogProvider(ProjectControllerPrivate* const p) : d(p) {} ProjectDialogProvider::~ProjectDialogProvider() {} bool writeNewProjectFile( const QString& localConfigFile, const QString& name, const QString& manager ) { KSharedConfigPtr cfg = KSharedConfig::openConfig( localConfigFile, KConfig::SimpleConfig ); if (!cfg->isConfigWritable(true)) { qCDebug(SHELL) << "can't write to configfile"; return false; } KConfigGroup grp = cfg->group( "Project" ); grp.writeEntry( "Name", name ); grp.writeEntry( "Manager", manager ); cfg->sync(); return true; } bool writeProjectSettingsToConfigFile(const QUrl& projectFileUrl, const QString& projectName, const QString& projectManager) { if ( !projectFileUrl.isLocalFile() ) { QTemporaryFile tmp; if ( !tmp.open() ) { return false; } if ( !writeNewProjectFile( tmp.fileName(), projectName, projectManager ) ) { return false; } // explicitly close file before uploading it, see also: https://bugs.kde.org/show_bug.cgi?id=254519 tmp.close(); auto uploadJob = KIO::file_copy(QUrl::fromLocalFile(tmp.fileName()), projectFileUrl); KJobWidgets::setWindow(uploadJob, Core::self()->uiControllerInternal()->defaultMainWindow()); return uploadJob->exec(); } return writeNewProjectFile( projectFileUrl.toLocalFile(),projectName, projectManager ); } bool projectFileExists( const QUrl& u ) { if( u.isLocalFile() ) { return QFileInfo( u.toLocalFile() ).exists(); } else { auto statJob = KIO::stat(u, KIO::StatJob::DestinationSide, 0); KJobWidgets::setWindow(statJob, Core::self()->uiControllerInternal()->activeMainWindow()); return statJob->exec(); } } bool equalProjectFile( const QString& configPath, OpenProjectDialog* dlg ) { KSharedConfigPtr cfg = KSharedConfig::openConfig( configPath, KConfig::SimpleConfig ); KConfigGroup grp = cfg->group( "Project" ); QString defaultName = dlg->projectFileUrl().adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).fileName(); return (grp.readEntry( "Name", QString() ) == dlg->projectName() || dlg->projectName() == defaultName) && grp.readEntry( "Manager", QString() ) == dlg->projectManager(); } QUrl ProjectDialogProvider::askProjectConfigLocation(bool fetch, const QUrl& startUrl) { Q_ASSERT(d); OpenProjectDialog dlg( fetch, startUrl, Core::self()->uiController()->activeMainWindow() ); if(dlg.exec() == QDialog::Rejected) return QUrl(); QUrl projectFileUrl = dlg.projectFileUrl(); qCDebug(SHELL) << "selected project:" << projectFileUrl << dlg.projectName() << dlg.projectManager(); // controls if existing project file should be saved bool writeProjectConfigToFile = true; if( projectFileExists( projectFileUrl ) ) { // check whether config is equal bool shouldAsk = true; if( projectFileUrl.isLocalFile() ) { shouldAsk = !equalProjectFile( projectFileUrl.toLocalFile(), &dlg ); } else { shouldAsk = false; QTemporaryFile tmpFile; if (tmpFile.open()) { auto downloadJob = KIO::file_copy(projectFileUrl, QUrl::fromLocalFile(tmpFile.fileName())); KJobWidgets::setWindow(downloadJob, qApp->activeWindow()); if (downloadJob->exec()) { shouldAsk = !equalProjectFile(tmpFile.fileName(), &dlg); } } } if ( shouldAsk ) { KGuiItem yes = KStandardGuiItem::yes(); yes.setText(i18n("Override")); yes.setToolTip(i18nc("@info:tooltip", "Continue to open the project and use the just provided project configuration.")); yes.setIcon(QIcon()); KGuiItem no = KStandardGuiItem::no(); no.setText(i18n("Open Existing File")); no.setToolTip(i18nc("@info:tooltip", "Continue to open the project but use the existing project configuration.")); no.setIcon(QIcon()); KGuiItem cancel = KStandardGuiItem::cancel(); cancel.setToolTip(i18nc("@info:tooltip", "Cancel and do not open the project.")); int ret = KMessageBox::questionYesNoCancel(qApp->activeWindow(), i18n("There already exists a project configuration file at %1.\n" "Do you want to override it or open the existing file?", projectFileUrl.toDisplayString(QUrl::PreferLocalFile)), i18n("Override existing project configuration"), yes, no, cancel ); if ( ret == KMessageBox::No ) { writeProjectConfigToFile = false; } else if ( ret == KMessageBox::Cancel ) { return QUrl(); } // else fall through and write new file } else { writeProjectConfigToFile = false; } } if (writeProjectConfigToFile) { if (!writeProjectSettingsToConfigFile(projectFileUrl, dlg.projectName(), dlg.projectManager())) { KMessageBox::error(d->m_core->uiControllerInternal()->defaultMainWindow(), i18n("Unable to create configuration file %1", projectFileUrl.url())); return QUrl(); } } return projectFileUrl; } bool ProjectDialogProvider::userWantsReopen() { Q_ASSERT(d); return (KMessageBox::questionYesNo( d->m_core->uiControllerInternal()->defaultMainWindow(), i18n( "Reopen the current project?" ) ) == KMessageBox::No) ? false : true; } void ProjectController::setDialogProvider(IProjectDialogProvider* dialog) { Q_ASSERT(d->dialog); delete d->dialog; d->dialog = dialog; } ProjectController::ProjectController( Core* core ) : IProjectController( core ), d( new ProjectControllerPrivate( this ) ) { qRegisterMetaType>(); setObjectName("ProjectController"); d->m_core = core; d->model = new ProjectModel(); //NOTE: this is required to be called here, such that the // actions are available when the UI controller gets // initialized *before* the project controller if (Core::self()->setupFlags() != Core::NoUi) { setupActions(); } } void ProjectController::setupActions() { KActionCollection * ac = d->m_core->uiControllerInternal()->defaultMainWindow()->actionCollection(); QAction*action; d->m_openProject = action = ac->addAction( "project_open" ); action->setText(i18nc( "@action", "Open / Import Project..." ) ); action->setToolTip( i18nc( "@info:tooltip", "Open or import project" ) ); action->setWhatsThis( i18nc( "@info:whatsthis", "Open an existing KDevelop 4 project or import " "an existing Project into KDevelop 4. This entry " "allows to select a KDevelop4 project file or an " "existing directory to open it in KDevelop. " "When opening an existing directory that does " "not yet have a KDevelop4 project file, the file " "will be created." ) ); action->setIcon(QIcon::fromTheme("project-open")); connect(action, &QAction::triggered, this, [&] { openProject(); }); d->m_fetchProject = action = ac->addAction( "project_fetch" ); action->setText(i18nc( "@action", "Fetch Project..." ) ); action->setIcon( QIcon::fromTheme( "download" ) ); action->setToolTip( i18nc( "@info:tooltip", "Fetch project" ) ); action->setWhatsThis( i18nc( "@info:whatsthis", "Guides the user through the project fetch " "and then imports it into KDevelop 4." ) ); // action->setIcon(QIcon::fromTheme("project-open")); connect( action, &QAction::triggered, this, &ProjectController::fetchProject ); // action = ac->addAction( "project_close" ); // action->setText( i18n( "C&lose Project" ) ); // connect( action, SIGNAL(triggered(bool)), SLOT(closeProject()) ); // action->setToolTip( i18n( "Close project" ) ); // action->setWhatsThis( i18n( "Closes the current project." ) ); // action->setEnabled( false ); d->m_closeProject = action = ac->addAction( "project_close" ); connect( action, &QAction::triggered, this, [&] { d->closeSelectedProjects(); } ); action->setText( i18nc( "@action", "Close Project(s)" ) ); action->setIcon( QIcon::fromTheme( "project-development-close" ) ); action->setToolTip( i18nc( "@info:tooltip", "Closes all currently selected projects" ) ); action->setEnabled( false ); d->m_openConfig = action = ac->addAction( "project_open_config" ); connect( action, &QAction::triggered, this, [&] { d->openProjectConfig(); } ); action->setText( i18n( "Open Configuration..." ) ); action->setIcon( QIcon::fromTheme("configure") ); action->setEnabled( false ); action = ac->addAction( "commit_current_project" ); connect( action, &QAction::triggered, this, &ProjectController::commitCurrentProject ); action->setText( i18n( "Commit Current Project..." ) ); action->setIconText( i18n( "Commit..." ) ); action->setIcon( QIcon::fromTheme("svn-commit") ); connect(d->m_core->uiControllerInternal()->defaultMainWindow(), &MainWindow::areaChanged, this, [&] (Sublime::Area* area) { d->areaChanged(area); }); d->m_core->uiControllerInternal()->area(0, "code")->addAction(action); KSharedConfig * config = KSharedConfig::openConfig().data(); // KConfigGroup group = config->group( "General Options" ); d->m_recentAction = KStandardAction::openRecent(this, SLOT(openProject(QUrl)), this); ac->addAction( "project_open_recent", d->m_recentAction ); d->m_recentAction->setText( i18n( "Open Recent Project" ) ); d->m_recentAction->setWhatsThis( i18nc( "@info:whatsthis", "Opens recently opened project." ) ); d->m_recentAction->loadEntries( KConfigGroup(config, "RecentProjects") ); QAction* openProjectForFileAction = new QAction( this ); ac->addAction("project_open_for_file", openProjectForFileAction); openProjectForFileAction->setText(i18n("Open Project for Current File")); connect( openProjectForFileAction, &QAction::triggered, this, &ProjectController::openProjectForUrlSlot); } ProjectController::~ProjectController() { delete d->model; delete d->dialog; delete d; } void ProjectController::cleanup() { if ( d->m_currentlyOpening.isEmpty() ) { d->saveListOfOpenedProjects(); } d->m_cleaningUp = true; if( buildSetModel() ) { buildSetModel()->storeToSession( Core::self()->activeSession() ); } foreach( IProject* project, d->m_projects ) { closeProject( project ); } } void ProjectController::initialize() { d->buildset = new ProjectBuildSetModel( this ); buildSetModel()->loadFromSession( Core::self()->activeSession() ); connect( this, &ProjectController::projectOpened, d->buildset, &ProjectBuildSetModel::loadFromProject ); connect( this, &ProjectController::projectClosing, d->buildset, &ProjectBuildSetModel::saveToProject ); connect( this, &ProjectController::projectClosed, d->buildset, &ProjectBuildSetModel::projectClosed ); d->selectionModel = new QItemSelectionModel(d->model); loadSettings(false); d->dialog = new ProjectDialogProvider(d); QDBusConnection::sessionBus().registerObject( "/org/kdevelop/ProjectController", this, QDBusConnection::ExportScriptableSlots ); KSharedConfigPtr config = Core::self()->activeSession()->config(); KConfigGroup group = config->group( "General Options" ); QList openProjects = group.readEntry( "Open Projects", QList() ); QMetaObject::invokeMethod(this, "openProjects", Qt::QueuedConnection, Q_ARG(QList, openProjects)); connect( Core::self()->selectionController(), &ISelectionController::selectionChanged, this, [&] (Context* ctx) { d->updateActionStates(ctx); } ); } void ProjectController::openProjects(const QList& projects) { foreach (const QUrl& url, projects) openProject(url); } void ProjectController::loadSettings( bool projectIsLoaded ) { Q_UNUSED(projectIsLoaded) } void ProjectController::saveSettings( bool projectIsLoaded ) { Q_UNUSED( projectIsLoaded ); } int ProjectController::projectCount() const { return d->m_projects.count(); } IProject* ProjectController::projectAt( int num ) const { if( !d->m_projects.isEmpty() && num >= 0 && num < d->m_projects.count() ) return d->m_projects.at( num ); return 0; } QList ProjectController::projects() const { return d->m_projects; } void ProjectController::eventuallyOpenProjectFile(KIO::Job* _job, KIO::UDSEntryList entries ) { KIO::SimpleJob* job(dynamic_cast(_job)); Q_ASSERT(job); foreach(const KIO::UDSEntry& entry, entries) { if(d->m_foundProjectFile) break; if(!entry.isDir()) { QString name = entry.stringValue( KIO::UDSEntry::UDS_NAME ); if(name.endsWith(".kdev4")) { //We have found a project-file, open it openProject(Path(Path(job->url()), name).toUrl()); d->m_foundProjectFile = true; } } } } void ProjectController::openProjectForUrlSlot(bool) { if(ICore::self()->documentController()->activeDocument()) { QUrl url = ICore::self()->documentController()->activeDocument()->url(); IProject* project = ICore::self()->projectController()->findProjectForUrl(url); if(!project) { openProjectForUrl(url); }else{ KMessageBox::error(Core::self()->uiController()->activeMainWindow(), i18n("Project already open: %1", project->name())); } }else{ KMessageBox::error(Core::self()->uiController()->activeMainWindow(), i18n("No active document")); } } void ProjectController::openProjectForUrl(const QUrl& sourceUrl) { Q_ASSERT(!sourceUrl.isRelative()); QUrl dirUrl = sourceUrl.adjusted(QUrl::RemoveFilename); QUrl testAt = dirUrl; d->m_foundProjectFile = false; while(!testAt.path().isEmpty()) { QUrl testProjectFile(testAt); KIO::ListJob* job = KIO::listDir(testAt); connect(job, &KIO::ListJob::entries, this, &ProjectController::eventuallyOpenProjectFile); KJobWidgets::setWindow(job, ICore::self()->uiController()->activeMainWindow()); job->exec(); if(d->m_foundProjectFile) { //Fine! We have directly opened the project d->m_foundProjectFile = false; return; } QUrl oldTest = testAt.adjusted(QUrl::RemoveFilename); if(oldTest == testAt) break; } QUrl askForOpen = d->dialog->askProjectConfigLocation(false, dirUrl); if(askForOpen.isValid()) openProject(askForOpen); } void ProjectController::openProject( const QUrl &projectFile ) { QUrl url = projectFile; if ( url.isEmpty() ) { url = d->dialog->askProjectConfigLocation(false); if ( url.isEmpty() ) { return; } } Q_ASSERT(!url.isRelative()); QList existingSessions; if(!Core::self()->sessionController()->activeSession()->containedProjects().contains(url)) { foreach( const Session* session, Core::self()->sessionController()->sessions()) { if(session->containedProjects().contains(url)) { existingSessions << session; #if 0 ///@todo Think about this! Problem: The session might already contain files, the debugger might be active, etc. //If this session is empty, close it if(Core::self()->sessionController()->activeSession()->description().isEmpty()) { //Terminate this instance of kdevelop if the user agrees foreach(Sublime::MainWindow* window, Core::self()->uiController()->controller()->mainWindows()) window->close(); } #endif } } } if ( ! existingSessions.isEmpty() ) { QDialog dialog(Core::self()->uiControllerInternal()->activeMainWindow()); dialog.setWindowTitle(i18n("Project Already Open")); auto mainLayout = new QVBoxLayout(&dialog); mainLayout->addWidget(new QLabel(i18n("The project you're trying to open is already open in at least one " "other session.
What do you want to do?"))); QGroupBox sessions; sessions.setLayout(new QVBoxLayout); QRadioButton* newSession = new QRadioButton(i18n("Add project to current session")); sessions.layout()->addWidget(newSession); newSession->setChecked(true); foreach ( const Session* session, existingSessions ) { QRadioButton* button = new QRadioButton(i18n("Open session %1", session->description())); button->setProperty("sessionid", session->id().toString()); sessions.layout()->addWidget(button); } sessions.layout()->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding)); mainLayout->addWidget(&sessions); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Abort); auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); mainLayout->addWidget(buttonBox); bool success = dialog.exec(); if (!success) return; foreach ( const QObject* obj, sessions.children() ) { if ( const QRadioButton* button = qobject_cast(obj) ) { QString sessionid = button->property("sessionid").toString(); if ( button->isChecked() && ! sessionid.isEmpty() ) { Core::self()->sessionController()->loadSession(sessionid); return; } } } } if ( url.isEmpty() ) { url = d->dialog->askProjectConfigLocation(false); } if ( !url.isEmpty() ) { d->importProject(url); } } void ProjectController::fetchProject() { QUrl url = d->dialog->askProjectConfigLocation(true); if ( !url.isEmpty() ) { d->importProject(url); } } void ProjectController::projectImportingFinished( IProject* project ) { if( !project ) { qWarning() << "OOOPS: 0-pointer project"; return; } IPlugin *managerPlugin = project->managerPlugin(); QList pluglist; pluglist.append( managerPlugin ); d->m_projectPlugins.insert( project, pluglist ); d->m_projects.append( project ); d->saveListOfOpenedProjects(); if (Core::self()->setupFlags() != Core::NoUi) { d->m_recentAction->addUrl( project->projectFileUrl() ); KSharedConfig * config = KSharedConfig::openConfig().data(); KConfigGroup recentGroup = config->group("RecentProjects"); d->m_recentAction->saveEntries( recentGroup ); config->sync(); } Q_ASSERT(d->m_currentlyOpening.contains(project->projectFileUrl())); d->m_currentlyOpening.removeAll(project->projectFileUrl()); emit projectOpened( project ); reparseProject(project); } // helper method for closeProject() void ProjectController::unloadUnusedProjectPlugins(IProject* proj) { QList pluginsForProj = d->m_projectPlugins.value( proj ); d->m_projectPlugins.remove( proj ); QList otherProjectPlugins; Q_FOREACH( const QList& _list, d->m_projectPlugins ) { otherProjectPlugins << _list; } QSet pluginsForProjSet = QSet::fromList( pluginsForProj ); QSet otherPrjPluginsSet = QSet::fromList( otherProjectPlugins ); // loaded - target = tobe unloaded. QSet tobeRemoved = pluginsForProjSet.subtract( otherPrjPluginsSet ); Q_FOREACH( IPlugin* _plugin, tobeRemoved ) { KPluginInfo _plugInfo = Core::self()->pluginController()->pluginInfo( _plugin ); if( _plugInfo.isValid() ) { QString _plugName = _plugInfo.pluginName(); qCDebug(SHELL) << "about to unloading :" << _plugName; Core::self()->pluginController()->unloadPlugin( _plugName ); } } } // helper method for closeProject() void ProjectController::closeAllOpenedFiles(IProject* proj) { foreach(IDocument* doc, Core::self()->documentController()->openDocuments()) { if (proj->inProject(IndexedString(doc->url()))) { doc->close(); } } } // helper method for closeProject() void ProjectController::initializePluginCleanup(IProject* proj) { // Unloading (and thus deleting) these plugins is not a good idea just yet // as we're being called by the view part and it gets deleted when we unload the plugin(s) // TODO: find a better place to unload connect(proj, &IProject::destroyed, this, [&] { d->unloadAllProjectPlugins(); }); } void ProjectController::closeProject(IProject* proj_) { if (!proj_) { return; } // loading might have failed d->m_currentlyOpening.removeAll(proj_->projectFileUrl()); Project* proj = dynamic_cast( proj_ ); if( !proj ) { qWarning() << "Unknown Project subclass found!"; return; } d->m_projects.removeAll(proj); emit projectClosing(proj); //Core::self()->saveSettings(); // The project file is being closed. // Now we can save settings for all of the Core // objects including this one!! unloadUnusedProjectPlugins(proj); closeAllOpenedFiles(proj); proj->close(); proj->deleteLater(); //be safe when deleting if (d->m_projects.isEmpty()) { initializePluginCleanup(proj); } if(!d->m_cleaningUp) d->saveListOfOpenedProjects(); emit projectClosed(proj); return; } void ProjectController::abortOpeningProject(IProject* proj) { d->m_currentlyOpening.removeAll(proj->projectFileUrl()); emit projectOpeningAborted(proj); } ProjectModel* ProjectController::projectModel() { return d->model; } IProject* ProjectController::findProjectForUrl( const QUrl& url ) const { if (d->m_projects.isEmpty()) { return 0; } ProjectBaseItem* item = d->model->itemForPath(IndexedString(url)); if (item) { return item->project(); } return 0; } IProject* ProjectController::findProjectByName( const QString& name ) { Q_FOREACH( IProject* proj, d->m_projects ) { if( proj->name() == name ) { return proj; } } return 0; } void ProjectController::configureProject( IProject* project ) { d->projectConfig( project ); } void ProjectController::addProject(IProject* project) { d->m_projects.append( project ); } QItemSelectionModel* ProjectController::projectSelectionModel() { return d->selectionModel; } bool ProjectController::isProjectNameUsed( const QString& name ) const { foreach( IProject* p, projects() ) { if( p->name() == name ) { return true; } } return false; } QUrl ProjectController::projectsBaseDirectory() const { KConfigGroup group = ICore::self()->activeSession()->config()->group( "Project Manager" ); return group.readEntry( "Projects Base Directory", QUrl::fromLocalFile( QDir::homePath() + "/projects" ) ); } QString ProjectController::prettyFilePath(const QUrl& url, FormattingOptions format) const { IProject* project = Core::self()->projectController()->findProjectForUrl(url); if(!project) { // Find a project with the correct base directory at least foreach(IProject* candidateProject, Core::self()->projectController()->projects()) { if(candidateProject->folder().isParentOf(url)) { project = candidateProject; break; } } } Path parent = Path(url).parent(); QString prefixText; if (project) { if (format == FormatHtml) { prefixText = "" + project->name() + "/"; } else { prefixText = project->name() + '/'; } QString relativePath = project->path().relativePath(parent); if(relativePath.startsWith("./")) { relativePath = relativePath.mid(2); } if (!relativePath.isEmpty()) { prefixText += relativePath + '/'; } } else { prefixText = parent.pathOrUrl() + '/'; } return prefixText; } QString ProjectController::prettyFileName(const QUrl& url, FormattingOptions format) const { IProject* project = Core::self()->projectController()->findProjectForUrl(url); if(project && project->path() == Path(url)) { if (format == FormatHtml) { return "" + project->name() + ""; } else { return project->name(); } } QString prefixText = prettyFilePath( url, format ); if (format == FormatHtml) { return prefixText + "" + url.fileName() + ""; } else { return prefixText + url.fileName(); } } ContextMenuExtension ProjectController::contextMenuExtension ( Context* ctx ) { ContextMenuExtension ext; if ( ctx->type() != Context::ProjectItemContext || !static_cast(ctx)->items().isEmpty() ) { return ext; } ext.addAction(ContextMenuExtension::ProjectGroup, d->m_openProject); ext.addAction(ContextMenuExtension::ProjectGroup, d->m_fetchProject); ext.addAction(ContextMenuExtension::ProjectGroup, d->m_recentAction); return ext; } ProjectBuildSetModel* ProjectController::buildSetModel() { return d->buildset; } ProjectChangesModel* ProjectController::changesModel() { if(!d->m_changesModel) d->m_changesModel=new ProjectChangesModel(this); return d->m_changesModel; } void ProjectController::commitCurrentProject() { IDocument* doc=ICore::self()->documentController()->activeDocument(); if(!doc) return; QUrl url=doc->url(); IProject* project = ICore::self()->projectController()->findProjectForUrl(url); if(project && project->versionControlPlugin()) { IPlugin* plugin = project->versionControlPlugin(); IBasicVersionControl* vcs=plugin->extension(); if(vcs) { ICore::self()->documentController()->saveAllDocuments(KDevelop::IDocument::Silent); const Path basePath = project->path(); VCSCommitDiffPatchSource* patchSource = new VCSCommitDiffPatchSource(new VCSStandardDiffUpdater(vcs, basePath.toUrl())); bool ret = showVcsDiff(patchSource); if(!ret) { VcsCommitDialog *commitDialog = new VcsCommitDialog(patchSource); commitDialog->setCommitCandidates(patchSource->infos()); commitDialog->exec(); } } } } QString ProjectController::mapSourceBuild( const QString& path_, bool reverse, bool fallbackRoot ) const { Path path(path_); IProject* sourceDirProject = 0, *buildDirProject = 0; Q_FOREACH(IProject* proj, d->m_projects) { if(proj->path().isParentOf(path)) sourceDirProject = proj; if(proj->buildSystemManager()) { Path buildDir = proj->buildSystemManager()->buildDirectory(proj->projectItem()); if(buildDir.isValid() && buildDir.isParentOf(path)) buildDirProject = proj; } } if(!reverse) { // Map-target is the build directory if(sourceDirProject && sourceDirProject->buildSystemManager()) { // We're in the source, map into the build directory QString relativePath = sourceDirProject->path().relativePath(path); Path build = sourceDirProject->buildSystemManager()->buildDirectory(sourceDirProject->projectItem()); build.addPath(relativePath); while(!QFile::exists(build.path())) build = build.parent(); return build.pathOrUrl(); }else if(buildDirProject && fallbackRoot) { // We're in the build directory, map to the build directory root return buildDirProject->buildSystemManager()->buildDirectory(buildDirProject->projectItem()).pathOrUrl(); } }else{ // Map-target is the source directory if(buildDirProject) { Path build = buildDirProject->buildSystemManager()->buildDirectory(buildDirProject->projectItem()); // We're in the source, map into the build directory QString relativePath = build.relativePath(path); Path source = buildDirProject->path(); source.addPath(relativePath); while(!QFile::exists(source.path())) source = source.parent(); return source.pathOrUrl(); }else if(sourceDirProject && fallbackRoot) { // We're in the source directory, map to the root return sourceDirProject->path().pathOrUrl(); } } return QString(); } void ProjectController::reparseProject( IProject* project, bool forceUpdate ) { if (auto job = d->m_parseJobs.value(project)) { job->kill(); } d->m_parseJobs[project] = new KDevelop::ParseProjectJob(project, forceUpdate); ICore::self()->runController()->registerJob(d->m_parseJobs[project]); } } #include "moc_projectcontroller.cpp" diff --git a/shell/savedialog.cpp b/shell/savedialog.cpp index 044e46b322..ff52cfd19e 100644 --- a/shell/savedialog.cpp +++ b/shell/savedialog.cpp @@ -1,99 +1,99 @@ /* This file is part of the KDE project Copyright (C) 2002 Harald Fernengel Copyright (C) 2008 Hamish Rodda 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 "savedialog.h" #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; class DocumentItem : public QListWidgetItem { public: DocumentItem( IDocument* doc, QListWidget* parent ) : QListWidgetItem(parent) , m_doc( doc ) { setFlags(Qt::ItemIsUserCheckable | flags()); setData(Qt::CheckStateRole, Qt::Checked); setText(m_doc->url().toDisplayString(QUrl::PreferLocalFile)); } IDocument* doc() const { return m_doc; } private: IDocument* m_doc; }; KSaveSelectDialog::KSaveSelectDialog( const QList& files, QWidget * parent ) : QDialog( parent ) { setWindowTitle( i18n("Save Modified Files?") ); auto mainLayout = new QVBoxLayout(this); mainLayout->addWidget(new QLabel( i18n("The following files have been modified. Save them?"), this )); m_listWidget = new QListWidget(this); mainLayout->addWidget(m_listWidget); // m_listWidget->addColumn( "" ); // m_listWidget->header()->hide(); // m_listWidget->setSectionResizeMode( QListView::LastColumn ); foreach (IDocument* doc, files) new DocumentItem( doc, m_listWidget ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Save|QDialogButtonBox::Cancel); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Save); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(save())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &KSaveSelectDialog::save); + connect(buttonBox, &QDialogButtonBox::rejected, this, &KSaveSelectDialog::reject); auto user1Button = buttonBox->addButton(i18n("Save &None" ), QDialogButtonBox::ActionRole); user1Button->setToolTip(i18n("Discard all modifications" )); - connect(user1Button, SIGNAL(clicked()), this, SLOT(accept())); + connect(user1Button, &QPushButton::clicked, this, &KSaveSelectDialog::accept); mainLayout->addWidget(buttonBox); } KSaveSelectDialog::~KSaveSelectDialog() { } void KSaveSelectDialog::save( ) { for (int i = 0; i < m_listWidget->count(); ++i) { DocumentItem* item = static_cast(m_listWidget->item(i)); if (item->data(Qt::CheckStateRole).toBool()) item->doc()->save(IDocument::Silent); } accept(); } diff --git a/shell/sessionchooserdialog.cpp b/shell/sessionchooserdialog.cpp index 5538d0c749..23ad60b939 100644 --- a/shell/sessionchooserdialog.cpp +++ b/shell/sessionchooserdialog.cpp @@ -1,236 +1,236 @@ /* This file is part of KDevelop Copyright 2008 Andreas Pakulat Copyright 2010 David Nolden 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 "sessionchooserdialog.h" #include "sessioncontroller.h" #include "core.h" #include #include #include #include #include #include #include #include #include using namespace KDevelop; SessionChooserDialog::SessionChooserDialog(QListView* view, QAbstractItemModel* model, QLineEdit* filter) : m_view(view), m_model(model), m_filter(filter), m_deleteCandidateRow(-1) { m_updateStateTimer.setInterval(5000); m_updateStateTimer.setSingleShot(false); m_updateStateTimer.start(); connect(&m_updateStateTimer, &QTimer::timeout, this, &SessionChooserDialog::updateState); connect(view, &QListView::doubleClicked, this, &SessionChooserDialog::doubleClicked); connect(view, &QListView::entered, this, &SessionChooserDialog::itemEntered); m_deleteButton = new QPushButton(view->viewport()); m_deleteButton->setIcon(QIcon::fromTheme("edit-delete")); m_deleteButton->setToolTip(i18nc("@info", "Delete session")); m_deleteButton->hide(); connect(m_deleteButton, &QPushButton::clicked, this, &SessionChooserDialog::deleteButtonPressed); m_deleteButtonTimer.setInterval(500); m_deleteButtonTimer.setSingleShot(true); connect(&m_deleteButtonTimer, &QTimer::timeout, this, &SessionChooserDialog::showDeleteButton); view->setMouseTracking(true); view->installEventFilter(this); filter->installEventFilter(this); connect(filter, &QLineEdit::textChanged, this, &SessionChooserDialog::filterTextChanged); setWindowTitle(i18n("Pick a Session")); m_buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Close); auto mainLayout = new QVBoxLayout(this); m_mainWidget = new QWidget(this); mainLayout->addWidget(m_mainWidget); QPushButton *okButton = m_buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::Key_Return); - connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(m_buttonBox, &QDialogButtonBox::accepted, this, &SessionChooserDialog::accept); + connect(m_buttonBox, &QDialogButtonBox::rejected, this, &SessionChooserDialog::reject); mainLayout->addWidget(m_buttonBox); okButton->setText(i18n("Run")); okButton->setIcon(QIcon::fromTheme("media-playback-start")); } void SessionChooserDialog::filterTextChanged() { m_view->selectionModel()->setCurrentIndex(m_model->index(0, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); bool enabled = m_view->model()->rowCount(QModelIndex())>0; m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enabled); m_deleteButton->setVisible(false); } void SessionChooserDialog::doubleClicked(const QModelIndex& index) { if(m_model->flags(index) & Qt::ItemIsEnabled) accept(); } void SessionChooserDialog::updateState() { // Sometimes locking may take some time, so we stop the timer, to prevent an 'avalanche' of events m_updateStateTimer.stop(); for(int row = 0; row < m_model->rowCount(); ++row) { QString session = m_model->index(row, 0).data().toString(); if(session.isEmpty()) //create new session continue; QString state, tooltip; SessionRunInfo info = SessionController::sessionRunInfo(session); if(info.isRunning) { tooltip = i18n("Active session.\npid %1, app %2, host %3", info.holderPid, info.holderApp, info.holderHostname); state = i18n("Running"); } m_model->setData(m_model->index(row, 1), !info.isRunning ? QIcon::fromTheme("") : QIcon::fromTheme("media-playback-start"), Qt::DecorationRole); m_model->setData(m_model->index(row, 1), tooltip, Qt::ToolTipRole); m_model->setData(m_model->index(row, 2), state, Qt::DisplayRole); } m_updateStateTimer.start(); } void SessionChooserDialog::itemEntered(const QModelIndex& index) { // The last row says "Create new session", we don't want to delete that if(index.row() == m_model->rowCount()-1) { m_deleteButton->hide(); m_deleteButtonTimer.stop(); return; } // align the delete-button to stay on the right border of the item // we need the right most column's index QModelIndex in = m_model->index( index.row(), 1 ); const QRect rect = m_view->visualRect(in); m_deleteButton->resize(rect.height(), rect.height()); QPoint p(rect.right() - m_deleteButton->size().width(), rect.top()+rect.height()/2-m_deleteButton->height()/2); m_deleteButton->move(p); m_deleteCandidateRow = index.row(); m_deleteButtonTimer.start(); } void SessionChooserDialog::showDeleteButton() { m_deleteButton->show(); } bool SessionChooserDialog::eventFilter(QObject* object, QEvent* event) { if(object == m_view && event->type() == QEvent::Leave ) { m_deleteButtonTimer.stop(); m_deleteButton->hide(); } if(object == m_filter && event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast(event); if(keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down || keyEvent->key() == Qt::Key_Return) { QModelIndex currentIndex = m_view->selectionModel()->currentIndex(); int selectRow = -1; switch (keyEvent->key()) { case Qt::Key_Up: if(!currentIndex.isValid()) { selectRow = m_model->rowCount()-1; } else if(currentIndex.row()-1 >= 0) { selectRow = currentIndex.row()-1; } break; case Qt::Key_Down: if(!currentIndex.isValid()) { selectRow = 0; } else if(currentIndex.row()+1 < m_model->rowCount()) { selectRow = currentIndex.row()+1; } break; case Qt::Key_Return: accept(); return false; default: return false; } if (selectRow != -1) { m_view->selectionModel()->setCurrentIndex(m_model->index(selectRow, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } return true; } } return false; } QWidget* SessionChooserDialog::mainWidget() const { return m_mainWidget; } void SessionChooserDialog::deleteButtonPressed() { if(m_deleteCandidateRow == -1) return; QModelIndex index = m_model->index(m_deleteCandidateRow, 0); const QString uuid = m_model->data(index, Qt::DisplayRole).toString(); TryLockSessionResult result = SessionController::tryLockSession( uuid ); if( !result.lock ) { const QString errCaption = i18nc("@title", "Cannot Delete Session"); QString errText = i18nc("@info", "

Cannot delete a locked session."); if( result.runInfo.holderPid != -1 ) { errText += i18nc("@info", "

The session is locked by %1 on %2 (PID %3).", result.runInfo.holderApp, result.runInfo.holderHostname, result.runInfo.holderPid); } KMessageBox::error( this, errText, errCaption ); return; } const QString text = i18nc("@info", "The session and all contained settings will be deleted. The projects will stay unaffected. Do you really want to continue?"); const QString caption = i18nc("@title", "Delete Session"); const KGuiItem deleteItem = KStandardGuiItem::del(); const KGuiItem cancelItem = KStandardGuiItem::cancel(); if(KMessageBox::warningYesNo(this, text, caption, deleteItem, cancelItem) == KMessageBox::Yes) { QModelIndex index = m_model->index(m_deleteCandidateRow, 0); const QString uuid = m_model->data(index, Qt::DisplayRole).toString(); SessionController::deleteSessionFromDisk(result.lock); m_model->removeRows( m_deleteCandidateRow, 1 ); m_deleteCandidateRow = -1; } } diff --git a/shell/sessioncontroller.cpp b/shell/sessioncontroller.cpp index d6ecf0c41c..aa2310f51d 100644 --- a/shell/sessioncontroller.cpp +++ b/shell/sessioncontroller.cpp @@ -1,922 +1,922 @@ /* This file is part of KDevelop Copyright 2008 Andreas Pakulat Copyright 2010 David Nolden 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 "sessioncontroller.h" #include #include #include #include #include #include #include #include #include #include "session.h" #include "core.h" #include "uicontroller.h" #include "sessiondialog.h" #include "shellextension.h" #include "sessionlock.h" #include "sessionchooserdialog.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const int recoveryStorageInterval = 10; ///@todo Make this configurable namespace KDevelop { namespace { int argc = 0; char** argv = 0; }; void SessionController::setArguments(int _argc, char** _argv) { argc = _argc; argv = _argv; } static QStringList standardArguments() { QStringList ret; for(int a = 0; a < argc; ++a) { QString arg = QString::fromLocal8Bit(argv[a]); if(arg.startsWith("-graphicssystem") || arg.startsWith("-style")) { ret << '-' + arg; if(a+1 < argc) ret << QString::fromLocal8Bit(argv[a+1]); } } return ret; } class SessionControllerPrivate : public QObject { Q_OBJECT public: SessionControllerPrivate( SessionController* s ) : q(s) , activeSession(0) , grp(0) , recoveryDirectoryIsOwn(false) { recoveryTimer.setInterval(recoveryStorageInterval * 1000); connect(&recoveryTimer, &QTimer::timeout, this, &SessionControllerPrivate::recoveryStorageTimeout); // Try the recovery only after the initialization has finished connect(ICore::self(), &ICore::initializationCompleted, this, &SessionControllerPrivate::lateInitialization, Qt::QueuedConnection); recoveryTimer.setSingleShot(false); recoveryTimer.start(); } ~SessionControllerPrivate() { if (activeSession) { // when session was active, we deleted the folder already // in that case activeSession = 0 clearRecoveryDirectory(); } } Session* findSessionForName( const QString& name ) const { foreach( Session* s, sessionActions.keys() ) { if( s->name() == name ) return s; } return 0; } Session* findSessionForId(QString idString) { QUuid id(idString); foreach( Session* s, sessionActions.keys() ) { if( s->id() == id) return s; } return 0; } void newSession() { qsrand(QDateTime::currentDateTime().toTime_t()); Session* session = new Session( QUuid::createUuid().toString() ); KProcess::startDetached(ShellExtension::getInstance()->binaryPath(), QStringList() << "-s" << session->id().toString() << standardArguments()); delete session; #if 0 //Terminate this instance of kdevelop if the user agrees foreach(Sublime::MainWindow* window, Core::self()->uiController()->controller()->mainWindows()) window->close(); #endif } void configureSessions() { SessionDialog dlg(ICore::self()->uiController()-> activeMainWindow()); dlg.exec(); } void deleteCurrentSession() { int choice = KMessageBox::warningContinueCancel(Core::self()->uiController()->activeMainWindow(), i18n("The current session and all contained settings will be deleted. The projects will stay unaffected. Do you really want to continue?")); if(choice == KMessageBox::Continue) { q->deleteSessionFromDisk(sessionLock); q->emitQuitSession(); } } void renameSession() { QDialog dialog; dialog.setWindowTitle(i18n("Rename Session")); auto mainLayout = new QVBoxLayout(&dialog); QGroupBox box; QHBoxLayout layout(&box); box.setTitle(i18n("New Session Name")); QLineEdit edit; layout.addWidget(&edit); mainLayout->addWidget(&box); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); mainLayout->addWidget(buttonBox); edit.setText(q->activeSession()->name()); edit.setFocus(); if(dialog.exec() == QDialog::Accepted) { static_cast(q->activeSession())->setName(edit.text()); } } bool loadSessionExternally( Session* s ) { Q_ASSERT( s ); KProcess::startDetached(ShellExtension::getInstance()->binaryPath(), QStringList() << "-s" << s->id().toString() << standardArguments()); return true; } TryLockSessionResult activateSession( Session* s ) { Q_ASSERT( s ); activeSession = s; TryLockSessionResult result = SessionController::tryLockSession( s->id().toString()); if( !result.lock ) { activeSession = 0; return result; } Q_ASSERT(s->id().toString() == result.lock->id()); sessionLock = result.lock; KConfigGroup grp = KSharedConfig::openConfig()->group( SessionController::cfgSessionGroup() ); grp.writeEntry( SessionController::cfgActiveSessionEntry(), s->id().toString() ); grp.sync(); if (Core::self()->setupFlags() & Core::NoUi) return result; QHash::iterator it = sessionActions.find(s); Q_ASSERT( it != sessionActions.end() ); (*it)->setCheckable(true); (*it)->setChecked(true); for(it = sessionActions.begin(); it != sessionActions.end(); ++it) { if(it.key() != s) (*it)->setCheckable(false); } return result; } void loadSessionFromAction( QAction* a ) { foreach( Session* s, sessionActions.keys() ) { if( s->id() == QUuid( a->data().toString() ) && s != activeSession ) { loadSessionExternally( s ); break; } } } void addSession( Session* s ) { if (Core::self()->setupFlags() & Core::NoUi) { sessionActions[s] = 0; return; } QAction* a = new QAction( grp ); a->setText( s->description() ); a->setCheckable( false ); a->setData( s->id().toString() ); sessionActions[s] = a; q->actionCollection()->addAction( "session_"+s->id().toString(), a ); q->unplugActionList( "available_sessions" ); q->plugActionList( "available_sessions", grp->actions() ); connect( s, &Session::sessionUpdated, this, &SessionControllerPrivate::sessionUpdated ); sessionUpdated( s ); } SessionController* q; QHash sessionActions; ISession* activeSession; QActionGroup* grp; ISessionLock::Ptr sessionLock; // Whether this process owns the recovery directory bool recoveryDirectoryIsOwn; QTimer recoveryTimer; QMap currentRecoveryFiles; static QString sessionBaseDirectory() { return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +'/'+ qApp->applicationName() + "/sessions/"; } QString ownSessionDirectory() const { Q_ASSERT(activeSession); return q->sessionDirectory( activeSession->id().toString() ); } void clearRecoveryDirectory() { removeDirectory(ownSessionDirectory() + "/recovery"); } public slots: void documentSavedOrClosed( KDevelop::IDocument* document ) { if(currentRecoveryFiles.contains(document->url())) { qCDebug(SHELL) << "deleting recovery-info for" << document->url(); foreach(const QString& recoveryFileName, currentRecoveryFiles[document->url()]) { bool result = QFile::remove(recoveryFileName); qCDebug(SHELL) << "deleted" << recoveryFileName << result; } currentRecoveryFiles.remove(document->url()); } } private slots: void lateInitialization() { performRecovery(); connect(Core::self()->documentController(), &IDocumentController::documentSaved, this, &SessionControllerPrivate::documentSavedOrClosed); connect(Core::self()->documentController(), &IDocumentController::documentClosed, this, &SessionControllerPrivate::documentSavedOrClosed); } void performRecovery() { qCDebug(SHELL) << "Checking recovery"; QDir recoveryDir(ownSessionDirectory() + "/recovery"); if(recoveryDir.exists()) { qCDebug(SHELL) << "Have recovery directory, starting recovery"; QFile dateFile(recoveryDir.path() + "/date"); dateFile.open(QIODevice::ReadOnly); QString date = QString::fromUtf8(dateFile.readAll()); QDir recoverySubDir(recoveryDir.path() + "/current"); if(!recoverySubDir.exists()) recoverySubDir = QDir(recoveryDir.path() + "/backup"); if(recoverySubDir.exists()) { qWarning() << "Starting recovery from " << recoverySubDir.absolutePath(); QStringList urlList; for(uint num = 0; ; ++num) { QFile urlFile(recoverySubDir.path() + QString("/%1_url").arg(num)); if(!urlFile.exists()) break; urlFile.open(QIODevice::ReadOnly); QUrl originalFile = QUrl::fromLocalFile(QString::fromUtf8(urlFile.readAll())); urlList << originalFile.toDisplayString(QUrl::PreferLocalFile); } if(!urlList.isEmpty()) { //Either recover, or delete the recovery directory ///TODO: user proper runtime locale for date, it might be different /// from what was used when the recovery file was saved KGuiItem recover = KStandardGuiItem::cont(); recover.setIcon(QIcon::fromTheme("edit-redo")); recover.setText(i18n("Recover")); KGuiItem discard = KStandardGuiItem::discard(); int choice = KMessageBox::warningContinueCancelList(qApp->activeWindow(), i18nc("%1: date of the last snapshot", "The session crashed the last time it was used. " "The following modified files can be recovered from a backup from %1.", date), urlList, i18n("Crash Recovery"), recover, discard ); if(choice == KMessageBox::Continue) { //Recover the files for(uint num = 0; ; ++num) { QFile urlFile(recoverySubDir.path() + QString("/%1_url").arg(num)); if(!urlFile.exists()) break; urlFile.open(QIODevice::ReadOnly); QUrl originalFile = QUrl::fromLocalFile(QString::fromUtf8(urlFile.readAll())); QFile f(recoverySubDir.path() + '/' + QString("/%1_text").arg(num)); f.open(QIODevice::ReadOnly); QString text = QString::fromUtf8(f.readAll()); if(text.isEmpty()) { KMessageBox::error(ICore::self()->uiController()->activeMainWindow(), i18n("Could not recover %1, the recovery file is empty", originalFile.toDisplayString(QUrl::PreferLocalFile)), i18n("Recovery")); continue; } qCDebug(SHELL) << "opening" << originalFile << "for recovery"; KDevelop::IDocument* doc = ICore::self()->documentController()->openDocument(originalFile); if(!doc || !doc->textDocument()) { qWarning() << "The document " << originalFile << " could not be opened as a text-document, creating a new document with the recovered contents"; doc = ICore::self()->documentController()->openDocumentFromText(text); }else{ KTextEditor::Document* recovery = doc->textDocument(); if(recovery && recovery->isDataRecoveryAvailable()) // Use the recovery from the kate swap-file if possible recovery->recoverData(); else // Use a simple recovery through "replace text" doc->textDocument()->setText(text); } } } } } } recoveryDirectoryIsOwn = true; } void sessionUpdated( KDevelop::ISession* s ) { sessionActions[static_cast( s )]->setText( KStringHandler::rsqueeze(s->description()) ); } void recoveryStorageTimeout() { if(!recoveryDirectoryIsOwn) return; currentRecoveryFiles.clear(); QDir recoveryDir(ownSessionDirectory() + "/recovery"); if(!recoveryDir.exists()) { // Try "taking" the recovery directory QDir sessionDir(ownSessionDirectory()); if(!sessionDir.mkdir("recovery")) return; } if (recoveryDir.exists("backup")) { // Clear the old backup recovery directory, as we will create a new one if (!removeDirectory(recoveryDir.absoluteFilePath("backup"))) { qWarning() << "RECOVERY ERROR: Removing the old recovery backup directory failed in " << recoveryDir; return; } } //Make the current recovery dir the backup dir, so we always have a recovery available //This may fail, because "current" might be nonexistent recoveryDir.rename("current", "backup"); { recoveryDir.mkdir("current_incomplete"); QDir recoveryCurrentDir(recoveryDir.path() + "/current_incomplete"); uint num = 0; foreach(KDevelop::IDocument* document, ICore::self()->documentController()->openDocuments()) { if(document->state() == IDocument::Modified || document->state() == IDocument::DirtyAndModified) { //This document was modified, create a recovery-backup if(document->textDocument()) { //Currently we can only back-up text documents QString text = document->textDocument()->text(); if(!text.isEmpty()) { QString urlFilePath = recoveryCurrentDir.path() + QString("/%1_url").arg(num); QFile urlFile(urlFilePath); urlFile.open(QIODevice::WriteOnly); urlFile.write(document->url().toString().toUtf8()); urlFile.close(); QString textFilePath = recoveryCurrentDir.path() + '/' + QString("/%1_text").arg(num); QFile f(textFilePath); f.open(QIODevice::WriteOnly); f.write(text.toUtf8()); f.close(); currentRecoveryFiles[document->url()] = QStringList() << (recoveryDir.path() + "/current" + QString("/%1_url").arg(num)) << (recoveryDir.path() + "/current" + QString("/%1_text").arg(num)); if(urlFile.error() != QFile::NoError || f.error() != QFile::NoError) { qWarning() << "RECOVERY ERROR: Failed to write recovery for" << document->url() << "to" << textFilePath; KMessageBox::error(ICore::self()->uiController()->activeMainWindow(), i18n("Failed to write recovery copies to %1. Please make sure that your home directory is writable and not full. This application requires available space in the home directory to run stable. You may experience application crashes until you free up some space.", recoveryCurrentDir.path()), i18n("Recovery Error")); return; } ++num; } } } } } recoveryDir.rename("current_incomplete", "current"); { //Write down the date of the recovery QFile dateFile(recoveryDir.path() + "/date"); dateFile.open(QIODevice::WriteOnly); dateFile.write(QDateTime::currentDateTime().toString(Qt::DefaultLocaleShortDate).toUtf8()); } } }; SessionController::SessionController( QObject *parent ) : QObject( parent ), d(new SessionControllerPrivate(this)) { setObjectName("SessionController"); setComponentName(QStringLiteral("kdevsession"), QStringLiteral("KDevSession")); setXMLFile("kdevsessionui.rc"); QDBusConnection::sessionBus().registerObject( "/kdevelop/SessionController", this, QDBusConnection::ExportScriptableSlots ); if (Core::self()->setupFlags() & Core::NoUi) return; QAction* action = actionCollection()->addAction( "new_session", this, SLOT(newSession()) ); action->setText( i18nc("@action:inmenu", "Start New Session") ); action->setToolTip( i18nc("@info:tooltip", "Start a new KDevelop instance with an empty session") ); action->setIcon(QIcon::fromTheme("window-new")); action = actionCollection()->addAction( "rename_session", this, SLOT(renameSession()) ); action->setText( i18n("Rename Current Session...") ); action->setIcon(QIcon::fromTheme("edit-rename")); action = actionCollection()->addAction( "delete_session", this, SLOT(deleteCurrentSession()) ); action->setText( i18n("Delete Current Session...") ); action->setIcon(QIcon::fromTheme("edit-delete")); action = actionCollection()->addAction( "quit", this, SIGNAL(quitSession()) ); action->setText( i18n("Quit") ); actionCollection()->setDefaultShortcut( action, Qt::CTRL | Qt::Key_Q ); action->setIcon(QIcon::fromTheme("application-exit")); #if 0 action = actionCollection()->addAction( "configure_sessions", this, SLOT(configureSessions()) ); action->setText( i18n("Configure Sessions...") ); action->setToolTip( i18n("Create/Delete/Activate Sessions") ); action->setWhatsThis( i18n( "Shows a dialog to Create/Delete Sessions and set a new active session." ) ); #endif d->grp = new QActionGroup( this ); connect( d->grp, &QActionGroup::triggered, this, [&] (QAction* a) { d->loadSessionFromAction(a); } ); } SessionController::~SessionController() { delete d; } void SessionController::startNewSession() { d->newSession(); } void SessionController::cleanup() { d->recoveryTimer.stop(); if (d->activeSession) { Q_ASSERT(d->activeSession->id().toString() == d->sessionLock->id()); if (d->activeSession->isTemporary()) { deleteSessionFromDisk(d->sessionLock); } d->activeSession = 0; } d->sessionLock.clear(); qDeleteAll(d->sessionActions); d->sessionActions.clear(); } void SessionController::initialize( const QString& session ) { QDir sessiondir( SessionControllerPrivate::sessionBaseDirectory() ); foreach( const QString& s, sessiondir.entryList( QDir::AllDirs | QDir::NoDotAndDotDot ) ) { QUuid id( s ); if( id.isNull() ) continue; // Only create sessions for directories that represent proper uuid's Session* ses = new Session( id.toString(), this ); //Delete sessions that have no name and are empty if( ses->containedProjects().isEmpty() && ses->name().isEmpty() && (session.isEmpty() || (ses->id().toString() != session && ses->name() != session)) ) { TryLockSessionResult result = tryLockSession(s); if (result.lock) { deleteSessionFromDisk(result.lock); } delete ses; } else { d->addSession( ses ); } } loadDefaultSession( session ); } ISession* SessionController::activeSession() const { return d->activeSession; } ISessionLock::Ptr SessionController::activeSessionLock() const { return d->sessionLock; } void SessionController::loadSession( const QString& nameOrId ) { d->loadSessionExternally( session( nameOrId ) ); } QList SessionController::sessionNames() const { QStringList l; foreach( const Session* s, d->sessionActions.keys() ) { l << s->name(); } return l; } QList< const KDevelop::Session* > SessionController::sessions() const { QList< const KDevelop::Session* > ret; foreach( const Session* s, d->sessionActions.keys() ) { ret << s; } return ret; } Session* SessionController::createSession( const QString& name ) { Session* s; if(name.startsWith('{')) { s = new Session( QUuid(name).toString() ); }else{ qsrand(QDateTime::currentDateTime().toTime_t()); s = new Session( QUuid::createUuid().toString() ); s->setName( name ); } d->addSession( s ); return s; } void SessionController::deleteSession( const ISessionLock::Ptr& lock ) { Session* s = session(lock->id()); QHash::iterator it = d->sessionActions.find(s); Q_ASSERT( it != d->sessionActions.end() ); unplugActionList( "available_sessions" ); actionCollection()->removeAction(*it); if (d->grp) { // happens in unit tests d->grp->removeAction(*it); plugActionList( "available_sessions", d->grp->actions() ); } if (s == d->activeSession) { d->activeSession = nullptr; } deleteSessionFromDisk(lock); emit sessionDeleted( s->id().toString() ); d->sessionActions.remove(s); delete s; } void SessionController::deleteSessionFromDisk( const ISessionLock::Ptr& lock ) { removeDirectory( sessionDirectory(lock->id()) ); ItemRepositoryRegistry::deleteRepositoryFromDisk( lock ); } void SessionController::loadDefaultSession( const QString& session ) { QString load = session; if (load.isEmpty()) { KConfigGroup grp = KSharedConfig::openConfig()->group( cfgSessionGroup() ); load = grp.readEntry( cfgActiveSessionEntry(), "default" ); } // Iteratively try to load the session, asking user what to do in case of failure // If showForceOpenDialog() returns empty string, stop trying Session* s = 0; do { s = this->session( load ); if( !s ) { s = createSession( load ); } TryLockSessionResult result = d->activateSession( s ); if( result.lock ) { Q_ASSERT(d->activeSession == s); Q_ASSERT(d->sessionLock = result.lock); break; } load = handleLockedSession( s->name(), s->id().toString(), result.runInfo ); } while( !load.isEmpty() ); } Session* SessionController::session( const QString& nameOrId ) const { Session* ret = d->findSessionForName( nameOrId ); if(ret) return ret; return d->findSessionForId( nameOrId ); } QString SessionController::cloneSession( const QString& nameOrid ) { Session* origSession = session( nameOrid ); qsrand(QDateTime::currentDateTime().toTime_t()); QUuid id = QUuid::createUuid(); auto copyJob = KIO::copy(QUrl::fromLocalFile(sessionDirectory(origSession->id().toString())), QUrl::fromLocalFile(sessionDirectory( id.toString()))); KJobWidgets::setWindow(copyJob, Core::self()->uiController()->activeMainWindow()); copyJob->exec(); Session* newSession = new Session( id.toString() ); newSession->setName( i18n( "Copy of %1", origSession->name() ) ); d->addSession(newSession); return newSession->name(); } void SessionController::plugActions() { unplugActionList( "available_sessions" ); plugActionList( "available_sessions", d->grp->actions() ); } QString SessionController::cfgSessionGroup() { return "Sessions"; } QString SessionController::cfgActiveSessionEntry() { return "Active Session ID"; } QList< SessionInfo > SessionController::availableSessionInfo() { QList< SessionInfo > available; foreach( const QString& sessionId, QDir( SessionControllerPrivate::sessionBaseDirectory() ).entryList( QDir::AllDirs ) ) { if( !QUuid( sessionId ).isNull() ) { available << Session::parse( sessionId ); } } return available; } QString SessionController::sessionDirectory(const QString& sessionId) { return SessionControllerPrivate::sessionBaseDirectory() + sessionId; } TryLockSessionResult SessionController::tryLockSession(const QString& id) { return SessionLock::tryLockSession(id, true); } bool SessionController::isSessionRunning(const QString& id) { return sessionRunInfo(id).isRunning; } SessionRunInfo SessionController::sessionRunInfo(const QString& id) { return SessionLock::tryLockSession(id, false).runInfo; } QString SessionController::showSessionChooserDialog(QString headerText, bool onlyRunning) { ///FIXME: move this code into sessiondialog.cpp QListView* view = new QListView; QLineEdit* filter = new QLineEdit; filter->setClearButtonEnabled( true ); filter->setPlaceholderText(i18n("Search")); QStandardItemModel* model = new QStandardItemModel(view); QSortFilterProxyModel *proxy = new QSortFilterProxyModel(model); proxy->setSourceModel(model); proxy->setFilterKeyColumn( 1 ); proxy->setFilterCaseSensitivity( Qt::CaseInsensitive ); connect(filter, &QLineEdit::textChanged, proxy, &QSortFilterProxyModel::setFilterFixedString); SessionChooserDialog dialog(view, proxy, filter); view->setEditTriggers(QAbstractItemView::NoEditTriggers); QVBoxLayout layout(dialog.mainWidget()); if(!headerText.isEmpty()) { QLabel* heading = new QLabel(headerText); QFont font = heading->font(); font.setBold(true); heading->setFont(font); layout.addWidget(heading); } model->setColumnCount(3); model->setHeaderData(0, Qt::Horizontal,i18n("Identity")); model->setHeaderData(1, Qt::Horizontal, i18n("Contents")); model->setHeaderData(2, Qt::Horizontal,i18n("State")); view->setModel(proxy); view->setModelColumn(1); QHBoxLayout* filterLayout = new QHBoxLayout(); filterLayout->addWidget(new QLabel(i18n("Filter:"))); filterLayout->addWidget(filter); layout.addLayout(filterLayout); layout.addWidget(view); filter->setFocus(); int row = 0; QString defaultSession = KSharedConfig::openConfig()->group( cfgSessionGroup() ).readEntry( cfgActiveSessionEntry(), "default" ); foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfo()) { if ( si.name.isEmpty() && si.projects.isEmpty() ) { continue; } bool running = KDevelop::SessionController::isSessionRunning(si.uuid.toString()); if(onlyRunning && !running) continue; model->setItem(row, 0, new QStandardItem(si.uuid.toString())); model->setItem(row, 1, new QStandardItem(si.description)); model->setItem(row, 2, new QStandardItem); ++row; } model->sort(1); if(!onlyRunning) { model->setItem(row, 0, new QStandardItem); model->setItem(row, 1, new QStandardItem(QIcon::fromTheme("window-new"), i18n("Create New Session"))); } dialog.updateState(); dialog.mainWidget()->layout()->setContentsMargins(0,0,0,0); const QModelIndex defaultSessionIndex = model->match(model->index(0, 0), Qt::DisplayRole, defaultSession, 1, Qt::MatchExactly).value(0); view->selectionModel()->setCurrentIndex(proxy->mapFromSource(defaultSessionIndex), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); view->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); ///@todo We need a way to get a proper size-hint from the view, but unfortunately, that only seems possible after the view was shown. dialog.resize(QSize(900, 600)); if(dialog.exec() != QDialog::Accepted) { return QString(); } QModelIndex selected = view->selectionModel()->currentIndex(); if (!selected.isValid()) return QString(); const QString selectedSessionId = selected.sibling(selected.row(), 0).data().toString(); if (selectedSessionId.isEmpty()) { // "Create New Session" item selected, return a fresh UUID qsrand(QDateTime::currentDateTime().toTime_t()); return QUuid::createUuid().toString(); } return selectedSessionId; } QString SessionController::handleLockedSession( const QString& sessionName, const QString& sessionId, const SessionRunInfo& runInfo ) { return SessionLock::handleLockedSession(sessionName, sessionId, runInfo); } QString SessionController::sessionDir() { if( !activeSession() ) return QString(); return d->ownSessionDirectory(); } QString SessionController::sessionName() { if(!activeSession()) return QString(); return activeSession()->description(); } } #include "sessioncontroller.moc" #include "moc_sessioncontroller.cpp" diff --git a/shell/settings/editstyledialog.cpp b/shell/settings/editstyledialog.cpp index 1fb1fcf757..ecb22401fb 100644 --- a/shell/settings/editstyledialog.cpp +++ b/shell/settings/editstyledialog.cpp @@ -1,125 +1,125 @@ /* This file is part of KDevelop * Copyright (C) 2008 Cédric Pasteur 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; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "editstyledialog.h" #include #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; EditStyleDialog::EditStyleDialog(ISourceFormatter* formatter, const QMimeType& mime, const SourceFormatterStyle& style, QWidget* parent) : QDialog(parent) , m_sourceFormatter(formatter) , m_mimeType(mime) , m_style(style) { m_content = new QWidget(); m_ui.setupUi(m_content); QVBoxLayout* mainLayout = new QVBoxLayout(this); mainLayout->addWidget(m_content); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &EditStyleDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &EditStyleDialog::reject); mainLayout->addWidget(buttonBox); m_settingsWidget = m_sourceFormatter->editStyleWidget(mime); init(); if (m_settingsWidget) { m_settingsWidget->load(style); } } EditStyleDialog::~EditStyleDialog() { } void EditStyleDialog::init() { // add plugin settings widget if (m_settingsWidget) { QVBoxLayout* layout = new QVBoxLayout(m_ui.settingsWidgetParent); layout->addWidget(m_settingsWidget); m_ui.settingsWidgetParent->setLayout(layout); connect(m_settingsWidget, &SettingsWidget::previewTextChanged, this, &EditStyleDialog::updatePreviewText); } m_document = KTextEditor::Editor::instance()->createDocument(this); m_document->setReadWrite(false); m_document->setHighlightingMode(m_style.modeForMimetype(m_mimeType)); m_view = m_document->createView(m_ui.textEditor); QVBoxLayout* layout2 = new QVBoxLayout(m_ui.textEditor); layout2->addWidget(m_view); m_ui.textEditor->setLayout(layout2); m_view->setStatusBarEnabled(false); m_view->show(); KTextEditor::ConfigInterface* iface = qobject_cast(m_view); if (iface) { iface->setConfigValue("dynamic-word-wrap", false); iface->setConfigValue("icon-bar", false); } if (m_sourceFormatter) { QString text = m_sourceFormatter->previewText(m_style, m_mimeType); updatePreviewText(text); } } void EditStyleDialog::updatePreviewText(const QString &text) { m_document->setReadWrite(true); m_style.setContent(content()); if (m_sourceFormatter) { m_document->setText(m_sourceFormatter->formatSourceWithStyle(m_style, text, QUrl(), m_mimeType)); } else { m_document->setText(i18n("No Source Formatter available")); } m_view->setCursorPosition(KTextEditor::Cursor(0, 0)); m_document->setReadWrite(false); } QString EditStyleDialog::content() { if (m_settingsWidget) { return m_settingsWidget->save(); } return QString(); } diff --git a/shell/settings/environmentwidget.cpp b/shell/settings/environmentwidget.cpp index 435bd7c6b2..f91665bdf3 100644 --- a/shell/settings/environmentwidget.cpp +++ b/shell/settings/environmentwidget.cpp @@ -1,230 +1,230 @@ /* This file is part of KDevelop Copyright 2006 Adam Treat Copyright 2007 Dukju Ahn Copyright 2008 Andreas Pakuat 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 "environmentwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "environmentgroupmodel.h" #include "placeholderitemproxymodel.h" #include "../debug.h" namespace KDevelop { EnvironmentWidget::EnvironmentWidget( QWidget *parent ) : QWidget( parent ), groupModel( new EnvironmentGroupModel() ), proxyModel( new QSortFilterProxyModel() ) { // setup ui ui.setupUi( this ); ui.variableTable->verticalHeader()->hide(); proxyModel->setSourceModel( groupModel ); PlaceholderItemProxyModel* topProxyModel = new PlaceholderItemProxyModel(this); topProxyModel->setSourceModel(proxyModel); topProxyModel->setColumnHint(0, i18n("Enter variable ...")); connect(topProxyModel, &PlaceholderItemProxyModel::dataInserted, this, &EnvironmentWidget::handleVariableInserted); ui.variableTable->setModel( topProxyModel ); ui.variableTable->horizontalHeader()->setSectionResizeMode( 1, QHeaderView::Stretch ); ui.addgrpBtn->setIcon(QIcon::fromTheme("list-add")); ui.removegrpBtn->setIcon(QIcon::fromTheme("list-remove")); ui.deleteButton->setIcon(QIcon::fromTheme("list-remove")); ui.deleteButton->setShortcut(Qt::Key_Delete); ui.newMultipleButton->setIcon(QIcon::fromTheme("format-list-unordered")); connect( ui.deleteButton, &QPushButton::clicked, this, &EnvironmentWidget::deleteButtonClicked ); connect( ui.newMultipleButton, &QPushButton::clicked, this, &EnvironmentWidget::newMultipleButtonClicked ); connect( ui.addgrpBtn, &QPushButton::clicked, this, &EnvironmentWidget::addGroupClicked ); connect( ui.addgrpBtn, &QPushButton::clicked, this, &EnvironmentWidget::changed ); connect( ui.removegrpBtn, &QPushButton::clicked, this, &EnvironmentWidget::removeGroupClicked ); connect( ui.removegrpBtn, &QPushButton::clicked, this, &EnvironmentWidget::changed ); connect( ui.setAsDefaultBtn, &QPushButton::clicked, this, &EnvironmentWidget::setAsDefault ); connect( ui.setAsDefaultBtn, &QPushButton::clicked, this, &EnvironmentWidget::changed ); connect( ui.activeCombo, static_cast(&KComboBox::currentIndexChanged), this, &EnvironmentWidget::activeGroupChanged ); connect( ui.activeCombo, &KComboBox::editTextChanged, this, &EnvironmentWidget::enableButtons); connect( groupModel, &EnvironmentGroupModel::dataChanged, this, &EnvironmentWidget::changed ); connect( groupModel, &EnvironmentGroupModel::rowsRemoved, this, &EnvironmentWidget::changed ); connect( groupModel, &EnvironmentGroupModel::rowsInserted, this, &EnvironmentWidget::changed ); connect( groupModel, &EnvironmentGroupModel::rowsRemoved, this, &EnvironmentWidget::enableDeleteButton ); connect( groupModel, &EnvironmentGroupModel::rowsInserted, this, &EnvironmentWidget::enableDeleteButton ); connect( groupModel, &EnvironmentGroupModel::modelReset, this, &EnvironmentWidget::enableDeleteButton ); } void EnvironmentWidget::setActiveGroup( const QString& group ) { ui.activeCombo->setCurrentItem(group); } void EnvironmentWidget::enableDeleteButton() { ui.deleteButton->setEnabled( groupModel->rowCount() > 0 ); } void EnvironmentWidget::setAsDefault() { groupModel->changeDefaultGroup( ui.activeCombo->currentText() ); enableButtons( ui.activeCombo->currentText() ); emit changed(); } void EnvironmentWidget::loadSettings( KConfig* config ) { qCDebug(SHELL) << "Loading groups from config"; groupModel->loadFromConfig( config ); ui.activeCombo->clear(); QStringList groupList = groupModel->groups(); qCDebug(SHELL) << "Grouplist:" << groupList << "default group:" << groupModel->defaultGroup(); ui.activeCombo->addItems( groupList ); int idx = ui.activeCombo->findText( groupModel->defaultGroup() ); ui.activeCombo->setCurrentIndex( idx ); } void EnvironmentWidget::saveSettings( KConfig* config ) { groupModel->saveToConfig( config ); } void EnvironmentWidget::defaults( KConfig* config ) { loadSettings( config ); } void EnvironmentWidget::deleteButtonClicked() { QModelIndexList selected = ui.variableTable->selectionModel()->selectedRows(); if( selected.isEmpty() ) return; QStringList variables; foreach( const QModelIndex &idx, selected ) { const QString variable = idx.data(EnvironmentGroupModel::VariableRole).toString(); variables << variable; } groupModel->removeVariables(variables); } void EnvironmentWidget::handleVariableInserted(int /*column*/, const QVariant& value) { groupModel->addVariable(value.toString(), QString()); } void EnvironmentWidget::newMultipleButtonClicked() { QDialog * dialog = new QDialog( this ); dialog->setWindowTitle( i18n( "New Environment Variables" ) ); QVBoxLayout *layout = new QVBoxLayout(dialog); QTextEdit *edit = new QTextEdit; edit->setPlaceholderText("VARIABLE1=VALUE1\nVARIABLE2=VALUE2"); layout->addWidget( edit ); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - dialog->connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); - dialog->connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); + dialog->connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept); + dialog->connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject); layout->addWidget(buttonBox); if ( dialog->exec() != QDialog::Accepted ) { return; } QStringList lines = edit->toPlainText().split( "\n", QString::SkipEmptyParts ); foreach(const QString &line, lines) { QString name = line.section('=', 0, 0); QString value = line.section('=', 1, -1).trimmed(); if (!name.isEmpty() && !value.isEmpty()) { groupModel->addVariable( name, value ); } } } void EnvironmentWidget::addGroupClicked() { QString curText = ui.activeCombo->currentText(); if( groupModel->groups().contains( curText ) ) { return; // same group name cannot be added twice. } ui.activeCombo->addItem( curText ); ui.activeCombo->setCurrentItem( curText ); } void EnvironmentWidget::removeGroupClicked() { int idx = ui.activeCombo->currentIndex(); if( idx < 0 || ui.activeCombo->count() == 1 ) { return; } QString curText = ui.activeCombo->currentText(); groupModel->removeGroup( curText ); ui.activeCombo->removeItem( idx ); ui.activeCombo->setCurrentItem( groupModel->defaultGroup() ); } void EnvironmentWidget::activeGroupChanged( int /*idx*/ ) { groupModel->setCurrentGroup( ui.activeCombo->currentText() ); enableButtons( ui.activeCombo->currentText() ); } void EnvironmentWidget::enableButtons( const QString& txt ) { ui.addgrpBtn->setEnabled( !groupModel->groups().contains( txt ) ); ui.removegrpBtn->setEnabled( ( groupModel->groups().contains( txt ) && groupModel->defaultGroup() != txt ) ); ui.setAsDefaultBtn->setEnabled( ( groupModel->groups().contains( txt ) && groupModel->defaultGroup() != txt ) ); } } #include "moc_environmentwidget.cpp" diff --git a/shell/uicontroller.cpp b/shell/uicontroller.cpp index f46d30708f..404d84c7aa 100644 --- a/shell/uicontroller.cpp +++ b/shell/uicontroller.cpp @@ -1,725 +1,725 @@ /*************************************************************************** * Copyright 2007 Alexander Dymo * * * * 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 Library 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 "uicontroller.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "configpage.h" #include "configdialog.h" #include "debug.h" #include "editorconfigpage.h" #include "shellextension.h" #include "partcontroller.h" #include "plugincontroller.h" #include "mainwindow.h" #include "partdocument.h" #include "textdocument.h" #include "documentcontroller.h" #include "assistantpopup.h" #include #include #include "workingsetcontroller.h" #include "workingsets/workingset.h" #include "settings/bgpreferences.h" #include "settings/ccpreferences.h" #include "settings/environmentpreferences.h" #include "settings/pluginpreferences.h" #include "settings/projectpreferences.h" #include "settings/sourceformattersettings.h" #include "settings/uipreferences.h" #include "settings/templateconfig.h" namespace KDevelop { class UiControllerPrivate { public: UiControllerPrivate(UiController *controller) : areasRestored(false), m_controller(controller) { if (Core::self()->workingSetControllerInternal()) Core::self()->workingSetControllerInternal()->initializeController(m_controller); QMap desired; desired["org.kdevelop.ClassBrowserView"] = Sublime::Left; desired["org.kdevelop.DocumentsView"] = Sublime::Left; desired["org.kdevelop.ProjectsView"] = Sublime::Left; desired["org.kdevelop.FileManagerView"] = Sublime::Left; desired["org.kdevelop.ProblemReporterView"] = Sublime::Bottom; desired["org.kdevelop.OutputView"] = Sublime::Bottom; desired["org.kdevelop.ContextBrowser"] = Sublime::Bottom; desired["org.kdevelop.KonsoleView"] = Sublime::Bottom; desired["org.kdevelop.SnippetView"] = Sublime::Right; desired["org.kdevelop.ExternalScriptView"] = Sublime::Right; Sublime::Area* a = new Sublime::Area(m_controller, "code", i18n("Code")); a->setDesiredToolViews(desired); a->setIconName("document-edit"); m_controller->addDefaultArea(a); desired.clear(); desired["org.kdevelop.debugger.VariablesView"] = Sublime::Left; desired["org.kdevelop.debugger.BreakpointsView"] = Sublime::Bottom; desired["org.kdevelop.debugger.StackView"] = Sublime::Bottom; desired["org.kdevelop.debugger.ConsoleView"] = Sublime::Bottom; desired["org.kdevelop.KonsoleView"] = Sublime::Bottom; a = new Sublime::Area(m_controller, "debug", i18n("Debug")); a->setDesiredToolViews(desired); a->setIconName("tools-report-bug"); m_controller->addDefaultArea(a); desired.clear(); desired["org.kdevelop.ProjectsView"] = Sublime::Left; desired["org.kdevelop.PatchReview"] = Sublime::Bottom; a = new Sublime::Area(m_controller, "review", i18n("Review")); a->setDesiredToolViews(desired); a->setIconName("applications-engineering"); m_controller->addDefaultArea(a); if(!(Core::self()->setupFlags() & Core::NoUi)) { defaultMainWindow = new MainWindow(m_controller); m_controller->addMainWindow(defaultMainWindow); activeSublimeWindow = defaultMainWindow; } else { activeSublimeWindow = defaultMainWindow = 0; } m_assistantTimer.setSingleShot(true); m_assistantTimer.setInterval(100); } void widgetChanged(QWidget*, QWidget* now) { if (now) { Sublime::MainWindow* win = qobject_cast(now->window()); if( win ) { activeSublimeWindow = win; } } } Core *core; MainWindow* defaultMainWindow; QMap factoryDocuments; Sublime::MainWindow* activeSublimeWindow; bool areasRestored; //Currently shown assistant popup. QPointer currentShownAssistant; QTimer m_assistantTimer; private: UiController *m_controller; }; class UiToolViewFactory: public Sublime::ToolFactory { public: UiToolViewFactory(IToolViewFactory *factory): m_factory(factory) {} ~UiToolViewFactory() { delete m_factory; } virtual QWidget* create(Sublime::ToolDocument *doc, QWidget *parent = 0) { Q_UNUSED( doc ); return m_factory->create(parent); } virtual QList< QAction* > contextMenuActions(QWidget* viewWidget) const { return m_factory->contextMenuActions( viewWidget ); } QList toolBarActions( QWidget* viewWidget ) const { return m_factory->toolBarActions( viewWidget ); } QString id() const { return m_factory->id(); } private: IToolViewFactory *m_factory; }; class ViewSelectorItem: public QListWidgetItem { public: ViewSelectorItem(const QString &text, QListWidget *parent = 0, int type = Type) :QListWidgetItem(text, parent, type) {} IToolViewFactory *factory; }; class NewToolViewListWidget: public QListWidget { Q_OBJECT public: NewToolViewListWidget(MainWindow *mw, QWidget* parent = 0) :QListWidget(parent), m_mw(mw) { connect(this, &NewToolViewListWidget::doubleClicked, this, &NewToolViewListWidget::addNewToolViewByDoubleClick); } Q_SIGNALS: void addNewToolView(MainWindow *mw, QListWidgetItem *item); private Q_SLOTS: void addNewToolViewByDoubleClick(QModelIndex index) { QListWidgetItem *item = itemFromIndex(index); // Disable item so that the toolview can not be added again. item->setFlags(item->flags() & ~Qt::ItemIsEnabled); emit addNewToolView(m_mw, item); } private: MainWindow *m_mw; }; UiController::UiController(Core *core) :Sublime::Controller(0), IUiController(), d(new UiControllerPrivate(this)) { setObjectName("UiController"); d->core = core; if (!defaultMainWindow() || (Core::self()->setupFlags() & Core::NoUi)) return; connect(qApp, &QApplication::focusChanged, this, [&] (QWidget* old, QWidget* now) { d->widgetChanged(old, now); } ); setupActions(); } UiController::~UiController() { delete d; } void UiController::setupActions() { } void UiController::mainWindowDeleted(MainWindow* mw) { if (d->defaultMainWindow == mw) d->defaultMainWindow = 0L; if (d->activeSublimeWindow == mw) d->activeSublimeWindow = 0L; } // FIXME: currently, this always create new window. Probably, // should just rename it. void UiController::switchToArea(const QString &areaName, SwitchMode switchMode) { if (switchMode == ThisWindow) { showArea(areaName, activeSublimeWindow()); return; } MainWindow *main = new MainWindow(this); addMainWindow(main); showArea(areaName, main); main->initialize(); // WTF? First, enabling this code causes crashes since we // try to disconnect some already-deleted action, or something. // Second, this code will disconnection the clients from guiFactory // of the previous main window. Ick! #if 0 //we need to add all existing guiclients to the new mainwindow //@todo adymo: add only ones that belong to the area (when the area code is there) foreach (KXMLGUIClient *client, oldMain->guiFactory()->clients()) main->guiFactory()->addClient(client); #endif main->show(); } QWidget* UiController::findToolView(const QString& name, IToolViewFactory *factory, FindFlags flags) { if(!d->areasRestored || !activeArea()) return 0; QList< Sublime::View* > views = activeArea()->toolViews(); foreach(Sublime::View* view, views) { Sublime::ToolDocument *doc = dynamic_cast(view->document()); if(doc && doc->title() == name && view->widget()) { if(flags & Raise) view->requestRaise(); return view->widget(); } } QWidget* ret = 0; if(flags & Create) { if(!d->factoryDocuments.contains(factory)) d->factoryDocuments[factory] = new Sublime::ToolDocument(name, this, new UiToolViewFactory(factory)); Sublime::ToolDocument *doc = d->factoryDocuments[factory]; Sublime::View* view = addToolViewToArea(factory, doc, activeArea()); if(view) ret = view->widget(); if(flags & Raise) findToolView(name, factory, Raise); } return ret; } void UiController::raiseToolView(QWidget* toolViewWidget) { if(!d->areasRestored) return; QList< Sublime::View* > views = activeArea()->toolViews(); foreach(Sublime::View* view, views) { if(view->widget() == toolViewWidget) { view->requestRaise(); return; } } } void UiController::addToolView(const QString & name, IToolViewFactory *factory) { if (!factory) return; qCDebug(SHELL) ; Sublime::ToolDocument *doc = new Sublime::ToolDocument(name, this, new UiToolViewFactory(factory)); d->factoryDocuments[factory] = doc; /* Until areas are restored, we don't know which views should be really added, and which not, so we just record view availability. */ if (d->areasRestored) { foreach (Sublime::Area* area, allAreas()) { addToolViewToArea(factory, doc, area); } } } void KDevelop::UiController::raiseToolView(Sublime::View * view) { foreach( Sublime::Area* area, allAreas() ) { if( area->toolViews().contains( view ) ) area->raiseToolView( view ); } } void KDevelop::UiController::removeToolView(IToolViewFactory *factory) { if (!factory) return; qCDebug(SHELL) ; //delete the tooldocument Sublime::ToolDocument *doc = d->factoryDocuments[factory]; ///@todo adymo: on document deletion all its views shall be also deleted foreach (Sublime::View *view, doc->views()) { foreach (Sublime::Area *area, allAreas()) if (area->removeToolView(view)) view->deleteLater(); } d->factoryDocuments.remove(factory); delete doc; } Sublime::Area *UiController::activeArea() { Sublime::MainWindow *m = activeSublimeWindow(); if (m) return activeSublimeWindow()->area(); return 0; } Sublime::MainWindow *UiController::activeSublimeWindow() { return d->activeSublimeWindow; } MainWindow *UiController::defaultMainWindow() { return d->defaultMainWindow; } void UiController::initialize() { defaultMainWindow()->initialize(); } void UiController::cleanup() { foreach (Sublime::MainWindow* w, mainWindows()) w->saveSettings(); saveAllAreas(KSharedConfig::openConfig()); } void UiController::selectNewToolViewToAdd(MainWindow *mw) { if (!mw || !mw->area()) return; QDialog *dia = new QDialog(mw); dia->setWindowTitle(i18n("Select Tool View to Add")); auto mainLayout = new QVBoxLayout(dia); NewToolViewListWidget *list = new NewToolViewListWidget(mw, dia); list->setSelectionMode(QAbstractItemView::ExtendedSelection); list->setSortingEnabled(true); for (QMap::const_iterator it = d->factoryDocuments.constBegin(); it != d->factoryDocuments.constEnd(); ++it) { ViewSelectorItem *item = new ViewSelectorItem(it.value()->title(), list); item->factory = it.key(); if (!item->factory->allowMultiple() && toolViewPresent(it.value(), mw->area())) { // Disable item if the toolview is already present. item->setFlags(item->flags() & ~Qt::ItemIsEnabled); } list->addItem(item); } list->setFocus(); connect(list, &NewToolViewListWidget::addNewToolView, this, &UiController::addNewToolView); mainLayout->addWidget(list); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel); auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - dia->connect(buttonBox, SIGNAL(accepted()), dia, SLOT(accept())); - dia->connect(buttonBox, SIGNAL(rejected()), dia, SLOT(reject())); + dia->connect(buttonBox, &QDialogButtonBox::accepted, dia, &QDialog::accept); + dia->connect(buttonBox, &QDialogButtonBox::rejected, dia, &QDialog::reject); mainLayout->addWidget(buttonBox); if (dia->exec() == QDialog::Accepted) { foreach (QListWidgetItem* item, list->selectedItems()) { addNewToolView(mw, item); } } delete dia; } void UiController::addNewToolView(MainWindow *mw, QListWidgetItem* item) { ViewSelectorItem *current = static_cast(item); Sublime::ToolDocument *doc = d->factoryDocuments[current->factory]; Sublime::View *view = doc->createView(); mw->area()->addToolView(view, Sublime::dockAreaToPosition(current->factory->defaultPosition())); current->factory->viewCreated(view); } void UiController::showSettingsDialog() { auto editorConfigPage = new EditorConfigPage(activeMainWindow()); auto configPages = QVector { new UiPreferences(activeMainWindow()), new PluginPreferences(activeMainWindow()), new SourceFormatterSettings(activeMainWindow()), new ProjectPreferences(activeMainWindow()), new EnvironmentPreferences(QString(), activeMainWindow()), new CCPreferences(activeMainWindow()), new BGPreferences(activeMainWindow()), new TemplateConfig(activeMainWindow()), editorConfigPage }; ConfigDialog cfgDlg(configPages, activeMainWindow()); auto addPluginPages = [&](IPlugin* plugin) { for (int i = 0, numPages = plugin->configPages(); i < numPages; ++i) { // insert them before the editor config page cfgDlg.addConfigPage(plugin->configPage(i, &cfgDlg), editorConfigPage); } }; for (IPlugin* plugin : ICore::self()->pluginController()->loadedPlugins()) { addPluginPages(plugin); } // TODO: only load settings if a UI related page was changed? connect(&cfgDlg, &ConfigDialog::configSaved, activeSublimeWindow(), &Sublime::MainWindow::loadSettings); // make sure that pages get added whenever a new plugin is loaded (probably from the plugin selection dialog) // removal on plugin unload is already handled in ConfigDialog connect(ICore::self()->pluginController(), &IPluginController::pluginLoaded, &cfgDlg, addPluginPages); cfgDlg.exec(); } Sublime::Controller* UiController::controller() { return this; } KParts::MainWindow *UiController::activeMainWindow() { return activeSublimeWindow(); } void UiController::saveArea(Sublime::Area * area, KConfigGroup & group) { area->save(group); if (!area->workingSet().isEmpty()) { WorkingSet* set = Core::self()->workingSetControllerInternal()->getWorkingSet(area->workingSet()); set->saveFromArea(area, area->rootIndex()); } } void UiController::loadArea(Sublime::Area * area, const KConfigGroup & group) { area->load(group); if (!area->workingSet().isEmpty()) { WorkingSet* set = Core::self()->workingSetControllerInternal()->getWorkingSet(area->workingSet()); Q_ASSERT(set->isConnected(area)); Q_UNUSED(set); } } void UiController::saveAllAreas(KSharedConfigPtr config) { KConfigGroup uiConfig(config, "User Interface"); int wc = mainWindows().size(); uiConfig.writeEntry("Main Windows Count", wc); for (int w = 0; w < wc; ++w) { KConfigGroup mainWindowConfig(&uiConfig, QString("Main Window %1").arg(w)); foreach (Sublime::Area* defaultArea, defaultAreas()) { // FIXME: using object name seems ugly. QString type = defaultArea->objectName(); Sublime::Area* area = this->area(w, type); KConfigGroup areaConfig(&mainWindowConfig, "Area " + type); areaConfig.deleteGroup(); areaConfig.writeEntry("id", type); saveArea(area, areaConfig); areaConfig.sync(); } } uiConfig.sync(); } void UiController::loadAllAreas(KSharedConfigPtr config) { KConfigGroup uiConfig(config, "User Interface"); int wc = uiConfig.readEntry("Main Windows Count", 1); /* It is expected the main windows are restored before restoring areas. */ if (wc > mainWindows().size()) wc = mainWindows().size(); QList changedAreas; /* Offer all toolviews to the default areas. */ foreach (Sublime::Area *area, defaultAreas()) { QMap::const_iterator i, e; for (i = d->factoryDocuments.constBegin(), e = d->factoryDocuments.constEnd(); i != e; ++i) { addToolViewIfWanted(i.key(), i.value(), area); } } /* Restore per-windows areas. */ for (int w = 0; w < wc; ++w) { KConfigGroup mainWindowConfig(&uiConfig, QString("Main Window %1").arg(w)); Sublime::MainWindow *mw = mainWindows()[w]; /* We loop over default areas. This means that if the config file has an area of some type that is not in default set, we'd just ignore it. I think it's fine -- the model were a given mainwindow can has it's own area types not represented in the default set is way too complex. */ foreach (Sublime::Area* defaultArea, defaultAreas()) { QString type = defaultArea->objectName(); Sublime::Area* area = this->area(w, type); KConfigGroup areaConfig(&mainWindowConfig, "Area " + type); qCDebug(SHELL) << "Trying to restore area " << type; /* This is just an easy check that a group exists, to avoid "restoring" area from empty config group, wiping away programmatically installed defaults. */ if (areaConfig.readEntry("id", "") == type) { qCDebug(SHELL) << "Restoring area " << type; loadArea(area, areaConfig); } // At this point we know which toolviews the area wants. // Tender all tool views we have. QMap::const_iterator i, e; for (i = d->factoryDocuments.constBegin(), e = d->factoryDocuments.constEnd(); i != e; ++i) { addToolViewIfWanted(i.key(), i.value(), area); } } // Force reload of the changes. showAreaInternal(mw->area(), mw); mw->enableAreaSettingsSave(); } d->areasRestored = true; } void UiController::addToolViewToDockArea(IToolViewFactory* factory, Qt::DockWidgetArea area) { addToolViewToArea(factory, d->factoryDocuments[factory], activeArea(), Sublime::dockAreaToPosition(area)); } bool UiController::toolViewPresent(Sublime::ToolDocument* doc, Sublime::Area* area) { foreach (Sublime::View *view, doc->views()) { if( area->toolViews().contains( view ) ) return true; } return false; } void UiController::addToolViewIfWanted(IToolViewFactory* factory, Sublime::ToolDocument* doc, Sublime::Area* area) { if (area->wantToolView(factory->id())) { addToolViewToArea(factory, doc, area); } } Sublime::View* UiController::addToolViewToArea(IToolViewFactory* factory, Sublime::ToolDocument* doc, Sublime::Area* area, Sublime::Position p) { Sublime::View* view = doc->createView(); area->addToolView( view, p == Sublime::AllPositions ? Sublime::dockAreaToPosition(factory->defaultPosition()) : p); connect(view, &Sublime::View::raise, this, static_cast(&UiController::raiseToolView)); factory->viewCreated(view); return view; } void UiController::registerStatus(QObject* status) { Sublime::MainWindow* w = activeSublimeWindow(); if (!w) return; MainWindow* mw = qobject_cast(w); if (!mw) return; mw->registerStatus(status); } void UiController::showErrorMessage(const QString& message, int timeout) { Sublime::MainWindow* w = activeSublimeWindow(); if (!w) return; MainWindow* mw = qobject_cast(w); if (!mw) return; QMetaObject::invokeMethod(mw, "showErrorMessage", Q_ARG(QString, message), Q_ARG(int, timeout)); } void UiController::hideAssistant() { if (d->currentShownAssistant) { d->currentShownAssistant->hide(); } } void UiController::popUpAssistant(const KDevelop::IAssistant::Ptr& assistant) { if(!assistant) return; Sublime::View* view = d->activeSublimeWindow->activeView(); if( !view ) { qCDebug(SHELL) << "no active view in mainwindow"; return; } auto editorView = qobject_cast(view->widget()); Q_ASSERT(editorView); if (editorView) { if ( !d->currentShownAssistant ) { d->currentShownAssistant = new AssistantPopup; } d->currentShownAssistant->reset(editorView, assistant); } } const QMap< IToolViewFactory*, Sublime::ToolDocument* >& UiController::factoryDocuments() const { return d->factoryDocuments; } } #include "uicontroller.moc" #include "moc_uicontroller.cpp" diff --git a/vcs/dvcs/ui/branchmanager.cpp b/vcs/dvcs/ui/branchmanager.cpp index b5702e7ef5..498f93b27a 100644 --- a/vcs/dvcs/ui/branchmanager.cpp +++ b/vcs/dvcs/ui/branchmanager.cpp @@ -1,166 +1,166 @@ /*************************************************************************** * Copyright 2008 Evgeniy Ivanov * * * * 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 "branchmanager.h" #include #include #include #include #include #include "../dvcsjob.h" #include "../dvcsplugin.h" #include #include "ui_branchmanager.h" #include "../../debug.h" #include #include #include #include #include #include using namespace KDevelop; BranchManager::BranchManager(const QString& repository, KDevelop::DistributedVersionControlPlugin* executor, QWidget *parent) : QDialog(parent) , m_repository(repository) , m_dvcPlugin(executor) { setWindowTitle(i18n("Branch Manager")); QWidget *mainWidget = new QWidget(this); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->addWidget(mainWidget); m_ui = new Ui::BranchDialogBase; QWidget* w = new QWidget(this); m_ui->setupUi(w); mainLayout->addWidget(w); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, &QDialogButtonBox::accepted, this, &BranchManager::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &BranchManager::reject); mainLayout->addWidget(buttonBox); m_model = new BranchesListModel(this); m_model->initialize(m_dvcPlugin, QUrl::fromLocalFile(repository)); m_ui->branchView->setModel(m_model); QString branchName = m_model->currentBranch(); // apply initial selection QList< QStandardItem* > items = m_model->findItems(branchName); if (!items.isEmpty()) { m_ui->branchView->setCurrentIndex(items.first()->index()); } m_ui->newButton->setIcon(QIcon::fromTheme("list-add")); connect(m_ui->newButton, &QPushButton::clicked, this, &BranchManager::createBranch); m_ui->deleteButton->setIcon(QIcon::fromTheme("list-remove")); connect(m_ui->deleteButton, &QPushButton::clicked, this, &BranchManager::deleteBranch); m_ui->renameButton->setIcon(QIcon::fromTheme("edit-rename")); connect(m_ui->renameButton, &QPushButton::clicked, this, &BranchManager::renameBranch); m_ui->checkoutButton->setIcon(QIcon::fromTheme("dialog-ok-apply")); connect(m_ui->checkoutButton, &QPushButton::clicked, this, &BranchManager::checkoutBranch); // checkout branch on double-click connect(m_ui->branchView, &QListView::doubleClicked, this, &BranchManager::checkoutBranch); } BranchManager::~BranchManager() { delete m_ui; } void BranchManager::createBranch() { const QModelIndex currentBranchIdx = m_ui->branchView->currentIndex(); if (!currentBranchIdx.isValid()) { KMessageBox::messageBox(this, KMessageBox::Error, i18n("You must select a base branch from the list before creating a new branch.")); return; } QString baseBranch = currentBranchIdx.data().toString(); bool branchNameEntered = false; QString newBranch = QInputDialog::getText(this, i18n("New branch"), i18n("Name of the new branch:"), QLineEdit::Normal, QString(), &branchNameEntered); if (!branchNameEntered) return; if (!m_model->findItems(newBranch).isEmpty()) { KMessageBox::messageBox(this, KMessageBox::Sorry, i18n("Branch \"%1\" already exists.\n" "Please, choose another name.", newBranch)); } else m_model->createBranch(baseBranch, newBranch); } void BranchManager::deleteBranch() { QString baseBranch = m_ui->branchView->selectionModel()->selection().indexes().first().data().toString(); if (baseBranch == m_model->currentBranch()) { KMessageBox::messageBox(this, KMessageBox::Sorry, i18n("Currently at the branch \"%1\".\n" "To remove it, please change to another branch.", baseBranch)); return; } int ret = KMessageBox::messageBox(this, KMessageBox::WarningYesNo, i18n("Are you sure you want to irreversibly remove the branch '%1'?", baseBranch)); if (ret == KMessageBox::Yes) m_model->removeBranch(baseBranch); } void BranchManager::renameBranch() { QModelIndex currentIndex = m_ui->branchView->currentIndex(); if (!currentIndex.isValid()) return; m_ui->branchView->edit(currentIndex); } void BranchManager::checkoutBranch() { QString branch = m_ui->branchView->currentIndex().data().toString(); if (branch == m_model->currentBranch()) { KMessageBox::messageBox(this, KMessageBox::Sorry, i18n("Already on branch \"%1\"\n", branch)); return; } qCDebug(VCS) << "Switching to" << branch << "in" << m_repository; KDevelop::VcsJob *branchJob = m_dvcPlugin->switchBranch(QUrl::fromLocalFile(m_repository), branch); // connect(branchJob, SIGNAL(finished(KJob*)), m_model, SIGNAL(resetCurrent())); ICore::self()->runController()->registerJob(branchJob); close(); } diff --git a/vcs/vcspluginhelper.cpp b/vcs/vcspluginhelper.cpp index 6ecf8de970..c11fbf28a3 100644 --- a/vcs/vcspluginhelper.cpp +++ b/vcs/vcspluginhelper.cpp @@ -1,548 +1,548 @@ /*************************************************************************** * Copyright 2008 Andreas Pakulat * * Copyright 2010 Aleix Pol Gonzalez * * * * 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. * * * ***************************************************************************/ #include "vcspluginhelper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "interfaces/idistributedversioncontrol.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vcsstatusinfo.h" #include #include #include "widgets/vcsdiffpatchsources.h" #include "widgets/flexibleaction.h" #include #include "vcsevent.h" #include #include #include #include #include #include #include #include #include namespace KDevelop { struct VcsPluginHelper::VcsPluginHelperPrivate { IPlugin * plugin; IBasicVersionControl * vcs; QList ctxUrls; QAction* commitAction; QAction* addAction; QAction* updateAction; QAction* historyAction; QAction* annotationAction; QAction* diffToBaseAction; QAction* revertAction; QAction* diffForRevAction; QAction* diffForRevGlobalAction; QAction* pushAction; QAction* pullAction; void createActions(VcsPluginHelper* parent) { commitAction = new QAction(QIcon::fromTheme("svn-commit"), i18n("Commit..."), parent); updateAction = new QAction(QIcon::fromTheme("svn-update"), i18n("Update"), parent); addAction = new QAction(QIcon::fromTheme("list-add"), i18n("Add"), parent); diffToBaseAction = new QAction(QIcon::fromTheme("text-x-patch"), i18n("Show Differences..."), parent); revertAction = new QAction(QIcon::fromTheme("archive-remove"), i18n("Revert"), parent); historyAction = new QAction(QIcon::fromTheme("view-history"), i18n("History..."), parent); annotationAction = new QAction(QIcon::fromTheme("user-properties"), i18n("Annotation..."), parent); diffForRevAction = new QAction(QIcon::fromTheme("text-x-patch"), i18n("Show Diff..."), parent); diffForRevGlobalAction = new QAction(QIcon::fromTheme("text-x-patch"), i18n("Show Diff (all files)..."), parent); pushAction = new QAction(QIcon::fromTheme("arrow-up-double"), i18n("Push"), parent); pullAction = new QAction(QIcon::fromTheme("arrow-down-double"), i18n("Pull"), parent); connect(commitAction, &QAction::triggered, parent, &VcsPluginHelper::commit); connect(addAction, &QAction::triggered, parent, &VcsPluginHelper::add); connect(updateAction, &QAction::triggered, parent, &VcsPluginHelper::update); connect(diffToBaseAction, &QAction::triggered, parent, &VcsPluginHelper::diffToBase); connect(revertAction, &QAction::triggered, parent, &VcsPluginHelper::revert); connect(historyAction, &QAction::triggered, parent, [=] { parent->history(); }); connect(annotationAction, &QAction::triggered, parent, &VcsPluginHelper::annotation); connect(diffForRevAction, &QAction::triggered, parent, static_cast(&VcsPluginHelper::diffForRev)); connect(diffForRevGlobalAction, &QAction::triggered, parent, &VcsPluginHelper::diffForRevGlobal); connect(pullAction, &QAction::triggered, parent, &VcsPluginHelper::pull); connect(pushAction, &QAction::triggered, parent, &VcsPluginHelper::push); } bool allLocalFiles(const QList& urls) { bool ret=true; foreach(const QUrl &url, urls) { QFileInfo info(url.toLocalFile()); ret &= info.isFile(); } return ret; } QMenu* createMenu() { bool allVersioned=true; foreach(const QUrl &url, ctxUrls) { allVersioned=allVersioned && vcs->isVersionControlled(url); if(!allVersioned) break; } QMenu* menu=new QMenu(vcs->name()); menu->setIcon(QIcon::fromTheme(ICore::self()->pluginController()->pluginInfo(plugin).icon())); menu->addAction(commitAction); if(plugin->extension()) { menu->addAction(pushAction); menu->addAction(pullAction); } else { menu->addAction(updateAction); } menu->addSeparator(); menu->addAction(addAction); menu->addAction(revertAction); menu->addSeparator(); menu->addAction(historyAction); menu->addAction(annotationAction); menu->addAction(diffToBaseAction); const bool singleVersionedFile = ctxUrls.count() == 1 && allVersioned; historyAction->setEnabled(singleVersionedFile); annotationAction->setEnabled(singleVersionedFile && allLocalFiles(ctxUrls)); diffToBaseAction->setEnabled(singleVersionedFile); commitAction->setEnabled(singleVersionedFile); return menu; } }; VcsPluginHelper::VcsPluginHelper(KDevelop::IPlugin* parent, KDevelop::IBasicVersionControl* vcs) : QObject(parent) , d(new VcsPluginHelperPrivate()) { Q_ASSERT(vcs); Q_ASSERT(parent); d->plugin = parent; d->vcs = vcs; d->createActions(this); } VcsPluginHelper::~VcsPluginHelper() {} void VcsPluginHelper::addContextDocument(const QUrl &url) { d->ctxUrls.append(url); } void VcsPluginHelper::disposeEventually(KTextEditor::View *, bool dont) { if ( ! dont ) { deleteLater(); } } void VcsPluginHelper::disposeEventually(KTextEditor::Document *) { deleteLater(); } void VcsPluginHelper::setupFromContext(Context* context) { d->ctxUrls.clear(); { KDevelop::ProjectItemContext* prjctx = dynamic_cast(context); if (prjctx) { foreach(KDevelop::ProjectBaseItem* item, prjctx->items()) { if(!item->target()) d->ctxUrls.append(item->path().toUrl()); } } } { KDevelop::EditorContext* editctx = dynamic_cast(context); if (editctx) { d->ctxUrls.append(editctx->url()); } } { KDevelop::FileContext* filectx = dynamic_cast(context); if (filectx) { d->ctxUrls = filectx->urls(); } } } QList VcsPluginHelper::contextUrlList() const { return d->ctxUrls; } QMenu* VcsPluginHelper::commonActions() { /* TODO: the following logic to determine which actions need to be enabled * or disabled does not work properly. What needs to be implemented is that * project items that are vc-controlled enable all except add, project * items that are not vc-controlled enable add action. For urls that cannot * be made into a project item, or if the project has no associated VC * plugin we need to check whether a VC controls the parent dir, if we have * one we assume the urls can be added but are not currently controlled. If * the url is already version controlled then just enable all except add */ return d->createMenu(); } #define EXECUTE_VCS_METHOD( method ) \ d->plugin->core()->runController()->registerJob( d->vcs-> method ( d->ctxUrls ) ) #define SINGLEURL_SETUP_VARS \ KDevelop::IBasicVersionControl* iface = d->vcs;\ const QUrl &url = d->ctxUrls.front(); void VcsPluginHelper::revert() { VcsJob* job=d->vcs->revert(d->ctxUrls); connect(job, &VcsJob::finished, this, &VcsPluginHelper::revertDone); foreach(const QUrl &url, d->ctxUrls) { IDocument* doc=ICore::self()->documentController()->documentForUrl(url); if(doc && doc->textDocument()) { KTextEditor::ModificationInterface* modif = dynamic_cast(doc->textDocument()); if (modif) { modif->setModifiedOnDiskWarning(false); } doc->textDocument()->setModified(false); } } job->setProperty("urls", QVariant::fromValue(d->ctxUrls)); d->plugin->core()->runController()->registerJob(job); } void VcsPluginHelper::revertDone(KJob* job) { QTimer* modificationTimer = new QTimer; modificationTimer->setInterval(100); connect(modificationTimer, &QTimer::timeout, this, &VcsPluginHelper::delayedModificationWarningOn); connect(modificationTimer, &QTimer::timeout, modificationTimer, &QTimer::deleteLater); modificationTimer->setProperty("urls", job->property("urls")); modificationTimer->start(); } void VcsPluginHelper::delayedModificationWarningOn() { QObject* timer = sender(); QList urls = timer->property("urls").value>(); foreach(const QUrl &url, urls) { IDocument* doc=ICore::self()->documentController()->documentForUrl(url); if(doc) { doc->reload(); KTextEditor::ModificationInterface* modif=dynamic_cast(doc->textDocument()); modif->setModifiedOnDiskWarning(true); } } } void VcsPluginHelper::diffJobFinished(KJob* job) { KDevelop::VcsJob* vcsjob = qobject_cast(job); Q_ASSERT(vcsjob); if (vcsjob->status() == KDevelop::VcsJob::JobSucceeded) { KDevelop::VcsDiff d = vcsjob->fetchResults().value(); if(d.isEmpty()) KMessageBox::information(ICore::self()->uiController()->activeMainWindow(), i18n("There are no differences."), i18n("VCS support")); else { VCSDiffPatchSource* patch=new VCSDiffPatchSource(d); showVcsDiff(patch); } } else { KMessageBox::error(ICore::self()->uiController()->activeMainWindow(), vcsjob->errorString(), i18n("Unable to get difference.")); } } void VcsPluginHelper::diffToBase() { SINGLEURL_SETUP_VARS ICore::self()->documentController()->saveAllDocuments(); VCSDiffPatchSource* patch =new VCSDiffPatchSource(new VCSStandardDiffUpdater(iface, url)); showVcsDiff(patch); } void VcsPluginHelper::diffForRev() { if (d->ctxUrls.isEmpty()) { return; } diffForRev(d->ctxUrls.first()); } void VcsPluginHelper::diffForRevGlobal() { if (d->ctxUrls.isEmpty()) { return; } QUrl url = d->ctxUrls.first(); IProject* project = ICore::self()->projectController()->findProjectForUrl( url ); if( project ) { url = project->path().toUrl(); } diffForRev(url); } void VcsPluginHelper::diffForRev(const QUrl& url) { QAction* action = qobject_cast( sender() ); Q_ASSERT(action); Q_ASSERT(action->data().canConvert()); VcsRevision rev = action->data().value(); ICore::self()->documentController()->saveAllDocuments(); VcsRevision prev = KDevelop::VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Previous); KDevelop::VcsJob* job = d->vcs->diff(url, prev, rev ); connect(job, &VcsJob::finished, this, &VcsPluginHelper::diffJobFinished); d->plugin->core()->runController()->registerJob(job); } void VcsPluginHelper::history(const VcsRevision& rev) { SINGLEURL_SETUP_VARS QDialog* dlg = new QDialog(ICore::self()->uiController()->activeMainWindow()); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->setWindowTitle(i18nc("%1: path or URL, %2: name of a version control system", "%2 History (%1)", url.toDisplayString(QUrl::PreferLocalFile), iface->name())); QVBoxLayout *mainLayout = new QVBoxLayout(dlg); KDevelop::VcsEventWidget* logWidget = new KDevelop::VcsEventWidget(url, rev, iface, dlg); mainLayout->addWidget(logWidget); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); - dlg->connect(buttonBox, SIGNAL(accepted()), dlg, SLOT(accept())); - dlg->connect(buttonBox, SIGNAL(rejected()), dlg, SLOT(reject())); + dlg->connect(buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept); + dlg->connect(buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject); mainLayout->addWidget(buttonBox); dlg->show(); } void VcsPluginHelper::annotation() { SINGLEURL_SETUP_VARS KDevelop::IDocument* doc = ICore::self()->documentController()->documentForUrl(url); if (!doc) doc = ICore::self()->documentController()->openDocument(url); KTextEditor::AnnotationInterface* annotateiface = qobject_cast(doc->textDocument()); KTextEditor::AnnotationViewInterface* viewiface = qobject_cast(doc->activeTextView()); if (viewiface && viewiface->isAnnotationBorderVisible()) { viewiface->setAnnotationBorderVisible(false); return; } if (doc && doc->textDocument() && iface) { KDevelop::VcsJob* job = iface->annotate(url); if( !job ) { qWarning() << "Couldn't create annotate job for:" << url << "with iface:" << iface << dynamic_cast( iface ); return; } QColor foreground(Qt::black); QColor background(Qt::white); if (KTextEditor::View* view = doc->activeTextView()) { KTextEditor::Attribute::Ptr style = view->defaultStyleAttribute(KTextEditor::dsNormal); foreground = style->foreground().color(); if (style->hasProperty(QTextFormat::BackgroundBrush)) { background = style->background().color(); } } if (annotateiface && viewiface) { KDevelop::VcsAnnotationModel* model = new KDevelop::VcsAnnotationModel(job, url, doc->textDocument(), foreground, background); annotateiface->setAnnotationModel(model); viewiface->setAnnotationBorderVisible(true); // can't use new signal slot syntax here, AnnotationInterface is not a QObject connect(doc->activeTextView(), SIGNAL(annotationContextMenuAboutToShow(KTextEditor::View*,QMenu*,int)), this, SLOT(annotationContextMenuAboutToShow(KTextEditor::View*,QMenu*,int))); } else { KMessageBox::error(0, i18n("Cannot display annotations, missing interface KTextEditor::AnnotationInterface for the editor.")); delete job; } } else { KMessageBox::error(0, i18n("Cannot execute annotate action because the " "document was not found, or was not a text document:\n%1", url.toDisplayString(QUrl::PreferLocalFile))); } } class CopyFunction : public AbstractFunction { public: CopyFunction(const QString& tocopy) : m_tocopy(tocopy) {} void operator()() { QApplication::clipboard()->setText(m_tocopy); } private: QString m_tocopy; }; class HistoryFunction : public AbstractFunction { public: HistoryFunction(VcsPluginHelper* helper, const VcsRevision& rev) : m_helper(helper), m_rev(rev) {} void operator()() { m_helper->history(m_rev); } private: VcsPluginHelper* m_helper; VcsRevision m_rev; }; void VcsPluginHelper::annotationContextMenuAboutToShow( KTextEditor::View* view, QMenu* menu, int line ) { KTextEditor::AnnotationInterface* annotateiface = qobject_cast(view->document()); VcsAnnotationModel* model = qobject_cast( annotateiface->annotationModel() ); Q_ASSERT(model); VcsRevision rev = model->revisionForLine(line); // check if the user clicked on a row without revision information if (rev.revisionType() == VcsRevision::Invalid) { // in this case, do not action depending on revision informations return; } d->diffForRevAction->setData(QVariant::fromValue(rev)); d->diffForRevGlobalAction->setData(QVariant::fromValue(rev)); menu->addSeparator(); menu->addAction(d->diffForRevAction); menu->addAction(d->diffForRevGlobalAction); menu->addAction(new FlexibleAction(QIcon::fromTheme("edit-copy"), i18n("Copy Revision"), new CopyFunction(rev.revisionValue().toString()), menu)); menu->addAction(new FlexibleAction(QIcon::fromTheme("view-history"), i18n("History..."), new HistoryFunction(this, rev), menu)); } void VcsPluginHelper::update() { EXECUTE_VCS_METHOD(update); } void VcsPluginHelper::add() { EXECUTE_VCS_METHOD(add); } void VcsPluginHelper::commit() { Q_ASSERT(!d->ctxUrls.isEmpty()); ICore::self()->documentController()->saveAllDocuments(); QUrl url = d->ctxUrls.first(); // We start the commit UI no matter whether there is real differences, as it can also be used to commit untracked files VCSCommitDiffPatchSource* patchSource = new VCSCommitDiffPatchSource(new VCSStandardDiffUpdater(d->vcs, url)); bool ret = showVcsDiff(patchSource); if(!ret) { VcsCommitDialog *commitDialog = new VcsCommitDialog(patchSource); commitDialog->setCommitCandidates(patchSource->infos()); commitDialog->exec(); } } void VcsPluginHelper::push() { foreach(const QUrl &url, d->ctxUrls) { VcsJob* job = d->plugin->extension()->push(url, VcsLocation()); ICore::self()->runController()->registerJob(job); } } void VcsPluginHelper::pull() { foreach(const QUrl &url, d->ctxUrls) { VcsJob* job = d->plugin->extension()->pull(VcsLocation(), url); ICore::self()->runController()->registerJob(job); } } } diff --git a/vcs/widgets/vcscommitdialog.cpp b/vcs/widgets/vcscommitdialog.cpp index 4da72aaa59..ecf53baab4 100644 --- a/vcs/widgets/vcscommitdialog.cpp +++ b/vcs/widgets/vcscommitdialog.cpp @@ -1,116 +1,116 @@ /*************************************************************************** * Copyright 2007 Dukju Ahn * * Copyright 2008 Evgeniy Ivanov * * Copyright 2011 Andrey Batyiev * * 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. * * * ***************************************************************************/ #include "vcscommitdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../vcsjob.h" #include "../interfaces/ibasicversioncontrol.h" #include "../interfaces/idistributedversioncontrol.h" #include "../interfaces/icentralizedversioncontrol.h" #include "../vcsstatusinfo.h" #include "../models/vcsfilechangesmodel.h" #include "ui_vcscommitdialog.h" #include #include #include #include #include namespace KDevelop { class VcsCommitDialogPrivate { public: Ui::VcsCommitDialog ui; IPatchSource* m_patchSource; VcsFileChangesModel* m_model; }; VcsCommitDialog::VcsCommitDialog( IPatchSource *patchSource, QWidget *parent ) : QDialog( parent ), d(new VcsCommitDialogPrivate()) { auto mainWidget = new QWidget(this); d->ui.setupUi(mainWidget); QWidget *customWidget = patchSource->customWidget(); if( customWidget ) { d->ui.gridLayout->addWidget( customWidget, 0, 0, 1, 2 ); } auto okButton = d->ui.buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - connect(d->ui.buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(d->ui.buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(d->ui.buttonBox, &QDialogButtonBox::accepted, this, &VcsCommitDialog::accept); + connect(d->ui.buttonBox, &QDialogButtonBox::rejected, this, &VcsCommitDialog::reject); d->m_patchSource = patchSource; d->m_model = new VcsFileChangesModel( this, true ); d->ui.files->setModel( d->m_model ); } VcsCommitDialog::~VcsCommitDialog() { delete d; } void VcsCommitDialog::setRecursive( bool recursive ) { d->ui.recursiveChk->setChecked( recursive ); } void VcsCommitDialog::setCommitCandidates( const QList& statuses ) { foreach( const VcsStatusInfo& info, statuses ) { d->m_model->updateState( info ); } } bool VcsCommitDialog::recursive() const { return d->ui.recursiveChk->isChecked(); } void VcsCommitDialog::ok() { if( d->m_patchSource->finishReview( d->m_model->checkedUrls() ) ) { deleteLater(); } } void VcsCommitDialog::cancel() { d->m_patchSource->cancelReview(); } } diff --git a/vcs/widgets/vcseventwidget.cpp b/vcs/widgets/vcseventwidget.cpp index 694c89cb17..ee7bb075a6 100644 --- a/vcs/widgets/vcseventwidget.cpp +++ b/vcs/widgets/vcseventwidget.cpp @@ -1,233 +1,233 @@ /*************************************************************************** * This file is part of KDevelop * * Copyright 2007 Dukju Ahn * * Copyright 2007 Andreas Pakulat * * * * 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 Library 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 "vcseventwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_vcseventwidget.h" #include "vcsdiffwidget.h" #include "../vcsjob.h" #include "../interfaces/ibasicversioncontrol.h" #include "../vcsrevision.h" #include "../vcsevent.h" #include "../vcslocation.h" #include "../debug.h" #include "../models/vcsitemeventmodel.h" #include "../models/vcseventmodel.h" namespace KDevelop { class VcsEventWidgetPrivate { public: VcsEventWidgetPrivate( VcsEventWidget* w ) : q( w ) { m_copyAction = new QAction(QIcon::fromTheme("edit-copy"), i18n("Copy revision number"), q); m_copyAction->setShortcut(Qt::ControlModifier+Qt::Key_C); QObject::connect(m_copyAction, &QAction::triggered, q, [&] { copyRevision(); }); } Ui::VcsEventWidget* m_ui; VcsItemEventModel* m_detailModel; VcsEventModel *m_logModel; QUrl m_url; QModelIndex m_contextIndex; VcsEventWidget* q; QAction* m_copyAction; IBasicVersionControl* m_iface; void eventViewCustomContextMenuRequested( const QPoint &point ); void eventViewClicked( const QModelIndex &index ); void jobReceivedResults( KDevelop::VcsJob* job ); void copyRevision(); void diffToPrevious(); void diffRevisions(); void currentRowChanged(const QModelIndex& start, const QModelIndex& end); }; void VcsEventWidgetPrivate::eventViewCustomContextMenuRequested( const QPoint &point ) { m_contextIndex = m_ui->eventView->indexAt( point ); if( !m_contextIndex.isValid() ){ qCDebug(VCS) << "contextMenu is not in TreeView"; return; } QMenu menu( m_ui->eventView ); menu.addAction(m_copyAction); menu.addAction(i18n("Diff to previous revision"), q, SLOT(diffToPrevious())); QAction* action = menu.addAction(i18n("Diff between revisions"), q, SLOT(diffRevisions())); action->setEnabled(m_ui->eventView->selectionModel()->selectedRows().size()>=2); menu.exec( m_ui->eventView->viewport()->mapToGlobal(point) ); } void VcsEventWidgetPrivate::currentRowChanged(const QModelIndex& start, const QModelIndex& end) { Q_UNUSED(end); if(start.isValid()) eventViewClicked(start); } void VcsEventWidgetPrivate::eventViewClicked( const QModelIndex &index ) { KDevelop::VcsEvent ev = m_logModel->eventForIndex( index ); m_detailModel->removeRows(0, m_detailModel->rowCount()); if( ev.revision().revisionType() != KDevelop::VcsRevision::Invalid ) { m_ui->itemEventView->setEnabled(true); m_ui->message->setEnabled(true); m_ui->message->setPlainText( ev.message() ); m_detailModel->addItemEvents( ev.items() ); }else { m_ui->itemEventView->setEnabled(false); m_ui->message->setEnabled(false); m_ui->message->clear(); } QHeaderView* header = m_ui->itemEventView->header(); header->setSectionResizeMode(QHeaderView::ResizeToContents); header->setStretchLastSection(true); } void VcsEventWidgetPrivate::copyRevision() { qApp->clipboard()->setText(m_contextIndex.sibling(m_contextIndex.row(), 0).data().toString()); } void VcsEventWidgetPrivate::diffToPrevious() { KDevelop::VcsEvent ev = m_logModel->eventForIndex( m_contextIndex ); KDevelop::VcsRevision prev = KDevelop::VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Previous); KDevelop::VcsJob* job = m_iface->diff( m_url, prev, ev.revision() ); VcsDiffWidget* widget = new VcsDiffWidget( job ); widget->setRevisions( prev, ev.revision() ); QDialog* dlg = new QDialog( q ); widget->connect(widget, &VcsDiffWidget::destroyed, dlg, &QDialog::deleteLater); dlg->setWindowTitle( i18n("Difference To Previous") ); QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); auto mainWidget = new QWidget; QVBoxLayout *mainLayout = new QVBoxLayout; dlg->setLayout(mainLayout); mainLayout->addWidget(mainWidget); QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - dlg->connect(buttonBox, SIGNAL(accepted()), dlg, SLOT(accept())); - dlg->connect(buttonBox, SIGNAL(rejected()), dlg, SLOT(reject())); + dlg->connect(buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept); + dlg->connect(buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject); mainLayout->addWidget(widget); mainLayout->addWidget(buttonBox); dlg->show(); } void VcsEventWidgetPrivate::diffRevisions() { QModelIndexList l = m_ui->eventView->selectionModel()->selectedRows(); KDevelop::VcsEvent ev1 = m_logModel->eventForIndex( l.first() ); KDevelop::VcsEvent ev2 = m_logModel->eventForIndex( l.last() ); KDevelop::VcsJob* job = m_iface->diff( m_url, ev1.revision(), ev2.revision() ); VcsDiffWidget* widget = new VcsDiffWidget( job ); widget->setRevisions( ev1.revision(), ev2.revision() ); auto dlg = new QDialog( q ); dlg->setWindowTitle( i18n("Difference between Revisions") ); widget->connect(widget, &VcsDiffWidget::destroyed, dlg, &QDialog::deleteLater); auto mainLayout = new QVBoxLayout(dlg); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); auto okButton = buttonBox->button(QDialogButtonBox::Ok); okButton->setDefault(true); okButton->setShortcut(Qt::CTRL | Qt::Key_Return); - dlg->connect(buttonBox, SIGNAL(accepted()), dlg, SLOT(accept())); - dlg->connect(buttonBox, SIGNAL(rejected()), dlg, SLOT(reject())); + dlg->connect(buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept); + dlg->connect(buttonBox, &QDialogButtonBox::rejected, dlg, &QDialog::reject); mainLayout->addWidget(buttonBox); mainLayout->addWidget(widget); dlg->show(); } VcsEventWidget::VcsEventWidget( const QUrl& url, const VcsRevision& rev, KDevelop::IBasicVersionControl* iface, QWidget* parent ) : QWidget(parent), d(new VcsEventWidgetPrivate(this) ) { d->m_iface = iface; d->m_url = url; d->m_ui = new Ui::VcsEventWidget(); d->m_ui->setupUi(this); d->m_logModel= new VcsEventModel(iface, rev, url, this); d->m_ui->eventView->setModel( d->m_logModel ); d->m_ui->eventView->sortByColumn(0, Qt::DescendingOrder); d->m_ui->eventView->setContextMenuPolicy( Qt::CustomContextMenu ); QHeaderView* header = d->m_ui->eventView->header(); header->setSectionResizeMode( 0, QHeaderView::ResizeToContents ); header->setSectionResizeMode( 1, QHeaderView::Stretch ); header->setSectionResizeMode( 2, QHeaderView::ResizeToContents ); header->setSectionResizeMode( 3, QHeaderView::ResizeToContents ); d->m_detailModel = new VcsItemEventModel(this); d->m_ui->itemEventView->setModel( d->m_detailModel ); connect( d->m_ui->eventView, &QTreeView::clicked, this, [&] (const QModelIndex& index) { d->eventViewClicked(index); } ); connect( d->m_ui->eventView->selectionModel(), &QItemSelectionModel::currentRowChanged, this, [&] (const QModelIndex& start, const QModelIndex& end) { d->currentRowChanged(start, end); }); connect( d->m_ui->eventView, &QTreeView::customContextMenuRequested, this, [&] (const QPoint& point) { d->eventViewCustomContextMenuRequested(point); } ); } VcsEventWidget::~VcsEventWidget() { delete d->m_ui; delete d; } } #include "moc_vcseventwidget.cpp"