diff --git a/addons/backtracebrowser/katebacktracebrowser.cpp b/addons/backtracebrowser/katebacktracebrowser.cpp index 9ce9dcee2..840cdaee6 100644 --- a/addons/backtracebrowser/katebacktracebrowser.cpp +++ b/addons/backtracebrowser/katebacktracebrowser.cpp @@ -1,419 +1,418 @@ /* This file is part of the KDE project Copyright 2008-2014 Dominik Haumann 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. */ //BEGIN Includes #include "katebacktracebrowser.h" #include "btparser.h" #include "btfileindexer.h" #include // i18n #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include //END Includes K_PLUGIN_FACTORY_WITH_JSON(KateBtBrowserFactory, "katebacktracebrowserplugin.json", registerPlugin();) KateBtBrowserPlugin *KateBtBrowserPlugin::s_self = nullptr; static QStringList fileExtensions = QStringList() << QStringLiteral("*.cpp") << QStringLiteral("*.cxx") << QStringLiteral("*.c") << QStringLiteral("*.cc") << QStringLiteral("*.h") << QStringLiteral("*.hpp") << QStringLiteral("*.hxx") << QStringLiteral("*.moc"); KateBtBrowserPlugin::KateBtBrowserPlugin(QObject *parent, const QList &) : KTextEditor::Plugin(parent) , indexer(&db) { s_self = this; db.loadFromFile(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/katebtbrowser/backtracedatabase.db")); } KateBtBrowserPlugin::~KateBtBrowserPlugin() { if (indexer.isRunning()) { indexer.cancel(); indexer.wait(); } const QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/katebtbrowser"); QDir().mkpath(path); db.saveToFile(path + QStringLiteral("/backtracedatabase.db")); s_self = nullptr; } KateBtBrowserPlugin &KateBtBrowserPlugin::self() { return *s_self; } QObject *KateBtBrowserPlugin::createView(KTextEditor::MainWindow *mainWindow) { KateBtBrowserPluginView *view = new KateBtBrowserPluginView(this, mainWindow); return view; } KateBtDatabase &KateBtBrowserPlugin::database() { return db; } BtFileIndexer &KateBtBrowserPlugin::fileIndexer() { return indexer; } void KateBtBrowserPlugin::startIndexer() { if (indexer.isRunning()) { indexer.cancel(); indexer.wait(); } KConfigGroup cg(KSharedConfig::openConfig(), "backtracebrowser"); indexer.setSearchPaths(cg.readEntry("search-folders", QStringList())); indexer.setFilter(cg.readEntry("file-extensions", fileExtensions)); indexer.start(); emit newStatus(i18n("Indexing files...")); } int KateBtBrowserPlugin::configPages() const { return 1; } KTextEditor::ConfigPage *KateBtBrowserPlugin::configPage(int number, QWidget *parent) { if (number == 0) { return new KateBtConfigWidget(parent); } return nullptr; } KateBtBrowserPluginView::KateBtBrowserPluginView(KateBtBrowserPlugin *plugin, KTextEditor::MainWindow *mainWindow) : QObject(mainWindow), m_plugin(plugin) { // init console QWidget *toolview = mainWindow->createToolView(plugin, QStringLiteral("kate_private_plugin_katebacktracebrowserplugin"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme(QStringLiteral("kbugbuster")), i18n("Backtrace Browser")); m_widget = new KateBtBrowserWidget(mainWindow, toolview); - connect(plugin, SIGNAL(newStatus(QString)), - m_widget, SLOT(setStatus(QString))); + connect(plugin, &KateBtBrowserPlugin::newStatus, m_widget, &KateBtBrowserWidget::setStatus); } KateBtBrowserPluginView::~KateBtBrowserPluginView() { // cleanup, kill toolview + widget QWidget *toolview = m_widget->parentWidget(); delete m_widget; delete toolview; } KateBtBrowserWidget::KateBtBrowserWidget(KTextEditor::MainWindow *mainwindow, QWidget *parent) : QWidget(parent) , mw(mainwindow) { setupUi(this); timer.setSingleShot(true); - connect(&timer, SIGNAL(timeout()), this, SLOT(clearStatus())); - - connect(btnBacktrace, SIGNAL(clicked()), this, SLOT(loadFile())); - connect(btnClipboard, SIGNAL(clicked()), this, SLOT(loadClipboard())); - connect(btnConfigure, SIGNAL(clicked()), this, SLOT(configure())); - connect(lstBacktrace, SIGNAL(itemActivated(QTreeWidgetItem *, int)), this, SLOT(itemActivated(QTreeWidgetItem *, int))); + connect(&timer, &QTimer::timeout, this, &KateBtBrowserWidget::clearStatus); + connect(btnBacktrace, &QPushButton::clicked, this, &KateBtBrowserWidget::loadFile); + connect(btnClipboard, &QPushButton::clicked, this, &KateBtBrowserWidget::loadClipboard); + connect(btnConfigure, &QPushButton::clicked, this, &KateBtBrowserWidget::configure); + connect(lstBacktrace, &QTreeWidget::itemActivated, this, &KateBtBrowserWidget::itemActivated); } KateBtBrowserWidget::~KateBtBrowserWidget() { } void KateBtBrowserWidget::loadFile() { QString url = QFileDialog::getOpenFileName(mw->window(), i18n("Load Backtrace")); QFile f(url); if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { QString str = QString::fromUtf8(f.readAll()); loadBacktrace(str); } } void KateBtBrowserWidget::loadClipboard() { QString bt = QApplication::clipboard()->text(); loadBacktrace(bt); } void KateBtBrowserWidget::loadBacktrace(const QString &bt) { QList infos = KateBtParser::parseBacktrace(bt); lstBacktrace->clear(); foreach(const BtInfo &info, infos) { QTreeWidgetItem *it = new QTreeWidgetItem(lstBacktrace); it->setData(0, Qt::DisplayRole, QString::number(info.step)); it->setData(0, Qt::ToolTipRole, QString::number(info.step)); QFileInfo fi(info.filename); it->setData(1, Qt::DisplayRole, fi.fileName()); it->setData(1, Qt::ToolTipRole, info.filename); if (info.type == BtInfo::Source) { it->setData(2, Qt::DisplayRole, QString::number(info.line)); it->setData(2, Qt::ToolTipRole, QString::number(info.line)); it->setData(2, Qt::UserRole, QVariant(info.line)); } it->setData(3, Qt::DisplayRole, info.function); it->setData(3, Qt::ToolTipRole, info.function); lstBacktrace->addTopLevelItem(it); } lstBacktrace->resizeColumnToContents(0); lstBacktrace->resizeColumnToContents(1); lstBacktrace->resizeColumnToContents(2); if (lstBacktrace->topLevelItemCount()) { setStatus(i18n("Loading backtrace succeeded")); } else { setStatus(i18n("Loading backtrace failed")); } } void KateBtBrowserWidget::configure() { KateBtConfigDialog dlg(mw->window()); dlg.exec(); } void KateBtBrowserWidget::itemActivated(QTreeWidgetItem *item, int column) { Q_UNUSED(column); QVariant variant = item->data(2, Qt::UserRole); if (variant.isValid()) { int line = variant.toInt(); QString file = QDir::fromNativeSeparators(item->data(1, Qt::ToolTipRole).toString()); file = QDir::cleanPath(file); QString path = file; // if not absolute path + exists, try to find with index if (!QFile::exists(path)) { // try to match the backtrace forms ".*/foo/bar.txt" and "foo/bar.txt" static QRegExp rx1(QStringLiteral("/([^/]+)/([^/]+)$")); int idx = rx1.indexIn(file); if (idx != -1) { file = rx1.cap(1) + QLatin1Char('/') + rx1.cap(2); } else { static QRegExp rx2(QStringLiteral("([^/]+)/([^/]+)$")); idx = rx2.indexIn(file); if (idx != -1) { // file is of correct form } else { qDebug() << "file patter did not match:" << file; setStatus(i18n("File not found: %1", file)); return; } } path = KateBtBrowserPlugin::self().database().value(file); } if (!path.isEmpty() && QFile::exists(path)) { KTextEditor::View *kv = mw->openUrl(QUrl(path)); kv->setCursorPosition(KTextEditor::Cursor(line - 1, 0)); kv->setFocus(); setStatus(i18n("Opened file: %1", file)); } } else { setStatus(i18n("No debugging information available")); } } void KateBtBrowserWidget::setStatus(const QString &status) { lblStatus->setText(status); timer.start(10 * 1000); } void KateBtBrowserWidget::clearStatus() { lblStatus->setText(QString()); } KateBtConfigWidget::KateBtConfigWidget(QWidget *parent) : KTextEditor::ConfigPage(parent) { setupUi(this); edtUrl->setMode(KFile::Directory); edtUrl->setUrl(QUrl(QDir().absolutePath())); reset(); - connect(btnAdd, SIGNAL(clicked()), this, SLOT(add())); - connect(btnRemove, SIGNAL(clicked()), this, SLOT(remove())); - connect(edtExtensions, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); + connect(btnAdd, &QPushButton::clicked, this, &KateBtConfigWidget::add); + connect(btnRemove, &QPushButton::clicked, this, &KateBtConfigWidget::remove); + connect(edtExtensions, &QLineEdit::textChanged, this, &KateBtConfigWidget::textChanged); m_changed = false; } KateBtConfigWidget::~KateBtConfigWidget() { } QString KateBtConfigWidget::name() const { return i18n("Backtrace"); } QString KateBtConfigWidget::fullName() const { return i18n("Backtrace Settings"); } QIcon KateBtConfigWidget::icon() const { return QIcon::fromTheme(QStringLiteral("kbugbuster")); } void KateBtConfigWidget::apply() { if (m_changed) { QStringList sl; for (int i = 0; i < lstFolders->count(); ++i) { sl << lstFolders->item(i)->data(Qt::DisplayRole).toString(); } KConfigGroup cg(KSharedConfig::openConfig(), "backtracebrowser"); cg.writeEntry("search-folders", sl); QString filter = edtExtensions->text(); filter.replace(QLatin1Char(','), QLatin1Char(' ')).replace(QLatin1Char(';'), QLatin1Char(' ')); cg.writeEntry("file-extensions", filter.split(QLatin1Char(' '), QString::SkipEmptyParts)); KateBtBrowserPlugin::self().startIndexer(); m_changed = false; } } void KateBtConfigWidget::reset() { KConfigGroup cg(KSharedConfig::openConfig(), "backtracebrowser"); lstFolders->clear(); lstFolders->addItems(cg.readEntry("search-folders", QStringList())); edtExtensions->setText(cg.readEntry("file-extensions", fileExtensions).join(QStringLiteral(" "))); } void KateBtConfigWidget::defaults() { lstFolders->clear(); edtExtensions->setText(fileExtensions.join(QStringLiteral(" "))); m_changed = true; } void KateBtConfigWidget::add() { QDir url(edtUrl->lineEdit()->text()); if (url.exists()) if (lstFolders->findItems(url.absolutePath(), Qt::MatchExactly).size() == 0) { lstFolders->addItem(url.absolutePath()); emit changed(); m_changed = true; } } void KateBtConfigWidget::remove() { QListWidgetItem *item = lstFolders->currentItem(); if (item) { delete item; emit changed(); m_changed = true; } } void KateBtConfigWidget::textChanged() { emit changed(); m_changed = true; } KateBtConfigDialog::KateBtConfigDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(i18n("Backtrace Browser Settings")); m_configWidget = new KateBtConfigWidget(this); QVBoxLayout *layout = new QVBoxLayout(this); QDialogButtonBox *box = new QDialogButtonBox(this); box->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); layout->addWidget(m_configWidget); layout->addWidget(box); - connect(this, SIGNAL(accepted()), m_configWidget, SLOT(apply())); - connect(box, SIGNAL(accepted()), this, SLOT(accept())); - connect(box, SIGNAL(rejected()), this, SLOT(reject())); + connect(this, &KateBtConfigDialog::accepted, m_configWidget, &KateBtConfigWidget::apply); + connect(box, &QDialogButtonBox::accepted, this, &KateBtConfigDialog::accept); + connect(box, &QDialogButtonBox::rejected, this, &KateBtConfigDialog::reject); } KateBtConfigDialog::~KateBtConfigDialog() { } #include "katebacktracebrowser.moc" // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/close-except-like/close_confirm_dialog.cpp b/addons/close-except-like/close_confirm_dialog.cpp index 551b93228..af1bc2e7e 100644 --- a/addons/close-except-like/close_confirm_dialog.cpp +++ b/addons/close-except-like/close_confirm_dialog.cpp @@ -1,131 +1,131 @@ /** * \file * * \brief Class \c kate::CloseConfirmDialog (implementation) * * Copyright (C) 2012 Alex Turbov * * \date Sun Jun 24 16:29:13 MSK 2012 -- Initial design */ /* * KateCloseExceptPlugin 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 3 of the License, or * (at your option) any later version. * * KateCloseExceptPlugin 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 . */ // Project specific includes #include "close_confirm_dialog.h" // Standard includes #include #include /// \todo Where is \c i18n() defiend? #include #include #include #include #include #include #include #include namespace kate { namespace { class KateDocItem : public QTreeWidgetItem { public: KateDocItem(KTextEditor::Document* doc, QTreeWidget* tw) : QTreeWidgetItem(tw) , document(doc) { setText(0, doc->documentName()); setText(1, doc->url().toString()); setCheckState(0, Qt::Checked); } KTextEditor::Document* document; }; } // anonymous namespace CloseConfirmDialog::CloseConfirmDialog( QList& docs , KToggleAction* show_confirmation_action , QWidget* const parent ) : QDialog(parent) , m_docs(docs) { assert("Documents container expected to be non empty" && !docs.isEmpty()); setupUi(this); setWindowTitle(i18nc("@title:window", "Close files confirmation")); setModal(true); buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); icon->setPixmap(KIconLoader::global()->loadIcon(QStringLiteral("dialog-warning"),KIconLoader::Desktop,KIconLoader::SizeLarge)); text->setText( i18nc("@label:listbox", "You are about to close the following documents:") ); QStringList headers; headers << i18nc("@title:column", "Document") << i18nc("@title:column", "Location"); m_docs_tree->setHeaderLabels(headers); m_docs_tree->setSelectionMode(QAbstractItemView::SingleSelection); m_docs_tree->setRootIsDecorated(false); for (int i = 0; i < m_docs.size(); i++) { new KateDocItem(m_docs[i], m_docs_tree); } m_docs_tree->header()->setStretchLastSection(false); m_docs_tree->header()->setSectionResizeMode(0, QHeaderView::ResizeToContents); m_docs_tree->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); m_dont_ask_again->setText(i18nc("option:check", "Do not ask again")); // NOTE If we are here, it means that 'Show Confirmation' action is enabled, // so not needed to read config... assert("Sanity check" && show_confirmation_action->isChecked()); m_dont_ask_again->setCheckState(Qt::Unchecked); - connect(m_dont_ask_again, SIGNAL(toggled(bool)), show_confirmation_action, SLOT(toggle())); + connect(m_dont_ask_again, &QCheckBox::toggled, show_confirmation_action, &KToggleAction::toggle); // Update documents list according checkboxes - connect(this, SIGNAL(accepted()), this, SLOT(updateDocsList())); + connect(this, &CloseConfirmDialog::accepted, this, &CloseConfirmDialog::updateDocsList); KConfigGroup gcg(KSharedConfig::openConfig(), "kate-close-except-like-CloseConfirmationDialog"); KWindowConfig::restoreWindowSize(windowHandle(),gcg); // restore dialog geometry from config } CloseConfirmDialog::~CloseConfirmDialog() { KConfigGroup gcg(KSharedConfig::openConfig(), "kate-close-except-like-CloseConfirmationDialog"); KWindowConfig::saveWindowSize(windowHandle(),gcg); // write dialog geometry to config gcg.sync(); } /** * Going to remove unchecked files from the given documents list */ void CloseConfirmDialog::updateDocsList() { for ( QTreeWidgetItemIterator it(m_docs_tree, QTreeWidgetItemIterator::NotChecked) ; *it ; ++it ) { KateDocItem* item = static_cast(*it); m_docs.removeAll(item->document); qDebug() << "do not close the file " << item->document->url().toString(); } } } // namespace kate diff --git a/addons/close-except-like/close_except_plugin.cpp b/addons/close-except-like/close_except_plugin.cpp index 3ceed284c..1f100c23b 100644 --- a/addons/close-except-like/close_except_plugin.cpp +++ b/addons/close-except-like/close_except_plugin.cpp @@ -1,391 +1,371 @@ /** * \file * * \brief Kate Close Except/Like plugin implementation * * Copyright (C) 2012 Alex Turbov * * \date Thu Mar 8 08:13:43 MSK 2012 -- Initial design */ /* * KateCloseExceptPlugin 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 3 of the License, or * (at your option) any later version. * * KateCloseExceptPlugin 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 . */ // Project specific includes #include "config.h" #include "close_except_plugin.h" #include "close_confirm_dialog.h" // Standard includes #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(CloseExceptPluginFactory, "katecloseexceptplugin.json", registerPlugin();) /*K_EXPORT_PLUGIN( CloseExceptPluginFactory( KAboutData( "katecloseexceptplugin" , "katecloseexceptplugin" , ki18n("Close Except/Like Plugin") , PLUGIN_VERSION , ki18n("Close all documents started from specified path") , KAboutData::License_LGPL_V3 ) ) )*/ namespace kate { //BEGIN CloseExceptPlugin CloseExceptPlugin::CloseExceptPlugin( QObject* application , const QList& ) : KTextEditor::Plugin(application) { } QObject* CloseExceptPlugin::createView(KTextEditor::MainWindow* parent) { return new CloseExceptPluginView(parent, this); } void CloseExceptPlugin::readSessionConfig(const KConfigGroup& config) { const KConfigGroup scg(&config, QStringLiteral("menu")); m_show_confirmation_needed = scg.readEntry(QStringLiteral("ShowConfirmation"), true); } void CloseExceptPlugin::writeSessionConfig(KConfigGroup& config) { KConfigGroup scg(&config, QStringLiteral("menu")); scg.writeEntry(QStringLiteral("ShowConfirmation"), m_show_confirmation_needed); scg.sync(); } //END CloseExceptPlugin //BEGIN CloseExceptPluginView CloseExceptPluginView::CloseExceptPluginView( KTextEditor::MainWindow* mw , CloseExceptPlugin* plugin ) : QObject(mw) , KXMLGUIClient() , m_plugin(plugin) , m_show_confirmation_action(new KToggleAction(i18nc("@action:inmenu", "Show Confirmation"), this)) , m_except_menu(new KActionMenu( i18nc("@action:inmenu close docs except the following...", "Close Except") , this )) , m_like_menu(new KActionMenu( i18nc("@action:inmenu close docs like the following...", "Close Like") , this )) , m_mainWindow(mw) { KXMLGUIClient::setComponentName (QStringLiteral("katecloseexceptplugin"), i18n("Close Except/Like Plugin")); setXMLFile( QStringLiteral("ui.rc") ); actionCollection()->addAction(QStringLiteral("file_close_except"), m_except_menu); actionCollection()->addAction(QStringLiteral("file_close_like"), m_like_menu); - // Subscribe self to document creation - connect( - KTextEditor::Editor::instance() - , SIGNAL(documentCreated(KTextEditor::Editor*, KTextEditor::Document*)) - , this - , SLOT(documentCreated(KTextEditor::Editor*, KTextEditor::Document*)) - ); + connect(KTextEditor::Editor::instance(), &KTextEditor::Editor::documentCreated, + this, &CloseExceptPluginView::documentCreated); // Configure toggle action and connect it to update state m_show_confirmation_action->setChecked(m_plugin->showConfirmationNeeded()); - connect( - m_show_confirmation_action - , SIGNAL(toggled(bool)) - , m_plugin - , SLOT(toggleShowConfirmation(bool)) - ); + connect(m_show_confirmation_action, &KToggleAction::toggled, + m_plugin, &CloseExceptPlugin::toggleShowConfirmation); // - connect( - m_mainWindow - , SIGNAL(viewCreated(KTextEditor::View*)) - , this - , SLOT(viewCreated(KTextEditor::View*)) - ); + connect(m_mainWindow, &KTextEditor::MainWindow::viewCreated, + this, &CloseExceptPluginView::viewCreated); // Fill menu w/ currently opened document masks/groups updateMenu(); m_mainWindow->guiFactory()->addClient(this); } CloseExceptPluginView::~CloseExceptPluginView() { m_mainWindow->guiFactory()->removeClient(this); } void CloseExceptPluginView::viewCreated(KTextEditor::View* view) { connectToDocument(view->document()); updateMenu(); } void CloseExceptPluginView::documentCreated(KTextEditor::Editor*, KTextEditor::Document* document) { connectToDocument(document); updateMenu(); } void CloseExceptPluginView::connectToDocument(KTextEditor::Document* document) { // Subscribe self to document close and name changes - connect( - document - , SIGNAL(aboutToClose(KTextEditor::Document*)) - , this - , SLOT(updateMenuSlotStub(KTextEditor::Document*)) - ); - connect( - document - , SIGNAL(documentNameChanged(KTextEditor::Document*)) - , this - , SLOT(updateMenuSlotStub(KTextEditor::Document*)) - ); - connect( - document - , SIGNAL(documentUrlChanged(KTextEditor::Document*)) - , this - , SLOT(updateMenuSlotStub(KTextEditor::Document*)) - ); + connect(document, &KTextEditor::Document::aboutToClose, + this, &CloseExceptPluginView::updateMenuSlotStub); + connect(document, &KTextEditor::Document::documentNameChanged, + this, &CloseExceptPluginView::updateMenuSlotStub); + connect(document, &KTextEditor::Document::documentUrlChanged, + this, &CloseExceptPluginView::updateMenuSlotStub); } void CloseExceptPluginView::updateMenuSlotStub(KTextEditor::Document*) { updateMenu(); } void CloseExceptPluginView::appendActionsFrom( const std::set& paths , actions_map_type& actions , KActionMenu* menu , QSignalMapper* mapper ) { Q_FOREACH(const QUrl& path, paths) { QString action = path.path() + QLatin1Char('*'); actions[action] = QPointer(new QAction(action, menu)); menu->addAction(actions[action]); - connect(actions[action], SIGNAL(triggered()), mapper, SLOT(map())); + //connect(actions[action], &QAction::triggered, mapper, &QSignalMapper::map); + connect(actions[action], &QAction::triggered, + mapper, static_cast(&QSignalMapper::map)); mapper->setMapping(actions[action], action); } } void CloseExceptPluginView::appendActionsFrom( const std::set& masks , actions_map_type& actions , KActionMenu* menu , QSignalMapper* mapper ) { Q_FOREACH(const QString& mask, masks) { QString action = mask.startsWith(QLatin1Char('*')) ? mask : mask + QLatin1Char('*'); actions[action] = QPointer(new QAction(action, menu)); menu->addAction(actions[action]); - connect(actions[action], SIGNAL(triggered()), mapper, SLOT(map())); + connect(actions[action], &QAction::triggered, + mapper, static_cast(&QSignalMapper::map)); mapper->setMapping(actions[action], action); } } QPointer CloseExceptPluginView::updateMenu( const std::set& paths , const std::set& masks , actions_map_type& actions , KActionMenu* menu ) { // turn menu ON or OFF depending on collected results menu->setEnabled(!paths.empty()); // Clear previous menus for (actions_map_type::iterator it = actions.begin(), last = actions.end(); it !=last;) { menu->removeAction(*it); actions.erase(it++); } // Form a new one QPointer mapper = QPointer(new QSignalMapper(this)); appendActionsFrom(paths, actions, menu, mapper); if (!masks.empty()) { if (!paths.empty()) menu->addSeparator(); // Add separator between paths and file's ext filters appendActionsFrom(masks, actions, menu, mapper); } // Append 'Show Confirmation' toggle menu item menu->addSeparator(); // Add separator between paths and show confirmation menu->addAction(m_show_confirmation_action); return mapper; } void CloseExceptPluginView::updateMenu() { const QList& docs = KTextEditor::Editor::instance()->application()->documents(); if (docs.size() < 2) { qDebug() << "No docs r (or the only) opened right now --> disable menu"; m_except_menu->setEnabled(false); m_except_menu->addSeparator(); m_like_menu->setEnabled(false); m_like_menu->addSeparator(); /// \note It seems there is always a document present... it named \em 'Untitled' } else { // Iterate over documents and form a set of candidates typedef std::set paths_set_type; typedef std::set paths_set_type_masks; paths_set_type doc_paths; paths_set_type_masks masks; Q_FOREACH(KTextEditor::Document* document, docs) { const QString& ext = QFileInfo(document->url().path()).completeSuffix(); if (!ext.isEmpty()) masks.insert(QStringLiteral("*.") + ext); doc_paths.insert(KIO::upUrl(document->url())); } paths_set_type paths = doc_paths; qDebug() << "stage #1: Collected" << paths.size() << "paths and" << masks.size() << "masks"; // Add common paths to the collection for (paths_set_type::iterator it = doc_paths.begin(), last = doc_paths.end(); it != last; ++it) { for ( QUrl url = *it ; (!url.path().isEmpty()) && url.path() != QStringLiteral("/") ; url = KIO::upUrl(url) ) { paths_set_type::iterator not_it = it; for (++not_it; not_it != last; ++not_it) if (!not_it->path().startsWith(url.path())) break; if (not_it == last) { paths.insert(url); break; } } } qDebug() << "stage #2: Collected" << paths.size() << "paths and" << masks.size() << "masks"; // m_except_mapper = updateMenu(paths, masks, m_except_actions, m_except_menu); m_like_mapper = updateMenu(paths, masks, m_like_actions, m_like_menu); - connect(m_except_mapper, SIGNAL(mapped(const QString&)), this, SLOT(closeExcept(const QString&))); - connect(m_like_mapper, SIGNAL(mapped(const QString&)), this, SLOT(closeLike(const QString&))); + connect(m_except_mapper, static_cast(&QSignalMapper::mapped), + this, &CloseExceptPluginView::closeExcept); + connect(m_like_mapper, static_cast(&QSignalMapper::mapped), + this, &CloseExceptPluginView::closeLike); } } void CloseExceptPluginView::close(const QString& item, const bool close_if_match) { QChar asterisk=QLatin1Char('*'); assert( "Parameter seems invalid! Is smth has changed in the code?" && !item.isEmpty() && (item[0] == asterisk || item[item.size() - 1] == asterisk) ); const bool is_path = item[0] != asterisk; const QString mask = is_path ? item.left(item.size() - 1) : item; qDebug() << "Going to close items [" << close_if_match << "/" << is_path << "]: " << mask; QList docs2close; const QList& docs = KTextEditor::Editor::instance()->application()->documents(); Q_FOREACH(KTextEditor::Document* document, docs) { const QString& path = KIO::upUrl(document->url()).path(); /// \note Take a dot in account, so \c *.c would not match for \c blah.kcfgc const QString& ext = QLatin1Char('.') + QFileInfo(document->url().fileName()).completeSuffix(); const bool match = (!is_path && mask.endsWith(ext)) || (is_path && path.startsWith(mask)) ; if (match == close_if_match) { qDebug() << "*** Will close: " << document->url(); docs2close.push_back(document); } } if (docs2close.isEmpty()) { displayMessage( i18nc("@title:window", "Error") , i18nc("@info:tooltip", "No files to close ...") , KTextEditor::Message::Error ); return; } // Show confirmation dialog if needed const bool removeNeeded = !m_plugin->showConfirmationNeeded() || CloseConfirmDialog(docs2close, m_show_confirmation_action, qobject_cast(this)).exec(); if (removeNeeded) { if (docs2close.isEmpty()) { displayMessage( i18nc("@title:window", "Error") , i18nc("@info:tooltip", "No files to close ...") , KTextEditor::Message::Error ); } else { // Close 'em all! KTextEditor::Editor::instance()->application()->closeDocuments(docs2close); updateMenu(); displayMessage( i18nc("@title:window", "Done") , i18np("%1 file closed", "%1 files closed", docs2close.size()) , KTextEditor::Message::Positive ); } } } void CloseExceptPluginView::displayMessage(const QString &title, const QString &msg, KTextEditor::Message::MessageType level) { KTextEditor::View *kv = m_mainWindow->activeView(); if (!kv) return; delete m_infoMessage; m_infoMessage = new KTextEditor::Message(xi18nc("@info", "%1%2", title, msg), level); m_infoMessage->setWordWrap(true); m_infoMessage->setPosition(KTextEditor::Message::TopInView); m_infoMessage->setAutoHide(5000); m_infoMessage->setAutoHideMode(KTextEditor::Message::Immediate); m_infoMessage->setView(kv); kv->document()->postMessage(m_infoMessage); } //END CloseExceptPluginView } // namespace kate #include "close_except_plugin.moc" // kate: hl C++11/Qt4; diff --git a/addons/filebrowser/katefilebrowser.cpp b/addons/filebrowser/katefilebrowser.cpp index 2d3dbac92..b982aab42 100644 --- a/addons/filebrowser/katefilebrowser.cpp +++ b/addons/filebrowser/katefilebrowser.cpp @@ -1,348 +1,345 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 Anders Lund Copyright (C) 2007 Mirko Stocker Copyright (C) 2009 Dominik Haumann 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. */ //BEGIN Includes #include "katefilebrowser.h" #include "katebookmarkhandler.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //END Includes KateFileBrowser::KateFileBrowser(KTextEditor::MainWindow *mainWindow, QWidget * parent) : QWidget (parent) , m_mainWindow(mainWindow) { QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setMargin(0); mainLayout->setSpacing(0); m_toolbar = new KToolBar(this); m_toolbar->setMovable(false); m_toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); m_toolbar->setContextMenuPolicy(Qt::NoContextMenu); mainLayout->addWidget(m_toolbar); // includes some actions, but not hooked into the shortcut dialog atm m_actionCollection = new KActionCollection(this); m_actionCollection->addAssociatedWidget(this); KFilePlacesModel* model = new KFilePlacesModel(this); m_urlNavigator = new KUrlNavigator(model, QUrl::fromLocalFile(QDir::homePath()), this); - connect(m_urlNavigator, SIGNAL(urlChanged(QUrl)), SLOT(updateDirOperator(QUrl))); + connect(m_urlNavigator, &KUrlNavigator::urlChanged, this, &KateFileBrowser::updateDirOperator); mainLayout->addWidget(m_urlNavigator); m_dirOperator = new KDirOperator(QUrl(), this); m_dirOperator->setView(KFile::/* Simple */Detail); m_dirOperator->view()->setSelectionMode(QAbstractItemView::ExtendedSelection); m_dirOperator->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding)); mainLayout->addWidget(m_dirOperator); // Mime filter for the KDirOperator QStringList filter; filter << QStringLiteral("text/plain") << QStringLiteral("text/html") << QStringLiteral("inode/directory"); m_dirOperator->setNewFileMenuSupportedMimeTypes(filter); setFocusProxy(m_dirOperator); - connect(m_dirOperator, SIGNAL(viewChanged(QAbstractItemView*)), - this, SLOT(selectorViewChanged(QAbstractItemView*))); - connect(m_urlNavigator, SIGNAL(returnPressed()), - m_dirOperator, SLOT(setFocus())); + connect(m_dirOperator, &KDirOperator::viewChanged, this, &KateFileBrowser::selectorViewChanged); + connect(m_urlNavigator, &KUrlNavigator::returnPressed, + m_dirOperator, static_cast(&KDirOperator::setFocus)); + // now all actions exist in dir operator and we can use them in the toolbar setupActions(); setupToolbar(); m_filter = new KHistoryComboBox(true, this); m_filter->setMaxCount(10); m_filter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); m_filter->lineEdit()->setPlaceholderText(i18n("Search")); mainLayout->addWidget(m_filter); - connect(m_filter, SIGNAL(editTextChanged(QString)), - SLOT(slotFilterChange(QString))); - connect(m_filter, SIGNAL(returnPressed(QString)), - m_filter, SLOT(addToHistory(QString))); - connect(m_filter, SIGNAL(returnPressed(QString)), - m_dirOperator, SLOT(setFocus())); - - connect(m_dirOperator, SIGNAL(urlEntered(QUrl)), - this, SLOT(updateUrlNavigator(QUrl))); + connect(m_filter, &KHistoryComboBox::editTextChanged, this, &KateFileBrowser::slotFilterChange); + connect(m_filter, static_cast(&KHistoryComboBox::returnPressed), + m_filter, &KHistoryComboBox::addToHistory); + connect(m_filter, static_cast(&KHistoryComboBox::returnPressed), + m_dirOperator, static_cast< void (KDirOperator::*)()>(&KDirOperator::setFocus)); + connect(m_dirOperator, &KDirOperator::urlEntered, this, &KateFileBrowser::updateUrlNavigator); // Connect the bookmark handler - connect(m_bookmarkHandler, SIGNAL(openUrl(QString)), - this, SLOT(setDir(QString))); + connect(m_bookmarkHandler, &KateBookmarkHandler::openUrl, + this, static_cast(&KateFileBrowser::setDir)); m_filter->setWhatsThis(i18n("Enter a name filter to limit which files are displayed.")); - connect(m_dirOperator, SIGNAL(fileSelected(KFileItem)), this, SLOT(fileSelected(KFileItem))); - connect(m_mainWindow, SIGNAL(viewChanged(KTextEditor::View *)), this, SLOT(autoSyncFolder())); + connect(m_dirOperator, &KDirOperator::fileSelected, this, &KateFileBrowser::fileSelected); + connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KateFileBrowser::autoSyncFolder); } KateFileBrowser::~KateFileBrowser() { } //END Constroctor/Destrctor //BEGIN Public Methods void KateFileBrowser::setupToolbar() { KConfigGroup config(KSharedConfig::openConfig(), "filebrowser"); QStringList actions = config.readEntry( "toolbar actions", QStringList() ); if ( actions.isEmpty() ) // default toolbar actions << QStringLiteral("back") << QStringLiteral("forward") << QStringLiteral("bookmarks") << QStringLiteral("sync_dir") << QStringLiteral("configure"); // remove all actions from the toolbar (there should be none) m_toolbar->clear(); // now add all actions to the toolbar foreach (const QString& it, actions) { QAction *ac = nullptr; if (it.isEmpty()) continue; if (it == QStringLiteral("bookmarks") || it == QStringLiteral("sync_dir") || it == QStringLiteral("configure")) ac = actionCollection()->action(it); else ac = m_dirOperator->actionCollection()->action(it); if (ac) m_toolbar->addAction(ac); } } void KateFileBrowser::readSessionConfig (const KConfigGroup& cg) { m_dirOperator->readConfig(cg); m_dirOperator->setView(KFile::Default); m_urlNavigator->setLocationUrl(cg.readEntry("location", QUrl::fromLocalFile (QDir::homePath()))); setDir(cg.readEntry("location", QUrl::fromLocalFile (QDir::homePath()))); m_autoSyncFolder->setChecked(cg.readEntry("auto sync folder", false)); m_filter->setHistoryItems(cg.readEntry("filter history", QStringList()), true); } void KateFileBrowser::writeSessionConfig (KConfigGroup& cg) { m_dirOperator->writeConfig(cg); cg.writeEntry("location", m_urlNavigator->locationUrl().url()); cg.writeEntry("auto sync folder", m_autoSyncFolder->isChecked()); cg.writeEntry("filter history", m_filter->historyItems()); } //END Public Methods //BEGIN Public Slots void KateFileBrowser::slotFilterChange(const QString & nf) { QString f = nf.trimmed(); const bool empty = f.isEmpty() || f == QStringLiteral("*"); if (empty) { m_dirOperator->clearFilter(); } else { m_dirOperator->setNameFilter(f); } m_dirOperator->updateDir(); } bool kateFileSelectorIsReadable (const QUrl& url) { if (!url.isLocalFile()) return true; // what else can we say? QDir dir(url.toLocalFile()); return dir.exists (); } void KateFileBrowser::setDir(QUrl u) { QUrl newurl; if (!u.isValid()) newurl = QUrl::fromLocalFile(QDir::homePath()); else newurl = u; QString path(newurl.path()); if (!path.endsWith(QLatin1Char('/'))) path += QLatin1Char('/'); newurl.setPath(path); if (!kateFileSelectorIsReadable(newurl)) { newurl.setPath(newurl.path() + QStringLiteral("../")); newurl = newurl.adjusted(QUrl::NormalizePathSegments); } if (!kateFileSelectorIsReadable(newurl)) { newurl = QUrl::fromLocalFile(QDir::homePath()); } m_dirOperator->setUrl(newurl, true); } //END Public Slots //BEGIN Private Slots void KateFileBrowser::fileSelected(const KFileItem & /*file*/) { openSelectedFiles(); } void KateFileBrowser::openSelectedFiles() { const KFileItemList list = m_dirOperator->selectedItems(); if (list.count()>20) { if (KMessageBox::questionYesNo(this,i18np("You are trying to open 1 file, are you sure?", "You are trying to open %1 files, are you sure?", list.count())) == KMessageBox::No) return; } foreach (const KFileItem& item, list) { m_mainWindow->openUrl(item.url()); } m_dirOperator->view()->selectionModel()->clear(); } void KateFileBrowser::updateDirOperator(const QUrl &u) { m_dirOperator->setUrl(u, true); } void KateFileBrowser::updateUrlNavigator(const QUrl &u) { m_urlNavigator->setLocationUrl(u); } void KateFileBrowser::setActiveDocumentDir() { QUrl u = activeDocumentUrl(); if (!u.isEmpty()) setDir(KIO::upUrl(u)); } void KateFileBrowser::autoSyncFolder() { if (m_autoSyncFolder->isChecked()) { setActiveDocumentDir(); } } void KateFileBrowser::selectorViewChanged(QAbstractItemView * newView) { newView->setSelectionMode(QAbstractItemView::ExtendedSelection); } //END Private Slots //BEGIN Protected QUrl KateFileBrowser::activeDocumentUrl() { KTextEditor::View *v = m_mainWindow->activeView(); if (v) return v->document()->url(); return QUrl(); } void KateFileBrowser::setupActions() { // bookmarks action! KActionMenu *acmBookmarks = new KActionMenu(QIcon::fromTheme(QStringLiteral("bookmarks")), i18n("Bookmarks"), this); acmBookmarks->setDelayed(false); m_bookmarkHandler = new KateBookmarkHandler(this, acmBookmarks->menu()); acmBookmarks->setShortcutContext(Qt::WidgetWithChildrenShortcut); // action for synchronizing the dir operator with the current document path QAction* syncFolder = new QAction(this); syncFolder->setShortcutContext(Qt::WidgetWithChildrenShortcut); syncFolder->setText(i18n("Current Document Folder")); syncFolder->setIcon(QIcon::fromTheme(QStringLiteral("system-switch-user"))); - connect(syncFolder, SIGNAL(triggered()), this, SLOT(setActiveDocumentDir())); + connect(syncFolder, &QAction::triggered, this, &KateFileBrowser::setActiveDocumentDir); m_actionCollection->addAction(QStringLiteral("sync_dir"), syncFolder); m_actionCollection->addAction(QStringLiteral("bookmarks"), acmBookmarks); // section for settings menu KActionMenu *optionsMenu = new KActionMenu(QIcon::fromTheme(QStringLiteral("configure")), i18n("Options"), this); optionsMenu->setDelayed(false); optionsMenu->addAction(m_dirOperator->actionCollection()->action(QStringLiteral("short view"))); optionsMenu->addAction(m_dirOperator->actionCollection()->action(QStringLiteral("detailed view"))); optionsMenu->addAction(m_dirOperator->actionCollection()->action(QStringLiteral("tree view"))); optionsMenu->addAction(m_dirOperator->actionCollection()->action(QStringLiteral("detailed tree view"))); optionsMenu->addSeparator(); optionsMenu->addAction(m_dirOperator->actionCollection()->action(QStringLiteral("show hidden"))); // action for synchronising the dir operator with the current document path m_autoSyncFolder = new QAction(this); m_autoSyncFolder->setCheckable(true); m_autoSyncFolder->setText(i18n("Automatically synchronize with current document")); m_autoSyncFolder->setIcon(QIcon::fromTheme(QStringLiteral("system-switch-user"))); - connect(m_autoSyncFolder, SIGNAL(triggered()), this, SLOT(autoSyncFolder())); + connect(m_autoSyncFolder, &QAction::triggered, this, &KateFileBrowser::autoSyncFolder); optionsMenu->addAction(m_autoSyncFolder); m_actionCollection->addAction(QStringLiteral("configure"), optionsMenu); // // Remove all shortcuts due to shortcut clashes (e.g. F5: reload, Ctrl+B: bookmark) // BUGS: #188954, #236368 // foreach (QAction* a, m_actionCollection->actions()) { a->setShortcut(QKeySequence()); } foreach (QAction* a, m_dirOperator->actionCollection()->actions()) { a->setShortcut(QKeySequence()); } } //END Protected // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/filebrowser/katefilebrowserconfig.cpp b/addons/filebrowser/katefilebrowserconfig.cpp index a6b88f795..2d12801df 100644 --- a/addons/filebrowser/katefilebrowserconfig.cpp +++ b/addons/filebrowser/katefilebrowserconfig.cpp @@ -1,191 +1,191 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 Anders Lund Copyright (C) 2007 Mirko Stocker 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 "katefilebrowserconfig.h" #include "katefilebrowser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include //BEGIN ACtionLBItem /* QListboxItem that can store and return a string, used for the toolbar action selector. */ class ActionLBItem : public QListWidgetItem { public: ActionLBItem( QListWidget *lb = nullptr, const QIcon &pm = QIcon(), const QString &text = QString(), const QString &str = QString() ) : QListWidgetItem(pm, text, lb, 0 ), _str(str) {} QString idstring() { return _str; } private: QString _str; }; //END ActionLBItem //BEGIN KateFileBrowserConfigPage KateFileBrowserConfigPage::KateFileBrowserConfigPage( QWidget *parent, KateFileBrowser *kfb ) : KTextEditor::ConfigPage( parent ), fileBrowser( kfb ), m_changed( false ) { QVBoxLayout *lo = new QVBoxLayout( this ); int spacing = QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing); lo->setSpacing( spacing ); // Toolbar - a lot for a little... QGroupBox *gbToolbar = new QGroupBox(i18n("Toolbar"), this ); acSel = new KActionSelector( gbToolbar ); acSel->setAvailableLabel( i18n("A&vailable actions:") ); acSel->setSelectedLabel( i18n("S&elected actions:") ); QVBoxLayout *vbox = new QVBoxLayout; vbox->addWidget(acSel); gbToolbar->setLayout(vbox); lo->addWidget( gbToolbar ); - connect( acSel, SIGNAL(added(QListWidgetItem*)), this, SLOT(slotMyChanged()) ); - connect( acSel, SIGNAL(removed(QListWidgetItem*)), this, SLOT(slotMyChanged()) ); - connect( acSel, SIGNAL(movedUp(QListWidgetItem*)), this, SLOT(slotMyChanged()) ); - connect( acSel, SIGNAL(movedDown(QListWidgetItem*)), this, SLOT(slotMyChanged()) ); + connect(acSel, &KActionSelector::added, this, &KateFileBrowserConfigPage::slotMyChanged); + connect(acSel, &KActionSelector::removed, this, &KateFileBrowserConfigPage::slotMyChanged); + connect(acSel, &KActionSelector::movedUp, this, &KateFileBrowserConfigPage::slotMyChanged); + connect(acSel, &KActionSelector::movedDown, this, &KateFileBrowserConfigPage::slotMyChanged); // make it look nice lo->addStretch( 1 ); init(); } QString KateFileBrowserConfigPage::name() const { return i18n("Filesystem Browser"); } QString KateFileBrowserConfigPage::fullName() const { return i18n("Filesystem Browser Settings"); } QIcon KateFileBrowserConfigPage::icon() const { return QIcon::fromTheme(QStringLiteral("document-open")); } void KateFileBrowserConfigPage::apply() { if ( ! m_changed ) return; m_changed = false; KConfigGroup config(KSharedConfig::openConfig(), "filebrowser"); QStringList l; ActionLBItem *aItem; QList list = acSel->selectedListWidget()->findItems(QStringLiteral("*"), Qt::MatchWildcard); foreach(QListWidgetItem *item, list) { aItem = static_cast(item); l << aItem->idstring(); } config.writeEntry( "toolbar actions", l ); fileBrowser->setupToolbar(); } void KateFileBrowserConfigPage::reset() { // hmm, what is this supposed to do, actually?? init(); m_changed = false; } void KateFileBrowserConfigPage::init() { KConfigGroup config(KSharedConfig::openConfig(), "filebrowser"); // toolbar QStringList l = config.readEntry( "toolbar actions", QStringList() ); if ( l.isEmpty() ) // default toolbar l << QStringLiteral("back") << QStringLiteral("forward") << QStringLiteral("bookmarks") << QStringLiteral("sync_dir") << QStringLiteral("configure"); // actions from diroperator + two of our own QStringList allActions; allActions << QStringLiteral("up") << QStringLiteral("back") << QStringLiteral("forward") << QStringLiteral("home") << QStringLiteral("reload") << QStringLiteral("mkdir") << QStringLiteral("delete") << QStringLiteral("short view") << QStringLiteral("detailed view") << QStringLiteral("tree view") << QStringLiteral("detailed tree view") << QStringLiteral("show hidden") /*<< QStringLiteral("view menu") << QStringLiteral("properties")*/ << QStringLiteral("bookmarks") << QStringLiteral("sync_dir") << QStringLiteral("configure"); QRegExp re(QStringLiteral ("&(?=[^&])")); QAction *ac = nullptr; QListWidget *lb; for ( QStringList::Iterator it = allActions.begin(); it != allActions.end(); ++it ) { lb = l.contains( *it ) ? acSel->selectedListWidget() : acSel->availableListWidget(); if ( *it == QStringLiteral ("bookmarks") || *it == QStringLiteral ("sync_dir") || *it == QStringLiteral ("configure") ) ac = fileBrowser->actionCollection()->action( *it ); else ac = fileBrowser->dirOperator()->actionCollection()->action( *it ); if ( ac ) { QString text = ac->text().remove( re ); // CJK languages need a filtering message for action texts in lists, // to remove special accelerators that they use. // The exact same filtering message exists in kdelibs; hence, // avoid extraction here and let it be sourced from kdelibs. #define i18ncX i18nc text = i18ncX( "@item:intable Action name in toolbar editor", "%1", text ); new ActionLBItem( lb, ac->icon(), text, *it ); } } } void KateFileBrowserConfigPage::slotMyChanged() { m_changed = true; emit changed(); } //END KateFileBrowserConfigPage // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/filebrowser/katefilebrowserplugin.cpp b/addons/filebrowser/katefilebrowserplugin.cpp index df0cdccc4..23624b2da 100644 --- a/addons/filebrowser/katefilebrowserplugin.cpp +++ b/addons/filebrowser/katefilebrowserplugin.cpp @@ -1,123 +1,123 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 Anders Lund Copyright (C) 2007 Mirko Stocker Copyright (C) 2009 Dominik Haumann 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. */ //BEGIN Includes #include "katefilebrowserplugin.h" #include "katefilebrowserconfig.h" #include "katefilebrowser.h" #include #include #include #include //END Includes K_PLUGIN_FACTORY_WITH_JSON (KateFileBrowserPluginFactory, "katefilebrowserplugin.json", registerPlugin();) //BEGIN KateFileBrowserPlugin KateFileBrowserPlugin::KateFileBrowserPlugin(QObject* parent, const QList&) : KTextEditor::Plugin (parent) { } QObject *KateFileBrowserPlugin::createView (KTextEditor::MainWindow *mainWindow) { KateFileBrowserPluginView* view = new KateFileBrowserPluginView (this, mainWindow); - connect(view, SIGNAL(destroyed(QObject*)), this, SLOT(viewDestroyed(QObject*))); + connect(view, &KateFileBrowserPluginView::destroyed, this, &KateFileBrowserPlugin::viewDestroyed); m_views.append(view); return view; } void KateFileBrowserPlugin::viewDestroyed(QObject* view) { // do not access the view pointer, since it is partially destroyed already m_views.removeAll(static_cast(view)); } int KateFileBrowserPlugin::configPages() const { return 1; } KTextEditor::ConfigPage *KateFileBrowserPlugin::configPage (int number, QWidget *parent) { if (number != 0) return nullptr; return new KateFileBrowserConfigPage(parent, m_views[0]->m_fileBrowser); } //END KateFileBrowserPlugin //BEGIN KateFileBrowserPluginView KateFileBrowserPluginView::KateFileBrowserPluginView (KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWindow) : QObject (mainWindow) , m_toolView( mainWindow->createToolView(plugin, QStringLiteral ("kate_private_plugin_katefileselectorplugin") , KTextEditor::MainWindow::Left , QIcon::fromTheme(QStringLiteral("document-open")) , i18n("Filesystem Browser") ) ) , m_fileBrowser(new KateFileBrowser(mainWindow, m_toolView)) , m_mainWindow (mainWindow) { m_toolView->installEventFilter(this); } KateFileBrowserPluginView::~KateFileBrowserPluginView () { // cleanup, kill toolview + console delete m_fileBrowser->parentWidget(); } void KateFileBrowserPluginView::readSessionConfig (const KConfigGroup& config) { m_fileBrowser->readSessionConfig(config); } void KateFileBrowserPluginView::writeSessionConfig (KConfigGroup& config) { m_fileBrowser->writeSessionConfig(config); } bool KateFileBrowserPluginView::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::KeyPress) { QKeyEvent* ke = static_cast(event); if ((obj == m_toolView) && (ke->key() == Qt::Key_Escape)) { m_mainWindow->hideToolView(m_toolView); event->accept(); return true; } } return QObject::eventFilter(obj, event); } //ENDKateFileBrowserPluginView #include "katefilebrowserplugin.moc" // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/filetree/katefiletree.cpp b/addons/filetree/katefiletree.cpp index a366042ea..64315b693 100644 --- a/addons/filetree/katefiletree.cpp +++ b/addons/filetree/katefiletree.cpp @@ -1,713 +1,713 @@ /* This file is part of the KDE project Copyright (C) 2010 Thomas Fjellstrom Copyright (C) 2014 Joseph Wenninger 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. */ //BEGIN Includes #include "katefiletree.h" #include "katefiletreemodel.h" #include "katefiletreeproxymodel.h" #include "katefiletreedebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //END Includes //BEGIN KateFileTree KateFileTree::KateFileTree(QWidget *parent): QTreeView(parent) { setAcceptDrops(false); setIndentation(12); setAllColumnsShowFocus(true); setFocusPolicy(Qt::NoFocus); setDragEnabled(true); setDragDropMode(QAbstractItemView::DragOnly); // handle activated (e.g. for pressing enter) + clicked (to avoid to need to do double-click e.g. on Windows) - connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(mouseClicked(QModelIndex))); - connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(mouseClicked(QModelIndex))); - connect(this, SIGNAL(pressed(QModelIndex)), this, SLOT(mouseClicked(QModelIndex))); + connect(this, &KateFileTree::activated, this, &KateFileTree::mouseClicked); + connect(this, &KateFileTree::clicked, this, &KateFileTree::mouseClicked); + connect(this, &KateFileTree::pressed, this, &KateFileTree::mouseClicked); m_filelistReloadDocument = new QAction(QIcon::fromTheme(QLatin1String("view-refresh")), i18nc("@action:inmenu", "Reloa&d"), this); - connect(m_filelistReloadDocument, SIGNAL(triggered(bool)), SLOT(slotDocumentReload())); + connect(m_filelistReloadDocument, &QAction::triggered, this, &KateFileTree::slotDocumentReload); m_filelistReloadDocument->setWhatsThis(i18n("Reload selected document(s) from disk.")); m_filelistCloseDocument = new QAction(QIcon::fromTheme(QLatin1String("document-close")), i18nc("@action:inmenu", "Close"), this); - connect(m_filelistCloseDocument, SIGNAL(triggered()), this, SLOT(slotDocumentClose())); + connect(m_filelistCloseDocument, &QAction::triggered, this, &KateFileTree::slotDocumentClose); m_filelistCloseDocument->setWhatsThis(i18n("Close the current document.")); m_filelistExpandRecursive = new QAction(QIcon::fromTheme(QLatin1String("view-list-tree")), i18nc("@action:inmenu", "Expand recursively"), this); - connect(m_filelistExpandRecursive, SIGNAL(triggered()), this, SLOT(slotExpandRecursive())); + connect(m_filelistExpandRecursive, &QAction::triggered, this, &KateFileTree::slotExpandRecursive); m_filelistExpandRecursive->setWhatsThis(i18n("Expand the file list sub tree recursively.")); m_filelistCollapseRecursive = new QAction(QIcon::fromTheme(QLatin1String("view-list-tree")), i18nc("@action:inmenu", "Collapse recursively"), this); - connect(m_filelistCollapseRecursive, SIGNAL(triggered()), this, SLOT(slotCollapseRecursive())); + connect(m_filelistCollapseRecursive, &QAction::triggered, this, &KateFileTree::slotCollapseRecursive); m_filelistCollapseRecursive->setWhatsThis(i18n("Collapse the file list sub tree recursively.")); m_filelistCloseOtherDocument = new QAction(QIcon::fromTheme(QLatin1String("document-close")), i18nc("@action:inmenu", "Close Other"), this); - connect(m_filelistCloseOtherDocument, SIGNAL(triggered()), this, SLOT(slotDocumentCloseOther())); + connect(m_filelistCloseOtherDocument, &QAction::triggered, this, &KateFileTree::slotDocumentCloseOther); m_filelistCloseOtherDocument->setWhatsThis(i18n("Close other documents in this folder.")); m_filelistCopyFilename = new QAction(QIcon::fromTheme(QLatin1String("edit-copy")), i18nc("@action:inmenu", "Copy Filename"), this); - connect(m_filelistCopyFilename, SIGNAL(triggered()), this, SLOT(slotCopyFilename())); + connect(m_filelistCopyFilename, &QAction::triggered, this, &KateFileTree::slotCopyFilename); m_filelistCopyFilename->setWhatsThis(i18n("Copy the filename of the file.")); m_filelistRenameFile = new QAction(QIcon::fromTheme(QLatin1String("edit-rename")), i18nc("@action:inmenu", "Rename File"), this); connect(m_filelistRenameFile, &QAction::triggered, this, &KateFileTree::slotRenameFile); m_filelistRenameFile->setWhatsThis(i18n("Rename the selected file.")); m_filelistPrintDocument = KStandardAction::print(this, SLOT(slotPrintDocument()), this); m_filelistPrintDocument->setWhatsThis(i18n("Print selected document.")); m_filelistPrintDocumentPreview = KStandardAction::printPreview(this, SLOT(slotPrintDocumentPreview()), this); m_filelistPrintDocumentPreview->setWhatsThis(i18n("Show print preview of current document")); m_filelistDeleteDocument = new QAction(QIcon::fromTheme(QLatin1String("edit-delete-shred")), i18nc("@action:inmenu", "Delete Document"), this); - connect(m_filelistDeleteDocument, SIGNAL(triggered()), this, SLOT(slotDocumentDelete())); + connect(m_filelistDeleteDocument, &QAction::triggered, this, &KateFileTree::slotDocumentDelete); m_filelistDeleteDocument->setWhatsThis(i18n("Close and delete selected file from storage.")); QActionGroup *modeGroup = new QActionGroup(this); m_treeModeAction = setupOption(modeGroup, QIcon::fromTheme(QLatin1String("view-list-tree")), i18nc("@action:inmenu", "Tree Mode"), i18n("Set view style to Tree Mode"), SLOT(slotTreeMode()), true); m_listModeAction = setupOption(modeGroup, QIcon::fromTheme(QLatin1String("view-list-text")), i18nc("@action:inmenu", "List Mode"), i18n("Set view style to List Mode"), SLOT(slotListMode()), false); QActionGroup *sortGroup = new QActionGroup(this); m_sortByFile = setupOption(sortGroup, QIcon(), i18nc("@action:inmenu sorting option", "Document Name"), i18n("Sort by Document Name"), SLOT(slotSortName()), true); m_sortByPath = setupOption(sortGroup, QIcon(), i18nc("@action:inmenu sorting option", "Document Path"), i18n("Sort by Document Path"), SLOT(slotSortPath()), false); m_sortByOpeningOrder = setupOption(sortGroup, QIcon(), i18nc("@action:inmenu sorting option", "Opening Order"), i18n("Sort by Opening Order"), SLOT(slotSortOpeningOrder()), false); m_resetHistory = new QAction(QIcon::fromTheme(QLatin1String("edit-clear-history")), i18nc("@action:inmenu", "Clear History"), this); - connect(m_resetHistory, SIGNAL(triggered()), this, SLOT(slotResetHistory())); + connect(m_resetHistory, &QAction::triggered, this, &KateFileTree::slotResetHistory); m_resetHistory->setWhatsThis(i18n("Clear edit/view history.")); QPalette p = palette(); p.setColor(QPalette::Inactive, QPalette::Highlight, p.color(QPalette::Active, QPalette::Highlight)); p.setColor(QPalette::Inactive, QPalette::HighlightedText, p.color(QPalette::Active, QPalette::HighlightedText)); setPalette(p); } KateFileTree::~KateFileTree() {} void KateFileTree::setModel(QAbstractItemModel *model) { Q_ASSERT(qobject_cast(model)); // we don't really work with anything else QTreeView::setModel(model); } QAction *KateFileTree::setupOption( QActionGroup *group, const QIcon &icon, const QString &label, const QString &whatsThis, const char *slot, bool checked ) { QAction *new_action = new QAction(icon, label, this); new_action->setWhatsThis(whatsThis); new_action->setActionGroup(group); new_action->setCheckable(true); new_action->setChecked(checked); connect(new_action, SIGNAL(triggered()), this, slot); return new_action; } void KateFileTree::slotListMode() { emit viewModeChanged(true); } void KateFileTree::slotTreeMode() { emit viewModeChanged(false); } void KateFileTree::slotSortName() { emit sortRoleChanged(Qt::DisplayRole); } void KateFileTree::slotSortPath() { emit sortRoleChanged(KateFileTreeModel::PathRole); } void KateFileTree::slotSortOpeningOrder() { emit sortRoleChanged(KateFileTreeModel::OpeningOrderRole); } void KateFileTree::slotCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous) { Q_UNUSED(previous); if (!current.isValid()) { return; } KTextEditor::Document *doc = model()->data(current, KateFileTreeModel::DocumentRole).value(); if (doc) { m_previouslySelected = current; } } void KateFileTree::mouseClicked(const QModelIndex &index) { KTextEditor::Document *doc = model()->data(index, KateFileTreeModel::DocumentRole).value(); if (doc) { emit activateDocument(doc); } else { setExpanded(index, !isExpanded(index)); } } void KateFileTree::contextMenuEvent(QContextMenuEvent *event) { m_indexContextMenu = selectionModel()->currentIndex(); selectionModel()->setCurrentIndex(m_indexContextMenu, QItemSelectionModel::ClearAndSelect); KateFileTreeProxyModel *ftpm = static_cast(model()); KateFileTreeModel *ftm = static_cast(ftpm->sourceModel()); bool listMode = ftm->listMode(); m_treeModeAction->setChecked(!listMode); m_listModeAction->setChecked(listMode); int sortRole = ftpm->sortRole(); m_sortByFile->setChecked(sortRole == Qt::DisplayRole); m_sortByPath->setChecked(sortRole == KateFileTreeModel::PathRole); m_sortByOpeningOrder->setChecked(sortRole == KateFileTreeModel::OpeningOrderRole); KTextEditor::Document *doc = m_indexContextMenu.data(KateFileTreeModel::DocumentRole).value(); const bool isFile = (nullptr != doc); QMenu menu; menu.addAction(m_filelistReloadDocument); menu.addAction(m_filelistCloseDocument); menu.addAction(m_filelistExpandRecursive); menu.addAction(m_filelistCollapseRecursive); if (isFile) { menu.addAction(m_filelistCloseOtherDocument); menu.addSeparator(); menu.addAction(m_filelistCopyFilename); menu.addAction(m_filelistRenameFile); menu.addAction(m_filelistPrintDocument); menu.addAction(m_filelistPrintDocumentPreview); QMenu *openWithMenu = menu.addMenu(i18nc("@action:inmenu", "Open With")); - connect(openWithMenu, SIGNAL(aboutToShow()), this, SLOT(slotFixOpenWithMenu())); - connect(openWithMenu, SIGNAL(triggered(QAction *)), this, SLOT(slotOpenWithMenuAction(QAction *))); + connect(openWithMenu, &QMenu::aboutToShow, this, &KateFileTree::slotFixOpenWithMenu); + connect(openWithMenu, &QMenu::triggered, this, &KateFileTree::slotOpenWithMenuAction); const bool hasFileName = doc->url().isValid(); m_filelistCopyFilename->setEnabled(hasFileName); m_filelistRenameFile->setEnabled(hasFileName); m_filelistDeleteDocument->setEnabled(hasFileName); menu.addAction(m_filelistDeleteDocument); } menu.addSeparator(); QMenu *view_menu = menu.addMenu(i18nc("@action:inmenu", "View Mode")); view_menu->addAction(m_treeModeAction); view_menu->addAction(m_listModeAction); QMenu *sort_menu = menu.addMenu(QIcon::fromTheme(QLatin1String("view-sort-ascending")), i18nc("@action:inmenu", "Sort By")); sort_menu->addAction(m_sortByFile); sort_menu->addAction(m_sortByPath); sort_menu->addAction(m_sortByOpeningOrder); menu.addAction(m_resetHistory); menu.exec(viewport()->mapToGlobal(event->pos())); if (m_previouslySelected.isValid()) { selectionModel()->setCurrentIndex(m_previouslySelected, QItemSelectionModel::ClearAndSelect); } event->accept(); } void KateFileTree::slotFixOpenWithMenu() { QMenu *menu = (QMenu *)sender(); menu->clear(); KTextEditor::Document *doc = model()->data(m_indexContextMenu, KateFileTreeModel::DocumentRole).value(); if (!doc) { return; } // get a list of appropriate services. QMimeDatabase db; QMimeType mime = db.mimeTypeForName(doc->mimeType()); QAction *a = nullptr; KService::List offers = KMimeTypeTrader::self()->query(mime.name(), QLatin1String("Application")); // for each one, insert a menu item... for (KService::List::Iterator it = offers.begin(); it != offers.end(); ++it) { KService::Ptr service = *it; if (service->name() == QLatin1String("Kate")) { continue; } a = menu->addAction(QIcon::fromTheme(service->icon()), service->name()); a->setData(service->entryPath()); } // append "Other..." to call the KDE "open with" dialog. a = menu->addAction(i18n("&Other...")); a->setData(QString()); } void KateFileTree::slotOpenWithMenuAction(QAction *a) { QList list; KTextEditor::Document *doc = model()->data(m_indexContextMenu, KateFileTreeModel::DocumentRole).value(); if (!doc) { return; } list.append(doc->url()); const QString openWith = a->data().toString(); if (openWith.isEmpty()) { // display "open with" dialog KOpenWithDialog dlg(list); if (dlg.exec()) { KRun::runService(*dlg.service(), list, this); } return; } KService::Ptr app = KService::serviceByDesktopPath(openWith); if (app) { KRun::runService(*app, list, this); } else { KMessageBox::error(this, i18n("Application '%1' not found.", openWith), i18n("Application not found")); } } Q_DECLARE_METATYPE(QList) void KateFileTree::slotDocumentClose() { m_previouslySelected = QModelIndex(); QVariant v = m_indexContextMenu.data(KateFileTreeModel::DocumentTreeRole); if (!v.isValid()) { return; } QList closingDocuments = v.value >(); KTextEditor::Editor::instance()->application()->closeDocuments(closingDocuments); } void KateFileTree::slotExpandRecursive() { if (! m_indexContextMenu.isValid()) { return; } // Work list for DFS walk over sub tree QList worklist = { m_indexContextMenu }; while (! worklist.isEmpty()) { QPersistentModelIndex index = worklist.takeLast(); // Expand current item expand(index); // Append all children of current item for (int i=0 ; i < model()->rowCount(index) ; ++i) { worklist.append(index.child(i,0)); } } } void KateFileTree::slotCollapseRecursive() { if (! m_indexContextMenu.isValid()) { return; } // Work list for DFS walk over sub tree QList worklist = { m_indexContextMenu }; while (! worklist.isEmpty()) { QPersistentModelIndex index = worklist.takeLast(); // Expand current item collapse(index); // Prepend all children of current item for (int i=0 ; i < model()->rowCount(index) ; ++i) { worklist.append(index.child(i,0)); } } } void KateFileTree::slotDocumentCloseOther() { QVariant v = model()->data(m_indexContextMenu.parent(), KateFileTreeModel::DocumentTreeRole); if (!v.isValid()) { return; } QList closingDocuments = v.value >(); KTextEditor::Document *doc = model()->data(m_indexContextMenu, KateFileTreeModel::DocumentRole).value(); closingDocuments.removeOne(doc); KTextEditor::Editor::instance()->application()->closeDocuments(closingDocuments); } void KateFileTree::slotDocumentReload() { QVariant v = m_indexContextMenu.data(KateFileTreeModel::DocumentTreeRole); if (!v.isValid()) { return; } QList docs = v.value >(); foreach(KTextEditor::Document * doc, docs) { doc->documentReload(); } } void KateFileTree::slotCopyFilename() { KTextEditor::Document *doc = model()->data(m_indexContextMenu, KateFileTreeModel::DocumentRole).value(); if (doc) { // ensure we prefer native separators, bug 381052 if (doc->url().isLocalFile()) { QApplication::clipboard()->setText(QDir::toNativeSeparators(doc->url().toLocalFile())); } else { QApplication::clipboard()->setText(doc->url().url()); } } } void KateFileTree::slotRenameFile() { KTextEditor::Document *doc = model()->data(m_indexContextMenu, KateFileTreeModel::DocumentRole).value(); if (!doc) { return; } const QUrl oldFileUrl = doc->url(); const QString oldFileName = doc->url().fileName(); bool ok; QString newFileName = QInputDialog::getText(this, i18n("Rename file"), i18n("New file name"), QLineEdit::Normal, oldFileName, &ok); if (!ok) { return; } QUrl newFileUrl = oldFileUrl.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash); newFileUrl.setPath(newFileUrl.path() + QLatin1Char('/') + newFileName); if (!newFileUrl.isValid()) { return; } if (!doc->closeUrl()) { return; } doc->waitSaveComplete(); KIO::CopyJob* job = KIO::move(oldFileUrl, newFileUrl); QSharedPointer sc(new QMetaObject::Connection()); auto success = [doc, sc] (KIO::Job*, const QUrl&, const QUrl &realNewFileUrl, const QDateTime&, bool, bool) { doc->openUrl(realNewFileUrl); doc->documentSavedOrUploaded(doc, true); QObject::disconnect(*sc); }; *sc = connect(job, &KIO::CopyJob::copyingDone, doc, success); if (!job->exec()) { KMessageBox::sorry(this, i18n("File \"%1\" could not be moved to \"%2\"", oldFileUrl.toDisplayString(), newFileUrl.toDisplayString())); doc->openUrl(oldFileUrl); } } void KateFileTree::slotDocumentFirst() { KTextEditor::Document *doc = model()->data(model()->index(0, 0), KateFileTreeModel::DocumentRole).value(); if (doc) { emit activateDocument(doc); } } void KateFileTree::slotDocumentLast() { int count = model()->rowCount(model()->parent(currentIndex())); KTextEditor::Document *doc = model()->data(model()->index(count - 1, 0), KateFileTreeModel::DocumentRole).value(); if (doc) { emit activateDocument(doc); } } void KateFileTree::slotDocumentPrev() { KateFileTreeProxyModel *ftpm = static_cast(model()); QModelIndex current_index = currentIndex(); QModelIndex prev; // scan up the tree skipping any dir nodes while (current_index.isValid()) { if (current_index.row() > 0) { current_index = ftpm->sibling(current_index.row() - 1, current_index.column(), current_index); if (!current_index.isValid()) { break; } if (ftpm->isDir(current_index)) { // try and select the last child in this parent int children = ftpm->rowCount(current_index); current_index = ftpm->index(children - 1, 0, current_index); if (ftpm->isDir(current_index)) { // since we're a dir, keep going while (ftpm->isDir(current_index)) { children = ftpm->rowCount(current_index); current_index = ftpm->index(children - 1, 0, current_index); } if (!ftpm->isDir(current_index)) { prev = current_index; break; } continue; } else { // we're the previous file, set prev prev = current_index; break; } } else { // found document item prev = current_index; break; } } else { // just select the parent, the logic above will handle the rest current_index = ftpm->parent(current_index); if (!current_index.isValid()) { // paste the root node here, try and wrap around int children = ftpm->rowCount(current_index); QModelIndex last_index = ftpm->index(children - 1, 0, current_index); if (!last_index.isValid()) { break; } if (ftpm->isDir(last_index)) { // last node is a dir, select last child row int last_children = ftpm->rowCount(last_index); prev = ftpm->index(last_children - 1, 0, last_index); // bug here? break; } else { // got last file node prev = last_index; break; } } } } if (prev.isValid()) { KTextEditor::Document *doc = model()->data(prev, KateFileTreeModel::DocumentRole).value(); emit activateDocument(doc); } } void KateFileTree::slotDocumentNext() { KateFileTreeProxyModel *ftpm = static_cast(model()); QModelIndex current_index = currentIndex(); int parent_row_count = ftpm->rowCount(ftpm->parent(current_index)); QModelIndex next; // scan down the tree skipping any dir nodes while (current_index.isValid()) { if (current_index.row() < parent_row_count - 1) { current_index = ftpm->sibling(current_index.row() + 1, current_index.column(), current_index); if (!current_index.isValid()) { break; } if (ftpm->isDir(current_index)) { // we have a dir node while (ftpm->isDir(current_index)) { current_index = ftpm->index(0, 0, current_index); } parent_row_count = ftpm->rowCount(ftpm->parent(current_index)); if (!ftpm->isDir(current_index)) { next = current_index; break; } } else { // found document item next = current_index; break; } } else { // select the parent's next sibling QModelIndex parent_index = ftpm->parent(current_index); int grandparent_row_count = ftpm->rowCount(ftpm->parent(parent_index)); current_index = parent_index; parent_row_count = grandparent_row_count; // at least if we're not past the last node if (!current_index.isValid()) { // paste the root node here, try and wrap around QModelIndex last_index = ftpm->index(0, 0, QModelIndex()); if (!last_index.isValid()) { break; } if (ftpm->isDir(last_index)) { // last node is a dir, select first child row while (ftpm->isDir(last_index)) { if (ftpm->rowCount(last_index)) { // has children, select first last_index = ftpm->index(0, 0, last_index); } } next = last_index; break; } else { // got first file node next = last_index; break; } } } } if (next.isValid()) { KTextEditor::Document *doc = model()->data(next, KateFileTreeModel::DocumentRole).value(); emit activateDocument(doc); } } void KateFileTree::slotPrintDocument() { KTextEditor::Document *doc = model()->data(m_indexContextMenu, KateFileTreeModel::DocumentRole).value(); if (!doc) { return; } doc->print(); } void KateFileTree::slotPrintDocumentPreview() { KTextEditor::Document *doc = model()->data(m_indexContextMenu, KateFileTreeModel::DocumentRole).value(); if (!doc) { return; } doc->printPreview(); } void KateFileTree::slotResetHistory() { KateFileTreeProxyModel *ftpm = static_cast(model()); KateFileTreeModel *ftm = static_cast(ftpm->sourceModel()); ftm->resetHistory(); } void KateFileTree::slotDocumentDelete() { KTextEditor::Document *doc = model()->data(m_indexContextMenu, KateFileTreeModel::DocumentRole).value(); if (!doc) { return; } QUrl url = doc->url(); bool go = (KMessageBox::warningContinueCancel(this, i18n("Do you really want to delete file \"%1\" from storage?", url.toDisplayString()), i18n("Delete file?"), KStandardGuiItem::yes(), KStandardGuiItem::no(), QLatin1String("filetreedeletefile") ) == KMessageBox::Continue); if (!go) { return; } if (!KTextEditor::Editor::instance()->application()->closeDocument(doc)) { return; // no extra message, the internals of ktexteditor should take care of that. } if (url.isValid()) { KIO::DeleteJob *job = KIO::del(url); if (!job->exec()) { KMessageBox::sorry(this, i18n("File \"%1\" could not be deleted.", url.toDisplayString())); } } } //END KateFileTree diff --git a/addons/filetree/katefiletreeconfigpage.cpp b/addons/filetree/katefiletreeconfigpage.cpp index 08a294c4f..7cc229f9a 100644 --- a/addons/filetree/katefiletreeconfigpage.cpp +++ b/addons/filetree/katefiletreeconfigpage.cpp @@ -1,196 +1,198 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001, 2007 Anders Lund Copyright (C) 2009, Abhishek Patil Copyright (C) 2010, Thomas Fjellstrom 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. */ /* Config stuff plan: ----------------- main default config is stored in KSharedConfig::openConfig()+":filetree" when main config is set, it needs to tell view's to delete existing customized settings, and use the global ones (somehow) (maybe some kind of "customized" flag?) view needs to pull default settings from the main plugin config */ #include "katefiletreeconfigpage.h" #include "katefiletreeplugin.h" #include "katefiletreedebug.h" #include "katefiletreemodel.h" #include "katefiletreeproxymodel.h" #include #include #include #include #include #include #include KateFileTreeConfigPage::KateFileTreeConfigPage(QWidget *parent, KateFileTreePlugin *fl) : KTextEditor::ConfigPage(parent), m_plug(fl), m_changed(false) { QVBoxLayout *layout = new QVBoxLayout(this); layout->setMargin(0); gbEnableShading = new QGroupBox(i18n("Background Shading"), this); gbEnableShading->setCheckable(true); layout->addWidget(gbEnableShading); QGridLayout *lo = new QGridLayout(gbEnableShading); kcbViewShade = new KColorButton(gbEnableShading); lViewShade = new QLabel(i18n("&Viewed documents' shade:"), gbEnableShading); lViewShade->setBuddy(kcbViewShade); lo->addWidget(lViewShade, 2, 0); lo->addWidget(kcbViewShade, 2, 1); kcbEditShade = new KColorButton(gbEnableShading); lEditShade = new QLabel(i18n("&Modified documents' shade:"), gbEnableShading); lEditShade->setBuddy(kcbEditShade); lo->addWidget(lEditShade, 3, 0); lo->addWidget(kcbEditShade, 3, 1); // sorting QHBoxLayout *lo2 = new QHBoxLayout; layout->addLayout(lo2); lSort = new QLabel(i18n("&Sort by:"), this); lo2->addWidget(lSort); cmbSort = new KComboBox(this); lo2->addWidget(cmbSort); lSort->setBuddy(cmbSort); cmbSort->addItem(i18n("Opening Order"), (int)KateFileTreeModel::OpeningOrderRole); cmbSort->addItem(i18n("Document Name"), (int)Qt::DisplayRole); cmbSort->addItem(i18n("Url"), (int)KateFileTreeModel::PathRole); // view mode QHBoxLayout *lo3 = new QHBoxLayout; layout->addLayout(lo3); lMode = new QLabel(i18n("&View Mode:"), this); lo3->addWidget(lMode); cmbMode = new KComboBox(this); lo3->addWidget(cmbMode); lMode->setBuddy(cmbMode); cmbMode->addItem(i18n("Tree View"), QVariant(false)); cmbMode->addItem(i18n("List View"), QVariant(true)); // Show Full Path on Roots? QHBoxLayout *lo4 = new QHBoxLayout; layout->addLayout(lo4); cbShowFullPath = new QCheckBox(i18n("&Show Full Path"), this); lo4->addWidget(cbShowFullPath); layout->insertStretch(-1, 10); gbEnableShading->setWhatsThis(i18n( "When background shading is enabled, documents that have been viewed " "or edited within the current session will have a shaded background. " "The most recent documents have the strongest shade.")); kcbViewShade->setWhatsThis(i18n( "Set the color for shading viewed documents.")); kcbEditShade->setWhatsThis(i18n( "Set the color for modified documents. This color is blended into " "the color for viewed files. The most recently edited documents get " "most of this color.")); cbShowFullPath->setWhatsThis(i18n( "When enabled, in tree mode, top level folders will show up with their full path " "rather than just the last folder name.")); // cmbSort->setWhatsThis( i18n( // "Set the sorting method for the documents.") ); reset(); - connect(gbEnableShading, SIGNAL(toggled(bool)), this, SLOT(slotMyChanged())); - connect(kcbViewShade, SIGNAL(changed(QColor)), this, SLOT(slotMyChanged())); - connect(kcbEditShade, SIGNAL(changed(QColor)), this, SLOT(slotMyChanged())); - connect(cmbSort, SIGNAL(activated(int)), this, SLOT(slotMyChanged())); - connect(cmbMode, SIGNAL(activated(int)), this, SLOT(slotMyChanged())); - connect(cbShowFullPath, SIGNAL(stateChanged(int)), this, SLOT(slotMyChanged())); + connect(gbEnableShading, &QGroupBox::toggled, this, &KateFileTreeConfigPage::slotMyChanged); + connect(kcbViewShade, &KColorButton::changed, this, &KateFileTreeConfigPage::slotMyChanged); + connect(kcbEditShade, &KColorButton::changed, this, &KateFileTreeConfigPage::slotMyChanged); + connect(cmbSort, static_cast(&KComboBox::activated), + this, &KateFileTreeConfigPage::slotMyChanged); + connect(cmbMode, static_cast(&KComboBox::activated), + this, &KateFileTreeConfigPage::slotMyChanged); + connect(cbShowFullPath, &QCheckBox::stateChanged, this, &KateFileTreeConfigPage::slotMyChanged); } QString KateFileTreeConfigPage::name() const { return QString(i18n("Documents")); } QString KateFileTreeConfigPage::fullName() const { return QString(i18n("Configure Documents")); } QIcon KateFileTreeConfigPage::icon() const { return QIcon::fromTheme(QLatin1String("view-list-tree")); } void KateFileTreeConfigPage::apply() { if (! m_changed) { return; } m_changed = false; // apply config to views m_plug->applyConfig( gbEnableShading->isChecked(), kcbViewShade->color(), kcbEditShade->color(), cmbMode->itemData(cmbMode->currentIndex()).toBool(), cmbSort->itemData(cmbSort->currentIndex()).toInt(), cbShowFullPath->checkState() == Qt::Checked ); } void KateFileTreeConfigPage::reset() { const KateFileTreePluginSettings &settings = m_plug->settings(); gbEnableShading->setChecked(settings.shadingEnabled()); kcbEditShade->setColor(settings.editShade()); kcbViewShade->setColor(settings.viewShade()); cmbSort->setCurrentIndex(cmbSort->findData(settings.sortRole())); cmbMode->setCurrentIndex(settings.listMode()); cbShowFullPath->setCheckState(settings.showFullPathOnRoots() ? Qt::Checked : Qt::Unchecked); m_changed = false; } void KateFileTreeConfigPage::defaults() { // m_plug->settings().revertToDefaults() ?? // not sure the above is ever needed... reset(); } void KateFileTreeConfigPage::slotMyChanged() { m_changed = true; emit changed(); } diff --git a/addons/filetree/katefiletreemodel.cpp b/addons/filetree/katefiletreemodel.cpp index 48c176518..483537d37 100644 --- a/addons/filetree/katefiletreemodel.cpp +++ b/addons/filetree/katefiletreemodel.cpp @@ -1,1337 +1,1337 @@ /* This file is part of the KDE project Copyright (C) 2010 Thomas Fjellstrom 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 "katefiletreemodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "katefiletreedebug.h" class ProxyItemDir; class ProxyItem { friend class KateFileTreeModel; public: enum Flag { None = 0, Dir = 1, Modified = 2, ModifiedExternally = 4, DeletedExternally = 8, Empty = 16, ShowFullPath = 32, Host = 64 }; Q_DECLARE_FLAGS(Flags, Flag) ProxyItem(const QString &n, ProxyItemDir *p = nullptr, Flags f = ProxyItem::None); ~ProxyItem(); int addChild(ProxyItem *p); void remChild(ProxyItem *p); ProxyItemDir *parent() const; ProxyItem *child(int idx) const; int childCount() const; int row() const; const QString &display() const; const QString &documentName() const; const QString &path() const; void setPath(const QString &str); void setHost(const QString &host); const QString &host() const; void setIcon(const QIcon &i); const QIcon &icon() const; const QList &children() const; QList &children(); void setDoc(KTextEditor::Document *doc); KTextEditor::Document *doc() const; /** * the view usess this to close all the documents under the folder * @returns list of all the (nested) documents under this node */ QList docTree() const; void setFlags(Flags flags); void setFlag(Flag flag); void clearFlag(Flag flag); bool flag(Flag flag) const; private: QString m_path; QString m_documentName; ProxyItemDir *m_parent; QList m_children; int m_row; Flags m_flags; QString m_display; QIcon m_icon; KTextEditor::Document *m_doc; QString m_host; protected: void updateDisplay(); void updateDocumentName(); }; QDebug operator<<(QDebug dbg, ProxyItem *item) { if (!item) { dbg.nospace() << "ProxyItem(0x0) "; return dbg.maybeSpace(); } const void *parent = static_cast(item->parent()); dbg.nospace() << "ProxyItem(" << (void *)item << ","; dbg.nospace() << parent << "," << item->row() << ","; dbg.nospace() << item->doc() << "," << item->path() << ") "; return dbg.maybeSpace(); } class ProxyItemDir : public ProxyItem { public: ProxyItemDir(QString n, ProxyItemDir *p = nullptr) : ProxyItem(n, p) { setFlag(ProxyItem::Dir); updateDisplay(); setIcon(QIcon::fromTheme(QLatin1String("folder"))); } }; QDebug operator<<(QDebug dbg, ProxyItemDir *item) { if (!item) { dbg.nospace() << "ProxyItemDir(0x0) "; return dbg.maybeSpace(); } const void *parent = static_cast(item->parent()); dbg.nospace() << "ProxyItemDir(" << (void *)item << ","; dbg.nospace() << parent << "," << item->row() << ","; dbg.nospace() << item->path() << ", children:" << item->childCount() << ") "; return dbg.maybeSpace(); } Q_DECLARE_OPERATORS_FOR_FLAGS(ProxyItem::Flags) //BEGIN ProxyItem ProxyItem::ProxyItem(const QString &d, ProxyItemDir *p, ProxyItem::Flags f) : m_path(d), m_parent(Q_NULLPTR), m_row(-1), m_flags(f), m_doc(nullptr) { updateDisplay(); /** * add to parent, if parent passed * we assigned above nullptr to parent to not trigger * remove from old parent here! */ if (p) { p->addChild(this); } } ProxyItem::~ProxyItem() { qDeleteAll(m_children); } void ProxyItem::updateDisplay() { // triggers only if this is a top level node and the root has the show full path flag set. if (flag(ProxyItem::Dir) && m_parent && !m_parent->m_parent && m_parent->flag(ProxyItem::ShowFullPath)) { m_display = m_path; if (m_display.startsWith(QDir::homePath())) { m_display.replace(0, QDir::homePath().length(), QLatin1String("~")); } } else { m_display = m_path.section(QLatin1Char('/'), -1, -1); if (flag(ProxyItem::Host) && (!m_parent || (m_parent && !m_parent->m_parent))) { const QString hostPrefix = QString::fromLatin1("[%1]").arg(host()); if (hostPrefix != m_display) { m_display = hostPrefix + m_display; } } } } int ProxyItem::addChild(ProxyItem *item) { // remove from old parent, is any if (item->m_parent) { item->m_parent->remChild(item); } const int item_row = m_children.count(); item->m_row = item_row; m_children.append(item); item->m_parent = static_cast(this); item->updateDisplay(); return item_row; } void ProxyItem::remChild(ProxyItem *item) { const int idx = m_children.indexOf(item); Q_ASSERT(idx != -1); m_children.removeAt(idx); for (int i = idx; i < m_children.count(); i++) { m_children[i]->m_row = i; } item->m_parent = nullptr; } ProxyItemDir *ProxyItem::parent() const { return m_parent; } ProxyItem *ProxyItem::child(int idx) const { return (idx < 0 || idx >= m_children.count()) ? 0 : m_children[idx]; } int ProxyItem::childCount() const { return m_children.count(); } int ProxyItem::row() const { return m_row; } const QIcon &ProxyItem::icon() const { return m_icon; } void ProxyItem::setIcon(const QIcon &i) { m_icon = i; } const QString &ProxyItem::documentName() const { return m_documentName; } const QString &ProxyItem::display() const { return m_display; } const QString &ProxyItem::path() const { return m_path; } void ProxyItem::setPath(const QString &p) { m_path = p; updateDisplay(); } const QList &ProxyItem::children() const { return m_children; } QList &ProxyItem::children() { return m_children; } void ProxyItem::setDoc(KTextEditor::Document *doc) { Q_ASSERT(doc); m_doc = doc; updateDocumentName(); } KTextEditor::Document *ProxyItem::doc() const { return m_doc; } QList ProxyItem::docTree() const { QList result; if (m_doc) { result.append(m_doc); return result; } foreach(const ProxyItem * item, m_children) { result.append(item->docTree()); } return result; } bool ProxyItem::flag(Flag f) const { return m_flags & f; } void ProxyItem::setFlag(Flag f) { m_flags |= f; } void ProxyItem::setFlags(Flags f) { m_flags = f; } void ProxyItem::clearFlag(Flag f) { m_flags &= ~f; } void ProxyItem::setHost(const QString &host) { m_host = host; if (host.isEmpty()) { clearFlag(Host); } else { setFlag(Host); } updateDocumentName(); updateDisplay(); } const QString &ProxyItem::host() const { return m_host; } void ProxyItem::updateDocumentName() { const QString docName = m_doc ? m_doc->documentName() : QString(); if (flag(ProxyItem::Host)) { m_documentName = QString::fromLatin1("[%1]%2").arg(m_host).arg(docName); } else { m_documentName = docName; } } //END ProxyItem KateFileTreeModel::KateFileTreeModel(QObject *p) : QAbstractItemModel(p) , m_root(new ProxyItemDir(QLatin1String("m_root"), nullptr)) { // setup default settings // session init will set these all soon const KColorScheme colors(QPalette::Active); const QColor bg = colors.background().color(); m_editShade = KColorUtils::tint(bg, colors.foreground(KColorScheme::ActiveText).color(), 0.5); m_viewShade = KColorUtils::tint(bg, colors.foreground(KColorScheme::VisitedText).color(), 0.5); m_shadingEnabled = true; m_listMode = false; initModel(); } KateFileTreeModel::~KateFileTreeModel() { delete m_root; } bool KateFileTreeModel::shadingEnabled() const { return m_shadingEnabled; } void KateFileTreeModel::setShadingEnabled(bool se) { if (m_shadingEnabled != se) { updateBackgrounds(true); m_shadingEnabled = se; } } const QColor &KateFileTreeModel::editShade() const { return m_editShade; } void KateFileTreeModel::setEditShade(const QColor &es) { m_editShade = es; } const QColor &KateFileTreeModel::viewShade() const { return m_viewShade; } void KateFileTreeModel::setViewShade(const QColor &vs) { m_viewShade = vs; } bool KateFileTreeModel::showFullPathOnRoots(void) const { return m_root->flag(ProxyItem::ShowFullPath); } void KateFileTreeModel::setShowFullPathOnRoots(bool s) { if (s) { m_root->setFlag(ProxyItem::ShowFullPath); } else { m_root->clearFlag(ProxyItem::ShowFullPath); } foreach(ProxyItem * root, m_root->children()) { root->updateDisplay(); } } void KateFileTreeModel::initModel() { // add already existing documents foreach(KTextEditor::Document * doc, KTextEditor::Editor::instance()->application()->documents()) { documentOpened(doc); } } void KateFileTreeModel::clearModel() { // remove all items // can safely ignore documentClosed here beginRemoveRows(QModelIndex(), 0, qMax(m_root->childCount() - 1, 0)); delete m_root; m_root = new ProxyItemDir(QLatin1String("m_root"), nullptr); m_docmap.clear(); m_viewHistory.clear(); m_editHistory.clear(); m_brushes.clear(); endRemoveRows(); } void KateFileTreeModel::connectDocument(const KTextEditor::Document *doc) { - connect(doc, SIGNAL(documentNameChanged(KTextEditor::Document *)), this, SLOT(documentNameChanged(KTextEditor::Document *))); - connect(doc, SIGNAL(documentUrlChanged(KTextEditor::Document *)), this, SLOT(documentNameChanged(KTextEditor::Document *))); - connect(doc, SIGNAL(modifiedChanged(KTextEditor::Document *)), this, SLOT(documentModifiedChanged(KTextEditor::Document *))); + connect(doc, &KTextEditor::Document::documentNameChanged, this, &KateFileTreeModel::documentNameChanged); + connect(doc, &KTextEditor::Document::documentUrlChanged, this, &KateFileTreeModel::documentNameChanged); + connect(doc, &KTextEditor::Document::modifiedChanged, this, &KateFileTreeModel::documentModifiedChanged); connect(doc, SIGNAL(modifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SLOT(documentModifiedOnDisc(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason))); } QModelIndex KateFileTreeModel::docIndex(const KTextEditor::Document *doc) const { if (!m_docmap.contains(doc)) { return QModelIndex(); } ProxyItem *item = m_docmap[doc]; return createIndex(item->row(), 0, item); } Qt::ItemFlags KateFileTreeModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = Qt::ItemIsEnabled; if (!index.isValid()) { return nullptr; } const ProxyItem *item = static_cast(index.internalPointer()); if (item) { if (!item->childCount()) { flags |= Qt::ItemIsSelectable; } if (item->doc() && item->doc()->url().isValid()) { flags |= Qt::ItemIsDragEnabled; } } return flags; } Q_DECLARE_METATYPE(QList) QVariant KateFileTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } ProxyItem *item = static_cast(index.internalPointer()); if (!item) { return QVariant(); } switch (role) { case KateFileTreeModel::PathRole: // allow to sort with hostname + path, bug 271488 return (item->doc() && !item->doc()->url().isEmpty()) ? item->doc()->url().toString() : item->path(); case KateFileTreeModel::DocumentRole: return QVariant::fromValue(item->doc()); case KateFileTreeModel::OpeningOrderRole: return item->row(); case KateFileTreeModel::DocumentTreeRole: return QVariant::fromValue(item->docTree()); case Qt::DisplayRole: // in list mode we want to use kate's fancy names. if (m_listMode) { return item->documentName(); } else { return item->display(); } case Qt::DecorationRole: return item->icon(); case Qt::ToolTipRole: { QString tooltip = item->path(); if (item->flag(ProxyItem::DeletedExternally) || item->flag(ProxyItem::ModifiedExternally)) { tooltip = i18nc("%1 is the full path", "

%1

The document has been modified by another application.

").arg(item->path()); } return tooltip; } case Qt::ForegroundRole: { const KColorScheme colors(QPalette::Active); if (!item->flag(ProxyItem::Dir) && (!item->doc() || item->doc()->openingError())) { return colors.foreground(KColorScheme::InactiveText).color(); } } break; case Qt::BackgroundRole: // TODO: do that funky shading the file list does... if (m_shadingEnabled && m_brushes.contains(item)) { return m_brushes[item]; } break; } return QVariant(); } QMimeData *KateFileTreeModel::mimeData(const QModelIndexList &indexes) const { QList urls; for (const auto &index : indexes) { ProxyItem *item = static_cast(index.internalPointer()); if (!item || !item->doc() || !item->doc()->url().isValid()) { continue; } urls.append(item->doc()->url()); } if (urls.isEmpty()) { return nullptr; } QMimeData *mimeData = new QMimeData(); mimeData->setUrls(urls); return mimeData; } QVariant KateFileTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(orientation); Q_UNUSED(role); if (section == 0) { return QLatin1String("name"); } return QVariant(); } int KateFileTreeModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) { return m_root->childCount(); } const ProxyItem *item = static_cast(parent.internalPointer()); if (!item) { return 0; } return item->childCount(); } int KateFileTreeModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 1; } QModelIndex KateFileTreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return QModelIndex(); } const ProxyItem *item = static_cast(index.internalPointer()); if (!item) { return QModelIndex(); } if (!item->parent()) { return QModelIndex(); } if (item->parent() == m_root) { return QModelIndex(); } return createIndex(item->parent()->row(), 0, item->parent()); } QModelIndex KateFileTreeModel::index(int row, int column, const QModelIndex &parent) const { const ProxyItem *p = nullptr; if (column != 0) { return QModelIndex(); } if (!parent.isValid()) { p = m_root; } else { p = static_cast(parent.internalPointer()); } if (!p) { return QModelIndex(); } if (row < 0 || row >= p->childCount()) { return QModelIndex(); } return createIndex(row, 0, p->child(row)); } bool KateFileTreeModel::hasChildren(const QModelIndex &parent) const { if (!parent.isValid()) { return m_root->childCount() > 0; } const ProxyItem *item = static_cast(parent.internalPointer()); if (!item) { return false; } return item->childCount() > 0; } bool KateFileTreeModel::isDir(const QModelIndex &index) const { if (!index.isValid()) { return true; } const ProxyItem *item = static_cast(index.internalPointer()); if (!item) { return false; } return item->flag(ProxyItem::Dir); } bool KateFileTreeModel::listMode() const { return m_listMode; } void KateFileTreeModel::setListMode(bool lm) { if (lm != m_listMode) { m_listMode = lm; clearModel(); initModel(); } } void KateFileTreeModel::documentOpened(KTextEditor::Document *doc) { ProxyItem *item = new ProxyItem(QString()); item->setDoc(doc); updateItemPathAndHost(item); setupIcon(item); handleInsert(item); m_docmap[doc] = item; connectDocument(doc); } void KateFileTreeModel::documentsOpened(const QList &docs) { foreach(KTextEditor::Document * doc, docs) { if (m_docmap.contains(doc)) { documentNameChanged(doc); } else { documentOpened(doc); } } } void KateFileTreeModel::documentModifiedChanged(KTextEditor::Document *doc) { if (!m_docmap.contains(doc)) { return; } ProxyItem *item = m_docmap[doc]; if (doc->isModified()) { item->setFlag(ProxyItem::Modified); } else { item->clearFlag(ProxyItem::Modified); item->clearFlag(ProxyItem::ModifiedExternally); item->clearFlag(ProxyItem::DeletedExternally); } setupIcon(item); const QModelIndex idx = createIndex(item->row(), 0, item); emit dataChanged(idx, idx); } void KateFileTreeModel::documentModifiedOnDisc(KTextEditor::Document *doc, bool modified, KTextEditor::ModificationInterface::ModifiedOnDiskReason reason) { Q_UNUSED(modified); if (!m_docmap.contains(doc)) { return; } ProxyItem *item = m_docmap[doc]; // This didn't do what I thought it did, on an ignore // we'd get !modified causing the warning icons to disappear if (!modified) { item->clearFlag(ProxyItem::ModifiedExternally); item->clearFlag(ProxyItem::DeletedExternally); } else { if (reason == KTextEditor::ModificationInterface::OnDiskDeleted) { item->setFlag(ProxyItem::DeletedExternally); } else if (reason == KTextEditor::ModificationInterface::OnDiskModified) { item->setFlag(ProxyItem::ModifiedExternally); } else if (reason == KTextEditor::ModificationInterface::OnDiskCreated) { // with out this, on "reload" we don't get the icons removed :( item->clearFlag(ProxyItem::ModifiedExternally); item->clearFlag(ProxyItem::DeletedExternally); } } setupIcon(item); const QModelIndex idx = createIndex(item->row(), 0, item); emit dataChanged(idx, idx); } void KateFileTreeModel::documentActivated(const KTextEditor::Document *doc) { if (!m_docmap.contains(doc)) { return; } ProxyItem *item = m_docmap[doc]; m_viewHistory.removeAll(item); m_viewHistory.prepend(item); while (m_viewHistory.count() > 10) { m_viewHistory.removeLast(); } updateBackgrounds(); } void KateFileTreeModel::documentEdited(const KTextEditor::Document *doc) { if (!m_docmap.contains(doc)) { return; } ProxyItem *item = m_docmap[doc]; m_editHistory.removeAll(item); m_editHistory.prepend(item); while (m_editHistory.count() > 10) { m_editHistory.removeLast(); } updateBackgrounds(); } void KateFileTreeModel::slotAboutToDeleteDocuments(const QList &docs) { foreach(const KTextEditor::Document * doc, docs) { - disconnect(doc, SIGNAL(documentNameChanged(KTextEditor::Document *)), this, SLOT(documentNameChanged(KTextEditor::Document *))); - disconnect(doc, SIGNAL(documentUrlChanged(KTextEditor::Document *)), this, SLOT(documentNameChanged(KTextEditor::Document *))); - disconnect(doc, SIGNAL(modifiedChanged(KTextEditor::Document *)), this, SLOT(documentModifiedChanged(KTextEditor::Document *))); + disconnect(doc, &KTextEditor::Document::documentNameChanged, this, &KateFileTreeModel::documentNameChanged); + disconnect(doc, &KTextEditor::Document::documentUrlChanged, this, &KateFileTreeModel::documentNameChanged); + disconnect(doc, &KTextEditor::Document::modifiedChanged, this, &KateFileTreeModel::documentModifiedChanged); disconnect(doc, SIGNAL(modifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SLOT(documentModifiedOnDisc(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason))); } } void KateFileTreeModel::slotDocumentsDeleted(const QList &docs) { foreach(const KTextEditor::Document * doc, docs) { connectDocument(doc); } } class EditViewCount { public: EditViewCount(): edit(0), view(0) {} int edit; int view; }; void KateFileTreeModel::updateBackgrounds(bool force) { if (!m_shadingEnabled && !force) { return; } QMap helper; int i = 1; foreach(ProxyItem * item, m_viewHistory) { helper[item].view = i; i++; } i = 1; foreach(ProxyItem * item, m_editHistory) { helper[item].edit = i; i++; } QMap oldBrushes = m_brushes; m_brushes.clear(); const int hc = m_viewHistory.count(); const int ec = m_editHistory.count(); for (QMap::iterator it = helper.begin(); it != helper.end(); ++it) { QColor shade(m_viewShade); QColor eshade(m_editShade); if (it.value().edit > 0) { int v = hc - it.value().view; int e = ec - it.value().edit + 1; e = e * e; const int n = qMax(v + e, 1); shade.setRgb( ((shade.red() * v) + (eshade.red() * e)) / n, ((shade.green() * v) + (eshade.green() * e)) / n, ((shade.blue() * v) + (eshade.blue() * e)) / n ); } // blend in the shade color; latest is most colored. const double t = double(hc - it.value().view + 1) / double(hc); m_brushes[it.key()] = QBrush(KColorUtils::mix(QPalette().color(QPalette::Base), shade, t)); } for (auto it = m_brushes.constBegin(), end = m_brushes.constEnd(); it != end; ++it) { ProxyItem *item = it.key(); oldBrushes.remove(item); const QModelIndex idx = createIndex(item->row(), 0, item); dataChanged(idx, idx); } for (auto it = oldBrushes.constBegin(), end = oldBrushes.constEnd(); it != end; ++it) { ProxyItem *item = it.key(); const QModelIndex idx = createIndex(item->row(), 0, item); dataChanged(idx, idx); } } void KateFileTreeModel::handleEmptyParents(ProxyItemDir *item) { Q_ASSERT(item != nullptr); if (!item->parent()) { return; } ProxyItemDir *parent = item->parent(); while (parent) { if (!item->childCount()) { const QModelIndex parent_index = (parent == m_root) ? QModelIndex() : createIndex(parent->row(), 0, parent); beginRemoveRows(parent_index, item->row(), item->row()); parent->remChild(item); endRemoveRows(); delete item; } else { // breakout early, if this node isn't empty, theres no use in checking its parents return; } item = parent; parent = item->parent(); } } void KateFileTreeModel::documentClosed(KTextEditor::Document *doc) { if (!m_docmap.contains(doc)) { return; } if (m_shadingEnabled) { ProxyItem *toRemove = m_docmap[doc]; if (m_brushes.contains(toRemove)) { m_brushes.remove(toRemove); } if (m_viewHistory.contains(toRemove)) { m_viewHistory.removeAll(toRemove); } if (m_editHistory.contains(toRemove)) { m_editHistory.removeAll(toRemove); } } ProxyItem *node = m_docmap[doc]; ProxyItemDir *parent = node->parent(); const QModelIndex parent_index = (parent == m_root) ? QModelIndex() : createIndex(parent->row(), 0, parent); beginRemoveRows(parent_index, node->row(), node->row()); node->parent()->remChild(node); endRemoveRows(); delete node; handleEmptyParents(parent); m_docmap.remove(doc); } void KateFileTreeModel::documentNameChanged(KTextEditor::Document *doc) { if (!m_docmap.contains(doc)) { return; } ProxyItem *item = m_docmap[doc]; if (m_shadingEnabled) { ProxyItem *toRemove = m_docmap[doc]; if (m_brushes.contains(toRemove)) { QBrush brush = m_brushes[toRemove]; m_brushes.remove(toRemove); m_brushes.insert(item, brush); } if (m_viewHistory.contains(toRemove)) { const int idx = m_viewHistory.indexOf(toRemove); if (idx != -1) { m_viewHistory.replace(idx, item); } } if (m_editHistory.contains(toRemove)) { const int idx = m_editHistory.indexOf(toRemove); if (idx != -1) { m_editHistory.replace(idx, item); } } } handleNameChange(item); emit triggerViewChangeAfterNameChange(); // FIXME: heh, non-standard signal? } ProxyItemDir *KateFileTreeModel::findRootNode(const QString &name, const int r) const { foreach(ProxyItem * item, m_root->children()) { if (!item->flag(ProxyItem::Dir)) { continue; } // make sure we're actually matching against the right dir, // previously the check below would match /foo/xy against /foo/x // and return /foo/x rather than /foo/xy // this seems a bit hackish, but is the simplest way to solve the // current issue. QString path = item->path().section(QLatin1Char('/'), 0, -r) + QLatin1Char('/'); if (name.startsWith(path)) { return static_cast(item); } } return nullptr; } ProxyItemDir *KateFileTreeModel::findChildNode(const ProxyItemDir *parent, const QString &name) const { Q_ASSERT(parent != nullptr); Q_ASSERT(!name.isEmpty()); if (!parent->childCount()) { return nullptr; } foreach(ProxyItem * item, parent->children()) { if (!item->flag(ProxyItem::Dir)) { continue; } if (item->display() == name) { return static_cast(item); } } return nullptr; } void KateFileTreeModel::insertItemInto(ProxyItemDir *root, ProxyItem *item) { Q_ASSERT(root != nullptr); Q_ASSERT(item != nullptr); QString tail = item->path(); tail.remove(0, root->path().length()); QStringList parts = tail.split(QLatin1Char('/'), QString::SkipEmptyParts); ProxyItemDir *ptr = root; QStringList current_parts; current_parts.append(root->path()); // seems this can be empty, see bug 286191 if (!parts.isEmpty()) { parts.pop_back(); } foreach(const QString & part, parts) { current_parts.append(part); ProxyItemDir *find = findChildNode(ptr, part); if (!find) { const QString new_name = current_parts.join(QLatin1String("/")); const QModelIndex parent_index = (ptr == m_root) ? QModelIndex() : createIndex(ptr->row(), 0, ptr); beginInsertRows(parent_index, ptr->childCount(), ptr->childCount()); ptr = new ProxyItemDir(new_name, ptr); endInsertRows(); } else { ptr = find; } } const QModelIndex parent_index = (ptr == m_root) ? QModelIndex() : createIndex(ptr->row(), 0, ptr); beginInsertRows(parent_index, ptr->childCount(), ptr->childCount()); ptr->addChild(item); endInsertRows(); } void KateFileTreeModel::handleInsert(ProxyItem *item) { Q_ASSERT(item != nullptr); if (m_listMode || item->flag(ProxyItem::Empty)) { beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount()); m_root->addChild(item); endInsertRows(); return; } // case (item.path > root.path) ProxyItemDir *root = findRootNode(item->path()); if (root) { insertItemInto(root, item); return; } // trim off trailing file and dir QString base = item->path().section(QLatin1Char('/'), 0, -2); // create new root ProxyItemDir *new_root = new ProxyItemDir(base); new_root->setHost(item->host()); // add new root to m_root beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount()); m_root->addChild(new_root); endInsertRows(); // same fix as in findRootNode, try to match a full dir, instead of a partial path base += QLatin1Char('/'); // try and merge existing roots with the new root node (new_root.path < root.path) foreach(ProxyItem * root, m_root->children()) { if (root == new_root || !root->flag(ProxyItem::Dir)) { continue; } if (root->path().startsWith(base)) { beginRemoveRows(QModelIndex(), root->row(), root->row()); m_root->remChild(root); endRemoveRows(); //beginInsertRows(new_root_index, new_root->childCount(), new_root->childCount()); // this can't use new_root->addChild directly, or it'll potentially miss a bunch of subdirs insertItemInto(new_root, root); //endInsertRows(); } } // add item to new root // have to call begin/endInsertRows here, or the new item won't show up. const QModelIndex new_root_index = createIndex(new_root->row(), 0, new_root); beginInsertRows(new_root_index, new_root->childCount(), new_root->childCount()); new_root->addChild(item); endInsertRows(); handleDuplicitRootDisplay(new_root); } void KateFileTreeModel::handleDuplicitRootDisplay(ProxyItemDir *init) { QStack rootsToCheck; rootsToCheck.push(init); // make sure the roots don't match (recursively) while (!rootsToCheck.isEmpty()) { ProxyItemDir *check_root = rootsToCheck.pop(); if (check_root->parent() != m_root) { continue; } foreach(ProxyItem * root, m_root->children()) { if (root == check_root || !root->flag(ProxyItem::Dir)) { continue; } if (check_root->display() == root->display()) { bool changed = false; bool check_root_removed = false; const QString rdir = root->path().section(QLatin1Char('/'), 0, -2); if (!rdir.isEmpty()) { beginRemoveRows(QModelIndex(), root->row(), root->row()); m_root->remChild(root); endRemoveRows(); ProxyItemDir *irdir = new ProxyItemDir(rdir); beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount()); m_root->addChild(irdir); endInsertRows(); insertItemInto(irdir, root); foreach(ProxyItem * node, m_root->children()) { if (node == irdir || !root->flag(ProxyItem::Dir)) { continue; } const QString xy = rdir + QLatin1Char('/'); if (node->path().startsWith(xy)) { beginRemoveRows(QModelIndex(), node->row(), node->row()); // check_root_removed must be sticky check_root_removed = check_root_removed || (node == check_root); m_root->remChild(node); endRemoveRows(); insertItemInto(irdir, node); } } rootsToCheck.push(irdir); changed = true; } if (!check_root_removed) { const QString nrdir = check_root->path().section(QLatin1Char('/'), 0, -2); if (!nrdir.isEmpty()) { beginRemoveRows(QModelIndex(), check_root->row(), check_root->row()); m_root->remChild(check_root); endRemoveRows(); ProxyItemDir *irdir = new ProxyItemDir(nrdir); beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount()); m_root->addChild(irdir); endInsertRows(); insertItemInto(irdir, check_root); rootsToCheck.push(irdir); changed = true; } } if (changed) { break; // restart } } } // foreach root } } void KateFileTreeModel::handleNameChange(ProxyItem *item) { Q_ASSERT(item != nullptr); Q_ASSERT(item->parent()); updateItemPathAndHost(item); if (m_listMode) { const QModelIndex idx = createIndex(item->row(), 0, item); setupIcon(item); emit dataChanged(idx, idx); return; } // in either case (new/change) we want to remove the item from its parent ProxyItemDir *parent = item->parent(); const QModelIndex parent_index = (parent == m_root) ? QModelIndex() : createIndex(parent->row(), 0, parent); beginRemoveRows(parent_index, item->row(), item->row()); parent->remChild(item); endRemoveRows(); handleEmptyParents(parent); // clear all but Empty flag if (item->flag(ProxyItem::Empty)) { item->setFlags(ProxyItem::Empty); } else { item->setFlags(ProxyItem::None); } setupIcon(item); handleInsert(item); } void KateFileTreeModel::updateItemPathAndHost(ProxyItem *item) const { const KTextEditor::Document *doc = item->doc(); Q_ASSERT(doc); // this method should not be called at directory items QString path = doc->url().path(); QString host; if (doc->url().isEmpty()) { path = doc->documentName(); item->setFlag(ProxyItem::Empty); } else { item->clearFlag(ProxyItem::Empty); host = doc->url().host(); if (!host.isEmpty()) { path = QString::fromLatin1("[%1]%2").arg(host).arg(path); } } // for some reason we get useless name changes [should be fixed in 5.0] if (item->path() == path) { return; } item->setPath(path); item->setHost(host); } void KateFileTreeModel::setupIcon(ProxyItem *item) const { Q_ASSERT(item != nullptr); QString icon_name; if (item->flag(ProxyItem::Modified)) { icon_name = QLatin1String("document-save"); } else { const QUrl url(item->path()); icon_name = QMimeDatabase().mimeTypeForFile(url.path(), QMimeDatabase::MatchExtension).iconName(); } QIcon icon = QIcon::fromTheme(icon_name); if (item->flag(ProxyItem::ModifiedExternally) || item->flag(ProxyItem::DeletedExternally)) { icon = KIconUtils::addOverlay(icon, QIcon(QLatin1String("emblem-important")), Qt::TopLeftCorner); } item->setIcon(icon); } void KateFileTreeModel::resetHistory() { QSet list = QSet::fromList(m_viewHistory); list += QSet::fromList(m_editHistory); m_viewHistory.clear(); m_editHistory.clear(); m_brushes.clear(); foreach(ProxyItem * item, list) { QModelIndex idx = createIndex(item->row(), 0, item); dataChanged(idx, idx, QVector(1, Qt::BackgroundRole)); } } diff --git a/addons/filetree/katefiletreeplugin.cpp b/addons/filetree/katefiletreeplugin.cpp index caf943508..a28ff652e 100644 --- a/addons/filetree/katefiletreeplugin.cpp +++ b/addons/filetree/katefiletreeplugin.cpp @@ -1,457 +1,461 @@ /* This file is part of the KDE project Copyright (C) 2010 Thomas Fjellstrom 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. */ //BEGIN Includes #include "katefiletreeplugin.h" #include "katefiletree.h" #include "katefiletreemodel.h" #include "katefiletreeproxymodel.h" #include "katefiletreeconfigpage.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "katefiletreedebug.h" //END Includes K_PLUGIN_FACTORY_WITH_JSON(KateFileTreeFactory, "katefiletreeplugin.json", registerPlugin();) Q_LOGGING_CATEGORY(FILETREE, "kate-filetree", QtWarningMsg) //BEGIN KateFileTreePlugin KateFileTreePlugin::KateFileTreePlugin(QObject *parent, const QList &) : KTextEditor::Plugin(parent) { } KateFileTreePlugin::~KateFileTreePlugin() { m_settings.save(); } QObject *KateFileTreePlugin::createView(KTextEditor::MainWindow *mainWindow) { KateFileTreePluginView *view = new KateFileTreePluginView(mainWindow, this); - connect(view, SIGNAL(destroyed(QObject *)), this, SLOT(viewDestroyed(QObject *))); + connect(view, &KateFileTreePluginView::destroyed, this, &KateFileTreePlugin::viewDestroyed); m_views.append(view); return view; } void KateFileTreePlugin::viewDestroyed(QObject *view) { // do not access the view pointer, since it is partially destroyed already m_views.removeAll(static_cast(view)); } int KateFileTreePlugin::configPages() const { return 1; } KTextEditor::ConfigPage *KateFileTreePlugin::configPage(int number, QWidget *parent) { if (number != 0) { return nullptr; } KateFileTreeConfigPage *page = new KateFileTreeConfigPage(parent, this); return page; } const KateFileTreePluginSettings &KateFileTreePlugin::settings() { return m_settings; } void KateFileTreePlugin::applyConfig(bool shadingEnabled, QColor viewShade, QColor editShade, bool listMode, int sortRole, bool showFullPath) { // save to settings m_settings.setShadingEnabled(shadingEnabled); m_settings.setViewShade(viewShade); m_settings.setEditShade(editShade); m_settings.setListMode(listMode); m_settings.setSortRole(sortRole); m_settings.setShowFullPathOnRoots(showFullPath); m_settings.save(); // update views foreach(KateFileTreePluginView * view, m_views) { view->setHasLocalPrefs(false); view->model()->setShadingEnabled(shadingEnabled); view->model()->setViewShade(viewShade); view->model()->setEditShade(editShade); view->setListMode(listMode); view->proxy()->setSortRole(sortRole); view->model()->setShowFullPathOnRoots(showFullPath); } } //END KateFileTreePlugin //BEGIN KateFileTreePluginView KateFileTreePluginView::KateFileTreePluginView(KTextEditor::MainWindow *mainWindow, KateFileTreePlugin *plug) : QObject(mainWindow) , m_loadingDocuments(false) , m_plug(plug) , m_mainWindow(mainWindow) { KXMLGUIClient::setComponentName(QLatin1String("katefiletree"), i18n("Kate File Tree")); setXMLFile(QLatin1String("ui.rc")); m_toolView = mainWindow->createToolView(plug, QLatin1String("kate_private_plugin_katefiletreeplugin"), KTextEditor::MainWindow::Left, QIcon::fromTheme(QLatin1String("document-open")), i18n("Documents")); Q_ASSERT(m_toolView->layout()); m_toolView->layout()->setMargin(0); m_toolView->layout()->setSpacing(0); auto mainLayout = m_toolView->layout(); // create toolbar m_toolbar = new KToolBar(m_toolView); m_toolbar->setMovable(false); m_toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); m_toolbar->setContextMenuPolicy(Qt::NoContextMenu); mainLayout->addWidget(m_toolbar); // create filetree m_fileTree = new KateFileTree(m_toolView); m_fileTree->setSortingEnabled(true); mainLayout->addWidget(m_fileTree); - connect(m_fileTree, SIGNAL(activateDocument(KTextEditor::Document *)), - this, SLOT(activateDocument(KTextEditor::Document *))); - - connect(m_fileTree, SIGNAL(viewModeChanged(bool)), this, SLOT(viewModeChanged(bool))); - connect(m_fileTree, SIGNAL(sortRoleChanged(int)), this, SLOT(sortRoleChanged(int))); + connect(m_fileTree, &KateFileTree::activateDocument, this, &KateFileTreePluginView::activateDocument); + connect(m_fileTree, &KateFileTree::viewModeChanged, this, &KateFileTreePluginView::viewModeChanged); + connect(m_fileTree, &KateFileTree::sortRoleChanged, this, &KateFileTreePluginView::sortRoleChanged); m_documentModel = new KateFileTreeModel(this); m_proxyModel = new KateFileTreeProxyModel(this); m_proxyModel->setSourceModel(m_documentModel); m_proxyModel->setDynamicSortFilter(true); m_documentModel->setShowFullPathOnRoots(m_plug->settings().showFullPathOnRoots()); m_documentModel->setShadingEnabled(m_plug->settings().shadingEnabled()); m_documentModel->setViewShade(m_plug->settings().viewShade()); m_documentModel->setEditShade(m_plug->settings().editShade()); - connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentWillBeDeleted(KTextEditor::Document *)), - m_documentModel, SLOT(documentClosed(KTextEditor::Document *))); - - connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentCreated(KTextEditor::Document *)), - this, SLOT(documentOpened(KTextEditor::Document *))); - connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentWillBeDeleted(KTextEditor::Document *)), - this, SLOT(documentClosed(KTextEditor::Document *))); - connect(KTextEditor::Editor::instance()->application(), SIGNAL(aboutToCreateDocuments()), - this, SLOT(slotAboutToCreateDocuments())); - connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentsCreated(QList)), + connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentWillBeDeleted, + m_documentModel, &KateFileTreeModel::documentClosed); + connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentCreated, + this, &KateFileTreePluginView::documentOpened); + connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentWillBeDeleted, + this, &KateFileTreePluginView::documentClosed); + connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::aboutToCreateDocuments, + this, &KateFileTreePluginView::slotAboutToCreateDocuments); + + connect(KTextEditor::Editor::instance()->application(), + SIGNAL(documentsCreated(QList)), this, SLOT(slotDocumentsCreated(const QList &))); - connect(KTextEditor::Editor::instance()->application(), SIGNAL(aboutToDeleteDocuments(const QList &)), - m_documentModel, SLOT(slotAboutToDeleteDocuments(const QList &))); - connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentsDeleted(const QList &)), - m_documentModel, SLOT(slotDocumentsDeleted(const QList &))); - connect(m_documentModel, SIGNAL(triggerViewChangeAfterNameChange()), this, SLOT(viewChanged())); + connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::aboutToDeleteDocuments, + m_documentModel, &KateFileTreeModel::slotAboutToDeleteDocuments); + connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentsDeleted, + m_documentModel, &KateFileTreeModel::slotDocumentsDeleted); + + connect(m_documentModel, &KateFileTreeModel::triggerViewChangeAfterNameChange, [=] { + KateFileTreePluginView::viewChanged(); + }); + m_fileTree->setModel(m_proxyModel); m_fileTree->setDragEnabled(false); m_fileTree->setDragDropMode(QAbstractItemView::InternalMove); m_fileTree->setDropIndicatorShown(false); m_fileTree->setSelectionMode(QAbstractItemView::SingleSelection); - connect(m_fileTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), m_fileTree, SLOT(slotCurrentChanged(QModelIndex, QModelIndex))); + connect(m_fileTree->selectionModel(), &QItemSelectionModel::currentChanged, + m_fileTree, &KateFileTree::slotCurrentChanged); - connect(mainWindow, SIGNAL(viewChanged(KTextEditor::View *)), this, SLOT(viewChanged(KTextEditor::View *))); + connect(mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KateFileTreePluginView::viewChanged); // // actions // setupActions(); mainWindow->guiFactory()->addClient(this); m_proxyModel->setSortRole(Qt::DisplayRole); m_proxyModel->sort(0, Qt::AscendingOrder); m_proxyModel->invalidate(); } KateFileTreePluginView::~KateFileTreePluginView() { m_mainWindow->guiFactory()->removeClient(this); // clean up tree and toolview delete m_fileTree->parentWidget(); // delete m_toolView; // and TreeModel delete m_documentModel; } void KateFileTreePluginView::setupActions() { auto aPrev = actionCollection()->addAction(QLatin1String("filetree_prev_document")); aPrev->setText(i18n("Previous Document")); aPrev->setIcon(QIcon::fromTheme(QLatin1String("go-up"))); actionCollection()->setDefaultShortcut(aPrev, Qt::ALT + Qt::Key_Up); - connect(aPrev, SIGNAL(triggered(bool)), m_fileTree, SLOT(slotDocumentPrev())); + connect(aPrev, &QAction::triggered, m_fileTree, &KateFileTree::slotDocumentPrev); auto aNext = actionCollection()->addAction(QLatin1String("filetree_next_document")); aNext->setText(i18n("Next Document")); aNext->setIcon(QIcon::fromTheme(QLatin1String("go-down"))); actionCollection()->setDefaultShortcut(aNext, Qt::ALT + Qt::Key_Down); - connect(aNext, SIGNAL(triggered(bool)), m_fileTree, SLOT(slotDocumentNext())); + connect(aNext, &QAction::triggered, m_fileTree, &KateFileTree::slotDocumentNext); auto aShowActive = actionCollection()->addAction(QLatin1String("filetree_show_active_document")); aShowActive->setText(i18n("&Show Active")); aShowActive->setIcon(QIcon::fromTheme(QLatin1String("folder-sync"))); - connect(aShowActive, SIGNAL(triggered(bool)), this, SLOT(showActiveDocument())); + connect(aShowActive, &QAction::triggered, this, &KateFileTreePluginView::showActiveDocument); auto aSave = actionCollection()->addAction(QLatin1String("filetree_save"), this, SLOT(slotDocumentSave())); aSave->setText(i18n("Save Current Document")); aSave->setToolTip(i18n("Save the current document")); aSave->setIcon(QIcon::fromTheme(QLatin1String("document-save"))); auto aSaveAs = actionCollection()->addAction(QLatin1String("filetree_save_as"), this, SLOT(slotDocumentSaveAs())); aSaveAs->setText(i18n("Save Current Document As")); aSaveAs->setToolTip(i18n("Save current document under new name")); aSaveAs->setIcon(QIcon::fromTheme(QLatin1String("document-save-as"))); /** * add new & open, if hosting application has it */ if (KXmlGuiWindow *parentClient = qobject_cast(m_mainWindow->window())) { bool newOrOpen = false; if (auto a = parentClient->action("file_new")) { m_toolbar->addAction(a); newOrOpen = true; } if (auto a = parentClient->action("file_open")) { m_toolbar->addAction(a); newOrOpen = true; } if (newOrOpen) { m_toolbar->addSeparator(); } } /** * add own actions */ m_toolbar->addAction(aPrev); m_toolbar->addAction(aNext); m_toolbar->addSeparator(); m_toolbar->addAction(aSave); m_toolbar->addAction(aSaveAs); } KateFileTreeModel *KateFileTreePluginView::model() { return m_documentModel; } KateFileTreeProxyModel *KateFileTreePluginView::proxy() { return m_proxyModel; } KateFileTree *KateFileTreePluginView::tree() { return m_fileTree; } void KateFileTreePluginView::documentOpened(KTextEditor::Document *doc) { if (m_loadingDocuments) { return; } m_documentModel->documentOpened(doc); m_proxyModel->invalidate(); } void KateFileTreePluginView::documentClosed(KTextEditor::Document *doc) { Q_UNUSED(doc); m_proxyModel->invalidate(); } void KateFileTreePluginView::viewChanged(KTextEditor::View *) { KTextEditor::View *view = m_mainWindow->activeView(); if (!view) { return; } KTextEditor::Document *doc = view->document(); QModelIndex index = m_proxyModel->docIndex(doc); QString display = m_proxyModel->data(index, Qt::DisplayRole).toString(); // update the model on which doc is active m_documentModel->documentActivated(doc); m_fileTree->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); m_fileTree->scrollTo(index); while (index != QModelIndex()) { m_fileTree->expand(index); index = index.parent(); } } void KateFileTreePluginView::setListMode(bool listMode) { if (listMode) { m_documentModel->setListMode(true); m_fileTree->setRootIsDecorated(false); } else { m_documentModel->setListMode(false); m_fileTree->setRootIsDecorated(true); } m_proxyModel->sort(0, Qt::AscendingOrder); m_proxyModel->invalidate(); } void KateFileTreePluginView::viewModeChanged(bool listMode) { setHasLocalPrefs(true); setListMode(listMode); } void KateFileTreePluginView::sortRoleChanged(int role) { setHasLocalPrefs(true); m_proxyModel->setSortRole(role); m_proxyModel->invalidate(); } void KateFileTreePluginView::activateDocument(KTextEditor::Document *doc) { m_mainWindow->activateView(doc); } void KateFileTreePluginView::showToolView() { m_mainWindow->showToolView(m_toolView); m_toolView->setFocus(); } void KateFileTreePluginView::hideToolView() { m_mainWindow->hideToolView(m_toolView); } void KateFileTreePluginView::showActiveDocument() { // hack? viewChanged(); // make the tool view show if it was hidden showToolView(); } bool KateFileTreePluginView::hasLocalPrefs() { return m_hasLocalPrefs; } void KateFileTreePluginView::setHasLocalPrefs(bool h) { m_hasLocalPrefs = h; } void KateFileTreePluginView::readSessionConfig(const KConfigGroup &g) { if (g.exists()) { m_hasLocalPrefs = true; } else { m_hasLocalPrefs = false; } // we chain to the global settings by using them as the defaults // here in the session view config loading. const KateFileTreePluginSettings &defaults = m_plug->settings(); bool listMode = g.readEntry("listMode", defaults.listMode()); setListMode(listMode); int sortRole = g.readEntry("sortRole", defaults.sortRole()); m_proxyModel->setSortRole(sortRole); } void KateFileTreePluginView::writeSessionConfig(KConfigGroup &g) { if (m_hasLocalPrefs) { g.writeEntry("listMode", QVariant(m_documentModel->listMode())); g.writeEntry("sortRole", int(m_proxyModel->sortRole())); } else { g.deleteEntry("listMode"); g.deleteEntry("sortRole"); } g.sync(); } void KateFileTreePluginView::slotAboutToCreateDocuments() { m_loadingDocuments = true; } void KateFileTreePluginView::slotDocumentsCreated(const QList &docs) { m_documentModel->documentsOpened(docs); m_loadingDocuments = false; viewChanged(); } void KateFileTreePluginView::slotDocumentSave() { if (auto view = m_mainWindow->activeView()) { view->document()->documentSave(); } } void KateFileTreePluginView::slotDocumentSaveAs() { if (auto view = m_mainWindow->activeView()) { view->document()->documentSaveAs(); } } //END KateFileTreePluginView #include "katefiletreeplugin.moc" diff --git a/addons/gdbplugin/advanced_settings.cpp b/addons/gdbplugin/advanced_settings.cpp index fee25d4f8..fe53ae93e 100644 --- a/addons/gdbplugin/advanced_settings.cpp +++ b/addons/gdbplugin/advanced_settings.cpp @@ -1,250 +1,250 @@ // Description: Advanced settings dialog for gdb // // // Copyright (c) 2012 Kåre Särs // // 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 "advanced_settings.h" #ifdef WIN32 static const QLatin1Char pathSeparator(';'); #else static const QLatin1Char pathSeparator(':'); #endif #include AdvancedGDBSettings::AdvancedGDBSettings(QWidget *parent) : QDialog(parent) { setupUi(this); u_gdbBrowse->setIcon(QIcon::fromTheme(QStringLiteral("application-x-ms-dos-executable"))); - connect(u_gdbBrowse, SIGNAL(clicked()), this, SLOT(slotBrowseGDB())); + connect(u_gdbBrowse, &QToolButton::clicked, this, &AdvancedGDBSettings::slotBrowseGDB); u_setSoPrefix->setIcon(QIcon::fromTheme(QStringLiteral("folder"))); - connect(u_setSoPrefix, SIGNAL(clicked()), this, SLOT(slotSetSoPrefix())); + connect(u_setSoPrefix, &QToolButton::clicked, this, &AdvancedGDBSettings::slotSetSoPrefix); u_addSoSearchPath->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); u_delSoSearchPath->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); - connect(u_addSoSearchPath, SIGNAL(clicked()), this, SLOT(slotAddSoPath())); - connect(u_delSoSearchPath, SIGNAL(clicked()), this, SLOT(slotDelSoPath())); + connect(u_addSoSearchPath, &QToolButton::clicked, this, &AdvancedGDBSettings::slotAddSoPath); + connect(u_delSoSearchPath, &QToolButton::clicked, this, &AdvancedGDBSettings::slotDelSoPath); u_addSrcPath->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); u_delSrcPath->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); - connect(u_addSrcPath, SIGNAL(clicked()), this, SLOT(slotAddSrcPath())); - connect(u_delSrcPath, SIGNAL(clicked()), this, SLOT(slotDelSrcPath())); + connect(u_addSrcPath, &QToolButton::clicked, this, &AdvancedGDBSettings::slotAddSrcPath); + connect(u_delSrcPath, &QToolButton::clicked, this, &AdvancedGDBSettings::slotDelSrcPath); - connect(u_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(u_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(u_buttonBox, &QDialogButtonBox::accepted, this, &AdvancedGDBSettings::accept); + connect(u_buttonBox, &QDialogButtonBox::rejected, this, &AdvancedGDBSettings::reject); - connect(u_localRemote, SIGNAL(activated(int)), this, SLOT(slotLocalRemoteChanged())); + connect(u_localRemote, static_cast(&QComboBox::activated), this, &AdvancedGDBSettings::slotLocalRemoteChanged); } AdvancedGDBSettings::~AdvancedGDBSettings() { } const QStringList AdvancedGDBSettings::configs() const { QStringList tmp; tmp << u_gdbCmd->text(); switch(u_localRemote->currentIndex()) { case 1: tmp << QStringLiteral("target remote %1:%2").arg(u_tcpHost->text()).arg(u_tcpPort->text()); tmp << QString(); break; case 2: tmp << QStringLiteral("target remote %1").arg(u_ttyPort->text()); tmp << QStringLiteral("set remotebaud %1").arg(u_baudCombo->currentText()); break; default: tmp << QString(); tmp << QString(); } if (!u_soAbsPrefix->text().isEmpty()) { tmp << QStringLiteral("set solib-absolute-prefix %1").arg(u_soAbsPrefix->text()); } else { tmp << QString(); } if (u_soSearchPaths->count() > 0) { QString paths = QStringLiteral("set solib-search-path "); for (int i=0; icount(); ++i) { if (i!=0) paths += pathSeparator; paths += u_soSearchPaths->item(i)->text(); } tmp << paths; } else { tmp << QString(); } if (u_srcPaths->count() > 0) { QString paths = QStringLiteral("set directories "); for (int i=0; icount(); ++i) { if (i!=0) paths += pathSeparator; paths += u_srcPaths->item(i)->text(); } tmp << paths; } else { tmp << QString(); } tmp << u_customInit->toPlainText().split(QLatin1Char('\n')); return tmp; } void AdvancedGDBSettings::setConfigs(const QStringList &cfgs) { // clear all info u_gdbCmd->setText(QStringLiteral("gdb")); u_localRemote->setCurrentIndex(0); u_soAbsPrefix->clear(); u_soSearchPaths->clear(); u_srcPaths->clear(); u_customInit->clear(); u_tcpHost->setText(QString()); u_tcpPort->setText(QString()); u_ttyPort->setText(QString()); u_baudCombo->setCurrentIndex(0); // GDB if (cfgs.count() <= GDBIndex) return; u_gdbCmd->setText(cfgs[GDBIndex]); // Local / Remote if (cfgs.count() <= LocalRemoteIndex) return; int start; int end; if (cfgs[LocalRemoteIndex].isEmpty()) { u_localRemote->setCurrentIndex(0); u_remoteStack->setCurrentIndex(0); } else if (cfgs[LocalRemoteIndex].contains(pathSeparator)) { u_localRemote->setCurrentIndex(1); u_remoteStack->setCurrentIndex(1); start = cfgs[LocalRemoteIndex].lastIndexOf(QLatin1Char(' ')); end = cfgs[LocalRemoteIndex].indexOf(pathSeparator); u_tcpHost->setText(cfgs[LocalRemoteIndex].mid(start+1, end-start-1)); u_tcpPort->setText(cfgs[LocalRemoteIndex].mid(end+1)); } else { u_localRemote->setCurrentIndex(2); u_remoteStack->setCurrentIndex(2); start = cfgs[LocalRemoteIndex].lastIndexOf(QLatin1Char(' ')); u_ttyPort->setText(cfgs[LocalRemoteIndex].mid(start+1)); start = cfgs[RemoteBaudIndex].lastIndexOf(QLatin1Char(' ')); setComboText(u_baudCombo, cfgs[RemoteBaudIndex].mid(start+1)); } // Solib absolute path if (cfgs.count() <= SoAbsoluteIndex) return; start = 26; // "set solib-absolute-prefix " u_soAbsPrefix->setText(cfgs[SoAbsoluteIndex].mid(start)); // Solib search path if (cfgs.count() <= SoRelativeIndex) return; start = 22; // "set solib-search-path " QString tmp = cfgs[SoRelativeIndex].mid(start); u_soSearchPaths->addItems(tmp.split(pathSeparator)); if (cfgs.count() <= SrcPathsIndex) return; start = 16; // "set directories " tmp = cfgs[SrcPathsIndex].mid(start); u_srcPaths->addItems(tmp.split(pathSeparator)); // Custom init for (int i=CustomStartIndex; iappendPlainText(cfgs[i]); } slotLocalRemoteChanged(); } void AdvancedGDBSettings::slotBrowseGDB() { u_gdbCmd->setText(QFileDialog::getOpenFileName(this, QString(), u_gdbCmd->text(), QStringLiteral("application/x-executable"))); if (u_gdbCmd->text().isEmpty()) { u_gdbCmd->setText(QStringLiteral("gdb")); } } void AdvancedGDBSettings::setComboText(QComboBox *combo, const QString &str) { if (!combo) return; for (int i=0; icount(); i++) { if (combo->itemText(i) == str) { combo->setCurrentIndex(i); return; } } // The string was not found -> add it combo->addItem(str); combo->setCurrentIndex(combo->count()-1); } void AdvancedGDBSettings::slotSetSoPrefix() { QString prefix = QFileDialog::getExistingDirectory(this); if (prefix.isEmpty()) return; u_soAbsPrefix->setText(prefix); } void AdvancedGDBSettings::slotAddSoPath() { QString path = QFileDialog::getExistingDirectory(this); if (path.isEmpty()) return; u_soSearchPaths->addItem(path); } void AdvancedGDBSettings::slotDelSoPath() { QListWidgetItem *item = u_soSearchPaths->takeItem(u_soSearchPaths->currentRow()); delete item; } void AdvancedGDBSettings::slotAddSrcPath() { QString path = QFileDialog::getExistingDirectory(this); if (path.isEmpty()) return; u_srcPaths->addItem(path); } void AdvancedGDBSettings::slotDelSrcPath() { QListWidgetItem *item = u_srcPaths->takeItem(u_srcPaths->currentRow()); delete item; } void AdvancedGDBSettings::slotLocalRemoteChanged() { u_soAbsPrefixLabel->setEnabled(u_localRemote->currentIndex() != 0); u_soSearchLabel->setEnabled(u_localRemote->currentIndex() != 0); u_soAbsPrefix->setEnabled(u_localRemote->currentIndex() != 0); u_soSearchPaths->setEnabled(u_localRemote->currentIndex() != 0); u_setSoPrefix->setEnabled(u_localRemote->currentIndex() != 0); u_addDelSoPaths->setEnabled(u_localRemote->currentIndex() != 0); } diff --git a/addons/gdbplugin/configview.cpp b/addons/gdbplugin/configview.cpp index 6abe744c9..5a318ac87 100644 --- a/addons/gdbplugin/configview.cpp +++ b/addons/gdbplugin/configview.cpp @@ -1,522 +1,522 @@ // // configview.cpp // // Description: View for configuring the set of targets to be used with the debugger // // // Copyright (c) 2010 Ian Wakeling // Copyright (c) 2012 Kåre Särs // // 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 "configview.h" #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 static const QLatin1Char pathSeparator(';'); #else static const QLatin1Char pathSeparator(':'); #endif ConfigView::ConfigView(QWidget* parent, KTextEditor::MainWindow* mainWin) : QWidget(parent), m_mainWindow(mainWin) { m_targetCombo = new QComboBox(); m_targetCombo->setEditable(true); // don't let Qt insert items when the user edits; new targets are only // added when the user explicitly says so m_targetCombo->setInsertPolicy(QComboBox::NoInsert); m_targetCombo->setDuplicatesEnabled(true); m_addTarget = new QToolButton(); m_addTarget->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); m_addTarget->setToolTip(i18n("Add new target")); m_copyTarget = new QToolButton(); m_copyTarget->setIcon(QIcon::fromTheme(QStringLiteral("document-copy"))); m_copyTarget->setToolTip(i18n("Copy target")); m_deleteTarget = new QToolButton(); m_deleteTarget->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); m_deleteTarget->setToolTip(i18n("Delete target")); m_line = new QFrame(this); m_line->setFrameShadow(QFrame::Sunken); m_execLabel = new QLabel(i18n("Executable:")); m_execLabel->setBuddy(m_targetCombo); m_executable = new QLineEdit(); QCompleter* completer1 = new QCompleter(this); completer1->setModel(new QDirModel(QStringList(), QDir::AllDirs|QDir::NoDotAndDotDot, QDir::Name, this)); m_executable->setCompleter(completer1); m_executable->setClearButtonEnabled(true); m_browseExe = new QToolButton(this); m_browseExe->setIcon(QIcon::fromTheme(QStringLiteral("application-x-executable"))); m_workingDirectory = new QLineEdit(); QCompleter* completer2 = new QCompleter(this); completer2->setModel(new QDirModel(completer2)); m_workingDirectory->setCompleter(completer2); m_workingDirectory->setClearButtonEnabled(true); m_workDirLabel = new QLabel(i18n("Working Directory:")); m_workDirLabel->setBuddy(m_workingDirectory); m_browseDir = new QToolButton(this); m_browseDir->setIcon(QIcon::fromTheme(QStringLiteral("inode-directory"))); m_arguments = new QLineEdit(); m_arguments->setClearButtonEnabled(true); m_argumentsLabel = new QLabel(i18nc("Program argument list", "Arguments:")); m_argumentsLabel->setBuddy(m_arguments); m_takeFocus = new QCheckBox(i18nc("Checkbox to for keeping focus on the command line", "Keep focus")); m_takeFocus->setToolTip(i18n("Keep the focus on the command line")); m_redirectTerminal = new QCheckBox(i18n("Redirect IO")); m_redirectTerminal->setToolTip(i18n("Redirect the debugged programs IO to a separate tab")); m_advancedSettings = new QPushButton(i18n("Advanced Settings")); m_checBoxLayout = nullptr; // first false then true to make sure a layout is set m_useBottomLayout = false; resizeEvent(nullptr); m_useBottomLayout = true; resizeEvent(nullptr); m_advanced = new AdvancedGDBSettings(this); m_advanced->hide(); - connect(m_targetCombo, SIGNAL(editTextChanged(QString)), this, SLOT(slotTargetEdited(QString))); - connect(m_targetCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotTargetSelected(int))); - connect(m_addTarget, SIGNAL(clicked()), this, SLOT(slotAddTarget())); - connect(m_copyTarget, SIGNAL(clicked()), this, SLOT(slotCopyTarget())); - connect(m_deleteTarget, SIGNAL(clicked()), this, SLOT(slotDeleteTarget())); - connect(m_browseExe, SIGNAL(clicked()), this, SLOT(slotBrowseExec())); - connect(m_browseDir, SIGNAL(clicked()), this, SLOT(slotBrowseDir())); - connect(m_redirectTerminal, SIGNAL(toggled(bool)), this, SIGNAL(showIO(bool))); - connect(m_advancedSettings, SIGNAL(clicked()), this, SLOT(slotAdvancedClicked())); + connect(m_targetCombo, &QComboBox::editTextChanged, this, &ConfigView::slotTargetEdited); + connect(m_targetCombo, static_cast(&QComboBox::currentIndexChanged), this, &ConfigView::slotTargetSelected); + connect(m_addTarget, &QToolButton::clicked, this, &ConfigView::slotAddTarget); + connect(m_copyTarget, &QToolButton::clicked, this, &ConfigView::slotCopyTarget); + connect(m_deleteTarget, &QToolButton::clicked, this, &ConfigView::slotDeleteTarget); + connect(m_browseExe, &QToolButton::clicked, this, &ConfigView::slotBrowseExec); + connect(m_browseDir, &QToolButton::clicked, this, &ConfigView::slotBrowseDir); + connect(m_redirectTerminal, &QCheckBox::toggled, this, &ConfigView::showIO); + connect(m_advancedSettings, &QPushButton::clicked, this, &ConfigView::slotAdvancedClicked); } ConfigView::~ConfigView() { } void ConfigView::registerActions(KActionCollection* actionCollection) { m_targetSelectAction = actionCollection->add(QStringLiteral("targets")); m_targetSelectAction->setText(i18n("Targets")); - connect(m_targetSelectAction, SIGNAL(triggered(int)), - this, SLOT(slotTargetSelected(int))); + connect(m_targetSelectAction, static_cast(&KSelectAction::triggered), + this, &ConfigView::slotTargetSelected); } void ConfigView::readConfig(const KConfigGroup& group) { m_targetCombo->clear(); int version = group.readEntry(QStringLiteral("version"), 4); int targetCount = group.readEntry(QStringLiteral("targetCount"), 1); int lastTarget = group.readEntry(QStringLiteral("lastTarget"), 0); QString targetKey(QStringLiteral("target_%1")); QStringList targetConfStrs; for (int i = 0; i < targetCount; i++) { targetConfStrs = group.readEntry(targetKey.arg(i), QStringList()); if (targetConfStrs.count() == 0) continue; if ((version == 1) && (targetConfStrs.count() == 3)) { // valid old style config, translate it now; note the // reordering happening here! QStringList temp; temp << targetConfStrs[2]; temp << targetConfStrs[1]; targetConfStrs = temp; } if (version < 4) { targetConfStrs.prepend(targetConfStrs[0].right(15)); } if (targetConfStrs.count() > NameIndex) { m_targetCombo->addItem(targetConfStrs[NameIndex], targetConfStrs); } } if (version < 4) { // all targets now have only one argument string int argListsCount = group.readEntry(QStringLiteral("argsCount"), 0); QString argsKey(QStringLiteral("args_%1")); QString targetName(QStringLiteral("%1<%2>")); QString argStr; int count = m_targetCombo->count(); for (int i = 0; i < argListsCount; i++) { argStr = group.readEntry(argsKey.arg(i), QString()); for (int j=0; jitemData(j).toStringList(); if (i>0) { // copy the firsts and change the arguments targetConfStrs[0] = targetName.arg(targetConfStrs[0]).arg(i+1); if (targetConfStrs.count() > 3) targetConfStrs[3] = argStr; m_targetCombo->addItem(targetConfStrs[0], targetConfStrs); } } } } // make sure there is at least one item. if (m_targetCombo->count() == 0) { slotAddTarget(); } QStringList targetNames; for (int i=0; icount(); i++) { targetNames << m_targetCombo->itemText(i); } m_targetSelectAction->setItems(targetNames); if (lastTarget<0 || lastTarget >= m_targetCombo->count()) lastTarget=0; m_targetCombo->setCurrentIndex(lastTarget); m_takeFocus->setChecked(group.readEntry("alwaysFocusOnInput",false)); m_redirectTerminal->setChecked(group.readEntry("redirectTerminal",false)); } void ConfigView::writeConfig(KConfigGroup& group) { // make sure the data is up to date before writing saveCurrentToIndex(m_currentTarget); group.writeEntry("version", 4); QString targetKey(QStringLiteral("target_%1")); QStringList targetConfStrs; group.writeEntry("targetCount", m_targetCombo->count()); group.writeEntry("lastTarget", m_targetCombo->currentIndex()); for (int i = 0; i < m_targetCombo->count(); i++) { targetConfStrs = m_targetCombo->itemData(i).toStringList(); group.writeEntry(targetKey.arg(i), targetConfStrs); } group.writeEntry("alwaysFocusOnInput", m_takeFocus->isChecked()); group.writeEntry("redirectTerminal", m_redirectTerminal->isChecked()); } const GDBTargetConf ConfigView::currentTarget() const { GDBTargetConf cfg; cfg.executable = m_executable->text(); cfg.workDir = m_workingDirectory->text(); cfg.arguments = m_arguments->text(); cfg.customInit = m_advanced->configs(); // Note: AdvancedGDBSettings::GDBIndex == 0 if ((cfg.customInit.size() >= 0) && !cfg.customInit[0].isEmpty()) { cfg.gdbCmd = cfg.customInit[0]; cfg.customInit.removeFirst(); } else { cfg.gdbCmd = QStringLiteral("gdb"); } // remove empty strings in the customInit int i = cfg.customInit.size()-1; while (i>=0) { if (cfg.customInit[i].isEmpty()) { cfg.customInit.removeAt(i); } else if (cfg.customInit[i].startsWith(QStringLiteral("set directories "))) { QString paths = cfg.customInit[i]; paths.remove(QStringLiteral("set directories ")); cfg.srcPaths = paths.split(pathSeparator, QString::SkipEmptyParts); } i--; } return cfg; } bool ConfigView::takeFocusAlways() const { return m_takeFocus->isChecked(); } bool ConfigView::showIOTab() const { return m_redirectTerminal->isChecked(); } void ConfigView::slotTargetEdited(const QString &newText) { int cursorPosition = m_targetCombo->lineEdit()->cursorPosition(); m_targetCombo->setItemText(m_targetCombo->currentIndex(), newText); m_targetCombo->lineEdit()->setCursorPosition(cursorPosition); // rebuild the target menu QStringList targets; for (int i = 0; i < m_targetCombo->count(); ++i) { targets.append(m_targetCombo->itemText(i)); } m_targetSelectAction->setItems(targets); m_targetSelectAction->setCurrentItem(m_targetCombo->currentIndex()); } void ConfigView::slotTargetSelected(int index) { if ((index < 0) || (index >= m_targetCombo->count())) { return; } if ((m_currentTarget > 0) && (m_currentTarget < m_targetCombo->count())) { saveCurrentToIndex(m_currentTarget); } loadFromIndex(index); m_currentTarget = index; setAdvancedOptions(); // Keep combo box and menu in sync m_targetSelectAction->setCurrentItem(index); } void ConfigView::slotAddTarget() { QStringList targetConfStrs; targetConfStrs << i18n("Target %1", m_targetCombo->count()+1); targetConfStrs << QString(); targetConfStrs << QString(); targetConfStrs << QString(); m_targetCombo->addItem(targetConfStrs[NameIndex], targetConfStrs); m_targetCombo->setCurrentIndex(m_targetCombo->count()-1); } void ConfigView::slotCopyTarget() { QStringList tmp = m_targetCombo->itemData(m_targetCombo->currentIndex()).toStringList(); if (tmp.size() < 1) { slotAddTarget(); return; } tmp[NameIndex] = i18n("Target %1", m_targetCombo->count()+1); m_targetCombo->addItem(tmp[NameIndex], tmp); m_targetCombo->setCurrentIndex(m_targetCombo->count()-1); } void ConfigView::slotDeleteTarget() { m_targetCombo->blockSignals(true); int currentIndex = m_targetCombo->currentIndex(); m_targetCombo->removeItem(currentIndex); if (m_targetCombo->count() == 0) { slotAddTarget(); } loadFromIndex(m_targetCombo->currentIndex()); m_targetCombo->blockSignals(false); } void ConfigView::resizeEvent(QResizeEvent *) { if (m_useBottomLayout && size().height() > size().width()) { // Set layout for the side delete m_checBoxLayout; m_checBoxLayout = nullptr; delete layout(); QGridLayout* layout = new QGridLayout(this); layout->addWidget(m_targetCombo, 0, 0); layout->addWidget(m_addTarget, 0, 1); layout->addWidget(m_copyTarget, 0, 2); layout->addWidget(m_deleteTarget, 0, 3); m_line->setFrameShape(QFrame::HLine); layout->addWidget(m_line, 1, 0, 1, 4); layout->addWidget(m_execLabel, 3, 0, Qt::AlignLeft); layout->addWidget(m_executable, 4, 0, 1, 3); layout->addWidget(m_browseExe, 4, 3); layout->addWidget(m_workDirLabel, 5, 0, Qt::AlignLeft); layout->addWidget(m_workingDirectory, 6, 0, 1, 3); layout->addWidget(m_browseDir, 6, 3); layout->addWidget(m_argumentsLabel, 7, 0, Qt::AlignLeft); layout->addWidget(m_arguments, 8, 0, 1, 4); layout->addWidget(m_takeFocus, 9, 0, 1, 4); layout->addWidget(m_redirectTerminal, 10, 0, 1, 4); layout->addWidget(m_advancedSettings, 11, 0, 1 , 4); layout->addItem(new QSpacerItem(1, 1), 12, 0); layout->setColumnStretch(0, 1); layout->setRowStretch(12, 1); m_useBottomLayout = false; } else if (!m_useBottomLayout && (size().height() < size().width())) { // Set layout for the bottom delete m_checBoxLayout; delete layout(); m_checBoxLayout = new QHBoxLayout(); m_checBoxLayout->addWidget(m_takeFocus, 10); m_checBoxLayout->addWidget(m_redirectTerminal, 10); m_checBoxLayout->addWidget(m_advancedSettings, 0); QGridLayout* layout = new QGridLayout(this); layout->addWidget(m_targetCombo, 0, 0, 1, 3); layout->addWidget(m_addTarget, 1, 0); layout->addWidget(m_copyTarget, 1, 1); layout->addWidget(m_deleteTarget, 1, 2); m_line->setFrameShape(QFrame::VLine); layout->addWidget(m_line, 0, 3, 4, 1); layout->addWidget(m_execLabel, 0, 5, Qt::AlignRight); layout->addWidget(m_executable, 0, 6); layout->addWidget(m_browseExe, 0, 7); layout->addWidget(m_workDirLabel, 1, 5, Qt::AlignRight); layout->addWidget(m_workingDirectory, 1, 6); layout->addWidget(m_browseDir, 1, 7); layout->addWidget(m_argumentsLabel, 2, 5, Qt::AlignRight); layout->addWidget(m_arguments, 2, 6, 1, 2); layout->addLayout(m_checBoxLayout, 3, 5, 1, 3); layout->addItem(new QSpacerItem(1, 1), 4, 0); layout->setColumnStretch(6, 100); layout->setRowStretch(4, 100); m_useBottomLayout = true; } } void ConfigView::setAdvancedOptions() { QStringList tmp = m_targetCombo->itemData(m_targetCombo->currentIndex()).toStringList(); // make sure we have enough strings; while (tmp.count() < CustomStartIndex) tmp << QString(); if (tmp[GDBIndex].isEmpty()) { tmp[GDBIndex] = QStringLiteral("gdb"); } // Remove the strings that are not part of the advanced settings for(int i=0; isetConfigs(tmp); } void ConfigView::slotAdvancedClicked() { setAdvancedOptions(); QStringList newList = m_targetCombo->itemData(m_targetCombo->currentIndex()).toStringList(); // make sure we have enough strings; while (newList.count() < GDBIndex) newList << QString(); // Remove old advanced settings while (newList.count() > GDBIndex) newList.takeLast(); if (m_advanced->exec() == QDialog::Accepted) { // save the new values newList << m_advanced->configs(); m_targetCombo->setItemData(m_targetCombo->currentIndex(), newList); } } void ConfigView::slotBrowseExec() { QString exe = m_executable->text(); if (m_executable->text().isEmpty()) { // try current document dir KTextEditor::View* view = m_mainWindow->activeView(); if (view != nullptr) { exe = view->document()->url().toLocalFile(); } } m_executable->setText(QFileDialog::getOpenFileName((QWidget *)nullptr, QString(), exe, QStringLiteral("application/x-executable"))); } void ConfigView::slotBrowseDir() { QString dir = m_workingDirectory->text(); if (m_workingDirectory->text().isEmpty()) { // try current document dir KTextEditor::View* view = m_mainWindow->activeView(); if (view != nullptr) { dir = view->document()->url().toLocalFile(); } } m_workingDirectory->setText(QFileDialog::getExistingDirectory(this, QString(), dir)); } void ConfigView::saveCurrentToIndex(int index) { if ((index < 0) || (index >= m_targetCombo->count())) { return; } QStringList tmp = m_targetCombo->itemData(index).toStringList(); // make sure we have enough strings. The custom init strings are set in slotAdvancedClicked(). while (tmp.count() < CustomStartIndex) tmp << QString(); tmp[NameIndex] = m_targetCombo->itemText(index); tmp[ExecIndex] = m_executable->text(); tmp[WorkDirIndex] = m_workingDirectory->text(); tmp[ArgsIndex] = m_arguments->text(); m_targetCombo->setItemData(index, tmp); } void ConfigView::loadFromIndex(int index) { if ((index < 0) || (index >= m_targetCombo->count())) { return; } QStringList tmp = m_targetCombo->itemData(index).toStringList(); // make sure we have enough strings. The custom init strings are set in slotAdvancedClicked(). while (tmp.count() < CustomStartIndex) tmp << QString(); m_executable->setText(tmp[ExecIndex]); m_workingDirectory->setText(tmp[WorkDirIndex]); m_arguments->setText(tmp[ArgsIndex]); } diff --git a/addons/gdbplugin/debugview.cpp b/addons/gdbplugin/debugview.cpp index eebe2bc2a..e8b21e287 100644 --- a/addons/gdbplugin/debugview.cpp +++ b/addons/gdbplugin/debugview.cpp @@ -1,696 +1,696 @@ // // debugview.cpp // // Description: Manages the interaction with GDB // // // Copyright (c) 2008-2010 Ian Wakeling // Copyright (c) 2011 Kåre Särs // // 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 "debugview.h" #include #include #include #include #include #include #include #include static const QString PromptStr = QStringLiteral("(prompt)"); DebugView::DebugView(QObject* parent) : QObject(parent), m_debugProcess(nullptr), m_state(none), m_subState(normal), m_debugLocationChanged(true), m_queryLocals(false) { } DebugView::~DebugView() { if ( m_debugProcess.state() != QProcess::NotRunning) { m_debugProcess.kill(); m_debugProcess.blockSignals(true); m_debugProcess.waitForFinished(); } } void DebugView::runDebugger(const GDBTargetConf &conf, const QStringList &ioFifos) { if (conf.executable.isEmpty()) { return; } m_targetConf = conf; if (ioFifos.size() == 3) { m_ioPipeString = QStringLiteral("< %1 1> %2 2> %3") .arg(ioFifos[0]) .arg(ioFifos[1]) .arg(ioFifos[2]); } if (m_state == none) { m_outBuffer.clear(); m_errBuffer.clear(); m_errorList.clear(); //create a process to control GDB m_debugProcess.setWorkingDirectory(m_targetConf.workDir); - connect(&m_debugProcess, SIGNAL(error(QProcess::ProcessError)), - this, SLOT(slotError())); + connect(&m_debugProcess, static_cast(&QProcess::error), + this, &DebugView::slotError); - connect(&m_debugProcess, SIGNAL(readyReadStandardError()), - this, SLOT(slotReadDebugStdErr())); + connect(&m_debugProcess, &QProcess::readyReadStandardError, + this, &DebugView::slotReadDebugStdErr); - connect(&m_debugProcess, SIGNAL(readyReadStandardOutput()), - this, SLOT(slotReadDebugStdOut())); + connect(&m_debugProcess, &QProcess::readyReadStandardOutput, + this, &DebugView::slotReadDebugStdOut); - connect(&m_debugProcess, SIGNAL(finished(int,QProcess::ExitStatus)), - this, SLOT(slotDebugFinished(int,QProcess::ExitStatus))); + connect(&m_debugProcess, static_cast(&QProcess::finished), + this, &DebugView::slotDebugFinished); m_debugProcess.start(m_targetConf.gdbCmd); m_nextCommands << QStringLiteral("set pagination off"); m_state = ready; } else { // On startup the gdb prompt will trigger the "nextCommands", // here we have to trigger it manually. QTimer::singleShot(0, this, SLOT(issueNextCommand())); } m_nextCommands << QStringLiteral("file %1").arg(m_targetConf.executable); m_nextCommands << QStringLiteral("set args %1 %2").arg(m_targetConf.arguments).arg(m_ioPipeString); m_nextCommands << QStringLiteral("set inferior-tty /dev/null"); m_nextCommands << m_targetConf.customInit; m_nextCommands << QStringLiteral("(Q) info breakpoints"); } bool DebugView::debuggerRunning() const { return(m_state != none); } bool DebugView::debuggerBusy() const { return(m_state == executingCmd); } bool DebugView::hasBreakpoint(const QUrl& url, int line) { for (int i = 0; i")) { m_outBuffer.clear(); processLine(PromptStr); } } void DebugView::slotReadDebugStdErr() { m_errBuffer += QString::fromLocal8Bit(m_debugProcess.readAllStandardError().data()); int end=0; // add whole lines at a time to the error list do { end = m_errBuffer.indexOf(QLatin1Char('\n')); if (end < 0) break; m_errorList << m_errBuffer.mid(0, end); m_errBuffer.remove(0,end+1); } while (1); processErrors(); } void DebugView::slotDebugFinished(int /*exitCode*/, QProcess::ExitStatus status) { if(status != QProcess::NormalExit) { emit outputText(i18n("*** gdb exited normally ***") + QLatin1Char('\n')); } m_state = none; emit readyForInput(false); // remove all old breakpoints BreakPoint bPoint; while (m_breakPointList.size() > 0) { bPoint = m_breakPointList.takeFirst(); emit breakPointCleared(bPoint.file, bPoint.line -1); } emit gdbEnded(); } void DebugView::movePC(QUrl const& url, int line) { if(m_state == ready) { QString cmd = QStringLiteral("tbreak %1:%2").arg(url.path()).arg(line); m_nextCommands << QStringLiteral("jump %1:%2").arg(url.path()).arg(line); issueCommand(cmd); } } void DebugView::runToCursor(QUrl const& url, int line) { if(m_state == ready) { QString cmd = QStringLiteral("tbreak %1:%2").arg(url.path()).arg(line); m_nextCommands << QStringLiteral("continue"); issueCommand(cmd); } } void DebugView::slotInterrupt() { if (m_state == executingCmd) { m_debugLocationChanged = true; } int pid = m_debugProcess.pid(); if (pid != 0) { ::kill(pid, SIGINT); } } void DebugView::slotKill() { if(m_state != ready) { slotInterrupt(); m_state = ready; } issueCommand(QStringLiteral("kill")); } void DebugView::slotReRun() { slotKill(); m_nextCommands << QStringLiteral("file %1").arg(m_targetConf.executable); m_nextCommands << QStringLiteral("set args %1 %2").arg(m_targetConf.arguments).arg(m_ioPipeString); m_nextCommands << QStringLiteral("set inferior-tty /dev/null"); m_nextCommands << m_targetConf.customInit; m_nextCommands << QStringLiteral("(Q) info breakpoints"); m_nextCommands << QStringLiteral("tbreak main"); m_nextCommands << QStringLiteral("run"); m_nextCommands << QStringLiteral("p setvbuf(stdout, 0, %1, 1024)").arg(_IOLBF); m_nextCommands << QStringLiteral("continue"); } void DebugView::slotStepInto() { issueCommand(QStringLiteral("step")); } void DebugView::slotStepOver() { issueCommand(QStringLiteral("next")); } void DebugView::slotStepOut() { issueCommand(QStringLiteral("finish")); } void DebugView::slotContinue() { issueCommand(QStringLiteral("continue")); } static QRegExp breakpointList(QStringLiteral("Num\\s+Type\\s+Disp\\s+Enb\\s+Address\\s+What.*")); static QRegExp breakpointListed(QStringLiteral("(\\d)\\s+breakpoint\\s+keep\\sy\\s+0x[\\da-f]+\\sin\\s.+\\sat\\s([^:]+):(\\d+).*")); static QRegExp stackFrameAny(QStringLiteral("#(\\d+)\\s(.*)")); static QRegExp stackFrameFile(QStringLiteral("#(\\d+)\\s+(?:0x[\\da-f]+\\s*in\\s)*(\\S+)(\\s\\(.*\\)) at ([^:]+):(\\d+).*")); static QRegExp changeFile(QStringLiteral("(?:(?:Temporary\\sbreakpoint|Breakpoint)\\s*\\d+,\\s*|0x[\\da-f]+\\s*in\\s*)?[^\\s]+\\s*\\([^)]*\\)\\s*at\\s*([^:]+):(\\d+).*")); static QRegExp changeLine(QStringLiteral("(\\d+)\\s+.*")); static QRegExp breakPointReg(QStringLiteral("Breakpoint\\s+(\\d+)\\s+at\\s+0x[\\da-f]+:\\s+file\\s+([^\\,]+)\\,\\s+line\\s+(\\d+).*")); static QRegExp breakPointMultiReg(QStringLiteral("Breakpoint\\s+(\\d+)\\s+at\\s+0x[\\da-f]+:\\s+([^\\,]+):(\\d+).*")); static QRegExp breakPointDel(QStringLiteral("Deleted\\s+breakpoint.*")); static QRegExp exitProgram(QStringLiteral("(?:Program|.*Inferior.*)\\s+exited.*")); static QRegExp threadLine(QStringLiteral("\\**\\s+(\\d+)\\s+Thread.*")); void DebugView::processLine(QString line) { if (line.isEmpty()) return; switch(m_state) { case none: case ready: if(PromptStr == line) { // we get here after initialization QTimer::singleShot(0, this, SLOT(issueNextCommand())); } break; case executingCmd: if(breakpointList.exactMatch(line)) { m_state = listingBreakpoints; emit clearBreakpointMarks(); m_breakPointList.clear(); } else if (line.contains(QStringLiteral("No breakpoints or watchpoints."))) { emit clearBreakpointMarks(); m_breakPointList.clear(); } else if (stackFrameAny.exactMatch(line)) { if (m_lastCommand.contains(QStringLiteral("info stack"))) { emit stackFrameInfo(stackFrameAny.cap(1), stackFrameAny.cap(2)); } else { m_subState = (m_subState == normal) ? stackFrameSeen : stackTraceSeen; m_newFrameLevel = stackFrameAny.cap(1).toInt(); if (stackFrameFile.exactMatch(line)) { m_newFrameFile = stackFrameFile.cap(4); } } } else if(changeFile.exactMatch(line)) { m_currentFile = changeFile.cap(1).trimmed(); int lineNum = changeFile.cap(2).toInt(); if (!m_nextCommands.contains(QStringLiteral("continue"))) { // GDB uses 1 based line numbers, kate uses 0 based... emit debugLocationChanged(resolveFileName(m_currentFile), lineNum - 1); } m_debugLocationChanged = true; } else if(changeLine.exactMatch(line)) { int lineNum = changeLine.cap(1).toInt(); if(m_subState == stackFrameSeen) { m_currentFile = m_newFrameFile; } if (!m_nextCommands.contains(QStringLiteral("continue"))) { // GDB uses 1 based line numbers, kate uses 0 based... emit debugLocationChanged(resolveFileName(m_currentFile), lineNum - 1); } m_debugLocationChanged = true; } else if (breakPointReg.exactMatch(line)) { BreakPoint breakPoint; breakPoint.number = breakPointReg.cap(1).toInt(); breakPoint.file = resolveFileName(breakPointReg.cap(2)); breakPoint.line = breakPointReg.cap(3).toInt(); m_breakPointList << breakPoint; emit breakPointSet(breakPoint.file, breakPoint.line -1); } else if (breakPointMultiReg.exactMatch(line)) { BreakPoint breakPoint; breakPoint.number = breakPointMultiReg.cap(1).toInt(); breakPoint.file = resolveFileName(breakPointMultiReg.cap(2)); breakPoint.line = breakPointMultiReg.cap(3).toInt(); m_breakPointList << breakPoint; emit breakPointSet(breakPoint.file, breakPoint.line -1); } else if (breakPointDel.exactMatch(line)) { line.remove(QStringLiteral("Deleted breakpoint")); line.remove(QLatin1Char('s')); // in case of multiple breakpoints QStringList numbers = line.split(QLatin1Char(' '), QString::SkipEmptyParts); for (int i=0; i 0) && !m_nextCommands[0].contains(QStringLiteral("file"))) { m_nextCommands.clear(); } m_debugLocationChanged = false; // do not insert (Q) commands emit programEnded(); } else if(PromptStr == line) { if(m_subState == stackFrameSeen) { emit stackFrameChanged(m_newFrameLevel); } m_state = ready; // Give the error a possibility get noticed since stderr and stdout are not in sync QTimer::singleShot(0, this, SLOT(issueNextCommand())); } break; case listingBreakpoints: if (breakpointListed.exactMatch(line)) { BreakPoint breakPoint; breakPoint.number = breakpointListed.cap(1).toInt(); breakPoint.file = resolveFileName(breakpointListed.cap(2)); breakPoint.line = breakpointListed.cap(3).toInt(); m_breakPointList << breakPoint; emit breakPointSet(breakPoint.file, breakPoint.line -1); } else if(PromptStr == line) { m_state = ready; QTimer::singleShot(0, this, SLOT(issueNextCommand())); } break; case infoArgs: if(PromptStr == line) { m_state = ready; QTimer::singleShot(0, this, SLOT(issueNextCommand())); } else { emit infoLocal(line); } break; case printThis: if(PromptStr == line) { m_state = ready; QTimer::singleShot(0, this, SLOT(issueNextCommand())); } else { emit infoLocal(line); } break; case infoLocals: if(PromptStr == line) { m_state = ready; emit infoLocal(QString()); QTimer::singleShot(0, this, SLOT(issueNextCommand())); } else { emit infoLocal(line); } break; case infoStack: if(PromptStr == line) { m_state = ready; emit stackFrameInfo(QString(), QString()); QTimer::singleShot(0, this, SLOT(issueNextCommand())); } else if (stackFrameAny.exactMatch(line)) { emit stackFrameInfo(stackFrameAny.cap(1), stackFrameAny.cap(2)); } break; case infoThreads: if(PromptStr == line) { m_state = ready; QTimer::singleShot(0, this, SLOT(issueNextCommand())); } else if (threadLine.exactMatch(line)) { emit threadInfo(threadLine.cap(1).toInt(), (line[0] == QLatin1Char('*'))); } break; } outputTextMaybe(line); } void DebugView::processErrors() { QString error; while (m_errorList.size() > 0) { error = m_errorList.takeFirst(); //qDebug() << error; if(error == QLatin1String("The program is not being run.")) { if (m_lastCommand == QLatin1String("continue")) { m_nextCommands.clear(); m_nextCommands << QStringLiteral("tbreak main"); m_nextCommands << QStringLiteral("run"); m_nextCommands << QStringLiteral("p setvbuf(stdout, 0, %1, 1024)").arg(_IOLBF); m_nextCommands << QStringLiteral("continue"); QTimer::singleShot(0, this, SLOT(issueNextCommand())); } else if ((m_lastCommand == QLatin1String("step")) || (m_lastCommand == QLatin1String("next")) || (m_lastCommand == QLatin1String("finish"))) { m_nextCommands.clear(); m_nextCommands << QStringLiteral("tbreak main"); m_nextCommands << QStringLiteral("run"); m_nextCommands << QStringLiteral("p setvbuf(stdout, 0, %1, 1024)").arg(_IOLBF); QTimer::singleShot(0, this, SLOT(issueNextCommand())); } else if ((m_lastCommand == QLatin1String("kill"))) { if (m_nextCommands.size() > 0) { if (!m_nextCommands[0].contains(QStringLiteral("file"))) { m_nextCommands.clear(); m_nextCommands << QStringLiteral("quit"); } // else continue with "ReRun" } else { m_nextCommands << QStringLiteral("quit"); } m_state = ready; QTimer::singleShot(0, this, SLOT(issueNextCommand())); } // else do nothing } else if (error.contains(QStringLiteral("No line ")) || error.contains(QStringLiteral("No source file named"))) { // setting a breakpoint failed. Do not continue. m_nextCommands.clear(); emit readyForInput(true); } else if (error.contains(QStringLiteral("No stack"))) { m_nextCommands.clear(); emit programEnded(); } if ((m_lastCommand == QLatin1String("(Q)print *this")) && error.contains(QStringLiteral("No symbol \"this\" in current context."))) { continue; } emit outputError(error + QLatin1Char('\n')); } } void DebugView::issueCommand(QString const& cmd) { if(m_state == ready) { emit readyForInput(false); m_state = executingCmd; if (cmd == QLatin1String("(Q)info locals")) { m_state = infoLocals; } else if (cmd == QLatin1String("(Q)info args")) { m_state = infoArgs; } else if (cmd == QLatin1String("(Q)print *this")) { m_state = printThis; } else if (cmd == QLatin1String("(Q)info stack")) { m_state = infoStack; } else if (cmd == QLatin1String("(Q)info thread")) { emit threadInfo(-1 , false); m_state = infoThreads; } m_subState = normal; m_lastCommand = cmd; if (cmd.startsWith(QStringLiteral("(Q)"))) { m_debugProcess.write(qPrintable(cmd.mid(3))); } else { emit outputText(QStringLiteral("(gdb) ") + cmd + QLatin1Char('\n')); m_debugProcess.write(qPrintable(cmd)); } m_debugProcess.write("\n"); } } void DebugView::issueNextCommand() { if(m_state == ready) { if(m_nextCommands.size() > 0) { QString cmd = m_nextCommands.takeFirst(); //qDebug() << "Next command" << cmd; issueCommand(cmd); } else { // FIXME "thread" needs a better generic solution if (m_debugLocationChanged || m_lastCommand.startsWith(QStringLiteral("thread"))) { m_debugLocationChanged = false; if (m_queryLocals && !m_lastCommand.startsWith(QStringLiteral("(Q)"))) { m_nextCommands << QStringLiteral("(Q)info stack"); m_nextCommands << QStringLiteral("(Q)frame"); m_nextCommands << QStringLiteral("(Q)info args"); m_nextCommands << QStringLiteral("(Q)print *this"); m_nextCommands << QStringLiteral("(Q)info locals"); m_nextCommands << QStringLiteral("(Q)info thread"); issueNextCommand(); return; } } emit readyForInput(true); } } } QUrl DebugView::resolveFileName(const QString &fileName) { QUrl url; QFileInfo fInfo = QFileInfo(fileName); //did we end up with an absolute path or a relative one? if (fInfo.exists()) { return QUrl::fromUserInput(fInfo.absoluteFilePath()); } if (fInfo.isAbsolute()) { // we can not do anything just return the fileName return QUrl::fromUserInput(fileName); } // Now try to add the working path fInfo = QFileInfo(m_targetConf.workDir + fileName); if (fInfo.exists()) { return QUrl::fromUserInput(fInfo.absoluteFilePath()); } // now try the executable path fInfo = QFileInfo(QFileInfo(m_targetConf.executable).absolutePath() + fileName); if (fInfo.exists()) { return QUrl::fromUserInput(fInfo.absoluteFilePath()); } foreach (QString srcPath, m_targetConf.srcPaths) { fInfo = QFileInfo(srcPath + QDir::separator() + fileName); if (fInfo.exists()) { return QUrl::fromUserInput(fInfo.absoluteFilePath()); } } // we can not do anything just return the fileName return QUrl::fromUserInput(fileName); } void DebugView::outputTextMaybe(const QString &text) { if (!m_lastCommand.startsWith(QStringLiteral("(Q)")) && !text.contains(PromptStr)) { emit outputText(text + QLatin1Char('\n')); } } void DebugView::slotQueryLocals(bool query) { m_queryLocals = query; if (query && (m_state == ready) && (m_nextCommands.size() == 0)) { m_nextCommands << QStringLiteral("(Q)info stack"); m_nextCommands << QStringLiteral("(Q)frame"); m_nextCommands << QStringLiteral("(Q)info args"); m_nextCommands << QStringLiteral("(Q)print *this"); m_nextCommands << QStringLiteral("(Q)info locals"); m_nextCommands << QStringLiteral("(Q)info thread"); issueNextCommand(); } } diff --git a/addons/gdbplugin/ioview.cpp b/addons/gdbplugin/ioview.cpp index 089a7a974..27a20669d 100644 --- a/addons/gdbplugin/ioview.cpp +++ b/addons/gdbplugin/ioview.cpp @@ -1,219 +1,219 @@ // // configview.cpp // // Description: View for configuring the set of targets to be used with the debugger // // // Copyright (c) 2010 Kåre Särs // // 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 "ioview.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include IOView::IOView(QWidget *parent) : QWidget(parent) { m_output = new QTextEdit(); m_output->setReadOnly(true); m_output->setUndoRedoEnabled(false); m_output->setAcceptRichText(false); // fixed wide font, like konsole m_output->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); // alternate color scheme, like konsole KColorScheme schemeView(QPalette::Active, KColorScheme::View); m_output->setTextBackgroundColor(schemeView.foreground().color()); m_output->setTextColor(schemeView.background().color()); QPalette p = m_output->palette (); p.setColor(QPalette::Base, schemeView.foreground().color()); m_output->setPalette(p); m_input = new QLineEdit(); m_output->setFocusProxy(m_input); // take the focus from the output QVBoxLayout *layout = new QVBoxLayout(this); layout->addWidget(m_output, 10); layout->addWidget(m_input, 0); layout->setContentsMargins(0,0,0,0); layout->setSpacing(0); - connect(m_input, SIGNAL(returnPressed()), this, SLOT(returnPressed())); + connect(m_input, &QLineEdit::returnPressed, this, &IOView::returnPressed); createFifos(); } IOView::~IOView() { m_stdin.close(); m_stdout.close(); m_stdout.setFileName(m_stdoutFifo); ::close(m_stdoutFD); m_stderr.close(); m_stderr.setFileName(m_stderrFifo); ::close(m_stderrFD); m_stdin.remove(); m_stdout.remove(); m_stderr.remove(); } void IOView::createFifos() { m_stdinFifo = createFifo(QStringLiteral("stdInFifo")); m_stdoutFifo = createFifo(QStringLiteral("stdOutFifo")); m_stderrFifo = createFifo(QStringLiteral("stdErrFifo")); m_stdin.setFileName(m_stdinFifo); if (!m_stdin.open(QIODevice::ReadWrite)) return; m_stdoutD.setFileName(m_stdoutFifo); m_stdoutD.open(QIODevice::ReadWrite); m_stdout.setFileName(m_stdoutFifo); m_stdoutFD = ::open(m_stdoutFifo.toLocal8Bit().data(), O_RDWR|O_NONBLOCK); if (m_stdoutFD == -1) return; if (!m_stdout.open(m_stdoutFD, QIODevice::ReadWrite)) return; m_stdoutNotifier = new QSocketNotifier(m_stdoutFD, QSocketNotifier::Read, this); - connect(m_stdoutNotifier, SIGNAL(activated(int)), this, SLOT(readOutput())); + connect(m_stdoutNotifier, &QSocketNotifier::activated, this, &IOView::readOutput); m_stdoutNotifier->setEnabled(true); m_stderrD.setFileName(m_stderrFifo); m_stderrD.open(QIODevice::ReadWrite); m_stderr.setFileName(m_stderrFifo); m_stderrFD = ::open(m_stderrFifo.toLocal8Bit().data(), O_RDONLY|O_NONBLOCK); if (m_stderrFD == -1) return; if (!m_stderr.open(m_stderrFD, QIODevice::ReadOnly)) return; m_stderrNotifier = new QSocketNotifier(m_stderrFD, QSocketNotifier::Read, this); - connect(m_stderrNotifier, SIGNAL(activated(int)), this, SLOT(readErrors())); + connect(m_stderrNotifier, &QSocketNotifier::activated, this, &IOView::readErrors); m_stderrNotifier->setEnabled(true); return; } void IOView::returnPressed() { m_stdin.write(m_input->text().toLocal8Bit()); m_stdin.write("\n"); m_stdin.flush(); m_input->clear(); } void IOView::readOutput() { m_stdoutNotifier->setEnabled(false); qint64 res; char chData[256]; QByteArray data; do { res = m_stdout.read(chData, 255); if (res <= 0) { m_stdoutD.flush(); } else { data.append(chData, res); } } while (res == 255); if (data.size() > 0) { emit stdOutText(QString::fromLocal8Bit(data)); } m_stdoutNotifier->setEnabled(true); } void IOView::readErrors() { m_stderrNotifier->setEnabled(false); qint64 res; char chData[256]; QByteArray data; do { res = m_stderr.read(chData, 255); if (res <= 0) { m_stderrD.flush(); } else { data.append(chData, res); } } while (res == 255); if (data.size() > 0) { emit stdErrText(QString::fromLocal8Bit(data)); } m_stderrNotifier->setEnabled(true); } void IOView::addStdOutText(const QString &text) { QScrollBar *scrollb = m_output->verticalScrollBar(); if (!scrollb) return; bool atEnd = (scrollb->value() == scrollb->maximum()); QTextCursor cursor = m_output->textCursor(); if (!cursor.atEnd()) cursor.movePosition(QTextCursor::End); cursor.insertText(text); if (atEnd) { scrollb->setValue(scrollb->maximum()); } } void IOView::addStdErrText(const QString &text) { m_output->setFontItalic(true); addStdOutText(text); m_output->setFontItalic(false); } QString IOView::createFifo(const QString &prefix) { QString fifo = QStandardPaths::writableLocation(QStandardPaths::TempLocation) + QDir::separator() + prefix + KRandom::randomString(3); int result = mkfifo(QFile::encodeName(fifo).data(), 0666); if (result != 0) return QString(); return fifo; } const QString IOView::stdinFifo() { return m_stdinFifo; } const QString IOView::stdoutFifo() { return m_stdoutFifo; } const QString IOView::stderrFifo() { return m_stderrFifo; } void IOView::enableInput(bool enable) { m_input->setEnabled(enable); } void IOView::clearOutput() { m_output->clear(); } diff --git a/addons/gdbplugin/plugin_kategdb.cpp b/addons/gdbplugin/plugin_kategdb.cpp index 2546098d4..0c2dda785 100644 --- a/addons/gdbplugin/plugin_kategdb.cpp +++ b/addons/gdbplugin/plugin_kategdb.cpp @@ -1,775 +1,747 @@ // // Description: Kate Plugin for GDB integration // // // Copyright (c) 2010 Ian Wakeling // Copyright (c) 2010-2014 Kåre Särs // // 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 "plugin_kategdb.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 K_PLUGIN_FACTORY_WITH_JSON (KatePluginGDBFactory, "kategdbplugin.json", registerPlugin();) KatePluginGDB::KatePluginGDB(QObject* parent, const VariantList&) : KTextEditor::Plugin(parent) { // FIXME KF5 KGlobal::locale()->insertCatalog("kategdbplugin"); } KatePluginGDB::~KatePluginGDB() { } QObject* KatePluginGDB::createView(KTextEditor::MainWindow* mainWindow) { return new KatePluginGDBView(this, mainWindow); } KatePluginGDBView::KatePluginGDBView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWin) : QObject(mainWin), m_mainWin(mainWin) { m_lastExecUrl = QUrl(); m_lastExecLine = -1; m_lastExecFrame = 0; m_kateApplication = KTextEditor::Editor::instance()->application(); m_focusOnInput = true; m_activeThread = -1; KXMLGUIClient::setComponentName (QLatin1String("kategdb"), i18n ("Kate GDB")); setXMLFile(QLatin1String("ui.rc")); m_toolView = m_mainWin->createToolView(plugin, i18n("Debug View"), KTextEditor::MainWindow::Bottom, QIcon(QStringLiteral(":/kategdb/22-actions-debug-kategdb.png")), i18n("Debug View")); m_localsStackToolView = m_mainWin->createToolView(plugin, i18n("Locals and Stack"), KTextEditor::MainWindow::Right, QIcon(QStringLiteral(":/kategdb/22-actions-debug-kategdb.png")), i18n("Locals and Stack")); m_tabWidget = new QTabWidget(m_toolView); // Output m_outputArea = new QTextEdit(); m_outputArea->setAcceptRichText(false ); m_outputArea->setReadOnly(true); m_outputArea->setUndoRedoEnabled(false); // fixed wide font, like konsole m_outputArea->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); // alternate color scheme, like konsole KColorScheme schemeView(QPalette::Active, KColorScheme::View); m_outputArea->setTextBackgroundColor(schemeView.foreground().color()); m_outputArea->setTextColor(schemeView.background().color()); QPalette p = m_outputArea->palette (); p.setColor(QPalette::Base, schemeView.foreground().color()); m_outputArea->setPalette(p); // input m_inputArea = new KHistoryComboBox(true); - connect(m_inputArea, SIGNAL(returnPressed()), this, SLOT(slotSendCommand())); + connect(m_inputArea, static_cast(&KHistoryComboBox::returnPressed), this, &KatePluginGDBView::slotSendCommand); QHBoxLayout *inputLayout = new QHBoxLayout(); inputLayout->addWidget(m_inputArea, 10); inputLayout->setContentsMargins(0,0,0,0); m_outputArea->setFocusProxy(m_inputArea); // take the focus from the outputArea m_gdbPage = new QWidget(); QVBoxLayout *layout = new QVBoxLayout(m_gdbPage); layout->addWidget(m_outputArea); layout->addLayout(inputLayout); layout->setStretch(0, 10); layout->setContentsMargins(0,0,0,0); layout->setSpacing(0); // stack page QWidget *stackContainer = new QWidget(); QVBoxLayout *stackLayout = new QVBoxLayout(stackContainer); m_threadCombo = new QComboBox(); m_stackTree = new QTreeWidget(); stackLayout->addWidget(m_threadCombo); stackLayout->addWidget(m_stackTree); stackLayout->setStretch(0, 10); stackLayout->setContentsMargins(0,0,0,0); stackLayout->setSpacing(0); QStringList headers; headers << QStringLiteral(" ") << i18nc("Column label (frame number)", "Nr") << i18nc("Column label", "Frame"); m_stackTree->setHeaderLabels(headers); m_stackTree->setRootIsDecorated(false); m_stackTree->resizeColumnToContents(0); m_stackTree->resizeColumnToContents(1); m_stackTree->setAutoScroll(false); - connect(m_stackTree, SIGNAL(itemActivated(QTreeWidgetItem*,int)), - this, SLOT(stackFrameSelected())); + connect(m_stackTree, &QTreeWidget::itemActivated, this, &KatePluginGDBView::stackFrameSelected); - connect(m_threadCombo, SIGNAL(currentIndexChanged(int)), - this, SLOT(threadSelected(int))); + connect(m_threadCombo, static_cast(&QComboBox::currentIndexChanged), this, &KatePluginGDBView::threadSelected); m_localsView = new LocalsView(); QSplitter *locStackSplitter = new QSplitter(m_localsStackToolView); locStackSplitter->addWidget(m_localsView); locStackSplitter->addWidget(stackContainer); locStackSplitter->setOrientation(Qt::Vertical); // config page m_configView = new ConfigView(nullptr, mainWin); m_ioView = new IOView(); - connect(m_configView, SIGNAL(showIO(bool)), - this, SLOT(showIO(bool))); + connect(m_configView, &ConfigView::showIO, this, &KatePluginGDBView::showIO); m_tabWidget->addTab(m_gdbPage, i18nc("Tab label", "GDB Output")); m_tabWidget->addTab(m_configView, i18nc("Tab label", "Settings")); m_debugView = new DebugView(this); - connect(m_debugView, SIGNAL(readyForInput(bool)), - this, SLOT(enableDebugActions(bool))); + connect(m_debugView, &DebugView::readyForInput, this, &KatePluginGDBView::enableDebugActions); - connect(m_debugView, SIGNAL(outputText(QString)), - this, SLOT(addOutputText(QString))); + connect(m_debugView, &DebugView::outputText, this, &KatePluginGDBView::addOutputText); - connect(m_debugView, SIGNAL(outputError(QString)), - this, SLOT(addErrorText(QString))); + connect(m_debugView, &DebugView::outputError, this, &KatePluginGDBView::addErrorText); - connect(m_debugView, SIGNAL(debugLocationChanged(QUrl,int)), - this, SLOT(slotGoTo(QUrl,int))); + connect(m_debugView, &DebugView::debugLocationChanged, this, &KatePluginGDBView::slotGoTo); - connect(m_debugView, SIGNAL(breakPointSet(QUrl,int)), - this, SLOT(slotBreakpointSet(QUrl,int))); + connect(m_debugView, &DebugView::breakPointSet, this, &KatePluginGDBView::slotBreakpointSet); - connect(m_debugView, SIGNAL(breakPointCleared(QUrl,int)), - this, SLOT(slotBreakpointCleared(QUrl,int))); + connect(m_debugView, &DebugView::breakPointCleared, this, &KatePluginGDBView::slotBreakpointCleared); - connect(m_debugView, SIGNAL(clearBreakpointMarks()), - this, SLOT(clearMarks())); + connect(m_debugView, &DebugView::clearBreakpointMarks, this, &KatePluginGDBView::clearMarks); - connect(m_debugView, SIGNAL(programEnded()), - this, SLOT(programEnded())); + connect(m_debugView, &DebugView::programEnded, this, &KatePluginGDBView::programEnded); - connect(m_debugView, SIGNAL(gdbEnded()), - this, SLOT(programEnded())); + connect(m_debugView, &DebugView::gdbEnded, this, &KatePluginGDBView::programEnded); - connect(m_debugView, SIGNAL(gdbEnded()), - this, SLOT(gdbEnded())); + connect(m_debugView, &DebugView::gdbEnded, this, &KatePluginGDBView::gdbEnded); - connect(m_debugView, SIGNAL(stackFrameInfo(QString,QString)), - this, SLOT(insertStackFrame(QString,QString))); + connect(m_debugView, &DebugView::stackFrameInfo, this, &KatePluginGDBView::insertStackFrame); - connect(m_debugView, SIGNAL(stackFrameChanged(int)), - this, SLOT(stackFrameChanged(int))); + connect(m_debugView, &DebugView::stackFrameChanged, this, &KatePluginGDBView::stackFrameChanged); - connect(m_debugView, SIGNAL(infoLocal(QString)), - m_localsView, SLOT(addLocal(QString))); + connect(m_debugView, &DebugView::infoLocal, m_localsView, &LocalsView::addLocal); - connect(m_debugView, SIGNAL(threadInfo(int,bool)), - this, SLOT(insertThread(int,bool))); + connect(m_debugView, &DebugView::threadInfo, this, &KatePluginGDBView::insertThread); - connect(m_localsView, SIGNAL(localsVisible(bool)), - m_debugView, SLOT(slotQueryLocals(bool))); + connect(m_localsView, &LocalsView::localsVisible, m_debugView, &DebugView::slotQueryLocals); // Actions m_configView->registerActions(actionCollection()); QAction* a = actionCollection()->addAction(QStringLiteral("debug")); a->setText(i18n("Start Debugging")); a->setIcon(QIcon(QStringLiteral(":/kategdb/22-actions-debug-kategdb.png"))); - connect( a, SIGNAL(triggered(bool)), - this, SLOT(slotDebug())); + connect(a, &QAction::triggered, this, &KatePluginGDBView::slotDebug); a = actionCollection()->addAction(QStringLiteral("kill")); a->setText(i18n("Kill / Stop Debugging")); a->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop"))); - connect( a, SIGNAL(triggered(bool)), - m_debugView, SLOT(slotKill())); + connect(a, &QAction::triggered, m_debugView, &DebugView::slotKill); a = actionCollection()->addAction(QStringLiteral("rerun")); a->setText(i18n("Restart Debugging")); a->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); - connect( a, SIGNAL(triggered(bool)), - this, SLOT(slotRestart())); + connect(a, &QAction::triggered,this, &KatePluginGDBView::slotRestart); a = actionCollection()->addAction(QStringLiteral("toggle_breakpoint")); a->setText(i18n("Toggle Breakpoint / Break")); a->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause"))); - connect( a, SIGNAL(triggered(bool)), - this, SLOT(slotToggleBreakpoint())); + connect(a, &QAction::triggered,this, &KatePluginGDBView::slotToggleBreakpoint); a = actionCollection()->addAction(QStringLiteral("step_in")); a->setText(i18n("Step In")); a->setIcon(QIcon::fromTheme(QStringLiteral("debug-step-into"))); - connect( a, SIGNAL(triggered(bool)), - m_debugView, SLOT(slotStepInto())); + connect(a, &QAction::triggered, m_debugView, &DebugView::slotStepInto); a = actionCollection()->addAction(QStringLiteral("step_over")); a->setText(i18n("Step Over")); a->setIcon(QIcon::fromTheme(QStringLiteral("debug-step-over"))); - connect( a, SIGNAL(triggered(bool)), - m_debugView, SLOT(slotStepOver())); + connect(a, &QAction::triggered, m_debugView, &DebugView::slotStepOver); + a = actionCollection()->addAction(QStringLiteral("step_out")); a->setText(i18n("Step Out")); a->setIcon(QIcon::fromTheme(QStringLiteral("debug-step-out"))); - connect( a, SIGNAL(triggered(bool)), - m_debugView, SLOT(slotStepOut())); + connect(a, &QAction::triggered, m_debugView, &DebugView::slotStepOut); a = actionCollection()->addAction(QStringLiteral("move_pc")); a->setText(i18nc("Move Program Counter (next execution)", "Move PC")); - connect( a, SIGNAL(triggered(bool)), - this, SLOT(slotMovePC())); + connect(a, &QAction::triggered, this, &KatePluginGDBView::slotMovePC); a = actionCollection()->addAction(QStringLiteral("run_to_cursor")); a->setText(i18n("Run To Cursor")); a->setIcon(QIcon::fromTheme(QStringLiteral("debug-run-cursor"))); - connect( a, SIGNAL(triggered(bool)), - this, SLOT(slotRunToCursor())); + connect(a, &QAction::triggered, this, &KatePluginGDBView::slotRunToCursor); a = actionCollection()->addAction(QStringLiteral("continue")); a->setText(i18n("Continue")); a->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); - connect( a, SIGNAL(triggered(bool)), - m_debugView, SLOT(slotContinue())); + connect(a, &QAction::triggered, m_debugView, &DebugView::slotContinue); a = actionCollection()->addAction(QStringLiteral("print_value")); a->setText(i18n("Print Value")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-preview"))); - connect( a, SIGNAL(triggered(bool)), - this, SLOT(slotValue())); + connect(a, &QAction::triggered, this, &KatePluginGDBView::slotValue); // popup context m_menu m_menu = new KActionMenu(i18n("Debug"), this); actionCollection()->addAction(QStringLiteral("popup_gdb"), m_menu); - connect(m_menu->menu(), SIGNAL(aboutToShow()), this, SLOT(aboutToShowMenu())); + connect(m_menu->menu(), &QMenu::aboutToShow, this, &KatePluginGDBView::aboutToShowMenu); m_breakpoint = m_menu->menu()->addAction(i18n("popup_breakpoint"), this, SLOT(slotToggleBreakpoint())); QAction* popupAction = m_menu->menu()->addAction(i18n("popup_run_to_cursor"), this, SLOT(slotRunToCursor())); popupAction->setText(i18n("Run To Cursor")); popupAction = m_menu->menu()->addAction(QStringLiteral("move_pc"), this, SLOT(slotMovePC())); popupAction->setText(i18nc("Move Program Counter (next execution)", "Move PC")); enableDebugActions(false); - connect(m_mainWin, SIGNAL(unhandledShortcutOverride(QEvent*)), - this, SLOT(handleEsc(QEvent*))); + connect(m_mainWin, &KTextEditor::MainWindow::unhandledShortcutOverride, + this, &KatePluginGDBView::handleEsc); m_toolView->installEventFilter(this); m_mainWin->guiFactory()->addClient(this); } KatePluginGDBView::~KatePluginGDBView() { m_mainWin->guiFactory()->removeClient(this); delete m_toolView; delete m_localsStackToolView; } void KatePluginGDBView::readSessionConfig( const KConfigGroup& config) { m_configView->readConfig(config); } void KatePluginGDBView::writeSessionConfig(KConfigGroup& config) { m_configView->writeConfig(config); } void KatePluginGDBView::slotDebug() { - disconnect(m_ioView, SIGNAL(stdOutText(QString)), nullptr, nullptr); - disconnect(m_ioView, SIGNAL(stdErrText(QString)), nullptr, nullptr); + disconnect(m_ioView, &IOView::stdOutText, nullptr, nullptr); + disconnect(m_ioView, &IOView::stdErrText, nullptr, nullptr); if (m_configView->showIOTab()) { - connect(m_ioView, SIGNAL(stdOutText(QString)), m_ioView, SLOT(addStdOutText(QString))); - connect(m_ioView, SIGNAL(stdErrText(QString)), m_ioView, SLOT(addStdErrText(QString))); + connect(m_ioView, &IOView::stdOutText, m_ioView, &IOView::addStdOutText); + connect(m_ioView, &IOView::stdErrText, m_ioView, &IOView::addStdErrText); } else { - connect(m_ioView, SIGNAL(stdOutText(QString)), this, SLOT(addOutputText(QString))); - connect(m_ioView, SIGNAL(stdErrText(QString)), this, SLOT(addErrorText(QString))); + connect(m_ioView, &IOView::stdOutText, this, &KatePluginGDBView::addOutputText); + connect(m_ioView, &IOView::stdErrText, this, &KatePluginGDBView::addErrorText); } QStringList ioFifos; ioFifos << m_ioView->stdinFifo(); ioFifos << m_ioView->stdoutFifo(); ioFifos << m_ioView->stderrFifo(); enableDebugActions(true); m_mainWin->showToolView(m_toolView); m_tabWidget->setCurrentWidget(m_gdbPage); QScrollBar *sb = m_outputArea->verticalScrollBar(); sb->setValue(sb->maximum()); m_localsView->clear(); m_debugView->runDebugger(m_configView->currentTarget(), ioFifos); } void KatePluginGDBView::slotRestart() { m_mainWin->showToolView(m_toolView); m_tabWidget->setCurrentWidget(m_gdbPage); QScrollBar *sb = m_outputArea->verticalScrollBar(); sb->setValue(sb->maximum()); m_localsView->clear(); m_debugView->slotReRun(); } void KatePluginGDBView::aboutToShowMenu() { if (!m_debugView->debuggerRunning() || m_debugView->debuggerBusy()) { m_breakpoint->setText(i18n("Insert breakpoint")); m_breakpoint->setDisabled(true); return; } m_breakpoint->setDisabled(false); KTextEditor::View* editView = m_mainWin->activeView(); QUrl url = editView->document()->url(); int line = editView->cursorPosition().line(); line++; // GDB uses 1 based line numbers, kate uses 0 based... if (m_debugView->hasBreakpoint(url, line)) { m_breakpoint->setText(i18n("Remove breakpoint")); } else { m_breakpoint->setText(i18n("Insert breakpoint")); } } void KatePluginGDBView::slotToggleBreakpoint() { if (!actionCollection()->action(QStringLiteral("continue"))->isEnabled()) { m_debugView->slotInterrupt(); } else { KTextEditor::View* editView = m_mainWin->activeView(); QUrl currURL = editView->document()->url(); int line = editView->cursorPosition().line(); m_debugView->toggleBreakpoint(currURL, line + 1); } } void KatePluginGDBView::slotBreakpointSet(const QUrl &file, int line) { KTextEditor::MarkInterface* iface = qobject_cast(m_kateApplication->findUrl(file)); if (iface) { iface->setMarkDescription(KTextEditor::MarkInterface::BreakpointActive, i18n("Breakpoint")); iface->setMarkPixmap(KTextEditor::MarkInterface::BreakpointActive, QIcon::fromTheme(QStringLiteral("media-playback-pause")).pixmap(10,10)); iface->addMark(line, KTextEditor::MarkInterface::BreakpointActive); } } void KatePluginGDBView::slotBreakpointCleared(const QUrl &file, int line) { KTextEditor::MarkInterface* iface = qobject_cast(m_kateApplication->findUrl(file)); if (iface) { iface->removeMark(line, KTextEditor::MarkInterface::BreakpointActive); } } void KatePluginGDBView::slotMovePC() { KTextEditor::View* editView = m_mainWin->activeView(); QUrl currURL = editView->document()->url(); KTextEditor::Cursor cursor = editView->cursorPosition(); m_debugView->movePC(currURL, cursor.line() + 1); } void KatePluginGDBView::slotRunToCursor() { KTextEditor::View* editView = m_mainWin->activeView(); QUrl currURL = editView->document()->url(); KTextEditor::Cursor cursor = editView->cursorPosition(); // GDB starts lines from 1, kate returns lines starting from 0 (displaying 1) m_debugView->runToCursor(currURL, cursor.line() + 1); } void KatePluginGDBView::slotGoTo(const QUrl &url, int lineNum) { // skip not existing files if (!QFile::exists (url.toLocalFile ())) { m_lastExecLine = -1; return; } m_lastExecUrl = url; m_lastExecLine = lineNum; KTextEditor::View* editView = m_mainWin->openUrl(m_lastExecUrl); editView->setCursorPosition(KTextEditor::Cursor(m_lastExecLine, 0)); m_mainWin->window()->raise(); m_mainWin->window()->setFocus(); } void KatePluginGDBView::enableDebugActions(bool enable) { actionCollection()->action(QStringLiteral("step_in" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("step_over" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("step_out" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("move_pc" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("run_to_cursor"))->setEnabled(enable); actionCollection()->action(QStringLiteral("popup_gdb" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("continue" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("print_value" ))->setEnabled(enable); // "toggle breakpoint" doubles as interrupt while the program is running actionCollection()->action(QStringLiteral("toggle_breakpoint"))->setEnabled(m_debugView->debuggerRunning()); actionCollection()->action(QStringLiteral("kill" ))->setEnabled(m_debugView->debuggerRunning()); actionCollection()->action(QStringLiteral("rerun" ))->setEnabled(m_debugView->debuggerRunning()); m_inputArea->setEnabled(enable); m_threadCombo->setEnabled(enable); m_stackTree->setEnabled(enable); m_localsView->setEnabled(enable); if (enable) { m_inputArea->setFocusPolicy(Qt::WheelFocus); if (m_focusOnInput || m_configView->takeFocusAlways()) { m_inputArea->setFocus(); m_focusOnInput = false; } else { m_mainWin->activeView()->setFocus(); } } else { m_inputArea->setFocusPolicy(Qt::NoFocus); if (m_mainWin->activeView()) m_mainWin->activeView()->setFocus(); } m_ioView->enableInput(!enable && m_debugView->debuggerRunning()); if ((m_lastExecLine > -1)) { KTextEditor::MarkInterface* iface = qobject_cast(m_kateApplication->findUrl(m_lastExecUrl)); if (iface) { if (enable) { iface->setMarkDescription(KTextEditor::MarkInterface::Execution, i18n("Execution point")); iface->setMarkPixmap(KTextEditor::MarkInterface::Execution, QIcon::fromTheme(QStringLiteral("arrow-right")).pixmap(10,10)); iface->addMark(m_lastExecLine, KTextEditor::MarkInterface::Execution); } else { iface->removeMark(m_lastExecLine, KTextEditor::MarkInterface::Execution); } } } } void KatePluginGDBView::programEnded() { // don't set the execution mark on exit m_lastExecLine = -1; m_stackTree->clear(); m_localsView->clear(); m_threadCombo->clear(); // Indicate the state change by showing the debug outputArea m_mainWin->showToolView(m_toolView); m_tabWidget->setCurrentWidget(m_gdbPage); } void KatePluginGDBView::gdbEnded() { m_outputArea->clear(); m_localsView->clear(); m_ioView->clearOutput(); clearMarks(); } void KatePluginGDBView::clearMarks() { KTextEditor::MarkInterface* iface; foreach (KTextEditor::Document* doc, m_kateApplication->documents()) { iface = qobject_cast(doc); if (iface) { const QHash marks = iface->marks(); QHashIterator i(marks); while (i.hasNext()) { i.next(); if ((i.value()->type == KTextEditor::MarkInterface::Execution) || (i.value()->type == KTextEditor::MarkInterface::BreakpointActive)) { iface->removeMark(i.value()->line, i.value()->type); } } } } } void KatePluginGDBView::slotSendCommand() { QString cmd = m_inputArea->currentText(); if (cmd.isEmpty()) cmd = m_lastCommand; m_inputArea->addToHistory(cmd); m_inputArea->setCurrentItem(QString()); m_focusOnInput = true; m_lastCommand = cmd; m_debugView->issueCommand(cmd); QScrollBar *sb = m_outputArea->verticalScrollBar(); sb->setValue(sb->maximum()); } void KatePluginGDBView::insertStackFrame(QString const& level, QString const& info) { if (level.isEmpty() && info.isEmpty()) { m_stackTree->resizeColumnToContents(2); return; } if (level == QLatin1String("0")) { m_stackTree->clear(); } QStringList columns; columns << QStringLiteral(" "); // icon place holder columns << level; int lastSpace = info.lastIndexOf(QLatin1String(" ")); QString shortInfo = info.mid(lastSpace); columns << shortInfo; QTreeWidgetItem *item = new QTreeWidgetItem(columns); item->setToolTip(2, QStringLiteral("%1").arg(info)); m_stackTree->insertTopLevelItem(level.toInt(), item); } void KatePluginGDBView::stackFrameSelected() { m_debugView->issueCommand(QStringLiteral("(Q)f %1").arg(m_stackTree->currentIndex().row())); } void KatePluginGDBView::stackFrameChanged(int level) { QTreeWidgetItem *current = m_stackTree->topLevelItem(m_lastExecFrame); QTreeWidgetItem *next = m_stackTree->topLevelItem(level); if (current) current->setIcon (0, QIcon()); if (next) next->setIcon(0, QIcon::fromTheme(QStringLiteral("arrow-right"))); m_lastExecFrame = level; } void KatePluginGDBView::insertThread(int number, bool active) { if (number < 0) { m_threadCombo->clear(); m_activeThread = -1; return; } if (!active) { m_threadCombo->addItem(QIcon::fromTheme(QStringLiteral("")).pixmap(10,10), i18n("Thread %1", number), number); } else { m_threadCombo->addItem(QIcon::fromTheme(QStringLiteral("arrow-right")).pixmap(10,10), i18n("Thread %1", number), number); m_activeThread = m_threadCombo->count()-1; } m_threadCombo->setCurrentIndex(m_activeThread); } void KatePluginGDBView::threadSelected(int thread) { m_debugView->issueCommand(QStringLiteral("thread %1"). arg(m_threadCombo->itemData(thread).toInt())); } QString KatePluginGDBView::currentWord() { KTextEditor::View *kv = m_mainWin->activeView(); if (!kv) { qDebug() << "no KTextEditor::View" << endl; return QString(); } if (!kv->cursorPosition().isValid()) { qDebug() << "cursor not valid!" << endl; return QString(); } int line = kv->cursorPosition().line(); int col = kv->cursorPosition().column(); QString linestr = kv->document()->line(line); int startPos = qMax(qMin(col, linestr.length()-1), 0); int lindex = linestr.length()-1; int endPos = startPos; while (startPos >= 0 && (linestr[startPos].isLetterOrNumber() || linestr[startPos] == QLatin1Char('_') || linestr[startPos] == QLatin1Char('~') || ((startPos > 1) && (linestr[startPos] == QLatin1Char('.')) && !linestr[startPos-1].isSpace()) || ((startPos > 2) && (linestr[startPos] == QLatin1Char('>')) && (linestr[startPos-1] == QLatin1Char('-')) && !linestr[startPos-2].isSpace()))) { if (linestr[startPos] == QLatin1Char('>')) { startPos--; } startPos--; } while (endPos < (int)linestr.length() && (linestr[endPos].isLetterOrNumber() || linestr[endPos] == QLatin1Char('_') || ((endPos < lindex-1) && (linestr[endPos] == QLatin1Char('.')) && !linestr[endPos+1].isSpace()) || ((endPos < lindex-2) && (linestr[endPos] == QLatin1Char('-')) && (linestr[endPos+1] == QLatin1Char('>')) && !linestr[endPos+2].isSpace()) || ((endPos > 1) && (linestr[endPos-1] == QLatin1Char('-')) && (linestr[endPos] == QLatin1Char('>'))) )) { if (linestr[endPos] == QLatin1Char('-')) { endPos++; } endPos++; } if (startPos == endPos) { qDebug() << "no word found!" << endl; return QString(); } //qDebug() << linestr.mid(startPos+1, endPos-startPos-1); return linestr.mid(startPos+1, endPos-startPos-1); } void KatePluginGDBView::slotValue() { QString variable; KTextEditor::View* editView = m_mainWin->activeView(); if (editView && editView->selection() && editView->selectionRange().onSingleLine()) { variable = editView->selectionText(); } if (variable.isEmpty()) variable = currentWord(); if (variable.isEmpty()) return; QString cmd = QStringLiteral("print %1").arg(variable); m_debugView->issueCommand(cmd); m_inputArea->addToHistory(cmd); m_inputArea->setCurrentItem(QString()); m_mainWin->showToolView(m_toolView); m_tabWidget->setCurrentWidget(m_gdbPage); QScrollBar *sb = m_outputArea->verticalScrollBar(); sb->setValue(sb->maximum()); } void KatePluginGDBView::showIO(bool show) { if (show) { m_tabWidget->addTab(m_ioView, i18n("IO")); } else { m_tabWidget->removeTab(m_tabWidget->indexOf(m_ioView)); } } void KatePluginGDBView::addOutputText(QString const& text) { QScrollBar *scrollb = m_outputArea->verticalScrollBar(); if (!scrollb) return; bool atEnd = (scrollb->value() == scrollb->maximum()); QTextCursor cursor = m_outputArea->textCursor(); if (!cursor.atEnd()) cursor.movePosition(QTextCursor::End); cursor.insertText(text); if (atEnd) { scrollb->setValue(scrollb->maximum()); } } void KatePluginGDBView::addErrorText(QString const& text) { m_outputArea->setFontItalic(true); addOutputText(text); m_outputArea->setFontItalic(false); } bool KatePluginGDBView::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); if ((obj == m_toolView) && (ke->key() == Qt::Key_Escape)) { m_mainWin->hideToolView(m_toolView); event->accept(); return true; } } return QObject::eventFilter(obj, event); } void KatePluginGDBView::handleEsc(QEvent *e) { if (!m_mainWin) return; QKeyEvent *k = static_cast(e); if (k->key() == Qt::Key_Escape && k->modifiers() == Qt::NoModifier) { if (m_toolView->isVisible()) { m_mainWin->hideToolView(m_toolView); } } } #include "plugin_kategdb.moc" diff --git a/addons/kate-ctags/kate_ctags_plugin.cpp b/addons/kate-ctags/kate_ctags_plugin.cpp index 8035abfc5..7eb87dada 100644 --- a/addons/kate-ctags/kate_ctags_plugin.cpp +++ b/addons/kate-ctags/kate_ctags_plugin.cpp @@ -1,257 +1,257 @@ /* Description : Kate CTags plugin * * Copyright (C) 2008-2011 by Kare Sars * * 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.1 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 6 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 "kate_ctags_plugin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON (KateCTagsPluginFactory, "katectagsplugin.json", registerPlugin();) /******************************************************************/ KateCTagsPlugin::KateCTagsPlugin(QObject* parent, const QList&): KTextEditor::Plugin (parent), m_view(nullptr) { // FIXME KF5 //KGlobal::locale()->insertCatalog("kate-ctags-plugin"); } /******************************************************************/ QObject *KateCTagsPlugin::createView(KTextEditor::MainWindow *mainWindow) { m_view = new KateCTagsView(this, mainWindow); return m_view; } /******************************************************************/ KTextEditor::ConfigPage *KateCTagsPlugin::configPage (int number, QWidget *parent) { if (number != 0) return nullptr; return new KateCTagsConfigPage(parent, this); } /******************************************************************/ void KateCTagsPlugin::readConfig() { } /******************************************************************/ KateCTagsConfigPage::KateCTagsConfigPage( QWidget* parent, KateCTagsPlugin *plugin ) : KTextEditor::ConfigPage( parent ) , m_plugin( plugin ) { m_confUi.setupUi(this); m_confUi.cmdEdit->setText(DEFAULT_CTAGS_CMD); m_confUi.addButton->setToolTip(i18n("Add a directory to index.")); m_confUi.addButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); m_confUi.delButton->setToolTip(i18n("Remove a directory.")); m_confUi.delButton->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); m_confUi.updateDB->setToolTip(i18n("(Re-)generate the common CTags database.")); m_confUi.updateDB->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); - connect(m_confUi.updateDB, SIGNAL(clicked()), this, SLOT(updateGlobalDB())); - connect(m_confUi.addButton, SIGNAL(clicked()), this, SLOT(addGlobalTagTarget())); - connect(m_confUi.delButton, SIGNAL(clicked()), this, SLOT(delGlobalTagTarget())); + connect(m_confUi.updateDB, &QPushButton::clicked, this, &KateCTagsConfigPage::updateGlobalDB); + connect(m_confUi.addButton, &QPushButton::clicked, this, &KateCTagsConfigPage::addGlobalTagTarget); + connect(m_confUi.delButton, &QPushButton::clicked, this, &KateCTagsConfigPage::delGlobalTagTarget); - connect(&m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), - this, SLOT(updateDone(int,QProcess::ExitStatus))); + connect(&m_proc, static_cast(&QProcess::finished), + this, &KateCTagsConfigPage::updateDone); reset(); } /******************************************************************/ QString KateCTagsConfigPage::name() const { return i18n("CTags"); } /******************************************************************/ QString KateCTagsConfigPage::fullName() const { return i18n("CTags Settings"); } /******************************************************************/ QIcon KateCTagsConfigPage::icon() const { return QIcon::fromTheme(QStringLiteral("text-x-csrc")); } /******************************************************************/ void KateCTagsConfigPage::apply() { KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CTags")); config.writeEntry("GlobalCommand", m_confUi.cmdEdit->text()); config.writeEntry("GlobalNumTargets", m_confUi.targetList->count()); QString nr; for (int i=0; icount(); i++) { nr = QStringLiteral("%1").arg(i,3); config.writeEntry(QStringLiteral("GlobalTarget_")+nr, m_confUi.targetList->item(i)->text()); } config.sync(); } /******************************************************************/ void KateCTagsConfigPage::reset() { KConfigGroup config(KSharedConfig::openConfig(), "CTags"); m_confUi.cmdEdit->setText(config.readEntry(QStringLiteral("GlobalCommand"), DEFAULT_CTAGS_CMD)); int numEntries = config.readEntry(QStringLiteral("GlobalNumTargets"), 0); QString nr; QString target; for (int i=0; icurrentItem()) { dir = m_confUi.targetList->currentItem()->text(); } else if (m_confUi.targetList->item(0)) { dir = m_confUi.targetList->item(0)->text(); } dialog.setDirectory(dir); // i18n("CTags Database Location")); if (dialog.exec() != QDialog::Accepted) { return; } QStringList urls = dialog.selectedFiles(); for (int i=0; icurrentItem (); } /******************************************************************/ bool KateCTagsConfigPage::listContains(const QString &target) { for (int i=0; icount(); i++) { if (m_confUi.targetList->item(i)->text() == target) { return true; } } return false; } /******************************************************************/ void KateCTagsConfigPage::updateGlobalDB() { if (m_proc.state() != QProcess::NotRunning) { return; } QString targets; QString target; for (int i=0; icount(); i++) { target = m_confUi.targetList->item(i)->text(); if (target.endsWith(QLatin1Char('/')) || target.endsWith(QLatin1Char('\\'))) { target = target.left(target.size() - 1); } targets += target + QLatin1Char(' '); } QString file = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/katectags"); QDir().mkpath(file); file += QLatin1String("/common_db"); if (targets.isEmpty()) { QFile::remove(file); return; } QString command = QStringLiteral("%1 -f %2 %3").arg(m_confUi.cmdEdit->text()).arg(file).arg(targets) ; m_proc.start(command); if(!m_proc.waitForStarted(500)) { KMessageBox::error(nullptr, i18n("Failed to run \"%1\". exitStatus = %2", command, m_proc.exitStatus())); return; } m_confUi.updateDB->setDisabled(true); QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); } /******************************************************************/ void KateCTagsConfigPage::updateDone(int exitCode, QProcess::ExitStatus status) { if (status == QProcess::CrashExit) { KMessageBox::error(this, i18n("The CTags executable crashed.")); } else if (exitCode != 0) { KMessageBox::error(this, i18n("The CTags command exited with code %1", exitCode)); } m_confUi.updateDB->setDisabled(false); QApplication::restoreOverrideCursor(); } #include "kate_ctags_plugin.moc" diff --git a/addons/kate-ctags/kate_ctags_view.cpp b/addons/kate-ctags/kate_ctags_view.cpp index c08b2fc14..1728bcd70 100644 --- a/addons/kate-ctags/kate_ctags_view.cpp +++ b/addons/kate-ctags/kate_ctags_view.cpp @@ -1,615 +1,613 @@ /* Description : Kate CTags plugin * * Copyright (C) 2008-2011 by Kare Sars * * 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.1 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 6 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 "kate_ctags_view.h" #include #include #include #include #include #include #include #include #include #include #include /******************************************************************/ KateCTagsView::KateCTagsView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWin) : QObject(mainWin) , m_proc(nullptr) { KXMLGUIClient::setComponentName (QLatin1String("katectags"), i18n ("Kate CTag")); setXMLFile( QLatin1String("ui.rc") ); m_toolView = mainWin->createToolView(plugin, QLatin1String("kate_plugin_katectagsplugin"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme(QStringLiteral("application-x-ms-dos-executable")), i18n("CTags")); m_mWin = mainWin; QAction *back = actionCollection()->addAction(QLatin1String("ctags_return_step")); back->setText(i18n("Jump back one step")); - connect(back, SIGNAL(triggered(bool)), this, SLOT(stepBack())); + connect(back, &QAction::triggered, this, &KateCTagsView::stepBack); QAction *decl = actionCollection()->addAction(QLatin1String("ctags_lookup_current_as_declaration")); decl->setText(i18n("Go to Declaration")); - connect(decl, SIGNAL(triggered(bool)), this, SLOT(gotoDeclaration())); + connect(decl, &QAction::triggered, this, &KateCTagsView::gotoDeclaration); QAction *defin = actionCollection()->addAction(QLatin1String("ctags_lookup_current_as_definition")); defin->setText(i18n("Go to Definition")); - connect(defin, SIGNAL(triggered(bool)), this, SLOT(gotoDefinition())); + connect(defin, &QAction::triggered, this, &KateCTagsView::gotoDefinition); QAction *lookup = actionCollection()->addAction(QLatin1String("ctags_lookup_current")); lookup->setText(i18n("Lookup Current Text")); - connect(lookup, SIGNAL(triggered(bool)), this, SLOT(lookupTag())); + connect(lookup, &QAction::triggered, this, &KateCTagsView::lookupTag); // popup menu m_menu = new KActionMenu(i18n("CTags"), this); actionCollection()->addAction(QLatin1String("popup_ctags"), m_menu); m_gotoDec=m_menu->menu()->addAction(i18n("Go to Declaration: %1",QString()), this, SLOT(gotoDeclaration())); m_gotoDef=m_menu->menu()->addAction(i18n("Go to Definition: %1",QString()), this, SLOT(gotoDefinition())); m_lookup=m_menu->menu()->addAction(i18n("Lookup: %1",QString()), this, SLOT(lookupTag())); - connect(m_menu->menu(), SIGNAL(aboutToShow()), this, SLOT(aboutToShow())); + connect(m_menu->menu(), &QMenu::aboutToShow, this, &KateCTagsView::aboutToShow); QWidget *ctagsWidget = new QWidget(m_toolView); m_ctagsUi.setupUi(ctagsWidget); m_ctagsUi.cmdEdit->setText(DEFAULT_CTAGS_CMD); m_ctagsUi.addButton->setToolTip(i18n("Add a directory to index.")); m_ctagsUi.addButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); m_ctagsUi.delButton->setToolTip(i18n("Remove a directory.")); m_ctagsUi.delButton->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); m_ctagsUi.updateButton->setToolTip(i18n("(Re-)generate the session specific CTags database.")); m_ctagsUi.updateButton->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); m_ctagsUi.updateButton2->setToolTip(i18n("(Re-)generate the session specific CTags database.")); m_ctagsUi.updateButton2->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); m_ctagsUi.resetCMD->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); m_ctagsUi.tagsFile->setToolTip(i18n("Select new or existing database file.")); m_ctagsUi.tagsFile->setMode(KFile::File); - connect(m_ctagsUi.resetCMD, SIGNAL(clicked()), this, SLOT(resetCMD())); - connect(m_ctagsUi.addButton, SIGNAL(clicked()), this, SLOT(addTagTarget())); - connect(m_ctagsUi.delButton, SIGNAL(clicked()), this, SLOT(delTagTarget())); - connect(m_ctagsUi.updateButton, SIGNAL(clicked()), this, SLOT(updateSessionDB())); - connect(m_ctagsUi.updateButton2, SIGNAL(clicked()), this, SLOT(updateSessionDB())); - connect(&m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), - this, SLOT(updateDone(int,QProcess::ExitStatus))); + connect(m_ctagsUi.resetCMD, &QToolButton::clicked, this, &KateCTagsView::resetCMD); + connect(m_ctagsUi.addButton, &QPushButton::clicked, this, &KateCTagsView::addTagTarget); + connect(m_ctagsUi.delButton, &QPushButton::clicked, this, &KateCTagsView::delTagTarget); + connect(m_ctagsUi.updateButton, &QPushButton::clicked, this, &KateCTagsView::updateSessionDB); + connect(m_ctagsUi.updateButton2, &QPushButton::clicked, this, &KateCTagsView::updateSessionDB); + connect(&m_proc, static_cast(&QProcess::finished), + this, &KateCTagsView::updateDone); - connect(m_ctagsUi.inputEdit, SIGNAL(textChanged(QString)), this, SLOT(startEditTmr())); + connect(m_ctagsUi.inputEdit, &QLineEdit::textChanged, this, &KateCTagsView::startEditTmr); m_editTimer.setSingleShot(true); - connect(&m_editTimer, SIGNAL(timeout()), this, SLOT(editLookUp())); + connect(&m_editTimer, &QTimer::timeout, this, &KateCTagsView::editLookUp); - connect(m_ctagsUi.tagTreeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), - SLOT(tagHitClicked(QTreeWidgetItem*))); + connect(m_ctagsUi.tagTreeWidget, &QTreeWidget::itemActivated, this, &KateCTagsView::tagHitClicked); - connect(m_mWin, SIGNAL(unhandledShortcutOverride(QEvent*)), - this, SLOT(handleEsc(QEvent*))); + connect(m_mWin, &KTextEditor::MainWindow::unhandledShortcutOverride, this, &KateCTagsView::handleEsc); m_toolView->installEventFilter(this); m_mWin->guiFactory()->addClient(this); m_commonDB = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/katectags/common_db"); } /******************************************************************/ KateCTagsView::~KateCTagsView() { m_mWin->guiFactory()->removeClient( this ); delete m_toolView; } /******************************************************************/ void KateCTagsView::aboutToShow() { QString currWord = currentWord(); if (currWord.isEmpty()) { return; } if (Tags::hasTag(m_commonDB, currWord) || Tags::hasTag(m_ctagsUi.tagsFile->text(), currWord)) { QString squeezed = KStringHandler::csqueeze(currWord, 30); m_gotoDec->setText(i18n("Go to Declaration: %1",squeezed)); m_gotoDef->setText(i18n("Go to Definition: %1",squeezed)); m_lookup->setText(i18n("Lookup: %1",squeezed)); } } /******************************************************************/ void KateCTagsView::readSessionConfig (const KConfigGroup& cg) { m_ctagsUi.cmdEdit->setText(cg.readEntry("TagsGenCMD", DEFAULT_CTAGS_CMD)); int numEntries = cg.readEntry("SessionNumTargets", 0); QString nr; QString target; for (int i=0; isetText(sessionDB); } /******************************************************************/ void KateCTagsView::writeSessionConfig (KConfigGroup& cg) { cg.writeEntry("TagsGenCMD", m_ctagsUi.cmdEdit->text()); cg.writeEntry("SessionNumTargets", m_ctagsUi.targetList->count()); QString nr; for (int i=0; icount(); i++) { nr = QStringLiteral("%1").arg(i,3); cg.writeEntry(QStringLiteral("SessionTarget_%1").arg(nr), m_ctagsUi.targetList->item(i)->text()); } cg.writeEntry("SessionDatabase", m_ctagsUi.tagsFile->text()); cg.sync(); } /******************************************************************/ void KateCTagsView::stepBack() { if (m_jumpStack.isEmpty()) { return; } TagJump back; back = m_jumpStack.pop(); m_mWin->openUrl(back.url); m_mWin->activeView()->setCursorPosition(back.cursor); m_mWin->activeView()->setFocus(); } /******************************************************************/ void KateCTagsView::lookupTag( ) { QString currWord = currentWord(); if (currWord.isEmpty()) { return; } setNewLookupText(currWord); Tags::TagList list = Tags::getExactMatches(m_ctagsUi.tagsFile->text(), currWord); if (list.size() == 0) list = Tags::getExactMatches(m_commonDB, currWord); displayHits(list); // activate the hits tab m_ctagsUi.tabWidget->setCurrentIndex(0); m_mWin->showToolView(m_toolView); } /******************************************************************/ void KateCTagsView::editLookUp() { Tags::TagList list = Tags::getPartialMatches(m_ctagsUi.tagsFile->text(), m_ctagsUi.inputEdit->text()); if (list.size() == 0) list = Tags::getPartialMatches(m_commonDB, m_ctagsUi.inputEdit->text()); displayHits(list); } /******************************************************************/ void KateCTagsView::gotoDefinition( ) { QString currWord = currentWord(); if (currWord.isEmpty()) { return; } QStringList types; types << QStringLiteral("S") << QStringLiteral("d") << QStringLiteral("f") << QStringLiteral("t") << QStringLiteral("v"); gotoTagForTypes(currWord, types); } /******************************************************************/ void KateCTagsView::gotoDeclaration( ) { QString currWord = currentWord(); if (currWord.isEmpty()) { return; } QStringList types; types << QStringLiteral("L") << QStringLiteral("c") << QStringLiteral("e") << QStringLiteral("g") << QStringLiteral("m") << QStringLiteral("n") << QStringLiteral("p") << QStringLiteral("s") << QStringLiteral("u") << QStringLiteral("x"); gotoTagForTypes(currWord, types); } /******************************************************************/ void KateCTagsView::gotoTagForTypes(const QString &word, const QStringList &types) { Tags::TagList list = Tags::getMatches(m_ctagsUi.tagsFile->text(), word, false, types); if (list.size() == 0) list = Tags::getMatches(m_commonDB, word, false, types); //qDebug() << "found" << list.count() << word << types; setNewLookupText(word); if ( list.count() < 1) { m_ctagsUi.tagTreeWidget->clear(); new QTreeWidgetItem(m_ctagsUi.tagTreeWidget, QStringList(i18n("No hits found"))); m_ctagsUi.tabWidget->setCurrentIndex(0); m_mWin->showToolView(m_toolView); return; } displayHits(list); if (list.count() == 1) { Tags::TagEntry tag = list.first(); jumpToTag(tag.file, tag.pattern, word); } else { Tags::TagEntry tag = list.first(); jumpToTag(tag.file, tag.pattern, word); m_ctagsUi.tabWidget->setCurrentIndex(0); m_mWin->showToolView(m_toolView); } } /******************************************************************/ void KateCTagsView::setNewLookupText(const QString &newString) { m_ctagsUi.inputEdit->blockSignals( true ); m_ctagsUi.inputEdit->setText(newString); m_ctagsUi.inputEdit->blockSignals( false ); } /******************************************************************/ void KateCTagsView::displayHits(const Tags::TagList &list) { m_ctagsUi.tagTreeWidget->clear(); if (list.isEmpty()) { new QTreeWidgetItem(m_ctagsUi.tagTreeWidget, QStringList(i18n("No hits found"))); return; } m_ctagsUi.tagTreeWidget->setSortingEnabled(false); for (int i=0; isetText(0, list[i].tag); item->setText(1, list[i].type); item->setText(2, list[i].file); item->setData(0, Qt::UserRole, list[i].pattern); QString pattern = list[i].pattern; pattern.replace( QStringLiteral("\\/"), QStringLiteral("/")); pattern = pattern.mid(2, pattern.length() - 4); pattern = pattern.trimmed(); item->setData(0, Qt::ToolTipRole, pattern); item->setData(1, Qt::ToolTipRole, pattern); item->setData(2, Qt::ToolTipRole, pattern); } m_ctagsUi.tagTreeWidget->setSortingEnabled(true); } /******************************************************************/ void KateCTagsView::tagHitClicked(QTreeWidgetItem *item) { // get stuff const QString file = item->data(2, Qt::DisplayRole).toString(); const QString pattern = item->data(0, Qt::UserRole).toString(); const QString word = item->data(0, Qt::DisplayRole).toString(); jumpToTag(file, pattern, word); } /******************************************************************/ QString KateCTagsView::currentWord( ) { KTextEditor::View *kv = m_mWin->activeView(); if (!kv) { qDebug() << "no KTextEditor::View" << endl; return QString(); } if (kv->selection() && kv->selectionRange().onSingleLine()) { return kv->selectionText(); } if (!kv->cursorPosition().isValid()) { qDebug() << "cursor not valid!" << endl; return QString(); } int line = kv->cursorPosition().line(); int col = kv->cursorPosition().column(); bool includeColon = m_ctagsUi.cmdEdit->text().contains(QLatin1String("--extra=+q")); QString linestr = kv->document()->line(line); int startPos = qMax(qMin(col, linestr.length()-1), 0); int endPos = startPos; while (startPos >= 0 && (linestr[startPos].isLetterOrNumber() || (linestr[startPos] == QLatin1Char(':') && includeColon) || linestr[startPos] == QLatin1Char('_') || linestr[startPos] == QLatin1Char('~'))) { startPos--; } while (endPos < (int)linestr.length() && (linestr[endPos].isLetterOrNumber() || (linestr[endPos] == QLatin1Char(':') && includeColon) || linestr[endPos] == QLatin1Char('_'))) { endPos++; } if (startPos == endPos) { qDebug() << "no word found!" << endl; return QString(); } linestr = linestr.mid(startPos+1, endPos-startPos-1); while (linestr.endsWith(QLatin1Char(':'))) { linestr.remove(linestr.size()-1, 1); } while (linestr.startsWith(QLatin1Char(':'))) { linestr.remove(0, 1); } //qDebug() << linestr; return linestr; } /******************************************************************/ void KateCTagsView::jumpToTag(const QString &file, const QString &pattern, const QString &word) { if (pattern.isEmpty()) return; // generate a regexp from the pattern // ctags interestingly escapes "/", but apparently nothing else. lets revert that QString unescaped = pattern; unescaped.replace( QStringLiteral("\\/"), QStringLiteral("/") ); // most of the time, the ctags pattern has the form /^foo$/ // but this isn't true for some macro definitions // where the form is only /^foo/ // I have no idea if this is a ctags bug or not, but we have to deal with it QString reduced; QString escaped; QString re_string; if (unescaped.endsWith(QStringLiteral("$/"))) { reduced = unescaped.mid(2, unescaped.length() - 4); escaped = QRegExp::escape(reduced); re_string = QStringLiteral("^%1$").arg(escaped); } else { reduced = unescaped.mid( 2, unescaped.length() -3 ); escaped = QRegExp::escape(reduced); re_string = QStringLiteral("^%1").arg(escaped); } QRegExp re(re_string); // save current location TagJump from; from.url = m_mWin->activeView()->document()->url(); from.cursor = m_mWin->activeView()->cursorPosition(); m_jumpStack.push(from); // open/activate the new file QFileInfo fInfo(file); //qDebug() << pattern << file << fInfo.absoluteFilePath(); m_mWin->openUrl(QUrl::fromLocalFile(fInfo.absoluteFilePath())); // any view active? if (!m_mWin->activeView()) { return; } // look for the line QString linestr; int line; for (line =0; line < m_mWin->activeView()->document()->lines(); line++) { linestr = m_mWin->activeView()->document()->line(line); if (linestr.indexOf(re) > -1) break; } // activate the line if (line != m_mWin->activeView()->document()->lines()) { // line found now look for the column int column = linestr.indexOf(word) + (word.length()/2); m_mWin->activeView()->setCursorPosition(KTextEditor::Cursor(line, column)); } m_mWin->activeView()->setFocus(); } /******************************************************************/ void KateCTagsView::startEditTmr() { if (m_ctagsUi.inputEdit->text().size() > 3) { m_editTimer.start(500); } } /******************************************************************/ void KateCTagsView::updateSessionDB() { if (m_proc.state() != QProcess::NotRunning) { return; } QString targets; QString target; for (int i=0; icount(); i++) { target = m_ctagsUi.targetList->item(i)->text(); if (target.endsWith(QLatin1Char('/')) || target.endsWith(QLatin1Char('\\'))) { target = target.left(target.size() - 1); } targets += target + QLatin1Char(' '); } QString pluginFolder = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/katectags"); QDir().mkpath(pluginFolder); if (m_ctagsUi.tagsFile->text().isEmpty()) { // FIXME we need a way to get the session name pluginFolder += QLatin1String("/session_db_"); pluginFolder += QDateTime::currentDateTimeUtc().toString(QStringLiteral("yyyyMMdd_hhmmss")); m_ctagsUi.tagsFile->setText(pluginFolder); } if (targets.isEmpty()) { KMessageBox::error(nullptr, i18n("No folders or files to index")); QFile::remove(m_ctagsUi.tagsFile->text()); return; } QString command = QStringLiteral("%1 -f %2 %3").arg(m_ctagsUi.cmdEdit->text()).arg(m_ctagsUi.tagsFile->text()).arg(targets); m_proc.start(command); if(!m_proc.waitForStarted(500)) { KMessageBox::error(nullptr, i18n("Failed to run \"%1\". exitStatus = %2", command, m_proc.exitStatus())); return; } QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); m_ctagsUi.updateButton->setDisabled(true); m_ctagsUi.updateButton2->setDisabled(true); } /******************************************************************/ void KateCTagsView::updateDone(int exitCode, QProcess::ExitStatus status) { if (status == QProcess::CrashExit) { KMessageBox::error(m_toolView, i18n("The CTags executable crashed.")); } else if (exitCode != 0) { KMessageBox::error(m_toolView, i18n("The CTags program exited with code %1: %2" , exitCode , QString::fromLocal8Bit(m_proc.readAllStandardError()))); } m_ctagsUi.updateButton->setDisabled(false); m_ctagsUi.updateButton2->setDisabled(false); QApplication::restoreOverrideCursor(); } /******************************************************************/ void KateCTagsView::addTagTarget() { QFileDialog dialog; dialog.setDirectory(m_mWin->activeView()->document()->url().path()); dialog.setFileMode(QFileDialog::Directory); // i18n("CTags Database Location")); if (dialog.exec() != QDialog::Accepted) { return; } QStringList urls = dialog.selectedFiles(); for (int i=0; icurrentItem (); } /******************************************************************/ bool KateCTagsView::listContains(const QString &target) { for (int i=0; icount(); i++) { if (m_ctagsUi.targetList->item(i)->text() == target) { return true; } } return false; } /******************************************************************/ bool KateCTagsView::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); if ((obj == m_toolView) && (ke->key() == Qt::Key_Escape)) { m_mWin->hideToolView(m_toolView); event->accept(); return true; } } return QObject::eventFilter(obj, event); } /******************************************************************/ void KateCTagsView::resetCMD() { m_ctagsUi.cmdEdit->setText(DEFAULT_CTAGS_CMD); } /******************************************************************/ void KateCTagsView::handleEsc(QEvent *e) { if (!m_mWin) return; QKeyEvent *k = static_cast(e); if (k->key() == Qt::Key_Escape && k->modifiers() == Qt::NoModifier) { if (m_toolView->isVisible()) { m_mWin->hideToolView(m_toolView); } } } diff --git a/addons/katebuild-plugin/SelectTargetView.cpp b/addons/katebuild-plugin/SelectTargetView.cpp index 30c4d4ce2..771b7f344 100644 --- a/addons/katebuild-plugin/SelectTargetView.cpp +++ b/addons/katebuild-plugin/SelectTargetView.cpp @@ -1,127 +1,127 @@ /*************************************************************************** * This file is part of Kate build plugin * * Copyright 2014 Kåre Särs * * * * 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 "SelectTargetView.h" #include "TargetHtmlDelegate.h" #include #include #include #include class TargetFilterProxyModel: public QSortFilterProxyModel { public: TargetFilterProxyModel(QObject *parent): QSortFilterProxyModel(parent) {} bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override { if (m_filter.isEmpty()) { return true; } QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent); QString name = index0.data().toString(); if (index0.internalId() == 0xffffffff) { int i=0; while (index0.child(i,0).data().isValid()) { name = index0.child(i,0).data().toString(); if (name.contains(m_filter, Qt::CaseInsensitive)) { return true; } i++; } return false; } return name.contains(m_filter, Qt::CaseInsensitive); } void setFilter(const QString &filter) { m_filter = filter; invalidateFilter(); } Qt::ItemFlags flags(const QModelIndex &index) const override { if (!index.isValid()) { return nullptr; } return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QString m_filter; }; SelectTargetView::SelectTargetView(QAbstractItemModel *model, QWidget* parent) :QDialog(parent) { setupUi(this); m_proxyModel = new TargetFilterProxyModel(this); m_proxyModel->setSourceModel(model); u_treeView->setModel(m_proxyModel); u_treeView->expandAll(); u_treeView->resizeColumnToContents(0); u_treeView->setEditTriggers(QAbstractItemView::EditKeyPressed); setFocusProxy(u_filterEdit); - connect(u_filterEdit, SIGNAL(textChanged(QString)), this, SLOT(setFilter(QString))); - connect(u_treeView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(accept())); + connect(u_filterEdit, &QLineEdit::textChanged, this, &SelectTargetView::setFilter); + connect(u_treeView, &QTreeView::doubleClicked, this, &SelectTargetView::accept); u_filterEdit->installEventFilter(this); } void SelectTargetView::setFilter(const QString &filter) { m_proxyModel->setFilter(filter); u_treeView->expandAll(); } const QModelIndex SelectTargetView::currentIndex() const { return m_proxyModel->mapToSource(u_treeView->currentIndex()); } void SelectTargetView::setCurrentIndex(const QModelIndex &index) { u_treeView->setCurrentIndex(m_proxyModel->mapFromSource(index)); } bool SelectTargetView::eventFilter(QObject *obj, QEvent *event) { if (event->type()==QEvent::KeyPress) { QKeyEvent *keyEvent=static_cast(event); if (obj==u_filterEdit) { if ((keyEvent->key()==Qt::Key_Up) || (keyEvent->key()==Qt::Key_Down) || (keyEvent->key()==Qt::Key_PageUp) || (keyEvent->key()==Qt::Key_PageDown)) { QCoreApplication::sendEvent(u_treeView ,event); return true; } } } return QDialog::eventFilter(obj, event); } diff --git a/addons/katebuild-plugin/TargetHtmlDelegate.cpp b/addons/katebuild-plugin/TargetHtmlDelegate.cpp index 6f1138057..348155160 100644 --- a/addons/katebuild-plugin/TargetHtmlDelegate.cpp +++ b/addons/katebuild-plugin/TargetHtmlDelegate.cpp @@ -1,182 +1,181 @@ /*************************************************************************** * This file is part of Kate search plugin * * Copyright 2014 Kåre Särs * * * * 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 "TargetHtmlDelegate.h" #include "TargetModel.h" #include #include #include #include #include #include #include #include #include #include #include "UrlInserter.h" #include TargetHtmlDelegate::TargetHtmlDelegate( QObject* parent ) : QStyledItemDelegate(parent), m_isEditing(false) { - connect(this, SIGNAL(sendEditStart()), - this, SLOT(editStarted())); + connect(this, &TargetHtmlDelegate::sendEditStart, this, &TargetHtmlDelegate::editStarted); } TargetHtmlDelegate::~TargetHtmlDelegate() {} void TargetHtmlDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { QStyleOptionViewItem options = option; initStyleOption(&options, index); QTextDocument doc; QString str; if (!index.parent().isValid()) { if (index.column() == 0) { str = i18nc("T as in Target set", "T: %1", index.data().toString().toHtmlEscaped()); } else if (index.column() == 1) { str = i18nc("D as in working Directory", "Dir: %1", index.data().toString().toHtmlEscaped()); } } else { str = index.data().toString().toHtmlEscaped(); } if (option.state & QStyle::State_Selected) { str = QStringLiteral("").arg(option.palette.highlightedText().color().name()) + str + QStringLiteral(""); } doc.setHtml(str); doc.setDocumentMargin(2); painter->save(); // paint background if (option.state & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); } else { painter->fillRect(option.rect, option.palette.base()); } options.text = QString(); // clear old text options.widget->style()->drawControl(QStyle::CE_ItemViewItem, &options, painter, options.widget); // draw text painter->translate(option.rect.x(), option.rect.y()); if (index.column() == 0 && index.internalId() != TargetModel::InvalidIndex) { painter->translate(25, 0); } doc.drawContents(painter); painter->restore(); } QSize TargetHtmlDelegate::sizeHint(const QStyleOptionViewItem& /* option */, const QModelIndex& index) const { QTextDocument doc; doc.setHtml(index.data().toString().toHtmlEscaped()); doc.setDocumentMargin(2); if (index.column() == 0 && index.internalId() != TargetModel::InvalidIndex) { return doc.size().toSize() + QSize(30, 0); // add margin for the check-box; } return doc.size().toSize(); } QWidget *TargetHtmlDelegate::createEditor(QWidget *dparent, const QStyleOptionViewItem &/* option */, const QModelIndex &index) const { QWidget *editor; if (index.internalId() == TargetModel::InvalidIndex && index.column() == 1) { UrlInserter *requester = new UrlInserter(parent()->property("docUrl").toUrl(), dparent); requester->setReplace(true); editor = requester; editor->setToolTip(i18n("Leave empty to use the directory of the current document.")); } else if (index.column() == 1) { UrlInserter *urlEditor = new UrlInserter(parent()->property("docUrl").toUrl(), dparent); editor = urlEditor; editor->setToolTip(i18n("Use:\n\"%f\" for current file\n\"%d\" for directory of current file\n\"%n\" for current file name without suffix")); } else { QLineEdit *e = new QLineEdit(dparent); QCompleter *completer = new QCompleter(e); completer->setModel(new QDirModel(QStringList(), QDir::AllDirs|QDir::NoDotAndDotDot, QDir::Name, e)); e->setCompleter(completer); editor = e; } editor->setAutoFillBackground(true); emit sendEditStart(); - connect(editor, SIGNAL(destroyed(QObject*)), this, SLOT(editEnded())); + connect(editor, &QWidget::destroyed, this, &TargetHtmlDelegate::editEnded); return editor; } void TargetHtmlDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QString value = index.model()->data(index, Qt::EditRole).toString(); if (index.column() == 1) { UrlInserter *ledit = static_cast(editor); if (ledit) ledit->lineEdit()->setText(value); } else { QLineEdit *ledit = static_cast(editor); if (ledit) ledit->setText(value); } } void TargetHtmlDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QString value; if (index.column() == 1) { UrlInserter *ledit = static_cast(editor); value = ledit->lineEdit()->text(); } else { QLineEdit *ledit = static_cast(editor); value = ledit->text(); } model->setData(index, value, Qt::EditRole); } void TargetHtmlDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const { QRect rect = option.rect; int heightDiff = QToolButton().sizeHint().height() - rect.height(); int half = heightDiff/2; rect.adjust(0, -half, 0, heightDiff-half); if (index.column() == 0 && index.internalId() != TargetModel::InvalidIndex) { rect.adjust(25, 0, 0, 0); } editor->setGeometry(rect); } void TargetHtmlDelegate::editStarted() { m_isEditing = true; } void TargetHtmlDelegate::editEnded() { m_isEditing = false; } bool TargetHtmlDelegate::isEditing() const { return m_isEditing; } diff --git a/addons/katebuild-plugin/UrlInserter.cpp b/addons/katebuild-plugin/UrlInserter.cpp index 71c64c64d..bed699742 100644 --- a/addons/katebuild-plugin/UrlInserter.cpp +++ b/addons/katebuild-plugin/UrlInserter.cpp @@ -1,79 +1,79 @@ /*************************************************************************** * This file is part of Kate search plugin * * Copyright 2014 Kåre Särs * * * * 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 "UrlInserter.h" #include #include #include #include #include #include #include #include UrlInserter::UrlInserter(const QUrl &startUrl, QWidget* parent): QWidget(parent), m_startUrl(startUrl), m_replace(false) { m_lineEdit = new QLineEdit(); QCompleter* completer = new QCompleter(m_lineEdit); completer->setModel(new QDirModel(QStringList(), QDir::AllEntries|QDir::NoDotAndDotDot|QDir::Executable, QDir::Name, m_lineEdit)); m_lineEdit->setCompleter(completer); m_toolButton = new QToolButton(); m_toolButton->setIcon(QIcon::fromTheme(QStringLiteral("archive-insert-directory"))); m_toolButton->setToolTip(i18n("Insert path")); QHBoxLayout* layout = new QHBoxLayout(this); layout->setContentsMargins(0,0,0,0); layout->setSpacing(0); layout->addWidget(m_lineEdit); layout->addWidget(m_toolButton); setFocusProxy(m_lineEdit); - connect(m_toolButton, SIGNAL(clicked(bool)), this, SLOT(insertFolder())); + connect(m_toolButton, &QToolButton::clicked, this, &UrlInserter::insertFolder); } void UrlInserter::insertFolder() { QUrl startUrl; if (QFileInfo(m_lineEdit->text()).exists()) { startUrl.setPath(m_lineEdit->text()); } else { startUrl = m_startUrl; } QString folder = QFileDialog::getExistingDirectory(this, i18n("Select directory to insert"), startUrl.path()); if (!folder.isEmpty()) { if (!m_replace) { m_lineEdit->insert(folder); } else { m_lineEdit->setText(folder); } } } void UrlInserter::setReplace(bool replace) { m_replace = replace; } diff --git a/addons/katebuild-plugin/plugin_katebuild.cpp b/addons/katebuild-plugin/plugin_katebuild.cpp index 0254b4e59..11c6316fc 100644 --- a/addons/katebuild-plugin/plugin_katebuild.cpp +++ b/addons/katebuild-plugin/plugin_katebuild.cpp @@ -1,1042 +1,1040 @@ /* plugin_katebuild.c Kate Plugin ** ** Copyright (C) 2013 by Alexander Neundorf ** Copyright (C) 2006-2015 by Kåre Särs ** Copyright (C) 2011 by Ian Wakeling ** ** This code is mostly a modification of the GPL'ed Make plugin ** by Adriaan de Groot. */ /* ** 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 in a file called COPYING; if not, write to ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ** MA 02110-1301, USA. */ #include "plugin_katebuild.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "SelectTargetView.h" K_PLUGIN_FACTORY_WITH_JSON (KateBuildPluginFactory, "katebuildplugin.json", registerPlugin();) static const QString DefConfigCmd = QStringLiteral("cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr/local ../"); static const QString DefConfClean; static const QString DefTargetName = QStringLiteral("all"); static const QString DefBuildCmd = QStringLiteral("make"); static const QString DefCleanCmd = QStringLiteral("make clean"); /******************************************************************/ KateBuildPlugin::KateBuildPlugin(QObject *parent, const VariantList&): KTextEditor::Plugin(parent) { // KF5 FIXME KGlobal::locale()->insertCatalog("katebuild-plugin"); } /******************************************************************/ QObject *KateBuildPlugin::createView (KTextEditor::MainWindow *mainWindow) { return new KateBuildView(this, mainWindow); } /******************************************************************/ KateBuildView::KateBuildView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mw) : QObject (mw) , m_win(mw) , m_buildWidget(nullptr) , m_outputWidgetWidth(0) , m_proc(this) , m_stdOut() , m_stdErr() , m_buildCancelled(false) , m_displayModeBeforeBuild(1) // NOTE this will not allow spaces in file names. // e.g. from gcc: "main.cpp:14: error: cannot convert ‘std::string’ to ‘int’ in return" , m_filenameDetector(QStringLiteral("(([a-np-zA-Z]:[\\\\/])?[a-zA-Z0-9_\\.\\-/\\\\]+\\.[a-zA-Z0-9]+):([0-9]+)(.*)")) // e.g. from icpc: "main.cpp(14): error: no suitable conversion function from "std::string" to "int" exists" , m_filenameDetectorIcpc(QStringLiteral("(([a-np-zA-Z]:[\\\\/])?[a-zA-Z0-9_\\.\\-/\\\\]+\\.[a-zA-Z0-9]+)\\(([0-9]+)\\)(:.*)")) , m_filenameDetectorGccWorked(false) , m_newDirDetector(QStringLiteral("make\\[.+\\]: .+ `.*'")) { KXMLGUIClient::setComponentName (QLatin1String("katebuild"), i18n ("Kate Build Plugin")); setXMLFile(QLatin1String("ui.rc")); m_toolView = mw->createToolView(plugin, QStringLiteral("kate_plugin_katebuildplugin"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme(QStringLiteral("application-x-ms-dos-executable")), i18n("Build Output")); QAction *a = actionCollection()->addAction(QStringLiteral("select_target")); a->setText(i18n("Select Target...")); a->setIcon(QIcon::fromTheme(QStringLiteral("select"))); - connect(a, SIGNAL(triggered(bool)), this, SLOT(slotSelectTarget())); - + connect(a, &QAction::triggered, this, &KateBuildView::slotSelectTarget); a = actionCollection()->addAction(QStringLiteral("build_default_target")); a->setText(i18n("Build Default Target")); - connect(a, SIGNAL(triggered(bool)), this, SLOT(slotBuildDefaultTarget())); + connect(a, &QAction::triggered, this, &KateBuildView::slotBuildDefaultTarget); a = actionCollection()->addAction(QStringLiteral("build_previous_target")); a->setText(i18n("Build Previous Target")); - connect(a, SIGNAL(triggered(bool)), this, SLOT(slotBuildPreviousTarget())); + connect(a, &QAction::triggered, this, &KateBuildView::slotBuildPreviousTarget); a = actionCollection()->addAction(QStringLiteral("stop")); a->setText(i18n("Stop")); a->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); - connect(a, SIGNAL(triggered(bool)), this, SLOT(slotStop())); + connect(a, &QAction::triggered, this, &KateBuildView::slotStop); a = actionCollection()->addAction(QStringLiteral("goto_next")); a->setText(i18n("Next Error")); a->setIcon(QIcon::fromTheme(QStringLiteral("go-next"))); actionCollection()->setDefaultShortcut(a, Qt::SHIFT+Qt::ALT+Qt::Key_Right); - connect(a, SIGNAL(triggered(bool)), this, SLOT(slotNext())); + connect(a, &QAction::triggered, this, &KateBuildView::slotNext); a = actionCollection()->addAction(QStringLiteral("goto_prev")); a->setText(i18n("Previous Error")); a->setIcon(QIcon::fromTheme(QStringLiteral("go-previous"))); actionCollection()->setDefaultShortcut(a, Qt::SHIFT+Qt::ALT+Qt::Key_Left); - connect(a, SIGNAL(triggered(bool)), this, SLOT(slotPrev())); + connect(a, &QAction::triggered, this, &KateBuildView::slotPrev); m_buildWidget = new QWidget(m_toolView); m_buildUi.setupUi(m_buildWidget); m_targetsUi = new TargetsUi(this, m_buildUi.u_tabWidget); m_buildUi.u_tabWidget->insertTab(0, m_targetsUi, i18nc("Tab label", "Target Settings")); m_buildUi.u_tabWidget->setCurrentWidget(m_targetsUi); m_buildWidget->installEventFilter(this); m_buildUi.buildAgainButton->setVisible(true); m_buildUi.cancelBuildButton->setVisible(true); m_buildUi.buildStatusLabel->setVisible(true); m_buildUi.buildAgainButton2->setVisible(false); m_buildUi.cancelBuildButton2->setVisible(false); m_buildUi.buildStatusLabel2->setVisible(false); m_buildUi.extraLineLayout->setAlignment(Qt::AlignRight); m_buildUi.cancelBuildButton->setEnabled(false); m_buildUi.cancelBuildButton2->setEnabled(false); - connect(m_buildUi.errTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), - SLOT(slotErrorSelected(QTreeWidgetItem*))); + connect(m_buildUi.errTreeWidget, &QTreeWidget::itemClicked, + this, &KateBuildView::slotErrorSelected); m_buildUi.plainTextEdit->setReadOnly(true); slotDisplayMode(FullOutput); - connect(m_buildUi.displayModeSlider, SIGNAL(valueChanged(int)), this, SLOT(slotDisplayMode(int))); + connect(m_buildUi.displayModeSlider, &QSlider::valueChanged, this, &KateBuildView::slotDisplayMode); - connect(m_buildUi.buildAgainButton, SIGNAL(clicked()), this, SLOT(slotBuildPreviousTarget())); - connect(m_buildUi.cancelBuildButton, SIGNAL(clicked()), this, SLOT(slotStop())); - connect(m_buildUi.buildAgainButton2, SIGNAL(clicked()), this, SLOT(slotBuildPreviousTarget())); - connect(m_buildUi.cancelBuildButton2, SIGNAL(clicked()), this, SLOT(slotStop())); + connect(m_buildUi.buildAgainButton, &QPushButton::clicked, this, &KateBuildView::slotBuildPreviousTarget); + connect(m_buildUi.cancelBuildButton, &QPushButton::clicked, this, &KateBuildView::slotStop); + connect(m_buildUi.buildAgainButton2, &QPushButton::clicked, this, &KateBuildView::slotBuildPreviousTarget); + connect(m_buildUi.cancelBuildButton2, &QPushButton::clicked, this, &KateBuildView::slotStop); - connect(m_targetsUi->newTarget, SIGNAL(clicked()), this, SLOT(targetSetNew())); - connect(m_targetsUi->copyTarget, SIGNAL(clicked()), this, SLOT(targetOrSetCopy())); - connect(m_targetsUi->deleteTarget, SIGNAL(clicked()), this, SLOT(targetDelete())); + connect(m_targetsUi->newTarget, &QToolButton::clicked, this, &KateBuildView::targetSetNew); + connect(m_targetsUi->copyTarget, &QToolButton::clicked, this, &KateBuildView::targetOrSetCopy); + connect(m_targetsUi->deleteTarget, &QToolButton::clicked, this, &KateBuildView::targetDelete); - connect(m_targetsUi->addButton, SIGNAL(clicked()), this, SLOT(slotAddTargetClicked())); - connect(m_targetsUi->buildButton, SIGNAL(clicked()), this, SLOT(slotBuildActiveTarget())); - connect(m_targetsUi, SIGNAL(enterPressed()), this, SLOT(slotBuildActiveTarget())); + connect(m_targetsUi->addButton, &QToolButton::clicked, this, &KateBuildView::slotAddTargetClicked); + connect(m_targetsUi->buildButton, &QToolButton::clicked, this, &KateBuildView::slotBuildActiveTarget); + connect(m_targetsUi, &TargetsUi::enterPressed, this, &KateBuildView::slotBuildActiveTarget); m_proc.setOutputChannelMode(KProcess::SeparateChannels); - connect(&m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotProcExited(int,QProcess::ExitStatus))); - connect(&m_proc, SIGNAL(readyReadStandardError()),this, SLOT(slotReadReadyStdErr())); - connect(&m_proc, SIGNAL(readyReadStandardOutput()),this, SLOT(slotReadReadyStdOut())); + connect(&m_proc, static_cast(&QProcess::finished), this, &KateBuildView::slotProcExited); + connect(&m_proc, &KProcess::readyReadStandardError, this, &KateBuildView::slotReadReadyStdErr); + connect(&m_proc, &KProcess::readyReadStandardOutput, this, &KateBuildView::slotReadReadyStdOut); - connect(m_win, SIGNAL(unhandledShortcutOverride(QEvent*)), this, SLOT(handleEsc(QEvent*))); + connect(m_win, &KTextEditor::MainWindow::unhandledShortcutOverride, this, &KateBuildView::handleEsc); m_toolView->installEventFilter(this); m_win->guiFactory()->addClient(this); // watch for project plugin view creation/deletion - connect(m_win, SIGNAL(pluginViewCreated (const QString &, QObject *)) - , this, SLOT(slotPluginViewCreated (const QString &, QObject *))); - - connect(m_win, SIGNAL(pluginViewDeleted (const QString &, QObject *)) - , this, SLOT(slotPluginViewDeleted (const QString &, QObject *))); + connect(m_win, &KTextEditor::MainWindow::pluginViewCreated, + this, &KateBuildView::slotPluginViewCreated); + connect(m_win, &KTextEditor::MainWindow::pluginViewDeleted, + this, &KateBuildView::slotPluginViewDeleted); // update once project plugin state manually m_projectPluginView = m_win->pluginView (QStringLiteral("kateprojectplugin")); slotProjectMapChanged (); } /******************************************************************/ KateBuildView::~KateBuildView() { m_win->guiFactory()->removeClient( this ); delete m_toolView; } /******************************************************************/ void KateBuildView::readSessionConfig(const KConfigGroup& cg) { int numTargets = cg.readEntry(QStringLiteral("NumTargets"), 0); m_targetsUi->targetsModel.clear(); int tmpIndex; int tmpCmd; if (numTargets == 0 ) { // either the config is empty or uses the older format m_targetsUi->targetsModel.addTargetSet(i18n("Target Set"), QString()); m_targetsUi->targetsModel.addCommand(0, i18n("build"), cg.readEntry(QStringLiteral("Make Command"), DefBuildCmd)); m_targetsUi->targetsModel.addCommand(0, i18n("clean"), cg.readEntry(QStringLiteral("Clean Command"), DefCleanCmd)); m_targetsUi->targetsModel.addCommand(0, i18n("config"), DefConfigCmd); QString quickCmd = cg.readEntry(QStringLiteral("Quick Compile Command")); if (!quickCmd.isEmpty()) { m_targetsUi->targetsModel.addCommand(0, i18n("quick"), quickCmd); } tmpIndex = 0; tmpCmd = 0; } else { for (int i=0; itargetsModel.addTargetSet(targetSetName, buildDir); if (targetNames.isEmpty()) { QString quickCmd = cg.readEntry(QStringLiteral("%1 QuickCmd").arg(i)); m_targetsUi->targetsModel.addCommand(i, i18n("build"), cg.readEntry(QStringLiteral("%1 BuildCmd"), DefBuildCmd)); m_targetsUi->targetsModel.addCommand(i, i18n("clean"), cg.readEntry(QStringLiteral("%1 CleanCmd"), DefCleanCmd)); if (!quickCmd.isEmpty()) { m_targetsUi->targetsModel.addCommand(i, i18n("quick"), quickCmd); } m_targetsUi->targetsModel.setDefaultCmd(i, i18n("build")); } else { for (int tn=0; tntargetsModel.addCommand(i, targetName, cg.readEntry(QStringLiteral("%1 BuildCmd %2").arg(i).arg(targetName), DefBuildCmd)); } QString defCmd = cg.readEntry(QStringLiteral("%1 Target Default").arg(i), QString()); m_targetsUi->targetsModel.setDefaultCmd(i, defCmd); } } tmpIndex = cg.readEntry(QStringLiteral("Active Target Index"), 0); tmpCmd = cg.readEntry(QStringLiteral("Active Target Command"), 0); } m_targetsUi->targetsView->expandAll(); m_targetsUi->targetsView->resizeColumnToContents(0); m_targetsUi->targetsView->collapseAll(); QModelIndex root = m_targetsUi->targetsModel.index(tmpIndex); QModelIndex cmdIndex = m_targetsUi->targetsModel.index(tmpCmd, 0, root); m_targetsUi->targetsView->setCurrentIndex(cmdIndex); } /******************************************************************/ void KateBuildView::writeSessionConfig(KConfigGroup& cg) { m_targetsUi->targetsModel.deleteTargetSet(i18n("Project Plugin Targets")); QList targets = m_targetsUi->targetsModel.targetSets(); cg.writeEntry("NumTargets", targets.size()); for (int i=0; itargetsView->currentIndex(); if (ind.internalId() == TargetModel::InvalidIndex) { set = ind.row(); } else { set = ind.internalId(); setRow = ind.row(); } if (setRow < 0) setRow = 0; cg.writeEntry(QStringLiteral("Active Target Index"), set); cg.writeEntry(QStringLiteral("Active Target Command"), setRow); slotAddProjectTarget(); } /******************************************************************/ void KateBuildView::slotNext() { const int itemCount = m_buildUi.errTreeWidget->topLevelItemCount(); if (itemCount == 0) { return; } QTreeWidgetItem *item = m_buildUi.errTreeWidget->currentItem(); if (item && item->isHidden()) item = nullptr; int i = (item == nullptr) ? -1 : m_buildUi.errTreeWidget->indexOfTopLevelItem(item); while (++i < itemCount) { item = m_buildUi.errTreeWidget->topLevelItem(i); if (!item->text(1).isEmpty() && !item->isHidden()) { m_buildUi.errTreeWidget->setCurrentItem(item); m_buildUi.errTreeWidget->scrollToItem(item); slotErrorSelected(item); return; } } } /******************************************************************/ void KateBuildView::slotPrev() { const int itemCount = m_buildUi.errTreeWidget->topLevelItemCount(); if (itemCount == 0) { return; } QTreeWidgetItem *item = m_buildUi.errTreeWidget->currentItem(); if (item && item->isHidden()) item = nullptr; int i = (item == nullptr) ? itemCount : m_buildUi.errTreeWidget->indexOfTopLevelItem(item); while (--i >= 0) { item = m_buildUi.errTreeWidget->topLevelItem(i); if (!item->text(1).isEmpty() && !item->isHidden()) { m_buildUi.errTreeWidget->setCurrentItem(item); m_buildUi.errTreeWidget->scrollToItem(item); slotErrorSelected(item); return; } } } /******************************************************************/ void KateBuildView::slotErrorSelected(QTreeWidgetItem *item) { // get stuff const QString filename = item->data(0, Qt::UserRole).toString(); if (filename.isEmpty()) return; const int line = item->data(1, Qt::UserRole).toInt(); const int column = item->data(2, Qt::UserRole).toInt(); // open file (if needed, otherwise, this will activate only the right view...) m_win->openUrl(QUrl::fromLocalFile(filename)); // any view active? if (!m_win->activeView()) { return; } // do it ;) m_win->activeView()->setCursorPosition(KTextEditor::Cursor(line-1, column-1)); m_win->activeView()->setFocus(); } /******************************************************************/ void KateBuildView::addError(const QString &filename, const QString &line, const QString &column, const QString &message) { ErrorCategory errorCategory = CategoryInfo; QTreeWidgetItem* item = new QTreeWidgetItem(m_buildUi.errTreeWidget); item->setBackground(1, Qt::gray); // The strings are twice in case kate is translated but not make. if (message.contains(QStringLiteral("error")) || message.contains(i18nc("The same word as 'make' uses to mark an error.","error")) || message.contains(QStringLiteral("undefined reference")) || message.contains(i18nc("The same word as 'ld' uses to mark an ...","undefined reference")) ) { errorCategory = CategoryError; item->setForeground(1, Qt::red); m_numErrors++; item->setHidden(false); } if (message.contains(QStringLiteral("warning")) || message.contains(i18nc("The same word as 'make' uses to mark a warning.","warning")) ) { errorCategory = CategoryWarning; item->setForeground(1, Qt::yellow); m_numWarnings++; item->setHidden(m_buildUi.displayModeSlider->value() > 2); } item->setTextAlignment(1, Qt::AlignRight); // visible text //remove path from visible file name QFileInfo file(filename); item->setText(0, file.fileName()); item->setText(1, line); item->setText(2, message.trimmed()); // used to read from when activating an item item->setData(0, Qt::UserRole, filename); item->setData(1, Qt::UserRole, line); item->setData(2, Qt::UserRole, column); if (errorCategory == CategoryInfo) { item->setHidden(m_buildUi.displayModeSlider->value() > 1); } item->setData(0, ErrorRole, errorCategory); // add tooltips in all columns // The enclosing ... enables word-wrap for long error messages item->setData(0, Qt::ToolTipRole, filename); item->setData(1, Qt::ToolTipRole, QStringLiteral("%1").arg(message)); item->setData(2, Qt::ToolTipRole, QStringLiteral("%1").arg(message)); } /******************************************************************/ QUrl KateBuildView::docUrl() { KTextEditor::View *kv = m_win->activeView(); if (!kv) { qDebug() << "no KTextEditor::View" << endl; return QUrl(); } if (kv->document()->isModified()) kv->document()->save(); return kv->document()->url(); } /******************************************************************/ bool KateBuildView::checkLocal(const QUrl &dir) { if (dir.path().isEmpty()) { KMessageBox::sorry(nullptr, i18n("There is no file or directory specified for building.")); return false; } else if (!dir.isLocalFile()) { KMessageBox::sorry(nullptr, i18n("The file \"%1\" is not a local file. " "Non-local files cannot be compiled.", dir.path())); return false; } return true; } /******************************************************************/ void KateBuildView::clearBuildResults() { m_buildUi.plainTextEdit->clear(); m_buildUi.errTreeWidget->clear(); m_stdOut.clear(); m_stdErr.clear(); m_numErrors = 0; m_numWarnings = 0; m_make_dir_stack.clear(); } /******************************************************************/ bool KateBuildView::startProcess(const QString &dir, const QString &command) { if (m_proc.state() != QProcess::NotRunning) { return false; } // clear previous runs clearBuildResults(); // activate the output tab m_buildUi.u_tabWidget->setCurrentIndex(1); m_displayModeBeforeBuild = m_buildUi.displayModeSlider->value(); m_buildUi.displayModeSlider->setValue(0); m_win->showToolView(m_toolView); // set working directory m_make_dir = dir; m_make_dir_stack.push(m_make_dir); // FIXME check m_proc.setWorkingDirectory(m_make_dir); m_proc.setShellCommand(command); m_proc.start(); if(!m_proc.waitForStarted(500)) { KMessageBox::error(nullptr, i18n("Failed to run \"%1\". exitStatus = %2", command, m_proc.exitStatus())); return false; } m_buildUi.cancelBuildButton->setEnabled(true); m_buildUi.cancelBuildButton2->setEnabled(true); m_buildUi.buildAgainButton->setEnabled(false); m_buildUi.buildAgainButton2->setEnabled(false); QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); return true; } /******************************************************************/ bool KateBuildView::slotStop() { if (m_proc.state() != QProcess::NotRunning) { m_buildCancelled = true; QString msg = i18n("Building %1 cancelled", m_currentlyBuildingTarget); m_buildUi.buildStatusLabel->setText(msg); m_buildUi.buildStatusLabel2->setText(msg); m_proc.terminate(); return true; } return false; } /******************************************************************/ void KateBuildView::slotBuildActiveTarget() { if (!m_targetsUi->targetsView->currentIndex().isValid()) { slotSelectTarget(); } else { buildCurrentTarget(); } } /******************************************************************/ void KateBuildView::slotBuildPreviousTarget() { if (!m_previousIndex.isValid()) { slotSelectTarget(); } else { m_targetsUi->targetsView->setCurrentIndex(m_previousIndex); buildCurrentTarget(); } } /******************************************************************/ void KateBuildView::slotBuildDefaultTarget() { QModelIndex defaultTarget = m_targetsUi->targetsModel.defaultTarget(m_targetsUi->targetsView->currentIndex()); m_targetsUi->targetsView->setCurrentIndex(defaultTarget); buildCurrentTarget(); } /******************************************************************/ void KateBuildView::slotSelectTarget() { SelectTargetView *dialog = new SelectTargetView(&(m_targetsUi->targetsModel)); dialog->setCurrentIndex(m_targetsUi->targetsView->currentIndex()); int result = dialog->exec(); if (result == QDialog::Accepted) { m_targetsUi->targetsView->setCurrentIndex(dialog->currentIndex()); buildCurrentTarget(); } delete dialog; dialog = nullptr; } /******************************************************************/ bool KateBuildView::buildCurrentTarget() { if (m_proc.state() != QProcess::NotRunning) { displayBuildResult(i18n("Already building..."), KTextEditor::Message::Warning); return false; } QFileInfo docFInfo = docUrl().toLocalFile(); // docUrl() saves the current document QModelIndex ind = m_targetsUi->targetsView->currentIndex(); m_previousIndex = ind; if (!ind.isValid()) { KMessageBox::sorry(nullptr, i18n("No target available for building.")); return false; } QString buildCmd = m_targetsUi->targetsModel.command(ind); QString cmdName = m_targetsUi->targetsModel.cmdName(ind); QString workDir = m_targetsUi->targetsModel.workDir(ind); QString targetSet = m_targetsUi->targetsModel.targetName(ind); QString dir = workDir; if (workDir.isEmpty()) { dir = docFInfo.absolutePath(); if (dir.isEmpty()) { KMessageBox::sorry(nullptr, i18n("There is no local file or directory specified for building.")); return false; } } // Check if the command contains the file name or directory if (buildCmd.contains(QStringLiteral("%f")) || buildCmd.contains(QStringLiteral("%d")) || buildCmd.contains(QStringLiteral("%n"))) { if (docFInfo.absoluteFilePath().isEmpty()) { return false; } buildCmd.replace(QStringLiteral("%n"), docFInfo.baseName()); buildCmd.replace(QStringLiteral("%f"), docFInfo.absoluteFilePath()); buildCmd.replace(QStringLiteral("%d"), docFInfo.absolutePath()); } m_filenameDetectorGccWorked = false; m_currentlyBuildingTarget = QStringLiteral("%1: %2").arg(targetSet).arg(cmdName); m_buildCancelled = false; QString msg = i18n("Building target %1 ...", m_currentlyBuildingTarget); m_buildUi.buildStatusLabel->setText(msg); m_buildUi.buildStatusLabel2->setText(msg); return startProcess(dir, buildCmd); } /******************************************************************/ void KateBuildView::displayBuildResult(const QString &msg, KTextEditor::Message::MessageType level) { KTextEditor::View *kv = m_win->activeView(); if (!kv) return; delete m_infoMessage; m_infoMessage = new KTextEditor::Message(xi18nc("@info", "Make Results:%1", msg), level); m_infoMessage->setWordWrap(true); m_infoMessage->setPosition(KTextEditor::Message::BottomInView); m_infoMessage->setAutoHide(5000); m_infoMessage->setAutoHideMode(KTextEditor::Message::Immediate); m_infoMessage->setView(kv); kv->document()->postMessage(m_infoMessage); } /******************************************************************/ void KateBuildView::slotProcExited(int exitCode, QProcess::ExitStatus) { QApplication::restoreOverrideCursor(); m_buildUi.cancelBuildButton->setEnabled(false); m_buildUi.cancelBuildButton2->setEnabled(false); m_buildUi.buildAgainButton->setEnabled(true); m_buildUi.buildAgainButton2->setEnabled(true); QString buildStatus = i18n("Building %1 completed.", m_currentlyBuildingTarget); // did we get any errors? if (m_numErrors || m_numWarnings || (exitCode != 0)) { m_buildUi.u_tabWidget->setCurrentIndex(1); if (m_buildUi.displayModeSlider->value() == 0) { m_buildUi.displayModeSlider->setValue(m_displayModeBeforeBuild > 0 ? m_displayModeBeforeBuild: 1); } m_buildUi.errTreeWidget->resizeColumnToContents(0); m_buildUi.errTreeWidget->resizeColumnToContents(1); m_buildUi.errTreeWidget->resizeColumnToContents(2); m_buildUi.errTreeWidget->horizontalScrollBar()->setValue(0); //m_buildUi.errTreeWidget->setSortingEnabled(true); m_win->showToolView(m_toolView); } if (m_numErrors || m_numWarnings) { QStringList msgs; if (m_numErrors) { msgs << i18np("Found one error.", "Found %1 errors.", m_numErrors); buildStatus = i18n("Building %1 had errors.", m_currentlyBuildingTarget); } else if (m_numWarnings) { msgs << i18np("Found one warning.", "Found %1 warnings.", m_numWarnings); buildStatus = i18n("Building %1 had warnings.", m_currentlyBuildingTarget); } displayBuildResult(msgs.join(QLatin1Char('\n')), m_numErrors ? KTextEditor::Message::Error : KTextEditor::Message::Warning); } else if (exitCode != 0) { displayBuildResult(i18n("Build failed."), KTextEditor::Message::Warning); } else { displayBuildResult(i18n("Build completed without problems."), KTextEditor::Message::Positive); } if (!m_buildCancelled) { m_buildUi.buildStatusLabel->setText(buildStatus); m_buildUi.buildStatusLabel2->setText(buildStatus); m_buildCancelled = false; } } /******************************************************************/ void KateBuildView::slotReadReadyStdOut() { // read data from procs stdout and add // the text to the end of the output // FIXME This works for utf8 but not for all charsets QString l = QString::fromUtf8(m_proc.readAllStandardOutput()); l.remove(QLatin1Char('\r')); m_stdOut += l; // handle one line at a time do { const int end = m_stdOut.indexOf(QLatin1Char('\n')); if (end < 0) break; const QString line = m_stdOut.mid(0, end); m_buildUi.plainTextEdit->appendPlainText(line); //qDebug() << line; if (m_newDirDetector.match(line).hasMatch()) { //qDebug() << "Enter/Exit dir found"; int open = line.indexOf(QLatin1Char('`')); int close = line.indexOf(QLatin1Char('\'')); QString newDir = line.mid(open+1, close-open-1); //qDebug () << "New dir = " << newDir; if ((m_make_dir_stack.size() > 1) && (m_make_dir_stack.top() == newDir)) { m_make_dir_stack.pop(); newDir = m_make_dir_stack.top(); } else { m_make_dir_stack.push(newDir); } m_make_dir = newDir; } m_stdOut.remove(0, end + 1); } while (1); } /******************************************************************/ void KateBuildView::slotReadReadyStdErr() { // FIXME This works for utf8 but not for all charsets QString l = QString::fromUtf8(m_proc.readAllStandardError()); l.remove(QLatin1Char('\r')); m_stdErr += l; do { const int end = m_stdErr.indexOf(QLatin1Char('\n')); if (end < 0) break; const QString line = m_stdErr.mid(0, end); m_buildUi.plainTextEdit->appendPlainText(line); processLine(line); m_stdErr.remove(0, end + 1); } while (1); } /******************************************************************/ void KateBuildView::processLine(const QString &line) { //qDebug() << line ; //look for a filename QRegularExpressionMatch match = m_filenameDetector.match(line); if (match.hasMatch()) { m_filenameDetectorGccWorked = true; } else { if (!m_filenameDetectorGccWorked) { // let's see whether the icpc regexp works: // so for icpc users error detection will be a bit slower, // since always both regexps are checked. // But this should be the minority, for gcc and clang users // both regexes will only be checked until the first regex // matched the first time. match = m_filenameDetectorIcpc.match(line); } } if (!match.hasMatch()) { addError(QString(), QStringLiteral("0"), QString(), line); //kDebug() << "A filename was not found in the line "; return; } QString filename = match.captured(1); const QString line_n = match.captured(3); const QString msg = match.captured(4); //qDebug() << "File Name:"<targetsView->currentIndex(); if (current.parent().isValid()) { current = current.parent(); } QModelIndex index = m_targetsUi->targetsModel.addCommand(current.row(), DefTargetName, DefBuildCmd); m_targetsUi->targetsView->setCurrentIndex(index); } /******************************************************************/ void KateBuildView::targetSetNew() { int row = m_targetsUi->targetsModel.addTargetSet(i18n("Target Set"), QString()); QModelIndex buildIndex = m_targetsUi->targetsModel.addCommand(row, i18n("Build"), DefBuildCmd); m_targetsUi->targetsModel.addCommand(row, i18n("Clean"), DefCleanCmd); m_targetsUi->targetsModel.addCommand(row, i18n("Config"), DefConfigCmd); m_targetsUi->targetsModel.addCommand(row, i18n("ConfigClean"), DefConfClean); m_targetsUi->targetsView->setCurrentIndex(buildIndex); } /******************************************************************/ void KateBuildView::targetOrSetCopy() { QModelIndex newIndex = m_targetsUi->targetsModel.copyTargetOrSet(m_targetsUi->targetsView->currentIndex()); if (m_targetsUi->targetsModel.hasChildren(newIndex)) { m_targetsUi->targetsView->setCurrentIndex(newIndex.child(0,0)); return; } m_targetsUi->targetsView->setCurrentIndex(newIndex); } /******************************************************************/ void KateBuildView::targetDelete() { QModelIndex current = m_targetsUi->targetsView->currentIndex(); m_targetsUi->targetsModel.deleteItem(current); if (m_targetsUi->targetsModel.rowCount() == 0) { targetSetNew(); } } /******************************************************************/ void KateBuildView::slotDisplayMode(int mode) { QTreeWidget *tree=m_buildUi.errTreeWidget; tree->setVisible(mode != 0); m_buildUi.plainTextEdit->setVisible(mode == 0); QString modeText; switch(mode) { case OnlyErrors: modeText = i18n("Only Errors"); break; case ErrorsAndWarnings: modeText = i18n("Errors and Warnings"); break; case ParsedOutput: modeText = i18n("Parsed Output"); break; case FullOutput: modeText = i18n("Full Output"); break; } m_buildUi.displayModeLabel->setText(modeText); if (mode < 1) { return; } const int itemCount = tree->topLevelItemCount(); for (int i=0;itopLevelItem(i); const ErrorCategory errorCategory = static_cast(item->data(0, ErrorRole).toInt()); switch (errorCategory) { case CategoryInfo: item->setHidden(mode > 1); break; case CategoryWarning: item->setHidden(mode > 2); break; case CategoryError: item->setHidden(false); break; } } } /******************************************************************/ void KateBuildView::slotPluginViewCreated (const QString &name, QObject *pluginView) { // add view if (name == QLatin1String("kateprojectplugin")) { m_projectPluginView = pluginView; slotProjectMapChanged (); - connect (pluginView, SIGNAL(projectMapChanged()), this, SLOT(slotProjectMapChanged())); + connect(pluginView, SIGNAL(projectMapChanged()), this, SLOT(slotProjectMapChanged())); } } /******************************************************************/ void KateBuildView::slotPluginViewDeleted (const QString &name, QObject *) { // remove view if (name == QLatin1String("kateprojectplugin")) { m_projectPluginView = nullptr; m_targetsUi->targetsModel.deleteTargetSet(i18n("Project Plugin Targets")); } } /******************************************************************/ void KateBuildView::slotProjectMapChanged () { // only do stuff with valid project if (!m_projectPluginView) { return; } m_targetsUi->targetsModel.deleteTargetSet(i18n("Project Plugin Targets")); slotAddProjectTarget(); } /******************************************************************/ void KateBuildView::slotAddProjectTarget() { // only do stuff with valid project if (!m_projectPluginView) { return; } // query new project map QVariantMap projectMap = m_projectPluginView->property("projectMap").toMap(); // do we have a valid map for build settings? QVariantMap buildMap = projectMap.value(QStringLiteral("build")).toMap(); if (buildMap.isEmpty()) { return; } // Delete any old project plugin targets m_targetsUi->targetsModel.deleteTargetSet(i18n("Project Plugin Targets")); int set = m_targetsUi->targetsModel.addTargetSet(i18n("Project Plugin Targets"), buildMap.value(QStringLiteral("directory")).toString()); QVariantList targetsets = buildMap.value(QStringLiteral("targets")).toList(); foreach (const QVariant &targetVariant, targetsets) { QVariantMap targetMap = targetVariant.toMap(); QString tgtName = targetMap[QStringLiteral("name")].toString(); QString buildCmd = targetMap[QStringLiteral("build_cmd")].toString(); if (tgtName.isEmpty() || buildCmd.isEmpty()) { continue; } m_targetsUi->targetsModel.addCommand(set, tgtName, buildCmd); } QModelIndex ind = m_targetsUi->targetsModel.index(set); if (!ind.child(0,0).data().isValid()) { QString buildCmd = buildMap.value(QStringLiteral("build")).toString(); QString cleanCmd = buildMap.value(QStringLiteral("clean")).toString(); QString quickCmd = buildMap.value(QStringLiteral("quick")).toString(); if (!buildCmd.isEmpty()) { // we have loaded an "old" project file (<= 4.12) m_targetsUi->targetsModel.addCommand(set, i18n("build"), buildCmd); } if (!cleanCmd.isEmpty()) { m_targetsUi->targetsModel.addCommand(set, i18n("clean"), cleanCmd); } if (!quickCmd.isEmpty()) { m_targetsUi->targetsModel.addCommand(set, i18n("quick"), quickCmd); } } } /******************************************************************/ bool KateBuildView::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); if ((obj == m_toolView) && (ke->key() == Qt::Key_Escape)) { m_win->hideToolView(m_toolView); event->accept(); return true; } } if ((event->type() == QEvent::Resize) && (obj == m_buildWidget)) { if (m_buildUi.u_tabWidget->currentIndex() == 1) { if ((m_outputWidgetWidth == 0) && m_buildUi.buildAgainButton->isVisible()) { QSize msh = m_buildWidget->minimumSizeHint(); m_outputWidgetWidth = msh.width(); } } bool useVertLayout = (m_buildWidget->width() < m_outputWidgetWidth); m_buildUi.buildAgainButton->setVisible(!useVertLayout); m_buildUi.cancelBuildButton->setVisible(!useVertLayout); m_buildUi.buildStatusLabel->setVisible(!useVertLayout); m_buildUi.buildAgainButton2->setVisible(useVertLayout); m_buildUi.cancelBuildButton2->setVisible(useVertLayout); m_buildUi.buildStatusLabel2->setVisible(useVertLayout); } return QObject::eventFilter(obj, event); } /******************************************************************/ void KateBuildView::handleEsc(QEvent *e) { if (!m_win) return; QKeyEvent *k = static_cast(e); if (k->key() == Qt::Key_Escape && k->modifiers() == Qt::NoModifier) { if (m_toolView->isVisible()) { m_win->hideToolView(m_toolView); } } } #include "plugin_katebuild.moc" // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/katebuild-plugin/targets.cpp b/addons/katebuild-plugin/targets.cpp index 7002035d9..db10c65c0 100644 --- a/addons/katebuild-plugin/targets.cpp +++ b/addons/katebuild-plugin/targets.cpp @@ -1,125 +1,126 @@ // // Description: Widget for configuring build targets // // Copyright (C) 2011-2014 Kåre Särs // // 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 "targets.h" #include #include #include #include #include TargetsUi::TargetsUi(QObject *view, QWidget *parent): QWidget(parent) { targetLabel = new QLabel(i18n("Active target-set:")); targetCombo = new QComboBox(this); targetCombo->setToolTip(i18n("Select active target set")); targetCombo->setModel(&targetsModel); targetLabel->setBuddy(targetCombo); newTarget = new QToolButton(this); newTarget->setToolTip(i18n("Create new set of targets")); newTarget->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); copyTarget = new QToolButton(this); copyTarget->setToolTip(i18n("Copy command or target set")); copyTarget->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy"))); deleteTarget = new QToolButton(this); deleteTarget->setToolTip(i18n("Delete current set of targets")); deleteTarget->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); addButton = new QToolButton(this); addButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); addButton->setToolTip(i18n("Add new target")); buildButton = new QToolButton(this); buildButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok"))); buildButton->setToolTip(i18n("Build selected target")); targetsView = new QTreeView(this); targetsView->setAlternatingRowColors(true); targetsView->setModel(&targetsModel); m_delegate = new TargetHtmlDelegate(view); targetsView->setItemDelegate(m_delegate); targetsView->setSelectionBehavior(QAbstractItemView::SelectItems); targetsView->setEditTriggers(QAbstractItemView::AnyKeyPressed | QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); QHBoxLayout* tLayout = new QHBoxLayout(); tLayout->addWidget(targetLabel); tLayout->addWidget(targetCombo); tLayout->addStretch(40); tLayout->addWidget(buildButton); tLayout->addSpacing(addButton->sizeHint().width()); tLayout->addWidget(addButton); tLayout->addWidget(newTarget); tLayout->addWidget(copyTarget); tLayout->addWidget(deleteTarget); tLayout->setContentsMargins(0,0,0,0); QVBoxLayout* layout = new QVBoxLayout(this); layout->addLayout(tLayout); layout->addWidget(targetsView); - connect(targetCombo, SIGNAL(activated(int)), this, SLOT(targetSetSelected(int))); - connect(targetsView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(targetActivated(QModelIndex))); + connect(targetCombo, static_cast(&QComboBox::activated), this, &TargetsUi::targetSetSelected); + connect(targetsView->selectionModel(), &QItemSelectionModel::currentChanged, + this, &TargetsUi::targetActivated); //connect(targetsView, SIGNAL(clicked(QModelIndex)), this, SLOT(targetActivated(QModelIndex))); targetsView->installEventFilter(this); } void TargetsUi::targetSetSelected(int index) { //qDebug() << index; targetsView->collapseAll(); QModelIndex rootItem = targetsModel.index(index, 0); targetsView->setExpanded(rootItem, true); targetsView->setCurrentIndex(rootItem.child(0,0)); } void TargetsUi::targetActivated(const QModelIndex &index) { //qDebug() << index; if (!index.isValid()) return; QModelIndex rootItem = index; if (rootItem.parent().isValid()) { rootItem = rootItem.parent(); } targetCombo->setCurrentIndex(rootItem.row()); } bool TargetsUi::eventFilter(QObject *obj, QEvent *event) { if (event->type()==QEvent::KeyPress) { QKeyEvent *keyEvent=static_cast(event); if (obj==targetsView) { if (((keyEvent->key()==Qt::Key_Return) || (keyEvent->key()==Qt::Key_Enter)) && m_delegate && !m_delegate->isEditing()) { emit enterPressed(); return true; } } } return QWidget::eventFilter(obj, event); } diff --git a/addons/katesql/dataoutputview.cpp b/addons/katesql/dataoutputview.cpp index 3771d75d7..e96589870 100644 --- a/addons/katesql/dataoutputview.cpp +++ b/addons/katesql/dataoutputview.cpp @@ -1,44 +1,45 @@ /* Copyright (C) 2010 Marco Mentasti 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 "dataoutputview.h" #include #include #include DataOutputView::DataOutputView(QWidget *parent) : QTableView(parent) { setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotCustomContextMenuRequested(QPoint))); + connect(this, &DataOutputView::customContextMenuRequested, + this, &DataOutputView::slotCustomContextMenuRequested); } void DataOutputView::slotCustomContextMenuRequested(const QPoint &pos) { Q_UNUSED(pos); QMenu menu; menu.addActions(actions()); menu.exec(QCursor::pos()); } diff --git a/addons/katesql/dataoutputwidget.cpp b/addons/katesql/dataoutputwidget.cpp index ebb35ca22..092f6752e 100644 --- a/addons/katesql/dataoutputwidget.cpp +++ b/addons/katesql/dataoutputwidget.cpp @@ -1,379 +1,379 @@ /* Copyright (C) 2010 Marco Mentasti 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 "dataoutputwidget.h" #include "dataoutputmodel.h" #include "dataoutputview.h" #include "exportwizard.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DataOutputWidget::DataOutputWidget(QWidget *parent) : QWidget(parent) , m_model(new DataOutputModel(this)) , m_view(new DataOutputView(this)) , m_isEmpty(true) { m_view->setModel(m_model); QHBoxLayout *layout = new QHBoxLayout(this); m_dataLayout = new QVBoxLayout(); KToolBar *toolbar = new KToolBar(this); toolbar->setOrientation(Qt::Vertical); toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); toolbar->setIconSize(QSize(16, 16)); /// TODO: disable actions if no results are displayed or selected QAction *action; action = new QAction( QIcon::fromTheme(QLatin1String("distribute-horizontal-x")), i18nc("@action:intoolbar", "Resize columns to contents"), this); toolbar->addAction(action); - connect(action, SIGNAL(triggered()), this, SLOT(resizeColumnsToContents())); + connect(action, &QAction::triggered, this, &DataOutputWidget::resizeColumnsToContents); action = new QAction( QIcon::fromTheme(QLatin1String("distribute-vertical-y")), i18nc("@action:intoolbar", "Resize rows to contents"), this); toolbar->addAction(action); - connect(action, SIGNAL(triggered()), this, SLOT(resizeRowsToContents())); + connect(action, &QAction::triggered, this, &DataOutputWidget::resizeRowsToContents); action = new QAction( QIcon::fromTheme(QLatin1String("edit-copy")), i18nc("@action:intoolbar", "Copy"), this); toolbar->addAction(action); m_view->addAction(action); - connect(action, SIGNAL(triggered()), this, SLOT(slotCopySelected())); + connect(action, &QAction::triggered, this, &DataOutputWidget::slotCopySelected); action = new QAction( QIcon::fromTheme(QLatin1String("document-export-table")), i18nc("@action:intoolbar", "Export..."), this); toolbar->addAction(action); m_view->addAction(action); - connect(action, SIGNAL(triggered()), this, SLOT(slotExport())); + connect(action, &QAction::triggered, this, &DataOutputWidget::slotExport); action = new QAction( QIcon::fromTheme(QLatin1String("edit-clear")), i18nc("@action:intoolbar", "Clear"), this); toolbar->addAction(action); - connect(action, SIGNAL(triggered()), this, SLOT(clearResults())); + connect(action, &QAction::triggered, this, &DataOutputWidget::clearResults); toolbar->addSeparator(); KToggleAction *toggleAction = new KToggleAction( QIcon::fromTheme(QLatin1String("applications-education-language")), i18nc("@action:intoolbar", "Use system locale"), this); toolbar->addAction(toggleAction); - connect(toggleAction, SIGNAL(triggered()), this, SLOT(slotToggleLocale())); + connect(action, &QAction::triggered, this, &DataOutputWidget::slotToggleLocale); m_dataLayout->addWidget(m_view); layout->addWidget(toolbar); layout->addLayout(m_dataLayout); layout->setContentsMargins(0, 0, 0, 0); setLayout(layout); } DataOutputWidget::~DataOutputWidget() { } void DataOutputWidget::showQueryResultSets(QSqlQuery &query) { /// TODO: loop resultsets if > 1 /// NOTE from Qt Documentation: /// When one of the statements is a non-select statement a count of affected rows /// may be available instead of a result set. if (!query.isSelect() || query.lastError().isValid()) return; m_model->setQuery(query); m_isEmpty = false; QTimer::singleShot(0, this, SLOT(resizeColumnsToContents())); raise(); } void DataOutputWidget::clearResults() { // avoid crash when calling QSqlQueryModel::clear() after removing connection from the QSqlDatabase list if (m_isEmpty) return; m_model->clear(); m_isEmpty = true; /// HACK needed to refresh headers. please correct if there's a better way m_view->horizontalHeader()->hide(); m_view->verticalHeader()->hide(); m_view->horizontalHeader()->show(); m_view->verticalHeader()->show(); } void DataOutputWidget::resizeColumnsToContents() { if (m_model->rowCount() == 0) return; m_view->resizeColumnsToContents(); } void DataOutputWidget::resizeRowsToContents() { if (m_model->rowCount() == 0) return; m_view->resizeRowsToContents(); int h = m_view->rowHeight(0); if (h > 0) m_view->verticalHeader()->setDefaultSectionSize(h); } void DataOutputWidget::slotToggleLocale() { m_model->setUseSystemLocale(!m_model->useSystemLocale()); } void DataOutputWidget::slotCopySelected() { if (m_model->rowCount() <= 0) return; while (m_model->canFetchMore()) m_model->fetchMore(); if (!m_view->selectionModel()->hasSelection()) m_view->selectAll(); QString text; QTextStream stream(&text); exportData(stream); if (!text.isEmpty()) QApplication::clipboard()->setText(text); } void DataOutputWidget::slotExport() { if (m_model->rowCount() <= 0) return; while (m_model->canFetchMore()) m_model->fetchMore(); if (!m_view->selectionModel()->hasSelection()) m_view->selectAll(); ExportWizard wizard(this); if (wizard.exec() != QDialog::Accepted) return; bool outputInDocument = wizard.field(QLatin1String("outDocument")).toBool(); bool outputInClipboard = wizard.field(QLatin1String("outClipboard")).toBool(); bool outputInFile = wizard.field(QLatin1String("outFile")).toBool(); bool exportColumnNames = wizard.field(QLatin1String("exportColumnNames")).toBool(); bool exportLineNumbers = wizard.field(QLatin1String("exportLineNumbers")).toBool(); Options opt = NoOptions; if (exportColumnNames) opt |= ExportColumnNames; if (exportLineNumbers) opt |= ExportLineNumbers; bool quoteStrings = wizard.field(QLatin1String("checkQuoteStrings")).toBool(); bool quoteNumbers = wizard.field(QLatin1String("checkQuoteNumbers")).toBool(); QChar stringsQuoteChar = (quoteStrings) ? wizard.field(QLatin1String("quoteStringsChar")).toString().at(0) : QLatin1Char('\0'); QChar numbersQuoteChar = (quoteNumbers) ? wizard.field(QLatin1String("quoteNumbersChar")).toString().at(0) : QLatin1Char('\0'); QString fieldDelimiter = wizard.field(QLatin1String("fieldDelimiter")).toString(); if (outputInDocument) { KTextEditor::MainWindow *mw = KTextEditor::Editor::instance()->application()->activeMainWindow(); KTextEditor::View *kv = mw->activeView(); if (!kv) return; QString text; QTextStream stream(&text); exportData(stream, stringsQuoteChar, numbersQuoteChar, fieldDelimiter, opt); kv->insertText(text); kv->setFocus(); } else if (outputInClipboard) { QString text; QTextStream stream(&text); exportData(stream, stringsQuoteChar, numbersQuoteChar, fieldDelimiter, opt); QApplication::clipboard()->setText(text); } else if (outputInFile) { QString url = wizard.field(QLatin1String ("outFileUrl")).toString(); QFile data(url); if (data.open(QFile::WriteOnly | QFile::Truncate)) { QTextStream stream(&data); exportData(stream, stringsQuoteChar, numbersQuoteChar, fieldDelimiter, opt); stream.flush(); } else { KMessageBox::error(this, xi18nc("@info", "Unable to open file %1", url)); } } } void DataOutputWidget::exportData(QTextStream &stream, const QChar stringsQuoteChar, const QChar numbersQuoteChar, const QString fieldDelimiter, const Options opt) { QItemSelectionModel *selectionModel = m_view->selectionModel(); if (!selectionModel->hasSelection()) return; QString fixedFieldDelimiter = fieldDelimiter; /// FIXME: ugly workaround... fixedFieldDelimiter = fixedFieldDelimiter.replace(QLatin1String ("\\t"), QLatin1String ("\t")); fixedFieldDelimiter = fixedFieldDelimiter.replace(QLatin1String ("\\r"), QLatin1String ("\r")); fixedFieldDelimiter = fixedFieldDelimiter.replace(QLatin1String ("\\n"), QLatin1String ("\n")); QTime t; t.start(); QSet columns; QSet rows; QHash,QString> snapshot; const QModelIndexList selectedIndexes = selectionModel->selectedIndexes(); snapshot.reserve(selectedIndexes.count()); foreach (const QModelIndex& index, selectedIndexes) { const QVariant data = index.data(Qt::UserRole); const int col = index.column(); const int row = index.row(); if (!columns.contains(col)) columns.insert(col); if (!rows.contains(row)) rows.insert(row); if (data.type() < 7) // is numeric or boolean { if (numbersQuoteChar != QLatin1Char ('\0')) snapshot[qMakePair(row,col)] = numbersQuoteChar + data.toString() + numbersQuoteChar; else snapshot[qMakePair(row,col)] = data.toString(); } else { if (stringsQuoteChar != QLatin1Char ('\0')) snapshot[qMakePair(row,col)] = stringsQuoteChar + data.toString() + stringsQuoteChar; else snapshot[qMakePair(row,col)] = data.toString(); } } if (opt.testFlag(ExportColumnNames)) { if (opt.testFlag(ExportLineNumbers)) stream << fixedFieldDelimiter; QSetIterator j(columns); while (j.hasNext()) { const QVariant data = m_model->headerData(j.next(), Qt::Horizontal); if (stringsQuoteChar != QLatin1Char ('\0')) stream << stringsQuoteChar + data.toString() + stringsQuoteChar; else stream << data.toString(); if (j.hasNext()) stream << fixedFieldDelimiter; } stream << "\n"; } foreach(const int row, rows) { if (opt.testFlag(ExportLineNumbers)) stream << row + 1 << fixedFieldDelimiter; QSetIterator j(columns); while (j.hasNext()) { stream << snapshot.value(qMakePair(row,j.next())); if (j.hasNext()) stream << fixedFieldDelimiter; } stream << "\n"; } qDebug() << "Export in" << t.elapsed() << "msecs"; } diff --git a/addons/katesql/exportwizard.cpp b/addons/katesql/exportwizard.cpp index 600bb88f9..2cac9cc7e 100644 --- a/addons/katesql/exportwizard.cpp +++ b/addons/katesql/exportwizard.cpp @@ -1,207 +1,207 @@ /* Copyright (C) 2010 Marco Mentasti 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 "exportwizard.h" #include "dataoutputwidget.h" #include #include #include #include #include #include #include #include #include #include //BEGIN ExportWizard ExportWizard::ExportWizard(QWidget *parent) : QWizard(parent) { setWindowTitle(i18nc("@title:window", "Export Wizard")); addPage(new ExportOutputPage(this)); addPage(new ExportFormatPage(this)); } ExportWizard::~ExportWizard() { } //END ExportWizard //BEGIN ExportOutputPage ExportOutputPage::ExportOutputPage(QWidget *parent) : QWizardPage(parent) { setTitle(i18nc("@title Wizard page title", "Output Target")); setSubTitle(i18nc("@title Wizard page subtitle", "Select the output target.")); QVBoxLayout *layout = new QVBoxLayout(); documentRadioButton = new QRadioButton(i18nc("@option:radio Output target", "Current document"), this); clipboardRadioButton = new QRadioButton(i18nc("@option:radio Output target", "Clipboard"), this); fileRadioButton = new QRadioButton(i18nc("@option:radio Output target", "File"), this); QHBoxLayout *fileLayout = new QHBoxLayout(); fileLayout->setContentsMargins(20, 0, 0, 0); fileUrl = new KUrlRequester(this); fileUrl->setMode(KFile::File); fileUrl->setFilter(i18n("*.csv|Comma Separated Values\n*|All files")); fileLayout->addWidget(fileUrl); layout->addWidget(documentRadioButton); layout->addWidget(clipboardRadioButton); layout->addWidget(fileRadioButton); layout->addLayout(fileLayout); setLayout(layout); registerField(QLatin1String("outDocument"), documentRadioButton); registerField(QLatin1String("outClipboard"), clipboardRadioButton); registerField(QLatin1String("outFile"), fileRadioButton); registerField(QLatin1String("outFileUrl"), fileUrl, "text"); - connect(fileRadioButton, SIGNAL(toggled(bool)), fileUrl, SLOT(setEnabled(bool))); + connect(fileRadioButton, &QRadioButton::toggled, fileUrl, &KUrlRequester::setEnabled); } void ExportOutputPage::initializePage() { documentRadioButton->setChecked(true); fileUrl->setEnabled(false); } bool ExportOutputPage::validatePage() { if (fileRadioButton->isChecked() && fileUrl->text().isEmpty()) { fileUrl->setFocus(); return false; } /// TODO: check url validity return true; } //END ExportOutputPage //BEGIN ExportFormatPage ExportFormatPage::ExportFormatPage(QWidget *parent) : QWizardPage(parent) { setTitle(i18nc("@title Wizard page title", "Fields Format")); setSubTitle(i18nc("@title Wizard page subtitle", "Select fields format.\nClick on \"Finish\" button to export data.")); QVBoxLayout *layout = new QVBoxLayout(); QGroupBox *headersGroupBox = new QGroupBox(i18nc("@title:group", "Headers"), this); QVBoxLayout *headersLayout = new QVBoxLayout(); exportColumnNamesCheckBox = new QCheckBox(i18nc("@option:check", "Export column names"), headersGroupBox); exportLineNumbersCheckBox = new QCheckBox(i18nc("@option:check", "Export line numbers"), headersGroupBox); headersLayout->addWidget(exportColumnNamesCheckBox); headersLayout->addWidget(exportLineNumbersCheckBox); headersGroupBox->setLayout(headersLayout); QGroupBox *quoteGroupBox = new QGroupBox(i18nc("@title:group", "Quotes"), this); QGridLayout *quoteLayout = new QGridLayout(); quoteStringsCheckBox = new QCheckBox(i18nc("@option:check", "Quote strings"), quoteGroupBox); quoteNumbersCheckBox = new QCheckBox(i18nc("@option:check", "Quote numbers"), quoteGroupBox); quoteStringsLine = new KLineEdit(quoteGroupBox); quoteNumbersLine = new KLineEdit(quoteGroupBox); quoteStringsLine->setMaxLength(1); quoteNumbersLine->setMaxLength(1); quoteLayout->addWidget(quoteStringsCheckBox, 0, 0, Qt::AlignLeft | Qt::AlignVCenter); quoteLayout->addWidget(new QLabel(i18nc("@label:textbox", "Character:")), 0, 1, Qt::AlignRight | Qt::AlignVCenter); quoteLayout->addWidget(quoteStringsLine, 0, 2, Qt::AlignRight | Qt::AlignVCenter); quoteLayout->addWidget(quoteNumbersCheckBox, 1, 0, Qt::AlignLeft | Qt::AlignVCenter); quoteLayout->addWidget(new QLabel(i18nc("@label:textbox", "Character:")), 1, 1, Qt::AlignRight | Qt::AlignVCenter); quoteLayout->addWidget(quoteNumbersLine, 1, 2, Qt::AlignRight | Qt::AlignVCenter); quoteLayout->setColumnStretch(1, 1); quoteGroupBox->setLayout(quoteLayout); QGroupBox *delimitersGroupBox = new QGroupBox(i18nc("@title:group", "Delimiters"), this); QFormLayout *delimitersLayout = new QFormLayout(); fieldDelimiterLine = new KLineEdit(delimitersGroupBox); fieldDelimiterLine->setMaxLength(3); delimitersLayout->addRow(i18nc("@label:textbox", "Field delimiter:"), fieldDelimiterLine); delimitersGroupBox->setLayout(delimitersLayout); layout->addWidget(headersGroupBox); layout->addWidget(quoteGroupBox); layout->addWidget(delimitersGroupBox); setLayout(layout); registerField(QLatin1String("exportColumnNames"), exportColumnNamesCheckBox); registerField(QLatin1String("exportLineNumbers"), exportLineNumbersCheckBox); registerField(QLatin1String("checkQuoteStrings"), quoteStringsCheckBox); registerField(QLatin1String("checkQuoteNumbers"), quoteNumbersCheckBox); registerField(QLatin1String("quoteStringsChar"), quoteStringsLine); registerField(QLatin1String("quoteNumbersChar"), quoteNumbersLine); registerField(QLatin1String("fieldDelimiter*"), fieldDelimiterLine); - connect(quoteStringsCheckBox, SIGNAL(toggled(bool)), quoteStringsLine, SLOT(setEnabled(bool))); - connect(quoteNumbersCheckBox, SIGNAL(toggled(bool)), quoteNumbersLine, SLOT(setEnabled(bool))); + connect(quoteStringsCheckBox, &QCheckBox::toggled, quoteStringsLine, &KLineEdit::setEnabled); + connect(quoteNumbersCheckBox, &QCheckBox::toggled, quoteNumbersLine, &KLineEdit::setEnabled); } void ExportFormatPage::initializePage() { exportColumnNamesCheckBox->setChecked(true); exportLineNumbersCheckBox->setChecked(false); quoteStringsCheckBox->setChecked(false); quoteNumbersCheckBox->setChecked(false); quoteStringsLine->setEnabled(false); quoteNumbersLine->setEnabled(false); quoteStringsLine->setText(QLatin1String("\"")); quoteNumbersLine->setText(QLatin1String("\"")); fieldDelimiterLine->setText(QLatin1String("\\t")); } bool ExportFormatPage::validatePage() { if ((quoteStringsCheckBox->isChecked() && quoteStringsLine->text().isEmpty()) || (quoteNumbersCheckBox->isChecked() && quoteNumbersLine->text().isEmpty())) return false; if (fieldDelimiterLine->text().isEmpty()) return false; return true; } //END ExportFormatPage diff --git a/addons/katesql/katesqlconfigpage.cpp b/addons/katesql/katesqlconfigpage.cpp index 095b98810..e933a789c 100644 --- a/addons/katesql/katesqlconfigpage.cpp +++ b/addons/katesql/katesqlconfigpage.cpp @@ -1,105 +1,105 @@ /* Copyright (C) 2010 Marco Mentasti 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 "katesqlconfigpage.h" #include "outputstylewidget.h" #include #include #include #include #include #include KateSQLConfigPage::KateSQLConfigPage( QWidget* parent ) : KTextEditor::ConfigPage( parent ) { QVBoxLayout *layout = new QVBoxLayout( this ); m_box = new QCheckBox(i18nc("@option:check", "Save and restore connections in Kate session"), this); QGroupBox *stylesGroupBox = new QGroupBox(i18nc("@title:group", "Output Customization"), this); QVBoxLayout *stylesLayout = new QVBoxLayout(stylesGroupBox); m_outputStyleWidget = new OutputStyleWidget(this); stylesLayout->addWidget(m_outputStyleWidget); layout->addWidget(m_box); layout->addWidget(stylesGroupBox, 1); setLayout(layout); reset(); - connect(m_box, SIGNAL(stateChanged(int)), this, SIGNAL(changed())); - connect(m_outputStyleWidget, SIGNAL(changed()), this, SIGNAL(changed())); + connect(m_box, &QCheckBox::stateChanged, this, &KateSQLConfigPage::changed); + connect(m_outputStyleWidget, &OutputStyleWidget::changed, this, &KateSQLConfigPage::changed); } KateSQLConfigPage::~KateSQLConfigPage() { } QString KateSQLConfigPage::name() const { return i18nc("@title", "SQL"); } QString KateSQLConfigPage::fullName() const { return i18nc("@title:window", "SQL ConfigPage Settings"); } QIcon KateSQLConfigPage::icon() const { return QIcon::fromTheme(QLatin1String ("server-database")); } void KateSQLConfigPage::apply() { KConfigGroup config(KSharedConfig::openConfig(), "KateSQLPlugin"); config.writeEntry("SaveConnections", m_box->isChecked()); m_outputStyleWidget->writeConfig(); config.sync(); emit settingsChanged(); } void KateSQLConfigPage::reset() { KConfigGroup config(KSharedConfig::openConfig(), "KateSQLPlugin"); m_box->setChecked(config.readEntry("SaveConnections", true)); m_outputStyleWidget->readConfig(); } void KateSQLConfigPage::defaults() { KConfigGroup config(KSharedConfig::openConfig(), "KateSQLPlugin"); config.revertToDefault("SaveConnections"); config.revertToDefault("OutputCustomization"); } diff --git a/addons/katesql/katesqlplugin.cpp b/addons/katesql/katesqlplugin.cpp index 7dbfe300e..80db8860f 100644 --- a/addons/katesql/katesqlplugin.cpp +++ b/addons/katesql/katesqlplugin.cpp @@ -1,69 +1,68 @@ /* Copyright (C) 2010 Marco Mentasti 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 "katesqlplugin.h" #include "katesqlconfigpage.h" #include "katesqlview.h" #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KateSQLFactory, "katesql.json", registerPlugin();) //BEGIN KateSQLPLugin KateSQLPlugin::KateSQLPlugin(QObject *parent, const QList&) : KTextEditor::Plugin (parent) { } KateSQLPlugin::~KateSQLPlugin() { } QObject *KateSQLPlugin::createView (KTextEditor::MainWindow *mainWindow) { KateSQLView *view = new KateSQLView(this, mainWindow); - connect(this, SIGNAL(globalSettingsChanged()), view, SLOT(slotGlobalSettingsChanged())); + connect(this, &KateSQLPlugin::globalSettingsChanged, view, &KateSQLView::slotGlobalSettingsChanged); return view; } KTextEditor::ConfigPage* KateSQLPlugin::configPage(int number, QWidget *parent) { if (number != 0) return nullptr; KateSQLConfigPage *page = new KateSQLConfigPage(parent); - - connect(page, SIGNAL(settingsChanged()), this, SIGNAL(globalSettingsChanged())); + connect(page, &KateSQLConfigPage::settingsChanged, this, &KateSQLPlugin::globalSettingsChanged); return page; } //END KateSQLPlugin #include "katesqlplugin.moc" diff --git a/addons/katesql/katesqlview.cpp b/addons/katesql/katesqlview.cpp index 89901c434..92ab518b1 100644 --- a/addons/katesql/katesqlview.cpp +++ b/addons/katesql/katesqlview.cpp @@ -1,392 +1,391 @@ /* Copyright (C) 2010 Marco Mentasti 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 "katesqlview.h" #include "katesqlplugin.h" #include "sqlmanager.h" #include "connectionmodel.h" #include "textoutputwidget.h" #include "dataoutputwidget.h" #include "dataoutputmodel.h" #include "dataoutputview.h" #include "schemawidget.h" #include "schemabrowserwidget.h" #include "connectionwizard.h" #include "outputwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KateSQLView::KateSQLView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mw) : QObject (mw) , KXMLGUIClient() , m_manager (new SQLManager(this)) , m_mainWindow (mw) { KXMLGUIClient::setComponentName (QLatin1String("katesql"), i18n ("Kate SQL Plugin")); setXMLFile( QLatin1String("ui.rc") ); m_outputToolView = mw->createToolView(plugin, QLatin1String ("kate_private_plugin_katesql_output"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme (QLatin1String ("view-form-table")), i18nc("@title:window", "SQL Results") ); m_schemaBrowserToolView = mw->createToolView(plugin, QLatin1String ("kate_private_plugin_katesql_schemabrowser"), KTextEditor::MainWindow::Left, QIcon::fromTheme (QLatin1String ("view-list-tree")), i18nc("@title:window", "SQL Schema Browser") ); m_outputWidget = new KateSQLOutputWidget(m_outputToolView); m_schemaBrowserWidget = new SchemaBrowserWidget(m_schemaBrowserToolView, m_manager); m_connectionsComboBox = new KComboBox(false); m_connectionsComboBox->setEditable(false); m_connectionsComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); m_connectionsComboBox->setModel(m_manager->connectionModel()); setupActions(); m_mainWindow->guiFactory()->addClient(this); QMenu *sqlMenu = (QMenu*)factory()->container(QLatin1String ("SQL"), this); m_connectionsGroup = new QActionGroup(sqlMenu); m_connectionsGroup->setExclusive(true); - connect(sqlMenu, SIGNAL(aboutToShow()), this, SLOT(slotSQLMenuAboutToShow())); - connect(m_connectionsGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotConnectionSelectedFromMenu(QAction*))); - - connect(m_manager, SIGNAL(error(QString)), this, SLOT(slotError(QString))); - connect(m_manager, SIGNAL(success(QString)), this, SLOT(slotSuccess(QString))); - connect(m_manager, SIGNAL(queryActivated(QSqlQuery&,QString)), this, SLOT(slotQueryActivated(QSqlQuery&,QString))); - connect(m_manager, SIGNAL(connectionCreated(QString)), this, SLOT(slotConnectionCreated(QString))); - connect(m_manager, SIGNAL(connectionAboutToBeClosed(QString)), this, SLOT(slotConnectionAboutToBeClosed(QString))); - connect(m_connectionsComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotConnectionChanged(QString))); + connect(sqlMenu, &QMenu::aboutToShow, this, &KateSQLView::slotSQLMenuAboutToShow); + connect(m_connectionsGroup, &QActionGroup::triggered, this, &KateSQLView::slotConnectionSelectedFromMenu); + connect(m_manager, &SQLManager::error, this, &KateSQLView::slotError); + connect(m_manager, &SQLManager::success, this, &KateSQLView::slotSuccess); + connect(m_manager, &SQLManager::queryActivated, this, &KateSQLView::slotQueryActivated); + connect(m_manager, &SQLManager::connectionCreated, this, &KateSQLView::slotConnectionCreated); + connect(m_manager, &SQLManager::connectionAboutToBeClosed, this, &KateSQLView::slotConnectionAboutToBeClosed); + connect(m_connectionsComboBox, static_cast(&KComboBox::currentIndexChanged), this, &KateSQLView::slotConnectionChanged); stateChanged(QLatin1String ("has_connection_selected"), KXMLGUIClient::StateReverse); } KateSQLView::~KateSQLView() { m_mainWindow->guiFactory()->removeClient( this ); delete m_outputToolView; delete m_schemaBrowserToolView; delete m_manager; } void KateSQLView::setupActions() { QAction* action; KActionCollection* collection = actionCollection(); action = collection->addAction(QLatin1String ("connection_create")); action->setText( i18nc("@action:inmenu", "Add connection...") ); action->setIcon( QIcon::fromTheme (QLatin1String ("list-add")) ); - connect( action , SIGNAL(triggered()) , this , SLOT(slotConnectionCreate()) ); + connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionCreate); action = collection->addAction(QLatin1String ("connection_remove")); action->setText( i18nc("@action:inmenu", "Remove connection") ); action->setIcon( QIcon::fromTheme (QLatin1String ("list-remove")) ); - connect( action , SIGNAL(triggered()) , this , SLOT(slotConnectionRemove()) ); + connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionRemove); action = collection->addAction(QLatin1String ("connection_edit")); action->setText( i18nc("@action:inmenu", "Edit connection...") ); action->setIcon( QIcon::fromTheme (QLatin1String ("configure")) ); - connect( action , SIGNAL(triggered()) , this , SLOT(slotConnectionEdit()) ); + connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionEdit); action = collection->addAction(QLatin1String ("connection_reconnect")); action->setText( i18nc("@action:inmenu", "Reconnect") ); action->setIcon( QIcon::fromTheme (QLatin1String ("view-refresh")) ); - connect( action , SIGNAL(triggered()) , this , SLOT(slotConnectionReconnect()) ); + connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionReconnect); QWidgetAction *wa = new QWidgetAction(this); collection->addAction(QLatin1String ("connection_chooser"), wa); wa->setText( i18nc("@action:intoolbar", "Connection") ); wa->setDefaultWidget(m_connectionsComboBox); action = collection->addAction(QLatin1String ("query_run")); action->setText( i18nc("@action:inmenu", "Run query") ); action->setIcon( QIcon::fromTheme (QLatin1String ("quickopen")) ); collection->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_E) ); - connect( action , SIGNAL(triggered()) , this , SLOT(slotRunQuery())); + connect(action, &QAction::triggered, this, &KateSQLView::slotRunQuery); /// TODO: stop sql query // action = collection->addAction("sql_stop"); // action->setText( i18n("Stop query") ); // action->setIcon( KIcon("process-stop") ); // action->setShortcut( QKeySequence(Qt::ALT + Qt::Key_F5) ); // connect( action , SIGNAL(triggered()) , this , SLOT(stopQuery())); } void KateSQLView::slotSQLMenuAboutToShow() { qDeleteAll( m_connectionsGroup->actions() ); QMenu *sqlMenu = (QMenu*)factory()->container(QLatin1String ("SQL"), this); QAction *before = action("query_run"); QAbstractItemModel *model = m_manager->connectionModel(); int rows = model->rowCount(QModelIndex()); for (int row = 0; row < rows; row++) { QModelIndex index = model->index(row, 0, QModelIndex()); Q_ASSERT(index.isValid()); QString connectionName = index.data(Qt::DisplayRole).toString(); QAction *act = new QAction(connectionName, m_connectionsGroup); act->setCheckable(true); if (m_connectionsComboBox->currentText() == connectionName) act->setChecked(true); sqlMenu->insertAction(before, act); } sqlMenu->insertSeparator(before); } void KateSQLView::slotConnectionSelectedFromMenu(QAction *action) { m_connectionsComboBox->setCurrentItem(action->text()); } void KateSQLView::slotConnectionChanged(const QString &connection) { stateChanged(QLatin1String ("has_connection_selected"), (connection.isEmpty()) ? KXMLGUIClient::StateReverse : KXMLGUIClient::StateNoReverse); m_schemaBrowserWidget->schemaWidget()->buildTree(connection); } void KateSQLView::slotGlobalSettingsChanged() { m_outputWidget->dataOutputWidget()->model()->readConfig(); } void KateSQLView::readSessionConfig (KConfigBase* config, const QString& groupPrefix) { KConfigGroup globalConfig(KSharedConfig::openConfig(), "KateSQLPlugin"); bool saveConnections = globalConfig.readEntry("SaveConnections", true); if (!saveConnections) return; KConfigGroup group(config, groupPrefix + QLatin1String (":connections")); m_manager->loadConnections(&group); QString lastConnection = group.readEntry("LastUsed"); if (m_connectionsComboBox->contains(lastConnection)) m_connectionsComboBox->setCurrentItem(lastConnection); } void KateSQLView::writeSessionConfig (KConfigBase* config, const QString& groupPrefix) { KConfigGroup group(config, groupPrefix + QLatin1String (":connections")); group.deleteGroup(); KConfigGroup globalConfig(KSharedConfig::openConfig(), "KateSQLPlugin"); bool saveConnections = globalConfig.readEntry("SaveConnections", true); if (saveConnections) { m_manager->saveConnections(&group); group.writeEntry("LastUsed", m_connectionsComboBox->currentText()); } config->sync(); } void KateSQLView::slotConnectionCreate() { Connection c; ConnectionWizard wizard(m_manager, &c); if (wizard.exec() != QDialog::Accepted) return; for (int i = 1; QSqlDatabase::contains(c.name); i++) c.name = QString::fromLatin1("%1 (%2)").arg(c.name).arg(i); m_manager->createConnection(c); if (m_manager->storeCredentials(c) != 0) qDebug() << "Connection credentials not saved"; } void KateSQLView::slotConnectionEdit() { int i = m_connectionsComboBox->currentIndex(); if (i == -1) return; ConnectionModel *model = m_manager->connectionModel(); Connection c = model->data(model->index(i), Qt::UserRole).value(); QString previousName = c.name; ConnectionWizard wizard(m_manager, &c); if (wizard.exec() != QDialog::Accepted) return; m_manager->removeConnection(previousName); m_manager->createConnection(c); if (m_manager->storeCredentials(c) != 0) qDebug() << "Connection credentials not saved"; } void KateSQLView::slotConnectionRemove() { QString connection = m_connectionsComboBox->currentText(); if (!connection.isEmpty()) m_manager->removeConnection(connection); } void KateSQLView::slotConnectionReconnect() { QString connection = m_connectionsComboBox->currentText(); if (!connection.isEmpty()) m_manager->reopenConnection(connection); } void KateSQLView::slotConnectionAboutToBeClosed (const QString& name) { /// must delete the QSqlQuery object inside the model before closing connection if (name == m_currentResultsetConnection) m_outputWidget->dataOutputWidget()->clearResults(); } void KateSQLView::slotRunQuery() { /// TODO: /// bind parameters dialog? QString connection = m_connectionsComboBox->currentText(); if (connection.isEmpty()) { slotConnectionCreate(); return; } KTextEditor::View *view = m_mainWindow->activeView(); if (!view) return; QString text = (view->selection()) ? view->selectionText() : view->document()->text(); text = text.trimmed(); if (text.isEmpty()) return; m_manager->runQuery(text, connection); } void KateSQLView::slotError(const QString &message) { m_outputWidget->textOutputWidget()->showErrorMessage(message); m_outputWidget->setCurrentWidget(m_outputWidget->textOutputWidget()); m_mainWindow->showToolView(m_outputToolView); } void KateSQLView::slotSuccess(const QString &message) { m_outputWidget->textOutputWidget()->showSuccessMessage(message); m_outputWidget->setCurrentWidget(m_outputWidget->textOutputWidget()); m_mainWindow->showToolView(m_outputToolView); } void KateSQLView::slotQueryActivated(QSqlQuery &query, const QString &connection) { if (query.isSelect()) { m_currentResultsetConnection = connection; m_outputWidget->dataOutputWidget()->showQueryResultSets(query); m_outputWidget->setCurrentWidget(m_outputWidget->dataOutputWidget()); m_mainWindow->showToolView(m_outputToolView); } } void KateSQLView::slotConnectionCreated(const QString &name) { m_connectionsComboBox->setCurrentItem(name); m_schemaBrowserWidget->schemaWidget()->buildTree(name); } //END KateSQLView diff --git a/addons/katesql/outputstylewidget.cpp b/addons/katesql/outputstylewidget.cpp index 2774b1d32..181a4a24f 100644 --- a/addons/katesql/outputstylewidget.cpp +++ b/addons/katesql/outputstylewidget.cpp @@ -1,217 +1,217 @@ /* Copyright (C) 2010 Marco Mentasti 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 "outputstylewidget.h" #include #include #include #include #include #include #include #include #include #include #include #include OutputStyleWidget::OutputStyleWidget(QWidget *parent) : QTreeWidget(parent) { setColumnCount(7); setRootIsDecorated(false); QStringList headerLabels; headerLabels << i18nc("@title:column", "Context") << QString() << QString() << QString() << QString() << i18nc("@title:column", "Text Color") << i18nc("@title:column", "Background Color"); setHeaderLabels(headerLabels); headerItem()->setIcon(1, QIcon::fromTheme(QLatin1String("format-text-bold"))); headerItem()->setIcon(2, QIcon::fromTheme(QLatin1String("format-text-italic"))); headerItem()->setIcon(3, QIcon::fromTheme(QLatin1String("format-text-underline"))); headerItem()->setIcon(4, QIcon::fromTheme(QLatin1String("format-text-strikethrough"))); addContext(QLatin1String("text"), i18nc("@item:intable", "Text")); addContext(QLatin1String("number"), i18nc("@item:intable", "Number")); addContext(QLatin1String("bool"), i18nc("@item:intable", "Bool")); addContext(QLatin1String("datetime"), i18nc("@item:intable", "Date & Time")); addContext(QLatin1String("null"), i18nc("@item:intable", "NULL")); addContext(QLatin1String("blob"), i18nc("@item:intable", "BLOB")); for (int i = 0; i < columnCount(); ++i) resizeColumnToContents(i); updatePreviews(); } OutputStyleWidget::~OutputStyleWidget() { } QTreeWidgetItem* OutputStyleWidget::addContext(const QString &key, const QString &name) { QTreeWidgetItem *item = new QTreeWidgetItem(this); item->setText(0, name); item->setData(0, Qt::UserRole, key); QCheckBox *boldCheckBox = new QCheckBox(this); QCheckBox *italicCheckBox = new QCheckBox(this); QCheckBox *underlineCheckBox = new QCheckBox(this); QCheckBox *strikeOutCheckBox = new QCheckBox(this); KColorButton *foregroundColorButton = new KColorButton(this); KColorButton *backgroundColorButton = new KColorButton(this); const KColorScheme scheme(QPalette::Active, KColorScheme::View); foregroundColorButton->setDefaultColor(scheme.foreground().color()); backgroundColorButton->setDefaultColor(scheme.background().color()); setItemWidget(item, 1, boldCheckBox); setItemWidget(item, 2, italicCheckBox); setItemWidget(item, 3, underlineCheckBox); setItemWidget(item, 4, strikeOutCheckBox); setItemWidget(item, 5, foregroundColorButton); setItemWidget(item, 6, backgroundColorButton); readConfig(item); - connect(boldCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotChanged())); - connect(italicCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotChanged())); - connect(underlineCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotChanged())); - connect(strikeOutCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotChanged())); - connect(foregroundColorButton, SIGNAL(changed(QColor)), this, SLOT(slotChanged())); - connect(backgroundColorButton, SIGNAL(changed(QColor)), this, SLOT(slotChanged())); + connect(boldCheckBox, &QCheckBox::toggled, this, &OutputStyleWidget::slotChanged); + connect(italicCheckBox, &QCheckBox::toggled, this, &OutputStyleWidget::slotChanged); + connect(underlineCheckBox, &QCheckBox::toggled, this, &OutputStyleWidget::slotChanged); + connect(strikeOutCheckBox, &QCheckBox::toggled, this, &OutputStyleWidget::slotChanged); + connect(foregroundColorButton, &KColorButton::changed, this, &OutputStyleWidget::slotChanged); + connect(backgroundColorButton, &KColorButton::changed, this, &OutputStyleWidget::slotChanged); return item; } void OutputStyleWidget::readConfig(QTreeWidgetItem *item) { KConfigGroup config(KSharedConfig::openConfig(), "KateSQLPlugin"); KConfigGroup g = config.group("OutputCustomization").group(item->data(0, Qt::UserRole).toString()); QCheckBox *boldCheckBox = static_cast(itemWidget(item, 1)); QCheckBox *italicCheckBox = static_cast(itemWidget(item, 2)); QCheckBox *underlineCheckBox = static_cast(itemWidget(item, 3)); QCheckBox *strikeOutCheckBox = static_cast(itemWidget(item, 4)); KColorButton *foregroundColorButton = static_cast(itemWidget(item, 5)); KColorButton *backgroundColorButton = static_cast(itemWidget(item, 6)); const QFont font = g.readEntry("font", QFontDatabase::systemFont(QFontDatabase::GeneralFont)); boldCheckBox->setChecked(font.bold()); italicCheckBox->setChecked(font.italic()); underlineCheckBox->setChecked(font.underline()); strikeOutCheckBox->setChecked(font.strikeOut()); foregroundColorButton->setColor(g.readEntry("foregroundColor", foregroundColorButton->defaultColor())); backgroundColorButton->setColor(g.readEntry("backgroundColor", backgroundColorButton->defaultColor())); } void OutputStyleWidget::writeConfig(QTreeWidgetItem *item) { KConfigGroup config(KSharedConfig::openConfig(), "KateSQLPlugin"); KConfigGroup g = config.group("OutputCustomization").group(item->data(0, Qt::UserRole).toString()); QCheckBox *boldCheckBox = static_cast(itemWidget(item, 1)); QCheckBox *italicCheckBox = static_cast(itemWidget(item, 2)); QCheckBox *underlineCheckBox = static_cast(itemWidget(item, 3)); QCheckBox *strikeOutCheckBox = static_cast(itemWidget(item, 4)); KColorButton *foregroundColorButton = static_cast(itemWidget(item, 5)); KColorButton *backgroundColorButton = static_cast(itemWidget(item, 6)); QFont f(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); f.setBold(boldCheckBox->isChecked()); f.setItalic(italicCheckBox->isChecked()); f.setUnderline(underlineCheckBox->isChecked()); f.setStrikeOut(strikeOutCheckBox->isChecked()); g.writeEntry("font", f); g.writeEntry("foregroundColor", foregroundColorButton->color()); g.writeEntry("backgroundColor", backgroundColorButton->color()); } void OutputStyleWidget::readConfig() { QTreeWidgetItem *root = invisibleRootItem(); for (int i = 0; i < root->childCount(); ++i) readConfig(root->child(i)); } void OutputStyleWidget::writeConfig() { KConfigGroup config(KSharedConfig::openConfig(), "KateSQLPlugin"); config.deleteGroup("OutputCustomization"); QTreeWidgetItem *root = invisibleRootItem(); for (int i = 0; i < root->childCount(); ++i) writeConfig(root->child(i)); } void OutputStyleWidget::updatePreviews() { QTreeWidgetItem *root = invisibleRootItem(); for (int i = 0; i < root->childCount(); ++i) { QTreeWidgetItem *item = root->child(i); const QCheckBox *boldCheckBox = static_cast(itemWidget(item, 1)); const QCheckBox *italicCheckBox = static_cast(itemWidget(item, 2)); const QCheckBox *underlineCheckBox = static_cast(itemWidget(item, 3)); const QCheckBox *strikeOutCheckBox = static_cast(itemWidget(item, 4)); const KColorButton *foregroundColorButton = static_cast(itemWidget(item, 5)); const KColorButton *backgroundColorButton = static_cast(itemWidget(item, 6)); QFont f(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); f.setBold(boldCheckBox->isChecked()); f.setItalic(italicCheckBox->isChecked()); f.setUnderline(underlineCheckBox->isChecked()); f.setStrikeOut(strikeOutCheckBox->isChecked()); item->setFont(0, f); item->setForeground(0, foregroundColorButton->color()); item->setBackground(0, backgroundColorButton->color()); } } void OutputStyleWidget::slotChanged() { updatePreviews(); emit changed(); } diff --git a/addons/katesql/schemawidget.cpp b/addons/katesql/schemawidget.cpp index a8bc27a95..51c43e8a1 100644 --- a/addons/katesql/schemawidget.cpp +++ b/addons/katesql/schemawidget.cpp @@ -1,413 +1,413 @@ /* Copyright (C) 2010 Marco Mentasti 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 "schemawidget.h" #include "sqlmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SchemaWidget::SchemaWidget(QWidget *parent, SQLManager *manager) : QTreeWidget(parent) , m_manager(manager) { m_tablesLoaded = false; m_viewsLoaded = false; setHeaderLabels(QStringList() << i18nc("@title:column", "Database schema")); setContextMenuPolicy(Qt::CustomContextMenu); setDragDropMode(QAbstractItemView::DragOnly); setDragEnabled(true); setAcceptDrops(false); - connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotCustomContextMenuRequested(QPoint))); - connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotItemExpanded(QTreeWidgetItem*))); + connect(this, &SchemaWidget::customContextMenuRequested, this, &SchemaWidget::slotCustomContextMenuRequested); + connect(this, &SchemaWidget::itemExpanded, this, &SchemaWidget::slotItemExpanded); } SchemaWidget::~SchemaWidget() { } bool SchemaWidget::isConnectionValidAndOpen() { return m_manager->isValidAndOpen(m_connectionName); } void SchemaWidget::deleteChildren(QTreeWidgetItem *item) { QList items = item->takeChildren(); foreach (QTreeWidgetItem *i, items) delete i; } void SchemaWidget::buildTree(const QString &connection) { m_connectionName = connection; clear(); m_tablesLoaded = false; m_viewsLoaded = false; if (!m_connectionName.isEmpty()) buildDatabase(new QTreeWidgetItem(this)); } void SchemaWidget::refresh() { buildTree(m_connectionName); } void SchemaWidget::buildDatabase(QTreeWidgetItem * databaseItem) { QSqlDatabase db = QSqlDatabase::database(m_connectionName); QString dbname = (db.isValid() ? db.databaseName() : m_connectionName); databaseItem->setText(0, dbname); databaseItem->setIcon(0, QIcon::fromTheme(QLatin1String("server-database"))); QTreeWidgetItem *tablesItem = new QTreeWidgetItem(databaseItem, TablesFolderType); tablesItem->setText(0, i18nc("@title Folder name", "Tables")); tablesItem->setIcon(0, QIcon::fromTheme(QLatin1String("folder"))); tablesItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); QTreeWidgetItem *viewsItem = new QTreeWidgetItem(databaseItem, ViewsFolderType); viewsItem->setText(0, i18nc("@title Folder name", "Views")); viewsItem->setIcon(0, QIcon::fromTheme(QLatin1String("folder"))); viewsItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); databaseItem->setExpanded(true); } void SchemaWidget::buildTables(QTreeWidgetItem * tablesItem) { if (!isConnectionValidAndOpen()) return; QTreeWidgetItem *systemTablesItem = new QTreeWidgetItem(tablesItem, SystemTablesFolderType); systemTablesItem->setText(0, i18nc("@title Folder name", "System Tables")); systemTablesItem->setIcon(0, QIcon::fromTheme(QLatin1String("folder"))); systemTablesItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); QSqlDatabase db = QSqlDatabase::database(m_connectionName); QStringList tables = db.tables(QSql::SystemTables); foreach(const QString& table, tables) { QTreeWidgetItem *item = new QTreeWidgetItem(systemTablesItem, SystemTableType); item->setText(0, table); item->setIcon(0, QIcon(QLatin1String(":/katesql/pics/16-actions-sql-table.png"))); item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } tables = db.tables(QSql::Tables); foreach(const QString& table, tables) { QTreeWidgetItem *item = new QTreeWidgetItem(tablesItem, TableType); item->setText(0, table); item->setIcon(0, QIcon(QLatin1String(":/katesql/pics/16-actions-sql-table.png"))); item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } m_tablesLoaded = true; } void SchemaWidget::buildViews(QTreeWidgetItem * viewsItem) { if (!isConnectionValidAndOpen()) return; QSqlDatabase db = QSqlDatabase::database(m_connectionName); const QStringList views = db.tables(QSql::Views); foreach(const QString& view, views) { QTreeWidgetItem *item = new QTreeWidgetItem(viewsItem, ViewType); item->setText(0, view); item->setIcon(0, QIcon(QLatin1String(":/katesql/pics/16-actions-sql-view.png"))); item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } m_viewsLoaded = true; } void SchemaWidget::buildFields(QTreeWidgetItem * tableItem) { if (!isConnectionValidAndOpen()) return; QSqlDatabase db = QSqlDatabase::database(m_connectionName); QString tableName = tableItem->text(0); QSqlIndex pk = db.primaryIndex(tableName); QSqlRecord rec = db.record(tableName); for (int i = 0; i < rec.count(); ++i) { QSqlField f = rec.field(i); QString fieldName = f.name(); QTreeWidgetItem *item = new QTreeWidgetItem(tableItem, FieldType); item->setText(0, fieldName); if (pk.contains(fieldName)) item->setIcon(0, QIcon(QLatin1String(":/katesql/pics/16-actions-sql-field-pk.png"))); else item->setIcon(0, QIcon(QLatin1String(":/katesql/pics/16-actions-sql-field.png"))); } } void SchemaWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) m_dragStartPosition = event->pos(); QTreeWidget::mousePressEvent(event); } void SchemaWidget::mouseMoveEvent(QMouseEvent *event) { if (!(event->buttons() & Qt::LeftButton)) return; if ((event->pos() - m_dragStartPosition).manhattanLength() < QApplication::startDragDistance()) return; // QTreeWidgetItem *item = currentItem(); QTreeWidgetItem *item = itemAt(event->pos()); if (!item) return; if (item->type() != SchemaWidget::SystemTableType && item->type() != SchemaWidget::TableType && item->type() != SchemaWidget::ViewType && item->type() != SchemaWidget::FieldType) return; QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; if (item->type() == SchemaWidget::FieldType) mimeData->setText(QString::fromLatin1("%1.%2").arg(item->parent()->text(0)).arg(item->text(0))); else mimeData->setText(item->text(0)); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction); QTreeWidget::mouseMoveEvent(event); } void SchemaWidget::slotItemExpanded(QTreeWidgetItem *item) { if (!item) return; switch(item->type()) { case SchemaWidget::TablesFolderType: { if (!m_tablesLoaded) buildTables(item); } break; case SchemaWidget::ViewsFolderType: { if (!m_viewsLoaded) buildViews(item); } break; case SchemaWidget::TableType: case SchemaWidget::SystemTableType: case SchemaWidget::ViewType: { if (item->childCount() == 0) buildFields(item); } break; default: break; } } void SchemaWidget::slotCustomContextMenuRequested(const QPoint &pos) { QMenu menu; menu.addAction(QIcon::fromTheme(QLatin1String("view-refresh")), i18nc("@action:inmenu Context menu", "Refresh"), this, SLOT(refresh())); QTreeWidgetItem *item = itemAt(pos); if (item) { if (item->type() == SchemaWidget::SystemTableType || item->type() == SchemaWidget::TableType || item->type() == SchemaWidget::ViewType || item->type() == SchemaWidget::FieldType) { menu.addSeparator(); QMenu *submenu = menu.addMenu(QIcon::fromTheme(QLatin1String("tools-wizard")), i18nc("@action:inmenu Submenu title", "Generate")); submenu->addAction(i18n ("SELECT"), this, SLOT(generateSelect())); submenu->addAction(i18n ("UPDATE"), this, SLOT(generateUpdate())); submenu->addAction(i18n ("INSERT"), this, SLOT(generateInsert())); submenu->addAction(i18n ("DELETE"), this, SLOT(generateDelete())); } } menu.exec(QCursor::pos()); } void SchemaWidget::generateStatement(QSqlDriver::StatementType statementType) { if (!isConnectionValidAndOpen()) return; QSqlDatabase db = QSqlDatabase::database(m_connectionName); QSqlDriver *drv = db.driver(); if (!drv) return; QTreeWidgetItem *item = currentItem(); if (!item) return; QString statement; switch (item->type()) { case TableType: case SystemTableType: case ViewType: { QString tableName = item->text(0); QSqlRecord rec = db.record(tableName); // set all fields to a value (NULL) // values are needed to generate update and insert statements if (statementType == QSqlDriver::UpdateStatement || QSqlDriver::InsertStatement) for (int i = 0, n = rec.count(); i < n; ++i) rec.setNull(i); statement = drv->sqlStatement(statementType, tableName, rec, false); } break; case FieldType: { QString tableName = item->parent()->text(0); QSqlRecord rec = db.record(tableName); // get the selected column... QSqlField field = rec.field(item->text(0)); // ...and set its value to NULL field.clear(); // clear all columns and re-append the selected one rec.clear(); rec.append(field); statement = drv->sqlStatement(statementType, tableName, rec, false); if (statementType == QSqlDriver::DeleteStatement) statement += QLatin1String (" ") + drv->sqlStatement(QSqlDriver::WhereStatement, tableName, rec, false).replace(QLatin1String (" IS NULL"), QLatin1String ("=?")); } break; } KTextEditor::MainWindow *mw = KTextEditor::Editor::instance()->application()->activeMainWindow(); KTextEditor::View *kv = mw->activeView(); // replace NULL with a more generic '?' statement = statement.replace(QLatin1String ("NULL"), QLatin1String ("?")); if (kv) { // paste statement in the active view kv->insertText(statement); kv->setFocus(); } qDebug() << "Generated statement:" << statement; } void SchemaWidget::generateSelect() { generateStatement(QSqlDriver::SelectStatement); } void SchemaWidget::generateUpdate() { generateStatement(QSqlDriver::UpdateStatement); } void SchemaWidget::generateInsert() { generateStatement(QSqlDriver::InsertStatement); } void SchemaWidget::generateDelete() { generateStatement(QSqlDriver::DeleteStatement); } diff --git a/addons/katesql/textoutputwidget.cpp b/addons/katesql/textoutputwidget.cpp index b461d782e..9d97403a6 100644 --- a/addons/katesql/textoutputwidget.cpp +++ b/addons/katesql/textoutputwidget.cpp @@ -1,106 +1,105 @@ /* Copyright (C) 2010 Marco Mentasti 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 "textoutputwidget.h" #include "connection.h" #include #include #include #include #include #include #include TextOutputWidget::TextOutputWidget(QWidget *parent) : QWidget(parent) { m_succesTextColor = QColor::fromRgb(3, 191, 3); m_succesBackgroundColor = QColor::fromRgb(231, 247, 231); m_errorTextColor = QColor::fromRgb(191, 3, 3); m_errorBackgroundColor = QColor::fromRgb(247, 231, 231); m_layout = new QHBoxLayout(this); m_output = new QTextEdit(); m_output->setReadOnly(true); QFont fixedFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); m_output->setCurrentFont(fixedFont); KToolBar *toolbar = new KToolBar(this); toolbar->setOrientation(Qt::Vertical); toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); toolbar->setIconSize(QSize(16, 16)); /// TODO: disable actions if no results are displayed QAction *action = new QAction( QIcon::fromTheme(QLatin1String("edit-clear")), i18nc("@action:intoolbar", "Clear"), this); toolbar->addAction(action); - connect(action, SIGNAL(triggered()), m_output, SLOT(clear())); - + connect(action, &QAction::triggered, m_output, &QTextEdit::clear); m_layout->addWidget(toolbar); m_layout->addWidget(m_output, 1); m_layout->setContentsMargins(0, 0, 0, 0); setLayout(m_layout); } TextOutputWidget::~TextOutputWidget() { } void TextOutputWidget::showErrorMessage(const QString &message) { QColor previousBackgroundColor = m_output->textBackgroundColor(); QColor previousColor = m_output->textColor(); m_output->setTextBackgroundColor(m_errorBackgroundColor); m_output->setTextColor(m_errorTextColor); writeMessage(message); m_output->setTextBackgroundColor(previousBackgroundColor); m_output->setTextColor(previousColor); } void TextOutputWidget::showSuccessMessage(const QString &message) { QColor previousBackgroundColor = m_output->textBackgroundColor(); QColor previousColor = m_output->textColor(); m_output->setTextBackgroundColor(m_succesBackgroundColor); m_output->setTextColor(m_succesTextColor); writeMessage(message); m_output->setTextBackgroundColor(previousBackgroundColor); m_output->setTextColor(previousColor); } void TextOutputWidget::writeMessage(const QString& msg) { m_output->append(QString::fromLatin1("%1: %2\n").arg(QDateTime::currentDateTime().toString(Qt::SystemLocaleDate)).arg(msg)); raise(); } diff --git a/addons/konsole/kateconsole.cpp b/addons/konsole/kateconsole.cpp index edd209f5f..44c5813b2 100644 --- a/addons/konsole/kateconsole.cpp +++ b/addons/konsole/kateconsole.cpp @@ -1,388 +1,387 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2002 Joseph Wenninger Copyright (C) 2002 Anders Lund Copyright (C) 2007 Anders Lund 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 "kateconsole.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 K_PLUGIN_FACTORY_WITH_JSON (KateKonsolePluginFactory, "katekonsoleplugin.json", registerPlugin();) KateKonsolePlugin::KateKonsolePlugin( QObject* parent, const QList& ): KTextEditor::Plugin ( parent ) { m_previousEditorEnv=qgetenv("EDITOR"); if (!KAuthorized::authorize(QStringLiteral("shell_access"))) { KMessageBox::sorry(nullptr, i18n ("You do not have enough karma to access a shell or terminal emulation")); } } KateKonsolePlugin::~KateKonsolePlugin() { qputenv("EDITOR", m_previousEditorEnv.data()); } QObject *KateKonsolePlugin::createView (KTextEditor::MainWindow *mainWindow) { KateKonsolePluginView *view = new KateKonsolePluginView (this, mainWindow); return view; } KTextEditor::ConfigPage *KateKonsolePlugin::configPage (int number, QWidget *parent) { if (number != 0) return nullptr; return new KateKonsoleConfigPage(parent, this); } void KateKonsolePlugin::readConfig() { foreach ( KateKonsolePluginView *view, mViews ) view->readConfig(); } KateKonsolePluginView::KateKonsolePluginView (KateKonsolePlugin* plugin, KTextEditor::MainWindow *mainWindow) : QObject(mainWindow),m_plugin(plugin) { // init console QWidget *toolview = mainWindow->createToolView (plugin, QStringLiteral("kate_private_plugin_katekonsoleplugin"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme(QStringLiteral("utilities-terminal")), i18n("Terminal")); m_console = new KateConsole(m_plugin, mainWindow, toolview); // register this view m_plugin->mViews.append ( this ); } KateKonsolePluginView::~KateKonsolePluginView () { // unregister this view m_plugin->mViews.removeAll (this); // cleanup, kill toolview + console QWidget *toolview = m_console->parentWidget(); delete m_console; delete toolview; } void KateKonsolePluginView::readConfig() { m_console->readConfig(); } KateConsole::KateConsole (KateKonsolePlugin* plugin, KTextEditor::MainWindow *mw, QWidget *parent) : QWidget (parent) , m_part (nullptr) , m_mw (mw) , m_toolView (parent) , m_plugin(plugin) { KXMLGUIClient::setComponentName (QStringLiteral("katekonsole"), i18n ("Kate Terminal")); setXMLFile( QStringLiteral("ui.rc") ); // make sure we have a vertical layout new QVBoxLayout(this); layout()->setContentsMargins(0, 0, 0, 0); QAction* a = actionCollection()->addAction(QStringLiteral("katekonsole_tools_pipe_to_terminal")); a->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); a->setText(i18nc("@action", "&Pipe to Terminal")); - connect(a, SIGNAL(triggered()), this, SLOT(slotPipeToConsole())); - + connect(a, &QAction::triggered, this, &KateConsole::slotPipeToConsole); a = actionCollection()->addAction(QStringLiteral("katekonsole_tools_sync")); a->setText(i18nc("@action", "S&ynchronize Terminal with Current Document")); - connect(a, SIGNAL(triggered()), this, SLOT(slotManualSync())); + connect(a, &QAction::triggered, this, &KateConsole::slotManualSync); a = actionCollection()->addAction(QStringLiteral("katekonsole_tools_toggle_focus")); a->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); a->setText(i18nc("@action", "&Focus Terminal")); - connect(a, SIGNAL(triggered()), this, SLOT(slotToggleFocus())); + connect(a, &QAction::triggered, this, &KateConsole::slotToggleFocus); m_mw->guiFactory()->addClient (this); readConfig(); } KateConsole::~KateConsole () { m_mw->guiFactory()->removeClient (this); if (m_part) - disconnect ( m_part, SIGNAL(destroyed()), this, SLOT(slotDestroyed()) ); + disconnect(m_part, &KParts::ReadOnlyPart::destroyed, this, &KateConsole::slotDestroyed); } void KateConsole::loadConsoleIfNeeded() { if (m_part) return; if (!window() || !parentWidget()) return; if (!window() || !isVisibleTo(window())) return; /** * get konsole part factory */ KPluginFactory *factory = KPluginLoader(QStringLiteral("konsolepart")).factory(); if (!factory) return; m_part = factory->create(this, this); if (!m_part) return; layout()->addWidget(m_part->widget()); // start the terminal qobject_cast(m_part)->showShellInDir( QString() ); // KGlobal::locale()->insertCatalog("konsole"); // FIXME KF5: insert catalog setFocusProxy(m_part->widget()); m_part->widget()->show(); - connect ( m_part, SIGNAL(destroyed()), this, SLOT(slotDestroyed()) ); + connect(m_part, &KParts::ReadOnlyPart::destroyed, this, &KateConsole::slotDestroyed); connect ( m_part, SIGNAL(overrideShortcut(QKeyEvent*,bool&)), this, SLOT(overrideShortcut(QKeyEvent*,bool&))); slotSync(); } void KateConsole::slotDestroyed () { m_part = nullptr; m_currentPath.clear (); // hide the dockwidget if (parentWidget()) { m_mw->hideToolView (m_toolView); } } void KateConsole::overrideShortcut (QKeyEvent *, bool &override) { /** * let konsole handle all shortcuts */ override = true; } void KateConsole::showEvent(QShowEvent *) { if (m_part) return; loadConsoleIfNeeded(); } void KateConsole::cd (const QString & path) { if (m_currentPath == path) return; if (!m_part) return; m_currentPath = path; QString command = QStringLiteral(" cd ") + KShell::quoteArg(m_currentPath) + QLatin1Char('\n'); // special handling for some interpreters TerminalInterface *t = qobject_cast(m_part); if (t) { // ghci doesn't allow \space dir names, does allow spaces in dir names // irb can take spaces or \space but doesn't allow " 'path' " if (t->foregroundProcessName() == QStringLiteral("irb") ) { command = QStringLiteral("Dir.chdir(\"") + path + QStringLiteral("\") \n") ; } else if(t->foregroundProcessName() == QStringLiteral("ghc")) { command = QStringLiteral(":cd ") + path + QStringLiteral("\n"); } } sendInput(command); } void KateConsole::sendInput( const QString& text ) { loadConsoleIfNeeded(); if (!m_part) return; TerminalInterface *t = qobject_cast(m_part); if (!t) return; t->sendInput (text); } void KateConsole::slotPipeToConsole () { if (KMessageBox::warningContinueCancel (m_mw->window() , i18n ("Do you really want to pipe the text to the console? This will execute any contained commands with your user rights.") , i18n ("Pipe to Terminal?") , KGuiItem(i18n("Pipe to Terminal")), KStandardGuiItem::cancel(), QStringLiteral("Pipe To Terminal Warning")) != KMessageBox::Continue) return; KTextEditor::View *v = m_mw->activeView(); if (!v) return; if (v->selection()) sendInput (v->selectionText()); else sendInput (v->document()->text()); } void KateConsole::slotSync(KTextEditor::View *) { if (m_mw->activeView()) { QUrl u = m_mw->activeView()->document()->url(); if (u.isValid() && u.isLocalFile()) { QFileInfo fi(u.toLocalFile()); cd(fi.absolutePath()); } else if (!u.isEmpty()) { sendInput( QStringLiteral("### ") + i18n("Sorry, cannot cd into '%1'", u.toLocalFile() ) + QLatin1Char('\n') ); } } } void KateConsole::slotManualSync() { m_currentPath.clear (); slotSync(); if ( ! m_part || ! m_part->widget()->isVisible() ) m_mw->showToolView( parentWidget() ); } void KateConsole::slotToggleFocus() { QAction *action = actionCollection()->action(QStringLiteral("katekonsole_tools_toggle_focus")); if ( ! m_part ) { m_mw->showToolView( parentWidget() ); action->setText( i18n("Defocus Terminal") ); return; // this shows and focuses the konsole } if ( ! m_part ) return; if (m_part->widget()->hasFocus()) { if (m_mw->activeView()) m_mw->activeView()->setFocus(); action->setText( i18n("Focus Terminal") ); } else { // show the view if it is hidden if (parentWidget()->isHidden()) m_mw->showToolView( parentWidget() ); else // should focus the widget too! m_part->widget()->setFocus( Qt::OtherFocusReason ); action->setText( i18n("Defocus Terminal") ); } } void KateConsole::readConfig() { disconnect(m_mw, &KTextEditor::MainWindow::viewChanged, this, &KateConsole::slotSync); if ( KConfigGroup(KSharedConfig::openConfig(), "Konsole").readEntry("AutoSyncronize", false) ) { connect(m_mw, &KTextEditor::MainWindow::viewChanged, this, &KateConsole::slotSync); } if ( KConfigGroup(KSharedConfig::openConfig(), "Konsole").readEntry("SetEditor", false) ) qputenv( "EDITOR", "kate -b"); else qputenv( "EDITOR", m_plugin->previousEditorEnv().data()); } KateKonsoleConfigPage::KateKonsoleConfigPage( QWidget* parent, KateKonsolePlugin *plugin ) : KTextEditor::ConfigPage( parent ) , mPlugin( plugin ) { QVBoxLayout *lo = new QVBoxLayout( this ); lo->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing)); cbAutoSyncronize = new QCheckBox( i18n("&Automatically synchronize the terminal with the current document when possible"), this ); lo->addWidget( cbAutoSyncronize ); cbSetEditor = new QCheckBox( i18n("Set &EDITOR environment variable to 'kate -b'"), this ); lo->addWidget( cbSetEditor ); QLabel *tmp = new QLabel(this); tmp->setText(i18n("Important: The document has to be closed to make the console application continue")); lo->addWidget(tmp); reset(); lo->addStretch(); - connect( cbAutoSyncronize, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); - connect( cbSetEditor, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); + connect(cbAutoSyncronize, &QCheckBox::stateChanged, this, &KateKonsoleConfigPage::changed); + connect(cbSetEditor, &QCheckBox::stateChanged, this, &KateKonsoleConfigPage::changed); } QString KateKonsoleConfigPage::name() const { return i18n("Terminal"); } QString KateKonsoleConfigPage::fullName() const { return i18n("Terminal Settings"); } QIcon KateKonsoleConfigPage::icon() const { return QIcon::fromTheme(QStringLiteral("utilities-terminal")); } void KateKonsoleConfigPage::apply() { KConfigGroup config(KSharedConfig::openConfig(), "Konsole"); config.writeEntry("AutoSyncronize", cbAutoSyncronize->isChecked()); config.writeEntry("SetEditor", cbSetEditor->isChecked()); config.sync(); mPlugin->readConfig(); } void KateKonsoleConfigPage::reset() { KConfigGroup config(KSharedConfig::openConfig(), "Konsole"); cbAutoSyncronize->setChecked(config.readEntry("AutoSyncronize", false)); cbSetEditor->setChecked(config.readEntry("SetEditor", false)); } #include "kateconsole.moc" // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/lumen/lumen.cpp b/addons/lumen/lumen.cpp index b584dc8ee..31f328cfa 100644 --- a/addons/lumen/lumen.cpp +++ b/addons/lumen/lumen.cpp @@ -1,187 +1,185 @@ /* * Copyright 2014-2015 David Herberth kde@dav1d.de * * 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) 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 6 of version 3 of the license. * * 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, see . **/ #include "lumen.h" #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(LumenPluginFactory, "ktexteditor_lumen.json", registerPlugin();) LumenPluginView::LumenPluginView(LumenPlugin *plugin, KTextEditor::MainWindow *mainWin) : QObject(mainWin) , m_plugin(plugin) , m_mainWin(mainWin) , m_registered(false) { m_model = new LumenCompletionModel((QObject*)m_mainWin, m_plugin->dcd()); m_hinter = new LumenHintProvider(m_plugin); connect(m_mainWin, &KTextEditor::MainWindow::viewCreated, this, &LumenPluginView::viewCreated); foreach(KTextEditor::View *view, m_mainWin->views()) { viewCreated(view); } } void LumenPluginView::viewCreated(KTextEditor::View *view) { connect(view->document(), &KTextEditor::Document::documentUrlChanged, this, &LumenPluginView::documentChanged, Qt::UniqueConnection); connect(view->document(), &KTextEditor::Document::highlightingModeChanged, this, &LumenPluginView::documentChanged, Qt::UniqueConnection); - connect(view->document(), SIGNAL(documentUrlChanged(KTextEditor::Document*)), - this, SLOT(urlChanged(KTextEditor::Document*))); - + connect(view->document(), &Document::documentUrlChanged, this, &LumenPluginView::urlChanged); registerCompletion(view); } void LumenPluginView::viewDestroyed(QObject *view) { m_completionViews.remove(static_cast(view)); } void LumenPluginView::documentChanged(KTextEditor::Document *document) { foreach(KTextEditor::View *view, document->views()) { registerCompletion(view); registerTextHints(view); } } void LumenPluginView::registerCompletion(KTextEditor::View *view) { KTextEditor::CodeCompletionInterface *completion = qobject_cast(view); bool isD = view->document()->url().path().endsWith(QStringLiteral(".d")) || view->document()->highlightingMode() == QStringLiteral("D"); if (isD && !m_registered) { completion->registerCompletionModel(m_model); m_registered = true; } else if(!isD && m_registered) { completion->unregisterCompletionModel(m_model); m_registered = false; } } void LumenPluginView::registerTextHints(KTextEditor::View *view) { KTextEditor::TextHintInterface *th = qobject_cast(view); if (th) { th->setTextHintDelay(500); th->registerTextHintProvider(m_hinter); } } LumenPluginView::~LumenPluginView() { } void LumenPluginView::urlChanged(Document* document) { QStringList paths; QDir dir = QDir(document->url().toLocalFile()); for (; !dir.isRoot(); dir.cdUp()) { QFile file(dir.filePath(QStringLiteral(".lumenconfig"))); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { while (!file.atEnd()) { QString path = QString::fromUtf8(file.readLine().trimmed()); if (QDir::isRelativePath(path)){ path = QDir::cleanPath(dir.filePath(path)); } paths.append(path); } } } if (!paths.isEmpty()) { m_plugin->dcd()->addImportPath(paths); } } LumenHintProvider::LumenHintProvider(LumenPlugin* plugin) : m_plugin(plugin) { } QString LumenHintProvider::textHint(View* view, const Cursor& position) { KTextEditor::Document* document = view->document(); KTextEditor::Cursor cursorEnd = document->documentEnd(); KTextEditor::Range range0c = KTextEditor::Range(0, 0, position.line(), position.column()); KTextEditor::Range rangece = KTextEditor::Range(position.line(), position.column(), cursorEnd.line(), cursorEnd.column()); QString text0c = document->text(range0c, false); QByteArray utf8 = text0c.toUtf8(); int offset = utf8.length(); utf8.append(document->text(rangece, false).toUtf8()); return m_plugin->dcd()->doc(utf8, offset).trimmed().replace(QStringLiteral("\\n"), QStringLiteral("\n")); } LumenPlugin::LumenPlugin(QObject *parent, const QList &) : Plugin(parent) { m_dcd = new DCD(9166, QStringLiteral("dcd-server"), QStringLiteral("dcd-client")); m_dcd->startServer(); } LumenPlugin::~LumenPlugin() { m_dcd->stopServer(); delete m_dcd; } DCD* LumenPlugin::dcd() { return m_dcd; } QObject* LumenPlugin::createView(KTextEditor::MainWindow *mainWin) { return new LumenPluginView(this, mainWin); } -#include "lumen.moc" \ No newline at end of file +#include "lumen.moc" diff --git a/addons/openheader/plugin_kateopenheader.cpp b/addons/openheader/plugin_kateopenheader.cpp index a91d3e9be..0c3812a9a 100644 --- a/addons/openheader/plugin_kateopenheader.cpp +++ b/addons/openheader/plugin_kateopenheader.cpp @@ -1,235 +1,234 @@ /* This file is part of the KDE project Copyright (C) 2001 Joseph Wenninger Copyright (C) 2009 Erlend Hamberg 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 "plugin_kateopenheader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KateOpenHeaderFactory,"kateopenheaderplugin.json", registerPlugin();) //K_EXPORT_PLUGIN(KateOpenHeaderFactory(KAboutData("kateopenheader","kateopenheader",ki18n("Open Header"), "0.1", ki18n("Open header for a source file"), KAboutData::License_LGPL_V2)) ) PluginViewKateOpenHeader::PluginViewKateOpenHeader(PluginKateOpenHeader *plugin, KTextEditor::MainWindow *mainwindow) : KTextEditor::Command(QStringList() << QStringLiteral("toggle-header"), mainwindow) , KXMLGUIClient() , m_plugin(plugin) , m_mainWindow(mainwindow) { KXMLGUIClient::setComponentName (QStringLiteral("kateopenheaderplugin"), i18n ("Open Header")); setXMLFile( QStringLiteral("ui.rc") ); QAction *a = actionCollection()->addAction(QStringLiteral("file_openheader")); a->setText(i18n("Open .h/.cpp/.c")); actionCollection()->setDefaultShortcut(a, Qt::Key_F12 ); - connect( a, SIGNAL(triggered(bool)), plugin, SLOT(slotOpenHeader()) ); - + connect(a, &QAction::triggered, plugin, &PluginKateOpenHeader::slotOpenHeader); mainwindow->guiFactory()->addClient (this); } PluginViewKateOpenHeader::~PluginViewKateOpenHeader() { m_mainWindow->guiFactory()->removeClient (this); } PluginKateOpenHeader::PluginKateOpenHeader( QObject* parent, const QList& ) : KTextEditor::Plugin ( parent ) { } PluginKateOpenHeader::~PluginKateOpenHeader() { } QObject *PluginKateOpenHeader::createView (KTextEditor::MainWindow *mainWindow) { return new PluginViewKateOpenHeader(this,mainWindow); } void PluginKateOpenHeader::slotOpenHeader () { KTextEditor::Application *application=KTextEditor::Editor::instance()->application(); if (!application->activeMainWindow()) return; KTextEditor::View * kv (application->activeMainWindow()->activeView()); if (!kv) return; QUrl url=kv->document()->url(); if ((!url.isValid()) || (url.isEmpty())) return; qDebug() << "Trying to open opposite of " << url.toString(); qDebug() << "Trying to open opposite of toLocalFile:" << url.toLocalFile(); qDebug() << "Trying to open opposite of path:" << url.path(); QFileInfo info( url.path() ); QString extension = info.suffix().toLower(); QStringList headers( QStringList() << QStringLiteral("h") << QStringLiteral("H") << QStringLiteral("hh") << QStringLiteral("hpp") << QStringLiteral("cuh")); QStringList sources( QStringList() << QStringLiteral("c") << QStringLiteral("cpp") << QStringLiteral("cc") << QStringLiteral("cp") << QStringLiteral("cxx") << QStringLiteral("m")<< QStringLiteral("cu")); if( sources.contains( extension ) ) { if (tryOpenInternal(url, headers)) return; tryOpen( url, headers ); } else if ( headers.contains( extension ) ) { if (tryOpenInternal(url, sources)) return; tryOpen( url, sources ); } } bool PluginKateOpenHeader::tryOpenInternal( const QUrl& url, const QStringList& extensions ) { KTextEditor::Application *application=KTextEditor::Editor::instance()->application(); if (!application->activeMainWindow()) return false; qDebug() << "Trying to find already opened" << url.toString() << " with extensions " << extensions.join(QStringLiteral(" ")); QString basename = QFileInfo( url.path() ).baseName(); QUrl newURL( url ); for( QStringList::ConstIterator it = extensions.begin(); it != extensions.end(); ++it ) { setFileName( &newURL,basename + QStringLiteral(".") + *it ); KTextEditor::Document *doc= application->findUrl(newURL); if (doc) { application->activeMainWindow()->openUrl(newURL); return true; } setFileName(&newURL, basename + QStringLiteral(".") + (*it).toUpper() ); doc= application->findUrl(newURL); if (doc) { application->activeMainWindow()->openUrl(newURL); return true; } } return false; } void PluginKateOpenHeader::tryOpen( const QUrl& url, const QStringList& extensions ) { KTextEditor::Application *application=KTextEditor::Editor::instance()->application(); if (!application->activeMainWindow()) return; qDebug() << "Trying to open " << url.toString() << " with extensions " << extensions.join(QStringLiteral(" ")); QString basename = QFileInfo( url.path() ).baseName(); QUrl newURL( url ); for( QStringList::ConstIterator it = extensions.begin(); it != extensions.end(); ++it ) { setFileName( &newURL,basename + QStringLiteral(".") + *it ); if( fileExists( newURL) ) { application->activeMainWindow()->openUrl( newURL ); return; } setFileName(&newURL, basename + QStringLiteral(".") + (*it).toUpper() ); if( fileExists( newURL) ) { application->activeMainWindow()->openUrl( newURL ); return; } } } bool PluginKateOpenHeader::fileExists(const QUrl &url) { if (url.isLocalFile()) { return QFile::exists(url.toLocalFile()); } KIO::JobFlags flags = KIO::DefaultFlags; KIO::StatJob *job = KIO::stat(url, flags); KJobWidgets::setWindow(job, KTextEditor::Editor::instance()->application()->activeMainWindow()->window()); job->setSide(KIO::StatJob::DestinationSide/*SourceSide*/); job->exec(); return !job->error(); } void PluginKateOpenHeader::setFileName(QUrl *url,const QString &_txt) { url->setFragment(QString()); int i = 0; while (i < _txt.length() && _txt[i] == QLatin1Char('/')) { ++i; } QString tmp = i ? _txt.mid(i) : _txt; QString path = url->path(); if (path.isEmpty()) #ifdef Q_OS_WIN path = url->isLocalFile() ? QDir::rootPath() : QStringLiteral("/"); #else path = QDir::rootPath(); #endif else { int lastSlash = path.lastIndexOf(QLatin1Char('/')); if (lastSlash == -1) { path.clear(); // there's only the file name, remove it } else if (!path.endsWith(QLatin1Char('/'))) { path.truncate(lastSlash + 1); // keep the "/" } } path += tmp; url->setPath(path); } bool PluginViewKateOpenHeader::exec(KTextEditor::View *view, const QString &cmd, QString &msg, const KTextEditor::Range &) { Q_UNUSED(view) Q_UNUSED(cmd) Q_UNUSED(msg) m_plugin->slotOpenHeader(); return true; } bool PluginViewKateOpenHeader::help(KTextEditor::View *view, const QString &cmd, QString &msg) { Q_UNUSED(view) Q_UNUSED(cmd) msg = i18n("

toggle-header — switch between header and corresponding c/cpp file

" "

usage: toggle-header

" "

When editing C or C++ code, this command will switch between a header file and " "its corresponding C/C++ file or vice versa.

" "

For example, if you are editing myclass.cpp, toggle-header will change " "to myclass.h if this file is available.

" "

Pairs of the following filename suffixes will work:
" " Header files: h, H, hh, hpp
" " Source files: c, cpp, cc, cp, cxx

"); return true; } #include "plugin_kateopenheader.moc" diff --git a/addons/project/kateprojectinfoviewcodeanalysis.cpp b/addons/project/kateprojectinfoviewcodeanalysis.cpp index a4fbf3b56..f996bb6ff 100644 --- a/addons/project/kateprojectinfoviewcodeanalysis.cpp +++ b/addons/project/kateprojectinfoviewcodeanalysis.cpp @@ -1,216 +1,216 @@ /* This file is part of the Kate project. * * Copyright (C) 2012 Christoph Cullmann * * 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 "kateprojectinfoviewcodeanalysis.h" #include "kateprojectpluginview.h" #include #include #include #include #include KateProjectInfoViewCodeAnalysis::KateProjectInfoViewCodeAnalysis(KateProjectPluginView *pluginView, KateProject *project) : QWidget() , m_pluginView(pluginView) , m_project(project) , m_messageWidget(nullptr) , m_startStopAnalysis(new QPushButton(i18n("Start Analysis..."))) , m_treeView(new QTreeView()) , m_model(new QStandardItemModel(m_treeView)) , m_analyzer(nullptr) { /** * default style */ m_treeView->setEditTriggers(QAbstractItemView::NoEditTriggers); m_treeView->setUniformRowHeights(true); m_treeView->setRootIsDecorated(false); m_model->setHorizontalHeaderLabels(QStringList() << i18n("File") << i18n("Line") << i18n("Severity") << i18n("Message")); /** * attach model * kill selection model */ QItemSelectionModel *m = m_treeView->selectionModel(); m_treeView->setModel(m_model); delete m; m_treeView->setSortingEnabled(true); m_treeView->sortByColumn(1, Qt::AscendingOrder); m_treeView->sortByColumn(2, Qt::AscendingOrder); /** * layout widget */ QVBoxLayout *layout = new QVBoxLayout; layout->setSpacing(0); layout->addWidget(m_treeView); QHBoxLayout *hlayout = new QHBoxLayout; layout->addLayout(hlayout); hlayout->setSpacing(0); hlayout->addStretch(); hlayout->addWidget(m_startStopAnalysis); setLayout(layout); /** * connect needed signals */ - connect(m_startStopAnalysis, SIGNAL(clicked(bool)), this, SLOT(slotStartStopClicked())); - connect(m_treeView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(slotClicked(const QModelIndex &))); + connect(m_startStopAnalysis, &QPushButton::clicked, this, &KateProjectInfoViewCodeAnalysis::slotStartStopClicked); + connect(m_treeView, &QTreeView::clicked, this, &KateProjectInfoViewCodeAnalysis::slotClicked); } KateProjectInfoViewCodeAnalysis::~KateProjectInfoViewCodeAnalysis() { } void KateProjectInfoViewCodeAnalysis::slotStartStopClicked() { /** * get files for cppcheck */ QStringList files = m_project->files().filter(QRegExp(QStringLiteral("\\.(cpp|cxx|cc|c\\+\\+|c|tpp|txx)$"))); /** * clear existing entries */ m_model->removeRows(0, m_model->rowCount(), QModelIndex()); /** * launch cppcheck */ m_analyzer = new QProcess(this); m_analyzer->setProcessChannelMode(QProcess::MergedChannels); - connect(m_analyzer, SIGNAL(readyRead()), this, SLOT(slotReadyRead())); - connect(m_analyzer, SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(finished(int, QProcess::ExitStatus))); + connect(m_analyzer, &QProcess::readyRead, this, &KateProjectInfoViewCodeAnalysis::slotReadyRead); + connect(m_analyzer, static_cast(&QProcess::finished), + this, &KateProjectInfoViewCodeAnalysis::finished); QStringList args; args << QStringLiteral("-q") << QStringLiteral("--inline-suppr") << QStringLiteral("--enable=all") << QStringLiteral("--template={file}////{line}////{severity}////{message}") << QStringLiteral("--file-list=-"); m_analyzer->start(QStringLiteral("cppcheck"), args); if (m_messageWidget) { delete m_messageWidget; m_messageWidget = nullptr; } if (!m_analyzer->waitForStarted()) { m_messageWidget = new KMessageWidget(); m_messageWidget->setCloseButtonVisible(true); m_messageWidget->setMessageType(KMessageWidget::Warning); m_messageWidget->setWordWrap(false); m_messageWidget->setText(i18n("Please install 'cppcheck'.")); static_cast(layout())->insertWidget(0, m_messageWidget); m_messageWidget->animatedShow(); return; } /** * write files list and close write channel */ m_analyzer->write(files.join(QStringLiteral("\n")).toLocal8Bit()); m_analyzer->closeWriteChannel(); } void KateProjectInfoViewCodeAnalysis::slotReadyRead() { /** * get results of analysis */ while (m_analyzer->canReadLine()) { /** * get one line, split it, skip it, if too few elements */ QString line = QString::fromLocal8Bit(m_analyzer->readLine()); QStringList elements = line.split(QRegExp(QStringLiteral("////")), QString::SkipEmptyParts); if (elements.size() < 4) { continue; } /** * feed into model */ QList items; QStandardItem *fileNameItem = new QStandardItem(QFileInfo(elements[0]).fileName()); fileNameItem->setToolTip(elements[0]); items << fileNameItem; items << new QStandardItem(elements[1]); items << new QStandardItem(elements[2]); const auto message = elements[3].simplified(); auto messageItem = new QStandardItem(message); messageItem->setToolTip(message); items << messageItem; m_model->appendRow(items); } /** * tree view polish ;) */ m_treeView->resizeColumnToContents(2); m_treeView->resizeColumnToContents(1); m_treeView->resizeColumnToContents(0); } void KateProjectInfoViewCodeAnalysis::slotClicked(const QModelIndex &index) { /** * get path */ QString filePath = m_model->item(index.row(), 0)->toolTip(); if (filePath.isEmpty()) { return; } /** * create view */ KTextEditor::View *view = m_pluginView->mainWindow()->openUrl(QUrl::fromLocalFile(filePath)); if (!view) { return; } /** * set cursor, if possible */ int line = m_model->item(index.row(), 1)->text().toInt(); if (line >= 1) { view->setCursorPosition(KTextEditor::Cursor(line - 1, 0)); } } void KateProjectInfoViewCodeAnalysis::finished(int exitCode, QProcess::ExitStatus) { m_messageWidget = new KMessageWidget(); m_messageWidget->setCloseButtonVisible(true); m_messageWidget->setWordWrap(false); if (exitCode == 0) { m_messageWidget->setMessageType(KMessageWidget::Information); m_messageWidget->setText(i18n("Analysis finished.")); } else { // unfortunately, output was eaten by slotReadyRead() // TODO: get stderr output, show it here m_messageWidget->setMessageType(KMessageWidget::Warning); m_messageWidget->setText(i18n("Analysis failed!")); } static_cast(layout ())->insertWidget(0, m_messageWidget); m_messageWidget->animatedShow (); } diff --git a/addons/project/kateprojectinfoviewindex.cpp b/addons/project/kateprojectinfoviewindex.cpp index 7b38bf89e..5fa197bef 100644 --- a/addons/project/kateprojectinfoviewindex.cpp +++ b/addons/project/kateprojectinfoviewindex.cpp @@ -1,161 +1,161 @@ /* This file is part of the Kate project. * * Copyright (C) 2012 Christoph Cullmann * * 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 "kateprojectinfoviewindex.h" #include "kateprojectpluginview.h" #include #include #include KateProjectInfoViewIndex::KateProjectInfoViewIndex(KateProjectPluginView *pluginView, KateProject *project) : QWidget() , m_pluginView(pluginView) , m_project(project) , m_messageWidget(nullptr) , m_lineEdit(new QLineEdit()) , m_treeView(new QTreeView()) , m_model(new QStandardItemModel(m_treeView)) { /** * default style */ m_treeView->setEditTriggers(QAbstractItemView::NoEditTriggers); m_treeView->setUniformRowHeights(true); m_treeView->setRootIsDecorated(false); m_model->setHorizontalHeaderLabels(QStringList() << i18n("Name") << i18n("Kind") << i18n("File") << i18n("Line")); m_lineEdit->setPlaceholderText(i18n("Search")); m_lineEdit->setClearButtonEnabled(true); /** * attach model * kill selection model */ QItemSelectionModel *m = m_treeView->selectionModel(); m_treeView->setModel(m_model); delete m; /** * layout widget */ QVBoxLayout *layout = new QVBoxLayout; layout->setSpacing(0); layout->addWidget(m_lineEdit); layout->addWidget(m_treeView); setLayout(layout); setFocusProxy(m_lineEdit); /** * connect needed signals */ - connect(m_pluginView, SIGNAL(projectLookupWord(const QString &)), m_lineEdit, SLOT(setText(const QString &))); - connect(m_lineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(slotTextChanged(const QString &))); - connect(m_treeView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(slotClicked(const QModelIndex &))); - connect(m_project, SIGNAL(indexChanged()), this, SLOT(indexAvailable())); + connect(m_pluginView, &KateProjectPluginView::projectLookupWord, m_lineEdit, &QLineEdit::setText); + connect(m_lineEdit, &QLineEdit::textChanged, this, &KateProjectInfoViewIndex::slotTextChanged); + connect(m_treeView, &QTreeView::clicked, this, &KateProjectInfoViewIndex::slotClicked); + connect(m_project, &KateProject::indexChanged, this, &KateProjectInfoViewIndex::indexAvailable); /** * trigger once search with nothing */ slotTextChanged(QString()); } KateProjectInfoViewIndex::~KateProjectInfoViewIndex() { } void KateProjectInfoViewIndex::slotTextChanged(const QString &text) { /** * init */ m_treeView->setSortingEnabled(false); m_model->setRowCount(0); /** * get results */ if (m_project->projectIndex() && !text.isEmpty()) { m_project->projectIndex()->findMatches(*m_model, text, KateProjectIndex::FindMatches); } /** * tree view polish ;) */ m_treeView->setSortingEnabled(true); m_treeView->resizeColumnToContents(2); m_treeView->resizeColumnToContents(1); m_treeView->resizeColumnToContents(0); } void KateProjectInfoViewIndex::slotClicked(const QModelIndex &index) { /** * get path */ QString filePath = m_model->item(index.row(), 2)->text(); if (filePath.isEmpty()) { return; } /** * create view */ KTextEditor::View *view = m_pluginView->mainWindow()->openUrl(QUrl::fromLocalFile(filePath)); if (!view) { return; } /** * set cursor, if possible */ int line = m_model->item(index.row(), 3)->text().toInt(); if (line >= 1) { view->setCursorPosition(KTextEditor::Cursor(line - 1, 0)); } } void KateProjectInfoViewIndex::indexAvailable() { /** * update enabled state of widgets */ const bool valid = m_project->projectIndex()->isValid(); m_lineEdit->setEnabled(valid); m_treeView->setEnabled(valid); /** * if index exists, hide possible message widget, else create it */ if (valid) { if (m_messageWidget && m_messageWidget->isVisible()) { m_messageWidget->animatedHide(); } } else if (!m_messageWidget) { m_messageWidget = new KMessageWidget(); m_messageWidget->setCloseButtonVisible(true); m_messageWidget->setMessageType(KMessageWidget::Warning); m_messageWidget->setWordWrap(false); m_messageWidget->setText(i18n("The index could not be created. Please install 'ctags'.")); static_cast(layout())->insertWidget(0, m_messageWidget); } else { m_messageWidget->animatedShow(); } } diff --git a/addons/project/kateprojectinfoviewterminal.cpp b/addons/project/kateprojectinfoviewterminal.cpp index b2e1ff990..0bd91f21f 100644 --- a/addons/project/kateprojectinfoviewterminal.cpp +++ b/addons/project/kateprojectinfoviewterminal.cpp @@ -1,112 +1,112 @@ /* This file is part of the Kate project. * * Copyright (C) 2012 Christoph Cullmann * * 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 "kateprojectinfoviewterminal.h" #include "kateprojectpluginview.h" #include #include #include #include KateProjectInfoViewTerminal::KateProjectInfoViewTerminal(KateProjectPluginView *pluginView, KateProject *project) : QWidget() , m_pluginView(pluginView) , m_project(project) , m_konsolePart(nullptr) { /** * layout widget */ m_layout = new QVBoxLayout(this); m_layout->setSpacing(0); m_layout->setContentsMargins(0, 0, 0, 0); /** * initial terminal creation */ loadTerminal(); } KateProjectInfoViewTerminal::~KateProjectInfoViewTerminal() { /** * avoid endless loop */ if (m_konsolePart) { - disconnect(m_konsolePart, SIGNAL(destroyed()), this, SLOT(loadTerminal())); + disconnect(m_konsolePart, &KParts::ReadOnlyPart::destroyed, this, &KateProjectInfoViewTerminal::loadTerminal); } } void KateProjectInfoViewTerminal::loadTerminal() { /** * null in any case, if loadTerminal fails below and we are in the destroyed event */ m_konsolePart = nullptr; /** * get konsole part factory */ KPluginFactory *factory = KPluginLoader(QStringLiteral("konsolepart")).factory(); if (!factory) { return; } /** * create part */ m_konsolePart = factory->create(this, this); if (!m_konsolePart) { return; } /** * init locale translation stuff */ // FIXME KF5 KGlobal::locale()->insertCatalog("konsole"); /** * switch to right directory */ qobject_cast(m_konsolePart)->showShellInDir(QFileInfo(m_project->fileName()).absolutePath()); /** * add to widget */ m_layout->addWidget(m_konsolePart->widget()); setFocusProxy(m_konsolePart->widget()); /** * guard destruction, create new terminal! */ - connect(m_konsolePart, SIGNAL(destroyed()), this, SLOT(loadTerminal())); + connect(m_konsolePart, &KParts::ReadOnlyPart::destroyed, this, &KateProjectInfoViewTerminal::loadTerminal); connect(m_konsolePart, SIGNAL(overrideShortcut(QKeyEvent *, bool &)), this, SLOT(overrideShortcut(QKeyEvent *, bool &))); } void KateProjectInfoViewTerminal::overrideShortcut(QKeyEvent *, bool &override) { /** * let konsole handle all shortcuts */ override = true; } diff --git a/addons/project/kateprojectpluginview.cpp b/addons/project/kateprojectpluginview.cpp index 2de71b612..9e731877a 100644 --- a/addons/project/kateprojectpluginview.cpp +++ b/addons/project/kateprojectpluginview.cpp @@ -1,523 +1,523 @@ /* This file is part of the Kate project. * * Copyright (C) 2010 Christoph Cullmann * * 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 "kateprojectpluginview.h" #include "fileutil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KateProjectPluginFactory, "kateprojectplugin.json", registerPlugin();) KateProjectPluginView::KateProjectPluginView(KateProjectPlugin *plugin, KTextEditor::MainWindow *mainWin) : QObject(mainWin) , m_plugin(plugin) , m_mainWindow(mainWin) , m_toolView(nullptr) , m_toolInfoView(nullptr) , m_lookupAction(nullptr) { KXMLGUIClient::setComponentName(QStringLiteral("kateproject"), i18n("Kate Project Manager")); setXMLFile(QStringLiteral("ui.rc")); /** * create views for all already existing projects * will create toolviews on demand! */ foreach(KateProject * project, m_plugin->projects()) viewForProject(project); /** * connect to important signals, e.g. for auto project view creation */ connect(m_plugin, &KateProjectPlugin::projectCreated, this, &KateProjectPluginView::viewForProject); connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KateProjectPluginView::slotViewChanged); connect(m_mainWindow, &KTextEditor::MainWindow::viewCreated, this, &KateProjectPluginView::slotViewCreated); /** * connect for all already existing views */ foreach(KTextEditor::View * view, m_mainWindow->views()) slotViewCreated(view); /** * trigger once view change, to highlight right document */ slotViewChanged(); /** * back + forward */ auto a = actionCollection()->addAction(KStandardAction::Back, QStringLiteral("projects_prev_project"), this, SLOT(slotProjectPrev())); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Left)); a = actionCollection()->addAction(KStandardAction::Forward, QStringLiteral("projects_next_project"), this, SLOT(slotProjectNext())); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Right)); a = actionCollection()->addAction(KStandardAction::Goto, QStringLiteral("projects_goto_index"), this, SLOT(slotProjectIndex())); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::ALT | Qt::Key_1)); // popup menu auto popup = new KActionMenu(i18n("Project"), this); actionCollection()->addAction(QLatin1String("popup_project"), popup); m_lookupAction = popup->menu()->addAction(i18n("Lookup: %1", QString()), this, SLOT(slotProjectIndex())); - connect(popup->menu(), SIGNAL(aboutToShow()), this, SLOT(slotContextMenuAboutToShow())); + connect(popup->menu(), &QMenu::aboutToShow, this, &KateProjectPluginView::slotContextMenuAboutToShow); /** * add us to gui */ m_mainWindow->guiFactory()->addClient(this); } KateProjectPluginView::~KateProjectPluginView() { /** * cleanup for all views */ foreach(QObject * view, m_textViews) { KTextEditor::CodeCompletionInterface *cci = qobject_cast(view); if (cci) { cci->unregisterCompletionModel(m_plugin->completion()); } } /** * cu toolviews */ delete m_toolView; m_toolView = nullptr; delete m_toolInfoView; m_toolInfoView = nullptr; /** * cu gui client */ m_mainWindow->guiFactory()->removeClient(this); } QPair KateProjectPluginView::viewForProject(KateProject *project) { /** * needs valid project */ Q_ASSERT(project); /** * create toolviews on demand */ if (!m_toolView) { /** * create toolviews */ m_toolView = m_mainWindow->createToolView(m_plugin, QStringLiteral("kateproject"), KTextEditor::MainWindow::Left, QIcon::fromTheme(QStringLiteral("project-open")), i18n("Projects")); m_toolInfoView = m_mainWindow->createToolView(m_plugin, QStringLiteral("kateprojectinfo"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme(QStringLiteral("view-choose")), i18n("Current Project")); /** * create the combo + buttons for the toolViews + stacked widgets */ m_projectsCombo = new QComboBox(m_toolView); m_projectsCombo->setFrame(false); m_reloadButton = new QToolButton(m_toolView); m_reloadButton->setAutoRaise(true); m_reloadButton->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); QHBoxLayout *layout = new QHBoxLayout(); layout->setSpacing(0); layout->addWidget(m_projectsCombo); layout->addWidget(m_reloadButton); m_toolView->layout()->addItem(layout); m_toolView->layout()->setSpacing(0); m_stackedProjectViews = new QStackedWidget(m_toolView); m_stackedProjectInfoViews = new QStackedWidget(m_toolInfoView); - connect(m_projectsCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentChanged(int))); + connect(m_projectsCombo, static_cast(&QComboBox::currentIndexChanged), this, &KateProjectPluginView::slotCurrentChanged); connect(m_reloadButton, &QToolButton::clicked, this, &KateProjectPluginView::slotProjectReload); } /** * existing view? */ if (m_project2View.contains(project)) { return m_project2View.value(project); } /** * create new views */ KateProjectView *view = new KateProjectView(this, project); KateProjectInfoView *infoView = new KateProjectInfoView(this, project); /** * attach to toolboxes * first the views, then the combo, that triggers signals */ m_stackedProjectViews->addWidget(view); m_stackedProjectInfoViews->addWidget(infoView); m_stackedProjectInfoViews->setFocusProxy(infoView); m_projectsCombo->addItem(QIcon::fromTheme(QStringLiteral("project-open")), project->name(), project->fileName()); /** * remember and return it */ return (m_project2View[project] = QPair (view, infoView)); } QString KateProjectPluginView::projectFileName() const { // nothing there, skip if (!m_toolView) { return QString(); } QWidget *active = m_stackedProjectViews->currentWidget(); if (!active) { return QString(); } return static_cast(active)->project()->fileName(); } QString KateProjectPluginView::projectName() const { // nothing there, skip if (!m_toolView) { return QString(); } QWidget *active = m_stackedProjectViews->currentWidget(); if (!active) { return QString(); } return static_cast(active)->project()->name(); } QString KateProjectPluginView::projectBaseDir() const { // nothing there, skip if (!m_toolView) { return QString(); } QWidget *active = m_stackedProjectViews->currentWidget(); if (!active) { return QString(); } return static_cast(active)->project()->baseDir(); } QVariantMap KateProjectPluginView::projectMap() const { // nothing there, skip if (!m_toolView) { return QVariantMap(); } QWidget *active = m_stackedProjectViews->currentWidget(); if (!active) { return QVariantMap(); } return static_cast(active)->project()->projectMap(); } QStringList KateProjectPluginView::projectFiles() const { // nothing there, skip if (!m_toolView) { return QStringList(); } KateProjectView *active = static_cast(m_stackedProjectViews->currentWidget()); if (!active) { return QStringList(); } return active->project()->files(); } QString KateProjectPluginView::allProjectsCommonBaseDir() const { auto projects = m_plugin->projects(); if (projects.empty()) { return QString(); } if (projects.size() == 1) { return projects[0]->baseDir(); } QString commonParent1 = FileUtil::commonParent(projects[0]->baseDir(), projects[1]->baseDir()); for (int i = 2; i < projects.size(); i++) { commonParent1 = FileUtil::commonParent(commonParent1, projects[i]->baseDir()); } return commonParent1; } QStringList KateProjectPluginView::allProjectsFiles() const { QStringList fileList; foreach (auto project, m_plugin->projects()) { fileList.append(project->files()); } return fileList; } void KateProjectPluginView::slotViewChanged() { /** * get active view */ KTextEditor::View *activeView = m_mainWindow->activeView(); /** * update pointer, maybe disconnect before */ if (m_activeTextEditorView) { m_activeTextEditorView->document()->disconnect(this); } m_activeTextEditorView = activeView; /** * no current active view, return */ if (!m_activeTextEditorView) { return; } /** * connect to url changed, for auto load */ connect(m_activeTextEditorView->document(), &KTextEditor::Document::documentUrlChanged, this, &KateProjectPluginView::slotDocumentUrlChanged); /** * trigger slot once */ slotDocumentUrlChanged(m_activeTextEditorView->document()); } void KateProjectPluginView::slotCurrentChanged(int index) { // nothing there, skip if (!m_toolView) { return; } /** * trigger change of stacked widgets */ m_stackedProjectViews->setCurrentIndex(index); m_stackedProjectInfoViews->setCurrentIndex(index); /** * open currently selected document */ if (QWidget *current = m_stackedProjectViews->currentWidget()) { static_cast(current)->openSelectedDocument(); } /** * project file name might have changed */ emit projectFileNameChanged(); emit projectMapChanged(); } void KateProjectPluginView::slotDocumentUrlChanged(KTextEditor::Document *document) { /** * abort if empty url or no local path */ if (document->url().isEmpty() || !document->url().isLocalFile()) { return; } /** * search matching project */ KateProject *project = m_plugin->projectForUrl(document->url()); if (!project) { return; } /** * select the file FIRST */ m_project2View.value(project).first->selectFile(document->url().toLocalFile()); /** * get active project view and switch it, if it is for a different project * do this AFTER file selection */ KateProjectView *active = static_cast(m_stackedProjectViews->currentWidget()); if (active != m_project2View.value(project).first) { int index = m_projectsCombo->findData(project->fileName()); if (index >= 0) { m_projectsCombo->setCurrentIndex(index); } } } void KateProjectPluginView::slotViewCreated(KTextEditor::View *view) { /** * connect to destroyed */ connect(view, &KTextEditor::View::destroyed, this, &KateProjectPluginView::slotViewDestroyed); /** * add completion model if possible */ KTextEditor::CodeCompletionInterface *cci = qobject_cast(view); if (cci) { cci->registerCompletionModel(m_plugin->completion()); } /** * remember for this view we need to cleanup! */ m_textViews.insert(view); } void KateProjectPluginView::slotViewDestroyed(QObject *view) { /** * remove remembered views for which we need to cleanup on exit! */ m_textViews.remove(view); } void KateProjectPluginView::slotProjectPrev() { // nothing there, skip if (!m_toolView) { return; } if (!m_projectsCombo->count()) { return; } if (m_projectsCombo->currentIndex() == 0) { m_projectsCombo->setCurrentIndex(m_projectsCombo->count() - 1); } else { m_projectsCombo->setCurrentIndex(m_projectsCombo->currentIndex() - 1); } } void KateProjectPluginView::slotProjectNext() { // nothing there, skip if (!m_toolView) { return; } if (!m_projectsCombo->count()) { return; } if (m_projectsCombo->currentIndex() + 1 == m_projectsCombo->count()) { m_projectsCombo->setCurrentIndex(0); } else { m_projectsCombo->setCurrentIndex(m_projectsCombo->currentIndex() + 1); } } void KateProjectPluginView::slotProjectReload() { // nothing there, skip if (!m_toolView) { return; } /** * force reload if any active project */ if (QWidget *current = m_stackedProjectViews->currentWidget()) { static_cast(current)->project()->reload(true); } } QString KateProjectPluginView::currentWord() const { KTextEditor::View *kv = m_activeTextEditorView; if (!kv) { return QString(); } if (kv->selection() && kv->selectionRange().onSingleLine()) { return kv->selectionText(); } return kv->document()->wordAt(kv->cursorPosition()); } void KateProjectPluginView::slotProjectIndex() { if (!m_toolView) { return; } const QString word = currentWord(); if (!word.isEmpty()) { auto tabView = qobject_cast(m_stackedProjectInfoViews->currentWidget()); if (tabView) { tabView->setCurrentIndex(1); } m_mainWindow->showToolView(m_toolInfoView); emit projectLookupWord(word); } } void KateProjectPluginView::slotContextMenuAboutToShow() { const QString word = currentWord(); if (word.isEmpty()) { return; } const QString squeezed = KStringHandler::csqueeze(word, 30); m_lookupAction->setText(i18n("Lookup: %1", squeezed)); } #include "kateprojectpluginview.moc" diff --git a/addons/replicode/replicodeconfigpage.cpp b/addons/replicode/replicodeconfigpage.cpp index 7dd67f0df..e1216b573 100644 --- a/addons/replicode/replicodeconfigpage.cpp +++ b/addons/replicode/replicodeconfigpage.cpp @@ -1,79 +1,79 @@ /* This file is part of the KDE project Copyright (C) 2014 Martin Sandsmark 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 "replicodeconfigpage.h" #include "replicodeconfig.h" #include #include #include #include #include #include #include #include #include ReplicodeConfigPage::ReplicodeConfigPage(QWidget *parent) : KTextEditor::ConfigPage(parent), m_config(new ReplicodeConfig(this)) { QGridLayout *gridlayout = new QGridLayout; setLayout(gridlayout); gridlayout->addWidget(new QLabel(i18n("Path to replicode executor:")), 0, 0); m_requester = new KUrlRequester; m_requester->setMode(KFile::File | KFile::ExistingOnly); gridlayout->addWidget(m_requester, 0, 1); gridlayout->addWidget(m_config, 1, 0, 1, 2); reset(); - connect(m_requester, SIGNAL(textChanged(QString)), SIGNAL(changed())); + connect(m_requester, &KUrlRequester::textChanged, this, &ReplicodeConfigPage::changed); } QString ReplicodeConfigPage::name() const { return i18n("Replicode"); } QString ReplicodeConfigPage::fullName() const { return i18n("Replicode configuration"); } void ReplicodeConfigPage::apply() { KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Replicode")); config.writeEntry("replicodePath", m_requester->text()); m_config->save(); } void ReplicodeConfigPage::reset() { KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Replicode")); m_requester->setText(config.readEntry("replicodePath", QString())); m_config->load(); } void ReplicodeConfigPage::defaults() { m_requester->setText(QString()); m_config->reset(); } diff --git a/addons/replicode/replicodeview.cpp b/addons/replicode/replicodeview.cpp index 68b4a6699..963b2f006 100644 --- a/addons/replicode/replicodeview.cpp +++ b/addons/replicode/replicodeview.cpp @@ -1,245 +1,245 @@ #include "replicodeview.h" #include #include #include #include #include "replicodesettings.h" #include "replicodeconfig.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ReplicodeView::ReplicodeView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow* mainWindow) : QObject(mainWindow), m_mainWindow(mainWindow), m_executor(nullptr) { m_runAction = new QAction(QIcon(QStringLiteral("code-block")), i18n("Run replicode"), this); actionCollection()->setDefaultShortcut(m_runAction, Qt::Key_F8); - connect(m_runAction, SIGNAL(triggered()), SLOT(runReplicode())); + connect(m_runAction, &QAction::triggered, this, &ReplicodeView::runReplicode); actionCollection()->addAction(QStringLiteral("katereplicode_run"), m_runAction); m_stopAction = new QAction(QIcon(QStringLiteral("process-stop")), i18n("Stop replicode"), this); actionCollection()->setDefaultShortcut(m_stopAction, Qt::Key_F9); - connect(m_stopAction, SIGNAL(triggered()), SLOT(stopReplicode())); + connect(m_stopAction, &QAction::triggered, this, &ReplicodeView::stopReplicode); actionCollection()->addAction(QStringLiteral("katereplicode_stop"), m_stopAction); m_stopAction->setEnabled(false); m_toolview = m_mainWindow->createToolView( plugin, QStringLiteral("kate_private_plugin_katereplicodeplugin_run"), KTextEditor::MainWindow::Bottom, SmallIcon(QStringLiteral("code-block")), i18n("Replicode Output")); m_replicodeOutput = new QListWidget(m_toolview); m_replicodeOutput->setSelectionMode(QAbstractItemView::ContiguousSelection); - connect(m_replicodeOutput, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(outputClicked(QListWidgetItem*))); + connect(m_replicodeOutput, &QListWidget::itemActivated, this, &ReplicodeView::outputClicked); m_mainWindow->hideToolView(m_toolview); m_configSidebar = m_mainWindow->createToolView( plugin, QStringLiteral("kate_private_plugin_katereplicodeplugin_config") , KTextEditor::MainWindow::Right, SmallIcon(QStringLiteral("code-block")), i18n("Replicode Config")); m_configView = new ReplicodeConfig(m_configSidebar); m_runButton = new QPushButton(i18nc("shortcut for action", "Run (%1)", m_runAction->shortcut().toString())); m_stopButton = new QPushButton(i18nc("shortcut for action", "Stop (%1)", m_stopAction->shortcut().toString())); m_stopButton->setEnabled(false); QFormLayout *l = qobject_cast(m_configView->widget(0)->layout()); Q_ASSERT(l); l->addRow(m_runButton, m_stopButton); - connect(m_runButton, SIGNAL(clicked()), m_runAction, SLOT(trigger())); - connect(m_stopButton, SIGNAL(clicked()), m_stopAction, SLOT(trigger())); + connect(m_runButton, &QPushButton::clicked, m_runAction, &QAction::trigger); + connect(m_stopButton, &QPushButton::clicked, m_stopAction, &QAction::trigger); m_mainWindow->guiFactory()->addClient(this); - connect(m_mainWindow, SIGNAL(viewChanged(KTextEditor::View*)), SLOT(viewChanged())); + connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &ReplicodeView::viewChanged); } ReplicodeView::~ReplicodeView() { m_mainWindow->guiFactory()->removeClient(this); delete m_executor; } void ReplicodeView::viewChanged() { if (m_mainWindow->activeView() && m_mainWindow->activeView()->document() && m_mainWindow->activeView()->document()->url().fileName().endsWith(QStringLiteral(".replicode"))) { m_mainWindow->showToolView(m_configSidebar); } else { m_mainWindow->hideToolView(m_configSidebar); m_mainWindow->hideToolView(m_toolview); } } void ReplicodeView::runReplicode() { m_mainWindow->showToolView(m_toolview); KTextEditor::View *editor = m_mainWindow->activeView(); if (!editor || !editor->document()) { QMessageBox::warning(m_mainWindow->window(), i18nc("@title:window", "Active Document Not Found"), i18n("Could not find an active document to run.")); return; } if (editor->document()->isEmpty()) { QMessageBox::warning(m_mainWindow->window(), i18nc("@title:window", "Empty Document"), i18n("Cannot execute an empty document.")); return; } QFileInfo sourceFile = QFileInfo(editor->document()->url().toLocalFile()); if (!sourceFile.isReadable()) { QMessageBox::warning(m_mainWindow->window(), i18nc("@title:window", "File Not Found"), i18n("Unable to open source file for reading.")); return; } KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("Replicode")); QString executorPath = config.readEntry("replicodePath", QString()); if (executorPath.isEmpty()) { QMessageBox::warning(m_mainWindow->window(), i18nc("@title:window", "Replicode Executable Not Found"), i18n("Unable to find replicode executor.\n" "Please go to settings and set the path to the Replicode executable.")); return; } if (m_configView->settingsObject()->userOperatorPath.isEmpty()) { QMessageBox::warning(m_mainWindow->window(), i18nc("@title:window", "User Operator Library Not Found"), i18n("Unable to find user operator library.\n" "Please go to settings and set the path to the library.")); } m_configView->settingsObject()->sourcePath = editor->document()->url().toLocalFile(); m_configView->load(); m_configView->settingsObject()->save(); m_replicodeOutput->clear(); if (m_executor) delete m_executor; m_executor = new QProcess(this); m_executor->setWorkingDirectory(sourceFile.canonicalPath()); - connect(m_executor, SIGNAL(readyReadStandardError()), SLOT(gotStderr())); - connect(m_executor, SIGNAL(readyReadStandardOutput()), SLOT(gotStdout())); - connect(m_executor, SIGNAL(finished(int)), SLOT(replicodeFinished())); - connect(m_executor, SIGNAL(error(QProcess::ProcessError)), SLOT(runErrored(QProcess::ProcessError))); + connect(m_executor, &QProcess::readyReadStandardError, this, &ReplicodeView::gotStderr); + connect(m_executor, &QProcess::readyReadStandardOutput, this, &ReplicodeView::gotStdout); + connect(m_executor, static_cast(&QProcess::finished), this, &ReplicodeView::replicodeFinished); + connect(m_executor, static_cast(&QProcess::error), this, &ReplicodeView::runErrored); qDebug() << executorPath << sourceFile.canonicalPath(); m_completed = false; m_executor->start(executorPath, QStringList(), QProcess::ReadOnly); m_runAction->setEnabled(false); m_runButton->setEnabled(false); m_stopAction->setEnabled(true); m_stopButton->setEnabled(true); } void ReplicodeView::stopReplicode() { if (m_executor) { m_executor->kill(); } } void ReplicodeView::outputClicked(QListWidgetItem *item) { QString output = item->text(); QStringList pieces = output.split(QLatin1Char(':')); if (pieces.length() < 2) return; QFileInfo file(pieces[0]); if (!file.isReadable()) return; bool ok = false; int lineNumber = pieces[1].toInt(&ok); qDebug() << lineNumber; if (!ok) return; KTextEditor::View *doc = m_mainWindow->openUrl(QUrl::fromLocalFile(pieces[0])); doc->setCursorPosition(KTextEditor::Cursor(lineNumber, 0)); qDebug() << doc->cursorPosition().line(); } void ReplicodeView::runErrored(QProcess::ProcessError error) { Q_UNUSED(error); QListWidgetItem *item = new QListWidgetItem(i18n("Replicode execution failed: %1", m_executor->errorString())); item->setForeground(Qt::red); m_replicodeOutput->addItem(item); m_replicodeOutput->scrollToBottom(); m_completed = true; } void ReplicodeView::replicodeFinished() { if (!m_completed) { QListWidgetItem *item = new QListWidgetItem(i18n("Replicode execution finished.")); item->setForeground(Qt::blue); m_replicodeOutput->addItem(item); m_replicodeOutput->scrollToBottom(); } m_runAction->setEnabled(true); m_runButton->setEnabled(true); m_stopAction->setEnabled(false); m_stopButton->setEnabled(false); // delete m_executor; // delete m_settingsFile; // m_executor = 0; // m_settingsFile = 0; } void ReplicodeView::gotStderr() { QByteArray output = m_executor->readAllStandardError(); foreach(QByteArray line, output.split('\n')) { line = line.simplified(); if (line.isEmpty()) continue; QListWidgetItem *item = new QListWidgetItem(QString::fromLocal8Bit(line)); item->setForeground(Qt::red); m_replicodeOutput->addItem(item); } m_replicodeOutput->scrollToBottom(); } void ReplicodeView::gotStdout() { QByteArray output = m_executor->readAllStandardOutput(); foreach(QByteArray line, output.split('\n')) { line = line.simplified(); if (line.isEmpty()) continue; QListWidgetItem *item = new QListWidgetItem(QString::fromLocal8Bit(' ' + line)); if (line[0] == '>') item->setForeground(Qt::gray); m_replicodeOutput->addItem(item); } m_replicodeOutput->scrollToBottom(); } diff --git a/addons/search/plugin_search.cpp b/addons/search/plugin_search.cpp index 961713610..4db8a6922 100644 --- a/addons/search/plugin_search.cpp +++ b/addons/search/plugin_search.cpp @@ -1,2191 +1,2179 @@ /* Kate search plugin * * Copyright (C) 2011-2013 by KÃ¥re Särs * * 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 in a file called COPYING; if not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include "plugin_search.h" #include "htmldelegate.h" #include #include #include #include #include #include #include #include #include "kacceleratormanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static QUrl localFileDirUp (const QUrl &url) { if (!url.isLocalFile()) return url; // else go up return QUrl::fromLocalFile (QFileInfo (url.toLocalFile()).dir().absolutePath()); } static QAction *menuEntry(QMenu *menu, const QString &before, const QString &after, const QString &desc, QString menuBefore = QString(), QString menuAfter = QString()); static QAction *menuEntry(QMenu *menu, const QString &before, const QString &after, const QString &desc, QString menuBefore, QString menuAfter) { if (menuBefore.isEmpty()) menuBefore = before; if (menuAfter.isEmpty()) menuAfter = after; QAction *const action = menu->addAction(menuBefore + menuAfter + QLatin1Char('\t') + desc); if (!action) return nullptr; action->setData(QString(before + QLatin1Char(' ') + after)); return action; } class TreeWidgetItem : public QTreeWidgetItem { public: TreeWidgetItem(QTreeWidget* parent):QTreeWidgetItem(parent){} TreeWidgetItem(QTreeWidget* parent, const QStringList &list):QTreeWidgetItem(parent, list){} TreeWidgetItem(QTreeWidgetItem* parent, const QStringList &list):QTreeWidgetItem(parent, list){} private: bool operator<(const QTreeWidgetItem &other) const override { if (childCount() == 0) { int line = data(0, ReplaceMatches::LineRole).toInt(); int column = data(0, ReplaceMatches::ColumnRole).toInt(); int oLine = other.data(0, ReplaceMatches::LineRole).toInt(); int oColumn = other.data(0, ReplaceMatches::ColumnRole).toInt(); if (line < oLine) { return true; } if ((line == oLine) && (column < oColumn)) { return true; } return false; } int sepCount = data(0, ReplaceMatches::FileUrlRole).toString().count(QDir::separator()); int oSepCount = other.data(0, ReplaceMatches::FileUrlRole).toString().count(QDir::separator()); if (sepCount < oSepCount) return true; if (sepCount > oSepCount) return false; return data(0, ReplaceMatches::FileUrlRole).toString().toLower() < other.data(0, ReplaceMatches::FileUrlRole).toString().toLower(); } }; Results::Results(QWidget *parent): QWidget(parent), matches(0), useRegExp(false), searchPlaceIndex(0) { setupUi(this); tree->setItemDelegate(new SPHtmlDelegate(tree)); } K_PLUGIN_FACTORY_WITH_JSON (KatePluginSearchFactory, "katesearch.json", registerPlugin();) KatePluginSearch::KatePluginSearch(QObject* parent, const QList&) : KTextEditor::Plugin (parent), m_searchCommand(nullptr) { m_searchCommand = new KateSearchCommand(this); } KatePluginSearch::~KatePluginSearch() { delete m_searchCommand; } QObject *KatePluginSearch::createView(KTextEditor::MainWindow *mainWindow) { KatePluginSearchView *view = new KatePluginSearchView(this, mainWindow, KTextEditor::Editor::instance()->application()); - connect(m_searchCommand, SIGNAL(setSearchPlace(int)), view, SLOT(setSearchPlace(int))); - connect(m_searchCommand, SIGNAL(setCurrentFolder()), view, SLOT(setCurrentFolder())); - connect(m_searchCommand, SIGNAL(setSearchString(QString)), view, SLOT(setSearchString(QString))); - connect(m_searchCommand, SIGNAL(startSearch()), view, SLOT(startSearch())); + connect(m_searchCommand, &KateSearchCommand::setSearchPlace, view, &KatePluginSearchView::setSearchPlace); + connect(m_searchCommand, &KateSearchCommand::setCurrentFolder, view, &KatePluginSearchView::setCurrentFolder); + connect(m_searchCommand, &KateSearchCommand::setSearchString, view, &KatePluginSearchView::setSearchString); + connect(m_searchCommand, &KateSearchCommand::startSearch, view, &KatePluginSearchView::startSearch); connect(m_searchCommand, SIGNAL(newTab()), view, SLOT(addTab())); - return view; } bool ContainerWidget::focusNextPrevChild (bool next) { QWidget* fw = focusWidget(); bool found = false; emit nextFocus(fw, &found, next); if (found) { return true; } return QWidget::focusNextPrevChild(next); } void KatePluginSearchView::nextFocus(QWidget *currentWidget, bool *found, bool next) { *found = false; if (!currentWidget) { return; } // we use the object names here because there can be multiple replaceButtons (on multiple result tabs) if (next) { if (currentWidget->objectName() == QStringLiteral("tree") || currentWidget == m_ui.binaryCheckBox) { m_ui.newTabButton->setFocus(); *found = true; return; } if (currentWidget == m_ui.displayOptions) { if (m_ui.displayOptions->isChecked()) { m_ui.folderRequester->setFocus(); *found = true; return; } else { Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!res) { return; } res->tree->setFocus(); *found = true; return; } } } else { if (currentWidget == m_ui.newTabButton) { if (m_ui.displayOptions->isChecked()) { m_ui.binaryCheckBox->setFocus(); } else { Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!res) { return; } res->tree->setFocus(); } *found = true; return; } else { if (currentWidget->objectName() == QStringLiteral("tree")) { m_ui.displayOptions->setFocus(); *found = true; return; } } } } KatePluginSearchView::KatePluginSearchView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWin, KTextEditor::Application* application) : QObject (mainWin), m_kateApp(application), m_curResults(nullptr), m_searchJustOpened(false), m_switchToProjectModeWhenAvailable(false), m_searchDiskFilesDone(true), m_searchOpenFilesDone(true), m_projectPluginView(nullptr), m_mainWindow (mainWin) { KXMLGUIClient::setComponentName (QStringLiteral("katesearch"), i18n ("Kate Search & Replace")); setXMLFile( QStringLiteral("ui.rc") ); m_toolView = mainWin->createToolView (plugin, QStringLiteral("kate_plugin_katesearch"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme(QStringLiteral("edit-find")), i18n("Search and Replace")); ContainerWidget *container = new ContainerWidget(m_toolView); m_ui.setupUi(container); container->setFocusProxy(m_ui.searchCombo); - connect(container, SIGNAL(nextFocus(QWidget*,bool*,bool)), this, SLOT(nextFocus(QWidget*,bool*,bool))); + connect(container, &ContainerWidget::nextFocus, this, &KatePluginSearchView::nextFocus); QAction *a = actionCollection()->addAction(QStringLiteral("search_in_files")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_F)); a->setText(i18n("Search in Files")); - connect(a, SIGNAL(triggered(bool)), this, SLOT(openSearchView())); + connect(a, &QAction::triggered, this, &KatePluginSearchView::openSearchView); a = actionCollection()->addAction(QStringLiteral("search_in_files_new_tab")); a->setText(i18n("Search in Files (in new tab)")); // first add tab, then open search view, since open search view switches to show the search options - connect(a, SIGNAL(triggered(bool)), this, SLOT(addTab())); - connect(a, SIGNAL(triggered(bool)), this, SLOT(openSearchView())); + connect(a, &QAction::triggered, this, &KatePluginSearchView::addTab); + connect(a, &QAction::triggered, this, &KatePluginSearchView::openSearchView); a = actionCollection()->addAction(QStringLiteral("go_to_next_match")); a->setText(i18n("Go to Next Match")); - connect(a, SIGNAL(triggered(bool)), this, SLOT(goToNextMatch())); + connect(a, &QAction::triggered, this, &KatePluginSearchView::goToNextMatch); a = actionCollection()->addAction(QStringLiteral("go_to_prev_match")); a->setText(i18n("Go to Previous Match")); - connect(a, SIGNAL(triggered(bool)), this, SLOT(goToPreviousMatch())); + connect(a, &QAction::triggered, this, &KatePluginSearchView::goToPreviousMatch); m_ui.resultTabWidget->tabBar()->setSelectionBehaviorOnRemove(QTabBar::SelectLeftTab); KAcceleratorManager::setNoAccel(m_ui.resultTabWidget); m_ui.displayOptions->setIcon(QIcon::fromTheme(QStringLiteral("games-config-options"))); m_ui.searchButton->setIcon(QIcon::fromTheme(QStringLiteral("edit-find"))); m_ui.nextButton->setIcon(QIcon::fromTheme(QStringLiteral("go-down-search"))); m_ui.stopButton->setIcon(QIcon::fromTheme(QStringLiteral("process-stop"))); m_ui.matchCase->setIcon(QIcon::fromTheme(QStringLiteral("format-text-superscript"))); m_ui.useRegExp->setIcon(QIcon::fromTheme(QStringLiteral("code-context"))); m_ui.expandResults->setIcon(QIcon::fromTheme(QStringLiteral("view-list-tree"))); m_ui.searchPlaceCombo->setItemIcon(CurrentFile, QIcon::fromTheme(QStringLiteral("text-plain"))); m_ui.searchPlaceCombo->setItemIcon(OpenFiles, QIcon::fromTheme(QStringLiteral("text-plain"))); m_ui.searchPlaceCombo->setItemIcon(Folder, QIcon::fromTheme(QStringLiteral("folder"))); m_ui.folderUpButton->setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); m_ui.currentFolderButton->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); m_ui.newTabButton->setIcon(QIcon::fromTheme(QStringLiteral("tab-new"))); m_ui.filterCombo->setToolTip(i18n("Comma separated list of file types to search in. Example: \"*.cpp,*.h\"\n")); m_ui.excludeCombo->setToolTip(i18n("Comma separated list of files and directories to exclude from the search. Example: \"build*\"")); // the order here is important to get the tabBar hidden for only one tab addTab(); m_ui.resultTabWidget->tabBar()->hide(); // get url-requester's combo box and sanely initialize KComboBox* cmbUrl = m_ui.folderRequester->comboBox(); cmbUrl->setDuplicatesEnabled(false); cmbUrl->setEditable(true); m_ui.folderRequester->setMode(KFile::Directory | KFile::LocalOnly); KUrlCompletion* cmpl = new KUrlCompletion(KUrlCompletion::DirCompletion); cmbUrl->setCompletionObject(cmpl); cmbUrl->setAutoDeleteCompletionObject(true); - connect(m_ui.newTabButton, SIGNAL(clicked()), this, SLOT(addTab())); - connect(m_ui.resultTabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(tabCloseRequested(int))); - connect(m_ui.resultTabWidget, SIGNAL(currentChanged(int)), this, SLOT(resultTabChanged(int))); + connect(m_ui.newTabButton, &QToolButton::clicked, this, &KatePluginSearchView::addTab); + connect(m_ui.resultTabWidget, &QTabWidget::tabCloseRequested, this, &KatePluginSearchView::tabCloseRequested); + connect(m_ui.resultTabWidget, &QTabWidget::currentChanged, this, &KatePluginSearchView::resultTabChanged); - connect(m_ui.folderUpButton, SIGNAL(clicked()), this, SLOT(navigateFolderUp())); - connect(m_ui.currentFolderButton, SIGNAL(clicked()), this, SLOT(setCurrentFolder())); - connect(m_ui.expandResults, SIGNAL(clicked()), this, SLOT(expandResults())); + connect(m_ui.folderUpButton, &QToolButton::clicked, this, &KatePluginSearchView::navigateFolderUp); + connect(m_ui.currentFolderButton, &QToolButton::clicked, this, &KatePluginSearchView::setCurrentFolder); + connect(m_ui.expandResults, &QToolButton::clicked, this, &KatePluginSearchView::expandResults); - connect(m_ui.searchCombo, SIGNAL(editTextChanged(QString)), &m_changeTimer, SLOT(start())); - connect(m_ui.matchCase, SIGNAL(toggled(bool)), &m_changeTimer, SLOT(start())); - connect(m_ui.matchCase, &QToolButton::toggled, this, [this](bool) { + connect(m_ui.searchCombo, &QComboBox::editTextChanged, &m_changeTimer, static_cast(&QTimer::start)); + connect(m_ui.matchCase, &QToolButton::toggled, &m_changeTimer, static_cast(&QTimer::start)); + connect(m_ui.matchCase, &QToolButton::toggled, [=]{ Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (res) { res->matchCase = m_ui.matchCase->isChecked(); } }); - connect(m_ui.useRegExp, SIGNAL(toggled(bool)), &m_changeTimer, SLOT(start())); - connect(m_ui.useRegExp, &QToolButton::toggled, this, [this](bool) { + connect(m_ui.useRegExp, &QToolButton::toggled, &m_changeTimer, static_cast(&QTimer::start)); + connect(m_ui.useRegExp, &QToolButton::toggled, [=]{ Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (res) { res->useRegExp = m_ui.useRegExp->isChecked(); } }); m_changeTimer.setInterval(300); m_changeTimer.setSingleShot(true); - connect(&m_changeTimer, SIGNAL(timeout()), this, SLOT(startSearchWhileTyping())); + connect(&m_changeTimer, &QTimer::timeout, this, &KatePluginSearchView::startSearchWhileTyping); - connect(m_ui.searchCombo->lineEdit(), SIGNAL(returnPressed()), this, SLOT(startSearch())); + connect(m_ui.searchCombo->lineEdit(), &QLineEdit::returnPressed, this, &KatePluginSearchView::startSearch); // connecting to returnPressed() of the folderRequester doesn't work, I haven't found out why yet. But connecting to the linedit works: - connect(m_ui.folderRequester->comboBox()->lineEdit(), SIGNAL(returnPressed()), this, SLOT(startSearch())); - connect(m_ui.filterCombo, SIGNAL(returnPressed()), this, SLOT(startSearch())); - connect(m_ui.excludeCombo, SIGNAL(returnPressed()), this, SLOT(startSearch())); - connect(m_ui.searchButton, SIGNAL(clicked()), this, SLOT(startSearch())); + connect(m_ui.folderRequester->comboBox()->lineEdit(), &QLineEdit::returnPressed, this, &KatePluginSearchView::startSearch); + connect(m_ui.filterCombo, static_cast(&KComboBox::returnPressed), this, &KatePluginSearchView::startSearch); + connect(m_ui.excludeCombo, static_cast(&KComboBox::returnPressed), this, &KatePluginSearchView::startSearch); + connect(m_ui.searchButton, &QPushButton::clicked, this, &KatePluginSearchView::startSearch); - connect(m_ui.displayOptions, SIGNAL(toggled(bool)), this, SLOT(toggleOptions(bool))); - connect(m_ui.searchPlaceCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(searchPlaceChanged())); + connect(m_ui.displayOptions, &QToolButton::toggled, this, &KatePluginSearchView::toggleOptions); + connect(m_ui.searchPlaceCombo, static_cast(&QComboBox::currentIndexChanged), this, &KatePluginSearchView::searchPlaceChanged); connect(m_ui.searchPlaceCombo, static_cast(&QComboBox::currentIndexChanged), this, [this](int) { if (m_ui.searchPlaceCombo->currentIndex() == Folder) { m_ui.displayOptions->setChecked(true); } }); - connect(m_ui.stopButton, SIGNAL(clicked()), &m_searchOpenFiles, SLOT(cancelSearch())); - connect(m_ui.stopButton, SIGNAL(clicked()), &m_searchDiskFiles, SLOT(cancelSearch())); - connect(m_ui.stopButton, SIGNAL(clicked()), &m_folderFilesList, SLOT(cancelSearch())); - connect(m_ui.stopButton, SIGNAL(clicked()), &m_replacer, SLOT(cancelReplace())); + connect(m_ui.stopButton, &QPushButton::clicked, &m_searchOpenFiles, &SearchOpenFiles::cancelSearch); + connect(m_ui.stopButton, &QPushButton::clicked, &m_searchDiskFiles, &SearchDiskFiles::cancelSearch); + connect(m_ui.stopButton, &QPushButton::clicked, &m_folderFilesList, &FolderFilesList::cancelSearch); + connect(m_ui.stopButton, &QPushButton::clicked, &m_replacer, &ReplaceMatches::cancelReplace); - connect(m_ui.nextButton, SIGNAL(clicked()), this, SLOT(goToNextMatch())); + connect(m_ui.newTabButton, &QToolButton::clicked, this, &KatePluginSearchView::goToNextMatch); - connect(m_ui.replaceButton, SIGNAL(clicked(bool)), this, SLOT(replaceSingleMatch())); - connect(m_ui.replaceCheckedBtn, SIGNAL(clicked(bool)), this, SLOT(replaceChecked())); - connect(m_ui.replaceCombo->lineEdit(), SIGNAL(returnPressed()), this, SLOT(replaceChecked())); + connect(m_ui.replaceButton, &QPushButton::clicked, this, &KatePluginSearchView::replaceSingleMatch); + connect(m_ui.replaceCheckedBtn, &QPushButton::clicked, this, &KatePluginSearchView::replaceChecked); + connect(m_ui.replaceCombo->lineEdit(), &QLineEdit::returnPressed, this, &KatePluginSearchView::replaceChecked); m_ui.displayOptions->setChecked(true); - connect(&m_searchOpenFiles, SIGNAL(matchFound(QString,QString,int,int,QString,int)), - this, SLOT(matchFound(QString,QString,int,int,QString,int))); - connect(&m_searchOpenFiles, SIGNAL(searchDone()), this, SLOT(searchDone())); - connect(&m_searchOpenFiles, SIGNAL(searching(QString)), this, SLOT(searching(QString))); + connect(&m_searchOpenFiles, &SearchOpenFiles::matchFound, this, &KatePluginSearchView::matchFound); + connect(&m_searchOpenFiles, &SearchOpenFiles::searchDone, this, &KatePluginSearchView::searchDone); + connect(&m_searchOpenFiles, static_cast(&SearchOpenFiles::searching), this, &KatePluginSearchView::searching); - connect(&m_folderFilesList, SIGNAL(finished()), this, SLOT(folderFileListChanged())); - connect(&m_folderFilesList, SIGNAL(searching(QString)), this, SLOT(searching(QString))); + connect(&m_folderFilesList, &FolderFilesList::finished, this, &KatePluginSearchView::folderFileListChanged); + connect(&m_folderFilesList, &FolderFilesList::searching, this, &KatePluginSearchView::searching); - connect(&m_searchDiskFiles, SIGNAL(matchFound(QString,QString,int,int,QString,int)), - this, SLOT(matchFound(QString,QString,int,int,QString,int))); - connect(&m_searchDiskFiles, SIGNAL(searchDone()), this, SLOT(searchDone())); - connect(&m_searchDiskFiles, SIGNAL(searching(QString)), this, SLOT(searching(QString))); + connect(&m_searchDiskFiles, &SearchDiskFiles::matchFound, this, &KatePluginSearchView::matchFound); + connect(&m_searchDiskFiles, &SearchDiskFiles::searchDone, this, &KatePluginSearchView::searchDone); + connect(&m_searchDiskFiles, static_cast(&SearchDiskFiles::searching), this, &KatePluginSearchView::searching); - connect(m_kateApp, SIGNAL(documentWillBeDeleted(KTextEditor::Document*)), - &m_searchOpenFiles, SLOT(cancelSearch())); + connect(m_kateApp, &KTextEditor::Application::documentWillBeDeleted, &m_searchOpenFiles, &SearchOpenFiles::cancelSearch); - connect(m_kateApp, SIGNAL(documentWillBeDeleted(KTextEditor::Document*)), - &m_replacer, SLOT(cancelReplace())); + connect(m_kateApp, &KTextEditor::Application::documentWillBeDeleted, &m_replacer, &ReplaceMatches::cancelReplace); - connect(m_kateApp, SIGNAL(documentWillBeDeleted(KTextEditor::Document*)), - this, SLOT(clearDocMarks(KTextEditor::Document*))); + connect(m_kateApp, &KTextEditor::Application::documentWillBeDeleted, this, &KatePluginSearchView::clearDocMarks); - connect(&m_replacer, SIGNAL(matchReplaced(KTextEditor::Document*,int,int,int)), - this, SLOT(addMatchMark(KTextEditor::Document*,int,int,int))); + connect(&m_replacer, &ReplaceMatches::matchReplaced, this, &KatePluginSearchView::addMatchMark); connect(&m_replacer, &ReplaceMatches::replaceStatus, this, &KatePluginSearchView::replaceStatus); // Hook into line edit context menus m_ui.searchCombo->setContextMenuPolicy(Qt::CustomContextMenu); - connect(m_ui.searchCombo, SIGNAL(customContextMenuRequested(QPoint)), this, - SLOT(searchContextMenu(QPoint))); + connect(m_ui.searchButton, &QPushButton::customContextMenuRequested, this, &KatePluginSearchView::searchContextMenu); m_ui.searchCombo->completer()->setCompletionMode(QCompleter::PopupCompletion); m_ui.searchCombo->completer()->setCaseSensitivity(Qt::CaseSensitive); m_ui.searchCombo->setInsertPolicy(QComboBox::NoInsert); m_ui.searchCombo->lineEdit()->setClearButtonEnabled(true); m_ui.searchCombo->setMaxCount(25); m_ui.replaceCombo->completer()->setCompletionMode(QCompleter::PopupCompletion); m_ui.replaceCombo->completer()->setCaseSensitivity(Qt::CaseSensitive); m_ui.replaceCombo->setInsertPolicy(QComboBox::NoInsert); m_ui.replaceCombo->lineEdit()->setClearButtonEnabled(true); m_ui.replaceCombo->setMaxCount(25); m_toolView->setMinimumHeight(container->sizeHint().height()); - connect(m_mainWindow, SIGNAL(unhandledShortcutOverride(QEvent*)), - this, SLOT(handleEsc(QEvent*))); + connect(m_mainWindow, &KTextEditor::MainWindow::unhandledShortcutOverride, this, &KatePluginSearchView::handleEsc); // watch for project plugin view creation/deletion - connect(m_mainWindow, SIGNAL(pluginViewCreated (const QString &, QObject *)) - , this, SLOT(slotPluginViewCreated (const QString &, QObject *))); + connect(m_mainWindow, &KTextEditor::MainWindow::pluginViewCreated, this, &KatePluginSearchView::slotPluginViewCreated); - connect(m_mainWindow, SIGNAL(pluginViewDeleted (const QString &, QObject *)) - , this, SLOT(slotPluginViewDeleted (const QString &, QObject *))); + connect(m_mainWindow, &KTextEditor::MainWindow::pluginViewDeleted, this, &KatePluginSearchView::slotPluginViewDeleted); - connect(m_mainWindow, SIGNAL(viewChanged(KTextEditor::View *)), this, SLOT(docViewChanged())); + connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KatePluginSearchView::docViewChanged); // update once project plugin state manually m_projectPluginView = m_mainWindow->pluginView (QStringLiteral("kateprojectplugin")); slotProjectFileNameChanged (); m_replacer.setDocumentManager(m_kateApp); - connect(&m_replacer, SIGNAL(replaceDone()), this, SLOT(replaceDone())); + connect(&m_replacer, &ReplaceMatches::replaceDone, this, &KatePluginSearchView::replaceDone); searchPlaceChanged(); m_toolView->installEventFilter(this); m_mainWindow->guiFactory()->addClient(this); } KatePluginSearchView::~KatePluginSearchView() { clearMarks(); m_mainWindow->guiFactory()->removeClient(this); delete m_toolView; } void KatePluginSearchView::navigateFolderUp() { // navigate one folder up m_ui.folderRequester->setUrl(localFileDirUp(m_ui.folderRequester->url())); } void KatePluginSearchView::setCurrentFolder() { if (!m_mainWindow) { return; } KTextEditor::View* editView = m_mainWindow->activeView(); if (editView && editView->document()) { // upUrl as we want the folder not the file m_ui.folderRequester->setUrl(localFileDirUp(editView->document()->url())); } m_ui.displayOptions->setChecked(true); } void KatePluginSearchView::openSearchView() { if (!m_mainWindow) { return; } if (!m_toolView->isVisible()) { m_mainWindow->showToolView(m_toolView); } m_ui.searchCombo->setFocus(Qt::OtherFocusReason); if (m_ui.searchPlaceCombo->currentIndex() == Folder) { m_ui.displayOptions->setChecked(true); } KTextEditor::View* editView = m_mainWindow->activeView(); if (editView && editView->document()) { if (m_ui.folderRequester->text().isEmpty()) { // upUrl as we want the folder not the file m_ui.folderRequester->setUrl(localFileDirUp (editView->document()->url())); } QString selection; if (editView->selection()) { selection = editView->selectionText(); // remove possible trailing '\n' if (selection.endsWith(QLatin1Char('\n'))) { selection = selection.left(selection.size() -1); } } if (selection.isEmpty()) { selection = editView->document()->wordAt(editView->cursorPosition()); } if (!selection.isEmpty() && !selection.contains(QLatin1Char('\n'))) { m_ui.searchCombo->blockSignals(true); m_ui.searchCombo->lineEdit()->setText(selection); m_ui.searchCombo->blockSignals(false); } m_ui.searchCombo->lineEdit()->selectAll(); m_searchJustOpened = true; startSearchWhileTyping(); } } void KatePluginSearchView::handleEsc(QEvent *e) { if (!m_mainWindow) return; QKeyEvent *k = static_cast(e); if (k->key() == Qt::Key_Escape && k->modifiers() == Qt::NoModifier) { static ulong lastTimeStamp; if (lastTimeStamp == k->timestamp()) { // Same as previous... This looks like a bug somewhere... return; } lastTimeStamp = k->timestamp(); if (!m_matchRanges.isEmpty()) { clearMarks(); } else if (m_toolView->isVisible()) { m_mainWindow->hideToolView(m_toolView); } } } void KatePluginSearchView::setSearchString(const QString &pattern) { m_ui.searchCombo->lineEdit()->setText(pattern); } void KatePluginSearchView::toggleOptions(bool show) { m_ui.stackedWidget->setCurrentIndex((show) ? 1:0); } void KatePluginSearchView::setSearchPlace(int place) { m_ui.searchPlaceCombo->setCurrentIndex(place); } QStringList KatePluginSearchView::filterFiles(const QStringList& files) const { QString types = m_ui.filterCombo->currentText(); QString excludes = m_ui.excludeCombo->currentText(); if (((types.isEmpty() || types == QStringLiteral("*"))) && (excludes.isEmpty())) { // shortcut for use all files return files; } QStringList tmpTypes = types.split(QLatin1Char(',')); QVector typeList; for (int i=0; i excludeList; for (int i=0; i openList; for (int i=0; idocuments().size(); i++) { int index = fileList.indexOf(m_kateApp->documents()[i]->url().toLocalFile()); if (index != -1) { openList << m_kateApp->documents()[i]; fileList.removeAt(index); } } // search order is important: Open files starts immediately and should finish // earliest after first event loop. // The DiskFile might finish immediately if (openList.size() > 0) { m_searchOpenFiles.startSearch(openList, m_curResults->regExp); } else { m_searchOpenFilesDone = true; } m_searchDiskFiles.startSearch(fileList, m_curResults->regExp); } void KatePluginSearchView::searchPlaceChanged() { int searchPlace = m_ui.searchPlaceCombo->currentIndex(); const bool inFolder = (searchPlace == Folder); m_ui.filterCombo->setEnabled(searchPlace >= Folder); m_ui.excludeCombo->setEnabled(searchPlace >= Folder); m_ui.folderRequester->setEnabled(inFolder); m_ui.folderUpButton->setEnabled(inFolder); m_ui.currentFolderButton->setEnabled(inFolder); m_ui.recursiveCheckBox->setEnabled(inFolder); m_ui.hiddenCheckBox->setEnabled(inFolder); m_ui.symLinkCheckBox->setEnabled(inFolder); m_ui.binaryCheckBox->setEnabled(inFolder); if (inFolder && sender() == m_ui.searchPlaceCombo) { setCurrentFolder(); } // ... and the labels: m_ui.folderLabel->setEnabled(m_ui.folderRequester->isEnabled()); m_ui.filterLabel->setEnabled(m_ui.filterCombo->isEnabled()); m_ui.excludeLabel->setEnabled(m_ui.excludeCombo->isEnabled()); Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (res) { res->searchPlaceIndex = searchPlace; } } void KatePluginSearchView::addHeaderItem() { QTreeWidgetItem *item = new QTreeWidgetItem(m_curResults->tree, QStringList()); item->setCheckState(0, Qt::Checked); item->setFlags(item->flags() | Qt::ItemIsTristate); m_curResults->tree->expandItem(item); } QTreeWidgetItem * KatePluginSearchView::rootFileItem(const QString &url, const QString &fName) { if (!m_curResults) { return nullptr; } QUrl fullUrl = QUrl::fromUserInput(url); QString path = fullUrl.isLocalFile() ? localFileDirUp(fullUrl).path() : fullUrl.url(); if (!path.isEmpty() && !path.endsWith(QLatin1Char('/'))) { path += QLatin1Char('/'); } path.replace(m_resultBaseDir, QString()); QString name = fullUrl.fileName(); if (url.isEmpty()) { name = fName; } // make sure we have a root item if (m_curResults->tree->topLevelItemCount() == 0) { addHeaderItem(); } QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); if (root->data(0, ReplaceMatches::FileNameRole).toString() == fName) { // The root item contains the document name -> // this is search as you type, return the root item return root; } for (int i=0; ichildCount(); i++) { //qDebug() << root->child(i)->data(0, ReplaceMatches::FileNameRole).toString() << fName; if ((root->child(i)->data(0, ReplaceMatches::FileUrlRole).toString() == url)&& (root->child(i)->data(0, ReplaceMatches::FileNameRole).toString() == fName)) { int matches = root->child(i)->data(0, ReplaceMatches::LineRole).toInt() + 1; QString tmpUrl = QString::fromLatin1("%1%2: %3").arg(path).arg(name).arg(matches); root->child(i)->setData(0, Qt::DisplayRole, tmpUrl); root->child(i)->setData(0, ReplaceMatches::LineRole, matches); return root->child(i); } } // file item not found create a new one QString tmpUrl = QString::fromLatin1("%1%2: %3").arg(path).arg(name).arg(1); TreeWidgetItem *item = new TreeWidgetItem(root, QStringList(tmpUrl)); item->setData(0, ReplaceMatches::FileUrlRole, url); item->setData(0, ReplaceMatches::FileNameRole, fName); item->setData(0, ReplaceMatches::LineRole, 1); item->setCheckState(0, Qt::Checked); item->setFlags(item->flags() | Qt::ItemIsTristate); return item; } void KatePluginSearchView::addMatchMark(KTextEditor::Document* doc, int line, int column, int matchLen) { if (!doc) return; KTextEditor::View* activeView = m_mainWindow->activeView(); KTextEditor::MovingInterface* miface = qobject_cast(doc); KTextEditor::ConfigInterface* ciface = qobject_cast(activeView); KTextEditor::Attribute::Ptr attr(new KTextEditor::Attribute()); bool replace = ((sender() == &m_replacer) || (sender() == nullptr) || (sender() == m_ui.replaceButton)); if (replace) { QColor replaceColor(Qt::green); if (ciface) replaceColor = ciface->configValue(QStringLiteral("replace-highlight-color")).value(); attr->setBackground(replaceColor); if (activeView) { attr->setForeground(activeView->defaultStyleAttribute(KTextEditor::dsNormal)->foreground().color()); } } else { QColor searchColor(Qt::yellow); if (ciface) searchColor = ciface->configValue(QStringLiteral("search-highlight-color")).value(); attr->setBackground(searchColor); if (activeView) { attr->setForeground(activeView->defaultStyleAttribute(KTextEditor::dsNormal)->foreground().color()); } } // calculate end line in case of multi-line match int endLine = line; int endColumn = column + matchLen; while ((endLine < doc->lines()) && (endColumn > doc->line(endLine).size())) { endColumn -= doc->line(endLine).size(); endColumn--; // remove one for '\n' endLine++; } KTextEditor::Range range(line, column, endLine, endColumn); if (m_curResults && !replace) { // special handling for "(?=\\n)" in multi-line search QRegularExpression tmpReg = m_curResults->regExp; if (m_curResults->regExp.pattern().endsWith(QStringLiteral("(?=\\n)"))) { QString newPatern = tmpReg.pattern(); newPatern.replace(QStringLiteral("(?=\\n)"), QStringLiteral("$")); tmpReg.setPattern(newPatern); } if (tmpReg.match(doc->text(range)).capturedStart() != 0) { qDebug() << doc->text(range) << "Does not match" << m_curResults->regExp.pattern(); return; } } KTextEditor::MovingRange* mr = miface->newMovingRange(range); mr->setAttribute(attr); mr->setZDepth(-90000.0); // Set the z-depth to slightly worse than the selection mr->setAttributeOnlyForViews(true); m_matchRanges.append(mr); KTextEditor::MarkInterface* iface = qobject_cast(doc); if (!iface) return; iface->setMarkDescription(KTextEditor::MarkInterface::markType32, i18n("SearchHighLight")); iface->setMarkPixmap(KTextEditor::MarkInterface::markType32, QIcon().pixmap(0,0)); iface->addMark(line, KTextEditor::MarkInterface::markType32); connect(doc, SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)), this, SLOT(clearMarks()), Qt::UniqueConnection); } void KatePluginSearchView::matchFound(const QString &url, const QString &fName, int line, int column, const QString &lineContent, int matchLen) { if (!m_curResults) { return; } QString pre = lineContent.left(column).toHtmlEscaped(); QString match = lineContent.mid(column, matchLen).toHtmlEscaped(); match.replace(QLatin1Char('\n'), QStringLiteral("\\n")); QString post = lineContent.mid(column + matchLen).toHtmlEscaped(); QStringList row; row << i18n("Line: %1: %2", line+1, pre+QStringLiteral("")+match+QStringLiteral("")+post); TreeWidgetItem *item = new TreeWidgetItem(rootFileItem(url, fName), row); item->setData(0, ReplaceMatches::FileUrlRole, url); item->setData(0, Qt::ToolTipRole, url); item->setData(0, ReplaceMatches::FileNameRole, fName); item->setData(0, ReplaceMatches::LineRole, line); item->setData(0, ReplaceMatches::ColumnRole, column); item->setData(0, ReplaceMatches::MatchLenRole, matchLen); item->setData(0, ReplaceMatches::PreMatchRole, pre); item->setData(0, ReplaceMatches::MatchRole, match); item->setData(0, ReplaceMatches::PostMatchRole, post); item->setCheckState (0, Qt::Checked); m_curResults->matches++; // Add mark if the document is open KTextEditor::Document* doc; if (url.isEmpty()) { doc = m_replacer.findNamed(fName); } else { doc = m_kateApp->findUrl(QUrl::fromUserInput(url)); } addMatchMark(doc, line, column, matchLen); } void KatePluginSearchView::clearMarks() { // FIXME: check for ongoing search... KTextEditor::MarkInterface* iface; foreach (KTextEditor::Document* doc, m_kateApp->documents()) { iface = qobject_cast(doc); if (iface) { const QHash marks = iface->marks(); QHashIterator i(marks); while (i.hasNext()) { i.next(); if (i.value()->type & KTextEditor::MarkInterface::markType32) { iface->removeMark(i.value()->line, KTextEditor::MarkInterface::markType32); } } } } qDeleteAll(m_matchRanges); m_matchRanges.clear(); } void KatePluginSearchView::clearDocMarks(KTextEditor::Document* doc) { //qDebug() << sender(); // FIXME: check for ongoing search... KTextEditor::MarkInterface* iface; iface = qobject_cast(doc); if (iface) { const QHash marks = iface->marks(); QHashIterator i(marks); while (i.hasNext()) { i.next(); if (i.value()->type & KTextEditor::MarkInterface::markType32) { iface->removeMark(i.value()->line, KTextEditor::MarkInterface::markType32); } } } int i = 0; while (idocument() == doc) { //qDebug() << "removing mark in" << doc->url(); delete m_matchRanges.at(i); m_matchRanges.removeAt(i); } else { i++; } } } void KatePluginSearchView::startSearch() { m_changeTimer.stop(); // make sure not to start a "while you type" search now m_mainWindow->showToolView(m_toolView); // in case we are invoked from the command interface m_switchToProjectModeWhenAvailable = false; // now that we started, don't switch back automatically if (m_ui.searchCombo->currentText().isEmpty()) { // return pressed in the folder combo or filter combo return; } QString currentSearchText = m_ui.searchCombo->currentText(); m_ui.searchCombo->setItemText(0, QString()); // remove the text from index 0 on enter/search int index = m_ui.searchCombo->findText(currentSearchText); if (index > 0) { m_ui.searchCombo->removeItem(index); } m_ui.searchCombo->insertItem(1, currentSearchText); m_ui.searchCombo->setCurrentIndex(1); if (m_ui.filterCombo->findText(m_ui.filterCombo->currentText()) == -1) { m_ui.filterCombo->insertItem(0, m_ui.filterCombo->currentText()); m_ui.filterCombo->setCurrentIndex(0); } if (m_ui.excludeCombo->findText(m_ui.excludeCombo->currentText()) == -1) { m_ui.excludeCombo->insertItem(0, m_ui.excludeCombo->currentText()); m_ui.excludeCombo->setCurrentIndex(0); } if (m_ui.folderRequester->comboBox()->findText(m_ui.folderRequester->comboBox()->currentText()) == -1) { m_ui.folderRequester->comboBox()->insertItem(0, m_ui.folderRequester->comboBox()->currentText()); m_ui.folderRequester->comboBox()->setCurrentIndex(0); } m_curResults = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!m_curResults) { qWarning() << "This is a bug"; return; } QRegularExpression::PatternOptions patternOptions = (m_ui.matchCase->isChecked() ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption); QString pattern = (m_ui.useRegExp->isChecked() ? currentSearchText : QRegularExpression::escape(currentSearchText)); QRegularExpression reg(pattern, patternOptions); if (!reg.isValid()) { //qDebug() << "invalid regexp"; indicateMatch(false); return; } m_curResults->regExp = reg; m_curResults->useRegExp = m_ui.useRegExp->isChecked(); m_curResults->matchCase = m_ui.matchCase->isChecked(); m_curResults->searchPlaceIndex = m_ui.searchPlaceCombo->currentIndex(); m_ui.newTabButton->setDisabled(true); m_ui.searchCombo->setDisabled(true); m_ui.searchButton->setDisabled(true); m_ui.displayOptions->setChecked (false); m_ui.displayOptions->setDisabled(true); m_ui.replaceCheckedBtn->setDisabled(true); m_ui.replaceButton->setDisabled(true); m_ui.stopAndNext->setCurrentIndex(1); m_ui.replaceCombo->setDisabled(true); m_ui.searchPlaceCombo->setDisabled(true); m_ui.useRegExp->setDisabled(true); m_ui.matchCase->setDisabled(true); m_ui.expandResults->setDisabled(true); m_ui.currentFolderButton->setDisabled(true); clearMarks(); m_curResults->tree->clear(); m_curResults->tree->setCurrentItem(nullptr); m_curResults->matches = 0; m_ui.resultTabWidget->setTabText(m_ui.resultTabWidget->currentIndex(), m_ui.searchCombo->currentText()); m_toolView->setCursor(Qt::WaitCursor); m_searchDiskFilesDone = false; m_searchOpenFilesDone = false; const bool inCurrentProject = m_ui.searchPlaceCombo->currentIndex() == Project; const bool inAllOpenProjects = m_ui.searchPlaceCombo->currentIndex() == AllProjects; if (m_ui.searchPlaceCombo->currentIndex() == CurrentFile) { m_searchDiskFilesDone = true; m_resultBaseDir.clear(); QList documents; documents << m_mainWindow->activeView()->document(); addHeaderItem(); m_searchOpenFiles.startSearch(documents, reg); } else if (m_ui.searchPlaceCombo->currentIndex() == OpenFiles) { m_searchDiskFilesDone = true; m_resultBaseDir.clear(); const QList documents = m_kateApp->documents(); addHeaderItem(); m_searchOpenFiles.startSearch(documents, reg); } else if (m_ui.searchPlaceCombo->currentIndex() == Folder) { m_resultBaseDir = m_ui.folderRequester->url().path(); if (!m_resultBaseDir.isEmpty() && !m_resultBaseDir.endsWith(QLatin1Char('/'))) m_resultBaseDir += QLatin1Char('/'); addHeaderItem(); m_folderFilesList.generateList(m_ui.folderRequester->text(), m_ui.recursiveCheckBox->isChecked(), m_ui.hiddenCheckBox->isChecked(), m_ui.symLinkCheckBox->isChecked(), m_ui.binaryCheckBox->isChecked(), m_ui.filterCombo->currentText(), m_ui.excludeCombo->currentText()); // the file list will be ready when the thread returns (connected to folderFileListChanged) } else if (inCurrentProject || inAllOpenProjects) { /** * init search with file list from current project, if any */ m_resultBaseDir.clear(); QStringList files; if (m_projectPluginView) { if (inCurrentProject) { m_resultBaseDir = m_projectPluginView->property ("projectBaseDir").toString(); } else { m_resultBaseDir = m_projectPluginView->property ("allProjectsCommonBaseDir").toString(); } if (!m_resultBaseDir.endsWith(QLatin1Char('/'))) m_resultBaseDir += QLatin1Char('/'); QStringList projectFiles; if (inCurrentProject) { projectFiles = m_projectPluginView->property ("projectFiles").toStringList(); } else { projectFiles = m_projectPluginView->property ("allProjectsFiles").toStringList(); } files = filterFiles(projectFiles); } addHeaderItem(); QList openList; for (int i=0; idocuments().size(); i++) { int index = files.indexOf(m_kateApp->documents()[i]->url().toString()); if (index != -1) { openList << m_kateApp->documents()[i]; files.removeAt(index); } } // search order is important: Open files starts immediately and should finish // earliest after first event loop. // The DiskFile might finish immediately if (openList.size() > 0) { m_searchOpenFiles.startSearch(openList, m_curResults->regExp); } else { m_searchOpenFilesDone = true; } m_searchDiskFiles.startSearch(files, reg); } else { Q_ASSERT_X(false, "KatePluginSearchView::startSearch", "case not handled"); } } void KatePluginSearchView::startSearchWhileTyping() { if (!m_searchDiskFilesDone || !m_searchOpenFilesDone) { return; } QString currentSearchText = m_ui.searchCombo->currentText(); m_ui.searchButton->setDisabled(currentSearchText.isEmpty()); // Do not clear the search results if you press up by mistake if (currentSearchText.isEmpty()) return; if (!m_mainWindow->activeView()) return; KTextEditor::Document *doc = m_mainWindow->activeView()->document(); if (!doc) return; m_curResults =qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!m_curResults) { qWarning() << "This is a bug"; return; } // check if we typed something or just changed combobox index // changing index should not trigger a search-as-you-type if (m_ui.searchCombo->currentIndex() > 0 && currentSearchText == m_ui.searchCombo->itemText(m_ui.searchCombo->currentIndex())) { return; } // Now we should have a true typed text change QRegularExpression::PatternOptions patternOptions = (m_ui.matchCase->isChecked() ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption); QString pattern = (m_ui.useRegExp->isChecked() ? currentSearchText : QRegularExpression::escape(currentSearchText)); QRegularExpression reg(pattern, patternOptions); if (!reg.isValid()) { //qDebug() << "invalid regexp"; indicateMatch(false); return; } m_curResults->regExp = reg; m_curResults->useRegExp = m_ui.useRegExp->isChecked(); m_ui.replaceCheckedBtn->setDisabled(true); m_ui.replaceButton->setDisabled(true); m_ui.nextButton->setDisabled(true); int cursorPosition = m_ui.searchCombo->lineEdit()->cursorPosition(); bool hasSelected = m_ui.searchCombo->lineEdit()->hasSelectedText(); m_ui.searchCombo->blockSignals(true); m_ui.searchCombo->setItemText(0, currentSearchText); m_ui.searchCombo->setCurrentIndex(0); m_ui.searchCombo->lineEdit()->setCursorPosition(cursorPosition); if (hasSelected) { // This restores the select all from invoking openSearchView // This selects too much if we have a partial selection and toggle match-case/regexp m_ui.searchCombo->lineEdit()->selectAll(); } m_ui.searchCombo->blockSignals(false); // Prepare for the new search content clearMarks(); m_resultBaseDir.clear(); m_curResults->tree->clear(); m_curResults->tree->setCurrentItem(nullptr); m_curResults->matches = 0; // Add the search-as-you-type header item TreeWidgetItem *item = new TreeWidgetItem(m_curResults->tree, QStringList()); item->setData(0, ReplaceMatches::FileUrlRole, doc->url().toString()); item->setData(0, ReplaceMatches::FileNameRole, doc->documentName()); item->setData(0, ReplaceMatches::LineRole, 0); item->setCheckState(0, Qt::Checked); item->setFlags(item->flags() | Qt::ItemIsTristate); // Do the search int searchStoppedAt = m_searchOpenFiles.searchOpenFile(doc, reg, 0); searchWhileTypingDone(); if (searchStoppedAt != 0) { delete m_infoMessage; const QString msg = i18n("Searching while you type was interrupted. It would have taken too long."); m_infoMessage = new KTextEditor::Message(msg, KTextEditor::Message::Warning); m_infoMessage->setPosition(KTextEditor::Message::TopInView); m_infoMessage->setAutoHide(3000); m_infoMessage->setAutoHideMode(KTextEditor::Message::Immediate); m_infoMessage->setView(m_mainWindow->activeView()); m_mainWindow->activeView()->document()->postMessage(m_infoMessage); } } void KatePluginSearchView::searchDone() { m_changeTimer.stop(); // avoid "while you type" search directly after if (sender() == &m_searchDiskFiles) { m_searchDiskFilesDone = true; } if (sender() == &m_searchOpenFiles) { m_searchOpenFilesDone = true; } if (!m_searchDiskFilesDone || !m_searchOpenFilesDone) { return; } QWidget* fw = QApplication::focusWidget(); // NOTE: we take the focus widget here before the enabling/disabling // moves the focus around. m_ui.newTabButton->setDisabled(false); m_ui.searchCombo->setDisabled(false); m_ui.searchButton->setDisabled(false); m_ui.stopAndNext->setCurrentIndex(0); m_ui.displayOptions->setDisabled(false); m_ui.replaceCombo->setDisabled(false); m_ui.searchPlaceCombo->setDisabled(false); m_ui.useRegExp->setDisabled(false); m_ui.matchCase->setDisabled(false); m_ui.expandResults->setDisabled(false); m_ui.currentFolderButton->setDisabled(false); if (!m_curResults) { return; } m_ui.replaceCheckedBtn->setDisabled(m_curResults->matches < 1); m_ui.replaceButton->setDisabled(m_curResults->matches < 1); m_ui.nextButton->setDisabled(m_curResults->matches < 1); m_curResults->tree->sortItems(0, Qt::AscendingOrder); m_curResults->tree->expandAll(); m_curResults->tree->resizeColumnToContents(0); if (m_curResults->tree->columnWidth(0) < m_curResults->tree->width()-30) { m_curResults->tree->setColumnWidth(0, m_curResults->tree->width()-30); } // expand the "header item " to display all files and all results if configured QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); expandResults(); if (root) { switch (m_ui.searchPlaceCombo->currentIndex()) { case CurrentFile: root->setData(0, Qt::DisplayRole, i18np("One match found in current file", "%1 matches found in current file", m_curResults->matches)); break; case OpenFiles: root->setData(0, Qt::DisplayRole, i18np("One match found in open files", "%1 matches found in open files", m_curResults->matches)); break; case Folder: root->setData(0, Qt::DisplayRole, i18np("One match found in folder %2", "%1 matches found in folder %2", m_curResults->matches, m_resultBaseDir)); break; case Project: { QString projectName; if (m_projectPluginView) { projectName = m_projectPluginView->property("projectName").toString(); } root->setData(0, Qt::DisplayRole, i18np("One match found in project %2 (%3)", "%1 matches found in project %2 (%3)", m_curResults->matches, projectName, m_resultBaseDir)); break; } case AllProjects: // "in Open Projects" root->setData(0, Qt::DisplayRole, i18np("One match found in all open projects (common parent: %2)", "%1 matches found in all open projects (common parent: %2)", m_curResults->matches, m_resultBaseDir)); break; } } indicateMatch(m_curResults->matches > 0); m_curResults = nullptr; m_toolView->unsetCursor(); if (fw == m_ui.stopButton) { m_ui.searchCombo->setFocus(); } m_searchJustOpened = false; } void KatePluginSearchView::searchWhileTypingDone() { if (!m_curResults) { return; } bool popupVisible = m_ui.searchCombo->lineEdit()->completer()->popup()->isVisible(); m_ui.replaceCheckedBtn->setDisabled(m_curResults->matches < 1); m_ui.replaceButton->setDisabled(m_curResults->matches < 1); m_ui.nextButton->setDisabled(m_curResults->matches < 1); m_curResults->tree->expandAll(); m_curResults->tree->resizeColumnToContents(0); if (m_curResults->tree->columnWidth(0) < m_curResults->tree->width()-30) { m_curResults->tree->setColumnWidth(0, m_curResults->tree->width()-30); } QWidget *focusObject = nullptr; QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); if (root) { QTreeWidgetItem *child = root->child(0); if (!m_searchJustOpened) { focusObject = qobject_cast(QGuiApplication::focusObject()); } indicateMatch(child); root->setData(0, Qt::DisplayRole, i18np("One match found", "%1 matches found", m_curResults->matches)); } m_curResults = nullptr; if (focusObject) { focusObject->setFocus(); } if (popupVisible) { m_ui.searchCombo->lineEdit()->completer()->complete(); } m_searchJustOpened = false; } void KatePluginSearchView::searching(const QString &file) { if (!m_curResults) { return; } QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); if (root) { if (file.size() > 70) { root->setData(0, Qt::DisplayRole, i18n("Searching: ...%1", file.right(70))); } else { root->setData(0, Qt::DisplayRole, i18n("Searching: %1", file)); } } } void KatePluginSearchView::indicateMatch(bool hasMatch) { QLineEdit * const lineEdit = m_ui.searchCombo->lineEdit(); QPalette background(lineEdit->palette()); if (hasMatch) { // Green background for line edit KColorScheme::adjustBackground(background, KColorScheme::PositiveBackground); } else { // Reset background of line edit background = QPalette(); } // Red background for line edit //KColorScheme::adjustBackground(background, KColorScheme::NegativeBackground); // Neutral background //KColorScheme::adjustBackground(background, KColorScheme::NeutralBackground); lineEdit->setPalette(background); } void KatePluginSearchView::replaceSingleMatch() { if (m_ui.searchCombo->findText(m_ui.searchCombo->currentText()) == -1) { m_ui.searchCombo->insertItem(1, m_ui.searchCombo->currentText()); m_ui.searchCombo->setCurrentIndex(1); } if (m_ui.replaceCombo->findText(m_ui.replaceCombo->currentText()) == -1) { m_ui.replaceCombo->insertItem(1, m_ui.replaceCombo->currentText()); m_ui.replaceCombo->setCurrentIndex(1); } // check if the cursor is at the current item if not jump there Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!res) { return; } QTreeWidgetItem *item = res->tree->currentItem(); if (!item || !item->parent()) { // nothing was selected goToNextMatch(); return; } if (!m_mainWindow->activeView() || !m_mainWindow->activeView()->cursorPosition().isValid()) { itemSelected(item); return; } int dLine = m_mainWindow->activeView()->cursorPosition().line(); int dColumn = m_mainWindow->activeView()->cursorPosition().column(); int iLine = item->data(0, ReplaceMatches::LineRole).toInt(); int iColumn = item->data(0, ReplaceMatches::ColumnRole).toInt(); if ((dLine != iLine) || (dColumn != iColumn)) { itemSelected(item); return; } KTextEditor::Document *doc = m_mainWindow->activeView()->document(); // Find the corresponding range int i; for (i=0; idocument() != doc) continue; if (m_matchRanges[i]->start().line() != iLine) continue; if (m_matchRanges[i]->start().column() != iColumn) continue; break; } if (i >=m_matchRanges.size()) { goToNextMatch(); return; } QRegularExpressionMatch match = res->regExp.match(doc->text(m_matchRanges[i]->toRange())); if (match.capturedStart() != 0) { qDebug() << doc->text(m_matchRanges[i]->toRange()) << "Does not match" << res->regExp.pattern(); goToNextMatch(); return; } QString replaceText = m_ui.replaceCombo->currentText(); replaceText.replace(QStringLiteral("\\\\"), QStringLiteral("¤Search&Replace¤")); for (int j=1; j<=match.lastCapturedIndex() ; j++) { replaceText.replace(QString(QStringLiteral("\\%1")).arg(j), match.captured(j)); } replaceText.replace(QStringLiteral("\\n"), QStringLiteral("\n")); replaceText.replace(QStringLiteral("\\t"), QStringLiteral("\t")); replaceText.replace(QStringLiteral("¤Search&Replace¤"), QStringLiteral("\\\\")); doc->replaceText(m_matchRanges[i]->toRange(), replaceText); addMatchMark(doc, dLine, dColumn, replaceText.size()); replaceText.replace(QLatin1Char('\n'), QStringLiteral("\\n")); replaceText.replace(QLatin1Char('\t'), QStringLiteral("\\t")); QString html = item->data(0, ReplaceMatches::PreMatchRole).toString(); html += QStringLiteral("") + item->data(0, ReplaceMatches::MatchRole).toString() + QStringLiteral(" "); html += QStringLiteral("") + replaceText + QStringLiteral(""); html += item->data(0, ReplaceMatches::PostMatchRole).toString(); item->setData(0, Qt::DisplayRole, i18n("Line: %1: %2",m_matchRanges[i]->start().line()+1, html)); // now update the rest of the tree items for this file (they are sorted in ascending order i++; for (; idocument() != doc) continue; item = res->tree->itemBelow(item); if (!item) break; if (item->data(0, ReplaceMatches::FileUrlRole).toString() != doc->url().toString()) break; iLine = item->data(0, ReplaceMatches::LineRole).toInt(); iColumn = item->data(0, ReplaceMatches::ColumnRole).toInt(); if ((m_matchRanges[i]->start().line() == iLine) && (m_matchRanges[i]->start().column() == iColumn)) { break; } item->setData(0, ReplaceMatches::LineRole, m_matchRanges[i]->start().line()); item->setData(0, ReplaceMatches::ColumnRole, m_matchRanges[i]->start().column()); } goToNextMatch(); } void KatePluginSearchView::replaceChecked() { if (m_ui.searchCombo->findText(m_ui.searchCombo->currentText()) == -1) { m_ui.searchCombo->insertItem(1, m_ui.searchCombo->currentText()); m_ui.searchCombo->setCurrentIndex(1); } if (m_ui.replaceCombo->findText(m_ui.replaceCombo->currentText()) == -1) { m_ui.replaceCombo->insertItem(1, m_ui.replaceCombo->currentText()); m_ui.replaceCombo->setCurrentIndex(1); } m_curResults =qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!m_curResults) { qWarning() << "Results not found"; return; } m_ui.stopAndNext->setCurrentIndex(1); m_ui.displayOptions->setChecked(false); m_ui.displayOptions->setDisabled(true); m_ui.newTabButton->setDisabled(true); m_ui.searchCombo->setDisabled(true); m_ui.searchButton->setDisabled(true); m_ui.replaceCheckedBtn->setDisabled(true); m_ui.replaceButton->setDisabled(true); m_ui.replaceCombo->setDisabled(true); m_ui.searchPlaceCombo->setDisabled(true); m_ui.useRegExp->setDisabled(true); m_ui.matchCase->setDisabled(true); m_ui.expandResults->setDisabled(true); m_ui.currentFolderButton->setDisabled(true); m_curResults->replaceStr = m_ui.replaceCombo->currentText(); QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); if (root) { m_curResults->treeRootText = root->data(0, Qt::DisplayRole).toString(); } m_replacer.replaceChecked(m_curResults->tree, m_curResults->regExp, m_curResults->replaceStr); } void KatePluginSearchView::replaceStatus(const QUrl &url) { if (!m_curResults) { qDebug() << "m_curResults == nullptr"; return; } QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); if (root) { QString file = url.toString(QUrl::PreferLocalFile); if (file.size() > 70) { root->setData(0, Qt::DisplayRole, i18n("Replacing in: ...%1", file.right(70))); } else { root->setData(0, Qt::DisplayRole, i18n("Replacing in: %1", file)); } } } void KatePluginSearchView::replaceDone() { m_ui.stopAndNext->setCurrentIndex(0); m_ui.replaceCombo->setDisabled(false); m_ui.newTabButton->setDisabled(false); m_ui.searchCombo->setDisabled(false); m_ui.searchButton->setDisabled(false); m_ui.replaceCheckedBtn->setDisabled(false); m_ui.replaceButton->setDisabled(false); m_ui.displayOptions->setDisabled(false); m_ui.searchPlaceCombo->setDisabled(false); m_ui.useRegExp->setDisabled(false); m_ui.matchCase->setDisabled(false); m_ui.expandResults->setDisabled(false); m_ui.currentFolderButton->setDisabled(false); if (!m_curResults) { qDebug() << "m_curResults == nullptr"; return; } QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); if (root) { root->setData(0, Qt::DisplayRole, m_curResults->treeRootText); } } void KatePluginSearchView::docViewChanged() { Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!res) { return; } m_curResults = res; if (!m_mainWindow->activeView()) { return; } // add the marks if it is not already open KTextEditor::Document *doc = m_mainWindow->activeView()->document(); if (doc) { QTreeWidgetItem *rootItem = nullptr; for (int i=0; itree->topLevelItemCount(); i++) { QString url = res->tree->topLevelItem(i)->data(0, ReplaceMatches::FileUrlRole).toString(); QString fName = res->tree->topLevelItem(i)->data(0, ReplaceMatches::FileNameRole).toString(); if (url == doc->url().toString() && fName == doc->documentName()) { rootItem = res->tree->topLevelItem(i); break; } } if (rootItem) { int line; int column; int len; QTreeWidgetItem *item; for (int i=0; ichildCount(); i++) { item = rootItem->child(i); line = item->data(0, ReplaceMatches::LineRole).toInt(); column = item->data(0, ReplaceMatches::ColumnRole).toInt(); len = item->data(0, ReplaceMatches::MatchLenRole).toInt(); addMatchMark(doc, line, column, len); } } } } void KatePluginSearchView::expandResults() { m_curResults =qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!m_curResults) { qWarning() << "Results not found"; return; } if (m_ui.expandResults->isChecked()) { m_curResults->tree->expandAll(); } else { QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); m_curResults->tree->expandItem(root); if (root && (root->childCount() > 1)) { for (int i=0; ichildCount(); i++) { m_curResults->tree->collapseItem(root->child(i)); } } } } void KatePluginSearchView::itemSelected(QTreeWidgetItem *item) { if (!item) return; m_curResults = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!m_curResults) { return; } while (item->data(0, ReplaceMatches::ColumnRole).toString().isEmpty()) { item->treeWidget()->expandItem(item); item = item->child(0); if (!item) return; } item->treeWidget()->setCurrentItem(item); // get stuff int toLine = item->data(0, ReplaceMatches::LineRole).toInt(); int toColumn = item->data(0, ReplaceMatches::ColumnRole).toInt(); KTextEditor::Document* doc; QString url = item->data(0, ReplaceMatches::FileUrlRole).toString(); if (!url.isEmpty()) { doc = m_kateApp->findUrl(QUrl::fromUserInput(url)); } else { doc = m_replacer.findNamed(item->data(0, ReplaceMatches::FileNameRole).toString()); } // add the marks to the document if it is not already open if (!doc) { doc = m_kateApp->openUrl(QUrl::fromUserInput(url)); if (doc) { int line; int column; int len; QTreeWidgetItem *rootItem = (item->parent()==nullptr) ? item : item->parent(); for (int i=0; ichildCount(); i++) { item = rootItem->child(i); line = item->data(0, ReplaceMatches::LineRole).toInt(); column = item->data(0, ReplaceMatches::ColumnRole).toInt(); len = item->data(0, ReplaceMatches::MatchLenRole).toInt(); addMatchMark(doc, line, column, len); } } } if (!doc) return; // open the right view... m_mainWindow->activateView(doc); // any view active? if (!m_mainWindow->activeView()) { return; } // set the cursor to the correct position m_mainWindow->activeView()->setCursorPosition(KTextEditor::Cursor(toLine, toColumn)); m_mainWindow->activeView()->setFocus(); } void KatePluginSearchView::goToNextMatch() { bool wrapFromFirst = false; bool startFromFirst = false; bool startFromCursor = false; Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!res) { return; } QTreeWidgetItem *curr = res->tree->currentItem(); bool focusInView = m_mainWindow->activeView() && m_mainWindow->activeView()->hasFocus(); if (!curr && focusInView) { // no item has been visited && focus is not in searchCombo (probably in the view) -> // jump to the closest match after current cursor position // check if current file is in the file list curr = res->tree->topLevelItem(0); while (curr && curr->data(0, ReplaceMatches::FileUrlRole).toString() != m_mainWindow->activeView()->document()->url().toString()) { curr = res->tree->itemBelow(curr); } // now we are either in this file or !curr if (curr) { QTreeWidgetItem *fileBefore = curr; res->tree->expandItem(curr); int lineNr = 0; int columnNr = 0; if (m_mainWindow->activeView()->cursorPosition().isValid()) { lineNr = m_mainWindow->activeView()->cursorPosition().line(); columnNr = m_mainWindow->activeView()->cursorPosition().column(); } if (!curr->data(0, ReplaceMatches::ColumnRole).isValid()) { curr = res->tree->itemBelow(curr); }; while (curr && curr->data(0, ReplaceMatches::LineRole).toInt() <= lineNr && curr->data(0, ReplaceMatches::FileUrlRole).toString() == m_mainWindow->activeView()->document()->url().toString()) { if (curr->data(0, ReplaceMatches::LineRole).toInt() == lineNr && curr->data(0, ReplaceMatches::ColumnRole).toInt() >= columnNr - curr->data(0, ReplaceMatches::MatchLenRole).toInt()) { break; } fileBefore = curr; curr = res->tree->itemBelow(curr); } curr = fileBefore; startFromCursor = true; } } if (!curr) { curr = res->tree->topLevelItem(0); startFromFirst = true; } if (!curr) return; if (!curr->data(0, ReplaceMatches::ColumnRole).toString().isEmpty()) { curr = res->tree->itemBelow(curr); if (!curr) { wrapFromFirst = true; curr = res->tree->topLevelItem(0); } } itemSelected(curr); if (startFromFirst) { delete m_infoMessage; const QString msg = i18n("Starting from first match"); m_infoMessage = new KTextEditor::Message(msg, KTextEditor::Message::Information); m_infoMessage->setPosition(KTextEditor::Message::TopInView); m_infoMessage->setAutoHide(2000); m_infoMessage->setAutoHideMode(KTextEditor::Message::Immediate); m_infoMessage->setView(m_mainWindow->activeView()); m_mainWindow->activeView()->document()->postMessage(m_infoMessage); } else if (startFromCursor) { delete m_infoMessage; const QString msg = i18n("Next from cursor"); m_infoMessage = new KTextEditor::Message(msg, KTextEditor::Message::Information); m_infoMessage->setPosition(KTextEditor::Message::BottomInView); m_infoMessage->setAutoHide(2000); m_infoMessage->setAutoHideMode(KTextEditor::Message::Immediate); m_infoMessage->setView(m_mainWindow->activeView()); m_mainWindow->activeView()->document()->postMessage(m_infoMessage); } else if (wrapFromFirst) { delete m_infoMessage; const QString msg = i18n("Continuing from first match"); m_infoMessage = new KTextEditor::Message(msg, KTextEditor::Message::Information); m_infoMessage->setPosition(KTextEditor::Message::TopInView); m_infoMessage->setAutoHide(2000); m_infoMessage->setAutoHideMode(KTextEditor::Message::Immediate); m_infoMessage->setView(m_mainWindow->activeView()); m_mainWindow->activeView()->document()->postMessage(m_infoMessage); } } void KatePluginSearchView::goToPreviousMatch() { bool fromLast = false; Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!res) { return; } if (res->tree->topLevelItemCount() == 0) { return; } QTreeWidgetItem *curr = res->tree->currentItem(); if (!curr) { // no item has been visited -> jump to the closest match before current cursor position // check if current file is in the file curr = res->tree->topLevelItem(0); while (curr && curr->data(0, ReplaceMatches::FileUrlRole).toString() != m_mainWindow->activeView()->document()->url().toString()) { curr = res->tree->itemBelow(curr); } // now we are either in this file or !curr if (curr) { res->tree->expandItem(curr); int lineNr = 0; int columnNr = 0; if (m_mainWindow->activeView()->cursorPosition().isValid()) { lineNr = m_mainWindow->activeView()->cursorPosition().line(); columnNr = m_mainWindow->activeView()->cursorPosition().column()-1; } if (!curr->data(0, ReplaceMatches::ColumnRole).isValid()) { curr = res->tree->itemBelow(curr); }; while (curr && curr->data(0, ReplaceMatches::LineRole).toInt() <= lineNr && curr->data(0, ReplaceMatches::FileUrlRole).toString() == m_mainWindow->activeView()->document()->url().toString()) { if (curr->data(0, ReplaceMatches::LineRole).toInt() == lineNr && curr->data(0, ReplaceMatches::ColumnRole).toInt() > columnNr) { break; } curr = res->tree->itemBelow(curr); } } } QTreeWidgetItem *startChild = curr; // go to the item above. (curr == null is not a problem) curr = res->tree->itemAbove(curr); // expand the items above if needed if (curr && curr->data(0, ReplaceMatches::ColumnRole).toString().isEmpty()) { res->tree->expandItem(curr); // probably this file item curr = res->tree->itemAbove(curr); if (curr && curr->data(0, ReplaceMatches::ColumnRole).toString().isEmpty()) { res->tree->expandItem(curr); // probably file above if this is reached } curr = res->tree->itemAbove(startChild); } // skip file name items and the root item while (curr && curr->data(0, ReplaceMatches::ColumnRole).toString().isEmpty()) { curr = res->tree->itemAbove(curr); } if (!curr) { // select the last child of the last next-to-top-level item QTreeWidgetItem *root = res->tree->topLevelItem(0); // select the last "root item" if (!root || (root->childCount() < 1)) return; root = root->child(root->childCount()-1); // select the last match of the "root item" if (!root || (root->childCount() < 1)) return; curr = root->child(root->childCount()-1); fromLast = true; } itemSelected(curr); if (fromLast) { delete m_infoMessage; const QString msg = i18n("Continuing from last match"); m_infoMessage = new KTextEditor::Message(msg, KTextEditor::Message::Information); m_infoMessage->setPosition(KTextEditor::Message::BottomInView); m_infoMessage->setAutoHide(2000); m_infoMessage->setAutoHideMode(KTextEditor::Message::Immediate); m_infoMessage->setView(m_mainWindow->activeView()); m_mainWindow->activeView()->document()->postMessage(m_infoMessage); } } void KatePluginSearchView::readSessionConfig(const KConfigGroup &cg) { m_ui.searchCombo->clear(); m_ui.searchCombo->addItem(QString()); // Add empty Item m_ui.searchCombo->addItems(cg.readEntry("Search", QStringList())); m_ui.replaceCombo->clear(); m_ui.replaceCombo->addItem(QString()); // Add empty Item m_ui.replaceCombo->addItems(cg.readEntry("Replaces", QStringList())); m_ui.matchCase->setChecked(cg.readEntry("MatchCase", false)); m_ui.useRegExp->setChecked(cg.readEntry("UseRegExp", false)); m_ui.expandResults->setChecked(cg.readEntry("ExpandSearchResults", false)); int searchPlaceIndex = cg.readEntry("Place", 1); if (searchPlaceIndex < 0) { searchPlaceIndex = Folder; // for the case we happen to read -1 as Place } if ((searchPlaceIndex == Project) && (searchPlaceIndex >= m_ui.searchPlaceCombo->count())) { // handle the case that project mode was selected, but not yet available m_switchToProjectModeWhenAvailable = true; searchPlaceIndex = Folder; } m_ui.searchPlaceCombo->setCurrentIndex(searchPlaceIndex); m_ui.recursiveCheckBox->setChecked(cg.readEntry("Recursive", true)); m_ui.hiddenCheckBox->setChecked(cg.readEntry("HiddenFiles", false)); m_ui.symLinkCheckBox->setChecked(cg.readEntry("FollowSymLink", false)); m_ui.binaryCheckBox->setChecked(cg.readEntry("BinaryFiles", false)); m_ui.folderRequester->comboBox()->clear(); m_ui.folderRequester->comboBox()->addItems(cg.readEntry("SearchDiskFiless", QStringList())); m_ui.folderRequester->setText(cg.readEntry("SearchDiskFiles", QString())); m_ui.filterCombo->clear(); m_ui.filterCombo->addItems(cg.readEntry("Filters", QStringList())); m_ui.filterCombo->setCurrentIndex(cg.readEntry("CurrentFilter", -1)); m_ui.excludeCombo->clear(); m_ui.excludeCombo->addItems(cg.readEntry("ExcludeFilters", QStringList())); m_ui.excludeCombo->setCurrentIndex(cg.readEntry("CurrentExcludeFilter", -1)); m_ui.displayOptions->setChecked(searchPlaceIndex == Folder); } void KatePluginSearchView::writeSessionConfig(KConfigGroup &cg) { QStringList searchHistoy; for (int i=1; icount(); i++) { searchHistoy << m_ui.searchCombo->itemText(i); } cg.writeEntry("Search", searchHistoy); QStringList replaceHistoy; for (int i=1; icount(); i++) { replaceHistoy << m_ui.replaceCombo->itemText(i); } cg.writeEntry("Replaces", replaceHistoy); cg.writeEntry("MatchCase", m_ui.matchCase->isChecked()); cg.writeEntry("UseRegExp", m_ui.useRegExp->isChecked()); cg.writeEntry("ExpandSearchResults", m_ui.expandResults->isChecked()); cg.writeEntry("Place", m_ui.searchPlaceCombo->currentIndex()); cg.writeEntry("Recursive", m_ui.recursiveCheckBox->isChecked()); cg.writeEntry("HiddenFiles", m_ui.hiddenCheckBox->isChecked()); cg.writeEntry("FollowSymLink", m_ui.symLinkCheckBox->isChecked()); cg.writeEntry("BinaryFiles", m_ui.binaryCheckBox->isChecked()); QStringList folders; for (int i=0; icomboBox()->count(), 10); i++) { folders << m_ui.folderRequester->comboBox()->itemText(i); } cg.writeEntry("SearchDiskFiless", folders); cg.writeEntry("SearchDiskFiles", m_ui.folderRequester->text()); QStringList filterItems; for (int i=0; icount(), 10); i++) { filterItems << m_ui.filterCombo->itemText(i); } cg.writeEntry("Filters", filterItems); cg.writeEntry("CurrentFilter", m_ui.filterCombo->findText(m_ui.filterCombo->currentText())); QStringList excludeFilterItems; for (int i=0; icount(), 10); i++) { excludeFilterItems << m_ui.excludeCombo->itemText(i); } cg.writeEntry("ExcludeFilters", excludeFilterItems); cg.writeEntry("CurrentExcludeFilter", m_ui.excludeCombo->findText(m_ui.excludeCombo->currentText())); } void KatePluginSearchView::addTab() { if ((sender() != m_ui.newTabButton) && (m_ui.resultTabWidget->count() > 0) && m_ui.resultTabWidget->tabText(m_ui.resultTabWidget->currentIndex()).isEmpty()) { return; } Results *res = new Results(); res->tree->setRootIsDecorated(false); - connect(res->tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), - this, SLOT (itemSelected(QTreeWidgetItem*)), Qt::QueuedConnection); + connect(res->tree, &QTreeWidget::itemDoubleClicked, this, &KatePluginSearchView::itemSelected, Qt::UniqueConnection); res->searchPlaceIndex = m_ui.searchPlaceCombo->currentIndex(); res->useRegExp = m_ui.useRegExp->isChecked(); res->matchCase = m_ui.matchCase->isChecked(); m_ui.resultTabWidget->addTab(res, QString()); m_ui.resultTabWidget->setCurrentIndex(m_ui.resultTabWidget->count()-1); m_ui.stackedWidget->setCurrentIndex(0); m_ui.resultTabWidget->tabBar()->show(); m_ui.displayOptions->setChecked(false); res->tree->installEventFilter(this); } void KatePluginSearchView::tabCloseRequested(int index) { Results *tmp = qobject_cast(m_ui.resultTabWidget->widget(index)); if (m_curResults == tmp) { m_searchOpenFiles.cancelSearch(); m_searchDiskFiles.cancelSearch(); } if (m_ui.resultTabWidget->count() > 1) { delete tmp; // remove the tab m_curResults = nullptr; } if (m_ui.resultTabWidget->count() == 1) { m_ui.resultTabWidget->tabBar()->hide(); } } void KatePluginSearchView::resultTabChanged(int index) { if (index < 0) { return; } Results *res = qobject_cast(m_ui.resultTabWidget->widget(index)); if (!res) { qDebug() << "No res found"; return; } m_ui.searchCombo->blockSignals(true); m_ui.matchCase->blockSignals(true); m_ui.useRegExp->blockSignals(true); m_ui.searchPlaceCombo->blockSignals(true); m_ui.searchCombo->lineEdit()->setText(m_ui.resultTabWidget->tabText(index)); m_ui.useRegExp->setChecked(res->useRegExp); m_ui.matchCase->setChecked(res->matchCase); m_ui.searchPlaceCombo->setCurrentIndex(res->searchPlaceIndex); m_ui.searchCombo->blockSignals(false); m_ui.matchCase->blockSignals(false); m_ui.useRegExp->blockSignals(false); m_ui.searchPlaceCombo->blockSignals(false); searchPlaceChanged(); } bool KatePluginSearchView::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); QTreeWidget *tree = qobject_cast(obj); if (tree) { if (ke->matches(QKeySequence::Copy)) { // user pressed ctrl+c -> copy full URL to the clipboard QVariant variant = tree->currentItem()->data(0, ReplaceMatches::FileUrlRole); QApplication::clipboard()->setText(variant.toString()); event->accept(); return true; } if (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return) { if (tree->currentItem()) { itemSelected(tree->currentItem()); event->accept(); return true; } } } // NOTE: Qt::Key_Escape is handeled by handleEsc } return QObject::eventFilter(obj, event); } void KatePluginSearchView::searchContextMenu(const QPoint& pos) { QSet actionPointers; QMenu* const contextMenu = m_ui.searchCombo->lineEdit()->createStandardContextMenu(); if (!contextMenu) return; if (m_ui.useRegExp->isChecked()) { QMenu* menu = contextMenu->addMenu(i18n("Add...")); if (!menu) return; menu->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); actionPointers << menuEntry(menu, QStringLiteral("^"), QStringLiteral(""), i18n("Beginning of line")); actionPointers << menuEntry(menu, QStringLiteral("$"), QStringLiteral(""), i18n("End of line")); menu->addSeparator(); actionPointers << menuEntry(menu, QStringLiteral("."), QStringLiteral(""), i18n("Any single character (excluding line breaks)")); menu->addSeparator(); actionPointers << menuEntry(menu, QStringLiteral("+"), QStringLiteral(""), i18n("One or more occurrences")); actionPointers << menuEntry(menu, QStringLiteral("*"), QStringLiteral(""), i18n("Zero or more occurrences")); actionPointers << menuEntry(menu, QStringLiteral("?"), QStringLiteral(""), i18n("Zero or one occurrences")); actionPointers << menuEntry(menu, QStringLiteral("{"), QStringLiteral(",}"), i18n(" through occurrences"), QStringLiteral("{a"), QStringLiteral(",b}")); menu->addSeparator(); actionPointers << menuEntry(menu, QStringLiteral("("), QStringLiteral(")"), i18n("Group, capturing")); actionPointers << menuEntry(menu, QStringLiteral("|"), QStringLiteral(""), i18n("Or")); actionPointers << menuEntry(menu, QStringLiteral("["), QStringLiteral("]"), i18n("Set of characters")); actionPointers << menuEntry(menu, QStringLiteral("[^"), QStringLiteral("]"), i18n("Negative set of characters")); actionPointers << menuEntry(menu, QStringLiteral("(?:"), QStringLiteral(")"), i18n("Group, non-capturing"), QStringLiteral("(?:E")); actionPointers << menuEntry(menu, QStringLiteral("(?="), QStringLiteral(")"), i18n("Lookahead"), QStringLiteral("(?=E")); actionPointers << menuEntry(menu, QStringLiteral("(?!"), QStringLiteral(")"), i18n("Negative lookahead"), QStringLiteral("(?!E")); menu->addSeparator(); actionPointers << menuEntry(menu, QStringLiteral("\\n"), QStringLiteral(""), i18n("Line break")); actionPointers << menuEntry(menu, QStringLiteral("\\t"), QStringLiteral(""), i18n("Tab")); actionPointers << menuEntry(menu, QStringLiteral("\\b"), QStringLiteral(""), i18n("Word boundary")); actionPointers << menuEntry(menu, QStringLiteral("\\B"), QStringLiteral(""), i18n("Not word boundary")); actionPointers << menuEntry(menu, QStringLiteral("\\d"), QStringLiteral(""), i18n("Digit")); actionPointers << menuEntry(menu, QStringLiteral("\\D"), QStringLiteral(""), i18n("Non-digit")); actionPointers << menuEntry(menu, QStringLiteral("\\s"), QStringLiteral(""), i18n("Whitespace (excluding line breaks)")); actionPointers << menuEntry(menu, QStringLiteral("\\S"), QStringLiteral(""), i18n("Non-whitespace (excluding line breaks)")); actionPointers << menuEntry(menu, QStringLiteral("\\w"), QStringLiteral(""), i18n("Word character (alphanumerics plus '_')")); actionPointers << menuEntry(menu, QStringLiteral("\\W"), QStringLiteral(""), i18n("Non-word character")); } // Show menu QAction * const result = contextMenu->exec(m_ui.searchCombo->mapToGlobal(pos)); // Act on action if (result && actionPointers.contains(result)) { QLineEdit * lineEdit = m_ui.searchCombo->lineEdit(); const int cursorPos = lineEdit->cursorPosition(); QStringList beforeAfter = result->data().toString().split(QLatin1Char(' ')); if (beforeAfter.size() != 2) return; lineEdit->insert(beforeAfter[0] + beforeAfter[1]); lineEdit->setCursorPosition(cursorPos + beforeAfter[0].count()); lineEdit->setFocus(); } } void KatePluginSearchView::slotPluginViewCreated (const QString &name, QObject *pluginView) { // add view if (name == QStringLiteral("kateprojectplugin")) { m_projectPluginView = pluginView; slotProjectFileNameChanged (); connect (pluginView, SIGNAL(projectFileNameChanged()), this, SLOT(slotProjectFileNameChanged())); } } void KatePluginSearchView::slotPluginViewDeleted (const QString &name, QObject *) { // remove view if (name == QStringLiteral("kateprojectplugin")) { m_projectPluginView = nullptr; slotProjectFileNameChanged (); } } void KatePluginSearchView::slotProjectFileNameChanged () { // query new project file name QString projectFileName; if (m_projectPluginView) { projectFileName = m_projectPluginView->property("projectFileName").toString(); } // have project, enable gui for it if (!projectFileName.isEmpty()) { if (m_ui.searchPlaceCombo->count() <= Project) { // add "in Project" m_ui.searchPlaceCombo->addItem (QIcon::fromTheme(QStringLiteral("project-open")), i18n("In Current Project")); if (m_switchToProjectModeWhenAvailable) { // switch to search "in Project" m_switchToProjectModeWhenAvailable = false; setSearchPlace(Project); } // add "in Open Projects" m_ui.searchPlaceCombo->addItem(QIcon::fromTheme(QStringLiteral("project-open")), i18n("In All Open Projects")); } } // else: disable gui for it else { if (m_ui.searchPlaceCombo->count() >= Project) { // switch to search "in Open files", if "in Project" is active if (m_ui.searchPlaceCombo->currentIndex() >= Project) { setSearchPlace(OpenFiles); } // remove "in Project" and "in all projects" while (m_ui.searchPlaceCombo->count() > Project) { m_ui.searchPlaceCombo->removeItem(m_ui.searchPlaceCombo->count()-1); } } } } KateSearchCommand::KateSearchCommand(QObject *parent) : KTextEditor::Command(QStringList() << QStringLiteral("grep") << QStringLiteral("newGrep") << QStringLiteral("search") << QStringLiteral("newSearch") << QStringLiteral("pgrep") << QStringLiteral("newPGrep"), parent) { } bool KateSearchCommand::exec(KTextEditor::View* /*view*/, const QString& cmd, QString& /*msg*/, const KTextEditor::Range &) { //create a list of args QStringList args(cmd.split(QLatin1Char(' '), QString::KeepEmptyParts)); QString command = args.takeFirst(); QString searchText = args.join(QLatin1Char(' ')); if (command == QStringLiteral("grep") || command == QStringLiteral("newGrep")) { emit setSearchPlace(KatePluginSearchView::Folder); emit setCurrentFolder(); if (command == QStringLiteral("newGrep")) emit newTab(); } else if (command == QStringLiteral("search") || command == QStringLiteral("newSearch")) { emit setSearchPlace(KatePluginSearchView::OpenFiles); if (command == QStringLiteral("newSearch")) emit newTab(); } else if (command == QStringLiteral("pgrep") || command == QStringLiteral("newPGrep")) { emit setSearchPlace(KatePluginSearchView::Project); if (command == QStringLiteral("newPGrep")) emit newTab(); } emit setSearchString(searchText); emit startSearch(); return true; } bool KateSearchCommand::help(KTextEditor::View */*view*/, const QString &cmd, QString & msg) { if (cmd.startsWith(QStringLiteral("grep"))) { msg = i18n("Usage: grep [pattern to search for in folder]"); } else if (cmd.startsWith(QStringLiteral("newGrep"))) { msg = i18n("Usage: newGrep [pattern to search for in folder]"); } else if (cmd.startsWith(QStringLiteral("search"))) { msg = i18n("Usage: search [pattern to search for in open files]"); } else if (cmd.startsWith(QStringLiteral("newSearch"))) { msg = i18n("Usage: search [pattern to search for in open files]"); } else if (cmd.startsWith(QStringLiteral("pgrep"))) { msg = i18n("Usage: pgrep [pattern to search for in current project]"); } else if (cmd.startsWith(QStringLiteral("newPGrep"))) { msg = i18n("Usage: newPGrep [pattern to search for in current project]"); } return true; } #include "plugin_search.moc" // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/search/replace_matches.cpp b/addons/search/replace_matches.cpp index 94e42b4e1..e4fe90454 100644 --- a/addons/search/replace_matches.cpp +++ b/addons/search/replace_matches.cpp @@ -1,209 +1,209 @@ /* Kate search plugin * * Copyright (C) 2011-2013 by KÃ¥re Särs * * 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 in a file called COPYING; if not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include "replace_matches.h" #include #include #include #include #include ReplaceMatches::ReplaceMatches(QObject *parent) : QObject(parent), m_manager(nullptr), m_tree(nullptr), m_rootIndex(-1) { - connect(this, SIGNAL(replaceNextMatch()), this, SLOT(doReplaceNextMatch()), Qt::QueuedConnection); + connect(this, &ReplaceMatches::replaceNextMatch, this, &ReplaceMatches::doReplaceNextMatch, Qt::QueuedConnection); } void ReplaceMatches::replaceChecked(QTreeWidget *tree, const QRegularExpression ®exp, const QString &replace) { if (m_manager == nullptr) return; if (m_rootIndex != -1) return; m_tree = tree; m_rootIndex = 0; m_regExp = regexp; m_replaceText = replace; m_cancelReplace = false; m_progressTime.restart(); emit replaceNextMatch(); } void ReplaceMatches::setDocumentManager(KTextEditor::Application *manager) { m_manager = manager; } void ReplaceMatches::cancelReplace() { m_cancelReplace = true; } KTextEditor::Document *ReplaceMatches::findNamed(const QString &name) { QList docs = m_manager->documents(); foreach (KTextEditor::Document* it, docs) { if ( it->documentName() == name) { return it; } } return nullptr; } void ReplaceMatches::doReplaceNextMatch() { if ((!m_manager) || (m_cancelReplace) || (m_tree->topLevelItemCount() != 1)) { m_rootIndex = -1; emit replaceDone(); return; } // NOTE The document managers signal documentWillBeDeleted() must be connected to // cancelReplace(). A closed file could lead to a crash if it is not handled. // Open the file QTreeWidgetItem *rootItem = m_tree->topLevelItem(0)->child(m_rootIndex); if (!rootItem) { m_rootIndex = -1; emit replaceDone(); return; } if (!rootItem->data(0, ColumnRole).toString().isEmpty()) { // this is a search as you type replace rootItem = m_tree->topLevelItem(0); m_cancelReplace = true; // only one document... } if (rootItem->checkState(0) == Qt::Unchecked) { m_rootIndex++; emit replaceNextMatch(); return; } KTextEditor::Document *doc; QString docUrl = rootItem->data(0, FileUrlRole).toString(); if (docUrl.isEmpty()) { doc = findNamed(rootItem->data(0, FileNameRole).toString()); } else { doc = m_manager->findUrl(QUrl::fromUserInput(docUrl)); if (!doc) { doc = m_manager->openUrl(QUrl::fromUserInput(rootItem->data(0, FileUrlRole).toString())); } } if (!doc) { m_rootIndex++; emit replaceNextMatch(); return; } if (m_progressTime.elapsed() > 100) { m_progressTime.restart(); emit replaceStatus(doc->url()); } QVector rVector; QStringList rTexts; KTextEditor::MovingInterface* miface = qobject_cast(doc); int line; int column; int matchLen; int endLine; int endColumn; QTreeWidgetItem *item; QString matchLines; // lines might be modified so search the document again for (int i=0; ichildCount(); i++) { item = rootItem->child(i); if (item->checkState(0) == Qt::Unchecked) continue; line = endLine= item->data(0, LineRole).toInt(); column = item->data(0, ColumnRole).toInt(); matchLen = item->data(0, MatchLenRole).toInt(); matchLines = doc->line(line).mid(column); while (matchLines.size() < matchLen) { if (endLine+1 >= doc->lines()) break; endLine++; matchLines+= QLatin1Char('\n') + doc->line(endLine); } QRegularExpressionMatch match = m_regExp.match(matchLines); if (match.capturedStart() != 0) { qDebug() << matchLines << "Does not match" << m_regExp.pattern(); continue; } QString replaceText = m_replaceText; replaceText.replace(QStringLiteral("\\\\"), QStringLiteral("¤Search&Replace¤")); // allow captures \0 .. \9 for (int j = qMin(9, match.lastCapturedIndex()); j >= 0; --j) { replaceText.replace(QString(QStringLiteral("\\%1")).arg(j), match.captured(j)); } // allow captures \{0} .. \{9999999}... for (int j = match.lastCapturedIndex(); j >= 0; --j) { replaceText.replace(QString(QStringLiteral("\\{%1}")).arg(j), match.captured(j)); } replaceText.replace(QStringLiteral("\\n"), QStringLiteral("\n")); replaceText.replace(QStringLiteral("\\t"), QStringLiteral("\t")); replaceText.replace(QStringLiteral("¤Search&Replace¤"), QStringLiteral("\\")); rTexts << replaceText; replaceText.replace(QLatin1Char('\n'), QStringLiteral("\\n")); replaceText.replace(QLatin1Char('\t'), QStringLiteral("\\t")); QString html = item->data(0, PreMatchRole).toString(); html += QStringLiteral("") + item->data(0, MatchRole).toString() + QStringLiteral(" "); html += QStringLiteral("") + replaceText + QStringLiteral(""); html += item->data(0, PostMatchRole).toString(); item->setData(0, Qt::DisplayRole, i18n("Line: %1: %2",line+1, html)); endLine = line; endColumn = column+matchLen; while ((endLine < doc->lines()) && (endColumn > doc->line(endLine).size())) { endColumn -= doc->line(endLine).size(); endColumn--; // remove one for '\n' endLine++; } KTextEditor::Range range(line, column, endLine, endColumn); KTextEditor::MovingRange* mr = miface->newMovingRange(range); rVector.append(mr); } for (int i=0; istart().line(); column = rVector[i]->start().column(); doc->replaceText(*rVector[i], rTexts[i]); emit matchReplaced(doc, line, column, rTexts[i].length()); } qDeleteAll(rVector); m_rootIndex++; emit replaceNextMatch(); } diff --git a/addons/search/search_open_files.cpp b/addons/search/search_open_files.cpp index 6a392dbb0..e0db9b918 100644 --- a/addons/search/search_open_files.cpp +++ b/addons/search/search_open_files.cpp @@ -1,186 +1,186 @@ /* Kate search plugin * * Copyright (C) 2011-2013 by KÃ¥re Särs * * 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 in a file called COPYING; if not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include "search_open_files.h" #include SearchOpenFiles::SearchOpenFiles(QObject *parent) : QObject(parent), m_nextIndex(-1), m_cancelSearch(true) { - connect(this, SIGNAL(searchNextFile(int)), this, SLOT(doSearchNextFile(int)), Qt::QueuedConnection); + connect(this, &SearchOpenFiles::searchNextFile, this, &SearchOpenFiles::doSearchNextFile, Qt::QueuedConnection); } bool SearchOpenFiles::searching() { return !m_cancelSearch; } void SearchOpenFiles::startSearch(const QList &list, const QRegularExpression ®exp) { if (m_nextIndex != -1) return; m_docList = list; m_nextIndex = 0; m_regExp = regexp; m_cancelSearch = false; m_statusTime.restart(); emit searchNextFile(0); } void SearchOpenFiles::cancelSearch() { m_cancelSearch = true; } void SearchOpenFiles::doSearchNextFile(int startLine) { if (m_cancelSearch) { m_nextIndex = -1; m_cancelSearch = true; emit searchDone(); return; } // NOTE The document managers signal documentWillBeDeleted() must be connected to // cancelSearch(). A closed file could lead to a crash if it is not handled. int line = searchOpenFile(m_docList[m_nextIndex], m_regExp, startLine); if (line == 0) { // file searched go to next m_nextIndex++; if (m_nextIndex == m_docList.size()) { m_nextIndex = -1; m_cancelSearch = true; emit searchDone(); } else { emit searchNextFile(0); } } else { emit searchNextFile(line); } } int SearchOpenFiles::searchOpenFile(KTextEditor::Document *doc, const QRegularExpression ®Exp, int startLine) { if (m_statusTime.elapsed() > 100) { m_statusTime.restart(); emit searching(doc->url().toString()); } if (regExp.pattern().contains(QStringLiteral("\\n"))) { return searchMultiLineRegExp(doc, regExp, startLine); } return searchSingleLineRegExp(doc, regExp, startLine); } int SearchOpenFiles::searchSingleLineRegExp(KTextEditor::Document *doc, const QRegularExpression ®Exp, int startLine) { int column; QTime time; time.start(); for (int line = startLine; line < doc->lines(); line++) { if (time.elapsed() > 100) { qDebug() << "Search time exceeded" << time.elapsed() << line; return line; } QRegularExpressionMatch match; match = regExp.match(doc->line(line)); column = match.capturedStart(); while (column != -1 && !match.captured().isEmpty()) { emit matchFound(doc->url().toString(), doc->documentName(), line, column, doc->line(line), match.capturedLength()); match = regExp.match(doc->line(line), column + match.capturedLength()); column = match.capturedStart(); } } return 0; } int SearchOpenFiles::searchMultiLineRegExp(KTextEditor::Document *doc, const QRegularExpression ®Exp, int startLine) { int column = 0; int line = 0; QTime time; time.start(); QRegularExpression tmpRegExp = regExp; if (startLine == 0) { // Copy the whole file to a temporary buffer to be able to search newlines m_fullDoc.clear(); m_lineStart.clear(); m_lineStart << 0; for (int i=0; ilines(); i++) { m_fullDoc += doc->line(i) + QLatin1Char('\n'); m_lineStart << m_fullDoc.size(); } if (!regExp.pattern().endsWith(QStringLiteral("$"))) { // if regExp ends with '$' leave the extra newline at the end as // '$' will be replaced with (?=\\n), which needs the extra newline m_fullDoc.remove(m_fullDoc.size()-1, 1); } } else { if (startLine>0 && startLine column) { line = i-1; break; } } if (line == -1) { break; } emit matchFound(doc->url().toString(), doc->documentName(), line, (column - m_lineStart[line]), doc->line(line).left(column - m_lineStart[line])+match.captured(), match.capturedLength()); match = tmpRegExp.match(m_fullDoc, column + match.capturedLength()); column = match.capturedStart(); if (time.elapsed() > 100) { //qDebug() << "Search time exceeded" << time.elapsed() << line; return line; } } return 0; } diff --git a/addons/sessionapplet/engine/katesessionsmodel.cpp b/addons/sessionapplet/engine/katesessionsmodel.cpp index 6dd279502..bdd08617a 100644 --- a/addons/sessionapplet/engine/katesessionsmodel.cpp +++ b/addons/sessionapplet/engine/katesessionsmodel.cpp @@ -1,131 +1,131 @@ /*************************************************************************** * Copyright (C) 2014 Joseph Wenninger * * Copyright (C) 2008 by Montel Laurent * * * * 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 "katesessionsmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bool katesessions_compare_sessions(const QString &s1, const QString &s2) { //return KStringHandler::naturalCompare(s1,s2)==-1; return s1.compare(s2)==-1; } KateSessionsModel::KateSessionsModel(QObject *parent) : QStandardItemModel(parent) /*, m_config(0)*/ { KDirWatch *dirwatch = new KDirWatch( this ); m_sessionsDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/kate/sessions"); dirwatch->addDir( m_sessionsDir ); - connect( dirwatch, SIGNAL(dirty(QString)), this, SLOT(slotUpdateSessionMenu()) ); + connect(dirwatch, &KDirWatch::dirty, this, &KateSessionsModel::slotUpdateSessionMenu); slotUpdateSessionMenu(); } KateSessionsModel::~KateSessionsModel() { } void KateSessionsModel::slotUpdateSessionMenu() { clear(); m_sessions.clear(); m_fullList.clear(); initSessionFiles(); } void KateSessionsModel::initSessionFiles() { QStandardItem *item = new QStandardItem(); item->setData(i18n("Start Kate (no arguments)"), Qt::DisplayRole); item->setData( QIcon::fromTheme( QStringLiteral("kate") ), Qt::DecorationRole ); item->setData( QStringLiteral("_kate_noargs"), Uuid ); item->setData(0,TypeRole); m_fullList << item->data(Qt::DisplayRole).toString(); appendRow(item); item = new QStandardItem(); item->setData( i18n("New Kate Session"), Qt::DisplayRole); item->setData( QIcon::fromTheme( QStringLiteral("document-new") ), Qt::DecorationRole ); qDebug()<setData( QStringLiteral("_kate_newsession"), Uuid ); item->setData(1,TypeRole); m_fullList << item->data(Qt::DisplayRole).toString(); appendRow(item); item = new QStandardItem(); item->setData( i18n("New Anonymous Session"), Qt::DisplayRole); item->setData( QStringLiteral("_kate_anon_newsession"), Uuid ); item->setData(0,TypeRole); item->setData( QIcon::fromTheme( QStringLiteral("document-new") ), Qt::DecorationRole ); m_fullList << item->data(Qt::DisplayRole).toString(); appendRow(item); QDir dir(m_sessionsDir, QStringLiteral("*.katesession")); for (unsigned int i = 0; i < dir.count(); ++i) { QString name = dir[i]; name.chop(12); // .katesession m_sessions << QUrl::fromPercentEncoding(name.toLatin1()); } qSort(m_sessions.begin(),m_sessions.end(),katesessions_compare_sessions); QLatin1String ext(".katesession"); for(QStringList::ConstIterator it=m_sessions.constBegin();it!=m_sessions.constEnd();++it) { m_fullList << *it; item = new QStandardItem(); item->setData(*it, Qt::DisplayRole); item->setData( QString((*it)+ext), Uuid ); item->setData( QIcon::fromTheme( QStringLiteral("document-open") ), Qt::DecorationRole ); item->setData(2,TypeRole); appendRow( item); } } QHash< int, QByteArray > KateSessionsModel::roleNames() const { QHash hash; hash.insert(Qt::DisplayRole, QByteArrayLiteral("DisplayRole")); hash.insert(Qt::DecorationRole, QByteArrayLiteral("DecorationRole")); hash.insert(Qt::UserRole+3, QByteArrayLiteral("UuidRole")); hash.insert(Qt::UserRole+4, QByteArrayLiteral("TypeRole")); return hash; } diff --git a/addons/snippets/editrepository.cpp b/addons/snippets/editrepository.cpp index 8517e7513..db08121a6 100644 --- a/addons/snippets/editrepository.cpp +++ b/addons/snippets/editrepository.cpp @@ -1,138 +1,138 @@ /* This file is part of the Kate project. * Based on the snippet plugin from KDevelop 4. * * Copyright (C) 2007 Robert Gruber * Copyright (C) 2010 Milian Wolff * Copyright (C) 2012 Christoph Cullmann * Copyright (C) 2014 Sven Brauch * * 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 "editrepository.h" #include "snippetrepository.h" #include "snippetstore.h" #include #include #include #include #include #include #include EditRepository::EditRepository(SnippetRepository* repository, QWidget* parent) : QDialog(parent), Ui::EditRepositoryBase(), m_repo(repository) { setupUi(this); connect(repoNameEdit, &KLineEdit::textEdited, this, &EditRepository::validate); connect(this, &QDialog::accepted, this, &EditRepository::save); auto ok = buttonBox->button(QDialogButtonBox::Ok); KGuiItem::assign(ok, KStandardGuiItem::ok()); - connect(ok, SIGNAL(clicked()), this, SLOT(accept())); + connect(ok, &QPushButton::clicked, this, &EditRepository::accept); auto cancel = buttonBox->button(QDialogButtonBox::Cancel); KGuiItem::assign(cancel, KStandardGuiItem::cancel()); - connect(cancel, SIGNAL(clicked()), this, SLOT(reject())); + connect(cancel, &QPushButton::clicked, this, &EditRepository::reject); // fill list of available modes QSharedPointer document(KTextEditor::Editor::instance()->createDocument(nullptr)); repoFileTypesList->addItems(document->highlightingModes()); repoFileTypesList->sortItems(); repoFileTypesList->setSelectionMode(QAbstractItemView::ExtendedSelection); connect(repoFileTypesList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &EditRepository::updateFileTypes); // add default licenses repoLicenseEdit->addItems(QStringList() << QLatin1String("BSD") << QLatin1String("Artistic") << QLatin1String("LGPL v2+") << QLatin1String("LGPL v3+")); repoLicenseEdit->setEditable(true); // if we edit a repo, add all existing data if ( m_repo ) { repoNameEdit->setText(m_repo->text()); repoAuthorsEdit->setText(m_repo->authors()); repoNamespaceEdit->setText(m_repo->completionNamespace()); if ( !m_repo->license().isEmpty() ) { int index = repoLicenseEdit->findText(m_repo->license()); if ( index == -1 ) { repoLicenseEdit->addItem(m_repo->license()); repoLicenseEdit->model()->sort(0); index = repoLicenseEdit->findText(m_repo->license()); } repoLicenseEdit->setCurrentIndex(index); } foreach ( const QString& type, m_repo->fileTypes() ) { foreach( QListWidgetItem* item, repoFileTypesList->findItems(type, Qt::MatchExactly) ) { item->setSelected(true); } } setWindowTitle(i18n("Edit Snippet Repository %1", m_repo->text())); } else { setWindowTitle(i18n("Create New Snippet Repository")); KUser user; repoAuthorsEdit->setText(user.property(KUser::FullName).toString()); } validate(); updateFileTypes(); repoNameEdit->setFocus(); } void EditRepository::validate() { bool valid = !repoNameEdit->text().isEmpty() && !repoNameEdit->text().contains(QLatin1Char('/')); buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid); } void EditRepository::save() { Q_ASSERT(!repoNameEdit->text().isEmpty()); if ( !m_repo ) { // save as new repo m_repo = SnippetRepository::createRepoFromName(repoNameEdit->text()); } m_repo->setText(repoNameEdit->text()); m_repo->setAuthors(repoAuthorsEdit->text()); m_repo->setLicense(repoLicenseEdit->currentText()); m_repo->setCompletionNamespace(repoNamespaceEdit->text()); QStringList types; foreach( QListWidgetItem* item, repoFileTypesList->selectedItems() ) { types << item->text(); } m_repo->setFileTypes(types); m_repo->save(); setWindowTitle(i18n("Edit Snippet Repository %1", m_repo->text())); } void EditRepository::updateFileTypes() { QStringList types; foreach( QListWidgetItem* item, repoFileTypesList->selectedItems() ) { types << item->text(); } if ( types.isEmpty() ) { repoFileTypesListLabel->setText(i18n("leave empty for general purpose snippets")); } else { repoFileTypesListLabel->setText(types.join(QLatin1String(", "))); } } diff --git a/addons/symbolviewer/plugin_katesymbolviewer.cpp b/addons/symbolviewer/plugin_katesymbolviewer.cpp index 034be92a8..c61e5abef 100644 --- a/addons/symbolviewer/plugin_katesymbolviewer.cpp +++ b/addons/symbolviewer/plugin_katesymbolviewer.cpp @@ -1,468 +1,465 @@ /*************************************************************************** * plugin_katesymbolviewer.cpp - description * ------------------- * Copyright (C) 2014 by KÃ¥re Särs * * begin : Apr 2 2003 * author : 2003 Massimo Callegari * email : massimocallegari@yahoo.it * * Changes: * Nov 09 2004 v.1.3 - For changelog please refer to KDE CVS * Nov 05 2004 v.1.2 - Choose parser from the current highlight. Minor i18n changes. * Nov 28 2003 v.1.1 - Structured for multilanguage support * Added preliminary Tcl/Tk parser (thanks Rohit). To be improved. * Various bugfixing. * Jun 19 2003 v.1.0 - Removed QTimer (polling is Evil(tm)... ) * - Captured documentChanged() event to refresh symbol list * - Tooltips vanished into nowhere...sigh :( * May 04 2003 v 0.6 - Symbol List becomes a K3ListView object. Removed Tooltip class. * Added a QTimer that every 200ms checks: * * if the list width has changed * * if the document has changed * Added an entry in the m_popup menu to switch between List and Tree mode * Various bugfixing. * Apr 24 2003 v 0.5 - Added three check buttons in m_popup menu to show/hide symbols * Apr 23 2003 v 0.4 - "View Symbol" moved in Settings menu. "Refresh List" is no * longer in Kate menu. Moved into a m_popup menu activated by a * mouse right button click. + Bugfixing. * Apr 22 2003 v 0.3 - Added macro extraction + several bugfixing * Apr 19 2003 v 0.2 - Added to CVS. Extract functions and structures * Apr 07 2003 v 0.1 - First version. * ***************************************************************************/ /*************************************************************************** * * * 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 "plugin_katesymbolviewer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON (KatePluginSymbolViewerFactory, "katesymbolviewerplugin.json", registerPlugin();) KatePluginSymbolViewerView::KatePluginSymbolViewerView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mw) :QObject(mw) ,m_mainWindow(mw) ,m_plugin(qobject_cast(plugin)) { // FIXME KF5 KGlobal::locale()->insertCatalog("katesymbolviewerplugin"); KXMLGUIClient::setComponentName (QLatin1String("katesymbolviewer"), i18n ("SymbolViewer")); setXMLFile(QLatin1String("ui.rc")); mw->guiFactory()->addClient (this); m_symbols = nullptr; m_popup = new QMenu(m_symbols); m_popup->addAction(i18n("Refresh List"), this, SLOT(slotRefreshSymbol())); m_popup->addSeparator(); m_macro = m_popup->addAction(i18n("Show Macros"), this, SLOT(toggleShowMacros())); m_struct = m_popup->addAction(i18n("Show Structures"), this, SLOT(toggleShowStructures())); m_func = m_popup->addAction(i18n("Show Functions"), this, SLOT(toggleShowFunctions())); m_popup->addSeparator(); m_popup->addAction(i18n("List/Tree Mode"), this, SLOT(slotChangeMode())); m_sort = m_popup->addAction(i18n("Enable Sorting"), this, SLOT(slotEnableSorting())); KConfigGroup config(KSharedConfig::openConfig(), "PluginSymbolViewer"); m_plugin->typesOn = config.readEntry(QLatin1String("ViewTypes"), false); m_plugin->expandedOn = config.readEntry(QLatin1String("ExpandTree"), false); m_plugin->treeOn = config.readEntry(QLatin1String("TreeView"), false); m_plugin->sortOn = config.readEntry(QLatin1String("SortSymbols"), false); m_macro->setChecked(true); m_struct->setChecked(true); m_func->setChecked(true); m_sort->setChecked(m_plugin->sortOn); macro_on = true; struct_on = true; func_on = true; m_updateTimer.setSingleShot(true); - connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(slotRefreshSymbol())); + connect(&m_updateTimer, &QTimer::timerId, this, &KatePluginSymbolViewerView::slotRefreshSymbol); m_currItemTimer.setSingleShot(true); - connect(&m_currItemTimer, SIGNAL(timeout()), this, SLOT(updateCurrTreeItem())); + connect(&m_currItemTimer, &QTimer::timeout, this, &KatePluginSymbolViewerView::updateCurrTreeItem); QPixmap cls( ( const char** ) class_xpm ); m_toolview = m_mainWindow->createToolView(plugin, QLatin1String("kate_plugin_symbolviewer"), KTextEditor::MainWindow::Left, cls, i18n("Symbol List")); QWidget *container = new QWidget(m_toolview); QHBoxLayout *layout = new QHBoxLayout(container); m_symbols = new QTreeWidget(); m_symbols->setFocusPolicy(Qt::NoFocus); m_symbols->setLayoutDirection( Qt::LeftToRight ); layout->addWidget(m_symbols, 10); layout->setContentsMargins(0,0,0,0); - connect(m_symbols, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(goToSymbol(QTreeWidgetItem*))); - connect(m_symbols, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(slotShowContextMenu(QPoint))); + connect(m_symbols, &QTreeWidget::itemClicked, this, &KatePluginSymbolViewerView::goToSymbol); + connect(m_symbols, &QTreeWidget::customContextMenuRequested, this, &KatePluginSymbolViewerView::slotShowContextMenu); - connect(m_mainWindow, SIGNAL(viewChanged(KTextEditor::View *)), this, SLOT(slotDocChanged())); + connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KatePluginSymbolViewerView::slotDocChanged); QStringList titles; titles << i18nc("@title:column", "Symbols") << i18nc("@title:column", "Position"); m_symbols->setColumnCount(2); m_symbols->setHeaderLabels(titles); m_symbols->setColumnHidden(1, true); m_symbols->setSortingEnabled(m_plugin->sortOn); m_symbols->setRootIsDecorated(0); m_symbols->setContextMenuPolicy(Qt::CustomContextMenu); m_symbols->setIndentation(10); m_toolview->installEventFilter(this); /* First Symbols parsing here...*/ QTimer::singleShot(10, this, SLOT(slotRefreshSymbol())); if (m_plugin->sortOn == true) m_symbols->sortItems(0, Qt::AscendingOrder); } KatePluginSymbolViewerView::~KatePluginSymbolViewerView() { m_mainWindow->guiFactory()->removeClient (this); delete m_toolview; delete m_popup; } void KatePluginSymbolViewerView::toggleShowMacros(void) { bool s = !m_macro->isChecked(); m_macro->setChecked(s); macro_on = s; slotRefreshSymbol(); } void KatePluginSymbolViewerView::toggleShowStructures(void) { bool s = !m_struct->isChecked(); m_struct->setChecked(s); struct_on = s; slotRefreshSymbol(); } void KatePluginSymbolViewerView::toggleShowFunctions(void) { bool s = !m_func->isChecked(); m_func->setChecked(s); func_on = s; slotRefreshSymbol(); } void KatePluginSymbolViewerView::slotRefreshSymbol() { if (!m_symbols) return; // hack to get always apply sorting option to apply immediately if ((m_plugin->sortOn && !m_symbols->isSortingEnabled()) || (!m_plugin->sortOn && m_symbols->isSortingEnabled())) { m_plugin->sortOn = !m_plugin->sortOn; return slotEnableSorting(); } m_symbols->clear(); parseSymbols(); updateCurrTreeItem(); } void KatePluginSymbolViewerView::slotChangeMode() { m_plugin->treeOn = !m_plugin->treeOn; m_symbols->clear(); parseSymbols(); } void KatePluginSymbolViewerView::slotEnableSorting() { m_plugin->sortOn = !m_plugin->sortOn; m_sort->setChecked(m_plugin->sortOn); m_symbols->clear(); if (m_plugin->sortOn == true) m_symbols->setSortingEnabled(true); else m_symbols->setSortingEnabled(false); parseSymbols(); if (m_plugin->sortOn == true) m_symbols->sortItems(0, Qt::AscendingOrder); } void KatePluginSymbolViewerView::slotDocChanged() { slotRefreshSymbol(); KTextEditor::View *view = m_mainWindow->activeView(); //qDebug()<<"Document changed !!!!" << view; if (view) { - connect(view, SIGNAL(cursorPositionChanged(KTextEditor::View*,KTextEditor::Cursor)), - this, SLOT(cursorPositionChanged()), Qt::UniqueConnection); + connect(view, &KTextEditor::View::cursorPositionChanged, this, &KatePluginSymbolViewerView::cursorPositionChanged); if (view->document()) { - connect(view->document(), SIGNAL(textChanged(KTextEditor::Document*)), - this, SLOT(slotDocEdited()), Qt::UniqueConnection); + connect(view->document(), &KTextEditor::Document::textChanged, this, &KatePluginSymbolViewerView::slotDocEdited); } } } void KatePluginSymbolViewerView::slotDocEdited() { m_updateTimer.start(500); } void KatePluginSymbolViewerView::cursorPositionChanged() { m_currItemTimer.start(100); } void KatePluginSymbolViewerView::updateCurrTreeItem() { if (!m_mainWindow) { return; } KTextEditor::View* editView = m_mainWindow->activeView(); if (!editView) { return; } KTextEditor::Document* doc = editView->document(); if (!doc) { return; } int currLine = editView->cursorPositionVirtual().line(); int newItemLine = 0; QTreeWidgetItem *newItem = nullptr; QTreeWidgetItem *tmp = nullptr; for (int i=0; itopLevelItemCount(); i++) { tmp = newActveItem(newItemLine, currLine, m_symbols->topLevelItem(i)); if (tmp) newItem = tmp; } if (newItem) { m_symbols->blockSignals(true); m_symbols->setCurrentItem(newItem); m_symbols->blockSignals(false); } } QTreeWidgetItem *KatePluginSymbolViewerView::newActveItem(int &newItemLine, int currLine, QTreeWidgetItem *item) { QTreeWidgetItem *newItem = nullptr; QTreeWidgetItem *tmp = nullptr; int itemLine = item->data(1, Qt::DisplayRole).toInt(); if ((itemLine <= currLine) && (itemLine > newItemLine)) { newItemLine = itemLine; newItem = item; } for (int i=0; ichildCount(); i++) { tmp = newActveItem(newItemLine, currLine, item->child(i)); if (tmp) newItem = tmp; } return newItem; } bool KatePluginSymbolViewerView::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); if ((obj == m_toolview) && (ke->key() == Qt::Key_Escape)) { m_mainWindow->activeView()->setFocus(); event->accept(); return true; } } return QObject::eventFilter(obj, event); } void KatePluginSymbolViewerView::slotShowContextMenu(const QPoint &p) { m_popup->popup(m_symbols->mapToGlobal(p)); } void KatePluginSymbolViewerView::parseSymbols(void) { if (!m_mainWindow->activeView()) return; KTextEditor::Document *doc = m_mainWindow->activeView()->document(); // be sure we have some document around ! if (!doc) return; /** Get the current highlighting mode */ QString hlModeName = doc->mode(); if (hlModeName.contains(QLatin1String("C++")) || hlModeName == QLatin1String("C") || hlModeName == QLatin1String("ANSI C89")) parseCppSymbols(); else if (hlModeName == QLatin1String("PHP (HTML)")) parsePhpSymbols(); else if (hlModeName == QLatin1String("Tcl/Tk")) parseTclSymbols(); else if (hlModeName == QLatin1String("Fortran")) parseFortranSymbols(); else if (hlModeName == QLatin1String("Perl")) parsePerlSymbols(); else if (hlModeName == QLatin1String("Python")) parsePythonSymbols(); else if (hlModeName == QLatin1String("Ruby")) parseRubySymbols(); else if (hlModeName == QLatin1String("Java")) parseCppSymbols(); else if (hlModeName == QLatin1String("xslt")) parseXsltSymbols(); else if (hlModeName == QLatin1String("Bash")) parseBashSymbols(); else if (hlModeName == QLatin1String("ActionScript 2.0") || hlModeName == QLatin1String("JavaScript") || hlModeName == QLatin1String("QML")) parseEcmaSymbols(); else new QTreeWidgetItem(m_symbols, QStringList(i18n("Sorry. Language not supported yet") ) ); } void KatePluginSymbolViewerView::goToSymbol(QTreeWidgetItem *it) { KTextEditor::View *kv = m_mainWindow->activeView(); // be sure we really have a view ! if (!kv) return; //qDebug()<<"Slot Activated at pos: "<indexOfTopLevelItem(it); kv->setCursorPosition (KTextEditor::Cursor (it->text(1).toInt(nullptr, 10), 0)); } KatePluginSymbolViewer::KatePluginSymbolViewer( QObject* parent, const QList& ) : KTextEditor::Plugin (parent) { //qDebug()<<"KatePluginSymbolViewer"; } KatePluginSymbolViewer::~KatePluginSymbolViewer() { //qDebug()<<"~KatePluginSymbolViewer"; } QObject *KatePluginSymbolViewer::createView (KTextEditor::MainWindow *mainWindow) { return new KatePluginSymbolViewerView (this, mainWindow); } KTextEditor::ConfigPage* KatePluginSymbolViewer::configPage(int, QWidget *parent) { KatePluginSymbolViewerConfigPage* p = new KatePluginSymbolViewerConfigPage(this, parent); KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("PluginSymbolViewer")); p->viewReturns->setChecked(config.readEntry(QLatin1String("ViewTypes"), false)); p->expandTree->setChecked(config.readEntry(QLatin1String("ExpandTree"), false)); p->treeView->setChecked(config.readEntry(QLatin1String("TreeView"), false)); p->sortSymbols->setChecked(config.readEntry(QLatin1String("SortSymbols"), false)); - connect( p, SIGNAL(configPageApplyRequest(KatePluginSymbolViewerConfigPage*)), - SLOT(applyConfig(KatePluginSymbolViewerConfigPage*)) ); + connect(p, &KatePluginSymbolViewerConfigPage::configPageApplyRequest, this, &KatePluginSymbolViewer::applyConfig); return (KTextEditor::ConfigPage*)p; } void KatePluginSymbolViewer::applyConfig( KatePluginSymbolViewerConfigPage* p ) { KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("PluginSymbolViewer")); config.writeEntry(QLatin1String("ViewTypes"), p->viewReturns->isChecked()); config.writeEntry(QLatin1String("ExpandTree"), p->expandTree->isChecked()); config.writeEntry(QLatin1String("TreeView"), p->treeView->isChecked()); config.writeEntry(QLatin1String("SortSymbols"), p->sortSymbols->isChecked()); typesOn = p->viewReturns->isChecked(); expandedOn = p->expandTree->isChecked(); treeOn = p->treeView->isChecked(); sortOn = p->sortSymbols->isChecked(); } // BEGIN KatePluginSymbolViewerConfigPage KatePluginSymbolViewerConfigPage::KatePluginSymbolViewerConfigPage( QObject* /*parent*/ /*= 0L*/, QWidget *parentWidget /*= 0L*/) : KTextEditor::ConfigPage( parentWidget ) { QVBoxLayout *lo = new QVBoxLayout( this ); //int spacing = KDialog::spacingHint(); //lo->setSpacing( spacing ); viewReturns = new QCheckBox(i18n("Display functions parameters")); expandTree = new QCheckBox(i18n("Automatically expand nodes in tree mode")); treeView = new QCheckBox(i18n("Always display symbols in tree mode")); sortSymbols = new QCheckBox(i18n("Always sort symbols")); QGroupBox* parserGBox = new QGroupBox( i18n("Parser Options"), this); QVBoxLayout* top = new QVBoxLayout(parserGBox); top->addWidget(viewReturns); top->addWidget(expandTree); top->addWidget(treeView); top->addWidget(sortSymbols); //QGroupBox* generalGBox = new QGroupBox( i18n("General Options"), this); //QVBoxLayout* genLay = new QVBoxLayout(generalGBox); //genLay->addWidget( ); lo->addWidget( parserGBox ); //lo->addWidget( generalGBox ); lo->addStretch( 1 ); // throw signal changed - connect(viewReturns, SIGNAL(toggled(bool)), this, SIGNAL(changed())); - connect(expandTree, SIGNAL(toggled(bool)), this, SIGNAL(changed())); - connect(treeView, SIGNAL(toggled(bool)), this, SIGNAL(changed())); - connect(sortSymbols, SIGNAL(toggled(bool)), this, SIGNAL(changed())); + connect(viewReturns, &QCheckBox::toggled, this, &KatePluginSymbolViewerConfigPage::changed); + connect(expandTree, &QCheckBox::toggled, this, &KatePluginSymbolViewerConfigPage::changed); + connect(treeView, &QCheckBox::toggled, this, &KatePluginSymbolViewerConfigPage::changed); + connect(sortSymbols, &QCheckBox::toggled, this, &KatePluginSymbolViewerConfigPage::changed); } KatePluginSymbolViewerConfigPage::~KatePluginSymbolViewerConfigPage() {} QString KatePluginSymbolViewerConfigPage::name() const { return i18n("Symbol Viewer"); } QString KatePluginSymbolViewerConfigPage::fullName() const { return i18n("Symbol Viewer Configuration Page"); } QIcon KatePluginSymbolViewerConfigPage::icon() const { return QPixmap(( const char** ) class_xpm ); } void KatePluginSymbolViewerConfigPage::apply() { emit configPageApplyRequest( this ); } // END KatePluginSymbolViewerConfigPage #include "plugin_katesymbolviewer.moc" // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/tabswitcher/tabswitcher.cpp b/addons/tabswitcher/tabswitcher.cpp index d71fc8c7a..570c0de77 100644 --- a/addons/tabswitcher/tabswitcher.cpp +++ b/addons/tabswitcher/tabswitcher.cpp @@ -1,286 +1,284 @@ /* This file is part of the KDE project Copyright (C) 2014 Dominik Haumann 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 "tabswitcher.h" #include "tabswitchertreeview.h" #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(TabSwitcherPluginFactory, "tabswitcherplugin.json", registerPlugin();) TabSwitcherPlugin::TabSwitcherPlugin(QObject *parent, const QList &): KTextEditor::Plugin(parent) { } QObject *TabSwitcherPlugin::createView(KTextEditor::MainWindow *mainWindow) { return new TabSwitcherPluginView(this, mainWindow); } TabSwitcherPluginView::TabSwitcherPluginView(TabSwitcherPlugin *plugin, KTextEditor::MainWindow *mainWindow) : QObject(mainWindow) , m_plugin(plugin) , m_mainWindow(mainWindow) { // register this view m_plugin->m_views.append(this); m_model = new QStandardItemModel(this); m_treeView = new TabSwitcherTreeView(); m_treeView->setModel(m_model); KXMLGUIClient::setComponentName(QStringLiteral("tabswitcher"), i18n("Document Switcher")); setXMLFile(QStringLiteral("ui.rc")); // note: call after m_treeView is created setupActions(); // fill the model setupModel(); // register action in menu m_mainWindow->guiFactory()->addClient(this); // popup connections - connect(m_treeView, SIGNAL(pressed(QModelIndex)), SLOT(switchToClicked(QModelIndex))); - connect(m_treeView, SIGNAL(itemActivated(QModelIndex)), SLOT(activateView(QModelIndex))); + connect(m_treeView, &TabSwitcherTreeView::pressed, this, &TabSwitcherPluginView::switchToClicked); + connect(m_treeView, &TabSwitcherTreeView::itemActivated, this, &TabSwitcherPluginView::activateView); // track existing documents - connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentCreated(KTextEditor::Document*)), - this, SLOT(registerDocument(KTextEditor::Document*))); - connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentWillBeDeleted(KTextEditor::Document*)), - this, SLOT(unregisterDocument(KTextEditor::Document*))); + connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentCreated, + this, &TabSwitcherPluginView::registerDocument); + connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentWillBeDeleted, + this, &TabSwitcherPluginView::unregisterDocument);; // track lru activation of views to raise the respective documents in the model - connect(m_mainWindow, SIGNAL(viewChanged(KTextEditor::View*)), - this, SLOT(raiseView(KTextEditor::View*))); + connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &TabSwitcherPluginView::raiseView); } TabSwitcherPluginView::~TabSwitcherPluginView() { // delete popup widget delete m_treeView; // unregister action in menu m_mainWindow->guiFactory()->removeClient(this); // unregister this view m_plugin->m_views.removeAll(this); } void TabSwitcherPluginView::setupActions() { auto aNext = actionCollection()->addAction(QStringLiteral("view_lru_document_next")); aNext->setText(i18n("Last Used Views")); aNext->setIcon(QIcon::fromTheme(QStringLiteral("go-next-view-page"))); actionCollection()->setDefaultShortcut(aNext, Qt::CTRL | Qt::Key_Tab); aNext->setWhatsThis(i18n("Opens a list to walk through the list of last used views.")); aNext->setStatusTip(i18n("Walk through the list of last used views")); - connect(aNext, SIGNAL(triggered()), SLOT(walkForward())); + connect(aNext, &QAction::triggered, this, &TabSwitcherPluginView::walkForward); auto aPrev = actionCollection()->addAction(QStringLiteral("view_lru_document_prev")); aPrev->setText(i18n("Last Used Views (Reverse)")); aPrev->setIcon(QIcon::fromTheme(QStringLiteral("go-previous-view-page"))); actionCollection()->setDefaultShortcut(aPrev, Qt::CTRL | Qt::SHIFT | Qt::Key_Tab); aPrev->setWhatsThis(i18n("Opens a list to walk through the list of last used views in reverse.")); aPrev->setStatusTip(i18n("Walk through the list of last used views")); - connect(aPrev, SIGNAL(triggered()), SLOT(walkBackward())); + connect(aPrev, &QAction::triggered, this, &TabSwitcherPluginView::walkBackward); // make sure action work when the popup has focus m_treeView->addAction(aNext); m_treeView->addAction(aPrev); } static QIcon iconForDocument(KTextEditor::Document * doc) { return QIcon::fromTheme(QMimeDatabase().mimeTypeForUrl(doc->url()).iconName()); } void TabSwitcherPluginView::setupModel() { // initial fill of model foreach (auto doc, KTextEditor::Editor::instance()->application()->documents()) { registerDocument(doc); } } void TabSwitcherPluginView::registerDocument(KTextEditor::Document * document) { // insert into hash m_documents.insert(document); // add to model auto item = new QStandardItem(iconForDocument(document), document->documentName()); item->setData(QVariant::fromValue(document)); m_model->insertRow(0, item); // track document name changes - connect(document, SIGNAL(documentNameChanged(KTextEditor::Document*)), - this, SLOT(updateDocumentName(KTextEditor::Document*))); + connect(document, &KTextEditor::Document::documentNameChanged, this, &TabSwitcherPluginView::updateDocumentName); } void TabSwitcherPluginView::unregisterDocument(KTextEditor::Document * document) { // remove from hash if (!m_documents.contains(document)) { return; } m_documents.remove(document); // remove from model const auto rowCount = m_model->rowCount(); for (int i = 0; i < rowCount; ++i) { auto doc = m_model->item(i)->data().value(); if (doc == document) { m_model->removeRow(i); // disconnect documentNameChanged() signal disconnect(document, nullptr, this, nullptr); break; } } } void TabSwitcherPluginView::updateDocumentName(KTextEditor::Document * document) { if (!m_documents.contains(document)) { return; } const auto rowCount = m_model->rowCount(); for (int i = 0; i < rowCount; ++i) { auto doc = m_model->item(i)->data().value(); if (doc == document) { m_model->item(i)->setText(document->documentName()); break; } } } void TabSwitcherPluginView::raiseView(KTextEditor::View * view) { if (!view || !m_documents.contains(view->document())) { return; } unregisterDocument(view->document()); registerDocument(view->document()); } void TabSwitcherPluginView::walk(const int from, const int to) { QModelIndex index; const int step = from < to ? 1 : -1; if (! m_treeView->isVisible()) { updateViewGeometry(); index = m_model->index(from + step, 0); if(! index.isValid()) { index = m_model->index(0, 0); } m_treeView->show(); m_treeView->setFocus(); } else { int newRow = m_treeView->selectionModel()->currentIndex().row() + step; if(newRow == to + step) { newRow = from; } index = m_model->index(newRow, 0); } m_treeView->selectionModel()->select(index, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect); m_treeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); } void TabSwitcherPluginView::walkForward() { walk(0, m_model->rowCount() - 1); } void TabSwitcherPluginView::walkBackward() { walk(m_model->rowCount() - 1, 0); } void TabSwitcherPluginView::updateViewGeometry() { QWidget * window = m_mainWindow->window(); const QSize centralSize = window->size(); // Maximum size of the view is 3/4th of the central widget (the editor area) // so the view does not overlap the mainwindow since that looks awkward. const QSize viewMaxSize( centralSize.width() * 3/4, centralSize.height() * 3/4 ); // The actual view size should be as big as the columns/rows need it, but // smaller than the max-size. This means the view will get quite high with // many open files but I think thats ok. Otherwise one can easily tweak the // max size to be only 1/2th of the central widget size const int rowHeight = m_treeView->sizeHintForRow(0); const int frameWidth = m_treeView->frameWidth(); const QSize viewSize(std::min(m_treeView->sizeHintForColumn(0) + 2 * frameWidth + m_treeView->verticalScrollBar()->width(), viewMaxSize.width()), std::min(std::max(rowHeight * m_model->rowCount() + 2 * frameWidth, rowHeight * 6 ), viewMaxSize.height())); // Position should be central over the editor area, so map to global from // parent of central widget since the view is positioned in global coords const QPoint centralWidgetPos = window->parentWidget() ? window->mapToGlobal(window->pos()) : window->pos(); const int xPos = std::max(0, centralWidgetPos.x() + (centralSize.width() - viewSize.width() ) / 2); const int yPos = std::max(0, centralWidgetPos.y() + (centralSize.height() - viewSize.height() ) / 2); m_treeView->setFixedSize(viewSize); m_treeView->move(xPos, yPos); } void TabSwitcherPluginView::switchToClicked(const QModelIndex & index) { m_treeView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); activateView(index); } void TabSwitcherPluginView::activateView(const QModelIndex & index) { Q_UNUSED(index) // guard against empty selection if (m_treeView->selectionModel()->selectedRows().isEmpty()) { return; } const int row = m_treeView->selectionModel()->selectedRows().first().row(); auto doc = m_model->item(row)->data().value(); m_mainWindow->activateView(doc); m_treeView->hide(); } // required for TabSwitcherPluginFactory vtable #include "tabswitcher.moc" diff --git a/addons/textfilter/plugin_katetextfilter.cpp b/addons/textfilter/plugin_katetextfilter.cpp index 4cde9ca31..023c9b66e 100644 --- a/addons/textfilter/plugin_katetextfilter.cpp +++ b/addons/textfilter/plugin_katetextfilter.cpp @@ -1,281 +1,278 @@ /*************************************************************************** plugin_katetextfilter.cpp - description ------------------- begin : FRE Feb 23 2001 copyright : (C) 2001 by Joseph Wenninger copyright : (C) 2009 Dominik Haumann ***************************************************************************/ /*************************************************************************** * * * 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 "plugin_katetextfilter.h" #include "ui_textfilterwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(TextFilterPluginFactory, "textfilterplugin.json", registerPlugin();) PluginKateTextFilter::PluginKateTextFilter(QObject *parent, const QList &): KTextEditor::Plugin(parent) , m_pFilterProcess(Q_NULLPTR) , copyResult(false) , mergeOutput(false) { // register command new PluginKateTextFilterCommand(this); } PluginKateTextFilter::~PluginKateTextFilter() { // cleanup the process the right way (TM) if (m_pFilterProcess) { m_pFilterProcess->kill(); m_pFilterProcess->waitForFinished(); delete m_pFilterProcess; } } QObject *PluginKateTextFilter::createView (KTextEditor::MainWindow *mainWindow) { // create a plugin view return new PluginViewKateTextFilter(this, mainWindow); } void PluginKateTextFilter::slotFilterReceivedStdout() { m_strFilterOutput += QString::fromLocal8Bit(m_pFilterProcess->readAllStandardOutput()); } void PluginKateTextFilter::slotFilterReceivedStderr () { const QString block = QString::fromLocal8Bit(m_pFilterProcess->readAllStandardError()); if (mergeOutput) m_strFilterOutput += block; else m_stderrOutput += block; } void PluginKateTextFilter::slotFilterProcessExited(int, QProcess::ExitStatus) { KTextEditor::View* kv(KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView()); if (!kv) return; // Is there any error output to display? if (!mergeOutput && !m_stderrOutput.isEmpty()) { QPointer message = new KTextEditor::Message( xi18nc( "@info" , "Result of:
$ %1\n%2
" , m_last_command , m_stderrOutput ) , KTextEditor::Message::Error ); message->setWordWrap(true); message->setAutoHide(1000); kv->document()->postMessage(message); } if (copyResult) { QApplication::clipboard()->setText(m_strFilterOutput); return; } // Do not even try to change the document if no result collected... if (m_strFilterOutput.isEmpty()) return; KTextEditor::Document::EditingTransaction transaction(kv->document()); KTextEditor::Cursor start = kv->cursorPosition(); if (kv->selection()) { start = kv->selectionRange().start(); kv->removeSelectionText(); } kv->setCursorPosition(start); // for block selection kv->insertText(m_strFilterOutput); } static void slipInFilter(KProcess & proc, KTextEditor::View & view, QString command) { QString inputText; if (view.selection()) { inputText = view.selectionText(); } proc.clearProgram (); proc.setShellCommand(command); proc.start(); QByteArray encoded = inputText.toLocal8Bit(); proc.write(encoded); proc.closeWriteChannel(); // TODO: Put up a modal dialog to defend the text from further // keystrokes while the command is out. With a cancel button... } void PluginKateTextFilter::slotEditFilter() { if (!KAuthorized::authorize(QStringLiteral("shell_access"))) { KMessageBox::sorry(nullptr,i18n( "You are not allowed to execute arbitrary external applications. If " "you want to be able to do this, contact your system administrator."), i18n("Access Restrictions")); return; } if (!KTextEditor::Editor::instance()->application()->activeMainWindow()) return; KTextEditor::View* kv(KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView()); if (!kv) return; QDialog dialog(KTextEditor::Editor::instance()->application()->activeMainWindow()->window()); Ui::TextFilterWidget ui; ui.setupUi(&dialog); ui.filterBox->setFocus(); dialog.setWindowTitle(i18n("Text Filter")); KConfigGroup config(KSharedConfig::openConfig(), "PluginTextFilter"); QStringList items = config.readEntry("Completion list", QStringList()); copyResult = config.readEntry("Copy result", false); mergeOutput = config.readEntry("Merge output", true); ui.filterBox->setMaxCount(10); ui.filterBox->setHistoryItems(items, true); ui.filterBox->setMinimumContentsLength(80); ui.copyResult->setChecked(copyResult); ui.mergeOutput->setChecked(mergeOutput); if (dialog.exec() == QDialog::Accepted) { copyResult = ui.copyResult->isChecked(); mergeOutput = ui.mergeOutput->isChecked(); const QString filter = ui.filterBox->currentText(); if (!filter.isEmpty()) { ui.filterBox->addToHistory(filter); config.writeEntry("Completion list", ui.filterBox->historyItems()); config.writeEntry("Copy result", copyResult); config.writeEntry("Merge output", mergeOutput); m_last_command = filter; runFilter(kv, filter); } } } void PluginKateTextFilter::runFilter(KTextEditor::View *kv, const QString &filter) { m_strFilterOutput.clear(); m_stderrOutput.clear(); if (!m_pFilterProcess) { m_pFilterProcess = new KProcess; - connect (m_pFilterProcess, SIGNAL(readyReadStandardOutput()), - this, SLOT(slotFilterReceivedStdout())); + connect(m_pFilterProcess, &KProcess::readyReadStandardOutput, this, &PluginKateTextFilter::slotFilterReceivedStdout); - connect (m_pFilterProcess, SIGNAL(readyReadStandardError()), - this, SLOT(slotFilterReceivedStderr())); + connect(m_pFilterProcess, &KProcess::readyReadStandardError, this, &PluginKateTextFilter::slotFilterReceivedStderr); - connect (m_pFilterProcess, SIGNAL(finished(int,QProcess::ExitStatus)), - this, SLOT(slotFilterProcessExited(int,QProcess::ExitStatus))); + connect(m_pFilterProcess, static_cast(&KProcess::finished), this, &PluginKateTextFilter::slotFilterProcessExited); } m_pFilterProcess->setOutputChannelMode( mergeOutput ? KProcess::MergedChannels : KProcess::SeparateChannels ); slipInFilter(*m_pFilterProcess, *kv, filter); } //BEGIN Kate::Command methods PluginKateTextFilterCommand::PluginKateTextFilterCommand(PluginKateTextFilter *plugin) : KTextEditor::Command(QStringList() << QStringLiteral("textfilter"), plugin) , m_plugin(plugin) { } bool PluginKateTextFilterCommand::exec (KTextEditor::View *view, const QString &cmd, QString &msg, const KTextEditor::Range &) { QString filter = cmd.section(QLatin1Char(' '), 1).trimmed(); if (filter.isEmpty()) { msg = i18n("Usage: textfilter COMMAND"); return false; } m_plugin->runFilter(view, filter); return true; } bool PluginKateTextFilterCommand::help (KTextEditor::View *, const QString &, QString &msg) { msg = i18n("

Usage: textfilter COMMAND

" "

Replace the selection with the output of the specified shell command.

"); return true; } //END PluginViewKateTextFilter::PluginViewKateTextFilter(PluginKateTextFilter *plugin, KTextEditor::MainWindow *mainwindow) : QObject(mainwindow) , m_mainWindow(mainwindow) { // setup right xml gui data KXMLGUIClient::setComponentName(QStringLiteral("textfilter"), i18n("Text Filter")); setXMLFile(QStringLiteral("ui.rc")); // create our one and only action QAction* a = actionCollection()->addAction(QStringLiteral("edit_filter")); a->setText(i18n("Filter Te&xt...")); actionCollection()->setDefaultShortcut(a, Qt::CTRL + Qt::Key_Backslash); - connect(a, SIGNAL(triggered(bool)), plugin, SLOT(slotEditFilter())); + connect(a, &QAction::triggered, plugin, &PluginKateTextFilter::slotEditFilter); // register us at the UI mainwindow->guiFactory()->addClient(this); } PluginViewKateTextFilter::~PluginViewKateTextFilter() { // remove us from the UI again m_mainWindow->guiFactory()->removeClient (this); } // required for TextFilterPluginFactory vtable #include "plugin_katetextfilter.moc" diff --git a/addons/xmlcheck/plugin_katexmlcheck.cpp b/addons/xmlcheck/plugin_katexmlcheck.cpp index b1669f332..a365faf38 100644 --- a/addons/xmlcheck/plugin_katexmlcheck.cpp +++ b/addons/xmlcheck/plugin_katexmlcheck.cpp @@ -1,403 +1,403 @@ /*************************************************************************** plugin_katexmlcheck.cpp - checks XML files using xmllint ------------------- begin : 2002-07-06 copyright : (C) 2002 by Daniel Naber email : daniel.naber@t-online.de ***************************************************************************/ /*************************************************************************** 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. ***************************************************************************/ /* -fixme: show dock if "Validate XML" is selected (doesn't currently work when Kate was just started and the dockwidget isn't yet visible) -fixme(?): doesn't correctly disappear when deactivated in config */ //TODO: // Cleanup unneeded headers // Find resourses and translate i18n messages // all translations were deleted in https://websvn.kde.org/?limit_changes=0&view=revision&revision=1433517 // What to do with catalogs? What is it for? // Implement hot key shoutcut to do xml validation // Remove copyright above due to author orphoned this plugin? // Possibility to check only well-formdness without validation // Hide output in dock when switching to another tab // Make ability to validate agains xml schema and then edit docbook // Should del space in [km] strang in katexmlcheck.desktop? // Which variant should I choose? QUrl.adjusted(rm filename).path() or QUrl.toString(rm filename|rm schema) // What about replace xmllint xmlstarlet or something? // Maybe use QXmlReader to take dtds and xsds? #include "plugin_katexmlcheck.h" #include //#include "plugin_katexmlcheck.moc" this goes to end #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 K_PLUGIN_FACTORY_WITH_JSON(PluginKateXMLCheckFactory, "katexmlcheck.json", registerPlugin();) PluginKateXMLCheck::PluginKateXMLCheck( QObject * const parent, const QVariantList& ) : KTextEditor::Plugin(parent) { qDebug() << "PluginXmlCheck()"; } PluginKateXMLCheck::~PluginKateXMLCheck() { } QObject *PluginKateXMLCheck::createView(KTextEditor::MainWindow *mainWindow) { return new PluginKateXMLCheckView(this, mainWindow); } //--------------------------------- PluginKateXMLCheckView::PluginKateXMLCheckView( KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainwin) : QObject(mainwin) , KXMLGUIClient() , m_mainWindow(mainwin) { KXMLGUIClient::setComponentName(QLatin1String("katexmlcheck"), i18n ("Kate XML check")); // where i18n resources? setXMLFile(QLatin1String("ui.rc")); dock = m_mainWindow->createToolView(plugin, "kate_plugin_xmlcheck_ouputview", KTextEditor::MainWindow::Bottom, QIcon::fromTheme("misc"), i18n("XML Checker Output")); listview = new QTreeWidget( dock ); m_tmp_file=nullptr; QAction *a = actionCollection()->addAction("xml_check"); a->setText(i18n("Validate XML")); - connect(a, SIGNAL(triggered()), this, SLOT(slotValidate())); + connect(a, &QAction::triggered, this, &PluginKateXMLCheckView::slotValidate); // TODO?: //(void) new KAction ( i18n("Indent XML"), KShortcut(), this, // SLOT(slotIndent()), actionCollection(), "xml_indent" ); listview->setFocusPolicy(Qt::NoFocus); QStringList headers; headers << i18n("#"); headers << i18n("Line"); headers << i18n("Column"); headers << i18n("Message"); listview->setHeaderLabels(headers); listview->setRootIsDecorated(false); - connect(listview, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SLOT(slotClicked(QTreeWidgetItem*,int))); + connect(listview, &QTreeWidget::itemClicked, this, &PluginKateXMLCheckView::slotClicked); QHeaderView *header = listview->header(); header->setSectionResizeMode(0, QHeaderView::ResizeToContents); header->setSectionResizeMode(1, QHeaderView::ResizeToContents); header->setSectionResizeMode(2, QHeaderView::ResizeToContents); /* TODO?: invalidate the listview when document has changed Kate::View *kv = application()->activeMainWindow()->activeView(); if( ! kv ) { qDebug() << "Warning: no Kate::View"; return; } connect(kv, SIGNAL(modifiedChanged()), this, SLOT(slotUpdate())); */ - connect(&m_proc, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotProcExited(int,QProcess::ExitStatus))); + connect(&m_proc, static_cast(&QProcess::finished), this, &PluginKateXMLCheckView::slotProcExited); // we currently only want errors: m_proc.setProcessChannelMode(QProcess::SeparateChannels); // m_proc.setProcessChannelMode(QProcess::ForwardedChannels); // For Debugging. Do not use this. mainwin->guiFactory()->addClient(this); } PluginKateXMLCheckView::~PluginKateXMLCheckView() { m_mainWindow->guiFactory()->removeClient( this ); delete m_tmp_file; delete dock; } void PluginKateXMLCheckView::slotProcExited(int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitCode); // FIXME: doesn't work correct the first time: //if( m_dockwidget->isDockBackPossible() ) { // m_dockwidget->dockBack(); // } if (exitStatus != QProcess::NormalExit) { QTreeWidgetItem *item = new QTreeWidgetItem(); item->setText(0, QString("1").rightJustified(4,' ')); item->setText(3, "Validate process crashed."); listview->addTopLevelItem(item); return; } qDebug() << "slotProcExited()"; QApplication::restoreOverrideCursor(); delete m_tmp_file; QString proc_stderr = QString::fromLocal8Bit(m_proc.readAllStandardError()); m_tmp_file=nullptr; listview->clear(); uint list_count = 0; uint err_count = 0; if( ! m_validating ) { // no i18n here, so we don't get an ugly English<->Non-english mixup: QString msg; if( m_dtdname.isEmpty() ) { msg = "No DOCTYPE found, will only check well-formedness."; } else { msg = '\'' + m_dtdname + "' not found, will only check well-formedness."; } QTreeWidgetItem *item = new QTreeWidgetItem(); item->setText(0, QString("1").rightJustified(4,' ')); item->setText(3, msg); listview->addTopLevelItem(item); list_count++; } if( ! proc_stderr.isEmpty() ) { QStringList lines = proc_stderr.split("\n", QString::SkipEmptyParts); QString linenumber, msg; int line_count = 0; for(QStringList::Iterator it = lines.begin(); it != lines.end(); ++it) { QString line = *it; line_count++; int semicolon_1 = line.indexOf(':'); int semicolon_2 = line.indexOf(':', semicolon_1+1); int semicolon_3 = line.indexOf(':', semicolon_2+2); int caret_pos = line.indexOf('^'); if( semicolon_1 != -1 && semicolon_2 != -1 && semicolon_3 != -1 ) { linenumber = line.mid(semicolon_1+1, semicolon_2-semicolon_1-1).trimmed(); linenumber = linenumber.rightJustified(6, ' '); // for sorting numbers msg = line.mid(semicolon_3+1, line.length()-semicolon_3-1).trimmed(); } else if( caret_pos != -1 || line_count == lines.size() ) { // TODO: this fails if "^" occurs in the real text?! if( line_count == lines.size() && caret_pos == -1 ) { msg = msg+'\n'+line; } QString col = QString::number(caret_pos); if( col == "-1" ) { col = ""; } err_count++; list_count++; QTreeWidgetItem *item = new QTreeWidgetItem(); item->setText(0, QString::number(list_count).rightJustified(4,' ')); item->setText(1, linenumber); item->setTextAlignment(1, (item->textAlignment(1) & ~Qt::AlignHorizontal_Mask) | Qt::AlignRight); item->setText(2, col); item->setTextAlignment(2, (item->textAlignment(2) & ~Qt::AlignHorizontal_Mask) | Qt::AlignRight); item->setText(3, msg); listview->addTopLevelItem(item); } else { msg = msg+'\n'+line; } } } if( err_count == 0 ) { QString msg; if( m_validating ) { msg = "No errors found, document is valid."; // no i18n here } else { msg = "No errors found, document is well-formed."; // no i18n here } QTreeWidgetItem *item = new QTreeWidgetItem(); item->setText(0, QString::number(list_count+1).rightJustified(4,' ')); item->setText(3, msg); listview->addTopLevelItem(item); } } void PluginKateXMLCheckView::slotClicked(QTreeWidgetItem *item, int column) { Q_UNUSED(column); qDebug() << "slotClicked"; if( item ) { bool ok = true; uint line = item->text(1).toUInt(&ok); bool ok2 = true; uint column = item->text(2).toUInt(&ok); if( ok && ok2 ) { KTextEditor::View *kv = m_mainWindow->activeView(); if( ! kv ) return; kv->setCursorPosition(KTextEditor::Cursor (line-1, column)); } } } void PluginKateXMLCheckView::slotUpdate() { qDebug() << "slotUpdate() (not implemented yet)"; } bool PluginKateXMLCheckView::slotValidate() { qDebug() << "slotValidate()"; m_mainWindow->showToolView (dock); m_validating = false; m_dtdname = ""; KTextEditor::View *kv = m_mainWindow->activeView(); if( ! kv ) return false; delete m_tmp_file; m_tmp_file = new QTemporaryFile(); if( !m_tmp_file->open() ) { qDebug() << "Error (slotValidate()): could not create '" << m_tmp_file->fileName() << "': " << m_tmp_file->errorString(); KMessageBox::error(nullptr, i18n("Error: Could not create " "temporary file '%1'.", m_tmp_file->fileName())); delete m_tmp_file; m_tmp_file=nullptr; return false; } QTextStream s ( m_tmp_file ); s << kv->document()->text(); s.flush(); QString exe = QStandardPaths::findExecutable("xmllint"); if( exe.isEmpty() ) { exe = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, "xmllint"); } //qDebug() << "exe=" <findResource("data", "ksgmltools2/customization/catalog.xml"); // qDebug() << "catalogs: " << catalogs; // setenv("XML_CATALOG_FILES", QFile::encodeName( catalogs ).data(), 1); // } //qDebug() << "**catalogs: " << getenv("XML_CATALOG_FILES"); QStringList args; args << "--noout"; // tell xmllint the working path of the document's file, if possible. // otherweise it will not find relative DTDs // I should give path to location of file, but remove filename // I can make QUrl.adjusted(rm filename).path() // or QUrl.toString(rm filename|rm schema) // Result is the same. Which variant should I choose? //QString path = kv->document()->url().adjusted(QUrl::RemoveFilename).path(); // xmllint uses space- or colon-separated path option, so spaces should be encoded to %20. It is done with EncodeSpaces. // Now what about colons in file names or paths? // This way xmllint works normally: // xmllint --noout --path "/home/user/my/with:colon/" --valid "/home/user/my/with:colon/demo-1.xml" // but because this plugin makes temp file path to file is another and this way xmllint refuses to find dtd: // xmllint --noout --path "/home/user/my/with:colon/" --valid "/tmp/kate.X23725" // As workaround we can encode ':' with %3A QString path = kv->document()->url().toString(QUrl::RemoveFilename|QUrl::PreferLocalFile|QUrl::EncodeSpaces); path.replace(":","%3A"); // because of such inconvinience with xmllint and pathes, maybe switch to xmlstarlet? qDebug() << "path=" << path; if (!path.isEmpty()) { args << "--path" << path; } // heuristic: assume that the doctype is in the first 10,000 bytes: QString text_start = kv->document()->text().left(10000); // remove comments before looking for doctype (as a doctype might be commented out // and needs to be ignored then): QRegExp re(""); re.setMinimal(true); text_start.remove(re); QRegExp re_doctype("fileName(); qDebug() << "m_tmp_file->fileName()=" << m_tmp_file->fileName(); m_proc.start(exe,args); qDebug() << "m_proc.program():" << m_proc.program(); // I want to see parmeters qDebug() << "args=" << args; qDebug() << "exit code:"<< m_proc.exitCode(); if( ! m_proc.waitForStarted(-1) ) { KMessageBox::error(nullptr, i18n("Error: Failed to execute xmllint. Please make " "sure that xmllint is installed. It is part of libxml2.")); return false; } QApplication::setOverrideCursor(Qt::WaitCursor); return true; } #include "plugin_katexmlcheck.moc" diff --git a/addons/xmltools/plugin_katexmltools.cpp b/addons/xmltools/plugin_katexmltools.cpp index ede35e265..62be3b19d 100644 --- a/addons/xmltools/plugin_katexmltools.cpp +++ b/addons/xmltools/plugin_katexmltools.cpp @@ -1,1116 +1,1115 @@ /*************************************************************************** pluginKatexmltools.cpp List elements, attributes, attribute values and entities allowed by DTD. Needs a DTD in XML format ( as produced by dtdparse ) for most features. copyright : ( C ) 2001-2002 by Daniel Naber email : daniel.naber@t-online.de Copyright (C) 2005 by Anders Lund KDE SC 4 version (C) 2010 Tomas Trnka ***************************************************************************/ /*************************************************************************** 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. ***************************************************************************/ /* README: The basic idea is this: certain keyEvents(), namely [<&" ], trigger a completion box. This is intended as a help for editing. There are some cases where the XML spec is not followed, e.g. one can add the same attribute twice to an element. Also see the user documentation. If backspace is pressed after a completion popup was closed, the popup will re-open. This way typos can be corrected and the popup will reappear, which is quite comfortable. FIXME: -( docbook ) : insert space between the quotes, press "de" and return -> only "d" inserted -The "Insert Element" dialog isn't case insensitive, but it should be -See the "fixme"'s in the code TODO: -check for mem leaks -add "Go to opening/parent tag"? -check doctype to get top-level element -can undo behaviour be improved?, e.g. the plugins internal deletions of text don't have to be an extra step -don't offer entities if inside tag but outside attribute value -Support for more than one namespace at the same time ( e.g. XSLT + XSL-FO )? =>This could also be handled in the XSLT DTD fragment, as described in the XSLT 1.0 spec, but then at it will only show you HTML elements! =>So better "Assign meta DTD" and "Add meta DTD", the latter will expand the current meta DTD -Option to insert empty element in form -Show expanded entities with QChar::QChar( int rc ) + unicode font -Don't ignore entities defined in the document's prologue -Only offer 'valid' elements, i.e. don't take the elements as a set but check if the DTD is matched ( order, number of occurrences, ... ) -Maybe only read the meta DTD file once, then store the resulting QMap on disk ( using QDataStream )? We'll then have to compare timeOf_cacheFile <-> timeOf_metaDtd. -Try to use libxml */ #include "plugin_katexmltools.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 K_PLUGIN_FACTORY_WITH_JSON(PluginKateXMLToolsFactory, "katexmltools.json", registerPlugin();) PluginKateXMLTools::PluginKateXMLTools(QObject *const parent, const QVariantList &) : KTextEditor::Plugin(parent) { } PluginKateXMLTools::~PluginKateXMLTools() { } QObject *PluginKateXMLTools::createView(KTextEditor::MainWindow *mainWindow) { return new PluginKateXMLToolsView(mainWindow); } PluginKateXMLToolsView::PluginKateXMLToolsView(KTextEditor::MainWindow *mainWin) : QObject(mainWin) , KXMLGUIClient() , m_mainWindow(mainWin) , m_model(this) { //qDebug() << "PluginKateXMLTools constructor called"; KXMLGUIClient::setComponentName(QLatin1String("katexmltools"), i18n("Kate XML Tools")); setXMLFile(QLatin1String("ui.rc")); QAction *actionInsert = new QAction(i18n("&Insert Element..."), this); - connect(actionInsert, SIGNAL(triggered()), &m_model, SLOT(slotInsertElement())); + connect(actionInsert, &QAction::triggered, &m_model, &PluginKateXMLToolsCompletionModel::slotInsertElement); actionCollection()->addAction("xml_tool_insert_element", actionInsert); actionCollection()->setDefaultShortcut(actionInsert, Qt::CTRL + Qt::Key_Return); QAction *actionClose = new QAction(i18n("&Close Element"), this); - connect(actionClose, SIGNAL(triggered()), &m_model, SLOT(slotCloseElement())); + connect(actionClose, &QAction::triggered, &m_model, &PluginKateXMLToolsCompletionModel::slotCloseElement); actionCollection()->addAction("xml_tool_close_element", actionClose); actionCollection()->setDefaultShortcut(actionClose, Qt::CTRL + Qt::Key_Less); QAction *actionAssignDTD = new QAction(i18n("Assign Meta &DTD..."), this); - connect(actionAssignDTD, SIGNAL(triggered()), &m_model, SLOT(getDTD())); + connect(actionAssignDTD, &QAction::triggered, &m_model, &PluginKateXMLToolsCompletionModel::getDTD); actionCollection()->addAction("xml_tool_assign", actionAssignDTD); mainWin->guiFactory()->addClient(this); - connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentDeleted(KTextEditor::Document *)), - &m_model, SLOT(slotDocumentDeleted(KTextEditor::Document *))); + connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentDeleted, + &m_model, &PluginKateXMLToolsCompletionModel::slotDocumentDeleted); } PluginKateXMLToolsView::~PluginKateXMLToolsView() { m_mainWindow->guiFactory()->removeClient(this); //qDebug() << "xml tools descructor 1..."; //TODO: unregister the model } PluginKateXMLToolsCompletionModel::PluginKateXMLToolsCompletionModel(QObject *const parent) : CodeCompletionModel(parent) , m_viewToAssignTo(nullptr) , m_mode(none) , m_correctPos(0) { } PluginKateXMLToolsCompletionModel::~PluginKateXMLToolsCompletionModel() { qDeleteAll(m_dtds); m_dtds.clear(); } void PluginKateXMLToolsCompletionModel::slotDocumentDeleted(KTextEditor::Document *doc) { // Remove the document from m_DTDs, and also delete the PseudoDTD // if it becomes unused. if (m_docDtds.contains(doc)) { qDebug() << "XMLTools:slotDocumentDeleted: documents: " << m_docDtds.count() << ", DTDs: " << m_dtds.count(); PseudoDTD *dtd = m_docDtds.take(doc); if (m_docDtds.key(dtd)) { return; } QHash::iterator it; for (it = m_dtds.begin() ; it != m_dtds.end() ; ++it) { if (it.value() == dtd) { m_dtds.erase(it); delete dtd; return; } } } } void PluginKateXMLToolsCompletionModel::completionInvoked(KTextEditor::View *kv, const KTextEditor::Range &range, const InvocationType invocationType) { Q_UNUSED(range) Q_UNUSED(invocationType) qDebug() << "xml tools completionInvoked"; KTextEditor::Document *doc = kv->document(); if (! m_docDtds[ doc ]) // no meta DTD assigned yet { return; } // debug to test speed: //QTime t; t.start(); beginResetModel(); m_allowed.clear(); // get char on the left of the cursor: KTextEditor::Cursor curpos = kv->cursorPosition(); uint line = curpos.line(), col = curpos.column(); QString lineStr = kv->document()->line(line); QString leftCh = lineStr.mid(col - 1, 1); QString secondLeftCh = lineStr.mid(col - 2, 1); if (leftCh == "&") { qDebug() << "Getting entities"; m_allowed = m_docDtds[doc]->entities(QString()); m_mode = entities; } else if (leftCh == "<") { qDebug() << "*outside tag -> get elements"; QString parentElement = getParentElement(*kv, 1); qDebug() << "parent: " << parentElement; m_allowed = m_docDtds[doc]->allowedElements(parentElement); m_mode = elements; } else if (leftCh == "/" && secondLeftCh == "<") { qDebug() << "*close parent element"; QString parentElement = getParentElement(*kv, 2); if (! parentElement.isEmpty()) { m_mode = closingtag; m_allowed = QStringList(parentElement); } } else if (leftCh == " " || (isQuote(leftCh) && secondLeftCh == "=")) { // TODO: check secondLeftChar, too?! then you don't need to trigger // with space and we yet save CPU power QString currentElement = insideTag(*kv); QString currentAttribute; if (! currentElement.isEmpty()) { currentAttribute = insideAttribute(*kv); } qDebug() << "Tag: " << currentElement; qDebug() << "Attr: " << currentAttribute; if (! currentElement.isEmpty() && ! currentAttribute.isEmpty()) { qDebug() << "*inside attribute -> get attribute values"; m_allowed = m_docDtds[doc]->attributeValues(currentElement, currentAttribute); if (m_allowed.count() == 1 && (m_allowed[0] == "CDATA" || m_allowed[0] == "ID" || m_allowed[0] == "IDREF" || m_allowed[0] == "IDREFS" || m_allowed[0] == "ENTITY" || m_allowed[0] == "ENTITIES" || m_allowed[0] == "NMTOKEN" || m_allowed[0] == "NMTOKENS" || m_allowed[0] == "NAME")) { // these must not be taken literally, e.g. don't insert the string "CDATA" m_allowed.clear(); } else { m_mode = attributevalues; } } else if (! currentElement.isEmpty()) { qDebug() << "*inside tag -> get attributes"; m_allowed = m_docDtds[doc]->allowedAttributes(currentElement); m_mode = attributes; } } //qDebug() << "time elapsed (ms): " << t.elapsed(); qDebug() << "Allowed strings: " << m_allowed.count(); if (m_allowed.count() >= 1 && m_allowed[0] != "__EMPTY") { m_allowed = sortQStringList(m_allowed); } setRowCount(m_allowed.count()); endResetModel(); } int PluginKateXMLToolsCompletionModel::columnCount(const QModelIndex &) const { return 1; } int PluginKateXMLToolsCompletionModel::rowCount(const QModelIndex &parent) const { if (!m_allowed.isEmpty()) { // Is there smth to complete? if (!parent.isValid()) { // Return the only one group node for root return 1; } if (parent.internalId() == groupNode) { // Return available rows count for group level node return m_allowed.size(); } } return 0; } QModelIndex PluginKateXMLToolsCompletionModel::parent(const QModelIndex &index) const { if (!index.isValid()) { // Is root/invalid index? return QModelIndex(); // Nothing to return... } if (index.internalId() == groupNode) { // Return a root node for group return QModelIndex(); } // Otherwise, this is a leaf level, so return the only group as a parent return createIndex(0, 0, groupNode); } QModelIndex PluginKateXMLToolsCompletionModel::index(const int row, const int column, const QModelIndex &parent) const { if (!parent.isValid()) { // At 'top' level only 'header' present, so nothing else than row 0 can be here... return row == 0 ? createIndex(row, column, groupNode) : QModelIndex(); } if (parent.internalId() == groupNode) { // Is this a group node? if (0 <= row && row < m_allowed.size()) { // Make sure to return only valid indices return createIndex(row, column, (void *)nullptr); // Just return a leaf-level index } } // Leaf node has no children... nothing to return return QModelIndex(); } QVariant PluginKateXMLToolsCompletionModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { // Nothing to do w/ invalid index return QVariant(); } if (index.internalId() == groupNode) { // Return group level node data switch (role) { case KTextEditor::CodeCompletionModel::GroupRole: return QVariant(Qt::DisplayRole); case Qt::DisplayRole: return currentModeToString(); default: break; } return QVariant(); // Nothing to return for other roles } switch (role) { case Qt::DisplayRole: switch (index.column()) { case KTextEditor::CodeCompletionModel::Name: return m_allowed.at(index.row()); default: break; } default: break; } return QVariant(); } bool PluginKateXMLToolsCompletionModel::shouldStartCompletion(KTextEditor::View *view, const QString &insertedText, bool userInsertion, const KTextEditor::Cursor &position) { Q_UNUSED(view) Q_UNUSED(userInsertion) Q_UNUSED(position) const QString triggerChars = "&application()->activeMainWindow()) { return; } KTextEditor::View *kv = KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView(); if (! kv) { qDebug() << "Warning: no KTextEditor::View"; return; } // ### replace this with something more sane // Start where the supplied XML-DTDs are fed by default unless // user changed directory last time: QString defaultDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "katexmltools") + "/katexmltools/"; if (m_urlString.isNull()) { m_urlString = defaultDir; } // Guess the meta DTD by looking at the doctype's public identifier. // XML allows comments etc. before the doctype, so look further than // just the first line. // Example syntax: // uint checkMaxLines = 200; QString documentStart = kv->document()->text(KTextEditor::Range(0, 0, checkMaxLines + 1, 0)); QRegExp re(" */ filename = "xslt-1.0.dtd.xml"; doctype = "XSLT 1.0"; } else { qDebug() << "No doctype found"; } QUrl url; if (filename.isEmpty()) { // no meta dtd found for this file url = QFileDialog::getOpenFileUrl(KTextEditor::Editor::instance()->application()->activeMainWindow()->window(), i18n("Assign Meta DTD in XML Format"), QUrl::fromLocalFile(m_urlString), "*.xml"); } else { url.setUrl(defaultDir + filename); KMessageBox::information(nullptr, i18n("The current file has been identified " "as a document of type \"%1\". The meta DTD for this document type " "will now be loaded.", doctype), i18n("Loading XML Meta DTD"), QString::fromLatin1("DTDAssigned")); } if (url.isEmpty()) { return; } m_urlString = url.url(); // remember directory for next time if (m_dtds[ m_urlString ]) { assignDTD(m_dtds[ m_urlString ], kv); } else { m_dtdString.clear(); m_viewToAssignTo = kv; QGuiApplication::setOverrideCursor(Qt::WaitCursor); KIO::Job *job = KIO::get(url); - connect(job, SIGNAL(result(KJob *)), this, SLOT(slotFinished(KJob *))); + connect(job, &KIO::Job::result, this, &PluginKateXMLToolsCompletionModel::slotFinished); connect(job, SIGNAL(data(KIO::Job *, QByteArray)), - this, SLOT(slotData(KIO::Job *, QByteArray))); + this, SLOT(slotData(KIO::Job *, QByteArray))); } qDebug() << "XMLTools::getDTD: Documents: " << m_docDtds.count() << ", DTDs: " << m_dtds.count(); } void PluginKateXMLToolsCompletionModel::slotFinished(KJob *job) { if (job->error()) { //qDebug() << "XML Plugin error: DTD in XML format (" << filename << " ) could not be loaded"; static_cast(job)->uiDelegate()->showErrorMessage(); } else if (static_cast(job)->isErrorPage()) { // catch failed loading loading via http: KMessageBox::error(nullptr, i18n("The file '%1' could not be opened. " "The server returned an error.", m_urlString), i18n("XML Plugin Error")); } else { PseudoDTD *dtd = new PseudoDTD(); dtd->analyzeDTD(m_urlString, m_dtdString); m_dtds.insert(m_urlString, dtd); assignDTD(dtd, m_viewToAssignTo); // clean up a bit m_viewToAssignTo = nullptr; m_dtdString.clear(); } QGuiApplication::restoreOverrideCursor(); } void PluginKateXMLToolsCompletionModel::slotData(KIO::Job *, const QByteArray &data) { m_dtdString += QString(data); } void PluginKateXMLToolsCompletionModel::assignDTD(PseudoDTD *dtd, KTextEditor::View *view) { m_docDtds.insert(view->document(), dtd); //TODO:perhaps foreach views()? KTextEditor::CodeCompletionInterface *cci = qobject_cast(view); if (cci) { cci->registerCompletionModel(this); cci->setAutomaticInvocationEnabled(true); qDebug() << "PluginKateXMLToolsView: completion model registered"; } else { qWarning() << "PluginKateXMLToolsView: completion interface unavailable"; } } /** * Offer a line edit with completion for possible elements at cursor position and insert the * tag one chosen/entered by the user, plus its closing tag. If there's a text selection, * add the markup around it. */ void PluginKateXMLToolsCompletionModel::slotInsertElement() { if (!KTextEditor::Editor::instance()->application()->activeMainWindow()) { return; } KTextEditor::View *kv = KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView(); if (! kv) { qDebug() << "Warning: no KTextEditor::View"; return; } KTextEditor::Document *doc = kv->document(); PseudoDTD *dtd = m_docDtds[doc]; QString parentElement = getParentElement(*kv, 0); QStringList allowed; if (dtd) { allowed = dtd->allowedElements(parentElement); } QString text; InsertElement dialog(allowed, kv); if (dialog.exec() == QDialog::Accepted) { text = dialog.text(); } if (!text.isEmpty()) { QStringList list = text.split(QChar(' ')); QString pre; QString post; // anders: use if the tag is required to be empty. // In that case maybe we should not remove the selection? or overwrite it? int adjust = 0; // how much to move cursor. // if we know that we have attributes, it goes // just after the tag name, otherwise between tags. if (dtd && dtd->allowedAttributes(list[0]).count()) { adjust++; // the ">" } if (dtd && dtd->allowedElements(list[0]).contains("__EMPTY")) { pre = '<' + text + "/>"; if (adjust) { adjust++; // for the "/" } } else { pre = '<' + text + '>'; post = "'; } QString marked; if (! post.isEmpty()) { marked = kv->selectionText(); } KTextEditor::Document::EditingTransaction transaction(doc); if (! marked.isEmpty()) { kv->removeSelectionText(); } // with the old selection now removed, curPos points to the start of pre KTextEditor::Cursor curPos = kv->cursorPosition(); curPos.setColumn(curPos.column() + pre.length() - adjust); kv->insertText(pre + marked + post); kv->setCursorPosition(curPos); } } /** * Insert a closing tag for the nearest not-closed parent element. */ void PluginKateXMLToolsCompletionModel::slotCloseElement() { if (!KTextEditor::Editor::instance()->application()->activeMainWindow()) { return; } KTextEditor::View *kv = KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView(); if (! kv) { qDebug() << "Warning: no KTextEditor::View"; return; } QString parentElement = getParentElement(*kv, 0); //qDebug() << "parentElement: '" << parentElement << "'"; QString closeTag = "'; if (! parentElement.isEmpty()) { kv->insertText(closeTag); } } // modify the completion string before it gets inserted void PluginKateXMLToolsCompletionModel::executeCompletionItem(KTextEditor::View *view, const KTextEditor::Range &word, const QModelIndex &index) const { KTextEditor::Range toReplace = word; KTextEditor::Document *document = view->document(); QString text = data(index.sibling(index.row(), Name), Qt::DisplayRole).toString(); qDebug() << "executeCompletionItem text: " << text; int line, col; view->cursorPosition().position(line, col); QString lineStr = document->line(line); QString leftCh = lineStr.mid(col - 1, 1); QString rightCh = lineStr.mid(col, 1); int posCorrection = 0; // where to move the cursor after completion ( >0 = move right ) if (m_mode == entities) { text = text + ';'; } else if (m_mode == attributes) { text = text + "=\"\""; posCorrection = -1; if (!rightCh.isEmpty() && rightCh != ">" && rightCh != "/" && rightCh != " ") { // TODO: other whitespaces // add space in front of the next attribute text = text + ' '; posCorrection--; } } else if (m_mode == attributevalues) { // TODO: support more than one line uint startAttValue = 0; uint endAttValue = 0; // find left quote: for (startAttValue = col; startAttValue > 0; startAttValue--) { QString ch = lineStr.mid(startAttValue - 1, 1); if (isQuote(ch)) { break; } } // find right quote: for (endAttValue = col; endAttValue <= (uint) lineStr.length(); endAttValue++) { QString ch = lineStr.mid(endAttValue - 1, 1); if (isQuote(ch)) { break; } } // replace the current contents of the attribute if (startAttValue < endAttValue) { toReplace = KTextEditor::Range(line, startAttValue, line, endAttValue - 1); } } else if (m_mode == elements) { // anders: if the tag is marked EMPTY, insert in form QString str; bool isEmptyTag = m_docDtds[document]->allowedElements(text).contains("__EMPTY"); if (isEmptyTag) { str = text + "/>"; } else { str = text + ">'; } // Place the cursor where it is most likely wanted: // always inside the tag if the tag is empty AND the DTD indicates that there are attribs) // outside for open tags, UNLESS there are mandatory attributes if (m_docDtds[document]->requiredAttributes(text).count() || (isEmptyTag && m_docDtds[document]->allowedAttributes(text).count())) { posCorrection = text.length() - str.length(); } else if (! isEmptyTag) { posCorrection = text.length() - str.length() + 1; } text = str; } else if (m_mode == closingtag) { text += '>'; } document->replaceText(toReplace, text); // move the cursor to desired position KTextEditor::Cursor curPos = view->cursorPosition(); curPos.setColumn(curPos.column() + posCorrection); view->setCursorPosition(curPos); } // ======================================================================== // Pseudo-XML stuff: /** * Check if cursor is inside a tag, that is * if "<" occurs before ">" occurs ( on the left side of the cursor ). * Return the tag name, return "" if we cursor is outside a tag. */ QString PluginKateXMLToolsCompletionModel::insideTag(KTextEditor::View &kv) { int line, col; kv.cursorPosition().position(line, col); int y = line; // another variable because uint <-> int do { QString lineStr = kv.document()->line(y); for (uint x = col; x > 0; x--) { QString ch = lineStr.mid(x - 1, 1); if (ch == ">") { // cursor is outside tag return QString(); } if (ch == "<") { QString tag; // look for white space on the right to get the tag name for (int z = x; z <= lineStr.length() ; ++z) { ch = lineStr.mid(z - 1, 1); if (ch.at(0).isSpace() || ch == "/" || ch == ">") { return tag.right(tag.length() - 1); } if (z == lineStr.length()) { tag += ch; return tag.right(tag.length() - 1); } tag += ch; } } } y--; col = kv.document()->line(y).length(); } while (y >= 0); return QString(); } /** * Check if cursor is inside an attribute value, that is * if '="' is on the left, and if it's nearer than "<" or ">". * * @Return the attribute name or "" if we're outside an attribute * value. * * Note: only call when insideTag() == true. * TODO: allow whitespace around "=" */ QString PluginKateXMLToolsCompletionModel::insideAttribute(KTextEditor::View &kv) { int line, col; kv.cursorPosition().position(line, col); int y = line; // another variable because uint <-> int uint x = 0; QString lineStr; QString ch; do { lineStr = kv.document()->line(y); for (x = col; x > 0; x--) { ch = lineStr.mid(x - 1, 1); QString chLeft = lineStr.mid(x - 2, 1); // TODO: allow whitespace if (isQuote(ch) && chLeft == "=") { break; } else if (isQuote(ch) && chLeft != "=") { return QString(); } else if (ch == "<" || ch == ">") { return QString(); } } y--; col = kv.document()->line(y).length(); } while (!isQuote(ch)); // look for next white space on the left to get the tag name QString attr; for (int z = x; z >= 0; z--) { ch = lineStr.mid(z - 1, 1); if (ch.at(0).isSpace()) { break; } if (z == 0) { // start of line == whitespace attr += ch; break; } attr = ch + attr; } return attr.left(attr.length() - 2); } /** * Find the parent element for the current cursor position. That is, * go left and find the first opening element that's not closed yet, * ignoring empty elements. * Examples: If cursor is at "X", the correct parent element is "p": *

foo bar X *

foo bar X *

foo bar X */ QString PluginKateXMLToolsCompletionModel::getParentElement(KTextEditor::View &kv, int skipCharacters) { enum { parsingText, parsingElement, parsingElementBoundary, parsingNonElement, parsingAttributeDquote, parsingAttributeSquote, parsingIgnore } parseState; parseState = (skipCharacters > 0) ? parsingIgnore : parsingText; int nestingLevel = 0; int line, col; kv.cursorPosition().position(line, col); QString str = kv.document()->line(line); while (true) { // move left a character if (!col--) { do { if (!line--) { return QString(); // reached start of document } str = kv.document()->line(line); col = str.length(); } while (!col); --col; } ushort ch = str.at(col).unicode(); switch (parseState) { case parsingIgnore: // ignore the specified number of characters parseState = (--skipCharacters > 0) ? parsingIgnore : parsingText; break; case parsingText: switch (ch) { case '<': // hmm... we were actually inside an element return QString(); case '>': // we just hit an element boundary parseState = parsingElementBoundary; break; } break; case parsingElement: switch (ch) { case '"': // attribute ( double quoted ) parseState = parsingAttributeDquote; break; case '\'': // attribute ( single quoted ) parseState = parsingAttributeSquote; break; case '/': // close tag parseState = parsingNonElement; ++nestingLevel; break; case '<': // we just hit the start of the element... if (nestingLevel--) { break; } QString tag = str.mid(col + 1); for (uint pos = 0, len = tag.length(); pos < len; ++pos) { ch = tag.at(pos).unicode(); if (ch == ' ' || ch == '\t' || ch == '>') { tag.truncate(pos); break; } } return tag; } break; case parsingElementBoundary: switch (ch) { case '?': // processing instruction case '-': // comment case '/': // empty element parseState = parsingNonElement; break; case '"': parseState = parsingAttributeDquote; break; case '\'': parseState = parsingAttributeSquote; break; case '<': // empty tag ( bad XML ) parseState = parsingText; break; default: parseState = parsingElement; } break; case parsingAttributeDquote: if (ch == '"') { parseState = parsingElement; } break; case parsingAttributeSquote: if (ch == '\'') { parseState = parsingElement; } break; case parsingNonElement: if (ch == '<') { parseState = parsingText; } break; } } } /** * Return true if the tag is neither a closing tag * nor an empty tag, nor a comment, nor processing instruction. */ bool PluginKateXMLToolsCompletionModel::isOpeningTag(const QString &tag) { return (!isClosingTag(tag) && !isEmptyTag(tag) && !tag.startsWith(""); } /** * Return true if ch is a single or double quote. Expects ch to be of length 1. */ bool PluginKateXMLToolsCompletionModel::isQuote(const QString &ch) { return (ch == "\"" || ch == "'"); } // ======================================================================== // Tools: /// Get string describing current mode QString PluginKateXMLToolsCompletionModel::currentModeToString() const { switch (m_mode) { case entities: return i18n("XML entities"); case attributevalues: return i18n("XML attribute values"); case attributes: return i18n("XML attributes"); case elements: case closingtag: return i18n("XML elements"); default: break; } return QString(); } /** Sort a QStringList case-insensitively. Static. TODO: make it more simple. */ QStringList PluginKateXMLToolsCompletionModel::sortQStringList(QStringList list) { // Sort list case-insensitive. This looks complicated but using a QMap // is even suggested by the Qt documentation. QMap mapList; for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) { QString str = *it; if (mapList.contains(str.toLower())) { // do not override a previous value, e.g. "Auml" and "auml" are two different // entities, but they should be sorted next to each other. // TODO: currently it's undefined if e.g. "A" or "a" comes first, it depends on // the meta DTD ( really? it seems to work okay?!? ) mapList[str.toLower() + '_'] = str; } else { mapList[str.toLower()] = str; } } list.clear(); QMap::Iterator it; // Qt doc: "the items are alphabetically sorted [by key] when iterating over the map": for (it = mapList.begin(); it != mapList.end(); ++it) { list.append(it.value()); } return list; } //BEGIN InsertElement dialog InsertElement::InsertElement(const QStringList & completions, QWidget * parent) : QDialog(parent) { setWindowTitle(i18n("Insert XML Element")); QVBoxLayout *topLayout = new QVBoxLayout(this); // label QString text = i18n("Enter XML tag name and attributes (\"<\", \">\" and closing tag will be supplied):"); QLabel *label = new QLabel(text, this); label->setWordWrap(true); // combo box m_cmbElements = new KHistoryComboBox(this); static_cast(m_cmbElements)->setHistoryItems(completions, true); - connect(m_cmbElements->lineEdit(), SIGNAL(textChanged(QString)), - this, SLOT(slotHistoryTextChanged(QString))); + connect(m_cmbElements->lineEdit(), &QLineEdit::textChanged, this, &InsertElement::slotHistoryTextChanged); // button box QDialogButtonBox * box = new QDialogButtonBox(this); box->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); m_okButton = box->button(QDialogButtonBox::Ok); m_okButton->setDefault(true); - connect(box, SIGNAL(accepted()), this, SLOT(accept())); - connect(box, SIGNAL(rejected()), this, SLOT(reject())); + connect(box, &QDialogButtonBox::accepted, this, &InsertElement::accept); + connect(box, &QDialogButtonBox::rejected, this, &InsertElement::reject); // fill layout topLayout->addWidget(label); topLayout->addWidget(m_cmbElements); topLayout->addWidget(box); m_cmbElements->setFocus(); // make sure the ok button is enabled/disabled correctly slotHistoryTextChanged(m_cmbElements->lineEdit()->text()); } InsertElement::~InsertElement() { } void InsertElement::slotHistoryTextChanged(const QString &text) { m_okButton->setEnabled(!text.isEmpty()); } QString InsertElement::text() const { return m_cmbElements->currentText(); } //END InsertElement dialog #include "plugin_katexmltools.moc" // kate: space-indent on; indent-width 4; replace-tabs on; mixed-indent off;

foo test bar X *