diff --git a/addons/backtracebrowser/katebacktracebrowser.cpp b/addons/backtracebrowser/katebacktracebrowser.cpp index d0e5a3e29..9ce9dcee2 100644 --- a/addons/backtracebrowser/katebacktracebrowser.cpp +++ b/addons/backtracebrowser/katebacktracebrowser.cpp @@ -1,419 +1,419 @@ /* 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 //END Includes K_PLUGIN_FACTORY_WITH_JSON(KateBtBrowserFactory, "katebacktracebrowserplugin.json", registerPlugin();) -KateBtBrowserPlugin *KateBtBrowserPlugin::s_self = 0L; +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 = 0; + 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 0L; + 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))); } 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))); } 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())); 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())); } KateBtConfigDialog::~KateBtConfigDialog() { } #include "katebacktracebrowser.moc" // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/backtracebrowser/katebacktracebrowser.h b/addons/backtracebrowser/katebacktracebrowser.h index 0cf2bdfeb..1280990f3 100644 --- a/addons/backtracebrowser/katebacktracebrowser.h +++ b/addons/backtracebrowser/katebacktracebrowser.h @@ -1,153 +1,153 @@ /* 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. */ #ifndef KATE_BACKTRACEBROWSER_H #define KATE_BACKTRACEBROWSER_H #include #include #include #include "ui_btbrowserwidget.h" #include "ui_btconfigwidget.h" #include "btdatabase.h" #include "btfileindexer.h" #include #include #include class KateBtConfigWidget; class KateBtBrowserWidget; class KateBtBrowserPlugin : public KTextEditor::Plugin { Q_OBJECT public: - explicit KateBtBrowserPlugin(QObject *parent = 0, const QList & = QList()); + explicit KateBtBrowserPlugin(QObject *parent = nullptr, const QList & = QList()); virtual ~KateBtBrowserPlugin(); static KateBtBrowserPlugin &self(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; KateBtDatabase &database(); BtFileIndexer &fileIndexer(); void startIndexer(); Q_SIGNALS: void newStatus(const QString &); public: int configPages() const Q_DECL_OVERRIDE; - KTextEditor::ConfigPage *configPage(int number, QWidget *parent = 0) Q_DECL_OVERRIDE; + KTextEditor::ConfigPage *configPage(int number, QWidget *parent = nullptr) Q_DECL_OVERRIDE; // // private data // private: KateBtDatabase db; BtFileIndexer indexer; static KateBtBrowserPlugin *s_self; }; class KateBtBrowserPluginView : public QObject { Q_OBJECT public: KateBtBrowserPluginView(KateBtBrowserPlugin *plugin, KTextEditor::MainWindow *mainWindow); /** * Virtual destructor. */ ~KateBtBrowserPluginView(); private: KateBtBrowserPlugin *m_plugin; KateBtBrowserWidget *m_widget; }; class KateBtBrowserWidget : public QWidget, public Ui::BtBrowserWidget { Q_OBJECT public: KateBtBrowserWidget(KTextEditor::MainWindow *mainwindow, QWidget *parent); ~KateBtBrowserWidget(); void loadBacktrace(const QString &bt); public Q_SLOTS: void loadFile(); void loadClipboard(); void configure(); void clearStatus(); void setStatus(const QString &status); private Q_SLOTS: void itemActivated(QTreeWidgetItem *item, int column); private: KTextEditor::MainWindow *mw; QTimer timer; }; class KateBtConfigWidget : public KTextEditor::ConfigPage, private Ui::BtConfigWidget { Q_OBJECT public: - explicit KateBtConfigWidget(QWidget *parent = 0); + explicit KateBtConfigWidget(QWidget *parent = nullptr); virtual ~KateBtConfigWidget(); QString name() const Q_DECL_OVERRIDE; QString fullName() const Q_DECL_OVERRIDE; QIcon icon() const Q_DECL_OVERRIDE; public Q_SLOTS: void apply() Q_DECL_OVERRIDE; void reset() Q_DECL_OVERRIDE; void defaults() Q_DECL_OVERRIDE; private Q_SLOTS: void add(); void remove(); void textChanged(); private: bool m_changed; }; class KateBtConfigDialog : public QDialog { Q_OBJECT public: - KateBtConfigDialog(QWidget *parent = 0); + KateBtConfigDialog(QWidget *parent = nullptr); ~KateBtConfigDialog(); private: KateBtConfigWidget *m_configWidget; }; #endif //KATE_BACKTRACEBROWSER_H // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/close-except-like/close_confirm_dialog.h b/addons/close-except-like/close_confirm_dialog.h index b38092f54..6eebed73e 100644 --- a/addons/close-except-like/close_confirm_dialog.h +++ b/addons/close-except-like/close_confirm_dialog.h @@ -1,65 +1,65 @@ /** * \file * * \brief Class \c kate::CloseConfirmDialog (interface) * * 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 . */ #ifndef __SRC__CLOSE_CONFIRM_DIALOG_H__ # define __SRC__CLOSE_CONFIRM_DIALOG_H__ // Project specific includes // Standard includes # include # include # include # include # include # include # include # include # include "ui_close_confirm_dialog.h" namespace kate { /** * \brief [Type brief class description here] * * [More detailed description here] * */ class CloseConfirmDialog : public QDialog, public Ui::CloseConfirmDialog { Q_OBJECT public: /// Default constructor - explicit CloseConfirmDialog(QList&, KToggleAction*, QWidget* const = 0); + explicit CloseConfirmDialog(QList&, KToggleAction*, QWidget* const = nullptr); ~CloseConfirmDialog(); private Q_SLOTS: void updateDocsList(); private: QList& m_docs; }; } // namespace kate #endif // __SRC__CLOSE_CONFIRM_DIALOG_H__ diff --git a/addons/close-except-like/close_except_plugin.h b/addons/close-except-like/close_except_plugin.h index 452387f2a..9326b5c67 100644 --- a/addons/close-except-like/close_except_plugin.h +++ b/addons/close-except-like/close_except_plugin.h @@ -1,148 +1,148 @@ /** * \file * * \brief Declate Kate's Close Except/Like plugin classes * * 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 . */ #ifndef __SRC__CLOSE_EXCEPT_PLUGIN_H__ # define __SRC__CLOSE_EXCEPT_PLUGIN_H__ // Project specific includes // Standard includes # include # include # include # include # include # include # include # include # include # include # include # include # include namespace kate { class CloseExceptPlugin; // forward declaration /** * \brief Plugin to close docs grouped by extension or location */ class CloseExceptPluginView : public QObject , public KXMLGUIClient { Q_OBJECT typedef QMap > actions_map_type; public: /// Default constructor CloseExceptPluginView(KTextEditor::MainWindow*, CloseExceptPlugin*); /// Destructor ~CloseExceptPluginView(); private Q_SLOTS: void viewCreated(KTextEditor::View*); void documentCreated(KTextEditor::Editor*, KTextEditor::Document*); void updateMenuSlotStub(KTextEditor::Document*); void close(const QString&, const bool); void closeExcept(const QString& item) { close(item, false); } void closeLike(const QString& item) { close(item, true); } private: void displayMessage(const QString&, const QString&, KTextEditor::Message::MessageType); void connectToDocument(KTextEditor::Document*); void updateMenu(); QPointer updateMenu( const std::set& , const std::set& , actions_map_type& , KActionMenu* ); void appendActionsFrom( const std::set& , actions_map_type& , KActionMenu* , QSignalMapper* ); void appendActionsFrom( const std::set& masks , actions_map_type& actions , KActionMenu* menu , QSignalMapper* mapper ); CloseExceptPlugin* m_plugin; QPointer m_show_confirmation_action; QPointer m_except_menu; QPointer m_like_menu; QPointer m_except_mapper; QPointer m_like_mapper; actions_map_type m_except_actions; actions_map_type m_like_actions; KTextEditor::MainWindow *m_mainWindow; QPointer m_infoMessage; }; /** * \brief Plugin view class */ class CloseExceptPlugin : public KTextEditor::Plugin, public KTextEditor::SessionConfigInterface { Q_OBJECT Q_INTERFACES(KTextEditor::SessionConfigInterface) public: /// Default constructor - CloseExceptPlugin(QObject* = 0, const QList& = QList()); + CloseExceptPlugin(QObject* = nullptr, const QList& = QList()); /// Destructor virtual ~CloseExceptPlugin() {} /// Create a new view of this plugin for the given main window QObject* createView(KTextEditor::MainWindow*) Q_DECL_OVERRIDE; /// \name Plugin interface implementation //@{ void readSessionConfig(const KConfigGroup&) Q_DECL_OVERRIDE; void writeSessionConfig(KConfigGroup&) Q_DECL_OVERRIDE; //@} bool showConfirmationNeeded() const { return m_show_confirmation_needed; } public Q_SLOTS: void toggleShowConfirmation(bool flag) { m_show_confirmation_needed = flag; } private: bool m_show_confirmation_needed; }; } // namespace kate #endif // __SRC__CLOSE_EXCEPT_PLUGIN_H__ diff --git a/addons/filebrowser/katebookmarkhandler.h b/addons/filebrowser/katebookmarkhandler.h index 3848787a7..0d7a309ce 100644 --- a/addons/filebrowser/katebookmarkhandler.h +++ b/addons/filebrowser/katebookmarkhandler.h @@ -1,60 +1,60 @@ /* This file is part of the KDE project Copyright (C) xxxx KFile Authors Copyright (C) 2002 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. */ #ifndef KATE_BOOKMARK_HANDLER_H #define KATE_BOOKMARK_HANDLER_H #include #include class KateFileBrowser; class QMenu; class KateBookmarkHandler : public QObject, public KBookmarkOwner { Q_OBJECT public: - explicit KateBookmarkHandler( KateFileBrowser *parent, QMenu *kpopupmenu = 0 ); + explicit KateBookmarkHandler( KateFileBrowser *parent, QMenu *kpopupmenu = nullptr ); ~KateBookmarkHandler(); // KBookmarkOwner interface: QUrl currentUrl() const Q_DECL_OVERRIDE; QString currentTitle() const Q_DECL_OVERRIDE; QMenu *menu() const { return m_menu; } void openBookmark( const KBookmark &, Qt::MouseButtons, Qt::KeyboardModifiers ) Q_DECL_OVERRIDE; Q_SIGNALS: void openUrl( const QString& url ); private: KateFileBrowser *mParent; QMenu *m_menu; KBookmarkMenu *m_bookmarkMenu; }; #endif // KATE_BOOKMARK_HANDLER_H // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/filebrowser/katefilebrowser.cpp b/addons/filebrowser/katefilebrowser.cpp index 9155d3701..75741b5ba 100644 --- a/addons/filebrowser/katefilebrowser.cpp +++ b/addons/filebrowser/katefilebrowser.cpp @@ -1,345 +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))); 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())); // 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 the bookmark handler connect(m_bookmarkHandler, SIGNAL(openUrl(QString)), this, SLOT(setDir(QString))); 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())); } 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 = 0; + 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; newurl.setPath(newurl.path() + QLatin1Char('/')); 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())); 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())); 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/katefilebrowser.h b/addons/filebrowser/katefilebrowser.h index 590da6455..50c13d2ec 100644 --- a/addons/filebrowser/katefilebrowser.h +++ b/addons/filebrowser/katefilebrowser.h @@ -1,109 +1,109 @@ /* 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. */ #ifndef KATE_FILEBROWSER_H #define KATE_FILEBROWSER_H #include #include #include #include class KateBookmarkHandler; class KActionCollection; class KDirOperator; class KFileItem; class KHistoryComboBox; class KToolBar; class KConfigGroup; class KUrlNavigator; class QAbstractItemView; class QAction; /* The kate file selector presents a directory view, in which the default action is to open the activated file. Additionally, a toolbar for managing the kdiroperator widget + sync that to the directory of the current file is available, as well as a filter widget allowing to filter the displayed files using a name filter. */ class KateFileBrowser : public QWidget { Q_OBJECT public: - explicit KateFileBrowser( KTextEditor::MainWindow *mainWindow = 0, - QWidget * parent = 0); + explicit KateFileBrowser( KTextEditor::MainWindow *mainWindow = nullptr, + QWidget * parent = nullptr); ~KateFileBrowser(); void readSessionConfig (const KConfigGroup& config); void writeSessionConfig (KConfigGroup& config); void setupToolbar(); void setView( KFile::FileView ); KDirOperator *dirOperator() { return m_dirOperator; } KActionCollection* actionCollection() { return m_actionCollection; } public Q_SLOTS: void slotFilterChange(const QString&); void setDir(QUrl); void setDir( const QString &url ) { setDir( QUrl( url ) ); } void selectorViewChanged( QAbstractItemView * ); private Q_SLOTS: void fileSelected(const KFileItem & /*file*/); void updateDirOperator( const QUrl &u ); void updateUrlNavigator( const QUrl &u ); void setActiveDocumentDir(); void autoSyncFolder(); protected: QUrl activeDocumentUrl(); void openSelectedFiles(); void setupActions(); public: KTextEditor::MainWindow* mainWindow() { return m_mainWindow; } private: KToolBar *m_toolbar; KActionCollection *m_actionCollection; KateBookmarkHandler *m_bookmarkHandler; KUrlNavigator *m_urlNavigator; KDirOperator * m_dirOperator; KHistoryComboBox * m_filter; QAction *m_autoSyncFolder; KTextEditor::MainWindow *m_mainWindow; }; #endif //KATE_FILEBROWSER_H // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/filebrowser/katefilebrowserconfig.cpp b/addons/filebrowser/katefilebrowserconfig.cpp index 12297f1ca..a6b88f795 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 = 0, + 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()) ); // 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 = 0; + 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/katefilebrowserconfig.h b/addons/filebrowser/katefilebrowserconfig.h index c9c9b6474..1d153b9f3 100644 --- a/addons/filebrowser/katefilebrowserconfig.h +++ b/addons/filebrowser/katefilebrowserconfig.h @@ -1,63 +1,63 @@ /* 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. */ #ifndef KATE_FILEBROWSER_CONFIG_H #define KATE_FILEBROWSER_CONFIG_H #include class KateFileBrowser; class KActionSelector; class KateFileBrowserConfigPage : public KTextEditor::ConfigPage { Q_OBJECT public: - explicit KateFileBrowserConfigPage( QWidget* parent = 0, KateFileBrowser *kfb = 0); + explicit KateFileBrowserConfigPage( QWidget* parent = nullptr, KateFileBrowser *kfb = nullptr); virtual ~KateFileBrowserConfigPage() {} QString name() const Q_DECL_OVERRIDE; QString fullName() const Q_DECL_OVERRIDE; QIcon icon() const Q_DECL_OVERRIDE; void apply() Q_DECL_OVERRIDE; void reset() Q_DECL_OVERRIDE; void defaults() Q_DECL_OVERRIDE {} private Q_SLOTS: void slotMyChanged(); private: void init(); KateFileBrowser *fileBrowser; KActionSelector *acSel; bool m_changed; }; #endif //KATE_FILEBROWSER_CONFIG_H // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/filebrowser/katefilebrowserplugin.cpp b/addons/filebrowser/katefilebrowserplugin.cpp index e4efe306c..df0cdccc4 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*))); 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 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/filebrowser/katefilebrowserplugin.h b/addons/filebrowser/katefilebrowserplugin.h index 1425da52e..77e8df234 100644 --- a/addons/filebrowser/katefilebrowserplugin.h +++ b/addons/filebrowser/katefilebrowserplugin.h @@ -1,86 +1,86 @@ /* 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. */ #ifndef KATE_FILEBROWSER_PLUGIN_H #define KATE_FILEBROWSER_PLUGIN_H #include #include #include #include #include class KateFileBrowser; class KateFileBrowserPluginView; class KateFileBrowserPlugin: public KTextEditor::Plugin { Q_OBJECT public: - explicit KateFileBrowserPlugin( QObject* parent = 0, const QList& = QList() ); + explicit KateFileBrowserPlugin( QObject* parent = nullptr, const QList& = QList() ); virtual ~KateFileBrowserPlugin() {} QObject *createView (KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; int configPages() const Q_DECL_OVERRIDE; - KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = 0) Q_DECL_OVERRIDE; + KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = nullptr) Q_DECL_OVERRIDE; public Q_SLOTS: void viewDestroyed(QObject* view); private: QList m_views; }; class KateFileBrowserPluginView : public QObject, public KTextEditor::SessionConfigInterface { Q_OBJECT Q_INTERFACES(KTextEditor::SessionConfigInterface) public: /** * Constructor. */ KateFileBrowserPluginView (KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWindow); /** * Virtual destructor. */ ~KateFileBrowserPluginView (); void readSessionConfig (const KConfigGroup& config) Q_DECL_OVERRIDE; void writeSessionConfig (KConfigGroup& config) Q_DECL_OVERRIDE; private: bool eventFilter(QObject*, QEvent*) Q_DECL_OVERRIDE; QWidget *m_toolView; KateFileBrowser *m_fileBrowser; KTextEditor::MainWindow *m_mainWindow; friend class KateFileBrowserPlugin; }; #endif //KATE_FILEBROWSER_PLUGIN_H // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/filetree/autotests/document_dummy.h b/addons/filetree/autotests/document_dummy.h index 67c3cd8b1..db9ae114b 100644 --- a/addons/filetree/autotests/document_dummy.h +++ b/addons/filetree/autotests/document_dummy.h @@ -1,127 +1,127 @@ /* This file is part of the KDE libraries Copyright (C) 2001 Christoph Cullmann Copyright (C) 2005 Dominik Haumann (dhdev@gmx.de) (documentation) 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. */ #ifndef TEST_DOCUMENT_H #define TEST_DOCUMENT_H #include #include class DummyDocument : public KTextEditor::Document { Q_OBJECT public: DummyDocument (const QString &url = QString()) : KTextEditor::Document(nullptr, nullptr) , m_name(QLatin1String("foo")) , m_encoding() , m_views() { setUrl(url); m_name = url.section(QLatin1Char('/'), -1); // some nice default to mimic the KateDocument } DummyDocument (const char *url) : DummyDocument(QString::fromLatin1(url)) {} virtual ~DummyDocument () {} - KTextEditor::View *createView ( QWidget *, KTextEditor::MainWindow * = nullptr ) Q_DECL_OVERRIDE { return 0; } - virtual KTextEditor::View *activeView() const { return 0; } + KTextEditor::View *createView ( QWidget *, KTextEditor::MainWindow * = nullptr ) Q_DECL_OVERRIDE { return nullptr; } + virtual KTextEditor::View *activeView() const { return nullptr; } QList views() const Q_DECL_OVERRIDE { return m_views; } QString documentName() const Q_DECL_OVERRIDE { return m_name; } QString mimeType() Q_DECL_OVERRIDE { return QString(); } QByteArray checksum() const Q_DECL_OVERRIDE { return QByteArray(); } bool setEncoding (const QString &) Q_DECL_OVERRIDE { return false; } QString encoding () const Q_DECL_OVERRIDE { return m_encoding; } bool documentReload () Q_DECL_OVERRIDE { return true; } bool documentSave () Q_DECL_OVERRIDE { return true; } bool documentSaveAs () Q_DECL_OVERRIDE { return true; } bool isEditingTransactionRunning() const Q_DECL_OVERRIDE { return false; } QString text () const Q_DECL_OVERRIDE { return QString(); } QString text ( const KTextEditor::Range&, bool = false ) const Q_DECL_OVERRIDE { return QString(); } QChar characterAt( const KTextEditor::Cursor&) const Q_DECL_OVERRIDE { return QChar(); } QString wordAt(const KTextEditor::Cursor&) const Q_DECL_OVERRIDE { return QString(); } KTextEditor::Range wordRangeAt(const KTextEditor::Cursor&) const Q_DECL_OVERRIDE { return KTextEditor::Range(); } bool isValidTextPosition(const KTextEditor::Cursor&) const Q_DECL_OVERRIDE { return true; } QStringList textLines ( const KTextEditor::Range&, bool = false ) const Q_DECL_OVERRIDE { return QStringList(); } QString line ( int ) const Q_DECL_OVERRIDE { return QString(); } int lines () const Q_DECL_OVERRIDE { return 0; } KTextEditor::Cursor documentEnd() const Q_DECL_OVERRIDE { return KTextEditor::Cursor(); } int totalCharacters() const Q_DECL_OVERRIDE { return 0; } int lineLength ( int ) const Q_DECL_OVERRIDE { return 0; } bool setText ( const QString & ) Q_DECL_OVERRIDE { return false; } bool setText ( const QStringList & ) Q_DECL_OVERRIDE { return false; } bool clear () Q_DECL_OVERRIDE { return true; } bool insertText ( const KTextEditor::Cursor &, const QString &, bool = false ) Q_DECL_OVERRIDE { return false; } bool insertText ( const KTextEditor::Cursor &, const QStringList &, bool = false ) Q_DECL_OVERRIDE { return false; } bool removeText ( const KTextEditor::Range &, bool = false ) Q_DECL_OVERRIDE { return false; } bool insertLine ( int, const QString & ) Q_DECL_OVERRIDE { return false; } bool insertLines ( int, const QStringList & ) Q_DECL_OVERRIDE { return false; } bool removeLine ( int ) Q_DECL_OVERRIDE { return false; } KTextEditor::DefaultStyle defaultStyleAt(const KTextEditor::Cursor &) const Q_DECL_OVERRIDE { return KTextEditor::dsNormal; } QString mode() const Q_DECL_OVERRIDE { return QString(); } QString highlightingMode() const Q_DECL_OVERRIDE { return QString(); } QStringList modes() const Q_DECL_OVERRIDE { return QStringList(); } QStringList highlightingModes() const Q_DECL_OVERRIDE {return QStringList(); } bool setMode(const QString &) Q_DECL_OVERRIDE { return false; } bool setHighlightingMode(const QString &) Q_DECL_OVERRIDE { return false; } QString highlightingModeSection( int ) const Q_DECL_OVERRIDE { return QString(); } QString modeSection( int ) const Q_DECL_OVERRIDE { return QString(); } bool print() Q_DECL_OVERRIDE { return false; } void printPreview() Q_DECL_OVERRIDE {} QStringList embeddedHighlightingModes() const Q_DECL_OVERRIDE { return QStringList(); } QString highlightingModeAt(const KTextEditor::Cursor &) Q_DECL_OVERRIDE { return QString(); } bool isLineModified(int) const Q_DECL_OVERRIDE { return false; } bool isLineSaved(int) const Q_DECL_OVERRIDE { return false; } bool isLineTouched(int) const Q_DECL_OVERRIDE { return false; } // KParts::ReadWritePart bool saveFile() Q_DECL_OVERRIDE { return false; } // make QObject happy Q_SIGNALS: void modifiedOnDisk(KTextEditor::Document*, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason); public: void setUrl(const QString &url) { KParts::ReadOnlyPart::setUrl(QUrl(url)); } void setName(const QString &name) { m_name = name; } void readSessionConfig(const KConfigGroup &, const QSet & = QSet()) Q_DECL_OVERRIDE {} void writeSessionConfig(KConfigGroup &, const QSet & = QSet()) Q_DECL_OVERRIDE {} bool postMessage(KTextEditor::Message *) Q_DECL_OVERRIDE { return false; } bool isDataRecoveryAvailable() const Q_DECL_OVERRIDE { return false; } void recoverData() Q_DECL_OVERRIDE {} void discardDataRecovery() Q_DECL_OVERRIDE {} private: QString m_name, m_encoding; QList m_views; }; #endif // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/filetree/katefiletree.cpp b/addons/filetree/katefiletree.cpp index c3bcd918b..a366042ea 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))); m_filelistReloadDocument = new QAction(QIcon::fromTheme(QLatin1String("view-refresh")), i18nc("@action:inmenu", "Reloa&d"), this); connect(m_filelistReloadDocument, SIGNAL(triggered(bool)), SLOT(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())); 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())); 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())); 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())); 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())); 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())); 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())); 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 = (0 != doc); + 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 *))); 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 = 0; + 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.h b/addons/filetree/katefiletreeconfigpage.h index d875e351b..35453e6e2 100644 --- a/addons/filetree/katefiletreeconfigpage.h +++ b/addons/filetree/katefiletreeconfigpage.h @@ -1,66 +1,66 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001,2006 Joseph Wenninger Copyright (C) 2001, 2007 Anders Lund 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. */ #ifndef KATE_FILETREE_CONFIGPAGE_H #define KATE_FILETREE_CONFIGPAGE_H #include #include class KateFileTreePlugin; class KateFileTreeConfigPage : public KTextEditor::ConfigPage { Q_OBJECT public: - explicit KateFileTreeConfigPage(QWidget *parent = 0, KateFileTreePlugin *plug = 0); + explicit KateFileTreeConfigPage(QWidget *parent = nullptr, KateFileTreePlugin *plug = nullptr); ~KateFileTreeConfigPage() {} QString name() const Q_DECL_OVERRIDE; QString fullName() const Q_DECL_OVERRIDE; QIcon icon() const Q_DECL_OVERRIDE; public Q_SLOTS: void apply() Q_DECL_OVERRIDE; void defaults() Q_DECL_OVERRIDE; void reset() Q_DECL_OVERRIDE; //Q_SIGNALS: // void changed(); private Q_SLOTS: void slotMyChanged(); private: class QGroupBox *gbEnableShading; class KColorButton *kcbViewShade, *kcbEditShade; class QLabel *lEditShade, *lViewShade, *lSort, *lMode; class KComboBox *cmbSort, *cmbMode; class QCheckBox *cbShowFullPath; KateFileTreePlugin *m_plug; bool m_changed; }; #endif /* KATE_FILETREE_CONFIGPAGE_H */ diff --git a/addons/filetree/katefiletreemodel.cpp b/addons/filetree/katefiletreemodel.cpp index a6afeb11f..48c176518 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 = 0, Flags f = ProxyItem::None); + 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 = 0) : ProxyItem(n, p) { + 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(0) + : 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 = 0; + 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"), 0)) + , 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"), 0); + 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, 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 0; + 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 = 0; + 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, 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 != 0); + 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 0; + return nullptr; } ProxyItemDir *KateFileTreeModel::findChildNode(const ProxyItemDir *parent, const QString &name) const { - Q_ASSERT(parent != 0); + Q_ASSERT(parent != nullptr); Q_ASSERT(!name.isEmpty()); if (!parent->childCount()) { - return 0; + return nullptr; } foreach(ProxyItem * item, parent->children()) { if (!item->flag(ProxyItem::Dir)) { continue; } if (item->display() == name) { return static_cast(item); } } - return 0; + return nullptr; } void KateFileTreeModel::insertItemInto(ProxyItemDir *root, ProxyItem *item) { - Q_ASSERT(root != 0); - Q_ASSERT(item != 0); + 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 != 0); + 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 != 0); + 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 != 0); + 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 f776e0458..caf943508 100644 --- a/addons/filetree/katefiletreeplugin.cpp +++ b/addons/filetree/katefiletreeplugin.cpp @@ -1,457 +1,457 @@ /* 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 *))); 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 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))); 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)), 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())); 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(mainWindow, SIGNAL(viewChanged(KTextEditor::View *)), this, SLOT(viewChanged(KTextEditor::View *))); // // 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())); 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())); 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())); 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/filetree/katefiletreeplugin.h b/addons/filetree/katefiletreeplugin.h index 3e2728def..4bce7c56c 100644 --- a/addons/filetree/katefiletreeplugin.h +++ b/addons/filetree/katefiletreeplugin.h @@ -1,142 +1,142 @@ /* 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. */ #ifndef KATE_FILETREE_PLUGIN_H #define KATE_FILETREE_PLUGIN_H #include #include #include #include #include #include #include #include "katefiletreepluginsettings.h" #include class KToolBar; class KateFileTree; class KateFileTreeModel; class KateFileTreeProxyModel; class KateFileTreeConfigPage; class KateFileTreePluginView; class KateFileTreePlugin: public KTextEditor::Plugin { Q_OBJECT public: - explicit KateFileTreePlugin(QObject *parent = 0, const QList & = QList()); + explicit KateFileTreePlugin(QObject *parent = nullptr, const QList & = QList()); virtual ~KateFileTreePlugin(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; int configPages() const Q_DECL_OVERRIDE; - KTextEditor::ConfigPage *configPage(int number = 0, QWidget *parent = 0) Q_DECL_OVERRIDE; + KTextEditor::ConfigPage *configPage(int number = 0, QWidget *parent = nullptr) Q_DECL_OVERRIDE; const KateFileTreePluginSettings &settings(); void applyConfig(bool shadingEnabled, QColor viewShade, QColor editShade, bool listMode, int sortRole, bool showFulPath); public Q_SLOTS: void viewDestroyed(QObject *view); private: QList m_views; KateFileTreeConfigPage *m_confPage; KateFileTreePluginSettings m_settings; }; class KateFileTreePluginView : public QObject, public KXMLGUIClient, public KTextEditor::SessionConfigInterface { Q_OBJECT Q_INTERFACES(KTextEditor::SessionConfigInterface) public: /** * Constructor. */ KateFileTreePluginView(KTextEditor::MainWindow *mainWindow, KateFileTreePlugin *plug); /** * Virtual destructor. */ ~KateFileTreePluginView(); void readSessionConfig(const KConfigGroup &config) Q_DECL_OVERRIDE; void writeSessionConfig(KConfigGroup &config) Q_DECL_OVERRIDE; /** * The file tree model. * @return the file tree model */ KateFileTreeModel *model(); /** * The file tree proxy model. * @return the file tree proxy model */ KateFileTreeProxyModel *proxy(); /** * The file tree. * @return the file tree */ KateFileTree *tree(); void setListMode(bool listMode); bool hasLocalPrefs(); void setHasLocalPrefs(bool); protected: void setupActions(); private: QWidget *m_toolView; KToolBar *m_toolbar; KateFileTree *m_fileTree; KateFileTreeProxyModel *m_proxyModel; KateFileTreeModel *m_documentModel; bool m_hasLocalPrefs; bool m_loadingDocuments; KateFileTreePlugin *m_plug; KTextEditor::MainWindow *m_mainWindow; private Q_SLOTS: void showToolView(); void hideToolView(); void showActiveDocument(); void activateDocument(KTextEditor::Document *); void viewChanged(KTextEditor::View * = nullptr); void documentOpened(KTextEditor::Document *); void documentClosed(KTextEditor::Document *); void viewModeChanged(bool); void sortRoleChanged(int); void slotAboutToCreateDocuments(); void slotDocumentsCreated(const QList &); void slotDocumentSave(); void slotDocumentSaveAs(); }; #endif //KATE_FILETREE_PLUGIN_H diff --git a/addons/filetree/katefiletreeproxymodel.h b/addons/filetree/katefiletreeproxymodel.h index 6182ded4b..fb092fea5 100644 --- a/addons/filetree/katefiletreeproxymodel.h +++ b/addons/filetree/katefiletreeproxymodel.h @@ -1,46 +1,46 @@ /* 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. */ #ifndef KATE_FILETREEPROXYMODEL_H #define KATE_FILETREEPROXYMODEL_H #include namespace KTextEditor { class Document; } class KateFileTreeProxyModel : public QSortFilterProxyModel { Q_OBJECT public: - KateFileTreeProxyModel(QObject *p = 0); + KateFileTreeProxyModel(QObject *p = nullptr); QModelIndex docIndex(const KTextEditor::Document *) const; bool isDir(const QModelIndex &i) const; void setSourceModel(QAbstractItemModel *model) Q_DECL_OVERRIDE; protected: bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; }; #endif /* KATE_FILETREEPROXYMODEL_H */ diff --git a/addons/gdbplugin/advanced_settings.h b/addons/gdbplugin/advanced_settings.h index 163a5a1a3..f2658ca2d 100644 --- a/addons/gdbplugin/advanced_settings.h +++ b/addons/gdbplugin/advanced_settings.h @@ -1,65 +1,65 @@ // 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. #ifndef ADVANCED_SETTINGS_H #define ADVANCED_SETTINGS_H #include "ui_advanced_settings.h" #include #include class AdvancedGDBSettings : public QDialog, public Ui::AdvancedGDBSettings { Q_OBJECT public: enum CustomStringOrder { GDBIndex = 0, LocalRemoteIndex, RemoteBaudIndex, SoAbsoluteIndex, SoRelativeIndex, SrcPathsIndex, CustomStartIndex }; - AdvancedGDBSettings(QWidget *parent = 0); + AdvancedGDBSettings(QWidget *parent = nullptr); ~AdvancedGDBSettings(); const QStringList configs() const; void setConfigs(const QStringList &cfgs); private: void setComboText(QComboBox *combo, const QString &str); private Q_SLOTS: void slotBrowseGDB(); void slotSetSoPrefix(); void slotAddSoPath(); void slotDelSoPath(); void slotAddSrcPath(); void slotDelSrcPath(); void slotLocalRemoteChanged(); }; #endif diff --git a/addons/gdbplugin/configview.cpp b/addons/gdbplugin/configview.cpp index cb50d568d..6abe744c9 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 = 0; + m_checBoxLayout = nullptr; // first false then true to make sure a layout is set m_useBottomLayout = false; - resizeEvent(0); + resizeEvent(nullptr); m_useBottomLayout = true; - resizeEvent(0); + 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())); } 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))); } 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 = 0; + 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 != NULL) { + if (view != nullptr) { exe = view->document()->url().toLocalFile(); } } - m_executable->setText(QFileDialog::getOpenFileName((QWidget *)0, QString(), exe, QStringLiteral("application/x-executable"))); + 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 != NULL) { + 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 a6acd3ef9..eebe2bc2a 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(0), + 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, SIGNAL(readyReadStandardError()), this, SLOT(slotReadDebugStdErr())); connect(&m_debugProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(slotReadDebugStdOut())); connect(&m_debugProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotDebugFinished(int,QProcess::ExitStatus))); 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.h b/addons/gdbplugin/ioview.h index 33340f7c6..685d434dd 100644 --- a/addons/gdbplugin/ioview.h +++ b/addons/gdbplugin/ioview.h @@ -1,86 +1,86 @@ // // ioview.h // // Description: Widget that interacts with the debugged application // // // 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. #ifndef IOVIEW_H #define IOVIEW_H #include #include class QTextEdit; class QLineEdit; class QSocketNotifier; class IOView : public QWidget { Q_OBJECT public: - IOView(QWidget *parent = 0); + IOView(QWidget *parent = nullptr); ~IOView(); const QString stdinFifo(); const QString stdoutFifo(); const QString stderrFifo(); void enableInput(bool enable); void clearOutput(); public Q_SLOTS: void addStdOutText(const QString &text); void addStdErrText(const QString &text); private Q_SLOTS: void returnPressed(); void readOutput(); void readErrors(); Q_SIGNALS: void stdOutText(const QString &text); void stdErrText(const QString &text); private: void createFifos(); QString createFifo(const QString &prefix); QTextEdit *m_output; QLineEdit *m_input; QString m_stdinFifo; QString m_stdoutFifo; QString m_stderrFifo; QFile m_stdin; QFile m_stdout; QFile m_stderr; QFile m_stdoutD; QFile m_stderrD; int m_stdoutFD; int m_stderrFD; QSocketNotifier *m_stdoutNotifier; QSocketNotifier *m_stderrNotifier; }; #endif diff --git a/addons/gdbplugin/localsview.h b/addons/gdbplugin/localsview.h index 34ef61326..557385c1f 100644 --- a/addons/gdbplugin/localsview.h +++ b/addons/gdbplugin/localsview.h @@ -1,54 +1,54 @@ // // Description: Widget that local variables of the gdb inferior // // 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. #ifndef LOCALSVIEW_H #define LOCALSVIEW_H #include #include class LocalsView : public QTreeWidget { Q_OBJECT public: - LocalsView(QWidget *parent = 0); + LocalsView(QWidget *parent = nullptr); ~LocalsView(); public Q_SLOTS: // An empty value string ends the locals void addLocal(const QString &vString); void addStruct(QTreeWidgetItem *parent, const QString &vString); void addArray(QTreeWidgetItem *parent, const QString &vString); Q_SIGNALS: void localsVisible(bool visible); protected: void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; void hideEvent(QHideEvent *event) Q_DECL_OVERRIDE; private: void createWrappedItem(QTreeWidgetItem *parent, const QString &name, const QString &value); void createWrappedItem(QTreeWidget *parent, const QString &name, const QString &value); bool m_allAdded; QString m_local; }; #endif diff --git a/addons/gdbplugin/plugin_kategdb.cpp b/addons/gdbplugin/plugin_kategdb.cpp index 5efcb7445..2546098d4 100644 --- a/addons/gdbplugin/plugin_kategdb.cpp +++ b/addons/gdbplugin/plugin_kategdb.cpp @@ -1,775 +1,775 @@ // // 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())); 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_threadCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(threadSelected(int))); 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(NULL, mainWin); + m_configView = new ConfigView(nullptr, mainWin); m_ioView = new IOView(); connect(m_configView, SIGNAL(showIO(bool)), this, SLOT(showIO(bool))); 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, SIGNAL(outputText(QString)), this, SLOT(addOutputText(QString))); connect(m_debugView, SIGNAL(outputError(QString)), this, SLOT(addErrorText(QString))); connect(m_debugView, SIGNAL(debugLocationChanged(QUrl,int)), this, SLOT(slotGoTo(QUrl,int))); connect(m_debugView, SIGNAL(breakPointSet(QUrl,int)), this, SLOT(slotBreakpointSet(QUrl,int))); connect(m_debugView, SIGNAL(breakPointCleared(QUrl,int)), this, SLOT(slotBreakpointCleared(QUrl,int))); connect(m_debugView, SIGNAL(clearBreakpointMarks()), this, SLOT(clearMarks())); connect(m_debugView, SIGNAL(programEnded()), this, SLOT(programEnded())); connect(m_debugView, SIGNAL(gdbEnded()), this, SLOT(programEnded())); connect(m_debugView, SIGNAL(gdbEnded()), this, SLOT(gdbEnded())); connect(m_debugView, SIGNAL(stackFrameInfo(QString,QString)), this, SLOT(insertStackFrame(QString,QString))); connect(m_debugView, SIGNAL(stackFrameChanged(int)), this, SLOT(stackFrameChanged(int))); connect(m_debugView, SIGNAL(infoLocal(QString)), m_localsView, SLOT(addLocal(QString))); connect(m_debugView, SIGNAL(threadInfo(int,bool)), this, SLOT(insertThread(int,bool))); connect(m_localsView, SIGNAL(localsVisible(bool)), m_debugView, SLOT(slotQueryLocals(bool))); // 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())); 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())); 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())); 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())); 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())); 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())); 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())); a = actionCollection()->addAction(QStringLiteral("move_pc")); a->setText(i18nc("Move Program Counter (next execution)", "Move PC")); connect( a, SIGNAL(triggered(bool)), this, SLOT(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())); 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())); 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())); // 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())); 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*))); 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)), 0, 0); - disconnect(m_ioView, SIGNAL(stdErrText(QString)), 0, 0); + disconnect(m_ioView, SIGNAL(stdOutText(QString)), nullptr, nullptr); + disconnect(m_ioView, SIGNAL(stdErrText(QString)), 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))); } else { connect(m_ioView, SIGNAL(stdOutText(QString)), this, SLOT(addOutputText(QString))); connect(m_ioView, SIGNAL(stdErrText(QString)), this, SLOT(addErrorText(QString))); } 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/gdbplugin/plugin_kategdb.h b/addons/gdbplugin/plugin_kategdb.h index 600dff215..b175f7a78 100644 --- a/addons/gdbplugin/plugin_kategdb.h +++ b/addons/gdbplugin/plugin_kategdb.h @@ -1,130 +1,130 @@ // // 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. #ifndef PLUGIN_KATEGDB_H #define PLUGIN_KATEGDB_H #include #include #include #include #include #include #include #include "debugview.h" #include "configview.h" #include "ioview.h" #include "localsview.h" class KHistoryComboBox; class QTextEdit; class QTreeWidget; typedef QList VariantList; class KatePluginGDB : public KTextEditor::Plugin { Q_OBJECT public: - explicit KatePluginGDB(QObject* parent = NULL, const VariantList& = VariantList()); + explicit KatePluginGDB(QObject* parent = nullptr, const VariantList& = VariantList()); virtual ~KatePluginGDB(); QObject* createView(KTextEditor::MainWindow* mainWindow) Q_DECL_OVERRIDE; }; class KatePluginGDBView : public QObject, public KXMLGUIClient, public KTextEditor::SessionConfigInterface { Q_OBJECT Q_INTERFACES(KTextEditor::SessionConfigInterface) public: KatePluginGDBView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWin); ~KatePluginGDBView(); // reimplemented: read and write session config void readSessionConfig (const KConfigGroup& config) Q_DECL_OVERRIDE; void writeSessionConfig (KConfigGroup& config) Q_DECL_OVERRIDE; private Q_SLOTS: void slotDebug(); void slotRestart(); void slotToggleBreakpoint(); void slotMovePC(); void slotRunToCursor(); void slotGoTo(const QUrl &fileName, int lineNum); void slotValue(); void aboutToShowMenu(); void slotBreakpointSet(const QUrl &file, int line); void slotBreakpointCleared(const QUrl &file, int line); void slotSendCommand(); void enableDebugActions(bool enable); void programEnded(); void gdbEnded(); void insertStackFrame(QString const& level, QString const& info); void stackFrameChanged(int level); void stackFrameSelected(); void insertThread(int number, bool active); void threadSelected(int thread); void showIO(bool show); void addOutputText(QString const& text); void addErrorText(QString const& text); void clearMarks(); void handleEsc(QEvent *e); protected: bool eventFilter(QObject *obj, QEvent *ev) Q_DECL_OVERRIDE; private: QString currentWord(); KTextEditor::Application *m_kateApplication; KTextEditor::MainWindow *m_mainWin; QWidget* m_toolView; QWidget* m_localsStackToolView; QTabWidget* m_tabWidget; QTextEdit* m_outputArea; KHistoryComboBox* m_inputArea; QWidget* m_gdbPage; QComboBox* m_threadCombo; int m_activeThread; QTreeWidget* m_stackTree; QString m_lastCommand; DebugView* m_debugView; ConfigView* m_configView; IOView* m_ioView; LocalsView* m_localsView; QPointer m_menu; QAction* m_breakpoint; QUrl m_lastExecUrl; int m_lastExecLine; int m_lastExecFrame; bool m_focusOnInput; }; #endif diff --git a/addons/kate-ctags/ctagskinds.cpp b/addons/kate-ctags/ctagskinds.cpp index 8d7659280..d53fd4a68 100644 --- a/addons/kate-ctags/ctagskinds.cpp +++ b/addons/kate-ctags/ctagskinds.cpp @@ -1,305 +1,305 @@ /*************************************************************************** * Copyright (C) 2001-2002 by Bernd Gehrmann * * bernd@kdevelop.org * * * * 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 "ctagskinds.h" #include struct CTagsKindMapping { char abbrev; const char *verbose; }; struct CTagsExtensionMapping { const char *extension; CTagsKindMapping *kinds; }; static CTagsKindMapping kindMappingAsm[] = { { 'd', I18N_NOOP2("Tag Type", "define") }, { 'l', I18N_NOOP2("Tag Type", "label") }, { 'm', I18N_NOOP2("Tag Type", "macro") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingAsp[] = { { 'f', I18N_NOOP2("Tag Type", "function") }, { 's', I18N_NOOP2("Tag Type", "subroutine") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingAwk[] = { { 'f', I18N_NOOP2("Tag Type", "function") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingBeta[] = { { 'f', I18N_NOOP2("Tag Type", "fragment definition") }, { 'p', I18N_NOOP2("Tag Type", "any pattern") }, { 's', I18N_NOOP2("Tag Type", "slot") }, { 'v', I18N_NOOP2("Tag Type", "pattern") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingC[] = { { 'c', I18N_NOOP2("Tag Type", "class") }, { 'd', I18N_NOOP2("Tag Type", "macro") }, { 'e', I18N_NOOP2("Tag Type", "enumerator") }, { 'f', I18N_NOOP2("Tag Type", "function") }, { 'g', I18N_NOOP2("Tag Type", "enumeration") }, { 'm', I18N_NOOP2("Tag Type", "member") }, { 'n', I18N_NOOP2("Tag Type", "namespace") }, { 'p', I18N_NOOP2("Tag Type", "prototype") }, { 's', I18N_NOOP2("Tag Type", "struct") }, { 't', I18N_NOOP2("Tag Type", "typedef") }, { 'u', I18N_NOOP2("Tag Type", "union") }, { 'v', I18N_NOOP2("Tag Type", "variable") }, { 'x', I18N_NOOP2("Tag Type", "external variable") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingCobol[] = { { 'p', I18N_NOOP2("Tag Type", "paragraph") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingEiffel[] = { { 'c', I18N_NOOP2("Tag Type", "class") }, { 'f', I18N_NOOP2("Tag Type", "feature") }, { 'l', I18N_NOOP2("Tag Type", "local entity") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingFortran[] = { { 'b', I18N_NOOP2("Tag Type", "block") }, { 'c', I18N_NOOP2("Tag Type", "common") }, { 'e', I18N_NOOP2("Tag Type", "entry") }, { 'f', I18N_NOOP2("Tag Type", "function") }, { 'i', I18N_NOOP2("Tag Type", "interface") }, { 'k', I18N_NOOP2("Tag Type", "type component") }, { 'l', I18N_NOOP2("Tag Type", "label") }, { 'L', I18N_NOOP2("Tag Type", "local") }, { 'm', I18N_NOOP2("Tag Type", "module") }, { 'n', I18N_NOOP2("Tag Type", "namelist") }, { 'p', I18N_NOOP2("Tag Type", "program") }, { 's', I18N_NOOP2("Tag Type", "subroutine") }, { 't', I18N_NOOP2("Tag Type", "type") }, { 'v', I18N_NOOP2("Tag Type", "variable") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingJava[] = { { 'c', I18N_NOOP2("Tag Type", "class") }, { 'f', I18N_NOOP2("Tag Type", "field") }, { 'i', I18N_NOOP2("Tag Type", "interface") }, { 'm', I18N_NOOP2("Tag Type", "method") }, { 'p', I18N_NOOP2("Tag Type", "package") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingLisp[] = { { 'f', I18N_NOOP2("Tag Type", "function") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingMake[] = { { 'm', I18N_NOOP2("Tag Type", "macro") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingPascal[] = { { 'f', I18N_NOOP2("Tag Type", "function") }, { 'p', I18N_NOOP2("Tag Type", "procedure") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingPerl[] = { { 's', I18N_NOOP2("Tag Type", "subroutine") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingPHP[] = { { 'c', I18N_NOOP2("Tag Type", "class") }, { 'f', I18N_NOOP2("Tag Type", "function") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingPython[] = { { 'c', I18N_NOOP2("Tag Type", "class") }, { 'f', I18N_NOOP2("Tag Type", "function") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingRexx[] = { { 's', I18N_NOOP2("Tag Type", "subroutine") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingRuby[] = { { 'c', I18N_NOOP2("Tag Type", "class") }, { 'f', I18N_NOOP2("Tag Type", "function") }, { 'm', I18N_NOOP2("Tag Type", "mixin") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingScheme[] = { { 'f', I18N_NOOP2("Tag Type", "function") }, { 's', I18N_NOOP2("Tag Type", "set") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingSh[] = { { 'f', I18N_NOOP2("Tag Type", "function") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingSlang[] = { { 'f', I18N_NOOP2("Tag Type", "function") }, { 'n', I18N_NOOP2("Tag Type", "namespace") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingTcl[] = { { 'p', I18N_NOOP2("Tag Type", "procedure") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsKindMapping kindMappingVim[] = { { 'f', I18N_NOOP2("Tag Type", "function") }, - { 0 , 0 } + { 0 , nullptr } }; static CTagsExtensionMapping extensionMapping[] = { { "asm", kindMappingAsm }, { "s", kindMappingAsm }, { "S", kindMappingAsm }, { "asp", kindMappingAsp }, { "asa", kindMappingAsp }, { "awk", kindMappingAwk }, { "c++", kindMappingC }, { "cc", kindMappingC }, { "cp" , kindMappingC }, { "cpp", kindMappingC }, { "cxx", kindMappingC }, { "h" , kindMappingC }, { "h++", kindMappingC }, { "hh" , kindMappingC }, { "hp" , kindMappingC }, { "hpp", kindMappingC }, { "hxx", kindMappingC }, { "beta", kindMappingBeta }, { "cob", kindMappingCobol }, { "COB", kindMappingCobol }, { "e", kindMappingEiffel }, { "f" , kindMappingFortran }, { "for" , kindMappingFortran }, { "ftn" , kindMappingFortran }, { "f77" , kindMappingFortran }, { "f90" , kindMappingFortran }, { "f95" , kindMappingFortran }, { "java", kindMappingJava }, { "cl", kindMappingLisp }, { "clisp", kindMappingLisp }, { "el", kindMappingLisp }, { "l", kindMappingLisp }, { "lisp", kindMappingLisp }, { "lsp", kindMappingLisp }, { "ml", kindMappingLisp }, { "mak", kindMappingMake }, { "p", kindMappingPascal }, { "pas", kindMappingPascal }, { "pl", kindMappingPerl }, { "pm", kindMappingPerl }, { "perl", kindMappingPerl }, { "php", kindMappingPHP }, { "php3", kindMappingPHP }, { "phtml", kindMappingPHP }, { "py", kindMappingPython }, { "python", kindMappingPython }, { "cmd", kindMappingRexx }, { "rexx", kindMappingRexx }, { "rx", kindMappingRexx }, { "rb", kindMappingRuby }, { "sch", kindMappingScheme }, { "scheme", kindMappingScheme }, { "scm", kindMappingScheme }, { "sm", kindMappingScheme }, { "SCM", kindMappingScheme }, { "SM", kindMappingScheme }, { "sh", kindMappingSh }, { "SH", kindMappingSh }, { "bsh", kindMappingSh }, { "bash", kindMappingSh }, { "ksh", kindMappingSh }, { "zsh", kindMappingSh }, { "sl", kindMappingSlang }, { "tcl", kindMappingTcl }, { "wish", kindMappingTcl }, { "vim", kindMappingVim }, - { 0 , 0 } + { nullptr , nullptr } }; static CTagsKindMapping *findKindMapping(const QString &extension) { const char *pextension = extension.toLocal8Bit().constData(); CTagsExtensionMapping *pem = extensionMapping; - while (pem->extension != 0) { + while (pem->extension != nullptr) { if (strcmp(pem->extension, pextension) == 0) return pem->kinds; ++pem; } - return 0; + return nullptr; } QString CTagsKinds::findKind( const char * kindChar, const QString &extension ) { - if ( kindChar == 0 ) return QString(); + if ( kindChar == nullptr ) return QString(); CTagsKindMapping *kindMapping = findKindMapping(extension); if (kindMapping) { CTagsKindMapping *pkm = kindMapping; - while (pkm->verbose != 0) { + while (pkm->verbose != nullptr) { if (pkm->abbrev == *kindChar) return i18nc("Tag Type", pkm->verbose); ++pkm; } } return QString(); } diff --git a/addons/kate-ctags/kate_ctags_plugin.cpp b/addons/kate-ctags/kate_ctags_plugin.cpp index 817cf6c85..8035abfc5 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(0) +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 0; + 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_proc, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(updateDone(int,QProcess::ExitStatus))); 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(0, i18n("Failed to run \"%1\". exitStatus = %2", command, m_proc.exitStatus())); + 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_plugin.h b/addons/kate-ctags/kate_ctags_plugin.h index 5d9b6eea1..16bd3e5cb 100644 --- a/addons/kate-ctags/kate_ctags_plugin.h +++ b/addons/kate-ctags/kate_ctags_plugin.h @@ -1,85 +1,85 @@ #ifndef KATE_CTAGS_PLUGIN_H #define KATE_CTAGS_PLUGIN_H /* 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 #include #include #include #include #include #include "kate_ctags_view.h" #include "ui_CTagsGlobalConfig.h" //******************************************************************/ class KateCTagsPlugin : public KTextEditor::Plugin { Q_OBJECT public: - explicit KateCTagsPlugin(QObject* parent = 0, const QList & = QList()); + explicit KateCTagsPlugin(QObject* parent = nullptr, const QList & = QList()); virtual ~KateCTagsPlugin() {} QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; int configPages() const Q_DECL_OVERRIDE { return 1; }; - KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = 0) Q_DECL_OVERRIDE; + KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = nullptr) Q_DECL_OVERRIDE; void readConfig(); KateCTagsView *m_view; }; //******************************************************************/ class KateCTagsConfigPage : public KTextEditor::ConfigPage { Q_OBJECT public: - explicit KateCTagsConfigPage( QWidget* parent = 0, KateCTagsPlugin *plugin = 0 ); + explicit KateCTagsConfigPage( QWidget* parent = nullptr, KateCTagsPlugin *plugin = nullptr ); ~KateCTagsConfigPage() {} QString name() const Q_DECL_OVERRIDE; QString fullName() const Q_DECL_OVERRIDE; QIcon icon() const Q_DECL_OVERRIDE; void apply() Q_DECL_OVERRIDE; void reset() Q_DECL_OVERRIDE; void defaults() Q_DECL_OVERRIDE {} private Q_SLOTS: void addGlobalTagTarget(); void delGlobalTagTarget(); void updateGlobalDB(); void updateDone(int exitCode, QProcess::ExitStatus status); private: bool listContains(const QString &target); QProcess m_proc; KateCTagsPlugin *m_plugin; Ui_CTagsGlobalConfig m_confUi; }; #endif diff --git a/addons/kate-ctags/kate_ctags_view.cpp b/addons/kate-ctags/kate_ctags_view.cpp index ce1fe0e58..c08b2fc14 100644 --- a/addons/kate-ctags/kate_ctags_view.cpp +++ b/addons/kate-ctags/kate_ctags_view.cpp @@ -1,615 +1,615 @@ /* 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(0) +, 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())); QAction *decl = actionCollection()->addAction(QLatin1String("ctags_lookup_current_as_declaration")); decl->setText(i18n("Go to Declaration")); connect(decl, SIGNAL(triggered(bool)), this, SLOT(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())); QAction *lookup = actionCollection()->addAction(QLatin1String("ctags_lookup_current")); lookup->setText(i18n("Lookup Current Text")); connect(lookup, SIGNAL(triggered(bool)), this, SLOT(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())); 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.inputEdit, SIGNAL(textChanged(QString)), this, SLOT(startEditTmr())); m_editTimer.setSingleShot(true); connect(&m_editTimer, SIGNAL(timeout()), this, SLOT(editLookUp())); connect(m_ctagsUi.tagTreeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SLOT(tagHitClicked(QTreeWidgetItem*))); connect(m_mWin, SIGNAL(unhandledShortcutOverride(QEvent*)), this, SLOT(handleEsc(QEvent*))); 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(0, i18n("No folders or files to index")); + 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(0, i18n("Failed to run \"%1\". exitStatus = %2", command, m_proc.exitStatus())); + 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 0efbe8a2f..3422c369d 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 Q_DECL_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 Q_DECL_OVERRIDE { if (!index.isValid()) { - return 0; + 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())); 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/SelectTargetView.h b/addons/katebuild-plugin/SelectTargetView.h index fcf8492fb..0ca1f5b82 100644 --- a/addons/katebuild-plugin/SelectTargetView.h +++ b/addons/katebuild-plugin/SelectTargetView.h @@ -1,47 +1,47 @@ /*************************************************************************** * 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. * ***************************************************************************/ #ifndef SelectTargetView_H #define SelectTargetView_H #include "ui_SelectTargetUi.h" #include class TargetFilterProxyModel; class SelectTargetView : public QDialog, public Ui::SelectTargetUi { Q_OBJECT public: - SelectTargetView(QAbstractItemModel *model, QWidget *parent = 0); + SelectTargetView(QAbstractItemModel *model, QWidget *parent = nullptr); const QModelIndex currentIndex() const; void setCurrentIndex(const QModelIndex &index); public Q_SLOTS: void setFilter(const QString &filter); protected: bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; private: TargetFilterProxyModel *m_proxyModel; }; #endif diff --git a/addons/katebuild-plugin/TargetModel.cpp b/addons/katebuild-plugin/TargetModel.cpp index c5fc124a3..d352b2616 100644 --- a/addons/katebuild-plugin/TargetModel.cpp +++ b/addons/katebuild-plugin/TargetModel.cpp @@ -1,466 +1,466 @@ /*************************************************************************** * 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 "TargetModel.h" #include #include #include TargetModel::TargetSet::TargetSet(const QString &_name, const QString &_dir) : name(_name) , workDir(_dir) { } // Model data // parent is the m_targets list index or InvalidIndex if it is a root element // row is the m_targets.commands list index or m_targets index if it is a root element // column 0 is command name or target-set name if it is a root element // column 1 is the command or working directory if it is a root element TargetModel::TargetModel(QObject *parent):QAbstractItemModel(parent) {} TargetModel::~TargetModel() {} void TargetModel::clear() { m_targets.clear(); } void TargetModel::setDefaultCmd(int rootRow, const QString &defCmd) { if (rootRow < 0 || rootRow >= m_targets.size()) { qDebug() << "rootRow not valid"; return; } for (int i=0; i= m_targets.size()) { qDebug() << "rootRow not valid"; return QModelIndex(); } // make the name unique QString newName = cmdName; for (int i=0; i(newName, command); endInsertRows(); return createIndex(m_targets[rootRow].commands.size()-1, 0, rootRow); } QModelIndex TargetModel::copyTargetOrSet(const QModelIndex &index) { if (!index.isValid()) return QModelIndex(); quint32 rootRow = index.internalId(); if (rootRow == InvalidIndex) { rootRow = index.row(); if (m_targets.count() <= (int)rootRow) return QModelIndex(); beginInsertRows(QModelIndex(), m_targets.count(), m_targets.count()); QString newName = m_targets[rootRow].name + QStringLiteral(" 2"); for (int i=0; i= m_targets[rootRow].commands.count()) return QModelIndex(); QModelIndex rootIndex = createIndex(rootRow, 0, InvalidIndex); beginInsertRows(rootIndex, m_targets[rootRow].commands.count(), m_targets[rootRow].commands.count()); QString newName = m_targets[rootRow].commands[index.row()].first + QStringLiteral(" 2"); for (int i=0; i(newName, m_targets[rootRow].commands[index.row()].second); endInsertRows(); return createIndex(m_targets[rootRow].commands.count()-1, 0, rootRow); } QModelIndex TargetModel::defaultTarget(const QModelIndex &index) { int targetRow = 0; if (index.isValid()) { if (index.internalId() == InvalidIndex) { targetRow = index.row(); } else { targetRow = index.internalId(); } } return createIndex(0, 0, targetRow); } void TargetModel::deleteItem(const QModelIndex &index) { if (!index.isValid()) { return; } if (index.internalId() == InvalidIndex) { beginRemoveRows(index.parent(), index.row(), index.row()); m_targets.removeAt(index.row()); endRemoveRows(); } else if (index.internalId() < (quint64)m_targets.size() && m_targets[(int)index.internalId()].commands.count() > index.row()) { beginRemoveRows(index.parent(), index.row(), index.row()); m_targets[(int)index.internalId()].commands.removeAt(index.row()); endRemoveRows(); } } void TargetModel::deleteTargetSet(const QString &targetSet) { for (int i=0; i= m_targets.count()) { return QString(); } if (cRow < 0 || cRow >= m_targets[(int)rRow].commands.count()) { return QString(); } return m_targets[rRow].commands[cRow].second; } const QString TargetModel::cmdName(const QModelIndex &itemIndex) const { if (!itemIndex.isValid()) { return QString(); } quint32 rRow = itemIndex.internalId(); int cRow = itemIndex.row(); if (rRow == TargetModel::InvalidIndex) { rRow = cRow; cRow = 0; } if ((int)rRow >= m_targets.count()) { return QString(); } if (cRow < 0 || cRow >= m_targets[(int)rRow].commands.count()) { return QString(); } return m_targets[(int)rRow].commands[cRow].first; } const QString TargetModel::workDir(const QModelIndex &itemIndex) const { if (!itemIndex.isValid()) { return QString(); } quint32 rRow = itemIndex.internalId(); int cRow = itemIndex.row(); if (rRow == TargetModel::InvalidIndex) { rRow = cRow; cRow = 0; } if ((int)rRow >= m_targets.count()) { return QString(); } return m_targets[(int)rRow].workDir; } const QString TargetModel::targetName(const QModelIndex &itemIndex) const { if (!itemIndex.isValid()) { return QString(); } quint32 rRow = itemIndex.internalId(); int cRow = itemIndex.row(); if (rRow == TargetModel::InvalidIndex) { rRow = cRow; cRow = 0; } if ((int)rRow >= m_targets.count()) { return QString(); } return m_targets[(int)rRow].name; } QVariant TargetModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.column() < 0 || index.column() > 1) { return QVariant(); } // Tooltip if (role == Qt::ToolTipRole) { if (index.column() == 0 && index.parent().isValid()) { return i18n("Check the check-box to make the command the default for the target-set."); } } if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::CheckStateRole) { return QVariant(); } int row = index.row(); if (index.internalId() == InvalidIndex) { if (row < 0 || row >= m_targets.size() || role == Qt::CheckStateRole) { return QVariant(); } switch (index.column()) { case 0: return m_targets[row].name; case 1: return m_targets[row].workDir; } } else { int rootIndex = index.internalId(); if (rootIndex < 0 || rootIndex >= m_targets.size()) { return QVariant(); } if (row < 0 || row >= m_targets[rootIndex].commands.size()) { return QVariant(); } if (role == Qt::CheckStateRole) { if (index.column() != 0) { return QVariant(); } return m_targets[rootIndex].commands[row].first == m_targets[rootIndex].defaultCmd ? Qt::Checked : Qt::Unchecked; } else { switch (index.column()) { case 0: return m_targets[rootIndex].commands[row].first; case 1: return m_targets[rootIndex].commands[row].second; } } } return QVariant(); } QVariant TargetModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { return QVariant(); } if (orientation != Qt::Horizontal) { return QVariant(); } if (section == 0) { return i18n("Command/Target-set Name"); } if (section == 1) { return i18n("Working Directory / Command"); } return QVariant(); } bool TargetModel::setData(const QModelIndex &index, const QVariant &value, int role) { // FIXME if (role != Qt::EditRole && role != Qt::CheckStateRole) return false; if (!index.isValid()) return false; if (index.column() < 0 || index.column() > 1) return false; int row = index.row(); if (index.internalId() == InvalidIndex) { if (row < 0 || row >= m_targets.size()) { return false; } switch (index.column()) { case 0: m_targets[row].name = value.toString(); return true; case 1: m_targets[row].workDir = value.toString(); return true; } } else { int rootIndex = index.internalId(); if (rootIndex < 0 || rootIndex >= m_targets.size()) { return false; } if (row < 0 || row >= m_targets[rootIndex].commands.size()) { return false; } if (role == Qt::CheckStateRole) { if (index.column() == 0) { m_targets[rootIndex].defaultCmd = m_targets[rootIndex].commands[row].first; emit dataChanged(createIndex(0, 0, rootIndex), createIndex(m_targets[rootIndex].commands.size()-1, 0, rootIndex)); } } else { switch (index.column()) { case 0: m_targets[rootIndex].commands[row].first = value.toString(); return true; case 1: m_targets[rootIndex].commands[row].second = value.toString(); return true; } } } return false; } Qt::ItemFlags TargetModel::flags(const QModelIndex &index) const { if (!index.isValid()) { - return 0; + return nullptr; } if (index.internalId() != InvalidIndex && index.column() == 0) { return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable; } return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } int TargetModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) { return m_targets.size(); } if (parent.internalId() != InvalidIndex) { return 0; } int row = parent.row(); if (row < 0 || row >= m_targets.size()) { return 0; } return m_targets[row].commands.size(); } int TargetModel::columnCount(const QModelIndex &) const { return 2; } QModelIndex TargetModel::index(int row, int column, const QModelIndex &parent) const { quint32 rootIndex = InvalidIndex; if (parent.isValid()) { if (parent.internalId() == InvalidIndex) { rootIndex = parent.row(); } } return createIndex(row, column, rootIndex); } QModelIndex TargetModel::parent(const QModelIndex &child) const { if (child.internalId() == InvalidIndex) return QModelIndex(); return createIndex(child.internalId(), 0, InvalidIndex); } diff --git a/addons/katebuild-plugin/TargetModel.h b/addons/katebuild-plugin/TargetModel.h index fce553f75..b0eebfa58 100644 --- a/addons/katebuild-plugin/TargetModel.h +++ b/addons/katebuild-plugin/TargetModel.h @@ -1,97 +1,97 @@ /*************************************************************************** * 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. * ***************************************************************************/ #ifndef TargetModel_h #define TargetModel_h #include #include class TargetModel : public QAbstractItemModel { Q_OBJECT public: struct TargetSet { TargetSet(const QString &_name, const QString &_workDir); QString name; QString workDir; QString defaultCmd; QList > commands; }; - TargetModel(QObject *parent = 0); + TargetModel(QObject *parent = nullptr); ~TargetModel(); /** This function sets the default command for a target set */ void setDefaultCmd(int rootRow, const QString &defCmd); public Q_SLOTS: /** This function clears all the target-sets */ void clear(); /** This function adds a target set and returns the row number of the newly * inserted row */ int addTargetSet(const QString &setName, const QString &workDir); /** This function adds a new command to a target-set and returns the model index */ QModelIndex addCommand(int rootRow, const QString &cmdName, const QString &command); /** This function copies the target(-set) the model index points to and returns * the model index of the copy. */ QModelIndex copyTargetOrSet(const QModelIndex &index); /** This function returns the model index of the default command of the target-set */ QModelIndex defaultTarget(const QModelIndex &index); /** This function deletes the index */ void deleteItem(const QModelIndex &index); /** This function deletes the target-set with the same name */ void deleteTargetSet(const QString &targetSet); const QList targetSets() const { return m_targets; } const QString command(const QModelIndex &itemIndex) const; const QString cmdName(const QModelIndex &itemIndex) const; const QString workDir(const QModelIndex &itemIndex) const; const QString targetName(const QModelIndex &itemIndex) const; Q_SIGNALS: public: static const quint32 InvalidIndex = 0xFFFFFFFF; // Model-View model functions QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole) Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; private: QList m_targets; }; #endif diff --git a/addons/katebuild-plugin/plugin_katebuild.cpp b/addons/katebuild-plugin/plugin_katebuild.cpp index d085d2e82..0254b4e59 100644 --- a/addons/katebuild-plugin/plugin_katebuild.cpp +++ b/addons/katebuild-plugin/plugin_katebuild.cpp @@ -1,1042 +1,1042 @@ /* 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(0) + , 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())); a = actionCollection()->addAction(QStringLiteral("build_default_target")); a->setText(i18n("Build Default Target")); connect(a, SIGNAL(triggered(bool)), this, SLOT(slotBuildDefaultTarget())); a = actionCollection()->addAction(QStringLiteral("build_previous_target")); a->setText(i18n("Build Previous Target")); connect(a, SIGNAL(triggered(bool)), this, SLOT(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())); 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())); 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())); 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*))); m_buildUi.plainTextEdit->setReadOnly(true); slotDisplayMode(FullOutput); connect(m_buildUi.displayModeSlider, SIGNAL(valueChanged(int)), this, SLOT(slotDisplayMode(int))); 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_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->addButton, SIGNAL(clicked()), this, SLOT(slotAddTargetClicked())); connect(m_targetsUi->buildButton, SIGNAL(clicked()), this, SLOT(slotBuildActiveTarget())); connect(m_targetsUi, SIGNAL(enterPressed()), this, SLOT(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_win, SIGNAL(unhandledShortcutOverride(QEvent*)), this, SLOT(handleEsc(QEvent*))); 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 *))); // 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 = 0; + if (item && item->isHidden()) item = nullptr; - int i = (item == 0) ? -1 : m_buildUi.errTreeWidget->indexOfTopLevelItem(item); + 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 = 0; + if (item && item->isHidden()) item = nullptr; - int i = (item == 0) ? itemCount : m_buildUi.errTreeWidget->indexOfTopLevelItem(item); + 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(0, i18n("There is no file or directory specified for building.")); + KMessageBox::sorry(nullptr, i18n("There is no file or directory specified for building.")); return false; } else if (!dir.isLocalFile()) { - KMessageBox::sorry(0, i18n("The file \"%1\" is not a local file. " + 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(0, i18n("Failed to run \"%1\". exitStatus = %2", command, m_proc.exitStatus())); + 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 = 0; + 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(0, i18n("No target available for building.")); + 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(0, i18n("There is no local file or directory specified for building.")); + 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())); } } /******************************************************************/ void KateBuildView::slotPluginViewDeleted (const QString &name, QObject *) { // remove view if (name == QLatin1String("kateprojectplugin")) { - m_projectPluginView = 0; + 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/plugin_katebuild.h b/addons/katebuild-plugin/plugin_katebuild.h index f5cf9e623..5d73bd53b 100644 --- a/addons/katebuild-plugin/plugin_katebuild.h +++ b/addons/katebuild-plugin/plugin_katebuild.h @@ -1,182 +1,182 @@ #ifndef PLUGIN_KATEBUILD_H #define PLUGIN_KATEBUILD_H /* plugin_katebuild.h Kate Plugin ** ** Copyright (C) 2008-2015 by Kåre Särs ** ** This code is almost a total rewrite 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_build.h" #include "targets.h" /******************************************************************/ class KateBuildView : public QObject, public KXMLGUIClient, public KTextEditor::SessionConfigInterface { Q_OBJECT Q_INTERFACES(KTextEditor::SessionConfigInterface) Q_PROPERTY(QUrl docUrl READ docUrl) public: enum ResultDetails { FullOutput, ParsedOutput, ErrorsAndWarnings, OnlyErrors }; enum TreeWidgetRoles { ErrorRole = Qt::UserRole+1 }; enum ErrorCategory { CategoryInfo, CategoryWarning, CategoryError }; KateBuildView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mw); ~KateBuildView(); // reimplemented: read and write session config void readSessionConfig(const KConfigGroup& config) Q_DECL_OVERRIDE; void writeSessionConfig(KConfigGroup& config) Q_DECL_OVERRIDE; bool buildCurrentTarget(); QUrl docUrl(); private Q_SLOTS: // Building void slotSelectTarget(); void slotBuildActiveTarget(); void slotBuildPreviousTarget(); void slotBuildDefaultTarget(); bool slotStop(); // Parse output void slotProcExited(int exitCode, QProcess::ExitStatus exitStatus); void slotReadReadyStdErr(); void slotReadReadyStdOut(); // Selecting warnings/errors void slotNext(); void slotPrev(); void slotErrorSelected(QTreeWidgetItem *item); // Settings void targetSetNew(); void targetOrSetCopy(); void targetDelete(); void slotAddTargetClicked(); void slotDisplayMode(int mode); void handleEsc(QEvent *e); /** * keep track if the project plugin is alive and if the project map did change */ void slotPluginViewCreated(const QString &name, QObject *pluginView); void slotPluginViewDeleted(const QString &name, QObject *pluginView); void slotProjectMapChanged(); void slotAddProjectTarget(); protected: bool eventFilter(QObject *obj, QEvent *ev) Q_DECL_OVERRIDE; private: void processLine(const QString &); void addError(const QString &filename, const QString &line, const QString &column, const QString &message); bool startProcess(const QString &dir, const QString &command); bool checkLocal(const QUrl &dir); void clearBuildResults(); void displayBuildResult(const QString &message, KTextEditor::Message::MessageType level); KTextEditor::MainWindow *m_win; QWidget *m_toolView; Ui::build m_buildUi; QWidget *m_buildWidget; int m_outputWidgetWidth; TargetsUi *m_targetsUi; KProcess m_proc; QString m_stdOut; QString m_stdErr; QString m_currentlyBuildingTarget; bool m_buildCancelled; int m_displayModeBeforeBuild; QString m_make_dir; QStack m_make_dir_stack; QRegularExpression m_filenameDetector; QRegularExpression m_filenameDetectorIcpc; bool m_filenameDetectorGccWorked; QRegularExpression m_newDirDetector; unsigned int m_numErrors; unsigned int m_numWarnings; QString m_prevItemContent; QModelIndex m_previousIndex; QPointer m_infoMessage; /** * current project plugin view, if any */ QObject *m_projectPluginView; }; typedef QList VariantList; /******************************************************************/ class KateBuildPlugin : public KTextEditor::Plugin { Q_OBJECT public: - explicit KateBuildPlugin(QObject* parent = 0, const VariantList& = VariantList()); + explicit KateBuildPlugin(QObject* parent = nullptr, const VariantList& = VariantList()); virtual ~KateBuildPlugin() {} QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; }; #endif diff --git a/addons/katebuild-plugin/targets.h b/addons/katebuild-plugin/targets.h index 75ba6f9d1..3c6b4d976 100644 --- a/addons/katebuild-plugin/targets.h +++ b/addons/katebuild-plugin/targets.h @@ -1,66 +1,66 @@ // // 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. #ifndef TARGETS_H #define TARGETS_H #include #include #include #include #include #include #include "TargetHtmlDelegate.h" #include "TargetModel.h" class TargetsUi: public QWidget { Q_OBJECT public: - TargetsUi(QObject *view, QWidget *parent = 0); + TargetsUi(QObject *view, QWidget *parent = nullptr); QLabel *targetLabel; QComboBox *targetCombo; QToolButton *newTarget; QToolButton *copyTarget; QToolButton *deleteTarget; QTreeView *targetsView; TargetModel targetsModel; QToolButton *addButton; QToolButton *buildButton; public Q_SLOTS: void targetSetSelected(int index); void targetActivated(const QModelIndex &index); Q_SIGNALS: void enterPressed(); protected: bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; private: TargetHtmlDelegate *m_delegate; }; #endif diff --git a/addons/katesql/cachedsqlquerymodel.h b/addons/katesql/cachedsqlquerymodel.h index c95a8b6d0..95fec5040 100644 --- a/addons/katesql/cachedsqlquerymodel.h +++ b/addons/katesql/cachedsqlquerymodel.h @@ -1,51 +1,51 @@ /* 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. */ #ifndef CACHEDSQLQUERYMODEL_H #define CACHEDSQLQUERYMODEL_H #include #include #include class CachedSqlQueryModel : public QSqlQueryModel { Q_OBJECT public: - explicit CachedSqlQueryModel(QObject *parent = 0, int cacheCapacity = 1000); + explicit CachedSqlQueryModel(QObject *parent = nullptr, int cacheCapacity = 1000); QVariant data(const QModelIndex &item, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QSqlRecord record(int row) const; void clear() Q_DECL_OVERRIDE; int cacheCapacity() const; public Q_SLOTS: void clearCache(); void setCacheCapacity(int); protected: void queryChange() Q_DECL_OVERRIDE; private: void cacheRecords(int from, int to) const; mutable QContiguousCache cache; }; #endif // CACHEDSQLQUERYMODEL_H diff --git a/addons/katesql/connectionmodel.h b/addons/katesql/connectionmodel.h index eaaa42953..8fa629830 100644 --- a/addons/katesql/connectionmodel.h +++ b/addons/katesql/connectionmodel.h @@ -1,58 +1,58 @@ /* 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. */ #ifndef CONNECTIONMODEL_H #define CONNECTIONMODEL_H #include "connection.h" #include #include #include #include class ConnectionModel : public QAbstractListModel { Q_OBJECT public: - ConnectionModel(QObject *parent = 0); + ConnectionModel(QObject *parent = nullptr); virtual ~ConnectionModel(); int rowCount ( const QModelIndex & parent = QModelIndex() ) const Q_DECL_OVERRIDE; QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const Q_DECL_OVERRIDE; virtual int addConnection(Connection conn); virtual void removeConnection(const QString &name); Connection::Status status(const QString &name) const; void setStatus(const QString &name, const Connection::Status status); void setPassword(const QString &name, const QString &password); int indexOf(const QString &name); // virtual bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()); // virtual bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()); private: QHash m_connections; QHash m_icons; }; #endif // CONNECTIONMODEL_H diff --git a/addons/katesql/connectionwizard.h b/addons/katesql/connectionwizard.h index 9d90d1b5a..3bf9217c6 100644 --- a/addons/katesql/connectionwizard.h +++ b/addons/katesql/connectionwizard.h @@ -1,113 +1,113 @@ /* 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. */ #ifndef CONNECTIONWIZARD_H #define CONNECTIONWIZARD_H class SQLManager; class KComboBox; class KLineEdit; class QSpinBox; class KUrlRequester; #include "connection.h" #include #include class ConnectionWizard : public QWizard { public: enum { Page_Driver, Page_Standard_Server, Page_SQLite_Server, Page_Save }; - ConnectionWizard(SQLManager *manager, Connection *conn, QWidget *parent=0, Qt::WindowFlags flags = 0); + ConnectionWizard(SQLManager *manager, Connection *conn, QWidget *parent=nullptr, Qt::WindowFlags flags = nullptr); ~ConnectionWizard(); SQLManager *manager() { return m_manager; } Connection *connection() { return m_connection; } private: SQLManager *m_manager; Connection *m_connection; }; class ConnectionDriverPage : public QWizardPage { public: - ConnectionDriverPage(QWidget *parent=0); + ConnectionDriverPage(QWidget *parent=nullptr); void initializePage() Q_DECL_OVERRIDE; int nextId() const Q_DECL_OVERRIDE; private: KComboBox *driverComboBox; }; class ConnectionStandardServerPage : public QWizardPage { public: - ConnectionStandardServerPage(QWidget *parent=0); + ConnectionStandardServerPage(QWidget *parent=nullptr); ~ConnectionStandardServerPage(); void initializePage() Q_DECL_OVERRIDE; bool validatePage() Q_DECL_OVERRIDE; int nextId() const Q_DECL_OVERRIDE; private: KLineEdit *hostnameLineEdit; KLineEdit *usernameLineEdit; KLineEdit *passwordLineEdit; KLineEdit *databaseLineEdit; KLineEdit *optionsLineEdit; QSpinBox *portSpinBox; }; class ConnectionSQLiteServerPage : public QWizardPage { public: - ConnectionSQLiteServerPage(QWidget *parent=0); + ConnectionSQLiteServerPage(QWidget *parent=nullptr); void initializePage() Q_DECL_OVERRIDE; bool validatePage() Q_DECL_OVERRIDE; int nextId() const Q_DECL_OVERRIDE; private: // KLineEdit *pathLineEdit; KUrlRequester *pathUrlRequester; KLineEdit *optionsLineEdit; }; class ConnectionSavePage : public QWizardPage { public: - ConnectionSavePage(QWidget *parent=0); + ConnectionSavePage(QWidget *parent=nullptr); void initializePage() Q_DECL_OVERRIDE; bool validatePage() Q_DECL_OVERRIDE; int nextId() const Q_DECL_OVERRIDE; private: KLineEdit *connectionNameLineEdit; }; #endif // CONNECTIONWIZARD_H diff --git a/addons/katesql/dataoutputmodel.h b/addons/katesql/dataoutputmodel.h index 4887bde61..cbcb7f6d1 100644 --- a/addons/katesql/dataoutputmodel.h +++ b/addons/katesql/dataoutputmodel.h @@ -1,52 +1,52 @@ /* 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. */ #ifndef DATAOUTPUTMODEL_H #define DATAOUTPUTMODEL_H struct OutputStyle; #include "cachedsqlquerymodel.h" #include #include /// provide colors and styles class DataOutputModel : public CachedSqlQueryModel { Q_OBJECT public: - DataOutputModel(QObject *parent = 0); + DataOutputModel(QObject *parent = nullptr); ~DataOutputModel(); bool useSystemLocale() const; void setUseSystemLocale(bool useSystemLocale); QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const Q_DECL_OVERRIDE; void clear() Q_DECL_OVERRIDE; void readConfig(); private: QHash m_styles; bool m_useSystemLocale; }; #endif // DATAOUTPUTMODEL_H diff --git a/addons/katesql/dataoutputview.h b/addons/katesql/dataoutputview.h index f4e580a1a..42407ea1a 100644 --- a/addons/katesql/dataoutputview.h +++ b/addons/katesql/dataoutputview.h @@ -1,35 +1,35 @@ /* 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. */ #ifndef DATAOUTPUTVIEW_H #define DATAOUTPUTVIEW_H #include class DataOutputView : public QTableView { Q_OBJECT public: - DataOutputView(QWidget *parent = 0); + DataOutputView(QWidget *parent = nullptr); private Q_SLOTS: void slotCustomContextMenuRequested(const QPoint &pos); }; #endif // DATAOUTPUTVIEW_H diff --git a/addons/katesql/exportwizard.h b/addons/katesql/exportwizard.h index 831509409..8ece665ff 100644 --- a/addons/katesql/exportwizard.h +++ b/addons/katesql/exportwizard.h @@ -1,72 +1,72 @@ /* 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. */ #ifndef EXPORTWIZARD_H #define EXPORTWIZARD_H class KUrlRequester; class KLineEdit; class QRadioButton; class QCheckBox; #include class ExportWizard : public QWizard { public: ExportWizard(QWidget *parent); ~ExportWizard(); }; class ExportOutputPage : public QWizardPage { public: - ExportOutputPage(QWidget *parent=0); + ExportOutputPage(QWidget *parent=nullptr); void initializePage() Q_DECL_OVERRIDE; bool validatePage() Q_DECL_OVERRIDE; private: QRadioButton *documentRadioButton; QRadioButton *clipboardRadioButton; QRadioButton *fileRadioButton; KUrlRequester *fileUrl; }; class ExportFormatPage : public QWizardPage { public: - ExportFormatPage(QWidget *parent=0); + ExportFormatPage(QWidget *parent=nullptr); void initializePage() Q_DECL_OVERRIDE; bool validatePage() Q_DECL_OVERRIDE; private: QCheckBox *exportColumnNamesCheckBox; QCheckBox *exportLineNumbersCheckBox; QCheckBox *quoteStringsCheckBox; QCheckBox *quoteNumbersCheckBox; KLineEdit *quoteStringsLine; KLineEdit *quoteNumbersLine; KLineEdit *fieldDelimiterLine; }; #endif // EXPORTWIZARD_H diff --git a/addons/katesql/katesqlconfigpage.h b/addons/katesql/katesqlconfigpage.h index 90349fe05..194e84c5a 100644 --- a/addons/katesql/katesqlconfigpage.h +++ b/addons/katesql/katesqlconfigpage.h @@ -1,58 +1,58 @@ /* 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. */ #ifndef KATESQLCONFIGPAGE_H #define KATESQLCONFIGPAGE_H class OutputStyleWidget; class QCheckBox; #include "katesqlplugin.h" #include /// TODO: add options to change datetime and numbers format class KateSQLConfigPage : public KTextEditor::ConfigPage { Q_OBJECT public: - explicit KateSQLConfigPage( QWidget* parent = 0 ); + explicit KateSQLConfigPage( QWidget* parent = nullptr ); virtual ~KateSQLConfigPage(); QString name() const Q_DECL_OVERRIDE; QString fullName() const Q_DECL_OVERRIDE; QIcon icon() const Q_DECL_OVERRIDE; public Q_SLOTS: void apply() Q_DECL_OVERRIDE; void reset() Q_DECL_OVERRIDE; void defaults() Q_DECL_OVERRIDE; private: KateSQLPlugin *m_plugin; QCheckBox *m_box; OutputStyleWidget *m_outputStyleWidget; Q_SIGNALS: void settingsChanged(); }; #endif // KATESQLCONFIGPAGE_H diff --git a/addons/katesql/katesqlplugin.cpp b/addons/katesql/katesqlplugin.cpp index 9d2e7fe89..7dbfe300e 100644 --- a/addons/katesql/katesqlplugin.cpp +++ b/addons/katesql/katesqlplugin.cpp @@ -1,69 +1,69 @@ /* 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())); return view; } KTextEditor::ConfigPage* KateSQLPlugin::configPage(int number, QWidget *parent) { if (number != 0) - return 0; + return nullptr; KateSQLConfigPage *page = new KateSQLConfigPage(parent); connect(page, SIGNAL(settingsChanged()), this, SIGNAL(globalSettingsChanged())); return page; } //END KateSQLPlugin #include "katesqlplugin.moc" diff --git a/addons/katesql/katesqlplugin.h b/addons/katesql/katesqlplugin.h index 34167a8ff..24f8b3e34 100644 --- a/addons/katesql/katesqlplugin.h +++ b/addons/katesql/katesqlplugin.h @@ -1,51 +1,51 @@ /* 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. */ #ifndef KATESQLPLUGIN_H #define KATESQLPLUGIN_H #include #include #include #include #include class KateSQLPlugin : public KTextEditor::Plugin { Q_OBJECT public: - explicit KateSQLPlugin(QObject* parent = 0, const QList& = QList()); + explicit KateSQLPlugin(QObject* parent = nullptr, const QList& = QList()); virtual ~KateSQLPlugin(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; int configPages() const Q_DECL_OVERRIDE { return 1; }; - KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = 0) Q_DECL_OVERRIDE; + KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = nullptr) Q_DECL_OVERRIDE; QString configPageName (int number = 0) const; QString configPageFullName (int number = 0) const; QIcon configPageIcon (int number = 0) const; Q_SIGNALS: void globalSettingsChanged(); }; #endif // KATESQLPLUGIN_H diff --git a/addons/katesql/outputstylewidget.h b/addons/katesql/outputstylewidget.h index c1f7ce75d..14f1bd7ab 100644 --- a/addons/katesql/outputstylewidget.h +++ b/addons/katesql/outputstylewidget.h @@ -1,50 +1,50 @@ /* 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. */ #ifndef OUTPUTSTYLEWIDGET_H #define OUTPUTSTYLEWIDGET_H #include class OutputStyleWidget : public QTreeWidget { Q_OBJECT public: - OutputStyleWidget(QWidget *parent = 0); + OutputStyleWidget(QWidget *parent = nullptr); ~OutputStyleWidget(); QTreeWidgetItem* addContext(const QString &key, const QString &name); public Q_SLOTS: void readConfig(); void writeConfig(); protected Q_SLOTS: void slotChanged(); void updatePreviews(); void readConfig(QTreeWidgetItem *item); void writeConfig(QTreeWidgetItem *item); Q_SIGNALS: void changed(); }; #endif // OUTPUTSTYLEWIDGET_H diff --git a/addons/katesql/sqlmanager.cpp b/addons/katesql/sqlmanager.cpp index a4dbb2642..0be570946 100644 --- a/addons/katesql/sqlmanager.cpp +++ b/addons/katesql/sqlmanager.cpp @@ -1,391 +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 "sqlmanager.h" #include "connectionmodel.h" #include #include #include #include #include #include #include #include using KWallet::Wallet; SQLManager::SQLManager(QObject *parent) : QObject(parent) , m_model(new ConnectionModel(this)) -, m_wallet(0) +, m_wallet(nullptr) { } SQLManager::~SQLManager() { for(int i = 0; i < m_model->rowCount(); i++) { QString connection =m_model->data(m_model->index(i), Qt::DisplayRole).toString(); QSqlDatabase::removeDatabase(connection); } delete m_model; delete m_wallet; } void SQLManager::createConnection(const Connection &conn) { if (QSqlDatabase::contains(conn.name)) { qDebug() << "connection" << conn.name << "already exist"; QSqlDatabase::removeDatabase(conn.name); } QSqlDatabase db = QSqlDatabase::addDatabase(conn.driver, conn.name); if (!db.isValid()) { emit error(db.lastError().text()); QSqlDatabase::removeDatabase(conn.name); return; } db.setHostName(conn.hostname); db.setUserName(conn.username); db.setPassword(conn.password); db.setDatabaseName(conn.database); db.setConnectOptions(conn.options); if (conn.port > 0) db.setPort(conn.port); m_model->addConnection(conn); // try to open connection, with or without password if (db.open()) m_model->setStatus(conn.name, Connection::ONLINE); else { if (conn.status != Connection::REQUIRE_PASSWORD) { m_model->setStatus(conn.name, Connection::OFFLINE); emit error(db.lastError().text()); } } emit connectionCreated(conn.name); } bool SQLManager::testConnection(const Connection &conn, QSqlError &error) { QString connectionName = (conn.name.isEmpty()) ? QString::fromLatin1 ("katesql-test") : conn.name; QSqlDatabase db = QSqlDatabase::addDatabase(conn.driver, connectionName); if (!db.isValid()) { error = db.lastError(); QSqlDatabase::removeDatabase(connectionName); return false; } db.setHostName(conn.hostname); db.setUserName(conn.username); db.setPassword(conn.password); db.setDatabaseName(conn.database); db.setConnectOptions(conn.options); if (conn.port > 0) db.setPort(conn.port); if (!db.open()) { error = db.lastError(); QSqlDatabase::removeDatabase(connectionName); return false; } QSqlDatabase::removeDatabase(connectionName); return true; } bool SQLManager::isValidAndOpen(const QString &connection) { QSqlDatabase db = QSqlDatabase::database(connection); if (!db.isValid()) { m_model->setStatus(connection, Connection::OFFLINE); emit error(db.lastError().text()); return false; } if (!db.isOpen()) { qDebug() << "database connection is not open. trying to open it..."; if (m_model->status(connection) == Connection::REQUIRE_PASSWORD) { QString password; int ret = readCredentials(connection, password); if (ret != 0) qDebug() << "Can't retrieve password from kwallet. returned code" << ret; else { db.setPassword(password); m_model->setPassword(connection, password); } } if (!db.open()) { m_model->setStatus(connection, Connection::OFFLINE); emit error(db.lastError().text()); return false; } } m_model->setStatus(connection, Connection::ONLINE); return true; } void SQLManager::reopenConnection (const QString& name) { emit connectionAboutToBeClosed(name); QSqlDatabase db = QSqlDatabase::database(name); db.close(); isValidAndOpen(name); } Wallet *SQLManager::openWallet() { if (!m_wallet) /// FIXME get kate window id... m_wallet = Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0); if (!m_wallet) - return 0; + return nullptr; QString folder (QLatin1String ("SQL Connections")); if (!m_wallet->hasFolder(folder)) m_wallet->createFolder(folder); m_wallet->setFolder(folder); return m_wallet; } // return 0 on success, -1 on error, -2 on user reject int SQLManager::storeCredentials(const Connection &conn) { // Sqlite is without password, avoid to open wallet if (conn.driver.contains(QLatin1String ("QSQLITE"))) return 0; Wallet *wallet = openWallet(); if (!wallet) // user reject return -2; QMap map; map[QLatin1String ("driver")] = conn.driver.toUpper(); map[QLatin1String ("hostname")] = conn.hostname.toUpper(); map[QLatin1String ("port")] = QString::number(conn.port); map[QLatin1String ("database")] = conn.database.toUpper(); map[QLatin1String ("username")] = conn.username; map[QLatin1String ("password")] = conn.password; return (wallet->writeMap(conn.name, map) == 0) ? 0 : -1; } // return 0 on success, -1 on error or not found, -2 on user reject // if success, password contain the password int SQLManager::readCredentials(const QString &name, QString &password) { Wallet *wallet = openWallet(); if (!wallet) // user reject return -2; QMap map; if (wallet->readMap(name, map) == 0) { if (!map.isEmpty()) { password = map.value(QLatin1String("password")); return 0; } } return -1; } ConnectionModel* SQLManager::connectionModel() { return m_model; } void SQLManager::removeConnection(const QString &name) { emit connectionAboutToBeClosed(name); m_model->removeConnection(name); QSqlDatabase::removeDatabase(name); emit connectionRemoved(name); } /// TODO: read KUrl instead of QString for sqlite paths void SQLManager::loadConnections(KConfigGroup *connectionsGroup) { Connection c; foreach ( const QString& groupName, connectionsGroup->groupList() ) { qDebug() << "reading group:" << groupName; KConfigGroup group = connectionsGroup->group(groupName); c.name = groupName; c.driver = group.readEntry("driver"); c.database = group.readEntry("database"); c.options = group.readEntry("options"); if (!c.driver.contains(QLatin1String("QSQLITE"))) { c.hostname = group.readEntry("hostname"); c.username = group.readEntry("username"); c.port = group.readEntry("port", 0); // for compatibility with version 0.2, when passwords // were stored in config file instead of kwallet c.password = group.readEntry("password"); if (!c.password.isEmpty()) c.status = Connection::ONLINE; else c.status = Connection::REQUIRE_PASSWORD; } createConnection(c); } } void SQLManager::saveConnections(KConfigGroup *connectionsGroup) { for(int i = 0; i < m_model->rowCount(); i++) saveConnection(connectionsGroup, m_model->data(m_model->index(i), Qt::UserRole).value()); } /// TODO: write KUrl instead of QString for sqlite paths void SQLManager::saveConnection(KConfigGroup *connectionsGroup, const Connection &conn) { qDebug() << "saving connection" << conn.name; KConfigGroup group = connectionsGroup->group(conn.name); group.writeEntry("driver" , conn.driver); group.writeEntry("database", conn.database); group.writeEntry("options" , conn.options); if (!conn.driver.contains(QLatin1String("QSQLITE"))) { group.writeEntry("hostname", conn.hostname); group.writeEntry("username", conn.username); group.writeEntry("port" , conn.port); } } void SQLManager::runQuery(const QString &text, const QString &connection) { qDebug() << "connection:" << connection; qDebug() << "text:" << text; if (text.isEmpty()) return; if (!isValidAndOpen(connection)) return; QSqlDatabase db = QSqlDatabase::database(connection); QSqlQuery query(db); if (!query.prepare(text)) { QSqlError err = query.lastError(); if (err.type() == QSqlError::ConnectionError) m_model->setStatus(connection, Connection::OFFLINE); emit error(err.text()); return; } if (!query.exec()) { QSqlError err = query.lastError(); if (err.type() == QSqlError::ConnectionError) m_model->setStatus(connection, Connection::OFFLINE); emit error(err.text()); return; } QString message; /// TODO: improve messages if (query.isSelect()) { if (!query.driver()->hasFeature(QSqlDriver::QuerySize)) message = i18nc("@info", "Query completed successfully"); else { int nRowsSelected = query.size(); message = i18ncp("@info", "%1 record selected", "%1 records selected", nRowsSelected); } } else { int nRowsAffected = query.numRowsAffected(); message = i18ncp("@info", "%1 row affected", "%1 rows affected", nRowsAffected); } emit success(message); emit queryActivated(query, connection); } diff --git a/addons/katesql/sqlmanager.h b/addons/katesql/sqlmanager.h index 4e8b5f587..da46c31f3 100644 --- a/addons/katesql/sqlmanager.h +++ b/addons/katesql/sqlmanager.h @@ -1,71 +1,71 @@ /* 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. */ #ifndef SQLMANAGER_H #define SQLMANAGER_H class ConnectionModel; class KConfigGroup; #include "connection.h" #include #include class SQLManager : public QObject { Q_OBJECT public: - SQLManager(QObject *parent = 0); + SQLManager(QObject *parent = nullptr); ~SQLManager(); ConnectionModel *connectionModel(); void createConnection(const Connection &conn); bool testConnection(const Connection &conn, QSqlError &error); bool isValidAndOpen(const QString &connection); KWallet::Wallet * openWallet(); int storeCredentials(const Connection &conn); int readCredentials(const QString &name, QString &password); public Q_SLOTS: void removeConnection(const QString &name); void reopenConnection(const QString &name); void loadConnections(KConfigGroup *connectionsGroup); void saveConnections(KConfigGroup *connectionsGroup); void runQuery(const QString &text, const QString &connection ); protected: void saveConnection(KConfigGroup *connectionsGroup, const Connection &conn); Q_SIGNALS: void connectionCreated(const QString &name); void connectionRemoved(const QString &name); void connectionAboutToBeClosed(const QString &name); void queryActivated(QSqlQuery &query, const QString &connection); void error(const QString &message); void success(const QString &message); private: ConnectionModel *m_model; KWallet::Wallet *m_wallet; }; #endif // SQLMANAGER_H diff --git a/addons/katesql/textoutputwidget.h b/addons/katesql/textoutputwidget.h index 0d93193e7..7d0a0886f 100644 --- a/addons/katesql/textoutputwidget.h +++ b/addons/katesql/textoutputwidget.h @@ -1,53 +1,53 @@ /* 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. */ #ifndef TEXTOUTPUTWIDGET_H #define TEXTOUTPUTWIDGET_H class QHBoxLayout; class QTextEdit; #include "connection.h" #include class TextOutputWidget : public QWidget { Q_OBJECT public: - TextOutputWidget(QWidget *parent = 0); + TextOutputWidget(QWidget *parent = nullptr); ~TextOutputWidget(); public Q_SLOTS: void showErrorMessage(const QString &message); void showSuccessMessage(const QString &message); private: void writeMessage(const QString &msg); private: QHBoxLayout *m_layout; QTextEdit *m_output; QColor m_succesTextColor; QColor m_succesBackgroundColor; QColor m_errorTextColor; QColor m_errorBackgroundColor; }; #endif // TEXTOUTPUTWIDGET_H diff --git a/addons/konsole/kateconsole.cpp b/addons/konsole/kateconsole.cpp index b0a6d5c7e..edd209f5f 100644 --- a/addons/konsole/kateconsole.cpp +++ b/addons/konsole/kateconsole.cpp @@ -1,388 +1,388 @@ /* 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(0, i18n ("You do not have enough karma to access a shell or terminal emulation")); + 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 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 (0) + , 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())); a = actionCollection()->addAction(QStringLiteral("katekonsole_tools_sync")); a->setText(i18nc("@action", "S&ynchronize Terminal with Current Document")); connect(a, SIGNAL(triggered()), this, SLOT(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())); m_mw->guiFactory()->addClient (this); readConfig(); } KateConsole::~KateConsole () { m_mw->guiFactory()->removeClient (this); if (m_part) disconnect ( m_part, SIGNAL(destroyed()), this, SLOT(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, SIGNAL(overrideShortcut(QKeyEvent*,bool&)), this, SLOT(overrideShortcut(QKeyEvent*,bool&))); slotSync(); } void KateConsole::slotDestroyed () { - m_part = 0; + 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()) ); } 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/konsole/kateconsole.h b/addons/konsole/kateconsole.h index dc8c390cc..4c25d80a3 100644 --- a/addons/konsole/kateconsole.h +++ b/addons/konsole/kateconsole.h @@ -1,216 +1,216 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2002 Joseph Wenninger Copyright (C) 2002 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. */ #ifndef __KATE_CONSOLE_H__ #define __KATE_CONSOLE_H__ #include #include #include #include #include #include class QShowEvent; namespace KParts { class ReadOnlyPart; } class KateConsole; class KateKonsolePluginView; class KateKonsolePlugin: public KTextEditor::Plugin { Q_OBJECT friend class KateKonsolePluginView; public: - explicit KateKonsolePlugin( QObject* parent = 0, const QList& = QList() ); + explicit KateKonsolePlugin( QObject* parent = nullptr, const QList& = QList() ); virtual ~KateKonsolePlugin(); QObject *createView (KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; int configPages() const Q_DECL_OVERRIDE { return 1; } - KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = 0) Q_DECL_OVERRIDE; + KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = nullptr) Q_DECL_OVERRIDE; void readConfig(); QByteArray previousEditorEnv() {return m_previousEditorEnv;} private: QList mViews; QByteArray m_previousEditorEnv; }; class KateKonsolePluginView : public QObject { Q_OBJECT public: /** * Constructor. */ KateKonsolePluginView (KateKonsolePlugin* plugin, KTextEditor::MainWindow *mainWindow); /** * Virtual destructor. */ ~KateKonsolePluginView (); void readConfig(); private: KateKonsolePlugin *m_plugin; KateConsole *m_console; }; /** * KateConsole * This class is used for the internal terminal emulator * It uses internally the konsole part, thx to konsole devs :) */ class KateConsole : public QWidget, public KXMLGUIClient { Q_OBJECT public: /** * construct us * @param mw main window * @param parent toolview */ KateConsole (KateKonsolePlugin* plugin, KTextEditor::MainWindow *mw, QWidget* parent); /** * destruct us */ ~KateConsole (); void readConfig(); /** * cd to dir * @param path given local directory */ void cd (const QString & path); /** * send given text to console * @param text commands for console */ void sendInput( const QString& text ); KTextEditor::MainWindow *mainWindow() { return m_mw; } public Q_SLOTS: /** * pipe current document to console */ void slotPipeToConsole (); /** * synchronize the konsole with the current document (cd to the directory) */ - void slotSync(KTextEditor::View *view = 0); + void slotSync(KTextEditor::View *view = nullptr); /** * When syncing is done by the user, also show the terminal if it is hidden */ void slotManualSync(); private Q_SLOTS: /** * the konsole exited ;) * handle that, hide the dock */ void slotDestroyed (); /** * construct console if needed */ void loadConsoleIfNeeded(); /** * set or clear focus as appropriate. */ void slotToggleFocus(); /** * Handle that shortcuts are not eaten by console */ void overrideShortcut (QKeyEvent *event, bool &override); protected: /** * the konsole get shown * @param ev show event */ void showEvent(QShowEvent *ev) Q_DECL_OVERRIDE; private: /** * console part */ KParts::ReadOnlyPart *m_part; /** * main window of this console */ KTextEditor::MainWindow *m_mw; /** * toolview for this console */ QWidget *m_toolView; KateKonsolePlugin *m_plugin; QString m_currentPath; }; class KateKonsoleConfigPage : public KTextEditor::ConfigPage { Q_OBJECT public: - explicit KateKonsoleConfigPage( QWidget* parent = 0, KateKonsolePlugin *plugin = 0 ); + explicit KateKonsoleConfigPage( QWidget* parent = nullptr, KateKonsolePlugin *plugin = nullptr ); virtual ~KateKonsoleConfigPage() {} QString name() const Q_DECL_OVERRIDE; QString fullName() const Q_DECL_OVERRIDE; QIcon icon() const Q_DECL_OVERRIDE; void apply() Q_DECL_OVERRIDE; void reset() Q_DECL_OVERRIDE; void defaults() Q_DECL_OVERRIDE {} private: class QCheckBox *cbAutoSyncronize; class QCheckBox *cbSetEditor; KateKonsolePlugin *mPlugin; }; #endif // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/lumen/lumen.h b/addons/lumen/lumen.h index bb03a4c0c..6cce7e2ee 100644 --- a/addons/lumen/lumen.h +++ b/addons/lumen/lumen.h @@ -1,86 +1,86 @@ /* * 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 . **/ #ifndef LUMEN_H #define LUMEN_H #include #include #include #include #include #include #include "dcd.h" #include "completion.h" using namespace KTextEditor; class LumenPlugin; class LumenHintProvider; class LumenPluginView: public QObject { Q_OBJECT public: LumenPluginView(LumenPlugin *plugin, KTextEditor::MainWindow *view); virtual ~LumenPluginView(); void registerCompletion(KTextEditor::View *view); void registerTextHints(KTextEditor::View *view); private Q_SLOTS: void urlChanged(KTextEditor::Document*); void viewCreated(KTextEditor::View *view); void viewDestroyed(QObject *view); void documentChanged(KTextEditor::Document *document); private: LumenPlugin* m_plugin; MainWindow* m_mainWin; LumenCompletionModel* m_model; QSet m_completionViews; bool m_registered; LumenHintProvider* m_hinter; }; class LumenHintProvider : public KTextEditor::TextHintProvider { public: explicit LumenHintProvider(LumenPlugin* plugin); QString textHint(KTextEditor::View* view, const KTextEditor::Cursor& position) Q_DECL_OVERRIDE; private: LumenPlugin *m_plugin; }; class LumenPlugin: public Plugin { Q_OBJECT public: - explicit LumenPlugin(QObject *parent = 0, const QList & = QList()); + explicit LumenPlugin(QObject *parent = nullptr, const QList & = QList()); virtual ~LumenPlugin(); DCD* dcd(); QObject *createView(MainWindow *mainWindow) Q_DECL_OVERRIDE; private: DCD* m_dcd; }; #endif diff --git a/addons/openheader/plugin_kateopenheader.h b/addons/openheader/plugin_kateopenheader.h index 17fbb8cdd..991fc53a0 100644 --- a/addons/openheader/plugin_kateopenheader.h +++ b/addons/openheader/plugin_kateopenheader.h @@ -1,68 +1,68 @@ /* 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. */ #ifndef PLUGIN_KATEOPENHEADER_H #define PLUGIN_KATEOPENHEADER_H #include #include #include #include #include #include #include class PluginKateOpenHeader : public KTextEditor::Plugin { Q_OBJECT public: - explicit PluginKateOpenHeader( QObject* parent = 0, const QList& = QList() ); + explicit PluginKateOpenHeader( QObject* parent = nullptr, const QList& = QList() ); virtual ~PluginKateOpenHeader(); QObject *createView (KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; public Q_SLOTS: void slotOpenHeader (); void tryOpen( const QUrl& url, const QStringList& extensions ); bool tryOpenInternal( const QUrl& url, const QStringList& extensions ); private: bool fileExists(const QUrl &url); void setFileName(QUrl *url,const QString &_txt); }; class PluginViewKateOpenHeader : public KTextEditor::Command , public KXMLGUIClient { Q_OBJECT public: PluginViewKateOpenHeader(PluginKateOpenHeader* plugin, KTextEditor::MainWindow *mainwindow); virtual ~PluginViewKateOpenHeader(); bool exec (KTextEditor::View *view, const QString &cmd, QString &msg, const KTextEditor::Range &range = KTextEditor::Range::invalid()) Q_DECL_OVERRIDE; bool help (KTextEditor::View *view, const QString &cmd, QString &msg) Q_DECL_OVERRIDE; private: PluginKateOpenHeader* m_plugin; KTextEditor::MainWindow *m_mainWindow; }; #endif // PLUGIN_KATEOPENHEADER_H diff --git a/addons/project/ctags/readtags.c b/addons/project/ctags/readtags.c index 558bd1115..565a54495 100644 --- a/addons/project/ctags/readtags.c +++ b/addons/project/ctags/readtags.c @@ -1,910 +1,910 @@ /* * * Copyright (c) 1996-2003, Darren Hiebert * * This source code is released into the public domain. * * This module contains functions for reading tag files. * */ /* * INCLUDE FILES */ #include #include #include #include #include #include /* to declare off_t */ #include "readtags.h" /* * MACROS */ #define TAB '\t' /* * DATA DECLARATIONS */ typedef struct { size_t size; char *buffer; } vstring; /* Information about current tag file */ struct sTagFile { /* has the file been opened and this structure initialized? */ short initialized; /* format of tag file */ short format; /* how is the tag file sorted? */ sortType sortMethod; /* pointer to file structure */ FILE *fp; /* file position of first character of `line' */ off_t pos; /* size of tag file in seekable positions */ off_t size; /* last line read */ vstring line; /* name of tag in last line read */ vstring name; /* defines tag search state */ struct { /* file position of last match for tag */ off_t pos; /* name of tag last searched for */ const char *name; /* length of name for partial matches */ size_t nameLength; /* peforming partial match */ short partial; /* ignoring case */ short ignorecase; } search; /* miscellaneous extension fields */ struct { /* number of entries in `list' */ unsigned short max; /* list of key value pairs */ tagExtensionField *list; } fields; /* buffers to be freed at close */ struct { /* name of program author */ char *author; /* name of program */ char *name; /* URL of distribution */ char *url; /* program version */ char *version; } program; }; /* * DATA DEFINITIONS */ const char *const EmptyString = ""; const char *const PseudoTagPrefix = "!_"; /* * FUNCTION DEFINITIONS */ /* * Compare two strings, ignoring case. * Return 0 for match, < 0 for smaller, > 0 for bigger * Make sure case is folded to uppercase in comparison (like for 'sort -f') * This makes a difference when one of the chars lies between upper and lower * ie. one of the chars [ \ ] ^ _ ` for ascii. (The '_' in particular !) */ static int struppercmp(const char *s1, const char *s2) { int result; do { result = toupper((int) * s1) - toupper((int) * s2); } while (result == 0 && *s1++ != '\0' && *s2++ != '\0'); return result; } static int strnuppercmp(const char *s1, const char *s2, size_t n) { int result; do { result = toupper((int) * s1) - toupper((int) * s2); } while (result == 0 && --n > 0 && *s1++ != '\0' && *s2++ != '\0'); return result; } static int growString(vstring *s) { int result = 0; size_t newLength; char *newLine; if (s->size == 0) { newLength = 128; newLine = (char *) malloc(newLength); *newLine = '\0'; } else { newLength = 2 * s->size; newLine = (char *) realloc(s->buffer, newLength); } - if (newLine == NULL) { + if (newLine == nullptr) { perror("string too large"); } else { s->buffer = newLine; s->size = newLength; result = 1; } return result; } /* Copy name of tag out of tag line */ static void copyName(tagFile *const file) { size_t length; const char *end = strchr(file->line.buffer, '\t'); - if (end == NULL) { + if (end == nullptr) { end = strchr(file->line.buffer, '\n'); - if (end == NULL) { + if (end == nullptr) { end = strchr(file->line.buffer, '\r'); } } - if (end != NULL) { + if (end != nullptr) { length = end - file->line.buffer; } else { length = strlen(file->line.buffer); } while (length >= file->name.size) { growString(&file->name); } strncpy(file->name.buffer, file->line.buffer, length); file->name.buffer [length] = '\0'; } static int readTagLineRaw(tagFile *const file) { int result = 1; int reReadLine; /* If reading the line places any character other than a null or a * newline at the last character position in the buffer (one less than * the buffer size), then we must resize the buffer and reattempt to read * the line. */ do { char *const pLastChar = file->line.buffer + file->line.size - 2; char *line; file->pos = ftell(file->fp); reReadLine = 0; *pLastChar = '\0'; line = fgets(file->line.buffer, (int) file->line.size, file->fp); - if (line == NULL) { + if (line == nullptr) { /* read error */ if (! feof(file->fp)) { perror("readTagLine"); } result = 0; } else if (*pLastChar != '\0' && *pLastChar != '\n' && *pLastChar != '\r') { /* buffer overflow */ growString(&file->line); fseek(file->fp, file->pos, SEEK_SET); reReadLine = 1; } else { size_t i = strlen(file->line.buffer); while (i > 0 && (file->line.buffer [i - 1] == '\n' || file->line.buffer [i - 1] == '\r')) { file->line.buffer [i - 1] = '\0'; --i; } } } while (reReadLine && result); if (result) { copyName(file); } return result; } static int readTagLine(tagFile *const file) { int result; do { result = readTagLineRaw(file); } while (result && *file->name.buffer == '\0'); return result; } static tagResult growFields(tagFile *const file) { tagResult result = TagFailure; unsigned short newCount = 2 * file->fields.max; tagExtensionField *newFields = (tagExtensionField *) realloc(file->fields.list, newCount * sizeof(tagExtensionField)); - if (newFields == NULL) { + if (newFields == nullptr) { perror("too many extension fields"); } else { file->fields.list = newFields; file->fields.max = newCount; result = TagSuccess; } return result; } static void parseExtensionFields(tagFile *const file, tagEntry *const entry, char *const string) { char *p = string; - while (p != NULL && *p != '\0') { + while (p != nullptr && *p != '\0') { while (*p == TAB) { *p++ = '\0'; } if (*p != '\0') { char *colon; char *field = p; p = strchr(p, TAB); - if (p != NULL) { + if (p != nullptr) { *p++ = '\0'; } colon = strchr(field, ':'); - if (colon == NULL) { + if (colon == nullptr) { entry->kind = field; } else { const char *key = field; const char *value = colon + 1; *colon = '\0'; if (strcmp(key, "kind") == 0) { entry->kind = value; } else if (strcmp(key, "file") == 0) { entry->fileScope = 1; } else if (strcmp(key, "line") == 0) { entry->address.lineNumber = atol(value); } else { if (entry->fields.count == file->fields.max) { growFields(file); } file->fields.list [entry->fields.count].key = key; file->fields.list [entry->fields.count].value = value; ++entry->fields.count; } } } } } static void parseTagLine(tagFile *file, tagEntry *const entry) { int i; char *p = file->line.buffer; char *tab = strchr(p, TAB); int fieldsPresent = 0; - entry->fields.list = NULL; + entry->fields.list = nullptr; entry->fields.count = 0; - entry->kind = NULL; + entry->kind = nullptr; entry->fileScope = 0; entry->name = p; - if (tab != NULL) { + if (tab != nullptr) { *tab = '\0'; p = tab + 1; entry->file = p; tab = strchr(p, TAB); - if (tab != NULL) { + if (tab != nullptr) { *tab = '\0'; p = tab + 1; if (*p == '/' || *p == '?') { /* parse pattern */ int delimiter = *(unsigned char *) p; entry->address.lineNumber = 0; entry->address.pattern = p; do { p = strchr(p + 1, delimiter); - } while (p != NULL && *(p - 1) == '\\'); - if (p == NULL) { + } while (p != nullptr && *(p - 1) == '\\'); + if (p == nullptr) { /* invalid pattern */ } else { ++p; } } else if (isdigit((int) * (unsigned char *) p)) { /* parse line number */ entry->address.pattern = p; entry->address.lineNumber = atol(p); while (isdigit((int) * (unsigned char *) p)) { ++p; } } else { /* invalid pattern */ } - if (p != NULL) { + if (p != nullptr) { fieldsPresent = (strncmp(p, ";\"", 2) == 0); *p = '\0'; if (fieldsPresent) { parseExtensionFields(file, entry, p + 2); } } } } if (entry->fields.count > 0) { entry->fields.list = file->fields.list; } for (i = entry->fields.count ; i < file->fields.max ; ++i) { - file->fields.list [i].key = NULL; - file->fields.list [i].value = NULL; + file->fields.list [i].key = nullptr; + file->fields.list [i].value = nullptr; } } static char *duplicate(const char *str) { - char *result = NULL; - if (str != NULL) { + char *result = nullptr; + if (str != nullptr) { result = (char *) malloc(strlen(str) + 1); - if (result == NULL) { - perror(NULL); + if (result == nullptr) { + perror(nullptr); } else { strcpy(result, str); } } return result; } static void readPseudoTags(tagFile *const file, tagFileInfo *const info) { fpos_t startOfLine; const size_t prefixLength = strlen(PseudoTagPrefix); - if (info != NULL) { + if (info != nullptr) { info->file.format = 1; info->file.sort = TAG_UNSORTED; - info->program.author = NULL; - info->program.name = NULL; - info->program.url = NULL; - info->program.version = NULL; + info->program.author = nullptr; + info->program.name = nullptr; + info->program.url = nullptr; + info->program.version = nullptr; } while (1) { fgetpos(file->fp, &startOfLine); if (! readTagLine(file)) { break; } if (strncmp(file->line.buffer, PseudoTagPrefix, prefixLength) != 0) { break; } else { tagEntry entry; const char *key, *value; parseTagLine(file, &entry); key = entry.name + prefixLength; value = entry.file; if (strcmp(key, "TAG_FILE_SORTED") == 0) { file->sortMethod = (sortType) atoi(value); } else if (strcmp(key, "TAG_FILE_FORMAT") == 0) { file->format = atoi(value); } else if (strcmp(key, "TAG_PROGRAM_AUTHOR") == 0) { file->program.author = duplicate(value); } else if (strcmp(key, "TAG_PROGRAM_NAME") == 0) { file->program.name = duplicate(value); } else if (strcmp(key, "TAG_PROGRAM_URL") == 0) { file->program.url = duplicate(value); } else if (strcmp(key, "TAG_PROGRAM_VERSION") == 0) { file->program.version = duplicate(value); } - if (info != NULL) { + if (info != nullptr) { info->file.format = file->format; info->file.sort = file->sortMethod; info->program.author = file->program.author; info->program.name = file->program.name; info->program.url = file->program.url; info->program.version = file->program.version; } } } fsetpos(file->fp, &startOfLine); } static void gotoFirstLogicalTag(tagFile *const file) { fpos_t startOfLine; const size_t prefixLength = strlen(PseudoTagPrefix); rewind(file->fp); while (1) { fgetpos(file->fp, &startOfLine); if (! readTagLine(file)) { break; } if (strncmp(file->line.buffer, PseudoTagPrefix, prefixLength) != 0) { break; } } fsetpos(file->fp, &startOfLine); } static tagFile *initialize(const char *const filePath, tagFileInfo *const info) { tagFile *result = (tagFile *) malloc(sizeof(tagFile)); - if (result != NULL) { + if (result != nullptr) { memset(result, 0, sizeof(tagFile)); growString(&result->line); growString(&result->name); result->fields.max = 20; result->fields.list = (tagExtensionField *) malloc( result->fields.max * sizeof(tagExtensionField)); result->fp = fopen(filePath, "r"); - if (result->fp == NULL) { + if (result->fp == nullptr) { free(result); - result = NULL; + result = nullptr; info->status.error_number = errno; } else { fseek(result->fp, 0, SEEK_END); result->size = ftell(result->fp); rewind(result->fp); readPseudoTags(result, info); info->status.opened = 1; result->initialized = 1; } } return result; } static void terminate(tagFile *const file) { fclose(file->fp); free(file->line.buffer); free(file->name.buffer); free(file->fields.list); - if (file->program.author != NULL) { + if (file->program.author != nullptr) { free(file->program.author); } - if (file->program.name != NULL) { + if (file->program.name != nullptr) { free(file->program.name); } - if (file->program.url != NULL) { + if (file->program.url != nullptr) { free(file->program.url); } - if (file->program.version != NULL) { + if (file->program.version != nullptr) { free(file->program.version); } memset(file, 0, sizeof(tagFile)); free(file); } static tagResult readNext(tagFile *const file, tagEntry *const entry) { tagResult result = TagFailure; - if (file == NULL || ! file->initialized) { + if (file == nullptr || ! file->initialized) { result = TagFailure; } else if (! readTagLine(file)) { result = TagFailure; } else { - if (entry != NULL) { + if (entry != nullptr) { parseTagLine(file, entry); } result = TagSuccess; } return result; } static const char *readFieldValue( const tagEntry *const entry, const char *const key) { - const char *result = NULL; + const char *result = nullptr; int i; if (strcmp(key, "kind") == 0) { result = entry->kind; } else if (strcmp(key, "file") == 0) { result = EmptyString; - } else for (i = 0 ; i < entry->fields.count && result == NULL ; ++i) + } else for (i = 0 ; i < entry->fields.count && result == nullptr ; ++i) if (strcmp(entry->fields.list [i].key, key) == 0) { result = entry->fields.list [i].value; } return result; } static int readTagLineSeek(tagFile *const file, const off_t pos) { int result = 0; if (fseek(file->fp, pos, SEEK_SET) == 0) { result = readTagLine(file); /* read probable partial line */ if (pos > 0 && result) { result = readTagLine(file); /* read complete line */ } } return result; } static int nameComparison(tagFile *const file) { int result; if (file->search.ignorecase) { if (file->search.partial) result = strnuppercmp(file->search.name, file->name.buffer, file->search.nameLength); else { result = struppercmp(file->search.name, file->name.buffer); } } else { if (file->search.partial) result = strncmp(file->search.name, file->name.buffer, file->search.nameLength); else { result = strcmp(file->search.name, file->name.buffer); } } return result; } static void findFirstNonMatchBefore(tagFile *const file) { #define JUMP_BACK 512 int more_lines; int comp; off_t start = file->pos; off_t pos = start; do { if (pos < (off_t) JUMP_BACK) { pos = 0; } else { pos = pos - JUMP_BACK; } more_lines = readTagLineSeek(file, pos); comp = nameComparison(file); } while (more_lines && comp == 0 && pos > 0 && pos < start); } static tagResult findFirstMatchBefore(tagFile *const file) { tagResult result = TagFailure; int more_lines; off_t start = file->pos; findFirstNonMatchBefore(file); do { more_lines = readTagLine(file); if (nameComparison(file) == 0) { result = TagSuccess; } } while (more_lines && result != TagSuccess && file->pos < start); return result; } static tagResult findBinary(tagFile *const file) { tagResult result = TagFailure; off_t lower_limit = 0; off_t upper_limit = file->size; off_t last_pos = 0; off_t pos = upper_limit / 2; while (result != TagSuccess) { if (! readTagLineSeek(file, pos)) { /* in case we fell off end of file */ result = findFirstMatchBefore(file); break; } else if (pos == last_pos) { /* prevent infinite loop if we backed up to beginning of file */ break; } else { const int comp = nameComparison(file); last_pos = pos; if (comp < 0) { upper_limit = pos; pos = lower_limit + ((upper_limit - lower_limit) / 2); } else if (comp > 0) { lower_limit = pos; pos = lower_limit + ((upper_limit - lower_limit) / 2); } else if (pos == 0) { result = TagSuccess; } else { result = findFirstMatchBefore(file); } } } return result; } static tagResult findSequential(tagFile *const file) { tagResult result = TagFailure; if (file->initialized) { while (result == TagFailure && readTagLine(file)) { if (nameComparison(file) == 0) { result = TagSuccess; } } } return result; } static tagResult find(tagFile *const file, tagEntry *const entry, const char *const name, const int options) { tagResult result = TagFailure; file->search.name = name; file->search.nameLength = strlen(name); file->search.partial = (options & TAG_PARTIALMATCH) != 0; file->search.ignorecase = (options & TAG_IGNORECASE) != 0; fseek(file->fp, 0, SEEK_END); file->size = ftell(file->fp); rewind(file->fp); if ((file->sortMethod == TAG_SORTED && !file->search.ignorecase) || (file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase)) { #ifdef DEBUG printf("\n"); #endif result = findBinary(file); } else { #ifdef DEBUG printf("\n"); #endif result = findSequential(file); } if (result != TagSuccess) { file->search.pos = file->size; } else { file->search.pos = file->pos; - if (entry != NULL) { + if (entry != nullptr) { parseTagLine(file, entry); } } return result; } static tagResult findNext(tagFile *const file, tagEntry *const entry) { tagResult result = TagFailure; if ((file->sortMethod == TAG_SORTED && !file->search.ignorecase) || (file->sortMethod == TAG_FOLDSORTED && file->search.ignorecase)) { result = tagsNext(file, entry); if (result == TagSuccess && nameComparison(file) != 0) { result = TagFailure; } } else { result = findSequential(file); - if (result == TagSuccess && entry != NULL) { + if (result == TagSuccess && entry != nullptr) { parseTagLine(file, entry); } } return result; } /* * EXTERNAL INTERFACE */ extern tagFile *tagsOpen(const char *const filePath, tagFileInfo *const info) { return initialize(filePath, info); } extern tagResult tagsSetSortType(tagFile *const file, const sortType type) { tagResult result = TagFailure; - if (file != NULL && file->initialized) { + if (file != nullptr && file->initialized) { file->sortMethod = type; result = TagSuccess; } return result; } extern tagResult tagsFirst(tagFile *const file, tagEntry *const entry) { tagResult result = TagFailure; - if (file != NULL && file->initialized) { + if (file != nullptr && file->initialized) { gotoFirstLogicalTag(file); result = readNext(file, entry); } return result; } extern tagResult tagsNext(tagFile *const file, tagEntry *const entry) { tagResult result = TagFailure; - if (file != NULL && file->initialized) { + if (file != nullptr && file->initialized) { result = readNext(file, entry); } return result; } extern const char *tagsField(const tagEntry *const entry, const char *const key) { - const char *result = NULL; - if (entry != NULL) { + const char *result = nullptr; + if (entry != nullptr) { result = readFieldValue(entry, key); } return result; } extern tagResult tagsFind(tagFile *const file, tagEntry *const entry, const char *const name, const int options) { tagResult result = TagFailure; - if (file != NULL && file->initialized) { + if (file != nullptr && file->initialized) { result = find(file, entry, name, options); } return result; } extern tagResult tagsFindNext(tagFile *const file, tagEntry *const entry) { tagResult result = TagFailure; - if (file != NULL && file->initialized) { + if (file != nullptr && file->initialized) { result = findNext(file, entry); } return result; } extern tagResult tagsClose(tagFile *const file) { tagResult result = TagFailure; - if (file != NULL && file->initialized) { + if (file != nullptr && file->initialized) { terminate(file); result = TagSuccess; } return result; } /* * TEST FRAMEWORK */ #ifdef READTAGS_MAIN static const char *TagFileName = "tags"; static const char *ProgramName; static int extensionFields; static int SortOverride; static sortType SortMethod; static void printTag(const tagEntry *entry) { int i; int first = 1; const char *separator = ";\""; const char *const empty = ""; /* "sep" returns a value only the first time it is evaluated */ #define sep (first ? (first = 0, separator) : empty) printf("%s\t%s\t%s", entry->name, entry->file, entry->address.pattern); if (extensionFields) { if (entry->kind != NULL && entry->kind [0] != '\0') { printf("%s\tkind:%s", sep, entry->kind); } if (entry->fileScope) { printf("%s\tfile:", sep); } #if 0 if (entry->address.lineNumber > 0) { printf("%s\tline:%lu", sep, entry->address.lineNumber); } #endif for (i = 0 ; i < entry->fields.count ; ++i) printf("%s\t%s:%s", sep, entry->fields.list [i].key, entry->fields.list [i].value); } putchar('\n'); #undef sep } static void findTag(const char *const name, const int options) { tagFileInfo info; tagEntry entry; tagFile *const file = tagsOpen(TagFileName, &info); if (file == NULL) { fprintf(stderr, "%s: cannot open tag file: %s: %s\n", ProgramName, strerror(info.status.error_number), name); exit(1); } else { if (SortOverride) { tagsSetSortType(file, SortMethod); } if (tagsFind(file, &entry, name, options) == TagSuccess) { do { printTag(&entry); } while (tagsFindNext(file, &entry) == TagSuccess); } tagsClose(file); } } static void listTags(void) { tagFileInfo info; tagEntry entry; tagFile *const file = tagsOpen(TagFileName, &info); if (file == NULL) { fprintf(stderr, "%s: cannot open tag file: %s: %s\n", ProgramName, strerror(info.status.error_number), TagFileName); exit(1); } else { while (tagsNext(file, &entry) == TagSuccess) { printTag(&entry); } tagsClose(file); } } const char *const Usage = "Find tag file entries matching specified names.\n\n" "Usage: %s [-ilp] [-s[0|1]] [-t file] [name(s)]\n\n" "Options:\n" " -e Include extension fields in output.\n" " -i Perform case-insensitive matching.\n" " -l List all tags.\n" " -p Perform partial matching.\n" " -s[0|1|2] Override sort detection of tag file.\n" " -t file Use specified tag file (default: \"tags\").\n" "Note that options are acted upon as encountered, so order is significant.\n"; extern int main(int argc, char **argv) { int options = 0; int actionSupplied = 0; int i; ProgramName = argv [0]; if (argc == 1) { fprintf(stderr, Usage, ProgramName); exit(1); } for (i = 1 ; i < argc ; ++i) { const char *const arg = argv [i]; if (arg [0] != '-') { findTag(arg, options); actionSupplied = 1; } else { size_t j; for (j = 1 ; arg [j] != '\0' ; ++j) { switch (arg [j]) { case 'e': extensionFields = 1; break; case 'i': options |= TAG_IGNORECASE; break; case 'p': options |= TAG_PARTIALMATCH; break; case 'l': listTags(); actionSupplied = 1; break; case 't': if (arg [j + 1] != '\0') { TagFileName = arg + j + 1; j += strlen(TagFileName); } else if (i + 1 < argc) { TagFileName = argv [++i]; } else { fprintf(stderr, Usage, ProgramName); exit(1); } break; case 's': SortOverride = 1; ++j; if (arg [j] == '\0') { SortMethod = TAG_SORTED; } else if (strchr("012", arg[j]) != NULL) { SortMethod = (sortType)(arg[j] - '0'); } else { fprintf(stderr, Usage, ProgramName); exit(1); } break; default: fprintf(stderr, "%s: unknown option: %c\n", ProgramName, arg[j]); exit(1); break; } } } } if (! actionSupplied) { fprintf(stderr, "%s: no action specified: specify tag name(s) or -l option\n", ProgramName); exit(1); } return 0; } #endif /* vi:set tabstop=8 shiftwidth=4: */ diff --git a/addons/project/kateprojectcompletion.cpp b/addons/project/kateprojectcompletion.cpp index dc4ce35ae..65d782e4e 100644 --- a/addons/project/kateprojectcompletion.cpp +++ b/addons/project/kateprojectcompletion.cpp @@ -1,223 +1,223 @@ /* This file is part of the Kate project. * * Copyright (C) 2012 Christoph Cullmann * Copyright (C) 2003 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 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 "kateprojectcompletion.h" #include "kateprojectplugin.h" #include #include KateProjectCompletion::KateProjectCompletion(KateProjectPlugin *plugin) - : KTextEditor::CodeCompletionModel(0) + : KTextEditor::CodeCompletionModel(nullptr) , m_plugin(plugin) { } KateProjectCompletion::~KateProjectCompletion() { } void KateProjectCompletion::saveMatches(KTextEditor::View *view, const KTextEditor::Range &range) { m_matches.clear(); allMatches(m_matches, view, range); } QVariant KateProjectCompletion::data(const QModelIndex &index, int role) const { if (role == InheritanceDepth) { return 10010; //Very high value, so the word-completion group and items are shown behind any other groups/items if there is multiple } if (!index.parent().isValid()) { //It is the group header switch (role) { case Qt::DisplayRole: return i18n("Project Completion"); case GroupRole: return Qt::DisplayRole; } } if (index.column() == KTextEditor::CodeCompletionModel::Name && role == Qt::DisplayRole) { return m_matches.item(index.row())->data(Qt::DisplayRole); } if (index.column() == KTextEditor::CodeCompletionModel::Icon && role == Qt::DecorationRole) { static QIcon icon(QIcon::fromTheme(QStringLiteral("insert-text")).pixmap(QSize(16, 16))); return icon; } return QVariant(); } QModelIndex KateProjectCompletion::parent(const QModelIndex &index) const { if (index.internalId()) { return createIndex(0, 0, quintptr(0)); } else { return QModelIndex(); } } QModelIndex KateProjectCompletion::index(int row, int column, const QModelIndex &parent) const { if (!parent.isValid()) { if (row == 0) { return createIndex(row, column, quintptr(0)); } else { return QModelIndex(); } } else if (parent.parent().isValid()) { return QModelIndex(); } if (row < 0 || row >= m_matches.rowCount() || column < 0 || column >= ColumnCount) { return QModelIndex(); } return createIndex(row, column, 1); } int KateProjectCompletion::rowCount(const QModelIndex &parent) const { if (!parent.isValid() && !(m_matches.rowCount() == 0)) { return 1; //One root node to define the custom group } else if (parent.parent().isValid()) { return 0; //Completion-items have no children } else { return m_matches.rowCount(); } } bool KateProjectCompletion::shouldStartCompletion(KTextEditor::View *view, const QString &insertedText, bool userInsertion, const KTextEditor::Cursor &position) { if (!userInsertion) { return false; } if (insertedText.isEmpty()) { return false; } QString text = view->document()->line(position.line()).left(position.column()); uint check = 3; //v->config()->wordCompletionMinimalWordLength(); if (check <= 0) { return true; } int start = text.length(); int end = text.length() - check; if (end < 0) { return false; } for (int i = start - 1; i >= end; i--) { QChar c = text.at(i); if (!(c.isLetter() || (c.isNumber()) || c == QLatin1Char('_'))) { return false; } } return true; } bool KateProjectCompletion::shouldAbortCompletion(KTextEditor::View *view, const KTextEditor::Range &range, const QString ¤tCompletion) { if (m_automatic) { if (currentCompletion.length() < 3 /*v->config()->wordCompletionMinimalWordLength()*/) { return true; } } return CodeCompletionModelControllerInterface::shouldAbortCompletion(view, range, currentCompletion); } void KateProjectCompletion::completionInvoked(KTextEditor::View *view, const KTextEditor::Range &range, InvocationType it) { /** * auto invoke... */ m_automatic = false; if (it == AutomaticInvocation) { m_automatic = true; if (range.columnWidth() >= 3 /*v->config()->wordCompletionMinimalWordLength()*/) { saveMatches(view, range); } else { m_matches.clear(); } // done here... return; } // normal case ;) saveMatches(view, range); } // Scan throughout the entire document for possible completions, // ignoring any dublets void KateProjectCompletion::allMatches(QStandardItemModel &model, KTextEditor::View *view, const KTextEditor::Range &range) const { /** * get project for this document, else fail */ KateProject *project = m_plugin->projectForDocument(view->document()); if (!project) { return; } /** * let project index fill the completion for this document */ if (project->projectIndex()) { project->projectIndex()->findMatches(model, view->document()->text(range), KateProjectIndex::CompletionMatches); } } KTextEditor::CodeCompletionModelControllerInterface::MatchReaction KateProjectCompletion::matchingItem(const QModelIndex & /*matched*/) { return HideListIfAutomaticInvocation; } // Return the range containing the word left of the cursor KTextEditor::Range KateProjectCompletion::completionRange(KTextEditor::View *view, const KTextEditor::Cursor &position) { int line = position.line(); int col = position.column(); KTextEditor::Document *doc = view->document(); while (col > 0) { QChar c = (doc->characterAt(KTextEditor::Cursor(line, col - 1))); if (c.isLetterOrNumber() || c.isMark() || c == QLatin1Char('_')) { col--; continue; } break; } return KTextEditor::Range(KTextEditor::Cursor(line, col), position); } diff --git a/addons/project/kateprojectindex.cpp b/addons/project/kateprojectindex.cpp index cd4576bd2..436a8c333 100644 --- a/addons/project/kateprojectindex.cpp +++ b/addons/project/kateprojectindex.cpp @@ -1,205 +1,205 @@ /* 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 "kateprojectindex.h" #include #include /** * include ctags reading */ #include "ctags/readtags.c" KateProjectIndex::KateProjectIndex(const QStringList &files, const QVariantMap &ctagsMap) : m_ctagsIndexFile(QDir::tempPath() + QStringLiteral("/kate.project.ctags")) - , m_ctagsIndexHandle(0) + , m_ctagsIndexHandle(nullptr) { /** * load ctags */ loadCtags(files, ctagsMap); } KateProjectIndex::~KateProjectIndex() { /** * delete ctags handle if any */ if (m_ctagsIndexHandle) { tagsClose(m_ctagsIndexHandle); - m_ctagsIndexHandle = 0; + m_ctagsIndexHandle = nullptr; } } void KateProjectIndex::loadCtags(const QStringList &files, const QVariantMap &ctagsMap) { /** * create temporary file * if not possible, fail */ if (!m_ctagsIndexFile.open()) { return; } /** * close file again, other process will use it */ m_ctagsIndexFile.close(); /** * try to run ctags for all files in this project * output to our ctags index file */ QProcess ctags; QStringList args; args << QStringLiteral("-L") << QStringLiteral("-") << QStringLiteral("-f") << m_ctagsIndexFile.fileName() << QStringLiteral("--fields=+K+n"); const QString keyOptions = QStringLiteral("options"); for (const QVariant &optVariant : ctagsMap[keyOptions].toList()) { args << optVariant.toString(); } ctags.start(QStringLiteral("ctags"), args); if (!ctags.waitForStarted()) { return; } /** * write files list and close write channel */ ctags.write(files.join(QStringLiteral("\n")).toLocal8Bit()); ctags.closeWriteChannel(); /** * wait for done */ if (!ctags.waitForFinished()) { return; } /** * file not openable, bad */ if (!m_ctagsIndexFile.open()) { return; } /** * get size */ qint64 size = m_ctagsIndexFile.size(); /** * close again */ m_ctagsIndexFile.close(); /** * empty file, bad */ if (!size) { return; } /** * try to open ctags file */ tagFileInfo info; memset(&info, 0, sizeof(tagFileInfo)); m_ctagsIndexHandle = tagsOpen(m_ctagsIndexFile.fileName().toLocal8Bit().constData(), &info); } void KateProjectIndex::findMatches(QStandardItemModel &model, const QString &searchWord, MatchType type) { /** * abort if no ctags index */ if (!m_ctagsIndexHandle) { return; } /** * word to complete * abort if empty */ QByteArray word = searchWord.toLocal8Bit(); if (word.isEmpty()) { return; } /** * try to search entry * fail if none found */ tagEntry entry; if (tagsFind(m_ctagsIndexHandle, &entry, word.constData(), TAG_PARTIALMATCH | TAG_OBSERVECASE) != TagSuccess) { return; } /** * set to show words only once for completion matches */ QSet guard; /** * loop over all found tags * first one is filled by above find, others by find next */ do { /** * skip if no name */ if (!entry.name) { continue; } /** * get name */ QString name(QString::fromLocal8Bit(entry.name)); /** * construct right items */ switch (type) { case CompletionMatches: /** * add new completion item, if new name */ if (!guard.contains(name)) { model.appendRow(new QStandardItem(name)); guard.insert(name); } break; case FindMatches: /** * add new find item, contains of multiple columns */ QList items; items << new QStandardItem(name); items << new QStandardItem(entry.kind ? QString::fromLocal8Bit(entry.kind) : QString()); items << new QStandardItem(entry.file ? QString::fromLocal8Bit(entry.file) : QString()); items << new QStandardItem(QString::number(entry.address.lineNumber)); model.appendRow(items); break; } } while (tagsFindNext(m_ctagsIndexHandle, &entry) == TagSuccess); } diff --git a/addons/project/kateprojectinfoviewcodeanalysis.cpp b/addons/project/kateprojectinfoviewcodeanalysis.cpp index 2bb1a2c7c..a4fbf3b56 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(0) + , m_messageWidget(nullptr) , m_startStopAnalysis(new QPushButton(i18n("Start Analysis..."))) , m_treeView(new QTreeView()) , m_model(new QStandardItemModel(m_treeView)) - , m_analyzer(0) + , 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 &))); } 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))); 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 = 0; + 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 d0d1ad5df..7b38bf89e 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(0) + , 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())); /** * 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 d9d4a101b..b2e1ff990 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(0) + , 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())); } } void KateProjectInfoViewTerminal::loadTerminal() { /** * null in any case, if loadTerminal fails below and we are in the destroyed event */ - m_konsolePart = 0; + 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, 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/kateprojectplugin.cpp b/addons/project/kateprojectplugin.cpp index c523f3a17..7a879eff5 100644 --- a/addons/project/kateprojectplugin.cpp +++ b/addons/project/kateprojectplugin.cpp @@ -1,353 +1,353 @@ /* 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 "kateprojectplugin.h" #include "kateproject.h" #include "kateprojectconfigpage.h" #include "kateprojectpluginview.h" #include #include #include #include #include #include #include #include #include "config.h" #ifdef HAVE_CTERMID #include #include #include #include #include #endif namespace { const QString ProjectFileName = QStringLiteral(".kateproject"); const QString GitFolderName = QStringLiteral(".git"); const QString SubversionFolderName = QStringLiteral(".svn"); const QString MercurialFolderName = QStringLiteral(".hg"); const QString GitConfig = QStringLiteral("git"); const QString SubversionConfig = QStringLiteral("subversion"); const QString MercurialConfig = QStringLiteral("mercurial"); const QStringList DefaultConfig = QStringList() << GitConfig << SubversionConfig << MercurialConfig; } KateProjectPlugin::KateProjectPlugin(QObject *parent, const QList &) : KTextEditor::Plugin(parent) , m_completion(this) , m_autoGit(true) , m_autoSubversion(true) , m_autoMercurial(true) , m_weaver(new ThreadWeaver::Queue(this)) { qRegisterMetaType("KateProjectSharedQStandardItem"); qRegisterMetaType("KateProjectSharedQMapStringItem"); qRegisterMetaType("KateProjectSharedProjectIndex"); connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentCreated, this, &KateProjectPlugin::slotDocumentCreated); connect(&m_fileWatcher, &QFileSystemWatcher::directoryChanged, this, &KateProjectPlugin::slotDirectoryChanged); #ifdef HAVE_CTERMID /** * open project for our current working directory, if this kate has a terminal * http://stackoverflow.com/questions/1312922/detect-if-stdin-is-a-terminal-or-pipe-in-c-c-qt */ char tty[L_ctermid + 1] = {0}; ctermid(tty); int fd = ::open(tty, O_RDONLY); if (fd >= 0) { projectForDir(QDir::current()); ::close(fd); } #endif readConfig(); for (auto document : KTextEditor::Editor::instance()->application()->documents()) { slotDocumentCreated(document); } } KateProjectPlugin::~KateProjectPlugin() { for (KateProject *project : m_projects) { m_fileWatcher.removePath(QFileInfo(project->fileName()).canonicalPath()); delete project; } m_projects.clear(); m_weaver->shutDown(); delete m_weaver; } QObject *KateProjectPlugin::createView(KTextEditor::MainWindow *mainWindow) { return new KateProjectPluginView(this, mainWindow); } int KateProjectPlugin::configPages() const { return 1; } KTextEditor::ConfigPage *KateProjectPlugin::configPage(int number, QWidget *parent) { if (number != 0) { return nullptr; } return new KateProjectConfigPage(parent, this); } KateProject *KateProjectPlugin::createProjectForFileName(const QString &fileName) { KateProject *project = new KateProject(m_weaver); if (!project->loadFromFile(fileName)) { delete project; return nullptr; } m_projects.append(project); m_fileWatcher.addPath(QFileInfo(fileName).canonicalPath()); emit projectCreated(project); return project; } KateProject *KateProjectPlugin::projectForDir(QDir dir) { /** * search projects upwards * with recursion guard */ QSet seenDirectories; while (!seenDirectories.contains(dir.absolutePath())) { /** * fill recursion guard */ seenDirectories.insert(dir.absolutePath()); /** * check for project and load it if found */ QString canonicalPath = dir.canonicalPath(); QString canonicalFileName = dir.filePath(ProjectFileName); for (KateProject *project : m_projects) { if (project->baseDir() == canonicalPath || project->fileName() == canonicalFileName) { return project; } } if (dir.exists(ProjectFileName)) { return createProjectForFileName(canonicalFileName); } KateProject *project; if ((project = detectGit(dir)) || (project = detectSubversion(dir)) || (project = detectMercurial(dir))) { return project; } /** * else: cd up, if possible or abort */ if (!dir.cdUp()) { break; } } - return 0; + return nullptr; } KateProject *KateProjectPlugin::projectForUrl(const QUrl &url) { if (url.isEmpty() || !url.isLocalFile()) { return nullptr; } return projectForDir(QFileInfo(url.toLocalFile()).absoluteDir()); } void KateProjectPlugin::slotDocumentCreated(KTextEditor::Document *document) { connect(document, &KTextEditor::Document::documentUrlChanged, this, &KateProjectPlugin::slotDocumentUrlChanged); connect(document, &KTextEditor::Document::destroyed, this, &KateProjectPlugin::slotDocumentDestroyed); slotDocumentUrlChanged(document); } void KateProjectPlugin::slotDocumentDestroyed(QObject *document) { if (KateProject *project = m_document2Project.value(document)) { project->unregisterDocument(static_cast(document)); } m_document2Project.remove(document); } void KateProjectPlugin::slotDocumentUrlChanged(KTextEditor::Document *document) { KateProject *project = projectForUrl(document->url()); if (KateProject *project = m_document2Project.value(document)) { project->unregisterDocument(document); } if (!project) { m_document2Project.remove(document); } else { m_document2Project[document] = project; } if (KateProject *project = m_document2Project.value(document)) { project->registerDocument(document); } } void KateProjectPlugin::slotDirectoryChanged(const QString &path) { QString fileName = QDir(path).filePath(ProjectFileName); for (KateProject * project : m_projects) { if (project->fileName() == fileName) { QDateTime lastModified = QFileInfo(fileName).lastModified(); if (project->fileLastModified().isNull() || (lastModified > project->fileLastModified())) { project->reload(); } break; } } } KateProject* KateProjectPlugin::detectGit(const QDir &dir) { if (m_autoGit && dir.exists(GitFolderName) && QFileInfo(dir, GitFolderName).isDir()) { return createProjectForRepository(QStringLiteral("git"), dir); } return nullptr; } KateProject* KateProjectPlugin::detectSubversion(const QDir &dir) { if (m_autoSubversion && dir.exists(SubversionFolderName) && QFileInfo(dir, SubversionFolderName).isDir()) { return createProjectForRepository(QStringLiteral("svn"), dir); } return nullptr; } KateProject* KateProjectPlugin::detectMercurial(const QDir &dir) { if (m_autoMercurial && dir.exists(MercurialFolderName) && QFileInfo(dir, MercurialFolderName).isDir()) { return createProjectForRepository(QStringLiteral("hg"), dir); } return nullptr; } KateProject *KateProjectPlugin::createProjectForRepository(const QString &type, const QDir &dir) { QVariantMap cnf, files; files[type] = 1; cnf[QLatin1String("name")] = dir.dirName(); cnf[QLatin1String("files")] = (QVariantList() << files); KateProject *project = new KateProject(m_weaver); project->loadFromData(cnf, dir.canonicalPath()); m_projects.append(project); emit projectCreated(project); return project; } void KateProjectPlugin::setAutoRepository(bool onGit, bool onSubversion, bool onMercurial) { m_autoGit = onGit; m_autoSubversion = onSubversion; m_autoMercurial = onMercurial; writeConfig(); } bool KateProjectPlugin::autoGit() const { return m_autoGit; } bool KateProjectPlugin::autoSubversion() const { return m_autoSubversion; } bool KateProjectPlugin::autoMercurial() const { return m_autoMercurial; } void KateProjectPlugin::readConfig() { KConfigGroup config(KSharedConfig::openConfig(), "project"); QStringList autorepository = config.readEntry("autorepository", DefaultConfig); m_autoGit = m_autoSubversion = m_autoMercurial = false; if (autorepository.contains(GitConfig)) { m_autoGit = true; } if (autorepository.contains(SubversionConfig)) { m_autoSubversion = true; } if (autorepository.contains(MercurialConfig)) { m_autoMercurial = true; } } void KateProjectPlugin::writeConfig() { KConfigGroup config(KSharedConfig::openConfig(), "project"); QStringList repos; if (m_autoGit) { repos << GitConfig; } if (m_autoSubversion) { repos << SubversionConfig; } if (m_autoMercurial) { repos << MercurialConfig; } config.writeEntry("autorepository", repos); } diff --git a/addons/project/kateprojectplugin.h b/addons/project/kateprojectplugin.h index 33c2ea4f2..aa7c704b4 100644 --- a/addons/project/kateprojectplugin.h +++ b/addons/project/kateprojectplugin.h @@ -1,179 +1,179 @@ /* 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. */ #ifndef _PLUGIN_KATE_PROJECT_H_ #define _PLUGIN_KATE_PROJECT_H_ #include #include #include #include #include #include #include "kateproject.h" #include "kateprojectcompletion.h" namespace ThreadWeaver { class Queue; } class KateProjectPlugin : public KTextEditor::Plugin { Q_OBJECT public: - explicit KateProjectPlugin(QObject *parent = 0, const QList & = QList()); + explicit KateProjectPlugin(QObject *parent = nullptr, const QList & = QList()); virtual ~KateProjectPlugin(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; int configPages() const Q_DECL_OVERRIDE; - KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = 0) Q_DECL_OVERRIDE; + KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = nullptr) Q_DECL_OVERRIDE; /** * Create new project for given project filename. * Null pointer if no project can be opened. * File name will be canonicalized! * @param fileName canonicalized file name for the project * @return project or null if not openable */ KateProject *createProjectForFileName(const QString &fileName); /** * Search and open project for given dir, if possible. * Will search upwards for .kateproject file. * Will use internally projectForFileName if project file is found. * @param dir dir to search matching project for * @return project or null if not openable */ KateProject *projectForDir(QDir dir); /** * Search and open project that contains given url, if possible. * Will search upwards for .kateproject file, if the url is a local file. * Will use internally projectForDir. * @param url url to search matching project for * @return project or null if not openable */ KateProject *projectForUrl(const QUrl &url); /** * get list of all current open projects * @return list of all open projects */ QList projects() const { return m_projects; } /** * Get global code completion. * @return global completion object for KTextEditor::View */ KateProjectCompletion *completion() { return &m_completion; } /** * Map current open documents to projects. * @param document document we want to know which project it belongs to * @return project or 0 if none found for this document */ KateProject *projectForDocument(KTextEditor::Document *document) { return m_document2Project.value(document); } void setAutoRepository(bool onGit, bool onSubversion, bool onMercurial); bool autoGit() const; bool autoSubversion() const; bool autoMercurial() const; Q_SIGNALS: /** * Signal that a new project got created. * @param project new created project */ void projectCreated(KateProject *project); public Q_SLOTS: /** * New document got created, we need to update our connections * @param document new created document */ void slotDocumentCreated(KTextEditor::Document *document); /** * Document got destroyed. * @param document deleted document */ void slotDocumentDestroyed(QObject *document); /** * Url changed, to auto-load projects */ void slotDocumentUrlChanged(KTextEditor::Document *document); /** * did some project file change? * @param path name of directory that did change */ void slotDirectoryChanged(const QString &path); private: KateProject *createProjectForRepository(const QString &type, const QDir &dir); KateProject *detectGit(const QDir &dir); KateProject *detectSubversion(const QDir &dir); KateProject *detectMercurial(const QDir &dir); void readConfig(); void writeConfig(); private: /** * open plugins, maps project base directory => project */ QList m_projects; /** * filesystem watcher to keep track of all project files * and auto-reload */ QFileSystemWatcher m_fileWatcher; /** * Mapping document => project */ QHash m_document2Project; /** * Project completion */ KateProjectCompletion m_completion; bool m_autoGit : 1; bool m_autoSubversion : 1; bool m_autoMercurial : 1; ThreadWeaver::Queue *m_weaver; }; #endif diff --git a/addons/replicode/replicodeconfig.h b/addons/replicode/replicodeconfig.h index fb061467a..999e55a14 100644 --- a/addons/replicode/replicodeconfig.h +++ b/addons/replicode/replicodeconfig.h @@ -1,47 +1,47 @@ /* 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. */ #ifndef REPLICODECONFIG_H #define REPLICODECONFIG_H #include #include class Ui_tabWidget; class ReplicodeSettings; class ReplicodeConfig : public QTabWidget { Q_OBJECT public: - explicit ReplicodeConfig(QWidget *parent = 0); + explicit ReplicodeConfig(QWidget *parent = nullptr); virtual ~ReplicodeConfig(); public Q_SLOTS: void reset(); void save(); void load(); ReplicodeSettings *settingsObject() { save(); return m_settings; } private: Ui_tabWidget *m_ui; ReplicodeSettings *m_settings; }; #endif//REPLICODECONFIG_H diff --git a/addons/replicode/replicodeconfigpage.h b/addons/replicode/replicodeconfigpage.h index 5d714d8ca..2d9d5706b 100644 --- a/addons/replicode/replicodeconfigpage.h +++ b/addons/replicode/replicodeconfigpage.h @@ -1,46 +1,46 @@ /* 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. */ #ifndef REPLICODEPLUGINCONFIGPAGE_H #define REPLICODEPLUGINCONFIGPAGE_H #include class KUrlRequester; class ReplicodeConfig; class ReplicodeConfigPage : public KTextEditor::ConfigPage { Q_OBJECT public: - ReplicodeConfigPage(QWidget *parent = 0); + ReplicodeConfigPage(QWidget *parent = nullptr); QString name() const Q_DECL_OVERRIDE; QString fullName() const Q_DECL_OVERRIDE; public Q_SLOTS: void apply() Q_DECL_OVERRIDE; void reset() Q_DECL_OVERRIDE; void defaults() Q_DECL_OVERRIDE; private: KUrlRequester *m_requester; ReplicodeConfig *m_config; }; #endif//REPLICODEPLUGINCONFIGPAGE_H diff --git a/addons/replicode/replicodeplugin.h b/addons/replicode/replicodeplugin.h index a9b5622cb..986818ad8 100644 --- a/addons/replicode/replicodeplugin.h +++ b/addons/replicode/replicodeplugin.h @@ -1,45 +1,45 @@ /* 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. */ #ifndef REPLICODEPLUGIN_H #define REPLICODEPLUGIN_H #include #include #include "replicodeview.h" class ReplicodePlugin : public KTextEditor::Plugin { Q_OBJECT public: // Constructor - explicit ReplicodePlugin(QObject *parent = 0, const QList &args = QList()); + explicit ReplicodePlugin(QObject *parent = nullptr, const QList &args = QList()); // Destructor virtual ~ReplicodePlugin(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE { return new ReplicodeView(this, mainWindow); } // Config interface int configPages () const Q_DECL_OVERRIDE { return 1; } - KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = 0) Q_DECL_OVERRIDE; + KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = nullptr) Q_DECL_OVERRIDE; }; #endif diff --git a/addons/replicode/replicodesettings.cpp b/addons/replicode/replicodesettings.cpp index 148c42cd5..f5755304a 100644 --- a/addons/replicode/replicodesettings.cpp +++ b/addons/replicode/replicodesettings.cpp @@ -1,212 +1,212 @@ /* 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 "replicodesettings.h" #include #include #include #include ReplicodeSettings::ReplicodeSettings(QObject *parent) : QObject(parent) { load(); } void ReplicodeSettings::load() { QSettings settings(QStringLiteral("replicode"), QStringLiteral("replicode")); settings.beginGroup(QStringLiteral("Load")); userOperatorPath = settings.value(QStringLiteral("User Operator Module Path"), QString()).toString(); userClassPath = settings.value(QStringLiteral("User Class File Path"), QString()).toString(); sourcePath = settings.value(QStringLiteral("Source File Path"), QString()).toString(); settings.endGroup(); settings.beginGroup(QStringLiteral("Init")); basePeriod = settings.value(QStringLiteral("Base Period"), 50000).toInt(); reductionCoreCount = settings.value(QStringLiteral("Reduction Core Count"), 6).toInt(); timeCoreCount = settings.value(QStringLiteral("Time Core Count"), 2).toInt(); settings.beginGroup(QStringLiteral("System")); mdlInertiaSuccessRateThreshold = settings.value(QStringLiteral("Model Inertia Success Rate Threshold"), 0.9).toFloat(); mdlInertiaCountThreshold = settings.value(QStringLiteral("Model Inertia Count Threshold"), 6).toInt(); tpxDeltaSuccessRateThreshold = settings.value(QStringLiteral("Targeted Pattern Extractor Delta Success Rate Threshold"), 0.1).toFloat(); minimumSimulationTimeHorizon = settings.value(QStringLiteral("Minimum Simulation Time Horizon"), 0).toInt(); maximumSimulationTimeHorizon = settings.value(QStringLiteral("Maximum Simulation Time Horizon"), 0).toInt(); simulationTimeHorizon = settings.value(QStringLiteral("Simulation Time Horizon"), 0.3).toFloat(); tpxTimehorizon = settings.value(QStringLiteral("Targeted Pattern Extractor Time Horizon"), 500000).toInt(); perfSamplingPeriod = settings.value(QStringLiteral("Perf Sampling Period"), 250000).toInt(); floatTolerance = settings.value(QStringLiteral("Float Tolerance"), 0.00001).toFloat(); timeTolerance = settings.value(QStringLiteral("Timer Tolerance"), 10000).toInt(); primaryTimeHorizon = settings.value(QStringLiteral("Primary Time Horizon"), 3600000).toInt(); secondaryTimeHorizon = settings.value(QStringLiteral("Secondary Time Horizon"), 7200000).toInt(); settings.endGroup(); settings.beginGroup(QStringLiteral("Debug")); debug = settings.value(QStringLiteral("Debug"), true).toBool(); debugWindows = settings.value(QStringLiteral("Debug Windows"), 1).toInt(); - traceLevels = settings.value(QStringLiteral("Trace Levels"), QStringLiteral("CC")).toString().toInt(0, 16); + traceLevels = settings.value(QStringLiteral("Trace Levels"), QStringLiteral("CC")).toString().toInt(nullptr, 16); settings.endGroup(); settings.beginGroup(QStringLiteral("Resilience")); notificationMarkerResilience = settings.value(QStringLiteral("Notification Marker Resilience"), 1).toInt(); goalPredictionSuccessResilience = settings.value(QStringLiteral("Goal Prediction Success Resilience"), 1000).toInt(); settings.endGroup(); settings.beginGroup(QStringLiteral("Objects")); getObjects = settings.value(QStringLiteral("Get Objects"), true).toBool(); decompileObjects = settings.value(QStringLiteral("Decompile Objects"), true).toBool(); decompilationFilePath = settings.value(QStringLiteral("Decompilation Files Paths"), QString()).toString(); ignoreNamedObjects = settings.value(QStringLiteral("Ignore Named Objects"), false).toBool(); objectsPath = settings.value(QStringLiteral("Objects Path"), QString()).toString(); testObjects = settings.value(QStringLiteral("Test Objects"), false).toBool(); settings.endGroup(); settings.beginGroup(QStringLiteral("Run")); runTime = settings.value(QStringLiteral("Run Time"), 1080).toInt(); probeLevel = settings.value(QStringLiteral("Probe Level"), 2).toInt(); settings.endGroup(); settings.beginGroup(QStringLiteral("Models")); getModels = settings.value(QStringLiteral("Get Models"), false).toBool(); decompileModels = settings.value(QStringLiteral("Decompile Models"), false).toBool(); ignoreNamedModels = settings.value(QStringLiteral("Ignore Named Models"), true).toBool(); modelsPath = settings.value(QStringLiteral("Models Path"), QString()).toString(); testModels = settings.value(QStringLiteral("Test Models"), false).toBool(); settings.endGroup(); } void ReplicodeSettings::save() { QSettings settings(QStringLiteral("replicode"), QStringLiteral("replicode")); settings.beginGroup(QStringLiteral("Load")); settings.setValue(QStringLiteral("User Operator Module Path"), userOperatorPath); settings.setValue(QStringLiteral("User Class File Path"), userClassPath); settings.setValue(QStringLiteral("Source File Path"), sourcePath); settings.endGroup(); settings.beginGroup(QStringLiteral("Init")); settings.setValue(QStringLiteral("Base Period"), basePeriod); settings.setValue(QStringLiteral("Reduction Core Count"), reductionCoreCount); settings.setValue(QStringLiteral("Time Core Count"), timeCoreCount); settings.endGroup(); settings.beginGroup(QStringLiteral("System")); settings.setValue(QStringLiteral("Model Inertia Success Rate Threshold"), mdlInertiaSuccessRateThreshold); settings.setValue(QStringLiteral("Model Inertia Count Threshold"), mdlInertiaCountThreshold); settings.setValue(QStringLiteral("Targeted Pattern Extractor Delta Success Rate Threshold"), tpxDeltaSuccessRateThreshold); settings.setValue(QStringLiteral("Minimum Simulation Time Horizon"), minimumSimulationTimeHorizon); settings.setValue(QStringLiteral("Maximum Simulation Time Horizon"), maximumSimulationTimeHorizon); settings.setValue(QStringLiteral("Simulation Time Horizon"), simulationTimeHorizon); settings.setValue(QStringLiteral("Targeted Pattern Extractor Time Horizon"), tpxTimehorizon); settings.setValue(QStringLiteral("Perf Sampling Period"), perfSamplingPeriod); settings.setValue(QStringLiteral("Float Tolerance"), floatTolerance); settings.setValue(QStringLiteral("Timer Tolerance"), timeTolerance); settings.setValue(QStringLiteral("Primary Time Horizon"), primaryTimeHorizon); settings.setValue(QStringLiteral("Secondary Time Horizon"), secondaryTimeHorizon); settings.endGroup(); settings.beginGroup(QStringLiteral("Debug")); settings.setValue(QStringLiteral("Debug"), debug); settings.setValue(QStringLiteral("Debug Windows"), debugWindows); settings.setValue(QStringLiteral("Trace Levels"), QString::number(traceLevels, 16)); settings.endGroup(); settings.beginGroup(QStringLiteral("Resilience")); settings.setValue(QStringLiteral("Notification Marker Resilience"), notificationMarkerResilience); settings.setValue(QStringLiteral("Goal Prediction Success Resilience"), goalPredictionSuccessResilience); settings.endGroup(); settings.beginGroup(QStringLiteral("Objects")); settings.setValue(QStringLiteral("Get Objects"), getObjects); settings.setValue(QStringLiteral("Decompile Objects"), decompileObjects); settings.setValue(QStringLiteral("Decompilation Files Paths"), decompilationFilePath); settings.setValue(QStringLiteral("Ignore Named Objects"), ignoreNamedObjects); settings.setValue(QStringLiteral("Objects Path"), objectsPath); settings.setValue(QStringLiteral("Test Objects"), testObjects); settings.endGroup(); settings.beginGroup(QStringLiteral("Run")); settings.setValue(QStringLiteral("Run Time"), runTime); settings.setValue(QStringLiteral("Probe Level"), probeLevel); settings.endGroup(); settings.beginGroup(QStringLiteral("Models")); settings.setValue(QStringLiteral("Get Models"), getModels); settings.setValue(QStringLiteral("Decompile Models"), decompileModels); settings.setValue(QStringLiteral("Ignore Named Models"), ignoreNamedModels); settings.setValue(QStringLiteral("Models Path"), modelsPath); settings.setValue(QStringLiteral("Test Models"), testModels); } void ReplicodeSettings::setDefaults() { // Load userOperatorPath = QString(); userClassPath = QString(); sourcePath = QString(); // Init basePeriod = 50000; reductionCoreCount = 6; timeCoreCount = 2; // System mdlInertiaSuccessRateThreshold = 0.9f; mdlInertiaCountThreshold = 6; tpxDeltaSuccessRateThreshold = 0.1f; minimumSimulationTimeHorizon = 0; maximumSimulationTimeHorizon = 0; simulationTimeHorizon = 0.3f; tpxTimehorizon = 500000; perfSamplingPeriod = 250000; floatTolerance = 0.00001f; timeTolerance = 10000; primaryTimeHorizon = 3600000; secondaryTimeHorizon = 7200000; //Debug debug = true; debugWindows = 1; traceLevels = 0xCC; // Debug Resilience notificationMarkerResilience = 1; goalPredictionSuccessResilience = 1000; // Debug Objects getObjects = true; decompileObjects = true; decompilationFilePath = QString(); ignoreNamedObjects = false; objectsPath = QString(); testObjects = false; // Run runTime = 1080; probeLevel = 2; getModels = false; decompileModels = false; ignoreNamedModels = true; modelsPath = QString(); testModels = false; } diff --git a/addons/replicode/replicodesettings.h b/addons/replicode/replicodesettings.h index 537d49c27..c7ce2fe3e 100644 --- a/addons/replicode/replicodesettings.h +++ b/addons/replicode/replicodesettings.h @@ -1,97 +1,97 @@ /* 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. */ #ifndef REPLICODESETTINGS_H #define REPLICODESETTINGS_H #include class QIODevice; class ReplicodeSettings : public QObject { Q_OBJECT public: - explicit ReplicodeSettings(QObject *parent = 0); + explicit ReplicodeSettings(QObject *parent = nullptr); void load(); void save(); void setDefaults(); /////// // Load QString userOperatorPath; QString userClassPath; QString sourcePath; /////// // Init int basePeriod; int reductionCoreCount; int timeCoreCount; ///////// // System int perfSamplingPeriod; float floatTolerance; int timeTolerance; int primaryTimeHorizon; int secondaryTimeHorizon; // Model float mdlInertiaSuccessRateThreshold; int mdlInertiaCountThreshold; // Targeted Pattern Extractor float tpxDeltaSuccessRateThreshold; int tpxTimehorizon; // Simulation int minimumSimulationTimeHorizon; int maximumSimulationTimeHorizon; float simulationTimeHorizon; //////// // Debug bool debug; int notificationMarkerResilience; int goalPredictionSuccessResilience; int debugWindows; int traceLevels; bool getObjects; bool decompileObjects; QString decompilationFilePath; bool ignoreNamedObjects; QString objectsPath; bool testObjects; ////// // Run int runTime; int probeLevel; bool getModels; bool decompileModels; bool ignoreNamedModels; QString modelsPath; bool testModels; }; #endif // REPLICODESETTINGS_H diff --git a/addons/replicode/replicodeview.cpp b/addons/replicode/replicodeview.cpp index 7d07844bc..68b4a6699 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(0) + 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())); 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())); 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*))); 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())); m_mainWindow->guiFactory()->addClient(this); connect(m_mainWindow, SIGNAL(viewChanged(KTextEditor::View*)), SLOT(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))); 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/rustcompletion/kterustcompletion.cpp b/addons/rustcompletion/kterustcompletion.cpp index 451cf9528..ff6af855d 100644 --- a/addons/rustcompletion/kterustcompletion.cpp +++ b/addons/rustcompletion/kterustcompletion.cpp @@ -1,221 +1,221 @@ /*************************************************************************** * Copyright (C) 2012 Christoph Cullmann * * Copyright (C) 2003 Anders Lund * * Copyright (C) 2015 by Eike Hein * * * * 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 "kterustcompletion.h" #include "kterustcompletionplugin.h" #include #include #include #include #include #include KTERustCompletion::KTERustCompletion(KTERustCompletionPlugin *plugin) - : KTextEditor::CodeCompletionModel(0) + : KTextEditor::CodeCompletionModel(nullptr) , m_plugin(plugin) { } KTERustCompletion::~KTERustCompletion() { } QVariant KTERustCompletion::data(const QModelIndex &index, int role) const { if (!index.isValid() || index.row() >= m_matches.size()) { return QVariant(); } const CompletionMatch &match = m_matches.at(index.row()); if (index.column() == KTextEditor::CodeCompletionModel::Name && role == Qt::DisplayRole) { return match.text; } else if (index.column() == KTextEditor::CodeCompletionModel::Icon && role == Qt::DecorationRole) { return match.icon; } else if (role == KTextEditor::CodeCompletionModel::CompletionRole) { return (int)match.type; } else if (role == KTextEditor::CodeCompletionModel::ArgumentHintDepth) { return match.depth; } else if (role == KTextEditor::CodeCompletionModel::MatchQuality) { if (index.row() < 10) { return 10 - index.row(); } else { return 0; } } else if (role == KTextEditor::CodeCompletionModel::BestMatchesCount) { return (index.row() < 10) ? 1 : 0; } return QVariant(); } bool KTERustCompletion::shouldStartCompletion(KTextEditor::View *view, const QString &insertedText, bool userInsertion, const KTextEditor::Cursor &position) { if (!userInsertion) { return false; } if (insertedText.isEmpty()) { return false; } bool complete = CodeCompletionModelControllerInterface::shouldStartCompletion(view, insertedText, userInsertion, position); complete = complete || insertedText.endsWith(QStringLiteral("(")); complete = complete || insertedText.endsWith(QStringLiteral(".")); complete = complete || insertedText.endsWith(QStringLiteral("::")); return complete; } void KTERustCompletion::completionInvoked(KTextEditor::View *view, const KTextEditor::Range &range, InvocationType it) { Q_UNUSED(it) beginResetModel(); m_matches = getMatches(view->document(), Complete, range.end()); setRowCount(m_matches.size()); setHasGroups(false); endResetModel(); } void KTERustCompletion::aborted(KTextEditor::View *view) { Q_UNUSED(view); beginResetModel(); m_matches.clear(); endResetModel(); } QList KTERustCompletion::getMatches(const KTextEditor::Document *document, MatchAction action, const KTextEditor::Cursor &position) { QList matches; if (!m_plugin->configOk()) { return matches; } QTemporaryFile file; if (file.open()) { { QTextStream out(&file); out.setCodec("UTF-8"); out << document->text(); } QProcess proc; QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); env.insert(QStringLiteral("LC_ALL"), QStringLiteral("C")); env.insert(QStringLiteral("RUST_SRC_PATH"), m_plugin->rustSrcPath().toLocalFile()); proc.setProcessEnvironment(env); QStringList args; args << (action == Complete ? QStringLiteral("complete") : QStringLiteral("find-definition")); args << QString::number(position.line() + 1); args << QString::number(position.column()); args << file.fileName(); proc.start(m_plugin->racerCmd(), args, QIODevice::ReadOnly); if (proc.waitForFinished(1000)) { const QString &output = QString::fromUtf8(proc.readAllStandardOutput()); QStringList lines(output.split(QStringLiteral("\n"), QString::SkipEmptyParts)); foreach(QString line, lines) { if (line.startsWith(QStringLiteral("MATCH "))) { line = line.mid(6); CompletionMatch match; match.text = line.section(QStringLiteral(","), 0, 0); const QString &type = line.section(QStringLiteral(","), 4, 4); match.depth = (type == QStringLiteral("StructField")) ? 1 : 0; addType(match, type); QString path = line.section(QStringLiteral(","), 3, 3); if (path == file.fileName()) { match.url = document->url(); } else { match.url = QUrl::fromLocalFile(path); } bool ok = false; int row = line.section(QStringLiteral(","), 1, 1).toInt(&ok); if (ok) match.line = row - 1; int col = line.section(QStringLiteral(","), 2, 2).toInt(&ok); if (ok) match.col = col; matches.append(match); if (action == FindDefinition) { break; } } } } } return matches; } void KTERustCompletion::addType(CompletionMatch &match, const QString &type) { if (type == QStringLiteral("Function")) { match.type = CodeCompletionModel::Function; match.icon = QIcon::fromTheme(QStringLiteral("code-function")); } else if (type == QStringLiteral("Struct")) { match.type = CodeCompletionModel::Struct; match.icon = QIcon::fromTheme(QStringLiteral("code-class")); } else if (type == QStringLiteral("StructField")) { match.icon = QIcon::fromTheme(QStringLiteral("field")); } else if (type == QStringLiteral("Trait")) { match.type = CodeCompletionModel::Class; match.icon = QIcon::fromTheme(QStringLiteral("code-class")); } else if (type == QStringLiteral("Module")) { match.type = CodeCompletionModel::Namespace; match.icon = QIcon::fromTheme(QStringLiteral("field")); } else if (type == QStringLiteral("Crate")) { match.type = CodeCompletionModel::Namespace; match.icon = QIcon::fromTheme(QStringLiteral("field")); } else if (type == QStringLiteral("Let")) { match.type = CodeCompletionModel::Variable; match.icon = QIcon::fromTheme(QStringLiteral("code-variable")); } else if (type == QStringLiteral("Enum")) { match.type = CodeCompletionModel::Enum; match.icon = QIcon::fromTheme(QStringLiteral("icon")); } } diff --git a/addons/rustcompletion/kterustcompletionplugin.cpp b/addons/rustcompletion/kterustcompletionplugin.cpp index d196bdffe..32eef5a9f 100644 --- a/addons/rustcompletion/kterustcompletionplugin.cpp +++ b/addons/rustcompletion/kterustcompletionplugin.cpp @@ -1,147 +1,147 @@ /*************************************************************************** * Copyright (C) 2015 by Eike Hein * * * * 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 "kterustcompletionplugin.h" #include "kterustcompletionpluginview.h" #include "kterustcompletionconfigpage.h" #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KTERustCompletionPluginFactory, "kterustcompletionplugin.json", registerPlugin();) KTERustCompletionPlugin::KTERustCompletionPlugin(QObject *parent, const QList &) : KTextEditor::Plugin(parent), m_completion(this), - m_rustSrcWatch(0), + m_rustSrcWatch(nullptr), m_configOk(false) { readConfig(); } KTERustCompletionPlugin::~KTERustCompletionPlugin() { } QObject *KTERustCompletionPlugin::createView(KTextEditor::MainWindow *mainWindow) { return new KTERustCompletionPluginView(this, mainWindow); } int KTERustCompletionPlugin::configPages() const { return 1; } KTextEditor::ConfigPage *KTERustCompletionPlugin::configPage(int number, QWidget *parent) { if (number != 0) { return nullptr; } return new KTERustCompletionConfigPage(parent, this); } KTERustCompletion *KTERustCompletionPlugin::completion() { return &m_completion; } QString KTERustCompletionPlugin::racerCmd() const { return m_racerCmd; } void KTERustCompletionPlugin::setRacerCmd(const QString &cmd) { if (cmd != m_racerCmd) { m_racerCmd = cmd; writeConfig(); updateConfigOk(); } } QUrl KTERustCompletionPlugin::rustSrcPath() const { return m_rustSrcPath; } void KTERustCompletionPlugin::setRustSrcPath(const QUrl &path) { if (path != m_rustSrcPath) { m_rustSrcPath = path; writeConfig(); updateConfigOk(); } } bool KTERustCompletionPlugin::configOk() const { return m_configOk; } void KTERustCompletionPlugin::updateConfigOk() { m_configOk = false; if (m_rustSrcPath.isLocalFile()) { QString path = m_rustSrcPath.toLocalFile(); if (QDir(path).exists()) { m_configOk = true; if (m_rustSrcWatch && !m_rustSrcWatch->contains(path)) { delete m_rustSrcWatch; m_rustSrcWatch = nullptr; } if (!m_rustSrcWatch) { m_rustSrcWatch = new KDirWatch(this); m_rustSrcWatch->addDir(path, KDirWatch::WatchDirOnly); connect(m_rustSrcWatch, &KDirWatch::deleted, this, &KTERustCompletionPlugin::updateConfigOk, Qt::UniqueConnection); } } } } void KTERustCompletionPlugin::readConfig() { KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("kterustcompletion")); m_racerCmd = config.readEntry(QStringLiteral("racerCmd"), QStringLiteral("racer")); m_rustSrcPath = config.readEntry(QStringLiteral("rustSrcPath"), QUrl(QStringLiteral("/usr/local/src/rust/src"))); updateConfigOk(); } void KTERustCompletionPlugin::writeConfig() { KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("kterustcompletion")); config.writeEntry(QStringLiteral("racerCmd"), m_racerCmd); config.writeEntry(QStringLiteral("rustSrcPath"), m_rustSrcPath); } #include "kterustcompletionplugin.moc" diff --git a/addons/rustcompletion/kterustcompletionplugin.h b/addons/rustcompletion/kterustcompletionplugin.h index 8da86ff38..ffc7c63a2 100644 --- a/addons/rustcompletion/kterustcompletionplugin.h +++ b/addons/rustcompletion/kterustcompletionplugin.h @@ -1,71 +1,71 @@ /*************************************************************************** * Copyright (C) 2015 by Eike Hein * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ #ifndef KTERUSTCOMPLETIONPLUGIN_H #define KTERUSTCOMPLETIONPLUGIN_H #include "kterustcompletion.h" #include #include #include class KDirWatch; class KTERustCompletionPlugin : public KTextEditor::Plugin { Q_OBJECT public: - explicit KTERustCompletionPlugin(QObject *parent = 0, const QList & = QList()); + explicit KTERustCompletionPlugin(QObject *parent = nullptr, const QList & = QList()); virtual ~KTERustCompletionPlugin(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; int configPages() const Q_DECL_OVERRIDE; - KTextEditor::ConfigPage *configPage(int number = 0, QWidget *parent = 0) Q_DECL_OVERRIDE; + KTextEditor::ConfigPage *configPage(int number = 0, QWidget *parent = nullptr) Q_DECL_OVERRIDE; KTERustCompletion *completion(); QString racerCmd() const; void setRacerCmd(const QString &cmd); QUrl rustSrcPath() const; void setRustSrcPath(const QUrl &path); bool configOk() const; private Q_SLOTS: void updateConfigOk(); private: void readConfig(); void writeConfig(); KTERustCompletion m_completion; QString m_racerCmd; QUrl m_rustSrcPath; KDirWatch *m_rustSrcWatch; bool m_configOk; }; #endif diff --git a/addons/search/FolderFilesList.h b/addons/search/FolderFilesList.h index 6f0476698..2e5f339db 100644 --- a/addons/search/FolderFilesList.h +++ b/addons/search/FolderFilesList.h @@ -1,75 +1,75 @@ /* Kate search plugin * * Copyright (C) 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. */ #ifndef FolderFilesList_h #define FolderFilesList_h #include #include #include #include #include #include class FolderFilesList: public QThread { Q_OBJECT public: - FolderFilesList(QObject *parent = 0); + FolderFilesList(QObject *parent = nullptr); ~FolderFilesList(); void run() Q_DECL_OVERRIDE; void generateList(const QString &folder, bool recursive, bool hidden, bool symlinks, bool binary, const QString &types, const QString &excludes); QStringList fileList(); public Q_SLOTS: void cancelSearch(); Q_SIGNALS: void searching(const QString &path); private: void checkNextItem(const QFileInfo &item); private: QString m_folder; QStringList m_files; bool m_cancelSearch; bool m_recursive; bool m_hidden; bool m_symlinks; bool m_binary; QStringList m_types; QVector m_excludeList; QTime m_time; }; #endif diff --git a/addons/search/SearchDiskFiles.h b/addons/search/SearchDiskFiles.h index 869466946..04a09862f 100644 --- a/addons/search/SearchDiskFiles.h +++ b/addons/search/SearchDiskFiles.h @@ -1,68 +1,68 @@ /* 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. */ #ifndef SearchDiskFiles_h #define SearchDiskFiles_h #include #include #include #include #include #include #include class SearchDiskFiles: public QThread { Q_OBJECT public: - SearchDiskFiles(QObject *parent = 0); + SearchDiskFiles(QObject *parent = nullptr); ~SearchDiskFiles(); void startSearch(const QStringList &iles, const QRegularExpression ®exp); void run() Q_DECL_OVERRIDE; bool searching(); private: void searchSingleLineRegExp(const QString &fileName); void searchMultiLineRegExp(const QString &fileName); public Q_SLOTS: void cancelSearch(); Q_SIGNALS: void matchFound(const QString &url, const QString &docName, int line, int column, const QString &lineContent, int matchLen); void searchDone(); void searching(const QString &file); private: QRegularExpression m_regExp; QStringList m_files; bool m_cancelSearch; int m_matchCount; QTime m_statusTime; }; #endif diff --git a/addons/search/plugin_search.cpp b/addons/search/plugin_search.cpp index 707baed61..6f6cfdf72 100644 --- a/addons/search/plugin_search.cpp +++ b/addons/search/plugin_search.cpp @@ -1,2173 +1,2173 @@ /* 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 0; + 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 Q_DECL_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(0) + 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, 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(0), +m_curResults(nullptr), m_searchJustOpened(false), m_switchToProjectModeWhenAvailable(false), m_searchDiskFilesDone(true), m_searchOpenFilesDone(true), -m_projectPluginView(0), +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))); 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())); 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())); a = actionCollection()->addAction(QStringLiteral("go_to_next_match")); a->setText(i18n("Go to Next Match")); connect(a, SIGNAL(triggered(bool)), this, SLOT(goToNextMatch())); a = actionCollection()->addAction(QStringLiteral("go_to_prev_match")); a->setText(i18n("Go to Previous Match")); connect(a, SIGNAL(triggered(bool)), this, SLOT(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.folderUpButton, SIGNAL(clicked()), this, SLOT(navigateFolderUp())); connect(m_ui.currentFolderButton, SIGNAL(clicked()), this, SLOT(setCurrentFolder())); 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) { 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) { 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_ui.searchCombo->lineEdit(), SIGNAL(returnPressed()), this, SLOT(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.displayOptions, SIGNAL(toggled(bool)), this, SLOT(toggleOptions(bool))); connect(m_ui.searchPlaceCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(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.nextButton, SIGNAL(clicked()), this, SLOT(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())); 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_folderFilesList, SIGNAL(finished()), this, SLOT(folderFileListChanged())); connect(&m_folderFilesList, SIGNAL(searching(QString)), this, SLOT(searching(QString))); 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_kateApp, SIGNAL(documentWillBeDeleted(KTextEditor::Document*)), &m_searchOpenFiles, SLOT(cancelSearch())); connect(m_kateApp, SIGNAL(documentWillBeDeleted(KTextEditor::Document*)), &m_replacer, SLOT(cancelReplace())); connect(m_kateApp, SIGNAL(documentWillBeDeleted(KTextEditor::Document*)), this, SLOT(clearDocMarks(KTextEditor::Document*))); connect(&m_replacer, SIGNAL(matchReplaced(KTextEditor::Document*,int,int,int)), this, SLOT(addMatchMark(KTextEditor::Document*,int,int,int))); 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))); 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*))); // watch for project plugin view creation/deletion connect(m_mainWindow, SIGNAL(pluginViewCreated (const QString &, QObject *)) , this, SLOT(slotPluginViewCreated (const QString &, QObject *))); connect(m_mainWindow, SIGNAL(pluginViewDeleted (const QString &, QObject *)) , this, SLOT(slotPluginViewDeleted (const QString &, QObject *))); connect(m_mainWindow, SIGNAL(viewChanged(KTextEditor::View *)), this, SLOT(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())); 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 0; + 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() == 0) || (sender() == m_ui.replaceButton)); + 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); m_curResults->tree->expandItem(root); if (root && (root->childCount() > 1) && (!m_ui.expandResults->isChecked())) { for (int i=0; ichildCount(); i++) { m_curResults->tree->collapseItem(root->child(i)); } } 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 = 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 = 0; + 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 = 0; + 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 = 0; + 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::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()==0) ? item : item->parent(); + 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); 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 = 0; + 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 = 0; + 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/plugin_search.h b/addons/search/plugin_search.h index 1b820868e..700115587 100644 --- a/addons/search/plugin_search.h +++ b/addons/search/plugin_search.h @@ -1,237 +1,237 @@ /* 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. */ #ifndef _PLUGIN_SEARCH_H_ #define _PLUGIN_SEARCH_H_ #include #include #include #include #include #include #include #include #include #include #include "ui_search.h" #include "ui_results.h" #include "search_open_files.h" #include "SearchDiskFiles.h" #include "FolderFilesList.h" #include "replace_matches.h" class KateSearchCommand; namespace KTextEditor{ class MovingRange; } class Results: public QWidget, public Ui::Results { Q_OBJECT public: - Results(QWidget *parent = 0); + Results(QWidget *parent = nullptr); int matches; QRegularExpression regExp; bool useRegExp; bool matchCase; QString replaceStr; int searchPlaceIndex; QString treeRootText; }; // This class keeps the focus inside the S&R plugin when pressing tab/shift+tab by overriding focusNextPrevChild() class ContainerWidget:public QWidget { Q_OBJECT public: ContainerWidget(QWidget *parent): QWidget(parent) {} Q_SIGNALS: void nextFocus(QWidget *currentWidget, bool *found, bool next); protected: bool focusNextPrevChild (bool next) Q_DECL_OVERRIDE; }; class KatePluginSearch : public KTextEditor::Plugin { Q_OBJECT public: - explicit KatePluginSearch(QObject* parent = 0, const QList& = QList()); + explicit KatePluginSearch(QObject* parent = nullptr, const QList& = QList()); virtual ~KatePluginSearch(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; private: KateSearchCommand* m_searchCommand; }; class KatePluginSearchView : public QObject, public KXMLGUIClient, public KTextEditor::SessionConfigInterface { Q_OBJECT Q_INTERFACES(KTextEditor::SessionConfigInterface) public: enum SearchPlaces { CurrentFile, OpenFiles, Folder, Project, AllProjects }; KatePluginSearchView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWindow, KTextEditor::Application* application); ~KatePluginSearchView(); void readSessionConfig (const KConfigGroup& config) Q_DECL_OVERRIDE; void writeSessionConfig (KConfigGroup& config) Q_DECL_OVERRIDE; public Q_SLOTS: void startSearch(); void setSearchString(const QString &pattern); void navigateFolderUp(); void setCurrentFolder(); void setSearchPlace(int place); void goToNextMatch(); void goToPreviousMatch(); private Q_SLOTS: void openSearchView(); void handleEsc(QEvent *e); void nextFocus(QWidget *currentWidget, bool *found, bool next); void addTab(); void tabCloseRequested(int index); void toggleOptions(bool show); void searchContextMenu(const QPoint& pos); void searchPlaceChanged(); void startSearchWhileTyping(); void folderFileListChanged(); void matchFound(const QString &url, const QString &fileName, int line, int column, const QString &lineContent, int matchLen); void addMatchMark(KTextEditor::Document* doc, int line, int column, int len); void searchDone(); void searchWhileTypingDone(); void indicateMatch(bool hasMatch); void searching(const QString &file); void itemSelected(QTreeWidgetItem *item); void clearMarks(); void clearDocMarks(KTextEditor::Document* doc); void replaceSingleMatch(); void replaceChecked(); void replaceStatus(const QUrl &url); void replaceDone(); void docViewChanged(); void resultTabChanged(int index); /** * keep track if the project plugin is alive and if the project file did change */ void slotPluginViewCreated (const QString &name, QObject *pluginView); void slotPluginViewDeleted (const QString &name, QObject *pluginView); void slotProjectFileNameChanged (); protected: bool eventFilter(QObject *obj, QEvent *ev) Q_DECL_OVERRIDE; void addHeaderItem(); private: QTreeWidgetItem *rootFileItem(const QString &url, const QString &fName); QStringList filterFiles(const QStringList& files) const; Ui::SearchDialog m_ui; QWidget *m_toolView; KTextEditor::Application *m_kateApp; SearchOpenFiles m_searchOpenFiles; FolderFilesList m_folderFilesList; SearchDiskFiles m_searchDiskFiles; ReplaceMatches m_replacer; QAction *m_matchCase; QAction *m_useRegExp; Results *m_curResults; bool m_searchJustOpened; bool m_switchToProjectModeWhenAvailable; bool m_searchDiskFilesDone; bool m_searchOpenFilesDone; QString m_resultBaseDir; QList m_matchRanges; QTimer m_changeTimer; QPointer m_infoMessage; /** * current project plugin view, if any */ QObject *m_projectPluginView; /** * our main window */ KTextEditor::MainWindow *m_mainWindow; }; class KateSearchCommand : public KTextEditor::Command { Q_OBJECT public: KateSearchCommand(QObject *parent); Q_SIGNALS: void setSearchPlace(int place); void setCurrentFolder(); void setSearchString(const QString &pattern); void startSearch(); void newTab(); // // KTextEditor::Command // public: bool exec (KTextEditor::View *view, const QString &cmd, QString &msg, const KTextEditor::Range &range = KTextEditor::Range::invalid()) Q_DECL_OVERRIDE; bool help (KTextEditor::View *view, const QString &cmd, QString &msg) Q_DECL_OVERRIDE; }; #endif // 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 30e6a7c17..94e42b4e1 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(0), -m_tree(0), +m_manager(nullptr), +m_tree(nullptr), m_rootIndex(-1) { connect(this, SIGNAL(replaceNextMatch()), this, SLOT(doReplaceNextMatch()), Qt::QueuedConnection); } void ReplaceMatches::replaceChecked(QTreeWidget *tree, const QRegularExpression ®exp, const QString &replace) { - if (m_manager == 0) return; + 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 0; + 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/replace_matches.h b/addons/search/replace_matches.h index 54490700c..7364373a0 100644 --- a/addons/search/replace_matches.h +++ b/addons/search/replace_matches.h @@ -1,77 +1,77 @@ /* Kate search plugin * * Copyright (C) 2011 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. */ #ifndef _REPLACE_MATCHES_H_ #define _REPLACE_MATCHES_H_ #include #include #include #include #include #include class ReplaceMatches: public QObject { Q_OBJECT public: enum MatchData { FileUrlRole = Qt::UserRole, FileNameRole, LineRole, ColumnRole, MatchLenRole, PreMatchRole, MatchRole, PostMatchRole }; - ReplaceMatches(QObject *parent = 0); + ReplaceMatches(QObject *parent = nullptr); void setDocumentManager(KTextEditor::Application *manager); void replaceChecked(QTreeWidget *tree, const QRegularExpression ®exp, const QString &replace); KTextEditor::Document *findNamed(const QString &name); public Q_SLOTS: void cancelReplace(); private Q_SLOTS: void doReplaceNextMatch(); Q_SIGNALS: void replaceNextMatch(); void matchReplaced(KTextEditor::Document* doc, int line, int column, int matchLen); void replaceStatus(const QUrl &url); void replaceDone(); private: KTextEditor::Application *m_manager; QTreeWidget *m_tree; int m_rootIndex; QRegularExpression m_regExp; QString m_replaceText; bool m_cancelReplace; QElapsedTimer m_progressTime; }; #endif diff --git a/addons/search/search_open_files.h b/addons/search/search_open_files.h index 541a1bc57..01267d12d 100644 --- a/addons/search/search_open_files.h +++ b/addons/search/search_open_files.h @@ -1,69 +1,69 @@ /* 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. */ #ifndef _SEARCH_OPEN_FILES_H_ #define _SEARCH_OPEN_FILES_H_ #include #include #include #include class SearchOpenFiles: public QObject { Q_OBJECT public: - SearchOpenFiles(QObject *parent = 0); + SearchOpenFiles(QObject *parent = nullptr); void startSearch(const QList &list,const QRegularExpression ®exp); bool searching(); public Q_SLOTS: void cancelSearch(); /// return 0 on success or a line number where we stopped. int searchOpenFile(KTextEditor::Document *doc, const QRegularExpression ®Exp, int startLine); private Q_SLOTS: void doSearchNextFile(int startLine); private: int searchSingleLineRegExp(KTextEditor::Document *doc, const QRegularExpression ®Exp, int startLine); int searchMultiLineRegExp(KTextEditor::Document *doc, const QRegularExpression ®Exp, int startLine); Q_SIGNALS: void searchNextFile(int startLine); void matchFound(const QString &url, const QString &fileName, int line, int column, const QString &lineContent, int matchLen); void searchDone(); void searching(const QString &file); private: QList m_docList; int m_nextIndex; QRegularExpression m_regExp; bool m_cancelSearch; QString m_fullDoc; QVector m_lineStart; QTime m_statusTime; }; #endif diff --git a/addons/sessionapplet/engine/katesessionsjob.h b/addons/sessionapplet/engine/katesessionsjob.h index 2116e0cdb..a2c3df291 100644 --- a/addons/sessionapplet/engine/katesessionsjob.h +++ b/addons/sessionapplet/engine/katesessionsjob.h @@ -1,41 +1,41 @@ /******************************************************************** This file is part of the KDE project. Copyright (C) 2014 Joseph Wenninger based on clipboard engine: Copyright (C) 2014 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #ifndef KLIPPER_CLIPBOARDJOB_H #define KLIPPER_CLIPBOARDJOB_H #include class KateSessionsEngine; class KateSessionsJob : public Plasma::ServiceJob { Q_OBJECT public: - KateSessionsJob(KateSessionsEngine* engine,const QString &destination, const QString &operation, const QVariantMap ¶meters, QObject *parent=0); + KateSessionsJob(KateSessionsEngine* engine,const QString &destination, const QString &operation, const QVariantMap ¶meters, QObject *parent=nullptr); ~KateSessionsJob() = default; void start() override; private: KateSessionsEngine *m_engine; }; #endif diff --git a/addons/snippets/editrepository.cpp b/addons/snippets/editrepository.cpp index 0c9b48a5b..8517e7513 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())); auto cancel = buttonBox->button(QDialogButtonBox::Cancel); KGuiItem::assign(cancel, KStandardGuiItem::cancel()); connect(cancel, SIGNAL(clicked()), this, SLOT(reject())); // fill list of available modes - QSharedPointer document(KTextEditor::Editor::instance()->createDocument(0)); + 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/snippets/editrepository.h b/addons/snippets/editrepository.h index b34c7c6c4..813dc905c 100644 --- a/addons/snippets/editrepository.h +++ b/addons/snippets/editrepository.h @@ -1,57 +1,57 @@ /* 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 * * 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. */ #ifndef EDITREPOSITORY_H #define EDITREPOSITORY_H #include "ui_editrepository.h" #include class SnippetRepository; /** * This dialog is used to create/edit snippet repositories and * the snippets in them. * * @author Milian Wolff */ class EditRepository : public QDialog, public Ui::EditRepositoryBase { Q_OBJECT public: /// @p repo set to 0 when you want to create a new repository. - explicit EditRepository(SnippetRepository* repo, QWidget* parent = 0); + explicit EditRepository(SnippetRepository* repo, QWidget* parent = nullptr); private: SnippetRepository* m_repo; private Q_SLOTS: void save(); void validate(); void updateFileTypes(); }; #endif diff --git a/addons/snippets/editsnippet.h b/addons/snippets/editsnippet.h index 6f25afad6..ac3bd0126 100644 --- a/addons/snippets/editsnippet.h +++ b/addons/snippets/editsnippet.h @@ -1,74 +1,74 @@ /* 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 * * 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. */ #ifndef EDITSNIPPET_H #define EDITSNIPPET_H #include namespace KTextEditor { class View; } class SnippetRepository; class Snippet; namespace Ui { class EditSnippetBase; } /** * This dialog is used to create/edit snippets in a given repository. * * @author Milian Wolff */ class EditSnippet : public QDialog { Q_OBJECT public: /// @p snippet set to 0 when you want to create a new snippet. - explicit EditSnippet(SnippetRepository* repo, Snippet* snippet, QWidget* parent = 0); + explicit EditSnippet(SnippetRepository* repo, Snippet* snippet, QWidget* parent = nullptr); virtual ~EditSnippet(); void setSnippetText(const QString& text); void reject() Q_DECL_OVERRIDE; private: Ui::EditSnippetBase* m_ui; SnippetRepository* m_repo; Snippet* m_snippet; KTextEditor::View* m_snippetView; KTextEditor::View* m_scriptsView; KTextEditor::View* m_testView; bool m_topBoxModified; QPushButton* m_okButton; private Q_SLOTS: void test(); void save(); void validate(); void topBoxModified(); }; #endif diff --git a/addons/snippets/katesnippetglobal.cpp b/addons/snippets/katesnippetglobal.cpp index 8e318bf67..8932ae503 100644 --- a/addons/snippets/katesnippetglobal.cpp +++ b/addons/snippets/katesnippetglobal.cpp @@ -1,128 +1,128 @@ /* This file is part of the Kate project. * Based on the snippet plugin from KDevelop 4. * * Copyright (C) 2007 Robert Gruber * 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 "katesnippetglobal.h" #include "snippetcompletionmodel.h" #include "snippetstore.h" #include "snippet.h" #include "snippetrepository.h" #include "snippetcompletionitem.h" #include "editsnippet.h" #include #include #include #include #include #include #include #include #include #include #include #include KateSnippetGlobal *KateSnippetGlobal::s_self = nullptr; KateSnippetGlobal::KateSnippetGlobal(QObject *parent, const QVariantList &) : QObject(parent) { s_self = this; SnippetStore::init(this); m_model.reset(new SnippetCompletionModel); } KateSnippetGlobal::~KateSnippetGlobal () { delete SnippetStore::self(); s_self = nullptr; } void KateSnippetGlobal::insertSnippet(Snippet* snippet) { // query active view, always prefer that! KTextEditor::View *view = KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView (); // fallback to stuff set for dialog if (!view) view = m_activeViewForDialog; // no view => nothing to do if (!view) return; // try to insert snippet SnippetCompletionItem item(snippet, static_cast(snippet->parent())); item.execute(view, KTextEditor::Range(view->cursorPosition(), view->cursorPosition())); // set focus to view view->setFocus (); } void KateSnippetGlobal::insertSnippetFromActionData() { QAction* action = dynamic_cast(sender()); Q_ASSERT(action); Snippet* snippet = action->data().value(); Q_ASSERT(snippet); insertSnippet(snippet); } void KateSnippetGlobal::createSnippet (KTextEditor::View *view) { // no active view, bad if (!view) return; // get mode QString mode = view->document()->highlightingModeAt(view->selectionRange().isValid() ? view->selectionRange().start() : view->cursorPosition()); if ( mode.isEmpty() ) mode = view->document()->mode(); // try to look for a fitting repo - SnippetRepository* match = 0; + SnippetRepository* match = nullptr; for ( int i = 0; i < SnippetStore::self()->rowCount(); ++i ) { SnippetRepository* repo = dynamic_cast( SnippetStore::self()->item(i) ); if ( repo && repo->fileTypes().count() == 1 && repo->fileTypes().first() == mode ) { match = repo; break; } } bool created = !match; if ( created ) { match = SnippetRepository::createRepoFromName( i18nc("Autogenerated repository name for a programming language", "%1 snippets", mode) ); match->setFileTypes(QStringList() << mode); } - EditSnippet dlg(match, 0, view); + EditSnippet dlg(match, nullptr, view); dlg.setSnippetText(view->selectionText()); int status = dlg.exec(); if ( created && status != QDialog::Accepted ) { // cleanup match->remove(); } } diff --git a/addons/snippets/katesnippets.cpp b/addons/snippets/katesnippets.cpp index 23f2545c2..55dc604e6 100644 --- a/addons/snippets/katesnippets.cpp +++ b/addons/snippets/katesnippets.cpp @@ -1,131 +1,131 @@ /* 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 "katesnippets.h" #include "snippetcompletionmodel.h" #include "katesnippetglobal.h" #include "snippetview.h" #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KateSnippetsPluginFactory, "katesnippetsplugin.json", registerPlugin();) KateSnippetsPlugin::KateSnippetsPlugin(QObject *parent, const QList &) : KTextEditor::Plugin(parent) , m_snippetGlobal(new KateSnippetGlobal(this)) { } KateSnippetsPlugin::~KateSnippetsPlugin() { } QObject *KateSnippetsPlugin::createView(KTextEditor::MainWindow *mainWindow) { KateSnippetsPluginView *view = new KateSnippetsPluginView(this, mainWindow); return view; } KateSnippetsPluginView::KateSnippetsPluginView(KateSnippetsPlugin *plugin, KTextEditor::MainWindow *mainWindow) - : QObject(mainWindow), m_plugin(plugin), m_mainWindow(mainWindow), m_toolView(0), m_snippets(0) + : QObject(mainWindow), m_plugin(plugin), m_mainWindow(mainWindow), m_toolView(nullptr), m_snippets(nullptr) { KXMLGUIClient::setComponentName(QStringLiteral("katesnippets"), i18n("Snippets tool view")); setXMLFile(QStringLiteral("ui.rc")); // Toolview for snippets m_toolView = mainWindow->createToolView(plugin, QStringLiteral("kate_private_plugin_katesnippetsplugin"), KTextEditor::MainWindow::Right, QIcon::fromTheme(QStringLiteral("document-new")), i18n("Snippets")); // add snippets widget m_snippets = new SnippetView(KateSnippetGlobal::self(), m_toolView.data()); m_toolView->layout()->addWidget(m_snippets); m_snippets->setupActionsForWindow(m_toolView); m_toolView->addActions(m_snippets->actions()); // create actions QAction *a = actionCollection()->addAction(QStringLiteral("tools_create_snippet")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); a->setText(i18n("Create Snippet")); connect(a, &QAction::triggered, this, &KateSnippetsPluginView::createSnippet); connect(mainWindow, &KTextEditor::MainWindow::viewCreated, this, &KateSnippetsPluginView::slotViewCreated); /** * connect for all already existing views */ foreach (KTextEditor::View *view, mainWindow->views()) { slotViewCreated(view); } // register if factory around if (auto factory = m_mainWindow->guiFactory()) { factory->addClient(this); } } KateSnippetsPluginView::~KateSnippetsPluginView() { // cleanup for all views Q_FOREACH (auto view, m_textViews) { if (! view) { continue; } auto iface = qobject_cast(view); iface->unregisterCompletionModel(KateSnippetGlobal::self()->completionModel()); } // unregister if factory around if (auto factory = m_mainWindow->guiFactory()) { factory->removeClient(this); } if (m_toolView) { delete m_toolView; } } void KateSnippetsPluginView::slotViewCreated(KTextEditor::View *view) { m_textViews.append(QPointer(view)); // add snippet completion auto model = KateSnippetGlobal::self()->completionModel(); auto iface = qobject_cast(view); iface->unregisterCompletionModel(model); iface->registerCompletionModel(model); } void KateSnippetsPluginView::createSnippet() { KateSnippetGlobal::self()->createSnippet(m_mainWindow->activeView()); } #include "katesnippets.moc" diff --git a/addons/snippets/katesnippets.h b/addons/snippets/katesnippets.h index b7c687524..caf44e646 100644 --- a/addons/snippets/katesnippets.h +++ b/addons/snippets/katesnippets.h @@ -1,89 +1,89 @@ /* 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. */ #ifndef __KATE_SNIPPETS_H__ #define __KATE_SNIPPETS_H__ #include #include #include #include #include "katesnippetglobal.h" class SnippetView; class KateSnippetsPluginView; class KateSnippetsPlugin: public KTextEditor::Plugin { Q_OBJECT friend class KateSnippetsPluginView; public: - explicit KateSnippetsPlugin(QObject *parent = 0, const QList & = QList()); + explicit KateSnippetsPlugin(QObject *parent = nullptr, const QList & = QList()); virtual ~KateSnippetsPlugin(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; private: KateSnippetGlobal *m_snippetGlobal; }; class KateSnippetsPluginView : public QObject, public KXMLGUIClient { Q_OBJECT public: /** * Constructor. */ KateSnippetsPluginView(KateSnippetsPlugin *plugin, KTextEditor::MainWindow *mainWindow); /** * Virtual destructor. */ ~KateSnippetsPluginView(); void readConfig(); private Q_SLOTS: /** * New view got created, we need to update our connections * @param view new created view */ void slotViewCreated(KTextEditor::View *view); void createSnippet(); private: KateSnippetsPlugin *m_plugin; KTextEditor::MainWindow *m_mainWindow; QPointer m_toolView; SnippetView *m_snippets; /** * remember for which text views we might need to cleanup stuff */ QVector< QPointer > m_textViews; }; #endif diff --git a/addons/snippets/snippet.cpp b/addons/snippets/snippet.cpp index 157345bb5..4e8be644c 100644 --- a/addons/snippets/snippet.cpp +++ b/addons/snippets/snippet.cpp @@ -1,94 +1,94 @@ /* 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 * * 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 "snippet.h" #include "katesnippetglobal.h" #include "ktexteditor/editor.h" #include "ktexteditor/application.h" #include "ktexteditor/mainwindow.h" #include #include #include #include Snippet::Snippet() - : QStandardItem(i18n("")), m_action(0) + : QStandardItem(i18n("")), m_action(nullptr) { setIcon(QIcon::fromTheme(QLatin1String("text-plain"))); } Snippet::~Snippet() { delete m_action; } QString Snippet::snippet() const { return m_snippet; } void Snippet::setSnippet(const QString& snippet) { m_snippet = snippet; } void Snippet::registerActionForView(QWidget* view) { if ( view->actions().contains(m_action) ) { return; } view->addAction(m_action); } QAction* Snippet::action() { ///TODO: this is quite ugly, or is it? if someone knows how to do it better, please refactor if ( !m_action ) { static int actionCount = 0; actionCount += 1; m_action = new QAction(QString::fromLatin1("insertSnippet%1").arg(actionCount), KateSnippetGlobal::self()); m_action->setData(QVariant::fromValue(this)); KateSnippetGlobal::self()->connect(m_action, &QAction::triggered, KateSnippetGlobal::self(), &KateSnippetGlobal::insertSnippetFromActionData); } m_action->setText(i18n("insert snippet %1", text())); return m_action; } QVariant Snippet::data(int role) const { if ( role == Qt::ToolTipRole ) { return m_snippet; } else if ( (role == Qt::ForegroundRole || role == Qt::BackgroundRole) && parent()->checkState() != Qt::Checked ) { ///TODO: make the selected items also "disalbed" so the toggle action is seen directly KColorScheme scheme(QPalette::Disabled, KColorScheme::View); if (role == Qt::ForegroundRole) { return scheme.foreground(KColorScheme::NormalText).color(); } else { return scheme.background(KColorScheme::NormalBackground).color(); } } return QStandardItem::data(role); } diff --git a/addons/snippets/snippetcompletionmodel.cpp b/addons/snippets/snippetcompletionmodel.cpp index 74e5b89f8..024ff55fb 100644 --- a/addons/snippets/snippetcompletionmodel.cpp +++ b/addons/snippets/snippetcompletionmodel.cpp @@ -1,188 +1,188 @@ /* This file is part of the Kate project. * Based on the snippet plugin from KDevelop 4. * * Copyright (C) 2008 Andreas Pakulat * 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 "snippetcompletionmodel.h" #include #include #include "snippetstore.h" #include "snippetrepository.h" #include "snippet.h" #include "snippetcompletionitem.h" #include SnippetCompletionModel::SnippetCompletionModel() - : KTextEditor::CodeCompletionModel(0) + : KTextEditor::CodeCompletionModel(nullptr) { setHasGroups(false); } SnippetCompletionModel::~SnippetCompletionModel() { qDeleteAll(m_snippets); m_snippets.clear(); } QVariant SnippetCompletionModel::data( const QModelIndex& idx, int role ) const { if (role == KTextEditor::CodeCompletionModel::InheritanceDepth) return 11000; // grouping of snippets if (!idx.parent().isValid()) { if (role == Qt::DisplayRole) { return i18n("Snippets"); } if (role == KTextEditor::CodeCompletionModel::GroupRole) { return Qt::DisplayRole; } return QVariant(); } // snippets if( !idx.isValid() || idx.row() < 0 || idx.row() >= m_snippets.count() ) { return QVariant(); } else { - return m_snippets.at( idx.row() )->data(idx, role, 0); + return m_snippets.at( idx.row() )->data(idx, role, nullptr); } } void SnippetCompletionModel::executeCompletionItem (KTextEditor::View *view, const KTextEditor::Range &word, const QModelIndex &index) const { if ( index.parent().isValid() ) { m_snippets[index.row()]->execute(view, word); } } void SnippetCompletionModel::completionInvoked(KTextEditor::View *view, const KTextEditor::Range &range, InvocationType invocationType) { Q_UNUSED( range ); Q_UNUSED( invocationType ); initData(view); } void SnippetCompletionModel::initData(KTextEditor::View* view) { QString mode = view->document()->highlightingModeAt(view->cursorPosition()); if ( mode.isEmpty() ) { mode = view->document()->highlightingMode(); } beginResetModel(); qDeleteAll(m_snippets); m_snippets.clear(); SnippetStore* store = SnippetStore::self(); for(int i = 0; i < store->rowCount(); i++ ) { if ( store->item(i, 0)->checkState() != Qt::Checked ) { continue; } SnippetRepository* repo = dynamic_cast( store->item( i, 0 ) ); if( repo && (repo->fileTypes().isEmpty() || repo->fileTypes().contains(mode)) ) { for ( int j = 0; j < repo->rowCount(); ++j ) { if ( Snippet* snippet = dynamic_cast(repo->child(j)) ) { m_snippets << new SnippetCompletionItem(snippet, repo); } } } } endResetModel(); } QModelIndex SnippetCompletionModel::parent(const QModelIndex& index) const { if (index.internalId()) { return createIndex(0, 0, quintptr (0)); } else { return QModelIndex(); } } QModelIndex SnippetCompletionModel::index(int row, int column, const QModelIndex& parent) const { if (!parent.isValid()) { if (row == 0) { return createIndex(row, column, quintptr (0)); //header index } else { return QModelIndex(); } } else if (parent.parent().isValid()) { //we only have header and children, no subheaders return QModelIndex(); } if (row < 0 || row >= m_snippets.count() || column < 0 || column >= ColumnCount ) { return QModelIndex(); } return createIndex(row, column, 1); // normal item index } int SnippetCompletionModel::rowCount (const QModelIndex & parent) const { if (!parent.isValid() && !m_snippets.isEmpty()) { return 1; //one toplevel node (group header) } else if(parent.parent().isValid()) { return 0; //we don't have sub children } else { return m_snippets.count(); // only the children } } KTextEditor::Range SnippetCompletionModel::completionRange(KTextEditor::View* view, const KTextEditor::Cursor& position) { const QString& line = view->document()->line(position.line()); KTextEditor::Range range(position, position); // include everything non-space before for ( int i = position.column() - 1; i >= 0; --i ) { if ( line.at(i).isSpace() ) { break; } else { range.setStart(KTextEditor::Cursor (range.start().line(), i)); } } // include everything non-space after for ( int i = position.column() + 1; i < line.length(); ++i ) { if ( line.at(i).isSpace() ) { break; } else { range.setEnd(KTextEditor::Cursor (range.end().line(), i)); } } return range; } bool SnippetCompletionModel::shouldAbortCompletion(KTextEditor::View* view, const KTextEditor::Range& range, const QString& currentCompletion) { if(view->cursorPosition() < range.start() || view->cursorPosition() > range.end()) { return true; //Always abort when the completion-range has been left } for ( int i = 0; i < currentCompletion.length(); ++i ) { if ( currentCompletion.at(i).isSpace() ) { return true; } } // else it's valid return false; } diff --git a/addons/snippets/snippetrepository.cpp b/addons/snippets/snippetrepository.cpp index 55b8f4444..4f60ba59e 100644 --- a/addons/snippets/snippetrepository.cpp +++ b/addons/snippets/snippetrepository.cpp @@ -1,406 +1,406 @@ /* 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 * * 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 "snippetrepository.h" #include "snippet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "snippetstore.h" static const QString defaultScript = QStringLiteral("\ function fileName() { return document.fileName(); }\n\ function fileUrl() { return document.url(); }\n\ function encoding() { return document.encoding(); }\n\ function selection() { return view.selectedText(); }\n\ function year() { return new Date().getFullYear(); }\n\ function upper(x) { return x.toUpperCase(); }\n\ function lower(x) { return x.toLowerCase(); }\n" ); SnippetRepository::SnippetRepository(const QString& file) : QStandardItem(i18n("")), m_file(file), m_script(defaultScript) { setIcon( QIcon::fromTheme(QLatin1String("folder")) ); const auto& config = SnippetStore::self()->getConfig(); bool activated = config.readEntry("enabledRepositories", QStringList()).contains(file); setCheckState(activated ? Qt::Checked : Qt::Unchecked); if ( QFile::exists(file) ) { // Tell the new repository to load it's snippets QTimer::singleShot(0, this, SLOT(slotParseFile())); } qDebug() << "created new snippet repo" << file << this; } SnippetRepository::~SnippetRepository() { // remove all our children from both the model and our internal data structures removeRows( 0, rowCount() ); } QDir SnippetRepository::dataPath() { auto dir = QDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)); const auto& subdir = QLatin1String("ktexteditor_snippets/data/"); bool success = dir.mkpath(dir.absoluteFilePath(subdir)); Q_ASSERT(success); dir.setPath(dir.path() + QLatin1String("/") + subdir); return dir; } SnippetRepository* SnippetRepository::createRepoFromName(const QString& name) { QString cleanName = name; cleanName.replace(QLatin1Char('/'), QLatin1Char('-')); const auto& dir = dataPath(); const auto& path = dir.absoluteFilePath(cleanName + QLatin1String(".xml")); qDebug() << "repo path:" << path << cleanName; SnippetRepository* repo = new SnippetRepository(path); repo->setText(name); repo->setCheckState(Qt::Checked); KUser user; repo->setAuthors(user.property(KUser::FullName).toString()); SnippetStore::self()->appendRow(repo); return repo; } const QString& SnippetRepository::file() const { return m_file; } QString SnippetRepository::authors() const { return m_authors; } void SnippetRepository::setAuthors(const QString& authors) { m_authors = authors; } QStringList SnippetRepository::fileTypes() const { return m_filetypes; } void SnippetRepository::setFileTypes(const QStringList& filetypes) { if ( filetypes.contains(QLatin1String("*")) ) { m_filetypes.clear(); } else { m_filetypes = filetypes; } } QString SnippetRepository::license() const { return m_license; } void SnippetRepository::setLicense(const QString& license) { m_license = license; } QString SnippetRepository::completionNamespace() const { return m_namespace; } void SnippetRepository::setCompletionNamespace(const QString& completionNamespace) { m_namespace = completionNamespace; } QString SnippetRepository::script() const { return m_script; } void SnippetRepository::setScript(const QString& script) { m_script = script; } void SnippetRepository::remove() { QFile::remove(m_file); setCheckState(Qt::Unchecked); model()->invisibleRootItem()->removeRow(row()); } ///copied code from snippets_tng/lib/completionmodel.cpp ///@copyright 2009 Joseph Wenninger static void addAndCreateElement(QDomDocument& doc, QDomElement& item, const QString& name, const QString &content) { QDomElement element=doc.createElement(name); element.appendChild(doc.createTextNode(content)); item.appendChild(element); } void SnippetRepository::save() { qDebug() << "*** called"; ///based on the code from snippets_tng/lib/completionmodel.cpp ///@copyright 2009 Joseph Wenninger /* prefix test1 postfix (param1, param2) This is a test testtemplate This is a test ${WHAT} template */ QDomDocument doc; QDomElement root = doc.createElement(QLatin1String("snippets")); root.setAttribute(QLatin1String("name"), text()); root.setAttribute(QLatin1String("filetypes"), m_filetypes.isEmpty() ? QLatin1String("*") : m_filetypes.join(QLatin1String(";"))); root.setAttribute(QLatin1String("authors"), m_authors); root.setAttribute(QLatin1String("license"), m_license); root.setAttribute(QLatin1String("namespace"), m_namespace); doc.appendChild(root); addAndCreateElement(doc, root, QLatin1String("script"), m_script); for ( int i = 0; i < rowCount(); ++i ) { Snippet* snippet = dynamic_cast(child(i)); if ( !snippet ) { continue; } QDomElement item = doc.createElement(QLatin1String("item")); addAndCreateElement(doc, item, QLatin1String("match"), snippet->text()); addAndCreateElement(doc, item, QLatin1String("fillin"), snippet->snippet()); root.appendChild(item); } //KMessageBox::information(0,doc.toString()); QFileInfo fi(m_file); QDir dir = dataPath(); QString outname = dir.absoluteFilePath(fi.fileName()); if (m_file != outname) { QFileInfo fiout(outname); // there could be cases that new new name clashes with a global file, but I guess it is not that often. int i = 0; while (QFile::exists(outname)) { i++; outname = dir.absoluteFilePath(QString::number(i) + fi.fileName()); } KMessageBox::information(QApplication::activeWindow(), i18n("You have edited a data file not located in your personal data directory; as such, a renamed clone of the original data file has been created within your personal data directory.")); } QFile outfile(outname); if (!outfile.open(QIODevice::WriteOnly)) { - KMessageBox::error(0, i18n("Output file '%1' could not be opened for writing", outname)); + KMessageBox::error(nullptr, i18n("Output file '%1' could not be opened for writing", outname)); return; } outfile.write(doc.toByteArray()); outfile.close(); m_file = outname; // save shortcuts KConfigGroup config = SnippetStore::self()->getConfig().group(QLatin1String("repository ") + m_file); for ( int i = 0; i < rowCount(); ++i ) { Snippet* snippet = dynamic_cast(child(i)); if ( !snippet ) { continue; } QStringList shortcuts; foreach ( const QKeySequence &keys, snippet->action()->shortcuts() ) { shortcuts << keys.toString(); } config.writeEntry( QLatin1String("shortcut ") + snippet->text(), shortcuts ); } config.sync(); } void SnippetRepository::slotParseFile() { ///based on the code from snippets_tng/lib/completionmodel.cpp ///@copyright 2009 Joseph Wenninger QFile f(m_file); if ( !f.open(QIODevice::ReadOnly) ) { KMessageBox::error( QApplication::activeWindow(), i18n("Cannot open snippet repository %1.", m_file) ); return; } QDomDocument doc; QString errorMsg; int line, col; bool success = doc.setContent(&f, &errorMsg, &line, &col); f.close(); if (!success) { KMessageBox::error( QApplication::activeWindow(), i18n("The error %4
has been detected in the file %1 at %2/%3
", m_file, line, col, i18nc("QXml", errorMsg.toUtf8().data())) ); return; } // parse root item const QDomElement& docElement = doc.documentElement(); if (docElement.tagName() != QLatin1String("snippets")) { KMessageBox::error( QApplication::activeWindow(), i18n("Invalid XML snippet file: %1", m_file) ); return; } setLicense(docElement.attribute(QLatin1String("license"))); setAuthors(docElement.attribute(QLatin1String("authors"))); setFileTypes(docElement.attribute(QLatin1String("filetypes")).split(QLatin1Char(';'), QString::SkipEmptyParts)); setText(docElement.attribute(QLatin1String("name"))); setCompletionNamespace(docElement.attribute(QLatin1String("namespace"))); // load shortcuts KConfigGroup config = SnippetStore::self()->getConfig().group(QLatin1String("repository ") + m_file); // parse children, i.e. 's const QDomNodeList& nodes = docElement.childNodes(); for(int i = 0; i < nodes.size(); ++i ) { const QDomNode& node = nodes.at(i); if ( !node.isElement() ) { continue; } const QDomElement& item = node.toElement(); if ( item.tagName() == QLatin1String("script") ) { setScript(item.text()); } if ( item.tagName() != QLatin1String("item") ) { continue; } Snippet* snippet = new Snippet; const QDomNodeList& children = node.childNodes(); for(int j = 0; j < children.size(); ++j) { const QDomNode& childNode = children.at(j); if ( !childNode.isElement() ) { continue; } const QDomElement& child = childNode.toElement(); if ( child.tagName() == QLatin1String("match") ) { snippet->setText(child.text()); } else if ( child.tagName() == QLatin1String("fillin") ) { snippet->setSnippet(child.text()); } } // require at least a non-empty name and snippet if ( snippet->text().isEmpty() || snippet->snippet().isEmpty() ) { delete snippet; continue; } else { const QStringList shortcuts = config.readEntry(QLatin1String("shortcut ") + snippet->text(), QStringList()); QList sequences; foreach ( const QString &shortcut, shortcuts ) { sequences << QKeySequence::fromString( shortcut ); } snippet->action()->setShortcuts( sequences ); appendRow(snippet); } } } QVariant SnippetRepository::data(int role) const { if ( role == Qt::ToolTipRole ) { if ( checkState() != Qt::Checked ) { return i18n("Repository is disabled, the contained snippets will not be shown during code-completion."); } if ( m_filetypes.isEmpty() ) { return i18n("Applies to all filetypes"); } else { return i18n("Applies to the following filetypes: %1", m_filetypes.join(QLatin1String(", "))); } } else if ( role == Qt::ForegroundRole && checkState() != Qt::Checked ) { ///TODO: make the selected items also "disalbed" so the toggle action is seen directly KColorScheme scheme(QPalette::Disabled, KColorScheme::View); QColor c = scheme.foreground(KColorScheme::NormalText).color(); return QVariant(c); } return QStandardItem::data(role); } void SnippetRepository::setData(const QVariant& value, int role) { if ( role == Qt::CheckStateRole ) { const int state = value.toInt(); if ( state != checkState() ) { KConfigGroup config = SnippetStore::self()->getConfig(); QStringList currentlyEnabled = config.readEntry("enabledRepositories", QStringList()); bool shouldSave = false; if ( state == Qt::Checked && !currentlyEnabled.contains(m_file) ) { currentlyEnabled << m_file; shouldSave = true; } else if ( state == Qt::Unchecked && currentlyEnabled.contains(m_file) ) { currentlyEnabled.removeAll(m_file); shouldSave = true; } if ( shouldSave ) { config.writeEntry("enabledRepositories", currentlyEnabled); config.sync(); } } } QStandardItem::setData(value, role); } diff --git a/addons/snippets/snippetstore.cpp b/addons/snippets/snippetstore.cpp index 4e2848aa4..3401edfc0 100644 --- a/addons/snippets/snippetstore.cpp +++ b/addons/snippets/snippetstore.cpp @@ -1,133 +1,133 @@ /* 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 * * 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 "snippetstore.h" #include "katesnippetglobal.h" #include "snippetrepository.h" #include #include #include #include Q_DECLARE_METATYPE(KSharedConfig::Ptr) -SnippetStore* SnippetStore::m_self = 0; +SnippetStore* SnippetStore::m_self = nullptr; SnippetStore::SnippetStore(KateSnippetGlobal* plugin) : m_plugin(plugin) { m_self = this; const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("ktexteditor_snippets/data"), QStandardPaths::LocateDirectory) << QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("ktexteditor_snippets/ghns"), QStandardPaths::LocateDirectory); QStringList files; foreach (const QString& dir, dirs) { const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.xml")); foreach (const QString& file, fileNames) { files.append(dir + QLatin1Char('/') + file); } } foreach(const QString& file, files ) { SnippetRepository* repo = new SnippetRepository(file); appendRow(repo); } } SnippetStore::~SnippetStore() { invisibleRootItem()->removeRows( 0, invisibleRootItem()->rowCount() ); - m_self = 0; + m_self = nullptr; } void SnippetStore::init(KateSnippetGlobal* plugin) { Q_ASSERT(!SnippetStore::self()); new SnippetStore(plugin); } SnippetStore* SnippetStore::self() { return m_self; } Qt::ItemFlags SnippetStore::flags(const QModelIndex& index) const { Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable; if ( !index.parent().isValid() ) { flags |= Qt::ItemIsUserCheckable; } return flags; } KConfigGroup SnippetStore::getConfig() { return KSharedConfig::openConfig()->group("Snippets"); } bool SnippetStore::setData(const QModelIndex& index, const QVariant& value, int role) { if ( role == Qt::EditRole && value.toString().isEmpty() ) { // don't allow empty names return false; } const bool success = QStandardItemModel::setData(index, value, role); if ( !success || role != Qt::EditRole ) { return success; } // when we edited something, save the repository - QStandardItem* repoItem = 0; + QStandardItem* repoItem = nullptr; if ( index.parent().isValid() ) { repoItem = itemFromIndex(index.parent()); } else { repoItem = itemFromIndex(index); } SnippetRepository* repo = dynamic_cast(repoItem); if ( repo ) { repo->save(); } return true; } SnippetRepository* SnippetStore::repositoryForFile(const QString& file) { for ( int i = 0; i < rowCount(); ++i ) { if ( SnippetRepository* repo = dynamic_cast(item(i)) ) { if ( repo->file() == file ) { return repo; } } } - return 0; + return nullptr; } diff --git a/addons/snippets/snippetview.cpp b/addons/snippets/snippetview.cpp index 504d3d5b0..6d26ecfb3 100644 --- a/addons/snippets/snippetview.cpp +++ b/addons/snippets/snippetview.cpp @@ -1,378 +1,378 @@ /* 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 * * 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 "snippetview.h" #include "snippet.h" #include "katesnippetglobal.h" #include "snippetrepository.h" #include "snippetstore.h" #include "editrepository.h" #include "editsnippet.h" #include #include #include #include #include #include #include #include #include class SnippetFilterModel : public QSortFilterProxyModel { public: - SnippetFilterModel(QObject* parent = 0) : QSortFilterProxyModel(parent) { }; + SnippetFilterModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent) { }; bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE { auto index = sourceModel()->index(sourceRow, 0, sourceParent); auto item = SnippetStore::self()->itemFromIndex(index); if ( ! item ) { return false; } auto snippet = dynamic_cast(item); if ( ! snippet ) { return true; } return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); } }; void SnippetView::setupActionsForWindow(QWidget* widget) { const auto& model = SnippetStore::self(); for ( int i = 0; i < model->rowCount(); i++ ) { auto index = model->index(i, 0, QModelIndex()); auto item = model->itemFromIndex(index); auto repo = dynamic_cast(item); if ( ! repo ) { continue; } for ( int j = 0; j < model->rowCount(index); j++ ) { auto item = model->itemFromIndex(model->index(j, 0, index)); auto snippet = dynamic_cast(item); if ( ! snippet ) { continue; } snippet->registerActionForView(widget); } } } SnippetView::SnippetView(KateSnippetGlobal* plugin, QWidget* parent) : QWidget(parent), Ui::SnippetViewBase(), m_plugin(plugin) { Ui::SnippetViewBase::setupUi(this); setWindowTitle(i18n("Snippets")); setWindowIcon(QIcon::fromTheme(QLatin1String("document-new"), windowIcon())); snippetTree->setContextMenuPolicy( Qt::CustomContextMenu ); snippetTree->viewport()->installEventFilter( this ); connect(snippetTree, &QTreeView::customContextMenuRequested, this, &SnippetView::contextMenu); m_proxy = new SnippetFilterModel(this); m_proxy->setFilterKeyColumn(0); m_proxy->setSourceModel(SnippetStore::self()); connect(filterText, &KLineEdit::textChanged, m_proxy, &QSortFilterProxyModel::setFilterFixedString); snippetTree->setModel(m_proxy); snippetTree->header()->hide(); m_addRepoAction = new QAction(QIcon::fromTheme(QLatin1String("folder-new")), i18n("Add Repository"), this); connect(m_addRepoAction, &QAction::triggered, this, &SnippetView::slotAddRepo); addAction(m_addRepoAction); m_editRepoAction = new QAction(QIcon::fromTheme(QLatin1String("folder-txt")), i18n("Edit Repository"), this); connect(m_editRepoAction, &QAction::triggered, this, &SnippetView::slotEditRepo); addAction(m_editRepoAction); m_removeRepoAction = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), i18n("Remove Repository"), this); connect(m_removeRepoAction, &QAction::triggered, this, &SnippetView::slotRemoveRepo); addAction(m_removeRepoAction); const bool newStuffAllowed = KAuthorized::authorize(QStringLiteral("ghns")); m_putNewStuffAction = new QAction(QIcon::fromTheme(QLatin1String("get-hot-new-stuff")), i18n("Publish Repository"), this); m_putNewStuffAction->setVisible(newStuffAllowed); connect(m_putNewStuffAction, &QAction::triggered, this, &SnippetView::slotSnippetToGHNS); addAction(m_putNewStuffAction); QAction* separator = new QAction(this); separator->setSeparator(true); addAction(separator); m_addSnippetAction = new QAction(QIcon::fromTheme(QLatin1String("document-new")), i18n("Add Snippet"), this); connect(m_addSnippetAction, &QAction::triggered, this, &SnippetView::slotAddSnippet); addAction(m_addSnippetAction); m_editSnippetAction = new QAction(QIcon::fromTheme(QLatin1String("document-edit")), i18n("Edit Snippet"), this); connect(m_editSnippetAction, &QAction::triggered, this, &SnippetView::slotEditSnippet); addAction(m_editSnippetAction); m_removeSnippetAction = new QAction(QIcon::fromTheme(QLatin1String("document-close")), i18n("Remove Snippet"), this); connect(m_removeSnippetAction, &QAction::triggered, this, &SnippetView::slotRemoveSnippet); addAction(m_removeSnippetAction); addAction(separator); m_getNewStuffAction = new QAction(QIcon::fromTheme(QLatin1String("get-hot-new-stuff")), i18n("Get New Snippets"), this); m_getNewStuffAction->setVisible(newStuffAllowed); connect(m_getNewStuffAction, &QAction::triggered, this, &SnippetView::slotGHNS); addAction(m_getNewStuffAction); connect(snippetTree->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(validateActions())); validateActions(); connect(snippetTree->model(), &QAbstractItemModel::rowsInserted, this, [this]() { setupActionsForWindow(this); }); m_proxy->setDynamicSortFilter(true); m_proxy->sort(0, Qt::AscendingOrder); } void SnippetView::validateActions() { QStandardItem* item = currentItem(); Snippet* selectedSnippet = dynamic_cast( item ); SnippetRepository* selectedRepo = dynamic_cast( item ); m_addRepoAction->setEnabled(true); m_editRepoAction->setEnabled(selectedRepo); m_removeRepoAction->setEnabled(selectedRepo); m_putNewStuffAction->setEnabled(selectedRepo); m_addSnippetAction->setEnabled(selectedRepo || selectedSnippet); m_editSnippetAction->setEnabled(selectedSnippet); m_removeSnippetAction->setEnabled(selectedSnippet); } QStandardItem* SnippetView::currentItem() { ///TODO: support multiple selected items QModelIndex index = snippetTree->currentIndex(); index = m_proxy->mapToSource(index); return SnippetStore::self()->itemFromIndex( index ); } void SnippetView::slotSnippetClicked (const QModelIndex & index) { QStandardItem* item = SnippetStore::self()->itemFromIndex( m_proxy->mapToSource(index) ); if (!item) return; Snippet* snippet = dynamic_cast( item ); if (!snippet) return; m_plugin->insertSnippet( snippet ); } void SnippetView::contextMenu (const QPoint& pos) { QModelIndex index = snippetTree->indexAt( pos ); index = m_proxy->mapToSource(index); QStandardItem* item = SnippetStore::self()->itemFromIndex( index ); if (!item) { // User clicked into an empty place of the tree QMenu menu(this); menu.addSection(i18n("Snippets")); menu.addAction(m_addRepoAction); menu.addAction(m_getNewStuffAction); menu.exec(snippetTree->mapToGlobal(pos)); } else if (Snippet* snippet = dynamic_cast( item )) { QMenu menu(this); menu.addSection(i18n("Snippet: %1", snippet->text())); menu.addAction(m_editSnippetAction); menu.addAction(m_removeSnippetAction); menu.exec(snippetTree->mapToGlobal(pos)); } else if (SnippetRepository* repo = dynamic_cast( item )) { QMenu menu(this); menu.addSection(i18n("Repository: %1", repo->text())); menu.addAction(m_addSnippetAction); menu.addSeparator(); menu.addAction(m_editRepoAction); menu.addAction(m_removeRepoAction); menu.addAction(m_putNewStuffAction); menu.exec(snippetTree->mapToGlobal(pos)); } } void SnippetView::slotEditSnippet() { QStandardItem* item = currentItem(); if (!item) return; Snippet* snippet = dynamic_cast( item ); if (!snippet) return; SnippetRepository* repo = dynamic_cast( item->parent() ); if (!repo) return; EditSnippet dlg(repo, snippet, this); dlg.exec(); } void SnippetView::slotAddSnippet() { QStandardItem* item = currentItem(); if (!item) return; SnippetRepository* repo = dynamic_cast( item ); if (!repo) { repo = dynamic_cast( item->parent() ); if ( !repo ) return; } - EditSnippet dlg(repo, 0, this); + EditSnippet dlg(repo, nullptr, this); dlg.exec(); } void SnippetView::slotRemoveSnippet() { QStandardItem* item = currentItem(); if (!item) return; SnippetRepository* repo = dynamic_cast( item->parent() ); if (!repo) return; int ans = KMessageBox::warningContinueCancel( QApplication::activeWindow(), i18n("Do you really want to delete the snippet \"%1\"?", item->text()) ); if ( ans == KMessageBox::Continue ) { item->parent()->removeRow(item->row()); repo->save(); } } void SnippetView::slotAddRepo() { - EditRepository dlg(0, this); + EditRepository dlg(nullptr, this); dlg.exec(); } void SnippetView::slotEditRepo() { QStandardItem* item = currentItem(); if (!item) return; SnippetRepository* repo = dynamic_cast( item ); if (!repo) return; EditRepository dlg(repo, this); dlg.exec(); } void SnippetView::slotRemoveRepo() { QStandardItem* item = currentItem(); if (!item) return; SnippetRepository* repo = dynamic_cast( item ); if (!repo) return; int ans = KMessageBox::warningContinueCancel( QApplication::activeWindow(), i18n("Do you really want to delete the repository \"%1\" with all its snippets?", repo->text()) ); if ( ans == KMessageBox::Continue ) { repo->remove(); } } void SnippetView::slotGHNS() { KNS3::DownloadDialog dialog(QLatin1String(":/katesnippets/ktexteditor_codesnippets_core.knsrc"), this); dialog.exec(); foreach ( const KNS3::Entry& entry, dialog.changedEntries() ) { foreach ( const QString& path, entry.uninstalledFiles() ) { if ( path.endsWith(QLatin1String(".xml")) ) { if ( SnippetRepository* repo = SnippetStore::self()->repositoryForFile(path) ) { repo->remove(); } } } foreach ( const QString& path, entry.installedFiles() ) { if ( path.endsWith(QLatin1String(".xml")) ) { SnippetStore::self()->appendRow(new SnippetRepository(path)); } } } } void SnippetView::slotSnippetToGHNS() { QStandardItem* item = currentItem(); if ( !item) return; SnippetRepository* repo = dynamic_cast( item ); if ( !repo ) return; KNS3::UploadDialog dialog(QLatin1String(":/katesnippets/ktexteditor_codesnippets_core.knsrc"), this); dialog.setUploadFile(QUrl::fromLocalFile(repo->file())); dialog.setUploadName(repo->text()); dialog.exec(); } bool SnippetView::eventFilter(QObject* obj, QEvent* e) { // no, listening to activated() is not enough since that would also trigger the edit mode which we _dont_ want here // users may still rename stuff via select + F2 though if (obj == snippetTree->viewport()) { - const bool singleClick = style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, this); + const bool singleClick = style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, nullptr, this); if ( (!singleClick && e->type() == QEvent::MouseButtonDblClick) || (singleClick && e->type() == QEvent::MouseButtonRelease) ) { QMouseEvent* mouseEvent = dynamic_cast(e); Q_ASSERT(mouseEvent); QModelIndex clickedIndex = snippetTree->indexAt(mouseEvent->pos()); if (clickedIndex.isValid() && clickedIndex.parent().isValid()) { slotSnippetClicked(clickedIndex); e->accept(); return true; } } } return QObject::eventFilter(obj, e); } diff --git a/addons/snippets/snippetview.h b/addons/snippets/snippetview.h index 6b01ddb53..8e00b2c4a 100644 --- a/addons/snippets/snippetview.h +++ b/addons/snippets/snippetview.h @@ -1,122 +1,122 @@ /* 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. */ #ifndef SNIPPETVIEW_H #define SNIPPETVIEW_H #include "ui_snippetview.h" class QStandardItem; class KateSnippetGlobal; class QAction; class QSortFilterProxyModel; namespace KTextEditor { } /** * This class gets embedded into the right tool view by the KateSnippetGlobal. * @author Robert Gruber * @author Milian Wolff */ class SnippetView : public QWidget, public Ui::SnippetViewBase { Q_OBJECT public: - explicit SnippetView(KateSnippetGlobal* plugin, QWidget* parent = 0); + explicit SnippetView(KateSnippetGlobal* plugin, QWidget* parent = nullptr); public: void setupActionsForWindow(QWidget* widget); private Q_SLOTS: /** * Opens the "Add Repository" dialog. */ void slotAddRepo(); /** * Opens the "Edit repository" dialog. */ void slotEditRepo(); /** * Removes the selected repository from the disk. */ void slotRemoveRepo(); /** * Insert the selected snippet into the current file */ void slotSnippetClicked(const QModelIndex & index); /** * Open the edit dialog for the selected snippet */ void slotEditSnippet(); /** * Removes the selected snippet from the tree and the filesystem */ void slotRemoveSnippet(); /** * Creates a new snippet and open the edit dialog for it */ void slotAddSnippet(); /** * Slot to get hot new stuff. */ void slotGHNS(); /** * Slot to put the selected snippet to GHNS */ void slotSnippetToGHNS(); void contextMenu (const QPoint & pos); /// disables or enables available actions based on the currently selected item void validateActions(); /// insert snippet on double click bool eventFilter(QObject* , QEvent* ) Q_DECL_OVERRIDE; private: QStandardItem* currentItem(); KateSnippetGlobal* m_plugin; QSortFilterProxyModel* m_proxy; QAction *m_addRepoAction; QAction *m_removeRepoAction; QAction *m_editRepoAction; QAction *m_addSnippetAction; QAction *m_removeSnippetAction; QAction *m_editSnippetAction; QAction *m_getNewStuffAction; QAction *m_putNewStuffAction; }; #endif diff --git a/addons/symbolviewer/bash_parser.cpp b/addons/symbolviewer/bash_parser.cpp index 51ba96c33..6feb86d9b 100644 --- a/addons/symbolviewer/bash_parser.cpp +++ b/addons/symbolviewer/bash_parser.cpp @@ -1,106 +1,106 @@ /*************************************************************************** bash_parser.cpp - description ------------------- begin : dec 12 2008 author : Daniel Dumitrache email : daniel.dumitrache@gmail.com ***************************************************************************/ /*************************************************************************** This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ***************************************************************************/ #include "plugin_katesymbolviewer.h" void KatePluginSymbolViewerView::parseBashSymbols(void) { if (!m_mainWindow->activeView()) return; QString currline; QString funcStr(QLatin1String("function ")); int i; //bool mainprog; - QTreeWidgetItem *node = NULL; - QTreeWidgetItem *funcNode = NULL; - QTreeWidgetItem *lastFuncNode = NULL; + QTreeWidgetItem *node = nullptr; + QTreeWidgetItem *funcNode = nullptr; + QTreeWidgetItem *lastFuncNode = nullptr; QPixmap func( ( const char** ) class_xpm ); //It is necessary to change names m_func->setText(i18n("Show Functions")); if(m_plugin->treeOn) { funcNode = new QTreeWidgetItem(m_symbols, QStringList(i18n("Functions") ) ); funcNode->setIcon(0, QIcon(func)); if (m_plugin->expandedOn) { m_symbols->expandItem(funcNode); } lastFuncNode = funcNode; m_symbols->setRootIsDecorated(1); } else m_symbols->setRootIsDecorated(0); KTextEditor::Document *kDoc = m_mainWindow->activeView()->document(); for (i = 0; i < kDoc->lines(); i++) { currline = kDoc->line(i); currline = currline.trimmed(); currline = currline.simplified(); bool comment = false; //qDebug(13000)<treeOn) { node = new QTreeWidgetItem(funcNode, lastFuncNode); lastFuncNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, funcName); node->setIcon(0, QIcon(func)); node->setText(1, QString::number( i, 10)); } } //for i loop } diff --git a/addons/symbolviewer/cpp_parser.cpp b/addons/symbolviewer/cpp_parser.cpp index c1a90f17c..9f3614a2d 100644 --- a/addons/symbolviewer/cpp_parser.cpp +++ b/addons/symbolviewer/cpp_parser.cpp @@ -1,365 +1,365 @@ /*************************************************************************** cpp_parser.cpp - description ------------------- begin : Apr 2 2003 author : 2003 Massimo Callegari email : massimocallegari@yahoo.it ***************************************************************************/ /*************************************************************************** * * * 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" void KatePluginSymbolViewerView::parseCppSymbols(void) { if (!m_mainWindow->activeView()) return; QString cl; // Current Line QString stripped; int i, j, tmpPos = 0; int par = 0, graph = 0/*, retry = 0*/; char mclass = 0, block = 0, comment = 0; // comment: 0-no comment 1-inline comment 2-multiline comment 3-string char macro = 0/*, macro_pos = 0*/, func_close = 0; bool structure = false; QPixmap cls( ( const char** ) class_xpm ); QPixmap sct( ( const char** ) struct_xpm ); QPixmap mcr( ( const char** ) macro_xpm ); QPixmap mtd( ( const char** ) method_xpm ); //It is necessary to change names to defaults m_macro->setText(i18n("Show Macros")); m_struct->setText(i18n("Show Structures")); m_func->setText(i18n("Show Functions")); - QTreeWidgetItem *node = NULL; - QTreeWidgetItem *mcrNode = NULL, *sctNode = NULL, *clsNode = NULL, *mtdNode = NULL; - QTreeWidgetItem *lastMcrNode = NULL, *lastSctNode = NULL, *lastClsNode = NULL, *lastMtdNode = NULL; + QTreeWidgetItem *node = nullptr; + QTreeWidgetItem *mcrNode = nullptr, *sctNode = nullptr, *clsNode = nullptr, *mtdNode = nullptr; + QTreeWidgetItem *lastMcrNode = nullptr, *lastSctNode = nullptr, *lastClsNode = nullptr, *lastMtdNode = nullptr; KTextEditor::Document *kv = m_mainWindow->activeView()->document(); //qDebug(13000)<<"Lines counted :"<lines(); if(m_plugin->treeOn) { mcrNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Macros") ) ); sctNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Structures") ) ); clsNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Functions") ) ); mcrNode->setIcon(0, QIcon(mcr)); sctNode->setIcon(0, QIcon(sct)); clsNode->setIcon(0, QIcon(cls)); if (m_plugin->expandedOn) { m_symbols->expandItem(mcrNode); m_symbols->expandItem(sctNode); m_symbols->expandItem(clsNode); } lastMcrNode = mcrNode; lastSctNode = sctNode; lastClsNode = clsNode; mtdNode = clsNode; lastMtdNode = clsNode; m_symbols->setRootIsDecorated(1); } else m_symbols->setRootIsDecorated(0); for (i=0; ilines(); i++) { //qDebug(13000)<<"Current line :"<line(i); cl = cl.trimmed(); func_close = 0; if ( (cl.length()>=2) && (cl.at(0) == QLatin1Char('/') && cl.at(1) == QLatin1Char('/'))) continue; if(cl.indexOf(QLatin1String("/*")) == 0 && (cl.indexOf(QLatin1String("*/")) == ((signed)cl.length() - 2)) && graph == 0) continue; // workaround :( if(cl.indexOf(QLatin1String("/*")) >= 0 && graph == 0) comment = 1; if(cl.indexOf(QLatin1String("*/")) >= 0 && graph == 0) comment = 0; if(cl.indexOf(QLatin1Char('#')) >= 0 && graph == 0 ) macro = 1; if (comment != 1) { /* *********************** MACRO PARSING *****************************/ if(macro == 1) { //macro_pos = cl.indexOf(QLatin1Char('#')); for (j = 0; j < cl.length(); j++) { if ( ((j+1) = 0x20) stripped += cl.at(j); if (cl.at(j) == QLatin1Char(' ') || cl.at(j) == QLatin1Char('\t') || j == cl.length() - 1) macro = 4; } //qDebug(13000)<<"Macro -- Stripped : "<treeOn) { node = new QTreeWidgetItem(mcrNode, lastMcrNode); lastMcrNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(mcr)); node->setText(1, QString::number( i, 10)); } macro = 0; //macro_pos = 0; stripped.clear(); //qDebug(13000)<<"Macro -- Inserted : "<= 0 && graph == 0 && block == 0)) { mclass = 1; for (j = 0; j < cl.length(); j++) { if(((j+1) < cl.length()) && (cl.at(j)==QLatin1Char('/') && cl.at(j+1)==QLatin1Char('/'))) { mclass = 2; break; } if(cl.at(j)==QLatin1Char('{')) { mclass = 4; break;} stripped += cl.at(j); } if(func_on == true) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(clsNode, lastClsNode); if (m_plugin->expandedOn) m_symbols->expandItem(node); lastClsNode = node; mtdNode = lastClsNode; lastMtdNode = lastClsNode; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(cls)); node->setText(1, QString::number( i, 10)); stripped.clear(); if (mclass == 1) mclass = 3; } continue; } if (mclass == 3) { if (cl.indexOf(QLatin1Char('{')) >= 0) { cl = cl.mid(cl.indexOf(QLatin1Char('{'))); mclass = 4; } } if(cl.indexOf(QLatin1Char('(')) >= 0 && cl.at(0) != QLatin1Char('#') && block == 0 && comment != 2) { structure = false; block = 1; } if((cl.indexOf(QLatin1String("typedef")) >= 0 || cl.indexOf(QLatin1String("struct")) >= 0) && graph == 0 && block == 0) { structure = true; block = 2; stripped.clear(); } //if(cl.indexOf(QLatin1Char(';')) >= 0 && graph == 0) // block = 0; if(block > 0 && mclass != 1 ) { for (j = 0; j < cl.length(); j++) { if ( ((j+1) < cl.length()) && (cl.at(j) == QLatin1Char('/') && (cl.at(j + 1) == QLatin1Char('*')) && comment != 3)) comment = 2; if ( ((j+1) < cl.length()) && (cl.at(j) == QLatin1Char('*') && (cl.at(j + 1) == QLatin1Char('/')) && comment != 3) ) { comment = 0; j+=2; if (j>=cl.length()) break;} // Skip escaped double quotes if ( ((j+1) < cl.length()) && (cl.at(j) == QLatin1Char('\\') && (cl.at(j + 1) == QLatin1Char('"')) && comment == 3) ) { j+=2; if (j>=cl.length()) break;} // Skip char declarations that could be interpreted as range start/end if ( ((cl.indexOf(QStringLiteral("'\"'"), j) == j) || (cl.indexOf(QStringLiteral("'{'"), j) == j) || (cl.indexOf(QStringLiteral("'}'"), j) == j)) && comment != 3 ) { j+=3; if (j>=cl.length()) break;} // Handles a string. Those are freaking evilish ! if (cl.at(j) == QLatin1Char('"') && comment == 3) { comment = 0; j++; if (j>=cl.length()) break;} else if (cl.at(j) == QLatin1Char('"') && comment == 0) comment = 3; if ( ((j+1) = 0x20) stripped += cl.at(j); if(cl.at(j) == QLatin1Char('(')) par++; if(cl.at(j) == QLatin1Char(')')) { par--; if(par == 0) { stripped = stripped.trimmed(); stripped.remove(QLatin1String("static ")); //qDebug(13000)<<"Function -- Inserted : "< (int)j)) { stripped.replace(0x9, QLatin1String(" ")); if(func_on == true) { QString strippedWithTypes = stripped; if (m_plugin->typesOn == false) { while (stripped.indexOf(QLatin1Char('(')) >= 0) stripped = stripped.left(stripped.indexOf(QLatin1Char('('))); while (stripped.indexOf(QLatin1String("::")) >= 0) stripped = stripped.mid(stripped.indexOf(QLatin1String("::")) + 2); stripped = stripped.trimmed(); while (stripped.indexOf(0x20) >= 0) stripped = stripped.mid(stripped.indexOf(0x20, 0) + 1); while ( (stripped.length()>0) && ( (stripped.at(0)==QLatin1Char('*')) || (stripped.at(0)==QLatin1Char('&')) ) ) stripped=stripped.right(stripped.length()-1); } if (m_plugin->treeOn) { if (mclass == 4) { node = new QTreeWidgetItem(mtdNode, lastMtdNode); lastMtdNode = node; } else { node = new QTreeWidgetItem(clsNode, lastClsNode); lastClsNode = node; } } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); if (mclass == 4) node->setIcon(0, QIcon(mtd)); else node->setIcon(0, QIcon(cls)); node->setText(1, QString::number( tmpPos, 10)); node->setToolTip(0, strippedWithTypes); } stripped.clear(); //retry = 0; block = 3; } if(cl.at(j)==QLatin1Char('{') && structure == true) { block = 3; tmpPos = i; } if(cl.at(j)==QLatin1Char('(') && structure == true) { //retry = 1; block = 0; j = 0; //qDebug(13000)<<"Restart from the beginning of line..."; stripped.clear(); break; // Avoid an infinite loop :( } if(structure == true && cl.at(j) >= 0x20) stripped += cl.at(j); } // BLOCK 2 if (block == 3) { // A comment...there can be anything if( ((j+1)treeOn) { node = new QTreeWidgetItem(sctNode, lastSctNode); lastSctNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(sct)); node->setText(1, QString::number( tmpPos, 10)); } //qDebug(13000)<<"Structure -- Inserted : "<= 0x20) stripped += cl.at(j); } // BLOCK 4 } // comment != 2 //qDebug(13000)<<"Stripped : "< 0 if (mclass == 4 && block == 0 && func_close == 0) { if (cl.indexOf(QLatin1Char('}')) >= 0) { cl = cl.mid(cl.indexOf(QLatin1Char('}'))); mclass = 0; } } } // Comment != 1 } // for kv->numlines //for (i= 0; i < (m_symbols->itemIndex(node) + 1); i++) // qDebug(13000)<<"Symbol row :"<activeView()) return; // the current line QString cl; // the current line stripped of all comments and strings QString stripped; // a parsed class/function identifier QString identifier; // temporary characters QChar current, next, string_start = QLatin1Char('\0'); // whether we are in a multiline comment bool in_comment = false; // the current line index int line = 0; // indices into the string int c, function_start = 0; // the current depth of curly brace encapsulation int brace_depth = 0; // a list of inserted nodes with the index being the brace depth at insertion QList nodes; QPixmap cls( ( const char** ) class_xpm ); QPixmap mtd( ( const char** ) method_xpm ); - QTreeWidgetItem *node = NULL; + QTreeWidgetItem *node = nullptr; if (m_plugin->treeOn) { m_symbols->setRootIsDecorated(1); } else { m_symbols->setRootIsDecorated(0); } // read the document line by line KTextEditor::Document *kv = m_mainWindow->activeView()->document(); for (line=0; line < kv->lines(); line++) { // get a line to process, trimming off whitespace cl = kv->line(line); cl = cl.trimmed(); stripped.clear(); bool in_string = false; for (c = 0; c < cl.length(); c++) { // get the current character and the next current = cl.at(c); if ((c+1) < cl.length()) next = cl.at(c+1); else next = QLatin1Char('\0'); // skip the rest of the line if we find a line comment if ((! in_comment) && (current == QLatin1Char('/')) && (next == QLatin1Char('/'))) break; // open/close multiline comments if ((! in_string) && (current == QLatin1Char('/')) && (next == QLatin1Char('*'))) { in_comment = true; c++; continue; } else if ((in_comment) && (current == QLatin1Char('*')) && (next == QLatin1Char('/'))) { in_comment = false; c++; continue; } // open strings if ((! in_comment) && (! in_string)) { if ((current == QLatin1Char('\'')) || (current == QLatin1Char('"'))) { string_start = current; in_string = true; continue; } } // close strings if (in_string) { // skip escaped backslashes if ((current == QLatin1Char('\\')) && (next == QLatin1Char('\\'))) { c++; continue; } // skip escaped string closures if ((current == QLatin1Char('\\')) && (next == string_start)) { c++; continue; } else if (current == string_start) { in_string = false; continue; } } // add anything outside strings and comments to the stripped line if ((! in_comment) && (! in_string)) { stripped += current; } } // scan the stripped line for (c = 0; c < stripped.length(); c++) { current = stripped.at(c); // look for class definitions (for ActionScript) if ((current == QLatin1Char('c')) && (stripped.indexOf(QLatin1String("class"), c) == c)) { identifier.clear(); c += 6; for (c = c; c < stripped.length(); c++) { current = stripped.at(c); // look for the beginning of the class itself if ((current == QLatin1Char('(')) || (current == QLatin1Char('{'))) { c--; break; } else { identifier += current; } } // trim whitespace identifier = identifier.trimmed(); // get the node to add the class entry to if ((m_plugin->treeOn) && (! nodes.isEmpty())) { node = new QTreeWidgetItem(nodes.last()); if (m_plugin->expandedOn) m_symbols->expandItem(node); } else { node = new QTreeWidgetItem(m_symbols); } // add an entry for the class node->setText(0, identifier); node->setIcon(0, QIcon(cls)); node->setText(1, QString::number(line, 10)); if (m_plugin->expandedOn) m_symbols->expandItem(node); } // (look for classes) // look for function definitions if ((current == QLatin1Char('f')) && (stripped.indexOf(QLatin1String("function"), c) == c)) { function_start = c; c += 8; // look for the beginning of the parameters identifier.clear(); for (c = c; c < stripped.length(); c++) { current = stripped.at(c); // look for the beginning of the function definition if ((current == QLatin1Char('(')) || (current == QLatin1Char('{'))) { c--; break; } else { identifier += current; } } // trim off whitespace identifier = identifier.trimmed(); // if we have an anonymous function, back up to see if it's assigned to anything if (! (identifier.length() > 0)) { QChar ch = QLatin1Char('\0'); for (int end = function_start - 1; end >= 0; end--) { ch = stripped.at(end); // skip whitespace if ((ch == QLatin1Char(' ')) || (ch == QLatin1Char('\t'))) continue; // if we hit an assignment or object property operator, // get the preceding identifier if ((ch == QLatin1Char('=')) || (ch == QLatin1Char(':'))) { end--; while (end >= 0) { ch = stripped.at(end); if ((ch != QLatin1Char(' ')) && (ch != QLatin1Char('\t'))) break; end--; } int start = end; while (start >= 0) { ch = stripped.at(start); if (((ch >= QLatin1Char('a')) && (ch <= QLatin1Char('z'))) || ((ch >= QLatin1Char('A')) && (ch <= QLatin1Char('Z'))) || ((ch >= QLatin1Char('0')) && (ch <= QLatin1Char('9'))) || (ch == QLatin1Char('_'))) start--; else { start++; break; } } identifier = stripped.mid(start, (end - start) + 1); break; } // if we hit something else, we're not going to be able // to read an assignment identifier else break; } } // if we have a function identifier, make a node if (identifier.length() > 0) { // make a node for the function - QTreeWidgetItem *parent = NULL; + QTreeWidgetItem *parent = nullptr; if (! nodes.isEmpty()) { parent = nodes.last(); } - if ((m_plugin->treeOn) && (parent != NULL)) + if ((m_plugin->treeOn) && (parent != nullptr)) node = new QTreeWidgetItem(parent); else node = new QTreeWidgetItem(m_symbols); // mark the parent as a class (if it's not the root level) - if (parent != NULL) { + if (parent != nullptr) { parent->setIcon(0, QIcon(cls)); // mark this function as a method of the parent node->setIcon(0, QIcon(mtd)); } // mark root-level functions as classes else { node->setIcon(0, QIcon(cls)); } // add the function node->setText(0, identifier); node->setText(1, QString::number(line, 10)); if (m_plugin->expandedOn) m_symbols->expandItem(node); } } // (look for functions) // look for QML id: .... if (stripped.midRef(c, 3) == QLatin1String("id:")) { c += 3; identifier.clear(); // parse the id name for (c = c; c < stripped.length(); c++) { current = stripped.at(c); // look for the beginning of the id if (current == QLatin1Char(';')) { c--; break; } else { identifier += current; } } identifier = identifier.trimmed(); // if we have an id, make a node if (identifier.length() > 0) { - QTreeWidgetItem *parent = NULL; + QTreeWidgetItem *parent = nullptr; if (! nodes.isEmpty()) { parent = nodes.last(); } - if ((m_plugin->treeOn) && (parent != NULL)) + if ((m_plugin->treeOn) && (parent != nullptr)) node = new QTreeWidgetItem(parent); else node = new QTreeWidgetItem(m_symbols); // mark the node as a class node->setIcon(0, QIcon(cls)); // add the id node->setText(0, identifier); node->setText(1, QString::number(line, 10)); if (m_plugin->expandedOn) m_symbols->expandItem(node); } } // keep track of brace depth if (current == QLatin1Char('{')) { brace_depth++; // if a node has been added at this level or above, // use it to extend the stack - if (node != NULL) + if (node != nullptr) nodes.append(node); // if no node has been added, extend the last node to this depth else if (! nodes.isEmpty()) nodes.append(nodes.last()); } else if (current == QLatin1Char('}')) { brace_depth--; // pop the last node off the stack - node = NULL; + node = nullptr; if (! nodes.isEmpty()) nodes.removeLast(); } } // (scan the stripped line) } // (iterate through lines of the document) } diff --git a/addons/symbolviewer/fortran_parser.cpp b/addons/symbolviewer/fortran_parser.cpp index 2242f6f04..4be1d7377 100644 --- a/addons/symbolviewer/fortran_parser.cpp +++ b/addons/symbolviewer/fortran_parser.cpp @@ -1,255 +1,255 @@ /*************************************************************************** fortran_parser.cpp - description ------------------- begin : jul 10 2005 author : 2005 Roberto Quitiliani email : roby(dot)q(AT)tiscali(dot)it ***************************************************************************/ /*************************************************************************** * * * 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" void KatePluginSymbolViewerView::parseFortranSymbols(void) { if (!m_mainWindow->activeView()) return; QString currline; QString subrStr(QLatin1String("subroutine ")); QString funcStr(QLatin1String("function ")); QString modStr(QLatin1String("module ")); QString stripped; int i; int fnd,block=0,blockend=0,paro=0,parc=0; bool mainprog; - QTreeWidgetItem *node = NULL; - QTreeWidgetItem *subrNode = NULL, *funcNode = NULL, *modNode = NULL; - QTreeWidgetItem *lastSubrNode = NULL, *lastFuncNode = NULL, *lastModNode = NULL; + QTreeWidgetItem *node = nullptr; + QTreeWidgetItem *subrNode = nullptr, *funcNode = nullptr, *modNode = nullptr; + QTreeWidgetItem *lastSubrNode = nullptr, *lastFuncNode = nullptr, *lastModNode = nullptr; QPixmap func( ( const char** ) class_xpm ); QPixmap subr( ( const char** ) macro_xpm ); QPixmap mod( ( const char** ) struct_xpm ); //It is necessary to change names m_macro->setText(i18n("Show Subroutines")); m_struct->setText(i18n("Show Modules")); m_func->setText(i18n("Show Functions")); if(m_plugin->treeOn) { funcNode = new QTreeWidgetItem(m_symbols, QStringList(i18n("Functions") ) ); subrNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Subroutines") ) ); modNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Modules") ) ); funcNode->setIcon(0, QIcon(func)); modNode->setIcon(0, QIcon(mod)); subrNode->setIcon(0, QIcon(subr)); if (m_plugin->expandedOn) { m_symbols->expandItem(funcNode); m_symbols->expandItem(subrNode); m_symbols->expandItem(modNode); } lastSubrNode = subrNode; lastFuncNode = funcNode; lastModNode = modNode; m_symbols->setRootIsDecorated(1); } else m_symbols->setRootIsDecorated(0); KTextEditor::Document *kDoc = m_mainWindow->activeView()->document(); for (i = 0; i < kDoc->lines(); i++) { currline = kDoc->line(i); currline = currline.trimmed(); //currline = currline.simplified(); is this really needed ? //Fortran is case insensitive currline = currline.toLower(); bool comment = false; //kdDebug(13000)< 0) || currline.startsWith(funcStr) ) { block=3; stripped.clear(); } //Subroutines if(block==1) { if(currline.startsWith(QLatin1String("program "))) mainprog=true; if (macro_on == true) // not really a macro, but a subroutines { stripped += currline.right(currline.length()); stripped = stripped.simplified(); stripped.remove(QLatin1Char('*')); stripped.remove(QLatin1Char('+')); stripped.remove(QLatin1Char('$')); if(blockend==0) { fnd = stripped.indexOf(QLatin1Char(' ')); stripped = currline.right(currline.length()-fnd-1); } stripped.remove(QLatin1Char(' ')); fnd = stripped.indexOf(QLatin1Char('!')); if(fnd>0) { stripped = stripped.left(fnd); } paro+=currline.count(QLatin1Char(')'), Qt::CaseSensitive); parc+=currline.count(QLatin1Char('('), Qt::CaseSensitive); if((paro==parc || mainprog) && stripped.endsWith(QLatin1Char('&'), Qt::CaseInsensitive)==false) { stripped.remove(QLatin1Char('&')); if(mainprog && stripped.indexOf(QLatin1Char('('))<0 && stripped.indexOf(QLatin1Char(')'))<0) stripped.prepend(QLatin1String("Main: ")); if(stripped.indexOf(QLatin1Char('='))==-1) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(subrNode, lastSubrNode); lastSubrNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(subr)); node->setText(1, QString::number( i, 10)); } stripped.clear(); block=0; blockend=0; paro=0; parc=0; } else { blockend=1; } } } //Modules else if(block==2) { if (struct_on == true) // not really a struct, but a module { stripped = currline.right(currline.length()); stripped = stripped.simplified(); fnd = stripped.indexOf(QLatin1Char(' ')); stripped = currline.right(currline.length()-fnd-1); fnd = stripped.indexOf(QLatin1Char('!')); if(fnd>0) { stripped = stripped.left(fnd); } if(stripped.indexOf(QLatin1Char('='))==-1) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(modNode, lastModNode); lastModNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(mod)); node->setText(1, QString::number( i, 10)); } stripped.clear(); } block=0; blockend=0; } //Functions else if(block==3) { if (func_on == true) { stripped += currline.right(currline.length()); stripped = stripped.trimmed(); stripped.remove( QLatin1String("function") ); stripped.remove(QLatin1Char('*')); stripped.remove(QLatin1Char('+')); stripped.remove(QLatin1Char('$')); stripped = stripped.simplified(); fnd = stripped.indexOf(QLatin1Char('!')); if(fnd>0) { stripped = stripped.left(fnd); } stripped = stripped.trimmed(); paro+=currline.count(QLatin1Char(')'), Qt::CaseSensitive); parc+=currline.count(QLatin1Char('('), Qt::CaseSensitive); if(paro==parc && stripped.endsWith(QLatin1Char('&'))==false) { stripped.remove(QLatin1Char('&')); if (m_plugin->treeOn) { node = new QTreeWidgetItem(funcNode, lastFuncNode); lastFuncNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(func)); node->setText(1, QString::number( i, 10)); stripped.clear(); block=0; paro=0; parc=0; } blockend=0; } } } } //for i loop } diff --git a/addons/symbolviewer/perl_parser.cpp b/addons/symbolviewer/perl_parser.cpp index 5ab796bb8..87ddc512a 100644 --- a/addons/symbolviewer/perl_parser.cpp +++ b/addons/symbolviewer/perl_parser.cpp @@ -1,142 +1,142 @@ /*************************************************************************** perl_parser.cpp - description ------------------- begin : Apr 2 2003 author : 2003 Massimo Callegari email : massimocallegari@yahoo.it ***************************************************************************/ /*************************************************************************** * * * 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" void KatePluginSymbolViewerView::parsePerlSymbols(void) { if (!m_mainWindow->activeView()) return; m_macro->setText(i18n("Show Uses")); m_struct->setText(i18n("Show Pragmas")); m_func->setText(i18n("Show Subroutines")); QString cl; // Current Line QString stripped; char comment = 0; QPixmap cls( ( const char** ) class_xpm ); QPixmap sct( ( const char** ) struct_xpm ); QPixmap mcr( ( const char** ) macro_xpm ); QPixmap cls_int( ( const char** ) class_int_xpm ); - QTreeWidgetItem *node = NULL; - QTreeWidgetItem *mcrNode = NULL, *sctNode = NULL, *clsNode = NULL; - QTreeWidgetItem *lastMcrNode = NULL, *lastSctNode = NULL, *lastClsNode = NULL; + QTreeWidgetItem *node = nullptr; + QTreeWidgetItem *mcrNode = nullptr, *sctNode = nullptr, *clsNode = nullptr; + QTreeWidgetItem *lastMcrNode = nullptr, *lastSctNode = nullptr, *lastClsNode = nullptr; KTextEditor::Document *kv = m_mainWindow->activeView()->document(); //kdDebug(13000)<<"Lines counted :"<numLines()<treeOn) { mcrNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Uses") ) ); sctNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Pragmas") ) ); clsNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Subroutines") ) ); mcrNode->setIcon(0, QIcon(mcr)); sctNode->setIcon(0, QIcon(sct)); clsNode->setIcon(0, QIcon(cls)); if (m_plugin->expandedOn) { m_symbols->expandItem(mcrNode); m_symbols->expandItem(sctNode); m_symbols->expandItem(clsNode); } lastMcrNode = mcrNode; lastSctNode = sctNode; lastClsNode = clsNode; m_symbols->setRootIsDecorated(1); } else m_symbols->setRootIsDecorated(0); for (int i=0; ilines(); i++) { cl = kv->line(i); //qDebug()<< "Line " << i << " : "<< cl; if(cl.isEmpty() || cl.at(0) == QLatin1Char('#')) continue; if(cl.indexOf(QRegExp(QLatin1String("^=[a-zA-Z]"))) >= 0) comment = 1; if(cl.indexOf(QRegExp(QLatin1String("^=cut$"))) >= 0) { comment = 0; continue; } if (comment==1) continue; cl = cl.trimmed(); //qDebug()<<"Trimmed line " << i << " : "<< cl; if(cl.indexOf(QRegExp(QLatin1String("^use +[A-Z]"))) == 0 && macro_on) { QString stripped=cl.remove( QRegExp(QLatin1String("^use +")) ); //stripped=stripped.replace( QRegExp(QLatin1String(";$")), "" ); // Doesn't work ?? stripped = stripped.left(stripped.indexOf(QLatin1Char(';'))); if (m_plugin->treeOn) { node = new QTreeWidgetItem(mcrNode, lastMcrNode); lastMcrNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(mcr)); node->setText(1, QString::number( i, 10)); } #if 1 if(cl.indexOf(QRegExp(QLatin1String("^use +[a-z]"))) == 0 && struct_on) { QString stripped=cl.remove( QRegExp(QLatin1String("^use +")) ); stripped=stripped.remove( QRegExp(QLatin1String(";$")) ); if (m_plugin->treeOn) { node = new QTreeWidgetItem(sctNode, lastSctNode); lastMcrNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(sct)); node->setText(1, QString::number( i, 10)); } #endif #if 1 if(cl.indexOf(QRegExp(QLatin1String("^sub +")))==0 && func_on) { QString stripped=cl.remove( QRegExp(QLatin1String("^sub +")) ); stripped=stripped.remove( QRegExp(QLatin1String("[{;] *$")) ); if (m_plugin->treeOn) { node = new QTreeWidgetItem(clsNode, lastClsNode); lastClsNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); if (!stripped.isEmpty() && stripped.at(0)==QLatin1Char('_')) node->setIcon(0, QIcon(cls_int)); else node->setIcon(0, QIcon(cls)); node->setText(1, QString::number( i, 10)); } #endif } } diff --git a/addons/symbolviewer/php_parser.cpp b/addons/symbolviewer/php_parser.cpp index cfdd7eb41..9cd68013d 100644 --- a/addons/symbolviewer/php_parser.cpp +++ b/addons/symbolviewer/php_parser.cpp @@ -1,335 +1,335 @@ /*************************************************************************** php_parser.cpp - description ------------------- begin : Apr 1st 2007 last update : Sep 14th 2010 author(s) : 2007, Massimo Callegari : 2010, Emmanuel Bouthenot ***************************************************************************/ /*************************************************************************** * * * 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" void KatePluginSymbolViewerView::parsePhpSymbols(void) { if (m_mainWindow->activeView()) { QString line, lineWithliterals; QPixmap namespacePix( ( const char** ) class_int_xpm ); QPixmap definePix( ( const char** ) macro_xpm ); QPixmap varPix( ( const char** ) struct_xpm ); QPixmap classPix( ( const char** ) class_xpm ); QPixmap constPix( ( const char** ) macro_xpm ); QPixmap functionPix( ( const char** ) method_xpm ); - QTreeWidgetItem *node = NULL; - QTreeWidgetItem *namespaceNode = NULL, *defineNode = NULL, \ - *classNode = NULL, *functionNode = NULL; - QTreeWidgetItem *lastNamespaceNode = NULL, *lastDefineNode = NULL, \ - *lastClassNode = NULL, *lastFunctionNode = NULL; + QTreeWidgetItem *node = nullptr; + QTreeWidgetItem *namespaceNode = nullptr, *defineNode = nullptr, \ + *classNode = nullptr, *functionNode = nullptr; + QTreeWidgetItem *lastNamespaceNode = nullptr, *lastDefineNode = nullptr, \ + *lastClassNode = nullptr, *lastFunctionNode = nullptr; KTextEditor::Document *kv = m_mainWindow->activeView()->document(); if (m_plugin->treeOn) { namespaceNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Namespaces") ) ); defineNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Defines") ) ); classNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Classes") ) ); functionNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Functions") ) ); namespaceNode->setIcon(0, QIcon( namespacePix ) ); defineNode->setIcon(0, QIcon( definePix ) ); classNode->setIcon(0, QIcon( classPix ) ); functionNode->setIcon(0, QIcon( functionPix ) ); if (m_plugin->expandedOn) { m_symbols->expandItem(namespaceNode); m_symbols->expandItem(defineNode); m_symbols->expandItem(classNode); m_symbols->expandItem(functionNode); } lastNamespaceNode = namespaceNode; lastDefineNode = defineNode; lastClassNode = classNode; lastFunctionNode = functionNode; m_symbols->setRootIsDecorated(1); } else { m_symbols->setRootIsDecorated(0); } // Namespaces: http://www.php.net/manual/en/language.namespaces.php QRegExp namespaceRegExp(QLatin1String("^namespace\\s+([^;\\s]+)"), Qt::CaseInsensitive); // defines: http://www.php.net/manual/en/function.define.php QRegExp defineRegExp(QLatin1String("(^|\\W)define\\s*\\(\\s*['\"]([^'\"]+)['\"]"), Qt::CaseInsensitive); // classes: http://www.php.net/manual/en/language.oop5.php QRegExp classRegExp(QLatin1String("^((abstract\\s+|final\\s+)?)class\\s+([\\w_][\\w\\d_]*)\\s*(implements\\s+[\\w\\d_]*)?"), Qt::CaseInsensitive); // interfaces: http://www.php.net/manual/en/language.oop5.php QRegExp interfaceRegExp(QLatin1String("^interface\\s+([\\w_][\\w\\d_]*)"), Qt::CaseInsensitive); // classes constants: http://www.php.net/manual/en/language.oop5.constants.php QRegExp constantRegExp(QLatin1String("^const\\s+([\\w_][\\w\\d_]*)"), Qt::CaseInsensitive); // functions: http://www.php.net/manual/en/language.oop5.constants.php QRegExp functionRegExp(QLatin1String("^((public|protected|private)?(\\s*static)?\\s+)?function\\s+&?\\s*([\\w_][\\w\\d_]*)\\s*(.*)$"), Qt::CaseInsensitive); // variables: http://www.php.net/manual/en/language.oop5.properties.php QRegExp varRegExp(QLatin1String("^((var|public|protected|private)?(\\s*static)?\\s+)?\\$([\\w_][\\w\\d_]*)"), Qt::CaseInsensitive); // function args detection: “function a($b, $c=null)” => “$b, $v” QRegExp functionArgsRegExp(QLatin1String("(\\$[\\w_]+)"), Qt::CaseInsensitive); QStringList functionArgsList; QString functionArgs; QString nameWithTypes; // replace literals by empty strings: “function a($b='nothing', $c="pretty \"cool\" string")” => “function ($b='', $c="")” QRegExp literalRegExp(QLatin1String("([\"'])(?:\\\\.|[^\\\\])*\\1")); literalRegExp.setMinimal(true); // remove useless comments: “public/* static */ function a($b, $c=null) /* test */” => “public function a($b, $c=null)” QRegExp blockCommentInline(QLatin1String("/\\*.*\\*/")); blockCommentInline.setMinimal(true); int i, pos; bool isClass, isInterface; bool inBlockComment = false; bool inClass = false, inFunction = false; //QString debugBuffer("SymbolViewer(PHP), line %1 %2 → [%3]"); for (i=0; ilines(); i++) { //kdDebug(13000) << debugBuffer.arg(i, 4).arg("=origin", 10).arg(kv->line(i)); line = kv->line(i).simplified(); //kdDebug(13000) << debugBuffer.arg(i, 4).arg("+simplified", 10).arg(line); // keeping a copy with literals for catching “defines()” lineWithliterals = line; // reduce literals to empty strings to not match comments separators in literals line.replace(literalRegExp, QLatin1String("\\1\\1")); //kdDebug(13000) << debugBuffer.arg(i, 4).arg("-literals", 10).arg(line); line.remove(blockCommentInline); //kdDebug(13000) << debugBuffer.arg(i, 4).arg("-comments", 10).arg(line); // trying to find comments and to remove commented parts pos = line.indexOf(QLatin1Char('#')); if (pos >= 0) { line = line.left(pos); } pos = line.indexOf(QLatin1String("//")); if (pos >= 0) { line = line.left(pos); } pos = line.indexOf(QLatin1String("/*")); if (pos >= 0) { line = line.left(pos); inBlockComment = true; } pos = line.indexOf(QLatin1String("*/")); if (pos >= 0) { line = line.right(line.length() - pos - 2); inBlockComment = false; } if (inBlockComment) { continue; } // trimming again after having removed the comments line = line.simplified(); //kdDebug(13000) << debugBuffer.arg(i, 4).arg("+simplified", 10).arg(line); // detect NameSpaces if (namespaceRegExp.indexIn(line) != -1) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(namespaceNode, lastNamespaceNode); if (m_plugin->expandedOn) { m_symbols->expandItem(node); } lastNamespaceNode = node; } else { node = new QTreeWidgetItem(m_symbols); } node->setText(0, namespaceRegExp.cap(1)); node->setIcon(0, QIcon(namespacePix)); node->setText(1, QString::number( i, 10)); } // detect defines if (defineRegExp.indexIn(lineWithliterals) != -1) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(defineNode, lastDefineNode); lastDefineNode = node; } else { node = new QTreeWidgetItem(m_symbols); } node->setText(0, defineRegExp.cap(2)); node->setIcon(0, QIcon(definePix)); node->setText(1, QString::number( i, 10)); } // detect classes, interfaces isClass = classRegExp.indexIn(line) != -1; isInterface = interfaceRegExp.indexIn(line) != -1; if (isClass || isInterface) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(classNode, lastClassNode); if (m_plugin->expandedOn) { m_symbols->expandItem(node); } lastClassNode = node; } else { node = new QTreeWidgetItem(m_symbols); } if (isClass) { if (m_plugin->typesOn) { if (!classRegExp.cap(1).trimmed().isEmpty() && !classRegExp.cap(4).trimmed().isEmpty()) { nameWithTypes = classRegExp.cap(3)+QLatin1String(" [")+classRegExp.cap(1).trimmed()+QLatin1Char(',')+classRegExp.cap(4).trimmed()+QLatin1Char(']'); } else if (!classRegExp.cap(1).trimmed().isEmpty()) { nameWithTypes = classRegExp.cap(3)+QLatin1String(" [")+classRegExp.cap(1).trimmed()+QLatin1Char(']'); } else if (!classRegExp.cap(4).trimmed().isEmpty()) { nameWithTypes = classRegExp.cap(3)+QLatin1String(" [")+classRegExp.cap(4).trimmed()+QLatin1Char(']'); } node->setText(0, nameWithTypes); } else { node->setText(0, classRegExp.cap(3)); } } else { if (m_plugin->typesOn) { nameWithTypes = interfaceRegExp.cap(1) + QLatin1String(" [interface]"); node->setText(0, nameWithTypes); } else { node->setText(0, interfaceRegExp.cap(1)); } } node->setIcon(0, QIcon(classPix)); node->setText(1, QString::number( i, 10)); node->setToolTip(0, nameWithTypes); inClass = true; inFunction = false; } // detect class constants if (constantRegExp.indexIn(line) != -1) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(lastClassNode); } else { node = new QTreeWidgetItem(m_symbols); } node->setText(0, constantRegExp.cap(1)); node->setIcon(0, QIcon(constPix)); node->setText(1, QString::number( i, 10)); } // detect class variables if (inClass && !inFunction) { if (varRegExp.indexIn(line) != -1) { if (m_plugin->treeOn && inClass) { node = new QTreeWidgetItem(lastClassNode); } else { node = new QTreeWidgetItem(m_symbols); } node->setText(0, varRegExp.cap(4)); node->setIcon(0, QIcon(varPix)); node->setText(1, QString::number( i, 10)); } } // detect functions if (functionRegExp.indexIn(line) != -1) { if (m_plugin->treeOn && inClass) { node = new QTreeWidgetItem(lastClassNode); } else if (m_plugin->treeOn) { node = new QTreeWidgetItem(lastFunctionNode); } else { node = new QTreeWidgetItem(m_symbols); } QString functionArgs(functionRegExp.cap(5)); pos = 0; while (pos >= 0) { pos = functionArgsRegExp.indexIn(functionArgs, pos); if (pos >= 0) { pos += functionArgsRegExp.matchedLength(); functionArgsList += functionArgsRegExp.cap(1); } } nameWithTypes = functionRegExp.cap(4) + QLatin1Char('(') + functionArgsList.join(QLatin1String(", ")) + QLatin1Char(')'); if (m_plugin->typesOn) { node->setText(0, nameWithTypes); } else { node->setText(0, functionRegExp.cap(4)); } node->setIcon(0, QIcon(functionPix)); node->setText(1, QString::number( i, 10)); node->setToolTip(0, nameWithTypes); functionArgsList.clear(); inFunction = true; } } } } diff --git a/addons/symbolviewer/plugin_katesymbolviewer.cpp b/addons/symbolviewer/plugin_katesymbolviewer.cpp index 1d3d8949a..034be92a8 100644 --- a/addons/symbolviewer/plugin_katesymbolviewer.cpp +++ b/addons/symbolviewer/plugin_katesymbolviewer.cpp @@ -1,468 +1,468 @@ /*************************************************************************** * 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 = 0; + 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())); m_currItemTimer.setSingleShot(true); connect(&m_currItemTimer, SIGNAL(timeout()), this, SLOT(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_mainWindow, SIGNAL(viewChanged(KTextEditor::View *)), this, SLOT(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); if (view->document()) { connect(view->document(), SIGNAL(textChanged(KTextEditor::Document*)), this, SLOT(slotDocEdited()), Qt::UniqueConnection); } } } 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 = 0; - QTreeWidgetItem *tmp = 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 = 0; - QTreeWidgetItem *tmp = 0; + 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(NULL, 10), 0)); + 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*)) ); 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())); } 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/symbolviewer/plugin_katesymbolviewer.h b/addons/symbolviewer/plugin_katesymbolviewer.h index 8c58eac36..d10551c20 100644 --- a/addons/symbolviewer/plugin_katesymbolviewer.h +++ b/addons/symbolviewer/plugin_katesymbolviewer.h @@ -1,312 +1,312 @@ /*************************************************************************** plugin_katesymbolviewer.h - description ------------------- begin : Apr 2 2003 author : 2003 Massimo Callegari email : massimocallegari@yahoo.it ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifndef _PLUGIN_KATE_SYMBOLVIEWER_H_ #define _PLUGIN_KATE_SYMBOLVIEWER_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** * Plugin's config page */ class KatePluginSymbolViewerConfigPage : public KTextEditor::ConfigPage { Q_OBJECT friend class KatePluginSymbolViewer; public: - explicit KatePluginSymbolViewerConfigPage (QObject* parent = 0L, QWidget *parentWidget = 0L); + explicit KatePluginSymbolViewerConfigPage (QObject* parent = nullptr, QWidget *parentWidget = nullptr); ~KatePluginSymbolViewerConfigPage (); /** * Reimplemented from KTextEditor::ConfigPage * just emits configPageApplyRequest( this ). */ QString name() const Q_DECL_OVERRIDE; QString fullName() const Q_DECL_OVERRIDE; QIcon icon() const Q_DECL_OVERRIDE; void apply() Q_DECL_OVERRIDE; void reset () Q_DECL_OVERRIDE { ; } void defaults () Q_DECL_OVERRIDE { ; } Q_SIGNALS: /** * Ask the plugin to set initial values */ void configPageApplyRequest( KatePluginSymbolViewerConfigPage* ); /** * Ask the plugin to apply changes */ void configPageInitRequest( KatePluginSymbolViewerConfigPage* ); private: QCheckBox* viewReturns; QCheckBox* expandTree; QCheckBox* treeView; QCheckBox* sortSymbols; }; class KatePluginSymbolViewer; class KatePluginSymbolViewerView : public QObject, public KXMLGUIClient { Q_OBJECT public: KatePluginSymbolViewerView (KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mw); virtual ~KatePluginSymbolViewerView (); void parseSymbols(void); public Q_SLOTS: void slotRefreshSymbol(); void slotChangeMode(); void slotEnableSorting(); void slotDocChanged(); void goToSymbol(QTreeWidgetItem *); void slotShowContextMenu(const QPoint&); void toggleShowMacros(void); void toggleShowStructures(void); void toggleShowFunctions(void); void cursorPositionChanged(); QTreeWidgetItem *newActveItem(int &currMinLine, int currLine, QTreeWidgetItem *item); void updateCurrTreeItem(); void slotDocEdited(); protected: bool eventFilter(QObject *obj, QEvent *ev) Q_DECL_OVERRIDE; private: KTextEditor::MainWindow *m_mainWindow; KatePluginSymbolViewer *m_plugin; QMenu *m_popup; QWidget *m_toolview; QTreeWidget *m_symbols; QAction *m_macro, *m_struct, *m_func, *m_sort; bool macro_on, struct_on, func_on; QTimer m_updateTimer; QTimer m_currItemTimer; void updatePixmapScroll(); void parseCppSymbols(void); void parseTclSymbols(void); void parseFortranSymbols(void); void parsePerlSymbols(void); void parsePythonSymbols(void); void parseRubySymbols(void); void parseXsltSymbols(void); void parsePhpSymbols(void); void parseBashSymbols(void); void parseEcmaSymbols(void); }; class KatePluginSymbolViewer : public KTextEditor::Plugin { Q_OBJECT public: - explicit KatePluginSymbolViewer(QObject* parent = 0, const QList& = QList()); + explicit KatePluginSymbolViewer(QObject* parent = nullptr, const QList& = QList()); virtual ~KatePluginSymbolViewer(); QObject *createView (KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; int configPages () const Q_DECL_OVERRIDE { return 1; } - KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = 0) Q_DECL_OVERRIDE; + KTextEditor::ConfigPage *configPage (int number = 0, QWidget *parent = nullptr) Q_DECL_OVERRIDE; public Q_SLOTS: void applyConfig( KatePluginSymbolViewerConfigPage* p ); public: bool typesOn; bool expandedOn; bool treeOn; bool sortOn; }; /* XPM */ static const char* const class_xpm[] = { "16 16 10 1", " c None", ". c #000000", "+ c #A4E8FC", "@ c #24D0FC", "# c #001CD0", "$ c #0080E8", "% c #C0FFFF", "& c #00FFFF", "* c #008080", "= c #00C0C0", " .. ", " .++.. ", " .+++@@. ", " .@@@@@#... ", " .$$@@##.%%.. ", " .$$$##.%%%&&. ", " .$$$#.&&&&&*. ", " ...#.==&&**. ", " .++..===***. ", " .+++@@.==**. ", " .@@@@@#..=*. ", " .$$@@##. .. ", " .$$$###. ", " .$$$##. ", " ..$#. ", " .. "}; static const char * const class_int_xpm[] = { "16 16 10 1", " c None", ". c #000000", "+ c #B8B8B8", "@ c #8A8A8A", "# c #212121", "$ c #575757", "% c #CCCCCC", "& c #9A9A9A", "* c #4D4D4D", "= c #747474", " .. ", " .++.. ", " .+++@@. ", " .@@@@@#... ", " .$$@@##.%%.. ", " .$$$##.%%%&&. ", " .$$$#.&&&&&*. ", " ...#.==&&**. ", " .++..===***. ", " .+++@@.==**. ", " .@@@@@#..=*. ", " .$$@@##. .. ", " .$$$###. ", " .$$$##. ", " ..$#. ", " .. "}; static const char* const struct_xpm[] = { "16 16 14 1", " c None", ". c #000000", "+ c #C0FFC0", "@ c #00FF00", "# c #008000", "$ c #00C000", "% c #C0FFFF", "& c #00FFFF", "* c #008080", "= c #00C0C0", "- c #FFFFC0", "; c #FFFF00", "> c #808000", ", c #C0C000", " .. ", " .++.. ", " .+++@@. ", " .@@@@@#... ", " .$$@@##.%%.. ", " .$$$##.%%%&&. ", " .$$$#.&&&&&*. ", " ...#.==&&**. ", " .--..===***. ", " .---;;.==**. ", " .;;;;;>..=*. ", " .,,;;>>. .. ", " .,,,>>>. ", " .,,,>>. ", " ..,>. ", " .. "}; static const char* const macro_xpm[] = { "16 16 14 1", " c None", ". c #000000", "+ c #FF7FE5", "@ c #FF00C7", "# c #7F0066", "$ c #BC0096", "% c #C0FFFF", "& c #00FFFF", "* c #008080", "= c #00C0C0", "- c #D493FF", "; c #A100FF", "> c #470082", ", c #6B00B7", " .. ", " .++.. ", " .+++@@. ", " .@@@@@#... ", " .$$@@##.%%.. ", " .$$$##.%%%&&. ", " .$$$#.&&&&&*. ", " ...#.==&&**. ", " .--..===***. ", " .---;;.==**. ", " .;;;;;>..=*. ", " .,,;;>>. .. ", " .,,,>>>. ", " .,,,>>. ", " ..,>. ", " .. "}; static const char* const method_xpm[] = { "16 16 5 1", " c None", ". c #000000", "+ c #FCFC80", "@ c #E0BC38", "# c #F0DC5C", " ", " ", " ", " .. ", " .++.. ", " .+++++. ", " .+++++@. ", " .. .##++@@. ", " .++..###@@@. ", " .+++++.##@@. ", " .+++++@..#@. ", " .##++@@. .. ", " .###@@@. ", " .###@@. ", " ..#@. ", " .. " }; #endif diff --git a/addons/symbolviewer/python_parser.cpp b/addons/symbolviewer/python_parser.cpp index f85b41b00..7be0848f8 100644 --- a/addons/symbolviewer/python_parser.cpp +++ b/addons/symbolviewer/python_parser.cpp @@ -1,165 +1,165 @@ /*************************************************************************** python_parser.cpp - description ------------------- begin : Apr 2 2003 author : 2003 Massimo Callegari email : massimocallegari@yahoo.it ***************************************************************************/ /*************************************************************************** * * * 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" void KatePluginSymbolViewerView::parsePythonSymbols(void) { if (!m_mainWindow->activeView()) return; m_macro->setText(i18n("Show Globals")); m_struct->setText(i18n("Show Methods")); m_func->setText(i18n("Show Classes")); QString cl; // Current Line QPixmap cls( ( const char** ) class_xpm ); QPixmap mtd( ( const char** ) method_xpm ); QPixmap mcr( ( const char** ) macro_xpm ); int in_class = 0, state = 0, j; QString name; - QTreeWidgetItem *node = NULL; - QTreeWidgetItem *mcrNode = NULL, *mtdNode = NULL, *clsNode = NULL; - QTreeWidgetItem *lastMcrNode = NULL, *lastMtdNode = NULL, *lastClsNode = NULL; + QTreeWidgetItem *node = nullptr; + QTreeWidgetItem *mcrNode = nullptr, *mtdNode = nullptr, *clsNode = nullptr; + QTreeWidgetItem *lastMcrNode = nullptr, *lastMtdNode = nullptr, *lastClsNode = nullptr; KTextEditor::Document *kv = m_mainWindow->activeView()->document(); //kdDebug(13000)<<"Lines counted :"<numLines()<treeOn) { clsNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Classes") ) ); mcrNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Globals") ) ); mcrNode->setIcon(0, QIcon(mcr)); clsNode->setIcon(0, QIcon(cls)); if (m_plugin->expandedOn) { m_symbols->expandItem(mcrNode); m_symbols->expandItem(clsNode); } lastClsNode = clsNode; lastMcrNode = mcrNode; mtdNode = clsNode; lastMtdNode = clsNode; m_symbols->setRootIsDecorated(1); } else m_symbols->setRootIsDecorated(0); for (int i=0; ilines(); i++) { int line=i; cl = kv->line(i); // concatenate continued lines and remove continuation marker if (cl.length()==0) continue; while (cl[cl.length()-1]==QLatin1Char('\\')) { cl=cl.left(cl.length()-1); i++; if (ilines()) cl+=kv->line(i); else break; } if(cl.indexOf( QRegExp(QLatin1String("^class [a-zA-Z0-9_,\\s\\(\\).]+:")) ) >= 0) in_class = 1; //if(cl.find( QRegExp(QLatin1String("[\\s]+def [a-zA-Z_]+[^#]*:")) ) >= 0) in_class = 2; if(cl.indexOf( QRegExp(QLatin1String("^def\\s+[a-zA-Z_]+[^#]*:")) ) >= 0 ) in_class = 0; if (cl.indexOf(QLatin1String("def ")) >= 0 || (cl.indexOf(QLatin1String("class ")) >= 0 && in_class == 1)) { if (cl.indexOf(QLatin1String("def ")) >= 0 && in_class == 1) in_class = 2; state = 1; if (cl.indexOf(QLatin1Char(':')) >= 0) state = 3; // found in the same line. Done else if (cl.indexOf(QLatin1Char('(')) >= 0) state = 2; if (state == 2 || state == 3) name = cl.left (cl.indexOf (QLatin1Char('('))); } if (state > 0 && state < 3) { for (j = 0; j < cl.length(); j++) { if (cl.at(j) == QLatin1Char('(')) state = 2; else if (cl.at(j) == QLatin1Char(':')) { state = 3; break; } if (state == 1) name += cl.at(j); } } if (state == 3) { //qDebug(13000)<<"Function -- Inserted : "<treeOn) { node = new QTreeWidgetItem(clsNode, lastClsNode); if (m_plugin->expandedOn) m_symbols->expandItem(node); lastClsNode = node; mtdNode = lastClsNode; lastMtdNode = lastClsNode; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, name); node->setIcon(0, QIcon(cls)); node->setText(1, QString::number( line, 10)); } if (struct_on == true && in_class == 2) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(mtdNode, lastMtdNode); lastMtdNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, name); node->setIcon(0, QIcon(mtd)); node->setText(1, QString::number( line, 10)); } if (macro_on == true && in_class == 0) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(mcrNode, lastMcrNode); lastMcrNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, name); node->setIcon(0, QIcon(mcr)); node->setText(1, QString::number( line, 10)); } state = 0; name.clear(); } } } // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/symbolviewer/ruby_parser.cpp b/addons/symbolviewer/ruby_parser.cpp index 63a7896ff..c77148b27 100644 --- a/addons/symbolviewer/ruby_parser.cpp +++ b/addons/symbolviewer/ruby_parser.cpp @@ -1,106 +1,106 @@ /*************************************************************************** ruby_parser.cpp - description ------------------- begin : May 9th 2007 author : 2007 Massimo Callegari email : massimocallegari@yahoo.it ***************************************************************************/ /*************************************************************************** * * * 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" void KatePluginSymbolViewerView::parseRubySymbols(void) { if (!m_mainWindow->activeView()) return; m_macro->setText(i18n("Show Globals")); m_struct->setText(i18n("Show Methods")); m_func->setText(i18n("Show Classes")); QString cl; // Current Line QPixmap cls( ( const char** ) class_xpm ); QPixmap mtd( ( const char** ) method_xpm ); QPixmap mcr( ( const char** ) macro_xpm ); int i; QString name; - QTreeWidgetItem *node = NULL; - QTreeWidgetItem *mtdNode = NULL, *clsNode = NULL; - QTreeWidgetItem *lastMtdNode = NULL, *lastClsNode = NULL; + QTreeWidgetItem *node = nullptr; + QTreeWidgetItem *mtdNode = nullptr, *clsNode = nullptr; + QTreeWidgetItem *lastMtdNode = nullptr, *lastClsNode = nullptr; KTextEditor::Document *kv = m_mainWindow->activeView()->document(); //kdDebug(13000)<<"Lines counted :"<numLines()<treeOn) { clsNode = new QTreeWidgetItem(m_symbols); clsNode->setText(0, i18n("Classes")); clsNode->setIcon(0, QIcon(cls)); if (m_plugin->expandedOn) m_symbols->expandItem(clsNode); lastClsNode = clsNode; mtdNode = clsNode; lastMtdNode = clsNode; m_symbols->setRootIsDecorated(1); } else m_symbols->setRootIsDecorated(0); for (i=0; ilines(); i++) { cl = kv->line(i); cl = cl.trimmed(); if (cl.indexOf( QRegExp(QLatin1String("^class [a-zA-Z0-9]+[^#]")) ) >= 0) { if (func_on == true) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(clsNode, lastClsNode); if (m_plugin->expandedOn) m_symbols->expandItem(node); lastClsNode = node; mtdNode = lastClsNode; lastMtdNode = lastClsNode; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, cl.mid(6)); node->setIcon(0, QIcon(cls)); node->setText(1, QString::number( i, 10)); } } if (cl.indexOf( QRegExp(QLatin1String("^def [a-zA-Z_]+[^#]")) ) >= 0 ) { if (struct_on == true) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(mtdNode, lastMtdNode); lastMtdNode = node; } else node = new QTreeWidgetItem(m_symbols); name = cl.mid(4); node->setToolTip(0, name); if (m_plugin->typesOn == false) { name = name.left(name.indexOf(QLatin1Char('('))); } node->setText(0, name); node->setIcon(0, QIcon(mtd)); node->setText(1, QString::number( i, 10)); } } } } diff --git a/addons/symbolviewer/tcl_parser.cpp b/addons/symbolviewer/tcl_parser.cpp index 3f2722252..c6a2035b3 100644 --- a/addons/symbolviewer/tcl_parser.cpp +++ b/addons/symbolviewer/tcl_parser.cpp @@ -1,157 +1,157 @@ /*************************************************************************** tcl_parser.cpp - description ------------------- begin : Apr 2 2003 author : 2003 Massimo Callegari email : massimocallegari@yahoo.it ***************************************************************************/ /*************************************************************************** * * * 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 void KatePluginSymbolViewerView::parseTclSymbols(void) { if (!m_mainWindow->activeView()) return; QString currline, prevline; bool prevComment = false; QString varStr(QLatin1String("set ")); QString procStr(QLatin1String("proc")); QString stripped; int i, j, args_par = 0, graph = 0; char block = 0, parse_func = 0; - QTreeWidgetItem *node = NULL; - QTreeWidgetItem *mcrNode = NULL, *clsNode = NULL; - QTreeWidgetItem *lastMcrNode = NULL, *lastClsNode = NULL; + QTreeWidgetItem *node = nullptr; + QTreeWidgetItem *mcrNode = nullptr, *clsNode = nullptr; + QTreeWidgetItem *lastMcrNode = nullptr, *lastClsNode = nullptr; QPixmap mcr( ( const char** ) macro_xpm ); QPixmap cls( ( const char** ) class_xpm ); if(m_plugin->treeOn) { clsNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Functions") ) ); mcrNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Globals") ) ); clsNode->setIcon(0, QIcon(cls)); mcrNode->setIcon(0, QIcon(mcr)); lastMcrNode = mcrNode; lastClsNode = clsNode; if (m_plugin->expandedOn) { m_symbols->expandItem(clsNode); m_symbols->expandItem(mcrNode); } m_symbols->setRootIsDecorated(1); } else m_symbols->setRootIsDecorated(0); KTextEditor::Document *kDoc = m_mainWindow->activeView()->document(); //positions.resize(kDoc->numLines() + 3); // Maximum m_symbols number o.O //positions.fill(0); for (i = 0; ilines(); i++) { currline = kDoc->line(i); currline = currline.trimmed(); bool comment = false; //qDebug(13000)< 0) { prevline = kDoc->line(i-1); if(prevline.endsWith(QLatin1String("\\")) && prevComment) comment = true; } prevComment = comment; if(!comment) { if(currline.startsWith(varStr) && block == 0) { if (macro_on == true) // not really a macro, but a variable { stripped = currline.right(currline.length() - 3); stripped = stripped.simplified(); int fnd = stripped.indexOf(QLatin1Char(' ')); //fnd = stripped.indexOf(QLatin1Char(';')); if(fnd > 0) stripped = stripped.left(fnd); if (m_plugin->treeOn) { node = new QTreeWidgetItem(mcrNode, lastMcrNode); lastMcrNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(mcr)); node->setText(1, QString::number( i, 10)); stripped.clear(); }//macro } // starts with "set" else if(currline.startsWith(procStr)) { parse_func = 1; } if (parse_func == 1) { for (j = 0; j < currline.length(); j++) { if (block == 1) { if(currline.at(j)==QLatin1Char('{')) graph++; if(currline.at(j)==QLatin1Char('}')) { graph--; if (graph == 0) { block = 0; parse_func = 0; continue; } } } if (block == 0) { stripped += currline.at(j); if(currline.at(j) == QLatin1Char('{')) args_par++; if(currline.at(j) == QLatin1Char('}')) { args_par--; if (args_par == 0) { //stripped = stripped.simplified(); if(func_on == true) { if (m_plugin->treeOn) { node = new QTreeWidgetItem(clsNode, lastClsNode); lastClsNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(cls)); node->setText(1, QString::number( i, 10)); } stripped.clear(); block = 1; } } } // block = 0 } // for j loop }//func_on } // not a comment } //for i loop //positions.resize(m_symbols->itemIndex(node) + 1); } diff --git a/addons/symbolviewer/xslt_parser.cpp b/addons/symbolviewer/xslt_parser.cpp index 96edd6315..3d082a4a9 100644 --- a/addons/symbolviewer/xslt_parser.cpp +++ b/addons/symbolviewer/xslt_parser.cpp @@ -1,158 +1,158 @@ /*************************************************************************** xslt_parser.cpp - description ------------------- begin : Mar 28 2007 author : 2007 jiri Tyr email : jiri.tyr@vslib.cz ***************************************************************************/ /*************************************************************************** * * * 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" void KatePluginSymbolViewerView::parseXsltSymbols(void) { if (!m_mainWindow->activeView()) return; m_macro->setText(i18n("Show Params")); m_struct->setText(i18n("Show Variables")); m_func->setText(i18n("Show Templates")); QString cl; // Current Line QString stripped; char comment = 0; char templ = 0; int i; QPixmap cls( ( const char** ) class_xpm ); QPixmap sct( ( const char** ) struct_xpm ); QPixmap mcr( ( const char** ) macro_xpm ); QPixmap cls_int( ( const char** ) class_int_xpm ); - QTreeWidgetItem *node = NULL; - QTreeWidgetItem *mcrNode = NULL, *sctNode = NULL, *clsNode = NULL; - QTreeWidgetItem *lastMcrNode = NULL, *lastSctNode = NULL, *lastClsNode = NULL; + QTreeWidgetItem *node = nullptr; + QTreeWidgetItem *mcrNode = nullptr, *sctNode = nullptr, *clsNode = nullptr; + QTreeWidgetItem *lastMcrNode = nullptr, *lastSctNode = nullptr, *lastClsNode = nullptr; KTextEditor::Document *kv = m_mainWindow->activeView()->document(); //kdDebug(13000)<<"Lines counted :"<numLines()<treeOn) { mcrNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Params") ) ); sctNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Variables") ) ); clsNode = new QTreeWidgetItem(m_symbols, QStringList( i18n("Templates") ) ); mcrNode->setIcon(0, QIcon(mcr)); sctNode->setIcon(0, QIcon(sct)); clsNode->setIcon(0, QIcon(cls)); if (m_plugin->expandedOn) { m_symbols->expandItem(mcrNode); m_symbols->expandItem(sctNode); m_symbols->expandItem(clsNode); } lastMcrNode = mcrNode; lastSctNode = sctNode; lastClsNode = clsNode; m_symbols->setRootIsDecorated(1); } else { m_symbols->setRootIsDecorated(0); } for (i=0; ilines(); i++) { cl = kv->line(i); cl = cl.trimmed(); if(cl.indexOf(QRegExp(QLatin1String(""))) >= 0) { comment = 0; continue; } if(cl.indexOf(QRegExp(QLatin1String("^"))) >= 0) { templ = 0; continue; } if (comment==1) { continue; } if (templ==1) { continue; } if(cl.indexOf(QRegExp(QLatin1String("^treeOn) { node = new QTreeWidgetItem(mcrNode, lastMcrNode); lastMcrNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(mcr)); node->setText(1, QString::number( i, 10)); } if(cl.indexOf(QRegExp(QLatin1String("^treeOn) { node = new QTreeWidgetItem(sctNode, lastSctNode); lastSctNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(sct)); node->setText(1, QString::number( i, 10)); } if(cl.indexOf(QRegExp(QLatin1String("^treeOn) { node = new QTreeWidgetItem(clsNode, lastClsNode); lastClsNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(cls_int)); node->setText(1, QString::number( i, 10)); } if(cl.indexOf(QRegExp(QLatin1String("^treeOn) { node = new QTreeWidgetItem(clsNode, lastClsNode); lastClsNode = node; } else node = new QTreeWidgetItem(m_symbols); node->setText(0, stripped); node->setIcon(0, QIcon(cls)); node->setText(1, QString::number( i, 10)); } if(cl.indexOf(QRegExp(QLatin1String("= 0) { templ = 1; } } } diff --git a/addons/tabswitcher/tabswitcher.cpp b/addons/tabswitcher/tabswitcher.cpp index 0d4fcde34..d71fc8c7a 100644 --- a/addons/tabswitcher/tabswitcher.cpp +++ b/addons/tabswitcher/tabswitcher.cpp @@ -1,286 +1,286 @@ /* 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))); // 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*))); // 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*))); } 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())); 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())); // 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*))); } 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, 0, this, 0); + 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/tabswitcher/tabswitcher.h b/addons/tabswitcher/tabswitcher.h index e94d60945..81c385a10 100644 --- a/addons/tabswitcher/tabswitcher.h +++ b/addons/tabswitcher/tabswitcher.h @@ -1,144 +1,144 @@ /* 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. */ #ifndef KTEXTEDITOR_TAB_SWITCHER_PLUGIN_H #define KTEXTEDITOR_TAB_SWITCHER_PLUGIN_H #include #include #include #include #include #include class TabSwitcherPluginView; class TabSwitcherTreeView; class QStandardItemModel; class QModelIndex; class TabSwitcherPlugin : public KTextEditor::Plugin { Q_OBJECT friend TabSwitcherPluginView; public: /** * Plugin constructor. */ - explicit TabSwitcherPlugin(QObject *parent = 0, const QList & = QList()); + explicit TabSwitcherPlugin(QObject *parent = nullptr, const QList & = QList()); /** * Create a new tab switcher for @p mainWindow. */ QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; private: QList m_views; }; class TabSwitcherPluginView : public QObject, public KXMLGUIClient { Q_OBJECT public: /** * View constructor. */ TabSwitcherPluginView(TabSwitcherPlugin *plugin, KTextEditor::MainWindow *mainWindow); /** * View destructor. */ virtual ~TabSwitcherPluginView(); /** * Setup the shortcut actions. */ void setupActions(); /** * Initial fill of model with documents from the application. */ void setupModel(); public Q_SLOTS: /** * Adds @p document to the model. */ void registerDocument(KTextEditor::Document * document); /** * Removes @p document from the model. */ void unregisterDocument(KTextEditor::Document * document); /** * Update the name in the model for @p document. */ void updateDocumentName(KTextEditor::Document * document); /** * Raise @p view in a lru fasion. */ void raiseView(KTextEditor::View * view); /** * Focus next item in the treeview. */ void walkForward(); /** * Focus previous item in the treeview. */ void walkBackward(); /** * Activate the document for @p index. */ void switchToClicked(const QModelIndex& index); /** * Show the document for @p index. */ void activateView(const QModelIndex& index); protected: /** * Move through the list. */ void walk(const int from, const int to); /** * Make sure the popup view has a sane size. */ void updateViewGeometry(); private: TabSwitcherPlugin *m_plugin; KTextEditor::MainWindow *m_mainWindow; QStandardItemModel * m_model; QSet m_documents; TabSwitcherTreeView * m_treeView; }; #endif // KTEXTEDITOR_TAB_SWITCHER_PLUGIN_H diff --git a/addons/textfilter/plugin_katetextfilter.cpp b/addons/textfilter/plugin_katetextfilter.cpp index d61a36c3e..4cde9ca31 100644 --- a/addons/textfilter/plugin_katetextfilter.cpp +++ b/addons/textfilter/plugin_katetextfilter.cpp @@ -1,281 +1,281 @@ /*************************************************************************** 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(0,i18n( + 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, SIGNAL(readyReadStandardError()), this, SLOT(slotFilterReceivedStderr())); connect (m_pFilterProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(slotFilterProcessExited(int,QProcess::ExitStatus))); } 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())); // 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/textfilter/plugin_katetextfilter.h b/addons/textfilter/plugin_katetextfilter.h index c834191c7..0c845ab15 100644 --- a/addons/textfilter/plugin_katetextfilter.h +++ b/addons/textfilter/plugin_katetextfilter.h @@ -1,104 +1,104 @@ /*************************************************************************** plugin_katetextfilter.h - description ------------------- begin : FRE Feb 23 2001 copyright : (C) 2001 by Joseph Wenninger email : jowenn@bigfoot.com ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifndef PLUGIN_KATETEXTFILTER_H #define PLUGIN_KATETEXTFILTER_H #include #include #include #include #include #include #include #include class PluginKateTextFilter : public KTextEditor::Plugin { Q_OBJECT public: /** * Plugin constructor. */ - explicit PluginKateTextFilter(QObject *parent = 0, const QList & = QList()); + explicit PluginKateTextFilter(QObject *parent = nullptr, const QList & = QList()); virtual ~PluginKateTextFilter(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; void runFilter(KTextEditor::View *kv, const QString & filter); private: QString m_strFilterOutput; QString m_stderrOutput; QString m_last_command; KProcess * m_pFilterProcess; QStringList completionList; bool copyResult; bool mergeOutput; public Q_SLOTS: void slotEditFilter (); void slotFilterReceivedStdout(); void slotFilterReceivedStderr(); void slotFilterProcessExited(int exitCode, QProcess::ExitStatus exitStatus); }; class PluginKateTextFilterCommand : public KTextEditor::Command { Q_OBJECT public: PluginKateTextFilterCommand (PluginKateTextFilter *plugin); // Kate::Command bool exec (KTextEditor::View *view, const QString &cmd, QString &msg, const KTextEditor::Range &range = KTextEditor::Range::invalid()) Q_DECL_OVERRIDE; bool help (KTextEditor::View *view, const QString &cmd, QString &msg) Q_DECL_OVERRIDE; private: PluginKateTextFilter *m_plugin; }; /** * Plugin view to merge the actions into the UI */ class PluginViewKateTextFilter: public QObject, public KXMLGUIClient { Q_OBJECT public: /** * Construct plugin view * @param plugin our plugin * @param mainwindows the mainwindow for this view */ explicit PluginViewKateTextFilter(PluginKateTextFilter *plugin, KTextEditor::MainWindow *mainwindow); /** * Our Destructor */ virtual ~PluginViewKateTextFilter(); private: /** * the main window we belong to */ KTextEditor::MainWindow *m_mainWindow; }; #endif diff --git a/addons/xmlcheck/plugin_katexmlcheck.cpp b/addons/xmlcheck/plugin_katexmlcheck.cpp index 8e431b8d7..b1669f332 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=0; + m_tmp_file=nullptr; QAction *a = actionCollection()->addAction("xml_check"); a->setText(i18n("Validate XML")); connect(a, SIGNAL(triggered()), this, SLOT(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))); 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))); // 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=0; + 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(0, i18n("Error: Could not create " + KMessageBox::error(nullptr, i18n("Error: Could not create " "temporary file '%1'.", m_tmp_file->fileName())); delete m_tmp_file; - m_tmp_file=0L; + 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(0, i18n("Error: Failed to execute xmllint. Please make " + 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/xmlcheck/plugin_katexmlcheck.h b/addons/xmlcheck/plugin_katexmlcheck.h index 0a85a9841..39e5550de 100644 --- a/addons/xmlcheck/plugin_katexmlcheck.h +++ b/addons/xmlcheck/plugin_katexmlcheck.h @@ -1,84 +1,84 @@ /*************************************************************************** plugin_katexmlcheck.h ------------------- 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. ***************************************************************************/ #ifndef PLUGIN_KATEXMLCHECK_H #define PLUGIN_KATEXMLCHECK_H #include #include #include #include #include #include #include #include class QTreeWidget; class QTreeWidgetItem; class QTemporaryFile; class QProcess; class PluginKateXMLCheckView : public QObject, public KXMLGUIClient { Q_OBJECT public: PluginKateXMLCheckView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainwin); virtual ~PluginKateXMLCheckView(); KTextEditor::MainWindow *m_mainWindow; QWidget *dock; public Q_SLOTS: bool slotValidate(); void slotClicked(QTreeWidgetItem *item, int column); void slotProcExited(int exitCode, QProcess::ExitStatus exitStatus); void slotUpdate(); private: QTemporaryFile *m_tmp_file; KParts::ReadOnlyPart *part; bool m_validating; QProcess m_proc; QString m_proc_stderr; QString m_dtdname; QTreeWidget *listview; }; class PluginKateXMLCheck : public KTextEditor::Plugin { Q_OBJECT public: - explicit PluginKateXMLCheck( QObject* parent = 0, const QVariantList& = QVariantList() ); + explicit PluginKateXMLCheck( QObject* parent = nullptr, const QVariantList& = QVariantList() ); virtual ~PluginKateXMLCheck(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; }; #endif // PLUGIN_KATEXMLCHECK_H diff --git a/addons/xmltools/plugin_katexmltools.cpp b/addons/xmltools/plugin_katexmltools.cpp index f7290c0a2..ede35e265 100644 --- a/addons/xmltools/plugin_katexmltools.cpp +++ b/addons/xmltools/plugin_katexmltools.cpp @@ -1,1116 +1,1116 @@ /*************************************************************************** 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())); 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())); 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())); 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 *))); } 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(0) + , 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 *)0); // Just return a leaf-level index + 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(0, i18n("The current file has been identified " + 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, SIGNAL(data(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(0, i18n("The file '%1' could not be opened. " + 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 = 0; + 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))); // 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())); // 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; diff --git a/addons/xmltools/plugin_katexmltools.h b/addons/xmltools/plugin_katexmltools.h index e79097afd..c3d2931f7 100644 --- a/addons/xmltools/plugin_katexmltools.h +++ b/addons/xmltools/plugin_katexmltools.h @@ -1,182 +1,182 @@ /*************************************************************************** pluginKatexmltools.cpp copyright : (C) 2001-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. ***************************************************************************/ #ifndef PLUGIN_KATEXMLTOOLS_H #define PLUGIN_KATEXMLTOOLS_H #include "pseudo_dtd.h" #include #include #include #include #include #include #include #include #include #include class QComboBox; class QPushButton; class PluginKateXMLTools : public KTextEditor::Plugin { Q_OBJECT public: - explicit PluginKateXMLTools(QObject *parent = 0, const QVariantList& = QVariantList()); + explicit PluginKateXMLTools(QObject *parent = nullptr, const QVariantList& = QVariantList()); ~PluginKateXMLTools(); QObject *createView(KTextEditor::MainWindow *mainWindow) Q_DECL_OVERRIDE; }; class PluginKateXMLToolsCompletionModel : public KTextEditor::CodeCompletionModel , public KTextEditor::CodeCompletionModelControllerInterface { Q_OBJECT Q_INTERFACES(KTextEditor::CodeCompletionModelControllerInterface) public: PluginKateXMLToolsCompletionModel(QObject *parent); virtual ~PluginKateXMLToolsCompletionModel(); // // KTextEditor::CodeCompletionModel // public: int columnCount(const QModelIndex &) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; QModelIndex index(int row, int column, const QModelIndex &parent) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &idx, int role) const Q_DECL_OVERRIDE; void executeCompletionItem(KTextEditor::View *view, const KTextEditor::Range &word, const QModelIndex &index) const Q_DECL_OVERRIDE; // // KTextEditor::CodeCompletionModelControllerInterface // public: bool shouldStartCompletion(KTextEditor::View *view, const QString &insertedText, bool userInsertion, const KTextEditor::Cursor &position) Q_DECL_OVERRIDE; public Q_SLOTS: void getDTD(); void slotInsertElement(); void slotCloseElement(); void slotFinished(KJob *job); void slotData(KIO::Job *, const QByteArray &data); void completionInvoked(KTextEditor::View *kv, const KTextEditor::Range &range, InvocationType invocationType) Q_DECL_OVERRIDE; /// Connected to the document manager, to manage the dtd collection. void slotDocumentDeleted(KTextEditor::Document *doc); protected: QString currentModeToString() const; static QStringList sortQStringList(QStringList list); //bool eventFilter( QObject *object, QEvent *event ); QString insideTag(KTextEditor::View &kv); QString insideAttribute(KTextEditor::View &kv); static bool isOpeningTag(const QString &tag); static bool isClosingTag(const QString &tag); static bool isEmptyTag(const QString &tag); static bool isQuote(const QString &ch); QString getParentElement(KTextEditor::View &view, int skipCharacters); enum Mode {none, entities, attributevalues, attributes, elements, closingtag}; enum PopupMode {noPopup, tagname, attributename, attributevalue, entityname}; enum Level {groupNode = 1}; /// Assign the PseudoDTD @p dtd to the Kate::View @p view void assignDTD(PseudoDTD *dtd, KTextEditor::View *view); /// temporary placeholder for the metaDTD file QString m_dtdString; /// temporary placeholder for the view to assign a DTD to while the file is loaded KTextEditor::View *m_viewToAssignTo; /// URL of the last loaded meta DTD QString m_urlString; QStringList m_allowed; Mode m_mode; int m_correctPos; // code completion stuff: KTextEditor::CodeCompletionInterface *m_codeInterface; /// maps KTE::Document -> DTD QHash m_docDtds; /// maps DTD filename -> DTD QHash m_dtds; }; class PluginKateXMLToolsView : public QObject, public KXMLGUIClient { Q_OBJECT public: explicit PluginKateXMLToolsView(KTextEditor::MainWindow *mainWin); virtual ~PluginKateXMLToolsView(); protected: KTextEditor::MainWindow *m_mainWindow; PluginKateXMLToolsCompletionModel m_model; }; class InsertElement : public QDialog { Q_OBJECT public: InsertElement(const QStringList &completions, QWidget *parent); virtual ~InsertElement(); QString text() const; private Q_SLOTS: void slotHistoryTextChanged(const QString &); private: QComboBox * m_cmbElements; QPushButton * m_okButton; }; #endif // PLUGIN_KATEXMLTOOLS_H // kate: space-indent on; indent-width 4; replace-tabs on; mixed-indent off; diff --git a/addons/xmltools/pseudo_dtd.cpp b/addons/xmltools/pseudo_dtd.cpp index adf73b185..8b3bcb677 100644 --- a/addons/xmltools/pseudo_dtd.cpp +++ b/addons/xmltools/pseudo_dtd.cpp @@ -1,448 +1,448 @@ /*************************************************************************** pseudoDtd.cpp copyright : (C) 2001-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. ***************************************************************************/ #include "pseudo_dtd.h" #include #include #include #include PseudoDTD::PseudoDTD() { // "SGML support" only means case-insensivity, because HTML is case-insensitive up to version 4: m_sgmlSupport = true; // TODO: make this an run-time option ( maybe automatically set ) } PseudoDTD::~PseudoDTD() { } void PseudoDTD::analyzeDTD(QString &metaDtdUrl, QString &metaDtd) { QDomDocument doc("dtdIn_xml"); if (! doc.setContent(metaDtd)) { - KMessageBox::error(0, i18n("The file '%1' could not be parsed. " + KMessageBox::error(nullptr, i18n("The file '%1' could not be parsed. " "Please check that the file is well-formed XML.", metaDtdUrl), i18n("XML Plugin Error")); return; } if (doc.doctype().name() != "dtd") { - KMessageBox::error(0, i18n("The file '%1' is not in the expected format. " + KMessageBox::error(nullptr, i18n("The file '%1' is not in the expected format. " "Please check that the file is of this type:\n" "-//Norman Walsh//DTD DTDParse V2.0//EN\n" "You can produce such files with dtdparse. " "See the Kate Plugin documentation for more information.", metaDtdUrl), i18n("XML Plugin Error")); return; } uint listLength = 0; listLength += doc.elementsByTagName("entity").count(); listLength += doc.elementsByTagName("element").count(); // count this twice, as it will be iterated twice ( TODO: optimize that? ): listLength += doc.elementsByTagName("attlist").count() * 2; QProgressDialog progress(i18n("Analyzing meta DTD..."), i18n("Cancel"), 0, listLength); progress.setMinimumDuration(400); progress.setValue(0); // Get information from meta DTD and put it in Qt data structures for fast access: if (! parseEntities(&doc, &progress)) { return; } if (! parseElements(&doc, &progress)) { return; } if (! parseAttributes(&doc, &progress)) { return; } if (! parseAttributeValues(&doc, &progress)) { return; } progress.setValue(listLength); // just to make sure the dialog disappears } // ======================================================================== // DOM stuff: /** * Iterate through the XML to get a mapping which sub-elements are allowed for * all elements. */ bool PseudoDTD::parseElements(QDomDocument *doc, QProgressDialog *progress) { m_elementsList.clear(); // We only display a list, i.e. we pretend that the content model is just // a set, so we use a map. This is necessay e.g. for xhtml 1.0's head element, // which would otherwise display some elements twice. QMap subelementList; // the bool is not used QDomNodeList list = doc->elementsByTagName("element"); uint listLength = list.count(); // speedup (really! ) for (uint i = 0; i < listLength; i++) { if (progress->wasCanceled()) { return false; } progress->setValue(progress->value() + 1); // FIXME!: //qApp->processEvents(); subelementList.clear(); QDomNode node = list.item(i); QDomElement elem = node.toElement(); if (!elem.isNull()) { // Enter the expanded content model, which may also include stuff not allowed. // We do not care if it's a or whatever. QDomNodeList contentModelList = elem.elementsByTagName("content-model-expanded"); QDomNode contentModelNode = contentModelList.item(0); QDomElement contentModelElem = contentModelNode.toElement(); if (! contentModelElem.isNull()) { // check for : QDomNodeList pcdataList = contentModelElem.elementsByTagName("pcdata"); // check for other sub elements: QDomNodeList subList = contentModelElem.elementsByTagName("element-name"); uint subListLength = subList.count(); for (uint l = 0; l < subListLength; l++) { QDomNode subNode = subList.item(l); QDomElement subElem = subNode.toElement(); if (!subElem.isNull()) { subelementList[subElem.attribute("name")] = true; } } // anders: check if this is an EMPTY element, and put "__EMPTY" in the // sub list, so that we can insert tags in empty form if required. QDomNodeList emptyList = elem.elementsByTagName("empty"); if (emptyList.count()) { subelementList["__EMPTY"] = true; } } // Now remove the elements not allowed (e.g. is explicitly not allowed in // in the HTML 4.01 Strict DTD): QDomNodeList exclusionsList = elem.elementsByTagName("exclusions"); if (exclusionsList.length() > 0) { // sometimes there are no exclusions ( e.g. in XML DTDs there are never exclusions ) QDomNode exclusionsNode = exclusionsList.item(0); QDomElement exclusionsElem = exclusionsNode.toElement(); if (! exclusionsElem.isNull()) { QDomNodeList subList = exclusionsElem.elementsByTagName("element-name"); uint subListLength = subList.count(); for (uint l = 0; l < subListLength; l++) { QDomNode subNode = subList.item(l); QDomElement subElem = subNode.toElement(); if (!subElem.isNull()) { QMap::Iterator it = subelementList.find(subElem.attribute("name")); if (it != subelementList.end()) { subelementList.erase(it); } } } } } // turn the map into a list: QStringList subelementListTmp; QMap::Iterator it; for (it = subelementList.begin(); it != subelementList.end(); ++it) { subelementListTmp.append(it.key()); } m_elementsList.insert(elem.attribute("name"), subelementListTmp); } } // end iteration over all nodes return true; } /** * Check which elements are allowed inside a parent element. This returns * a list of allowed elements, but it doesn't care about order or if only a certain * number of occurrences is allowed. */ QStringList PseudoDTD::allowedElements(QString parentElement) { if (m_sgmlSupport) { // find the matching element, ignoring case: QMap::Iterator it; for (it = m_elementsList.begin(); it != m_elementsList.end(); ++it) { if (it.key().compare(parentElement, Qt::CaseInsensitive) == 0) { return it.value(); } } } else if (m_elementsList.contains(parentElement)) { return m_elementsList[parentElement]; } return QStringList(); } /** * Iterate through the XML to get a mapping which attributes are allowed inside * all elements. */ bool PseudoDTD::parseAttributes(QDomDocument *doc, QProgressDialog *progress) { m_attributesList.clear(); // QStringList allowedAttributes; QDomNodeList list = doc->elementsByTagName("attlist"); uint listLength = list.count(); for (uint i = 0; i < listLength; i++) { if (progress->wasCanceled()) { return false; } progress->setValue(progress->value() + 1); // FIXME!! //qApp->processEvents(); ElementAttributes attrs; QDomNode node = list.item(i); QDomElement elem = node.toElement(); if (!elem.isNull()) { QDomNodeList attributeList = elem.elementsByTagName("attribute"); uint attributeListLength = attributeList.count(); for (uint l = 0; l < attributeListLength; l++) { QDomNode attributeNode = attributeList.item(l); QDomElement attributeElem = attributeNode.toElement(); if (! attributeElem.isNull()) { if (attributeElem.attribute("type") == "#REQUIRED") { attrs.requiredAttributes.append(attributeElem.attribute("name")); } else { attrs.optionalAttributes.append(attributeElem.attribute("name")); } } } m_attributesList.insert(elem.attribute("name"), attrs); } } return true; } /** Check which attributes are allowed for an element. */ QStringList PseudoDTD::allowedAttributes(QString element) { if (m_sgmlSupport) { // find the matching element, ignoring case: QMap::Iterator it; for (it = m_attributesList.begin(); it != m_attributesList.end(); ++it) { if (it.key().compare(element, Qt::CaseInsensitive) == 0) { return it.value().optionalAttributes + it.value().requiredAttributes; } } } else if (m_attributesList.contains(element)) { return m_attributesList[element].optionalAttributes + m_attributesList[element].requiredAttributes; } return QStringList(); } QStringList PseudoDTD::requiredAttributes(const QString &element) const { if (m_sgmlSupport) { QMap::ConstIterator it; for (it = m_attributesList.begin(); it != m_attributesList.end(); ++it) { if (it.key().compare(element, Qt::CaseInsensitive) == 0) { return it.value().requiredAttributes; } } } else if (m_attributesList.contains(element)) { return m_attributesList[element].requiredAttributes; } return QStringList(); } /** * Iterate through the XML to get a mapping which attribute values are allowed * for all attributes inside all elements. */ bool PseudoDTD::parseAttributeValues(QDomDocument *doc, QProgressDialog *progress) { m_attributevaluesList.clear(); // 1 element : n possible attributes QMap attributevaluesTmp; // 1 attribute : n possible values QDomNodeList list = doc->elementsByTagName("attlist"); uint listLength = list.count(); for (uint i = 0; i < listLength; i++) { if (progress->wasCanceled()) { return false; } progress->setValue(progress->value() + 1); // FIXME! //qApp->processEvents(); attributevaluesTmp.clear(); QDomNode node = list.item(i); QDomElement elem = node.toElement(); if (!elem.isNull()) { // Enter the list of : QDomNodeList attributeList = elem.elementsByTagName("attribute"); uint attributeListLength = attributeList.count(); for (uint l = 0; l < attributeListLength; l++) { QDomNode attributeNode = attributeList.item(l); QDomElement attributeElem = attributeNode.toElement(); if (! attributeElem.isNull()) { QString value = attributeElem.attribute("value"); attributevaluesTmp.insert(attributeElem.attribute("name"), value.split(QChar(' '))); } } m_attributevaluesList.insert(elem.attribute("name"), attributevaluesTmp); } } return true; } /** * Check which attributes values are allowed for an attribute in an element * (the element is necessary because e.g. "href" inside could be different * to an "href" inside ): */ QStringList PseudoDTD::attributeValues(QString element, QString attribute) { // Direct access would be faster than iteration of course but not always correct, // because we need to be case-insensitive. if (m_sgmlSupport) { // first find the matching element, ignoring case: QMap< QString, QMap >::Iterator it; for (it = m_attributevaluesList.begin(); it != m_attributevaluesList.end(); ++it) { if (it.key().compare(element, Qt::CaseInsensitive) == 0) { QMap attrVals = it.value(); QMap::Iterator itV; // then find the matching attribute for that element, ignoring case: for (itV = attrVals.begin(); itV != attrVals.end(); ++itV) { if (itV.key().compare(attribute, Qt::CaseInsensitive) == 0) { return(itV.value()); } } } } } else if (m_attributevaluesList.contains(element)) { QMap attrVals = m_attributevaluesList[element]; if (attrVals.contains(attribute)) { return attrVals[attribute]; } } // no predefined values available: return QStringList(); } /** * Iterate through the XML to get a mapping of all entity names and their expanded * version, e.g. nbsp =>  . Parameter entities are ignored. */ bool PseudoDTD::parseEntities(QDomDocument *doc, QProgressDialog *progress) { m_entityList.clear(); QDomNodeList list = doc->elementsByTagName("entity"); uint listLength = list.count(); for (uint i = 0; i < listLength; i++) { if (progress->wasCanceled()) { return false; } progress->setValue(progress->value() + 1); //FIXME!! //qApp->processEvents(); QDomNode node = list.item(i); QDomElement elem = node.toElement(); if (!elem.isNull() && elem.attribute("type") != "param") { // TODO: what's cdata <-> gen ? QDomNodeList expandedList = elem.elementsByTagName("text-expanded"); QDomNode expandedNode = expandedList.item(0); QDomElement expandedElem = expandedNode.toElement(); if (! expandedElem.isNull()) { QString exp = expandedElem.text(); // TODO: support more than one &#...; in the expanded text /* TODO include do this when the unicode font problem is solved: if( exp.contains(QRegExp("^&#x[a-zA-Z0-9]+;$")) ) { // hexadecimal numbers, e.g. "ȶ" uint end = exp.find( ";" ); exp = exp.mid( 3, end-3 ); exp = QChar(); } else if( exp.contains(QRegExp("^&#[0-9]+;$")) ) { // decimal numbers, e.g. "ì" uint end = exp.find( ";" ); exp = exp.mid( 2, end-2 ); exp = QChar( exp.toInt() ); } */ m_entityList.insert(elem.attribute("name"), exp); } else { m_entityList.insert(elem.attribute("name"), QString()); } } } return true; } /** * Get a list of all ( non-parameter ) entities that start with a certain string. */ QStringList PseudoDTD::entities(QString start) { QStringList entities; QMap::Iterator it; for (it = m_entityList.begin(); it != m_entityList.end(); ++it) { if ((*it).startsWith(start)) { QString str = it.key(); /* TODO: show entities as unicode character if( !it.data().isEmpty() ) { //str += " -- " + it.data(); QRegExp re( "&#(\\d+);" ); if( re.search(it.data()) != -1 ) { uint ch = re.cap( 1).toUInt(); str += " -- " + QChar( ch).decomposition(); } //qDebug() << "#" << it.data(); } */ entities.append(str); // TODO: later use a table view } } return entities; } // kate: space-indent on; indent-width 4; replace-tabs on; mixed-indent off; diff --git a/kate/kateapp.cpp b/kate/kateapp.cpp index c89ccce97..2248d3aeb 100644 --- a/kate/kateapp.cpp +++ b/kate/kateapp.cpp @@ -1,460 +1,460 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2002 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 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 "kateapp.h" #include "kateviewmanager.h" #include "katemainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "../../urlinfo.h" /** * singleton instance pointer */ static KateApp *appSelf = Q_NULLPTR; Q_LOGGING_CATEGORY(LOG_KATE, "kate", QtWarningMsg) KateApp::KateApp(const QCommandLineParser &args) : m_args(args) , m_wrapper(appSelf = this) , m_docManager(this) , m_adaptor(this) , m_pluginManager(this) , m_sessionManager(this) { /** * re-route some signals to application wrapper */ connect(&m_docManager, &KateDocManager::documentCreated, &m_wrapper, &KTextEditor::Application::documentCreated); connect(&m_docManager, &KateDocManager::documentWillBeDeleted, &m_wrapper, &KTextEditor::Application::documentWillBeDeleted); connect(&m_docManager, &KateDocManager::documentDeleted, &m_wrapper, &KTextEditor::Application::documentDeleted); connect(&m_docManager, &KateDocManager::aboutToCreateDocuments, &m_wrapper, &KTextEditor::Application::aboutToCreateDocuments); connect(&m_docManager, &KateDocManager::documentsCreated, &m_wrapper, &KTextEditor::Application::documentsCreated); /** * handle mac os x like file open request via event filter */ qApp->installEventFilter(this); } KateApp::~KateApp() { /** * unregister from dbus before we get unusable... */ if (QDBusConnection::sessionBus().interface()) { m_adaptor.emitExiting(); QDBusConnection::sessionBus().unregisterObject(QStringLiteral("/MainApplication")); } /** * delete all main windows before the document manager & co. die */ while (!m_mainWindows.isEmpty()) { // mainwindow itself calls KateApp::removeMainWindow(this) delete m_mainWindows[0]; } } KateApp *KateApp::self() { return appSelf; } bool KateApp::init() { // set KATE_PID for use in child processes qputenv("KATE_PID", QString::fromLatin1("%1").arg(QCoreApplication::applicationPid()).toLatin1().constData()); // handle restore different if (qApp->isSessionRestored()) { restoreKate(); } else { // let us handle our command line args and co ;) // we can exit here if session chooser decides if (!startupKate()) { // session chooser telled to exit kate return false; } } // application dbus interface if (QDBusConnection::sessionBus().interface()) { QDBusConnection::sessionBus().registerObject(QStringLiteral("/MainApplication"), this); } return true; } void KateApp::restoreKate() { KConfig *sessionConfig = KConfigGui::sessionConfig(); // activate again correct session!!! QString lastSession(sessionConfig->group("General").readEntry("Last Session", QString())); sessionManager()->activateSession(lastSession, false, false); // plugins KateApp::self()->pluginManager()->loadConfig(sessionConfig); // restore the files we need m_docManager.restoreDocumentList(sessionConfig); // restore all windows ;) for (int n = 1; KMainWindow::canBeRestored(n); n++) { newMainWindow(sessionConfig, QString::number(n)); } // oh, no mainwindow, create one, should not happen, but make sure ;) if (mainWindowsCount() == 0) { newMainWindow(); } } bool KateApp::startupKate() { // user specified session to open if (m_args.isSet(QStringLiteral("start"))) { sessionManager()->activateSession(m_args.value(QStringLiteral("start")), false); } else if (m_args.isSet(QStringLiteral("startanon"))) { sessionManager()->activateAnonymousSession(); } else if (!m_args.isSet(QStringLiteral("stdin")) && (m_args.positionalArguments().count() == 0)) { // only start session if no files specified // let the user choose session if possible if (!sessionManager()->chooseSession()) { // we will exit kate now, notify the rest of the world we are done KStartupInfo::appStarted(KStartupInfo::startupId()); return false; } } else { sessionManager()->activateAnonymousSession(); } // oh, no mainwindow, create one, should not happen, but make sure ;) if (mainWindowsCount() == 0) { newMainWindow(); } // notify about start KStartupInfo::setNewStartupId(activeKateMainWindow(), KStartupInfo::startupId()); - QTextCodec *codec = m_args.isSet(QStringLiteral("encoding")) ? QTextCodec::codecForName(m_args.value(QStringLiteral("encoding")).toUtf8()) : 0; + QTextCodec *codec = m_args.isSet(QStringLiteral("encoding")) ? QTextCodec::codecForName(m_args.value(QStringLiteral("encoding")).toUtf8()) : nullptr; bool tempfileSet = m_args.isSet(QStringLiteral("tempfile")); - KTextEditor::Document *doc = 0; + KTextEditor::Document *doc = nullptr; const QString codec_name = codec ? QString::fromLatin1(codec->name()) : QString(); Q_FOREACH(const QString positionalArgument, m_args.positionalArguments()) { UrlInfo info(positionalArgument); // this file is no local dir, open it, else warn bool noDir = !info.url.isLocalFile() || !QFileInfo(info.url.toLocalFile()).isDir(); if (noDir) { doc = openDocUrl(info.url, codec_name, tempfileSet); if (info.cursor.isValid()) { setCursor(info.cursor.line(), info.cursor.column()); } } else { KMessageBox::sorry(activeKateMainWindow(), i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.", info.url.toString())); } } // handle stdin input if (m_args.isSet(QStringLiteral("stdin"))) { QTextStream input(stdin, QIODevice::ReadOnly); // set chosen codec if (codec) { input.setCodec(codec); } QString line; QString text; do { line = input.readLine(); text.append(line + QLatin1Char('\n')); } while (!line.isNull()); openInput(text, codec_name); } else if (doc) { activeKateMainWindow()->viewManager()->activateView(doc); } int line = 0; int column = 0; bool nav = false; if (m_args.isSet(QStringLiteral("line"))) { line = m_args.value(QStringLiteral("line")).toInt() - 1; nav = true; } if (m_args.isSet(QStringLiteral("column"))) { column = m_args.value(QStringLiteral("column")).toInt() - 1; nav = true; } if (nav && activeKateMainWindow()->viewManager()->activeView()) { activeKateMainWindow()->viewManager()->activeView()->setCursorPosition(KTextEditor::Cursor(line, column)); } activeKateMainWindow()->setAutoSaveSettings(); return true; } void KateApp::shutdownKate(KateMainWindow *win) { if (!win->queryClose_internal()) { return; } sessionManager()->saveActiveSession(true); /** * all main windows will be cleaned up * in the KateApp destructor after the event * loop is left */ QApplication::quit(); } KatePluginManager *KateApp::pluginManager() { return &m_pluginManager; } KateDocManager *KateApp::documentManager() { return &m_docManager; } KateSessionManager *KateApp::sessionManager() { return &m_sessionManager; } bool KateApp::openUrl(const QUrl &url, const QString &encoding, bool isTempFile) { return openDocUrl(url, encoding, isTempFile); } KTextEditor::Document *KateApp::openDocUrl(const QUrl &url, const QString &encoding, bool isTempFile) { KateMainWindow *mainWindow = activeKateMainWindow(); if (!mainWindow) { - return 0; + return nullptr; } - QTextCodec *codec = encoding.isEmpty() ? 0 : QTextCodec::codecForName(encoding.toLatin1()); + QTextCodec *codec = encoding.isEmpty() ? nullptr : QTextCodec::codecForName(encoding.toLatin1()); // this file is no local dir, open it, else warn bool noDir = !url.isLocalFile() || !QFileInfo(url.toLocalFile()).isDir(); - KTextEditor::Document *doc = 0; + KTextEditor::Document *doc = nullptr; if (noDir) { // open a normal file if (codec) { doc = mainWindow->viewManager()->openUrl(url, QString::fromLatin1(codec->name()), true, isTempFile); } else { doc = mainWindow->viewManager()->openUrl(url, QString(), true, isTempFile); } } else KMessageBox::sorry(mainWindow, i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.", url.url())); return doc; } bool KateApp::setCursor(int line, int column) { KateMainWindow *mainWindow = activeKateMainWindow(); if (!mainWindow) { return false; } if (auto v = mainWindow->viewManager()->activeView()) { v->removeSelection(); v->setCursorPosition(KTextEditor::Cursor(line, column)); } return true; } bool KateApp::openInput(const QString &text, const QString &encoding) { activeKateMainWindow()->viewManager()->openUrl(QUrl(), encoding, true); if (!activeKateMainWindow()->viewManager()->activeView()) { return false; } KTextEditor::Document *doc = activeKateMainWindow()->viewManager()->activeView()->document(); if (!doc) { return false; } return doc->setText(text); } KateMainWindow *KateApp::newMainWindow(KConfig *sconfig_, const QString &sgroup_) { KConfig *sconfig = sconfig_ ? sconfig_ : KSharedConfig::openConfig().data(); QString sgroup = !sgroup_.isEmpty() ? sgroup_ : QStringLiteral("MainWindow0"); KateMainWindow *mainWindow = new KateMainWindow(sconfig, sgroup); mainWindow->show(); return mainWindow; } void KateApp::addMainWindow(KateMainWindow *mainWindow) { m_mainWindows.push_back(mainWindow); } void KateApp::removeMainWindow(KateMainWindow *mainWindow) { m_mainWindows.removeAll(mainWindow); } KateMainWindow *KateApp::activeKateMainWindow() { if (m_mainWindows.isEmpty()) { - return 0; + return nullptr; } int n = m_mainWindows.indexOf(static_cast((static_cast(QCoreApplication::instance())->activeWindow()))); if (n < 0) { n = 0; } return m_mainWindows[n]; } int KateApp::mainWindowsCount() const { return m_mainWindows.size(); } int KateApp::mainWindowID(KateMainWindow *window) { return m_mainWindows.indexOf(window); } KateMainWindow *KateApp::mainWindow(int n) { if (n < m_mainWindows.size()) { return m_mainWindows[n]; } - return 0; + return nullptr; } void KateApp::emitDocumentClosed(const QString &token) { m_adaptor.emitDocumentClosed(token); } KTextEditor::Plugin *KateApp::plugin(const QString &name) { return m_pluginManager.plugin(name); } bool KateApp::eventFilter(QObject *obj, QEvent *event) { /** * handle mac os like file open */ if (event->type() == QEvent::FileOpen) { /** * try to open and activate the new document, like we would do for stuff * opened via dbus */ QFileOpenEvent *foe = static_cast(event); KTextEditor::Document *doc = openDocUrl(foe->url(), QString(), false); if (doc && activeKateMainWindow()) { activeKateMainWindow()->viewManager()->activateView(doc); } return true; } /** * else: pass over to default implementation */ return QObject::eventFilter(obj, event); } void KateApp::remoteMessageReceived(const QString &message, QObject *) { /** * try to parse message, ignore if no object */ const QJsonDocument jsonMessage = QJsonDocument::fromJson(message.toUtf8()); if (!jsonMessage.isObject()) return; /** * open all passed urls */ const QJsonArray urls = jsonMessage.object().value(QLatin1String("urls")).toArray(); Q_FOREACH(QJsonValue urlObject, urls) { /** * get url meta data */ const QUrl url = urlObject.toObject().value(QLatin1String("url")).toVariant().toUrl(); const int line = urlObject.toObject().value(QLatin1String("line")).toVariant().toInt(); const int column = urlObject.toObject().value(QLatin1String("column")).toVariant().toInt(); /** * open file + set line/column if requested */ openUrl(url, QString(), false); if (line >= 0 && column >= 0) { setCursor(line, column); } } if (activeKateMainWindow()) { activeKateMainWindow()->activateWindow(); activeKateMainWindow()->raise(); } } diff --git a/kate/kateapp.h b/kate/kateapp.h index b47a12b9d..ae43a1087 100644 --- a/kate/kateapp.h +++ b/kate/kateapp.h @@ -1,366 +1,366 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2002 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. */ #ifndef __KATE_APP_H__ #define __KATE_APP_H__ #include #include "kateprivate_export.h" #include "katemainwindow.h" #include "katedocmanager.h" #include "katepluginmanager.h" #include "katesessionmanager.h" #include "kateappadaptor.h" #include #include class KateSessionManager; class KateMainWindow; class KatePluginManager; class KateDocManager; class KateAppCommands; class KateAppAdaptor; class QCommandLineParser; /** * Kate Application * This class represents the core kate application object */ class KATE_TESTS_EXPORT KateApp : public QObject { Q_OBJECT /** * constructors & accessor to app object + plugin interface for it */ public: /** * application constructor */ KateApp(const QCommandLineParser &args); /** * get kate inited * @return false, if application should exit */ bool init(); /** * application destructor */ ~KateApp(); /** * static accessor to avoid casting ;) * @return app instance */ static KateApp *self(); /** * KTextEditor::Application wrapper * @return KTextEditor::Application wrapper. */ KTextEditor::Application *wrapper() { return &m_wrapper; } /** * kate init */ private: /** * restore a old kate session */ void restoreKate(); /** * try to start kate * @return success, if false, kate should exit */ bool startupKate(); /** * kate shutdown */ public: /** * shutdown kate application * @param win mainwindow which is used for dialogs */ void shutdownKate(KateMainWindow *win); /** * other accessors for global unique instances */ public: /** * accessor to plugin manager * @return plugin manager instance */ KatePluginManager *pluginManager(); /** * accessor to document manager * @return document manager instance */ KateDocManager *documentManager(); /** * accessor to session manager * @return session manager instance */ KateSessionManager *sessionManager(); /** * window management */ public: /** * create a new main window, use given config if any for restore * @param sconfig session config object * @param sgroup session group for this window * @return new constructed main window */ - KateMainWindow *newMainWindow(KConfig *sconfig = 0, const QString &sgroup = QString()); + KateMainWindow *newMainWindow(KConfig *sconfig = nullptr, const QString &sgroup = QString()); /** * add the mainwindow given * should be called in mainwindow constructor * @param mainWindow window to remove */ void addMainWindow(KateMainWindow *mainWindow); /** * removes the mainwindow given, DOES NOT DELETE IT * should be called in mainwindow destructor * @param mainWindow window to remove */ void removeMainWindow(KateMainWindow *mainWindow); /** * give back current active main window * can only be 0 at app start or exit * @return current active main window */ KateMainWindow *activeKateMainWindow(); /** * give back number of existing main windows * @return number of main windows */ int mainWindowsCount() const; /** * give back the window you want * @param n window index * @return requested main window */ KateMainWindow *mainWindow(int n); int mainWindowID(KateMainWindow *window); /** * some stuff for the dcop API */ public: /** * open url with given encoding * used by kate if --use given * @param url filename * @param encoding encoding name * @return success */ bool openUrl(const QUrl &url, const QString &encoding, bool isTempFile); KTextEditor::Document *openDocUrl(const QUrl &url, const QString &encoding, bool isTempFile); void emitDocumentClosed(const QString &token); /** * position cursor in current active view * will clear selection * @param line line to set * @param column column to set * @return success */ bool setCursor(int line, int column); /** * helper to handle stdin input * open a new document/view, fill it with the text given * @param text text to fill in the new doc/view * @param encoding encoding to set for the document, if any * @return success */ bool openInput(const QString &text, const QString &encoding); // // KTextEditor::Application interface, called by wrappers via invokeMethod // public Q_SLOTS: /** * Get a list of all main windows. * @return all main windows */ QList mainWindows() { // assemble right list QList windows; for (int i = 0; i < m_mainWindows.size(); ++i) { windows.push_back(m_mainWindows[i]->wrapper()); } return windows; } /** * Accessor to the active main window. * \return a pointer to the active mainwindow */ KTextEditor::MainWindow *activeMainWindow() { // either return wrapper or nullptr if (KateMainWindow *a = activeKateMainWindow()) { return a->wrapper(); } return nullptr; } /** * Get a list of all documents that are managed by the application. * This might contain less documents than the editor has in his documents () list. * @return all documents the application manages */ QList documents() { return m_docManager.documentList(); } /** * Get the document with the URL \p url. * if multiple documents match the searched url, return the first found one... * \param url the document's URL * \return the document with the given \p url or NULL, if none found */ KTextEditor::Document *findUrl(const QUrl &url) { return m_docManager.findDocument(url); } /** * Open the document \p url with the given \p encoding. * if the url is empty, a new empty document will be created * \param url the document's url * \param encoding the preferred encoding. If encoding is QString() the * encoding will be guessed or the default encoding will be used. * \return a pointer to the created document */ KTextEditor::Document *openUrl(const QUrl &url, const QString &encoding = QString()) { return m_docManager.openUrl(url, encoding); } /** * Close the given \p document. If the document is modified, user will be asked if he wants that. * \param document the document to be closed * \return \e true on success, otherwise \e false */ bool closeDocument(KTextEditor::Document *document) { return m_docManager.closeDocument(document); } /** * Close a list of documents. If any of them are modified, user will be asked if he wants that. * Use this, if you want to close multiple documents at once, as the application might * be able to group the "do you really want that" dialogs into one. * \param documents list of documents to be closed * \return \e true on success, otherwise \e false */ bool closeDocuments(const QList &documents) { return m_docManager.closeDocumentList(documents); } /** * Get a plugin for the plugin with with identifier \p name. * \param name the plugin's name * \return pointer to the plugin if a plugin with \p name is loaded, otherwise nullptr */ KTextEditor::Plugin *plugin(const QString &name); /** * Ask app to quit. The app might interact with the user and decide that * quitting is not possible and return false. * * \return true if the app could quit */ bool quit() { shutdownKate(activeKateMainWindow()); return true; } /** * A message is received from an external instance, if we use QtSingleApplication * * \p message is a serialized message (at the moment just the file list separated by ';') * \p socket is the QLocalSocket used for the communication */ void remoteMessageReceived(const QString &message, QObject *socket); protected: /** * Event filter for QApplication to handle mac os like file open */ bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; private: /** * kate's command line args */ const QCommandLineParser &m_args; /** * known main windows */ QList m_mainWindows; /** * Wrapper of application for KTextEditor */ KTextEditor::Application m_wrapper; /** * document manager */ KateDocManager m_docManager; /** * dbus interface */ KateAppAdaptor m_adaptor; /** * plugin manager */ KatePluginManager m_pluginManager; /** * session manager */ KateSessionManager m_sessionManager; }; #endif diff --git a/kate/kateconfigplugindialogpage.h b/kate/kateconfigplugindialogpage.h index 94db2ad20..c97c50984 100644 --- a/kate/kateconfigplugindialogpage.h +++ b/kate/kateconfigplugindialogpage.h @@ -1,65 +1,65 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2002 Joseph Wenninger 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 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. */ #ifndef __KATE_CONFIGPLUGINDIALOGPAGE_H__ #define __KATE_CONFIGPLUGINDIALOGPAGE_H__ #include #include class KatePluginListItem; class KatePluginListView : public QTreeWidget { Q_OBJECT public: - KatePluginListView(QWidget *parent = 0); + KatePluginListView(QWidget *parent = nullptr); Q_SIGNALS: void stateChange(KatePluginListItem *, bool); private Q_SLOTS: void stateChanged(QTreeWidgetItem *); }; class KateConfigPluginPage: public QFrame { Q_OBJECT public: KateConfigPluginPage(QWidget *parent, class KateConfigDialog *dialog); private: class KateConfigDialog *myDialog; Q_SIGNALS: void changed(); private Q_SLOTS: void stateChange(KatePluginListItem *, bool); void loadPlugin(KatePluginListItem *); void unloadPlugin(KatePluginListItem *); }; #endif diff --git a/kate/katedocmanager.cpp b/kate/katedocmanager.cpp index 887ba9f98..fdfd583f5 100644 --- a/kate/katedocmanager.cpp +++ b/kate/katedocmanager.cpp @@ -1,611 +1,611 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2002 Joseph Wenninger Copyright (C) 2007 Flavio Castelli 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 "katedocmanager.h" #include "kateapp.h" #include "katemainwindow.h" #include "kateviewmanager.h" #include "katesavemodifieddialog.h" #include "katedebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KateDocManager::KateDocManager(QObject *parent) : QObject(parent) , m_metaInfos(QStringLiteral("katemetainfos"), KConfig::NoGlobals) , m_saveMetaInfos(true) , m_daysMetaInfos(0) , m_documentStillToRestore(0) { // set our application wrapper KTextEditor::Editor::instance()->setApplication(KateApp::self()->wrapper()); // create one doc, we always have at least one around! createDoc(); } KateDocManager::~KateDocManager() { // write metainfos? if (m_saveMetaInfos) { // saving meta-infos when file is saved is not enough, we need to do it once more at the end saveMetaInfos(m_docList); // purge saved filesessions if (m_daysMetaInfos > 0) { const QStringList groups = m_metaInfos.groupList(); QDateTime def(QDate(1970, 1, 1)); for (QStringList::const_iterator it = groups.begin(); it != groups.end(); ++it) { QDateTime last = m_metaInfos.group(*it).readEntry("Time", def); if (last.daysTo(QDateTime::currentDateTimeUtc()) > m_daysMetaInfos) { m_metaInfos.deleteGroup(*it); } } } } qDeleteAll(m_docInfos); } KTextEditor::Document *KateDocManager::createDoc(const KateDocumentInfo &docInfo) { KTextEditor::Document *doc = KTextEditor::Editor::instance()->createDocument(this); // turn of the editorpart's own modification dialog, we have our own one, too! const KConfigGroup generalGroup(KSharedConfig::openConfig(), "General"); bool ownModNotification = generalGroup.readEntry("Modified Notification", false); if (qobject_cast(doc)) { qobject_cast(doc)->setModifiedOnDiskWarning(!ownModNotification); } m_docList.append(doc); m_docInfos.insert(doc, new KateDocumentInfo(docInfo)); // connect internal signals... connect(doc, SIGNAL(modifiedChanged(KTextEditor::Document*)), this, SLOT(slotModChanged1(KTextEditor::Document*))); connect(doc, SIGNAL(modifiedOnDisk(KTextEditor::Document*,bool,KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SLOT(slotModifiedOnDisc(KTextEditor::Document*,bool,KTextEditor::ModificationInterface::ModifiedOnDiskReason))); // we have a new document, show it the world emit documentCreated(doc); emit documentCreatedViewManager(doc); // return our new document return doc; } KateDocumentInfo *KateDocManager::documentInfo(KTextEditor::Document *doc) { return m_docInfos.contains(doc) ? m_docInfos[doc] : 0; } KTextEditor::Document *KateDocManager::findDocument(const QUrl &url) const { QUrl u(url.adjusted(QUrl::NormalizePathSegments)); // Resolve symbolic links for local files (done anyway in KTextEditor) if (u.isLocalFile()) { QString normalizedUrl = QFileInfo(u.toLocalFile()).canonicalFilePath(); if (!normalizedUrl.isEmpty()) { u = QUrl::fromLocalFile(normalizedUrl); } } foreach(KTextEditor::Document * it, m_docList) { if (it->url() == u) { return it; } } - return 0; + return nullptr; } QList KateDocManager::openUrls(const QList &urls, const QString &encoding, bool isTempFile, const KateDocumentInfo &docInfo) { QList docs; emit aboutToCreateDocuments(); foreach(const QUrl & url, urls) { docs << openUrl(url, encoding, isTempFile, docInfo); } emit documentsCreated(docs); return docs; } KTextEditor::Document *KateDocManager::openUrl(const QUrl &url, const QString &encoding, bool isTempFile, const KateDocumentInfo &docInfo) { // special handling: if only one unmodified empty buffer in the list, // keep this buffer in mind to close it after opening the new url - KTextEditor::Document *untitledDoc = 0; + KTextEditor::Document *untitledDoc = nullptr; if ((documentList().count() == 1) && (!documentList().at(0)->isModified() && documentList().at(0)->url().isEmpty())) { untitledDoc = documentList().first(); } // // create new document // QUrl u(url.adjusted(QUrl::NormalizePathSegments)); - KTextEditor::Document *doc = 0; + KTextEditor::Document *doc = nullptr; // always new document if url is empty... if (!u.isEmpty()) { doc = findDocument(u); } if (!doc) { doc = createDoc(docInfo); if (!encoding.isEmpty()) { doc->setEncoding(encoding); } if (!u.isEmpty()) { if (!loadMetaInfos(doc, u)) { doc->openUrl(u); } } } // // if needed, register as temporary file // if (isTempFile && u.isLocalFile()) { QFileInfo fi(u.toLocalFile()); if (fi.exists()) { m_tempFiles[doc] = qMakePair(u, fi.lastModified()); qCDebug(LOG_KATE) << "temporary file will be deleted after use unless modified: " << u; } } // // close untitled document, as it is not wanted // if (untitledDoc) { closeDocument(untitledDoc); } return doc; } bool KateDocManager::closeDocuments(const QList documents, bool closeUrl) { if (documents.isEmpty()) { return false; } saveMetaInfos(documents); emit aboutToDeleteDocuments(documents); int last = 0; bool success = true; foreach(KTextEditor::Document * doc, documents) { if (closeUrl && !doc->closeUrl()) { success = false; // get out on first error break; } if (closeUrl && m_tempFiles.contains(doc)) { QFileInfo fi(m_tempFiles[ doc ].first.toLocalFile()); if (fi.lastModified() <= m_tempFiles[ doc ].second || KMessageBox::questionYesNo(KateApp::self()->activeKateMainWindow(), i18n("The supposedly temporary file %1 has been modified. " "Do you want to delete it anyway?", m_tempFiles[ doc ].first.url(QUrl::PreferLocalFile)), i18n("Delete File?")) == KMessageBox::Yes) { KIO::del(m_tempFiles[ doc ].first, KIO::HideProgressInfo); qCDebug(LOG_KATE) << "Deleted temporary file " << m_tempFiles[ doc ].first; m_tempFiles.remove(doc); } else { m_tempFiles.remove(doc); qCDebug(LOG_KATE) << "The supposedly temporary file " << m_tempFiles[ doc ].first.url() << " have been modified since loaded, and has not been deleted."; } } KateApp::self()->emitDocumentClosed(QString::number((qptrdiff)doc)); // document will be deleted, soon emit documentWillBeDeleted(doc); // really delete the document and its infos delete m_docInfos.take(doc); delete m_docList.takeAt(m_docList.indexOf(doc)); // document is gone, emit our signals emit documentDeleted(doc); last++; } /** * never ever empty the whole document list * do this before documentsDeleted is emitted, to have no flicker */ if (m_docList.isEmpty()) { createDoc(); } emit documentsDeleted(documents.mid(last)); return success; } bool KateDocManager::closeDocument(KTextEditor::Document *doc, bool closeUrl) { if (!doc) { return false; } QList documents; documents.append(doc); return closeDocuments(documents, closeUrl); } bool KateDocManager::closeDocumentList(QList documents) { QList modifiedDocuments; foreach(KTextEditor::Document * document, documents) { if (document->isModified()) { modifiedDocuments.append(document); } } - if (modifiedDocuments.size() > 0 && !KateSaveModifiedDialog::queryClose(0, modifiedDocuments)) { + if (modifiedDocuments.size() > 0 && !KateSaveModifiedDialog::queryClose(nullptr, modifiedDocuments)) { return false; } return closeDocuments(documents, false); // Do not show save/discard dialog } bool KateDocManager::closeAllDocuments(bool closeUrl) { /** * just close all documents */ return closeDocuments(m_docList, closeUrl); } bool KateDocManager::closeOtherDocuments(KTextEditor::Document *doc) { /** * close all documents beside the passed one */ QList documents = m_docList; documents.removeOne(doc); return closeDocuments(documents); } /** * Find all modified documents. * @return Return the list of all modified documents. */ QList KateDocManager::modifiedDocumentList() { QList modified; foreach(KTextEditor::Document * doc, m_docList) { if (doc->isModified()) { modified.append(doc); } } return modified; } bool KateDocManager::queryCloseDocuments(KateMainWindow *w) { int docCount = m_docList.count(); foreach(KTextEditor::Document * doc, m_docList) { if (doc->url().isEmpty() && doc->isModified()) { int msgres = KMessageBox::warningYesNoCancel(w, i18n("

The document '%1' has been modified, but not saved.

" "

Do you want to save your changes or discard them?

", doc->documentName()), i18n("Close Document"), KStandardGuiItem::save(), KStandardGuiItem::discard()); if (msgres == KMessageBox::Cancel) { return false; } if (msgres == KMessageBox::Yes) { const QUrl url = QFileDialog::getSaveFileUrl(w, i18n("Save As")); if (!url.isEmpty()) { if (!doc->saveAs(url)) { return false; } } else { return false; } } } else { if (!doc->queryClose()) { return false; } } } // document count changed while queryClose, abort and notify user if (m_docList.count() > docCount) { KMessageBox::information(w, i18n("New file opened while trying to close Kate, closing aborted."), i18n("Closing Aborted")); return false; } return true; } void KateDocManager::saveAll() { foreach(KTextEditor::Document * doc, m_docList) if (doc->isModified()) { doc->documentSave(); } } void KateDocManager::saveSelected(const QList &docList) { foreach(KTextEditor::Document * doc, docList) { if (doc->isModified()) { doc->documentSave(); } } } void KateDocManager::reloadAll() { // reload all docs that are NOT modified on disk foreach(KTextEditor::Document * doc, m_docList) { if (! documentInfo(doc)->modifiedOnDisc) { doc->documentReload(); } } // take care of all documents that ARE modified on disk KateApp::self()->activeKateMainWindow()->showModOnDiskPrompt(); } void KateDocManager::closeOrphaned() { QList documents; foreach(KTextEditor::Document * doc, m_docList) { KateDocumentInfo *info = documentInfo(doc); if (info && !info->openSuccess) { documents.append(doc); } } closeDocuments(documents); } void KateDocManager::saveDocumentList(KConfig *config) { KConfigGroup openDocGroup(config, "Open Documents"); openDocGroup.writeEntry("Count", m_docList.count()); int i = 0; foreach(KTextEditor::Document * doc, m_docList) { KConfigGroup cg(config, QString::fromLatin1("Document %1").arg(i)); doc->writeSessionConfig(cg); i++; } } void KateDocManager::restoreDocumentList(KConfig *config) { KConfigGroup openDocGroup(config, "Open Documents"); unsigned int count = openDocGroup.readEntry("Count", 0); if (count == 0) { return; } QProgressDialog progress; progress.setWindowTitle(i18n("Starting Up")); progress.setLabelText(i18n("Reopening files from the last session...")); progress.setModal(true); - progress.setCancelButton(0); + progress.setCancelButton(nullptr); progress.setRange(0, count); m_documentStillToRestore = count; m_openingErrors.clear(); for (unsigned int i = 0; i < count; i++) { KConfigGroup cg(config, QString::fromLatin1("Document %1").arg(i)); - KTextEditor::Document *doc = 0; + KTextEditor::Document *doc = nullptr; if (i == 0) { doc = m_docList.first(); } else { doc = createDoc(); } connect(doc, SIGNAL(completed()), this, SLOT(documentOpened())); connect(doc, SIGNAL(canceled(QString)), this, SLOT(documentOpened())); doc->readSessionConfig(cg); progress.setValue(i); } } void KateDocManager::slotModifiedOnDisc(KTextEditor::Document *doc, bool b, KTextEditor::ModificationInterface::ModifiedOnDiskReason reason) { if (m_docInfos.contains(doc)) { m_docInfos[doc]->modifiedOnDisc = b; m_docInfos[doc]->modifiedOnDiscReason = reason; slotModChanged1(doc); } } /** * Load file and file's meta-information if the MD5 didn't change since last time. */ bool KateDocManager::loadMetaInfos(KTextEditor::Document *doc, const QUrl &url) { if (!m_saveMetaInfos) { return false; } if (!m_metaInfos.hasGroup(url.toDisplayString())) { return false; } const QByteArray checksum = doc->checksum().toHex(); bool ok = true; if (!checksum.isEmpty()) { KConfigGroup urlGroup(&m_metaInfos, url.toDisplayString()); const QString old_checksum = urlGroup.readEntry("Checksum"); if (QString::fromLatin1(checksum) == old_checksum) { QSet flags; if (documentInfo(doc)->openedByUser) { flags << QStringLiteral ("SkipEncoding"); } doc->readSessionConfig(urlGroup, flags); } else { urlGroup.deleteGroup(); ok = false; } m_metaInfos.sync(); } return ok && doc->url() == url; } /** * Save file's meta-information if doc is in 'unmodified' state */ void KateDocManager::saveMetaInfos(const QList &documents) { /** * skip work if no meta infos wanted */ if (!m_saveMetaInfos) { return; } /** * store meta info for all non-modified documents which have some checksum */ const QDateTime now = QDateTime::currentDateTimeUtc(); foreach(KTextEditor::Document * doc, documents) { /** * skip modified docs */ if (doc->isModified()) { continue; } const QByteArray checksum = doc->checksum().toHex(); if (!checksum.isEmpty()) { /** * write the group with checksum and time */ KConfigGroup urlGroup(&m_metaInfos, doc->url().toString()); urlGroup.writeEntry("Checksum", QString::fromLatin1(checksum)); urlGroup.writeEntry("Time", now); /** * write document session config */ doc->writeSessionConfig(urlGroup); } } /** * sync to not loose data */ m_metaInfos.sync(); } void KateDocManager::slotModChanged(KTextEditor::Document *doc) { QList documents; documents.append(doc); saveMetaInfos(documents); } void KateDocManager::slotModChanged1(KTextEditor::Document *doc) { QMetaObject::invokeMethod(KateApp::self()->activeKateMainWindow(), "queueModifiedOnDisc", Qt::QueuedConnection, Q_ARG(KTextEditor::Document *, doc)); } void KateDocManager::documentOpened() { KColorScheme colors(QPalette::Active); KTextEditor::Document *doc = qobject_cast(sender()); if (!doc) { return; // should never happen, but who knows } disconnect(doc, SIGNAL(completed()), this, SLOT(documentOpened())); disconnect(doc, SIGNAL(canceled(QString)), this, SLOT(documentOpened())); if (doc->openingError()) { m_openingErrors += QLatin1Char('\n') + doc->openingErrorMessage() + QStringLiteral("\n\n"); KateDocumentInfo *info = documentInfo(doc); if (info) { info->openSuccess = false; } } --m_documentStillToRestore; if (m_documentStillToRestore == 0) { QTimer::singleShot(0, this, SLOT(showRestoreErrors())); } } void KateDocManager::showRestoreErrors() { if (!m_openingErrors.isEmpty()) { - KMessageBox::information(0, + KMessageBox::information(nullptr, m_openingErrors, i18n("Errors/Warnings while opening documents")); // clear errors m_openingErrors.clear(); } } diff --git a/kate/katemainwindow.cpp b/kate/katemainwindow.cpp index 39dd96e85..f390bc4de 100644 --- a/kate/katemainwindow.cpp +++ b/kate/katemainwindow.cpp @@ -1,1178 +1,1178 @@ /* 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 Flavio Castelli 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 "katemainwindow.h" #include "kateconfigdialog.h" #include "katedocmanager.h" #include "katepluginmanager.h" #include "kateconfigplugindialogpage.h" #include "kateviewmanager.h" #include "kateapp.h" #include "katesavemodifieddialog.h" #include "katemwmodonhddialog.h" #include "katesessionsaction.h" #include "katesessionmanager.h" #include "kateviewspace.h" #include "katequickopen.h" #include "kateupdatedisabler.h" #include "katedebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //END -KateMwModOnHdDialog *KateMainWindow::s_modOnHdDialog = 0; +KateMwModOnHdDialog *KateMainWindow::s_modOnHdDialog = nullptr; KateContainerStackedLayout::KateContainerStackedLayout(QWidget *parent) : QStackedLayout(parent) {} QSize KateContainerStackedLayout::sizeHint() const { if (currentWidget()) { return currentWidget()->sizeHint(); } return QStackedLayout::sizeHint(); } QSize KateContainerStackedLayout::minimumSize() const { if (currentWidget()) { return currentWidget()->minimumSize(); } return QStackedLayout::minimumSize(); } KateMainWindow::KateMainWindow(KConfig *sconfig, const QString &sgroup) - : KateMDI::MainWindow(0) + : KateMDI::MainWindow(nullptr) , m_modignore(false) , m_wrapper(new KTextEditor::MainWindow(this)) { /** * we don't want any flicker here */ KateUpdateDisabler disableUpdates (this); /** * get and set config revision */ static const int currentConfigRevision = 10; const int readConfigRevision = KConfigGroup(KSharedConfig::openConfig(), "General").readEntry("Config Revision", 0); KConfigGroup(KSharedConfig::openConfig(), "General").writeEntry("Config Revision", currentConfigRevision); const bool firstStart = readConfigRevision < currentConfigRevision; // start session restore if needed startRestore(sconfig, sgroup); // setup most important actions first, needed by setupMainWindow setupImportantActions(); // setup the most important widgets setupMainWindow(); // setup the actions setupActions(); setStandardToolBarMenuEnabled(true); setXMLFile(QStringLiteral("kateui.rc")); createShellGUI(true); //qCDebug(LOG_KATE) << "****************************************************************************" << sconfig; // register mainwindow in app KateApp::self()->addMainWindow(this); // enable plugin guis KateApp::self()->pluginManager()->enableAllPluginsGUI(this, sconfig); // caption update Q_FOREACH (auto doc, KateApp::self()->documentManager()->documentList()) { slotDocumentCreated(doc); } connect(KateApp::self()->documentManager(), SIGNAL(documentCreated(KTextEditor::Document*)), this, SLOT(slotDocumentCreated(KTextEditor::Document*))); readOptions(); if (sconfig) { m_viewManager->restoreViewConfiguration(KConfigGroup(sconfig, sgroup)); } finishRestore(); m_fileOpenRecent->loadEntries(KConfigGroup(sconfig, "Recent Files")); setAcceptDrops(true); connect(KateApp::self()->sessionManager(), SIGNAL(sessionChanged()), this, SLOT(updateCaption())); connect(this, SIGNAL(sigShowPluginConfigPage(KTextEditor::Plugin*,uint)), this, SLOT(showPluginConfigPage(KTextEditor::Plugin*,uint))); // prior to this there was (possibly) no view, therefore not context menu. // Hence, we have to take care of the menu bar here toggleShowMenuBar(false); // on first start: deactivate toolbar if (firstStart) toolBar(QLatin1String("mainToolBar"))->hide(); // pass focus to first view! if (m_viewManager->activeView()) m_viewManager->activeView()->setFocus(); } KateMainWindow::~KateMainWindow() { // first, save our fallback window size ;) KConfigGroup cfg(KSharedConfig::openConfig(), "MainWindow"); KWindowConfig::saveWindowSize(windowHandle(), cfg); // save other options ;=) saveOptions(); // unregister mainwindow in app KateApp::self()->removeMainWindow(this); // disable all plugin guis, delete all pluginViews KateApp::self()->pluginManager()->disableAllPluginsGUI(this); // delete the view manager, before KateMainWindow's wrapper is dead delete m_viewManager; - m_viewManager = 0; + m_viewManager = nullptr; // kill the wrapper object, now that all views are dead delete m_wrapper; - m_wrapper = 0; + m_wrapper = nullptr; } QSize KateMainWindow::sizeHint() const { /** * have some useful size hint, else we have mini windows per default */ return (QSize(640, 480).expandedTo(minimumSizeHint())); } void KateMainWindow::setupImportantActions() { m_paShowStatusBar = KStandardAction::showStatusbar(this, SLOT(toggleShowStatusBar()), actionCollection()); m_paShowStatusBar->setWhatsThis(i18n("Use this command to show or hide the view's statusbar")); m_paShowMenuBar = KStandardAction::showMenubar(this, SLOT(toggleShowMenuBar()), actionCollection()); m_paShowTabBar = new KToggleAction(i18n("Show &Tabs"), this); actionCollection()->addAction(QStringLiteral("settings_show_tab_bar"), m_paShowTabBar); connect(m_paShowTabBar, SIGNAL(toggled(bool)), this, SLOT(toggleShowTabBar())); m_paShowTabBar->setWhatsThis(i18n("Use this command to show or hide the tabs for the views")); m_paShowPath = new KToggleAction(i18n("Sho&w Path in Titlebar"), this); actionCollection()->addAction(QStringLiteral("settings_show_full_path"), m_paShowPath); connect(m_paShowPath, SIGNAL(toggled(bool)), this, SLOT(updateCaption())); m_paShowPath->setWhatsThis(i18n("Show the complete document path in the window caption")); QAction * a = actionCollection()->addAction(KStandardAction::Back, QStringLiteral("view_prev_tab")); a->setText(i18n("&Previous Tab")); a->setWhatsThis(i18n("Focus the previous tab.")); actionCollection()->setDefaultShortcuts(a, a->shortcuts() << KStandardShortcut::tabPrev()); connect(a, SIGNAL(triggered()), this, SLOT(slotFocusPrevTab())); a = actionCollection()->addAction(KStandardAction::Forward, QStringLiteral("view_next_tab")); a->setText(i18n("&Next Tab")); a->setWhatsThis(i18n("Focus the next tab.")); actionCollection()->setDefaultShortcuts(a, a->shortcuts() << KStandardShortcut::tabNext()); connect(a, SIGNAL(triggered()), this, SLOT(slotFocusNextTab())); // the quick open action is used by the KateViewSpace "quick open button" a = actionCollection()->addAction(QStringLiteral("view_quick_open")); a->setIcon(QIcon::fromTheme(QStringLiteral("quickopen"))); a->setText(i18n("&Quick Open")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_O)); connect(a, SIGNAL(triggered()), this, SLOT(slotQuickOpen())); a->setWhatsThis(i18n("Open a form to quick open documents.")); } void KateMainWindow::setupMainWindow() { setToolViewStyle(KMultiTabBar::KDEV3ICON); /** * create central stacked widget with its children */ m_mainStackedWidget = new QStackedWidget(centralWidget()); centralWidget()->layout()->addWidget(m_mainStackedWidget); (static_cast(centralWidget()->layout()))->setStretchFactor(m_mainStackedWidget, 100); m_quickOpen = new KateQuickOpen(m_mainStackedWidget, this); m_mainStackedWidget->addWidget(m_quickOpen); m_viewManager = new KateViewManager(m_mainStackedWidget, this); m_mainStackedWidget->addWidget(m_viewManager); // make view manager default visible! m_mainStackedWidget->setCurrentWidget(m_viewManager); m_bottomViewBarContainer = new QWidget(centralWidget()); centralWidget()->layout()->addWidget(m_bottomViewBarContainer); m_bottomContainerStack = new KateContainerStackedLayout(m_bottomViewBarContainer); } void KateMainWindow::setupActions() { QAction *a; actionCollection()->addAction(KStandardAction::New, QStringLiteral("file_new"), m_viewManager, SLOT(slotDocumentNew())) ->setWhatsThis(i18n("Create a new document")); actionCollection()->addAction(KStandardAction::Open, QStringLiteral("file_open"), m_viewManager, SLOT(slotDocumentOpen())) ->setWhatsThis(i18n("Open an existing document for editing")); m_fileOpenRecent = KStandardAction::openRecent(m_viewManager, SLOT(openUrl(QUrl)), this); m_fileOpenRecent->setMaxItems(KateConfigDialog::recentFilesMaxCount()); actionCollection()->addAction(m_fileOpenRecent->objectName(), m_fileOpenRecent); m_fileOpenRecent->setWhatsThis(i18n("This lists files which you have opened recently, and allows you to easily open them again.")); a = actionCollection()->addAction(QStringLiteral("file_save_all")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-save-all"))); a->setText(i18n("Save A&ll")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL + Qt::Key_L)); connect(a, SIGNAL(triggered()), KateApp::self()->documentManager(), SLOT(saveAll())); a->setWhatsThis(i18n("Save all open, modified documents to disk.")); a = actionCollection()->addAction(QStringLiteral("file_reload_all")); a->setText(i18n("&Reload All")); connect(a, SIGNAL(triggered()), KateApp::self()->documentManager(), SLOT(reloadAll())); a->setWhatsThis(i18n("Reload all open documents.")); a = actionCollection()->addAction(QStringLiteral("file_close_orphaned")); a->setText(i18n("Close Orphaned")); connect(a, SIGNAL(triggered()), KateApp::self()->documentManager(), SLOT(closeOrphaned())); a->setWhatsThis(i18n("Close all documents in the file list that could not be reopened, because they are not accessible anymore.")); a = actionCollection()->addAction(KStandardAction::Close, QStringLiteral("file_close"), m_viewManager, SLOT(slotDocumentClose())); a->setIcon(QIcon::fromTheme(QStringLiteral("document-close"))); a->setWhatsThis(i18n("Close the current document.")); a = actionCollection()->addAction(QStringLiteral("file_close_other")); a->setText(i18n("Close Other")); connect(a, SIGNAL(triggered()), this, SLOT(slotDocumentCloseOther())); a->setWhatsThis(i18n("Close other open documents.")); a = actionCollection()->addAction(QStringLiteral("file_close_all")); a->setText(i18n("Clos&e All")); connect(a, SIGNAL(triggered()), this, SLOT(slotDocumentCloseAll())); a->setWhatsThis(i18n("Close all open documents.")); a = actionCollection()->addAction(KStandardAction::Quit, QStringLiteral("file_quit")); // Qt::QueuedConnection: delay real shutdown, as we are inside menu action handling (bug #185708) connect(a, SIGNAL(triggered()), this, SLOT(slotFileQuit()), Qt::QueuedConnection); a->setWhatsThis(i18n("Close this window")); a = actionCollection()->addAction(QStringLiteral("view_new_view")); a->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); a->setText(i18n("&New Window")); connect(a, SIGNAL(triggered()), this, SLOT(newWindow())); a->setWhatsThis(i18n("Create a new Kate view (a new window with the same document list).")); - m_showFullScreenAction = KStandardAction::fullScreen(0, 0, this, this); + m_showFullScreenAction = KStandardAction::fullScreen(nullptr, nullptr, this, this); actionCollection()->addAction(m_showFullScreenAction->objectName(), m_showFullScreenAction); connect(m_showFullScreenAction, SIGNAL(toggled(bool)), this, SLOT(slotFullScreen(bool))); documentOpenWith = new KActionMenu(i18n("Open W&ith"), this); actionCollection()->addAction(QStringLiteral("file_open_with"), documentOpenWith); documentOpenWith->setWhatsThis(i18n("Open the current document using another application registered for its file type, or an application of your choice.")); connect(documentOpenWith->menu(), SIGNAL(aboutToShow()), this, SLOT(mSlotFixOpenWithMenu())); connect(documentOpenWith->menu(), SIGNAL(triggered(QAction*)), this, SLOT(slotOpenWithMenuAction(QAction*))); a = KStandardAction::keyBindings(this, SLOT(editKeys()), actionCollection()); a->setWhatsThis(i18n("Configure the application's keyboard shortcut assignments.")); a = KStandardAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection()); a->setWhatsThis(i18n("Configure which items should appear in the toolbar(s).")); QAction *settingsConfigure = KStandardAction::preferences(this, SLOT(slotConfigure()), actionCollection()); settingsConfigure->setWhatsThis(i18n("Configure various aspects of this application and the editing component.")); if (KateApp::self()->pluginManager()->pluginList().count() > 0) { a = actionCollection()->addAction(QStringLiteral("help_plugins_contents")); a->setText(i18n("&Plugins Handbook")); connect(a, SIGNAL(triggered()), this, SLOT(pluginHelp())); a->setWhatsThis(i18n("This shows help files for various available plugins.")); } a = actionCollection()->addAction(QStringLiteral("help_about_editor")); a->setText(i18n("&About Editor Component")); connect(a, SIGNAL(triggered()), this, SLOT(aboutEditor())); connect(m_viewManager, SIGNAL(viewChanged(KTextEditor::View*)), this, SLOT(slotWindowActivated())); connect(m_viewManager, SIGNAL(viewChanged(KTextEditor::View*)), this, SLOT(slotUpdateOpenWith())); connect(m_viewManager, SIGNAL(viewChanged(KTextEditor::View*)), this, SLOT(slotUpdateBottomViewBar())); // re-route signals to our wrapper connect(m_viewManager, SIGNAL(viewChanged(KTextEditor::View*)), m_wrapper, SIGNAL(viewChanged(KTextEditor::View*))); connect(m_viewManager, SIGNAL(viewCreated(KTextEditor::View*)), m_wrapper, SIGNAL(viewCreated(KTextEditor::View*))); connect(this, SIGNAL(unhandledShortcutOverride(QEvent*)), m_wrapper, SIGNAL(unhandledShortcutOverride(QEvent*))); slotWindowActivated(); // session actions a = actionCollection()->addAction(QStringLiteral("sessions_new")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); a->setText(i18nc("Menu entry Session->New", "&New")); // Qt::QueuedConnection to avoid deletion of code that is executed when reducing the amount of mainwindows. (bug #227008) connect(a, SIGNAL(triggered()), KateApp::self()->sessionManager(), SLOT(sessionNew()), Qt::QueuedConnection); a = actionCollection()->addAction(QStringLiteral("sessions_open")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-open"))); a->setText(i18n("&Open Session")); // Qt::QueuedConnection to avoid deletion of code that is executed when reducing the amount of mainwindows. (bug #227008) connect(a, SIGNAL(triggered()), KateApp::self()->sessionManager(), SLOT(sessionOpen()), Qt::QueuedConnection); a = actionCollection()->addAction(QStringLiteral("sessions_save")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); a->setText(i18n("&Save Session")); connect(a, SIGNAL(triggered()), KateApp::self()->sessionManager(), SLOT(sessionSave())); a = actionCollection()->addAction(QStringLiteral("sessions_save_as")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-save-as"))); a->setText(i18n("Save Session &As...")); connect(a, SIGNAL(triggered()), KateApp::self()->sessionManager(), SLOT(sessionSaveAs())); a = actionCollection()->addAction(QStringLiteral("sessions_manage")); a->setIcon(QIcon::fromTheme(QStringLiteral("view-choose"))); a->setText(i18n("&Manage Sessions...")); // Qt::QueuedConnection to avoid deletion of code that is executed when reducing the amount of mainwindows. (bug #227008) connect(a, SIGNAL(triggered()), KateApp::self()->sessionManager(), SLOT(sessionManage()), Qt::QueuedConnection); // quick open menu ;) a = new KateSessionsAction(i18n("&Quick Open Session"), this); actionCollection()->addAction(QStringLiteral("sessions_list"), a); } void KateMainWindow::slotDocumentCloseAll() { if (KateApp::self()->documentManager()->documentList().size() >= 1 && KMessageBox::warningContinueCancel(this, i18n("This will close all open documents. Are you sure you want to continue?"), i18n("Close all documents"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QStringLiteral("closeAll")) != KMessageBox::Cancel) { if (queryClose_internal()) { KateApp::self()->documentManager()->closeAllDocuments(false); } } } void KateMainWindow::slotDocumentCloseOther(KTextEditor::Document *document) { if (KateApp::self()->documentManager()->documentList().size() > 1 && KMessageBox::warningContinueCancel(this, i18n("This will close all open documents beside the current one. Are you sure you want to continue?"), i18n("Close all documents beside current one"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QStringLiteral("closeOther")) != KMessageBox::Cancel) { if (queryClose_internal(document)) { KateApp::self()->documentManager()->closeOtherDocuments(document); } } } void KateMainWindow::slotDocumentCloseSelected(const QList &docList) { QList documents; foreach(KTextEditor::Document * doc, docList) { if (queryClose_internal(doc)) { documents.append(doc); } } KateApp::self()->documentManager()->closeDocuments(documents); } void KateMainWindow::slotDocumentCloseOther() { slotDocumentCloseOther(m_viewManager->activeView()->document()); } bool KateMainWindow::queryClose_internal(KTextEditor::Document *doc) { int documentCount = KateApp::self()->documentManager()->documentList().size(); if (! showModOnDiskPrompt()) { return false; } QList modifiedDocuments = KateApp::self()->documentManager()->modifiedDocumentList(); modifiedDocuments.removeAll(doc); bool shutdown = (modifiedDocuments.count() == 0); if (!shutdown) { shutdown = KateSaveModifiedDialog::queryClose(this, modifiedDocuments); } if (KateApp::self()->documentManager()->documentList().size() > documentCount) { KMessageBox::information(this, i18n("New file opened while trying to close Kate, closing aborted."), i18n("Closing Aborted")); shutdown = false; } return shutdown; } /** * queryClose(), take care that after the last mainwindow the stuff is closed */ bool KateMainWindow::queryClose() { // session saving, can we close all views ? // just test, not close them actually if (qApp->isSavingSession()) { return queryClose_internal(); } // normal closing of window // allow to close all windows until the last without restrictions if (KateApp::self()->mainWindowsCount() > 1) { return true; } // last one: check if we can close all documents, try run // and save docs if we really close down ! if (queryClose_internal()) { KateApp::self()->sessionManager()->saveActiveSession(true); return true; } return false; } void KateMainWindow::newWindow() { KateApp::self()->newMainWindow(KateApp::self()->sessionManager()->activeSession()->config()); } void KateMainWindow::slotEditToolbars() { KConfigGroup cfg(KSharedConfig::openConfig(), "MainWindow"); saveMainWindowSettings(cfg); KEditToolBar dlg(factory()); connect(&dlg, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig())); dlg.exec(); } void KateMainWindow::reloadXmlGui() { for (KTextEditor::Document* doc : KateApp::self()->documentManager()->documentList()) { doc->reloadXML(); for (KTextEditor::View* view : doc->views()) { view->reloadXML(); } } } void KateMainWindow::slotNewToolbarConfig() { applyMainWindowSettings(KConfigGroup(KSharedConfig::openConfig(), "MainWindow")); // we neeed to relod all View's XML Gui from disk to ensure toolbar // changes are applied to all views. reloadXmlGui(); } void KateMainWindow::slotFileQuit() { KateApp::self()->shutdownKate(this); } void KateMainWindow::slotFileClose() { m_viewManager->slotDocumentClose(); } void KateMainWindow::slotOpenDocument(QUrl url) { m_viewManager->openUrl(url, QString(), true, false); } void KateMainWindow::readOptions() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); const KConfigGroup generalGroup(config, "General"); m_modNotification = generalGroup.readEntry("Modified Notification", false); KateApp::self()->documentManager()->setSaveMetaInfos(generalGroup.readEntry("Save Meta Infos", true)); KateApp::self()->documentManager()->setDaysMetaInfos(generalGroup.readEntry("Days Meta Infos", 30)); m_paShowPath->setChecked(generalGroup.readEntry("Show Full Path in Title", false)); m_paShowStatusBar->setChecked(generalGroup.readEntry("Show Status Bar", true)); m_paShowMenuBar->setChecked(generalGroup.readEntry("Show Menu Bar", true)); m_paShowTabBar->setChecked(generalGroup.readEntry("Show Tab Bar", true)); // emit signal to hide/show statusbars toggleShowStatusBar(); toggleShowTabBar(); } void KateMainWindow::saveOptions() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); KConfigGroup generalGroup(config, "General"); generalGroup.writeEntry("Save Meta Infos", KateApp::self()->documentManager()->getSaveMetaInfos()); generalGroup.writeEntry("Days Meta Infos", KateApp::self()->documentManager()->getDaysMetaInfos()); generalGroup.writeEntry("Show Full Path in Title", m_paShowPath->isChecked()); generalGroup.writeEntry("Show Status Bar", m_paShowStatusBar->isChecked()); generalGroup.writeEntry("Show Menu Bar", m_paShowMenuBar->isChecked()); generalGroup.writeEntry("Show Tab Bar", m_paShowTabBar->isChecked()); } void KateMainWindow::toggleShowMenuBar(bool showMessage) { if (m_paShowMenuBar->isChecked()) { menuBar()->show(); removeMenuBarActionFromContextMenu(); } else { if (showMessage) { const QString accel = m_paShowMenuBar->shortcut().toString(); KMessageBox::information(this, i18n("This will hide the menu bar completely." " You can show it again by typing %1.", accel), i18n("Hide menu bar"), QLatin1String("HideMenuBarWarning")); } menuBar()->hide(); addMenuBarActionToContextMenu(); } } void KateMainWindow::addMenuBarActionToContextMenu() { if (m_viewManager->activeView()) { m_viewManager->activeView()->contextMenu()->addAction(m_paShowMenuBar); } } void KateMainWindow::removeMenuBarActionFromContextMenu() { if (m_viewManager->activeView()) { m_viewManager->activeView()->contextMenu()->removeAction(m_paShowMenuBar); } } void KateMainWindow::toggleShowStatusBar() { emit statusBarToggled(); } bool KateMainWindow::showStatusBar() { return m_paShowStatusBar->isChecked(); } void KateMainWindow::toggleShowTabBar() { emit tabBarToggled(); } bool KateMainWindow::showTabBar() { return m_paShowTabBar->isChecked(); } void KateMainWindow::slotWindowActivated() { if (m_viewManager->activeView()) { updateCaption(m_viewManager->activeView()->document()); } // show view manager in any case if (m_mainStackedWidget->currentWidget() != m_viewManager) { m_mainStackedWidget->setCurrentWidget(m_viewManager); } // update proxy centralWidget()->setFocusProxy(m_viewManager->activeView()); } void KateMainWindow::slotUpdateOpenWith() { if (m_viewManager->activeView()) { documentOpenWith->setEnabled(!m_viewManager->activeView()->document()->url().isEmpty()); } else { documentOpenWith->setEnabled(false); } } void KateMainWindow::dragEnterEvent(QDragEnterEvent *event) { if (!event->mimeData()) { return; } const bool accept = event->mimeData()->hasUrls() || event->mimeData()->hasText(); event->setAccepted(accept); } void KateMainWindow::dropEvent(QDropEvent *event) { slotDropEvent(event); } void KateMainWindow::slotDropEvent(QDropEvent *event) { - if (event->mimeData() == 0) { + if (event->mimeData() == nullptr) { return; } // // are we dropping files? // if (event->mimeData()->hasUrls()) { QList textlist = event->mimeData()->urls(); // Try to get the KTextEditor::View that sent this, and activate it, so that the file opens in the // view where it was dropped KTextEditor::View *kVsender = qobject_cast(QObject::sender()); - if (kVsender != 0) { + if (kVsender != nullptr) { QWidget *parent = kVsender->parentWidget(); - if (parent != 0) { + if (parent != nullptr) { KateViewSpace *vs = qobject_cast(parent->parentWidget()); - if (vs != 0) { + if (vs != nullptr) { m_viewManager->setActiveSpace(vs); } } } foreach(const QUrl & url, textlist) { // if url has no file component, try and recursively scan dir KFileItem kitem(url); kitem.setDelayedMimeTypes(true); if (kitem.isDir()) { if (KMessageBox::questionYesNo(this, i18n("You dropped the directory %1 into Kate. " "Do you want to load all files contained in it ?", url.url()), i18n("Load files recursively?")) == KMessageBox::Yes) { KIO::ListJob *list_job = KIO::listRecursive(url, KIO::DefaultFlags, false); connect(list_job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)), this, SLOT(slotListRecursiveEntries(KIO::Job*,KIO::UDSEntryList))); } } else { m_viewManager->openUrl(url); } } } // // or are we dropping text? // else if (event->mimeData()->hasText()) { KTextEditor::Document *doc = KateApp::self()->documentManager()->createDoc(); doc->setText(event->mimeData()->text()); m_viewManager->activateView(doc); } } void KateMainWindow::slotListRecursiveEntries(KIO::Job *job, const KIO::UDSEntryList &list) { const QUrl dir = static_cast(job)->url(); foreach(const KIO::UDSEntry & entry, list) { if (!entry.isDir()) { QUrl url(dir); url = url.adjusted(QUrl::StripTrailingSlash); url.setPath(url.path() + QLatin1Char('/') + entry.stringValue(KIO::UDSEntry::UDS_NAME)); m_viewManager->openUrl(url); } } } void KateMainWindow::editKeys() { KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this); QList clients = guiFactory()->clients(); foreach(KXMLGUIClient * client, clients) { // FIXME there appear to be invalid clients after session switching // qCDebug(LOG_KATE)<<"adding client to shortcut editor"; // qCDebug(LOG_KATE)<actionCollection(); // qCDebug(LOG_KATE)<componentData().aboutData(); // qCDebug(LOG_KATE)<componentData().aboutData()->programName(); dlg.addCollection(client->actionCollection(), client->componentName()); } dlg.configure(); // reloadXML gui clients, to ensure all clients are up-to-date reloadXmlGui(); } void KateMainWindow::openUrl(const QString &name) { m_viewManager->openUrl(QUrl(name)); } void KateMainWindow::slotConfigure() { - showPluginConfigPage(0, 0); + showPluginConfigPage(nullptr, 0); } void KateMainWindow::showPluginConfigPage(KTextEditor::Plugin *configpageinterface, uint id) { if (!m_viewManager->activeView()) { return; } KateConfigDialog *dlg = new KateConfigDialog(this, m_viewManager->activeView()); if (configpageinterface) { dlg->showAppPluginPage(configpageinterface, id); } if (dlg->exec() == QDialog::Accepted) { m_fileOpenRecent->setMaxItems(KateConfigDialog::recentFilesMaxCount()); } delete dlg; m_viewManager->reactivateActiveView(); // gui (toolbars...) needs to be updated, because // of possible changes that the configure dialog // could have done on it, specially for plugins. } QUrl KateMainWindow::activeDocumentUrl() { // anders: i make this one safe, as it may be called during // startup (by the file selector) KTextEditor::View *v = m_viewManager->activeView(); if (v) { return v->document()->url(); } return QUrl(); } void KateMainWindow::mSlotFixOpenWithMenu() { // dh: in bug #307699, this slot is called when launching the Kate application // unfortunately, no one ever could reproduce except users. KTextEditor::View *activeView = m_viewManager->activeView(); if (! activeView) { return; } // cleanup menu QMenu *menu = documentOpenWith->menu(); menu->clear(); // get a list of appropriate services. QMimeDatabase db; QMimeType mime = db.mimeTypeForName(activeView->document()->mimeType()); //qCDebug(LOG_KATE) << "mime type: " << mime.name(); - QAction *a = 0; + QAction *a = nullptr; KService::List offers = KMimeTypeTrader::self()->query(mime.name(), QStringLiteral("Application")); // add all default open-with-actions except "Kate" for (KService::List::Iterator it = offers.begin(); it != offers.end(); ++it) { KService::Ptr service = *it; if (service->name() == QStringLiteral("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 = documentOpenWith->menu()->addAction(i18n("&Other...")); a->setData(QString()); } void KateMainWindow::slotOpenWithMenuAction(QAction *a) { QList list; list.append(m_viewManager->activeView()->document()->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")); } } void KateMainWindow::pluginHelp() { KHelpClient::invokeHelp(QString(), QStringLiteral("kate-plugins")); } void KateMainWindow::aboutEditor() { KAboutApplicationDialog ad(KTextEditor::Editor::instance()->aboutData(), this); ad.exec(); } void KateMainWindow::slotFullScreen(bool t) { KToggleFullScreenAction::setFullScreen(this, t); QMenuBar *mb = menuBar(); if (t) { QToolButton *b = new QToolButton(mb); b->setDefaultAction(m_showFullScreenAction); b->setSizePolicy(QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Ignored)); b->setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); mb->setCornerWidget(b,Qt::TopRightCorner); b->setVisible(true); b->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); } else { QWidget *w=mb->cornerWidget(Qt::TopRightCorner); if (w) w->deleteLater(); } } bool KateMainWindow::showModOnDiskPrompt() { KTextEditor::Document *doc; DocVector list; list.reserve(KateApp::self()->documentManager()->documentList().size()); foreach(doc, KateApp::self()->documentManager()->documentList()) { if (KateApp::self()->documentManager()->documentInfo(doc)->modifiedOnDisc) { list.append(doc); } } if (!list.isEmpty() && !m_modignore) { KateMwModOnHdDialog mhdlg(list, this); m_modignore = true; bool res = mhdlg.exec(); m_modignore = false; return res; } return true; } void KateMainWindow::slotDocumentCreated(KTextEditor::Document *doc) { connect(doc, SIGNAL(modifiedChanged(KTextEditor::Document*)), this, SLOT(updateCaption(KTextEditor::Document*))); connect(doc, SIGNAL(readWriteChanged(KTextEditor::Document*)), this, SLOT(updateCaption(KTextEditor::Document*))); connect(doc, SIGNAL(documentNameChanged(KTextEditor::Document*)), this, SLOT(updateCaption(KTextEditor::Document*))); connect(doc, SIGNAL(documentUrlChanged(KTextEditor::Document*)), this, SLOT(updateCaption(KTextEditor::Document*))); connect(doc, SIGNAL(documentNameChanged(KTextEditor::Document*)), this, SLOT(slotUpdateOpenWith())); updateCaption(doc); } void KateMainWindow::updateCaption() { if (m_viewManager->activeView()) { updateCaption(m_viewManager->activeView()->document()); } } void KateMainWindow::updateCaption(KTextEditor::Document *doc) { if (!m_viewManager->activeView()) { setCaption(QString(), false); return; } // block signals from inactive docs if (!((KTextEditor::Document *)m_viewManager->activeView()->document() == doc)) { return; } QString c; if (m_viewManager->activeView()->document()->url().isEmpty() || (!m_paShowPath || !m_paShowPath->isChecked())) { c = ((KTextEditor::Document *)m_viewManager->activeView()->document())->documentName(); } else { c = m_viewManager->activeView()->document()->url().toString(QUrl::PreferLocalFile); const QString homePath = QDir::homePath(); if (c.startsWith(homePath)) { c = QStringLiteral("~") + c.right(c.length() - homePath.length()); } } QString sessName = KateApp::self()->sessionManager()->activeSession()->name(); if (!sessName.isEmpty()) { sessName = QString::fromLatin1("%1: ").arg(sessName); } QString readOnlyCaption; if (!m_viewManager->activeView()->document()->isReadWrite()) { readOnlyCaption = i18n(" [read only]"); } setCaption(sessName + c + readOnlyCaption + QStringLiteral(" [*]"), m_viewManager->activeView()->document()->isModified()); } void KateMainWindow::saveProperties(KConfigGroup &config) { saveSession(config); // store all plugin view states int id = KateApp::self()->mainWindowID(this); foreach(const KatePluginInfo & item, KateApp::self()->pluginManager()->pluginList()) { if (item.plugin && pluginViews().contains(item.plugin)) { if (auto interface = qobject_cast (pluginViews().value(item.plugin))) { KConfigGroup group(config.config(), QString::fromLatin1("Plugin:%1:MainWindow:%2").arg(item.saveName()).arg(id)); interface->writeSessionConfig(group); } } } m_fileOpenRecent->saveEntries(KConfigGroup(config.config(), "Recent Files")); m_viewManager->saveViewConfiguration(config); } void KateMainWindow::readProperties(const KConfigGroup &config) { // KDE5: TODO startRestore should take a const KConfigBase*, or even just a const KConfigGroup&, // but this propagates down to interfaces/kate/plugin.h so all plugins have to be ported KConfigBase *configBase = const_cast(config.config()); startRestore(configBase, config.name()); // perhaps enable plugin guis KateApp::self()->pluginManager()->enableAllPluginsGUI(this, configBase); finishRestore(); m_fileOpenRecent->loadEntries(KConfigGroup(config.config(), "Recent Files")); m_viewManager->restoreViewConfiguration(config); } void KateMainWindow::saveGlobalProperties(KConfig *sessionConfig) { KateApp::self()->documentManager()->saveDocumentList(sessionConfig); KConfigGroup cg(sessionConfig, "General"); cg.writeEntry("Last Session", KateApp::self()->sessionManager()->activeSession()->name()); // save plugin config !! KateApp::self()->pluginManager()->writeConfig(sessionConfig); } void KateMainWindow::saveWindowConfig(const KConfigGroup &_config) { KConfigGroup config(_config); saveMainWindowSettings(config); KWindowConfig::saveWindowSize(windowHandle(), config); config.writeEntry("WindowState", int(((KParts::MainWindow *)this)->windowState())); config.sync(); } void KateMainWindow::restoreWindowConfig(const KConfigGroup &config) { setWindowState(Qt::WindowNoState); applyMainWindowSettings(config); KWindowConfig::restoreWindowSize(windowHandle(), config); setWindowState(QFlags(config.readEntry("WindowState", int(Qt::WindowActive)))); } void KateMainWindow::slotUpdateBottomViewBar() { //qCDebug(LOG_KATE)<<"slotUpdateHorizontalViewBar()"<activeView(); BarState bs = m_bottomViewBarMapping[view]; if (bs.bar() && bs.state()) { m_bottomContainerStack->setCurrentWidget(bs.bar()); m_bottomContainerStack->currentWidget()->show(); m_bottomViewBarContainer->show(); } else { QWidget *wid = m_bottomContainerStack->currentWidget(); if (wid) { wid->hide(); } //qCDebug(LOG_KATE)<hide(); } } void KateMainWindow::queueModifiedOnDisc(KTextEditor::Document *doc) { if (!m_modNotification) { return; } KateDocumentInfo *docInfo = KateApp::self()->documentManager()->documentInfo(doc); if (!docInfo) { return; } bool modOnDisk = (uint)docInfo->modifiedOnDisc; - if (s_modOnHdDialog == 0 && modOnDisk) { + if (s_modOnHdDialog == nullptr && modOnDisk) { DocVector list; list.append(doc); s_modOnHdDialog = new KateMwModOnHdDialog(list, this); m_modignore = true; KWindowSystem::setOnAllDesktops(s_modOnHdDialog->winId(), true); s_modOnHdDialog->exec(); delete s_modOnHdDialog; // s_modOnHdDialog is set to 0 in destructor of KateMwModOnHdDialog (jowenn!!!) m_modignore = false; - } else if (s_modOnHdDialog != 0) { + } else if (s_modOnHdDialog != nullptr) { s_modOnHdDialog->addDocument(doc); } } bool KateMainWindow::event(QEvent *e) { if (e->type() == QEvent::ShortcutOverride) { QKeyEvent *k = static_cast(e); emit unhandledShortcutOverride(k); } return KateMDI::MainWindow::event(e); } QObject *KateMainWindow::pluginView(const QString &name) { KTextEditor::Plugin *plugin = KateApp::self()->pluginManager()->plugin(name); if (!plugin) { - return 0; + return nullptr; } return m_pluginViews.contains(plugin) ? m_pluginViews.value(plugin) : 0; } void KateMainWindow::mousePressEvent(QMouseEvent *e) { switch(e->button()) { case Qt::ForwardButton: slotFocusNextTab(); break; case Qt::BackButton: slotFocusPrevTab(); break; default: ; } } void KateMainWindow::slotFocusPrevTab() { if (m_viewManager->activeViewSpace()) { m_viewManager->activeViewSpace()->focusPrevTab(); } } void KateMainWindow::slotFocusNextTab() { if (m_viewManager->activeViewSpace()) { m_viewManager->activeViewSpace()->focusNextTab(); } } void KateMainWindow::slotQuickOpen() { /** * show quick open and pass focus to it */ m_quickOpen->update(); m_mainStackedWidget->setCurrentWidget(m_quickOpen); centralWidget()->setFocusProxy(m_quickOpen); m_quickOpen->setFocus(); } QWidget *KateMainWindow::createToolView(KTextEditor::Plugin *plugin, const QString &identifier, KTextEditor::MainWindow::ToolViewPosition pos, const QIcon &icon, const QString &text) { // FIXME KF5 return KateMDI::MainWindow::createToolView(plugin, identifier, (KMultiTabBar::KMultiTabBarPosition)(pos), icon.pixmap(QSize(16, 16)), text); } bool KateMainWindow::moveToolView(QWidget *widget, KTextEditor::MainWindow::ToolViewPosition pos) { if (!qobject_cast(widget)) { return false; } // FIXME KF5 return KateMDI::MainWindow::moveToolView(qobject_cast(widget), (KMultiTabBar::KMultiTabBarPosition)(pos)); } bool KateMainWindow::showToolView(QWidget *widget) { if (!qobject_cast(widget)) { return false; } return KateMDI::MainWindow::showToolView(qobject_cast(widget)); } bool KateMainWindow::hideToolView(QWidget *widget) { if (!qobject_cast(widget)) { return false; } return KateMDI::MainWindow::hideToolView(qobject_cast(widget)); } diff --git a/kate/katemainwindow.h b/kate/katemainwindow.h index 71124204e..ba514a497 100644 --- a/kate/katemainwindow.h +++ b/kate/katemainwindow.h @@ -1,575 +1,575 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 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. */ #ifndef __KATE_MAINWINDOW_H__ #define __KATE_MAINWINDOW_H__ #include "katemdi.h" #include "kateviewmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class QMenu; namespace KIO { class UDSEntry; typedef class QList UDSEntryList; } class KFileItem; class KRecentFilesAction; class KateViewManager; class KateMwModOnHdDialog; class KateQuickOpen; // Helper layout class to always provide minimum size class KateContainerStackedLayout : public QStackedLayout { Q_OBJECT public: KateContainerStackedLayout(QWidget *parent); QSize sizeHint() const Q_DECL_OVERRIDE; QSize minimumSize() const Q_DECL_OVERRIDE; }; class KateMainWindow : public KateMDI::MainWindow, virtual public KParts::PartBase { Q_OBJECT public: /** * Construct the window and restore its state from given config if any * @param sconfig session config for this window, 0 if none * @param sgroup session config group to use */ KateMainWindow(KConfig *sconfig, const QString &sgroup); /** * Destruct the nice window */ ~KateMainWindow(); /** * Accessor methodes for interface and child objects */ public: KateViewManager *viewManager() { return m_viewManager; } /** * KTextEditor::MainWindow wrapper * @return KTextEditor::MainWindow wrapper. */ KTextEditor::MainWindow *wrapper() { return m_wrapper; } public: /** Returns the URL of the current document. * anders: I add this for use from the file selector. */ QUrl activeDocumentUrl(); /** * Prompts the user for what to do with files that are modified on disk if any. * This is optionally run when the window receives focus, and when the last * window is closed. * @return true if no documents are modified on disk, or all documents were * handled by the dialog; otherwise (the dialog was canceled) false. */ bool showModOnDiskPrompt(); public: /*reimp*/ void readProperties(const KConfigGroup &config) Q_DECL_OVERRIDE; /*reimp*/ void saveProperties(KConfigGroup &config) Q_DECL_OVERRIDE; /*reimp*/ void saveGlobalProperties(KConfig *sessionConfig) Q_DECL_OVERRIDE; public: - bool queryClose_internal(KTextEditor::Document *doc = NULL); + bool queryClose_internal(KTextEditor::Document *doc = nullptr); /** * save the settings, size and state of this window in * the provided config group */ void saveWindowConfig(const KConfigGroup &); /** * restore the settings, size and state of this window from * the provided config group. */ void restoreWindowConfig(const KConfigGroup &); /** * save some global options to katerc */ void saveOptions(); private: /** * Setup actions which pointers are needed already in setupMainWindow */ void setupImportantActions(); void setupMainWindow(); void setupActions(); bool queryClose() Q_DECL_OVERRIDE; void addMenuBarActionToContextMenu(); void removeMenuBarActionFromContextMenu(); /** * read some global options from katerc */ void readOptions(); void dragEnterEvent(QDragEnterEvent *) Q_DECL_OVERRIDE; void dropEvent(QDropEvent *) Q_DECL_OVERRIDE; public Q_SLOTS: void slotFileClose(); void slotFileQuit(); void queueModifiedOnDisc(KTextEditor::Document *doc); void slotFocusPrevTab(); void slotFocusNextTab(); /** * Show quick open */ void slotQuickOpen(); /** * Overwrite size hint for better default window sizes * @return size hint */ QSize sizeHint() const Q_DECL_OVERRIDE; /** * slots used for actions in the menus/toolbars * or internal signal connections */ private Q_SLOTS: void newWindow(); void slotConfigure(); void slotOpenWithMenuAction(QAction *a); void slotEditToolbars(); void slotNewToolbarConfig(); void slotUpdateOpenWith(); void slotOpenDocument(QUrl); void slotDropEvent(QDropEvent *); void editKeys(); void mSlotFixOpenWithMenu(); void reloadXmlGui(); /* to update the caption */ void slotDocumentCreated(KTextEditor::Document *doc); void updateCaption(KTextEditor::Document *doc); // calls updateCaption(doc) with the current document void updateCaption(); void pluginHelp(); void aboutEditor(); void slotFullScreen(bool); void slotListRecursiveEntries(KIO::Job *job, const KIO::UDSEntryList &list); private Q_SLOTS: void toggleShowMenuBar(bool showMessage = true); void toggleShowStatusBar(); void toggleShowTabBar(); public: bool showStatusBar(); bool showTabBar(); Q_SIGNALS: void statusBarToggled(); void tabBarToggled(); void unhandledShortcutOverride(QEvent *e); public: void openUrl(const QString &name = QString()); QHash &pluginViews() { return m_pluginViews; } QWidget *bottomViewBarContainer() { return m_bottomViewBarContainer; } void addToBottomViewBarContainer(KTextEditor::View *view, QWidget *bar) { m_bottomContainerStack->addWidget(bar); m_bottomViewBarMapping[view] = BarState(bar); } void hideBottomViewBarForView(KTextEditor::View *view) { BarState &state = m_bottomViewBarMapping[view]; if (state.bar()) { m_bottomContainerStack->setCurrentWidget(state.bar()); state.bar()->hide(); state.setState(false); } m_bottomViewBarContainer->hide(); } void showBottomViewBarForView(KTextEditor::View *view) { BarState &state = m_bottomViewBarMapping[view]; if (state.bar()) { m_bottomContainerStack->setCurrentWidget(state.bar()); state.bar()->show(); state.setState(true); m_bottomViewBarContainer->show(); } } void deleteBottomViewBarForView(KTextEditor::View *view) { BarState state = m_bottomViewBarMapping.take(view); if (state.bar()) { if (m_bottomContainerStack->currentWidget() == state.bar()) { m_bottomViewBarContainer->hide(); } delete state.bar(); } } bool modNotificationEnabled() const { return m_modNotification; } void setModNotificationEnabled(bool e) { m_modNotification = e; } KRecentFilesAction *fileOpenRecent() const { return m_fileOpenRecent; } // // KTextEditor::MainWindow interface, get called by invokeMethod from our wrapper object! // public Q_SLOTS: /** * get the toplevel widget. * \return the real main window widget. */ QWidget *window() { return this; } /** * Accessor to the XMLGUIFactory. * \return the mainwindow's KXMLGUIFactory. */ KXMLGUIFactory *guiFactory() Q_DECL_OVERRIDE { return KateMDI::MainWindow::guiFactory(); } /** * Get a list of all views for this main window. * @return all views */ QList views() { return viewManager()->views(); } /** * Access the active view. * \return active view */ KTextEditor::View *activeView() { return viewManager()->activeView(); } /** * Activate the view with the corresponding \p document. * If none exist for this document, create one * \param document the document * \return activated view of this document */ KTextEditor::View *activateView(KTextEditor::Document *document) { return viewManager()->activateView(document); } /** * Open the document \p url with the given \p encoding. * \param url the document's url * \param encoding the preferred encoding. If encoding is QString() the * encoding will be guessed or the default encoding will be used. * \return a pointer to the created view for the new document, if a document * with this url is already existing, its view will be activated */ KTextEditor::View *openUrl(const QUrl &url, const QString &encoding = QString()) { return viewManager()->openUrlWithView(url, encoding); } /** * Close selected view * \param view the view * \return true if view was closed */ bool closeView(KTextEditor::View *view) { m_viewManager->closeView(view); return true; } /** * Close the split view where the given view is contained. * \param view the view. * \return true if the split view was closed. */ bool closeSplitView(KTextEditor::View *view) { m_viewManager->closeViewSpace(view); return true; } /** * @returns true if the two given views share the same split view, * false otherwise. */ bool viewsInSameSplitView(KTextEditor::View *view1, KTextEditor::View *view2) { return m_viewManager->viewsInSameViewSpace(view1, view2); } /** * Split current view space according to @orientation * \param orientation in which line split the view */ void splitView(Qt::Orientation orientation) { - m_viewManager->splitViewSpace(0L, orientation); + m_viewManager->splitViewSpace(nullptr, orientation); } /** * Try to create a view bar for the given view. * @param view view for which we want an view bar * @return suitable widget that can host view bars widgets or nullptr */ QWidget *createViewBar(KTextEditor::View *) { return bottomViewBarContainer(); } /** * Delete the view bar for the given view. * @param view view for which we want an view bar */ void deleteViewBar(KTextEditor::View *view) { deleteBottomViewBarForView(view); } /** * Add a widget to the view bar. * @param view view for which the view bar is used * @param bar bar widget, shall have the viewBarParent() as parent widget */ void addWidgetToViewBar(KTextEditor::View *view, QWidget *bar) { addToBottomViewBarContainer(view, bar); } /** * Show the view bar for the given view * @param view view for which the view bar is used */ void showViewBar(KTextEditor::View *view) { showBottomViewBarForView(view); } /** * Hide the view bar for the given view * @param view view for which the view bar is used */ void hideViewBar(KTextEditor::View *view) { hideBottomViewBarForView(view); } /** * Create a new toolview with unique \p identifier at side \p pos * with \p icon and caption \p text. Use the returned widget to embedd * your widgets. * \param plugin which owns this tool view * \param identifier unique identifier for this toolview * \param pos position for the toolview, if we are in session restore, * this is only a preference * \param icon icon to use in the sidebar for the toolview * \param text translated text (i18n()) to use in addition to icon * \return created toolview on success, otherwise NULL */ QWidget *createToolView(KTextEditor::Plugin *plugin, const QString &identifier, KTextEditor::MainWindow::ToolViewPosition pos, const QIcon &icon, const QString &text); /** * Move the toolview \p widget to position \p pos. * \param widget the toolview to move, where the widget was constructed * by createToolView(). * \param pos new position to move widget to * \return \e true on success, otherwise \e false */ bool moveToolView(QWidget *widget, KTextEditor::MainWindow::ToolViewPosition pos); /** * Show the toolview \p widget. * \param widget the toolview to show, where the widget was constructed * by createToolView(). * \return \e true on success, otherwise \e false * \todo add focus parameter: bool showToolView (QWidget *widget, bool giveFocus ); */ bool showToolView(QWidget *widget); /** * Hide the toolview \p widget. * \param widget the toolview to hide, where the widget was constructed * by createToolView(). * \return \e true on success, otherwise \e false */ bool hideToolView(QWidget *widget); /** * Get a plugin view for the plugin with with identifier \p name. * \param name the plugin's name * \return pointer to the plugin view if a plugin with \p name is loaded and has a view for this mainwindow, * otherwise NULL */ QObject *pluginView(const QString &name); private Q_SLOTS: void slotUpdateBottomViewBar(); private Q_SLOTS: void slotDocumentCloseAll(); void slotDocumentCloseOther(); void slotDocumentCloseOther(KTextEditor::Document *document); void slotDocumentCloseSelected(const QList &); private: /** * Notify about file modifications from other processes? */ bool m_modNotification; /** * stacked widget containing the central area, aka view manager, quickopen, ... */ QStackedWidget *m_mainStackedWidget; /** * quick open to fast switch documents */ KateQuickOpen *m_quickOpen; /** * keeps track of views */ KateViewManager *m_viewManager; KRecentFilesAction *m_fileOpenRecent; KActionMenu *documentOpenWith; KToggleAction *settingsShowFileselector; KToggleAction *m_showFullScreenAction; bool m_modignore; // all plugin views for this mainwindow, used by the pluginmanager QHash m_pluginViews; // options: show statusbar + show path KToggleAction *m_paShowPath; KToggleAction *m_paShowMenuBar; KToggleAction *m_paShowStatusBar; KToggleAction *m_paShowTabBar; QWidget *m_bottomViewBarContainer; KateContainerStackedLayout *m_bottomContainerStack; class BarState { public: - BarState(): m_bar(0), m_state(false) {} + BarState(): m_bar(nullptr), m_state(false) {} BarState(QWidget *bar): m_bar(bar), m_state(false) {} ~BarState() {} QWidget *bar() { return m_bar; } bool state() { return m_state; } void setState(bool state) { m_state = state; } private: QWidget *m_bar; bool m_state; }; QHash m_bottomViewBarMapping; public: static void unsetModifiedOnDiscDialogIfIf(KateMwModOnHdDialog *diag) { if (s_modOnHdDialog == diag) { - s_modOnHdDialog = 0; + s_modOnHdDialog = nullptr; } } private: static KateMwModOnHdDialog *s_modOnHdDialog; /** * Wrapper of main window for KTextEditor */ KTextEditor::MainWindow *m_wrapper; public Q_SLOTS: void showPluginConfigPage(KTextEditor::Plugin *configpageinterface, uint id); void slotWindowActivated(); protected: bool event(QEvent *e) Q_DECL_OVERRIDE; void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; }; #endif diff --git a/kate/katemdi.cpp b/kate/katemdi.cpp index 7f227d632..a5bd77738 100644 --- a/kate/katemdi.cpp +++ b/kate/katemdi.cpp @@ -1,1054 +1,1054 @@ /* This file is part of the KDE libraries Copyright (C) 2005 Christoph Cullmann Copyright (C) 2002, 2003 Joseph Wenninger GUIClient partly based on ktoolbarhandler.cpp: Copyright (C) 2002 Simon Hausmann 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 "katemdi.h" #include "katedebug.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KateMDI { //BEGIN TOGGLETOOLVIEWACTION // ToggleToolViewAction::ToggleToolViewAction(const QString &text, ToolView *tv, QObject *parent) : KToggleAction(text, parent) , m_tv(tv) { connect(this, &ToggleToolViewAction::toggled, this, &ToggleToolViewAction::slotToggled); connect(m_tv, &ToolView::toolVisibleChanged, this, &ToggleToolViewAction::toolVisibleChanged); setChecked(m_tv->toolVisible()); } ToggleToolViewAction::~ToggleToolViewAction() {} void ToggleToolViewAction::toolVisibleChanged(bool) { if (isChecked() != m_tv->toolVisible()) { setChecked(m_tv->toolVisible()); } } void ToggleToolViewAction::slotToggled(bool t) { if (t) { m_tv->mainWindow()->showToolView(m_tv); m_tv->setFocus(); } else { m_tv->mainWindow()->hideToolView(m_tv); } } //END TOGGLETOOLVIEWACTION //BEGIN GUICLIENT static const QString actionListName = QStringLiteral("kate_mdi_view_actions"); // please don't use QStringLiteral since it can't be used with a concatenated string parameter on all platforms static const QString guiDescription = QLatin1String("" "" "" " " " " " " "" ""); GUIClient::GUIClient(MainWindow *mw) : QObject(mw) , KXMLGUIClient(mw) , m_mw(mw) { connect(m_mw->guiFactory(), SIGNAL(clientAdded(KXMLGUIClient*)), this, SLOT(clientAdded(KXMLGUIClient*))); if (domDocument().documentElement().isNull()) { QString completeDescription = guiDescription.arg(actionListName); setXML(completeDescription, false /*merge*/); } m_toolMenu = new KActionMenu(i18n("Tool &Views"), this); actionCollection()->addAction(QStringLiteral("kate_mdi_toolview_menu"), m_toolMenu); m_showSidebarsAction = new KToggleAction(i18n("Show Side&bars"), this); actionCollection()->addAction(QStringLiteral("kate_mdi_sidebar_visibility"), m_showSidebarsAction); actionCollection()->setDefaultShortcut(m_showSidebarsAction, Qt::CTRL | Qt::ALT | Qt::SHIFT | Qt::Key_F); m_showSidebarsAction->setChecked(m_mw->sidebarsVisible()); connect(m_showSidebarsAction, &KToggleAction::toggled, m_mw, &MainWindow::setSidebarsVisible); m_toolMenu->addAction(m_showSidebarsAction); QAction *sep_act = new QAction(this); sep_act->setSeparator(true); m_toolMenu->addAction(sep_act); // read shortcuts actionCollection()->setConfigGroup(QStringLiteral("Shortcuts")); actionCollection()->readSettings(); actionCollection()->addAssociatedWidget(m_mw); foreach(QAction * action, actionCollection()->actions()) action->setShortcutContext(Qt::WidgetWithChildrenShortcut); } GUIClient::~GUIClient() {} void GUIClient::updateSidebarsVisibleAction() { m_showSidebarsAction->setChecked(m_mw->sidebarsVisible()); } void GUIClient::registerToolView(ToolView *tv) { QString aname = QString::fromLatin1("kate_mdi_toolview_") + tv->id; // try to read the action shortcut QList shortcuts; KSharedConfigPtr cfg = KSharedConfig::openConfig(); QString shortcutString = cfg->group("Shortcuts").readEntry(aname, QString()); foreach(const QString & shortcut, shortcutString.split(QLatin1String(";"))) { shortcuts << QKeySequence::fromString(shortcut); } KToggleAction *a = new ToggleToolViewAction(i18n("Show %1", tv->text), tv, this); actionCollection()->setDefaultShortcuts(a, shortcuts); actionCollection()->addAction(aname, a); m_toolViewActions.append(a); m_toolMenu->addAction(a); m_toolToAction.insert(tv, a); updateActions(); } void GUIClient::unregisterToolView(ToolView *tv) { QAction *a = m_toolToAction[tv]; if (!a) { return; } m_toolViewActions.removeAt(m_toolViewActions.indexOf(a)); delete a; m_toolToAction.remove(tv); updateActions(); } void GUIClient::clientAdded(KXMLGUIClient *client) { if (client == this) { updateActions(); } } void GUIClient::updateActions() { if (!factory()) { return; } unplugActionList(actionListName); QList addList; addList.append(m_toolMenu); plugActionList(actionListName, addList); } //END GUICLIENT //BEGIN TOOLVIEW ToolView::ToolView(MainWindow *mainwin, Sidebar *sidebar, QWidget *parent) : QFrame(parent) , m_mainWin(mainwin) , m_sidebar(sidebar) - , m_toolbar(0) + , m_toolbar(nullptr) , m_toolVisible(false) , persistent(false) { // try to fix resize policy QSizePolicy policy(QSizePolicy::Preferred, QSizePolicy::Preferred); policy.setRetainSizeWhenHidden(true); setSizePolicy(policy); QVBoxLayout *layout = new QVBoxLayout(this); layout->setMargin(0); m_toolbar = new KToolBar(this); m_toolbar->setVisible(false); m_toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); } QSize ToolView::sizeHint() const { return size(); } QSize ToolView::minimumSizeHint() const { return QSize(160, 160); } ToolView::~ToolView() { m_mainWin->toolViewDeleted(this); } void ToolView::setToolVisible(bool vis) { if (m_toolVisible == vis) { return; } m_toolVisible = vis; emit toolVisibleChanged(m_toolVisible); } bool ToolView::toolVisible() const { return m_toolVisible; } void ToolView::childEvent(QChildEvent *ev) { // set the widget to be focus proxy if possible if ((ev->type() == QEvent::ChildAdded) && qobject_cast(ev->child())) { QWidget *widget = qobject_cast(ev->child()); setFocusProxy(widget); layout()->addWidget(widget); } QFrame::childEvent(ev); } void ToolView::actionEvent(QActionEvent* event) { QFrame::actionEvent(event); if (event->type() == QEvent::ActionAdded) { m_toolbar->addAction(event->action()); } else if (event->type() == QEvent::ActionRemoved) { m_toolbar->removeAction(event->action()); } m_toolbar->setVisible(!m_toolbar->actions().isEmpty()); } //END TOOLVIEW //BEGIN SIDEBAR Sidebar::Sidebar(KMultiTabBar::KMultiTabBarPosition pos, MainWindow *mainwin, QWidget *parent) : KMultiTabBar(pos, parent) , m_mainWin(mainwin) - , m_splitter(0) - , m_ownSplit(0) + , m_splitter(nullptr) + , m_ownSplit(nullptr) , m_lastSize(0) { hide(); } Sidebar::~Sidebar() {} void Sidebar::setSplitter(QSplitter *sp) { m_splitter = sp; m_ownSplit = new QSplitter((position() == KMultiTabBar::Top || position() == KMultiTabBar::Bottom) ? Qt::Horizontal : Qt::Vertical, m_splitter); m_ownSplit->setChildrenCollapsible(false); m_ownSplit->hide(); } ToolView *Sidebar::addWidget(const QIcon &icon, const QString &text, ToolView *widget) { static int id = 0; if (widget) { if (widget->sidebar() == this) { return widget; } widget->sidebar()->removeWidget(widget); } int newId = ++id; appendTab(icon, newId, text); if (!widget) { widget = new ToolView(m_mainWin, this, m_ownSplit); widget->hide(); widget->icon = icon; widget->text = text; } else { widget->hide(); widget->setParent(m_ownSplit); widget->m_sidebar = this; } // save its pos ;) widget->persistent = false; m_idToWidget.insert(newId, widget); m_widgetToId.insert(widget, newId); m_toolviews.push_back(widget); // widget => size, for correct size restoration after hide/show // starts with invalid size m_widgetToSize.insert(widget, QSize()); show(); connect(tab(newId), SIGNAL(clicked(int)), this, SLOT(tabClicked(int))); tab(newId)->installEventFilter(this); return widget; } bool Sidebar::removeWidget(ToolView *widget) { if (!m_widgetToId.contains(widget)) { return false; } removeTab(m_widgetToId[widget]); m_idToWidget.remove(m_widgetToId[widget]); m_widgetToId.remove(widget); m_widgetToSize.remove(widget); m_toolviews.removeAt(m_toolviews.indexOf(widget)); bool anyVis = false; QMapIterator it(m_idToWidget); while (it.hasNext()) { it.next(); if ((anyVis = it.value()->isVisible())) { break; } } if (m_idToWidget.isEmpty()) { m_ownSplit->hide(); hide(); } else if (!anyVis) { m_ownSplit->hide(); } return true; } bool Sidebar::showWidget(ToolView *widget) { if (!m_widgetToId.contains(widget)) { return false; } // hide other non-persistent views QMapIterator it(m_idToWidget); while (it.hasNext()) { it.next(); if ((it.value() != widget) && !it.value()->persistent) { hideWidget(it.value()); } } setTab(m_widgetToId[widget], true); /** * resize to right size again and show, else artefacts */ if (m_widgetToSize[widget].isValid()) { widget->resize(m_widgetToSize[widget]); } /** * resize to right size again and show, else artefacts * same as for widget, both needed */ if (m_preHideSize.isValid()) { widget->resize(m_preHideSize); m_ownSplit->resize(m_preHideSize); } m_ownSplit->show(); widget->show(); /** * we are visible again! */ widget->setToolVisible(true); return true; } bool Sidebar::hideWidget(ToolView *widget) { if (!m_widgetToId.contains(widget)) { return false; } bool anyVis = false; updateLastSize(); QMapIterator it(m_idToWidget); while (it.hasNext()) { it.next(); if (it.value() == widget) { // remember size and hide if (widget->isVisible()) { m_widgetToSize[widget] = widget->size(); } } else if ((anyVis = it.value()->isVisible())) { break; } } widget->hide(); // lower tab setTab(m_widgetToId[widget], false); if (!anyVis) { if (m_ownSplit->isVisible()) { m_preHideSize = m_ownSplit->size(); } m_ownSplit->hide(); } widget->setToolVisible(false); return true; } void Sidebar::tabClicked(int i) { ToolView *w = m_idToWidget[i]; if (!w) { return; } if (isTabRaised(i)) { showWidget(w); w->setFocus(); } else { hideWidget(w); } } bool Sidebar::eventFilter(QObject *obj, QEvent *ev) { if (ev->type() == QEvent::ContextMenu) { QContextMenuEvent *e = (QContextMenuEvent *) ev; KMultiTabBarTab *bt = dynamic_cast(obj); if (bt) { //qCDebug(LOG_KATE) << "Request for popup"; m_popupButton = bt->id(); ToolView *w = m_idToWidget[m_popupButton]; if (w) { QMenu *menu = new QMenu(this); if (!w->plugin.isNull()) { if (w->plugin.data()->configPages() > 0) { menu->addAction(i18n("Configure ..."))->setData(20); } } menu->addSection(QIcon::fromTheme(QStringLiteral("view_remove")), i18n("Behavior")); menu->addAction(w->persistent ? QIcon::fromTheme(QStringLiteral("view-restore")) : QIcon::fromTheme(QStringLiteral("view-fullscreen")), w->persistent ? i18n("Make Non-Persistent") : i18n("Make Persistent")) -> setData(10); menu->addSection(QIcon::fromTheme(QStringLiteral("move")), i18n("Move To")); if (position() != 0) { menu->addAction(QIcon::fromTheme(QStringLiteral("go-previous")), i18n("Left Sidebar"))->setData(0); } if (position() != 1) { menu->addAction(QIcon::fromTheme(QStringLiteral("go-next")), i18n("Right Sidebar"))->setData(1); } if (position() != 2) { menu->addAction(QIcon::fromTheme(QStringLiteral("go-up")), i18n("Top Sidebar"))->setData(2); } if (position() != 3) { menu->addAction(QIcon::fromTheme(QStringLiteral("go-down")), i18n("Bottom Sidebar"))->setData(3); } connect(menu, &QMenu::triggered, this, &Sidebar::buttonPopupActivate); menu->exec(e->globalPos()); delete menu; return true; } } } return false; } void Sidebar::setVisible(bool visible) { // visible==true means show-request if (visible && (m_idToWidget.isEmpty() || !m_mainWin->sidebarsVisible())) { return; } KMultiTabBar::setVisible(visible); } void Sidebar::buttonPopupActivate(QAction *a) { int id = a->data().toInt(); ToolView *w = m_idToWidget[m_popupButton]; if (!w) { return; } // move ids if (id < 4) { // move + show ;) m_mainWin->moveToolView(w, (KMultiTabBar::KMultiTabBarPosition) id); m_mainWin->showToolView(w); } // toggle persistent if (id == 10) { w->persistent = !w->persistent; } // configure actionCollection if (id == 20) { if (!w->plugin.isNull()) { if (w->plugin.data()->configPages() > 0) { emit sigShowPluginConfigPage(w->plugin.data(), 0); } } } } void Sidebar::updateLastSize() { QList s = m_splitter->sizes(); int i = 0; if ((position() == KMultiTabBar::Right || position() == KMultiTabBar::Bottom)) { i = 2; } // little threshold if (s[i] > 2) { m_lastSize = s[i]; } } class TmpToolViewSorter { public: ToolView *tv; unsigned int pos; }; void Sidebar::restoreSession(KConfigGroup &config) { // get the last correct placed toolview int firstWrong = 0; for (; firstWrong < m_toolviews.size(); ++firstWrong) { ToolView *tv = m_toolviews[firstWrong]; int pos = config.readEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Sidebar-Position").arg(tv->id), firstWrong); if (pos != firstWrong) { break; } } // we need to reshuffle, ahhh :( if (firstWrong < m_toolviews.size()) { // first: collect the items to reshuffle QList toSort; for (int i = firstWrong; i < m_toolviews.size(); ++i) { TmpToolViewSorter s; s.tv = m_toolviews[i]; s.pos = config.readEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Sidebar-Position").arg(m_toolviews[i]->id), i); toSort.push_back(s); } // now: sort the stuff we need to reshuffle for (int m = 0; m < toSort.size(); ++m) for (int n = m + 1; n < toSort.size(); ++n) if (toSort[n].pos < toSort[m].pos) { TmpToolViewSorter tmp = toSort[n]; toSort[n] = toSort[m]; toSort[m] = tmp; } // then: remove this items from the button bar // do this backwards, to minimize the relayout efforts for (int i = m_toolviews.size() - 1; i >= (int)firstWrong; --i) { removeTab(m_widgetToId[m_toolviews[i]]); } // insert the reshuffled things in order :) for (int i = 0; i < toSort.size(); ++i) { ToolView *tv = toSort[i].tv; m_toolviews[firstWrong + i] = tv; // readd the button int newId = m_widgetToId[tv]; appendTab(tv->icon, newId, tv->text); connect(tab(newId), SIGNAL(clicked(int)), this, SLOT(tabClicked(int))); tab(newId)->installEventFilter(this); // reshuffle in splitter: move to last m_ownSplit->addWidget(tv); } } // update last size if needed updateLastSize(); // restore the own splitter sizes QList s = config.readEntry(QString::fromLatin1("Kate-MDI-Sidebar-%1-Splitter").arg(position()), QList()); m_ownSplit->setSizes(s); // show only correct toolviews, remember persistent values ;) bool anyVis = false; for (int i = 0; i < m_toolviews.size(); ++i) { ToolView *tv = m_toolviews[i]; tv->persistent = config.readEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Persistent").arg(tv->id), false); tv->setToolVisible(config.readEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Visible").arg(tv->id), false)); if (!anyVis) { anyVis = tv->toolVisible(); } setTab(m_widgetToId[tv], tv->toolVisible()); if (tv->toolVisible()) { tv->show(); } else { tv->hide(); } } if (anyVis) { m_ownSplit->show(); } else { m_ownSplit->hide(); } } void Sidebar::saveSession(KConfigGroup &config) { // store the own splitter sizes QList s = m_ownSplit->sizes(); config.writeEntry(QString::fromLatin1("Kate-MDI-Sidebar-%1-Splitter").arg(position()), s); // store the data about all toolviews in this sidebar ;) for (int i = 0; i < m_toolviews.size(); ++i) { ToolView *tv = m_toolviews[i]; config.writeEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Position").arg(tv->id), int(tv->sidebar()->position())); config.writeEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Sidebar-Position").arg(tv->id), i); config.writeEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Visible").arg(tv->id), tv->toolVisible()); config.writeEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Persistent").arg(tv->id), tv->persistent); } } //END SIDEBAR //BEGIN MAIN WINDOW MainWindow::MainWindow(QWidget *parentWidget) : KParts::MainWindow(parentWidget, Qt::Window) , m_sidebarsVisible(true) - , m_restoreConfig(0) + , m_restoreConfig(nullptr) , m_guiClient(new GUIClient(this)) { // init the internal widgets QFrame *hb = new QFrame(this); QHBoxLayout *hlayout = new QHBoxLayout(hb); hlayout->setMargin(0); hlayout->setSpacing(0); setCentralWidget(hb); m_sidebars[KMultiTabBar::Left] = new Sidebar(KMultiTabBar::Left, this, hb); hlayout->addWidget(m_sidebars[KMultiTabBar::Left]); m_hSplitter = new QSplitter(Qt::Horizontal, hb); hlayout->addWidget(m_hSplitter); m_sidebars[KMultiTabBar::Left]->setSplitter(m_hSplitter); QFrame *vb = new QFrame(m_hSplitter); QVBoxLayout *vlayout = new QVBoxLayout(vb); vlayout->setMargin(0); vlayout->setSpacing(0); m_hSplitter->setCollapsible(m_hSplitter->indexOf(vb), false); m_hSplitter->setStretchFactor(m_hSplitter->indexOf(vb), 1); m_sidebars[KMultiTabBar::Top] = new Sidebar(KMultiTabBar::Top, this, vb); vlayout->addWidget(m_sidebars[KMultiTabBar::Top]); m_vSplitter = new QSplitter(Qt::Vertical, vb); vlayout->addWidget(m_vSplitter); m_sidebars[KMultiTabBar::Top]->setSplitter(m_vSplitter); m_centralWidget = new QWidget(m_vSplitter); m_centralWidget->setLayout(new QVBoxLayout); m_centralWidget->layout()->setSpacing(0); m_centralWidget->layout()->setMargin(0); m_vSplitter->setCollapsible(m_vSplitter->indexOf(m_centralWidget), false); m_vSplitter->setStretchFactor(m_vSplitter->indexOf(m_centralWidget), 1); m_sidebars[KMultiTabBar::Bottom] = new Sidebar(KMultiTabBar::Bottom, this, vb); vlayout->addWidget(m_sidebars[KMultiTabBar::Bottom]); m_sidebars[KMultiTabBar::Bottom]->setSplitter(m_vSplitter); m_sidebars[KMultiTabBar::Right] = new Sidebar(KMultiTabBar::Right, this, hb); hlayout->addWidget(m_sidebars[KMultiTabBar::Right]); m_sidebars[KMultiTabBar::Right]->setSplitter(m_hSplitter); for (int i = 0; i < 4; i++) { connect(m_sidebars[i], SIGNAL(sigShowPluginConfigPage(KTextEditor::Plugin*,uint)), this, SIGNAL(sigShowPluginConfigPage(KTextEditor::Plugin*,uint))); } } MainWindow::~MainWindow() { // cu toolviews qDeleteAll(m_toolviews); // seems like we really should delete this by hand ;) delete m_centralWidget; // cleanup the sidebars for (unsigned int i = 0; i < 4; ++i) { delete m_sidebars[i]; } } QWidget *MainWindow::centralWidget() const { return m_centralWidget; } ToolView *MainWindow::createToolView(KTextEditor::Plugin *plugin, const QString &identifier, KMultiTabBar::KMultiTabBarPosition pos, const QIcon &icon, const QString &text) { if (m_idToWidget[identifier]) { - return 0; + return nullptr; } // try the restore config to figure out real pos if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) { KConfigGroup cg(m_restoreConfig, m_restoreGroup); pos = (KMultiTabBar::KMultiTabBarPosition) cg.readEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Position").arg(identifier), int(pos)); } - ToolView *v = m_sidebars[pos]->addWidget(icon, text, 0); + ToolView *v = m_sidebars[pos]->addWidget(icon, text, nullptr); v->id = identifier; v->plugin = plugin; m_idToWidget.insert(identifier, v); m_toolviews.push_back(v); // register for menu stuff m_guiClient->registerToolView(v); return v; } ToolView *MainWindow::toolView(const QString &identifier) const { return m_idToWidget[identifier]; } void MainWindow::toolViewDeleted(ToolView *widget) { if (!widget) { return; } if (widget->mainWindow() != this) { return; } // unregister from menu stuff m_guiClient->unregisterToolView(widget); widget->sidebar()->removeWidget(widget); m_idToWidget.remove(widget->id); m_toolviews.removeAt(m_toolviews.indexOf(widget)); } void MainWindow::setSidebarsVisible(bool visible) { bool old_visible = m_sidebarsVisible; m_sidebarsVisible = visible; m_sidebars[0]->setVisible(visible); m_sidebars[1]->setVisible(visible); m_sidebars[2]->setVisible(visible); m_sidebars[3]->setVisible(visible); m_guiClient->updateSidebarsVisibleAction(); // show information message box, if the users hides the sidebars if (old_visible && (!m_sidebarsVisible)) { KMessageBox::information(this, i18n("You are about to hide the sidebars. With " "hidden sidebars it is not possible to directly " "access the tool views with the mouse anymore, " "so if you need to access the sidebars again " "invoke View > Tool Views > Show Sidebars " "in the menu. It is still possible to show/hide " "the tool views with the assigned shortcuts."), QString(), QStringLiteral("Kate hide sidebars notification message")); } } bool MainWindow::sidebarsVisible() const { return m_sidebarsVisible; } void MainWindow::setToolViewStyle(KMultiTabBar::KMultiTabBarStyle style) { m_sidebars[0]->setStyle(style); m_sidebars[1]->setStyle(style); m_sidebars[2]->setStyle(style); m_sidebars[3]->setStyle(style); } KMultiTabBar::KMultiTabBarStyle MainWindow::toolViewStyle() const { // all sidebars have the same style, so just take Top return m_sidebars[KMultiTabBar::Top]->tabStyle(); } bool MainWindow::moveToolView(ToolView *widget, KMultiTabBar::KMultiTabBarPosition pos) { if (!widget || widget->mainWindow() != this) { return false; } // try the restore config to figure out real pos if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) { KConfigGroup cg(m_restoreConfig, m_restoreGroup); pos = (KMultiTabBar::KMultiTabBarPosition) cg.readEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Position").arg(widget->id), int(pos)); } m_sidebars[pos]->addWidget(widget->icon, widget->text, widget); return true; } bool MainWindow::showToolView(ToolView *widget) { if (!widget || widget->mainWindow() != this) { return false; } // skip this if happens during restoring, or we will just see flicker if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) { return true; } return widget->sidebar()->showWidget(widget); } bool MainWindow::hideToolView(ToolView *widget) { if (!widget || widget->mainWindow() != this) { return false; } // skip this if happens during restoring, or we will just see flicker if (m_restoreConfig && m_restoreConfig->hasGroup(m_restoreGroup)) { return true; } const bool ret = widget->sidebar()->hideWidget(widget); m_centralWidget->setFocus(); return ret; } void MainWindow::startRestore(KConfigBase *config, const QString &group) { // first save this stuff m_restoreConfig = config; m_restoreGroup = group; if (!m_restoreConfig || !m_restoreConfig->hasGroup(m_restoreGroup)) { // if no config around, set already now sane default sizes // otherwise, set later in ::finishRestore(), since it does not work // if set already now (see bug #164438) QList hs = (QList() << 200 << 100 << 200); QList vs = (QList() << 150 << 100 << 200); m_sidebars[0]->setLastSize(hs[0]); m_sidebars[1]->setLastSize(hs[2]); m_sidebars[2]->setLastSize(vs[0]); m_sidebars[3]->setLastSize(vs[2]); m_hSplitter->setSizes(hs); m_vSplitter->setSizes(vs); return; } // apply size once, to get sizes ready ;) KConfigGroup cg(m_restoreConfig, m_restoreGroup); KWindowConfig::restoreWindowSize(windowHandle(), cg); setToolViewStyle((KMultiTabBar::KMultiTabBarStyle)cg.readEntry("Kate-MDI-Sidebar-Style", (int)toolViewStyle())); // after reading m_sidebarsVisible, update the GUI toggle action m_sidebarsVisible = cg.readEntry("Kate-MDI-Sidebar-Visible", true); m_guiClient->updateSidebarsVisibleAction(); } void MainWindow::finishRestore() { if (!m_restoreConfig) { return; } if (m_restoreConfig->hasGroup(m_restoreGroup)) { // apply all settings, like toolbar pos and more ;) KConfigGroup cg(m_restoreConfig, m_restoreGroup); applyMainWindowSettings(cg); // reshuffle toolviews only if needed for (int i = 0; i < m_toolviews.size(); ++i) { KMultiTabBar::KMultiTabBarPosition newPos = (KMultiTabBar::KMultiTabBarPosition) cg.readEntry(QString::fromLatin1("Kate-MDI-ToolView-%1-Position").arg(m_toolviews[i]->id), int(m_toolviews[i]->sidebar()->position())); if (m_toolviews[i]->sidebar()->position() != newPos) { moveToolView(m_toolviews[i], newPos); } } // restore the sidebars for (unsigned int i = 0; i < 4; ++i) { m_sidebars[i]->restoreSession(cg); } // restore splitter sizes QList hs = (QList() << 200 << 100 << 200); QList vs = (QList() << 150 << 100 << 200); // get main splitter sizes ;) hs = cg.readEntry("Kate-MDI-H-Splitter", hs); vs = cg.readEntry("Kate-MDI-V-Splitter", vs); m_sidebars[0]->setLastSize(hs[0]); m_sidebars[1]->setLastSize(hs[2]); m_sidebars[2]->setLastSize(vs[0]); m_sidebars[3]->setLastSize(vs[2]); m_hSplitter->setSizes(hs); m_vSplitter->setSizes(vs); } // clear this stuff, we are done ;) - m_restoreConfig = 0; + m_restoreConfig = nullptr; m_restoreGroup.clear(); } void MainWindow::saveSession(KConfigGroup &config) { saveMainWindowSettings(config); // save main splitter sizes ;) QList hs = m_hSplitter->sizes(); QList vs = m_vSplitter->sizes(); if (hs[0] <= 2 && !m_sidebars[0]->splitterVisible()) { hs[0] = m_sidebars[0]->lastSize(); } if (hs[2] <= 2 && !m_sidebars[1]->splitterVisible()) { hs[2] = m_sidebars[1]->lastSize(); } if (vs[0] <= 2 && !m_sidebars[2]->splitterVisible()) { vs[0] = m_sidebars[2]->lastSize(); } if (vs[2] <= 2 && !m_sidebars[3]->splitterVisible()) { vs[2] = m_sidebars[3]->lastSize(); } config.writeEntry("Kate-MDI-H-Splitter", hs); config.writeEntry("Kate-MDI-V-Splitter", vs); // save sidebar style config.writeEntry("Kate-MDI-Sidebar-Style", (int)toolViewStyle()); config.writeEntry("Kate-MDI-Sidebar-Visible", m_sidebarsVisible); // save the sidebars for (unsigned int i = 0; i < 4; ++i) { m_sidebars[i]->saveSession(config); } } //END MAIN WINDOW } // namespace KateMDI diff --git a/kate/katemdi.h b/kate/katemdi.h index 570cb21b2..680ebb338 100644 --- a/kate/katemdi.h +++ b/kate/katemdi.h @@ -1,461 +1,461 @@ /* This file is part of the KDE libraries Copyright (C) 2005 Christoph Cullmann Copyright (C) 2002, 2003 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. */ #ifndef __KATE_MDI_H__ #define __KATE_MDI_H__ #include #include #include #include #include #include #include #include #include #include #include #include class KActionMenu; class QAction; class QPixmap; class KConfigBase; namespace KTextEditor { class ConfigPageInterface; }; namespace KateMDI { class ToolView; class ToggleToolViewAction : public KToggleAction { Q_OBJECT public: ToggleToolViewAction(const QString &text, ToolView *tv, QObject *parent); virtual ~ToggleToolViewAction(); protected Q_SLOTS: void slotToggled(bool) Q_DECL_OVERRIDE; void toolVisibleChanged(bool); private: ToolView *m_tv; }; class GUIClient : public QObject, public KXMLGUIClient { Q_OBJECT public: GUIClient(class MainWindow *mw); virtual ~GUIClient(); void registerToolView(ToolView *tv); void unregisterToolView(ToolView *tv); void updateSidebarsVisibleAction(); private Q_SLOTS: void clientAdded(KXMLGUIClient *client); void updateActions(); private: MainWindow *m_mw; KToggleAction *m_showSidebarsAction; QList m_toolViewActions; QMap m_toolToAction; KActionMenu *m_toolMenu; }; class ToolView : public QFrame { Q_OBJECT friend class Sidebar; friend class MainWindow; friend class GUIClient; friend class ToggleToolViewAction; protected: /** * ToolView * Objects of this clas represent a toolview in the mainwindow * you should only add one widget as child to this toolview, it will * be automatically set to be the focus proxy of the toolview * @param mainwin main window for this toolview * @param sidebar sidebar of this toolview * @param parent parent widget, e.g. the splitter of one of the sidebars */ ToolView(class MainWindow *mainwin, class Sidebar *sidebar, QWidget *parent); public: /** * destuct me, this is allowed for all, will care itself that the toolview is removed * from the mainwindow and sidebar */ virtual ~ToolView(); Q_SIGNALS: /** * toolview hidden or shown * @param visible is this toolview made visible? */ void toolVisibleChanged(bool visible); /** * some internal methodes needed by the main window and the sidebars */ protected: MainWindow *mainWindow() { return m_mainWin; } Sidebar *sidebar() { return m_sidebar; } void setToolVisible(bool vis); public: bool toolVisible() const; QSize sizeHint() const Q_DECL_OVERRIDE; QSize minimumSizeHint() const Q_DECL_OVERRIDE; protected: void childEvent(QChildEvent *ev) Q_DECL_OVERRIDE; void actionEvent(QActionEvent *event) Q_DECL_OVERRIDE; private: MainWindow *m_mainWin; Sidebar *m_sidebar; KToolBar *m_toolbar; ///plugin this view belongs to, may be 0 QPointer plugin; /** * unique id */ QString id; /** * is visible in sidebar */ bool m_toolVisible; /** * is this view persistent? */ bool persistent; QIcon icon; QString text; }; class Sidebar : public KMultiTabBar { Q_OBJECT public: Sidebar(KMultiTabBar::KMultiTabBarPosition pos, class MainWindow *mainwin, QWidget *parent); virtual ~Sidebar(); void setSplitter(QSplitter *sp); public: ToolView *addWidget(const QIcon &icon, const QString &text, ToolView *widget); bool removeWidget(ToolView *widget); bool showWidget(ToolView *widget); bool hideWidget(ToolView *widget); void setLastSize(int s) { m_lastSize = s; } int lastSize() const { return m_lastSize; } void updateLastSize(); bool splitterVisible() const { return m_ownSplit->isVisible(); } void restoreSession(); /** * restore the current session config from given object, use current group * @param config config object to use */ void restoreSession(KConfigGroup &config); /** * save the current session config to given object, use current group * @param config config object to use */ void saveSession(KConfigGroup &config); public Q_SLOTS: // reimplemented, to block a show() call if all sidebars are forced hidden void setVisible(bool visible) Q_DECL_OVERRIDE; private Q_SLOTS: void tabClicked(int); protected: bool eventFilter(QObject *obj, QEvent *ev) Q_DECL_OVERRIDE; private Q_SLOTS: void buttonPopupActivate(QAction *); private: MainWindow *m_mainWin; KMultiTabBar::KMultiTabBarPosition m_pos; QSplitter *m_splitter; KMultiTabBar *m_tabBar; QSplitter *m_ownSplit; QMap m_idToWidget; QMap m_widgetToId; QMap m_widgetToSize; /** * list of all toolviews around in this sidebar */ QList m_toolviews; int m_lastSize; QSize m_preHideSize; int m_popupButton; Q_SIGNALS: void sigShowPluginConfigPage(KTextEditor::Plugin*configpageinterface, uint id); }; class MainWindow : public KParts::MainWindow { Q_OBJECT friend class ToolView; // // Constructor area // public: /** * Constructor */ - MainWindow(QWidget *parentWidget = 0); + MainWindow(QWidget *parentWidget = nullptr); /** * Destructor */ virtual ~MainWindow(); // // public interfaces // /** * add a given widget to the given sidebar if possible, name is very important * @param identifier unique identifier for this toolview * @param pos position for the toolview, if we are in session restore, this is only a preference * @param icon icon to use for the toolview * @param text text to use in addition to icon * @return created toolview on success or 0 */ ToolView *createToolView(KTextEditor::Plugin *plugin, const QString &identifier, KMultiTabBar::KMultiTabBarPosition pos, const QIcon &icon, const QString &text); /** * give you handle to toolview for the given name, 0 if no toolview around * @param identifier toolview name * @return toolview if existing, else 0 */ ToolView *toolView(const QString &identifier) const; /** * set the toolview's tabbar style. * @param style the tabbar style. */ void setToolViewStyle(KMultiTabBar::KMultiTabBarStyle style); /** * get the toolview's tabbar style. Call this before @p startRestore(), * otherwise you overwrite the usersettings. * @return toolview's tabbar style */ KMultiTabBar::KMultiTabBarStyle toolViewStyle() const; /** * get the sidebars' visibility. * @return false, if the sidebars' visibility is forced hidden, otherwise true */ bool sidebarsVisible() const; public Q_SLOTS: /** * set the sidebars' visibility to @p visible. If false, the sidebars * are @e always hidden. Usually you do not have to call this because * the user can set this in the menu. * @param visible sidebars visibility */ void setSidebarsVisible(bool visible); protected: /** * called by toolview destructor * @param widget toolview which is destroyed */ void toolViewDeleted(ToolView *widget); /** * central widget ;) * use this as parent for your content * this widget will get focus if a toolview is hidden * @return central widget */ QWidget *centralWidget() const; /** * modifiers for existing toolviews */ public: /** * move a toolview around * @param widget toolview to move * @param pos position to move too, during session restore, only preference * @return success */ bool moveToolView(ToolView *widget, KMultiTabBar::KMultiTabBarPosition pos); /** * show given toolview, discarded while session restore * @param widget toolview to show * @return success */ bool showToolView(ToolView *widget); /** * hide given toolview, discarded while session restore * @param widget toolview to hide * @return success */ bool hideToolView(ToolView *widget); /** * session saving and restore stuff */ public: /** * start the restore * @param config config object to use * @param group config group to use */ void startRestore(KConfigBase *config, const QString &group); /** * finish the restore */ void finishRestore(); /** * save the current session config to given object and group * @param config config object to use * @param group config group to use */ void saveSession(KConfigGroup &group); /** * internal data ;) */ private: /** * map identifiers to widgets */ QMap m_idToWidget; /** * list of all toolviews around */ QList m_toolviews; /** * widget, which is the central part of the * main window ;) */ QWidget *m_centralWidget; /** * horizontal splitter */ QSplitter *m_hSplitter; /** * vertical splitter */ QSplitter *m_vSplitter; /** * sidebars for the four sides */ Sidebar *m_sidebars[4]; /** * sidebars state. */ bool m_sidebarsVisible; /** * config object for session restore, only valid between * start and finish restore calls */ KConfigBase *m_restoreConfig; /** * restore group */ QString m_restoreGroup; /** * out guiclient */ GUIClient *m_guiClient; Q_SIGNALS: void sigShowPluginConfigPage(KTextEditor::Plugin*configpageinterface, uint id); }; } #endif diff --git a/kate/katemwmodonhddialog.cpp b/kate/katemwmodonhddialog.cpp index 98134c1b9..b8ac4ffb0 100644 --- a/kate/katemwmodonhddialog.cpp +++ b/kate/katemwmodonhddialog.cpp @@ -1,375 +1,375 @@ /* 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. --- Copyright (C) 2004, Anders Lund */ #include "katemwmodonhddialog.h" #include "kateapp.h" #include "katedocmanager.h" #include "katemainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include class KateDocItem : public QTreeWidgetItem { public: KateDocItem(KTextEditor::Document *doc, const QString &status, QTreeWidget *tw) : QTreeWidgetItem(tw), document(doc) { setText(0, doc->url().toString()); setText(1, status); if (! doc->isModified()) { setCheckState(0, Qt::Checked); } else { setCheckState(0, Qt::Unchecked); } } ~KateDocItem() {} KTextEditor::Document *document; }; KateMwModOnHdDialog::KateMwModOnHdDialog(DocVector docs, QWidget *parent, const char *name) : QDialog(parent), - m_proc(0), - m_diffFile(0), + m_proc(nullptr), + m_diffFile(nullptr), m_blockAddDocument(false) { setWindowTitle(i18n("Documents Modified on Disk")); setObjectName(QString::fromLatin1(name)); setModal(true); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); // Message QHBoxLayout *hb = new QHBoxLayout; mainLayout->addLayout(hb); // dialog text QLabel *icon = new QLabel(this); hb->addWidget(icon); icon->setPixmap(DesktopIcon(QStringLiteral("dialog-warning"))); QLabel *t = new QLabel(i18n( "The documents listed below have changed on disk.

Select one " "or more at once, and press an action button until the list is empty.

"), this); hb->addWidget(t); hb->setStretchFactor(t, 1000); // Document list twDocuments = new QTreeWidget(this); mainLayout->addWidget(twDocuments); QStringList header; header << i18n("Filename") << i18n("Status on Disk"); twDocuments->setHeaderLabels(header); twDocuments->setSelectionMode(QAbstractItemView::SingleSelection); twDocuments->setRootIsDecorated(false); m_stateTexts << QString() << i18n("Modified") << i18n("Created") << i18n("Deleted"); for (int i = 0; i < docs.size(); i++) { new KateDocItem(docs[i], m_stateTexts[(uint)KateApp::self()->documentManager()->documentInfo(docs[i])->modifiedOnDiscReason ], twDocuments); } twDocuments->header()->setStretchLastSection(false); twDocuments->header()->setSectionResizeMode(0, QHeaderView::Stretch); twDocuments->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); connect(twDocuments, &QTreeWidget::currentItemChanged, this, &KateMwModOnHdDialog::slotSelectionChanged); // Diff line hb = new QHBoxLayout; mainLayout->addLayout(hb); btnDiff = new QPushButton(QIcon::fromTheme(QStringLiteral("document-preview")), i18n("&View Difference"), this); btnDiff->setWhatsThis(i18n( "Calculates the difference between the editor contents and the disk " "file for the selected document, and shows the difference with the " "default application. Requires diff(1).")); hb->addWidget(btnDiff); connect(btnDiff, &QPushButton::clicked, this, &KateMwModOnHdDialog::slotDiff); // Dialog buttons QDialogButtonBox *buttons = new QDialogButtonBox(this); mainLayout->addWidget(buttons); QPushButton *ignoreButton = new QPushButton(QIcon::fromTheme(QStringLiteral("dialog-warning")), i18n("&Ignore Changes")); ignoreButton->setToolTip(i18n("Remove modified flag from selected documents")); buttons->addButton(ignoreButton, QDialogButtonBox::RejectRole); connect(ignoreButton, &QPushButton::clicked, this, &KateMwModOnHdDialog::slotIgnore); QPushButton *overwriteButton = new QPushButton; KGuiItem::assign(overwriteButton, KStandardGuiItem::overwrite()); overwriteButton->setToolTip(i18n("Overwrite selected documents, discarding disk changes")); buttons->addButton(overwriteButton, QDialogButtonBox::DestructiveRole); connect(overwriteButton, &QPushButton::clicked, this, &KateMwModOnHdDialog::slotOverwrite); QPushButton *reloadButton = new QPushButton(QIcon::fromTheme(QStringLiteral("view-refresh")), i18n("&Reload")); reloadButton->setDefault(true); reloadButton->setToolTip(i18n("Reload selected documents from disk")); buttons->addButton(reloadButton, QDialogButtonBox::DestructiveRole); connect(reloadButton, &QPushButton::clicked, this, &KateMwModOnHdDialog::slotReload); - slotSelectionChanged(NULL, NULL); + slotSelectionChanged(nullptr, nullptr); } KateMwModOnHdDialog::~KateMwModOnHdDialog() { KateMainWindow::unsetModifiedOnDiscDialogIfIf(this); if (m_proc) { m_proc->kill(); m_proc->waitForFinished(); delete m_proc; m_proc = Q_NULLPTR; } if (m_diffFile) { m_diffFile->setAutoRemove(true); delete m_diffFile; m_diffFile = Q_NULLPTR; } } void KateMwModOnHdDialog::slotIgnore() { handleSelected(Ignore); } void KateMwModOnHdDialog::slotOverwrite() { handleSelected(Overwrite); } void KateMwModOnHdDialog::slotReload() { handleSelected(Reload); } void KateMwModOnHdDialog::handleSelected(int action) { // don't alter the treewidget via addDocument, we modify it here! m_blockAddDocument = true; // collect all items we can remove QList itemsToDelete; for (QTreeWidgetItemIterator it(twDocuments); *it; ++it) { KateDocItem *item = (KateDocItem *) * it; if (item->checkState(0) == Qt::Checked) { KTextEditor::ModificationInterface::ModifiedOnDiskReason reason = KateApp::self()->documentManager()->documentInfo(item->document)->modifiedOnDiscReason; bool success = true; if (KTextEditor::ModificationInterface *iface = qobject_cast(item->document)) { iface->setModifiedOnDisk(KTextEditor::ModificationInterface::OnDiskUnmodified); } switch (action) { case Overwrite: success = item->document->save(); if (! success) { KMessageBox::sorry(this, i18n("Could not save the document \n'%1'", item->document->url().toString())); } break; case Reload: item->document->documentReload(); break; default: break; } if (success) { itemsToDelete.append(item); } else { if (KTextEditor::ModificationInterface *iface = qobject_cast(item->document)) { iface->setModifiedOnDisk(reason); } } } } // remove the marked items, addDocument is blocked, this is save! for (int i = 0; i < itemsToDelete.count(); ++i) { delete itemsToDelete[i]; } // any documents left unhandled? if (! twDocuments->topLevelItemCount()) { accept(); } // allow addDocument again m_blockAddDocument = false; } void KateMwModOnHdDialog::slotSelectionChanged(QTreeWidgetItem *current, QTreeWidgetItem *) { KateDocItem *currentDocItem = static_cast(current); // set the diff button enabled btnDiff->setEnabled(currentDocItem && KateApp::self()->documentManager()->documentInfo(currentDocItem->document)->modifiedOnDiscReason != KTextEditor::ModificationInterface::OnDiskDeleted); } // ### the code below is slightly modified from kdelibs/kate/part/katedialogs, // class KateModOnHdPrompt. void KateMwModOnHdDialog::slotDiff() { if (!btnDiff->isEnabled()) { // diff button already pressed, proc not finished yet return; } if (! twDocuments->currentItem()) { return; } KTextEditor::Document *doc = (static_cast(twDocuments->currentItem()))->document; // don't try to diff a deleted file if (KateApp::self()->documentManager()->documentInfo(doc)->modifiedOnDiscReason == KTextEditor::ModificationInterface::OnDiskDeleted) { return; } if (m_diffFile) { return; } m_diffFile = new QTemporaryFile(); m_diffFile->open(); // Start a KProcess that creates a diff m_proc = new KProcess(this); m_proc->setOutputChannelMode(KProcess::MergedChannels); *m_proc << QStringLiteral("diff") << QStringLiteral("-ub") << QStringLiteral("-") << doc->url().toLocalFile(); connect(m_proc, &KProcess::readyRead, this, &KateMwModOnHdDialog::slotDataAvailable); connect(m_proc, static_cast(&KProcess::finished), this, &KateMwModOnHdDialog::slotPDone); setCursor(Qt::WaitCursor); btnDiff->setEnabled(false); m_proc->start(); QTextStream ts(m_proc); int lastln = doc->lines() - 1; for (int l = 0; l < lastln; ++l) { ts << doc->line(l) << QLatin1Char('\n'); } ts << doc->line(lastln); ts.flush(); m_proc->closeWriteChannel(); } void KateMwModOnHdDialog::slotDataAvailable() { m_diffFile->write(m_proc->readAll()); } void KateMwModOnHdDialog::slotPDone() { setCursor(Qt::ArrowCursor); - slotSelectionChanged(twDocuments->currentItem(), 0); + slotSelectionChanged(twDocuments->currentItem(), nullptr); const QProcess::ExitStatus es = m_proc->exitStatus(); delete m_proc; - m_proc = 0; + m_proc = nullptr; if (es != QProcess::NormalExit) { KMessageBox::sorry(this, i18n("The diff command failed. Please make sure that " "diff(1) is installed and in your PATH."), i18n("Error Creating Diff")); delete m_diffFile; - m_diffFile = 0; + m_diffFile = nullptr; return; } if (m_diffFile->size() == 0) { KMessageBox::information(this, i18n("Ignoring amount of white space changed, the files are identical."), i18n("Diff Output")); delete m_diffFile; - m_diffFile = 0; + m_diffFile = nullptr; return; } m_diffFile->setAutoRemove(false); QUrl url = QUrl::fromLocalFile(m_diffFile->fileName()); delete m_diffFile; - m_diffFile = 0; + m_diffFile = nullptr; // KRun::runUrl should delete the file, once the client exits KRun::runUrl(url, QStringLiteral("text/x-patch"), this, true); } void KateMwModOnHdDialog::addDocument(KTextEditor::Document *doc) { // guard this e.g. during handleSelected if (m_blockAddDocument) return; for (QTreeWidgetItemIterator it(twDocuments); *it; ++it) { KateDocItem *item = (KateDocItem *) * it; if (item->document == doc) { delete item; break; } } uint reason = (uint)KateApp::self()->documentManager()->documentInfo(doc)->modifiedOnDiscReason; if (reason) { new KateDocItem(doc, m_stateTexts[reason], twDocuments); } if (! twDocuments->topLevelItemCount()) { accept(); } } void KateMwModOnHdDialog::keyPressEvent(QKeyEvent *event) { if (event->modifiers() == 0) { if (event->key() == Qt::Key_Escape) { event->accept(); return; } } QDialog::keyPressEvent(event); } void KateMwModOnHdDialog::closeEvent(QCloseEvent *e) { if (! twDocuments->topLevelItemCount()) { QDialog::closeEvent(e); } else { e->ignore(); } } diff --git a/kate/katemwmodonhddialog.h b/kate/katemwmodonhddialog.h index 9092a755e..266522bd2 100644 --- a/kate/katemwmodonhddialog.h +++ b/kate/katemwmodonhddialog.h @@ -1,72 +1,72 @@ /* Copyright (C) 2004, 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 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. */ #ifndef _KATE_MW_MODONHD_DIALOG_H_ #define _KATE_MW_MODONHD_DIALOG_H_ #include #include #include class KProcess; class QTemporaryFile; class QTreeWidget; class QTreeWidgetItem; typedef QVector DocVector; /** * A dialog for handling multiple documents modified on disk * from within KateMainWindow */ class KateMwModOnHdDialog : public QDialog { Q_OBJECT public: - explicit KateMwModOnHdDialog(DocVector docs, QWidget *parent = 0, const char *name = 0); + explicit KateMwModOnHdDialog(DocVector docs, QWidget *parent = nullptr, const char *name = nullptr); ~KateMwModOnHdDialog(); void addDocument(KTextEditor::Document *doc); private Q_SLOTS: void slotIgnore(); void slotOverwrite(); void slotReload(); void slotDiff(); void slotSelectionChanged(QTreeWidgetItem *current, QTreeWidgetItem *); void slotDataAvailable(); void slotPDone(); private: enum Action { Ignore, Overwrite, Reload }; void handleSelected(int action); class QTreeWidget *twDocuments; class QPushButton *btnDiff; KProcess *m_proc; QTemporaryFile *m_diffFile; QStringList m_stateTexts; bool m_blockAddDocument; protected: void closeEvent(QCloseEvent *e) Q_DECL_OVERRIDE; void keyPressEvent(QKeyEvent *) Q_DECL_OVERRIDE; }; #endif // _KATE_MW_MODONHD_DIALOG_H_ diff --git a/kate/katepluginmanager.cpp b/kate/katepluginmanager.cpp index 3f0f5f925..19b44eac8 100644 --- a/kate/katepluginmanager.cpp +++ b/kate/katepluginmanager.cpp @@ -1,351 +1,351 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 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 "config.h" #include "katepluginmanager.h" #include "kateapp.h" #include "katemainwindow.h" #include "katedebug.h" #include #include #include #include #include #include #include QString KatePluginInfo::saveName() const { return QFileInfo(metaData.fileName()).baseName(); } KatePluginManager::KatePluginManager(QObject *parent) : QObject(parent) { setupPluginList(); } KatePluginManager::~KatePluginManager() { // than unload the plugins unloadAllPlugins(); } void KatePluginManager::setupPluginList() { /** * get all KTextEditor/Plugins */ const QVector plugins = KPluginLoader::findPlugins(QStringLiteral("ktexteditor"), [](const KPluginMetaData & md) { return md.serviceTypes().contains(QStringLiteral("KTextEditor/Plugin")); }); /** * move them to our internal data structure * activate some plugins per default */ QSet defaultPlugins; defaultPlugins.insert (QLatin1String("katefiletreeplugin")); defaultPlugins.insert (QLatin1String("tabswitcherplugin")); defaultPlugins.insert (QLatin1String("kateprojectplugin")); defaultPlugins.insert (QLatin1String("katesearchplugin")); m_pluginList.clear(); QVectorIterator i(plugins); QSet unique; while (i.hasNext()) { KatePluginInfo info; info.metaData = i.next(); // only load plugins once, even if found multiple times! if (unique.contains(info.saveName())) continue; info.defaultLoad = defaultPlugins.contains(info.saveName()); info.load = false; info.plugin = nullptr; m_pluginList.push_back(info); unique.insert (info.saveName()); } /** * construct fast lookup map */ m_name2Plugin.clear(); for (int i = 0; i < m_pluginList.size(); ++i) { m_name2Plugin[m_pluginList[i].saveName()] = &(m_pluginList[i]); } } void KatePluginManager::loadConfig(KConfig *config) { // first: unload the plugins unloadAllPlugins(); /** * ask config object */ if (config) { KConfigGroup cg = KConfigGroup(config, QStringLiteral("Kate Plugins")); // disable all plugin if no config, beside the ones marked as default load for (int i = 0; i < m_pluginList.size(); ++i) { m_pluginList[i].load = cg.readEntry(m_pluginList[i].saveName(), m_pluginList[i].defaultLoad); } } /** * load plugins */ for (KatePluginList::iterator it = m_pluginList.begin(); it != m_pluginList.end(); ++it) { if (it->load) { /** * load plugin + trigger update of GUI for already existing main windows */ loadPlugin(&(*it)); enablePluginGUI(&(*it)); // restore config if (auto interface = qobject_cast (it->plugin)) { KConfigGroup group(config, QString::fromLatin1("Plugin:%1:").arg(it->saveName())); interface->readSessionConfig(group); } } } } void KatePluginManager::writeConfig(KConfig *config) { Q_ASSERT(config); KConfigGroup cg = KConfigGroup(config, QStringLiteral("Kate Plugins")); foreach(const KatePluginInfo & plugin, m_pluginList) { QString saveName = plugin.saveName(); cg.writeEntry(saveName, plugin.load); // save config if (auto interface = qobject_cast (plugin.plugin)) { KConfigGroup group(config, QString::fromLatin1("Plugin:%1:").arg(saveName)); interface->writeSessionConfig(group); } } } void KatePluginManager::unloadAllPlugins() { for (KatePluginList::iterator it = m_pluginList.begin(); it != m_pluginList.end(); ++it) { if (it->plugin) { unloadPlugin(&(*it)); } } } void KatePluginManager::enableAllPluginsGUI(KateMainWindow *win, KConfigBase *config) { for (KatePluginList::iterator it = m_pluginList.begin(); it != m_pluginList.end(); ++it) { if (it->plugin) { enablePluginGUI(&(*it), win, config); } } } void KatePluginManager::disableAllPluginsGUI(KateMainWindow *win) { for (KatePluginList::iterator it = m_pluginList.begin(); it != m_pluginList.end(); ++it) { if (it->plugin) { disablePluginGUI(&(*it), win); } } } bool KatePluginManager::loadPlugin(KatePluginInfo *item) { /** * try to load the plugin */ auto factory = KPluginLoader(item->metaData.fileName()).factory(); if (factory) { item->plugin = factory->create(this, QVariantList() << item->saveName()); } item->load = item->plugin != nullptr; /** * tell the world about the success */ if (item->plugin) { emit KateApp::self()->wrapper()->pluginCreated(item->saveName(), item->plugin); } return item->plugin != nullptr; } void KatePluginManager::unloadPlugin(KatePluginInfo *item) { disablePluginGUI(item); delete item->plugin; KTextEditor::Plugin *plugin = item->plugin; - item->plugin = 0L; + item->plugin = nullptr; item->load = false; emit KateApp::self()->wrapper()->pluginDeleted(item->saveName(), plugin); } void KatePluginManager::enablePluginGUI(KatePluginInfo *item, KateMainWindow *win, KConfigBase *config) { // plugin around at all? if (!item->plugin) { return; } // lookup if there is already a view for it.. QObject *createdView = nullptr; if (!win->pluginViews().contains(item->plugin)) { // create the view + try to correctly load shortcuts, if it's a GUI Client createdView = item->plugin->createView(win->wrapper()); if (createdView) { win->pluginViews().insert(item->plugin, createdView); } } // load session config if needed if (config && win->pluginViews().contains(item->plugin)) { if (auto interface = qobject_cast (win->pluginViews().value(item->plugin))) { KConfigGroup group(config, QString::fromLatin1("Plugin:%1:MainWindow:0").arg(item->saveName())); interface->readSessionConfig(group); } } if (createdView) { emit win->wrapper()->pluginViewCreated(item->saveName(), createdView); } } void KatePluginManager::enablePluginGUI(KatePluginInfo *item) { // plugin around at all? if (!item->plugin) { return; } // enable the gui for all mainwindows... for (int i = 0; i < KateApp::self()->mainWindowsCount(); i++) { - enablePluginGUI(item, KateApp::self()->mainWindow(i), 0); + enablePluginGUI(item, KateApp::self()->mainWindow(i), nullptr); } } void KatePluginManager::disablePluginGUI(KatePluginInfo *item, KateMainWindow *win) { // plugin around at all? if (!item->plugin) { return; } // lookup if there is a view for it.. if (!win->pluginViews().contains(item->plugin)) { return; } // really delete the view of this plugin QObject *deletedView = win->pluginViews().value(item->plugin); delete deletedView; win->pluginViews().remove(item->plugin); emit win->wrapper()->pluginViewDeleted(item->saveName(), deletedView); } void KatePluginManager::disablePluginGUI(KatePluginInfo *item) { // plugin around at all? if (!item->plugin) { return; } // disable the gui for all mainwindows... for (int i = 0; i < KateApp::self()->mainWindowsCount(); i++) { disablePluginGUI(item, KateApp::self()->mainWindow(i)); } } KTextEditor::Plugin *KatePluginManager::plugin(const QString &name) { /** * name known? */ if (!m_name2Plugin.contains(name)) { - return 0; + return nullptr; } /** * real plugin instance, if any ;) */ return m_name2Plugin.value(name)->plugin; } bool KatePluginManager::pluginAvailable(const QString &name) { return m_name2Plugin.contains(name); } class KTextEditor::Plugin *KatePluginManager::loadPlugin(const QString &name, bool permanent) { /** * name known? */ if (!m_name2Plugin.contains(name)) { - return 0; + return nullptr; } /** * load, bail out on error */ loadPlugin(m_name2Plugin.value(name)); if (!m_name2Plugin.value(name)->plugin) { - return 0; + return nullptr; } /** * perhaps patch not load again back to "ok, load it once again on next loadConfig" */ m_name2Plugin.value(name)->load = permanent; return m_name2Plugin.value(name)->plugin; } void KatePluginManager::unloadPlugin(const QString &name, bool permanent) { /** * name known? */ if (!m_name2Plugin.contains(name)) { return; } /** * unload */ unloadPlugin(m_name2Plugin.value(name)); /** * perhaps patch load again back to "ok, load it once again on next loadConfig" */ m_name2Plugin.value(name)->load = !permanent; } diff --git a/kate/katepluginmanager.h b/kate/katepluginmanager.h index 4274fdc5b..aac474b75 100644 --- a/kate/katepluginmanager.h +++ b/kate/katepluginmanager.h @@ -1,104 +1,104 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 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 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. */ #ifndef __KATE_PLUGINMANAGER_H__ #define __KATE_PLUGINMANAGER_H__ #include #include #include #include #include #include class KConfig; class KateMainWindow; class KatePluginInfo { public: KatePluginInfo() : load(false) , defaultLoad(false) , plugin(nullptr) {} bool load; bool defaultLoad; KPluginMetaData metaData; KTextEditor::Plugin *plugin; QString saveName() const; }; typedef QList KatePluginList; class KatePluginManager : public QObject { Q_OBJECT public: KatePluginManager(QObject *parent); ~KatePluginManager(); void unloadAllPlugins(); - void enableAllPluginsGUI(KateMainWindow *win, KConfigBase *config = 0); + void enableAllPluginsGUI(KateMainWindow *win, KConfigBase *config = nullptr); void disableAllPluginsGUI(KateMainWindow *win); void loadConfig(KConfig *); void writeConfig(KConfig *); bool loadPlugin(KatePluginInfo *item); void unloadPlugin(KatePluginInfo *item); - void enablePluginGUI(KatePluginInfo *item, KateMainWindow *win, KConfigBase *config = 0); + void enablePluginGUI(KatePluginInfo *item, KateMainWindow *win, KConfigBase *config = nullptr); void enablePluginGUI(KatePluginInfo *item); void disablePluginGUI(KatePluginInfo *item, KateMainWindow *win); void disablePluginGUI(KatePluginInfo *item); inline KatePluginList &pluginList() { return m_pluginList; } KTextEditor::Plugin *plugin(const QString &name); bool pluginAvailable(const QString &name); KTextEditor::Plugin *loadPlugin(const QString &name, bool permanent = true); void unloadPlugin(const QString &name, bool permanent = true); private: void setupPluginList(); /** * all known plugins */ KatePluginList m_pluginList; /** * fast access map from name => plugin info * uses the info stored in the plugin list */ QMap m_name2Plugin; }; #endif diff --git a/kate/katetabbar.cpp b/kate/katetabbar.cpp index 3d17c3ca6..9aed55240 100644 --- a/kate/katetabbar.cpp +++ b/kate/katetabbar.cpp @@ -1,595 +1,595 @@ /* 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 "katetabbar.h" #include "katetabbutton.h" #include // ceil // #include #include #include #include #include #include class KateTabBarPrivate { public: // pointer to tabbar KateTabBar *q; // minimum and maximum tab width int minimumTabWidth; int maximumTabWidth; // current tab width: when closing tabs with the mouse, we keep // the tab width fixed until the mouse leaves the tab bar. This // way the user can keep clicking the close button without moving // the ouse. qreal currentTabWidth; bool keepTabWidth; bool isActive; QVector tabButtons; QHash idToTab; KateTabButton *activeButton; int nextID; public: // functions /** * Set tab geometry. The tabs are animated only if @p animate is @e true. */ void updateButtonPositions(bool animate = false) { // if there are no tabs there is nothing to do if (tabButtons.count() == 0) { return; } // check whether an animation is still running, in that case, // continue animations to avoid jumping tabs const int maxi = tabButtons.size(); if (!animate) { for (int i = 0; i < maxi; ++i) { if (tabButtons.value(i)->geometryAnimationRunning()) { animate = true; break; } } } const int barWidth = q->width(); const int maxCount = q->maxTabCount(); // how many tabs do we show? const int visibleTabCount = qMin(q->count(), maxCount); // new tab width of each tab qreal tabWidth; const bool keepWidth = keepTabWidth && ceil(currentTabWidth) * visibleTabCount < barWidth; if (keepWidth) { // only keep tab width if the tabs still fit tabWidth = currentTabWidth; } else { tabWidth = qMin(static_cast(barWidth) / visibleTabCount, static_cast(maximumTabWidth)); } // if the last tab was closed through the close button, make sure the // close button of the new tab is again under the mouse if (keepWidth) { const int xPos = q->mapFromGlobal(QCursor::pos()).x(); if (tabWidth * visibleTabCount < xPos) { tabWidth = qMin(static_cast(tabWidth * (visibleTabCount + 1.0)) / visibleTabCount, static_cast(maximumTabWidth)); } } // now save the current tab width for future adaptation currentTabWidth = tabWidth; // now set the sizes const int w = ceil(tabWidth); const int h = q->height(); for (int i = 0; i < maxi; ++i) { KateTabButton *tabButton = tabButtons.value(i); if (i >= maxCount) { tabButton->hide(); } else { QRect endGeometry(i * tabWidth, 0, w, h); if (i > 0) { // make sure the tab button starts exactly next to the previous tab (avoid rounding errors) endGeometry.setLeft((i-1) * tabWidth + w); } if (animate) { const QRect startGeometry = tabButton->isVisible() ? tabButton->geometry() : QRect(i * tabWidth, 0, 0, h); tabButton->setAnimatedGeometry(startGeometry, endGeometry); } else { // two times endGeometry. Takes care of stopping a running animation tabButton->setAnimatedGeometry(endGeometry, endGeometry); } tabButton->show(); } } } }; /** * Creates a new tab bar with the given \a parent. */ KateTabBar::KateTabBar(QWidget *parent) : QWidget(parent) , d(new KateTabBarPrivate()) { d->q = this; d->minimumTabWidth = 150; d->maximumTabWidth = 350; d->currentTabWidth = 350; d->keepTabWidth = false; d->isActive = false; d->activeButton = nullptr; d->nextID = 0; setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); setAcceptDrops(true); } /** * Destroys the tab bar. */ KateTabBar::~KateTabBar() { delete d; } void KateTabBar::setActive(bool active) { if (active != d->isActive) { d->isActive = active; update(); } } bool KateTabBar::isActive() const { return d->isActive; } int KateTabBar::addTab(const QString &text) { return insertTab(d->tabButtons.size(), text); } int KateTabBar::insertTab(int position, const QString & text) { Q_ASSERT(position <= d->tabButtons.size()); // -1 is append if (position < 0) { position = d->tabButtons.size(); } KateTabButton *tabButton = new KateTabButton(text, this); d->tabButtons.insert(position, tabButton); d->idToTab[d->nextID] = tabButton; connect(tabButton, &KateTabButton::activated, this, &KateTabBar::tabButtonActivated); connect(tabButton, &KateTabButton::closeRequest, this, &KateTabBar::tabButtonCloseRequest); // abort potential keeping of width d->keepTabWidth = false; d->updateButtonPositions(true); return d->nextID++; } int KateTabBar::currentTab() const { return d->idToTab.key(d->activeButton, -1); } void KateTabBar::setCurrentTab(int id) { Q_ASSERT(d->idToTab.contains(id)); KateTabButton *tabButton = d->idToTab.value(id, nullptr); if (d->activeButton == tabButton) { return; } if (d->activeButton) { d->activeButton->setChecked(false); } d->activeButton = tabButton; if (d->activeButton) { d->activeButton->setChecked(true); } } int KateTabBar::prevTab() const { const int curId = currentTab(); if (curId >= 0) { KateTabButton *tabButton = d->idToTab.value(curId, nullptr); const int index = d->tabButtons.indexOf(tabButton); Q_ASSERT(index >= 0); if (index > 0) { return d->idToTab.key(d->tabButtons[index - 1], -1); } else if (count() > 1) { // cycle through tabbar return d->idToTab.key(d->tabButtons.last(), -1); } } return -1; } int KateTabBar::nextTab() const { const int curId = currentTab(); if (curId >= 0) { KateTabButton *tabButton = d->idToTab.value(curId, nullptr); const int index = d->tabButtons.indexOf(tabButton); Q_ASSERT(index >= 0); if (index < d->tabButtons.size() - 1) { return d->idToTab.key(d->tabButtons[index + 1], -1); } else if (count() > 1) { // cycle through tabbar return d->idToTab.key(d->tabButtons.first(), -1); } } return -1; } int KateTabBar::removeTab(int id) { Q_ASSERT(d->idToTab.contains(id)); KateTabButton *tabButton = d->idToTab.value(id, nullptr); if (tabButton == d->activeButton) { d->activeButton = Q_NULLPTR; } const int position = d->tabButtons.indexOf(tabButton); if (position != -1) { d->idToTab.remove(id); d->tabButtons.removeAt(position); } if (tabButton) { // delete the button with deleteLater() because the button itself might // have send a close-request. So the app-execution is still in the // button, a delete tabButton; would lead to a crash. tabButton->hide(); tabButton->deleteLater(); } d->updateButtonPositions(true); return position; } bool KateTabBar::containsTab(int id) const { return d->idToTab.contains(id); } void KateTabBar::setTabText(int id, const QString &text) { Q_ASSERT(d->idToTab.contains(id)); KateTabButton * tabButton = d->idToTab.value(id, nullptr); if (tabButton) { tabButton->setText(text); } } QString KateTabBar::tabText(int id) const { Q_ASSERT(d->idToTab.contains(id)); KateTabButton * tabButton = d->idToTab.value(id, nullptr); if (tabButton) { return tabButton->text(); } return QString(); } void KateTabBar::setTabToolTip(int id, const QString &tip) { Q_ASSERT(d->idToTab.contains(id)); KateTabButton * tabButton = d->idToTab.value(id, nullptr); if (tabButton) { tabButton->setToolTip(tip); } } QString KateTabBar::tabToolTip(int id) const { Q_ASSERT(d->idToTab.contains(id)); KateTabButton * tabButton = d->idToTab.value(id, nullptr); if (tabButton) { return tabButton->toolTip(); } return QString(); } void KateTabBar::setTabUrl(int id, const QUrl &url) { Q_ASSERT(d->idToTab.contains(id)); KateTabButton * tabButton = d->idToTab.value(id, nullptr); if (tabButton) { tabButton->setUrl(url); } } QUrl KateTabBar::tabUrl(int id) const { Q_ASSERT(d->idToTab.contains(id)); KateTabButton * tabButton = d->idToTab.value(id, nullptr); if (tabButton) { return tabButton->url(); } return QUrl(); } void KateTabBar::setTabIcon(int id, const QIcon &icon) { Q_ASSERT(d->idToTab.contains(id)); KateTabButton * tabButton = d->idToTab.value(id, nullptr); if (tabButton) { tabButton->setIcon(icon); } } QIcon KateTabBar::tabIcon(int id) const { Q_ASSERT(d->idToTab.contains(id)); KateTabButton * tabButton = d->idToTab.value(id, nullptr); if (tabButton) { return tabButton->icon(); } return QIcon(); } int KateTabBar::count() const { return d->tabButtons.count(); } void KateTabBar::tabButtonActivated(KateTabButton *tabButton) { if (!tabButton) { return; } if (tabButton == d->activeButton) { // make sure we are the currently active view space if (! isActive()) { emit activateViewSpaceRequested(); } return; } if (d->activeButton) { d->activeButton->setChecked(false); } d->activeButton = tabButton; d->activeButton->setChecked(true); const int id = d->idToTab.key(d->activeButton, -1); Q_ASSERT(id >= 0); if (id >= 0) { emit currentChanged(id); } } void KateTabBar::tabButtonCloseRequest(KateTabButton *tabButton) { // keep width if (underMouse()) { d->keepTabWidth = true; } const int id = d->idToTab.key(tabButton, -1); Q_ASSERT(id >= 0); if (id >= 0) { emit closeTabRequested(id); } } void KateTabBar::resizeEvent(QResizeEvent *event) { Q_UNUSED(event) // fix button positions if (!d->keepTabWidth || event->size().width() < event->oldSize().width()) { d->updateButtonPositions(); } const int tabDiff = maxTabCount() - d->tabButtons.size(); if (tabDiff > 0) { emit moreTabsRequested(tabDiff); } else if (tabDiff < 0) { emit lessTabsRequested(-tabDiff); } } int KateTabBar::maxTabCount() const { return qMax(1, width() / d->minimumTabWidth); } void KateTabBar::mouseDoubleClickEvent(QMouseEvent *event) { event->accept(); emit newTabRequested(); } void KateTabBar::mousePressEvent(QMouseEvent *event) { if (! isActive()) { emit activateViewSpaceRequested(); } QWidget::mousePressEvent(event); } void KateTabBar::leaveEvent(QEvent *event) { if (d->keepTabWidth) { d->keepTabWidth = false; d->updateButtonPositions(true); } QWidget::leaveEvent(event); } void KateTabBar::paintEvent(QPaintEvent *event) { Q_UNUSED(event) const int buttonCount = d->tabButtons.size(); if (buttonCount < 1) { return; } // draw separators QStyleOption option; option.initFrom(d->tabButtons[0]); option.state |= QStyle::State_Horizontal; - const int w = style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, 0, this); + const int w = style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, nullptr, this); const int offset = w / 2; option.rect.setWidth(w); option.rect.moveTop(0); QPainter painter(this); // first separator option.rect.moveLeft(d->tabButtons[0]->geometry().left() - offset); style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &option, &painter); // all other separators for (int i = 0; i < buttonCount; ++i) { option.rect.moveLeft(d->tabButtons[i]->geometry().right() - offset); style()->drawPrimitive(QStyle::PE_IndicatorToolBarSeparator, &option, &painter); } } void KateTabBar::contextMenuEvent(QContextMenuEvent *ev) { int id = -1; foreach (KateTabButton * button, d->tabButtons) { if (button->rect().contains(button->mapFromGlobal(ev->globalPos()))) { id = d->idToTab.key(button, -1); Q_ASSERT(id >= 0); break; } } if (id >= 0) { emit contextMenuRequest(id, ev->globalPos()); } } void KateTabBar::wheelEvent(QWheelEvent * event) { event->accept(); // cycle through the tabs const int delta = event->angleDelta().x() + event->angleDelta().y(); const int id = (delta > 0) ? prevTab() : nextTab(); if (id >= 0) { Q_ASSERT(d->idToTab.contains(id)); KateTabButton *tabButton = d->idToTab.value(id, nullptr); if (tabButton) { tabButtonActivated(tabButton); } } } void KateTabBar::dragEnterEvent(QDragEnterEvent *event) { const bool sameApplication = event->source() != nullptr; if (sameApplication && event->mimeData()->hasFormat(QStringLiteral("application/x-dndkatetabbutton"))) { if (event->source()->parent() == this) { event->setDropAction(Qt::MoveAction); event->accept(); } else { // possibly dragged from another tabbar (not yet implemented) event->ignore(); } } else { event->ignore(); } } void KateTabBar::dragMoveEvent(QDragMoveEvent *event) { // first of all, make sure the dragged button is from this tabbar auto button = qobject_cast(event->source()); if (!button) { event->ignore(); return; } // save old tab position const int oldButtonIndex = d->tabButtons.indexOf(button); d->tabButtons.removeAt(oldButtonIndex); // find new position const qreal currentPos = event->pos().x(); int index = d->tabButtons.size(); for (int i = 0; i < d->tabButtons.size(); ++i) { auto tab = d->tabButtons[i]; if (tab->geometry().center().x() > currentPos) { index = i; break; } } d->tabButtons.insert(index, button); // trigger rearrange if required if (oldButtonIndex != index) { d->updateButtonPositions(true); } event->accept(); } void KateTabBar::dropEvent(QDropEvent *event) { // no action required event->acceptProposedAction(); } diff --git a/kate/katetabbar.h b/kate/katetabbar.h index 2f7b91a1f..66926c8a6 100644 --- a/kate/katetabbar.h +++ b/kate/katetabbar.h @@ -1,262 +1,262 @@ /* 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. */ #ifndef KATE_TAB_BAR_H #define KATE_TAB_BAR_H #include #include #include #include class KateTabButton; class KateTabBarPrivate; /** * The \p KateTabBar class provides a tab bar, e.g. for tabbed documents. * * The API closely follows the API of QTabBar. * * @author Dominik Haumann */ class KateTabBar : public QWidget { Q_OBJECT Q_PROPERTY(bool isActive READ isActive WRITE setActive) public: - explicit KateTabBar(QWidget *parent = 0); + explicit KateTabBar(QWidget *parent = nullptr); virtual ~KateTabBar(); /** * Adds a new tab with \a text. Returns the new tab's id. */ int addTab(const QString &text); /** * Insert a tab at \p position with \a text. Returns the new tab's id. * @param position index of the tab, i.e. 0, ..., count() */ int insertTab(int position, const QString & text); /** * Removes the tab with ID \a id. * @return the position where the tab was */ int removeTab(int index); /** * Get the ID of the tab bar's activated tab. Returns -1 if no tab is activated. */ int currentTab() const; /** * Get the ID of the tab that is located left of the current tab. * The return value is -1, if there is no previous tab. */ int prevTab() const; /** * Get the ID of the tab that is located right of the current tab. * The return value is -1, if there is no next tab. */ int nextTab() const; public Q_SLOTS: /** * Activate the tab with \p id. No signal is emitted. */ void setCurrentTab(int index); // does not emit signal public: /** * Returns whether a tab with ID \a id exists. */ bool containsTab(int index) const; /** * Set the button @p id's tool tip to @p tip. */ void setTabToolTip(int index, const QString &tip); /** * Get the button @p id's url. Result is QStrint() if not available. */ QString tabToolTip(int index) const; /** * Sets the text of the tab with ID \a id to \a text. * \see tabText() */ void setTabText(int index, const QString &text); /** * Returns the text of the tab with ID \a id. If the button id does not * exist \a QString() is returned. * \see setTabText() */ QString tabText(int index) const; /** * Sets the URL of the tab with ID \a id to \a url. * \see tabUrl() * \since 17.08 */ void setTabUrl(int index, const QUrl &url); /** * Returns the text of the tab with ID \a id. If the button id does not * exist \a QString() is returned. * \see setTabUrl() * \since 17.08 */ QUrl tabUrl(int index) const; /** * Sets the icon of the tab with ID \a id to \a icon. * \see tabIcon() */ void setTabIcon(int index, const QIcon &pixmap); /** * Returns the icon of the tab with ID \a id. If the button id does not * exist \a QIcon() is returned. * \see setTabIcon() */ QIcon tabIcon(int index) const; /** * Returns the number of tabs in the tab bar. */ int count() const; /** * Return the maximum amount of tabs that fit into the tab bar given * the minimumTabWidth(). */ int maxTabCount() const; /** * Marks this tabbar as active. That is, current-tab indicators are * properly highlighted, indicating that child widgets of this tabbar * will get input. * * This concept is mostly useful, if your application has multiple tabbars. * Inactive tabbars are grayed out. */ void setActive(bool active); /** * Returns whether this tabbar is active. */ bool isActive() const; Q_SIGNALS: /** * This signal is emitted whenever the current activated tab changes. */ void currentChanged(int id); /** * This signal is emitted whenever tab @p id should be closed. */ void closeTabRequested(int id); /** * This signal is emitted whenever the context menu is requested for * button @p id at position @p globalPos. * @param id the button, or -1 if the context menu was requested on * at a place where no tab exists * @param globalPos the position of the context menu in global coordinates */ void contextMenuRequest(int id, const QPoint & globalPos); /** * This signal is emitted whenever the tab bar's width allows to * show more tabs than currently available. In other words, * you can safely add @p count tabs which are guaranteed to be visible. */ void moreTabsRequested(int count); /** * This signal is emitted whenever the tab bar's width is too small, * such that not all tabs can be shown. * Therefore, @p count tabs should be removed. */ void lessTabsRequested(int count); /** * This signal is emitted whenever the users double clicks on the free * space next to the tab bar. Typically, a new document should be * created. */ void newTabRequested(); /** * This signal is emitted whenever the tab bar was clicked while the * tab bar is not the active view space tab bar. */ void activateViewSpaceRequested(); protected Q_SLOTS: /** * Active button changed. Emit signal \p currentChanged() with the button's ID. */ void tabButtonActivated(KateTabButton *tabButton); /** * If the user wants to close a tab with the context menu, it sends a close * request. */ void tabButtonCloseRequest(KateTabButton *tabButton); protected: //! Recalculate geometry for all tabs. void resizeEvent(QResizeEvent *event) override; //! Override to avoid requesting a new tab. void mouseDoubleClickEvent(QMouseEvent *event) override; //! Override to request making the tab bar active. void mousePressEvent(QMouseEvent *event) override; //! trigger repaint on hover leave event void leaveEvent(QEvent *event) override; //! Paint tab separators void paintEvent(QPaintEvent *event) override; //! Request context menu void contextMenuEvent(QContextMenuEvent *ev) override; //! Cycle through tabs void wheelEvent(QWheelEvent * event) override; //! Support for drag & drop of tabs void dragEnterEvent(QDragEnterEvent *event) override; void dragMoveEvent(QDragMoveEvent *event) override; void dropEvent(QDropEvent *event) override; private: // pimpl data holder KateTabBarPrivate * const d; }; #endif // KATE_TAB_BAR_H diff --git a/kate/katetabbutton.cpp b/kate/katetabbutton.cpp index c50aa7bc2..dd999df34 100644 --- a/kate/katetabbutton.cpp +++ b/kate/katetabbutton.cpp @@ -1,303 +1,303 @@ /* 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 "katetabbutton.h" #include #include // #include #include #include #include #include #include #include #include #include #include #include TabCloseButton::TabCloseButton(QWidget * parent) : QAbstractButton(parent) { // should never have focus setFocusPolicy(Qt::NoFocus); // closing a tab closes the document setToolTip(i18n("Close Document")); } void TabCloseButton::paintEvent(QPaintEvent *event) { Q_UNUSED(event) // get the tab this close button belongs to KateTabButton *tabButton = qobject_cast(parent()); const bool isActive = underMouse() || (tabButton && tabButton->isChecked()); // set style options depending on current state QStyleOption opt; opt.init(this); if (isActive && !isChecked()) { opt.state |= QStyle::State_Raised; } if (isChecked()) { opt.state |= QStyle::State_Sunken; } QPainter p(this); style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &p, this); } QSize TabCloseButton::sizeHint() const { // make sure the widget is polished ensurePolished(); // read the metrics from the style - const int w = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, 0, this); - const int h = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, 0, this); + const int w = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, nullptr, this); + const int h = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, nullptr, this); return QSize(w, h); } void TabCloseButton::enterEvent(QEvent *event) { update(); // repaint on hover QAbstractButton::enterEvent(event); } void TabCloseButton::leaveEvent(QEvent *event) { update(); // repaint on hover QAbstractButton::leaveEvent(event); } KateTabButton::KateTabButton(const QString &text, QWidget *parent) : QAbstractButton(parent) - , m_geometryAnimation(0) + , m_geometryAnimation(nullptr) { setCheckable(true); setFocusPolicy(Qt::NoFocus); setText(text); // add close button - const int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, 0, this); + const int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, nullptr, this); m_closeButton = new TabCloseButton(this); QHBoxLayout * hbox = new QHBoxLayout(this); hbox->setSpacing(0); hbox->setContentsMargins(margin, 0, margin, 0); hbox->addStretch(); hbox->addWidget(m_closeButton); setLayout(hbox); connect(m_closeButton, &TabCloseButton::clicked, this, &KateTabButton::closeButtonClicked); } void KateTabButton::closeButtonClicked() { emit closeRequest(this); } void KateTabButton::paintEvent(QPaintEvent *ev) { Q_UNUSED(ev) QColor barColor(palette().color(QPalette::Highlight)); // read from the parent widget (=KateTabBar) the isActiveTabBar property if (!isActiveTabBar()) { // if inactive, convert color to gray value const int g = qGray(barColor.rgb()); barColor = QColor(g, g, g); } // compute sane margins - const int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, 0, this); + const int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, nullptr, this); const int barMargin = margin / 2; const int barHeight = ceil(height() / 10.0); QPainter p(this); // paint bar if inactive but hovered if (!isChecked() && underMouse()) { barColor.setAlpha(80); p.fillRect(QRect(barMargin, height() - barHeight, width() - 2 * barMargin, barHeight), barColor); } // paint bar if (isChecked()) { barColor.setAlpha(255); p.fillRect(QRect(barMargin, height() - barHeight, width() - 2 * barMargin, barHeight), barColor); } // icon, if applicable int leftMargin = margin; if (! icon().isNull()) { const int y = (height() - 16) / 2; icon().paint(&p, margin, y, 16, 16); leftMargin += 16; leftMargin += margin; } // the width of the text is reduced by the close button + 2 * margin const int w = width() // width of widget - m_closeButton->width() - 2 * margin // close button - leftMargin; // modified button // draw text, we need to elide to xxx...xxx is too long const QString elidedText = QFontMetrics(font()).elidedText (text(), Qt::ElideMiddle, w); const QRect textRect(leftMargin, 0, w, height()); const QPalette pal = QApplication::palette(); style()->drawItemText(&p, textRect, Qt::AlignHCenter | Qt::AlignVCenter, pal, true, elidedText, QPalette::WindowText); } void KateTabButton::mousePressEvent(QMouseEvent *ev) { ev->accept(); // save mouse position for possible drag start event m_mouseDownPosition = ev->globalPos(); // activation code if (ev->button() == Qt::LeftButton) { if (! isChecked()) { // make sure we stay checked setChecked(true); } // notify that this button was activated emit activated(this); } else if (ev->button() == Qt::MiddleButton) { emit closeRequest(this); } else { ev->ignore(); } } void KateTabButton::mouseMoveEvent(QMouseEvent *event) { // possibly start drag event if (QPoint(event->globalPos() - m_mouseDownPosition).manhattanLength() > QApplication::startDragDistance()) { QMimeData *mimeData = new QMimeData; mimeData->setData(QStringLiteral("application/x-dndkatetabbutton"), QByteArray()); mimeData->setUrls({m_url}); auto drag = new QDrag(this); drag->setMimeData(mimeData); drag->setDragCursor(QPixmap(), Qt::MoveAction); drag->start(Qt::MoveAction); event->accept(); } QAbstractButton::mouseMoveEvent(event); } void KateTabButton::mouseDoubleClickEvent(QMouseEvent *event) { event->accept(); } void KateTabButton::enterEvent(QEvent *event) { update(); // repaint on hover QAbstractButton::enterEvent(event); } void KateTabButton::leaveEvent(QEvent *event) { update(); // repaint on hover QAbstractButton::leaveEvent(event); } void KateTabButton::moveEvent(QMoveEvent *event) { // tell the tabbar to redraw its separators. Since the separators overlap // the tab buttons geometry, we need to adjust the width by the separator's // width to avoid artifacts if (parentWidget()) { - const int w = style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, 0, this); + const int w = style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, nullptr, this); QRect rect = geometry(); rect.moveLeft(event->oldPos().x()); rect.adjust(-w, 0, w, 0); parentWidget()->update(rect); } QAbstractButton::moveEvent(event); } bool KateTabButton::isActiveTabBar() const { Q_ASSERT(parentWidget()); // read from the parent widget (=KateTabBar) the isActive property return parentWidget()->property("isActive").toBool(); } void KateTabButton::setAnimatedGeometry(const QRect & startGeom, const QRect & endGeom) { // stop animation in case it is running if (m_geometryAnimation && m_geometryAnimation->state() != QAbstractAnimation::Stopped) { m_geometryAnimation->stop(); } // already at desired position if (startGeom == geometry() && endGeom == startGeom) { return; } // if the style does not want animations, just set geometry - if (! style()->styleHint(QStyle::SH_Widget_Animate, 0, this) + if (! style()->styleHint(QStyle::SH_Widget_Animate, nullptr, this) || (isVisible() && endGeom == startGeom)) { setGeometry(endGeom); return; } if (! m_geometryAnimation) { m_geometryAnimation = new QPropertyAnimation(this, "geometry", this); m_geometryAnimation->setDuration(100); } // finally start geometry animation m_geometryAnimation->setStartValue(startGeom); m_geometryAnimation->setEndValue(endGeom); m_geometryAnimation->start(); } bool KateTabButton::geometryAnimationRunning() const { return m_geometryAnimation && (m_geometryAnimation->state() != QAbstractAnimation::Stopped); } QUrl KateTabButton::url() const { return m_url; } void KateTabButton::setUrl(const QUrl &url) { m_url = url; } diff --git a/kate/katetabbutton.h b/kate/katetabbutton.h index 8888da3c7..1029049b9 100644 --- a/kate/katetabbutton.h +++ b/kate/katetabbutton.h @@ -1,135 +1,135 @@ /* 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. */ #ifndef KATE_TAB_BUTTON #define KATE_TAB_BUTTON #include #include class QPropertyAnimation; class TabCloseButton : public QAbstractButton { Q_OBJECT public: // constructor - TabCloseButton(QWidget * parent = 0); + TabCloseButton(QWidget * parent = nullptr); // paint close button depending on its state void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; // returns the size hint depending on the style QSize sizeHint() const Q_DECL_OVERRIDE; protected: void enterEvent(QEvent *event) Q_DECL_OVERRIDE; void leaveEvent(QEvent *event) Q_DECL_OVERRIDE; }; /** * A \p KateTabButton represents a button on the tab bar. It can either be * \e activated or \e deactivated. If the state is \e deactivated it will * be @e activated when the mouse is pressed. It then emits the signal * @p activated(). The \p KateTabButton's text can be set with \p setText() * and an additional icon can be shown with \p setIcon(). * * @author Dominik Haumann */ class KateTabButton : public QAbstractButton { Q_OBJECT public: /** * Constructs a new tab bar button with \a text and \a parent. */ - KateTabButton(const QString &text, QWidget *parent = 0); + KateTabButton(const QString &text, QWidget *parent = nullptr); /** * Returns @e true, if the tabbar is the currently active tab bar. */ bool isActiveTabBar() const; /** * Check whether a geometry animation is running. */ bool geometryAnimationRunning() const; /** * The URL of the document this tab represents. * \since 17.08 */ QUrl url() const; /** * Sets the URL of the document this tab represents. * \since 17.08 */ void setUrl(const QUrl &url); public Q_SLOTS: /** * Animate the button's geometry from @p startGeom to @p endGeom * with linear interpolation. */ void setAnimatedGeometry(const QRect & startGeom, const QRect & endGeom); Q_SIGNALS: /** * Emitted whenever the button changes state from deactivated to activated, * or when the button was clicked although it was already active. * @param tabbutton the pressed button (this) */ void activated(KateTabButton *tabbutton); /** * Emitted whenever the user wants to close the tab button. * @param tabbutton the button that emitted this signal */ void closeRequest(KateTabButton *tabbutton); protected Q_SLOTS: void closeButtonClicked(); protected: /** paint eyecandy rectangles around the button */ void paintEvent(QPaintEvent *ev) override; /** activate, and for drag & drop */ void mousePressEvent(QMouseEvent *ev) override; /** possibly start drag event */ void mouseMoveEvent(QMouseEvent *event) override; /** eat double click events */ void mouseDoubleClickEvent(QMouseEvent *event) override; /** trigger repaint on hover enter event */ void enterEvent(QEvent *event) override; /** trigger repaint on hover leave event */ void leaveEvent(QEvent *event) override; /** track geometry changes to trigger proper repaint*/ void moveEvent(QMoveEvent *event) override; private: TabCloseButton * m_closeButton; QPropertyAnimation * m_geometryAnimation; QPoint m_mouseDownPosition; QUrl m_url; }; #endif diff --git a/kate/kateviewmanager.cpp b/kate/kateviewmanager.cpp index 1c99f1c14..4fc4bd81c 100644 --- a/kate/kateviewmanager.cpp +++ b/kate/kateviewmanager.cpp @@ -1,1241 +1,1241 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 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. */ //BEGIN Includes #include "kateviewmanager.h" #include "kateapp.h" #include "katemainwindow.h" #include "kateviewspace.h" #include "kateupdatedisabler.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KActivities_FOUND #include #endif #include #include //END Includes static const qint64 FileSizeAboveToAskUserIfProceedWithOpen = 10 * 1024 * 1024; // 10MB should suffice KateViewManager::KateViewManager(QWidget *parentW, KateMainWindow *parent) : QSplitter(parentW) , m_mainWindow(parent) , m_blockViewCreationAndActivation(false) , m_activeViewRunning(false) , m_minAge(0) , m_guiMergedView(nullptr) { // while init m_init = true; // important, set them up, as we use them in other methodes setupActions(); - KateViewSpace *vs = new KateViewSpace(this, 0); + KateViewSpace *vs = new KateViewSpace(this, nullptr); addWidget(vs); vs->setActive(true); m_viewSpaceList.append(vs); connect(this, SIGNAL(viewChanged(KTextEditor::View*)), this, SLOT(slotViewChanged())); connect(KateApp::self()->documentManager(), SIGNAL(documentCreatedViewManager(KTextEditor::Document*)), this, SLOT(documentCreated(KTextEditor::Document*))); /** * before document is really deleted: cleanup all views! */ connect(KateApp::self()->documentManager(), SIGNAL(documentWillBeDeleted(KTextEditor::Document*)) , this, SLOT(documentWillBeDeleted(KTextEditor::Document*))); /** * handle document deletion transactions * disable view creation in between * afterwards ensure we have views ;) */ connect(KateApp::self()->documentManager(), SIGNAL(aboutToDeleteDocuments(const QList &)) , this, SLOT(aboutToDeleteDocuments(const QList &))); connect(KateApp::self()->documentManager(), SIGNAL(documentsDeleted(const QList &)) , this, SLOT(documentsDeleted(const QList &))); // register all already existing documents m_blockViewCreationAndActivation = true; const QList &docs = KateApp::self()->documentManager()->documentList(); foreach(KTextEditor::Document * doc, docs) { documentCreated(doc); } m_blockViewCreationAndActivation = false; // init done m_init = false; } KateViewManager::~KateViewManager() { /** * remove the single client that is registered at the factory, if any */ if (m_guiMergedView) { mainWindow()->guiFactory()->removeClient(m_guiMergedView); m_guiMergedView = nullptr; } } void KateViewManager::setupActions() { /** * view splitting */ m_splitViewVert = m_mainWindow->actionCollection()->addAction(QStringLiteral("view_split_vert")); m_splitViewVert->setIcon(QIcon::fromTheme(QStringLiteral("view-split-left-right"))); m_splitViewVert->setText(i18n("Split Ve&rtical")); m_mainWindow->actionCollection()->setDefaultShortcut(m_splitViewVert, Qt::CTRL + Qt::SHIFT + Qt::Key_L); connect(m_splitViewVert, SIGNAL(triggered()), this, SLOT(slotSplitViewSpaceVert())); m_splitViewVert->setWhatsThis(i18n("Split the currently active view vertically into two views.")); m_splitViewHoriz = m_mainWindow->actionCollection()->addAction(QStringLiteral("view_split_horiz")); m_splitViewHoriz->setIcon(QIcon::fromTheme(QStringLiteral("view-split-top-bottom"))); m_splitViewHoriz->setText(i18n("Split &Horizontal")); m_mainWindow->actionCollection()->setDefaultShortcut(m_splitViewHoriz, Qt::CTRL + Qt::SHIFT + Qt::Key_T); connect(m_splitViewHoriz, SIGNAL(triggered()), this, SLOT(slotSplitViewSpaceHoriz())); m_splitViewHoriz->setWhatsThis(i18n("Split the currently active view horizontally into two views.")); m_closeView = m_mainWindow->actionCollection()->addAction(QStringLiteral("view_close_current_space")); m_closeView->setIcon(QIcon::fromTheme(QStringLiteral("view-close"))); m_closeView->setText(i18n("Cl&ose Current View")); m_mainWindow->actionCollection()->setDefaultShortcut(m_closeView, Qt::CTRL + Qt::SHIFT + Qt::Key_R); connect(m_closeView, SIGNAL(triggered()), this, SLOT(slotCloseCurrentViewSpace()), Qt::QueuedConnection); m_closeView->setWhatsThis(i18n("Close the currently active split view")); m_closeOtherViews = m_mainWindow->actionCollection()->addAction(QStringLiteral("view_close_others")); m_closeOtherViews->setIcon(QIcon::fromTheme(QStringLiteral("view-close"))); m_closeOtherViews->setText(i18n("Close Inactive Views")); connect(m_closeOtherViews, SIGNAL(triggered()), this, SLOT(slotCloseOtherViews()), Qt::QueuedConnection); m_closeOtherViews->setWhatsThis(i18n("Close every view but the active one")); m_hideOtherViews = m_mainWindow->actionCollection()->addAction(QStringLiteral("view_hide_others")); m_hideOtherViews->setIcon(QIcon::fromTheme(QStringLiteral("view-fullscreen"))); m_hideOtherViews->setText(i18n("Hide Inactive Views")); m_hideOtherViews->setCheckable(true); connect(m_hideOtherViews, SIGNAL(triggered(bool)), this, SLOT(slotHideOtherViews(bool)), Qt::QueuedConnection); m_hideOtherViews->setWhatsThis(i18n("Hide every view but the active one")); m_toggleSplitterOrientation = m_mainWindow->actionCollection()->addAction(QStringLiteral("view_split_toggle")); m_toggleSplitterOrientation->setText(i18n("Toggle Orientation")); connect(m_toggleSplitterOrientation, SIGNAL(triggered()), this, SLOT(toggleSplitterOrientation()), Qt::QueuedConnection); m_toggleSplitterOrientation->setWhatsThis(i18n("Toggles the orientation of the current split view")); goNext = m_mainWindow->actionCollection()->addAction(QStringLiteral("go_next_split_view")); goNext->setText(i18n("Next Split View")); m_mainWindow->actionCollection()->setDefaultShortcut(goNext, Qt::Key_F8); connect(goNext, SIGNAL(triggered()), this, SLOT(activateNextView())); goNext->setWhatsThis(i18n("Make the next split view the active one.")); goPrev = m_mainWindow->actionCollection()->addAction(QStringLiteral("go_prev_split_view")); goPrev->setText(i18n("Previous Split View")); m_mainWindow->actionCollection()->setDefaultShortcut(goPrev, Qt::SHIFT + Qt::Key_F8); connect(goPrev, SIGNAL(triggered()), this, SLOT(activatePrevView())); goPrev->setWhatsThis(i18n("Make the previous split view the active one.")); QAction * a = m_mainWindow->actionCollection()->addAction(QStringLiteral("view_split_move_right")); a->setText(i18n("Move Splitter Right")); connect(a, SIGNAL(triggered()), this, SLOT(moveSplitterRight())); a->setWhatsThis(i18n("Move the splitter of the current view to the right")); a = m_mainWindow->actionCollection()->addAction(QStringLiteral("view_split_move_left")); a->setText(i18n("Move Splitter Left")); connect(a, SIGNAL(triggered()), this, SLOT(moveSplitterLeft())); a->setWhatsThis(i18n("Move the splitter of the current view to the left")); a = m_mainWindow->actionCollection()->addAction(QStringLiteral("view_split_move_up")); a->setText(i18n("Move Splitter Up")); connect(a, SIGNAL(triggered()), this, SLOT(moveSplitterUp())); a->setWhatsThis(i18n("Move the splitter of the current view up")); a = m_mainWindow->actionCollection()->addAction(QStringLiteral("view_split_move_down")); a->setText(i18n("Move Splitter Down")); connect(a, SIGNAL(triggered()), this, SLOT(moveSplitterDown())); a->setWhatsThis(i18n("Move the splitter of the current view down")); } void KateViewManager::updateViewSpaceActions() { m_closeView->setEnabled(m_viewSpaceList.count() > 1); m_closeOtherViews->setEnabled(m_viewSpaceList.count() > 1); m_toggleSplitterOrientation->setEnabled(m_viewSpaceList.count() > 1); goNext->setEnabled(m_viewSpaceList.count() > 1); goPrev->setEnabled(m_viewSpaceList.count() > 1); } void KateViewManager::slotDocumentNew() { createView(); } void KateViewManager::slotDocumentOpen() { // try to start dialog in useful dir: either dir of current doc or last used one KTextEditor::View * const cv = activeView(); QUrl startUrl = cv ? cv->document()->url() : QUrl(); if (startUrl.isValid()) { m_lastOpenDialogUrl = startUrl; } else { startUrl = m_lastOpenDialogUrl; } const QList urls = QFileDialog::getOpenFileUrls(m_mainWindow, i18n("Open File"), startUrl); /** * emit size warning, for local files */ QString fileListWithTooLargeFiles; Q_FOREACH(const QUrl & url, urls) { if (!url.isLocalFile()) { continue; } const auto size = QFile(url.toLocalFile()).size(); if (size > FileSizeAboveToAskUserIfProceedWithOpen) { fileListWithTooLargeFiles += QString::fromLatin1("
  • %1 (%2MB)
  • ").arg(url.fileName()).arg(size / 1024 / 1024); } } if (!fileListWithTooLargeFiles.isEmpty()) { const QString text = i18n("

    You are attempting to open one or more large files:

      %1

    Do you want to proceed?

    Beware that kate may stop responding for some time when opening large files.

    "); const auto ret = KMessageBox::warningYesNo(this, text.arg(fileListWithTooLargeFiles), i18n("Opening Large File"), KStandardGuiItem::cont(), KStandardGuiItem::stop()); if (ret == KMessageBox::No) { return; } } // activate view of last opened document KateDocumentInfo docInfo; docInfo.openedByUser = true; if (KTextEditor::Document *lastID = openUrls(urls, QString(), false, docInfo)) { activateView(lastID); } } void KateViewManager::slotDocumentClose(KTextEditor::Document *document) { // prevent close document if only one view alive and the document of // it is not modified and empty !!! if ((KateApp::self()->documentManager()->documentList().size() == 1) && !document->isModified() && document->url().isEmpty() && document->documentEnd() == KTextEditor::Cursor::start()) { document->closeUrl(); return; } // close document KateApp::self()->documentManager()->closeDocument(document); } void KateViewManager::slotDocumentClose() { // no active view, do nothing if (!activeView()) { return; } slotDocumentClose(activeView()->document()); } KTextEditor::Document *KateViewManager::openUrl(const QUrl &url, const QString &encoding, bool activate, bool isTempFile, const KateDocumentInfo &docInfo) { KTextEditor::Document *doc = KateApp::self()->documentManager()->openUrl(url, encoding, isTempFile, docInfo); if (!doc->url().isEmpty()) { m_mainWindow->fileOpenRecent()->addUrl(doc->url()); } if (activate) { activateView(doc); } return doc; } KTextEditor::Document *KateViewManager::openUrls(const QList &urls, const QString &encoding, bool isTempFile, const KateDocumentInfo &docInfo) { QList docs = KateApp::self()->documentManager()->openUrls(urls, encoding, isTempFile, docInfo); foreach(const KTextEditor::Document * doc, docs) { if (!doc->url().isEmpty()) { m_mainWindow->fileOpenRecent()->addUrl(doc->url()); } } return docs.isEmpty() ? 0 : docs.last(); } KTextEditor::View *KateViewManager::openUrlWithView(const QUrl &url, const QString &encoding) { KTextEditor::Document *doc = KateApp::self()->documentManager()->openUrl(url, encoding); if (!doc) { - return 0; + return nullptr; } if (!doc->url().isEmpty()) { m_mainWindow->fileOpenRecent()->addUrl(doc->url()); } activateView(doc); return activeView(); } void KateViewManager::openUrl(const QUrl &url) { openUrl(url, QString()); } KateMainWindow *KateViewManager::mainWindow() { return m_mainWindow; } void KateViewManager::documentCreated(KTextEditor::Document *doc) { // forward to currently active view space activeViewSpace()->registerDocument(doc); // to update open recent files on saving connect(doc, SIGNAL(documentSavedOrUploaded(KTextEditor::Document*,bool)), this, SLOT(documentSavedOrUploaded(KTextEditor::Document*,bool))); if (m_blockViewCreationAndActivation) { return; } if (!activeView()) { activateView(doc); } /** * check if we have any empty viewspaces and give them a view */ Q_FOREACH(KateViewSpace * vs, m_viewSpaceList) { if (!vs->currentView()) { createView(activeView()->document(), vs); } } } void KateViewManager::aboutToDeleteDocuments(const QList &) { /** * block view creation until the transaction is done * this shall not stack! */ Q_ASSERT (!m_blockViewCreationAndActivation); m_blockViewCreationAndActivation = true; /** * disable updates hard (we can't use KateUpdateDisabler here, we have delayed signal */ mainWindow()->setUpdatesEnabled(false); } void KateViewManager::documentsDeleted(const QList &) { /** * again allow view creation */ m_blockViewCreationAndActivation = false; /** * try to have active view around! */ if (!activeView() && !KateApp::self()->documentManager()->documentList().isEmpty()) { createView(KateApp::self()->documentManager()->documentList().last()); } /** * if we have one now, show them in all viewspaces that got empty! */ if (KTextEditor::View *const newActiveView = activeView()) { /** * check if we have any empty viewspaces and give them a view */ Q_FOREACH(KateViewSpace * vs, m_viewSpaceList) { if (!vs->currentView()) { createView(newActiveView->document(), vs); } } emit viewChanged(newActiveView); } /** * enable updates hard (we can't use KateUpdateDisabler here, we have delayed signal */ mainWindow()->setUpdatesEnabled(true); } void KateViewManager::documentSavedOrUploaded(KTextEditor::Document *doc, bool) { if (!doc->url().isEmpty()) { m_mainWindow->fileOpenRecent()->addUrl(doc->url()); } } KTextEditor::View *KateViewManager::createView(KTextEditor::Document *doc, KateViewSpace *vs) { if (m_blockViewCreationAndActivation) { return nullptr; } // create doc if (!doc) { doc = KateApp::self()->documentManager()->createDoc(); } /** * create view, registers its XML gui itself * pass the view the correct main window */ KTextEditor::View *view = (vs ? vs : activeViewSpace())->createView(doc); /** * remember this view, active == false, min age set * create activity resource */ m_views[view].active = false; m_views[view].lruAge = m_minAge--; #ifdef KActivities_FOUND m_views[view].activityResource = new KActivities::ResourceInstance(view->window()->winId(), view); m_views[view].activityResource->setUri(doc->url()); #endif // disable settings dialog action delete view->actionCollection()->action(QStringLiteral("set_confdlg")); delete view->actionCollection()->action(QStringLiteral("editor_options")); connect(view, SIGNAL(dropEventPass(QDropEvent*)), mainWindow(), SLOT(slotDropEvent(QDropEvent*))); connect(view, SIGNAL(focusIn(KTextEditor::View*)), this, SLOT(activateSpace(KTextEditor::View*))); viewCreated(view); if (!vs) { activateView(view); } return view; } bool KateViewManager::deleteView(KTextEditor::View *view) { if (!view) { return true; } KateViewSpace *viewspace = static_cast(view->parentWidget()->parentWidget()); viewspace->removeView(view); /** * deregister if needed */ if (m_guiMergedView == view) { mainWindow()->guiFactory()->removeClient(m_guiMergedView); m_guiMergedView = nullptr; } // remove view from mapping and memory !! m_views.remove(view); delete view; return true; } KateViewSpace *KateViewManager::activeViewSpace() { for (QList::const_iterator it = m_viewSpaceList.constBegin(); it != m_viewSpaceList.constEnd(); ++it) { if ((*it)->isActiveSpace()) { return *it; } } // none active, so use the first we grab if (!m_viewSpaceList.isEmpty()) { m_viewSpaceList.first()->setActive(true); return m_viewSpaceList.first(); } Q_ASSERT(false); - return 0L; + return nullptr; } KTextEditor::View *KateViewManager::activeView() { if (m_activeViewRunning) { - return 0L; + return nullptr; } m_activeViewRunning = true; QHashIterator it(m_views); while (it.hasNext()) { it.next(); if (it.value().active) { m_activeViewRunning = false; return it.key(); } } // if we get to here, no view isActive() // first, try to get one from activeViewSpace() KateViewSpace *vs = activeViewSpace(); if (vs && vs->currentView()) { activateView(vs->currentView()); m_activeViewRunning = false; return vs->currentView(); } // last attempt: just pick first if (!m_views.isEmpty()) { KTextEditor::View *v = m_views.begin().key(); activateView(v); m_activeViewRunning = false; return v; } m_activeViewRunning = false; // no views exists! - return 0L; + return nullptr; } void KateViewManager::setActiveSpace(KateViewSpace *vs) { if (activeViewSpace()) { activeViewSpace()->setActive(false); } vs->setActive(true); } void KateViewManager::setActiveView(KTextEditor::View *view) { if (activeView()) { m_views[activeView()].active = false; } if (view) { m_views[view].active = true; } } void KateViewManager::activateSpace(KTextEditor::View *v) { if (!v) { return; } KateViewSpace *vs = static_cast(v->parentWidget()->parentWidget()); if (!vs->isActiveSpace()) { setActiveSpace(vs); activateView(v); } } void KateViewManager::reactivateActiveView() { KTextEditor::View *view = activeView(); if (view) { m_views[view].active = false; activateView(view); } } void KateViewManager::activateView(KTextEditor::View *view) { if (!view) { return; } Q_ASSERT (m_views.contains(view)); if (!m_views[view].active) { // avoid flicker KateUpdateDisabler disableUpdates (mainWindow()); if (!activeViewSpace()->showView(view)) { // since it wasn't found, give'em a new one createView(view->document()); return; } setActiveView(view); bool toolbarVisible = mainWindow()->toolBar()->isVisible(); if (toolbarVisible) { mainWindow()->toolBar()->hide(); // hide to avoid toolbar flickering } if (m_guiMergedView) { mainWindow()->guiFactory()->removeClient(m_guiMergedView); m_guiMergedView = nullptr; } if (!m_blockViewCreationAndActivation) { mainWindow()->guiFactory()->addClient(view); m_guiMergedView = view; } if (toolbarVisible) { mainWindow()->toolBar()->show(); } // remember age of this view m_views[view].lruAge = m_minAge--; emit viewChanged(view); #ifdef KActivities_FOUND // inform activity manager m_views[view].activityResource->setUri(view->document()->url()); m_views[view].activityResource->notifyFocusedIn(); #endif } } KTextEditor::View *KateViewManager::activateView(KTextEditor::Document *d) { // no doc with this id found if (!d) { return activeView(); } // activate existing view if possible if (activeViewSpace()->showView(d)) { activateView(activeViewSpace()->currentView()); return activeView(); } // create new view otherwise createView(d); return activeView(); } void KateViewManager::slotViewChanged() { if (activeView() && !activeView()->hasFocus()) { activeView()->setFocus(); } } void KateViewManager::activateNextView() { int i = m_viewSpaceList.indexOf(activeViewSpace()) + 1; if (i >= m_viewSpaceList.count()) { i = 0; } setActiveSpace(m_viewSpaceList.at(i)); activateView(m_viewSpaceList.at(i)->currentView()); } void KateViewManager::activatePrevView() { int i = m_viewSpaceList.indexOf(activeViewSpace()) - 1; if (i < 0) { i = m_viewSpaceList.count() - 1; } setActiveSpace(m_viewSpaceList.at(i)); activateView(m_viewSpaceList.at(i)->currentView()); } void KateViewManager::documentWillBeDeleted(KTextEditor::Document *doc) { /** * collect all views of that document that belong to this manager */ QList closeList; Q_FOREACH (KTextEditor::View *v, doc->views()) { if (m_views.contains(v)) { closeList.append(v); } } while (!closeList.isEmpty()) { deleteView(closeList.takeFirst()); } } void KateViewManager::closeView(KTextEditor::View *view) { /** * kill view we want to kill */ deleteView(view); /** * try to have active view around! */ if (!activeView() && !KateApp::self()->documentManager()->documentList().isEmpty()) { createView(KateApp::self()->documentManager()->documentList().last()); } /** * if we have one now, show them in all viewspaces that got empty! */ if (KTextEditor::View *const newActiveView = activeView()) { /** * check if we have any empty viewspaces and give them a view */ Q_FOREACH(KateViewSpace * vs, m_viewSpaceList) { if (!vs->currentView()) { createView(newActiveView->document(), vs); } } emit viewChanged(newActiveView); } } void KateViewManager::splitViewSpace(KateViewSpace *vs, // = 0 Qt::Orientation o) // = Qt::Horizontal { // emergency: fallback to activeViewSpace, and if still invalid, abort if (!vs) { vs = activeViewSpace(); } if (!vs) { return; } // get current splitter, and abort if null QSplitter *currentSplitter = qobject_cast(vs->parentWidget()); if (!currentSplitter) { return; } // avoid flicker KateUpdateDisabler disableUpdates (mainWindow()); // index where to insert new splitter/viewspace const int index = currentSplitter->indexOf(vs); // create new viewspace KateViewSpace *vsNew = new KateViewSpace(this); // only 1 children -> we are the root container. So simply set the orientation // and add the new view space, then correct the sizes to 50%:50% if (currentSplitter->count() == 1) { if (currentSplitter->orientation() != o) { currentSplitter->setOrientation(o); } QList sizes = currentSplitter->sizes(); sizes << (sizes.first() - currentSplitter->handleWidth()) / 2; sizes[0] = sizes[1]; currentSplitter->insertWidget(index, vsNew); currentSplitter->setSizes(sizes); } else { // create a new QSplitter and replace vs with the splitter. vs and newVS are // the new children of the new QSplitter QSplitter *newContainer = new QSplitter(o); QList currentSizes = currentSplitter->sizes(); newContainer->addWidget(vs); newContainer->addWidget(vsNew); currentSplitter->insertWidget(index, newContainer); newContainer->show(); // fix sizes of children of old and new splitter currentSplitter->setSizes(currentSizes); QList newSizes = newContainer->sizes(); newSizes[0] = (newSizes[0] + newSizes[1] - newContainer->handleWidth()) / 2; newSizes[1] = newSizes[0]; newContainer->setSizes(newSizes); } m_viewSpaceList.append(vsNew); activeViewSpace()->setActive(false); vsNew->setActive(true); vsNew->show(); createView((KTextEditor::Document *)activeView()->document()); updateViewSpaceActions(); } void KateViewManager::closeViewSpace(KTextEditor::View *view) { KateViewSpace *space; if (view) { space = static_cast(view->parentWidget()->parentWidget()); } else { space = activeViewSpace(); } removeViewSpace(space); } void KateViewManager::toggleSplitterOrientation() { KateViewSpace *vs = activeViewSpace(); if (!vs) { return; } // get current splitter, and abort if null QSplitter *currentSplitter = qobject_cast(vs->parentWidget()); if (!currentSplitter || (currentSplitter->count() == 1)) { return; } // avoid flicker KateUpdateDisabler disableUpdates (mainWindow()); // toggle orientation if (currentSplitter->orientation() == Qt::Horizontal) { currentSplitter->setOrientation(Qt::Vertical); } else { currentSplitter->setOrientation(Qt::Horizontal); } } bool KateViewManager::viewsInSameViewSpace(KTextEditor::View *view1, KTextEditor::View *view2) { if (!view1 || !view2) { return false; } if (m_viewSpaceList.size() == 1) { return true; } KateViewSpace *vs1 = static_cast(view1->parentWidget()->parentWidget()); KateViewSpace *vs2 = static_cast(view2->parentWidget()->parentWidget()); return vs1 && (vs1 == vs2); } void KateViewManager::removeViewSpace(KateViewSpace *viewspace) { // abort if viewspace is 0 if (!viewspace) { return; } // abort if this is the last viewspace if (m_viewSpaceList.count() < 2) { return; } // get current splitter QSplitter *currentSplitter = qobject_cast(viewspace->parentWidget()); // no splitter found, bah if (!currentSplitter) { return; } // // 1. get LRU document list from current viewspace // 2. delete current view space // 3. add LRU documents from deleted viewspace to new active viewspace // // backup LRU list const QVector lruDocumntsList = viewspace->lruDocumentList(); // avoid flicker KateUpdateDisabler disableUpdates (mainWindow()); // delete views of the viewspace while (viewspace->currentView()) { deleteView(viewspace->currentView()); } // cu viewspace m_viewSpaceList.removeAt(m_viewSpaceList.indexOf(viewspace)); delete viewspace; // at this point, the splitter has exactly 1 child Q_ASSERT(currentSplitter->count() == 1); // if we are not the root splitter, move the child one level up and delete // the splitter then. if (currentSplitter != this) { // get parent splitter QSplitter *parentSplitter = qobject_cast(currentSplitter->parentWidget()); // only do magic if found ;) if (parentSplitter) { int index = parentSplitter->indexOf(currentSplitter); // save current splitter size, as the removal of currentSplitter looses the info QList parentSizes = parentSplitter->sizes(); parentSplitter->insertWidget(index, currentSplitter->widget(0)); delete currentSplitter; // now restore the sizes again parentSplitter->setSizes(parentSizes); } } else if (QSplitter *splitter = qobject_cast(currentSplitter->widget(0))) { // we are the root splitter and have only one child, which is also a splitter // -> eliminate the redundant splitter and move both children into the root splitter QList sizes = splitter->sizes(); // adapt splitter orientation to the splitter we are about to delete currentSplitter->setOrientation(splitter->orientation()); currentSplitter->addWidget(splitter->widget(0)); currentSplitter->addWidget(splitter->widget(0)); delete splitter; currentSplitter->setSizes(sizes); } // merge docuemnts of closed view space activeViewSpace()->mergeLruList(lruDocumntsList); // find the view that is now active. KTextEditor::View *v = activeViewSpace()->currentView(); if (v) { activateView(v); } updateViewSpaceActions(); emit viewChanged(v); } void KateViewManager::slotCloseOtherViews() { // avoid flicker KateUpdateDisabler disableUpdates(mainWindow()); const KateViewSpace *active = activeViewSpace(); foreach(KateViewSpace * v, m_viewSpaceList) { if (active != v) { removeViewSpace(v); } } } void KateViewManager::slotHideOtherViews(bool hideOthers) { // avoid flicker KateUpdateDisabler disableUpdates(mainWindow()); const KateViewSpace *active = activeViewSpace(); foreach(KateViewSpace * v, m_viewSpaceList) { if (active != v) { v->setVisible(!hideOthers); } } // disable the split actions, if we are in single-view-mode m_splitViewVert->setDisabled(hideOthers); m_splitViewHoriz->setDisabled(hideOthers); m_closeView->setDisabled(hideOthers); m_closeOtherViews->setDisabled(hideOthers); m_toggleSplitterOrientation->setDisabled(hideOthers); } /** * session config functions */ void KateViewManager::saveViewConfiguration(KConfigGroup &config) { // set Active ViewSpace to 0, just in case there is none active (would be // strange) and config somehow has previous value set config.writeEntry("Active ViewSpace", 0); m_splitterIndex = 0; saveSplitterConfig(this, config.config(), config.name()); } void KateViewManager::restoreViewConfiguration(const KConfigGroup &config) { /** * remove the single client that is registered at the factory, if any */ if (m_guiMergedView) { mainWindow()->guiFactory()->removeClient(m_guiMergedView); m_guiMergedView = nullptr; } /** * delete viewspaces, they will delete the views */ qDeleteAll(m_viewSpaceList); m_viewSpaceList.clear(); /** * delete mapping of now deleted views */ m_views.clear(); // reset lru history, too! m_minAge = 0; // start recursion for the root splitter (Splitter 0) restoreSplitter(config.config(), config.name() + QStringLiteral("-Splitter 0"), this, config.name()); // finally, make the correct view from the last session active int lastViewSpace = config.readEntry("Active ViewSpace", 0); if (lastViewSpace > m_viewSpaceList.size()) { lastViewSpace = 0; } if (lastViewSpace >= 0 && lastViewSpace < m_viewSpaceList.size()) { setActiveSpace(m_viewSpaceList.at(lastViewSpace)); // activate correct view (wish #195435, #188764) activateView(m_viewSpaceList.at(lastViewSpace)->currentView()); // give view the focus to avoid focus stealing by toolviews / plugins m_viewSpaceList.at(lastViewSpace)->currentView()->setFocus(); } // emergency if (m_viewSpaceList.empty()) { // kill bad children while (count()) { delete widget(0); } - KateViewSpace *vs = new KateViewSpace(this, 0); + KateViewSpace *vs = new KateViewSpace(this, nullptr); addWidget(vs); vs->setActive(true); m_viewSpaceList.append(vs); /** * activate at least one document! */ activateView(KateApp::self()->documentManager()->documentList().last()); if (!vs->currentView()) { createView(activeView()->document(), vs); } } updateViewSpaceActions(); } QString KateViewManager::saveSplitterConfig(QSplitter *s, KConfigBase *configBase, const QString &viewConfGrp) { /** * avoid to export invisible view spaces * else they will stick around for ever in sessions * bug 358266 - code initially done during load * bug 381433 - moved code to save */ /** * create new splitter name, might be not used */ const auto grp = QString(viewConfGrp + QStringLiteral("-Splitter %1")).arg(m_splitterIndex); ++m_splitterIndex; // a QSplitter has two children, either QSplitters and/or KateViewSpaces // special case: root splitter might have only one child (just for info) QStringList childList; const auto sizes = s->sizes(); for (int it = 0; it < s->count(); ++it) { // skip empty sized invisible ones, if not last one, we need one thing at least if ((sizes[it] == 0) && ((it + 1 < s->count()) || !childList.empty())) continue; // For KateViewSpaces, ask them to save the file list. auto obj = s->widget(it); if (auto kvs = qobject_cast(obj)) { childList.append(QString(viewConfGrp + QStringLiteral("-ViewSpace %1")).arg(m_viewSpaceList.indexOf(kvs))); kvs->saveConfig(configBase, m_viewSpaceList.indexOf(kvs), viewConfGrp); // save active viewspace if (kvs->isActiveSpace()) { KConfigGroup viewConfGroup(configBase, viewConfGrp); viewConfGroup.writeEntry("Active ViewSpace", m_viewSpaceList.indexOf(kvs)); } } // for QSplitters, recurse else if (auto splitter = qobject_cast(obj)) { childList.append(saveSplitterConfig(splitter, configBase, viewConfGrp)); } } // if only one thing, skip splitter config export, if not top splitter if ((s != this) && (childList.size() == 1)) return childList.at(0); // Save sizes, orient, children for this splitter KConfigGroup config(configBase, grp); config.writeEntry("Sizes", sizes); config.writeEntry("Orientation", int(s->orientation())); config.writeEntry("Children", childList); return grp; } void KateViewManager::restoreSplitter(const KConfigBase *configBase, const QString &group, QSplitter *parent, const QString &viewConfGrp) { KConfigGroup config(configBase, group); parent->setOrientation((Qt::Orientation)config.readEntry("Orientation", int(Qt::Horizontal))); QStringList children = config.readEntry("Children", QStringList()); for (QStringList::Iterator it = children.begin(); it != children.end(); ++it) { // for a viewspace, create it and open all documents therein. if ((*it).startsWith(viewConfGrp + QStringLiteral("-ViewSpace"))) { - KateViewSpace *vs = new KateViewSpace(this, 0); + KateViewSpace *vs = new KateViewSpace(this, nullptr); m_viewSpaceList.append(vs); // make active so that the view created in restoreConfig has this // new view space as parent. setActiveSpace(vs); parent->addWidget(vs); vs->restoreConfig(this, configBase, *it); vs->show(); } else { // for a splitter, recurse. restoreSplitter(configBase, *it, new QSplitter(parent), viewConfGrp); } } // set sizes parent->setSizes(config.readEntry("Sizes", QList())); parent->show(); } void KateViewManager::moveSplitter(Qt::Key key, int repeats) { if (repeats < 1) { return; } KateViewSpace *vs = activeViewSpace(); if (!vs) { return; } QSplitter *currentSplitter = qobject_cast(vs->parentWidget()); if (!currentSplitter) { return; } if (currentSplitter->count() == 1) { return; } int move = 4 * repeats; // try to use font height in pixel to move splitter { KTextEditor::Attribute::Ptr attrib(vs->currentView()->defaultStyleAttribute(KTextEditor::dsNormal)); QFontMetrics fm(attrib->font()); move = fm.height() * repeats; } QWidget *currentWidget = (QWidget *)vs; bool foundSplitter = false; // find correct splitter to be moved while (currentSplitter && currentSplitter->count() != 1) { if (currentSplitter->orientation() == Qt::Horizontal && (key == Qt::Key_Right || key == Qt::Key_Left)) { foundSplitter = true; } if (currentSplitter->orientation() == Qt::Vertical && (key == Qt::Key_Up || key == Qt::Key_Down)) { foundSplitter = true; } // if the views within the current splitter can be resized, resize them if (foundSplitter) { QList currentSizes = currentSplitter->sizes(); int index = currentSplitter->indexOf(currentWidget); if ((index == 0 && (key == Qt::Key_Left || key == Qt::Key_Up)) || (index == 1 && (key == Qt::Key_Right || key == Qt::Key_Down))) { currentSizes[index] -= move; } if ((index == 0 && (key == Qt::Key_Right || key == Qt::Key_Down)) || (index == 1 && (key == Qt::Key_Left || key == Qt::Key_Up))) { currentSizes[index] += move; } if (index == 0 && (key == Qt::Key_Right || key == Qt::Key_Down)) { currentSizes[index + 1] -= move; } if (index == 0 && (key == Qt::Key_Left || key == Qt::Key_Up)) { currentSizes[index + 1] += move; } if (index == 1 && (key == Qt::Key_Right || key == Qt::Key_Down)) { currentSizes[index - 1] += move; } if (index == 1 && (key == Qt::Key_Left || key == Qt::Key_Up)) { currentSizes[index - 1] -= move; } currentSplitter->setSizes(currentSizes); break; } currentWidget = (QWidget *)currentSplitter; // the parent of the current splitter will become the current splitter currentSplitter = qobject_cast(currentSplitter->parentWidget()); } } diff --git a/kate/kateviewmanager.h b/kate/kateviewmanager.h index c52040abe..305376de3 100644 --- a/kate/kateviewmanager.h +++ b/kate/kateviewmanager.h @@ -1,351 +1,351 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 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. */ #ifndef __KATE_VIEWMANAGER_H__ #define __KATE_VIEWMANAGER_H__ #include "katedocmanager.h" #include #include #include #include #include namespace KActivities { class ResourceInstance; } namespace KTextEditor { class View; class Document; } class KateDocumentInfo; class KConfigGroup; class KConfigBase; class KateMainWindow; class KateViewSpace; class KateViewManager : public QSplitter { Q_OBJECT public: KateViewManager(QWidget *parentW, KateMainWindow *parent); ~KateViewManager(); private: /** * create all actions needed for the view manager */ void setupActions(); void updateViewSpaceActions(); public: /* This will save the splitter configuration */ void saveViewConfiguration(KConfigGroup &group); /* restore it */ void restoreViewConfiguration(const KConfigGroup &group); KTextEditor::Document *openUrl(const QUrl &url, const QString &encoding, bool activate = true, bool isTempFile = false, const KateDocumentInfo &docInfo = KateDocumentInfo()); KTextEditor::Document *openUrls(const QList &url, const QString &encoding, bool isTempFile = false, const KateDocumentInfo &docInfo = KateDocumentInfo()); KTextEditor::View *openUrlWithView(const QUrl &url, const QString &encoding); public Q_SLOTS: void openUrl(const QUrl &url); public: void closeView(KTextEditor::View *view); KateMainWindow *mainWindow(); private Q_SLOTS: void activateView(KTextEditor::View *view); void activateSpace(KTextEditor::View *v); public Q_SLOTS: void slotDocumentNew(); void slotDocumentOpen(); void slotDocumentClose(); void slotDocumentClose(KTextEditor::Document *document); void setActiveSpace(KateViewSpace *vs); void setActiveView(KTextEditor::View *view); void activateNextView(); void activatePrevView(); Q_SIGNALS: void viewChanged(KTextEditor::View *); void viewCreated(KTextEditor::View *); public: /** * create and activate a new view for doc, if doc == 0, then * create a new document. * Can return NULL. */ - KTextEditor::View *createView(KTextEditor::Document *doc = 0L, KateViewSpace *vs = nullptr); + KTextEditor::View *createView(KTextEditor::Document *doc = nullptr, KateViewSpace *vs = nullptr); private: bool deleteView(KTextEditor::View *view); void moveViewtoSplit(KTextEditor::View *view); void moveViewtoStack(KTextEditor::View *view); /* Save the configuration of a single splitter. * If child splitters are found, it calls it self with those as the argument. * If a viewspace child is found, it is asked to save its filelist. */ QString saveSplitterConfig(QSplitter *s, KConfigBase *config, const QString &viewConfGrp); /** Restore a single splitter. * This is all the work is done for @see saveSplitterConfig() */ void restoreSplitter(const KConfigBase *config, const QString &group, QSplitter *parent, const QString &viewConfGrp); void removeViewSpace(KateViewSpace *viewspace); public: KTextEditor::View *activeView(); KateViewSpace *activeViewSpace(); private Q_SLOTS: void slotViewChanged(); void documentCreated(KTextEditor::Document *doc); void documentWillBeDeleted(KTextEditor::Document *doc); void documentSavedOrUploaded(KTextEditor::Document *document, bool saveAs); /** * This signal is emitted before the documents batch is going to be deleted * * note that the batch can be interrupted in the middle and only some * of the documents may be actually deleted. See documentsDeleted() signal. * * @param documents documents we want to delete, may not be deleted */ void aboutToDeleteDocuments(const QList &documents); /** * This singnal is emitted after the documents batch was deleted * * This is the batch closing signal for aboutToDeleteDocuments * @param documents the documents that weren't deleted after all */ void documentsDeleted(const QList &documents); public Q_SLOTS: /** * Splits a KateViewSpace into two in the following steps: * 1. create a QSplitter in the parent of the KateViewSpace to be split * 2. move the to-be-split KateViewSpace to the new splitter * 3. create new KateViewSpace and added to the new splitter * 4. create KateView to populate the new viewspace. * 5. The new KateView is made the active one, because createView() does that. * If no viewspace is provided, the result of activeViewSpace() is used. * The orientation of the new splitter is determined by the value of o. * Note: horizontal splitter means vertically aligned views. */ - void splitViewSpace(KateViewSpace *vs = 0L, Qt::Orientation o = Qt::Horizontal); + void splitViewSpace(KateViewSpace *vs = nullptr, Qt::Orientation o = Qt::Horizontal); /** * Close the view space that contains the given view. If no view was * given, then the active view space will be closed instead. */ void closeViewSpace(KTextEditor::View *view = nullptr); /** * @returns true of the two given views share the same view space. */ bool viewsInSameViewSpace(KTextEditor::View *view1, KTextEditor::View *view2); /** * activate view for given document * @param doc document to activate view for */ KTextEditor::View *activateView(KTextEditor::Document *doc); /** Splits the active viewspace horizontally */ void slotSplitViewSpaceHoriz() { - splitViewSpace(0L, Qt::Vertical); + splitViewSpace(nullptr, Qt::Vertical); } /** Splits the active viewspace vertically */ void slotSplitViewSpaceVert() { splitViewSpace(); } /** moves the splitter according to the key that has been pressed */ void moveSplitter(Qt::Key key, int repeats = 1); /** moves the splitter to the right */ void moveSplitterRight() { moveSplitter(Qt::Key_Right); } /** moves the splitter to the left */ void moveSplitterLeft() { moveSplitter(Qt::Key_Left); } /** moves the splitter up */ void moveSplitterUp() { moveSplitter(Qt::Key_Up); } /** moves the splitter down */ void moveSplitterDown() { moveSplitter(Qt::Key_Down); } /** closes the current view space. */ void slotCloseCurrentViewSpace() { closeViewSpace(); } /** closes every view but the active one */ void slotCloseOtherViews(); /** hide every view but the active one */ void slotHideOtherViews(bool hideOthers); void reactivateActiveView(); /** * Toogle the orientation of current split view */ void toggleSplitterOrientation(); /** * Get a list of all views. * @return all views */ QList views() const { return m_views.keys(); } /** * get views in lru order * @return views in lru order */ QList sortedViews() const { QMap sortedViews; QHashIterator i(m_views); while (i.hasNext()) { i.next(); sortedViews[i.value().lruAge] = i.key(); } return sortedViews.values(); } private: KateMainWindow *m_mainWindow; bool m_init; QAction *m_splitViewVert; QAction *m_splitViewHoriz; QAction *m_closeView; QAction *m_closeOtherViews; QAction *m_toggleSplitterOrientation; QAction *m_hideOtherViews; QAction *goNext; QAction *goPrev; QList m_viewSpaceList; bool m_blockViewCreationAndActivation; bool m_activeViewRunning; int m_splitterIndex; // used during saving splitter config. /** * View meta data */ class ViewData { public: /** * Default constructor */ ViewData() : active(false) , lruAge(0) , activityResource(Q_NULLPTR) { } /** * view active? */ bool active; /** * lru age of the view * important: smallest age ==> latest used view */ qint64 lruAge; /** * activity resource for the view */ KActivities::ResourceInstance *activityResource; }; /** * central storage of all views known in the view manager * maps the view to meta data */ QHash m_views; /** * current minimal age */ qint64 m_minAge; /** * the view that is ATM merged to the xml gui factory */ QPointer m_guiMergedView; /** * last url of open file dialog, used if current document has no valid url */ QUrl m_lastOpenDialogUrl; }; #endif diff --git a/kate/kateviewspace.cpp b/kate/kateviewspace.cpp index b72ee2953..50791cd09 100644 --- a/kate/kateviewspace.cpp +++ b/kate/kateviewspace.cpp @@ -1,707 +1,707 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001, 2005 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 "kateviewspace.h" #include "katemainwindow.h" #include "kateviewmanager.h" #include "katedocmanager.h" #include "kateapp.h" #include "katesessionmanager.h" #include "katedebug.h" #include "katetabbar.h" #include "kactioncollection.h" #include "kateupdatedisabler.h" #include #include #include // remove #ifdef, once Kate depends on KF 5.24 #include #if KIO_VERSION >= QT_VERSION_CHECK(5, 24, 0) #include #endif #include #include #include #include #include #include #include #include #include //BEGIN KateViewSpace KateViewSpace::KateViewSpace(KateViewManager *viewManager, QWidget *parent, const char *name) : QWidget(parent) , m_viewManager(viewManager) , m_isActiveSpace(false) { setObjectName(QString::fromLatin1(name)); QVBoxLayout *layout = new QVBoxLayout(this); layout->setSpacing(0); layout->setMargin(0); //BEGIN tab bar QHBoxLayout *hLayout = new QHBoxLayout(); hLayout->setSpacing(0); hLayout->setMargin(0); // add tab bar m_tabBar = new KateTabBar(this); connect(m_tabBar, &KateTabBar::currentChanged, this, &KateViewSpace::changeView); connect(m_tabBar, &KateTabBar::moreTabsRequested, this, &KateViewSpace::addTabs); connect(m_tabBar, &KateTabBar::lessTabsRequested, this, &KateViewSpace::removeTabs); connect(m_tabBar, &KateTabBar::closeTabRequested, this, &KateViewSpace::closeTabRequest, Qt::QueuedConnection); connect(m_tabBar, &KateTabBar::contextMenuRequest, this, &KateViewSpace::showContextMenu, Qt::QueuedConnection); connect(m_tabBar, &KateTabBar::newTabRequested, this, &KateViewSpace::createNewDocument); connect(m_tabBar, SIGNAL(activateViewSpaceRequested()), this, SLOT(makeActive())); hLayout->addWidget(m_tabBar); // add quick open m_quickOpen = new QToolButton(this); m_quickOpen->setAutoRaise(true); KAcceleratorManager::setNoAccel(m_quickOpen); m_quickOpen->installEventFilter(this); // on click, active this view space hLayout->addWidget(m_quickOpen); // forward tab bar quick open action to globa quick open action QAction * bridge = new QAction(QIcon::fromTheme(QStringLiteral("tab-duplicate")), i18nc("indicator for more documents", "+%1", 100), this); m_quickOpen->setDefaultAction(bridge); QAction * quickOpen = m_viewManager->mainWindow()->actionCollection()->action(QStringLiteral("view_quick_open")); Q_ASSERT(quickOpen); bridge->setToolTip(quickOpen->toolTip()); bridge->setWhatsThis(i18n("Click here to switch to the Quick Open view.")); connect(bridge, SIGNAL(triggered()), quickOpen, SLOT(trigger())); // add vertical split view space m_split = new QToolButton(this); m_split->setAutoRaise(true); m_split->setPopupMode(QToolButton::InstantPopup); m_split->setIcon(QIcon::fromTheme(QStringLiteral("view-split-left-right"))); m_split->addAction(m_viewManager->mainWindow()->actionCollection()->action(QStringLiteral("view_split_vert"))); m_split->addAction(m_viewManager->mainWindow()->actionCollection()->action(QStringLiteral("view_split_horiz"))); m_split->addAction(m_viewManager->mainWindow()->actionCollection()->action(QStringLiteral("view_close_current_space"))); m_split->addAction(m_viewManager->mainWindow()->actionCollection()->action(QStringLiteral("view_close_others"))); m_split->addAction(m_viewManager->mainWindow()->actionCollection()->action(QStringLiteral("view_hide_others"))); m_split->setWhatsThis(i18n("Control view space splitting")); m_split->installEventFilter(this); // on click, active this view space hLayout->addWidget(m_split); layout->addLayout(hLayout); //END tab bar stack = new QStackedWidget(this); stack->setFocus(); stack->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding)); layout->addWidget(stack); m_group.clear(); // connect signal to hide/show statusbar connect(m_viewManager->mainWindow(), SIGNAL(statusBarToggled()), this, SLOT(statusBarToggled())); connect(m_viewManager->mainWindow(), SIGNAL(tabBarToggled()), this, SLOT(tabBarToggled())); // init the bars... statusBarToggled(); tabBarToggled(); // make sure we show correct number of hidden documents updateQuickOpen(); connect(KateApp::self()->documentManager(), SIGNAL(documentCreated(KTextEditor::Document*)), this, SLOT(updateQuickOpen())); connect(KateApp::self()->documentManager(), SIGNAL(documentsDeleted(const QList&)), this, SLOT(updateQuickOpen())); } bool KateViewSpace::eventFilter(QObject *obj, QEvent *event) { QToolButton *button = qobject_cast(obj); // quick open button: show tool tip with shortcut if (button == m_quickOpen && event->type() == QEvent::ToolTip) { QHelpEvent *e = static_cast(event); QAction *quickOpen = m_viewManager->mainWindow()->actionCollection()->action(QStringLiteral("view_quick_open")); Q_ASSERT(quickOpen); QToolTip::showText(e->globalPos(), button->toolTip() + QStringLiteral(" (%1)").arg(quickOpen->shortcut().toString()), button); return true; } // quick open button: What's This if (button == m_quickOpen && event->type() == QEvent::WhatsThis) { QHelpEvent *e = static_cast(event); const int hiddenDocs = hiddenDocuments(); QString helpText = (hiddenDocs == 0) ? i18n("Click here to switch to the Quick Open view.") : i18np("Currently, there is one more document open. To see all open documents, switch to the Quick Open view by clicking here.", "Currently, there are %1 more documents open. To see all open documents, switch to the Quick Open view by clicking here.", hiddenDocs); QWhatsThis::showText(e->globalPos(), helpText, m_quickOpen); return true; } // on mouse press on view space bar tool buttons: activate this space if (button && ! isActiveSpace() && event->type() == QEvent::MouseButtonPress) { m_viewManager->setActiveSpace(this); if (currentView()) { m_viewManager->activateView(currentView()->document()); } } return false; } void KateViewSpace::statusBarToggled() { KateUpdateDisabler updatesDisabled (m_viewManager->mainWindow()); Q_FOREACH(KTextEditor::Document * doc, m_lruDocList) { if (m_docToView.contains(doc)) { m_docToView[doc]->setStatusBarEnabled(m_viewManager->mainWindow()->showStatusBar()); } } } QVector KateViewSpace::lruDocumentList() const { return m_lruDocList; } void KateViewSpace::mergeLruList(const QVector & lruList) { // merge lruList documents that are not in m_lruDocList QVectorIterator it(lruList); it.toBack(); while (it.hasPrevious()) { KTextEditor::Document *doc = it.previous(); if (! m_lruDocList.contains(doc)) { registerDocument(doc, false); } } } void KateViewSpace::tabBarToggled() { KateUpdateDisabler updatesDisabled (m_viewManager->mainWindow()); m_tabBar->setVisible(m_viewManager->mainWindow()->showTabBar()); m_split->setVisible(m_viewManager->mainWindow()->showTabBar()); m_quickOpen->setVisible(m_viewManager->mainWindow()->showTabBar()); } KTextEditor::View *KateViewSpace::createView(KTextEditor::Document *doc) { // should only be called if a view does not yet exist Q_ASSERT(! m_docToView.contains(doc)); /** * Create a fresh view */ KTextEditor::View *v = doc->createView(stack, m_viewManager->mainWindow()->wrapper()); // set status bar to right state v->setStatusBarEnabled(m_viewManager->mainWindow()->showStatusBar()); // restore the config of this view if possible if (!m_group.isEmpty()) { QString fn = v->document()->url().toString(); if (! fn.isEmpty()) { QString vgroup = QString::fromLatin1("%1 %2").arg(m_group).arg(fn); KateSession::Ptr as = KateApp::self()->sessionManager()->activeSession(); if (as->config() && as->config()->hasGroup(vgroup)) { KConfigGroup cg(as->config(), vgroup); v->readSessionConfig(cg); } } } // register document, it is shown below through showView() then if (! m_lruDocList.contains(doc)) { registerDocument(doc); Q_ASSERT(m_lruDocList.contains(doc)); } // insert View into stack stack->addWidget(v); m_docToView[doc] = v; showView(v); return v; } void KateViewSpace::removeView(KTextEditor::View *v) { // remove view mappings Q_ASSERT(m_docToView.contains(v->document())); m_docToView.remove(v->document()); // ...and now: remove from view space stack->removeWidget(v); } bool KateViewSpace::showView(KTextEditor::Document *document) { const int index = m_lruDocList.lastIndexOf(document); if (index < 0) { return false; } if (! m_docToView.contains(document)) { return false; } KTextEditor::View *kv = m_docToView[document]; // move view to end of list m_lruDocList.removeAt(index); m_lruDocList.append(document); stack->setCurrentWidget(kv); kv->show(); // in case a tab does not exist, add one if (! m_docToTabId.contains(document)) { // if space is available, add button if (m_tabBar->count() < m_tabBar->maxTabCount()) { // just insert insertTab(0, document); } else { // remove "oldest" button and replace with new one Q_ASSERT(m_lruDocList.size() > m_tabBar->count()); // we need to subtract by 1 more, as we just added ourself to the end of the lru list! KTextEditor::Document * docToHide = m_lruDocList[m_lruDocList.size() - m_tabBar->maxTabCount() - 1]; Q_ASSERT(m_docToTabId.contains(docToHide)); removeTab(docToHide, false); // add new one always at the beginning insertTab(0, document); } } // follow current view Q_ASSERT(m_docToTabId.contains(document)); m_tabBar->setCurrentTab(m_docToTabId.value(document, -1)); return true; } void KateViewSpace::changeView(int id) { KTextEditor::Document *doc = m_docToTabId.key(id); Q_ASSERT(doc); // make sure we open the view in this view space if (! isActiveSpace()) { m_viewManager->setActiveSpace(this); } // tell the view manager to show the view m_viewManager->activateView(doc); } KTextEditor::View *KateViewSpace::currentView() { // might be 0 if the stack contains no view return (KTextEditor::View *)stack->currentWidget(); } bool KateViewSpace::isActiveSpace() { return m_isActiveSpace; } void KateViewSpace::setActive(bool active) { m_isActiveSpace = active; m_tabBar->setActive(active); } void KateViewSpace::makeActive(bool focusCurrentView) { if (! isActiveSpace()) { m_viewManager->setActiveSpace(this); if (focusCurrentView && currentView()) { m_viewManager->activateView(currentView()->document()); } } Q_ASSERT(isActiveSpace()); } void KateViewSpace::insertTab(int index, KTextEditor::Document * doc) { // doc should be in the lru list Q_ASSERT(m_lruDocList.contains(doc)); // doc should not have a id Q_ASSERT(! m_docToTabId.contains(doc)); const int id = m_tabBar->insertTab(index, doc->documentName()); m_tabBar->setTabToolTip(id, doc->url().toDisplayString()); m_docToTabId[doc] = id; updateDocumentState(doc); connect(doc, SIGNAL(documentNameChanged(KTextEditor::Document*)), this, SLOT(updateDocumentName(KTextEditor::Document*))); connect(doc, &KTextEditor::Document::documentUrlChanged, this, &KateViewSpace::updateDocumentUrl); connect(doc, SIGNAL(modifiedChanged(KTextEditor::Document*)), this, SLOT(updateDocumentState(KTextEditor::Document*))); } int KateViewSpace::removeTab(KTextEditor::Document * doc, bool documentDestroyed) { // // WARNING: removeTab() is also called from documentDestroyed(). // Therefore, is may be that doc is half destroyed already. // Therefore, do not access any KTextEditor::Document functions here! // Only access QObject functions! // Q_ASSERT(m_docToTabId.contains(doc)); const int id = m_docToTabId.value(doc, -1); const int removeIndex = m_tabBar->removeTab(id); m_docToTabId.remove(doc); if (!documentDestroyed) { disconnect(doc, SIGNAL(documentNameChanged(KTextEditor::Document*)), this, SLOT(updateDocumentName(KTextEditor::Document*))); disconnect(doc, &KTextEditor::Document::documentUrlChanged, this, &KateViewSpace::updateDocumentUrl); disconnect(doc, SIGNAL(modifiedChanged(KTextEditor::Document*)), this, SLOT(updateDocumentState(KTextEditor::Document*))); } return removeIndex; } void KateViewSpace::removeTabs(int count) { const int start = count; /// remove @p count tabs from the tab bar, as they do not all fit while (count > 0) { const int tabCount = m_tabBar->count(); KTextEditor::Document * removeDoc = m_lruDocList[m_lruDocList.size() - tabCount]; removeTab(removeDoc, false); Q_ASSERT(! m_docToTabId.contains(removeDoc)); --count; } // make sure quick open shows the correct number of hidden documents if (start != count) { updateQuickOpen(); } } void KateViewSpace::addTabs(int count) { const int start = count; /// @p count tabs still fit into the tab bar: add as man as possible while (count > 0) { const int tabCount = m_tabBar->count(); if (m_lruDocList.size() <= tabCount) { break; } insertTab(tabCount, m_lruDocList[m_lruDocList.size() - tabCount - 1]); --count; } // make sure quick open shows the correct number of hidden documents if (start != count) { updateQuickOpen(); } } void KateViewSpace::registerDocument(KTextEditor::Document *doc, bool append) { // at this point, the doc should be completely unknown Q_ASSERT(! m_lruDocList.contains(doc)); Q_ASSERT(! m_docToView.contains(doc)); Q_ASSERT(! m_docToTabId.contains(doc)); if (append) { m_lruDocList.append(doc); } else { // prepending == merge doc of closed viewspace m_lruDocList.prepend(doc); } connect(doc, SIGNAL(destroyed(QObject*)), this, SLOT(documentDestroyed(QObject*))); // if space is available, add button if (m_tabBar->count() < m_tabBar->maxTabCount()) { insertTab(0, doc); updateQuickOpen(); } else if (append) { // remove "oldest" button and replace with new one Q_ASSERT(m_lruDocList.size() > m_tabBar->count()); KTextEditor::Document * docToHide = m_lruDocList[m_lruDocList.size() - m_tabBar->maxTabCount() - 1]; Q_ASSERT(m_docToTabId.contains(docToHide)); removeTab(docToHide, false); // add new one at removed position insertTab(0, doc); } } void KateViewSpace::documentDestroyed(QObject *doc) { // WARNING: this pointer is half destroyed KTextEditor::Document *invalidDoc = static_cast(doc); Q_ASSERT(m_lruDocList.contains(invalidDoc)); m_lruDocList.remove(m_lruDocList.indexOf(invalidDoc)); // disconnect entirely - disconnect(doc, 0, this, 0); + disconnect(doc, nullptr, this, nullptr); // case: there was no view created yet, but still a button was added if (m_docToTabId.contains(invalidDoc)) { removeTab(invalidDoc, true); // maybe show another tab button in its stead if (m_lruDocList.size() >= m_tabBar->maxTabCount() && m_tabBar->count() < m_tabBar->maxTabCount() ) { KTextEditor::Document * docToShow = m_lruDocList[m_lruDocList.size() - m_tabBar->count() - 1]; Q_ASSERT(! m_docToTabId.contains(docToShow)); // add tab that now fits into the bar insertTab(m_tabBar->count(), docToShow); } } // at this point, the doc should be completely unknown Q_ASSERT(! m_lruDocList.contains(invalidDoc)); Q_ASSERT(! m_docToView.contains(invalidDoc)); Q_ASSERT(! m_docToTabId.contains(invalidDoc)); } void KateViewSpace::updateDocumentName(KTextEditor::Document *doc) { const int buttonId = m_docToTabId[doc]; Q_ASSERT(buttonId >= 0); m_tabBar->setTabText(buttonId, doc->documentName()); m_tabBar->setTabToolTip(buttonId, doc->url().toDisplayString()); } void KateViewSpace::updateDocumentUrl(KTextEditor::Document *doc) { const int buttonId = m_docToTabId[doc]; Q_ASSERT(buttonId >= 0); m_tabBar->setTabUrl(buttonId, doc->url()); } void KateViewSpace::updateDocumentState(KTextEditor::Document *doc) { QIcon icon; if (doc->isModified()) { icon = QIcon::fromTheme(QLatin1String("document-save")); } Q_ASSERT(m_docToTabId.contains(doc)); const int buttonId = m_docToTabId[doc]; m_tabBar->setTabIcon(buttonId, icon); } void KateViewSpace::closeTabRequest(int id) { KTextEditor::Document *doc = m_docToTabId.key(id); Q_ASSERT(doc); KateApp::self()->documentManager()->closeDocument(doc); } void KateViewSpace::createNewDocument() { // make sure we open the view in this view space if (! isActiveSpace()) { m_viewManager->setActiveSpace(this); } // create document KTextEditor::Document *doc = KateApp::self()->documentManager()->createDoc(); // tell the view manager to show the document m_viewManager->activateView(doc); } void KateViewSpace::updateQuickOpen() { const int hiddenDocs = hiddenDocuments(); if (hiddenDocs == 0) { m_quickOpen->setToolButtonStyle(Qt::ToolButtonIconOnly); m_quickOpen->defaultAction()->setText(QString()); } else { m_quickOpen->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); m_quickOpen->defaultAction()->setText(i18nc("indicator for more documents", "+%1", hiddenDocs)); } } void KateViewSpace::focusPrevTab() { const int id = m_tabBar->prevTab(); if (id >= 0) { changeView(id); } } void KateViewSpace::focusNextTab() { const int id = m_tabBar->nextTab(); if (id >= 0) { changeView(id); } } int KateViewSpace::hiddenDocuments() const { const int hiddenDocs = KateApp::self()->documents().count() - m_tabBar->count(); Q_ASSERT(hiddenDocs >= 0); return hiddenDocs; } void KateViewSpace::showContextMenu(int id, const QPoint & globalPos) { // right now, show no context menu on empty tab bar space if (id < 0) { return; } KTextEditor::Document *doc = m_docToTabId.key(id); Q_ASSERT(doc); QMenu menu(this); QAction *aCloseTab = menu.addAction(QIcon::fromTheme(QStringLiteral("tab-close")), i18n("&Close Document")); QAction *aCloseOthers = menu.addAction(QIcon::fromTheme(QStringLiteral("tab-close-other")), i18n("Close Other &Documents")); menu.addSeparator(); QAction *aCopyPath = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy &Path")); QAction *aOpenFolder = menu.addAction(QIcon::fromTheme(QStringLiteral("document-open-folder")), i18n("&Open Containing Folder")); if (KateApp::self()->documentManager()->documentList().count() < 2) { aCloseOthers->setEnabled(false); } if (doc->url().isEmpty()) { aCopyPath->setEnabled(false); aOpenFolder->setEnabled(false); } QAction *choice = menu.exec(globalPos); if (choice == aCloseTab) { closeTabRequest(id); } else if (choice == aCloseOthers) { KateApp::self()->documentManager()->closeOtherDocuments(doc); } else if (choice == aCopyPath) { QApplication::clipboard()->setText(doc->url().toDisplayString(QUrl::PreferLocalFile)); } else if (choice == aOpenFolder) { #if KIO_VERSION >= QT_VERSION_CHECK(5, 24, 0) KIO::highlightInFileManager({doc->url()}); #else QDesktopServices::openUrl(doc->url().adjusted(QUrl::RemoveFilename)); #endif } } void KateViewSpace::saveConfig(KConfigBase *config, int myIndex , const QString &viewConfGrp) { // qCDebug(LOG_KATE)<<"KateViewSpace::saveConfig("< views; QStringList lruList; Q_FOREACH(KTextEditor::Document* doc, m_lruDocList) { lruList << doc->url().toString(); if (m_docToView.contains(doc)) { views.append(m_docToView[doc]); } } KConfigGroup group(config, groupname); group.writeEntry("Documents", lruList); group.writeEntry("Count", views.count()); if (currentView()) { group.writeEntry("Active View", currentView()->document()->url().toString()); } // Save file list, including cursor position in this instance. int idx = 0; for (QVector::iterator it = views.begin(); it != views.end(); ++it) { if (!(*it)->document()->url().isEmpty()) { group.writeEntry(QString::fromLatin1("View %1").arg(idx), (*it)->document()->url().toString()); // view config, group: "ViewSpace url" QString vgroup = QString::fromLatin1("%1 %2").arg(groupname).arg((*it)->document()->url().toString()); KConfigGroup viewGroup(config, vgroup); (*it)->writeSessionConfig(viewGroup); } ++idx; } } void KateViewSpace::restoreConfig(KateViewManager *viewMan, const KConfigBase *config, const QString &groupname) { KConfigGroup group(config, groupname); // restore Document lru list so that all tabs from the last session reappear const QStringList lruList = group.readEntry("Documents", QStringList()); for (int i = 0; i < lruList.size(); ++i) { auto doc = KateApp::self()->documentManager()->findDocument(QUrl(lruList[i])); if (doc) { const int index = m_lruDocList.indexOf(doc); if (index < 0) { registerDocument(doc); Q_ASSERT(m_lruDocList.contains(doc)); } else { m_lruDocList.removeAt(index); m_lruDocList.append(doc); } } } // restore active view properties const QString fn = group.readEntry("Active View"); if (!fn.isEmpty()) { KTextEditor::Document *doc = KateApp::self()->documentManager()->findDocument(QUrl(fn)); if (doc) { // view config, group: "ViewSpace url" QString vgroup = QString::fromLatin1("%1 %2").arg(groupname).arg(fn); KConfigGroup configGroup(config, vgroup); auto view = viewMan->createView(doc, this); if (view) { view->readSessionConfig(configGroup); } } } // avoid empty view space if (m_docToView.isEmpty()) { viewMan->createView (KateApp::self()->documentManager()->documentList().first(), this); } m_group = groupname; // used for restroing view configs later } //END KateViewSpace diff --git a/kate/kateviewspace.h b/kate/kateviewspace.h index 425bc56ce..ed844cdf2 100644 --- a/kate/kateviewspace.h +++ b/kate/kateviewspace.h @@ -1,214 +1,214 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 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. */ #ifndef KATE_VIEWSPACE_H #define KATE_VIEWSPACE_H #include #include #include #include #include class KConfigBase; class KateViewManager; class QStackedWidget; class QToolButton; class KateTabBar; class KateViewSpace : public QWidget { Q_OBJECT public: - explicit KateViewSpace(KateViewManager *, QWidget *parent = 0, const char *name = 0); + explicit KateViewSpace(KateViewManager *, QWidget *parent = nullptr, const char *name = nullptr); /** * Returns \e true, if this view space is currently the active view space. */ bool isActiveSpace(); /** * Depending on @p active, mark this view space as active or inactive. * Called from the view manager. */ void setActive(bool active); /** * Create new view for given document * @param doc document to create view for * @return new created view */ KTextEditor::View *createView(KTextEditor::Document *doc); void removeView(KTextEditor::View *v); bool showView(KTextEditor::View *view) { return showView(view->document()); } bool showView(KTextEditor::Document *document); // might be nullptr, if there is no view KTextEditor::View *currentView(); void saveConfig(KConfigBase *config, int myIndex, const QString &viewConfGrp); void restoreConfig(KateViewManager *viewMan, const KConfigBase *config, const QString &group); /** * Returns the document LRU list of this view space. */ QVector lruDocumentList() const; /** * Called by the view manager if a viewspace was closed. * The documents of the closed are merged into this viewspace */ void mergeLruList(const QVector & lruList); /** * Called by the view manager to notify that new documents were created * while this view space was active. If @p append is @e true, the @p doc * is appended to the lru document list, otherwise, it is prepended. */ void registerDocument(KTextEditor::Document *doc, bool append = true); /** * Event filter to catch events from view space tool buttons. */ bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; /** * Focus the previous tab in the tabbar. */ void focusPrevTab(); /** * Focus the next tab in the tabbar. */ void focusNextTab(); public Q_SLOTS: void documentDestroyed(QObject *doc); void updateDocumentName(KTextEditor::Document *doc); void updateDocumentUrl(KTextEditor::Document *doc); void updateDocumentState(KTextEditor::Document *doc); private Q_SLOTS: void statusBarToggled(); void tabBarToggled(); void changeView(int buttonId); /** * Calls this slot to make this view space the currently active view space. * Making it active goes through the KateViewManager. * @param focusCurrentView if @e true, the current view will get focus */ void makeActive(bool focusCurrentView = true); /** * Add a tab for @p doc at position @p index. */ void insertTab(int index, KTextEditor::Document * doc); /** * Remove tab for @p doc, and return the index (position) * of the removed tab. */ int removeTab(KTextEditor::Document * doc, bool documentDestroyed); /** * Remove @p count tabs, since the tab bar shrinked. */ void removeTabs(int count); /** * Add @p count tabs, since the tab bar grew. */ void addTabs(int count); /** * This slot is called by the tabbar, if tab @p id was closed through the * context menu. */ void closeTabRequest(int id); /** * This slot is called when the context menu is requested for button * @p id at position @p globalPos. * @param id the button, or -1 if the context menu was requested on * at a place where no tab exists * @param globalPos the position of the context menu in global coordinates */ void showContextMenu(int id, const QPoint & globalPos); /** * Called to create a new empty document. */ void createNewDocument(); /** * Update the quick open button to reflect the currently hidden tabs. */ void updateQuickOpen(); private: /** * Returns the amount of documents in KateDocManager that currently * have no tab in this tab bar. */ int hiddenDocuments() const; private: // Kate's view manager KateViewManager *m_viewManager; // config group string, used for restoring View session configuration QString m_group; // flag that indicates whether this view space is the active one. // correct setter: m_viewManager->setActiveSpace(this); bool m_isActiveSpace; // widget stack that contains all KTE::Views QStackedWidget *stack; // document's in the view space, sorted in LRU mode: // the most recently used Document is at the end of the list QVector m_lruDocList; // the list of views that are contained in this view space, // mapped through a hash from Document to View. // note: the number of entries match stack->count(); QHash m_docToView; // tab bar that contains viewspace tabs KateTabBar *m_tabBar; // split action QToolButton *m_split; // quick open action QToolButton *m_quickOpen; // map from Document to button id QHash m_docToTabId; }; #endif diff --git a/kate/main.cpp b/kate/main.cpp index 342cd5db3..dcaf184a2 100644 --- a/kate/main.cpp +++ b/kate/main.cpp @@ -1,584 +1,584 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2002 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 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 "config.h" #include "kateapp.h" #include "katerunninginstanceinfo.h" #include "katewaiter.h" #include #include // for KAboutData::setDesktopFileName() #include #include #include #include #include #if KCrash_VERSION >= QT_VERSION_CHECK(5, 15, 0) #include #endif // KCrash >= 5.15 #include #include #include #include #include #include #include #include #include #include #include "../urlinfo.h" #ifdef USE_QT_SINGLE_APP #include "qtsingleapplication/qtsingleapplication.h" #endif #ifndef Q_OS_WIN #include #endif #include int main(int argc, char **argv) { #ifndef Q_OS_WIN /** * Check whether we are running as root **/ if (getuid() == 0) { std::cout << "Executing Kate as root is not possible. To edit files as root use:" << std::endl; std::cout << "SUDO_EDITOR=kate sudoedit " << std::endl; return 0; } #endif /** * init resources from our static lib */ Q_INIT_RESOURCE(kate); /** * Create application first */ #ifdef USE_QT_SINGLE_APP SharedTools::QtSingleApplication app(QStringLiteral("kate"),argc, argv); #else QApplication app(argc, argv); #endif /** * Enforce application name even if the executable is renamed */ app.setApplicationName(QStringLiteral("kate")); /** * enable high dpi support */ app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); /** * Enable crash handling through KCrash. */ #if KCrash_VERSION >= QT_VERSION_CHECK(5, 15, 0) KCrash::initialize(); #endif /** * Connect application with translation catalogs */ KLocalizedString::setApplicationDomain("kate"); /** * construct about data for Kate */ KAboutData aboutData(QStringLiteral("kate"), i18n("Kate"), QStringLiteral(KATE_VERSION), i18n("Kate - Advanced Text Editor"), KAboutLicense::LGPL_V2, i18n("(c) 2000-2017 The Kate Authors"), QString(), QStringLiteral("http://kate-editor.org")); /** * right dbus prefix == org.kde. */ aboutData.setOrganizationDomain("kde.org"); /** * desktop file association to make application icon work (e.g. in Wayland window decoration) */ #if KCOREADDONS_VERSION >= QT_VERSION_CHECK(5, 16, 0) aboutData.setDesktopFileName(QStringLiteral("org.kde.kate")); #endif aboutData.addAuthor(i18n("Christoph Cullmann"), i18n("Maintainer"), QStringLiteral("cullmann@kde.org"), QStringLiteral("http://www.cullmann.io")); aboutData.addAuthor(i18n("Anders Lund"), i18n("Core Developer"), QStringLiteral("anders@alweb.dk"), QStringLiteral("http://www.alweb.dk")); aboutData.addAuthor(i18n("Joseph Wenninger"), i18n("Core Developer"), QStringLiteral("jowenn@kde.org"), QStringLiteral("http://stud3.tuwien.ac.at/~e9925371")); aboutData.addAuthor(i18n("Hamish Rodda"), i18n("Core Developer"), QStringLiteral("rodda@kde.org")); aboutData.addAuthor(i18n("Dominik Haumann"), i18n("Developer & Highlight wizard"), QStringLiteral("dhdev@gmx.de")); aboutData.addAuthor(i18n("Kåre Särs"), i18n("Developer"), QStringLiteral("kare.sars@iki.fi")); aboutData.addAuthor(i18n("Alexander Neundorf"), i18n("Developer"), QStringLiteral("neundorf@kde.org")); aboutData.addAuthor(i18n("Sven Brauch"), i18n("Developer"), QStringLiteral("mail@svenbrauch.de")); aboutData.addAuthor(i18n("Waldo Bastian"), i18n("The cool buffersystem"), QStringLiteral("bastian@kde.org")); aboutData.addAuthor(i18n("Charles Samuels"), i18n("The Editing Commands"), QStringLiteral("charles@kde.org")); aboutData.addAuthor(i18n("Matt Newell"), i18n("Testing, ..."), QStringLiteral("newellm@proaxis.com")); aboutData.addAuthor(i18n("Michael Bartl"), i18n("Former Core Developer"), QStringLiteral("michael.bartl1@chello.at")); aboutData.addAuthor(i18n("Michael McCallum"), i18n("Core Developer"), QStringLiteral("gholam@xtra.co.nz")); aboutData.addAuthor(i18n("Jochen Wilhemly"), i18n("KWrite Author"), QStringLiteral("digisnap@cs.tu-berlin.de")); aboutData.addAuthor(i18n("Michael Koch"), i18n("KWrite port to KParts"), QStringLiteral("koch@kde.org")); aboutData.addAuthor(i18n("Christian Gebauer"), QString(), QStringLiteral("gebauer@kde.org")); aboutData.addAuthor(i18n("Simon Hausmann"), QString(), QStringLiteral("hausmann@kde.org")); aboutData.addAuthor(i18n("Glen Parker"), i18n("KWrite Undo History, Kspell integration"), QStringLiteral("glenebob@nwlink.com")); aboutData.addAuthor(i18n("Scott Manson"), i18n("KWrite XML Syntax highlighting support"), QStringLiteral("sdmanson@alltel.net")); aboutData.addAuthor(i18n("John Firebaugh"), i18n("Patches and more"), QStringLiteral("jfirebaugh@kde.org")); aboutData.addAuthor(i18n("Pablo Martín"), i18n("Python Plugin Developer"), QStringLiteral("goinnn@gmail.com"), QStringLiteral("http://github.com/goinnn/")); aboutData.addAuthor(i18n("Gerald Senarclens de Grancy"), i18n("QA and Scripting"), QStringLiteral("oss@senarclens.eu"), QStringLiteral("http://find-santa.eu/")); aboutData.addCredit(i18n("Matteo Merli"), i18n("Highlighting for RPM Spec-Files, Perl, Diff and more"), QStringLiteral("merlim@libero.it")); aboutData.addCredit(i18n("Rocky Scaletta"), i18n("Highlighting for VHDL"), QStringLiteral("rocky@purdue.edu")); aboutData.addCredit(i18n("Yury Lebedev"), i18n("Highlighting for SQL")); aboutData.addCredit(i18n("Chris Ross"), i18n("Highlighting for Ferite")); aboutData.addCredit(i18n("Nick Roux"), i18n("Highlighting for ILERPG")); aboutData.addCredit(i18n("Carsten Niehaus"), i18n("Highlighting for LaTeX")); aboutData.addCredit(i18n("Per Wigren"), i18n("Highlighting for Makefiles, Python")); aboutData.addCredit(i18n("Jan Fritz"), i18n("Highlighting for Python")); aboutData.addCredit(i18n("Daniel Naber")); aboutData.addCredit(i18n("Roland Pabel"), i18n("Highlighting for Scheme")); aboutData.addCredit(i18n("Cristi Dumitrescu"), i18n("PHP Keyword/Datatype list")); aboutData.addCredit(i18n("Carsten Pfeiffer"), i18n("Very nice help")); aboutData.addCredit(i18n("All people who have contributed and I have forgotten to mention")); /** * set the new Kate mascot */ aboutData.setProgramLogo (QImage(QLatin1String(":/kate/mascot.png"))); /** * set and register app about data */ KAboutData::setApplicationData(aboutData); /** * set the program icon */ QApplication::setWindowIcon(QIcon::fromTheme(QLatin1String("kate"), app.windowIcon())); /** * Create command line parser and feed it with known options */ QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.addHelpOption(); parser.addVersionOption(); // -s/--start session option const QCommandLineOption startSessionOption(QStringList() << QStringLiteral("s") << QStringLiteral("start"), i18n("Start Kate with a given session."), i18n("session")); parser.addOption(startSessionOption); // --startanon session option const QCommandLineOption startAnonymousSessionOption(QStringList() << QStringLiteral("startanon"), i18n("Start Kate with a new anonymous session, implies '-n'.")); parser.addOption(startAnonymousSessionOption); // -n/--new option const QCommandLineOption startNewInstanceOption(QStringList() << QStringLiteral("n") << QStringLiteral("new"), i18n("Force start of a new kate instance (is ignored if start is used and another kate instance already has the given session opened), forced if no parameters and no URLs are given at all.")); parser.addOption(startNewInstanceOption); // -b/--block option const QCommandLineOption startBlockingOption(QStringList() << QStringLiteral("b") << QStringLiteral("block"), i18n("If using an already running kate instance, block until it exits, if URLs given to open.")); parser.addOption(startBlockingOption); // -p/--pid option const QCommandLineOption usePidOption(QStringList() << QStringLiteral("p") << QStringLiteral("pid"), i18n("Only try to reuse kate instance with this pid (is ignored if start is used and another kate instance already has the given session opened)."), i18n("pid")); parser.addOption(usePidOption); // -e/--encoding option const QCommandLineOption useEncodingOption(QStringList() << QStringLiteral("e") << QStringLiteral("encoding"), i18n("Set encoding for the file to open."), i18n("encoding")); parser.addOption(useEncodingOption); // -l/--line option const QCommandLineOption gotoLineOption(QStringList() << QStringLiteral("l") << QStringLiteral("line"), i18n("Navigate to this line."), i18n("line")); parser.addOption(gotoLineOption); // -c/--column option const QCommandLineOption gotoColumnOption(QStringList() << QStringLiteral("c") << QStringLiteral("column"), i18n("Navigate to this column."), i18n("column")); parser.addOption(gotoColumnOption); // -i/--stdin option const QCommandLineOption readStdInOption(QStringList() << QStringLiteral("i") << QStringLiteral("stdin"), i18n("Read the contents of stdin.")); parser.addOption(readStdInOption); // --tempfile option const QCommandLineOption tempfileOption(QStringList() << QStringLiteral("tempfile"), i18n("The files/URLs opened by the application will be deleted after use")); parser.addOption(tempfileOption); // urls to open parser.addPositionalArgument(QStringLiteral("urls"), i18n("Documents to open."), i18n("[urls...]")); /** * do the command line parsing */ parser.process(app); /** * handle standard options */ aboutData.processCommandLine(&parser); /** * remember the urls we shall open */ const QStringList urls = parser.positionalArguments(); /** * compute if we shall start a new instance or reuse * an old one * this will later be updated once more after detecting some * things about already running kate's, like their sessions */ bool force_new = parser.isSet(startNewInstanceOption); if (!force_new) { if (!( parser.isSet(startSessionOption) || parser.isSet(startNewInstanceOption) || parser.isSet(usePidOption) || parser.isSet(useEncodingOption) || parser.isSet(gotoLineOption) || parser.isSet(gotoColumnOption) || parser.isSet(readStdInOption) ) && (urls.isEmpty())) { force_new = true; } } /** * only block, if files to open there.... */ const bool needToBlock = parser.isSet(startBlockingOption) && !urls.isEmpty(); /** * use dbus, if available for linux and co. * allows for resuse of running Kate instances */ #ifndef USE_QT_SINGLE_APP if (QDBusConnectionInterface * const sessionBusInterface = QDBusConnection::sessionBus().interface()) { /** * try to get the current running kate instances */ KateRunningInstanceMap mapSessionRii; if (!fillinRunningKateAppInstances(&mapSessionRii)) { return 1; } QStringList kateServices; for (KateRunningInstanceMap::const_iterator it = mapSessionRii.constBegin(); it != mapSessionRii.constEnd(); ++it) { kateServices << (*it)->serviceName; } QString serviceName; QString start_session; bool session_already_opened = false; //check if we try to start an already opened session if (parser.isSet(startAnonymousSessionOption)) { force_new = true; } else if (parser.isSet(startSessionOption)) { start_session = parser.value(startSessionOption); if (mapSessionRii.contains(start_session)) { serviceName = mapSessionRii[start_session]->serviceName; force_new = false; session_already_opened = true; } } //cleanup map cleanupRunningKateAppInstanceMap(&mapSessionRii); //if no new instance is forced and no already opened session is requested, //check if a pid is given, which should be reused. // two possibilities: pid given or not... if ((!force_new) && serviceName.isEmpty()) { if ((parser.isSet(usePidOption)) || (!qgetenv("KATE_PID").isEmpty())) { QString usePid = (parser.isSet(usePidOption)) ? parser.value(usePidOption) : QString::fromLocal8Bit(qgetenv("KATE_PID")); serviceName = QStringLiteral("org.kde.kate-") + usePid; if (!kateServices.contains(serviceName)) { serviceName.clear(); } } } // prefer the Kate instance running on the current virtual desktop bool foundRunningService = false; if ((!force_new) && (serviceName.isEmpty())) { const int desktopnumber = KWindowSystem::currentDesktop(); int sessionDesktopNumber; for (int s = 0; s < kateServices.count(); s++) { serviceName = kateServices[s]; if (!serviceName.isEmpty()) { QDBusReply there = sessionBusInterface->isServiceRegistered(serviceName); if (there.isValid() && there.value()) { sessionDesktopNumber = -1; // query instance current desktop QDBusMessage m = QDBusMessage::createMethodCall(serviceName, QStringLiteral("/MainApplication"), QStringLiteral("org.kde.Kate.Application"), QStringLiteral("desktopNumber")); QDBusMessage res = QDBusConnection::sessionBus().call(m); QList answer = res.arguments(); if (answer.size() == 1) { sessionDesktopNumber = answer.at(0).toInt(); if (sessionDesktopNumber == desktopnumber) { // stop searching. a candidate instance in the current desktop has been found foundRunningService = true; break; } } } } serviceName.clear(); } } //check again if service is still running foundRunningService = false; if (!serviceName.isEmpty()) { QDBusReply there = sessionBusInterface->isServiceRegistered(serviceName); foundRunningService = there.isValid() && there.value(); } if (foundRunningService) { // open given session if (parser.isSet(startSessionOption) && (!session_already_opened)) { QDBusMessage m = QDBusMessage::createMethodCall(serviceName, QStringLiteral("/MainApplication"), QStringLiteral("org.kde.Kate.Application"), QStringLiteral("activateSession")); QList dbusargs; dbusargs.append(parser.value(startSessionOption)); m.setArguments(dbusargs); QDBusConnection::sessionBus().call(m); } QString enc = parser.isSet(useEncodingOption) ? parser.value(useEncodingOption) : QString(); bool tempfileSet = parser.isSet(tempfileOption); QStringList tokens; // open given files... foreach(const QString & url, urls) { QDBusMessage m = QDBusMessage::createMethodCall(serviceName, QStringLiteral("/MainApplication"), QStringLiteral("org.kde.Kate.Application"), QStringLiteral("tokenOpenUrlAt")); UrlInfo info(url); QList dbusargs; // convert to an url dbusargs.append(info.url.toString()); dbusargs.append(info.cursor.line()); dbusargs.append(info.cursor.column()); dbusargs.append(enc); dbusargs.append(tempfileSet); m.setArguments(dbusargs); QDBusMessage res = QDBusConnection::sessionBus().call(m); if (res.type() == QDBusMessage::ReplyMessage) { if (res.arguments().count() == 1) { QVariant v = res.arguments()[0]; if (v.isValid()) { QString s = v.toString(); if ((!s.isEmpty()) && (s != QStringLiteral("ERROR"))) { tokens << s; } } } } } if (parser.isSet(readStdInOption)) { QTextStream input(stdin, QIODevice::ReadOnly); // set chosen codec QTextCodec *codec = parser.isSet(useEncodingOption) ? - QTextCodec::codecForName(parser.value(useEncodingOption).toUtf8()) : 0; + QTextCodec::codecForName(parser.value(useEncodingOption).toUtf8()) : nullptr; if (codec) { input.setCodec(codec); } QString line; QString text; do { line = input.readLine(); text.append(line + QLatin1Char('\n')); } while (!line.isNull()); QDBusMessage m = QDBusMessage::createMethodCall(serviceName, QStringLiteral("/MainApplication"), QStringLiteral("org.kde.Kate.Application"), QStringLiteral("openInput")); QList dbusargs; dbusargs.append(text); dbusargs.append(codec ? QString::fromLatin1(codec->name()) : QString()); m.setArguments(dbusargs); QDBusConnection::sessionBus().call(m); } int line = 0; int column = 0; bool nav = false; if (parser.isSet(gotoLineOption)) { line = parser.value(gotoLineOption).toInt() - 1; nav = true; } if (parser.isSet(gotoColumnOption)) { column = parser.value(gotoColumnOption).toInt() - 1; nav = true; } if (nav) { QDBusMessage m = QDBusMessage::createMethodCall(serviceName, QStringLiteral("/MainApplication"), QStringLiteral("org.kde.Kate.Application"), QStringLiteral("setCursor")); QList args; args.append(line); args.append(column); m.setArguments(args); QDBusConnection::sessionBus().call(m); } // activate the used instance QDBusMessage activateMsg = QDBusMessage::createMethodCall(serviceName, QStringLiteral("/MainApplication"), QStringLiteral("org.kde.Kate.Application"), QStringLiteral("activate")); QDBusConnection::sessionBus().call(activateMsg); // connect dbus signal if (needToBlock) { KateWaiter *waiter = new KateWaiter(serviceName, tokens); QDBusConnection::sessionBus().connect(serviceName, QStringLiteral("/MainApplication"), QStringLiteral("org.kde.Kate.Application"), QStringLiteral("exiting"), waiter, SLOT(exiting())); QDBusConnection::sessionBus().connect(serviceName, QStringLiteral("/MainApplication"), QStringLiteral("org.kde.Kate.Application"), QStringLiteral("documentClosed"), waiter, SLOT(documentClosed(QString))); } // KToolInvocation (and KRun) will wait until we register on dbus KDBusService dbusService(KDBusService::Multiple); dbusService.unregister(); // make the world happy, we are started, kind of... KStartupInfo::appStarted(); // this will wait until exiting is emitted by the used instance, if wanted... return needToBlock ? app.exec() : 0; } } /** * for mac & windows: use QtSingleApplication */ #else /** * only try to reuse existing kate instances if not already forbidden by arguments */ if (!force_new) { /** * any instance running we can use? * later we could do here pid checks and stuff */ bool instanceFound = app.isRunning(); /** * if instance was found, send over all urls to be opened */ if (instanceFound) { /** * tell single application to block if needed */ app.setBlock(needToBlock); /** * construct one big message with all urls to open * later we will add additional data to this */ QVariantMap message; QVariantList messageUrls; foreach(const QString & url, urls) { /** * get url info and pack them into the message as extra element in urls list */ UrlInfo info(url); QVariantMap urlMessagePart; urlMessagePart[QLatin1String("url")] = info.url; urlMessagePart[QLatin1String("line")] = info.cursor.line(); urlMessagePart[QLatin1String("column")] = info.cursor.column(); messageUrls.append(urlMessagePart); } message[QLatin1String("urls")] = messageUrls; /** * try to send message, return success */ return !app.sendMessage(QString::fromUtf8(QJsonDocument::fromVariant(QVariant(message)).toJson())); } } #endif // USE_QT_SINGLE_APP /** * if we arrive here, we need to start a new kate instance! */ /** * construct the real kate app object ;) * behaves like a singleton, one unique instance * we are passing our local command line parser to it */ KateApp kateApp(parser); /** * init kate * if this returns false, we shall exit * else we may enter the main event loop */ if (!kateApp.init()) { return 0; } #ifndef USE_QT_SINGLE_APP /** * finally register this kate instance for dbus, don't die if no dbus is around! */ const KDBusService dbusService(KDBusService::Multiple | KDBusService::NoExitOnFailure); #else /** * else: connect the single application notifications */ QObject::connect(&app, &SharedTools::QtSingleApplication::messageReceived, &kateApp, &KateApp::remoteMessageReceived); #endif /** * start main event loop for our application */ return app.exec(); } diff --git a/kate/session/katesession.cpp b/kate/session/katesession.cpp index aa5a37e6a..4f64b78ad 100644 --- a/kate/session/katesession.cpp +++ b/kate/session/katesession.cpp @@ -1,130 +1,130 @@ /* This file is part of the KDE project * * Copyright (C) 2005 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 "katesession.h" #include "katesessionmanager.h" #include "katedebug.h" #include #include #include #include #include static const QLatin1String opGroupName("Open Documents"); static const QLatin1String keyCount("Count"); KateSession::KateSession(const QString &file, const QString &name, const bool anonymous, const KConfig *_config) : m_name(name) , m_file(file) , m_anonymous(anonymous) , m_documents(0) - , m_config(0) + , m_config(nullptr) , m_timestamp() { Q_ASSERT(!m_file.isEmpty()); if (_config) { // copy data from config instead m_config = _config->copyTo(m_file); } else if (!QFile::exists(m_file)) { // given file exists, use it to load some stuff qCDebug(LOG_KATE) << "Warning, session file not found: " << m_file; return; } m_timestamp = QFileInfo(m_file).lastModified(); // get the document count m_documents = config()->group(opGroupName).readEntry(keyCount, 0); } KateSession::~KateSession() { delete m_config; } const QString &KateSession::file() const { return m_file; } void KateSession::setDocuments(const unsigned int number) { config()->group(opGroupName).writeEntry(keyCount, number); m_documents = number; } void KateSession::setFile(const QString &filename) { if (m_config) { KConfig *cfg = m_config->copyTo(filename); delete m_config; m_config = cfg; } m_file = filename; } void KateSession::setName(const QString &name) { m_name = name; } KConfig *KateSession::config() { if (m_config) { return m_config; } // reread documents number? return m_config = new KConfig(m_file, KConfig::SimpleConfig); } KateSession::Ptr KateSession::create(const QString &file, const QString &name) { return Ptr(new KateSession(file, name, false)); } KateSession::Ptr KateSession::createFrom(const KateSession::Ptr &session, const QString &file, const QString &name) { return Ptr(new KateSession(file, name, false, session->config())); } KateSession::Ptr KateSession::createAnonymous(const QString &file) { return Ptr(new KateSession(file, QString(), true)); } KateSession::Ptr KateSession::createAnonymousFrom(const KateSession::Ptr &session, const QString &file) { return Ptr(new KateSession(file, QString(), true, session->config())); } bool KateSession::compareByName(const KateSession::Ptr &s1, const KateSession::Ptr &s2) { return QCollator().compare(s1->name(), s2->name()) == -1; } bool KateSession::compareByTimeDesc(const KateSession::Ptr &s1, const KateSession::Ptr &s2) { return s1->timestamp() > s2->timestamp(); } diff --git a/kate/session/katesession.h b/kate/session/katesession.h index cd40bc3e3..a963b06d4 100644 --- a/kate/session/katesession.h +++ b/kate/session/katesession.h @@ -1,136 +1,136 @@ /* This file is part of the KDE project * * Copyright (C) 2005 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. */ #ifndef __KATE_SESSION_H__ #define __KATE_SESSION_H__ #include #include #include #include "kateprivate_export.h" class KConfig; class KATE_TESTS_EXPORT KateSession : public QSharedData { public: /** * Define a Shared-Pointer type */ typedef QExplicitlySharedDataPointer Ptr; public: ~KateSession(); /** * session name * @return name for this session */ const QString &name() const { return m_name; } /** * session config * on first access, will create the config object, delete will be done automagic * return 0 if we have no file to read config from atm * @return correct KConfig, neverl null * @note never delete configRead(), because the return value might be * KSharedConfig::openConfig(). Only delete the member variables directly. */ KConfig *config(); /** * count of documents in this session * @return documents count */ unsigned int documents() const { return m_documents; } /** * update @number of openned documents in session */ void setDocuments(const unsigned int number); /** * @return true if this is anonymouse/new session */ bool isAnonymous() const { return m_anonymous; } /** * @return path to session file */ const QString &file() const; /** * returns last save time of this session */ const QDateTime ×tamp() const { return m_timestamp; } /** * Factories */ public: static KateSession::Ptr create(const QString &file, const QString &name); static KateSession::Ptr createFrom(const KateSession::Ptr &session, const QString &file, const QString &name); static KateSession::Ptr createAnonymous(const QString &file); static KateSession::Ptr createAnonymousFrom(const KateSession::Ptr &session, const QString &file); static bool compareByName(const KateSession::Ptr &s1, const KateSession::Ptr &s2); static bool compareByTimeDesc(const KateSession::Ptr &s1, const KateSession::Ptr &s2); private: friend class KateSessionManager; friend class KateSessionTest; /** * set session name */ void setName(const QString &name); /** * set's new session file to @filename */ void setFile(const QString &filename); /** * create a session from given @file * @param file configuration file * @param name name of this session * @param anonymous anonymous flag * @param config if specified, the session will copy configuration from the KConfig instead of opening the file */ - KateSession(const QString &file, const QString &name, const bool anonymous, const KConfig *config = 0); + KateSession(const QString &file, const QString &name, const bool anonymous, const KConfig *config = nullptr); private: QString m_name; QString m_file; bool m_anonymous; unsigned int m_documents; KConfig *m_config; QDateTime m_timestamp; }; #endif diff --git a/kate/session/katesessionchooser.cpp b/kate/session/katesessionchooser.cpp index 8e4e46f7d..857a3d845 100644 --- a/kate/session/katesessionchooser.cpp +++ b/kate/session/katesessionchooser.cpp @@ -1,187 +1,187 @@ /* This file is part of the KDE project * * Copyright (C) 2005 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 "katesessionchooser.h" #include "kateapp.h" #include "katesessionmanager.h" #include "katesessionchooseritem.h" #include "katedebug.h" #include #include #include #include #include #include #include #include //BEGIN CHOOSER DIALOG KateSessionChooser::KateSessionChooser(QWidget *parent, const QString &lastSession) : QDialog(parent) { setWindowTitle(i18n("Session Chooser")); QVBoxLayout *mainLayout = new QVBoxLayout(this); m_sessions = new QTreeWidget(this); m_sessions->setMinimumSize(400, 200); mainLayout->addWidget(m_sessions); QStringList header; header << i18n("Session Name"); header << i18nc("The number of open documents", "Open Documents"); header << QString(); m_sessions->setHeaderLabels(header); m_sessions->header()->setStretchLastSection(false); m_sessions->header()->setSectionResizeMode(0, QHeaderView::Stretch); m_sessions->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); m_sessions->header()->setSectionResizeMode(2, QHeaderView::Fixed); m_sessions->header()->resizeSection(2, 32); m_sessions->setRootIsDecorated(false); m_sessions->setItemsExpandable(false); m_sessions->setAllColumnsShowFocus(true); m_sessions->setSelectionBehavior(QAbstractItemView::SelectRows); m_sessions->setSelectionMode(QAbstractItemView::SingleSelection); qCDebug(LOG_KATE) << "Last session is:" << lastSession; KateSessionList slist = KateApp::self()->sessionManager()->sessionList(); qSort(slist.begin(), slist.end(), KateSession::compareByName); foreach(const KateSession::Ptr & session, slist) { KateSessionChooserItem *item = new KateSessionChooserItem(m_sessions, session); QPushButton *tmp = new QPushButton(QIcon::fromTheme(QStringLiteral("document")), QString(), m_sessions); QMenu *popup = new QMenu(tmp); QAction *a = popup->addAction(i18n("Clone session settings")); a->setData(QVariant::fromValue((void *)item)); connect(a, SIGNAL(triggered()), this, SLOT(slotCopySession())); a = popup->addAction(i18n("Delete this session")); a->setData(QVariant::fromValue((void *)item)); connect(a, SIGNAL(triggered()), this, SLOT(slotDeleteSession())); tmp->setMenu(popup); m_sessions->setItemWidget(item, 2, tmp); if (session->name() == lastSession) { m_sessions->setCurrentItem(item); } } connect(m_sessions, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(selectionChanged(QTreeWidgetItem*,QTreeWidgetItem*))); connect(m_sessions, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(slotOpen())); // bottom box QHBoxLayout *hb = new QHBoxLayout(); hb->setMargin(0); mainLayout->addLayout(hb); m_useLast = new QCheckBox(i18n("&Always use this choice"), this); hb->addWidget(m_useLast); // buttons QDialogButtonBox *buttonBox = new QDialogButtonBox(this); hb->addWidget(buttonBox); QPushButton *cancelButton = new QPushButton(); KGuiItem::assign(cancelButton, KStandardGuiItem::quit()); connect(cancelButton, SIGNAL(clicked()), this, SLOT(slotCancel())); buttonBox->addButton(cancelButton, QDialogButtonBox::RejectRole); m_openButton = new QPushButton(QIcon::fromTheme(QStringLiteral("document-open")), i18n("Open Session")); m_openButton->setEnabled(m_sessions->currentIndex().isValid()); m_openButton->setDefault(true); m_openButton->setFocus(); buttonBox->addButton(m_openButton, QDialogButtonBox::ActionRole); connect(m_openButton, SIGNAL(clicked()), this, SLOT(slotOpen())); QPushButton *newButton = new QPushButton(QIcon::fromTheme(QStringLiteral("document-new")), i18n("New Session")); buttonBox->addButton(newButton, QDialogButtonBox::ActionRole); connect(newButton, SIGNAL(clicked()), this, SLOT(slotNew())); setResult(resultNone); - selectionChanged(NULL, NULL); + selectionChanged(nullptr, nullptr); } KateSessionChooser::~KateSessionChooser() {} void KateSessionChooser::slotCopySession() { m_sessions->setCurrentItem((KateSessionChooserItem *)((QAction *)sender())->data().value()); Q_ASSERT(static_cast(m_sessions->currentItem())); done(resultCopy); } void KateSessionChooser::slotDeleteSession() { KateSessionChooserItem *item = (KateSessionChooserItem *)((QAction *)sender())->data().value(); if (!item) { return; } KateApp::self()->sessionManager()->deleteSession(item->session); m_sessions->removeItemWidget(item, 2); delete item; } KateSession::Ptr KateSessionChooser::selectedSession() { KateSessionChooserItem *item = static_cast(m_sessions->currentItem()); Q_ASSERT(item || ((result() != resultOpen) && (result() != resultCopy))); if (!item) { return KateSession::Ptr(); } return item->session; } bool KateSessionChooser::reopenLastSession() { return m_useLast->isChecked(); } void KateSessionChooser::slotOpen() { Q_ASSERT(static_cast(m_sessions->currentItem())); done(resultOpen); } void KateSessionChooser::slotNew() { done(resultNew); } void KateSessionChooser::slotCancel() { done(resultQuit); } void KateSessionChooser::selectionChanged(QTreeWidgetItem *current, QTreeWidgetItem *) { Q_UNUSED(current); m_openButton->setEnabled(true); } //END CHOOSER DIALOG diff --git a/kate/session/katesessionmanagedialog.cpp b/kate/session/katesessionmanagedialog.cpp index a1191a6c9..de8a6ea4b 100644 --- a/kate/session/katesessionmanagedialog.cpp +++ b/kate/session/katesessionmanagedialog.cpp @@ -1,181 +1,181 @@ /* This file is part of the KDE project * * Copyright (C) 2005 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 "katesessionmanagedialog.h" #include "kateapp.h" #include "katesessionmanager.h" #include "katesessionchooseritem.h" #include #include #include #include #include #include #include #include #include #include KateSessionManageDialog::KateSessionManageDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(i18n("Manage Sessions")); QVBoxLayout *mainLayout = new QVBoxLayout(this); setLayout(mainLayout); QHBoxLayout *hb = new QHBoxLayout(); mainLayout->addLayout(hb); m_sessions = new QTreeWidget(this); m_sessions->setMinimumSize(400, 200); hb->addWidget(m_sessions); m_sessions->setColumnCount(2); QStringList header; header << i18n("Session Name"); header << i18nc("The number of open documents", "Open Documents"); m_sessions->setHeaderLabels(header); m_sessions->setRootIsDecorated(false); m_sessions->setItemsExpandable(false); m_sessions->setAllColumnsShowFocus(true); m_sessions->setSelectionBehavior(QAbstractItemView::SelectRows); m_sessions->setSelectionMode(QAbstractItemView::SingleSelection); connect(m_sessions, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(selectionChanged(QTreeWidgetItem*,QTreeWidgetItem*))); updateSessionList(); m_sessions->resizeColumnToContents(0); // right column buttons QDialogButtonBox *rightButtons = new QDialogButtonBox(this); rightButtons->setOrientation(Qt::Vertical); hb->addWidget(rightButtons); m_rename = new QPushButton(i18n("&Rename...")); connect(m_rename, SIGNAL(clicked()), this, SLOT(rename())); rightButtons->addButton(m_rename, QDialogButtonBox::ApplyRole); m_del = new QPushButton(); KGuiItem::assign(m_del, KStandardGuiItem::del()); connect(m_del, SIGNAL(clicked()), this, SLOT(del())); rightButtons->addButton(m_del, QDialogButtonBox::ApplyRole); // dialog buttons QDialogButtonBox *bottomButtons = new QDialogButtonBox(this); mainLayout->addWidget(bottomButtons); QPushButton *closeButton = new QPushButton; KGuiItem::assign(closeButton, KStandardGuiItem::close()); closeButton->setDefault(true); bottomButtons->addButton(closeButton, QDialogButtonBox::RejectRole); connect(closeButton, SIGNAL(clicked()), this, SLOT(slotClose())); m_openButton = new QPushButton(QIcon::fromTheme(QStringLiteral("document-open")), i18n("&Open")); bottomButtons->addButton(m_openButton, QDialogButtonBox::AcceptRole); connect(m_openButton, SIGNAL(clicked()), this, SLOT(open())); // trigger action update - selectionChanged(NULL, NULL); + selectionChanged(nullptr, nullptr); } KateSessionManageDialog::~KateSessionManageDialog() {} void KateSessionManageDialog::slotClose() { done(0); } void KateSessionManageDialog::selectionChanged(QTreeWidgetItem *current, QTreeWidgetItem *) { - const bool validItem = (current != NULL); + const bool validItem = (current != nullptr); m_rename->setEnabled(validItem); m_del->setEnabled(validItem && (static_cast(current))->session != KateApp::self()->sessionManager()->activeSession()); m_openButton->setEnabled(true); } void KateSessionManageDialog::rename() { KateSessionChooserItem *item = static_cast(m_sessions->currentItem()); if (!item) { return; } bool ok = false; QString name = QInputDialog::getText(QApplication::activeWindow(), // nasty trick:) i18n("Specify New Name for Session"), i18n("Session name:"), QLineEdit::Normal, item->session->name(), &ok); if (!ok) { return; } if (name.isEmpty()) { KMessageBox::sorry(this, i18n("To save a session, you must specify a name."), i18n("Missing Session Name")); return; } if (KateApp::self()->sessionManager()->renameSession(item->session, name)) { updateSessionList(); } } void KateSessionManageDialog::del() { KateSessionChooserItem *item = static_cast(m_sessions->currentItem()); if (!item) { return; } KateApp::self()->sessionManager()->deleteSession(item->session); updateSessionList(); } void KateSessionManageDialog::open() { KateSessionChooserItem *item = static_cast(m_sessions->currentItem()); if (!item) { return; } hide(); KateApp::self()->sessionManager()->activateSession(item->session); done(0); } void KateSessionManageDialog::updateSessionList() { m_sessions->clear(); KateSessionList slist = KateApp::self()->sessionManager()->sessionList(); qSort(slist.begin(), slist.end(), KateSession::compareByName); foreach(const KateSession::Ptr & session, slist) { new KateSessionChooserItem(m_sessions, session); } } diff --git a/kate/session/katesessionmanager.cpp b/kate/session/katesessionmanager.cpp index bf3a0b136..11509e858 100644 --- a/kate/session/katesessionmanager.cpp +++ b/kate/session/katesessionmanager.cpp @@ -1,508 +1,508 @@ /* This file is part of the KDE project * * Copyright (C) 2005 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 "config.h" #include "katesessionmanager.h" #include "katesessionchooser.h" #include "katesessionmanagedialog.h" #include "katesessionopendialog.h" #include "kateapp.h" #include "katepluginmanager.h" #include "katerunninginstanceinfo.h" #include #include #include #include #include #include #include #include #include #include #ifndef Q_OS_WIN #include #endif //BEGIN KateSessionManager KateSessionManager::KateSessionManager(QObject *parent, const QString &sessionsDir) : QObject(parent) { if (sessionsDir.isEmpty()) { m_sessionsDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/kate/sessions"); } else { m_sessionsDir = sessionsDir; } // create dir if needed QDir().mkpath(m_sessionsDir); m_dirWatch = new KDirWatch(this); m_dirWatch->addDir(m_sessionsDir); connect(m_dirWatch, SIGNAL(dirty(QString)), this, SLOT(updateSessionList())); updateSessionList(); m_activeSession = KateSession::createAnonymous(anonymousSessionFile()); } KateSessionManager::~KateSessionManager() { delete m_dirWatch; } void KateSessionManager::updateSessionList() { QStringList list; // Let's get a list of all session we have atm QDir dir(m_sessionsDir, QStringLiteral("*.katesession")); for (unsigned int i = 0; i < dir.count(); ++i) { QString name = dir[i]; name.chop(12); // .katesession list << QUrl::fromPercentEncoding(name.toLatin1()); } // delete old items; QMutableHashIterator i(m_sessions); while (i.hasNext()) { i.next(); const int idx = list.indexOf(i.key()); if (idx == -1) { // the key is invalid, remove it from m_session if (i.value() != m_activeSession) { // if active, ignore missing config i.remove(); } } else { // remove it from scan list list.removeAt(idx); } } // load the new ones foreach(const QString & newName, list) { const QString file = sessionFileForName(newName); m_sessions[newName] = KateSession::create(file, newName); } } bool KateSessionManager::activateSession(KateSession::Ptr session, const bool closeAndSaveLast, const bool loadNew) { if (m_activeSession == session) { return true; } if (!session->isAnonymous()) { //check if the requested session is already open in another instance KateRunningInstanceMap instances; if (!fillinRunningKateAppInstances(&instances)) { - KMessageBox::error(0, i18n("Internal error: there is more than one instance open for a given session.")); + KMessageBox::error(nullptr, i18n("Internal error: there is more than one instance open for a given session.")); return false; } if (instances.contains(session->name())) { - if (KMessageBox::questionYesNo(0, i18n("Session '%1' is already opened in another kate instance, change there instead of reopening?", session->name()), + if (KMessageBox::questionYesNo(nullptr, i18n("Session '%1' is already opened in another kate instance, change there instead of reopening?", session->name()), QString(), KStandardGuiItem::yes(), KStandardGuiItem::no(), QStringLiteral("katesessionmanager_switch_instance")) == KMessageBox::Yes) { instances[session->name()]->dbus_if->call(QStringLiteral("activate")); cleanupRunningKateAppInstanceMap(&instances); return false; } } cleanupRunningKateAppInstanceMap(&instances); } // try to close and save last session if (closeAndSaveLast) { if (KateApp::self()->activeKateMainWindow()) { if (!KateApp::self()->activeKateMainWindow()->queryClose_internal()) { return true; } } // save last session or not? saveActiveSession(); // really close last KateApp::self()->documentManager()->closeAllDocuments(); } // set the new session m_activeSession = session; // there is one case in which we don't want the restoration and that is // when restoring session from session manager. // In that case the restore is handled by the caller if (loadNew) { loadSession(session); } emit sessionChanged(); return true; } void KateSessionManager::loadSession(const KateSession::Ptr &session) const { // open the new session KSharedConfigPtr sharedConfig = KSharedConfig::openConfig(); KConfig *sc = session->config(); const bool loadDocs = !session->isAnonymous(); // do not load docs for new sessions // if we have no session config object, try to load the default // (anonymous/unnamed sessions) // load plugin config + plugins KateApp::self()->pluginManager()->loadConfig(sc); if (loadDocs) { KateApp::self()->documentManager()->restoreDocumentList(sc); } // window config KConfigGroup c(sharedConfig, "General"); if (c.readEntry("Restore Window Configuration", true)) { KConfig *cfg = sc; bool delete_cfg = false; // a new, named session, read settings of the default session. if (! sc->hasGroup("Open MainWindows")) { delete_cfg = true; cfg = new KConfig(anonymousSessionFile(), KConfig::SimpleConfig); } int wCount = cfg->group("Open MainWindows").readEntry("Count", 1); for (int i = 0; i < wCount; ++i) { if (i >= KateApp::self()->mainWindowsCount()) { KateApp::self()->newMainWindow(cfg, QString::fromLatin1("MainWindow%1").arg(i)); } else { KateApp::self()->mainWindow(i)->readProperties(KConfigGroup(cfg, QString::fromLatin1("MainWindow%1").arg(i))); } KateApp::self()->mainWindow(i)->restoreWindowConfig(KConfigGroup(cfg, QString::fromLatin1("MainWindow%1 Settings").arg(i))); } if (delete_cfg) { delete cfg; } // remove mainwindows we need no longer... if (wCount > 0) { while (wCount < KateApp::self()->mainWindowsCount()) { delete KateApp::self()->mainWindow(KateApp::self()->mainWindowsCount() - 1); } } } } bool KateSessionManager::activateSession(const QString &name, const bool closeAndSaveLast, const bool loadNew) { return activateSession(giveSession(name), closeAndSaveLast, loadNew); } bool KateSessionManager::activateAnonymousSession() { return activateSession(QString(), false); } KateSession::Ptr KateSessionManager::giveSession(const QString &name) { if (name.isEmpty()) { return KateSession::createAnonymous(anonymousSessionFile()); } if (m_sessions.contains(name)) { return m_sessions.value(name); } KateSession::Ptr s = KateSession::create(sessionFileForName(name), name); saveSessionTo(s->config()); m_sessions[name] = s; return s; } void KateSessionManager::deleteSession(KateSession::Ptr session) { QFile::remove(session->file()); if (session != activeSession()) { m_sessions.remove(session->name()); } } bool KateSessionManager::renameSession(KateSession::Ptr session, const QString &newName) { Q_ASSERT(!newName.isEmpty()); if (session->name() == newName) { return true; } const QString newFile = sessionFileForName(newName); if (QFile::exists(newFile)) { KMessageBox::sorry(QApplication::activeWindow(), i18n("The session could not be renamed to \"%1\", there already exists another session with the same name", newName), i18n("Session Renaming")); return false; } session->config()->sync(); const QUrl srcUrl = QUrl::fromLocalFile(session->file()); const QUrl dstUrl = QUrl::fromLocalFile(newFile); KIO::CopyJob *job = KIO::move(srcUrl, dstUrl, KIO::HideProgressInfo); if (!job->exec()) { KMessageBox::sorry(QApplication::activeWindow(), i18n("The session could not be renamed to \"%1\". Failed to write to \"%2\"", newName, newFile), i18n("Session Renaming")); return false; } m_sessions[newName] = m_sessions.take(session->name()); session->setName(newName); session->setFile(newFile); if (session == activeSession()) { emit sessionChanged(); } return true; } void KateSessionManager::saveSessionTo(KConfig *sc) const { // save plugin configs and which plugins to load KateApp::self()->pluginManager()->writeConfig(sc); // save document configs + which documents to load KateApp::self()->documentManager()->saveDocumentList(sc); sc->group("Open MainWindows").writeEntry("Count", KateApp::self()->mainWindowsCount()); // save config for all windows around ;) bool saveWindowConfig = KConfigGroup(KSharedConfig::openConfig(), "General").readEntry("Restore Window Configuration", true); for (int i = 0; i < KateApp::self()->mainWindowsCount(); ++i) { KConfigGroup cg(sc, QString::fromLatin1("MainWindow%1").arg(i)); KateApp::self()->mainWindow(i)->saveProperties(cg); if (saveWindowConfig) { KateApp::self()->mainWindow(i)->saveWindowConfig(KConfigGroup(sc, QString::fromLatin1("MainWindow%1 Settings").arg(i))); } } sc->sync(); /** * try to sync file to disk */ QFile fileToSync(sc->name()); if (fileToSync.open(QIODevice::ReadOnly)) { #ifndef Q_OS_WIN // ensure that the file is written to disk #ifdef HAVE_FDATASYNC fdatasync(fileToSync.handle()); #else fsync(fileToSync.handle()); #endif #endif } } bool KateSessionManager::saveActiveSession(bool rememberAsLast) { KConfig *sc = activeSession()->config(); saveSessionTo(sc); if (rememberAsLast) { KSharedConfigPtr c = KSharedConfig::openConfig(); c->group("General").writeEntry("Last Session", activeSession()->name()); c->sync(); } return true; } bool KateSessionManager::chooseSession() { const KConfigGroup c(KSharedConfig::openConfig(), "General"); // get last used session, default to default session const QString lastSession(c.readEntry("Last Session", QString())); const QString sesStart(c.readEntry("Startup Session", "manual")); // uhh, just open last used session, show no chooser if (sesStart == QStringLiteral("last")) { activateSession(lastSession, false); return true; } // start with empty new session or in case no sessions exist if (sesStart == QStringLiteral("new") || sessionList().size() == 0) { activateAnonymousSession(); return true; } - QScopedPointer chooser(new KateSessionChooser(0, lastSession)); + QScopedPointer chooser(new KateSessionChooser(nullptr, lastSession)); const int res = chooser->exec(); bool success = true; switch (res) { case KateSessionChooser::resultOpen: { KateSession::Ptr s = chooser->selectedSession(); // dialog guarantees this to be valid success = activateSession(s, false); break; } case KateSessionChooser::resultCopy: { KateSession::Ptr s = chooser->selectedSession(); // dialog guarantees this to be valid KateSession::Ptr ns = KateSession::createAnonymousFrom(s, anonymousSessionFile()); activateSession(ns, false); break; } // exit the app lateron case KateSessionChooser::resultQuit: return false; case KateSessionChooser::resultNew: default: activateAnonymousSession(); break; } // write back our nice boolean :) if (success && chooser->reopenLastSession()) { KConfigGroup generalConfig(KSharedConfig::openConfig(), QStringLiteral("General")); if (res == KateSessionChooser::resultOpen) { generalConfig.writeEntry("Startup Session", "last"); } else if (res == KateSessionChooser::resultNew) { generalConfig.writeEntry("Startup Session", "new"); } generalConfig.sync(); } return success; } void KateSessionManager::sessionNew() { activateSession(giveSession(QString())); } void KateSessionManager::sessionOpen() { - QScopedPointer chooser(new KateSessionOpenDialog(0)); + QScopedPointer chooser(new KateSessionOpenDialog(nullptr)); const int res = chooser->exec(); if (res == KateSessionOpenDialog::resultCancel) { return; } KateSession::Ptr s = chooser->selectedSession(); if (s) { activateSession(s); } } void KateSessionManager::sessionSave() { saveActiveSession(); // this is the optional point to handle saveSessionAs for anonymous session } void KateSessionManager::sessionSaveAs() { if (newSessionName()) { saveActiveSession(); emit sessionChanged(); } } bool KateSessionManager::newSessionName() { bool alreadyExists = false; do { bool ok = false; const QString name = QInputDialog::getText(QApplication::activeWindow(), i18n("Specify New Name for Current Session"), alreadyExists ? i18n("There is already an existing session with your chosen name.\nPlease choose a different one\nSession name:") : i18n("Session name:"), QLineEdit::Normal, activeSession()->name(), &ok); if (!ok) { return false; } if (name.isEmpty()) { - KMessageBox::sorry(0, i18n("To save a session, you must specify a name."), i18n("Missing Session Name")); + KMessageBox::sorry(nullptr, i18n("To save a session, you must specify a name."), i18n("Missing Session Name")); continue; } const QString file = sessionFileForName(name); if (QFile::exists(file)) { alreadyExists = true; continue; } activeSession()->config()->sync(); KateSession::Ptr ns = KateSession::createFrom(activeSession(), file, name); m_activeSession = ns; emit sessionChanged(); alreadyExists = false; } while (alreadyExists); return true; } void KateSessionManager::sessionManage() { - QScopedPointer(new KateSessionManageDialog(0))->exec(); + QScopedPointer(new KateSessionManageDialog(nullptr))->exec(); } QString KateSessionManager::anonymousSessionFile() const { const QString file = m_sessionsDir + QStringLiteral("/../anonymous.katesession"); return QDir().cleanPath(file); } QString KateSessionManager::sessionFileForName(const QString &name) const { Q_ASSERT(!name.isEmpty()); const QString sname = QString::fromLatin1(QUrl::toPercentEncoding(name, QByteArray(), QByteArray("."))); return m_sessionsDir + QStringLiteral("/") + sname + QStringLiteral(".katesession"); } KateSessionList KateSessionManager::sessionList() { return m_sessions.values(); } //END KateSessionManager diff --git a/kate/session/katesessionmanager.h b/kate/session/katesessionmanager.h index 15a710ebc..ee05d6fd3 100644 --- a/kate/session/katesessionmanager.h +++ b/kate/session/katesessionmanager.h @@ -1,209 +1,209 @@ /* This file is part of the KDE project * * Copyright (C) 2005 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. */ #ifndef __KATE_SESSION_MANAGER_H__ #define __KATE_SESSION_MANAGER_H__ #include "katesession.h" #include #include typedef QList KateSessionList; class KATE_TESTS_EXPORT KateSessionManager : public QObject { Q_OBJECT public: - KateSessionManager(QObject *parent = 0, const QString &sessionsDir = QString()); + KateSessionManager(QObject *parent = nullptr, const QString &sessionsDir = QString()); ~KateSessionManager(); /** * allow access to the session list * kept up to date by watching the dir */ KateSessionList sessionList(); /** * activate session by @name * first, it will look if a session with this name exists in list * if yes, it will use this session, else it will create a new session file * @param name name of the session to activate * @param closeAndSaveLast try to close and save last session or not? * @param loadNew load new session stuff? * @return false==session has been delegated, true==session has been activated in this distance */ bool activateSession(const QString &name, const bool closeAndSaveLast = true, const bool loadNew = true); /** * activates new/anonymous session */ bool activateAnonymousSession(); /** * save current session * @param rememberAsLast remember this session as last used? * @return success */ bool saveActiveSession(bool rememberAsLast = false); /** * return the current active session * sessionFile == empty means we have no session around for this instance of kate * @return session active atm */ inline KateSession::Ptr activeSession() { return m_activeSession; } /** * session dir * @return global session dir */ inline const QString &sessionsDir() const { return m_sessionsDir; } /** * initial session chooser, on app start * @return success, if false, app should exit */ bool chooseSession(); public Q_SLOTS: /** * try to start a new session * asks user first for name */ void sessionNew(); /** * try to open a existing session */ void sessionOpen(); /** * try to save current session */ void sessionSave(); /** * try to save as current session */ void sessionSaveAs(); /** * show dialog to manage our sessions */ void sessionManage(); Q_SIGNALS: /** * Emitted, whenever the session changes, e.g. when it was renamed. */ void sessionChanged(); /** * module internal APIs */ public: /** * return session with given name * if no existing session matches, create new one with this name * @param name session name */ KateSession::Ptr giveSession(const QString &name); /** * deletes session file and removes the session from sessions list */ void deleteSession(KateSession::Ptr session); /** * renames the session to @newName * @return true if succesfull */ bool renameSession(KateSession::Ptr session, const QString &newName); /** * activate a session * first, it will look if a session with this name exists in list * if yes, it will use this session, else it will create a new session file * @param session session to activate * @param closeAndSaveLast try to close and save last session or not? * @param loadNew load new session stuff? * @return false==session has been delegated, true==session has been activated in this distance */ bool activateSession(KateSession::Ptr session, const bool closeAndSaveLast = true, const bool loadNew = true); private Q_SLOTS: /** * trigger update of session list */ void updateSessionList(); private: /** * Asks the user for a new session name. Used by save as for example. */ bool newSessionName(); /** * returns session config file according to policy */ QString sessionFileForName(const QString &name) const; /** * returns session file for anonymous session */ QString anonymousSessionFile() const; /** * helper function to save the session to a given config object */ void saveSessionTo(KConfig *sc) const; /** * restore sessions documents, windows, etc... */ void loadSession(const KateSession::Ptr &session) const; private: /** * absolute path to dir in home dir where to store the sessions */ QString m_sessionsDir; /** * list of current available sessions */ QHash m_sessions; /** * current active session */ KateSession::Ptr m_activeSession; class KDirWatch *m_dirWatch; }; #endif diff --git a/kate/session/katesessionsaction.h b/kate/session/katesessionsaction.h index 0fd4ea4c7..3b48a0ae3 100644 --- a/kate/session/katesessionsaction.h +++ b/kate/session/katesessionsaction.h @@ -1,50 +1,50 @@ /* This file is part of the KDE project * * Copyright (C) 2005 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. */ #ifndef __KATE_SESSIONS_ACTION_H__ #define __KATE_SESSIONS_ACTION_H__ #include "kateprivate_export.h" #include class KateSessionManager; class KATE_TESTS_EXPORT KateSessionsAction : public KActionMenu { Q_OBJECT public: - KateSessionsAction(const QString &text, QObject *parent, KateSessionManager *manager = 0); + KateSessionsAction(const QString &text, QObject *parent, KateSessionManager *manager = nullptr); ~KateSessionsAction() { } public Q_SLOTS: void slotAboutToShow(); void openSession(QAction *action); void slotSessionChanged(); private: friend class KateSessionsActionTest; // tfuj QActionGroup *sessionsGroup; KateSessionManager *m_manager; }; #endif diff --git a/kwrite/kwrite.cpp b/kwrite/kwrite.cpp index ad1d919ba..d18ed0ffb 100644 --- a/kwrite/kwrite.cpp +++ b/kwrite/kwrite.cpp @@ -1,560 +1,560 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 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 "kwrite.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef KActivities_FOUND #include #endif #include #include #include #include #include #include #include #include #include #include QList KWrite::docList; QList KWrite::winList; KWrite::KWrite(KTextEditor::Document *doc) - : m_view(0) - , m_recentFiles(0) - , m_paShowPath(0) - , m_paShowMenuBar(0) - , m_paShowStatusBar(0) - , m_activityResource(0) + : m_view(nullptr) + , m_recentFiles(nullptr) + , m_paShowPath(nullptr) + , m_paShowMenuBar(nullptr) + , m_paShowStatusBar(nullptr) + , m_activityResource(nullptr) { if (!doc) { - doc = KTextEditor::Editor::instance()->createDocument(0); + doc = KTextEditor::Editor::instance()->createDocument(nullptr); // enable the modified on disk warning dialogs if any if (qobject_cast(doc)) { qobject_cast(doc)->setModifiedOnDiskWarning(true); } docList.append(doc); } m_view = doc->createView(this); setCentralWidget(m_view); setupActions(); // signals for the statusbar connect(m_view->document(), &KTextEditor::Document::modifiedChanged, this, &KWrite::modifiedChanged); connect(m_view->document(), SIGNAL(documentNameChanged(KTextEditor::Document*)), this, SLOT(documentNameChanged())); connect(m_view->document(), SIGNAL(readWriteChanged(KTextEditor::Document*)), this, SLOT(documentNameChanged())); connect(m_view->document(), SIGNAL(documentUrlChanged(KTextEditor::Document*)), this, SLOT(urlChanged())); setAcceptDrops(true); connect(m_view, SIGNAL(dropEventPass(QDropEvent*)), this, SLOT(slotDropEvent(QDropEvent*))); setXMLFile(QStringLiteral("kwriteui.rc")); createShellGUI(true); guiFactory()->addClient(m_view); // FIXME: make sure the config dir exists, any idea how to do it more cleanly? QDir(QStandardPaths::writableLocation(QStandardPaths::DataLocation)).mkpath(QStringLiteral(".")); // call it as last thing, must be sure everything is already set up ;) setAutoSaveSettings(); readConfig(); winList.append(this); documentNameChanged(); show(); // give view focus m_view->setFocus(Qt::OtherFocusReason); /** * handle mac os x like file open request via event filter */ qApp->installEventFilter(this); } KWrite::~KWrite() { guiFactory()->removeClient(m_view); winList.removeAll(this); KTextEditor::Document *doc = m_view->document(); delete m_view; // kill document, if last view is closed if (doc->views().isEmpty()) { docList.removeAll(doc); delete doc; } KSharedConfig::openConfig()->sync(); } QSize KWrite::sizeHint () const { /** * have some useful size hint, else we have mini windows per default */ return (QSize(640, 480).expandedTo(minimumSizeHint())); } void KWrite::setupActions() { m_closeAction = actionCollection()->addAction(KStandardAction::Close, QStringLiteral("file_close"), this, SLOT(slotFlush())); m_closeAction->setIcon(QIcon::fromTheme(QStringLiteral("document-close"))); m_closeAction->setWhatsThis(i18n("Use this command to close the current document")); m_closeAction->setDisabled(true); // setup File menu actionCollection()->addAction(KStandardAction::New, QStringLiteral("file_new"), this, SLOT(slotNew())) ->setWhatsThis(i18n("Use this command to create a new document")); actionCollection()->addAction(KStandardAction::Open, QStringLiteral("file_open"), this, SLOT(slotOpen())) ->setWhatsThis(i18n("Use this command to open an existing document for editing")); m_recentFiles = KStandardAction::openRecent(this, SLOT(slotOpen(QUrl)), this); actionCollection()->addAction(m_recentFiles->objectName(), m_recentFiles); m_recentFiles->setWhatsThis(i18n("This lists files which you have opened recently, and allows you to easily open them again.")); QAction *a = actionCollection()->addAction(QStringLiteral("view_new_view")); a->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); a->setText(i18n("&New Window")); connect(a, SIGNAL(triggered()), this, SLOT(newView())); a->setWhatsThis(i18n("Create another view containing the current document")); actionCollection()->addAction(KStandardAction::Quit, this, SLOT(close())) ->setWhatsThis(i18n("Close the current document view")); // setup Settings menu setStandardToolBarMenuEnabled(true); m_paShowMenuBar = KStandardAction::showMenubar(this, SLOT(toggleMenuBar()), actionCollection()); m_paShowStatusBar = KStandardAction::showStatusbar(this, SLOT(toggleStatusBar()), this); actionCollection()->addAction(m_paShowStatusBar->objectName(), m_paShowStatusBar); m_paShowStatusBar->setWhatsThis(i18n("Use this command to show or hide the view's statusbar")); m_paShowPath = new KToggleAction(i18n("Sho&w Path in Titlebar"), this); actionCollection()->addAction(QStringLiteral("set_showPath"), m_paShowPath); connect(m_paShowPath, SIGNAL(triggered()), this, SLOT(documentNameChanged())); m_paShowPath->setWhatsThis(i18n("Show the complete document path in the window caption")); a = actionCollection()->addAction(KStandardAction::KeyBindings, this, SLOT(editKeys())); a->setWhatsThis(i18n("Configure the application's keyboard shortcut assignments.")); a = actionCollection()->addAction(KStandardAction::ConfigureToolbars, QStringLiteral("options_configure_toolbars"), this, SLOT(editToolbars())); a->setWhatsThis(i18n("Configure which items should appear in the toolbar(s).")); a = actionCollection()->addAction(QStringLiteral("help_about_editor")); a->setText(i18n("&About Editor Component")); connect(a, SIGNAL(triggered()), this, SLOT(aboutEditor())); } // load on url void KWrite::loadURL(const QUrl &url) { m_view->document()->openUrl(url); #ifdef KActivities_FOUND if (!m_activityResource) { m_activityResource = new KActivities::ResourceInstance(winId(), this); } m_activityResource->setUri(m_view->document()->url()); #endif m_closeAction->setEnabled(true); } // is closing the window wanted by user ? bool KWrite::queryClose() { if (m_view->document()->views().count() > 1) { return true; } if (m_view->document()->queryClose()) { writeConfig(); return true; } return false; } void KWrite::slotFlush() { if (m_view->document()->closeUrl()) { m_closeAction->setDisabled(true); } } void KWrite::modifiedChanged() { documentNameChanged(); m_closeAction->setEnabled(true); } void KWrite::slotNew() { new KWrite(); } void KWrite::slotOpen() { const QList urls = QFileDialog::getOpenFileUrls(this, i18n("Open File"), m_view->document()->url()); Q_FOREACH(QUrl url, urls) { slotOpen(url); } } void KWrite::slotOpen(const QUrl &url) { if (url.isEmpty()) { return; } if (m_view->document()->isModified() || !m_view->document()->url().isEmpty()) { KWrite *t = new KWrite(); t->loadURL(url); } else { loadURL(url); } } void KWrite::urlChanged() { if (! m_view->document()->url().isEmpty()) { m_recentFiles->addUrl(m_view->document()->url()); } // update caption documentNameChanged(); } void KWrite::newView() { new KWrite(m_view->document()); } void KWrite::toggleMenuBar(bool showMessage) { if (m_paShowMenuBar->isChecked()) { menuBar()->show(); removeMenuBarActionFromContextMenu(); } else { if (showMessage) { const QString accel = m_paShowMenuBar->shortcut().toString(); KMessageBox::information(this, i18n("This will hide the menu bar completely." " You can show it again by typing %1.", accel), i18n("Hide menu bar"), QLatin1String("HideMenuBarWarning")); } menuBar()->hide(); addMenuBarActionToContextMenu(); } } void KWrite::addMenuBarActionToContextMenu() { m_view->contextMenu()->addAction(m_paShowMenuBar); } void KWrite::removeMenuBarActionFromContextMenu() { m_view->contextMenu()->removeAction(m_paShowMenuBar); } void KWrite::toggleStatusBar() { m_view->setStatusBarEnabled(m_paShowStatusBar->isChecked()); } void KWrite::editKeys() { KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, this); dlg.addCollection(actionCollection()); if (m_view) { dlg.addCollection(m_view->actionCollection()); } dlg.configure(); } void KWrite::editToolbars() { KConfigGroup cfg = KSharedConfig::openConfig()->group("MainWindow"); saveMainWindowSettings(cfg); KEditToolBar dlg(guiFactory(), this); connect(&dlg, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig())); dlg.exec(); } void KWrite::slotNewToolbarConfig() { applyMainWindowSettings(KSharedConfig::openConfig()->group("MainWindow")); } void KWrite::dragEnterEvent(QDragEnterEvent *event) { const QList uriList = event->mimeData()->urls(); event->setAccepted(! uriList.isEmpty()); } void KWrite::dropEvent(QDropEvent *event) { slotDropEvent(event); } void KWrite::slotDropEvent(QDropEvent *event) { const QList textlist = event->mimeData()->urls(); foreach(const QUrl & url, textlist) slotOpen(url); } void KWrite::slotEnableActions(bool enable) { QList actions = actionCollection()->actions(); QList::ConstIterator it = actions.constBegin(); QList::ConstIterator end = actions.constEnd(); for (; it != end; ++it) { (*it)->setEnabled(enable); } actions = m_view->actionCollection()->actions(); it = actions.constBegin(); end = actions.constEnd(); for (; it != end; ++it) { (*it)->setEnabled(enable); } } //common config void KWrite::readConfig(KSharedConfigPtr config) { KConfigGroup cfg(config, "General Options"); m_paShowMenuBar->setChecked(cfg.readEntry("ShowMenuBar", true)); m_paShowStatusBar->setChecked(cfg.readEntry("ShowStatusBar", true)); m_paShowPath->setChecked(cfg.readEntry("ShowPath", false)); m_recentFiles->loadEntries(config->group("Recent Files")); // update visibility of menu bar and status bar toggleMenuBar(false); m_view->setStatusBarEnabled(m_paShowStatusBar->isChecked()); } void KWrite::writeConfig(KSharedConfigPtr config) { KConfigGroup generalOptions(config, "General Options"); generalOptions.writeEntry("ShowMenuBar", m_paShowMenuBar->isChecked()); generalOptions.writeEntry("ShowStatusBar", m_paShowStatusBar->isChecked()); generalOptions.writeEntry("ShowPath", m_paShowPath->isChecked()); m_recentFiles->saveEntries(KConfigGroup(config, "Recent Files")); config->sync(); } //config file void KWrite::readConfig() { readConfig(KSharedConfig::openConfig()); } void KWrite::writeConfig() { writeConfig(KSharedConfig::openConfig()); } // session management void KWrite::restore(KConfig *config, int n) { readPropertiesInternal(config, n); } void KWrite::readProperties(const KConfigGroup &config) { readConfig(); m_view->readSessionConfig(KConfigGroup(&config, QStringLiteral("General Options"))); } void KWrite::saveProperties(KConfigGroup &config) { writeConfig(); config.writeEntry("DocumentNumber", docList.indexOf(m_view->document()) + 1); KConfigGroup cg(&config, QStringLiteral("General Options")); m_view->writeSessionConfig(cg); } void KWrite::saveGlobalProperties(KConfig *config) //save documents { config->group("Number").writeEntry("NumberOfDocuments", docList.count()); for (int z = 1; z <= docList.count(); z++) { QString buf = QString::fromLatin1("Document %1").arg(z); KConfigGroup cg(config, buf); KTextEditor::Document *doc = docList.at(z - 1); doc->writeSessionConfig(cg); } for (int z = 1; z <= winList.count(); z++) { QString buf = QString::fromLatin1("Window %1").arg(z); KConfigGroup cg(config, buf); cg.writeEntry("DocumentNumber", docList.indexOf(winList.at(z - 1)->view()->document()) + 1); } } //restore session void KWrite::restore() { KConfig *config = KConfigGui::sessionConfig(); if (!config) { return; } int docs, windows; QString buf; KTextEditor::Document *doc; KWrite *t; KConfigGroup numberConfig(config, "Number"); docs = numberConfig.readEntry("NumberOfDocuments", 0); windows = numberConfig.readEntry("NumberOfWindows", 0); for (int z = 1; z <= docs; z++) { buf = QString::fromLatin1("Document %1").arg(z); KConfigGroup cg(config, buf); - doc = KTextEditor::Editor::instance()->createDocument(0); + doc = KTextEditor::Editor::instance()->createDocument(nullptr); doc->readSessionConfig(cg); docList.append(doc); } for (int z = 1; z <= windows; z++) { buf = QString::fromLatin1("Window %1").arg(z); KConfigGroup cg(config, buf); t = new KWrite(docList.at(cg.readEntry("DocumentNumber", 0) - 1)); t->restore(config, z); } } void KWrite::aboutEditor() { KAboutApplicationDialog dlg(KTextEditor::Editor::instance()->aboutData(), this); dlg.exec(); } void KWrite::documentNameChanged() { QString readOnlyCaption; if (!m_view->document()->isReadWrite()) { readOnlyCaption = i18n(" [read only]"); } if (m_view->document()->url().isEmpty()) { setCaption(i18n("Untitled") + readOnlyCaption + QStringLiteral(" [*]"), m_view->document()->isModified()); return; } QString c; if (m_paShowPath->isChecked()) { c = m_view->document()->url().toString(QUrl::PreferLocalFile); const QString homePath = QDir::homePath(); if (c.startsWith(homePath)) { c = QStringLiteral("~") + c.right(c.length() - homePath.length()); } //File name shouldn't be too long - Maciek if (c.length() > 64) { c = QStringLiteral("...") + c.right(64); } } else { c = m_view->document()->url().fileName(); //File name shouldn't be too long - Maciek if (c.length() > 64) { c = c.left(64) + QStringLiteral("..."); } } setCaption(c + readOnlyCaption + QStringLiteral(" [*]"), m_view->document()->isModified()); } bool KWrite::eventFilter(QObject *obj, QEvent *event) { /** * handle mac os like file open */ if (event->type() == QEvent::FileOpen) { /** * try to open and activate the new document, like we would do for stuff * opened via file dialog */ QFileOpenEvent *foe = static_cast(event); slotOpen(foe->url()); return true; } /** * else: pass over to default implementation */ return KParts::MainWindow::eventFilter(obj, event); } diff --git a/kwrite/kwrite.h b/kwrite/kwrite.h index 01cbd85d6..a3e0bf07f 100644 --- a/kwrite/kwrite.h +++ b/kwrite/kwrite.h @@ -1,147 +1,147 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 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. */ #ifndef KWRITE_MAIN_H #define KWRITE_MAIN_H #include #include #include #include #include #include class QLabel; namespace KActivities { class ResourceInstance; } class KToggleAction; class KRecentFilesAction; class KSqueezedTextLabel; class KWrite : public KParts::MainWindow { Q_OBJECT public: - KWrite(KTextEditor::Document * = 0L); + KWrite(KTextEditor::Document * = nullptr); ~KWrite(); void loadURL(const QUrl &url); KTextEditor::View *view() const { return m_view; } static bool noWindows() { return winList.isEmpty(); } private: void setupActions(); void addMenuBarActionToContextMenu(); void removeMenuBarActionFromContextMenu(); bool queryClose() Q_DECL_OVERRIDE; void dragEnterEvent(QDragEnterEvent *) Q_DECL_OVERRIDE; void dropEvent(QDropEvent *) Q_DECL_OVERRIDE; public Q_SLOTS: void slotNew(); void slotFlush(); void slotOpen(); void slotOpen(const QUrl &url); void newView(); void toggleStatusBar(); void toggleMenuBar(bool showMessage = true); void editKeys(); void editToolbars(); void aboutEditor(); void modifiedChanged(); private Q_SLOTS: void slotNewToolbarConfig(); public Q_SLOTS: void slotDropEvent(QDropEvent *); void slotEnableActions(bool enable); /** * adds a changed URL to the recent files */ void urlChanged(); /** * Overwrite size hint for better default window sizes * @return size hint */ QSize sizeHint () const Q_DECL_OVERRIDE; //config file functions public: void readConfig(KSharedConfigPtr); void writeConfig(KSharedConfigPtr); void readConfig(); void writeConfig(); //session management public: void restore(KConfig *, int); static void restore(); private: void readProperties(const KConfigGroup &) Q_DECL_OVERRIDE; void saveProperties(KConfigGroup &) Q_DECL_OVERRIDE; void saveGlobalProperties(KConfig *) Q_DECL_OVERRIDE; private: KTextEditor::View *m_view; KRecentFilesAction *m_recentFiles; KToggleAction *m_paShowPath; KToggleAction *m_paShowMenuBar; KToggleAction *m_paShowStatusBar; QAction *m_closeAction; KActivities::ResourceInstance *m_activityResource; static QList docList; static QList winList; public Q_SLOTS: void documentNameChanged(); protected: /** * Event filter for QApplication to handle mac os like file open */ bool eventFilter(QObject *obj, QEvent *event) Q_DECL_OVERRIDE; }; #endif diff --git a/kwrite/main.cpp b/kwrite/main.cpp index 68a055edb..62f4f2db4 100644 --- a/kwrite/main.cpp +++ b/kwrite/main.cpp @@ -1,295 +1,295 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 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 "kwrite.h" #include #include #include #include #include // for KAboutData::setDesktopFileName() #include #include #include #include #if KCrash_VERSION >= QT_VERSION_CHECK(5, 15, 0) #include #endif // KCrash >= 5.15 #include #include #include #include #include #include "../urlinfo.h" #ifndef Q_OS_WIN #include #endif #include extern "C" Q_DECL_EXPORT int main(int argc, char **argv) { #ifndef Q_OS_WIN /** * Check whether we are running as root **/ if (getuid() == 0) { std::cout << "Executing KWrite as root is not possible. To edit files as root use:" << std::endl; std::cout << "SUDO_EDITOR=kwrite sudoedit " << std::endl; return 0; } #endif /** * Create application first * Enforce application name even if the executable is renamed */ QApplication app(argc, argv); app.setApplicationName(QStringLiteral("kwrite")); /** * enable high dpi support */ app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); /** * Enable crash handling through KCrash. */ #if KCrash_VERSION >= QT_VERSION_CHECK(5, 15, 0) KCrash::initialize(); #endif /** * Connect application with translation catalogs */ KLocalizedString::setApplicationDomain("kwrite"); /** * then use i18n and co */ KAboutData aboutData(QStringLiteral("kwrite"), i18n("KWrite"), QStringLiteral(KATE_VERSION), i18n("KWrite - Text Editor"), KAboutLicense::LGPL_V2, i18n("(c) 2000-2016 The Kate Authors"), QString(), QStringLiteral("http://kate-editor.org")); /** * right dbus prefix == org.kde. */ aboutData.setOrganizationDomain(QByteArray("kde.org")); /** * desktop file association to make application icon work (e.g. in Wayland window decoration) */ #if KCOREADDONS_VERSION >= QT_VERSION_CHECK(5, 16, 0) aboutData.setDesktopFileName(QStringLiteral("org.kde.kwrite")); #endif aboutData.addAuthor(i18n("Christoph Cullmann"), i18n("Maintainer"), QStringLiteral("cullmann@kde.org"), QStringLiteral("http://www.cullmann.io")); aboutData.addAuthor(i18n("Anders Lund"), i18n("Core Developer"), QStringLiteral("anders@alweb.dk"), QStringLiteral("http://www.alweb.dk")); aboutData.addAuthor(i18n("Joseph Wenninger"), i18n("Core Developer"), QStringLiteral("jowenn@kde.org"), QStringLiteral("http://stud3.tuwien.ac.at/~e9925371")); aboutData.addAuthor(i18n("Hamish Rodda"), i18n("Core Developer"), QStringLiteral("rodda@kde.org")); aboutData.addAuthor(i18n("Dominik Haumann"), i18n("Developer & Highlight wizard"), QStringLiteral("dhdev@gmx.de")); aboutData.addAuthor(i18n("Waldo Bastian"), i18n("The cool buffersystem"), QStringLiteral("bastian@kde.org")); aboutData.addAuthor(i18n("Charles Samuels"), i18n("The Editing Commands"), QStringLiteral("charles@kde.org")); aboutData.addAuthor(i18n("Matt Newell"), i18nc("Credit text for someone that did testing and some other similar things", "Testing, ..."), QStringLiteral("newellm@proaxis.com")); aboutData.addAuthor(i18n("Michael Bartl"), i18n("Former Core Developer"), QStringLiteral("michael.bartl1@chello.at")); aboutData.addAuthor(i18n("Michael McCallum"), i18n("Core Developer"), QStringLiteral("gholam@xtra.co.nz")); aboutData.addAuthor(i18n("Jochen Wilhemly"), i18n("KWrite Author"), QStringLiteral("digisnap@cs.tu-berlin.de")); aboutData.addAuthor(i18n("Michael Koch"), i18n("KWrite port to KParts"), QStringLiteral("koch@kde.org")); aboutData.addAuthor(i18n("Christian Gebauer"), QString(), QStringLiteral("gebauer@kde.org")); aboutData.addAuthor(i18n("Simon Hausmann"), QString(), QStringLiteral("hausmann@kde.org")); aboutData.addAuthor(i18n("Glen Parker"), i18n("KWrite Undo History, Kspell integration"), QStringLiteral("glenebob@nwlink.com")); aboutData.addAuthor(i18n("Scott Manson"), i18n("KWrite XML Syntax highlighting support"), QStringLiteral("sdmanson@alltel.net")); aboutData.addAuthor(i18n("John Firebaugh"), i18n("Patches and more"), QStringLiteral("jfirebaugh@kde.org")); aboutData.addAuthor(i18n("Gerald Senarclens de Grancy"), i18n("QA and Scripting"), QStringLiteral("oss@senarclens.eu"), QStringLiteral("http://find-santa.eu/")); aboutData.addCredit(i18n("Matteo Merli"), i18n("Highlighting for RPM Spec-Files, Perl, Diff and more"), QStringLiteral("merlim@libero.it")); aboutData.addCredit(i18n("Rocky Scaletta"), i18n("Highlighting for VHDL"), QStringLiteral("rocky@purdue.edu")); aboutData.addCredit(i18n("Yury Lebedev"), i18n("Highlighting for SQL")); aboutData.addCredit(i18n("Chris Ross"), i18n("Highlighting for Ferite")); aboutData.addCredit(i18n("Nick Roux"), i18n("Highlighting for ILERPG")); aboutData.addCredit(i18n("Carsten Niehaus"), i18n("Highlighting for LaTeX")); aboutData.addCredit(i18n("Per Wigren"), i18n("Highlighting for Makefiles, Python")); aboutData.addCredit(i18n("Jan Fritz"), i18n("Highlighting for Python")); aboutData.addCredit(i18n("Daniel Naber")); aboutData.addCredit(i18n("Roland Pabel"), i18n("Highlighting for Scheme")); aboutData.addCredit(i18n("Cristi Dumitrescu"), i18n("PHP Keyword/Datatype list")); aboutData.addCredit(i18n("Carsten Pfeiffer"), i18nc("Credit text for someone that helped a lot", "Very nice help")); aboutData.addCredit(i18n("All people who have contributed and I have forgotten to mention")); /** * bugzilla */ aboutData.setProductName(QByteArray("kate/kwrite")); /** * set and register app about data */ KAboutData::setApplicationData(aboutData); /** * set the program icon */ QApplication::setWindowIcon(QIcon::fromTheme(QLatin1String("accessories-text-editor"), app.windowIcon())); /** * Create command line parser and feed it with known options */ QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.addHelpOption(); parser.addVersionOption(); // -e/--encoding option const QCommandLineOption useEncoding(QStringList() << QStringLiteral("e") << QStringLiteral("encoding"), i18n("Set encoding for the file to open."), i18n("encoding")); parser.addOption(useEncoding); // -l/--line option const QCommandLineOption gotoLine(QStringList() << QStringLiteral("l") << QStringLiteral("line"), i18n("Navigate to this line."), i18n("line")); parser.addOption(gotoLine); // -c/--column option const QCommandLineOption gotoColumn(QStringList() << QStringLiteral("c") << QStringLiteral("column"), i18n("Navigate to this column."), i18n("column")); parser.addOption(gotoColumn); // -i/--stdin option const QCommandLineOption readStdIn(QStringList() << QStringLiteral("i") << QStringLiteral("stdin"), i18n("Read the contents of stdin.")); parser.addOption(readStdIn); // --tempfile option const QCommandLineOption tempfile(QStringList() << QStringLiteral("tempfile"), i18n("The files/URLs opened by the application will be deleted after use")); parser.addOption(tempfile); // urls to open parser.addPositionalArgument(QStringLiteral("urls"), i18n("Documents to open."), i18n("[urls...]")); /** * do the command line parsing */ parser.process(app); /** * handle standard options */ aboutData.processCommandLine(&parser); if (app.isSessionRestored()) { KWrite::restore(); } else { bool nav = false; int line = 0, column = 0; - QTextCodec *codec = parser.isSet(QStringLiteral("encoding")) ? QTextCodec::codecForName(parser.value(QStringLiteral("encoding")).toLocal8Bit()) : 0; + QTextCodec *codec = parser.isSet(QStringLiteral("encoding")) ? QTextCodec::codecForName(parser.value(QStringLiteral("encoding")).toLocal8Bit()) : nullptr; if (parser.isSet(QStringLiteral("line"))) { line = parser.value(QStringLiteral("line")).toInt() - 1; nav = true; } if (parser.isSet(QStringLiteral("column"))) { column = parser.value(QStringLiteral("column")).toInt() - 1; nav = true; } if (parser.positionalArguments().count() == 0) { KWrite *t = new KWrite; if (parser.isSet(QStringLiteral("stdin"))) { QTextStream input(stdin, QIODevice::ReadOnly); // set chosen codec if (codec) { input.setCodec(codec); } QString line; QString text; do { line = input.readLine(); text.append(line + QLatin1Char('\n')); } while (!line.isNull()); KTextEditor::Document *doc = t->view()->document(); if (doc) { // remember codec in document, e.g. to show the right one if (codec) { doc->setEncoding(QString::fromLatin1(codec->name())); } doc->setText(text); } } if (nav && t->view()) { t->view()->setCursorPosition(KTextEditor::Cursor(line, column)); } } else { int docs_opened = 0; Q_FOREACH(const QString positionalArgument, parser.positionalArguments()) { UrlInfo info(positionalArgument); if (nav) { info.cursor = KTextEditor::Cursor(line, column); } // this file is no local dir, open it, else warn bool noDir = !info.url.isLocalFile() || !QFileInfo(info.url.toLocalFile()).isDir(); if (noDir) { ++docs_opened; KWrite *t = new KWrite(); if (codec) { t->view()->document()->setEncoding(QString::fromLatin1(codec->name())); } t->loadURL(info.url); if (info.cursor.isValid()) { t->view()->setCursorPosition(info.cursor); } } else { - KMessageBox::sorry(0, i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.", info.url.toString())); + KMessageBox::sorry(nullptr, i18n("The file '%1' could not be opened: it is not a normal file, it is a folder.", info.url.toString())); } } if (!docs_opened) { ::exit(1); // see http://bugs.kde.org/show_bug.cgi?id=124708 } } } // no window there, uh, ohh, for example borked session config !!! // create at least one !! if (KWrite::noWindows()) { new KWrite(); } /** * finally register this kwrite instance for dbus, don't die if no dbus is around! */ const KDBusService dbusService(KDBusService::Multiple | KDBusService::NoExitOnFailure); /** * Run the event loop */ return app.exec(); }

    foo test bar X *