diff --git a/plugins/filetemplates/classidentifierpage.cpp b/plugins/filetemplates/classidentifierpage.cpp index 524a23f541..df10fc6f88 100644 --- a/plugins/filetemplates/classidentifierpage.cpp +++ b/plugins/filetemplates/classidentifierpage.cpp @@ -1,82 +1,91 @@ /* This file is part of KDevelop Copyright 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 version 2 as published by the Free Software Foundation. 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 "classidentifierpage.h" #include "language/duchain/identifier.h" #include #include "ui_newclass.h" using namespace KDevelop; struct KDevelop::ClassIdentifierPagePrivate { ClassIdentifierPagePrivate() : classid(nullptr) { } Ui::NewClassDialog* classid; }; ClassIdentifierPage::ClassIdentifierPage(QWidget* parent) : QWidget(parent) , d(new ClassIdentifierPagePrivate()) { d->classid = new Ui::NewClassDialog; d->classid->setupUi(this); d->classid->identifierLineEdit->setPlaceholderText(i18n("Class name, including any namespaces")); d->classid->keditlistwidget->lineEdit()->setPlaceholderText(i18n("Inheritance type and base class name")); d->classid->inheritanceLabel->setBuddy(d->classid->keditlistwidget->lineEdit()); connect(d->classid->identifierLineEdit, &QLineEdit::textChanged, this, &ClassIdentifierPage::checkIdentifier); + // ensure keyboard focus is returned to edit line + // Patch pending for KEditListWidget: https://phabricator.kde.org/D4392 + connect(d->classid->keditlistwidget, &KEditListWidget::added, + d->classid->keditlistwidget->lineEdit(), + static_cast(&QWidget::setFocus)); + connect(d->classid->keditlistwidget, &KEditListWidget::removed, + d->classid->keditlistwidget->lineEdit(), + static_cast(&QWidget::setFocus)); + emit isValid(false); } ClassIdentifierPage::~ClassIdentifierPage() { delete d->classid; delete d; } QString ClassIdentifierPage::identifier() const { return d->classid->identifierLineEdit->text(); } void ClassIdentifierPage::checkIdentifier() { emit isValid(!identifier().isEmpty()); } QStringList ClassIdentifierPage::inheritanceList() const { return d->classid->keditlistwidget->items(); } void ClassIdentifierPage::setInheritanceList (const QStringList& list) { d->classid->keditlistwidget->setItems(list); } void ClassIdentifierPage::setFocusToFirstEditWidget() { d->classid->identifierLineEdit->setFocus(); } diff --git a/plugins/filetemplates/classmemberspage.cpp b/plugins/filetemplates/classmemberspage.cpp index 11ec4fb5cd..3586d1f7cc 100644 --- a/plugins/filetemplates/classmemberspage.cpp +++ b/plugins/filetemplates/classmemberspage.cpp @@ -1,114 +1,124 @@ /* 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 "classmemberspage.h" #include "debug.h" #include #include #include #include using namespace KDevelop; class KDevelop::ClassMembersPagePrivate { public: KEditListWidget* editListWidget; }; ClassMembersPage::ClassMembersPage(QWidget* parent) : QWidget(parent) , d(new ClassMembersPagePrivate) { d->editListWidget = new KEditListWidget(this); d->editListWidget->lineEdit()->setPlaceholderText(i18n("Variable type and identifier")); QVBoxLayout* layout = new QVBoxLayout(this); layout->addWidget(d->editListWidget); + + // ensure keyboard focus is returned to edit line + // Patch pending for KEditListWidget: https://phabricator.kde.org/D4392 + connect(d->editListWidget, &KEditListWidget::added, + d->editListWidget->lineEdit(), + static_cast(&QWidget::setFocus)); + connect(d->editListWidget, &KEditListWidget::removed, + d->editListWidget->lineEdit(), + static_cast(&QWidget::setFocus)); + setLayout(layout); } ClassMembersPage::~ClassMembersPage() { delete d; } void ClassMembersPage::setMembers(const VariableDescriptionList& members) { QStringList memberItems; foreach (const VariableDescription& variable, members) { QStringList items; if (!variable.access.isEmpty()) { items << variable.access; } if (!variable.type.isEmpty()) { items << variable.type; } items << variable.name; memberItems << items.join(QLatin1Char(' ')); } d->editListWidget->setItems(memberItems); } VariableDescriptionList ClassMembersPage::members() const { VariableDescriptionList list; foreach (const QString& item, d->editListWidget->items()) { VariableDescription var; QStringList parts = item.split(' '); switch (parts.size()) { case 1: var.name = parts[0]; break; case 2: var.type = parts[0]; var.name = parts[1]; break; case 3: var.access = parts[0]; var.type = parts[1]; var.name = parts[2]; break; default: qCDebug(PLUGIN_FILETEMPLATES) << "Malformed class member" << item; break; } if (!var.name.isEmpty()) { list << var; } } return list; } void ClassMembersPage::setFocusToFirstEditWidget() { d->editListWidget->lineEdit()->setFocus(); } diff --git a/plugins/filetemplates/filetemplatesplugin.cpp b/plugins/filetemplates/filetemplatesplugin.cpp index 954cc2ce99..da3b1edff0 100644 --- a/plugins/filetemplates/filetemplatesplugin.cpp +++ b/plugins/filetemplates/filetemplatesplugin.cpp @@ -1,317 +1,317 @@ #include "filetemplatesplugin.h" #include "templateclassassistant.h" #include "templatepreviewtoolview.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; K_PLUGIN_FACTORY_WITH_JSON(FileTemplatesFactory, "kdevfiletemplates.json", registerPlugin();) class TemplatePreviewFactory : public KDevelop::IToolViewFactory { public: explicit TemplatePreviewFactory(FileTemplatesPlugin* plugin) : KDevelop::IToolViewFactory() , m_plugin(plugin) { } QWidget* create(QWidget* parent = nullptr) override { return new TemplatePreviewToolView(m_plugin, parent); } QString id() const override { return QStringLiteral("org.kdevelop.TemplateFilePreview"); } Qt::DockWidgetArea defaultPosition() override { return Qt::RightDockWidgetArea; } private: FileTemplatesPlugin* m_plugin; }; FileTemplatesPlugin::FileTemplatesPlugin(QObject* parent, const QVariantList& args) : IPlugin(QStringLiteral("kdevfiletemplates"), parent) , m_model(nullptr) { Q_UNUSED(args); setXMLFile(QStringLiteral("kdevfiletemplates.rc")); QAction* action = actionCollection()->addAction(QStringLiteral("new_from_template")); action->setText(i18n("New From Template...")); action->setIcon( QIcon::fromTheme( QStringLiteral("code-class") ) ); action->setWhatsThis( i18n( "Allows you to create new source code files, such as classes or unit tests, using templates." ) ); action->setStatusTip( i18n( "Create new files from a template" ) ); connect (action, &QAction::triggered, this, &FileTemplatesPlugin::createFromTemplate); m_toolView = new TemplatePreviewFactory(this); core()->uiController()->addToolView(i18n("Template Preview"), m_toolView); } FileTemplatesPlugin::~FileTemplatesPlugin() { } void FileTemplatesPlugin::unload() { core()->uiController()->removeToolView(m_toolView); } ContextMenuExtension FileTemplatesPlugin::contextMenuExtension (Context* context) { ContextMenuExtension ext; QUrl fileUrl; if (context->type() == Context::ProjectItemContext) { ProjectItemContext* projectContext = dynamic_cast(context); QList items = projectContext->items(); if (items.size() != 1) { return ext; } QUrl url; ProjectBaseItem* item = items.first(); if (item->folder()) { url = item->path().toUrl(); } else if (item->target()) { url = item->parent()->path().toUrl(); } if (url.isValid()) { QAction* action = new QAction(i18n("Create From Template..."), this); action->setIcon(QIcon::fromTheme(QStringLiteral("code-class"))); action->setData(url); connect(action, &QAction::triggered, this, &FileTemplatesPlugin::createFromTemplate); ext.addAction(ContextMenuExtension::FileGroup, action); } if (item->file()) { fileUrl = item->path().toUrl(); } } else if (context->type() == Context::EditorContext) { KDevelop::EditorContext* editorContext = dynamic_cast(context); fileUrl = editorContext->url(); } if (fileUrl.isValid() && determineTemplateType(fileUrl) != NoTemplate) { QAction* action = new QAction(i18n("Show Template Preview"), this); action->setIcon(QIcon::fromTheme(QStringLiteral("document-preview"))); action->setData(fileUrl); connect(action, &QAction::triggered, this, &FileTemplatesPlugin::previewTemplate); ext.addAction(ContextMenuExtension::ExtensionGroup, action); } return ext; } QString FileTemplatesPlugin::name() const { return i18n("File Templates"); } QIcon FileTemplatesPlugin::icon() const { return QIcon::fromTheme(QStringLiteral("code-class")); } QAbstractItemModel* FileTemplatesPlugin::templatesModel() { if(!m_model) { m_model = new TemplatesModel(QStringLiteral("kdevfiletemplates"), this); } return m_model; } QString FileTemplatesPlugin::knsConfigurationFile() const { return QStringLiteral("kdevfiletemplates.knsrc"); } QStringList FileTemplatesPlugin::supportedMimeTypes() const { QStringList types; types << QStringLiteral("application/x-desktop"); types << QStringLiteral("application/x-bzip-compressed-tar"); types << QStringLiteral("application/zip"); return types; } void FileTemplatesPlugin::reload() { templatesModel(); m_model->refresh(); } void FileTemplatesPlugin::loadTemplate(const QString& fileName) { templatesModel(); m_model->loadTemplateFile(fileName); } void FileTemplatesPlugin::createFromTemplate() { QUrl baseUrl; if (QAction* action = qobject_cast(sender())) { baseUrl = action->data().toUrl(); } if (!baseUrl.isValid()) { // fall-back to currently active document's parent directory IDocument* doc = ICore::self()->documentController()->activeDocument(); if (doc && doc->url().isValid()) { baseUrl = doc->url().adjusted(QUrl::RemoveFilename); } } if (!baseUrl.isValid()) { // fall-back to currently selected project's or item's base directory ProjectItemContext* projectContext = dynamic_cast(ICore::self()->selectionController()->currentSelection()); if (projectContext) { const QList items = projectContext->items(); if (items.size() == 1) { ProjectBaseItem* item = items.at(0); if (item->folder()) { baseUrl = item->path().toUrl(); } else if (item->target()) { baseUrl = item->parent()->path().toUrl(); } } } } if (!baseUrl.isValid()) { // fall back to base directory of currently open project, if there is only one const QList projects = ICore::self()->projectController()->projects(); if (projects.size() == 1) { baseUrl = projects.at(0)->path().toUrl(); } } if (!baseUrl.isValid()) { - // last resort: home path - baseUrl = QUrl::fromLocalFile(QDir::homePath()); + // last resort + baseUrl = ICore::self()->projectController()->projectsBaseDirectory(); } TemplateClassAssistant* assistant = new TemplateClassAssistant(QApplication::activeWindow(), baseUrl); assistant->setAttribute(Qt::WA_DeleteOnClose); assistant->show(); } FileTemplatesPlugin::TemplateType FileTemplatesPlugin::determineTemplateType(const QUrl& url) { QDir dir(url.toLocalFile()); /* * Search for a description file in the url's directory. * If it is not found there, try cascading up a maximum of 5 directories. */ int level = 0; while (dir.cdUp() && level < 5) { QStringList filters; filters << QStringLiteral("*.kdevtemplate") << QStringLiteral("*.desktop"); foreach (const QString& entry, dir.entryList(filters)) { qCDebug(PLUGIN_FILETEMPLATES) << "Trying entry" << entry; /* * This logic is not perfect, but it works for most cases. * * Project template description files usually have the suffix * ".kdevtemplate", so those are easy to find. For project templates, * all the files in the directory are template files. * * On the other hand, file templates use the generic suffix ".desktop". * Fortunately, those explicitly list input and output files, so we * only match the explicitly listed files */ if (entry.endsWith(QLatin1String(".kdevtemplate"))) { return ProjectTemplate; } KConfig* config = new KConfig(dir.absoluteFilePath(entry), KConfig::SimpleConfig); KConfigGroup group = config->group("General"); qCDebug(PLUGIN_FILETEMPLATES) << "General group keys:" << group.keyList(); if (!group.hasKey("Name") || !group.hasKey("Category")) { continue; } if (group.hasKey("Files")) { qCDebug(PLUGIN_FILETEMPLATES) << "Group has files " << group.readEntry("Files", QStringList()); foreach (const QString& outputFile, group.readEntry("Files", QStringList())) { if (dir.absoluteFilePath(config->group(outputFile).readEntry("File")) == url.toLocalFile()) { return FileTemplate; } } } if (group.hasKey("ShowFilesAfterGeneration")) { return ProjectTemplate; } } ++level; } return NoTemplate; } void FileTemplatesPlugin::previewTemplate() { QAction* action = qobject_cast(sender()); if (!action || !action->data().toUrl().isValid()) { return; } TemplatePreviewToolView* preview = qobject_cast(core()->uiController()->findToolView(i18n("Template Preview"), m_toolView)); if (!preview) { return; } core()->documentController()->activateDocument(core()->documentController()->openDocument(action->data().toUrl())); } #include "filetemplatesplugin.moc" diff --git a/plugins/filetemplates/testcasespage.cpp b/plugins/filetemplates/testcasespage.cpp index 6fc720137a..9adf7ae23b 100644 --- a/plugins/filetemplates/testcasespage.cpp +++ b/plugins/filetemplates/testcasespage.cpp @@ -1,78 +1,87 @@ /* * This file is part of KDevelop * Copyright 2012 Miha Čančula * * 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 "testcasespage.h" #include "ui_testcases.h" #include #include #include using namespace KDevelop; class KDevelop::TestCasesPagePrivate { public: Ui::TestCasesPage* ui; }; TestCasesPage::TestCasesPage(QWidget* parent, Qt::WindowFlags f) : QWidget (parent, f) , d(new TestCasesPagePrivate) { d->ui = new Ui::TestCasesPage(); d->ui->setupUi(this); d->ui->testCasesLabel->setBuddy(d->ui->keditlistwidget->lineEdit()); - + + // ensure keyboard focus is returned to edit line + // Patch pending for KEditListWidget: https://phabricator.kde.org/D4392 + connect(d->ui->keditlistwidget, &KEditListWidget::added, + d->ui->keditlistwidget->lineEdit(), + static_cast(&QWidget::setFocus)); + connect(d->ui->keditlistwidget, &KEditListWidget::removed, + d->ui->keditlistwidget->lineEdit(), + static_cast(&QWidget::setFocus)); + connect(d->ui->identifierLineEdit, &QLineEdit::textChanged, this, &TestCasesPage::identifierChanged); } TestCasesPage::~TestCasesPage() { delete d->ui; delete d; } QString TestCasesPage::name() const { return d->ui->identifierLineEdit->text(); } void TestCasesPage::setTestCases(const QStringList& testCases) { d->ui->keditlistwidget->setItems(testCases); } QStringList TestCasesPage::testCases() const { return d->ui->keditlistwidget->items(); } void TestCasesPage::setFocusToFirstEditWidget() { d->ui->identifierLineEdit->setFocus(); } void TestCasesPage::identifierChanged(const QString& identifier) { emit isValid(!identifier.isEmpty()); } diff --git a/plugins/filetemplates/ui/newclass.ui b/plugins/filetemplates/ui/newclass.ui index 2b5b7129bf..db6caed134 100644 --- a/plugins/filetemplates/ui/newclass.ui +++ b/plugins/filetemplates/ui/newclass.ui @@ -1,79 +1,64 @@ NewClassDialog 0 0 555 488 - - + + Identify the class and any classes from which it is to inherit. - + &Identifier: - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - identifierLineEdit + + + In&heritance: - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - Qt::Vertical - - - - 20 - 40 - + + + + + 0 + 1 + - - - - - - - + KEditListWidget QWidget
keditlistwidget.h
- - identifierLineEdit -
diff --git a/plugins/filetemplates/ui/testcases.ui b/plugins/filetemplates/ui/testcases.ui index b657d062b4..a7c98c1b68 100644 --- a/plugins/filetemplates/ui/testcases.ui +++ b/plugins/filetemplates/ui/testcases.ui @@ -1,88 +1,64 @@ TestCasesPage 0 0 555 488 Set the test name and its test cases. - - - - - - - &Identifier: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - identifierLineEdit - - - - - - - - - - - &Test Cases: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - Qt::Vertical + + + + + &Identifier: - - - 20 - 40 - + + identifierLineEdit - + - - + + - - - - - - + + + + &Test Cases: + + + + + + + + 0 + 1 + + + KEditListWidget QWidget
keditlistwidget.h