diff --git a/addons/backtracebrowser/autotests/btbrowsertest.cpp b/addons/backtracebrowser/autotests/btbrowsertest.cpp index a184c3e00..2bfdfc009 100644 --- a/addons/backtracebrowser/autotests/btbrowsertest.cpp +++ b/addons/backtracebrowser/autotests/btbrowsertest.cpp @@ -1,99 +1,99 @@ /* This file is part of the KDE project * * Copyright 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 "btbrowsertest.h" #include "btparser.h" #include #include #include QTEST_MAIN(KateBtBrowserTest) void KateBtBrowserTest::initTestCase() { } void KateBtBrowserTest::cleanupTestCase() { } void KateBtBrowserTest::testParser() { // make sure the different types of gdb backtraces are parsed correctly // 1) #24 0xb688ff8e in QApplication::notify (this=0xbf997e8c, receiver=0x82607e8, e=0xbf997074) at kernel/qapplication.cpp:3115 // 2) #39 0xb634211c in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0 // 3) #41 0x0805e690 in ?? () // 4) #5 0xffffe410 in __kernel_vsyscall () - QString bt = QLatin1String("#24 0xb688ff8e in QApplication::notify (this=0xbf997e8c, receiver=0x82607e8, e=0xbf997074) at kernel/qapplication.cpp:3115"); + QString bt = QStringLiteral("#24 0xb688ff8e in QApplication::notify (this=0xbf997e8c, receiver=0x82607e8, e=0xbf997074) at kernel/qapplication.cpp:3115"); QList info = KateBtParser::parseBacktrace(bt); QVERIFY(info.size() == 1); QCOMPARE(info[0].type, BtInfo::Source); QCOMPARE(info[0].original, bt); QCOMPARE(info[0].filename, QLatin1String("kernel/qapplication.cpp")); QCOMPARE(info[0].function, QLatin1String("QApplication::notify (this=0xbf997e8c, receiver=0x82607e8, e=0xbf997074)")); QCOMPARE(info[0].address, QLatin1String("0xb688ff8e")); QCOMPARE(info[0].line, 3115); QCOMPARE(info[0].step, 24); - bt = QLatin1String("#39 0xb634211c in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0"); + bt = QStringLiteral("#39 0xb634211c in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0"); info = KateBtParser::parseBacktrace(bt); QVERIFY(info.size() == 1); QCOMPARE(info[0].type, BtInfo::Lib); QCOMPARE(info[0].original, bt); QCOMPARE(info[0].filename, QLatin1String("/usr/lib/libglib-2.0.so.0")); QCOMPARE(info[0].function, QLatin1String("g_main_context_dispatch ()")); QCOMPARE(info[0].address, QLatin1String("0xb634211c")); QCOMPARE(info[0].line, -1); QCOMPARE(info[0].step, 39); - bt = QLatin1String("#41 0x0805e690 in ?? ()"); + bt = QStringLiteral("#41 0x0805e690 in ?? ()"); info = KateBtParser::parseBacktrace(bt); QVERIFY(info.size() == 1); QCOMPARE(info[0].type, BtInfo::Unknown); QCOMPARE(info[0].original, bt); QCOMPARE(info[0].filename, QString()); QCOMPARE(info[0].function, QString()); QCOMPARE(info[0].address, QLatin1String("0x0805e690")); QCOMPARE(info[0].line, -1); QCOMPARE(info[0].step, 41); - bt = QLatin1String("#5 0xffffe410 in __kernel_vsyscall ()"); + bt = QStringLiteral("#5 0xffffe410 in __kernel_vsyscall ()"); info = KateBtParser::parseBacktrace(bt); QVERIFY(info.size() == 1); QCOMPARE(info[0].type, BtInfo::Unknown); QCOMPARE(info[0].original, bt); QCOMPARE(info[0].filename, QString()); QCOMPARE(info[0].function, QLatin1String("__kernel_vsyscall ()")); QCOMPARE(info[0].address, QLatin1String("0xffffe410")); QCOMPARE(info[0].line, -1); QCOMPARE(info[0].step, 5); - bt = QLatin1String(" Thread 1 (Thread 0x7fb6ba260780 (LWP 16447)):\n[KCrash Handler]"); + bt = QStringLiteral(" Thread 1 (Thread 0x7fb6ba260780 (LWP 16447)):\n[KCrash Handler]"); info = KateBtParser::parseBacktrace(bt); QVERIFY(info.size() == 0); } // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/filebrowser/katefilebrowser.cpp b/addons/filebrowser/katefilebrowser.cpp index 281f10e20..63de2082c 100644 --- a/addons/filebrowser/katefilebrowser.cpp +++ b/addons/filebrowser/katefilebrowser.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 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, &KUrlNavigator::urlChanged, this, &KateFileBrowser::updateDirOperator); mainLayout->addWidget(m_urlNavigator); m_dirOperator = new KDirOperator(QUrl(), this); // Default to a view with only one column since columns are auto-sized m_dirOperator->setView(KFile::Tree); 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") << QStringLiteral("application/x-zerosize"); m_dirOperator->setNewFileMenuSupportedMimeTypes(filter); setFocusProxy(m_dirOperator); connect(m_dirOperator, &KDirOperator::viewChanged, this, &KateFileBrowser::selectorViewChanged); connect(m_urlNavigator, &KUrlNavigator::returnPressed, m_dirOperator, static_cast(&KDirOperator::setFocus)); // now all actions exist in dir operator and we can use them in the toolbar setupActions(); setupToolbar(); m_filter = new KHistoryComboBox(true, this); m_filter->setMaxCount(10); m_filter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); m_filter->lineEdit()->setPlaceholderText(i18n("Search")); mainLayout->addWidget(m_filter); connect(m_filter, &KHistoryComboBox::editTextChanged, this, &KateFileBrowser::slotFilterChange); connect(m_filter, static_cast(&KHistoryComboBox::returnPressed), m_filter, &KHistoryComboBox::addToHistory); connect(m_filter, static_cast(&KHistoryComboBox::returnPressed), m_dirOperator, static_cast< void (KDirOperator::*)()>(&KDirOperator::setFocus)); connect(m_dirOperator, &KDirOperator::urlEntered, this, &KateFileBrowser::updateUrlNavigator); // Connect the bookmark handler connect(m_bookmarkHandler, &KateBookmarkHandler::openUrl, this, static_cast(&KateFileBrowser::setDir)); m_filter->setWhatsThis(i18n("Enter a name filter to limit which files are displayed.")); connect(m_dirOperator, &KDirOperator::fileSelected, this, &KateFileBrowser::fileSelected); connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KateFileBrowser::autoSyncFolder); } KateFileBrowser::~KateFileBrowser() { } //END Constructor/Destructor //BEGIN Public Methods void KateFileBrowser::setupToolbar() { KConfigGroup config(KSharedConfig::openConfig(), "filebrowser"); QStringList actions = config.readEntry( "toolbar actions", QStringList() ); if ( actions.isEmpty() ) // default toolbar actions << QStringLiteral("back") << QStringLiteral("forward") << QStringLiteral("bookmarks") << QStringLiteral("sync_dir") << QStringLiteral("configure"); // remove all actions from the toolbar (there should be none) m_toolbar->clear(); // now add all actions to the toolbar foreach (const QString& it, actions) { QAction *ac = nullptr; if (it.isEmpty()) continue; if (it == QStringLiteral("bookmarks") || it == QStringLiteral("sync_dir") || it == QStringLiteral("configure")) ac = actionCollection()->action(it); else ac = m_dirOperator->actionCollection()->action(it); if (ac) m_toolbar->addAction(ac); } } void KateFileBrowser::readSessionConfig (const KConfigGroup& cg) { m_dirOperator->readConfig(cg); m_dirOperator->setView(KFile::Default); m_urlNavigator->setLocationUrl(cg.readEntry("location", QUrl::fromLocalFile (QDir::homePath()))); setDir(cg.readEntry("location", QUrl::fromLocalFile (QDir::homePath()))); m_autoSyncFolder->setChecked(cg.readEntry("auto sync folder", false)); m_filter->setHistoryItems(cg.readEntry("filter history", QStringList()), true); } void KateFileBrowser::writeSessionConfig (KConfigGroup& cg) { m_dirOperator->writeConfig(cg); cg.writeEntry("location", m_urlNavigator->locationUrl().url()); cg.writeEntry("auto sync folder", m_autoSyncFolder->isChecked()); cg.writeEntry("filter history", m_filter->historyItems()); } //END Public Methods //BEGIN Public Slots void KateFileBrowser::slotFilterChange(const QString & nf) { QString f = nf.trimmed(); const bool empty = f.isEmpty() || f == QStringLiteral("*"); if (empty) { m_dirOperator->clearFilter(); } else { m_dirOperator->setNameFilter(f); } m_dirOperator->updateDir(); } bool kateFileSelectorIsReadable (const QUrl& url) { if (!url.isLocalFile()) return true; // what else can we say? QDir dir(url.toLocalFile()); return dir.exists (); } -void KateFileBrowser::setDir(QUrl u) +void KateFileBrowser::setDir(const QUrl &u) { QUrl newurl; if (!u.isValid()) newurl = QUrl::fromLocalFile(QDir::homePath()); else newurl = u; QString path(newurl.path()); if (!path.endsWith(QLatin1Char('/'))) path += QLatin1Char('/'); newurl.setPath(path); if (!kateFileSelectorIsReadable(newurl)) { newurl.setPath(newurl.path() + QStringLiteral("../")); newurl = newurl.adjusted(QUrl::NormalizePathSegments); } if (!kateFileSelectorIsReadable(newurl)) { newurl = QUrl::fromLocalFile(QDir::homePath()); } m_dirOperator->setUrl(newurl, true); } //END Public Slots //BEGIN Private Slots void KateFileBrowser::fileSelected(const KFileItem & /*file*/) { openSelectedFiles(); } void KateFileBrowser::openSelectedFiles() { const KFileItemList list = m_dirOperator->selectedItems(); if (list.count()>20) { if (KMessageBox::questionYesNo(this,i18np("You are trying to open 1 file, are you sure?", "You are trying to open %1 files, are you sure?", list.count())) == KMessageBox::No) return; } foreach (const KFileItem& item, list) { m_mainWindow->openUrl(item.url()); } m_dirOperator->view()->selectionModel()->clear(); } void KateFileBrowser::updateDirOperator(const QUrl &u) { m_dirOperator->setUrl(u, true); } void KateFileBrowser::updateUrlNavigator(const QUrl &u) { m_urlNavigator->setLocationUrl(u); } void KateFileBrowser::setActiveDocumentDir() { QUrl u = activeDocumentUrl(); if (!u.isEmpty()) setDir(KIO::upUrl(u)); } void KateFileBrowser::autoSyncFolder() { if (m_autoSyncFolder->isChecked()) { setActiveDocumentDir(); } } void KateFileBrowser::selectorViewChanged(QAbstractItemView * newView) { newView->setSelectionMode(QAbstractItemView::ExtendedSelection); } //END Private Slots //BEGIN Protected QUrl KateFileBrowser::activeDocumentUrl() { KTextEditor::View *v = m_mainWindow->activeView(); if (v) return v->document()->url(); return QUrl(); } void KateFileBrowser::setupActions() { // bookmarks action! KActionMenu *acmBookmarks = new KActionMenu(QIcon::fromTheme(QStringLiteral("bookmarks")), i18n("Bookmarks"), this); acmBookmarks->setDelayed(false); m_bookmarkHandler = new KateBookmarkHandler(this, acmBookmarks->menu()); acmBookmarks->setShortcutContext(Qt::WidgetWithChildrenShortcut); // action for synchronizing the dir operator with the current document path QAction* syncFolder = new QAction(this); syncFolder->setShortcutContext(Qt::WidgetWithChildrenShortcut); syncFolder->setText(i18n("Current Document Folder")); syncFolder->setIcon(QIcon::fromTheme(QStringLiteral("system-switch-user"))); connect(syncFolder, &QAction::triggered, this, &KateFileBrowser::setActiveDocumentDir); m_actionCollection->addAction(QStringLiteral("sync_dir"), syncFolder); m_actionCollection->addAction(QStringLiteral("bookmarks"), acmBookmarks); // section for settings menu KActionMenu *optionsMenu = new KActionMenu(QIcon::fromTheme(QStringLiteral("configure")), i18n("Options"), this); optionsMenu->setDelayed(false); optionsMenu->addAction(m_dirOperator->actionCollection()->action(QStringLiteral("short view"))); optionsMenu->addAction(m_dirOperator->actionCollection()->action(QStringLiteral("detailed view"))); optionsMenu->addAction(m_dirOperator->actionCollection()->action(QStringLiteral("tree view"))); optionsMenu->addAction(m_dirOperator->actionCollection()->action(QStringLiteral("detailed tree view"))); optionsMenu->addSeparator(); optionsMenu->addAction(m_dirOperator->actionCollection()->action(QStringLiteral("show hidden"))); // action for synchronising the dir operator with the current document path m_autoSyncFolder = new QAction(this); m_autoSyncFolder->setCheckable(true); m_autoSyncFolder->setText(i18n("Automatically synchronize with current document")); m_autoSyncFolder->setIcon(QIcon::fromTheme(QStringLiteral("system-switch-user"))); connect(m_autoSyncFolder, &QAction::triggered, this, &KateFileBrowser::autoSyncFolder); optionsMenu->addAction(m_autoSyncFolder); m_actionCollection->addAction(QStringLiteral("configure"), optionsMenu); // // Remove all shortcuts due to shortcut clashes (e.g. F5: reload, Ctrl+B: bookmark) // BUGS: #188954, #236368 // foreach (QAction* a, m_actionCollection->actions()) { a->setShortcut(QKeySequence()); } foreach (QAction* a, m_dirOperator->actionCollection()->actions()) { a->setShortcut(QKeySequence()); } } //END Protected // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/filebrowser/katefilebrowser.h b/addons/filebrowser/katefilebrowser.h index 7c2520fc3..a225f43c9 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 = nullptr, QWidget * parent = nullptr); ~KateFileBrowser() override; 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 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/filetree/autotests/document_dummy.h b/addons/filetree/autotests/document_dummy.h index 0a10e5497..977e1c56e 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 (dhaumann@kde.org) (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 DOCUMENT_DUMMY_H #define DOCUMENT_DUMMY_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_name(QStringLiteral("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)) {} ~DummyDocument () override {} KTextEditor::View *createView ( QWidget *, KTextEditor::MainWindow * = nullptr ) override { return nullptr; } virtual KTextEditor::View *activeView() const { return nullptr; } QList views() const override { return m_views; } QString documentName() const override { return m_name; } QString mimeType() override { return QString(); } QByteArray checksum() const override { return QByteArray(); } bool setEncoding (const QString &) override { return false; } QString encoding () const override { return m_encoding; } bool documentReload () override { return true; } bool documentSave () override { return true; } bool documentSaveAs () override { return true; } bool isEditingTransactionRunning() const override { return false; } QString text () const override { return QString(); } QString text ( const KTextEditor::Range&, bool = false ) const override { return QString(); } QChar characterAt( const KTextEditor::Cursor&) const override { return QChar(); } QString wordAt(const KTextEditor::Cursor&) const override { return QString(); } KTextEditor::Range wordRangeAt(const KTextEditor::Cursor&) const override { return KTextEditor::Range(); } bool isValidTextPosition(const KTextEditor::Cursor&) const override { return true; } QStringList textLines ( const KTextEditor::Range&, bool = false ) const override { return QStringList(); } QString line ( int ) const override { return QString(); } int lines () const override { return 0; } KTextEditor::Cursor documentEnd() const override { return KTextEditor::Cursor(); } int totalCharacters() const override { return 0; } int lineLength ( int ) const override { return 0; } bool setText ( const QString & ) override { return false; } bool setText ( const QStringList & ) override { return false; } bool clear () override { return true; } bool insertText ( const KTextEditor::Cursor &, const QString &, bool = false ) override { return false; } bool insertText ( const KTextEditor::Cursor &, const QStringList &, bool = false ) override { return false; } bool removeText ( const KTextEditor::Range &, bool = false ) override { return false; } bool insertLine ( int, const QString & ) override { return false; } bool insertLines ( int, const QStringList & ) override { return false; } bool removeLine ( int ) override { return false; } KTextEditor::DefaultStyle defaultStyleAt(const KTextEditor::Cursor &) const override { return KTextEditor::dsNormal; } QString mode() const override { return QString(); } QString highlightingMode() const override { return QString(); } QStringList modes() const override { return QStringList(); } QStringList highlightingModes() const override {return QStringList(); } bool setMode(const QString &) override { return false; } bool setHighlightingMode(const QString &) override { return false; } QString highlightingModeSection( int ) const override { return QString(); } QString modeSection( int ) const override { return QString(); } bool print() override { return false; } void printPreview() override {} QStringList embeddedHighlightingModes() const override { return QStringList(); } QString highlightingModeAt(const KTextEditor::Cursor &) override { return QString(); } bool isLineModified(int) const override { return false; } bool isLineSaved(int) const override { return false; } bool isLineTouched(int) const override { return false; } // KParts::ReadWritePart bool saveFile() 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()) override {} void writeSessionConfig(KConfigGroup &, const QSet & = QSet()) override {} bool postMessage(KTextEditor::Message *) override { return false; } bool isDataRecoveryAvailable() const override { return false; } void recoverData() override {} void discardDataRecovery() 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/autotests/filetree_model_test.cpp b/addons/filetree/autotests/filetree_model_test.cpp index 72b3450bc..2f594b560 100644 --- a/addons/filetree/autotests/filetree_model_test.cpp +++ b/addons/filetree/autotests/filetree_model_test.cpp @@ -1,915 +1,915 @@ /* This file is part of the KDE project * * 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 "filetree_model_test.h" #include "katefiletreemodel.h" #include "document_dummy.h" #include QTEST_GUILESS_MAIN(FileTreeModelTest) //BEGIN ResultNode class ResultNode { public: ResultNode() : name(), dir(true), children() {} // root node ResultNode(const ResultNode &other) : name(other.name), dir(other.dir), children(other.children) {} ResultNode(const char *_name, const bool _dir = false) : ResultNode(QString::fromLatin1(_name), _dir) {} ResultNode(const QString &_name, const bool _dir = false) : name(_name), dir(_dir), children() {} ResultNode &operator<<(ResultNode node) { children << node; return *this; } bool operator!=(const ResultNode &other) const { return !(*this == other); } bool operator==(const ResultNode &other) const { return (other.name == name) && (other.dir == dir) && (other.children == children); } friend QDebug operator<< (QDebug s, const ResultNode &node) { s << node.toString(); return s; } friend void debugOutput(QString &s, const ResultNode &rootNode, const int level = 0) { for (int i = 0; i < level; i++) { s += QLatin1String(" "); } - const QString name = rootNode.name.isEmpty() ? QLatin1String("ROOT") : rootNode.name; + const QString name = rootNode.name.isEmpty() ? QStringLiteral("ROOT") : rootNode.name; s += QLatin1String("( ") + name; if (rootNode.dir) { s += QLatin1String(", {D}"); } if (rootNode.children.isEmpty()) { s += QLatin1String(" )"); } else { s += QLatin1String(",\n"); for (int i = 0; i < rootNode.children.size(); i++) { const ResultNode &node = rootNode.children[i]; debugOutput(s, node, level + 1); if ((i + 1) < rootNode.children.size()) { s+= QLatin1String("\n"); } } s += (level == 0) ? QLatin1String("\n);") : QLatin1String(")"); } } QString toString() const { QString out; debugOutput(out, *this, 0); return out; } QString name; bool dir; QList children; }; Q_DECLARE_METATYPE(ResultNode) namespace QTest { inline bool qCompare(const ResultNode &t1, const ResultNode &t2, const char *actual, const char *expected, const char *file, int line) { /* compare_helper is not helping that much, we need to prepare copy of data */ const QByteArray a = t1.toString().toLatin1(); const QByteArray b = t2.toString().toLatin1(); char *val1 = new char[a.size() + 1]; char *val2 = new char[b.size() + 1]; memcpy(val1, a.constData(), a.size() + 1); memcpy(val2, b.constData(), b.size() + 1); return compare_helper(t1 == t2, "Compared ResultNode trees are not the same", val1, val2, actual, expected, file, line); } } //END ResultNode void FileTreeModelTest::initTestCase() {} void FileTreeModelTest::cleanupTestCase() {} void FileTreeModelTest::init() {} void FileTreeModelTest::cleanup() {} void FileTreeModelTest::basic() { QScopedPointer d1(new DummyDocument()); QScopedPointer d2(new DummyDocument()); KateFileTreeModel m(this); QCOMPARE(m.rowCount(QModelIndex()), 0); m.documentOpened(d1.data()); QCOMPARE(m.rowCount(QModelIndex()), 1); m.documentOpened(d2.data()); QCOMPARE(m.rowCount(QModelIndex()), 2); } void FileTreeModelTest::buildTree_data() { QTest::addColumn>("documents"); QTest::addColumn("nodes"); QTest::newRow("easy") << ( QList() << new DummyDocument("file:///a/foo.txt") ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) ); QTest::newRow("two") << ( QList() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///a/bar.txt") ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt") << ResultNode("bar.txt")) ); QTest::newRow("strangers") << ( QList() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///b/bar.txt") ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt")) ); QTest::newRow("lvl1 strangers") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt")) ); QTest::newRow("multiples") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") << new DummyDocument("file:///c/a/bar.txt") ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt") << ResultNode("bar.txt")) << (ResultNode("b", true) << ResultNode("bar.txt")) ); QTest::newRow("stairs") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/bar.txt") ) << ( ResultNode() << (ResultNode("c", true) << (ResultNode("a", true) << ResultNode("foo.txt")) << ResultNode("bar.txt")) ); QTest::newRow("reverse stairs") << ( QList() << new DummyDocument("file:///c/bar.txt") << new DummyDocument("file:///c/a/foo.txt") ) << ( ResultNode() << (ResultNode("c", true) << ResultNode("bar.txt") << (ResultNode("a", true) << ResultNode("foo.txt"))) ); QTest::newRow("matching") << ( QList() << new DummyDocument("file:///a/x/foo.txt") << new DummyDocument("file:///b/x/bar.txt") ) << ( ResultNode() << (ResultNode("a", true) << (ResultNode("x", true) << ResultNode("foo.txt"))) << (ResultNode("b", true) << (ResultNode("x", true) << ResultNode("bar.txt"))) ); QTest::newRow("matching even more") << ( QList() << new DummyDocument("file:///a/x/y/z/foo.txt") << new DummyDocument("file:///b/x/y/z/bar.txt") ) << ( ResultNode() << (ResultNode("a", true) << (ResultNode("x", true) << (ResultNode("y", true) << (ResultNode("z", true) << ResultNode("foo.txt"))))) << (ResultNode("b", true) << (ResultNode("x", true) << (ResultNode("y", true) << (ResultNode("z", true) << ResultNode("bar.txt"))))) ); QTest::newRow("matching with booby trap") << ( QList() << new DummyDocument("file:///x/y/foo.txt") << new DummyDocument("file:///c/x/bar.txt") << new DummyDocument("file:///d/y/baz.txt") ) << ( ResultNode() << (ResultNode("x", true) << (ResultNode("y", true) << ResultNode("foo.txt"))) << (ResultNode("d", true) << (ResultNode("y", true) << ResultNode("baz.txt"))) << (ResultNode("c", true) << (ResultNode("x", true) << ResultNode("bar.txt"))) ); QTest::newRow("branches") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") << new DummyDocument("file:///d/a/foo.txt") ) << ( ResultNode() << (ResultNode("c", true) << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt"))) << (ResultNode("d", true) << (ResultNode("a", true) << ResultNode("foo.txt"))) ); QTest::newRow("branches (more)") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") << new DummyDocument("file:///c/c/bar.txt") << new DummyDocument("file:///d/a/foo.txt") ) << ( ResultNode() << (ResultNode("c", true) << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt")) << (ResultNode("c", true) << ResultNode("bar.txt"))) << (ResultNode("d", true) << (ResultNode("a", true) << ResultNode("foo.txt"))) ); QTest::newRow("bug347578") << ( QList() << new DummyDocument("file:///f/g/a/b/c/d/e.txt") << new DummyDocument("file:///f/g/a/t/b/c/d/e.txt") ) << ( ResultNode() << (ResultNode("a", true) << (ResultNode("b", true) << (ResultNode("c", true) << (ResultNode("d", true) << ResultNode("e.txt")))) << (ResultNode("t", true) << (ResultNode("b", true) << (ResultNode("c", true) << (ResultNode("d", true) << ResultNode("e.txt")))))) ); QTest::newRow("levels") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") << new DummyDocument("file:///d/foo.txt") ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt")) << (ResultNode("d", true) << ResultNode("foo.txt")) ); QTest::newRow("remote simple") << ( QList() << new DummyDocument("http://example.org/foo.txt") ) << ( ResultNode() << (ResultNode("[example.org]", true) << ResultNode("foo.txt")) ); QTest::newRow("remote nested") << ( QList() << new DummyDocument("http://example.org/a/foo.txt") ) << ( ResultNode() << (ResultNode("[example.org]a", true) << ResultNode("foo.txt")) ); /* NOTE: this one is also not completely ok, is it? * on other hand, it would get confusing or overly leveled if opening * something like http://example.org/a/b/c/d/e/f/g.txt */ QTest::newRow("remote diverge") << ( QList() << new DummyDocument("http://example.org/a/foo.txt") << new DummyDocument("http://example.org/b/foo.txt") ) << ( ResultNode() << (ResultNode("[example.org]a", true) << ResultNode("foo.txt")) << (ResultNode("[example.org]b", true) << ResultNode("foo.txt")) ); } void FileTreeModelTest::buildTree() { KateFileTreeModel m(this); QFETCH(QList, documents); QFETCH(ResultNode, nodes); foreach(DummyDocument *doc, documents) { m.documentOpened(doc); } ResultNode root; walkTree(m, QModelIndex(), root); QCOMPARE(root, nodes); qDeleteAll(documents); } void FileTreeModelTest::buildTreeBatch_data() { // the easiest way to verify the equality of those two calls:) buildTree_data(); } void FileTreeModelTest::buildTreeBatch() { KateFileTreeModel m(this); QFETCH(QList, documents); QFETCH(ResultNode, nodes); QList list; foreach(DummyDocument *doc, documents) { list << doc; } m.documentsOpened(list); ResultNode root; walkTree(m, QModelIndex(), root); QCOMPARE(root, nodes); qDeleteAll(documents); } void FileTreeModelTest::buildTreeBatchPrefill_data() { QTest::addColumn>("prefill"); QTest::addColumn>("documents"); QTest::addColumn("nodes"); QTest::newRow("easy") << ( QList() << new DummyDocument("file:///a/foo.txt") ) << ( QList() << new DummyDocument("file:///a/bar.txt") ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt") << ResultNode("bar.txt")) ); QTest::newRow("split") << ( QList() << new DummyDocument("file:///a/foo.txt") ) << ( QList() << new DummyDocument("file:///b/foo.txt") ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("foo.txt")) ); } void FileTreeModelTest::buildTreeBatchPrefill() { KateFileTreeModel m(this); QFETCH(QList, prefill); QFETCH(QList, documents); QFETCH(ResultNode, nodes); foreach(DummyDocument *doc, prefill) { m.documentOpened(doc); } QList list; foreach(DummyDocument *doc, documents) { list << doc; } m.documentsOpened(list); ResultNode root; walkTree(m, QModelIndex(), root); QCOMPARE(root, nodes); qDeleteAll(prefill); qDeleteAll(documents); } void FileTreeModelTest::walkTree(KateFileTreeModel &model, const QModelIndex &rootIndex, ResultNode &rootNode) { if (!model.hasChildren(rootIndex)) { return; } const int rows = model.rowCount(rootIndex); for (int i = 0; i < rows; i++) { const QModelIndex idx = model.index(i, 0, rootIndex); ResultNode node(model.data(idx).toString(), model.isDir(idx)); walkTree(model, idx, node); rootNode << node; } } void FileTreeModelTest::buildTreeFullPath_data() { QTest::addColumn>("documents"); QTest::addColumn("nodes"); QTest::newRow("two") << ( QList() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///a/bar.txt") ) << ( ResultNode() << (ResultNode("/a", true) << ResultNode("foo.txt") << ResultNode("bar.txt")) ); QTest::newRow("multiples") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") << new DummyDocument("file:///c/a/bar.txt") ) << ( ResultNode() << (ResultNode("/c/a", true) << ResultNode("foo.txt") << ResultNode("bar.txt")) << (ResultNode("/c/b", true) << ResultNode("bar.txt")) ); /* This one and the case after can get a little bit tricky and * in some situation could end up in little bit confusing layout. * current root merge algorithm sees the divergent paths, so it * doesn't invoke merging. QTest::newRow("branches") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") ) << ( ResultNode() << (ResultNode("/c", true) << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt"))) ); */ /* QTest::newRow("levels") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") << new DummyDocument("file:///d/foo.txt") ) << ( ResultNode() << (ResultNode("/c", true) << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt"))) << (ResultNode("/d", true) << ResultNode("foo.txt")) ); */ QTest::newRow("remote simple") << ( QList() << new DummyDocument("http://example.org/foo.txt") ) << ( ResultNode() << (ResultNode("[example.org]", true) << ResultNode("foo.txt")) ); QTest::newRow("remote nested") << ( QList() << new DummyDocument("http://example.org/a/b/foo.txt") ) << ( ResultNode() << (ResultNode("[example.org]/a/b", true) << ResultNode("foo.txt")) ); /* NOTE: see the similar testcase in buildTree */ QTest::newRow("remote diverge") << ( QList() << new DummyDocument("http://example.org/c/a/foo.txt") << new DummyDocument("http://example.org/c/b/foo.txt") ) << ( ResultNode() << (ResultNode("[example.org]/c/a", true) << ResultNode("foo.txt")) << (ResultNode("[example.org]/c/b", true) << ResultNode("foo.txt")) ); } void FileTreeModelTest::buildTreeFullPath() { KateFileTreeModel m(this); m.setShowFullPathOnRoots(true); QFETCH(QList, documents); QFETCH(ResultNode, nodes); foreach(DummyDocument *doc, documents) { m.documentOpened(doc); } ResultNode root; walkTree(m, QModelIndex(), root); QCOMPARE(root, nodes); qDeleteAll(documents); } void FileTreeModelTest::listMode_data() { QTest::addColumn>("documents"); QTest::addColumn("nodes"); QTest::newRow("easy") << ( QList() << new DummyDocument("file:///a/foo.txt") ) << ( ResultNode() << ResultNode("foo.txt") ); QTest::newRow("two") << ( QList() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///a/bar.txt") ) << ( ResultNode() << ResultNode("foo.txt") << ResultNode("bar.txt") ); QTest::newRow("multiples") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") << new DummyDocument("file:///c/a/bar.txt") ) << ( ResultNode() << ResultNode("foo.txt") << ResultNode("bar.txt") << ResultNode("bar.txt") ); QTest::newRow("remote diverge") << ( QList() << new DummyDocument("http://example.org/a/foo.txt") << new DummyDocument("http://example.org/b/foo.txt") ) << ( ResultNode() << ResultNode("[example.org]foo.txt") << ResultNode("[example.org]foo.txt") ); } void FileTreeModelTest::listMode() { KateFileTreeModel m(this); m.setListMode(true); QFETCH(QList, documents); QFETCH(ResultNode, nodes); foreach(DummyDocument *doc, documents) { m.documentOpened(doc); } ResultNode root; walkTree(m, QModelIndex(), root); QCOMPARE(root, nodes); qDeleteAll(documents); } void FileTreeModelTest::deleteDocument_data() { QTest::addColumn>("documents"); QTest::addColumn>("remove"); QTest::addColumn("nodes"); QTest::newRow("empty") << ( QList() << new DummyDocument("file:///a/foo.txt") ) << ( QList() << 0 ) << ( ResultNode() ); QTest::newRow("two") << ( QList() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///a/bar.txt") ) << ( QList() << 0 ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("bar.txt")) ); QTest::newRow("multiple") << ( QList() << new DummyDocument("file:///a/foo0.txt") << new DummyDocument("file:///a/foo1.txt") << new DummyDocument("file:///a/foo2.txt") << new DummyDocument("file:///a/foo3.txt") << new DummyDocument("file:///a/foo4.txt") << new DummyDocument("file:///a/foo5.txt") << new DummyDocument("file:///a/foo6.txt") << new DummyDocument("file:///a/foo7.txt") ) << ( QList() << 1 << 2 << 4 << 6 ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo0.txt") << ResultNode("foo3.txt") << ResultNode("foo5.txt") << ResultNode("foo7.txt")) ); QTest::newRow("strangers") << ( QList() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///b/bar.txt") ) << ( QList() << 1 ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) ); QTest::newRow("branches") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") << new DummyDocument("file:///d/a/foo.txt") ) << ( QList() << 1 ) << ( ResultNode() << (ResultNode("c", true) << (ResultNode("a", true) << ResultNode("foo.txt"))) << (ResultNode("d", true) << (ResultNode("a", true) << ResultNode("foo.txt"))) ); QTest::newRow("levels") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") << new DummyDocument("file:///d/foo.txt") ) << ( QList() << 0 ) << ( ResultNode() << (ResultNode("b", true) << ResultNode("bar.txt")) << (ResultNode("d", true) << ResultNode("foo.txt")) ); QTest::newRow("levels extra") << ( QList() << new DummyDocument("file:///c/a/foo.txt") << new DummyDocument("file:///c/b/bar.txt") << new DummyDocument("file:///d/foo.txt") ) << ( QList() << 2 ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) << (ResultNode("b", true) << ResultNode("bar.txt")) ); QTest::newRow("remote diverge") << ( QList() << new DummyDocument("http://example.org/a/foo.txt") << new DummyDocument("http://example.org/b/foo.txt") ) << ( QList() << 1 ) << ( ResultNode() << (ResultNode("[example.org]a", true) << ResultNode("foo.txt")) ); } void FileTreeModelTest::deleteDocument() { KateFileTreeModel m(this); QFETCH(QList, documents); QFETCH(QList, remove); QFETCH(ResultNode, nodes); foreach(DummyDocument *doc, documents) { m.documentOpened(doc); } foreach(const int &index, remove) { m.documentClosed(documents[index]); } ResultNode root; walkTree(m, QModelIndex(), root); QCOMPARE(root, nodes); qDeleteAll(documents); } void FileTreeModelTest::deleteDocumentBatch_data() { QTest::addColumn>("documents"); QTest::addColumn>("remove"); QTest::addColumn>("fail"); QTest::addColumn("nodes"); QTest::newRow("neo") << ( QList() << new DummyDocument("file:///a/foo0.txt") << new DummyDocument("file:///a/foo1.txt") << new DummyDocument("file:///a/foo2.txt") << new DummyDocument("file:///a/foo3.txt") << new DummyDocument("file:///a/foo4.txt") << new DummyDocument("file:///a/foo5.txt") << new DummyDocument("file:///a/foo6.txt") << new DummyDocument("file:///a/foo7.txt") ) << ( QList() << 1 << 2 << 4 << 6 ) << ( QList() << 2 << 4 ) << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo0.txt") << ResultNode("foo2.txt") << ResultNode("foo3.txt") << ResultNode("foo4.txt") << ResultNode("foo5.txt") << ResultNode("foo7.txt")) ); } void FileTreeModelTest::deleteDocumentBatch() { KateFileTreeModel m(this); QFETCH(QList, documents); QFETCH(QList, remove); QFETCH(QList, fail); QFETCH(ResultNode, nodes); foreach (DummyDocument *doc, documents) { m.documentOpened(doc); } QList removing; foreach (const int &index, remove) { removing << documents[index]; } m.slotAboutToDeleteDocuments(removing); foreach (const int &index, remove) { if (!fail.contains(index)) { m.documentClosed(documents[index]); } } removing.clear(); foreach (const int &index, fail) { removing << documents[index]; } m.slotDocumentsDeleted(removing); ResultNode root; walkTree(m, QModelIndex(), root); QCOMPARE(root, nodes); qDeleteAll(documents); } void FileTreeModelTest::rename_data() { QTest::addColumn>("documents"); QTest::addColumn("rename_idx"); QTest::addColumn("rename_url"); QTest::addColumn("nodes"); QTest::newRow("empty") << ( QList() << new DummyDocument() - ) << 0 << QString::fromLatin1("file:///a/foo.txt") + ) << 0 << QStringLiteral("file:///a/foo.txt") << ( ResultNode() << (ResultNode("a", true) << ResultNode("foo.txt")) ); QTest::newRow("moving") << ( QList() << new DummyDocument("file:///a/foo.txt") - ) << 0 << QString::fromLatin1("file:///b/foo.txt") + ) << 0 << QStringLiteral("file:///b/foo.txt") << ( ResultNode() << (ResultNode("b", true) << ResultNode("foo.txt")) ); QTest::newRow("splitting") << ( QList() << new DummyDocument("file:///a/foo.txt") << new DummyDocument("file:///a/bar.txt") - ) << 0 << QString::fromLatin1("file:///b/foo.txt") + ) << 0 << QStringLiteral("file:///b/foo.txt") << ( ResultNode() << (ResultNode("a", true) << ResultNode("bar.txt")) << (ResultNode("b", true) << ResultNode("foo.txt")) ); } void FileTreeModelTest::rename() { KateFileTreeModel m(this); QFETCH(QList, documents); QFETCH(int, rename_idx); QFETCH(QString, rename_url); QFETCH(ResultNode, nodes); foreach (DummyDocument *doc, documents) { m.documentOpened(doc); } documents[rename_idx]->setUrl(rename_url); m.documentNameChanged(documents[rename_idx]); ResultNode root; walkTree(m, QModelIndex(), root); QCOMPARE(root, nodes); qDeleteAll(documents); } // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/filetree/katefiletree.cpp b/addons/filetree/katefiletree.cpp index 3624421ef..6adb09a8b 100644 --- a/addons/filetree/katefiletree.cpp +++ b/addons/filetree/katefiletree.cpp @@ -1,717 +1,717 @@ /* 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, &KateFileTree::activated, this, &KateFileTree::mouseClicked); connect(this, &KateFileTree::clicked, this, &KateFileTree::mouseClicked); - m_filelistReloadDocument = new QAction(QIcon::fromTheme(QLatin1String("view-refresh")), i18nc("@action:inmenu", "Reloa&d"), this); + m_filelistReloadDocument = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), i18nc("@action:inmenu", "Reloa&d"), this); connect(m_filelistReloadDocument, &QAction::triggered, this, &KateFileTree::slotDocumentReload); m_filelistReloadDocument->setWhatsThis(i18n("Reload selected document(s) from disk.")); - m_filelistCloseDocument = new QAction(QIcon::fromTheme(QLatin1String("document-close")), i18nc("@action:inmenu", "Close"), this); + m_filelistCloseDocument = new QAction(QIcon::fromTheme(QStringLiteral("document-close")), i18nc("@action:inmenu", "Close"), this); connect(m_filelistCloseDocument, &QAction::triggered, this, &KateFileTree::slotDocumentClose); m_filelistCloseDocument->setWhatsThis(i18n("Close the current document.")); - m_filelistExpandRecursive = new QAction(QIcon::fromTheme(QLatin1String("view-list-tree")), i18nc("@action:inmenu", "Expand recursively"), this); + m_filelistExpandRecursive = new QAction(QIcon::fromTheme(QStringLiteral("view-list-tree")), i18nc("@action:inmenu", "Expand recursively"), this); connect(m_filelistExpandRecursive, &QAction::triggered, this, &KateFileTree::slotExpandRecursive); m_filelistExpandRecursive->setWhatsThis(i18n("Expand the file list sub tree recursively.")); - m_filelistCollapseRecursive = new QAction(QIcon::fromTheme(QLatin1String("view-list-tree")), i18nc("@action:inmenu", "Collapse recursively"), this); + m_filelistCollapseRecursive = new QAction(QIcon::fromTheme(QStringLiteral("view-list-tree")), i18nc("@action:inmenu", "Collapse recursively"), this); connect(m_filelistCollapseRecursive, &QAction::triggered, this, &KateFileTree::slotCollapseRecursive); m_filelistCollapseRecursive->setWhatsThis(i18n("Collapse the file list sub tree recursively.")); - m_filelistCloseOtherDocument = new QAction(QIcon::fromTheme(QLatin1String("document-close")), i18nc("@action:inmenu", "Close Other"), this); + m_filelistCloseOtherDocument = new QAction(QIcon::fromTheme(QStringLiteral("document-close")), i18nc("@action:inmenu", "Close Other"), this); connect(m_filelistCloseOtherDocument, &QAction::triggered, this, &KateFileTree::slotDocumentCloseOther); m_filelistCloseOtherDocument->setWhatsThis(i18n("Close other documents in this folder.")); - m_filelistCopyFilename = new QAction(QIcon::fromTheme(QLatin1String("edit-copy")), i18nc("@action:inmenu", "Copy File Path"), this); + m_filelistCopyFilename = new QAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action:inmenu", "Copy File Path"), this); connect(m_filelistCopyFilename, &QAction::triggered, this, &KateFileTree::slotCopyFilename); m_filelistCopyFilename->setWhatsThis(i18n("Copy path and filename to the clipboard.")); - m_filelistRenameFile = new QAction(QIcon::fromTheme(QLatin1String("edit-rename")), i18nc("@action:inmenu", "Rename File"), this); + m_filelistRenameFile = new QAction(QIcon::fromTheme(QStringLiteral("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); + m_filelistDeleteDocument = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete-shred")), i18nc("@action:inmenu", "Delete Document"), this); connect(m_filelistDeleteDocument, &QAction::triggered, this, &KateFileTree::slotDocumentDelete); m_filelistDeleteDocument->setWhatsThis(i18n("Close and delete selected file from storage.")); QActionGroup *modeGroup = new QActionGroup(this); - m_treeModeAction = setupOption(modeGroup, QIcon::fromTheme(QLatin1String("view-list-tree")), i18nc("@action:inmenu", "Tree Mode"), + m_treeModeAction = setupOption(modeGroup, QIcon::fromTheme(QStringLiteral("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"), + m_listModeAction = setupOption(modeGroup, QIcon::fromTheme(QStringLiteral("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); + m_resetHistory = new QAction(QIcon::fromTheme(QStringLiteral("edit-clear-history")), i18nc("@action:inmenu", "Clear History"), this); connect(m_resetHistory, &QAction::triggered, this, &KateFileTree::slotResetHistory); m_resetHistory->setWhatsThis(i18n("Clear edit/view history.")); QPalette p = palette(); p.setColor(QPalette::Inactive, QPalette::Highlight, p.color(QPalette::Active, QPalette::Highlight)); p.setColor(QPalette::Inactive, QPalette::HighlightedText, p.color(QPalette::Active, QPalette::HighlightedText)); setPalette(p); } KateFileTree::~KateFileTree() {} void KateFileTree::setModel(QAbstractItemModel *model) { Q_ASSERT(qobject_cast(model)); // we don't really work with anything else QTreeView::setModel(model); } QAction *KateFileTree::setupOption( QActionGroup *group, const QIcon &icon, const QString &label, const QString &whatsThis, const char *slot, bool checked ) { QAction *new_action = new QAction(icon, label, this); new_action->setWhatsThis(whatsThis); new_action->setActionGroup(group); new_action->setCheckable(true); new_action->setChecked(checked); connect(new_action, SIGNAL(triggered()), this, slot); return new_action; } void KateFileTree::slotListMode() { emit viewModeChanged(true); } void KateFileTree::slotTreeMode() { emit viewModeChanged(false); } void KateFileTree::slotSortName() { emit sortRoleChanged(Qt::DisplayRole); } void KateFileTree::slotSortPath() { emit sortRoleChanged(KateFileTreeModel::PathRole); } void KateFileTree::slotSortOpeningOrder() { emit sortRoleChanged(KateFileTreeModel::OpeningOrderRole); } void KateFileTree::slotCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous) { Q_UNUSED(previous); if (!current.isValid()) { return; } KTextEditor::Document *doc = model()->data(current, KateFileTreeModel::DocumentRole).value(); if (doc) { m_previouslySelected = current; } } void KateFileTree::mouseClicked(const QModelIndex &index) { if (auto doc = model()->data(index, KateFileTreeModel::DocumentRole).value()) { emit activateDocument(doc); } } void KateFileTree::contextMenuEvent(QContextMenuEvent *event) { m_indexContextMenu = selectionModel()->currentIndex(); selectionModel()->setCurrentIndex(m_indexContextMenu, QItemSelectionModel::ClearAndSelect); KateFileTreeProxyModel *ftpm = static_cast(model()); KateFileTreeModel *ftm = static_cast(ftpm->sourceModel()); bool listMode = ftm->listMode(); m_treeModeAction->setChecked(!listMode); m_listModeAction->setChecked(listMode); int sortRole = ftpm->sortRole(); m_sortByFile->setChecked(sortRole == Qt::DisplayRole); m_sortByPath->setChecked(sortRole == KateFileTreeModel::PathRole); m_sortByOpeningOrder->setChecked(sortRole == KateFileTreeModel::OpeningOrderRole); KTextEditor::Document *doc = m_indexContextMenu.data(KateFileTreeModel::DocumentRole).value(); const bool isFile = (nullptr != doc); QMenu menu; menu.addAction(m_filelistReloadDocument); menu.addAction(m_filelistCloseDocument); menu.addAction(m_filelistExpandRecursive); menu.addAction(m_filelistCollapseRecursive); if (isFile) { menu.addAction(m_filelistCloseOtherDocument); menu.addSeparator(); menu.addAction(m_filelistCopyFilename); menu.addAction(m_filelistRenameFile); menu.addAction(m_filelistPrintDocument); menu.addAction(m_filelistPrintDocumentPreview); QMenu *openWithMenu = menu.addMenu(i18nc("@action:inmenu", "Open With")); connect(openWithMenu, &QMenu::aboutToShow, this, &KateFileTree::slotFixOpenWithMenu); connect(openWithMenu, &QMenu::triggered, this, &KateFileTree::slotOpenWithMenuAction); const bool hasFileName = doc->url().isValid(); m_filelistCopyFilename->setEnabled(hasFileName); m_filelistRenameFile->setEnabled(hasFileName); m_filelistDeleteDocument->setEnabled(hasFileName); menu.addAction(m_filelistDeleteDocument); } menu.addSeparator(); QMenu *view_menu = menu.addMenu(i18nc("@action:inmenu", "View Mode")); view_menu->addAction(m_treeModeAction); view_menu->addAction(m_listModeAction); - QMenu *sort_menu = menu.addMenu(QIcon::fromTheme(QLatin1String("view-sort-ascending")), i18nc("@action:inmenu", "Sort By")); + QMenu *sort_menu = menu.addMenu(QIcon::fromTheme(QStringLiteral("view-sort-ascending")), i18nc("@action:inmenu", "Sort By")); sort_menu->addAction(m_sortByFile); sort_menu->addAction(m_sortByPath); sort_menu->addAction(m_sortByOpeningOrder); menu.addAction(m_resetHistory); menu.exec(viewport()->mapToGlobal(event->pos())); if (m_previouslySelected.isValid()) { selectionModel()->setCurrentIndex(m_previouslySelected, QItemSelectionModel::ClearAndSelect); } event->accept(); } void KateFileTree::slotFixOpenWithMenu() { QMenu *menu = (QMenu *)sender(); menu->clear(); KTextEditor::Document *doc = model()->data(m_indexContextMenu, KateFileTreeModel::DocumentRole).value(); if (!doc) { return; } // get a list of appropriate services. QMimeDatabase db; QMimeType mime = db.mimeTypeForName(doc->mimeType()); QAction *a = nullptr; - KService::List offers = KMimeTypeTrader::self()->query(mime.name(), QLatin1String("Application")); + KService::List offers = KMimeTypeTrader::self()->query(mime.name(), QStringLiteral("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(); // TODO: the following code was improved in kate/katefileactions.cpp and should be reused here // (make sure that the mentioned bug 381052 does not reappear) 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(); // TODO: the following code was improved in kate/katefileactions.cpp and should be reused here 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(); // TODO: the following code was improved in kate/katefileactions.cpp and should be reused here 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") + KStandardGuiItem::yes(), KStandardGuiItem::no(), QStringLiteral("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/katefiletreemodel.cpp b/addons/filetree/katefiletreemodel.cpp index cdef4484b..e84d1a165 100644 --- a/addons/filetree/katefiletreemodel.cpp +++ b/addons/filetree/katefiletreemodel.cpp @@ -1,1337 +1,1337 @@ /* This file is part of the KDE project Copyright (C) 2010 Thomas Fjellstrom This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "katefiletreemodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "katefiletreedebug.h" class ProxyItemDir; class ProxyItem { friend class KateFileTreeModel; public: enum Flag { None = 0, Dir = 1, Modified = 2, ModifiedExternally = 4, DeletedExternally = 8, Empty = 16, ShowFullPath = 32, Host = 64 }; Q_DECLARE_FLAGS(Flags, Flag) ProxyItem(const QString &n, ProxyItemDir *p = nullptr, Flags f = ProxyItem::None); ~ProxyItem(); int addChild(ProxyItem *p); void remChild(ProxyItem *p); ProxyItemDir *parent() const; ProxyItem *child(int idx) const; int childCount() const; int row() const; const QString &display() const; const QString &documentName() const; const QString &path() const; void setPath(const QString &str); void setHost(const QString &host); const QString &host() const; void setIcon(const QIcon &i); const QIcon &icon() const; const QList &children() const; QList &children(); void setDoc(KTextEditor::Document *doc); KTextEditor::Document *doc() const; /** * the view usess this to close all the documents under the folder * @returns list of all the (nested) documents under this node */ QList docTree() const; void setFlags(Flags flags); void setFlag(Flag flag); void clearFlag(Flag flag); bool flag(Flag flag) const; private: QString m_path; QString m_documentName; ProxyItemDir *m_parent; QList m_children; int m_row; Flags m_flags; QString m_display; QIcon m_icon; KTextEditor::Document *m_doc; QString m_host; protected: void updateDisplay(); void updateDocumentName(); }; QDebug operator<<(QDebug dbg, ProxyItem *item) { if (!item) { dbg.nospace() << "ProxyItem(0x0) "; return dbg.maybeSpace(); } const void *parent = static_cast(item->parent()); dbg.nospace() << "ProxyItem(" << (void *)item << ","; dbg.nospace() << parent << "," << item->row() << ","; dbg.nospace() << item->doc() << "," << item->path() << ") "; return dbg.maybeSpace(); } class ProxyItemDir : public ProxyItem { public: - ProxyItemDir(QString n, ProxyItemDir *p = nullptr) : ProxyItem(n, p) { + ProxyItemDir(const QString &n, ProxyItemDir *p = nullptr) : ProxyItem(n, p) { setFlag(ProxyItem::Dir); updateDisplay(); - setIcon(QIcon::fromTheme(QLatin1String("folder"))); + setIcon(QIcon::fromTheme(QStringLiteral("folder"))); } }; QDebug operator<<(QDebug dbg, ProxyItemDir *item) { if (!item) { dbg.nospace() << "ProxyItemDir(0x0) "; return dbg.maybeSpace(); } const void *parent = static_cast(item->parent()); dbg.nospace() << "ProxyItemDir(" << (void *)item << ","; dbg.nospace() << parent << "," << item->row() << ","; dbg.nospace() << item->path() << ", children:" << item->childCount() << ") "; return dbg.maybeSpace(); } Q_DECLARE_OPERATORS_FOR_FLAGS(ProxyItem::Flags) //BEGIN ProxyItem ProxyItem::ProxyItem(const QString &d, ProxyItemDir *p, ProxyItem::Flags f) : m_path(d), m_parent(Q_NULLPTR), m_row(-1), m_flags(f), m_doc(nullptr) { updateDisplay(); /** * add to parent, if parent passed * we assigned above nullptr to parent to not trigger * remove from old parent here! */ if (p) { p->addChild(this); } } ProxyItem::~ProxyItem() { qDeleteAll(m_children); } void ProxyItem::updateDisplay() { // triggers only if this is a top level node and the root has the show full path flag set. if (flag(ProxyItem::Dir) && m_parent && !m_parent->m_parent && m_parent->flag(ProxyItem::ShowFullPath)) { m_display = m_path; if (m_display.startsWith(QDir::homePath())) { - m_display.replace(0, QDir::homePath().length(), QLatin1String("~")); + m_display.replace(0, QDir::homePath().length(), QStringLiteral("~")); } } 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()); + const QString hostPrefix = QStringLiteral("[%1]").arg(host()); if (hostPrefix != m_display) { m_display = hostPrefix + m_display; } } } } int ProxyItem::addChild(ProxyItem *item) { // remove from old parent, is any if (item->m_parent) { item->m_parent->remChild(item); } const int item_row = m_children.count(); item->m_row = item_row; m_children.append(item); item->m_parent = static_cast(this); item->updateDisplay(); return item_row; } void ProxyItem::remChild(ProxyItem *item) { const int idx = m_children.indexOf(item); Q_ASSERT(idx != -1); m_children.removeAt(idx); for (int i = idx; i < m_children.count(); i++) { m_children[i]->m_row = i; } item->m_parent = nullptr; } ProxyItemDir *ProxyItem::parent() const { return m_parent; } ProxyItem *ProxyItem::child(int idx) const { return (idx < 0 || idx >= m_children.count()) ? nullptr : 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); + m_documentName = QStringLiteral("[%1]%2").arg(m_host, docName); } else { m_documentName = docName; } } //END ProxyItem KateFileTreeModel::KateFileTreeModel(QObject *p) : QAbstractItemModel(p) - , m_root(new ProxyItemDir(QLatin1String("m_root"), nullptr)) + , m_root(new ProxyItemDir(QStringLiteral("m_root"), nullptr)) { // setup default settings // session init will set these all soon const KColorScheme colors(QPalette::Active); const QColor bg = colors.background().color(); m_editShade = KColorUtils::tint(bg, colors.foreground(KColorScheme::ActiveText).color(), 0.5); m_viewShade = KColorUtils::tint(bg, colors.foreground(KColorScheme::VisitedText).color(), 0.5); m_shadingEnabled = true; m_listMode = false; initModel(); } KateFileTreeModel::~KateFileTreeModel() { delete m_root; } bool KateFileTreeModel::shadingEnabled() const { return m_shadingEnabled; } void KateFileTreeModel::setShadingEnabled(bool se) { if (m_shadingEnabled != se) { updateBackgrounds(true); m_shadingEnabled = se; } } const QColor &KateFileTreeModel::editShade() const { return m_editShade; } void KateFileTreeModel::setEditShade(const QColor &es) { m_editShade = es; } const QColor &KateFileTreeModel::viewShade() const { return m_viewShade; } void KateFileTreeModel::setViewShade(const QColor &vs) { m_viewShade = vs; } bool KateFileTreeModel::showFullPathOnRoots(void) const { return m_root->flag(ProxyItem::ShowFullPath); } void KateFileTreeModel::setShowFullPathOnRoots(bool s) { if (s) { m_root->setFlag(ProxyItem::ShowFullPath); } else { m_root->clearFlag(ProxyItem::ShowFullPath); } foreach(ProxyItem * root, m_root->children()) { root->updateDisplay(); } } void KateFileTreeModel::initModel() { // add already existing documents foreach(KTextEditor::Document * doc, KTextEditor::Editor::instance()->application()->documents()) { documentOpened(doc); } } void KateFileTreeModel::clearModel() { // remove all items // can safely ignore documentClosed here beginRemoveRows(QModelIndex(), 0, qMax(m_root->childCount() - 1, 0)); delete m_root; - m_root = new ProxyItemDir(QLatin1String("m_root"), nullptr); + m_root = new ProxyItemDir(QStringLiteral("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, &KTextEditor::Document::documentNameChanged, this, &KateFileTreeModel::documentNameChanged); connect(doc, &KTextEditor::Document::documentUrlChanged, this, &KateFileTreeModel::documentNameChanged); connect(doc, &KTextEditor::Document::modifiedChanged, this, &KateFileTreeModel::documentModifiedChanged); connect(doc, SIGNAL(modifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SLOT(documentModifiedOnDisc(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason))); } QModelIndex KateFileTreeModel::docIndex(const KTextEditor::Document *doc) const { if (!m_docmap.contains(doc)) { return QModelIndex(); } ProxyItem *item = m_docmap[doc]; return createIndex(item->row(), 0, item); } Qt::ItemFlags KateFileTreeModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = Qt::ItemIsEnabled; if (!index.isValid()) { return nullptr; } const ProxyItem *item = static_cast(index.internalPointer()); if (item) { if (!item->childCount()) { flags |= Qt::ItemIsSelectable; } if (item->doc() && item->doc()->url().isValid()) { flags |= Qt::ItemIsDragEnabled; } } return flags; } Q_DECLARE_METATYPE(QList) QVariant KateFileTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } ProxyItem *item = static_cast(index.internalPointer()); if (!item) { return QVariant(); } switch (role) { case KateFileTreeModel::PathRole: // allow to sort with hostname + path, bug 271488 return (item->doc() && !item->doc()->url().isEmpty()) ? item->doc()->url().toString() : item->path(); case KateFileTreeModel::DocumentRole: return QVariant::fromValue(item->doc()); case KateFileTreeModel::OpeningOrderRole: return item->row(); case KateFileTreeModel::DocumentTreeRole: return QVariant::fromValue(item->docTree()); case Qt::DisplayRole: // in list mode we want to use kate's fancy names. if (m_listMode) { return item->documentName(); } else { return item->display(); } case Qt::DecorationRole: return item->icon(); case Qt::ToolTipRole: { QString tooltip = item->path(); if (item->flag(ProxyItem::DeletedExternally) || item->flag(ProxyItem::ModifiedExternally)) { tooltip = i18nc("%1 is the full path", "

%1

The document has been modified by another application.

", item->path()); } return tooltip; } case Qt::ForegroundRole: { const KColorScheme colors(QPalette::Active); if (!item->flag(ProxyItem::Dir) && (!item->doc() || item->doc()->openingError())) { return colors.foreground(KColorScheme::InactiveText).color(); } } break; case Qt::BackgroundRole: // TODO: do that funky shading the file list does... if (m_shadingEnabled && m_brushes.contains(item)) { return m_brushes[item]; } break; } return QVariant(); } QMimeData *KateFileTreeModel::mimeData(const QModelIndexList &indexes) const { QList urls; for (const auto &index : indexes) { ProxyItem *item = static_cast(index.internalPointer()); if (!item || !item->doc() || !item->doc()->url().isValid()) { continue; } urls.append(item->doc()->url()); } if (urls.isEmpty()) { return nullptr; } QMimeData *mimeData = new QMimeData(); mimeData->setUrls(urls); return mimeData; } QVariant KateFileTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(orientation); Q_UNUSED(role); if (section == 0) { return QLatin1String("name"); } return QVariant(); } int KateFileTreeModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) { return m_root->childCount(); } const ProxyItem *item = static_cast(parent.internalPointer()); if (!item) { return 0; } return item->childCount(); } int KateFileTreeModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return 1; } QModelIndex KateFileTreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return QModelIndex(); } const ProxyItem *item = static_cast(index.internalPointer()); if (!item) { return QModelIndex(); } if (!item->parent()) { return QModelIndex(); } if (item->parent() == m_root) { return QModelIndex(); } return createIndex(item->parent()->row(), 0, item->parent()); } QModelIndex KateFileTreeModel::index(int row, int column, const QModelIndex &parent) const { const ProxyItem *p = nullptr; if (column != 0) { return QModelIndex(); } if (!parent.isValid()) { p = m_root; } else { p = static_cast(parent.internalPointer()); } if (!p) { return QModelIndex(); } if (row < 0 || row >= p->childCount()) { return QModelIndex(); } return createIndex(row, 0, p->child(row)); } bool KateFileTreeModel::hasChildren(const QModelIndex &parent) const { if (!parent.isValid()) { return m_root->childCount() > 0; } const ProxyItem *item = static_cast(parent.internalPointer()); if (!item) { return false; } return item->childCount() > 0; } bool KateFileTreeModel::isDir(const QModelIndex &index) const { if (!index.isValid()) { return true; } const ProxyItem *item = static_cast(index.internalPointer()); if (!item) { return false; } return item->flag(ProxyItem::Dir); } bool KateFileTreeModel::listMode() const { return m_listMode; } void KateFileTreeModel::setListMode(bool lm) { if (lm != m_listMode) { m_listMode = lm; clearModel(); initModel(); } } void KateFileTreeModel::documentOpened(KTextEditor::Document *doc) { ProxyItem *item = new ProxyItem(QString()); item->setDoc(doc); updateItemPathAndHost(item); setupIcon(item); handleInsert(item); m_docmap[doc] = item; connectDocument(doc); } void KateFileTreeModel::documentsOpened(const QList &docs) { foreach(KTextEditor::Document * doc, docs) { if (m_docmap.contains(doc)) { documentNameChanged(doc); } else { documentOpened(doc); } } } void KateFileTreeModel::documentModifiedChanged(KTextEditor::Document *doc) { if (!m_docmap.contains(doc)) { return; } ProxyItem *item = m_docmap[doc]; if (doc->isModified()) { item->setFlag(ProxyItem::Modified); } else { item->clearFlag(ProxyItem::Modified); item->clearFlag(ProxyItem::ModifiedExternally); item->clearFlag(ProxyItem::DeletedExternally); } setupIcon(item); const QModelIndex idx = createIndex(item->row(), 0, item); emit dataChanged(idx, idx); } void KateFileTreeModel::documentModifiedOnDisc(KTextEditor::Document *doc, bool modified, KTextEditor::ModificationInterface::ModifiedOnDiskReason reason) { Q_UNUSED(modified); if (!m_docmap.contains(doc)) { return; } ProxyItem *item = m_docmap[doc]; // This didn't do what I thought it did, on an ignore // we'd get !modified causing the warning icons to disappear if (!modified) { item->clearFlag(ProxyItem::ModifiedExternally); item->clearFlag(ProxyItem::DeletedExternally); } else { if (reason == KTextEditor::ModificationInterface::OnDiskDeleted) { item->setFlag(ProxyItem::DeletedExternally); } else if (reason == KTextEditor::ModificationInterface::OnDiskModified) { item->setFlag(ProxyItem::ModifiedExternally); } else if (reason == KTextEditor::ModificationInterface::OnDiskCreated) { // with out this, on "reload" we don't get the icons removed :( item->clearFlag(ProxyItem::ModifiedExternally); item->clearFlag(ProxyItem::DeletedExternally); } } setupIcon(item); const QModelIndex idx = createIndex(item->row(), 0, item); emit dataChanged(idx, idx); } void KateFileTreeModel::documentActivated(const KTextEditor::Document *doc) { if (!m_docmap.contains(doc)) { return; } ProxyItem *item = m_docmap[doc]; m_viewHistory.removeAll(item); m_viewHistory.prepend(item); while (m_viewHistory.count() > 10) { m_viewHistory.removeLast(); } updateBackgrounds(); } void KateFileTreeModel::documentEdited(const KTextEditor::Document *doc) { if (!m_docmap.contains(doc)) { return; } ProxyItem *item = m_docmap[doc]; m_editHistory.removeAll(item); m_editHistory.prepend(item); while (m_editHistory.count() > 10) { m_editHistory.removeLast(); } updateBackgrounds(); } void KateFileTreeModel::slotAboutToDeleteDocuments(const QList &docs) { foreach(const KTextEditor::Document * doc, docs) { disconnect(doc, &KTextEditor::Document::documentNameChanged, this, &KateFileTreeModel::documentNameChanged); disconnect(doc, &KTextEditor::Document::documentUrlChanged, this, &KateFileTreeModel::documentNameChanged); disconnect(doc, &KTextEditor::Document::modifiedChanged, this, &KateFileTreeModel::documentModifiedChanged); disconnect(doc, SIGNAL(modifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SLOT(documentModifiedOnDisc(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason))); } } void KateFileTreeModel::slotDocumentsDeleted(const QList &docs) { foreach(const KTextEditor::Document * doc, docs) { connectDocument(doc); } } class EditViewCount { public: EditViewCount(): edit(0), view(0) {} int edit; int view; }; void KateFileTreeModel::updateBackgrounds(bool force) { if (!m_shadingEnabled && !force) { return; } QMap helper; int i = 1; foreach(ProxyItem * item, m_viewHistory) { helper[item].view = i; i++; } i = 1; foreach(ProxyItem * item, m_editHistory) { helper[item].edit = i; i++; } QMap oldBrushes = m_brushes; m_brushes.clear(); const int hc = m_viewHistory.count(); const int ec = m_editHistory.count(); for (QMap::iterator it = helper.begin(); it != helper.end(); ++it) { QColor shade(m_viewShade); QColor eshade(m_editShade); if (it.value().edit > 0) { int v = hc - it.value().view; int e = ec - it.value().edit + 1; e = e * e; const int n = qMax(v + e, 1); shade.setRgb( ((shade.red() * v) + (eshade.red() * e)) / n, ((shade.green() * v) + (eshade.green() * e)) / n, ((shade.blue() * v) + (eshade.blue() * e)) / n ); } // blend in the shade color; latest is most colored. const double t = double(hc - it.value().view + 1) / double(hc); m_brushes[it.key()] = QBrush(KColorUtils::mix(QPalette().color(QPalette::Base), shade, t)); } for (auto it = m_brushes.constBegin(), end = m_brushes.constEnd(); it != end; ++it) { ProxyItem *item = it.key(); oldBrushes.remove(item); const QModelIndex idx = createIndex(item->row(), 0, item); dataChanged(idx, idx); } for (auto it = oldBrushes.constBegin(), end = oldBrushes.constEnd(); it != end; ++it) { ProxyItem *item = it.key(); const QModelIndex idx = createIndex(item->row(), 0, item); dataChanged(idx, idx); } } void KateFileTreeModel::handleEmptyParents(ProxyItemDir *item) { Q_ASSERT(item != nullptr); if (!item->parent()) { return; } ProxyItemDir *parent = item->parent(); while (parent) { if (!item->childCount()) { const QModelIndex parent_index = (parent == m_root) ? QModelIndex() : createIndex(parent->row(), 0, parent); beginRemoveRows(parent_index, item->row(), item->row()); parent->remChild(item); endRemoveRows(); delete item; } else { // breakout early, if this node isn't empty, theres no use in checking its parents return; } item = parent; parent = item->parent(); } } void KateFileTreeModel::documentClosed(KTextEditor::Document *doc) { if (!m_docmap.contains(doc)) { return; } if (m_shadingEnabled) { ProxyItem *toRemove = m_docmap[doc]; if (m_brushes.contains(toRemove)) { m_brushes.remove(toRemove); } if (m_viewHistory.contains(toRemove)) { m_viewHistory.removeAll(toRemove); } if (m_editHistory.contains(toRemove)) { m_editHistory.removeAll(toRemove); } } ProxyItem *node = m_docmap[doc]; ProxyItemDir *parent = node->parent(); const QModelIndex parent_index = (parent == m_root) ? QModelIndex() : createIndex(parent->row(), 0, parent); beginRemoveRows(parent_index, node->row(), node->row()); node->parent()->remChild(node); endRemoveRows(); delete node; handleEmptyParents(parent); m_docmap.remove(doc); } void KateFileTreeModel::documentNameChanged(KTextEditor::Document *doc) { if (!m_docmap.contains(doc)) { return; } ProxyItem *item = m_docmap[doc]; if (m_shadingEnabled) { ProxyItem *toRemove = m_docmap[doc]; if (m_brushes.contains(toRemove)) { QBrush brush = m_brushes[toRemove]; m_brushes.remove(toRemove); m_brushes.insert(item, brush); } if (m_viewHistory.contains(toRemove)) { const int idx = m_viewHistory.indexOf(toRemove); if (idx != -1) { m_viewHistory.replace(idx, item); } } if (m_editHistory.contains(toRemove)) { const int idx = m_editHistory.indexOf(toRemove); if (idx != -1) { m_editHistory.replace(idx, item); } } } handleNameChange(item); emit triggerViewChangeAfterNameChange(); // FIXME: heh, non-standard signal? } ProxyItemDir *KateFileTreeModel::findRootNode(const QString &name, const int r) const { foreach(ProxyItem * item, m_root->children()) { if (!item->flag(ProxyItem::Dir)) { continue; } // make sure we're actually matching against the right dir, // previously the check below would match /foo/xy against /foo/x // and return /foo/x rather than /foo/xy // this seems a bit hackish, but is the simplest way to solve the // current issue. QString path = item->path().section(QLatin1Char('/'), 0, -r) + QLatin1Char('/'); if (name.startsWith(path)) { return static_cast(item); } } return nullptr; } ProxyItemDir *KateFileTreeModel::findChildNode(const ProxyItemDir *parent, const QString &name) const { Q_ASSERT(parent != nullptr); Q_ASSERT(!name.isEmpty()); if (!parent->childCount()) { return nullptr; } foreach(ProxyItem * item, parent->children()) { if (!item->flag(ProxyItem::Dir)) { continue; } if (item->display() == name) { return static_cast(item); } } return nullptr; } void KateFileTreeModel::insertItemInto(ProxyItemDir *root, ProxyItem *item) { Q_ASSERT(root != nullptr); Q_ASSERT(item != nullptr); QString tail = item->path(); tail.remove(0, root->path().length()); QStringList parts = tail.split(QLatin1Char('/'), QString::SkipEmptyParts); ProxyItemDir *ptr = root; QStringList current_parts; current_parts.append(root->path()); // seems this can be empty, see bug 286191 if (!parts.isEmpty()) { parts.pop_back(); } foreach(const QString & part, parts) { current_parts.append(part); ProxyItemDir *find = findChildNode(ptr, part); if (!find) { const QString new_name = current_parts.join(QLatin1String("/")); const QModelIndex parent_index = (ptr == m_root) ? QModelIndex() : createIndex(ptr->row(), 0, ptr); beginInsertRows(parent_index, ptr->childCount(), ptr->childCount()); ptr = new ProxyItemDir(new_name, ptr); endInsertRows(); } else { ptr = find; } } const QModelIndex parent_index = (ptr == m_root) ? QModelIndex() : createIndex(ptr->row(), 0, ptr); beginInsertRows(parent_index, ptr->childCount(), ptr->childCount()); ptr->addChild(item); endInsertRows(); } void KateFileTreeModel::handleInsert(ProxyItem *item) { Q_ASSERT(item != nullptr); if (m_listMode || item->flag(ProxyItem::Empty)) { beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount()); m_root->addChild(item); endInsertRows(); return; } // case (item.path > root.path) ProxyItemDir *root = findRootNode(item->path()); if (root) { insertItemInto(root, item); return; } // trim off trailing file and dir QString base = item->path().section(QLatin1Char('/'), 0, -2); // create new root ProxyItemDir *new_root = new ProxyItemDir(base); new_root->setHost(item->host()); // add new root to m_root beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount()); m_root->addChild(new_root); endInsertRows(); // same fix as in findRootNode, try to match a full dir, instead of a partial path base += QLatin1Char('/'); // try and merge existing roots with the new root node (new_root.path < root.path) foreach(ProxyItem * root, m_root->children()) { if (root == new_root || !root->flag(ProxyItem::Dir)) { continue; } if (root->path().startsWith(base)) { beginRemoveRows(QModelIndex(), root->row(), root->row()); m_root->remChild(root); endRemoveRows(); //beginInsertRows(new_root_index, new_root->childCount(), new_root->childCount()); // this can't use new_root->addChild directly, or it'll potentially miss a bunch of subdirs insertItemInto(new_root, root); //endInsertRows(); } } // add item to new root // have to call begin/endInsertRows here, or the new item won't show up. const QModelIndex new_root_index = createIndex(new_root->row(), 0, new_root); beginInsertRows(new_root_index, new_root->childCount(), new_root->childCount()); new_root->addChild(item); endInsertRows(); handleDuplicitRootDisplay(new_root); } void KateFileTreeModel::handleDuplicitRootDisplay(ProxyItemDir *init) { QStack rootsToCheck; rootsToCheck.push(init); // make sure the roots don't match (recursively) while (!rootsToCheck.isEmpty()) { ProxyItemDir *check_root = rootsToCheck.pop(); if (check_root->parent() != m_root) { continue; } foreach(ProxyItem * root, m_root->children()) { if (root == check_root || !root->flag(ProxyItem::Dir)) { continue; } if (check_root->display() == root->display()) { bool changed = false; bool check_root_removed = false; const QString rdir = root->path().section(QLatin1Char('/'), 0, -2); if (!rdir.isEmpty()) { beginRemoveRows(QModelIndex(), root->row(), root->row()); m_root->remChild(root); endRemoveRows(); ProxyItemDir *irdir = new ProxyItemDir(rdir); beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount()); m_root->addChild(irdir); endInsertRows(); insertItemInto(irdir, root); foreach(ProxyItem * node, m_root->children()) { if (node == irdir || !root->flag(ProxyItem::Dir)) { continue; } const QString xy = rdir + QLatin1Char('/'); if (node->path().startsWith(xy)) { beginRemoveRows(QModelIndex(), node->row(), node->row()); // check_root_removed must be sticky check_root_removed = check_root_removed || (node == check_root); m_root->remChild(node); endRemoveRows(); insertItemInto(irdir, node); } } rootsToCheck.push(irdir); changed = true; } if (!check_root_removed) { const QString nrdir = check_root->path().section(QLatin1Char('/'), 0, -2); if (!nrdir.isEmpty()) { beginRemoveRows(QModelIndex(), check_root->row(), check_root->row()); m_root->remChild(check_root); endRemoveRows(); ProxyItemDir *irdir = new ProxyItemDir(nrdir); beginInsertRows(QModelIndex(), m_root->childCount(), m_root->childCount()); m_root->addChild(irdir); endInsertRows(); insertItemInto(irdir, check_root); rootsToCheck.push(irdir); changed = true; } } if (changed) { break; // restart } } } // foreach root } } void KateFileTreeModel::handleNameChange(ProxyItem *item) { Q_ASSERT(item != nullptr); Q_ASSERT(item->parent()); updateItemPathAndHost(item); if (m_listMode) { const QModelIndex idx = createIndex(item->row(), 0, item); setupIcon(item); emit dataChanged(idx, idx); return; } // in either case (new/change) we want to remove the item from its parent ProxyItemDir *parent = item->parent(); const QModelIndex parent_index = (parent == m_root) ? QModelIndex() : createIndex(parent->row(), 0, parent); beginRemoveRows(parent_index, item->row(), item->row()); parent->remChild(item); endRemoveRows(); handleEmptyParents(parent); // clear all but Empty flag if (item->flag(ProxyItem::Empty)) { item->setFlags(ProxyItem::Empty); } else { item->setFlags(ProxyItem::None); } setupIcon(item); handleInsert(item); } void KateFileTreeModel::updateItemPathAndHost(ProxyItem *item) const { const KTextEditor::Document *doc = item->doc(); Q_ASSERT(doc); // this method should not be called at directory items QString path = doc->url().path(); QString host; if (doc->url().isEmpty()) { path = doc->documentName(); item->setFlag(ProxyItem::Empty); } else { item->clearFlag(ProxyItem::Empty); host = doc->url().host(); if (!host.isEmpty()) { - path = QString::fromLatin1("[%1]%2").arg(host).arg(path); + path = QStringLiteral("[%1]%2").arg(host, path); } } // for some reason we get useless name changes [should be fixed in 5.0] if (item->path() == path) { return; } item->setPath(path); item->setHost(host); } void KateFileTreeModel::setupIcon(ProxyItem *item) const { Q_ASSERT(item != nullptr); QString icon_name; if (item->flag(ProxyItem::Modified)) { - icon_name = QLatin1String("document-save"); + icon_name = QStringLiteral("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 49c77e4ad..b607252ed 100644 --- a/addons/filetree/katefiletreeplugin.cpp +++ b/addons/filetree/katefiletreeplugin.cpp @@ -1,460 +1,460 @@ /* 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, &KateFileTreePluginView::destroyed, this, &KateFileTreePlugin::viewDestroyed); m_views.append(view); return view; } void KateFileTreePlugin::viewDestroyed(QObject *view) { // do not access the view pointer, since it is partially destroyed already m_views.removeAll(static_cast(view)); } int KateFileTreePlugin::configPages() const { return 1; } KTextEditor::ConfigPage *KateFileTreePlugin::configPage(int number, QWidget *parent) { if (number != 0) { return nullptr; } KateFileTreeConfigPage *page = new KateFileTreeConfigPage(parent, this); return page; } const KateFileTreePluginSettings &KateFileTreePlugin::settings() { return m_settings; } void KateFileTreePlugin::applyConfig(bool shadingEnabled, QColor viewShade, QColor editShade, bool listMode, int sortRole, bool showFullPath) { // save to settings m_settings.setShadingEnabled(shadingEnabled); m_settings.setViewShade(viewShade); m_settings.setEditShade(editShade); m_settings.setListMode(listMode); m_settings.setSortRole(sortRole); m_settings.setShowFullPathOnRoots(showFullPath); m_settings.save(); // update views foreach(KateFileTreePluginView * view, m_views) { view->setHasLocalPrefs(false); view->model()->setShadingEnabled(shadingEnabled); view->model()->setViewShade(viewShade); view->model()->setEditShade(editShade); view->setListMode(listMode); view->proxy()->setSortRole(sortRole); view->model()->setShowFullPathOnRoots(showFullPath); } } //END KateFileTreePlugin //BEGIN KateFileTreePluginView KateFileTreePluginView::KateFileTreePluginView(KTextEditor::MainWindow *mainWindow, KateFileTreePlugin *plug) : QObject(mainWindow) , m_loadingDocuments(false) , m_plug(plug) , m_mainWindow(mainWindow) { - KXMLGUIClient::setComponentName(QLatin1String("katefiletree"), i18n("Kate File Tree")); - setXMLFile(QLatin1String("ui.rc")); + KXMLGUIClient::setComponentName(QStringLiteral("katefiletree"), i18n("Kate File Tree")); + setXMLFile(QStringLiteral("ui.rc")); - m_toolView = mainWindow->createToolView(plug, QLatin1String("kate_private_plugin_katefiletreeplugin"), KTextEditor::MainWindow::Left, QIcon::fromTheme(QLatin1String("document-open")), i18n("Documents")); + m_toolView = mainWindow->createToolView(plug, QStringLiteral("kate_private_plugin_katefiletreeplugin"), KTextEditor::MainWindow::Left, QIcon::fromTheme(QStringLiteral("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, &KateFileTree::activateDocument, this, &KateFileTreePluginView::activateDocument); connect(m_fileTree, &KateFileTree::viewModeChanged, this, &KateFileTreePluginView::viewModeChanged); connect(m_fileTree, &KateFileTree::sortRoleChanged, this, &KateFileTreePluginView::sortRoleChanged); m_documentModel = new KateFileTreeModel(this); m_proxyModel = new KateFileTreeProxyModel(this); m_proxyModel->setSourceModel(m_documentModel); m_proxyModel->setDynamicSortFilter(true); m_documentModel->setShowFullPathOnRoots(m_plug->settings().showFullPathOnRoots()); m_documentModel->setShadingEnabled(m_plug->settings().shadingEnabled()); m_documentModel->setViewShade(m_plug->settings().viewShade()); m_documentModel->setEditShade(m_plug->settings().editShade()); connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentWillBeDeleted, m_documentModel, &KateFileTreeModel::documentClosed); connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentCreated, this, &KateFileTreePluginView::documentOpened); connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentWillBeDeleted, this, &KateFileTreePluginView::documentClosed); connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::aboutToCreateDocuments, this, &KateFileTreePluginView::slotAboutToCreateDocuments); connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentsCreated, this, &KateFileTreePluginView::slotDocumentsCreated); connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::aboutToDeleteDocuments, m_documentModel, &KateFileTreeModel::slotAboutToDeleteDocuments); connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentsDeleted, m_documentModel, &KateFileTreeModel::slotDocumentsDeleted); connect(m_documentModel, &KateFileTreeModel::triggerViewChangeAfterNameChange, [=] { KateFileTreePluginView::viewChanged(); }); m_fileTree->setModel(m_proxyModel); m_fileTree->setDragEnabled(false); m_fileTree->setDragDropMode(QAbstractItemView::InternalMove); m_fileTree->setDropIndicatorShown(false); m_fileTree->setSelectionMode(QAbstractItemView::SingleSelection); connect(m_fileTree->selectionModel(), &QItemSelectionModel::currentChanged, m_fileTree, &KateFileTree::slotCurrentChanged); connect(mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KateFileTreePluginView::viewChanged); // // actions // setupActions(); mainWindow->guiFactory()->addClient(this); m_proxyModel->setSortRole(Qt::DisplayRole); m_proxyModel->sort(0, Qt::AscendingOrder); m_proxyModel->invalidate(); } KateFileTreePluginView::~KateFileTreePluginView() { m_mainWindow->guiFactory()->removeClient(this); // clean up tree and toolview delete m_fileTree->parentWidget(); // delete m_toolView; // and TreeModel delete m_documentModel; } void KateFileTreePluginView::setupActions() { - auto aPrev = actionCollection()->addAction(QLatin1String("filetree_prev_document")); + auto aPrev = actionCollection()->addAction(QStringLiteral("filetree_prev_document")); aPrev->setText(i18n("Previous Document")); - aPrev->setIcon(QIcon::fromTheme(QLatin1String("go-up"))); + aPrev->setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); actionCollection()->setDefaultShortcut(aPrev, Qt::ALT + Qt::Key_Up); connect(aPrev, &QAction::triggered, m_fileTree, &KateFileTree::slotDocumentPrev); - auto aNext = actionCollection()->addAction(QLatin1String("filetree_next_document")); + auto aNext = actionCollection()->addAction(QStringLiteral("filetree_next_document")); aNext->setText(i18n("Next Document")); - aNext->setIcon(QIcon::fromTheme(QLatin1String("go-down"))); + aNext->setIcon(QIcon::fromTheme(QStringLiteral("go-down"))); actionCollection()->setDefaultShortcut(aNext, Qt::ALT + Qt::Key_Down); connect(aNext, &QAction::triggered, m_fileTree, &KateFileTree::slotDocumentNext); - auto aShowActive = actionCollection()->addAction(QLatin1String("filetree_show_active_document")); + auto aShowActive = actionCollection()->addAction(QStringLiteral("filetree_show_active_document")); aShowActive->setText(i18n("&Show Active")); - aShowActive->setIcon(QIcon::fromTheme(QLatin1String("folder-sync"))); + aShowActive->setIcon(QIcon::fromTheme(QStringLiteral("folder-sync"))); connect(aShowActive, &QAction::triggered, this, &KateFileTreePluginView::showActiveDocument); - auto aSave = actionCollection()->addAction(QLatin1String("filetree_save"), this, SLOT(slotDocumentSave())); + auto aSave = actionCollection()->addAction(QStringLiteral("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"))); + aSave->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); - auto aSaveAs = actionCollection()->addAction(QLatin1String("filetree_save_as"), this, SLOT(slotDocumentSaveAs())); + auto aSaveAs = actionCollection()->addAction(QStringLiteral("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"))); + aSaveAs->setIcon(QIcon::fromTheme(QStringLiteral("document-save-as"))); /** * add new & open, if hosting application has it */ if (KXmlGuiWindow *parentClient = qobject_cast(m_mainWindow->window())) { bool newOrOpen = false; if (auto a = parentClient->action("file_new")) { m_toolbar->addAction(a); newOrOpen = true; } if (auto a = parentClient->action("file_open")) { m_toolbar->addAction(a); newOrOpen = true; } if (newOrOpen) { m_toolbar->addSeparator(); } } /** * add own actions */ m_toolbar->addAction(aPrev); m_toolbar->addAction(aNext); m_toolbar->addSeparator(); m_toolbar->addAction(aSave); m_toolbar->addAction(aSaveAs); } KateFileTreeModel *KateFileTreePluginView::model() { return m_documentModel; } KateFileTreeProxyModel *KateFileTreePluginView::proxy() { return m_proxyModel; } KateFileTree *KateFileTreePluginView::tree() { return m_fileTree; } void KateFileTreePluginView::documentOpened(KTextEditor::Document *doc) { if (m_loadingDocuments) { return; } m_documentModel->documentOpened(doc); m_proxyModel->invalidate(); } void KateFileTreePluginView::documentClosed(KTextEditor::Document *doc) { Q_UNUSED(doc); m_proxyModel->invalidate(); } void KateFileTreePluginView::viewChanged(KTextEditor::View *) { KTextEditor::View *view = m_mainWindow->activeView(); if (!view) { return; } KTextEditor::Document *doc = view->document(); QModelIndex index = m_proxyModel->docIndex(doc); QString display = m_proxyModel->data(index, Qt::DisplayRole).toString(); // update the model on which doc is active m_documentModel->documentActivated(doc); m_fileTree->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); m_fileTree->scrollTo(index); while (index != QModelIndex()) { m_fileTree->expand(index); index = index.parent(); } } void KateFileTreePluginView::setListMode(bool listMode) { if (listMode) { m_documentModel->setListMode(true); m_fileTree->setRootIsDecorated(false); } else { m_documentModel->setListMode(false); m_fileTree->setRootIsDecorated(true); } m_proxyModel->sort(0, Qt::AscendingOrder); m_proxyModel->invalidate(); } void KateFileTreePluginView::viewModeChanged(bool listMode) { setHasLocalPrefs(true); setListMode(listMode); } void KateFileTreePluginView::sortRoleChanged(int role) { setHasLocalPrefs(true); m_proxyModel->setSortRole(role); m_proxyModel->invalidate(); } void KateFileTreePluginView::activateDocument(KTextEditor::Document *doc) { m_mainWindow->activateView(doc); } void KateFileTreePluginView::showToolView() { m_mainWindow->showToolView(m_toolView); m_toolView->setFocus(); } void KateFileTreePluginView::hideToolView() { m_mainWindow->hideToolView(m_toolView); } void KateFileTreePluginView::showActiveDocument() { // hack? viewChanged(); // make the tool view show if it was hidden showToolView(); } bool KateFileTreePluginView::hasLocalPrefs() { return m_hasLocalPrefs; } void KateFileTreePluginView::setHasLocalPrefs(bool h) { m_hasLocalPrefs = h; } void KateFileTreePluginView::readSessionConfig(const KConfigGroup &g) { if (g.exists()) { m_hasLocalPrefs = true; } else { m_hasLocalPrefs = false; } // we chain to the global settings by using them as the defaults // here in the session view config loading. const KateFileTreePluginSettings &defaults = m_plug->settings(); bool listMode = g.readEntry("listMode", defaults.listMode()); setListMode(listMode); int sortRole = g.readEntry("sortRole", defaults.sortRole()); m_proxyModel->setSortRole(sortRole); } void KateFileTreePluginView::writeSessionConfig(KConfigGroup &g) { if (m_hasLocalPrefs) { g.writeEntry("listMode", QVariant(m_documentModel->listMode())); g.writeEntry("sortRole", int(m_proxyModel->sortRole())); } else { g.deleteEntry("listMode"); g.deleteEntry("sortRole"); } g.sync(); } void KateFileTreePluginView::slotAboutToCreateDocuments() { m_loadingDocuments = true; } void KateFileTreePluginView::slotDocumentsCreated(const QList &docs) { m_documentModel->documentsOpened(docs); m_loadingDocuments = false; viewChanged(); } void KateFileTreePluginView::slotDocumentSave() { if (auto view = m_mainWindow->activeView()) { view->document()->documentSave(); } } void KateFileTreePluginView::slotDocumentSaveAs() { if (auto view = m_mainWindow->activeView()) { view->document()->documentSaveAs(); } } //END KateFileTreePluginView #include "katefiletreeplugin.moc" diff --git a/addons/gdbplugin/advanced_settings.cpp b/addons/gdbplugin/advanced_settings.cpp index fe53ae93e..a087fd0c3 100644 --- a/addons/gdbplugin/advanced_settings.cpp +++ b/addons/gdbplugin/advanced_settings.cpp @@ -1,250 +1,250 @@ // Description: Advanced settings dialog for gdb // // // Copyright (c) 2012 KÃ¥re Särs // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License version 2 as published by the Free Software Foundation. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public License // along with this library; see the file COPYING.LIB. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "advanced_settings.h" #ifdef WIN32 static const QLatin1Char pathSeparator(';'); #else static const QLatin1Char pathSeparator(':'); #endif #include AdvancedGDBSettings::AdvancedGDBSettings(QWidget *parent) : QDialog(parent) { setupUi(this); u_gdbBrowse->setIcon(QIcon::fromTheme(QStringLiteral("application-x-ms-dos-executable"))); connect(u_gdbBrowse, &QToolButton::clicked, this, &AdvancedGDBSettings::slotBrowseGDB); u_setSoPrefix->setIcon(QIcon::fromTheme(QStringLiteral("folder"))); connect(u_setSoPrefix, &QToolButton::clicked, this, &AdvancedGDBSettings::slotSetSoPrefix); u_addSoSearchPath->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); u_delSoSearchPath->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); connect(u_addSoSearchPath, &QToolButton::clicked, this, &AdvancedGDBSettings::slotAddSoPath); connect(u_delSoSearchPath, &QToolButton::clicked, this, &AdvancedGDBSettings::slotDelSoPath); u_addSrcPath->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); u_delSrcPath->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); connect(u_addSrcPath, &QToolButton::clicked, this, &AdvancedGDBSettings::slotAddSrcPath); connect(u_delSrcPath, &QToolButton::clicked, this, &AdvancedGDBSettings::slotDelSrcPath); connect(u_buttonBox, &QDialogButtonBox::accepted, this, &AdvancedGDBSettings::accept); connect(u_buttonBox, &QDialogButtonBox::rejected, this, &AdvancedGDBSettings::reject); connect(u_localRemote, static_cast(&QComboBox::activated), this, &AdvancedGDBSettings::slotLocalRemoteChanged); } AdvancedGDBSettings::~AdvancedGDBSettings() { } const QStringList AdvancedGDBSettings::configs() const { QStringList tmp; tmp << u_gdbCmd->text(); switch(u_localRemote->currentIndex()) { case 1: - tmp << QStringLiteral("target remote %1:%2").arg(u_tcpHost->text()).arg(u_tcpPort->text()); + tmp << QStringLiteral("target remote %1:%2").arg(u_tcpHost->text(), u_tcpPort->text()); tmp << QString(); break; case 2: tmp << QStringLiteral("target remote %1").arg(u_ttyPort->text()); tmp << QStringLiteral("set remotebaud %1").arg(u_baudCombo->currentText()); break; default: tmp << QString(); tmp << QString(); } if (!u_soAbsPrefix->text().isEmpty()) { tmp << QStringLiteral("set solib-absolute-prefix %1").arg(u_soAbsPrefix->text()); } else { tmp << QString(); } if (u_soSearchPaths->count() > 0) { QString paths = QStringLiteral("set solib-search-path "); for (int i=0; icount(); ++i) { if (i!=0) paths += pathSeparator; paths += u_soSearchPaths->item(i)->text(); } tmp << paths; } else { tmp << QString(); } if (u_srcPaths->count() > 0) { QString paths = QStringLiteral("set directories "); for (int i=0; icount(); ++i) { if (i!=0) paths += pathSeparator; paths += u_srcPaths->item(i)->text(); } tmp << paths; } else { tmp << QString(); } tmp << u_customInit->toPlainText().split(QLatin1Char('\n')); return tmp; } void AdvancedGDBSettings::setConfigs(const QStringList &cfgs) { // clear all info u_gdbCmd->setText(QStringLiteral("gdb")); u_localRemote->setCurrentIndex(0); u_soAbsPrefix->clear(); u_soSearchPaths->clear(); u_srcPaths->clear(); u_customInit->clear(); u_tcpHost->setText(QString()); u_tcpPort->setText(QString()); u_ttyPort->setText(QString()); u_baudCombo->setCurrentIndex(0); // GDB if (cfgs.count() <= GDBIndex) return; u_gdbCmd->setText(cfgs[GDBIndex]); // Local / Remote if (cfgs.count() <= LocalRemoteIndex) return; int start; int end; if (cfgs[LocalRemoteIndex].isEmpty()) { u_localRemote->setCurrentIndex(0); u_remoteStack->setCurrentIndex(0); } else if (cfgs[LocalRemoteIndex].contains(pathSeparator)) { u_localRemote->setCurrentIndex(1); u_remoteStack->setCurrentIndex(1); start = cfgs[LocalRemoteIndex].lastIndexOf(QLatin1Char(' ')); end = cfgs[LocalRemoteIndex].indexOf(pathSeparator); u_tcpHost->setText(cfgs[LocalRemoteIndex].mid(start+1, end-start-1)); u_tcpPort->setText(cfgs[LocalRemoteIndex].mid(end+1)); } else { u_localRemote->setCurrentIndex(2); u_remoteStack->setCurrentIndex(2); start = cfgs[LocalRemoteIndex].lastIndexOf(QLatin1Char(' ')); u_ttyPort->setText(cfgs[LocalRemoteIndex].mid(start+1)); start = cfgs[RemoteBaudIndex].lastIndexOf(QLatin1Char(' ')); setComboText(u_baudCombo, cfgs[RemoteBaudIndex].mid(start+1)); } // Solib absolute path if (cfgs.count() <= SoAbsoluteIndex) return; start = 26; // "set solib-absolute-prefix " u_soAbsPrefix->setText(cfgs[SoAbsoluteIndex].mid(start)); // Solib search path if (cfgs.count() <= SoRelativeIndex) return; start = 22; // "set solib-search-path " QString tmp = cfgs[SoRelativeIndex].mid(start); u_soSearchPaths->addItems(tmp.split(pathSeparator)); if (cfgs.count() <= SrcPathsIndex) return; start = 16; // "set directories " tmp = cfgs[SrcPathsIndex].mid(start); u_srcPaths->addItems(tmp.split(pathSeparator)); // Custom init for (int i=CustomStartIndex; iappendPlainText(cfgs[i]); } slotLocalRemoteChanged(); } void AdvancedGDBSettings::slotBrowseGDB() { u_gdbCmd->setText(QFileDialog::getOpenFileName(this, QString(), u_gdbCmd->text(), QStringLiteral("application/x-executable"))); if (u_gdbCmd->text().isEmpty()) { u_gdbCmd->setText(QStringLiteral("gdb")); } } void AdvancedGDBSettings::setComboText(QComboBox *combo, const QString &str) { if (!combo) return; for (int i=0; icount(); i++) { if (combo->itemText(i) == str) { combo->setCurrentIndex(i); return; } } // The string was not found -> add it combo->addItem(str); combo->setCurrentIndex(combo->count()-1); } void AdvancedGDBSettings::slotSetSoPrefix() { QString prefix = QFileDialog::getExistingDirectory(this); if (prefix.isEmpty()) return; u_soAbsPrefix->setText(prefix); } void AdvancedGDBSettings::slotAddSoPath() { QString path = QFileDialog::getExistingDirectory(this); if (path.isEmpty()) return; u_soSearchPaths->addItem(path); } void AdvancedGDBSettings::slotDelSoPath() { QListWidgetItem *item = u_soSearchPaths->takeItem(u_soSearchPaths->currentRow()); delete item; } void AdvancedGDBSettings::slotAddSrcPath() { QString path = QFileDialog::getExistingDirectory(this); if (path.isEmpty()) return; u_srcPaths->addItem(path); } void AdvancedGDBSettings::slotDelSrcPath() { QListWidgetItem *item = u_srcPaths->takeItem(u_srcPaths->currentRow()); delete item; } void AdvancedGDBSettings::slotLocalRemoteChanged() { u_soAbsPrefixLabel->setEnabled(u_localRemote->currentIndex() != 0); u_soSearchLabel->setEnabled(u_localRemote->currentIndex() != 0); u_soAbsPrefix->setEnabled(u_localRemote->currentIndex() != 0); u_soSearchPaths->setEnabled(u_localRemote->currentIndex() != 0); u_setSoPrefix->setEnabled(u_localRemote->currentIndex() != 0); u_addDelSoPaths->setEnabled(u_localRemote->currentIndex() != 0); } diff --git a/addons/gdbplugin/debugview.cpp b/addons/gdbplugin/debugview.cpp index e8b21e287..59da507e8 100644 --- a/addons/gdbplugin/debugview.cpp +++ b/addons/gdbplugin/debugview.cpp @@ -1,696 +1,696 @@ // // debugview.cpp // // Description: Manages the interaction with GDB // // // Copyright (c) 2008-2010 Ian Wakeling // Copyright (c) 2011 KÃ¥re Särs // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License version 2 as published by the Free Software Foundation. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public License // along with this library; see the file COPYING.LIB. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "debugview.h" #include #include #include #include #include #include #include #include static const QString PromptStr = QStringLiteral("(prompt)"); DebugView::DebugView(QObject* parent) : QObject(parent), m_debugProcess(nullptr), m_state(none), m_subState(normal), m_debugLocationChanged(true), m_queryLocals(false) { } DebugView::~DebugView() { if ( m_debugProcess.state() != QProcess::NotRunning) { m_debugProcess.kill(); m_debugProcess.blockSignals(true); m_debugProcess.waitForFinished(); } } void DebugView::runDebugger(const GDBTargetConf &conf, const QStringList &ioFifos) { if (conf.executable.isEmpty()) { return; } m_targetConf = conf; if (ioFifos.size() == 3) { m_ioPipeString = QStringLiteral("< %1 1> %2 2> %3") .arg(ioFifos[0]) .arg(ioFifos[1]) .arg(ioFifos[2]); } if (m_state == none) { m_outBuffer.clear(); m_errBuffer.clear(); m_errorList.clear(); //create a process to control GDB m_debugProcess.setWorkingDirectory(m_targetConf.workDir); connect(&m_debugProcess, static_cast(&QProcess::error), this, &DebugView::slotError); connect(&m_debugProcess, &QProcess::readyReadStandardError, this, &DebugView::slotReadDebugStdErr); connect(&m_debugProcess, &QProcess::readyReadStandardOutput, this, &DebugView::slotReadDebugStdOut); connect(&m_debugProcess, static_cast(&QProcess::finished), this, &DebugView::slotDebugFinished); m_debugProcess.start(m_targetConf.gdbCmd); m_nextCommands << QStringLiteral("set pagination off"); m_state = ready; } else { // On startup the gdb prompt will trigger the "nextCommands", // here we have to trigger it manually. - QTimer::singleShot(0, this, SLOT(issueNextCommand())); + QTimer::singleShot(0, this, &DebugView::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())); + QTimer::singleShot(0, this, &DebugView::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())); + QTimer::singleShot(0, this, &DebugView::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())); + QTimer::singleShot(0, this, &DebugView::issueNextCommand); } break; case infoArgs: if(PromptStr == line) { m_state = ready; - QTimer::singleShot(0, this, SLOT(issueNextCommand())); + QTimer::singleShot(0, this, &DebugView::issueNextCommand); } else { emit infoLocal(line); } break; case printThis: if(PromptStr == line) { m_state = ready; - QTimer::singleShot(0, this, SLOT(issueNextCommand())); + QTimer::singleShot(0, this, &DebugView::issueNextCommand); } else { emit infoLocal(line); } break; case infoLocals: if(PromptStr == line) { m_state = ready; emit infoLocal(QString()); - QTimer::singleShot(0, this, SLOT(issueNextCommand())); + QTimer::singleShot(0, this, &DebugView::issueNextCommand); } else { emit infoLocal(line); } break; case infoStack: if(PromptStr == line) { m_state = ready; emit stackFrameInfo(QString(), QString()); - QTimer::singleShot(0, this, SLOT(issueNextCommand())); + QTimer::singleShot(0, this, &DebugView::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())); + QTimer::singleShot(0, this, &DebugView::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())); + QTimer::singleShot(0, this, &DebugView::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())); + QTimer::singleShot(0, this, &DebugView::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())); + QTimer::singleShot(0, this, &DebugView::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/localsview.cpp b/addons/gdbplugin/localsview.cpp index 4421e0086..9d6434599 100644 --- a/addons/gdbplugin/localsview.cpp +++ b/addons/gdbplugin/localsview.cpp @@ -1,267 +1,267 @@ // // 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. #include "localsview.h" #include #include #include LocalsView::LocalsView(QWidget *parent) : QTreeWidget(parent), m_allAdded(true) { QStringList headers; headers << i18n("Symbol"); headers << i18n("Value"); setHeaderLabels(headers); setAutoScroll(false); } LocalsView::~LocalsView() { } void LocalsView::showEvent(QShowEvent *) { emit localsVisible(true); } void LocalsView::hideEvent(QHideEvent *) { emit localsVisible(false); } void LocalsView::createWrappedItem(QTreeWidgetItem *parent, const QString &name, const QString &value) { QTreeWidgetItem *item = new QTreeWidgetItem(parent, QStringList(name)); QLabel *label = new QLabel(value); label->setWordWrap(true); setItemWidget(item, 1, label); item->setData(1, Qt::UserRole, value); } void LocalsView::createWrappedItem(QTreeWidget *parent, const QString &name, const QString &value) { QTreeWidgetItem *item = new QTreeWidgetItem(parent, QStringList(name)); QLabel *label = new QLabel(value); label->setWordWrap(true); setItemWidget(item, 1, label); } void LocalsView::addLocal(const QString &vString) { static QRegExp isValue(QStringLiteral("(\\S*)\\s=\\s(.*)")); static QRegExp isStruct(QStringLiteral("\\{\\S*\\s=\\s.*")); static QRegExp isStartPartial(QStringLiteral("\\S*\\s=\\s\\S*\\s=\\s\\{")); static QRegExp isPrettyQList(QStringLiteral("\\s*\\[\\S*\\]\\s=\\s\\S*")); static QRegExp isPrettyValue(QStringLiteral("(\\S*)\\s=\\s(\\S*)\\s=\\s(.*)")); static QRegExp isThisValue(QStringLiteral("\\$\\d+")); if (m_allAdded) { clear(); m_allAdded = false; } if (vString.isEmpty()) { m_allAdded = true; return; } if (isStartPartial.exactMatch(vString)) { m_local = vString; return; } if (isPrettyQList.exactMatch(vString)) { m_local += vString.trimmed(); if (m_local.endsWith(QLatin1Char(','))) m_local += QLatin1Char(' '); return; } if (vString == QLatin1String("}")) { m_local += vString; } QStringList symbolAndValue; QString value; if (m_local.isEmpty()) { if (vString == QLatin1String("No symbol table info available.")) { return; /* this is not an error */ } if (!isValue.exactMatch(vString)) { qDebug() << "Could not parse:" << vString; return; } symbolAndValue << isValue.cap(1); // check out for "print *this" if (isThisValue.exactMatch(symbolAndValue[0])) { - symbolAndValue[0] = QLatin1String("*this"); + symbolAndValue[0] = QStringLiteral("*this"); } value = isValue.cap(2); } else { if (!isPrettyValue.exactMatch(m_local)) { qDebug() << "Could not parse:" << m_local; m_local.clear(); return; } symbolAndValue << isPrettyValue.cap(1) << isPrettyValue.cap(2); value = isPrettyValue.cap(3); } QTreeWidgetItem *item; if (value[0] == QLatin1Char('{')) { if (value[1] == QLatin1Char('{')) { item = new QTreeWidgetItem(this, symbolAndValue); addArray(item, value.mid(1, value.size()-2)); } else { if (isStruct.exactMatch(value)) { item = new QTreeWidgetItem(this, symbolAndValue); addStruct(item, value.mid(1, value.size()-2)); } else { createWrappedItem(this, symbolAndValue[0], value); } } } else { createWrappedItem(this, symbolAndValue[0], value); } m_local.clear(); } void LocalsView::addStruct(QTreeWidgetItem *parent, const QString &vString) { static QRegExp isArray(QStringLiteral("\\{\\.*\\s=\\s.*")); static QRegExp isStruct(QStringLiteral("\\.*\\s=\\s.*")); QTreeWidgetItem *item; QStringList symbolAndValue; QString subValue; int start = 0; int end; while (start < vString.size()) { // Symbol symbolAndValue.clear(); end = vString.indexOf(QStringLiteral(" = "), start); if (end < 0) { // error situation -> bail out createWrappedItem(parent, QString(), vString.right(start)); break; } symbolAndValue << vString.mid(start, end-start); //qDebug() << symbolAndValue; // Value start = end + 3; end = start; if (start < 0 || start >= vString.size()) { qDebug() << vString << start; break; } if (vString[start] == QLatin1Char('{')) { start++; end++; int count = 1; bool inComment = false; // search for the matching } while(end < vString.size()) { if (!inComment) { if (vString[end] == QLatin1Char('"')) inComment = true; else if (vString[end] == QLatin1Char('}')) count--; else if (vString[end] == QLatin1Char('{')) count++; if (count == 0) break; } else { if ((vString[end] == QLatin1Char('"')) && (vString[end-1] != QLatin1Char('\\'))) { inComment = false; } } end++; } subValue = vString.mid(start, end-start); if (isArray.exactMatch(subValue)) { item = new QTreeWidgetItem(parent, symbolAndValue); addArray(item, subValue); } else if (isStruct.exactMatch(subValue)) { item = new QTreeWidgetItem(parent, symbolAndValue); addStruct(item, subValue); } else { createWrappedItem(parent, symbolAndValue[0], vString.mid(start, end-start)); } start = end + 3; // },_ } else { // look for the end of the value in the vString bool inComment = false; while(end < vString.size()) { if (!inComment) { if (vString[end] == QLatin1Char('"')) inComment = true; else if (vString[end] == QLatin1Char(',')) break; } else { if ((vString[end] == QLatin1Char('"')) && (vString[end-1] != QLatin1Char('\\'))) { inComment = false; } } end++; } createWrappedItem(parent, symbolAndValue[0], vString.mid(start, end-start)); start = end + 2; // ,_ } } } void LocalsView::addArray(QTreeWidgetItem *parent, const QString &vString) { // getting here we have this kind of string: // "{...}" or "{...}, {...}" or ... QTreeWidgetItem *item; int count = 1; bool inComment = false; int index = 0; int start = 1; int end = 1; while (end < vString.size()) { if (!inComment) { if (vString[end] == QLatin1Char('"')) inComment = true; else if (vString[end] == QLatin1Char('}')) count--; else if (vString[end] == QLatin1Char('{')) count++; if (count == 0) { QStringList name; name << QStringLiteral("[%1]").arg(index); index++; item = new QTreeWidgetItem(parent, name); addStruct(item, vString.mid(start, end-start)); end += 4; // "}, {" start = end; count = 1; } } else { if ((vString[end] == QLatin1Char('"')) && (vString[end-1] != QLatin1Char('\\'))) { inComment = false; } } end++; } } diff --git a/addons/gdbplugin/plugin_kategdb.cpp b/addons/gdbplugin/plugin_kategdb.cpp index 0c2dda785..6590517fc 100644 --- a/addons/gdbplugin/plugin_kategdb.cpp +++ b/addons/gdbplugin/plugin_kategdb.cpp @@ -1,747 +1,747 @@ // // Description: Kate Plugin for GDB integration // // // Copyright (c) 2010 Ian Wakeling // Copyright (c) 2010-2014 KÃ¥re Särs // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License version 2 as published by the Free Software Foundation. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public License // along with this library; see the file COPYING.LIB. If not, write to // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, // Boston, MA 02110-1301, USA. #include "plugin_kategdb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON (KatePluginGDBFactory, "kategdbplugin.json", registerPlugin();) KatePluginGDB::KatePluginGDB(QObject* parent, const VariantList&) : KTextEditor::Plugin(parent) { // FIXME KF5 KGlobal::locale()->insertCatalog("kategdbplugin"); } KatePluginGDB::~KatePluginGDB() { } QObject* KatePluginGDB::createView(KTextEditor::MainWindow* mainWindow) { return new KatePluginGDBView(this, mainWindow); } KatePluginGDBView::KatePluginGDBView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWin) : QObject(mainWin), m_mainWin(mainWin) { m_lastExecUrl = QUrl(); m_lastExecLine = -1; m_lastExecFrame = 0; m_kateApplication = KTextEditor::Editor::instance()->application(); m_focusOnInput = true; m_activeThread = -1; - KXMLGUIClient::setComponentName (QLatin1String("kategdb"), i18n ("Kate GDB")); - setXMLFile(QLatin1String("ui.rc")); + KXMLGUIClient::setComponentName (QStringLiteral("kategdb"), i18n ("Kate GDB")); + setXMLFile(QStringLiteral("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, static_cast(&KHistoryComboBox::returnPressed), this, &KatePluginGDBView::slotSendCommand); QHBoxLayout *inputLayout = new QHBoxLayout(); inputLayout->addWidget(m_inputArea, 10); inputLayout->setContentsMargins(0,0,0,0); m_outputArea->setFocusProxy(m_inputArea); // take the focus from the outputArea m_gdbPage = new QWidget(); QVBoxLayout *layout = new QVBoxLayout(m_gdbPage); layout->addWidget(m_outputArea); layout->addLayout(inputLayout); layout->setStretch(0, 10); layout->setContentsMargins(0,0,0,0); layout->setSpacing(0); // stack page QWidget *stackContainer = new QWidget(); QVBoxLayout *stackLayout = new QVBoxLayout(stackContainer); m_threadCombo = new QComboBox(); m_stackTree = new QTreeWidget(); stackLayout->addWidget(m_threadCombo); stackLayout->addWidget(m_stackTree); stackLayout->setStretch(0, 10); stackLayout->setContentsMargins(0,0,0,0); stackLayout->setSpacing(0); QStringList headers; headers << QStringLiteral(" ") << i18nc("Column label (frame number)", "Nr") << i18nc("Column label", "Frame"); m_stackTree->setHeaderLabels(headers); m_stackTree->setRootIsDecorated(false); m_stackTree->resizeColumnToContents(0); m_stackTree->resizeColumnToContents(1); m_stackTree->setAutoScroll(false); connect(m_stackTree, &QTreeWidget::itemActivated, this, &KatePluginGDBView::stackFrameSelected); connect(m_threadCombo, static_cast(&QComboBox::currentIndexChanged), this, &KatePluginGDBView::threadSelected); m_localsView = new LocalsView(); QSplitter *locStackSplitter = new QSplitter(m_localsStackToolView); locStackSplitter->addWidget(m_localsView); locStackSplitter->addWidget(stackContainer); locStackSplitter->setOrientation(Qt::Vertical); // config page m_configView = new ConfigView(nullptr, mainWin); m_ioView = new IOView(); connect(m_configView, &ConfigView::showIO, this, &KatePluginGDBView::showIO); m_tabWidget->addTab(m_gdbPage, i18nc("Tab label", "GDB Output")); m_tabWidget->addTab(m_configView, i18nc("Tab label", "Settings")); m_debugView = new DebugView(this); connect(m_debugView, &DebugView::readyForInput, this, &KatePluginGDBView::enableDebugActions); connect(m_debugView, &DebugView::outputText, this, &KatePluginGDBView::addOutputText); connect(m_debugView, &DebugView::outputError, this, &KatePluginGDBView::addErrorText); connect(m_debugView, &DebugView::debugLocationChanged, this, &KatePluginGDBView::slotGoTo); connect(m_debugView, &DebugView::breakPointSet, this, &KatePluginGDBView::slotBreakpointSet); connect(m_debugView, &DebugView::breakPointCleared, this, &KatePluginGDBView::slotBreakpointCleared); connect(m_debugView, &DebugView::clearBreakpointMarks, this, &KatePluginGDBView::clearMarks); connect(m_debugView, &DebugView::programEnded, this, &KatePluginGDBView::programEnded); connect(m_debugView, &DebugView::gdbEnded, this, &KatePluginGDBView::programEnded); connect(m_debugView, &DebugView::gdbEnded, this, &KatePluginGDBView::gdbEnded); connect(m_debugView, &DebugView::stackFrameInfo, this, &KatePluginGDBView::insertStackFrame); connect(m_debugView, &DebugView::stackFrameChanged, this, &KatePluginGDBView::stackFrameChanged); connect(m_debugView, &DebugView::infoLocal, m_localsView, &LocalsView::addLocal); connect(m_debugView, &DebugView::threadInfo, this, &KatePluginGDBView::insertThread); connect(m_localsView, &LocalsView::localsVisible, m_debugView, &DebugView::slotQueryLocals); // Actions m_configView->registerActions(actionCollection()); QAction* a = actionCollection()->addAction(QStringLiteral("debug")); a->setText(i18n("Start Debugging")); a->setIcon(QIcon(QStringLiteral(":/kategdb/22-actions-debug-kategdb.png"))); connect(a, &QAction::triggered, this, &KatePluginGDBView::slotDebug); a = actionCollection()->addAction(QStringLiteral("kill")); a->setText(i18n("Kill / Stop Debugging")); a->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop"))); connect(a, &QAction::triggered, m_debugView, &DebugView::slotKill); a = actionCollection()->addAction(QStringLiteral("rerun")); a->setText(i18n("Restart Debugging")); a->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); connect(a, &QAction::triggered,this, &KatePluginGDBView::slotRestart); a = actionCollection()->addAction(QStringLiteral("toggle_breakpoint")); a->setText(i18n("Toggle Breakpoint / Break")); a->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause"))); connect(a, &QAction::triggered,this, &KatePluginGDBView::slotToggleBreakpoint); a = actionCollection()->addAction(QStringLiteral("step_in")); a->setText(i18n("Step In")); a->setIcon(QIcon::fromTheme(QStringLiteral("debug-step-into"))); connect(a, &QAction::triggered, m_debugView, &DebugView::slotStepInto); a = actionCollection()->addAction(QStringLiteral("step_over")); a->setText(i18n("Step Over")); a->setIcon(QIcon::fromTheme(QStringLiteral("debug-step-over"))); connect(a, &QAction::triggered, m_debugView, &DebugView::slotStepOver); a = actionCollection()->addAction(QStringLiteral("step_out")); a->setText(i18n("Step Out")); a->setIcon(QIcon::fromTheme(QStringLiteral("debug-step-out"))); connect(a, &QAction::triggered, m_debugView, &DebugView::slotStepOut); a = actionCollection()->addAction(QStringLiteral("move_pc")); a->setText(i18nc("Move Program Counter (next execution)", "Move PC")); connect(a, &QAction::triggered, this, &KatePluginGDBView::slotMovePC); a = actionCollection()->addAction(QStringLiteral("run_to_cursor")); a->setText(i18n("Run To Cursor")); a->setIcon(QIcon::fromTheme(QStringLiteral("debug-run-cursor"))); connect(a, &QAction::triggered, this, &KatePluginGDBView::slotRunToCursor); a = actionCollection()->addAction(QStringLiteral("continue")); a->setText(i18n("Continue")); a->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); connect(a, &QAction::triggered, m_debugView, &DebugView::slotContinue); a = actionCollection()->addAction(QStringLiteral("print_value")); a->setText(i18n("Print Value")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-preview"))); connect(a, &QAction::triggered, this, &KatePluginGDBView::slotValue); // popup context m_menu m_menu = new KActionMenu(i18n("Debug"), this); actionCollection()->addAction(QStringLiteral("popup_gdb"), m_menu); connect(m_menu->menu(), &QMenu::aboutToShow, this, &KatePluginGDBView::aboutToShowMenu); m_breakpoint = m_menu->menu()->addAction(i18n("popup_breakpoint"), - this, SLOT(slotToggleBreakpoint())); + this, &KatePluginGDBView::slotToggleBreakpoint); QAction* popupAction = m_menu->menu()->addAction(i18n("popup_run_to_cursor"), - this, SLOT(slotRunToCursor())); + this, &KatePluginGDBView::slotRunToCursor); popupAction->setText(i18n("Run To Cursor")); popupAction = m_menu->menu()->addAction(QStringLiteral("move_pc"), - this, SLOT(slotMovePC())); + this, &KatePluginGDBView::slotMovePC); popupAction->setText(i18nc("Move Program Counter (next execution)", "Move PC")); enableDebugActions(false); connect(m_mainWin, &KTextEditor::MainWindow::unhandledShortcutOverride, this, &KatePluginGDBView::handleEsc); m_toolView->installEventFilter(this); m_mainWin->guiFactory()->addClient(this); } KatePluginGDBView::~KatePluginGDBView() { m_mainWin->guiFactory()->removeClient(this); delete m_toolView; delete m_localsStackToolView; } void KatePluginGDBView::readSessionConfig( const KConfigGroup& config) { m_configView->readConfig(config); } void KatePluginGDBView::writeSessionConfig(KConfigGroup& config) { m_configView->writeConfig(config); } void KatePluginGDBView::slotDebug() { disconnect(m_ioView, &IOView::stdOutText, nullptr, nullptr); disconnect(m_ioView, &IOView::stdErrText, nullptr, nullptr); if (m_configView->showIOTab()) { connect(m_ioView, &IOView::stdOutText, m_ioView, &IOView::addStdOutText); connect(m_ioView, &IOView::stdErrText, m_ioView, &IOView::addStdErrText); } else { connect(m_ioView, &IOView::stdOutText, this, &KatePluginGDBView::addOutputText); connect(m_ioView, &IOView::stdErrText, this, &KatePluginGDBView::addErrorText); } QStringList ioFifos; ioFifos << m_ioView->stdinFifo(); ioFifos << m_ioView->stdoutFifo(); ioFifos << m_ioView->stderrFifo(); enableDebugActions(true); m_mainWin->showToolView(m_toolView); m_tabWidget->setCurrentWidget(m_gdbPage); QScrollBar *sb = m_outputArea->verticalScrollBar(); sb->setValue(sb->maximum()); m_localsView->clear(); m_debugView->runDebugger(m_configView->currentTarget(), ioFifos); } void KatePluginGDBView::slotRestart() { m_mainWin->showToolView(m_toolView); m_tabWidget->setCurrentWidget(m_gdbPage); QScrollBar *sb = m_outputArea->verticalScrollBar(); sb->setValue(sb->maximum()); m_localsView->clear(); m_debugView->slotReRun(); } void KatePluginGDBView::aboutToShowMenu() { if (!m_debugView->debuggerRunning() || m_debugView->debuggerBusy()) { m_breakpoint->setText(i18n("Insert breakpoint")); m_breakpoint->setDisabled(true); return; } m_breakpoint->setDisabled(false); KTextEditor::View* editView = m_mainWin->activeView(); QUrl url = editView->document()->url(); int line = editView->cursorPosition().line(); line++; // GDB uses 1 based line numbers, kate uses 0 based... if (m_debugView->hasBreakpoint(url, line)) { m_breakpoint->setText(i18n("Remove breakpoint")); } else { m_breakpoint->setText(i18n("Insert breakpoint")); } } void KatePluginGDBView::slotToggleBreakpoint() { if (!actionCollection()->action(QStringLiteral("continue"))->isEnabled()) { m_debugView->slotInterrupt(); } else { KTextEditor::View* editView = m_mainWin->activeView(); QUrl currURL = editView->document()->url(); int line = editView->cursorPosition().line(); m_debugView->toggleBreakpoint(currURL, line + 1); } } void KatePluginGDBView::slotBreakpointSet(const QUrl &file, int line) { KTextEditor::MarkInterface* iface = qobject_cast(m_kateApplication->findUrl(file)); if (iface) { iface->setMarkDescription(KTextEditor::MarkInterface::BreakpointActive, i18n("Breakpoint")); iface->setMarkPixmap(KTextEditor::MarkInterface::BreakpointActive, QIcon::fromTheme(QStringLiteral("media-playback-pause")).pixmap(10,10)); iface->addMark(line, KTextEditor::MarkInterface::BreakpointActive); } } void KatePluginGDBView::slotBreakpointCleared(const QUrl &file, int line) { KTextEditor::MarkInterface* iface = qobject_cast(m_kateApplication->findUrl(file)); if (iface) { iface->removeMark(line, KTextEditor::MarkInterface::BreakpointActive); } } void KatePluginGDBView::slotMovePC() { KTextEditor::View* editView = m_mainWin->activeView(); QUrl currURL = editView->document()->url(); KTextEditor::Cursor cursor = editView->cursorPosition(); m_debugView->movePC(currURL, cursor.line() + 1); } void KatePluginGDBView::slotRunToCursor() { KTextEditor::View* editView = m_mainWin->activeView(); QUrl currURL = editView->document()->url(); KTextEditor::Cursor cursor = editView->cursorPosition(); // GDB starts lines from 1, kate returns lines starting from 0 (displaying 1) m_debugView->runToCursor(currURL, cursor.line() + 1); } void KatePluginGDBView::slotGoTo(const QUrl &url, int lineNum) { // skip not existing files if (!QFile::exists (url.toLocalFile ())) { m_lastExecLine = -1; return; } m_lastExecUrl = url; m_lastExecLine = lineNum; KTextEditor::View* editView = m_mainWin->openUrl(m_lastExecUrl); editView->setCursorPosition(KTextEditor::Cursor(m_lastExecLine, 0)); m_mainWin->window()->raise(); m_mainWin->window()->setFocus(); } void KatePluginGDBView::enableDebugActions(bool enable) { actionCollection()->action(QStringLiteral("step_in" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("step_over" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("step_out" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("move_pc" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("run_to_cursor"))->setEnabled(enable); actionCollection()->action(QStringLiteral("popup_gdb" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("continue" ))->setEnabled(enable); actionCollection()->action(QStringLiteral("print_value" ))->setEnabled(enable); // "toggle breakpoint" doubles as interrupt while the program is running actionCollection()->action(QStringLiteral("toggle_breakpoint"))->setEnabled(m_debugView->debuggerRunning()); actionCollection()->action(QStringLiteral("kill" ))->setEnabled(m_debugView->debuggerRunning()); actionCollection()->action(QStringLiteral("rerun" ))->setEnabled(m_debugView->debuggerRunning()); m_inputArea->setEnabled(enable); m_threadCombo->setEnabled(enable); m_stackTree->setEnabled(enable); m_localsView->setEnabled(enable); if (enable) { m_inputArea->setFocusPolicy(Qt::WheelFocus); if (m_focusOnInput || m_configView->takeFocusAlways()) { m_inputArea->setFocus(); m_focusOnInput = false; } else { m_mainWin->activeView()->setFocus(); } } else { m_inputArea->setFocusPolicy(Qt::NoFocus); if (m_mainWin->activeView()) m_mainWin->activeView()->setFocus(); } m_ioView->enableInput(!enable && m_debugView->debuggerRunning()); if ((m_lastExecLine > -1)) { KTextEditor::MarkInterface* iface = qobject_cast(m_kateApplication->findUrl(m_lastExecUrl)); if (iface) { if (enable) { iface->setMarkDescription(KTextEditor::MarkInterface::Execution, i18n("Execution point")); iface->setMarkPixmap(KTextEditor::MarkInterface::Execution, QIcon::fromTheme(QStringLiteral("arrow-right")).pixmap(10,10)); iface->addMark(m_lastExecLine, KTextEditor::MarkInterface::Execution); } else { iface->removeMark(m_lastExecLine, KTextEditor::MarkInterface::Execution); } } } } void KatePluginGDBView::programEnded() { // don't set the execution mark on exit m_lastExecLine = -1; m_stackTree->clear(); m_localsView->clear(); m_threadCombo->clear(); // Indicate the state change by showing the debug outputArea m_mainWin->showToolView(m_toolView); m_tabWidget->setCurrentWidget(m_gdbPage); } void KatePluginGDBView::gdbEnded() { m_outputArea->clear(); m_localsView->clear(); m_ioView->clearOutput(); clearMarks(); } void KatePluginGDBView::clearMarks() { KTextEditor::MarkInterface* iface; foreach (KTextEditor::Document* doc, m_kateApplication->documents()) { iface = qobject_cast(doc); if (iface) { const QHash marks = iface->marks(); QHashIterator i(marks); while (i.hasNext()) { i.next(); if ((i.value()->type == KTextEditor::MarkInterface::Execution) || (i.value()->type == KTextEditor::MarkInterface::BreakpointActive)) { iface->removeMark(i.value()->line, i.value()->type); } } } } } void KatePluginGDBView::slotSendCommand() { QString cmd = m_inputArea->currentText(); if (cmd.isEmpty()) cmd = m_lastCommand; m_inputArea->addToHistory(cmd); m_inputArea->setCurrentItem(QString()); m_focusOnInput = true; m_lastCommand = cmd; m_debugView->issueCommand(cmd); QScrollBar *sb = m_outputArea->verticalScrollBar(); sb->setValue(sb->maximum()); } void KatePluginGDBView::insertStackFrame(QString const& level, QString const& info) { if (level.isEmpty() && info.isEmpty()) { m_stackTree->resizeColumnToContents(2); return; } if (level == QLatin1String("0")) { m_stackTree->clear(); } QStringList columns; columns << QStringLiteral(" "); // icon place holder columns << level; int lastSpace = info.lastIndexOf(QLatin1String(" ")); QString shortInfo = info.mid(lastSpace); columns << shortInfo; QTreeWidgetItem *item = new QTreeWidgetItem(columns); item->setToolTip(2, QStringLiteral("%1").arg(info)); m_stackTree->insertTopLevelItem(level.toInt(), item); } void KatePluginGDBView::stackFrameSelected() { m_debugView->issueCommand(QStringLiteral("(Q)f %1").arg(m_stackTree->currentIndex().row())); } void KatePluginGDBView::stackFrameChanged(int level) { QTreeWidgetItem *current = m_stackTree->topLevelItem(m_lastExecFrame); QTreeWidgetItem *next = m_stackTree->topLevelItem(level); if (current) current->setIcon (0, QIcon()); if (next) next->setIcon(0, QIcon::fromTheme(QStringLiteral("arrow-right"))); m_lastExecFrame = level; } void KatePluginGDBView::insertThread(int number, bool active) { if (number < 0) { m_threadCombo->clear(); m_activeThread = -1; return; } if (!active) { m_threadCombo->addItem(QIcon::fromTheme(QStringLiteral("")).pixmap(10,10), i18n("Thread %1", number), number); } else { m_threadCombo->addItem(QIcon::fromTheme(QStringLiteral("arrow-right")).pixmap(10,10), i18n("Thread %1", number), number); m_activeThread = m_threadCombo->count()-1; } m_threadCombo->setCurrentIndex(m_activeThread); } void KatePluginGDBView::threadSelected(int thread) { m_debugView->issueCommand(QStringLiteral("thread %1"). arg(m_threadCombo->itemData(thread).toInt())); } QString KatePluginGDBView::currentWord() { KTextEditor::View *kv = m_mainWin->activeView(); if (!kv) { qDebug() << "no KTextEditor::View" << endl; return QString(); } if (!kv->cursorPosition().isValid()) { qDebug() << "cursor not valid!" << endl; return QString(); } int line = kv->cursorPosition().line(); int col = kv->cursorPosition().column(); QString linestr = kv->document()->line(line); int startPos = qMax(qMin(col, linestr.length()-1), 0); int lindex = linestr.length()-1; int endPos = startPos; while (startPos >= 0 && (linestr[startPos].isLetterOrNumber() || linestr[startPos] == QLatin1Char('_') || linestr[startPos] == QLatin1Char('~') || ((startPos > 1) && (linestr[startPos] == QLatin1Char('.')) && !linestr[startPos-1].isSpace()) || ((startPos > 2) && (linestr[startPos] == QLatin1Char('>')) && (linestr[startPos-1] == QLatin1Char('-')) && !linestr[startPos-2].isSpace()))) { if (linestr[startPos] == QLatin1Char('>')) { startPos--; } startPos--; } while (endPos < (int)linestr.length() && (linestr[endPos].isLetterOrNumber() || linestr[endPos] == QLatin1Char('_') || ((endPos < lindex-1) && (linestr[endPos] == QLatin1Char('.')) && !linestr[endPos+1].isSpace()) || ((endPos < lindex-2) && (linestr[endPos] == QLatin1Char('-')) && (linestr[endPos+1] == QLatin1Char('>')) && !linestr[endPos+2].isSpace()) || ((endPos > 1) && (linestr[endPos-1] == QLatin1Char('-')) && (linestr[endPos] == QLatin1Char('>'))) )) { if (linestr[endPos] == QLatin1Char('-')) { endPos++; } endPos++; } if (startPos == endPos) { qDebug() << "no word found!" << endl; return QString(); } //qDebug() << linestr.mid(startPos+1, endPos-startPos-1); return linestr.mid(startPos+1, endPos-startPos-1); } void KatePluginGDBView::slotValue() { QString variable; KTextEditor::View* editView = m_mainWin->activeView(); if (editView && editView->selection() && editView->selectionRange().onSingleLine()) { variable = editView->selectionText(); } if (variable.isEmpty()) variable = currentWord(); if (variable.isEmpty()) return; QString cmd = QStringLiteral("print %1").arg(variable); m_debugView->issueCommand(cmd); m_inputArea->addToHistory(cmd); m_inputArea->setCurrentItem(QString()); m_mainWin->showToolView(m_toolView); m_tabWidget->setCurrentWidget(m_gdbPage); QScrollBar *sb = m_outputArea->verticalScrollBar(); sb->setValue(sb->maximum()); } void KatePluginGDBView::showIO(bool show) { if (show) { m_tabWidget->addTab(m_ioView, i18n("IO")); } else { m_tabWidget->removeTab(m_tabWidget->indexOf(m_ioView)); } } void KatePluginGDBView::addOutputText(QString const& text) { QScrollBar *scrollb = m_outputArea->verticalScrollBar(); if (!scrollb) return; bool atEnd = (scrollb->value() == scrollb->maximum()); QTextCursor cursor = m_outputArea->textCursor(); if (!cursor.atEnd()) cursor.movePosition(QTextCursor::End); cursor.insertText(text); if (atEnd) { scrollb->setValue(scrollb->maximum()); } } void KatePluginGDBView::addErrorText(QString const& text) { m_outputArea->setFontItalic(true); addOutputText(text); m_outputArea->setFontItalic(false); } bool KatePluginGDBView::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); if ((obj == m_toolView) && (ke->key() == Qt::Key_Escape)) { m_mainWin->hideToolView(m_toolView); event->accept(); return true; } } return QObject::eventFilter(obj, event); } void KatePluginGDBView::handleEsc(QEvent *e) { if (!m_mainWin) return; QKeyEvent *k = static_cast(e); if (k->key() == Qt::Key_Escape && k->modifiers() == Qt::NoModifier) { if (m_toolView->isVisible()) { m_mainWin->hideToolView(m_toolView); } } } #include "plugin_kategdb.moc" diff --git a/addons/kate-ctags/kate_ctags_plugin.cpp b/addons/kate-ctags/kate_ctags_plugin.cpp index 7eb87dada..9362bf682 100644 --- a/addons/kate-ctags/kate_ctags_plugin.cpp +++ b/addons/kate-ctags/kate_ctags_plugin.cpp @@ -1,257 +1,257 @@ /* Description : Kate CTags plugin * * Copyright (C) 2008-2011 by Kare Sars * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see . */ #include "kate_ctags_plugin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON (KateCTagsPluginFactory, "katectagsplugin.json", registerPlugin();) /******************************************************************/ KateCTagsPlugin::KateCTagsPlugin(QObject* parent, const QList&): KTextEditor::Plugin (parent), m_view(nullptr) { // FIXME KF5 //KGlobal::locale()->insertCatalog("kate-ctags-plugin"); } /******************************************************************/ QObject *KateCTagsPlugin::createView(KTextEditor::MainWindow *mainWindow) { m_view = new KateCTagsView(this, mainWindow); return m_view; } /******************************************************************/ KTextEditor::ConfigPage *KateCTagsPlugin::configPage (int number, QWidget *parent) { if (number != 0) return nullptr; return new KateCTagsConfigPage(parent, this); } /******************************************************************/ void KateCTagsPlugin::readConfig() { } /******************************************************************/ KateCTagsConfigPage::KateCTagsConfigPage( QWidget* parent, KateCTagsPlugin *plugin ) : KTextEditor::ConfigPage( parent ) , m_plugin( plugin ) { m_confUi.setupUi(this); m_confUi.cmdEdit->setText(DEFAULT_CTAGS_CMD); m_confUi.addButton->setToolTip(i18n("Add a directory to index.")); m_confUi.addButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); m_confUi.delButton->setToolTip(i18n("Remove a directory.")); m_confUi.delButton->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); m_confUi.updateDB->setToolTip(i18n("(Re-)generate the common CTags database.")); m_confUi.updateDB->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); connect(m_confUi.updateDB, &QPushButton::clicked, this, &KateCTagsConfigPage::updateGlobalDB); connect(m_confUi.addButton, &QPushButton::clicked, this, &KateCTagsConfigPage::addGlobalTagTarget); connect(m_confUi.delButton, &QPushButton::clicked, this, &KateCTagsConfigPage::delGlobalTagTarget); connect(&m_proc, static_cast(&QProcess::finished), this, &KateCTagsConfigPage::updateDone); reset(); } /******************************************************************/ QString KateCTagsConfigPage::name() const { return i18n("CTags"); } /******************************************************************/ QString KateCTagsConfigPage::fullName() const { return i18n("CTags Settings"); } /******************************************************************/ QIcon KateCTagsConfigPage::icon() const { return QIcon::fromTheme(QStringLiteral("text-x-csrc")); } /******************************************************************/ void KateCTagsConfigPage::apply() { KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("CTags")); config.writeEntry("GlobalCommand", m_confUi.cmdEdit->text()); config.writeEntry("GlobalNumTargets", m_confUi.targetList->count()); QString nr; for (int i=0; icount(); i++) { nr = QStringLiteral("%1").arg(i,3); config.writeEntry(QStringLiteral("GlobalTarget_")+nr, m_confUi.targetList->item(i)->text()); } config.sync(); } /******************************************************************/ void KateCTagsConfigPage::reset() { KConfigGroup config(KSharedConfig::openConfig(), "CTags"); m_confUi.cmdEdit->setText(config.readEntry(QStringLiteral("GlobalCommand"), DEFAULT_CTAGS_CMD)); int numEntries = config.readEntry(QStringLiteral("GlobalNumTargets"), 0); QString nr; QString target; for (int i=0; icurrentItem()) { dir = m_confUi.targetList->currentItem()->text(); } else if (m_confUi.targetList->item(0)) { dir = m_confUi.targetList->item(0)->text(); } dialog.setDirectory(dir); // i18n("CTags Database Location")); if (dialog.exec() != QDialog::Accepted) { return; } QStringList urls = dialog.selectedFiles(); for (int i=0; icurrentItem (); } /******************************************************************/ bool KateCTagsConfigPage::listContains(const QString &target) { for (int i=0; icount(); i++) { if (m_confUi.targetList->item(i)->text() == target) { return true; } } return false; } /******************************************************************/ void KateCTagsConfigPage::updateGlobalDB() { if (m_proc.state() != QProcess::NotRunning) { return; } QString targets; QString target; for (int i=0; icount(); i++) { target = m_confUi.targetList->item(i)->text(); if (target.endsWith(QLatin1Char('/')) || target.endsWith(QLatin1Char('\\'))) { target = target.left(target.size() - 1); } targets += target + QLatin1Char(' '); } QString file = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/katectags"); QDir().mkpath(file); file += QLatin1String("/common_db"); if (targets.isEmpty()) { QFile::remove(file); return; } - QString command = QStringLiteral("%1 -f %2 %3").arg(m_confUi.cmdEdit->text()).arg(file).arg(targets) ; + QString command = QStringLiteral("%1 -f %2 %3").arg(m_confUi.cmdEdit->text(), file, targets) ; m_proc.start(command); if(!m_proc.waitForStarted(500)) { KMessageBox::error(nullptr, i18n("Failed to run \"%1\". exitStatus = %2", command, m_proc.exitStatus())); return; } m_confUi.updateDB->setDisabled(true); QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); } /******************************************************************/ void KateCTagsConfigPage::updateDone(int exitCode, QProcess::ExitStatus status) { if (status == QProcess::CrashExit) { KMessageBox::error(this, i18n("The CTags executable crashed.")); } else if (exitCode != 0) { KMessageBox::error(this, i18n("The CTags command exited with code %1", exitCode)); } m_confUi.updateDB->setDisabled(false); QApplication::restoreOverrideCursor(); } #include "kate_ctags_plugin.moc" diff --git a/addons/kate-ctags/kate_ctags_view.cpp b/addons/kate-ctags/kate_ctags_view.cpp index 8049ec470..4abe72318 100644 --- a/addons/kate-ctags/kate_ctags_view.cpp +++ b/addons/kate-ctags/kate_ctags_view.cpp @@ -1,643 +1,643 @@ /* 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 "kate_ctags_plugin.h" #include "kate_ctags_debug.h" #include #include #include #include #include #include #include #include #include #include #include /******************************************************************/ KateCTagsView::KateCTagsView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWin) : QObject(mainWin) , m_proc(nullptr) { - KXMLGUIClient::setComponentName (QLatin1String("katectags"), i18n ("Kate CTag")); - setXMLFile( QLatin1String("ui.rc") ); + KXMLGUIClient::setComponentName (QStringLiteral("katectags"), i18n ("Kate CTag")); + setXMLFile( QStringLiteral("ui.rc") ); - m_toolView = mainWin->createToolView(plugin, QLatin1String("kate_plugin_katectagsplugin"), + m_toolView = mainWin->createToolView(plugin, QStringLiteral("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")); + QAction *back = actionCollection()->addAction(QStringLiteral("ctags_return_step")); back->setText(i18n("Jump back one step")); connect(back, &QAction::triggered, this, &KateCTagsView::stepBack); - QAction *decl = actionCollection()->addAction(QLatin1String("ctags_lookup_current_as_declaration")); + QAction *decl = actionCollection()->addAction(QStringLiteral("ctags_lookup_current_as_declaration")); decl->setText(i18n("Go to Declaration")); connect(decl, &QAction::triggered, this, &KateCTagsView::gotoDeclaration); - QAction *defin = actionCollection()->addAction(QLatin1String("ctags_lookup_current_as_definition")); + QAction *defin = actionCollection()->addAction(QStringLiteral("ctags_lookup_current_as_definition")); defin->setText(i18n("Go to Definition")); connect(defin, &QAction::triggered, this, &KateCTagsView::gotoDefinition); - QAction *lookup = actionCollection()->addAction(QLatin1String("ctags_lookup_current")); + QAction *lookup = actionCollection()->addAction(QStringLiteral("ctags_lookup_current")); lookup->setText(i18n("Lookup Current Text")); connect(lookup, &QAction::triggered, this, &KateCTagsView::lookupTag); - QAction *updateDB = actionCollection()->addAction(QLatin1String("ctags_update_global_db")); + QAction *updateDB = actionCollection()->addAction(QStringLiteral("ctags_update_global_db")); updateDB->setText(i18n("Configure ...")); connect(updateDB, &QAction::triggered, this, [this, plugin] (bool) { if (m_mWin) { KateCTagsPlugin *p = static_cast(plugin); QDialog *confWin = new QDialog(m_mWin->window()); confWin->setAttribute(Qt::WA_DeleteOnClose); auto confPage = p->configPage(0, confWin); auto controls = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, Qt::Horizontal, confWin); connect(confWin, &QDialog::accepted, confPage, &KTextEditor::ConfigPage::apply); connect(controls, &QDialogButtonBox::accepted, confWin, &QDialog::accept); connect(controls, &QDialogButtonBox::rejected, confWin, &QDialog::reject); auto layout = new QVBoxLayout(confWin); layout->addWidget(confPage); layout->addWidget(controls); confWin->setLayout(layout); confWin->setWindowTitle(i18nc("@title:window", "Configure CTags Plugin")); confWin->setWindowIcon(confPage->icon()); confWin->show(); confWin->exec(); } }); // popup menu m_menu = new KActionMenu(i18n("CTags"), this); - actionCollection()->addAction(QLatin1String("popup_ctags"), m_menu); + actionCollection()->addAction(QStringLiteral("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())); + m_gotoDec=m_menu->menu()->addAction(i18n("Go to Declaration: %1",QString()), this, &KateCTagsView::gotoDeclaration); + m_gotoDef=m_menu->menu()->addAction(i18n("Go to Definition: %1",QString()), this, &KateCTagsView::gotoDefinition); + m_lookup=m_menu->menu()->addAction(i18n("Lookup: %1",QString()), this, &KateCTagsView::lookupTag); connect(m_menu->menu(), &QMenu::aboutToShow, this, &KateCTagsView::aboutToShow); QWidget *ctagsWidget = new QWidget(m_toolView.data()); 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, &QToolButton::clicked, this, &KateCTagsView::resetCMD); connect(m_ctagsUi.addButton, &QPushButton::clicked, this, &KateCTagsView::addTagTarget); connect(m_ctagsUi.delButton, &QPushButton::clicked, this, &KateCTagsView::delTagTarget); connect(m_ctagsUi.updateButton, &QPushButton::clicked, this, &KateCTagsView::updateSessionDB); connect(m_ctagsUi.updateButton2, &QPushButton::clicked, this, &KateCTagsView::updateSessionDB); connect(&m_proc, static_cast(&QProcess::finished), this, &KateCTagsView::updateDone); connect(m_ctagsUi.inputEdit, &QLineEdit::textChanged, this, &KateCTagsView::startEditTmr); m_editTimer.setSingleShot(true); connect(&m_editTimer, &QTimer::timeout, this, &KateCTagsView::editLookUp); connect(m_ctagsUi.tagTreeWidget, &QTreeWidget::itemActivated, this, &KateCTagsView::tagHitClicked); connect(m_mWin, &KTextEditor::MainWindow::unhandledShortcutOverride, this, &KateCTagsView::handleEsc); m_toolView->layout()->addWidget(ctagsWidget); m_toolView->installEventFilter(this); m_mWin->guiFactory()->addClient(this); m_commonDB = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/katectags/common_db"); } /******************************************************************/ KateCTagsView::~KateCTagsView() { if (m_mWin && m_mWin->guiFactory()) { m_mWin->guiFactory()->removeClient( this ); } if (m_toolView) { 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); //qCDebug(KTECTAGS) << "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) { qCDebug(KTECTAGS) << "no KTextEditor::View" << endl; return QString(); } if (kv->selection() && kv->selectionRange().onSingleLine()) { return kv->selectionText(); } if (!kv->cursorPosition().isValid()) { qCDebug(KTECTAGS) << "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) { qCDebug(KTECTAGS) << "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); } //qCDebug(KTECTAGS) << 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); //qCDebug(KTECTAGS) << pattern << file << fInfo.absoluteFilePath(); m_mWin->openUrl(QUrl::fromLocalFile(fInfo.absoluteFilePath())); // any view active? if (!m_mWin->activeView()) { return; } // look for the line QString linestr; int line; for (line =0; line < m_mWin->activeView()->document()->lines(); line++) { linestr = m_mWin->activeView()->document()->line(line); if (linestr.indexOf(re) > -1) break; } // activate the line if (line != m_mWin->activeView()->document()->lines()) { // line found now look for the column int column = linestr.indexOf(word) + (word.length()/2); m_mWin->activeView()->setCursorPosition(KTextEditor::Cursor(line, column)); } m_mWin->activeView()->setFocus(); } /******************************************************************/ void KateCTagsView::startEditTmr() { if (m_ctagsUi.inputEdit->text().size() > 3) { m_editTimer.start(500); } } /******************************************************************/ void KateCTagsView::updateSessionDB() { if (m_proc.state() != QProcess::NotRunning) { return; } QString targets; QString target; for (int i=0; icount(); i++) { target = m_ctagsUi.targetList->item(i)->text(); if (target.endsWith(QLatin1Char('/')) || target.endsWith(QLatin1Char('\\'))) { target = target.left(target.size() - 1); } targets += target + QLatin1Char(' '); } QString pluginFolder = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1String("/katectags"); QDir().mkpath(pluginFolder); if (m_ctagsUi.tagsFile->text().isEmpty()) { // FIXME we need a way to get the session name pluginFolder += QLatin1String("/session_db_"); pluginFolder += QDateTime::currentDateTimeUtc().toString(QStringLiteral("yyyyMMdd_hhmmss")); m_ctagsUi.tagsFile->setText(pluginFolder); } if (targets.isEmpty()) { KMessageBox::error(nullptr, i18n("No folders or files to index")); QFile::remove(m_ctagsUi.tagsFile->text()); return; } - QString command = QStringLiteral("%1 -f %2 %3").arg(m_ctagsUi.cmdEdit->text()).arg(m_ctagsUi.tagsFile->text()).arg(targets); + QString command = QStringLiteral("%1 -f %2 %3").arg(m_ctagsUi.cmdEdit->text(), m_ctagsUi.tagsFile->text(), targets); m_proc.start(command); if(!m_proc.waitForStarted(500)) { KMessageBox::error(nullptr, i18n("Failed to run \"%1\". exitStatus = %2", command, m_proc.exitStatus())); return; } QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); m_ctagsUi.updateButton->setDisabled(true); m_ctagsUi.updateButton2->setDisabled(true); } /******************************************************************/ void KateCTagsView::updateDone(int exitCode, QProcess::ExitStatus status) { if (status == QProcess::CrashExit) { KMessageBox::error(m_toolView, i18n("The CTags executable crashed.")); } else if (exitCode != 0) { KMessageBox::error(m_toolView, i18n("The CTags program exited with code %1: %2" , exitCode , QString::fromLocal8Bit(m_proc.readAllStandardError()))); } m_ctagsUi.updateButton->setDisabled(false); m_ctagsUi.updateButton2->setDisabled(false); QApplication::restoreOverrideCursor(); } /******************************************************************/ void KateCTagsView::addTagTarget() { QFileDialog dialog; dialog.setDirectory(QFileInfo(m_mWin->activeView()->document()->url().path()).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/kate-ctags/kate_ctags_view.h b/addons/kate-ctags/kate_ctags_view.h index 4200f57bf..fa8494a85 100644 --- a/addons/kate-ctags/kate_ctags_view.h +++ b/addons/kate-ctags/kate_ctags_view.h @@ -1,119 +1,119 @@ #ifndef KATE_CTAGS_VIEW_H #define KATE_CTAGS_VIEW_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 #include #include #include #include #include "tags.h" #include "ui_kate_ctags.h" -const static QString DEFAULT_CTAGS_CMD = QLatin1String("ctags -R --c++-types=+px --extra=+q --excmd=pattern --exclude=Makefile --exclude=."); +const static QString DEFAULT_CTAGS_CMD = QStringLiteral("ctags -R --c++-types=+px --extra=+q --excmd=pattern --exclude=Makefile --exclude=."); typedef struct { QUrl url; KTextEditor::Cursor cursor; } TagJump; /******************************************************************/ class KateCTagsView : public QObject, public KXMLGUIClient, public KTextEditor::SessionConfigInterface { Q_OBJECT Q_INTERFACES(KTextEditor::SessionConfigInterface) public: KateCTagsView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWin); ~KateCTagsView() override; // reimplemented: read and write session config void readSessionConfig (const KConfigGroup& config) override; void writeSessionConfig (KConfigGroup& config) override; public Q_SLOTS: void gotoDefinition(); void gotoDeclaration(); void lookupTag(); void stepBack(); void editLookUp(); void aboutToShow(); void tagHitClicked(QTreeWidgetItem *); void startEditTmr(); void addTagTarget(); void delTagTarget(); void updateSessionDB(); void updateDone(int exitCode, QProcess::ExitStatus status); protected: bool eventFilter(QObject *obj, QEvent *ev) override; private Q_SLOTS: void resetCMD(); void handleEsc(QEvent *e); private: bool listContains(const QString &target); QString currentWord(); void setNewLookupText(const QString &newText); void displayHits(const Tags::TagList &list); void gotoTagForTypes(const QString &tag, QStringList const &types); void jumpToTag(const QString &file, const QString &pattern, const QString &word); QPointer m_mWin; QPointer m_toolView; Ui::kateCtags m_ctagsUi; QPointer m_menu; QAction *m_gotoDef; QAction *m_gotoDec; QAction *m_lookup; QProcess m_proc; QString m_commonDB; QTimer m_editTimer; QStack m_jumpStack; }; #endif diff --git a/addons/kate-ctags/tags.cpp b/addons/kate-ctags/tags.cpp index 5bb5f8a85..2bf931d46 100644 --- a/addons/kate-ctags/tags.cpp +++ b/addons/kate-ctags/tags.cpp @@ -1,167 +1,167 @@ /*************************************************************************** * Copyright (C) 2004 by Jens Dagerbo * * jens.dagerbo@swipnet.se * * * * 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 "tags.h" #include namespace ctags { #include "readtags.h" } #include "ctagskinds.h" QString Tags::_tagsfile; Tags::TagEntry::TagEntry() {} Tags::TagEntry::TagEntry( const QString & tag, const QString & type, const QString & file, const QString & pattern ) : tag(tag), type(type), file(file), pattern(pattern) {} bool Tags::hasTag( const QString & tag ) { ctags::tagFileInfo info; ctags::tagFile * file = ctags::tagsOpen( _tagsfile.toLocal8Bit().constData(), &info ); ctags::tagEntry entry; bool found = ( ctags::tagsFind( file, &entry, tag.toLocal8Bit().constData(), TAG_FULLMATCH | TAG_OBSERVECASE ) == ctags::TagSuccess ); ctags::tagsClose( file ); return found; } bool Tags::hasTag( const QString & fileName, const QString & tag ) { setTagsFile( fileName ); ctags::tagFileInfo info; ctags::tagFile * file = ctags::tagsOpen( _tagsfile.toLocal8Bit().constData(), &info ); ctags::tagEntry entry; bool found = ( ctags::tagsFind( file, &entry, tag.toLocal8Bit().constData(), TAG_FULLMATCH | TAG_OBSERVECASE ) == ctags::TagSuccess ); ctags::tagsClose( file ); return found; } unsigned int Tags::numberOfMatches( const QString & tagpart, bool partial ) { unsigned int n = 0; if ( tagpart.isEmpty() ) return 0; ctags::tagFileInfo info; ctags::tagFile * file = ctags::tagsOpen( _tagsfile.toLocal8Bit().constData(), &info ); ctags::tagEntry entry; QByteArray tagpartBArray = tagpart.toLocal8Bit(); // for holding the char * if ( ctags::tagsFind( file, &entry, tagpartBArray.data(), TAG_OBSERVECASE | (partial ? TAG_PARTIALMATCH : TAG_FULLMATCH) ) == ctags::TagSuccess ) { do { n++; } while ( ctags::tagsFindNext( file, &entry ) == ctags::TagSuccess ); } ctags::tagsClose( file ); return n; } Tags::TagList Tags::getMatches( const QString & tagpart, bool partial, const QStringList & types ) { Tags::TagList list; if ( tagpart.isEmpty() ) return list; ctags::tagFileInfo info; ctags::tagFile * file = ctags::tagsOpen( _tagsfile.toLocal8Bit().constData(), &info ); ctags::tagEntry entry; QByteArray tagpartBArray = tagpart.toLocal8Bit(); // for holding the char * if ( ctags::tagsFind( file, &entry, tagpartBArray.data(), TAG_OBSERVECASE | (partial ? TAG_PARTIALMATCH : TAG_FULLMATCH) ) == ctags::TagSuccess ) { do { QString type( CTagsKinds::findKind( entry.kind, QString::fromLocal8Bit(entry.file).section( QLatin1Char('.') , -1 ) ) ); QString file = QString::fromLocal8Bit( entry.file ); if ( type.isEmpty() && file.endsWith( QLatin1String("Makefile") ) ) { - type = QLatin1String("macro"); + type = QStringLiteral("macro"); } if ( types.isEmpty() || types.contains( QString::fromLocal8Bit(entry.kind) ) ) { list << TagEntry( QString::fromLocal8Bit( entry.name ), type, file, QString::fromLocal8Bit( entry.address.pattern ) ); } } while ( ctags::tagsFindNext( file, &entry ) == ctags::TagSuccess ); } ctags::tagsClose( file ); return list; } void Tags::setTagsFile( const QString & file ) { _tagsfile = file; } QString Tags::getTagsFile( ) { return _tagsfile; } unsigned int Tags::numberOfPartialMatches( const QString & tagpart ) { return numberOfMatches( tagpart, true ); } unsigned int Tags::numberOfExactMatches( const QString & tagpart ) { return numberOfMatches( tagpart, false ); } Tags::TagList Tags::getPartialMatches( const QString & tagpart ) { return getMatches( tagpart, true ); } Tags::TagList Tags::getExactMatches( const QString & tag ) { return getMatches( tag, false ); } Tags::TagList Tags::getPartialMatches( const QString & file, const QString & tagpart ) { setTagsFile( file ); return getMatches( tagpart, true ); } Tags::TagList Tags::getExactMatches( const QString & file, const QString & tag ) { setTagsFile( file ); return getMatches( tag, false ); } Tags::TagList Tags::getMatches( const QString & file, const QString & tagpart, bool partial, const QStringList & types ) { setTagsFile( file ); return getMatches( tagpart, partial, types); } // kate: space-indent off; indent-width 4; tab-width 4; show-tabs on; diff --git a/addons/katebuild-plugin/plugin_katebuild.cpp b/addons/katebuild-plugin/plugin_katebuild.cpp index 810b96bea..66f8f1520 100644 --- a/addons/katebuild-plugin/plugin_katebuild.cpp +++ b/addons/katebuild-plugin/plugin_katebuild.cpp @@ -1,1065 +1,1065 @@ /* plugin_katebuild.c Kate Plugin ** ** Copyright (C) 2013 by Alexander Neundorf ** Copyright (C) 2006-2015 by KÃ¥re Särs ** Copyright (C) 2011 by Ian Wakeling ** ** This code is mostly a modification of the GPL'ed Make plugin ** by Adriaan de Groot. */ /* ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program in a file called COPYING; if not, write to ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ** MA 02110-1301, USA. */ #include "plugin_katebuild.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "SelectTargetView.h" K_PLUGIN_FACTORY_WITH_JSON (KateBuildPluginFactory, "katebuildplugin.json", registerPlugin();) static const QString DefConfigCmd = QStringLiteral("cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/usr/local ../"); static const QString DefConfClean; static const QString DefTargetName = QStringLiteral("all"); static const QString DefBuildCmd = QStringLiteral("make"); static const QString DefCleanCmd = QStringLiteral("make clean"); /******************************************************************/ KateBuildPlugin::KateBuildPlugin(QObject *parent, const VariantList&): KTextEditor::Plugin(parent) { // KF5 FIXME KGlobal::locale()->insertCatalog("katebuild-plugin"); } /******************************************************************/ QObject *KateBuildPlugin::createView (KTextEditor::MainWindow *mainWindow) { return new KateBuildView(this, mainWindow); } /******************************************************************/ KateBuildView::KateBuildView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mw) : QObject (mw) , m_win(mw) , m_buildWidget(nullptr) , m_outputWidgetWidth(0) , m_proc(this) , m_stdOut() , m_stdErr() , m_buildCancelled(false) , m_displayModeBeforeBuild(1) // NOTE this will not allow spaces in file names. // e.g. from gcc: "main.cpp:14: error: cannot convert ‘std::string’ to ‘int’ in return" , m_filenameDetector(QStringLiteral("(([a-np-zA-Z]:[\\\\/])?[a-zA-Z0-9_\\.\\-/\\\\]+\\.[a-zA-Z0-9]+):([0-9]+)(.*)")) // e.g. from icpc: "main.cpp(14): error: no suitable conversion function from "std::string" to "int" exists" , m_filenameDetectorIcpc(QStringLiteral("(([a-np-zA-Z]:[\\\\/])?[a-zA-Z0-9_\\.\\-/\\\\]+\\.[a-zA-Z0-9]+)\\(([0-9]+)\\)(:.*)")) , m_filenameDetectorGccWorked(false) , m_newDirDetector(QStringLiteral("make\\[.+\\]: .+ `.*'")) { - KXMLGUIClient::setComponentName (QLatin1String("katebuild"), i18n ("Kate Build Plugin")); - setXMLFile(QLatin1String("ui.rc")); + KXMLGUIClient::setComponentName (QStringLiteral("katebuild"), i18n ("Kate Build Plugin")); + setXMLFile(QStringLiteral("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, &QAction::triggered, this, &KateBuildView::slotSelectTarget); a = actionCollection()->addAction(QStringLiteral("build_default_target")); a->setText(i18n("Build Default Target")); connect(a, &QAction::triggered, this, &KateBuildView::slotBuildDefaultTarget); a = actionCollection()->addAction(QStringLiteral("build_previous_target")); a->setText(i18n("Build Previous Target")); connect(a, &QAction::triggered, this, &KateBuildView::slotBuildPreviousTarget); a = actionCollection()->addAction(QStringLiteral("stop")); a->setText(i18n("Stop")); a->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete"))); connect(a, &QAction::triggered, this, &KateBuildView::slotStop); a = actionCollection()->addAction(QStringLiteral("goto_next")); a->setText(i18n("Next Error")); a->setIcon(QIcon::fromTheme(QStringLiteral("go-next"))); actionCollection()->setDefaultShortcut(a, Qt::SHIFT+Qt::ALT+Qt::Key_Right); connect(a, &QAction::triggered, this, &KateBuildView::slotNext); a = actionCollection()->addAction(QStringLiteral("goto_prev")); a->setText(i18n("Previous Error")); a->setIcon(QIcon::fromTheme(QStringLiteral("go-previous"))); actionCollection()->setDefaultShortcut(a, Qt::SHIFT+Qt::ALT+Qt::Key_Left); connect(a, &QAction::triggered, this, &KateBuildView::slotPrev); m_buildWidget = new QWidget(m_toolView); m_buildUi.setupUi(m_buildWidget); m_targetsUi = new TargetsUi(this, m_buildUi.u_tabWidget); m_buildUi.u_tabWidget->insertTab(0, m_targetsUi, i18nc("Tab label", "Target Settings")); m_buildUi.u_tabWidget->setCurrentWidget(m_targetsUi); m_buildWidget->installEventFilter(this); m_buildUi.buildAgainButton->setVisible(true); m_buildUi.cancelBuildButton->setVisible(true); m_buildUi.buildStatusLabel->setVisible(true); m_buildUi.buildAgainButton2->setVisible(false); m_buildUi.cancelBuildButton2->setVisible(false); m_buildUi.buildStatusLabel2->setVisible(false); m_buildUi.extraLineLayout->setAlignment(Qt::AlignRight); m_buildUi.cancelBuildButton->setEnabled(false); m_buildUi.cancelBuildButton2->setEnabled(false); connect(m_buildUi.errTreeWidget, &QTreeWidget::itemClicked, this, &KateBuildView::slotErrorSelected); m_buildUi.plainTextEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); m_buildUi.plainTextEdit->setReadOnly(true); slotDisplayMode(FullOutput); connect(m_buildUi.displayModeSlider, &QSlider::valueChanged, this, &KateBuildView::slotDisplayMode); connect(m_buildUi.buildAgainButton, &QPushButton::clicked, this, &KateBuildView::slotBuildPreviousTarget); connect(m_buildUi.cancelBuildButton, &QPushButton::clicked, this, &KateBuildView::slotStop); connect(m_buildUi.buildAgainButton2, &QPushButton::clicked, this, &KateBuildView::slotBuildPreviousTarget); connect(m_buildUi.cancelBuildButton2, &QPushButton::clicked, this, &KateBuildView::slotStop); connect(m_targetsUi->newTarget, &QToolButton::clicked, this, &KateBuildView::targetSetNew); connect(m_targetsUi->copyTarget, &QToolButton::clicked, this, &KateBuildView::targetOrSetCopy); connect(m_targetsUi->deleteTarget, &QToolButton::clicked, this, &KateBuildView::targetDelete); connect(m_targetsUi->addButton, &QToolButton::clicked, this, &KateBuildView::slotAddTargetClicked); connect(m_targetsUi->buildButton, &QToolButton::clicked, this, &KateBuildView::slotBuildActiveTarget); connect(m_targetsUi, &TargetsUi::enterPressed, this, &KateBuildView::slotBuildActiveTarget); m_proc.setOutputChannelMode(KProcess::SeparateChannels); connect(&m_proc, static_cast(&QProcess::finished), this, &KateBuildView::slotProcExited); connect(&m_proc, &KProcess::readyReadStandardError, this, &KateBuildView::slotReadReadyStdErr); connect(&m_proc, &KProcess::readyReadStandardOutput, this, &KateBuildView::slotReadReadyStdOut); connect(m_win, &KTextEditor::MainWindow::unhandledShortcutOverride, this, &KateBuildView::handleEsc); m_toolView->installEventFilter(this); m_win->guiFactory()->addClient(this); // watch for project plugin view creation/deletion connect(m_win, &KTextEditor::MainWindow::pluginViewCreated, this, &KateBuildView::slotPluginViewCreated); connect(m_win, &KTextEditor::MainWindow::pluginViewDeleted, this, &KateBuildView::slotPluginViewDeleted); // Connect signals from project plugin to our slots m_projectPluginView = m_win->pluginView(QStringLiteral("kateprojectplugin")); slotPluginViewCreated(QStringLiteral("kateprojectplugin"), m_projectPluginView); } /******************************************************************/ 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); // Add project targets, if any slotAddProjectTarget(); } /******************************************************************/ void KateBuildView::writeSessionConfig(KConfigGroup& cg) { // Don't save project targets, is not our area of accountability 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); // Restore project targets, if any slotAddProjectTarget(); } /******************************************************************/ void KateBuildView::slotNext() { const int itemCount = m_buildUi.errTreeWidget->topLevelItemCount(); if (itemCount == 0) { return; } QTreeWidgetItem *item = m_buildUi.errTreeWidget->currentItem(); if (item && item->isHidden()) item = nullptr; int i = (item == nullptr) ? -1 : m_buildUi.errTreeWidget->indexOfTopLevelItem(item); while (++i < itemCount) { item = m_buildUi.errTreeWidget->topLevelItem(i); // Search item which fit view settings and has desired data if (!item->text(1).isEmpty() && !item->isHidden() && item->data(1, Qt::UserRole).toInt()) { m_buildUi.errTreeWidget->setCurrentItem(item); m_buildUi.errTreeWidget->scrollToItem(item); slotErrorSelected(item); return; } } } /******************************************************************/ void KateBuildView::slotPrev() { const int itemCount = m_buildUi.errTreeWidget->topLevelItemCount(); if (itemCount == 0) { return; } QTreeWidgetItem *item = m_buildUi.errTreeWidget->currentItem(); if (item && item->isHidden()) item = nullptr; int i = (item == nullptr) ? itemCount : m_buildUi.errTreeWidget->indexOfTopLevelItem(item); while (--i >= 0) { item = m_buildUi.errTreeWidget->topLevelItem(i); // Search item which fit view settings and has desired data if (!item->text(1).isEmpty() && !item->isHidden() && item->data(1, Qt::UserRole).toInt()) { m_buildUi.errTreeWidget->setCurrentItem(item); m_buildUi.errTreeWidget->scrollToItem(item); slotErrorSelected(item); return; } } } /******************************************************************/ void KateBuildView::slotErrorSelected(QTreeWidgetItem *item) { // any view active? if (!m_win->activeView()) { return; } // Avoid garish highlighting of the selected line m_win->activeView()->setFocus(); // Search the item where the data we need is stored while (!item->data(1, Qt::UserRole).toInt()) { item = m_buildUi.errTreeWidget->itemAbove(item); if (!item) { return; } } // 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)); // do it ;) m_win->activeView()->setCursorPosition(KTextEditor::Cursor(line-1, column-1)); } /******************************************************************/ void KateBuildView::addError(const QString &filename, const QString &line, const QString &column, const QString &message) { ErrorCategory errorCategory = CategoryInfo; QTreeWidgetItem* item = new QTreeWidgetItem(m_buildUi.errTreeWidget); item->setBackground(1, Qt::gray); // The strings are twice in case kate is translated but not make. if (message.contains(QStringLiteral("error")) || message.contains(i18nc("The same word as 'make' uses to mark an error.","error")) || message.contains(QStringLiteral("undefined reference")) || message.contains(i18nc("The same word as 'ld' uses to mark an ...","undefined reference")) ) { errorCategory = CategoryError; item->setForeground(1, Qt::red); m_numErrors++; item->setHidden(false); } if (message.contains(QStringLiteral("warning")) || message.contains(i18nc("The same word as 'make' uses to mark a warning.","warning")) ) { errorCategory = CategoryWarning; item->setForeground(1, Qt::yellow); m_numWarnings++; item->setHidden(m_buildUi.displayModeSlider->value() > 2); } item->setTextAlignment(1, Qt::AlignRight); // visible text //remove path from visible file name QFileInfo file(filename); item->setText(0, file.fileName()); item->setText(1, line); item->setText(2, message.trimmed()); // used to read from when activating an item item->setData(0, Qt::UserRole, filename); item->setData(1, Qt::UserRole, line); item->setData(2, Qt::UserRole, column); if (errorCategory == CategoryInfo) { item->setHidden(m_buildUi.displayModeSlider->value() > 1); } item->setData(0, ErrorRole, errorCategory); // add tooltips in all columns // The enclosing ... enables word-wrap for long error messages item->setData(0, Qt::ToolTipRole, filename); item->setData(1, Qt::ToolTipRole, QStringLiteral("%1").arg(message)); item->setData(2, Qt::ToolTipRole, QStringLiteral("%1").arg(message)); } /******************************************************************/ QUrl KateBuildView::docUrl() { KTextEditor::View *kv = m_win->activeView(); if (!kv) { qDebug() << "no KTextEditor::View" << endl; return QUrl(); } if (kv->document()->isModified()) kv->document()->save(); return kv->document()->url(); } /******************************************************************/ bool KateBuildView::checkLocal(const QUrl &dir) { if (dir.path().isEmpty()) { KMessageBox::sorry(nullptr, i18n("There is no file or directory specified for building.")); return false; } else if (!dir.isLocalFile()) { KMessageBox::sorry(nullptr, i18n("The file \"%1\" is not a local file. " "Non-local files cannot be compiled.", dir.path())); return false; } return true; } /******************************************************************/ void KateBuildView::clearBuildResults() { m_buildUi.plainTextEdit->clear(); m_buildUi.errTreeWidget->clear(); m_stdOut.clear(); m_stdErr.clear(); m_numErrors = 0; m_numWarnings = 0; m_make_dir_stack.clear(); } /******************************************************************/ bool KateBuildView::startProcess(const QString &dir, const QString &command) { if (m_proc.state() != QProcess::NotRunning) { return false; } // clear previous runs clearBuildResults(); // activate the output tab m_buildUi.u_tabWidget->setCurrentIndex(1); m_displayModeBeforeBuild = m_buildUi.displayModeSlider->value(); m_buildUi.displayModeSlider->setValue(0); m_win->showToolView(m_toolView); // set working directory m_make_dir = dir; m_make_dir_stack.push(m_make_dir); if (!QFile::exists(m_make_dir)) { KMessageBox::error(nullptr, i18n("Cannot run command: %1\nWork path does not exist: %2", command, m_make_dir)); return false; } m_proc.setWorkingDirectory(m_make_dir); m_proc.setShellCommand(command); m_proc.start(); if(!m_proc.waitForStarted(500)) { KMessageBox::error(nullptr, i18n("Failed to run \"%1\". exitStatus = %2", command, m_proc.exitStatus())); return false; } m_buildUi.cancelBuildButton->setEnabled(true); m_buildUi.cancelBuildButton2->setEnabled(true); m_buildUi.buildAgainButton->setEnabled(false); m_buildUi.buildAgainButton2->setEnabled(false); QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); return true; } /******************************************************************/ bool KateBuildView::slotStop() { if (m_proc.state() != QProcess::NotRunning) { m_buildCancelled = true; QString msg = i18n("Building %1 cancelled", m_currentlyBuildingTarget); m_buildUi.buildStatusLabel->setText(msg); m_buildUi.buildStatusLabel2->setText(msg); m_proc.terminate(); return true; } return false; } /******************************************************************/ void KateBuildView::slotBuildActiveTarget() { if (!m_targetsUi->targetsView->currentIndex().isValid()) { slotSelectTarget(); } else { buildCurrentTarget(); } } /******************************************************************/ void KateBuildView::slotBuildPreviousTarget() { if (!m_previousIndex.isValid()) { slotSelectTarget(); } else { m_targetsUi->targetsView->setCurrentIndex(m_previousIndex); buildCurrentTarget(); } } /******************************************************************/ void KateBuildView::slotBuildDefaultTarget() { QModelIndex defaultTarget = m_targetsUi->targetsModel.defaultTarget(m_targetsUi->targetsView->currentIndex()); m_targetsUi->targetsView->setCurrentIndex(defaultTarget); buildCurrentTarget(); } /******************************************************************/ void KateBuildView::slotSelectTarget() { SelectTargetView *dialog = new SelectTargetView(&(m_targetsUi->targetsModel)); dialog->setCurrentIndex(m_targetsUi->targetsView->currentIndex()); int result = dialog->exec(); if (result == QDialog::Accepted) { m_targetsUi->targetsView->setCurrentIndex(dialog->currentIndex()); buildCurrentTarget(); } delete dialog; dialog = nullptr; } /******************************************************************/ bool KateBuildView::buildCurrentTarget() { if (m_proc.state() != QProcess::NotRunning) { displayBuildResult(i18n("Already building..."), KTextEditor::Message::Warning); return false; } QFileInfo docFInfo = docUrl().toLocalFile(); // docUrl() saves the current document QModelIndex ind = m_targetsUi->targetsView->currentIndex(); m_previousIndex = ind; if (!ind.isValid()) { KMessageBox::sorry(nullptr, i18n("No target available for building.")); return false; } QString buildCmd = m_targetsUi->targetsModel.command(ind); QString cmdName = m_targetsUi->targetsModel.cmdName(ind); QString workDir = m_targetsUi->targetsModel.workDir(ind); QString targetSet = m_targetsUi->targetsModel.targetName(ind); QString dir = workDir; if (workDir.isEmpty()) { dir = docFInfo.absolutePath(); if (dir.isEmpty()) { KMessageBox::sorry(nullptr, i18n("There is no local file or directory specified for building.")); return false; } } // Check if the command contains the file name or directory if (buildCmd.contains(QStringLiteral("%f")) || buildCmd.contains(QStringLiteral("%d")) || buildCmd.contains(QStringLiteral("%n"))) { if (docFInfo.absoluteFilePath().isEmpty()) { return false; } buildCmd.replace(QStringLiteral("%n"), docFInfo.baseName()); buildCmd.replace(QStringLiteral("%f"), docFInfo.absoluteFilePath()); buildCmd.replace(QStringLiteral("%d"), docFInfo.absolutePath()); } m_filenameDetectorGccWorked = false; - m_currentlyBuildingTarget = QStringLiteral("%1: %2").arg(targetSet).arg(cmdName); + m_currentlyBuildingTarget = QStringLiteral("%1: %2").arg(targetSet, 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 (pluginView && name == QLatin1String("kateprojectplugin")) { m_projectPluginView = pluginView; slotAddProjectTarget(); connect(pluginView, SIGNAL(projectMapChanged()), this, SLOT(slotProjectMapChanged()), Qt::UniqueConnection); } } /******************************************************************/ void KateBuildView::slotPluginViewDeleted(const QString &name, QObject *) { // remove view if (name == QLatin1String("kateprojectplugin")) { m_projectPluginView = nullptr; m_targetsUi->targetsModel.deleteTargetSet(i18n("Project Plugin Targets")); } } /******************************************************************/ void KateBuildView::slotProjectMapChanged() { // only do stuff with valid project if (!m_projectPluginView) { return; } m_targetsUi->targetsModel.deleteTargetSet(i18n("Project Plugin Targets")); slotAddProjectTarget(); } /******************************************************************/ void KateBuildView::slotAddProjectTarget() { // only do stuff with valid project if (!m_projectPluginView) { return; } // query new project map QVariantMap projectMap = m_projectPluginView->property("projectMap").toMap(); // do we have a valid map for build settings? QVariantMap buildMap = projectMap.value(QStringLiteral("build")).toMap(); if (buildMap.isEmpty()) { return; } // Delete any old project plugin targets m_targetsUi->targetsModel.deleteTargetSet(i18n("Project Plugin Targets")); int set = m_targetsUi->targetsModel.addTargetSet(i18n("Project Plugin Targets"), buildMap.value(QStringLiteral("directory")).toString()); QVariantList targetsets = buildMap.value(QStringLiteral("targets")).toList(); foreach (const QVariant &targetVariant, targetsets) { QVariantMap targetMap = targetVariant.toMap(); QString tgtName = targetMap[QStringLiteral("name")].toString(); QString buildCmd = targetMap[QStringLiteral("build_cmd")].toString(); if (tgtName.isEmpty() || buildCmd.isEmpty()) { continue; } m_targetsUi->targetsModel.addCommand(set, tgtName, buildCmd); } QModelIndex ind = m_targetsUi->targetsModel.index(set); if (!ind.child(0,0).data().isValid()) { QString buildCmd = buildMap.value(QStringLiteral("build")).toString(); QString cleanCmd = buildMap.value(QStringLiteral("clean")).toString(); QString quickCmd = buildMap.value(QStringLiteral("quick")).toString(); if (!buildCmd.isEmpty()) { // we have loaded an "old" project file (<= 4.12) m_targetsUi->targetsModel.addCommand(set, i18n("build"), buildCmd); } if (!cleanCmd.isEmpty()) { m_targetsUi->targetsModel.addCommand(set, i18n("clean"), cleanCmd); } if (!quickCmd.isEmpty()) { m_targetsUi->targetsModel.addCommand(set, i18n("quick"), quickCmd); } } } /******************************************************************/ bool KateBuildView::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); if ((obj == m_toolView) && (ke->key() == Qt::Key_Escape)) { m_win->hideToolView(m_toolView); event->accept(); return true; } } if ((event->type() == QEvent::Resize) && (obj == m_buildWidget)) { if (m_buildUi.u_tabWidget->currentIndex() == 1) { if ((m_outputWidgetWidth == 0) && m_buildUi.buildAgainButton->isVisible()) { QSize msh = m_buildWidget->minimumSizeHint(); m_outputWidgetWidth = msh.width(); } } bool useVertLayout = (m_buildWidget->width() < m_outputWidgetWidth); m_buildUi.buildAgainButton->setVisible(!useVertLayout); m_buildUi.cancelBuildButton->setVisible(!useVertLayout); m_buildUi.buildStatusLabel->setVisible(!useVertLayout); m_buildUi.buildAgainButton2->setVisible(useVertLayout); m_buildUi.cancelBuildButton2->setVisible(useVertLayout); m_buildUi.buildStatusLabel2->setVisible(useVertLayout); } return QObject::eventFilter(obj, event); } /******************************************************************/ void KateBuildView::handleEsc(QEvent *e) { if (!m_win) return; QKeyEvent *k = static_cast(e); if (k->key() == Qt::Key_Escape && k->modifiers() == Qt::NoModifier) { if (m_toolView->isVisible()) { m_win->hideToolView(m_toolView); } } } #include "plugin_katebuild.moc" // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/katesql/connectionmodel.cpp b/addons/katesql/connectionmodel.cpp index af2ebad5b..31a7b4207 100644 --- a/addons/katesql/connectionmodel.cpp +++ b/addons/katesql/connectionmodel.cpp @@ -1,153 +1,153 @@ /* 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 "connectionmodel.h" #include #include #include #include #include #include #include #include ConnectionModel::ConnectionModel(QObject *parent) : QAbstractListModel(parent) { - m_icons[Connection::UNKNOWN] = QIcon::fromTheme(QLatin1String("user-offline")); - m_icons[Connection::ONLINE] = QIcon::fromTheme(QLatin1String("user-online")); - m_icons[Connection::OFFLINE] = QIcon::fromTheme(QLatin1String("user-offline")); - m_icons[Connection::REQUIRE_PASSWORD] = QIcon::fromTheme(QLatin1String("user-invisible")); + m_icons[Connection::UNKNOWN] = QIcon::fromTheme(QStringLiteral("user-offline")); + m_icons[Connection::ONLINE] = QIcon::fromTheme(QStringLiteral("user-online")); + m_icons[Connection::OFFLINE] = QIcon::fromTheme(QStringLiteral("user-offline")); + m_icons[Connection::REQUIRE_PASSWORD] = QIcon::fromTheme(QStringLiteral("user-invisible")); } ConnectionModel::~ConnectionModel() { } int ConnectionModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return m_connections.count(); } QVariant ConnectionModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); const QString key = m_connections.keys().at(index.row()); switch (role) { case Qt::DisplayRole: return QVariant(m_connections.value(key).name); break; case Qt::UserRole: return qVariantFromValue(m_connections.value(key)); break; case Qt::DecorationRole: return m_icons[m_connections.value(key).status]; break; case Qt::SizeHintRole: { const QFontMetrics metrics(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); return QSize(metrics.width(m_connections.value(key).name), 22); } break; default: return QVariant(); break; } return QVariant(); } int ConnectionModel::addConnection( Connection conn ) { /// FIXME if (m_connections.contains(conn.name)) { qDebug() << "a connection named" << conn.name << "already exists!"; return -1; } int pos = m_connections.count(); beginInsertRows(QModelIndex(), pos, pos); m_connections[conn.name] = conn; endInsertRows(); return m_connections.keys().indexOf(conn.name); } void ConnectionModel::removeConnection( const QString &name ) { int pos = m_connections.keys().indexOf(name); beginRemoveRows(QModelIndex(), pos, pos); m_connections.remove(name); endRemoveRows(); } int ConnectionModel::indexOf(const QString &name) { return m_connections.keys().indexOf(name); } Connection::Status ConnectionModel::status(const QString &name) const { if (!m_connections.contains(name)) return Connection::UNKNOWN; return m_connections[name].status; } void ConnectionModel::setStatus(const QString &name, const Connection::Status status) { if (!m_connections.contains(name)) return; m_connections[name].status = status; const int i = indexOf(name); emit dataChanged(index(i), index(i)); } void ConnectionModel::setPassword(const QString &name, const QString &password) { if (!m_connections.contains(name)) return; m_connections[name].password = password; const int i = indexOf(name); emit dataChanged(index(i), index(i)); } diff --git a/addons/katesql/connectionwizard.cpp b/addons/katesql/connectionwizard.cpp index 313af593a..7d898b1d3 100644 --- a/addons/katesql/connectionwizard.cpp +++ b/addons/katesql/connectionwizard.cpp @@ -1,323 +1,323 @@ /* 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 "connectionwizard.h" #include "sqlmanager.h" #include #include #include #include #include #include #include #include #include ConnectionWizard::ConnectionWizard ( SQLManager *manager, Connection *conn, QWidget *parent, Qt::WindowFlags flags ) : QWizard(parent, flags) , m_manager(manager) , m_connection(conn) { setWindowTitle(i18nc("@title:window", "Connection Wizard")); setPage(Page_Driver, new ConnectionDriverPage); setPage(Page_Standard_Server, new ConnectionStandardServerPage); setPage(Page_SQLite_Server, new ConnectionSQLiteServerPage); setPage(Page_Save, new ConnectionSavePage); } ConnectionWizard::~ConnectionWizard() { } ConnectionDriverPage::ConnectionDriverPage ( QWidget *parent) : QWizardPage(parent) { setTitle(i18nc("@title Wizard page title", "Database Driver")); setSubTitle(i18nc("@title Wizard page subtitle", "Select the database driver")); QFormLayout *layout = new QFormLayout(); driverComboBox = new KComboBox(); driverComboBox->addItems(QSqlDatabase::drivers()); layout->addRow(i18nc("@label:listbox", "Database driver:"), driverComboBox); setLayout(layout); - registerField(QLatin1String ("driver"), driverComboBox, "currentText"); + registerField(QStringLiteral ("driver"), driverComboBox, "currentText"); } void ConnectionDriverPage::initializePage() { ConnectionWizard *wiz = static_cast(wizard()); Connection *c = wiz->connection(); if (!c->driver.isEmpty()) driverComboBox->setCurrentItem(c->driver); } int ConnectionDriverPage::nextId() const { if (driverComboBox->currentText().contains(QLatin1String("QSQLITE"))) return ConnectionWizard::Page_SQLite_Server; else return ConnectionWizard::Page_Standard_Server; } ConnectionStandardServerPage::ConnectionStandardServerPage ( QWidget *parent ) : QWizardPage(parent) { setTitle(i18nc("@title Wizard page title", "Connection Parameters")); setSubTitle(i18nc("@title Wizard page subtitle", "Please enter connection parameters")); QFormLayout *layout = new QFormLayout(); hostnameLineEdit = new KLineEdit(); usernameLineEdit = new KLineEdit(); passwordLineEdit = new KLineEdit(); databaseLineEdit = new KLineEdit(); optionsLineEdit = new KLineEdit(); portSpinBox = new QSpinBox(); portSpinBox->setMaximum(65535); portSpinBox->setSpecialValueText(i18nc("@item Spinbox special value", "Default")); portSpinBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); passwordLineEdit->setPasswordMode(true); layout->addRow(i18nc("@label:textbox", "Hostname:"), hostnameLineEdit); layout->addRow(i18nc("@label:textbox", "Username:"), usernameLineEdit); layout->addRow(i18nc("@label:textbox", "Password:"), passwordLineEdit); layout->addRow(i18nc("@label:spinbox", "Port:"), portSpinBox); layout->addRow(i18nc("@label:textbox", "Database name:"), databaseLineEdit); layout->addRow(i18nc("@label:textbox", "Connection options:"), optionsLineEdit); setLayout(layout); - registerField(QLatin1String("hostname*"), hostnameLineEdit); - registerField(QLatin1String("username") , usernameLineEdit); - registerField(QLatin1String("password") , passwordLineEdit); - registerField(QLatin1String("database") , databaseLineEdit); - registerField(QLatin1String("stdOptions") , optionsLineEdit); - registerField(QLatin1String("port") , portSpinBox); + registerField(QStringLiteral("hostname*"), hostnameLineEdit); + registerField(QStringLiteral("username") , usernameLineEdit); + registerField(QStringLiteral("password") , passwordLineEdit); + registerField(QStringLiteral("database") , databaseLineEdit); + registerField(QStringLiteral("stdOptions") , optionsLineEdit); + registerField(QStringLiteral("port") , portSpinBox); } ConnectionStandardServerPage::~ConnectionStandardServerPage() { } void ConnectionStandardServerPage::initializePage() { ConnectionWizard *wiz = static_cast(wizard()); Connection *c = wiz->connection(); - hostnameLineEdit->setText(QLatin1String("localhost")); + hostnameLineEdit->setText(QStringLiteral("localhost")); - if (c->driver == field(QLatin1String("driver")).toString()) + if (c->driver == field(QStringLiteral("driver")).toString()) { hostnameLineEdit->setText(c->hostname); usernameLineEdit->setText(c->username); passwordLineEdit->setText(c->password); databaseLineEdit->setText(c->database); optionsLineEdit->setText(c->options); portSpinBox->setValue(c->port); } hostnameLineEdit->selectAll(); } bool ConnectionStandardServerPage::validatePage() { Connection c; - c.driver = field(QLatin1String("driver")).toString(); - c.hostname = field(QLatin1String("hostname")).toString(); - c.username = field(QLatin1String("username")).toString(); - c.password = field(QLatin1String("password")).toString(); - c.database = field(QLatin1String("database")).toString(); - c.options = field(QLatin1String("stdOptions")).toString(); - c.port = field(QLatin1String("port")).toInt(); + c.driver = field(QStringLiteral("driver")).toString(); + c.hostname = field(QStringLiteral("hostname")).toString(); + c.username = field(QStringLiteral("username")).toString(); + c.password = field(QStringLiteral("password")).toString(); + c.database = field(QStringLiteral("database")).toString(); + c.options = field(QStringLiteral("stdOptions")).toString(); + c.port = field(QStringLiteral("port")).toInt(); QSqlError e; ConnectionWizard *wiz = static_cast(wizard()); if (!wiz->manager()->testConnection(c, e)) { KMessageBox::error(this, i18n("Unable to connect to database.") + QLatin1String("\n") + e.text()); return false; } return true; } int ConnectionStandardServerPage::nextId() const { return ConnectionWizard::Page_Save; } ConnectionSQLiteServerPage::ConnectionSQLiteServerPage ( QWidget *parent) : QWizardPage(parent) { setTitle(i18nc("@title Wizard page title", "Connection Parameters")); setSubTitle(i18nc("@title Wizard page subtitle", "Please enter the SQLite database file path.\nIf the file does not exist, a new database will be created.")); QFormLayout *layout = new QFormLayout(); pathUrlRequester = new KUrlRequester(this); optionsLineEdit = new KLineEdit(); pathUrlRequester->setMode( KFile::File); pathUrlRequester->setFilter(QLatin1String("*.db *.sqlite|") + i18n("Database files") + QLatin1String("\n*|") + i18n("All files")); layout->addRow(i18nc("@label:textbox", "Path:"), pathUrlRequester); layout->addRow(i18nc("@label:textbox", "Connection options:"), optionsLineEdit); setLayout(layout); - registerField(QLatin1String("path*"), pathUrlRequester->lineEdit()); - registerField(QLatin1String("sqliteOptions"), optionsLineEdit); + registerField(QStringLiteral("path*"), pathUrlRequester->lineEdit()); + registerField(QStringLiteral("sqliteOptions"), optionsLineEdit); } void ConnectionSQLiteServerPage::initializePage() { ConnectionWizard *wiz = static_cast(wizard()); Connection *c = wiz->connection(); - if (c->driver == field(QLatin1String("driver")).toString()) + if (c->driver == field(QStringLiteral("driver")).toString()) { pathUrlRequester->lineEdit()->setText(c->database); optionsLineEdit->setText(c->options); } } bool ConnectionSQLiteServerPage::validatePage() { Connection c; - c.driver = field(QLatin1String("driver")).toString(); - c.database = field(QLatin1String("path")).toString(); - c.options = field(QLatin1String("sqliteOptions")).toString(); + c.driver = field(QStringLiteral("driver")).toString(); + c.database = field(QStringLiteral("path")).toString(); + c.options = field(QStringLiteral("sqliteOptions")).toString(); QSqlError e; ConnectionWizard *wiz = static_cast(wizard()); if (!wiz->manager()->testConnection(c, e)) { KMessageBox::error(this, xi18nc("@info", "Unable to connect to database.%1", e.text())); return false; } return true; } int ConnectionSQLiteServerPage::nextId() const { return ConnectionWizard::Page_Save; } ConnectionSavePage::ConnectionSavePage ( QWidget *parent) : QWizardPage(parent) { setTitle(i18nc("@title Wizard page title", "Connection Name")); setSubTitle(i18nc("@title Wizard page subtitle", "Enter a unique connection name")); QFormLayout *layout = new QFormLayout(); connectionNameLineEdit = new KLineEdit(); layout->addRow(i18nc("@label:textbox", "Connection name:"), connectionNameLineEdit); setLayout(layout); - registerField(QLatin1String("connectionName*"), connectionNameLineEdit); + registerField(QStringLiteral("connectionName*"), connectionNameLineEdit); } void ConnectionSavePage::initializePage() { QString name; ConnectionWizard *wiz = static_cast(wizard()); Connection *c = wiz->connection(); if (!c->name.isEmpty()) { name = c->name; } - else if (field(QLatin1String("driver")).toString().contains(QLatin1String("QSQLITE"))) + else if (field(QStringLiteral("driver")).toString().contains(QLatin1String("QSQLITE"))) { /// TODO: use db file basename - name = QLatin1String("SQLite"); + name = QStringLiteral("SQLite"); for (int i = 1; QSqlDatabase::contains(name); i++) - name = QString::fromLatin1("%1%2").arg(QLatin1String("SQLite")).arg(i); + name = QStringLiteral("%1%2").arg(QLatin1String("SQLite")).arg(i); } else { - name = QString::fromLatin1("%1 on %2").arg(field(QLatin1String("database")).toString()).arg(field(QLatin1String("hostname")).toString()).simplified(); + name = QStringLiteral("%1 on %2").arg(field(QStringLiteral("database")).toString()).arg(field(QStringLiteral("hostname")).toString()).simplified(); for (int i = 1; QSqlDatabase::contains(name); i++) - name = QString::fromLatin1("%1 on %2 (%3)").arg(field(QLatin1String("database")).toString()).arg(field(QLatin1String("hostname")).toString()).arg(i).simplified(); + name = QStringLiteral("%1 on %2 (%3)").arg(field(QStringLiteral("database")).toString()).arg(field(QStringLiteral("hostname")).toString()).arg(i).simplified(); } connectionNameLineEdit->setText(name); connectionNameLineEdit->selectAll(); } bool ConnectionSavePage::validatePage() { - QString name = field(QLatin1String("connectionName")).toString().simplified(); + QString name = field(QStringLiteral("connectionName")).toString().simplified(); ConnectionWizard *wiz = static_cast(wizard()); Connection *c = wiz->connection(); c->name = name; - c->driver = field(QLatin1String("driver")).toString(); + c->driver = field(QStringLiteral("driver")).toString(); - if (field(QLatin1String("driver")).toString().contains(QLatin1String("QSQLITE"))) + if (field(QStringLiteral("driver")).toString().contains(QLatin1String("QSQLITE"))) { - c->database = field(QLatin1String("path")).toString(); - c->options = field(QLatin1String("sqliteOptions")).toString(); + c->database = field(QStringLiteral("path")).toString(); + c->options = field(QStringLiteral("sqliteOptions")).toString(); } else { - c->hostname = field(QLatin1String("hostname")).toString(); - c->username = field(QLatin1String("username")).toString(); - c->password = field(QLatin1String("password")).toString(); - c->database = field(QLatin1String("database")).toString(); - c->options = field(QLatin1String("stdOptions")).toString(); - c->port = field(QLatin1String("port")).toInt(); + c->hostname = field(QStringLiteral("hostname")).toString(); + c->username = field(QStringLiteral("username")).toString(); + c->password = field(QStringLiteral("password")).toString(); + c->database = field(QStringLiteral("database")).toString(); + c->options = field(QStringLiteral("stdOptions")).toString(); + c->port = field(QStringLiteral("port")).toInt(); } return true; } int ConnectionSavePage::nextId() const { return -1; } diff --git a/addons/katesql/dataoutputmodel.cpp b/addons/katesql/dataoutputmodel.cpp index 8d3cace10..49389ab43 100644 --- a/addons/katesql/dataoutputmodel.cpp +++ b/addons/katesql/dataoutputmodel.cpp @@ -1,217 +1,217 @@ /* Copyright (C) 2010 Marco Mentasti This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dataoutputmodel.h" #include "outputstyle.h" #include #include #include #include #include #include inline bool isNumeric(const QVariant::Type type) { return (type > 1 && type < 7); } DataOutputModel::DataOutputModel(QObject *parent) : CachedSqlQueryModel(parent, 1000) { m_useSystemLocale = false; - m_styles.insert(QLatin1String ("text"), new OutputStyle()); - m_styles.insert(QLatin1String ("number"), new OutputStyle()); - m_styles.insert(QLatin1String ("null"), new OutputStyle()); - m_styles.insert(QLatin1String ("blob"), new OutputStyle()); - m_styles.insert(QLatin1String ("datetime"), new OutputStyle()); - m_styles.insert(QLatin1String ("bool"), new OutputStyle()); + m_styles.insert(QStringLiteral ("text"), new OutputStyle()); + m_styles.insert(QStringLiteral ("number"), new OutputStyle()); + m_styles.insert(QStringLiteral ("null"), new OutputStyle()); + m_styles.insert(QStringLiteral ("blob"), new OutputStyle()); + m_styles.insert(QStringLiteral ("datetime"), new OutputStyle()); + m_styles.insert(QStringLiteral ("bool"), new OutputStyle()); readConfig(); } DataOutputModel::~DataOutputModel() { qDeleteAll(m_styles); } void DataOutputModel::clear() { beginResetModel(); CachedSqlQueryModel::clear(); endResetModel(); } void DataOutputModel::readConfig() { KConfigGroup config(KSharedConfig::openConfig(), "KateSQLPlugin"); KConfigGroup group = config.group("OutputCustomization"); KColorScheme scheme(QPalette::Active, KColorScheme::View); foreach(const QString& k, m_styles.keys()) { OutputStyle *s = m_styles[k]; KConfigGroup g = group.group(k); s->foreground = scheme.foreground(); s->background = scheme.background(); s->font = QFontDatabase::systemFont(QFontDatabase::GeneralFont); QFont dummy = g.readEntry("font", QFontDatabase::systemFont(QFontDatabase::GeneralFont)); s->font.setBold(dummy.bold()); s->font.setItalic(dummy.italic()); s->font.setUnderline(dummy.underline()); s->font.setStrikeOut(dummy.strikeOut()); s->foreground.setColor(g.readEntry("foregroundColor", s->foreground.color())); s->background.setColor(g.readEntry("backgroundColor", s->background.color())); } emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() -1)); } bool DataOutputModel::useSystemLocale() const { return m_useSystemLocale; } void DataOutputModel::setUseSystemLocale( bool useSystemLocale ) { m_useSystemLocale = useSystemLocale; emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() -1)); } QVariant DataOutputModel::data(const QModelIndex &index, int role) const { if (role == Qt::EditRole) return CachedSqlQueryModel::data(index, role); const QVariant value(CachedSqlQueryModel::data(index, Qt::DisplayRole)); const QVariant::Type type = value.type(); if (value.isNull()) { if (role == Qt::FontRole) - return QVariant(m_styles.value(QLatin1String ("null"))->font); + return QVariant(m_styles.value(QStringLiteral ("null"))->font); if (role == Qt::ForegroundRole) - return QVariant(m_styles.value(QLatin1String ("null"))->foreground); + return QVariant(m_styles.value(QStringLiteral ("null"))->foreground); if (role == Qt::BackgroundRole) - return QVariant(m_styles.value(QLatin1String ("null"))->background); + return QVariant(m_styles.value(QStringLiteral ("null"))->background); if (role == Qt::DisplayRole) return QVariant(QLatin1String ("NULL")); } if (type == QVariant::ByteArray) { if (role == Qt::FontRole) - return QVariant(m_styles.value(QLatin1String ("blob"))->font); + return QVariant(m_styles.value(QStringLiteral ("blob"))->font); if (role == Qt::ForegroundRole) - return QVariant(m_styles.value(QLatin1String ("blob"))->foreground); + return QVariant(m_styles.value(QStringLiteral ("blob"))->foreground); if (role == Qt::BackgroundRole) - return QVariant(m_styles.value(QLatin1String ("blob"))->background); + return QVariant(m_styles.value(QStringLiteral ("blob"))->background); if (role == Qt::DisplayRole) return QVariant(value.toByteArray().left(255)); } if (isNumeric(type)) { if (role == Qt::FontRole) - return QVariant(m_styles.value(QLatin1String ("number"))->font); + return QVariant(m_styles.value(QStringLiteral ("number"))->font); if (role == Qt::ForegroundRole) - return QVariant(m_styles.value(QLatin1String ("number"))->foreground); + return QVariant(m_styles.value(QStringLiteral ("number"))->foreground); if (role == Qt::BackgroundRole) - return QVariant(m_styles.value(QLatin1String ("number"))->background); + return QVariant(m_styles.value(QStringLiteral ("number"))->background); if (role == Qt::TextAlignmentRole) return QVariant(Qt::AlignRight | Qt::AlignVCenter); if (role == Qt::DisplayRole || role == Qt::UserRole) { if (useSystemLocale()) return QVariant(value.toString()); //FIXME KF5 KGlobal::locale()->formatNumber(value.toString(), false)); else return QVariant(value.toString()); } } if (type == QVariant::Bool) { if (role == Qt::FontRole) - return QVariant(m_styles.value(QLatin1String ("bool"))->font); + return QVariant(m_styles.value(QStringLiteral ("bool"))->font); if (role == Qt::ForegroundRole) - return QVariant(m_styles.value(QLatin1String ("bool"))->foreground); + return QVariant(m_styles.value(QStringLiteral ("bool"))->foreground); if (role == Qt::BackgroundRole) - return QVariant(m_styles.value(QLatin1String ("bool"))->background); + return QVariant(m_styles.value(QStringLiteral ("bool"))->background); if (role == Qt::DisplayRole) return QVariant(value.toBool() ? QLatin1String ("True") : QLatin1String ("False")); } if (type == QVariant::Date || type == QVariant::Time || type == QVariant::DateTime ) { if (role == Qt::FontRole) - return QVariant(m_styles.value(QLatin1String ("datetime"))->font); + return QVariant(m_styles.value(QStringLiteral ("datetime"))->font); if (role == Qt::ForegroundRole) - return QVariant(m_styles.value(QLatin1String ("datetime"))->foreground); + return QVariant(m_styles.value(QStringLiteral ("datetime"))->foreground); if (role == Qt::BackgroundRole) - return QVariant(m_styles.value(QLatin1String ("datetime"))->background); + return QVariant(m_styles.value(QStringLiteral ("datetime"))->background); if (role == Qt::DisplayRole || role == Qt::UserRole) { if (useSystemLocale()) { if (type == QVariant::Date) return QVariant(QLocale().toString(value.toDate(), QLocale::ShortFormat)); if (type == QVariant::Time) return QVariant(QLocale().toString(value.toTime())); if (type == QVariant::DateTime) return QVariant(QLocale().toString(value.toDateTime(), QLocale::ShortFormat)); } else // return sql server format return QVariant(value.toString()); } } if (role == Qt::FontRole) - return QVariant(m_styles.value(QLatin1String ("text"))->font); + return QVariant(m_styles.value(QStringLiteral ("text"))->font); if (role == Qt::ForegroundRole) - return QVariant(m_styles.value(QLatin1String ("text"))->foreground); + return QVariant(m_styles.value(QStringLiteral ("text"))->foreground); if (role == Qt::BackgroundRole) - return QVariant(m_styles.value(QLatin1String ("text"))->background); + return QVariant(m_styles.value(QStringLiteral ("text"))->background); if (role == Qt::TextAlignmentRole) return QVariant(Qt::AlignVCenter); if (role == Qt::DisplayRole) return value.toString(); if (role == Qt::UserRole) return value; return CachedSqlQueryModel::data(index, role); } diff --git a/addons/katesql/dataoutputwidget.cpp b/addons/katesql/dataoutputwidget.cpp index b9161d63b..7e0dc43d9 100644 --- a/addons/katesql/dataoutputwidget.cpp +++ b/addons/katesql/dataoutputwidget.cpp @@ -1,379 +1,379 @@ /* Copyright (C) 2010 Marco Mentasti This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dataoutputwidget.h" #include "dataoutputmodel.h" #include "dataoutputview.h" #include "exportwizard.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DataOutputWidget::DataOutputWidget(QWidget *parent) : QWidget(parent) , m_model(new DataOutputModel(this)) , m_view(new DataOutputView(this)) , m_isEmpty(true) { m_view->setModel(m_model); QHBoxLayout *layout = new QHBoxLayout(this); m_dataLayout = new QVBoxLayout(); KToolBar *toolbar = new KToolBar(this); toolbar->setOrientation(Qt::Vertical); toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); toolbar->setIconSize(QSize(16, 16)); /// TODO: disable actions if no results are displayed or selected QAction *action; - action = new QAction( QIcon::fromTheme(QLatin1String("distribute-horizontal-x")), i18nc("@action:intoolbar", "Resize columns to contents"), this); + action = new QAction( QIcon::fromTheme(QStringLiteral("distribute-horizontal-x")), i18nc("@action:intoolbar", "Resize columns to contents"), this); toolbar->addAction(action); connect(action, &QAction::triggered, this, &DataOutputWidget::resizeColumnsToContents); - action = new QAction( QIcon::fromTheme(QLatin1String("distribute-vertical-y")), i18nc("@action:intoolbar", "Resize rows to contents"), this); + action = new QAction( QIcon::fromTheme(QStringLiteral("distribute-vertical-y")), i18nc("@action:intoolbar", "Resize rows to contents"), this); toolbar->addAction(action); connect(action, &QAction::triggered, this, &DataOutputWidget::resizeRowsToContents); - action = new QAction( QIcon::fromTheme(QLatin1String("edit-copy")), i18nc("@action:intoolbar", "Copy"), this); + action = new QAction( QIcon::fromTheme(QStringLiteral("edit-copy")), i18nc("@action:intoolbar", "Copy"), this); toolbar->addAction(action); m_view->addAction(action); connect(action, &QAction::triggered, this, &DataOutputWidget::slotCopySelected); - action = new QAction( QIcon::fromTheme(QLatin1String("document-export-table")), i18nc("@action:intoolbar", "Export..."), this); + action = new QAction( QIcon::fromTheme(QStringLiteral("document-export-table")), i18nc("@action:intoolbar", "Export..."), this); toolbar->addAction(action); m_view->addAction(action); connect(action, &QAction::triggered, this, &DataOutputWidget::slotExport); - action = new QAction( QIcon::fromTheme(QLatin1String("edit-clear")), i18nc("@action:intoolbar", "Clear"), this); + action = new QAction( QIcon::fromTheme(QStringLiteral("edit-clear")), i18nc("@action:intoolbar", "Clear"), this); toolbar->addAction(action); connect(action, &QAction::triggered, this, &DataOutputWidget::clearResults); toolbar->addSeparator(); - KToggleAction *toggleAction = new KToggleAction( QIcon::fromTheme(QLatin1String("applications-education-language")), i18nc("@action:intoolbar", "Use system locale"), this); + KToggleAction *toggleAction = new KToggleAction( QIcon::fromTheme(QStringLiteral("applications-education-language")), i18nc("@action:intoolbar", "Use system locale"), this); toolbar->addAction(toggleAction); connect(toggleAction, &QAction::triggered, this, &DataOutputWidget::slotToggleLocale); m_dataLayout->addWidget(m_view); layout->addWidget(toolbar); layout->addLayout(m_dataLayout); layout->setContentsMargins(0, 0, 0, 0); setLayout(layout); } DataOutputWidget::~DataOutputWidget() { } void DataOutputWidget::showQueryResultSets(QSqlQuery &query) { /// TODO: loop resultsets if > 1 /// NOTE from Qt Documentation: /// When one of the statements is a non-select statement a count of affected rows /// may be available instead of a result set. if (!query.isSelect() || query.lastError().isValid()) return; m_model->setQuery(query); m_isEmpty = false; - QTimer::singleShot(0, this, SLOT(resizeColumnsToContents())); + QTimer::singleShot(0, this, &DataOutputWidget::resizeColumnsToContents); raise(); } void DataOutputWidget::clearResults() { // avoid crash when calling QSqlQueryModel::clear() after removing connection from the QSqlDatabase list if (m_isEmpty) return; m_model->clear(); m_isEmpty = true; /// HACK needed to refresh headers. please correct if there's a better way m_view->horizontalHeader()->hide(); m_view->verticalHeader()->hide(); m_view->horizontalHeader()->show(); m_view->verticalHeader()->show(); } void DataOutputWidget::resizeColumnsToContents() { if (m_model->rowCount() == 0) return; m_view->resizeColumnsToContents(); } void DataOutputWidget::resizeRowsToContents() { if (m_model->rowCount() == 0) return; m_view->resizeRowsToContents(); int h = m_view->rowHeight(0); if (h > 0) m_view->verticalHeader()->setDefaultSectionSize(h); } void DataOutputWidget::slotToggleLocale() { m_model->setUseSystemLocale(!m_model->useSystemLocale()); } void DataOutputWidget::slotCopySelected() { if (m_model->rowCount() <= 0) return; while (m_model->canFetchMore()) m_model->fetchMore(); if (!m_view->selectionModel()->hasSelection()) m_view->selectAll(); QString text; QTextStream stream(&text); exportData(stream); if (!text.isEmpty()) QApplication::clipboard()->setText(text); } void DataOutputWidget::slotExport() { if (m_model->rowCount() <= 0) return; while (m_model->canFetchMore()) m_model->fetchMore(); if (!m_view->selectionModel()->hasSelection()) m_view->selectAll(); ExportWizard wizard(this); if (wizard.exec() != QDialog::Accepted) return; - bool outputInDocument = wizard.field(QLatin1String("outDocument")).toBool(); - bool outputInClipboard = wizard.field(QLatin1String("outClipboard")).toBool(); - bool outputInFile = wizard.field(QLatin1String("outFile")).toBool(); + bool outputInDocument = wizard.field(QStringLiteral("outDocument")).toBool(); + bool outputInClipboard = wizard.field(QStringLiteral("outClipboard")).toBool(); + bool outputInFile = wizard.field(QStringLiteral("outFile")).toBool(); - bool exportColumnNames = wizard.field(QLatin1String("exportColumnNames")).toBool(); - bool exportLineNumbers = wizard.field(QLatin1String("exportLineNumbers")).toBool(); + bool exportColumnNames = wizard.field(QStringLiteral("exportColumnNames")).toBool(); + bool exportLineNumbers = wizard.field(QStringLiteral("exportLineNumbers")).toBool(); Options opt = NoOptions; if (exportColumnNames) opt |= ExportColumnNames; if (exportLineNumbers) opt |= ExportLineNumbers; - bool quoteStrings = wizard.field(QLatin1String("checkQuoteStrings")).toBool(); - bool quoteNumbers = wizard.field(QLatin1String("checkQuoteNumbers")).toBool(); + bool quoteStrings = wizard.field(QStringLiteral("checkQuoteStrings")).toBool(); + bool quoteNumbers = wizard.field(QStringLiteral("checkQuoteNumbers")).toBool(); - QChar stringsQuoteChar = (quoteStrings) ? wizard.field(QLatin1String("quoteStringsChar")).toString().at(0) : QLatin1Char('\0'); - QChar numbersQuoteChar = (quoteNumbers) ? wizard.field(QLatin1String("quoteNumbersChar")).toString().at(0) : QLatin1Char('\0'); + QChar stringsQuoteChar = (quoteStrings) ? wizard.field(QStringLiteral("quoteStringsChar")).toString().at(0) : QLatin1Char('\0'); + QChar numbersQuoteChar = (quoteNumbers) ? wizard.field(QStringLiteral("quoteNumbersChar")).toString().at(0) : QLatin1Char('\0'); - QString fieldDelimiter = wizard.field(QLatin1String("fieldDelimiter")).toString(); + QString fieldDelimiter = wizard.field(QStringLiteral("fieldDelimiter")).toString(); if (outputInDocument) { KTextEditor::MainWindow *mw = KTextEditor::Editor::instance()->application()->activeMainWindow(); KTextEditor::View *kv = mw->activeView(); if (!kv) return; QString text; QTextStream stream(&text); exportData(stream, stringsQuoteChar, numbersQuoteChar, fieldDelimiter, opt); kv->insertText(text); kv->setFocus(); } else if (outputInClipboard) { QString text; QTextStream stream(&text); exportData(stream, stringsQuoteChar, numbersQuoteChar, fieldDelimiter, opt); QApplication::clipboard()->setText(text); } else if (outputInFile) { - QString url = wizard.field(QLatin1String ("outFileUrl")).toString(); + QString url = wizard.field(QStringLiteral ("outFileUrl")).toString(); QFile data(url); if (data.open(QFile::WriteOnly | QFile::Truncate)) { QTextStream stream(&data); exportData(stream, stringsQuoteChar, numbersQuoteChar, fieldDelimiter, opt); stream.flush(); } else { KMessageBox::error(this, xi18nc("@info", "Unable to open file %1", url)); } } } void DataOutputWidget::exportData(QTextStream &stream, const QChar stringsQuoteChar, const QChar numbersQuoteChar, - const QString fieldDelimiter, + const QString &fieldDelimiter, const Options opt) { QItemSelectionModel *selectionModel = m_view->selectionModel(); if (!selectionModel->hasSelection()) return; QString fixedFieldDelimiter = fieldDelimiter; /// FIXME: ugly workaround... fixedFieldDelimiter = fixedFieldDelimiter.replace(QLatin1String ("\\t"), QLatin1String ("\t")); fixedFieldDelimiter = fixedFieldDelimiter.replace(QLatin1String ("\\r"), QLatin1String ("\r")); fixedFieldDelimiter = fixedFieldDelimiter.replace(QLatin1String ("\\n"), QLatin1String ("\n")); QTime t; t.start(); QSet columns; QSet rows; QHash,QString> snapshot; const QModelIndexList selectedIndexes = selectionModel->selectedIndexes(); snapshot.reserve(selectedIndexes.count()); foreach (const QModelIndex& index, selectedIndexes) { const QVariant data = index.data(Qt::UserRole); const int col = index.column(); const int row = index.row(); if (!columns.contains(col)) columns.insert(col); if (!rows.contains(row)) rows.insert(row); if (data.type() < 7) // is numeric or boolean { if (numbersQuoteChar != QLatin1Char ('\0')) snapshot[qMakePair(row,col)] = numbersQuoteChar + data.toString() + numbersQuoteChar; else snapshot[qMakePair(row,col)] = data.toString(); } else { if (stringsQuoteChar != QLatin1Char ('\0')) snapshot[qMakePair(row,col)] = stringsQuoteChar + data.toString() + stringsQuoteChar; else snapshot[qMakePair(row,col)] = data.toString(); } } if (opt.testFlag(ExportColumnNames)) { if (opt.testFlag(ExportLineNumbers)) stream << fixedFieldDelimiter; QSetIterator j(columns); while (j.hasNext()) { const QVariant data = m_model->headerData(j.next(), Qt::Horizontal); if (stringsQuoteChar != QLatin1Char ('\0')) stream << stringsQuoteChar + data.toString() + stringsQuoteChar; else stream << data.toString(); if (j.hasNext()) stream << fixedFieldDelimiter; } stream << "\n"; } foreach(const int row, rows) { if (opt.testFlag(ExportLineNumbers)) stream << row + 1 << fixedFieldDelimiter; QSetIterator j(columns); while (j.hasNext()) { stream << snapshot.value(qMakePair(row,j.next())); if (j.hasNext()) stream << fixedFieldDelimiter; } stream << "\n"; } qDebug() << "Export in" << t.elapsed() << "msecs"; } diff --git a/addons/katesql/dataoutputwidget.h b/addons/katesql/dataoutputwidget.h index 40a303b25..a69b3d5f6 100644 --- a/addons/katesql/dataoutputwidget.h +++ b/addons/katesql/dataoutputwidget.h @@ -1,77 +1,77 @@ /* 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 DATAOUTPUTWIDGET_H #define DATAOUTPUTWIDGET_H class QTextStream; class QVBoxLayout; class QSqlQuery; class DataOutputModel; class DataOutputView; #include class DataOutputWidget : public QWidget { Q_OBJECT public: enum Option { NoOptions = 0x0, ExportColumnNames = 0x1, ExportLineNumbers = 0x2 }; Q_DECLARE_FLAGS(Options, Option) DataOutputWidget(QWidget *parent); ~DataOutputWidget() override; void exportData(QTextStream &stream, const QChar stringsQuoteChar = QLatin1Char ('\0'), const QChar numbersQuoteChar = QLatin1Char ('\0'), - const QString fieldDelimiter = QLatin1String ("\t"), + const QString &fieldDelimiter = QStringLiteral ("\t"), const Options opt = NoOptions); DataOutputModel *model() const { return m_model; } DataOutputView *view() const { return m_view; } public Q_SLOTS: void showQueryResultSets(QSqlQuery &query); void resizeColumnsToContents(); void resizeRowsToContents(); void clearResults(); void slotToggleLocale(); void slotCopySelected(); void slotExport(); private: QVBoxLayout *m_dataLayout; /// TODO: manage multiple views for query with multiple resultsets DataOutputModel *m_model; DataOutputView *m_view; bool m_isEmpty; }; Q_DECLARE_OPERATORS_FOR_FLAGS(DataOutputWidget::Options) #endif // DATAOUTPUTWIDGET_H diff --git a/addons/katesql/exportwizard.cpp b/addons/katesql/exportwizard.cpp index 2cac9cc7e..0b2108b03 100644 --- a/addons/katesql/exportwizard.cpp +++ b/addons/katesql/exportwizard.cpp @@ -1,207 +1,207 @@ /* Copyright (C) 2010 Marco Mentasti This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "exportwizard.h" #include "dataoutputwidget.h" #include #include #include #include #include #include #include #include #include #include //BEGIN ExportWizard ExportWizard::ExportWizard(QWidget *parent) : QWizard(parent) { setWindowTitle(i18nc("@title:window", "Export Wizard")); addPage(new ExportOutputPage(this)); addPage(new ExportFormatPage(this)); } ExportWizard::~ExportWizard() { } //END ExportWizard //BEGIN ExportOutputPage ExportOutputPage::ExportOutputPage(QWidget *parent) : QWizardPage(parent) { setTitle(i18nc("@title Wizard page title", "Output Target")); setSubTitle(i18nc("@title Wizard page subtitle", "Select the output target.")); QVBoxLayout *layout = new QVBoxLayout(); documentRadioButton = new QRadioButton(i18nc("@option:radio Output target", "Current document"), this); clipboardRadioButton = new QRadioButton(i18nc("@option:radio Output target", "Clipboard"), this); fileRadioButton = new QRadioButton(i18nc("@option:radio Output target", "File"), this); QHBoxLayout *fileLayout = new QHBoxLayout(); fileLayout->setContentsMargins(20, 0, 0, 0); fileUrl = new KUrlRequester(this); fileUrl->setMode(KFile::File); fileUrl->setFilter(i18n("*.csv|Comma Separated Values\n*|All files")); fileLayout->addWidget(fileUrl); layout->addWidget(documentRadioButton); layout->addWidget(clipboardRadioButton); layout->addWidget(fileRadioButton); layout->addLayout(fileLayout); setLayout(layout); - registerField(QLatin1String("outDocument"), documentRadioButton); - registerField(QLatin1String("outClipboard"), clipboardRadioButton); - registerField(QLatin1String("outFile"), fileRadioButton); - registerField(QLatin1String("outFileUrl"), fileUrl, "text"); + registerField(QStringLiteral("outDocument"), documentRadioButton); + registerField(QStringLiteral("outClipboard"), clipboardRadioButton); + registerField(QStringLiteral("outFile"), fileRadioButton); + registerField(QStringLiteral("outFileUrl"), fileUrl, "text"); connect(fileRadioButton, &QRadioButton::toggled, fileUrl, &KUrlRequester::setEnabled); } void ExportOutputPage::initializePage() { documentRadioButton->setChecked(true); fileUrl->setEnabled(false); } bool ExportOutputPage::validatePage() { if (fileRadioButton->isChecked() && fileUrl->text().isEmpty()) { fileUrl->setFocus(); return false; } /// TODO: check url validity return true; } //END ExportOutputPage //BEGIN ExportFormatPage ExportFormatPage::ExportFormatPage(QWidget *parent) : QWizardPage(parent) { setTitle(i18nc("@title Wizard page title", "Fields Format")); setSubTitle(i18nc("@title Wizard page subtitle", "Select fields format.\nClick on \"Finish\" button to export data.")); QVBoxLayout *layout = new QVBoxLayout(); QGroupBox *headersGroupBox = new QGroupBox(i18nc("@title:group", "Headers"), this); QVBoxLayout *headersLayout = new QVBoxLayout(); exportColumnNamesCheckBox = new QCheckBox(i18nc("@option:check", "Export column names"), headersGroupBox); exportLineNumbersCheckBox = new QCheckBox(i18nc("@option:check", "Export line numbers"), headersGroupBox); headersLayout->addWidget(exportColumnNamesCheckBox); headersLayout->addWidget(exportLineNumbersCheckBox); headersGroupBox->setLayout(headersLayout); QGroupBox *quoteGroupBox = new QGroupBox(i18nc("@title:group", "Quotes"), this); QGridLayout *quoteLayout = new QGridLayout(); quoteStringsCheckBox = new QCheckBox(i18nc("@option:check", "Quote strings"), quoteGroupBox); quoteNumbersCheckBox = new QCheckBox(i18nc("@option:check", "Quote numbers"), quoteGroupBox); quoteStringsLine = new KLineEdit(quoteGroupBox); quoteNumbersLine = new KLineEdit(quoteGroupBox); quoteStringsLine->setMaxLength(1); quoteNumbersLine->setMaxLength(1); quoteLayout->addWidget(quoteStringsCheckBox, 0, 0, Qt::AlignLeft | Qt::AlignVCenter); quoteLayout->addWidget(new QLabel(i18nc("@label:textbox", "Character:")), 0, 1, Qt::AlignRight | Qt::AlignVCenter); quoteLayout->addWidget(quoteStringsLine, 0, 2, Qt::AlignRight | Qt::AlignVCenter); quoteLayout->addWidget(quoteNumbersCheckBox, 1, 0, Qt::AlignLeft | Qt::AlignVCenter); quoteLayout->addWidget(new QLabel(i18nc("@label:textbox", "Character:")), 1, 1, Qt::AlignRight | Qt::AlignVCenter); quoteLayout->addWidget(quoteNumbersLine, 1, 2, Qt::AlignRight | Qt::AlignVCenter); quoteLayout->setColumnStretch(1, 1); quoteGroupBox->setLayout(quoteLayout); QGroupBox *delimitersGroupBox = new QGroupBox(i18nc("@title:group", "Delimiters"), this); QFormLayout *delimitersLayout = new QFormLayout(); fieldDelimiterLine = new KLineEdit(delimitersGroupBox); fieldDelimiterLine->setMaxLength(3); delimitersLayout->addRow(i18nc("@label:textbox", "Field delimiter:"), fieldDelimiterLine); delimitersGroupBox->setLayout(delimitersLayout); layout->addWidget(headersGroupBox); layout->addWidget(quoteGroupBox); layout->addWidget(delimitersGroupBox); setLayout(layout); - registerField(QLatin1String("exportColumnNames"), exportColumnNamesCheckBox); - registerField(QLatin1String("exportLineNumbers"), exportLineNumbersCheckBox); - registerField(QLatin1String("checkQuoteStrings"), quoteStringsCheckBox); - registerField(QLatin1String("checkQuoteNumbers"), quoteNumbersCheckBox); - registerField(QLatin1String("quoteStringsChar"), quoteStringsLine); - registerField(QLatin1String("quoteNumbersChar"), quoteNumbersLine); - registerField(QLatin1String("fieldDelimiter*"), fieldDelimiterLine); + registerField(QStringLiteral("exportColumnNames"), exportColumnNamesCheckBox); + registerField(QStringLiteral("exportLineNumbers"), exportLineNumbersCheckBox); + registerField(QStringLiteral("checkQuoteStrings"), quoteStringsCheckBox); + registerField(QStringLiteral("checkQuoteNumbers"), quoteNumbersCheckBox); + registerField(QStringLiteral("quoteStringsChar"), quoteStringsLine); + registerField(QStringLiteral("quoteNumbersChar"), quoteNumbersLine); + registerField(QStringLiteral("fieldDelimiter*"), fieldDelimiterLine); connect(quoteStringsCheckBox, &QCheckBox::toggled, quoteStringsLine, &KLineEdit::setEnabled); connect(quoteNumbersCheckBox, &QCheckBox::toggled, quoteNumbersLine, &KLineEdit::setEnabled); } void ExportFormatPage::initializePage() { exportColumnNamesCheckBox->setChecked(true); exportLineNumbersCheckBox->setChecked(false); quoteStringsCheckBox->setChecked(false); quoteNumbersCheckBox->setChecked(false); quoteStringsLine->setEnabled(false); quoteNumbersLine->setEnabled(false); - quoteStringsLine->setText(QLatin1String("\"")); - quoteNumbersLine->setText(QLatin1String("\"")); - fieldDelimiterLine->setText(QLatin1String("\\t")); + quoteStringsLine->setText(QStringLiteral("\"")); + quoteNumbersLine->setText(QStringLiteral("\"")); + fieldDelimiterLine->setText(QStringLiteral("\\t")); } bool ExportFormatPage::validatePage() { if ((quoteStringsCheckBox->isChecked() && quoteStringsLine->text().isEmpty()) || (quoteNumbersCheckBox->isChecked() && quoteNumbersLine->text().isEmpty())) return false; if (fieldDelimiterLine->text().isEmpty()) return false; return true; } //END ExportFormatPage diff --git a/addons/katesql/exportwizard.h b/addons/katesql/exportwizard.h index 207d616b8..907c886aa 100644 --- a/addons/katesql/exportwizard.h +++ b/addons/katesql/exportwizard.h @@ -1,72 +1,73 @@ /* 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 { + Q_OBJECT public: - ExportWizard(QWidget *parent); + explicit ExportWizard(QWidget *parent); ~ExportWizard() override; }; class ExportOutputPage : public QWizardPage { public: - ExportOutputPage(QWidget *parent=nullptr); + explicit ExportOutputPage(QWidget *parent=nullptr); void initializePage() override; bool validatePage() override; private: QRadioButton *documentRadioButton; QRadioButton *clipboardRadioButton; QRadioButton *fileRadioButton; KUrlRequester *fileUrl; }; class ExportFormatPage : public QWizardPage { public: - ExportFormatPage(QWidget *parent=nullptr); + explicit ExportFormatPage(QWidget *parent=nullptr); void initializePage() override; bool validatePage() override; private: QCheckBox *exportColumnNamesCheckBox; QCheckBox *exportLineNumbersCheckBox; QCheckBox *quoteStringsCheckBox; QCheckBox *quoteNumbersCheckBox; KLineEdit *quoteStringsLine; KLineEdit *quoteNumbersLine; KLineEdit *fieldDelimiterLine; }; #endif // EXPORTWIZARD_H diff --git a/addons/katesql/katesqlview.cpp b/addons/katesql/katesqlview.cpp index 15fda95d0..5c81f05b4 100644 --- a/addons/katesql/katesqlview.cpp +++ b/addons/katesql/katesqlview.cpp @@ -1,392 +1,392 @@ /* Copyright (C) 2010 Marco Mentasti This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "katesqlview.h" #include "katesqlplugin.h" #include "sqlmanager.h" #include "connectionmodel.h" #include "textoutputwidget.h" #include "dataoutputwidget.h" #include "dataoutputmodel.h" #include "dataoutputview.h" #include "schemawidget.h" #include "schemabrowserwidget.h" #include "connectionwizard.h" #include "outputwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KateSQLView::KateSQLView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mw) : QObject (mw) , KXMLGUIClient() , m_manager (new SQLManager(this)) , m_mainWindow (mw) { - KXMLGUIClient::setComponentName (QLatin1String("katesql"), i18n ("Kate SQL Plugin")); - setXMLFile( QLatin1String("ui.rc") ); + KXMLGUIClient::setComponentName (QStringLiteral("katesql"), i18n ("Kate SQL Plugin")); + setXMLFile( QStringLiteral("ui.rc") ); - m_outputToolView = mw->createToolView(plugin, QLatin1String ("kate_private_plugin_katesql_output"), + m_outputToolView = mw->createToolView(plugin, QStringLiteral ("kate_private_plugin_katesql_output"), KTextEditor::MainWindow::Bottom, - QIcon::fromTheme (QLatin1String ("view-form-table")), + QIcon::fromTheme (QStringLiteral ("view-form-table")), i18nc("@title:window", "SQL Results") ); - m_schemaBrowserToolView = mw->createToolView(plugin, QLatin1String ("kate_private_plugin_katesql_schemabrowser"), + m_schemaBrowserToolView = mw->createToolView(plugin, QStringLiteral ("kate_private_plugin_katesql_schemabrowser"), KTextEditor::MainWindow::Left, - QIcon::fromTheme (QLatin1String ("view-list-tree")), + QIcon::fromTheme (QStringLiteral ("view-list-tree")), i18nc("@title:window", "SQL Schema Browser") ); m_outputWidget = new KateSQLOutputWidget(m_outputToolView); m_schemaBrowserWidget = new SchemaBrowserWidget(m_schemaBrowserToolView, m_manager); m_connectionsComboBox = new KComboBox(false); m_connectionsComboBox->setEditable(false); m_connectionsComboBox->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); m_connectionsComboBox->setModel(m_manager->connectionModel()); setupActions(); m_mainWindow->guiFactory()->addClient(this); - QMenu *sqlMenu = (QMenu*)factory()->container(QLatin1String ("SQL"), this); + QMenu *sqlMenu = (QMenu*)factory()->container(QStringLiteral ("SQL"), this); m_connectionsGroup = new QActionGroup(sqlMenu); m_connectionsGroup->setExclusive(true); connect(sqlMenu, &QMenu::aboutToShow, this, &KateSQLView::slotSQLMenuAboutToShow); connect(m_connectionsGroup, &QActionGroup::triggered, this, &KateSQLView::slotConnectionSelectedFromMenu); connect(m_manager, &SQLManager::error, this, &KateSQLView::slotError); connect(m_manager, &SQLManager::success, this, &KateSQLView::slotSuccess); connect(m_manager, &SQLManager::queryActivated, this, &KateSQLView::slotQueryActivated); connect(m_manager, &SQLManager::connectionCreated, this, &KateSQLView::slotConnectionCreated); connect(m_manager, &SQLManager::connectionAboutToBeClosed, this, &KateSQLView::slotConnectionAboutToBeClosed); connect(m_connectionsComboBox, static_cast(&KComboBox::currentIndexChanged), this, &KateSQLView::slotConnectionChanged); - stateChanged(QLatin1String ("has_connection_selected"), KXMLGUIClient::StateReverse); + stateChanged(QStringLiteral ("has_connection_selected"), KXMLGUIClient::StateReverse); } KateSQLView::~KateSQLView() { m_mainWindow->guiFactory()->removeClient( this ); delete m_outputToolView; delete m_schemaBrowserToolView; delete m_manager; } void KateSQLView::setupActions() { QAction* action; KActionCollection* collection = actionCollection(); - action = collection->addAction(QLatin1String ("connection_create")); + action = collection->addAction(QStringLiteral ("connection_create")); action->setText( i18nc("@action:inmenu", "Add connection...") ); - action->setIcon( QIcon::fromTheme (QLatin1String ("list-add")) ); + action->setIcon( QIcon::fromTheme (QStringLiteral ("list-add")) ); connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionCreate); - action = collection->addAction(QLatin1String ("connection_remove")); + action = collection->addAction(QStringLiteral ("connection_remove")); action->setText( i18nc("@action:inmenu", "Remove connection") ); - action->setIcon( QIcon::fromTheme (QLatin1String ("list-remove")) ); + action->setIcon( QIcon::fromTheme (QStringLiteral ("list-remove")) ); connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionRemove); - action = collection->addAction(QLatin1String ("connection_edit")); + action = collection->addAction(QStringLiteral ("connection_edit")); action->setText( i18nc("@action:inmenu", "Edit connection...") ); - action->setIcon( QIcon::fromTheme (QLatin1String ("configure")) ); + action->setIcon( QIcon::fromTheme (QStringLiteral ("configure")) ); connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionEdit); - action = collection->addAction(QLatin1String ("connection_reconnect")); + action = collection->addAction(QStringLiteral ("connection_reconnect")); action->setText( i18nc("@action:inmenu", "Reconnect") ); - action->setIcon( QIcon::fromTheme (QLatin1String ("view-refresh")) ); + action->setIcon( QIcon::fromTheme (QStringLiteral ("view-refresh")) ); connect(action, &QAction::triggered, this, &KateSQLView::slotConnectionReconnect); QWidgetAction *wa = new QWidgetAction(this); - collection->addAction(QLatin1String ("connection_chooser"), wa); + collection->addAction(QStringLiteral ("connection_chooser"), wa); wa->setText( i18nc("@action:intoolbar", "Connection") ); wa->setDefaultWidget(m_connectionsComboBox); - action = collection->addAction(QLatin1String ("query_run")); + action = collection->addAction(QStringLiteral ("query_run")); action->setText( i18nc("@action:inmenu", "Run query") ); - action->setIcon( QIcon::fromTheme (QLatin1String ("quickopen")) ); + action->setIcon( QIcon::fromTheme (QStringLiteral ("quickopen")) ); collection->setDefaultShortcut(action, QKeySequence(Qt::CTRL + Qt::Key_E) ); connect(action, &QAction::triggered, this, &KateSQLView::slotRunQuery); /// TODO: stop sql query // action = collection->addAction("sql_stop"); // action->setText( i18n("Stop query") ); // action->setIcon( KIcon("process-stop") ); // action->setShortcut( QKeySequence(Qt::ALT + Qt::Key_F5) ); // connect( action , SIGNAL(triggered()) , this , SLOT(stopQuery())); } void KateSQLView::slotSQLMenuAboutToShow() { qDeleteAll( m_connectionsGroup->actions() ); - QMenu *sqlMenu = (QMenu*)factory()->container(QLatin1String ("SQL"), this); + QMenu *sqlMenu = (QMenu*)factory()->container(QStringLiteral ("SQL"), this); QAction *before = action("query_run"); QAbstractItemModel *model = m_manager->connectionModel(); int rows = model->rowCount(QModelIndex()); for (int row = 0; row < rows; row++) { QModelIndex index = model->index(row, 0, QModelIndex()); Q_ASSERT(index.isValid()); QString connectionName = index.data(Qt::DisplayRole).toString(); QAction *act = new QAction(connectionName, m_connectionsGroup); act->setCheckable(true); if (m_connectionsComboBox->currentText() == connectionName) act->setChecked(true); sqlMenu->insertAction(before, act); } sqlMenu->insertSeparator(before); } void KateSQLView::slotConnectionSelectedFromMenu(QAction *action) { m_connectionsComboBox->setCurrentItem(action->text()); } void KateSQLView::slotConnectionChanged(const QString &connection) { - stateChanged(QLatin1String ("has_connection_selected"), (connection.isEmpty()) ? KXMLGUIClient::StateReverse : KXMLGUIClient::StateNoReverse); + stateChanged(QStringLiteral ("has_connection_selected"), (connection.isEmpty()) ? KXMLGUIClient::StateReverse : KXMLGUIClient::StateNoReverse); m_schemaBrowserWidget->schemaWidget()->buildTree(connection); } void KateSQLView::slotGlobalSettingsChanged() { m_outputWidget->dataOutputWidget()->model()->readConfig(); } void KateSQLView::readSessionConfig (KConfigBase* config, const QString& groupPrefix) { KConfigGroup globalConfig(KSharedConfig::openConfig(), "KateSQLPlugin"); bool saveConnections = globalConfig.readEntry("SaveConnections", true); if (!saveConnections) return; KConfigGroup group(config, groupPrefix + QLatin1String (":connections")); m_manager->loadConnections(&group); QString lastConnection = group.readEntry("LastUsed"); if (m_connectionsComboBox->contains(lastConnection)) m_connectionsComboBox->setCurrentItem(lastConnection); } void KateSQLView::writeSessionConfig (KConfigBase* config, const QString& groupPrefix) { KConfigGroup group(config, groupPrefix + QLatin1String (":connections")); group.deleteGroup(); KConfigGroup globalConfig(KSharedConfig::openConfig(), "KateSQLPlugin"); bool saveConnections = globalConfig.readEntry("SaveConnections", true); if (saveConnections) { m_manager->saveConnections(&group); group.writeEntry("LastUsed", m_connectionsComboBox->currentText()); } config->sync(); } void KateSQLView::slotConnectionCreate() { Connection c; ConnectionWizard wizard(m_manager, &c); if (wizard.exec() != QDialog::Accepted) return; for (int i = 1; QSqlDatabase::contains(c.name); i++) - c.name = QString::fromLatin1("%1 (%2)").arg(c.name).arg(i); + c.name = QStringLiteral("%1 (%2)").arg(c.name).arg(i); m_manager->createConnection(c); if (m_manager->storeCredentials(c) != 0) qDebug() << "Connection credentials not saved"; } void KateSQLView::slotConnectionEdit() { int i = m_connectionsComboBox->currentIndex(); if (i == -1) return; ConnectionModel *model = m_manager->connectionModel(); Connection c = model->data(model->index(i), Qt::UserRole).value(); QString previousName = c.name; ConnectionWizard wizard(m_manager, &c); if (wizard.exec() != QDialog::Accepted) return; m_manager->removeConnection(previousName); m_manager->createConnection(c); if (m_manager->storeCredentials(c) != 0) qDebug() << "Connection credentials not saved"; } void KateSQLView::slotConnectionRemove() { QString connection = m_connectionsComboBox->currentText(); if (!connection.isEmpty()) m_manager->removeConnection(connection); } void KateSQLView::slotConnectionReconnect() { QString connection = m_connectionsComboBox->currentText(); if (!connection.isEmpty()) m_manager->reopenConnection(connection); } void KateSQLView::slotConnectionAboutToBeClosed (const QString& name) { /// must delete the QSqlQuery object inside the model before closing connection if (name == m_currentResultsetConnection) m_outputWidget->dataOutputWidget()->clearResults(); } void KateSQLView::slotRunQuery() { /// TODO: /// bind parameters dialog? QString connection = m_connectionsComboBox->currentText(); if (connection.isEmpty()) { slotConnectionCreate(); return; } KTextEditor::View *view = m_mainWindow->activeView(); if (!view) return; QString text = (view->selection()) ? view->selectionText() : view->document()->text(); text = text.trimmed(); if (text.isEmpty()) return; m_manager->runQuery(text, connection); } void KateSQLView::slotError(const QString &message) { m_outputWidget->textOutputWidget()->showErrorMessage(message); m_outputWidget->setCurrentWidget(m_outputWidget->textOutputWidget()); m_mainWindow->showToolView(m_outputToolView); } void KateSQLView::slotSuccess(const QString &message) { m_outputWidget->textOutputWidget()->showSuccessMessage(message); m_outputWidget->setCurrentWidget(m_outputWidget->textOutputWidget()); m_mainWindow->showToolView(m_outputToolView); } void KateSQLView::slotQueryActivated(QSqlQuery &query, const QString &connection) { if (query.isSelect()) { m_currentResultsetConnection = connection; m_outputWidget->dataOutputWidget()->showQueryResultSets(query); m_outputWidget->setCurrentWidget(m_outputWidget->dataOutputWidget()); m_mainWindow->showToolView(m_outputToolView); } } void KateSQLView::slotConnectionCreated(const QString &name) { m_connectionsComboBox->setCurrentItem(name); m_schemaBrowserWidget->schemaWidget()->buildTree(name); } //END KateSQLView diff --git a/addons/katesql/outputstylewidget.cpp b/addons/katesql/outputstylewidget.cpp index 181a4a24f..9cb3b925c 100644 --- a/addons/katesql/outputstylewidget.cpp +++ b/addons/katesql/outputstylewidget.cpp @@ -1,217 +1,217 @@ /* Copyright (C) 2010 Marco Mentasti This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "outputstylewidget.h" #include #include #include #include #include #include #include #include #include #include #include #include OutputStyleWidget::OutputStyleWidget(QWidget *parent) : QTreeWidget(parent) { setColumnCount(7); setRootIsDecorated(false); QStringList headerLabels; headerLabels << i18nc("@title:column", "Context") << QString() << QString() << QString() << QString() << i18nc("@title:column", "Text Color") << i18nc("@title:column", "Background Color"); setHeaderLabels(headerLabels); - headerItem()->setIcon(1, QIcon::fromTheme(QLatin1String("format-text-bold"))); - headerItem()->setIcon(2, QIcon::fromTheme(QLatin1String("format-text-italic"))); - headerItem()->setIcon(3, QIcon::fromTheme(QLatin1String("format-text-underline"))); - headerItem()->setIcon(4, QIcon::fromTheme(QLatin1String("format-text-strikethrough"))); - - addContext(QLatin1String("text"), i18nc("@item:intable", "Text")); - addContext(QLatin1String("number"), i18nc("@item:intable", "Number")); - addContext(QLatin1String("bool"), i18nc("@item:intable", "Bool")); - addContext(QLatin1String("datetime"), i18nc("@item:intable", "Date & Time")); - addContext(QLatin1String("null"), i18nc("@item:intable", "NULL")); - addContext(QLatin1String("blob"), i18nc("@item:intable", "BLOB")); + headerItem()->setIcon(1, QIcon::fromTheme(QStringLiteral("format-text-bold"))); + headerItem()->setIcon(2, QIcon::fromTheme(QStringLiteral("format-text-italic"))); + headerItem()->setIcon(3, QIcon::fromTheme(QStringLiteral("format-text-underline"))); + headerItem()->setIcon(4, QIcon::fromTheme(QStringLiteral("format-text-strikethrough"))); + + addContext(QStringLiteral("text"), i18nc("@item:intable", "Text")); + addContext(QStringLiteral("number"), i18nc("@item:intable", "Number")); + addContext(QStringLiteral("bool"), i18nc("@item:intable", "Bool")); + addContext(QStringLiteral("datetime"), i18nc("@item:intable", "Date & Time")); + addContext(QStringLiteral("null"), i18nc("@item:intable", "NULL")); + addContext(QStringLiteral("blob"), i18nc("@item:intable", "BLOB")); for (int i = 0; i < columnCount(); ++i) resizeColumnToContents(i); updatePreviews(); } OutputStyleWidget::~OutputStyleWidget() { } QTreeWidgetItem* OutputStyleWidget::addContext(const QString &key, const QString &name) { QTreeWidgetItem *item = new QTreeWidgetItem(this); item->setText(0, name); item->setData(0, Qt::UserRole, key); QCheckBox *boldCheckBox = new QCheckBox(this); QCheckBox *italicCheckBox = new QCheckBox(this); QCheckBox *underlineCheckBox = new QCheckBox(this); QCheckBox *strikeOutCheckBox = new QCheckBox(this); KColorButton *foregroundColorButton = new KColorButton(this); KColorButton *backgroundColorButton = new KColorButton(this); const KColorScheme scheme(QPalette::Active, KColorScheme::View); foregroundColorButton->setDefaultColor(scheme.foreground().color()); backgroundColorButton->setDefaultColor(scheme.background().color()); setItemWidget(item, 1, boldCheckBox); setItemWidget(item, 2, italicCheckBox); setItemWidget(item, 3, underlineCheckBox); setItemWidget(item, 4, strikeOutCheckBox); setItemWidget(item, 5, foregroundColorButton); setItemWidget(item, 6, backgroundColorButton); readConfig(item); connect(boldCheckBox, &QCheckBox::toggled, this, &OutputStyleWidget::slotChanged); connect(italicCheckBox, &QCheckBox::toggled, this, &OutputStyleWidget::slotChanged); connect(underlineCheckBox, &QCheckBox::toggled, this, &OutputStyleWidget::slotChanged); connect(strikeOutCheckBox, &QCheckBox::toggled, this, &OutputStyleWidget::slotChanged); connect(foregroundColorButton, &KColorButton::changed, this, &OutputStyleWidget::slotChanged); connect(backgroundColorButton, &KColorButton::changed, this, &OutputStyleWidget::slotChanged); return item; } void OutputStyleWidget::readConfig(QTreeWidgetItem *item) { KConfigGroup config(KSharedConfig::openConfig(), "KateSQLPlugin"); KConfigGroup g = config.group("OutputCustomization").group(item->data(0, Qt::UserRole).toString()); QCheckBox *boldCheckBox = static_cast(itemWidget(item, 1)); QCheckBox *italicCheckBox = static_cast(itemWidget(item, 2)); QCheckBox *underlineCheckBox = static_cast(itemWidget(item, 3)); QCheckBox *strikeOutCheckBox = static_cast(itemWidget(item, 4)); KColorButton *foregroundColorButton = static_cast(itemWidget(item, 5)); KColorButton *backgroundColorButton = static_cast(itemWidget(item, 6)); const QFont font = g.readEntry("font", QFontDatabase::systemFont(QFontDatabase::GeneralFont)); boldCheckBox->setChecked(font.bold()); italicCheckBox->setChecked(font.italic()); underlineCheckBox->setChecked(font.underline()); strikeOutCheckBox->setChecked(font.strikeOut()); foregroundColorButton->setColor(g.readEntry("foregroundColor", foregroundColorButton->defaultColor())); backgroundColorButton->setColor(g.readEntry("backgroundColor", backgroundColorButton->defaultColor())); } void OutputStyleWidget::writeConfig(QTreeWidgetItem *item) { KConfigGroup config(KSharedConfig::openConfig(), "KateSQLPlugin"); KConfigGroup g = config.group("OutputCustomization").group(item->data(0, Qt::UserRole).toString()); QCheckBox *boldCheckBox = static_cast(itemWidget(item, 1)); QCheckBox *italicCheckBox = static_cast(itemWidget(item, 2)); QCheckBox *underlineCheckBox = static_cast(itemWidget(item, 3)); QCheckBox *strikeOutCheckBox = static_cast(itemWidget(item, 4)); KColorButton *foregroundColorButton = static_cast(itemWidget(item, 5)); KColorButton *backgroundColorButton = static_cast(itemWidget(item, 6)); QFont f(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); f.setBold(boldCheckBox->isChecked()); f.setItalic(italicCheckBox->isChecked()); f.setUnderline(underlineCheckBox->isChecked()); f.setStrikeOut(strikeOutCheckBox->isChecked()); g.writeEntry("font", f); g.writeEntry("foregroundColor", foregroundColorButton->color()); g.writeEntry("backgroundColor", backgroundColorButton->color()); } void OutputStyleWidget::readConfig() { QTreeWidgetItem *root = invisibleRootItem(); for (int i = 0; i < root->childCount(); ++i) readConfig(root->child(i)); } void OutputStyleWidget::writeConfig() { KConfigGroup config(KSharedConfig::openConfig(), "KateSQLPlugin"); config.deleteGroup("OutputCustomization"); QTreeWidgetItem *root = invisibleRootItem(); for (int i = 0; i < root->childCount(); ++i) writeConfig(root->child(i)); } void OutputStyleWidget::updatePreviews() { QTreeWidgetItem *root = invisibleRootItem(); for (int i = 0; i < root->childCount(); ++i) { QTreeWidgetItem *item = root->child(i); const QCheckBox *boldCheckBox = static_cast(itemWidget(item, 1)); const QCheckBox *italicCheckBox = static_cast(itemWidget(item, 2)); const QCheckBox *underlineCheckBox = static_cast(itemWidget(item, 3)); const QCheckBox *strikeOutCheckBox = static_cast(itemWidget(item, 4)); const KColorButton *foregroundColorButton = static_cast(itemWidget(item, 5)); const KColorButton *backgroundColorButton = static_cast(itemWidget(item, 6)); QFont f(QFontDatabase::systemFont(QFontDatabase::GeneralFont)); f.setBold(boldCheckBox->isChecked()); f.setItalic(italicCheckBox->isChecked()); f.setUnderline(underlineCheckBox->isChecked()); f.setStrikeOut(strikeOutCheckBox->isChecked()); item->setFont(0, f); item->setForeground(0, foregroundColorButton->color()); item->setBackground(0, backgroundColorButton->color()); } } void OutputStyleWidget::slotChanged() { updatePreviews(); emit changed(); } diff --git a/addons/katesql/outputwidget.cpp b/addons/katesql/outputwidget.cpp index b2901138d..69a07babb 100644 --- a/addons/katesql/outputwidget.cpp +++ b/addons/katesql/outputwidget.cpp @@ -1,42 +1,42 @@ /* 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 "outputwidget.h" #include "dataoutputwidget.h" #include "textoutputwidget.h" #include "klocalizedstring.h" KateSQLOutputWidget::KateSQLOutputWidget (QWidget *parent) : QTabWidget (parent) { addTab (m_textOutputWidget=new TextOutputWidget (this), - QIcon::fromTheme(QLatin1String("view-list-text")), i18nc("@title:window", "SQL Text Output")); + QIcon::fromTheme(QStringLiteral("view-list-text")), i18nc("@title:window", "SQL Text Output")); addTab (m_dataOutputWidget=new DataOutputWidget(this), - QIcon::fromTheme(QLatin1String("view-form-table")),i18nc("@title:window", "SQL Data Output")); + QIcon::fromTheme(QStringLiteral("view-form-table")),i18nc("@title:window", "SQL Data Output")); } KateSQLOutputWidget::~KateSQLOutputWidget () { } // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/katesql/schemawidget.cpp b/addons/katesql/schemawidget.cpp index 7d6f75407..b22c80f0d 100644 --- a/addons/katesql/schemawidget.cpp +++ b/addons/katesql/schemawidget.cpp @@ -1,413 +1,413 @@ /* Copyright (C) 2010 Marco Mentasti This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "schemawidget.h" #include "sqlmanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include SchemaWidget::SchemaWidget(QWidget *parent, SQLManager *manager) : QTreeWidget(parent) , m_manager(manager) { m_tablesLoaded = false; m_viewsLoaded = false; setHeaderLabels(QStringList() << i18nc("@title:column", "Database schema")); setContextMenuPolicy(Qt::CustomContextMenu); setDragDropMode(QAbstractItemView::DragOnly); setDragEnabled(true); setAcceptDrops(false); connect(this, &SchemaWidget::customContextMenuRequested, this, &SchemaWidget::slotCustomContextMenuRequested); connect(this, &SchemaWidget::itemExpanded, this, &SchemaWidget::slotItemExpanded); } SchemaWidget::~SchemaWidget() { } bool SchemaWidget::isConnectionValidAndOpen() { return m_manager->isValidAndOpen(m_connectionName); } void SchemaWidget::deleteChildren(QTreeWidgetItem *item) { QList items = item->takeChildren(); foreach (QTreeWidgetItem *i, items) delete i; } void SchemaWidget::buildTree(const QString &connection) { m_connectionName = connection; clear(); m_tablesLoaded = false; m_viewsLoaded = false; if (!m_connectionName.isEmpty()) buildDatabase(new QTreeWidgetItem(this)); } void SchemaWidget::refresh() { buildTree(m_connectionName); } void SchemaWidget::buildDatabase(QTreeWidgetItem * databaseItem) { QSqlDatabase db = QSqlDatabase::database(m_connectionName); QString dbname = (db.isValid() ? db.databaseName() : m_connectionName); databaseItem->setText(0, dbname); - databaseItem->setIcon(0, QIcon::fromTheme(QLatin1String("server-database"))); + databaseItem->setIcon(0, QIcon::fromTheme(QStringLiteral("server-database"))); QTreeWidgetItem *tablesItem = new QTreeWidgetItem(databaseItem, TablesFolderType); tablesItem->setText(0, i18nc("@title Folder name", "Tables")); - tablesItem->setIcon(0, QIcon::fromTheme(QLatin1String("folder"))); + tablesItem->setIcon(0, QIcon::fromTheme(QStringLiteral("folder"))); tablesItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); QTreeWidgetItem *viewsItem = new QTreeWidgetItem(databaseItem, ViewsFolderType); viewsItem->setText(0, i18nc("@title Folder name", "Views")); - viewsItem->setIcon(0, QIcon::fromTheme(QLatin1String("folder"))); + viewsItem->setIcon(0, QIcon::fromTheme(QStringLiteral("folder"))); viewsItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); databaseItem->setExpanded(true); } void SchemaWidget::buildTables(QTreeWidgetItem * tablesItem) { if (!isConnectionValidAndOpen()) return; QTreeWidgetItem *systemTablesItem = new QTreeWidgetItem(tablesItem, SystemTablesFolderType); systemTablesItem->setText(0, i18nc("@title Folder name", "System Tables")); - systemTablesItem->setIcon(0, QIcon::fromTheme(QLatin1String("folder"))); + systemTablesItem->setIcon(0, QIcon::fromTheme(QStringLiteral("folder"))); systemTablesItem->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); QSqlDatabase db = QSqlDatabase::database(m_connectionName); QStringList tables = db.tables(QSql::SystemTables); foreach(const QString& table, tables) { QTreeWidgetItem *item = new QTreeWidgetItem(systemTablesItem, SystemTableType); item->setText(0, table); item->setIcon(0, QIcon(QLatin1String(":/katesql/pics/16-actions-sql-table.png"))); item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } tables = db.tables(QSql::Tables); foreach(const QString& table, tables) { QTreeWidgetItem *item = new QTreeWidgetItem(tablesItem, TableType); item->setText(0, table); item->setIcon(0, QIcon(QLatin1String(":/katesql/pics/16-actions-sql-table.png"))); item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } m_tablesLoaded = true; } void SchemaWidget::buildViews(QTreeWidgetItem * viewsItem) { if (!isConnectionValidAndOpen()) return; QSqlDatabase db = QSqlDatabase::database(m_connectionName); const QStringList views = db.tables(QSql::Views); foreach(const QString& view, views) { QTreeWidgetItem *item = new QTreeWidgetItem(viewsItem, ViewType); item->setText(0, view); item->setIcon(0, QIcon(QLatin1String(":/katesql/pics/16-actions-sql-view.png"))); item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); } m_viewsLoaded = true; } void SchemaWidget::buildFields(QTreeWidgetItem * tableItem) { if (!isConnectionValidAndOpen()) return; QSqlDatabase db = QSqlDatabase::database(m_connectionName); QString tableName = tableItem->text(0); QSqlIndex pk = db.primaryIndex(tableName); QSqlRecord rec = db.record(tableName); for (int i = 0; i < rec.count(); ++i) { QSqlField f = rec.field(i); QString fieldName = f.name(); QTreeWidgetItem *item = new QTreeWidgetItem(tableItem, FieldType); item->setText(0, fieldName); if (pk.contains(fieldName)) item->setIcon(0, QIcon(QLatin1String(":/katesql/pics/16-actions-sql-field-pk.png"))); else item->setIcon(0, QIcon(QLatin1String(":/katesql/pics/16-actions-sql-field.png"))); } } void SchemaWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) m_dragStartPosition = event->pos(); QTreeWidget::mousePressEvent(event); } void SchemaWidget::mouseMoveEvent(QMouseEvent *event) { if (!(event->buttons() & Qt::LeftButton)) return; if ((event->pos() - m_dragStartPosition).manhattanLength() < QApplication::startDragDistance()) return; // QTreeWidgetItem *item = currentItem(); QTreeWidgetItem *item = itemAt(event->pos()); if (!item) return; if (item->type() != SchemaWidget::SystemTableType && item->type() != SchemaWidget::TableType && item->type() != SchemaWidget::ViewType && item->type() != SchemaWidget::FieldType) return; QDrag *drag = new QDrag(this); QMimeData *mimeData = new QMimeData; if (item->type() == SchemaWidget::FieldType) - mimeData->setText(QString::fromLatin1("%1.%2").arg(item->parent()->text(0)).arg(item->text(0))); + mimeData->setText(QStringLiteral("%1.%2").arg(item->parent()->text(0), item->text(0))); else mimeData->setText(item->text(0)); drag->setMimeData(mimeData); drag->exec(Qt::CopyAction); QTreeWidget::mouseMoveEvent(event); } void SchemaWidget::slotItemExpanded(QTreeWidgetItem *item) { if (!item) return; switch(item->type()) { case SchemaWidget::TablesFolderType: { if (!m_tablesLoaded) buildTables(item); } break; case SchemaWidget::ViewsFolderType: { if (!m_viewsLoaded) buildViews(item); } break; case SchemaWidget::TableType: case SchemaWidget::SystemTableType: case SchemaWidget::ViewType: { if (item->childCount() == 0) buildFields(item); } break; default: break; } } void SchemaWidget::slotCustomContextMenuRequested(const QPoint &pos) { QMenu menu; - menu.addAction(QIcon::fromTheme(QLatin1String("view-refresh")), i18nc("@action:inmenu Context menu", "Refresh"), this, SLOT(refresh())); + menu.addAction(QIcon::fromTheme(QStringLiteral("view-refresh")), i18nc("@action:inmenu Context menu", "Refresh"), this, &SchemaWidget::refresh); QTreeWidgetItem *item = itemAt(pos); if (item) { if (item->type() == SchemaWidget::SystemTableType || item->type() == SchemaWidget::TableType || item->type() == SchemaWidget::ViewType || item->type() == SchemaWidget::FieldType) { menu.addSeparator(); - QMenu *submenu = menu.addMenu(QIcon::fromTheme(QLatin1String("tools-wizard")), i18nc("@action:inmenu Submenu title", "Generate")); + QMenu *submenu = menu.addMenu(QIcon::fromTheme(QStringLiteral("tools-wizard")), i18nc("@action:inmenu Submenu title", "Generate")); - submenu->addAction(i18n ("SELECT"), this, SLOT(generateSelect())); - submenu->addAction(i18n ("UPDATE"), this, SLOT(generateUpdate())); - submenu->addAction(i18n ("INSERT"), this, SLOT(generateInsert())); - submenu->addAction(i18n ("DELETE"), this, SLOT(generateDelete())); + submenu->addAction(i18n ("SELECT"), this, &SchemaWidget::generateSelect); + submenu->addAction(i18n ("UPDATE"), this, &SchemaWidget::generateUpdate); + submenu->addAction(i18n ("INSERT"), this, &SchemaWidget::generateInsert); + submenu->addAction(i18n ("DELETE"), this, &SchemaWidget::generateDelete); } } menu.exec(QCursor::pos()); } void SchemaWidget::generateStatement(QSqlDriver::StatementType statementType) { if (!isConnectionValidAndOpen()) return; QSqlDatabase db = QSqlDatabase::database(m_connectionName); QSqlDriver *drv = db.driver(); if (!drv) return; QTreeWidgetItem *item = currentItem(); if (!item) return; QString statement; switch (item->type()) { case TableType: case SystemTableType: case ViewType: { QString tableName = item->text(0); QSqlRecord rec = db.record(tableName); // set all fields to a value (NULL) // values are needed to generate update and insert statements if (statementType == QSqlDriver::UpdateStatement || statementType == QSqlDriver::InsertStatement) for (int i = 0, n = rec.count(); i < n; ++i) rec.setNull(i); statement = drv->sqlStatement(statementType, tableName, rec, false); } break; case FieldType: { QString tableName = item->parent()->text(0); QSqlRecord rec = db.record(tableName); // get the selected column... QSqlField field = rec.field(item->text(0)); // ...and set its value to NULL field.clear(); // clear all columns and re-append the selected one rec.clear(); rec.append(field); statement = drv->sqlStatement(statementType, tableName, rec, false); if (statementType == QSqlDriver::DeleteStatement) statement += QLatin1String (" ") + drv->sqlStatement(QSqlDriver::WhereStatement, tableName, rec, false).replace(QLatin1String (" IS NULL"), QLatin1String ("=?")); } break; } KTextEditor::MainWindow *mw = KTextEditor::Editor::instance()->application()->activeMainWindow(); KTextEditor::View *kv = mw->activeView(); // replace NULL with a more generic '?' statement = statement.replace(QLatin1String ("NULL"), QLatin1String ("?")); if (kv) { // paste statement in the active view kv->insertText(statement); kv->setFocus(); } qDebug() << "Generated statement:" << statement; } void SchemaWidget::generateSelect() { generateStatement(QSqlDriver::SelectStatement); } void SchemaWidget::generateUpdate() { generateStatement(QSqlDriver::UpdateStatement); } void SchemaWidget::generateInsert() { generateStatement(QSqlDriver::InsertStatement); } void SchemaWidget::generateDelete() { generateStatement(QSqlDriver::DeleteStatement); } diff --git a/addons/katesql/sqlmanager.cpp b/addons/katesql/sqlmanager.cpp index 0be570946..ffb427b2b 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(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; + QString connectionName = (conn.name.isEmpty()) ? QStringLiteral ("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 nullptr; - QString folder (QLatin1String ("SQL Connections")); + QString folder (QStringLiteral ("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; + map[QStringLiteral ("driver")] = conn.driver.toUpper(); + map[QStringLiteral ("hostname")] = conn.hostname.toUpper(); + map[QStringLiteral ("port")] = QString::number(conn.port); + map[QStringLiteral ("database")] = conn.database.toUpper(); + map[QStringLiteral ("username")] = conn.username; + map[QStringLiteral ("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")); + password = map.value(QStringLiteral("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/textoutputwidget.cpp b/addons/katesql/textoutputwidget.cpp index 9d97403a6..f11df6187 100644 --- a/addons/katesql/textoutputwidget.cpp +++ b/addons/katesql/textoutputwidget.cpp @@ -1,105 +1,105 @@ /* Copyright (C) 2010 Marco Mentasti This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "textoutputwidget.h" #include "connection.h" #include #include #include #include #include #include #include TextOutputWidget::TextOutputWidget(QWidget *parent) : QWidget(parent) { m_succesTextColor = QColor::fromRgb(3, 191, 3); m_succesBackgroundColor = QColor::fromRgb(231, 247, 231); m_errorTextColor = QColor::fromRgb(191, 3, 3); m_errorBackgroundColor = QColor::fromRgb(247, 231, 231); m_layout = new QHBoxLayout(this); m_output = new QTextEdit(); m_output->setReadOnly(true); QFont fixedFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); m_output->setCurrentFont(fixedFont); KToolBar *toolbar = new KToolBar(this); toolbar->setOrientation(Qt::Vertical); toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly); toolbar->setIconSize(QSize(16, 16)); /// TODO: disable actions if no results are displayed - QAction *action = new QAction( QIcon::fromTheme(QLatin1String("edit-clear")), i18nc("@action:intoolbar", "Clear"), this); + QAction *action = new QAction( QIcon::fromTheme(QStringLiteral("edit-clear")), i18nc("@action:intoolbar", "Clear"), this); toolbar->addAction(action); connect(action, &QAction::triggered, m_output, &QTextEdit::clear); m_layout->addWidget(toolbar); m_layout->addWidget(m_output, 1); m_layout->setContentsMargins(0, 0, 0, 0); setLayout(m_layout); } TextOutputWidget::~TextOutputWidget() { } void TextOutputWidget::showErrorMessage(const QString &message) { QColor previousBackgroundColor = m_output->textBackgroundColor(); QColor previousColor = m_output->textColor(); m_output->setTextBackgroundColor(m_errorBackgroundColor); m_output->setTextColor(m_errorTextColor); writeMessage(message); m_output->setTextBackgroundColor(previousBackgroundColor); m_output->setTextColor(previousColor); } void TextOutputWidget::showSuccessMessage(const QString &message) { QColor previousBackgroundColor = m_output->textBackgroundColor(); QColor previousColor = m_output->textColor(); m_output->setTextBackgroundColor(m_succesBackgroundColor); m_output->setTextColor(m_succesTextColor); writeMessage(message); m_output->setTextBackgroundColor(previousBackgroundColor); m_output->setTextColor(previousColor); } void TextOutputWidget::writeMessage(const QString& msg) { - m_output->append(QString::fromLatin1("%1: %2\n").arg(QDateTime::currentDateTime().toString(Qt::SystemLocaleDate)).arg(msg)); + m_output->append(QStringLiteral("%1: %2\n").arg(QDateTime::currentDateTime().toString(Qt::SystemLocaleDate)).arg(msg)); raise(); } diff --git a/addons/konsole/kateconsole.cpp b/addons/konsole/kateconsole.cpp index 32d944aa3..e44da709f 100644 --- a/addons/konsole/kateconsole.cpp +++ b/addons/konsole/kateconsole.cpp @@ -1,502 +1,502 @@ /* 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 Copyright (C) 2017 Ederag 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 #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON (KateKonsolePluginFactory, "katekonsoleplugin.json", registerPlugin();) KateKonsolePlugin::KateKonsolePlugin( QObject* parent, const QList& ): KTextEditor::Plugin ( parent ) { m_previousEditorEnv=qgetenv("EDITOR"); if (!KAuthorized::authorize(QStringLiteral("shell_access"))) { KMessageBox::sorry(nullptr, i18n ("You do not have enough karma to access a shell or terminal emulation")); } } KateKonsolePlugin::~KateKonsolePlugin() { qputenv("EDITOR", m_previousEditorEnv.data()); } QObject *KateKonsolePlugin::createView (KTextEditor::MainWindow *mainWindow) { KateKonsolePluginView *view = new KateKonsolePluginView (this, mainWindow); return view; } KTextEditor::ConfigPage *KateKonsolePlugin::configPage (int number, QWidget *parent) { if (number != 0) return nullptr; return new KateKonsoleConfigPage(parent, this); } void KateKonsolePlugin::readConfig() { foreach ( KateKonsolePluginView *view, mViews ) view->readConfig(); } KateKonsolePluginView::KateKonsolePluginView (KateKonsolePlugin* plugin, KTextEditor::MainWindow *mainWindow) : QObject(mainWindow),m_plugin(plugin) { // init console QWidget *toolview = mainWindow->createToolView (plugin, QStringLiteral("kate_private_plugin_katekonsoleplugin"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme(QStringLiteral("utilities-terminal")), i18n("Terminal")); m_console = new KateConsole(m_plugin, mainWindow, toolview); // register this view m_plugin->mViews.append ( this ); } KateKonsolePluginView::~KateKonsolePluginView () { // unregister this view m_plugin->mViews.removeAll (this); // cleanup, kill toolview + console QWidget *toolview = m_console->parentWidget(); delete m_console; delete toolview; } void KateKonsolePluginView::readConfig() { m_console->readConfig(); } KateConsole::KateConsole (KateKonsolePlugin* plugin, KTextEditor::MainWindow *mw, QWidget *parent) : QWidget (parent) , m_part (nullptr) , m_mw (mw) , m_toolView (parent) , m_plugin(plugin) { KXMLGUIClient::setComponentName (QStringLiteral("katekonsole"), i18n ("Kate Terminal")); setXMLFile( QStringLiteral("ui.rc") ); // make sure we have a vertical layout new QVBoxLayout(this); layout()->setContentsMargins(0, 0, 0, 0); QAction* a = actionCollection()->addAction(QStringLiteral("katekonsole_tools_pipe_to_terminal")); a->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); a->setText(i18nc("@action", "&Pipe to Terminal")); connect(a, &QAction::triggered, this, &KateConsole::slotPipeToConsole); a = actionCollection()->addAction(QStringLiteral("katekonsole_tools_sync")); a->setText(i18nc("@action", "S&ynchronize Terminal with Current Document")); connect(a, &QAction::triggered, this, &KateConsole::slotManualSync); a = actionCollection()->addAction(QStringLiteral("katekonsole_tools_run")); a->setText(i18nc("@action", "Run Current Document")); - connect(a, SIGNAL(triggered()), this, SLOT(slotRun())); + connect(a, &QAction::triggered, this, &KateConsole::slotRun); a = actionCollection()->addAction(QStringLiteral("katekonsole_tools_toggle_focus")); a->setIcon(QIcon::fromTheme(QStringLiteral("utilities-terminal"))); a->setText(i18nc("@action", "&Focus Terminal")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::Key_F4)); connect(a, &QAction::triggered, this, &KateConsole::slotToggleFocus); m_mw->guiFactory()->addClient (this); readConfig(); } KateConsole::~KateConsole () { m_mw->guiFactory()->removeClient (this); if (m_part) disconnect(m_part, &KParts::ReadOnlyPart::destroyed, this, &KateConsole::slotDestroyed); } void KateConsole::loadConsoleIfNeeded() { if (m_part) return; if (!window() || !parentWidget()) return; if (!window() || !isVisibleTo(window())) return; /** * get konsole part factory */ KPluginFactory *factory = KPluginLoader(QStringLiteral("konsolepart")).factory(); if (!factory) return; m_part = factory->create(this, this); if (!m_part) return; layout()->addWidget(m_part->widget()); // start the terminal qobject_cast(m_part)->showShellInDir( QString() ); // KGlobal::locale()->insertCatalog("konsole"); // FIXME KF5: insert catalog setFocusProxy(m_part->widget()); m_part->widget()->show(); connect(m_part, &KParts::ReadOnlyPart::destroyed, this, &KateConsole::slotDestroyed); connect ( m_part, SIGNAL(overrideShortcut(QKeyEvent*,bool&)), this, SLOT(overrideShortcut(QKeyEvent*,bool&))); slotSync(); } void KateConsole::slotDestroyed () { m_part = nullptr; m_currentPath.clear (); // hide the dockwidget if (parentWidget()) { m_mw->hideToolView (m_toolView); } } void KateConsole::overrideShortcut (QKeyEvent *, bool &override) { /** * let konsole handle all shortcuts */ override = true; } void KateConsole::showEvent(QShowEvent *) { if (m_part) return; loadConsoleIfNeeded(); } void KateConsole::cd (const QString & path) { if (m_currentPath == path) return; if (!m_part) return; m_currentPath = path; QString command = QStringLiteral(" cd ") + KShell::quoteArg(m_currentPath) + QLatin1Char('\n'); // special handling for some interpreters TerminalInterface *t = qobject_cast(m_part); if (t) { // ghci doesn't allow \space dir names, does allow spaces in dir names // irb can take spaces or \space but doesn't allow " 'path' " if (t->foregroundProcessName() == QStringLiteral("irb") ) { command = QStringLiteral("Dir.chdir(\"") + path + QStringLiteral("\") \n") ; } else if(t->foregroundProcessName() == QStringLiteral("ghc")) { command = QStringLiteral(":cd ") + path + QStringLiteral("\n"); } } sendInput(command); } void KateConsole::sendInput( const QString& text ) { loadConsoleIfNeeded(); if (!m_part) return; TerminalInterface *t = qobject_cast(m_part); if (!t) return; t->sendInput (text); } void KateConsole::slotPipeToConsole () { if (KMessageBox::warningContinueCancel (m_mw->window() , i18n ("Do you really want to pipe the text to the console? This will execute any contained commands with your user rights.") , i18n ("Pipe to Terminal?") , KGuiItem(i18n("Pipe to Terminal")), KStandardGuiItem::cancel(), QStringLiteral("Pipe To Terminal Warning")) != KMessageBox::Continue) return; KTextEditor::View *v = m_mw->activeView(); if (!v) return; if (v->selection()) sendInput (v->selectionText()); else sendInput (v->document()->text()); } void KateConsole::slotSync(KTextEditor::View *) { if (m_mw->activeView()) { QUrl u = m_mw->activeView()->document()->url(); if (u.isValid() && u.isLocalFile()) { QFileInfo fi(u.toLocalFile()); cd(fi.absolutePath()); } else if (!u.isEmpty()) { sendInput( QStringLiteral("### ") + i18n("Sorry, cannot cd into '%1'", u.toLocalFile() ) + QLatin1Char('\n') ); } } } void KateConsole::slotManualSync() { m_currentPath.clear (); slotSync(); if ( ! m_part || ! m_part->widget()->isVisible() ) m_mw->showToolView( parentWidget() ); } void KateConsole::slotRun() { if ( m_mw->activeView() ) { KTextEditor::Document *document = m_mw->activeView()->document(); QUrl u = document->url(); if ( ! u.isLocalFile() ) { QPointer message = new KTextEditor::Message( i18n("Not a local file: '%1'", u.path()), KTextEditor::Message::Error ); // auto hide is enabled and set to a sane default value of several seconds. message->setAutoHide(2000); message->setAutoHideMode( KTextEditor::Message::Immediate ); document->postMessage( message ); return; } // ensure that file is saved if ( document->isModified() ) { document->save(); } // The string that should be output to terminal, upon acceptance QString output_str; // prefix first output_str += KConfigGroup( KSharedConfig::openConfig(), "Konsole" ).readEntry("RunPrefix", ""); // then filename if ( KConfigGroup(KSharedConfig::openConfig(), "Konsole" ).readEntry("RemoveExtension", true) ) { // append filename without extension (i.e. keep only the basename) output_str += QFileInfo( u.path() ).baseName() + QLatin1Char('\n'); } else { // append filename to the terminal output_str += QFileInfo( u.path() ).fileName() + QLatin1Char('\n'); } if ( KMessageBox::Continue != KMessageBox::warningContinueCancel( m_mw->window(), i18n("Do you really want to Run the document ?\n" "This will execute the following command,\n" "with your user rights, in the terminal:\n" "'%1'", output_str), i18n("Run in Terminal?"), KGuiItem( i18n("Run") ), KStandardGuiItem::cancel(), QStringLiteral("Konsole: Run in Terminal Warning") ) ) { return; } // echo to terminal sendInput( output_str ); } } 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", true) ) { 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 ); QVBoxLayout *vboxRun = new QVBoxLayout; QGroupBox *groupRun = new QGroupBox( i18n("Run in terminal"), this ); // Remove extension cbRemoveExtension = new QCheckBox( i18n("&Remove extension"), this ); vboxRun->addWidget( cbRemoveExtension ); // Prefix QFrame *framePrefix = new QFrame( this ); QHBoxLayout *hboxPrefix = new QHBoxLayout( framePrefix ); QLabel *label = new QLabel( i18n("Prefix:"), framePrefix ); hboxPrefix->addWidget( label ); lePrefix = new QLineEdit( framePrefix ); hboxPrefix->addWidget( lePrefix ); vboxRun->addWidget( framePrefix ); // show warning next time QFrame *frameWarn = new QFrame( this ); QHBoxLayout *hboxWarn = new QHBoxLayout( frameWarn ); QPushButton *buttonWarn = new QPushButton( i18n("&Show warning next time"), frameWarn); buttonWarn->setWhatsThis ( i18n ( "The next time '%1' is executed, " "make sure a warning window will pop up, " "displaying the command to be sent to terminal, " "for review.", i18n ("Run in terminal") ) ); connect( buttonWarn, &QPushButton::pressed, this, &KateKonsoleConfigPage::slotEnableRunWarning ); hboxWarn->addWidget( buttonWarn ); vboxRun->addWidget( frameWarn ); groupRun->setLayout( vboxRun ); lo->addWidget( groupRun ); 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, &QCheckBox::stateChanged, this, &KateKonsoleConfigPage::changed); - connect( cbRemoveExtension, SIGNAL(stateChanged(int)), SIGNAL(changed()) ); + connect( cbRemoveExtension, &QCheckBox::stateChanged, this, &KTextEditor::ConfigPage::changed ); connect( lePrefix, &QLineEdit::textChanged, this, &KateKonsoleConfigPage::changed ); connect(cbSetEditor, &QCheckBox::stateChanged, this, &KateKonsoleConfigPage::changed); } void KateKonsoleConfigPage::slotEnableRunWarning () { KMessageBox::enableMessage(QStringLiteral("Konsole: Run in Terminal Warning")); } 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("RemoveExtension", cbRemoveExtension->isChecked()); config.writeEntry("RunPrefix", lePrefix->text()); config.writeEntry("SetEditor", cbSetEditor->isChecked()); config.sync(); mPlugin->readConfig(); } void KateKonsoleConfigPage::reset() { KConfigGroup config(KSharedConfig::openConfig(), "Konsole"); cbAutoSyncronize->setChecked(config.readEntry("AutoSyncronize", true)); cbRemoveExtension->setChecked(config.readEntry("RemoveExtension", false)); lePrefix->setText(config.readEntry("RunPrefix", "")); cbSetEditor->setChecked(config.readEntry("SetEditor", false)); } #include "kateconsole.moc" // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/lumen/dcd.cpp b/addons/lumen/dcd.cpp index 1c399ab59..a6537d116 100644 --- a/addons/lumen/dcd.cpp +++ b/addons/lumen/dcd.cpp @@ -1,358 +1,358 @@ /* * Copyright 2014-2015 David Herberth kde@dav1d.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . **/ #include "dcd.h" #include #include #include #include #include char DCDCompletionItemType::toChar(DCDCompletionItemType e) { switch (e) { case Invalid: return 0; case Calltip: return 1; case ClassName: return 'c'; case InterfaceName: return 'i'; case StructName: return 's'; case UnionName: return 'u'; case VariableName: return 'v'; case MemberVariableName: return 'm'; case Keyword: return 'k'; case FunctionName: return 'f'; case EnumName: return 'g'; case EnumMember: return 'e'; case PackageName: return 'p'; case ModuleName: return 'M'; } return 0; } DCDCompletionItemType::DCDCompletionItemType DCDCompletionItemType::fromChar(char c) { switch (c) { case 0: return Invalid; case 1: return Calltip; case 'c': return ClassName; case 'i': return InterfaceName; case 's': return StructName; case 'u': return UnionName; case 'v': return VariableName; case 'm': return MemberVariableName; case 'k': return Keyword; case 'f': return FunctionName; case 'g': return EnumName; case 'e': return EnumMember; case 'p': return PackageName; case 'M': return ModuleName; } return Invalid; } -DCDCompletionItem::DCDCompletionItem(DCDCompletionItemType::DCDCompletionItemType t, QString s): type(t), name(s) +DCDCompletionItem::DCDCompletionItem(DCDCompletionItemType::DCDCompletionItemType t, const QString &s): type(t), name(s) { } #define RETURN_CACHED_ICON(name) {static QIcon icon(QIcon::fromTheme(QStringLiteral(name)).pixmap(QSize(16, 16))); return icon;} QIcon DCDCompletionItem::icon() const { using namespace DCDCompletionItemType; switch (type) { case Invalid: break; case Calltip: RETURN_CACHED_ICON("code-function") case ClassName: RETURN_CACHED_ICON("code-class") case InterfaceName: RETURN_CACHED_ICON("code-class") case StructName: RETURN_CACHED_ICON("struct") case UnionName: RETURN_CACHED_ICON("union") case VariableName: RETURN_CACHED_ICON("code-variable") case MemberVariableName: RETURN_CACHED_ICON("field") case Keyword: RETURN_CACHED_ICON("field") case FunctionName: RETURN_CACHED_ICON("code-function") case EnumName: RETURN_CACHED_ICON("enum") case EnumMember: RETURN_CACHED_ICON("enum") case PackageName: RETURN_CACHED_ICON("field") case ModuleName: RETURN_CACHED_ICON("field") } return QIcon(); } QString DCDCompletionItem::typeLong() const { using namespace DCDCompletionItemType; switch (type) { case Invalid: return QStringLiteral("invalid"); case Calltip: return QStringLiteral("calltip"); case ClassName: return QStringLiteral("class"); case InterfaceName: return QStringLiteral("interface"); case StructName: return QStringLiteral("struct"); case UnionName: return QStringLiteral("union"); case VariableName: return QStringLiteral("variable"); case MemberVariableName: return QStringLiteral("member"); case Keyword: return QStringLiteral("keyword"); case FunctionName: return QStringLiteral("function"); case EnumName: return QStringLiteral("enum"); case EnumMember: return QStringLiteral("enum member"); case PackageName: return QStringLiteral("package"); case ModuleName: return QStringLiteral("module"); } return QStringLiteral("completion"); } static const int TIMEOUT_START_SERVER = 200; static const int TIMEOUT_COMPLETE = 200; static const int TIMEOUT_IMPORTPATH = 200; static const int TIMEOUT_SHUTDOWN = 350; static const int TIMEOUT_SHUTDOWN_SERVER = 200; DCD::DCD(int port, const QString& server, const QString& client) { m_port = port; m_server = server; m_client = client; } int DCD::port() const { return m_port; } bool DCD::running() { return m_sproc.state() == QProcess::Running; } bool DCD::startServer() { m_sproc.setProcessChannelMode(QProcess::MergedChannels); m_sproc.start(m_server, QStringList(QStringLiteral("-p%1").arg(m_port))); bool started = m_sproc.waitForStarted(TIMEOUT_START_SERVER); bool finished = m_sproc.waitForFinished(TIMEOUT_START_SERVER); if (!started || finished || m_sproc.state() == QProcess::NotRunning) { qWarning() << "unable to start completion-server:" << m_sproc.exitCode(); qWarning() << m_sproc.readAllStandardOutput(); return false; } qDebug() << "started completion-server"; return true; } DCDCompletion DCD::complete(const QString& file, int offset) { QProcess proc; proc.setProcessChannelMode(QProcess::MergedChannels); proc.start(m_client, QStringList() << QStringLiteral("-p%1").arg(m_port) << QStringLiteral("-c%1").arg(offset) << file ); proc.waitForFinished(TIMEOUT_COMPLETE); proc.terminate(); if (proc.exitStatus() != QProcess::NormalExit || proc.exitCode() != 0) { qWarning() << "unable to complete:" << proc.exitCode(); qWarning() << proc.readAllStandardOutput(); return DCDCompletion(); } return processCompletion(QString::fromUtf8(proc.readAllStandardOutput())); } DCDCompletion DCD::complete(const QByteArray& data, int offset) { QProcess proc; proc.setProcessChannelMode(QProcess::MergedChannels); proc.start(m_client, QStringList() << QStringLiteral("-p%1").arg(m_port) << QStringLiteral("-c%1").arg(offset) ); proc.write(data); proc.closeWriteChannel(); if (!proc.waitForFinished(TIMEOUT_COMPLETE)) { qWarning() << "unable to complete: client didn't finish in time"; proc.close(); } else if (proc.exitCode() != 0) { qWarning() << "unable to complete:" << proc.exitCode(); qWarning() << proc.readAllStandardOutput(); } else { // everything Ok return processCompletion(QString::fromUtf8(proc.readAllStandardOutput())); } return DCDCompletion(); } QString DCD::doc(const QByteArray& data, int offset) { QProcess proc; proc.setProcessChannelMode(QProcess::MergedChannels); proc.start(m_client, QStringList() << QStringLiteral("-p%1").arg(m_port) << QStringLiteral("-c%1").arg(offset) << QStringLiteral("--doc") ); proc.write(data); proc.closeWriteChannel(); if (!proc.waitForFinished(TIMEOUT_COMPLETE)) { qWarning() << "unable to lookup documentation: client didn't finish in time"; proc.close(); } else if (proc.exitCode() != 0) { qWarning() << "unable to lookup documentation:" << proc.exitCode(); qWarning() << proc.readAllStandardOutput(); } else { return QString::fromUtf8(proc.readAllStandardOutput()); } return QString(); } DCDCompletion DCD::processCompletion(const QString& data) { DCDCompletion completion; QStringList lines = data.split(QRegularExpression(QStringLiteral("[\r\n]")), QString::SkipEmptyParts); if (lines.length() == 0) { return completion; } QString type = lines.front(); if (type == QStringLiteral("identifiers")) { completion.type = DCDCompletionType::Identifiers; } else if (type == QStringLiteral("calltips")) { completion.type = DCDCompletionType::Calltips; } else { qWarning() << "Invalid type:" << type; return completion; } lines.pop_front(); foreach(QString line, lines) { if (line.trimmed().length() == 0) { continue; } QStringList kv = line.split(QRegularExpression(QStringLiteral("\\s+")), QString::SkipEmptyParts); if (kv.length() != 2 && completion.type != DCDCompletionType::Calltips) { qWarning() << "invalid completion data:" << kv.length() << completion.type; continue; } if (completion.type == DCDCompletionType::Identifiers) { completion.completions.append(DCDCompletionItem( DCDCompletionItemType::fromChar(kv[1].at(0).toLatin1()), kv[0] )); } else { completion.completions.append(DCDCompletionItem( DCDCompletionItemType::Calltip, line )); } } return completion; } void DCD::addImportPath(const QString& path) { addImportPath(QStringList(path)); } void DCD::addImportPath(const QStringList& paths) { if (paths.isEmpty()) { return; } QStringList arguments = QStringList(QStringLiteral("-p%1").arg(m_port)); foreach(QString path, paths) { if (QFile::exists(path)) arguments << QStringLiteral("-I%1").arg(path); } QProcess proc; proc.setProcessChannelMode(QProcess::MergedChannels); proc.start(m_client, arguments); proc.waitForFinished(TIMEOUT_IMPORTPATH); if (proc.exitStatus() != QProcess::NormalExit || proc.exitCode() != 0) { qWarning() << "unable to add importpath(s)" << paths << ":" << proc.exitCode(); qWarning() << proc.readAll(); } } void DCD::shutdown() { QProcess proc; proc.setProcessChannelMode(QProcess::MergedChannels); proc.start(m_client, QStringList() << QStringLiteral("-p%1").arg(m_port) << QStringLiteral("--shutdown") ); proc.waitForFinished(TIMEOUT_SHUTDOWN); if (proc.exitStatus() != QProcess::NormalExit || proc.exitCode() != 0) { qWarning() << "unable to shutdown dcd:" << proc.exitCode(); qWarning() << proc.readAllStandardOutput(); } } bool DCD::stopServer() { if (m_sproc.state() == QProcess::Running) { qDebug() << "shutting down dcd"; shutdown(); if(!m_sproc.waitForFinished(TIMEOUT_SHUTDOWN_SERVER)) m_sproc.terminate(); if(!m_sproc.waitForFinished(TIMEOUT_SHUTDOWN_SERVER)) m_sproc.kill(); return true; } return false; } DCD::~DCD() { if (running()) { stopServer(); } } diff --git a/addons/lumen/dcd.h b/addons/lumen/dcd.h index 96b318f66..7b85e5933 100644 --- a/addons/lumen/dcd.h +++ b/addons/lumen/dcd.h @@ -1,95 +1,95 @@ /* * 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_DCD_H #define LUMEN_DCD_H #include #include #include #include #include #include namespace DCDCompletionType { enum DCDCompletionType { Identifiers, Calltips }; } namespace DCDCompletionItemType { enum DCDCompletionItemType { Invalid, Calltip, ClassName, InterfaceName, StructName, UnionName, VariableName, MemberVariableName, Keyword, FunctionName, EnumName, EnumMember, PackageName, ModuleName, }; char toChar(DCDCompletionItemType e); DCDCompletionItemType fromChar(char c); } struct DCDCompletionItem { - DCDCompletionItem(DCDCompletionItemType::DCDCompletionItemType, QString); + DCDCompletionItem(DCDCompletionItemType::DCDCompletionItemType, const QString &); DCDCompletionItemType::DCDCompletionItemType type; QString name; QIcon icon() const; QString typeLong() const; }; struct DCDCompletion { DCDCompletionType::DCDCompletionType type; QList completions; }; class DCD { public: DCD(int, const QString&, const QString&); virtual ~DCD(); int port() const; bool running(); bool startServer(); bool stopServer(); DCDCompletion complete(const QString&, int); DCDCompletion complete(const QByteArray&, int); QString doc(const QByteArray&, int); void shutdown(); void addImportPath(const QString&); void addImportPath(const QStringList&); private: DCDCompletion processCompletion(const QString&); int m_port; QString m_server; QString m_client; QProcess m_sproc; }; #endif diff --git a/addons/project/kateproject.cpp b/addons/project/kateproject.cpp index b41435d4a..2a92ee8c7 100644 --- a/addons/project/kateproject.cpp +++ b/addons/project/kateproject.cpp @@ -1,405 +1,405 @@ /* 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 "kateproject.h" #include "kateprojectworker.h" #include #include #include #include #include #include #include #include #include KateProject::KateProject(ThreadWeaver::Queue *weaver) : QObject() , m_fileLastModified() , m_notesDocument(nullptr) , m_untrackedDocumentsRoot(nullptr) , m_weaver(weaver) { } KateProject::~KateProject() { saveNotesDocument(); } bool KateProject::loadFromFile(const QString &fileName) { /** * bail out if already fileName set! */ if (!m_fileName.isEmpty()) { return false; } /** * set new filename and base directory */ m_fileName = fileName; m_baseDir = QFileInfo(m_fileName).canonicalPath(); /** * trigger reload */ return reload(); } bool KateProject::reload(bool force) { QVariantMap map = readProjectFile(); if (map.isEmpty()) { m_fileLastModified = QDateTime(); } else { m_fileLastModified = QFileInfo(m_fileName).lastModified(); m_globalProject = map; } return load(m_globalProject, force); } QVariantMap KateProject::readProjectFile() const { QFile file(m_fileName); if (!file.open(QFile::ReadOnly)) { return QVariantMap(); } /** * parse the whole file, bail out again on error! */ const QByteArray jsonData = file.readAll(); QJsonParseError parseError; QJsonDocument project(QJsonDocument::fromJson(jsonData, &parseError)); if (parseError.error != QJsonParseError::NoError) { return QVariantMap(); } return project.toVariant().toMap(); } bool KateProject::loadFromData(const QVariantMap& globalProject, const QString& directory) { m_baseDir = directory; - m_fileName = QDir(directory).filePath(QLatin1String(".kateproject")); + m_fileName = QDir(directory).filePath(QStringLiteral(".kateproject")); m_globalProject = globalProject; return load(globalProject); } bool KateProject::load(const QVariantMap &globalProject, bool force) { /** * no name, bad => bail out */ if (globalProject[QStringLiteral("name")].toString().isEmpty()) { return false; } /** * support out-of-source project files */ if (!globalProject[QStringLiteral("directory")].toString().isEmpty()) { m_baseDir = QFileInfo(globalProject[QStringLiteral("directory")].toString()).canonicalFilePath(); } /** * anything changed? * else be done without forced reload! */ if (!force && (m_projectMap == globalProject)) { return true; } /** * setup global attributes in this object */ m_projectMap = globalProject; /** * emit that we changed stuff */ emit projectMapChanged(); KateProjectWorker * w = new KateProjectWorker(m_baseDir, m_projectMap); connect(w, &KateProjectWorker::loadDone, this, &KateProject::loadProjectDone); connect(w, &KateProjectWorker::loadIndexDone, this, &KateProject::loadIndexDone); m_weaver->stream() << w; return true; } void KateProject::loadProjectDone(KateProjectSharedQStandardItem topLevel, KateProjectSharedQMapStringItem file2Item) { m_model.clear(); m_model.invisibleRootItem()->appendColumn(topLevel->takeColumn(0)); m_file2Item = file2Item; /** * readd the documents that are open atm */ m_untrackedDocumentsRoot = nullptr; for (auto i = m_documents.constBegin(); i != m_documents.constEnd(); i++) { registerDocument(i.key()); } emit modelChanged(); } void KateProject::loadIndexDone(KateProjectSharedProjectIndex projectIndex) { /** * move to our project */ m_projectIndex = projectIndex; /** * notify external world that data is available */ emit indexChanged(); } QString KateProject::projectLocalFileName(const QString &suffix) const { /** * nothing on empty file names for project * should not happen */ if (m_baseDir.isEmpty() || suffix.isEmpty()) { return QString(); } /** * compute full file name */ return m_baseDir + QStringLiteral(".kateproject.") + suffix; } QTextDocument *KateProject::notesDocument() { /** * already there? */ if (m_notesDocument) { return m_notesDocument; } /** * else create it */ m_notesDocument = new QTextDocument(this); m_notesDocument->setDocumentLayout(new QPlainTextDocumentLayout(m_notesDocument)); /** * get file name */ const QString notesFileName = projectLocalFileName(QStringLiteral("notes")); if (notesFileName.isEmpty()) { return m_notesDocument; } /** * and load text if possible */ QFile inFile(notesFileName); if (inFile.open(QIODevice::ReadOnly)) { QTextStream inStream(&inFile); inStream.setCodec("UTF-8"); m_notesDocument->setPlainText(inStream.readAll()); } /** * and be done */ return m_notesDocument; } void KateProject::saveNotesDocument() { /** * no notes document, nothing to do */ if (!m_notesDocument) { return; } /** * get content & filename */ const QString content = m_notesDocument->toPlainText(); const QString notesFileName = projectLocalFileName(QStringLiteral("notes")); if (notesFileName.isEmpty()) { return; } /** * no content => unlink file, if there */ if (content.isEmpty()) { if (QFile::exists(notesFileName)) { QFile::remove(notesFileName); } return; } /** * else: save content to file */ QFile outFile(projectLocalFileName(QStringLiteral("notes"))); if (outFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { QTextStream outStream(&outFile); outStream.setCodec("UTF-8"); outStream << content; } } void KateProject::slotModifiedChanged(KTextEditor::Document *document) { KateProjectItem *item = itemForFile(m_documents.value(document)); if (!item) { return; } item->slotModifiedChanged(document); } void KateProject::slotModifiedOnDisk(KTextEditor::Document *document, bool isModified, KTextEditor::ModificationInterface::ModifiedOnDiskReason reason) { KateProjectItem *item = itemForFile(m_documents.value(document)); if (!item) { return; } item->slotModifiedOnDisk(document, isModified, reason); } void KateProject::registerDocument(KTextEditor::Document *document) { // remember the document, if not already there if (!m_documents.contains(document)) { m_documents[document] = document->url().toLocalFile(); } // try to get item for the document KateProjectItem *item = itemForFile(document->url().toLocalFile()); // if we got one, we are done, else create a dummy! if (item) { disconnect(document, &KTextEditor::Document::modifiedChanged, this, &KateProject::slotModifiedChanged); disconnect(document, SIGNAL(modifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SLOT(slotModifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason))); item->slotModifiedChanged(document); /*FIXME item->slotModifiedOnDisk(document,document->isModified(),qobject_cast(document)->modifiedOnDisk()); FIXME*/ connect(document, &KTextEditor::Document::modifiedChanged, this, &KateProject::slotModifiedChanged); connect(document, SIGNAL(modifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SLOT(slotModifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason))); return; } registerUntrackedDocument(document); } void KateProject::registerUntrackedDocument(KTextEditor::Document *document) { // perhaps create the parent item if (!m_untrackedDocumentsRoot) { m_untrackedDocumentsRoot = new KateProjectItem(KateProjectItem::Directory, i18n("")); m_model.insertRow(0, m_untrackedDocumentsRoot); } // create document item QFileInfo fileInfo(document->url().toLocalFile()); KateProjectItem *fileItem = new KateProjectItem(KateProjectItem::File, fileInfo.fileName()); fileItem->setData(document->url().toLocalFile(), Qt::ToolTipRole); fileItem->slotModifiedChanged(document); connect(document, &KTextEditor::Document::modifiedChanged, this, &KateProject::slotModifiedChanged); connect(document, SIGNAL(modifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason)), this, SLOT(slotModifiedOnDisk(KTextEditor::Document *, bool, KTextEditor::ModificationInterface::ModifiedOnDiskReason))); bool inserted = false; for (int i = 0; i < m_untrackedDocumentsRoot->rowCount(); ++i) { if (m_untrackedDocumentsRoot->child(i)->data(Qt::UserRole).toString() > document->url().toLocalFile()) { m_untrackedDocumentsRoot->insertRow(i, fileItem); inserted = true; break; } } if (!inserted) { m_untrackedDocumentsRoot->appendRow(fileItem); } fileItem->setData(document->url().toLocalFile(), Qt::UserRole); fileItem->setData(QVariant(true), Qt::UserRole + 3); if (!m_file2Item) { m_file2Item = KateProjectSharedQMapStringItem(new QMap ()); } (*m_file2Item)[document->url().toLocalFile()] = fileItem; } void KateProject::unregisterDocument(KTextEditor::Document *document) { if (!m_documents.contains(document)) { return; } disconnect(document, &KTextEditor::Document::modifiedChanged, this, &KateProject::slotModifiedChanged); const QString &file = m_documents.value(document); if (m_untrackedDocumentsRoot) { KateProjectItem *item = static_cast(itemForFile(file)); if (item && item->data(Qt::UserRole + 3).toBool()) { unregisterUntrackedItem(item); m_file2Item->remove(file); } } m_documents.remove(document); } void KateProject::unregisterUntrackedItem(const KateProjectItem *item) { for (int i = 0; i < m_untrackedDocumentsRoot->rowCount(); ++i) { if (m_untrackedDocumentsRoot->child(i) == item) { m_untrackedDocumentsRoot->removeRow(i); break; } } if (m_untrackedDocumentsRoot->rowCount() < 1) { m_model.removeRow(0); m_untrackedDocumentsRoot = nullptr; } } diff --git a/addons/project/kateproject.h b/addons/project/kateproject.h index 3cf539ded..6652148a0 100644 --- a/addons/project/kateproject.h +++ b/addons/project/kateproject.h @@ -1,302 +1,302 @@ /* 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_PROJECT_H #define KATE_PROJECT_H #include #include #include #include #include #include "kateprojectindex.h" #include "kateprojectitem.h" /** * Shared pointer data types. * Used to pass pointers over queued connected slots */ typedef QSharedPointer KateProjectSharedQStandardItem; Q_DECLARE_METATYPE(KateProjectSharedQStandardItem) typedef QSharedPointer > KateProjectSharedQMapStringItem; Q_DECLARE_METATYPE(KateProjectSharedQMapStringItem) typedef QSharedPointer KateProjectSharedProjectIndex; Q_DECLARE_METATYPE(KateProjectSharedProjectIndex) namespace ThreadWeaver { class Queue; } /** * Class representing a project. * Holds project properties like name, groups, contained files, ... */ class KateProject : public QObject { Q_OBJECT public: /** * construct empty project */ KateProject(ThreadWeaver::Queue *weaver); /** * deconstruct project */ ~KateProject() override; /** * Load a project from project file * Only works once, afterwards use reload(). * @param fileName name of project file * @return success */ bool loadFromFile(const QString &fileName); bool loadFromData(const QVariantMap &globalProject, const QString &directory); /** * Try to reload a project. * If the reload fails, e.g. because the file is not readable or corrupt, nothing will happen! * @param force will enforce the worker to update files list and co even if the content of the file was not changed! * @return success */ bool reload(bool force = false); /** * Accessor to file name. * @return file name */ const QString &fileName() const { return m_fileName; } /** * Return the base directory of this project. * @return base directory of project, might not be the directory of the fileName! */ const QString &baseDir() const { return m_baseDir; } /** * Return the time when the project file has been modified last. * @return QFileInfo::lastModified() */ QDateTime fileLastModified() const { return m_fileLastModified; } /** * Accessor to project map containing the whole project info. * @return project info */ const QVariantMap &projectMap() const { return m_projectMap; } /** * Accessor to project name. * @return project name */ QString name() const { //MSVC doesn't support QStringLiteral here - return m_projectMap[QLatin1String("name")].toString(); + return m_projectMap[QStringLiteral("name")].toString(); } /** * Accessor for the model. * @return model of this project */ QStandardItemModel *model() { return &m_model; } /** * Flat list of all files in the project * @return list of files in project */ QStringList files() { return m_file2Item ? m_file2Item->keys() : QStringList(); } /** * get item for file * @param file file to get item for * @return item for given file or 0 */ KateProjectItem *itemForFile(const QString &file) { return m_file2Item ? m_file2Item->value(file) : nullptr; } /** * Access to project index. * May be null. * Don't store this pointer, might change. * @return project index */ KateProjectIndex *projectIndex() { return m_projectIndex.data(); } /** * Computes a suitable file name for the given suffix. * If you e.g. want to store a "notes" file, you could pass "notes" and get * the full path to projectbasedir/.kateproject.notes * @param suffix suffix for the file * @return full path for project local file, on error => empty string */ QString projectLocalFileName(const QString &suffix) const; /** * Document with project local notes. * Will be stored in a projectLocalFile "notes.txt". * @return notes document */ QTextDocument *notesDocument(); /** * Save the notes document to "notes.txt" if any document around. */ void saveNotesDocument(); /** * Register a document for this project. * @param document document to register */ void registerDocument(KTextEditor::Document *document); /** * Unregister a document for this project. * @param document document to unregister */ void unregisterDocument(KTextEditor::Document *document); private Q_SLOTS: bool load(const QVariantMap &globalProject, bool force = false); /** * Used for worker to send back the results of project loading * @param topLevel new toplevel element for model * @param file2Item new file => item mapping */ void loadProjectDone(KateProjectSharedQStandardItem topLevel, KateProjectSharedQMapStringItem file2Item); /** * Used for worker to send back the results of index loading * @param projectIndex new project index */ void loadIndexDone(KateProjectSharedProjectIndex projectIndex); void slotModifiedChanged(KTextEditor::Document *); void slotModifiedOnDisk(KTextEditor::Document *document, bool isModified, KTextEditor::ModificationInterface::ModifiedOnDiskReason reason); Q_SIGNALS: /** * Emitted on project map changes. * This includes the name! */ void projectMapChanged(); /** * Emitted on model changes. * This includes the files list, itemForFile mapping! */ void modelChanged(); /** * Emitted when the index creation is finished. * This includes the ctags index. */ void indexChanged(); private: void registerUntrackedDocument(KTextEditor::Document *document); void unregisterUntrackedItem(const KateProjectItem *item); QVariantMap readProjectFile() const; private: /** * Last modification time of the project file */ QDateTime m_fileLastModified; /** * project file name */ QString m_fileName; /** * base directory of the project */ QString m_baseDir; /** * project name */ QString m_name; /** * variant map representing the project */ QVariantMap m_projectMap; /** * standard item model with content of this project */ QStandardItemModel m_model; /** * mapping files => items */ KateProjectSharedQMapStringItem m_file2Item; /** * project index, if any */ KateProjectSharedProjectIndex m_projectIndex; /** * notes buffer for project local notes */ QTextDocument *m_notesDocument; /** * Set of existing documents for this project. */ QMap m_documents; /** * Parent item for existing documents that are not in the project tree */ QStandardItem *m_untrackedDocumentsRoot; ThreadWeaver::Queue *m_weaver; /** * project configuration (read from file or injected) */ QVariantMap m_globalProject; }; #endif diff --git a/addons/project/kateprojectplugin.cpp b/addons/project/kateprojectplugin.cpp index 0fa7ee419..baf373a60 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 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) { // allow .git as dir and file (file for git worktree stuff, https://git-scm.com/docs/git-worktree) if (m_autoGit && dir.exists(GitFolderName)) { 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); + cnf[QStringLiteral("name")] = dir.dirName(); + cnf[QStringLiteral("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/kateprojectpluginview.cpp b/addons/project/kateprojectpluginview.cpp index 9e731877a..dff11f687 100644 --- a/addons/project/kateprojectpluginview.cpp +++ b/addons/project/kateprojectpluginview.cpp @@ -1,523 +1,523 @@ /* This file is part of the Kate project. * * Copyright (C) 2010 Christoph Cullmann * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kateprojectpluginview.h" #include "fileutil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(KateProjectPluginFactory, "kateprojectplugin.json", registerPlugin();) KateProjectPluginView::KateProjectPluginView(KateProjectPlugin *plugin, KTextEditor::MainWindow *mainWin) : QObject(mainWin) , m_plugin(plugin) , m_mainWindow(mainWin) , m_toolView(nullptr) , m_toolInfoView(nullptr) , m_lookupAction(nullptr) { KXMLGUIClient::setComponentName(QStringLiteral("kateproject"), i18n("Kate Project Manager")); setXMLFile(QStringLiteral("ui.rc")); /** * create views for all already existing projects * will create toolviews on demand! */ foreach(KateProject * project, m_plugin->projects()) viewForProject(project); /** * connect to important signals, e.g. for auto project view creation */ connect(m_plugin, &KateProjectPlugin::projectCreated, this, &KateProjectPluginView::viewForProject); connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KateProjectPluginView::slotViewChanged); connect(m_mainWindow, &KTextEditor::MainWindow::viewCreated, this, &KateProjectPluginView::slotViewCreated); /** * connect for all already existing views */ foreach(KTextEditor::View * view, m_mainWindow->views()) slotViewCreated(view); /** * trigger once view change, to highlight right document */ slotViewChanged(); /** * back + forward */ auto a = actionCollection()->addAction(KStandardAction::Back, QStringLiteral("projects_prev_project"), this, SLOT(slotProjectPrev())); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Left)); a = actionCollection()->addAction(KStandardAction::Forward, QStringLiteral("projects_next_project"), this, SLOT(slotProjectNext())); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Right)); a = actionCollection()->addAction(KStandardAction::Goto, QStringLiteral("projects_goto_index"), this, SLOT(slotProjectIndex())); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::ALT | Qt::Key_1)); // popup menu auto popup = new KActionMenu(i18n("Project"), this); - actionCollection()->addAction(QLatin1String("popup_project"), popup); + actionCollection()->addAction(QStringLiteral("popup_project"), popup); - m_lookupAction = popup->menu()->addAction(i18n("Lookup: %1", QString()), this, SLOT(slotProjectIndex())); + m_lookupAction = popup->menu()->addAction(i18n("Lookup: %1", QString()), this, &KateProjectPluginView::slotProjectIndex); connect(popup->menu(), &QMenu::aboutToShow, this, &KateProjectPluginView::slotContextMenuAboutToShow); /** * add us to gui */ m_mainWindow->guiFactory()->addClient(this); } KateProjectPluginView::~KateProjectPluginView() { /** * cleanup for all views */ foreach(QObject * view, m_textViews) { KTextEditor::CodeCompletionInterface *cci = qobject_cast(view); if (cci) { cci->unregisterCompletionModel(m_plugin->completion()); } } /** * cu toolviews */ delete m_toolView; m_toolView = nullptr; delete m_toolInfoView; m_toolInfoView = nullptr; /** * cu gui client */ m_mainWindow->guiFactory()->removeClient(this); } QPair KateProjectPluginView::viewForProject(KateProject *project) { /** * needs valid project */ Q_ASSERT(project); /** * create toolviews on demand */ if (!m_toolView) { /** * create toolviews */ m_toolView = m_mainWindow->createToolView(m_plugin, QStringLiteral("kateproject"), KTextEditor::MainWindow::Left, QIcon::fromTheme(QStringLiteral("project-open")), i18n("Projects")); m_toolInfoView = m_mainWindow->createToolView(m_plugin, QStringLiteral("kateprojectinfo"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme(QStringLiteral("view-choose")), i18n("Current Project")); /** * create the combo + buttons for the toolViews + stacked widgets */ m_projectsCombo = new QComboBox(m_toolView); m_projectsCombo->setFrame(false); m_reloadButton = new QToolButton(m_toolView); m_reloadButton->setAutoRaise(true); m_reloadButton->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); QHBoxLayout *layout = new QHBoxLayout(); layout->setSpacing(0); layout->addWidget(m_projectsCombo); layout->addWidget(m_reloadButton); m_toolView->layout()->addItem(layout); m_toolView->layout()->setSpacing(0); m_stackedProjectViews = new QStackedWidget(m_toolView); m_stackedProjectInfoViews = new QStackedWidget(m_toolInfoView); connect(m_projectsCombo, static_cast(&QComboBox::currentIndexChanged), this, &KateProjectPluginView::slotCurrentChanged); connect(m_reloadButton, &QToolButton::clicked, this, &KateProjectPluginView::slotProjectReload); } /** * existing view? */ if (m_project2View.contains(project)) { return m_project2View.value(project); } /** * create new views */ KateProjectView *view = new KateProjectView(this, project); KateProjectInfoView *infoView = new KateProjectInfoView(this, project); /** * attach to toolboxes * first the views, then the combo, that triggers signals */ m_stackedProjectViews->addWidget(view); m_stackedProjectInfoViews->addWidget(infoView); m_stackedProjectInfoViews->setFocusProxy(infoView); m_projectsCombo->addItem(QIcon::fromTheme(QStringLiteral("project-open")), project->name(), project->fileName()); /** * remember and return it */ return (m_project2View[project] = QPair (view, infoView)); } QString KateProjectPluginView::projectFileName() const { // nothing there, skip if (!m_toolView) { return QString(); } QWidget *active = m_stackedProjectViews->currentWidget(); if (!active) { return QString(); } return static_cast(active)->project()->fileName(); } QString KateProjectPluginView::projectName() const { // nothing there, skip if (!m_toolView) { return QString(); } QWidget *active = m_stackedProjectViews->currentWidget(); if (!active) { return QString(); } return static_cast(active)->project()->name(); } QString KateProjectPluginView::projectBaseDir() const { // nothing there, skip if (!m_toolView) { return QString(); } QWidget *active = m_stackedProjectViews->currentWidget(); if (!active) { return QString(); } return static_cast(active)->project()->baseDir(); } QVariantMap KateProjectPluginView::projectMap() const { // nothing there, skip if (!m_toolView) { return QVariantMap(); } QWidget *active = m_stackedProjectViews->currentWidget(); if (!active) { return QVariantMap(); } return static_cast(active)->project()->projectMap(); } QStringList KateProjectPluginView::projectFiles() const { // nothing there, skip if (!m_toolView) { return QStringList(); } KateProjectView *active = static_cast(m_stackedProjectViews->currentWidget()); if (!active) { return QStringList(); } return active->project()->files(); } QString KateProjectPluginView::allProjectsCommonBaseDir() const { auto projects = m_plugin->projects(); if (projects.empty()) { return QString(); } if (projects.size() == 1) { return projects[0]->baseDir(); } QString commonParent1 = FileUtil::commonParent(projects[0]->baseDir(), projects[1]->baseDir()); for (int i = 2; i < projects.size(); i++) { commonParent1 = FileUtil::commonParent(commonParent1, projects[i]->baseDir()); } return commonParent1; } QStringList KateProjectPluginView::allProjectsFiles() const { QStringList fileList; foreach (auto project, m_plugin->projects()) { fileList.append(project->files()); } return fileList; } void KateProjectPluginView::slotViewChanged() { /** * get active view */ KTextEditor::View *activeView = m_mainWindow->activeView(); /** * update pointer, maybe disconnect before */ if (m_activeTextEditorView) { m_activeTextEditorView->document()->disconnect(this); } m_activeTextEditorView = activeView; /** * no current active view, return */ if (!m_activeTextEditorView) { return; } /** * connect to url changed, for auto load */ connect(m_activeTextEditorView->document(), &KTextEditor::Document::documentUrlChanged, this, &KateProjectPluginView::slotDocumentUrlChanged); /** * trigger slot once */ slotDocumentUrlChanged(m_activeTextEditorView->document()); } void KateProjectPluginView::slotCurrentChanged(int index) { // nothing there, skip if (!m_toolView) { return; } /** * trigger change of stacked widgets */ m_stackedProjectViews->setCurrentIndex(index); m_stackedProjectInfoViews->setCurrentIndex(index); /** * open currently selected document */ if (QWidget *current = m_stackedProjectViews->currentWidget()) { static_cast(current)->openSelectedDocument(); } /** * project file name might have changed */ emit projectFileNameChanged(); emit projectMapChanged(); } void KateProjectPluginView::slotDocumentUrlChanged(KTextEditor::Document *document) { /** * abort if empty url or no local path */ if (document->url().isEmpty() || !document->url().isLocalFile()) { return; } /** * search matching project */ KateProject *project = m_plugin->projectForUrl(document->url()); if (!project) { return; } /** * select the file FIRST */ m_project2View.value(project).first->selectFile(document->url().toLocalFile()); /** * get active project view and switch it, if it is for a different project * do this AFTER file selection */ KateProjectView *active = static_cast(m_stackedProjectViews->currentWidget()); if (active != m_project2View.value(project).first) { int index = m_projectsCombo->findData(project->fileName()); if (index >= 0) { m_projectsCombo->setCurrentIndex(index); } } } void KateProjectPluginView::slotViewCreated(KTextEditor::View *view) { /** * connect to destroyed */ connect(view, &KTextEditor::View::destroyed, this, &KateProjectPluginView::slotViewDestroyed); /** * add completion model if possible */ KTextEditor::CodeCompletionInterface *cci = qobject_cast(view); if (cci) { cci->registerCompletionModel(m_plugin->completion()); } /** * remember for this view we need to cleanup! */ m_textViews.insert(view); } void KateProjectPluginView::slotViewDestroyed(QObject *view) { /** * remove remembered views for which we need to cleanup on exit! */ m_textViews.remove(view); } void KateProjectPluginView::slotProjectPrev() { // nothing there, skip if (!m_toolView) { return; } if (!m_projectsCombo->count()) { return; } if (m_projectsCombo->currentIndex() == 0) { m_projectsCombo->setCurrentIndex(m_projectsCombo->count() - 1); } else { m_projectsCombo->setCurrentIndex(m_projectsCombo->currentIndex() - 1); } } void KateProjectPluginView::slotProjectNext() { // nothing there, skip if (!m_toolView) { return; } if (!m_projectsCombo->count()) { return; } if (m_projectsCombo->currentIndex() + 1 == m_projectsCombo->count()) { m_projectsCombo->setCurrentIndex(0); } else { m_projectsCombo->setCurrentIndex(m_projectsCombo->currentIndex() + 1); } } void KateProjectPluginView::slotProjectReload() { // nothing there, skip if (!m_toolView) { return; } /** * force reload if any active project */ if (QWidget *current = m_stackedProjectViews->currentWidget()) { static_cast(current)->project()->reload(true); } } QString KateProjectPluginView::currentWord() const { KTextEditor::View *kv = m_activeTextEditorView; if (!kv) { return QString(); } if (kv->selection() && kv->selectionRange().onSingleLine()) { return kv->selectionText(); } return kv->document()->wordAt(kv->cursorPosition()); } void KateProjectPluginView::slotProjectIndex() { if (!m_toolView) { return; } const QString word = currentWord(); if (!word.isEmpty()) { auto tabView = qobject_cast(m_stackedProjectInfoViews->currentWidget()); if (tabView) { tabView->setCurrentIndex(1); } m_mainWindow->showToolView(m_toolInfoView); emit projectLookupWord(word); } } void KateProjectPluginView::slotContextMenuAboutToShow() { const QString word = currentWord(); if (word.isEmpty()) { return; } const QString squeezed = KStringHandler::csqueeze(word, 30); m_lookupAction->setText(i18n("Lookup: %1", squeezed)); } #include "kateprojectpluginview.moc" diff --git a/addons/project/kateprojecttreeviewcontextmenu.cpp b/addons/project/kateprojecttreeviewcontextmenu.cpp index ea3700a75..d33a7a997 100644 --- a/addons/project/kateprojecttreeviewcontextmenu.cpp +++ b/addons/project/kateprojecttreeviewcontextmenu.cpp @@ -1,153 +1,153 @@ /* This file is part of the Kate project. * * Copyright (C) 2013 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 "kateprojecttreeviewcontextmenu.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include KateProjectTreeViewContextMenu::KateProjectTreeViewContextMenu() { } KateProjectTreeViewContextMenu::~KateProjectTreeViewContextMenu() { } static bool isGit(const QString &filename) { QFileInfo fi(filename); QDir dir(fi.absoluteDir()); QProcess git; git.setWorkingDirectory(dir.absolutePath()); QStringList args; args << QStringLiteral("ls-files") << fi.fileName(); git.start(QStringLiteral("git"), args); bool isGit = false; if (git.waitForStarted() && git.waitForFinished(-1)) { QStringList files = QString::fromLocal8Bit(git.readAllStandardOutput()).split(QRegExp(QStringLiteral("[\n\r]")), QString::SkipEmptyParts); isGit = files.contains(fi.fileName()); } return isGit; } void KateProjectTreeViewContextMenu::exec(const QString &filename, const QPoint &pos, QWidget *parent) { /** * Create context menu */ QMenu menu; /** * Copy Path */ QAction *copyAction = menu.addAction(QIcon::fromTheme(QStringLiteral("edit-copy")), i18n("Copy File Path")); /** * Handle "open with", * find correct mimetype to query for possible applications */ QMenu *openWithMenu = menu.addMenu(i18n("Open With")); QMimeType mimeType = QMimeDatabase().mimeTypeForFile(filename); KService::List offers = KMimeTypeTrader::self()->query(mimeType.name(), QStringLiteral("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() == QStringLiteral("Kate")) { continue; // omit Kate } QAction *action = openWithMenu->addAction(QIcon::fromTheme(service->icon()), service->name()); action->setData(service->entryPath()); } // Perhaps disable menu, if no entries openWithMenu->setEnabled(!openWithMenu->isEmpty()); /** * Open Containing folder */ auto openContaingFolderAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-open-folder")), i18n("&Open Containing Folder")); /** * File Properties Dialog */ auto filePropertiesAction = menu.addAction(QIcon::fromTheme(QStringLiteral("dialog-object-properties")), i18n("Properties")); /** * Git menu */ - KMoreToolsMenuFactory menuFactory(QLatin1String("kate/addons/project/git-tools")); + KMoreToolsMenuFactory menuFactory(QStringLiteral("kate/addons/project/git-tools")); QMenu gitMenu; // must live as long as the maybe filled menu items should live if (isGit(filename)) { menuFactory.fillMenuFromGroupingNames(&gitMenu, { QLatin1String("git-clients-and-actions") }, QUrl::fromLocalFile(filename)); menu.addSection(i18n("Git:")); Q_FOREACH(auto action, gitMenu.actions()) { menu.addAction(action); } } /** * run menu and handle the triggered action */ if (QAction* const action = menu.exec(pos)) { if (action == copyAction) { QApplication::clipboard()->setText(filename); } else if (action->parentWidget() == openWithMenu) { // handle "open with" const QString openWith = action->data().toString(); if (KService::Ptr app = KService::serviceByDesktopPath(openWith)) { QList list; list << QUrl::fromLocalFile(filename); KRun::runService(*app, list, parent); } } else if (action == openContaingFolderAction) { KIO::highlightInFileManager({ QUrl::fromLocalFile(filename) }); } else if (action == filePropertiesAction) { // code copied and adapted from frameworks/kio/src/filewidgets/knewfilemenu.cpp KFileItem fileItem(QUrl::fromLocalFile(filename)); QDialog* dlg = new KPropertiesDialog(fileItem); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->show(); } else { // One of the git actions was triggered } } } diff --git a/addons/project/kateprojectview.cpp b/addons/project/kateprojectview.cpp index fe73356eb..764ce19d5 100644 --- a/addons/project/kateprojectview.cpp +++ b/addons/project/kateprojectview.cpp @@ -1,87 +1,87 @@ /* 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 "kateprojectview.h" #include "kateprojectpluginview.h" #include #include #include #include #include #include #include KateProjectView::KateProjectView(KateProjectPluginView *pluginView, KateProject *project) : QWidget() , m_pluginView(pluginView) , m_project(project) , m_treeView(new KateProjectViewTree(pluginView, project)) , m_filter(new KLineEdit()) { /** * layout tree view and co. */ QVBoxLayout *layout = new QVBoxLayout(); layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(m_treeView); layout->addWidget(m_filter); setLayout(layout); /** * setup filter line edit */ m_filter->setPlaceholderText(i18n("Search")); m_filter->setClearButtonEnabled(true); connect(m_filter, &KLineEdit::textChanged, this, &KateProjectView::filterTextChanged); } KateProjectView::~KateProjectView() { } void KateProjectView::selectFile(const QString &file) { m_treeView->selectFile(file); } void KateProjectView::openSelectedDocument() { m_treeView->openSelectedDocument(); } -void KateProjectView::filterTextChanged(QString filterText) +void KateProjectView::filterTextChanged(const QString &filterText) { /** * filter */ static_cast(m_treeView->model())->setFilterFixedString(filterText); /** * expand */ if (!filterText.isEmpty()) { - QTimer::singleShot(100, m_treeView, SLOT(expandAll())); + QTimer::singleShot(100, m_treeView, &QTreeView::expandAll); } } diff --git a/addons/project/kateprojectview.h b/addons/project/kateprojectview.h index 44dc3ed4d..d340bf2ac 100644 --- a/addons/project/kateprojectview.h +++ b/addons/project/kateprojectview.h @@ -1,100 +1,100 @@ /* 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_PROJECT_VIEW_H #define KATE_PROJECT_VIEW_H #include "kateproject.h" #include "kateprojectviewtree.h" class KLineEdit; class KateProjectPluginView; /** * Class representing a view of a project. * A tree like view of project content. */ class KateProjectView : public QWidget { Q_OBJECT public: /** * construct project view for given project * @param pluginView our plugin view * @param project project this view is for */ KateProjectView(KateProjectPluginView *pluginView, KateProject *project); /** * deconstruct project */ ~KateProjectView() override; /** * our project. * @return project */ KateProject *project() const { return m_project; } /** * Select given file in the view. * @param file select this file in the view, will be shown if invisible */ void selectFile(const QString &file); /** * Open the selected document, if any. */ void openSelectedDocument(); private Q_SLOTS: /** * React on filter change * @param filterText new filter text */ - void filterTextChanged(QString filterText); + void filterTextChanged(const QString &filterText); private: /** * our plugin view */ KateProjectPluginView *m_pluginView; /** * our project */ KateProject *m_project; /** * our tree view */ KateProjectViewTree *m_treeView; /** * filter */ KLineEdit *m_filter; }; #endif diff --git a/addons/search/plugin_search.cpp b/addons/search/plugin_search.cpp index 68dab2ebd..780ba5f5e 100644 --- a/addons/search/plugin_search.cpp +++ b/addons/search/plugin_search.cpp @@ -1,2243 +1,2243 @@ /* Kate search plugin * * Copyright (C) 2011-2013 by KÃ¥re Särs * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program in a file called COPYING; if not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include "plugin_search.h" #include "htmldelegate.h" #include #include #include #include #include #include #include #include #include "kacceleratormanager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static QUrl localFileDirUp (const QUrl &url) { if (!url.isLocalFile()) return url; // else go up return QUrl::fromLocalFile (QFileInfo (url.toLocalFile()).dir().absolutePath()); } static QAction *menuEntry(QMenu *menu, const QString &before, const QString &after, const QString &desc, QString menuBefore = QString(), QString menuAfter = QString()); static QAction *menuEntry(QMenu *menu, const QString &before, const QString &after, const QString &desc, QString menuBefore, QString menuAfter) { if (menuBefore.isEmpty()) menuBefore = before; if (menuAfter.isEmpty()) menuAfter = after; QAction *const action = menu->addAction(menuBefore + menuAfter + QLatin1Char('\t') + desc); if (!action) return nullptr; action->setData(QString(before + QLatin1Char(' ') + after)); return action; } class TreeWidgetItem : public QTreeWidgetItem { public: TreeWidgetItem(QTreeWidget* parent):QTreeWidgetItem(parent){} TreeWidgetItem(QTreeWidget* parent, const QStringList &list):QTreeWidgetItem(parent, list){} TreeWidgetItem(QTreeWidgetItem* parent, const QStringList &list):QTreeWidgetItem(parent, list){} private: bool operator<(const QTreeWidgetItem &other) const override { if (childCount() == 0) { int line = data(0, ReplaceMatches::StartLineRole).toInt(); int column = data(0, ReplaceMatches::StartColumnRole).toInt(); int oLine = other.data(0, ReplaceMatches::StartLineRole).toInt(); int oColumn = other.data(0, ReplaceMatches::StartColumnRole).toInt(); if (line < oLine) { return true; } if ((line == oLine) && (column < oColumn)) { return true; } return false; } int sepCount = data(0, ReplaceMatches::FileUrlRole).toString().count(QDir::separator()); int oSepCount = other.data(0, ReplaceMatches::FileUrlRole).toString().count(QDir::separator()); if (sepCount < oSepCount) return true; if (sepCount > oSepCount) return false; return data(0, ReplaceMatches::FileUrlRole).toString().toLower() < other.data(0, ReplaceMatches::FileUrlRole).toString().toLower(); } }; Results::Results(QWidget *parent): QWidget(parent), matches(0), useRegExp(false), searchPlaceIndex(0) { setupUi(this); tree->setItemDelegate(new SPHtmlDelegate(tree)); } K_PLUGIN_FACTORY_WITH_JSON (KatePluginSearchFactory, "katesearch.json", registerPlugin();) KatePluginSearch::KatePluginSearch(QObject* parent, const QList&) : KTextEditor::Plugin (parent), m_searchCommand(nullptr) { m_searchCommand = new KateSearchCommand(this); } KatePluginSearch::~KatePluginSearch() { delete m_searchCommand; } QObject *KatePluginSearch::createView(KTextEditor::MainWindow *mainWindow) { KatePluginSearchView *view = new KatePluginSearchView(this, mainWindow, KTextEditor::Editor::instance()->application()); connect(m_searchCommand, &KateSearchCommand::setSearchPlace, view, &KatePluginSearchView::setSearchPlace); connect(m_searchCommand, &KateSearchCommand::setCurrentFolder, view, &KatePluginSearchView::setCurrentFolder); connect(m_searchCommand, &KateSearchCommand::setSearchString, view, &KatePluginSearchView::setSearchString); connect(m_searchCommand, &KateSearchCommand::startSearch, view, &KatePluginSearchView::startSearch); connect(m_searchCommand, SIGNAL(newTab()), view, SLOT(addTab())); return view; } bool ContainerWidget::focusNextPrevChild (bool next) { QWidget* fw = focusWidget(); bool found = false; emit nextFocus(fw, &found, next); if (found) { return true; } return QWidget::focusNextPrevChild(next); } void KatePluginSearchView::nextFocus(QWidget *currentWidget, bool *found, bool next) { *found = false; if (!currentWidget) { return; } // we use the object names here because there can be multiple replaceButtons (on multiple result tabs) if (next) { if (currentWidget->objectName() == QStringLiteral("tree") || currentWidget == m_ui.binaryCheckBox) { m_ui.newTabButton->setFocus(); *found = true; return; } if (currentWidget == m_ui.displayOptions) { if (m_ui.displayOptions->isChecked()) { m_ui.folderRequester->setFocus(); *found = true; return; } else { Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!res) { return; } res->tree->setFocus(); *found = true; return; } } } else { if (currentWidget == m_ui.newTabButton) { if (m_ui.displayOptions->isChecked()) { m_ui.binaryCheckBox->setFocus(); } else { Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!res) { return; } res->tree->setFocus(); } *found = true; return; } else { if (currentWidget->objectName() == QStringLiteral("tree")) { m_ui.displayOptions->setFocus(); *found = true; return; } } } } KatePluginSearchView::KatePluginSearchView(KTextEditor::Plugin *plugin, KTextEditor::MainWindow *mainWin, KTextEditor::Application* application) : QObject (mainWin), m_kateApp(application), m_curResults(nullptr), m_searchJustOpened(false), m_switchToProjectModeWhenAvailable(false), m_searchDiskFilesDone(true), m_searchOpenFilesDone(true), m_isSearchAsYouType(false), 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, &ContainerWidget::nextFocus, this, &KatePluginSearchView::nextFocus); QAction *a = actionCollection()->addAction(QStringLiteral("search_in_files")); actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_F)); a->setText(i18n("Search in Files")); connect(a, &QAction::triggered, this, &KatePluginSearchView::openSearchView); a = actionCollection()->addAction(QStringLiteral("search_in_files_new_tab")); a->setText(i18n("Search in Files (in new tab)")); // first add tab, then open search view, since open search view switches to show the search options connect(a, &QAction::triggered, this, &KatePluginSearchView::addTab); connect(a, &QAction::triggered, this, &KatePluginSearchView::openSearchView); a = actionCollection()->addAction(QStringLiteral("go_to_next_match")); a->setText(i18n("Go to Next Match")); connect(a, &QAction::triggered, this, &KatePluginSearchView::goToNextMatch); a = actionCollection()->addAction(QStringLiteral("go_to_prev_match")); a->setText(i18n("Go to Previous Match")); connect(a, &QAction::triggered, this, &KatePluginSearchView::goToPreviousMatch); m_ui.resultTabWidget->tabBar()->setSelectionBehaviorOnRemove(QTabBar::SelectLeftTab); KAcceleratorManager::setNoAccel(m_ui.resultTabWidget); // Gnome does not seem to have all icons we want, so we use fall-back icons for those that are missing. QIcon dispOptIcon = QIcon::fromTheme(QStringLiteral("games-config-options"), QIcon::fromTheme(QStringLiteral("preferences-system"))); QIcon matchCaseIcon = QIcon::fromTheme(QStringLiteral("format-text-superscript"), QIcon::fromTheme(QStringLiteral("format-text-bold"))); QIcon useRegExpIcon = QIcon::fromTheme(QStringLiteral("code-context"), QIcon::fromTheme(QStringLiteral("edit-find-replace"))); QIcon expandResultsIcon = QIcon::fromTheme(QStringLiteral("view-list-tree"), QIcon::fromTheme(QStringLiteral("format-indent-more"))); m_ui.displayOptions->setIcon(dispOptIcon); 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(matchCaseIcon); m_ui.useRegExp->setIcon(useRegExpIcon); m_ui.expandResults->setIcon(expandResultsIcon); 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, &QToolButton::clicked, this, &KatePluginSearchView::addTab); connect(m_ui.resultTabWidget, &QTabWidget::tabCloseRequested, this, &KatePluginSearchView::tabCloseRequested); connect(m_ui.resultTabWidget, &QTabWidget::currentChanged, this, &KatePluginSearchView::resultTabChanged); connect(m_ui.folderUpButton, &QToolButton::clicked, this, &KatePluginSearchView::navigateFolderUp); connect(m_ui.currentFolderButton, &QToolButton::clicked, this, &KatePluginSearchView::setCurrentFolder); connect(m_ui.expandResults, &QToolButton::clicked, this, &KatePluginSearchView::expandResults); connect(m_ui.searchCombo, &QComboBox::editTextChanged, &m_changeTimer, static_cast(&QTimer::start)); connect(m_ui.matchCase, &QToolButton::toggled, &m_changeTimer, static_cast(&QTimer::start)); connect(m_ui.matchCase, &QToolButton::toggled, this, [=]{ Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (res) { res->matchCase = m_ui.matchCase->isChecked(); } }); connect(m_ui.useRegExp, &QToolButton::toggled, &m_changeTimer, static_cast(&QTimer::start)); connect(m_ui.useRegExp, &QToolButton::toggled, this, [=]{ 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, &QTimer::timeout, this, &KatePluginSearchView::startSearchWhileTyping); connect(m_ui.searchCombo->lineEdit(), &QLineEdit::returnPressed, this, &KatePluginSearchView::startSearch); // connecting to returnPressed() of the folderRequester doesn't work, I haven't found out why yet. But connecting to the linedit works: connect(m_ui.folderRequester->comboBox()->lineEdit(), &QLineEdit::returnPressed, this, &KatePluginSearchView::startSearch); connect(m_ui.filterCombo, static_cast(&KComboBox::returnPressed), this, &KatePluginSearchView::startSearch); connect(m_ui.excludeCombo, static_cast(&KComboBox::returnPressed), this, &KatePluginSearchView::startSearch); connect(m_ui.searchButton, &QPushButton::clicked, this, &KatePluginSearchView::startSearch); connect(m_ui.displayOptions, &QToolButton::toggled, this, &KatePluginSearchView::toggleOptions); connect(m_ui.searchPlaceCombo, static_cast(&QComboBox::currentIndexChanged), this, &KatePluginSearchView::searchPlaceChanged); connect(m_ui.searchPlaceCombo, static_cast(&QComboBox::currentIndexChanged), this, [this](int) { if (m_ui.searchPlaceCombo->currentIndex() == Folder) { m_ui.displayOptions->setChecked(true); } }); connect(m_ui.stopButton, &QPushButton::clicked, &m_searchOpenFiles, &SearchOpenFiles::cancelSearch); connect(m_ui.stopButton, &QPushButton::clicked, &m_searchDiskFiles, &SearchDiskFiles::cancelSearch); connect(m_ui.stopButton, &QPushButton::clicked, &m_folderFilesList, &FolderFilesList::cancelSearch); connect(m_ui.stopButton, &QPushButton::clicked, &m_replacer, &ReplaceMatches::cancelReplace); connect(m_ui.nextButton, &QToolButton::clicked, this, &KatePluginSearchView::goToNextMatch); connect(m_ui.replaceButton, &QPushButton::clicked, this, &KatePluginSearchView::replaceSingleMatch); connect(m_ui.replaceCheckedBtn, &QPushButton::clicked, this, &KatePluginSearchView::replaceChecked); connect(m_ui.replaceCombo->lineEdit(), &QLineEdit::returnPressed, this, &KatePluginSearchView::replaceChecked); m_ui.displayOptions->setChecked(true); connect(&m_searchOpenFiles, &SearchOpenFiles::matchFound, this, &KatePluginSearchView::matchFound); connect(&m_searchOpenFiles, &SearchOpenFiles::searchDone, this, &KatePluginSearchView::searchDone); connect(&m_searchOpenFiles, static_cast(&SearchOpenFiles::searching), this, &KatePluginSearchView::searching); connect(&m_folderFilesList, &FolderFilesList::finished, this, &KatePluginSearchView::folderFileListChanged); connect(&m_folderFilesList, &FolderFilesList::searching, this, &KatePluginSearchView::searching); connect(&m_searchDiskFiles, &SearchDiskFiles::matchFound, this, &KatePluginSearchView::matchFound); connect(&m_searchDiskFiles, &SearchDiskFiles::searchDone, this, &KatePluginSearchView::searchDone); connect(&m_searchDiskFiles, static_cast(&SearchDiskFiles::searching), this, &KatePluginSearchView::searching); connect(m_kateApp, &KTextEditor::Application::documentWillBeDeleted, &m_searchOpenFiles, &SearchOpenFiles::cancelSearch); connect(m_kateApp, &KTextEditor::Application::documentWillBeDeleted, &m_replacer, &ReplaceMatches::cancelReplace); connect(m_kateApp, &KTextEditor::Application::documentWillBeDeleted, this, &KatePluginSearchView::clearDocMarks); connect(&m_replacer, &ReplaceMatches::replaceStatus, this, &KatePluginSearchView::replaceStatus); // Hook into line edit context menus m_ui.searchCombo->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_ui.searchCombo, &QComboBox::customContextMenuRequested, this, &KatePluginSearchView::searchContextMenu); m_ui.searchCombo->completer()->setCompletionMode(QCompleter::PopupCompletion); m_ui.searchCombo->completer()->setCaseSensitivity(Qt::CaseSensitive); m_ui.searchCombo->setInsertPolicy(QComboBox::NoInsert); m_ui.searchCombo->lineEdit()->setClearButtonEnabled(true); m_ui.searchCombo->setMaxCount(25); m_ui.replaceCombo->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_ui.replaceCombo, &QComboBox::customContextMenuRequested, this, &KatePluginSearchView::replaceContextMenu); 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, &KTextEditor::MainWindow::unhandledShortcutOverride, this, &KatePluginSearchView::handleEsc); // watch for project plugin view creation/deletion connect(m_mainWindow, &KTextEditor::MainWindow::pluginViewCreated, this, &KatePluginSearchView::slotPluginViewCreated); connect(m_mainWindow, &KTextEditor::MainWindow::pluginViewDeleted, this, &KatePluginSearchView::slotPluginViewDeleted); connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KatePluginSearchView::docViewChanged); // Connect signals from project plugin to our slots m_projectPluginView = m_mainWindow->pluginView(QStringLiteral("kateprojectplugin")); slotPluginViewCreated(QStringLiteral("kateprojectplugin"), m_projectPluginView); m_replacer.setDocumentManager(m_kateApp); connect(&m_replacer, &ReplaceMatches::replaceDone, this, &KatePluginSearchView::replaceDone); searchPlaceChanged(); m_toolView->installEventFilter(this); m_mainWindow->guiFactory()->addClient(this); m_updateSumaryTimer.setInterval(1); m_updateSumaryTimer.setSingleShot(true); connect(&m_updateSumaryTimer, &QTimer::timeout, this, &KatePluginSearchView::updateResultsRootItem); } 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); } // Remove check marks Results *curResults = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!curResults) { qWarning() << "This is a bug"; return; } QTreeWidgetItemIterator it(curResults->tree); while (*it) { (*it)->setCheckState(0, Qt::Unchecked); ++it; } } } void KatePluginSearchView::setSearchString(const QString &pattern) { m_ui.searchCombo->lineEdit()->setText(pattern); } void KatePluginSearchView::toggleOptions(bool show) { m_ui.stackedWidget->setCurrentIndex((show) ? 1:0); } void KatePluginSearchView::setSearchPlace(int place) { m_ui.searchPlaceCombo->setCurrentIndex(place); } QStringList KatePluginSearchView::filterFiles(const QStringList& files) const { QString types = m_ui.filterCombo->currentText(); QString excludes = m_ui.excludeCombo->currentText(); if (((types.isEmpty() || types == QStringLiteral("*"))) && (excludes.isEmpty())) { // shortcut for use all files return files; } QStringList tmpTypes = types.split(QLatin1Char(',')); QVector typeList; for (int i=0; i excludeList; for (int i=0; i openList; for (int i=0; idocuments().size(); i++) { int index = fileList.indexOf(m_kateApp->documents()[i]->url().toLocalFile()); if (index != -1) { openList << m_kateApp->documents()[i]; fileList.removeAt(index); } } // search order is important: Open files starts immediately and should finish // earliest after first event loop. // The DiskFile might finish immediately if (openList.size() > 0) { m_searchOpenFiles.startSearch(openList, m_curResults->regExp); } else { m_searchOpenFilesDone = true; } m_searchDiskFiles.startSearch(fileList, m_curResults->regExp); } void KatePluginSearchView::searchPlaceChanged() { int searchPlace = m_ui.searchPlaceCombo->currentIndex(); const bool inFolder = (searchPlace == Folder); m_ui.filterCombo->setEnabled(searchPlace >= Folder); m_ui.excludeCombo->setEnabled(searchPlace >= Folder); m_ui.folderRequester->setEnabled(inFolder); m_ui.folderUpButton->setEnabled(inFolder); m_ui.currentFolderButton->setEnabled(inFolder); m_ui.recursiveCheckBox->setEnabled(inFolder); m_ui.hiddenCheckBox->setEnabled(inFolder); m_ui.symLinkCheckBox->setEnabled(inFolder); m_ui.binaryCheckBox->setEnabled(inFolder); if (inFolder && sender() == m_ui.searchPlaceCombo) { setCurrentFolder(); } // ... and the labels: m_ui.folderLabel->setEnabled(m_ui.folderRequester->isEnabled()); m_ui.filterLabel->setEnabled(m_ui.filterCombo->isEnabled()); m_ui.excludeLabel->setEnabled(m_ui.excludeCombo->isEnabled()); Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (res) { res->searchPlaceIndex = searchPlace; } } void KatePluginSearchView::addHeaderItem() { QTreeWidgetItem *item = new QTreeWidgetItem(m_curResults->tree, QStringList()); item->setCheckState(0, Qt::Checked); item->setFlags(item->flags() | Qt::ItemIsTristate); m_curResults->tree->expandItem(item); } QTreeWidgetItem * KatePluginSearchView::rootFileItem(const QString &url, const QString &fName) { if (!m_curResults) { return nullptr; } QUrl fullUrl = QUrl::fromUserInput(url); QString path = fullUrl.isLocalFile() ? localFileDirUp(fullUrl).path() : fullUrl.url(); if (!path.isEmpty() && !path.endsWith(QLatin1Char('/'))) { path += QLatin1Char('/'); } path.replace(m_resultBaseDir, QString()); QString name = fullUrl.fileName(); if (url.isEmpty()) { name = fName; } // make sure we have a root item if (m_curResults->tree->topLevelItemCount() == 0) { addHeaderItem(); } QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); if (m_isSearchAsYouType) { 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::StartLineRole).toInt() + 1; - QString tmpUrl = QString::fromLatin1("%1%2: %3").arg(path).arg(name).arg(matches); + QString tmpUrl = QStringLiteral("%1%2: %3").arg(path, name).arg(matches); root->child(i)->setData(0, Qt::DisplayRole, tmpUrl); root->child(i)->setData(0, ReplaceMatches::StartLineRole, 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); + QString tmpUrl = QStringLiteral("%1%2: %3").arg(path, 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::StartLineRole, 1); item->setCheckState(0, Qt::Checked); item->setFlags(item->flags() | Qt::ItemIsTristate); return item; } void KatePluginSearchView::addMatchMark(KTextEditor::Document* doc, QTreeWidgetItem *item) { if (!doc || !item) { 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()); int line = item->data(0, ReplaceMatches::StartLineRole).toInt(); int column = item->data(0, ReplaceMatches::StartColumnRole).toInt(); int endLine = item->data(0, ReplaceMatches::EndLineRole).toInt(); int endColumn = item->data(0, ReplaceMatches::EndColumnRole).toInt(); bool isReplaced = item->data(0, ReplaceMatches::ReplacedRole).toBool(); if (isReplaced) { 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()); } } KTextEditor::Range range(line, column, endLine, endColumn); // Check that the match still matches if (m_curResults) { if (!isReplaced) { // 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); } // Check that the match still matches ;) if (tmpReg.match(doc->text(range)).capturedStart() != 0) { qDebug() << doc->text(range) << "Does not match" << m_curResults->regExp.pattern(); return; } } else { if (doc->text(range) != item->data(0, ReplaceMatches::ReplacedTextRole).toString()) { qDebug() << doc->text(range) << "Does not match" << item->data(0, ReplaceMatches::ReplacedTextRole).toString(); return; } } } // Highlight the match 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); // Add a match mark 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); } static const int contextLen = 70; void KatePluginSearchView::matchFound(const QString &url, const QString &fName, const QString &lineContent, int matchLen, int startLine, int startColumn, int endLine, int endColumn) { if (!m_curResults) { return; } int preLen = contextLen; int preStart = startColumn - preLen; if (preStart < 0) { preLen += preStart; preStart = 0; } QString pre; if (preLen == contextLen) { pre = QStringLiteral("..."); } pre += lineContent.mid(preStart, preLen).toHtmlEscaped(); QString match = lineContent.mid(startColumn, matchLen).toHtmlEscaped(); match.replace(QLatin1Char('\n'), QStringLiteral("\\n")); QString post = lineContent.mid(startColumn + matchLen, contextLen); if (post.size() >= contextLen) { post += QStringLiteral("..."); } post = post.toHtmlEscaped(); QStringList row; row << i18n("Line: %1 Column: %2: %3", startLine+1, startColumn+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::StartLineRole, startLine); item->setData(0, ReplaceMatches::StartColumnRole, startColumn); 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->setData(0, ReplaceMatches::EndLineRole, endLine); item->setData(0, ReplaceMatches::EndColumnRole, endColumn); item->setCheckState (0, Qt::Checked); m_curResults->matches++; } void KatePluginSearchView::clearMarks() { foreach (KTextEditor::Document* doc, m_kateApp->documents()) { clearDocMarks(doc); } qDeleteAll(m_matchRanges); m_matchRanges.clear(); } void KatePluginSearchView::clearDocMarks(KTextEditor::Document* doc) { 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) { delete m_matchRanges.at(i); m_matchRanges.removeAt(i); } else { i++; } } m_curResults = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!m_curResults) { qWarning() << "This is a bug"; return; } } 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; } m_isSearchAsYouType = false; 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; disconnect(m_curResults->tree, &QTreeWidget::itemChanged, &m_updateSumaryTimer, nullptr); 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; } m_isSearchAsYouType = true; 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; } disconnect(m_curResults->tree, &QTreeWidget::itemChanged, &m_updateSumaryTimer, nullptr); 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::StartLineRole, 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 expandResults(); updateResultsRootItem(); connect(m_curResults->tree, &QTreeWidget::itemChanged, &m_updateSumaryTimer, static_cast(&QTimer::start)); indicateMatch(m_curResults->matches > 0); m_curResults = nullptr; m_toolView->unsetCursor(); if (fw == m_ui.stopButton) { m_ui.searchCombo->setFocus(); } m_searchJustOpened = false; } void KatePluginSearchView::searchWhileTypingDone() { if (!m_curResults) { return; } bool popupVisible = m_ui.searchCombo->lineEdit()->completer()->popup()->isVisible(); m_ui.replaceCheckedBtn->setDisabled(m_curResults->matches < 1); m_ui.replaceButton->setDisabled(m_curResults->matches < 1); m_ui.nextButton->setDisabled(m_curResults->matches < 1); m_curResults->tree->expandAll(); m_curResults->tree->resizeColumnToContents(0); if (m_curResults->tree->columnWidth(0) < m_curResults->tree->width()-30) { m_curResults->tree->setColumnWidth(0, m_curResults->tree->width()-30); } QWidget *focusObject = nullptr; QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); if (root) { QTreeWidgetItem *child = root->child(0); if (!m_searchJustOpened) { focusObject = qobject_cast(QGuiApplication::focusObject()); } indicateMatch(child); updateResultsRootItem(); connect(m_curResults->tree, &QTreeWidget::itemChanged, &m_updateSumaryTimer, static_cast(&QTimer::start)); } 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() { // Save the search text if (m_ui.searchCombo->findText(m_ui.searchCombo->currentText()) == -1) { m_ui.searchCombo->insertItem(1, m_ui.searchCombo->currentText()); m_ui.searchCombo->setCurrentIndex(1); } // Save the replace text 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; // Security measure } 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); // Correct any bad cursor positions return; } int cursorLine = m_mainWindow->activeView()->cursorPosition().line(); int cursorColumn = m_mainWindow->activeView()->cursorPosition().column(); int startLine = item->data(0, ReplaceMatches::StartLineRole).toInt(); int startColumn = item->data(0, ReplaceMatches::StartColumnRole).toInt(); if ((cursorLine != startLine) || (cursorColumn != startColumn)) { 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() != startLine) continue; if (m_matchRanges[i]->start().column() != startColumn) continue; break; } if (i >=m_matchRanges.size()) { goToNextMatch(); return; } m_replacer.replaceSingleMatch(doc, item, res->regExp, m_ui.replaceCombo->currentText()); 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, int replacedInFile, int matchesInFile) { 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("Processed %1 of %2 matches in: ...%3", replacedInFile, matchesInFile, file.right(70))); } else { root->setData(0, Qt::DisplayRole, i18n("Processed %1 of %2 matches in: %3", replacedInFile, matchesInFile, 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() { if (!m_mainWindow->activeView()) { return; } Results *res = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!res) { qDebug() << "No res"; return; } m_curResults = res; // add the marks if it is not already open KTextEditor::Document *doc = m_mainWindow->activeView()->document(); if (doc && res->tree->topLevelItemCount() > 0) { // There is always one root item with match count // and X children with files or matches in case of search while typing QTreeWidgetItem *rootItem = res->tree->topLevelItem(0); QTreeWidgetItem *fileItem = nullptr; for (int i=0; ichildCount(); i++) { QString url = rootItem->child(i)->data(0, ReplaceMatches::FileUrlRole).toString(); QString fName = rootItem->child(i)->data(0, ReplaceMatches::FileNameRole).toString(); if (url == doc->url().toString() && fName == doc->documentName()) { fileItem = rootItem->child(i); break; } } if (fileItem) { clearDocMarks(doc); if (m_isSearchAsYouType) { fileItem = fileItem->parent(); } for (int i=0; ichildCount(); i++) { if (fileItem->child(i)->checkState(0) == Qt::Unchecked) { continue; } addMatchMark(doc, fileItem->child(i)); } } // Re-add the highlighting on document reload connect(doc, &KTextEditor::Document::reloaded, this, &KatePluginSearchView::docViewChanged, Qt::UniqueConnection); } } void KatePluginSearchView::expandResults() { m_curResults =qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!m_curResults) { qWarning() << "Results not found"; return; } if (m_ui.expandResults->isChecked()) { m_curResults->tree->expandAll(); } else { QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); m_curResults->tree->expandItem(root); if (root && (root->childCount() > 1)) { for (int i=0; ichildCount(); i++) { m_curResults->tree->collapseItem(root->child(i)); } } } } void KatePluginSearchView::updateResultsRootItem() { m_curResults = qobject_cast(m_ui.resultTabWidget->currentWidget()); if (!m_curResults) { return; } QTreeWidgetItem *root = m_curResults->tree->topLevelItem(0); if (!root) { // nothing to update return; } int checkedItemCount = 0; if (m_curResults->matches > 1) { for (QTreeWidgetItemIterator it(m_curResults->tree, QTreeWidgetItemIterator::Checked|QTreeWidgetItemIterator::NoChildren); *it; ++it) { checkedItemCount++; } } QString checkedStr = i18np("One checked", "%1 checked", checkedItemCount); int searchPlace = m_ui.searchPlaceCombo->currentIndex(); if (m_isSearchAsYouType) { searchPlace = CurrentFile; } switch (searchPlace) { case CurrentFile: root->setData(0, Qt::DisplayRole, i18np("One match (%2) found in file", "%1 matches (%2) found in file", m_curResults->matches, checkedStr)); break; case OpenFiles: root->setData(0, Qt::DisplayRole, i18np("One match (%2) found in open files", "%1 matches (%2) found in open files", m_curResults->matches, checkedStr)); break; case Folder: root->setData(0, Qt::DisplayRole, i18np("One match (%3) found in folder %2", "%1 matches (%3) found in folder %2", m_curResults->matches, m_resultBaseDir, checkedStr)); break; case Project: { QString projectName; if (m_projectPluginView) { projectName = m_projectPluginView->property("projectName").toString(); } root->setData(0, Qt::DisplayRole, i18np("One match (%4) found in project %2 (%3)", "%1 matches (%4) found in project %2 (%3)", m_curResults->matches, projectName, m_resultBaseDir, checkedStr)); break; } case AllProjects: // "in Open Projects" root->setData(0, Qt::DisplayRole, i18np("One match (%3) found in all open projects (common parent: %2)", "%1 matches (%3) found in all open projects (common parent: %2)", m_curResults->matches, m_resultBaseDir, checkedStr)); break; } docViewChanged(); } 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::StartColumnRole).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::StartLineRole).toInt(); int toColumn = item->data(0, ReplaceMatches::StartColumnRole).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) 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::StartColumnRole).isValid()) { curr = res->tree->itemBelow(curr); }; while (curr && curr->data(0, ReplaceMatches::StartLineRole).toInt() <= lineNr && curr->data(0, ReplaceMatches::FileUrlRole).toString() == m_mainWindow->activeView()->document()->url().toString()) { if (curr->data(0, ReplaceMatches::StartLineRole).toInt() == lineNr && curr->data(0, ReplaceMatches::StartColumnRole).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::StartColumnRole).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::StartColumnRole).isValid()) { curr = res->tree->itemBelow(curr); }; while (curr && curr->data(0, ReplaceMatches::StartLineRole).toInt() <= lineNr && curr->data(0, ReplaceMatches::FileUrlRole).toString() == m_mainWindow->activeView()->document()->url().toString()) { if (curr->data(0, ReplaceMatches::StartLineRole).toInt() == lineNr && curr->data(0, ReplaceMatches::StartColumnRole).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::StartColumnRole).toString().isEmpty()) { res->tree->expandItem(curr); // probably this file item curr = res->tree->itemAbove(curr); if (curr && curr->data(0, ReplaceMatches::StartColumnRole).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::StartColumnRole).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, &QTreeWidget::itemDoubleClicked, this, &KatePluginSearchView::itemSelected, Qt::UniqueConnection); res->searchPlaceIndex = m_ui.searchPlaceCombo->currentIndex(); res->useRegExp = m_ui.useRegExp->isChecked(); res->matchCase = m_ui.matchCase->isChecked(); m_ui.resultTabWidget->addTab(res, QString()); m_ui.resultTabWidget->setCurrentIndex(m_ui.resultTabWidget->count()-1); m_ui.stackedWidget->setCurrentIndex(0); m_ui.resultTabWidget->tabBar()->show(); m_ui.displayOptions->setChecked(false); res->tree->installEventFilter(this); } void KatePluginSearchView::tabCloseRequested(int index) { Results *tmp = qobject_cast(m_ui.resultTabWidget->widget(index)); if (m_curResults == tmp) { m_searchOpenFiles.cancelSearch(); m_searchDiskFiles.cancelSearch(); } if (m_ui.resultTabWidget->count() > 1) { delete tmp; // remove the tab m_curResults = nullptr; } if (m_ui.resultTabWidget->count() == 1) { m_ui.resultTabWidget->tabBar()->hide(); } } void KatePluginSearchView::resultTabChanged(int index) { if (index < 0) { return; } Results *res = qobject_cast(m_ui.resultTabWidget->widget(index)); if (!res) { qDebug() << "No res found"; return; } m_ui.searchCombo->blockSignals(true); m_ui.matchCase->blockSignals(true); m_ui.useRegExp->blockSignals(true); m_ui.searchPlaceCombo->blockSignals(true); m_ui.searchCombo->lineEdit()->setText(m_ui.resultTabWidget->tabText(index)); m_ui.useRegExp->setChecked(res->useRegExp); m_ui.matchCase->setChecked(res->matchCase); m_ui.searchPlaceCombo->setCurrentIndex(res->searchPlaceIndex); m_ui.searchCombo->blockSignals(false); m_ui.matchCase->blockSignals(false); m_ui.useRegExp->blockSignals(false); m_ui.searchPlaceCombo->blockSignals(false); searchPlaceChanged(); } bool KatePluginSearchView::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); QTreeWidget *tree = qobject_cast(obj); if (tree) { if (ke->matches(QKeySequence::Copy)) { // user pressed ctrl+c -> copy full URL to the clipboard QVariant variant = tree->currentItem()->data(0, ReplaceMatches::FileUrlRole); QApplication::clipboard()->setText(variant.toString()); event->accept(); return true; } if (ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return) { if (tree->currentItem()) { itemSelected(tree->currentItem()); event->accept(); return true; } } } // NOTE: Qt::Key_Escape is handled 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::replaceContextMenu(const QPoint& pos) { QMenu* const contextMenu = m_ui.replaceCombo->lineEdit()->createStandardContextMenu(); if (!contextMenu) return; QMenu* menu = contextMenu->addMenu(i18n("Add...")); if (!menu) return; menu->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); QSet actionPointers; actionPointers << menuEntry(menu, QStringLiteral("\\n"), QStringLiteral(""), i18n("Line break")); actionPointers << menuEntry(menu, QStringLiteral("\\t"), QStringLiteral(""), i18n("Tab")); if (m_ui.useRegExp->isChecked()) { menu->addSeparator(); actionPointers << menuEntry(menu, QStringLiteral("\\0"), QStringLiteral(""), i18n("Regular expression capture 0 (whole match)")); actionPointers << menuEntry(menu, QStringLiteral("\\"), QStringLiteral(""), i18n("Regular expression capture 1-9"), QStringLiteral("\\#")); actionPointers << menuEntry(menu, QStringLiteral("\\{"), QStringLiteral("}"), i18n("Regular expression capture 0-999"), QStringLiteral("\\{#")); menu->addSeparator(); actionPointers << menuEntry(menu, QStringLiteral("\\U\\"), QStringLiteral(""), i18n("Upper-cased capture 0-9"), QStringLiteral("\\U\\#")); actionPointers << menuEntry(menu, QStringLiteral("\\U\\{"), QStringLiteral("}"), i18n("Upper-cased capture 0-999"), QStringLiteral("\\U\\{###")); actionPointers << menuEntry(menu, QStringLiteral("\\L\\"), QStringLiteral(""), i18n("Lower-cased capture 0-9"), QStringLiteral("\\L\\#")); actionPointers << menuEntry(menu, QStringLiteral("\\L\\{"), QStringLiteral("}"), i18n("Lower-cased capture 0-999"), QStringLiteral("\\L\\{###")); } // Show menu QAction * const result = contextMenu->exec(m_ui.replaceCombo->mapToGlobal(pos)); // Act on action if (result && actionPointers.contains(result)) { QLineEdit * lineEdit = m_ui.replaceCombo->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 (pluginView && name == QStringLiteral("kateprojectplugin")) { m_projectPluginView = pluginView; slotProjectFileNameChanged(); connect (pluginView, SIGNAL(projectFileNameChanged()), this, SLOT(slotProjectFileNameChanged())); } } void KatePluginSearchView::slotPluginViewDeleted(const QString &name, QObject *) { // remove view if (name == QStringLiteral("kateprojectplugin")) { m_projectPluginView = nullptr; slotProjectFileNameChanged(); } } void KatePluginSearchView::slotProjectFileNameChanged() { // query new project file name QString projectFileName; if (m_projectPluginView) { projectFileName = m_projectPluginView->property("projectFileName").toString(); } // have project, enable gui for it if (!projectFileName.isEmpty()) { if (m_ui.searchPlaceCombo->count() <= Project) { // add "in Project" m_ui.searchPlaceCombo->addItem (QIcon::fromTheme(QStringLiteral("project-open")), i18n("In Current Project")); if (m_switchToProjectModeWhenAvailable) { // switch to search "in Project" m_switchToProjectModeWhenAvailable = false; setSearchPlace(Project); } // add "in Open Projects" m_ui.searchPlaceCombo->addItem(QIcon::fromTheme(QStringLiteral("project-open")), i18n("In All Open Projects")); } } // else: disable gui for it else { if (m_ui.searchPlaceCombo->count() >= Project) { // switch to search "in Open files", if "in Project" is active if (m_ui.searchPlaceCombo->currentIndex() >= Project) { setSearchPlace(OpenFiles); } // remove "in Project" and "in all projects" while (m_ui.searchPlaceCombo->count() > Project) { m_ui.searchPlaceCombo->removeItem(m_ui.searchPlaceCombo->count()-1); } } } } KateSearchCommand::KateSearchCommand(QObject *parent) : KTextEditor::Command(QStringList() << QStringLiteral("grep") << QStringLiteral("newGrep") << QStringLiteral("search") << QStringLiteral("newSearch") << QStringLiteral("pgrep") << QStringLiteral("newPGrep"), parent) { } bool KateSearchCommand::exec(KTextEditor::View* /*view*/, const QString& cmd, QString& /*msg*/, const KTextEditor::Range &) { //create a list of args QStringList args(cmd.split(QLatin1Char(' '), QString::KeepEmptyParts)); QString command = args.takeFirst(); QString searchText = args.join(QLatin1Char(' ')); if (command == QStringLiteral("grep") || command == QStringLiteral("newGrep")) { emit setSearchPlace(KatePluginSearchView::Folder); emit setCurrentFolder(); if (command == QStringLiteral("newGrep")) emit newTab(); } else if (command == QStringLiteral("search") || command == QStringLiteral("newSearch")) { emit setSearchPlace(KatePluginSearchView::OpenFiles); if (command == QStringLiteral("newSearch")) emit newTab(); } else if (command == QStringLiteral("pgrep") || command == QStringLiteral("newPGrep")) { emit setSearchPlace(KatePluginSearchView::Project); if (command == QStringLiteral("newPGrep")) emit newTab(); } emit setSearchString(searchText); emit startSearch(); return true; } bool KateSearchCommand::help(KTextEditor::View */*view*/, const QString &cmd, QString & msg) { if (cmd.startsWith(QStringLiteral("grep"))) { msg = i18n("Usage: grep [pattern to search for in folder]"); } else if (cmd.startsWith(QStringLiteral("newGrep"))) { msg = i18n("Usage: newGrep [pattern to search for in folder]"); } else if (cmd.startsWith(QStringLiteral("search"))) { msg = i18n("Usage: search [pattern to search for in open files]"); } else if (cmd.startsWith(QStringLiteral("newSearch"))) { msg = i18n("Usage: search [pattern to search for in open files]"); } else if (cmd.startsWith(QStringLiteral("pgrep"))) { msg = i18n("Usage: pgrep [pattern to search for in current project]"); } else if (cmd.startsWith(QStringLiteral("newPGrep"))) { msg = i18n("Usage: newPGrep [pattern to search for in current project]"); } return true; } #include "plugin_search.moc" // kate: space-indent on; indent-width 4; replace-tabs on; diff --git a/addons/sessionapplet/engine/katesessionsjob.cpp b/addons/sessionapplet/engine/katesessionsjob.cpp index cf3bc0fff..8afa93c58 100644 --- a/addons/sessionapplet/engine/katesessionsjob.cpp +++ b/addons/sessionapplet/engine/katesessionsjob.cpp @@ -1,84 +1,84 @@ /******************************************************************** This file is part of the KDE project. Copyright (C) 2014 Joseph Wenninger based on clipboard engine: Copyright (C) 2014 Martin Gräßlin partly based on code: Copyright (C) 2008 by Montel Laurent This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "katesessionsjob.h" #include "katesessionsengine.h" #include #include #include static const QString s_clipboardSourceName = QStringLiteral("katesessions"); KateSessionsJob::KateSessionsJob(KateSessionsEngine *engine, const QString &destination, const QString &operation, const QVariantMap ¶meters, QObject *parent) : Plasma::ServiceJob(destination, operation, parameters, parent) , m_engine(engine) { } void KateSessionsJob::start() { qDebug()<<"Job started:"< * 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, &QPushButton::clicked, this, &EditRepository::accept); auto cancel = buttonBox->button(QDialogButtonBox::Cancel); KGuiItem::assign(cancel, KStandardGuiItem::cancel()); connect(cancel, &QPushButton::clicked, this, &EditRepository::reject); // fill list of available modes QSharedPointer document(KTextEditor::Editor::instance()->createDocument(nullptr)); repoFileTypesList->addItems(document->highlightingModes()); repoFileTypesList->sortItems(); repoFileTypesList->setSelectionMode(QAbstractItemView::ExtendedSelection); connect(repoFileTypesList->selectionModel(), &QItemSelectionModel::selectionChanged, this, &EditRepository::updateFileTypes); // add default licenses - repoLicenseEdit->addItems(QStringList() << QLatin1String("BSD") << QLatin1String("Artistic") << QLatin1String("LGPL v2+") << QLatin1String("LGPL v3+")); + repoLicenseEdit->addItems(QStringList() << QStringLiteral("BSD") << QStringLiteral("Artistic") << QStringLiteral("LGPL v2+") << QStringLiteral("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/editsnippet.cpp b/addons/snippets/editsnippet.cpp index 9565a0cda..7aeef9cbe 100644 --- a/addons/snippets/editsnippet.cpp +++ b/addons/snippets/editsnippet.cpp @@ -1,209 +1,209 @@ /* 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 "editsnippet.h" #include "ui_editsnippet.h" #include "snippetrepository.h" #include "snippetstore.h" #include "snippet.h" #include #include #include #include #include #include #include #include #include #include #include #include KTextEditor::View* createView(QWidget* tabWidget) { auto document = KTextEditor::Editor::instance()->createDocument(tabWidget); auto view = document->createView(tabWidget); view->action("file_save")->setEnabled(false); tabWidget->layout()->addWidget(view); view->setStatusBarEnabled(false); return view; } EditSnippet::EditSnippet(SnippetRepository* repository, Snippet* snippet, QWidget* parent) : QDialog(parent), m_ui(new Ui::EditSnippetBase), m_repo(repository) , m_snippet(snippet), m_topBoxModified(false) { Q_ASSERT(m_repo); m_ui->setupUi(this); connect(this, &QDialog::accepted, this, &EditSnippet::save); m_okButton = m_ui->buttons->button(QDialogButtonBox::Ok); KGuiItem::assign(m_okButton, KStandardGuiItem::ok()); m_ui->buttons->addButton(m_okButton, QDialogButtonBox::AcceptRole); connect(m_okButton, &QPushButton::clicked, this, &QDialog::accept); auto cancelButton = m_ui->buttons->button(QDialogButtonBox::Cancel); KGuiItem::assign(cancelButton, KStandardGuiItem::cancel()); m_ui->buttons->addButton(cancelButton, QDialogButtonBox::RejectRole); connect(cancelButton, &QPushButton::clicked, this, &QDialog::reject); m_snippetView = createView(m_ui->snippetTab); if ( !m_repo->fileTypes().isEmpty() ) { m_snippetView->document()->setMode(m_repo->fileTypes().first()); } m_scriptsView = createView(m_ui->scriptTab); - m_scriptsView->document()->setMode(QLatin1String("JavaScript")); + m_scriptsView->document()->setMode(QStringLiteral("JavaScript")); m_scriptsView->document()->setText(m_repo->script()); m_scriptsView->document()->setModified(false); // view for testing the snippet m_testView = createView(m_ui->testWidget); // splitter default size ratio m_ui->splitter->setSizes(QList() << 400 << 150); connect(m_ui->dotest_button, &QPushButton::clicked, this, &EditSnippet::test); // modified notification stuff connect(m_ui->snippetNameEdit, &QLineEdit::textEdited, this, &EditSnippet::topBoxModified); connect(m_ui->snippetNameEdit, &QLineEdit::textEdited, this, &EditSnippet::validate); connect(m_ui->snippetShortcut, &KKeySequenceWidget::keySequenceChanged, this, &EditSnippet::topBoxModified); connect(m_snippetView->document(), &KTextEditor::Document::textChanged, this, &EditSnippet::validate); auto showHelp = [](const QString& text) { QWhatsThis::showText(QCursor::pos(), text); }; connect(m_ui->snippetLabel, &QLabel::linkActivated, showHelp); connect(m_ui->scriptLabel, &QLabel::linkActivated, showHelp); // if we edit a snippet, add all existing data if ( m_snippet ) { setWindowTitle(i18n("Edit Snippet %1 in %2", m_snippet->text(), m_repo->text())); m_snippetView->document()->setText(m_snippet->snippet()); m_ui->snippetNameEdit->setText(m_snippet->text()); m_ui->snippetShortcut->setKeySequence(m_snippet->action()->shortcut()); // unset modified flags m_snippetView->document()->setModified(false); m_topBoxModified = false; } else { setWindowTitle(i18n("Create New Snippet in Repository %1", m_repo->text())); } m_ui->messageWidget->hide(); validate(); m_ui->snippetNameEdit->setFocus(); setTabOrder(m_ui->snippetNameEdit, m_snippetView); QSize initSize = sizeHint(); initSize.setHeight( initSize.height() + 200 ); } void EditSnippet::test() { m_testView->document()->clear(); m_testView->insertTemplate(KTextEditor::Cursor(0, 0), m_snippetView->document()->text(), m_scriptsView->document()->text()); m_testView->setFocus(); } EditSnippet::~EditSnippet() { delete m_ui; } void EditSnippet::setSnippetText( const QString& text ) { m_snippetView->document()->setText(text); validate(); } void EditSnippet::validate() { const QString& name = m_ui->snippetNameEdit->text(); bool valid = !name.isEmpty() && !m_snippetView->document()->isEmpty(); // make sure the snippetname includes no spaces if ( name.contains(QLatin1Char(' ')) || name.contains(QLatin1Char('\t')) ) { m_ui->messageWidget->setText(i18n("Snippet name cannot contain spaces")); m_ui->messageWidget->animatedShow(); valid = false; } else { // hide message widget if snippet does not include spaces m_ui->messageWidget->animatedHide(); } if ( valid ) { m_ui->messageWidget->hide(); } m_okButton->setEnabled(valid); } void EditSnippet::save() { Q_ASSERT(!m_ui->snippetNameEdit->text().isEmpty()); if ( !m_snippet ) { // save as new snippet m_snippet = new Snippet(); m_repo->appendRow(m_snippet); } m_snippet->setSnippet(m_snippetView->document()->text()); m_snippetView->document()->setModified(false); m_snippet->setText(m_ui->snippetNameEdit->text()); m_snippet->action()->setShortcut(m_ui->snippetShortcut->keySequence()); m_repo->setScript(m_scriptsView->document()->text()); m_scriptsView->document()->setModified(false); m_topBoxModified = false; m_repo->save(); setWindowTitle(i18n("Edit Snippet %1 in %2", m_snippet->text(), m_repo->text())); } void EditSnippet::reject() { if (m_topBoxModified || m_snippetView->document()->isModified() || m_scriptsView->document()->isModified()) { int ret = KMessageBox::warningContinueCancel(qApp->activeWindow(), i18n("The snippet contains unsaved changes. Do you want to continue and lose all changes?"), i18n("Warning - Unsaved Changes") ); if (ret == KMessageBox::Cancel) { return; } } QDialog::reject(); } void EditSnippet::topBoxModified() { m_topBoxModified = true; } diff --git a/addons/snippets/snippet.cpp b/addons/snippets/snippet.cpp index 4e8be644c..b3e8e511c 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(nullptr) { - setIcon(QIcon::fromTheme(QLatin1String("text-plain"))); + setIcon(QIcon::fromTheme(QStringLiteral("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 = new QAction(QStringLiteral("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/snippetrepository.cpp b/addons/snippets/snippetrepository.cpp index 4f60ba59e..6d78601a6 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")) ); + setIcon( QIcon::fromTheme(QStringLiteral("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())); + QTimer::singleShot(0, this, &SnippetRepository::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); + QDomElement root = doc.createElement(QStringLiteral("snippets")); + root.setAttribute(QStringLiteral("name"), text()); + root.setAttribute(QStringLiteral("filetypes"), m_filetypes.isEmpty() ? QStringLiteral("*") : m_filetypes.join(QLatin1String(";"))); + root.setAttribute(QStringLiteral("authors"), m_authors); + root.setAttribute(QStringLiteral("license"), m_license); + root.setAttribute(QStringLiteral("namespace"), m_namespace); doc.appendChild(root); - addAndCreateElement(doc, root, QLatin1String("script"), m_script); + addAndCreateElement(doc, root, QStringLiteral("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()); + QDomElement item = doc.createElement(QStringLiteral("item")); + addAndCreateElement(doc, item, QStringLiteral("match"), snippet->text()); + addAndCreateElement(doc, item, QStringLiteral("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(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"))); + setLicense(docElement.attribute(QStringLiteral("license"))); + setAuthors(docElement.attribute(QStringLiteral("authors"))); + setFileTypes(docElement.attribute(QStringLiteral("filetypes")).split(QLatin1Char(';'), QString::SkipEmptyParts)); + setText(docElement.attribute(QStringLiteral("name"))); + setCompletionNamespace(docElement.attribute(QStringLiteral("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/snippetview.cpp b/addons/snippets/snippetview.cpp index 3180aab76..545d46fb4 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 = nullptr) : QSortFilterProxyModel(parent) { }; bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const 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())); + setWindowIcon(QIcon::fromTheme(QStringLiteral("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); + m_addRepoAction = new QAction(QIcon::fromTheme(QStringLiteral("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); + m_editRepoAction = new QAction(QIcon::fromTheme(QStringLiteral("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); + m_removeRepoAction = new QAction(QIcon::fromTheme(QStringLiteral("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 = new QAction(QIcon::fromTheme(QStringLiteral("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); + m_addSnippetAction = new QAction(QIcon::fromTheme(QStringLiteral("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); + m_editSnippetAction = new QAction(QIcon::fromTheme(QStringLiteral("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); + m_removeSnippetAction = new QAction(QIcon::fromTheme(QStringLiteral("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 = new QAction(QIcon::fromTheme(QStringLiteral("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())); + connect(snippetTree->selectionModel(), &QItemSelectionModel::selectionChanged, this, &SnippetView::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, 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(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); + KNS3::DownloadDialog dialog(QStringLiteral(":/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); + KNS3::UploadDialog dialog(QStringLiteral(":/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, 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/symbolviewer/bash_parser.cpp b/addons/symbolviewer/bash_parser.cpp index 4b1042240..2c6621e15 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 ")); + QString funcStr(QStringLiteral("function ")); int i; //bool mainprog; 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_treeOn->isChecked()) { funcNode = new QTreeWidgetItem(m_symbols, QStringList(i18n("Functions") ) ); funcNode->setIcon(0, QIcon(func)); if (m_expandOn->isChecked()) { 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)<isChecked()) { QString funcName; // skip line if no function defined // note: function name must match regex: [a-zA-Z0-9-_]+ if(!currline.contains(QRegExp(QLatin1String("^(function )*[a-zA-Z0-9-_]+ *\\( *\\)"))) && !currline.contains(QRegExp(QLatin1String("^function [a-zA-Z0-9-_]+")))) continue; // strip everything unneeded and get the function's name currline.remove(QRegExp(QLatin1String("^(function )*"))); funcName = currline.split(QRegExp(QLatin1String("((\\( *\\))|[^a-zA-Z0-9-_])")))[0].simplified(); if(!funcName.size()) continue; funcName.append(QLatin1String("()")); if (m_treeOn->isChecked()) { 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/fortran_parser.cpp b/addons/symbolviewer/fortran_parser.cpp index c9dcbe154..7ff8eb0fe 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 subrStr(QStringLiteral("subroutine ")); + QString funcStr(QStringLiteral("function ")); + QString modStr(QStringLiteral("module ")); QString stripped; int i; int fnd,block=0,blockend=0,paro=0,parc=0; bool mainprog; 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_treeOn->isChecked()) { 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_expandOn->isChecked()) { 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 (m_macro->isChecked()) // not really a macro, but a subroutines { - stripped += currline.right(currline.length()); + stripped += currline.rightRef(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_treeOn->isChecked()) { 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 (m_struct->isChecked()) // 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_treeOn->isChecked()) { 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 (m_func->isChecked()) { - stripped += currline.right(currline.length()); + stripped += currline.rightRef(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_treeOn->isChecked()) { 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/plugin_katesymbolviewer.cpp b/addons/symbolviewer/plugin_katesymbolviewer.cpp index 0988245fe..f5e4eff20 100644 --- a/addons/symbolviewer/plugin_katesymbolviewer.cpp +++ b/addons/symbolviewer/plugin_katesymbolviewer.cpp @@ -1,478 +1,478 @@ /*************************************************************************** * plugin_katesymbolviewer.cpp - description * ------------------- * 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. * * Copyright (C) 2014,2018 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. * * * ***************************************************************************/ #include "plugin_katesymbolviewer.h" #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 (KatePluginSymbolViewerFactory, "katesymbolviewerplugin.json", registerPlugin();) KatePluginSymbolViewerView::KatePluginSymbolViewerView(KatePluginSymbolViewer *plugin, KTextEditor::MainWindow *mw) :QObject(mw) ,m_mainWindow(mw) ,m_plugin(plugin) { // FIXME KF5 KGlobal::locale()->insertCatalog("katesymbolviewerplugin"); - KXMLGUIClient::setComponentName (QLatin1String("katesymbolviewer"), i18n ("SymbolViewer")); - setXMLFile(QLatin1String("ui.rc")); + KXMLGUIClient::setComponentName (QStringLiteral("katesymbolviewer"), i18n ("SymbolViewer")); + setXMLFile(QStringLiteral("ui.rc")); mw->guiFactory()->addClient (this); m_symbols = nullptr; // FIXME Let the parser decide which options are available and how they are named // because not all these options are supported by all parsers m_popup = new QMenu(m_symbols); m_treeOn = m_popup->addAction(i18n("Tree Mode"), this, &KatePluginSymbolViewerView::displayOptionChanged); m_treeOn->setCheckable(true); m_expandOn = m_popup->addAction(i18n("Expand Tree"), this, &KatePluginSymbolViewerView::displayOptionChanged); m_expandOn->setCheckable(true); m_sort = m_popup->addAction(i18n("Show Sorted"), this, &KatePluginSymbolViewerView::displayOptionChanged); m_sort->setCheckable(true); m_popup->addSeparator(); m_macro = m_popup->addAction(i18n("Show Macros"), this, &KatePluginSymbolViewerView::displayOptionChanged); m_macro->setCheckable(true); m_struct = m_popup->addAction(i18n("Show Structures"), this, &KatePluginSymbolViewerView::displayOptionChanged); m_struct->setCheckable(true); m_func = m_popup->addAction(i18n("Show Functions"), this, &KatePluginSymbolViewerView::displayOptionChanged); m_func->setCheckable(true); m_typesOn = m_popup->addAction(i18n("Show Parameters"), this, &KatePluginSymbolViewerView::displayOptionChanged); m_typesOn->setCheckable(true); KConfigGroup config(KSharedConfig::openConfig(), "PluginSymbolViewer"); - m_typesOn->setChecked(config.readEntry(QLatin1String("ViewTypes"), false)); - m_expandOn->setChecked(config.readEntry(QLatin1String("ExpandTree"), false)); - m_treeOn->setChecked(config.readEntry(QLatin1String("TreeView"), false)); - m_sort->setChecked(config.readEntry(QLatin1String("SortSymbols"), false)); + m_typesOn->setChecked(config.readEntry(QStringLiteral("ViewTypes"), false)); + m_expandOn->setChecked(config.readEntry(QStringLiteral("ExpandTree"), false)); + m_treeOn->setChecked(config.readEntry(QStringLiteral("TreeView"), false)); + m_sort->setChecked(config.readEntry(QStringLiteral("SortSymbols"), false)); m_macro->setChecked(true); m_struct->setChecked(true); m_func->setChecked(true); m_expandOn->setEnabled(m_treeOn->isChecked()); m_typesOn->setEnabled(m_func->isChecked()); m_updateTimer.setSingleShot(true); connect(&m_updateTimer, &QTimer::timeout, this, &KatePluginSymbolViewerView::parseSymbols); m_currItemTimer.setSingleShot(true); connect(&m_currItemTimer, &QTimer::timeout, this, &KatePluginSymbolViewerView::updateCurrTreeItem); QPixmap cls( ( const char** ) class_xpm ); - m_toolview = m_mainWindow->createToolView(plugin, QLatin1String("kate_plugin_symbolviewer"), + m_toolview = m_mainWindow->createToolView(plugin, QStringLiteral("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, &QTreeWidget::itemClicked, this, &KatePluginSymbolViewerView::goToSymbol); connect(m_symbols, &QTreeWidget::customContextMenuRequested, this, &KatePluginSymbolViewerView::slotShowContextMenu); connect(m_symbols, &QTreeWidget::itemExpanded, this, &KatePluginSymbolViewerView::updateCurrTreeItem); connect(m_symbols, &QTreeWidget::itemCollapsed, this, &KatePluginSymbolViewerView::updateCurrTreeItem); connect(m_mainWindow, &KTextEditor::MainWindow::viewChanged, this, &KatePluginSymbolViewerView::slotDocChanged); QStringList titles; titles << i18nc("@title:column", "Symbols") << i18nc("@title:column", "Position"); m_symbols->setColumnCount(2); m_symbols->setHeaderLabels(titles); m_symbols->setColumnHidden(1, true); m_symbols->setSortingEnabled(m_sort->isChecked()); m_symbols->setRootIsDecorated(0); m_symbols->setContextMenuPolicy(Qt::CustomContextMenu); m_symbols->setIndentation(10); m_toolview->installEventFilter(this); } KatePluginSymbolViewerView::~KatePluginSymbolViewerView() { m_mainWindow->guiFactory()->removeClient (this); delete m_toolview; delete m_popup; } void KatePluginSymbolViewerView::slotDocChanged() { parseSymbols(); KTextEditor::View *view = m_mainWindow->activeView(); //qDebug()<<"Document changed !!!!" << view; if (view) { connect(view, &KTextEditor::View::cursorPositionChanged, this, &KatePluginSymbolViewerView::cursorPositionChanged, Qt::UniqueConnection); if (view->document()) { connect(view->document(), &KTextEditor::Document::textChanged, this, &KatePluginSymbolViewerView::slotDocEdited, Qt::UniqueConnection); } } } void KatePluginSymbolViewerView::slotDocEdited() { m_currItemTimer.stop(); // Avoid unneeded update m_updateTimer.start(500); } void KatePluginSymbolViewerView::cursorPositionChanged() { if (m_updateTimer.isActive()) { // No need for update, will come anyway return; } KTextEditor::View* editView = m_mainWindow->activeView(); if (!editView) { return; } int currLine = editView->cursorPositionVirtual().line(); if (currLine != m_oldCursorLine) { m_oldCursorLine = currLine; m_currItemTimer.start(100); } } void KatePluginSymbolViewerView::updateCurrTreeItem() { if (!m_mainWindow) { return; } KTextEditor::View* editView = m_mainWindow->activeView(); if (!editView) { return; } KTextEditor::Document* doc = editView->document(); if (!doc) { return; } int currLine = editView->cursorPositionVirtual().line(); int newItemLine = 0; QTreeWidgetItem *newItem = nullptr; QTreeWidgetItem *tmp = nullptr; for (int i=0; itopLevelItemCount(); i++) { tmp = newActveItem(newItemLine, currLine, m_symbols->topLevelItem(i)); if (tmp) newItem = tmp; } if (!newItem) { return; } // check if the item has a parent and if that parent is expanded. // if the parent is not expanded, set the parent as current item in stead of // expanding the tree. The tree was probably collapsed on purpose QTreeWidgetItem *parent = newItem->parent(); if (parent && !parent->isExpanded()) { newItem = parent; } m_symbols->blockSignals(true); m_symbols->setCurrentItem(newItem); m_symbols->blockSignals(false); } QTreeWidgetItem *KatePluginSymbolViewerView::newActveItem(int &newItemLine, int currLine, QTreeWidgetItem *item) { QTreeWidgetItem *newItem = nullptr; QTreeWidgetItem *tmp = nullptr; int itemLine = item->data(1, Qt::DisplayRole).toInt(); if ((itemLine <= currLine) && (itemLine >= newItemLine)) { newItemLine = itemLine; newItem = item; } for (int i=0; ichildCount(); i++) { tmp = newActveItem(newItemLine, currLine, item->child(i)); if (tmp) newItem = tmp; } return newItem; } bool KatePluginSymbolViewerView::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(event); if ((obj == m_toolview) && (ke->key() == Qt::Key_Escape)) { m_mainWindow->activeView()->setFocus(); event->accept(); return true; } } return QObject::eventFilter(obj, event); } void KatePluginSymbolViewerView::slotShowContextMenu(const QPoint&) { m_popup->popup(QCursor::pos(), m_treeOn); } /** * Each popup menu action is connected to this slot which offer the possibility * to modify the menu depended on current settings. */ void KatePluginSymbolViewerView::displayOptionChanged() { m_expandOn->setEnabled(m_treeOn->isChecked()); m_typesOn->setEnabled(m_func->isChecked()); parseSymbols(); } void KatePluginSymbolViewerView::parseSymbols() { if (!m_symbols) return; m_symbols->clear(); // Qt docu recommends to populate view with disabled sorting // https://doc.qt.io/qt-5/qtreeview.html#sortingEnabled-prop m_symbols->setSortingEnabled(false); Qt::SortOrder sortOrder = m_symbols->header()->sortIndicatorOrder(); 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 { QTreeWidgetItem *node = new QTreeWidgetItem(m_symbols); node->setText(0, i18n("Sorry, not supported yet!")); // Setting invalid line number avoid jump to top of document when clicked - node->setText(1, QLatin1String("-1")); + node->setText(1, QStringLiteral("-1")); node = new QTreeWidgetItem(m_symbols); node->setText(0, i18n("File type: %1", hlModeName)); - node->setText(1, QLatin1String("-1")); + node->setText(1, QStringLiteral("-1")); } m_oldCursorLine = -1; updateCurrTreeItem(); if (m_sort->isChecked()) { m_symbols->setSortingEnabled(true); m_symbols->sortItems(0, sortOrder); } } 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); if (!it || it->text(1).isEmpty()) { return; } 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) { m_view = new KatePluginSymbolViewerView (this, mainWindow); return m_view; } 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)); + p->viewReturns->setChecked(config.readEntry(QStringLiteral("ViewTypes"), false)); + p->expandTree->setChecked(config.readEntry(QStringLiteral("ExpandTree"), false)); + p->treeView->setChecked(config.readEntry(QStringLiteral("TreeView"), false)); + p->sortSymbols->setChecked(config.readEntry(QStringLiteral("SortSymbols"), false)); connect(p, &KatePluginSymbolViewerConfigPage::configPageApplyRequest, this, &KatePluginSymbolViewer::applyConfig); return (KTextEditor::ConfigPage*)p; } void KatePluginSymbolViewer::applyConfig(KatePluginSymbolViewerConfigPage* p) { KConfigGroup config(KSharedConfig::openConfig(), QStringLiteral("PluginSymbolViewer")); - config.writeEntry(QLatin1String("ViewTypes"), p->viewReturns->isChecked()); - config.writeEntry(QLatin1String("ExpandTree"), p->expandTree->isChecked()); - config.writeEntry(QLatin1String("TreeView"), p->treeView->isChecked()); - config.writeEntry(QLatin1String("SortSymbols"), p->sortSymbols->isChecked()); + config.writeEntry(QStringLiteral("ViewTypes"), p->viewReturns->isChecked()); + config.writeEntry(QStringLiteral("ExpandTree"), p->expandTree->isChecked()); + config.writeEntry(QStringLiteral("TreeView"), p->treeView->isChecked()); + config.writeEntry(QStringLiteral("SortSymbols"), p->sortSymbols->isChecked()); if (m_view) { m_view->m_typesOn->setChecked(p->viewReturns->isChecked()); m_view->m_expandOn->setChecked(p->expandTree->isChecked()); m_view->m_treeOn->setChecked(p->treeView->isChecked()); m_view->m_sort->setChecked(p->sortSymbols->isChecked()); m_view->m_expandOn->setEnabled(m_view->m_treeOn->isChecked()); m_view->m_typesOn->setEnabled(m_view->m_func->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, &QCheckBox::toggled, this, &KatePluginSymbolViewerConfigPage::changed); connect(expandTree, &QCheckBox::toggled, this, &KatePluginSymbolViewerConfigPage::changed); connect(treeView, &QCheckBox::toggled, this, &KatePluginSymbolViewerConfigPage::changed); connect(sortSymbols, &QCheckBox::toggled, this, &KatePluginSymbolViewerConfigPage::changed); } KatePluginSymbolViewerConfigPage::~KatePluginSymbolViewerConfigPage() {} QString KatePluginSymbolViewerConfigPage::name() const { return i18n("Symbol Viewer"); } QString KatePluginSymbolViewerConfigPage::fullName() const { return i18n("Symbol Viewer Configuration Page"); } QIcon KatePluginSymbolViewerConfigPage::icon() const { return QPixmap(( const char** ) class_xpm ); } void KatePluginSymbolViewerConfigPage::apply() { emit configPageApplyRequest( this ); } // END KatePluginSymbolViewerConfigPage #include "plugin_katesymbolviewer.moc" // kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/addons/symbolviewer/tcl_parser.cpp b/addons/symbolviewer/tcl_parser.cpp index fb2db19d0..c42270163 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 varStr(QStringLiteral("set ")); + QString procStr(QStringLiteral("proc")); QString stripped; int i, j, args_par = 0, graph = 0; char block = 0, parse_func = 0; 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_treeOn->isChecked()) { 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_expandOn->isChecked()) { 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 (m_macro->isChecked()) // 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_treeOn->isChecked()) { 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(m_func->isChecked()) { if (m_treeOn->isChecked()) { 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 }//m_func->isChecked() } // not a comment } //for i loop //positions.resize(m_symbols->itemIndex(node) + 1); } diff --git a/addons/tabswitcher/autotests/tabswitchertest.cpp b/addons/tabswitcher/autotests/tabswitchertest.cpp index 858e64db0..a7b0a4a23 100644 --- a/addons/tabswitcher/autotests/tabswitchertest.cpp +++ b/addons/tabswitcher/autotests/tabswitchertest.cpp @@ -1,77 +1,77 @@ /* This file is part of the KDE project * * Copyright (C) 2018 Gregor Mi * * 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 "tabswitchertest.h" #include "tabswitcherfilesmodel.h" #include QTEST_MAIN(KateTabSwitcherTest) void KateTabSwitcherTest::initTestCase() { } void KateTabSwitcherTest::cleanupTestCase() { } void KateTabSwitcherTest::testLongestCommonPrefix() { QFETCH(std::vector, input_strings); QFETCH(QString, expected); QCOMPARE(detail::longestCommonPrefix(input_strings), expected); } void KateTabSwitcherTest::testLongestCommonPrefix_data() { QTest::addColumn>("input_strings"); QTest::addColumn("expected"); std::vector strs; strs.clear(); - strs.push_back(QLatin1String("/home/user1/a")); - strs.push_back(QLatin1String("/home/user1/bc")); - QTest::newRow("standard case") << strs << QString(QLatin1String("/home/user1/")); + strs.push_back(QStringLiteral("/home/user1/a")); + strs.push_back(QStringLiteral("/home/user1/bc")); + QTest::newRow("standard case") << strs << QStringLiteral("/home/user1/"); strs.clear(); - strs.push_back(QLatin1String("/home/a")); - strs.push_back(QLatin1String("/home/b")); + strs.push_back(QStringLiteral("/home/a")); + strs.push_back(QStringLiteral("/home/b")); strs.push_back(QLatin1String("")); QTest::newRow("empty string at the end of the list") << strs << QString(); strs.clear(); strs.push_back(QLatin1String("")); - strs.push_back(QLatin1String("/home/a")); - strs.push_back(QLatin1String("/home/b")); + strs.push_back(QStringLiteral("/home/a")); + strs.push_back(QStringLiteral("/home/b")); strs.push_back(QLatin1String("")); QTest::newRow("empty string not only at the end of the list") << strs << QString(); strs.clear(); - strs.push_back(QLatin1String("/home/a")); - strs.push_back(QLatin1String("/etc/b")); - QTest::newRow("a prefix with length 1") << strs << QString(QLatin1String("/")); + strs.push_back(QStringLiteral("/home/a")); + strs.push_back(QStringLiteral("/etc/b")); + QTest::newRow("a prefix with length 1") << strs << QStringLiteral("/"); strs.clear(); - strs.push_back(QLatin1String("a")); - strs.push_back(QLatin1String("a")); - QTest::newRow("two equal strings") << strs << QString(QLatin1String("a")); + strs.push_back(QStringLiteral("a")); + strs.push_back(QStringLiteral("a")); + QTest::newRow("two equal strings") << strs << QStringLiteral("a"); } diff --git a/addons/tabswitcher/tabswitcherfilesmodel.cpp b/addons/tabswitcher/tabswitcherfilesmodel.cpp index 1cf81658a..6117f10ad 100644 --- a/addons/tabswitcher/tabswitcherfilesmodel.cpp +++ b/addons/tabswitcher/tabswitcherfilesmodel.cpp @@ -1,208 +1,208 @@ /* This file is part of the KDE project Copyright (C) 2018 Gregor Mi 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 "tabswitcherfilesmodel.h" #include #include #include #include #include #include namespace detail { static QIcon iconForDocument(KTextEditor::Document * doc) { return QIcon::fromTheme(QMimeDatabase().mimeTypeForUrl(doc->url()).iconName()); } FilenameListItem::FilenameListItem(KTextEditor::Document* doc) : document(doc) , icon(iconForDocument(doc)) , documentName(doc->documentName()) , fullPath(doc->url().toLocalFile()) { } /** * adapted from https://helloacm.com/c-coding-exercise-longest-common-prefix/ * see also http://www.cplusplus.com/forum/beginner/83540/ * Note that if strs contains the empty string, the result will be "" */ QString longestCommonPrefix(std::vector const & strs) { int n = INT_MAX; if (strs.size() <= 0) { return QString(); } if (strs.size() == 1) { return strs[0]; } // get the min length for (size_t i = 0; i < strs.size(); i++) { n = strs[i].length() < n ? strs[i].length() : n; } for (int c = 0; c < n; c++) { // check each character for (size_t i = 1; i < strs.size(); i++) { if (strs[i][c] != strs[i - 1][c]) { // we find a mis-match return QStringRef(&strs[0], 0, c).toString(); } } } // prefix is n-length return QStringRef(&strs[0], 0, n).toString(); } void post_process(FilenameList & data) { std::vector paths; std::for_each(data.begin(), data.end(), [&paths](FilenameListItem & item) { paths.push_back(item.fullPath); }); // Removes empty strings because Documents without file have no path and we would // otherwise in this case always get "" paths.erase( // erase-remove idiom, see https://en.cppreference.com/w/cpp/algorithm/remove - std::remove_if(paths.begin(), paths.end(), [](QString s) { + std::remove_if(paths.begin(), paths.end(), [](const QString &s) { return s.isEmpty(); }), paths.end() ); QString prefix = longestCommonPrefix(paths); int prefix_length = prefix.length(); if (prefix_length == 1) { // if there is only the "/" at the beginning, then keep it prefix_length = 0; } std::for_each(data.begin(), data.end(), [prefix_length](FilenameListItem & item) { // Note that item.documentName can contain additional characters - e.g. "README.md (2)" - // so we cannot use that and have to parse the base filename by other means: QFileInfo fileinfo(item.fullPath); QString basename = fileinfo.fileName(); // e.g. "archive.tar.gz" // cut prefix (left side) and cut document name (plus slash) on the right side int len = item.fullPath.length() - prefix_length - basename.length() - 1; if (len > 0) { // only assign in case item.fullPath is not empty // "PREFIXPATH/REMAININGPATH/BASENAME" --> "REMAININGPATH" item.displayPathPrefix = QStringRef(&item.fullPath, prefix_length, len).toString(); } }); } } detail::TabswitcherFilesModel::TabswitcherFilesModel(QObject *parent) : QAbstractTableModel(parent) { } detail::TabswitcherFilesModel::TabswitcherFilesModel(const FilenameList & data) { data_ = data; post_process(data_); } bool detail::TabswitcherFilesModel::insertRow(int row, const FilenameListItem & item) { beginInsertRows(QModelIndex(), row, row + 1); data_.insert(data_.begin() + row, item); post_process(data_); endInsertRows(); return true; } bool detail::TabswitcherFilesModel::removeRow(int row) { if (data_.begin() + row == data_.end()) { return false; } beginRemoveRows(QModelIndex(), row, row); data_.erase(data_.begin() + row); post_process(data_); endRemoveRows(); return true; } void detail::TabswitcherFilesModel::clear() { if (data_.size() > 0) { beginRemoveRows(QModelIndex(), 0, data_.size() - 1); data_.clear(); endRemoveRows(); } } int detail::TabswitcherFilesModel::rowCount() const { return data_.size(); } detail::FilenameListItem * detail::TabswitcherFilesModel::item(int row) const { return const_cast(&data_[row]); } void detail::TabswitcherFilesModel::updateItem(FilenameListItem * item, QString const & documentName, QString const & fullPath) { item->documentName = documentName; item->fullPath = fullPath; post_process(data_); } int detail::TabswitcherFilesModel::columnCount(const QModelIndex & parent) const { Q_UNUSED(parent); return 2; } int detail::TabswitcherFilesModel::rowCount(const QModelIndex & parent) const { Q_UNUSED(parent); return data_.size(); } QVariant detail::TabswitcherFilesModel::data(const QModelIndex & index, int role) const { if (role == Qt::DisplayRole) { const auto & row = data_[index.row()]; if (index.column() == 0) return row.displayPathPrefix; else return row.documentName; } else if (role == Qt::DecorationRole) { if (index.column() == 1) { const auto & row = data_[index.row()]; return row.icon; } } else if (role == Qt::ToolTipRole) { const auto & row = data_[index.row()]; return row.fullPath; } else if (role == Qt::TextAlignmentRole) { if (index.column() == 0) return Qt::AlignRight + Qt::AlignVCenter; else return Qt::AlignVCenter; } else if (role == Qt::ForegroundRole) { if (index.column() == 0) return QBrush(Qt::darkGray); else return QVariant(); } return QVariant(); } diff --git a/addons/tabswitcher/tests/tstestapp.cpp b/addons/tabswitcher/tests/tstestapp.cpp index fe8dc6cf5..6d66389b6 100644 --- a/addons/tabswitcher/tests/tstestapp.cpp +++ b/addons/tabswitcher/tests/tstestapp.cpp @@ -1,128 +1,128 @@ #include "tstestapp.h" #include "../tabswitcherfilesmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include static KTextEditor::Document * addDoc(const QString & path) { auto doc = KTextEditor::Editor::instance()->createDocument(nullptr); doc->openUrl(QUrl::fromLocalFile(path)); return doc; } class TsTestApp::Impl { public: void insert_1_item() { - model.insertRow(0, detail::FilenameListItem(addDoc(QLatin1String("/home/user2/folder1/abc.d")))); + model.insertRow(0, detail::FilenameListItem(addDoc(QStringLiteral("/home/user2/folder1/abc.d")))); treeview1->resizeColumnToContents(0); } void remove_1_item() { model.removeRow(0); treeview1->resizeColumnToContents(0); } void set_items_cutoff_bug() { model.clear(); auto icon = QIcon::fromTheme(QLatin1String("document-export")); - model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gregor/logs/notifications/multimedia-system.log")))); - model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gregor/dev/src/kservicemenueditor-0.2a/servicemenueditor")))); - model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gregor/kde/src/kdesrc-build/kdesrc-build")))); - model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gregor/node_modules/autolinker/README.md")))); - model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gregor/node_modules/autolinker/package.json")))); - model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gregor/node_modules/autolinker/LICENSE")))); - model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gregor/node_modules/asynckit/package.json")))); + model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gregor/logs/notifications/multimedia-system.log")))); + model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gregor/dev/src/kservicemenueditor-0.2a/servicemenueditor")))); + model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gregor/kde/src/kdesrc-build/kdesrc-build")))); + model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gregor/node_modules/autolinker/README.md")))); + model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gregor/node_modules/autolinker/package.json")))); + model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gregor/node_modules/autolinker/LICENSE")))); + model.insertRow(model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gregor/node_modules/asynckit/package.json")))); treeview1->resizeColumnToContents(0); } public: detail::TabswitcherFilesModel model; QTreeView* treeview1; }; TsTestApp::TsTestApp(QWidget *parent) : QMainWindow(parent), impl_(new TsTestApp::Impl) { setGeometry(0, 0, 1024, 800); setCentralWidget(new QWidget(this)); auto l = new QVBoxLayout(); centralWidget()->setLayout(l); auto hl = new QHBoxLayout(); l->addLayout(hl); - auto buttonInsert1 = new QPushButton(QLatin1String("Ins 1 item"), this); + auto buttonInsert1 = new QPushButton(QStringLiteral("Ins 1 item"), this); connect(buttonInsert1, &QPushButton::clicked, this, [=] { impl_->insert_1_item(); }); hl->addWidget(buttonInsert1); - auto buttonRemove1 = new QPushButton(QLatin1String("Del 1 item"), this); + auto buttonRemove1 = new QPushButton(QStringLiteral("Del 1 item"), this); connect(buttonRemove1, &QPushButton::clicked, this, [=] { impl_->remove_1_item(); }); hl->addWidget(buttonRemove1); - auto buttonSetTestSet1 = new QPushButton(QLatin1String("set_items_cutoff_bug"), this); + auto buttonSetTestSet1 = new QPushButton(QStringLiteral("set_items_cutoff_bug"), this); connect(buttonSetTestSet1, &QPushButton::clicked, this, [=] { impl_->set_items_cutoff_bug(); }); hl->addWidget(buttonSetTestSet1); impl_->treeview1 = new QTreeView(this); l->addWidget(impl_->treeview1); impl_->treeview1->setHeaderHidden(true); impl_->treeview1->setRootIsDecorated(false); auto icon = QIcon::fromTheme(QLatin1String("edit-undo")); - impl_->model.insertRow(impl_->model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gm/projects/proj1/src/file1.h")))); - impl_->model.insertRow(impl_->model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gm/projects/proj1/src/file2.cpp")))); - impl_->model.insertRow(impl_->model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gm/dev/file3.py")))); - impl_->model.insertRow(impl_->model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gm/dev/file3kjaskdfkljasdfklj089asdfkjklasdjf90asdfsdfkj.py")))); - impl_->model.insertRow(impl_->model.rowCount(), detail::FilenameListItem(addDoc(QLatin1String("/home/gm/dev/proj2/asldfkjasdfk/asdlfkjasd;faf/;ajsdkfgjaskdfgasdf/file3.py")))); + impl_->model.insertRow(impl_->model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gm/projects/proj1/src/file1.h")))); + impl_->model.insertRow(impl_->model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gm/projects/proj1/src/file2.cpp")))); + impl_->model.insertRow(impl_->model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gm/dev/file3.py")))); + impl_->model.insertRow(impl_->model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gm/dev/file3kjaskdfkljasdfklj089asdfkjklasdjf90asdfsdfkj.py")))); + impl_->model.insertRow(impl_->model.rowCount(), detail::FilenameListItem(addDoc(QStringLiteral("/home/gm/dev/proj2/asldfkjasdfk/asdlfkjasd;faf/;ajsdkfgjaskdfgasdf/file3.py")))); //impl_->insert_a_item(); //impl_->remove_a_item(); impl_->model.rowCount(); impl_->model.item(0); impl_->model.index(0, 0); impl_->treeview1->setModel(&impl_->model); impl_->treeview1->resizeColumnToContents(0); impl_->treeview1->resizeColumnToContents(1); auto listview1 = new QListView(this); l->addWidget(listview1); listview1->setModel(&impl_->model); auto treeview2 = new QTreeView(this); l->addWidget(treeview2); } TsTestApp::~TsTestApp() { } int main(int argc, char *argv[]) { QApplication app(argc, argv); TsTestApp w; w.show(); return app.exec(); } diff --git a/addons/textfilter/plugin_katetextfilter.cpp b/addons/textfilter/plugin_katetextfilter.cpp index 6aa99419b..5e92dfbd6 100644 --- a/addons/textfilter/plugin_katetextfilter.cpp +++ b/addons/textfilter/plugin_katetextfilter.cpp @@ -1,278 +1,278 @@ /*************************************************************************** plugin_katetextfilter.cpp - description ------------------- begin : FRE Feb 23 2001 copyright : (C) 2001 by Joseph Wenninger copyright : (C) 2009 Dominik Haumann ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "plugin_katetextfilter.h" #include "ui_textfilterwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(TextFilterPluginFactory, "textfilterplugin.json", registerPlugin();) PluginKateTextFilter::PluginKateTextFilter(QObject *parent, const QList &): KTextEditor::Plugin(parent) , m_pFilterProcess(Q_NULLPTR) , copyResult(false) , mergeOutput(false) { // register command new PluginKateTextFilterCommand(this); } PluginKateTextFilter::~PluginKateTextFilter() { // cleanup the process the right way (TM) if (m_pFilterProcess) { m_pFilterProcess->kill(); m_pFilterProcess->waitForFinished(); delete m_pFilterProcess; } } QObject *PluginKateTextFilter::createView (KTextEditor::MainWindow *mainWindow) { // create a plugin view return new PluginViewKateTextFilter(this, mainWindow); } void PluginKateTextFilter::slotFilterReceivedStdout() { m_strFilterOutput += QString::fromLocal8Bit(m_pFilterProcess->readAllStandardOutput()); } void PluginKateTextFilter::slotFilterReceivedStderr () { const QString block = QString::fromLocal8Bit(m_pFilterProcess->readAllStandardError()); if (mergeOutput) m_strFilterOutput += block; else m_stderrOutput += block; } void PluginKateTextFilter::slotFilterProcessExited(int, QProcess::ExitStatus) { KTextEditor::View* kv(KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView()); if (!kv) return; // Is there any error output to display? if (!mergeOutput && !m_stderrOutput.isEmpty()) { QPointer message = new KTextEditor::Message( xi18nc( "@info" , "Result of:
$ %1\n%2
" , m_last_command , m_stderrOutput ) , KTextEditor::Message::Error ); message->setWordWrap(true); message->setAutoHide(1000); kv->document()->postMessage(message); } if (copyResult) { QApplication::clipboard()->setText(m_strFilterOutput); return; } // Do not even try to change the document if no result collected... if (m_strFilterOutput.isEmpty()) return; KTextEditor::Document::EditingTransaction transaction(kv->document()); KTextEditor::Cursor start = kv->cursorPosition(); if (kv->selection()) { start = kv->selectionRange().start(); kv->removeSelectionText(); } kv->setCursorPosition(start); // for block selection kv->insertText(m_strFilterOutput); } -static void slipInFilter(KProcess & proc, KTextEditor::View & view, QString command) +static void slipInFilter(KProcess & proc, KTextEditor::View & view, const QString &command) { QString inputText; if (view.selection()) { inputText = view.selectionText(); } proc.clearProgram (); proc.setShellCommand(command); proc.start(); QByteArray encoded = inputText.toLocal8Bit(); proc.write(encoded); proc.closeWriteChannel(); // TODO: Put up a modal dialog to defend the text from further // keystrokes while the command is out. With a cancel button... } void PluginKateTextFilter::slotEditFilter() { if (!KAuthorized::authorize(QStringLiteral("shell_access"))) { KMessageBox::sorry(nullptr,i18n( "You are not allowed to execute arbitrary external applications. If " "you want to be able to do this, contact your system administrator."), i18n("Access Restrictions")); return; } if (!KTextEditor::Editor::instance()->application()->activeMainWindow()) return; KTextEditor::View* kv(KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView()); if (!kv) return; QDialog dialog(KTextEditor::Editor::instance()->application()->activeMainWindow()->window()); Ui::TextFilterWidget ui; ui.setupUi(&dialog); ui.filterBox->setFocus(); dialog.setWindowTitle(i18n("Text Filter")); KConfigGroup config(KSharedConfig::openConfig(), "PluginTextFilter"); QStringList items = config.readEntry("Completion list", QStringList()); copyResult = config.readEntry("Copy result", false); mergeOutput = config.readEntry("Merge output", true); ui.filterBox->setMaxCount(10); ui.filterBox->setHistoryItems(items, true); ui.filterBox->setMinimumContentsLength(80); ui.copyResult->setChecked(copyResult); ui.mergeOutput->setChecked(mergeOutput); if (dialog.exec() == QDialog::Accepted) { copyResult = ui.copyResult->isChecked(); mergeOutput = ui.mergeOutput->isChecked(); const QString filter = ui.filterBox->currentText(); if (!filter.isEmpty()) { ui.filterBox->addToHistory(filter); config.writeEntry("Completion list", ui.filterBox->historyItems()); config.writeEntry("Copy result", copyResult); config.writeEntry("Merge output", mergeOutput); m_last_command = filter; runFilter(kv, filter); } } } void PluginKateTextFilter::runFilter(KTextEditor::View *kv, const QString &filter) { m_strFilterOutput.clear(); m_stderrOutput.clear(); if (!m_pFilterProcess) { m_pFilterProcess = new KProcess; connect(m_pFilterProcess, &KProcess::readyReadStandardOutput, this, &PluginKateTextFilter::slotFilterReceivedStdout); connect(m_pFilterProcess, &KProcess::readyReadStandardError, this, &PluginKateTextFilter::slotFilterReceivedStderr); connect(m_pFilterProcess, static_cast(&KProcess::finished), this, &PluginKateTextFilter::slotFilterProcessExited); } m_pFilterProcess->setOutputChannelMode( mergeOutput ? KProcess::MergedChannels : KProcess::SeparateChannels ); slipInFilter(*m_pFilterProcess, *kv, filter); } //BEGIN Kate::Command methods PluginKateTextFilterCommand::PluginKateTextFilterCommand(PluginKateTextFilter *plugin) : KTextEditor::Command(QStringList() << QStringLiteral("textfilter"), plugin) , m_plugin(plugin) { } bool PluginKateTextFilterCommand::exec (KTextEditor::View *view, const QString &cmd, QString &msg, const KTextEditor::Range &) { QString filter = cmd.section(QLatin1Char(' '), 1).trimmed(); if (filter.isEmpty()) { msg = i18n("Usage: textfilter COMMAND"); return false; } m_plugin->runFilter(view, filter); return true; } bool PluginKateTextFilterCommand::help (KTextEditor::View *, const QString &, QString &msg) { msg = i18n("

Usage: textfilter COMMAND

" "

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

"); return true; } //END PluginViewKateTextFilter::PluginViewKateTextFilter(PluginKateTextFilter *plugin, KTextEditor::MainWindow *mainwindow) : QObject(mainwindow) , m_mainWindow(mainwindow) { // setup right xml gui data KXMLGUIClient::setComponentName(QStringLiteral("textfilter"), i18n("Text Filter")); setXMLFile(QStringLiteral("ui.rc")); // create our one and only action QAction* a = actionCollection()->addAction(QStringLiteral("edit_filter")); a->setText(i18n("&Filter Through Command...")); actionCollection()->setDefaultShortcut(a, Qt::CTRL + Qt::Key_Backslash); connect(a, &QAction::triggered, plugin, &PluginKateTextFilter::slotEditFilter); // register us at the UI mainwindow->guiFactory()->addClient(this); } PluginViewKateTextFilter::~PluginViewKateTextFilter() { // remove us from the UI again m_mainWindow->guiFactory()->removeClient (this); } // required for TextFilterPluginFactory vtable #include "plugin_katetextfilter.moc" diff --git a/addons/xmlcheck/plugin_katexmlcheck.cpp b/addons/xmlcheck/plugin_katexmlcheck.cpp index 821c9f98b..f50b0e0d0 100644 --- a/addons/xmlcheck/plugin_katexmlcheck.cpp +++ b/addons/xmlcheck/plugin_katexmlcheck.cpp @@ -1,402 +1,402 @@ /*************************************************************************** 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 resources 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 shortcut to do xml validation // Remove copyright above due to author orphaned this plugin? // Possibility to check only well-formdness without validation // Hide output in dock when switching to another tab // Make ability to validate against 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 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")); + KXMLGUIClient::setComponentName(QStringLiteral("katexmlcheck"), i18n ("Kate XML check")); // where i18n resources? + setXMLFile(QStringLiteral("ui.rc")); - dock = m_mainWindow->createToolView(plugin, "kate_plugin_xmlcheck_ouputview", KTextEditor::MainWindow::Bottom, QIcon::fromTheme("misc"), i18n("XML Checker Output")); + dock = m_mainWindow->createToolView(plugin, QStringLiteral("kate_plugin_xmlcheck_ouputview"), KTextEditor::MainWindow::Bottom, QIcon::fromTheme(QStringLiteral("misc")), i18n("XML Checker Output")); listview = new QTreeWidget( dock ); m_tmp_file=nullptr; - QAction *a = actionCollection()->addAction("xml_check"); + QAction *a = actionCollection()->addAction(QStringLiteral("xml_check")); a->setText(i18n("Validate XML")); connect(a, &QAction::triggered, this, &PluginKateXMLCheckView::slotValidate); // TODO?: //(void) new KAction ( i18n("Indent XML"), KShortcut(), this, // SLOT(slotIndent()), actionCollection(), "xml_indent" ); listview->setFocusPolicy(Qt::NoFocus); QStringList headers; headers << i18n("#"); headers << i18n("Line"); headers << i18n("Column"); headers << i18n("Message"); listview->setHeaderLabels(headers); listview->setRootIsDecorated(false); connect(listview, &QTreeWidget::itemClicked, this, &PluginKateXMLCheckView::slotClicked); QHeaderView *header = listview->header(); header->setSectionResizeMode(0, QHeaderView::ResizeToContents); header->setSectionResizeMode(1, QHeaderView::ResizeToContents); header->setSectionResizeMode(2, QHeaderView::ResizeToContents); /* TODO?: invalidate the listview when document has changed Kate::View *kv = application()->activeMainWindow()->activeView(); if( ! kv ) { qDebug() << "Warning: no Kate::View"; return; } connect(kv, SIGNAL(modifiedChanged()), this, SLOT(slotUpdate())); */ connect(&m_proc, static_cast(&QProcess::finished), this, &PluginKateXMLCheckView::slotProcExited); // we currently only want errors: m_proc.setProcessChannelMode(QProcess::SeparateChannels); // m_proc.setProcessChannelMode(QProcess::ForwardedChannels); // For Debugging. Do not use this. mainwin->guiFactory()->addClient(this); } PluginKateXMLCheckView::~PluginKateXMLCheckView() { m_mainWindow->guiFactory()->removeClient( this ); delete m_tmp_file; delete dock; } void PluginKateXMLCheckView::slotProcExited(int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitCode); // FIXME: doesn't work correct the first time: //if( m_dockwidget->isDockBackPossible() ) { // m_dockwidget->dockBack(); // } if (exitStatus != QProcess::NormalExit) { QTreeWidgetItem *item = new QTreeWidgetItem(); - item->setText(0, QString("1").rightJustified(4,' ')); - item->setText(3, "Validate process crashed."); + item->setText(0, QStringLiteral("1").rightJustified(4,' ')); + item->setText(3, QStringLiteral("Validate process crashed.")); listview->addTopLevelItem(item); return; } qDebug() << "slotProcExited()"; QApplication::restoreOverrideCursor(); delete m_tmp_file; QString proc_stderr = QString::fromLocal8Bit(m_proc.readAllStandardError()); m_tmp_file=nullptr; listview->clear(); uint list_count = 0; uint err_count = 0; if( ! m_validating ) { // no i18n here, so we don't get an ugly English<->Non-english mixup: QString msg; if( m_dtdname.isEmpty() ) { - msg = "No DOCTYPE found, will only check well-formedness."; + msg = QStringLiteral("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(0, QStringLiteral("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 = ""; + if( col == QLatin1String("-1") ) { + col = QLatin1String(""); } 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 + msg = QStringLiteral("No errors found, document is valid."); // no i18n here } else { - msg = "No errors found, document is well-formed."; // no i18n here + msg = QStringLiteral("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 = ""; + m_dtdname = QLatin1String(""); KTextEditor::View *kv = m_mainWindow->activeView(); if( ! kv ) return false; delete m_tmp_file; m_tmp_file = new QTemporaryFile(); if( !m_tmp_file->open() ) { qDebug() << "Error (slotValidate()): could not create '" << m_tmp_file->fileName() << "': " << m_tmp_file->errorString(); KMessageBox::error(nullptr, i18n("Error: Could not create " "temporary file '%1'.", m_tmp_file->fileName())); delete m_tmp_file; m_tmp_file=nullptr; return false; } QTextStream s ( m_tmp_file ); s << kv->document()->text(); s.flush(); - QString exe = QStandardPaths::findExecutable("xmllint"); + QString exe = QStandardPaths::findExecutable(QStringLiteral("xmllint")); if( exe.isEmpty() ) { - exe = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, "xmllint"); + exe = QStandardPaths::locate(QStandardPaths::ApplicationsLocation, QStringLiteral("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"; + args << QStringLiteral("--noout"); // tell xmllint the working path of the document's file, if possible. // otherwise 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"); + path.replace(':',QLatin1String("%3A")); // because of such inconvenience with xmllint and paths, maybe switch to xmlstarlet? qDebug() << "path=" << path; if (!path.isEmpty()) { - args << "--path" << path; + args << QStringLiteral("--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 parameters qDebug() << "args=" << args; qDebug() << "exit code:"<< m_proc.exitCode(); if( ! m_proc.waitForStarted(-1) ) { KMessageBox::error(nullptr, i18n("Error: Failed to execute xmllint. Please make " "sure that xmllint is installed. It is part of libxml2.")); return false; } QApplication::setOverrideCursor(Qt::WaitCursor); return true; } #include "plugin_katexmlcheck.moc" diff --git a/addons/xmltools/plugin_katexmltools.cpp b/addons/xmltools/plugin_katexmltools.cpp index 4115e22f9..1cf116cdc 100644 --- a/addons/xmltools/plugin_katexmltools.cpp +++ b/addons/xmltools/plugin_katexmltools.cpp @@ -1,1114 +1,1114 @@ /*************************************************************************** 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")); + KXMLGUIClient::setComponentName(QStringLiteral("katexmltools"), i18n("Kate XML Tools")); + setXMLFile(QStringLiteral("ui.rc")); QAction *actionInsert = new QAction(i18n("&Insert Element..."), this); connect(actionInsert, &QAction::triggered, &m_model, &PluginKateXMLToolsCompletionModel::slotInsertElement); - actionCollection()->addAction("xml_tool_insert_element", actionInsert); + actionCollection()->addAction(QStringLiteral("xml_tool_insert_element"), actionInsert); actionCollection()->setDefaultShortcut(actionInsert, Qt::CTRL + Qt::Key_Return); QAction *actionClose = new QAction(i18n("&Close Element"), this); connect(actionClose, &QAction::triggered, &m_model, &PluginKateXMLToolsCompletionModel::slotCloseElement); - actionCollection()->addAction("xml_tool_close_element", actionClose); + actionCollection()->addAction(QStringLiteral("xml_tool_close_element"), actionClose); actionCollection()->setDefaultShortcut(actionClose, Qt::CTRL + Qt::Key_Less); QAction *actionAssignDTD = new QAction(i18n("Assign Meta &DTD..."), this); connect(actionAssignDTD, &QAction::triggered, &m_model, &PluginKateXMLToolsCompletionModel::getDTD); - actionCollection()->addAction("xml_tool_assign", actionAssignDTD); + actionCollection()->addAction(QStringLiteral("xml_tool_assign"), actionAssignDTD); mainWin->guiFactory()->addClient(this); connect(KTextEditor::Editor::instance()->application(), &KTextEditor::Application::documentDeleted, &m_model, &PluginKateXMLToolsCompletionModel::slotDocumentDeleted); } PluginKateXMLToolsView::~PluginKateXMLToolsView() { m_mainWindow->guiFactory()->removeClient(this); //qDebug() << "xml tools destructor 1..."; //TODO: unregister the model } PluginKateXMLToolsCompletionModel::PluginKateXMLToolsCompletionModel(QObject *const parent) : CodeCompletionModel(parent) , m_viewToAssignTo(nullptr) , m_mode(none) , m_correctPos(0) { } PluginKateXMLToolsCompletionModel::~PluginKateXMLToolsCompletionModel() { qDeleteAll(m_dtds); m_dtds.clear(); } void PluginKateXMLToolsCompletionModel::slotDocumentDeleted(KTextEditor::Document *doc) { // Remove the document from m_DTDs, and also delete the PseudoDTD // if it becomes unused. if (m_docDtds.contains(doc)) { qDebug() << "XMLTools:slotDocumentDeleted: documents: " << m_docDtds.count() << ", DTDs: " << m_dtds.count(); PseudoDTD *dtd = m_docDtds.take(doc); if (m_docDtds.key(dtd)) { return; } QHash::iterator it; for (it = m_dtds.begin() ; it != m_dtds.end() ; ++it) { if (it.value() == dtd) { m_dtds.erase(it); delete dtd; return; } } } } void PluginKateXMLToolsCompletionModel::completionInvoked(KTextEditor::View *kv, const KTextEditor::Range &range, const InvocationType invocationType) { Q_UNUSED(range) Q_UNUSED(invocationType) qDebug() << "xml tools completionInvoked"; KTextEditor::Document *doc = kv->document(); if (! m_docDtds[ doc ]) // no meta DTD assigned yet { return; } // debug to test speed: //QTime t; t.start(); beginResetModel(); m_allowed.clear(); // get char on the left of the cursor: KTextEditor::Cursor curpos = kv->cursorPosition(); uint line = curpos.line(), col = curpos.column(); QString lineStr = kv->document()->line(line); QString leftCh = lineStr.mid(col - 1, 1); QString secondLeftCh = lineStr.mid(col - 2, 1); - if (leftCh == "&") { + if (leftCh == QLatin1String("&")) { qDebug() << "Getting entities"; m_allowed = m_docDtds[doc]->entities(QString()); m_mode = entities; - } else if (leftCh == "<") { + } else if (leftCh == QLatin1String("<")) { 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 == "<") { + } else if (leftCh == QLatin1String("/") && secondLeftCh == QLatin1String("<")) { 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 == "=")) { + } else if (leftCh == QLatin1String(" ") || (isQuote(leftCh) && secondLeftCh == QLatin1String("="))) { // 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")) { + (m_allowed[0] == QLatin1String("CDATA") || m_allowed[0] == QLatin1String("ID") || m_allowed[0] == QLatin1String("IDREF") || + m_allowed[0] == QLatin1String("IDREFS") || m_allowed[0] == QLatin1String("ENTITY") || m_allowed[0] == QLatin1String("ENTITIES") || + m_allowed[0] == QLatin1String("NMTOKEN") || m_allowed[0] == QLatin1String("NMTOKENS") || m_allowed[0] == QLatin1String("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") { + if (m_allowed.count() >= 1 && m_allowed[0] != QLatin1String("__EMPTY")) { m_allowed = sortQStringList(m_allowed); } setRowCount(m_allowed.count()); endResetModel(); } int PluginKateXMLToolsCompletionModel::columnCount(const QModelIndex &) const { return 1; } int PluginKateXMLToolsCompletionModel::rowCount(const QModelIndex &parent) const { if (!m_allowed.isEmpty()) { // Is there smth to complete? if (!parent.isValid()) { // Return the only one group node for root return 1; } if (parent.internalId() == groupNode) { // Return available rows count for group level node return m_allowed.size(); } } return 0; } QModelIndex PluginKateXMLToolsCompletionModel::parent(const QModelIndex &index) const { if (!index.isValid()) { // Is root/invalid index? return QModelIndex(); // Nothing to return... } if (index.internalId() == groupNode) { // Return a root node for group return QModelIndex(); } // Otherwise, this is a leaf level, so return the only group as a parent return createIndex(0, 0, groupNode); } QModelIndex PluginKateXMLToolsCompletionModel::index(const int row, const int column, const QModelIndex &parent) const { if (!parent.isValid()) { // At 'top' level only 'header' present, so nothing else than row 0 can be here... return row == 0 ? createIndex(row, column, groupNode) : QModelIndex(); } if (parent.internalId() == groupNode) { // Is this a group node? if (0 <= row && row < m_allowed.size()) { // Make sure to return only valid indices return createIndex(row, column, (void *)nullptr); // Just return a leaf-level index } } // Leaf node has no children... nothing to return return QModelIndex(); } QVariant PluginKateXMLToolsCompletionModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { // Nothing to do w/ invalid index return QVariant(); } if (index.internalId() == groupNode) { // Return group level node data switch (role) { case KTextEditor::CodeCompletionModel::GroupRole: return QVariant(Qt::DisplayRole); case Qt::DisplayRole: return currentModeToString(); default: break; } return QVariant(); // Nothing to return for other roles } switch (role) { case Qt::DisplayRole: switch (index.column()) { case KTextEditor::CodeCompletionModel::Name: return m_allowed.at(index.row()); default: break; } default: break; } return QVariant(); } bool PluginKateXMLToolsCompletionModel::shouldStartCompletion(KTextEditor::View *view, const QString &insertedText, bool userInsertion, const KTextEditor::Cursor &position) { Q_UNUSED(view) Q_UNUSED(userInsertion) Q_UNUSED(position) - const QString triggerChars = "&application()->activeMainWindow()) { return; } KTextEditor::View *kv = KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView(); if (! kv) { qDebug() << "Warning: no KTextEditor::View"; return; } // ### replace this with something more sane // Start where the supplied XML-DTDs are fed by default unless // user changed directory last time: - QString defaultDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "katexmltools") + "/katexmltools/"; + QString defaultDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("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"; + filename = QStringLiteral("xslt-1.0.dtd.xml"); + doctype = QStringLiteral("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"); + QStringLiteral("*.xml")); } else { url.setUrl(defaultDir + filename); KMessageBox::information(nullptr, i18n("The current file has been identified " "as a document of type \"%1\". The meta DTD for this document type " "will now be loaded.", doctype), i18n("Loading XML Meta DTD"), - QString::fromLatin1("DTDAssigned")); + QStringLiteral("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::TransferJob *job = KIO::get(url); connect(job, &KIO::TransferJob::result, this, &PluginKateXMLToolsCompletionModel::slotFinished); connect(job, &KIO::TransferJob::data, this, &PluginKateXMLToolsCompletionModel::slotData); } qDebug() << "XMLTools::getDTD: Documents: " << m_docDtds.count() << ", DTDs: " << m_dtds.count(); } void PluginKateXMLToolsCompletionModel::slotFinished(KJob *job) { if (job->error()) { //qDebug() << "XML Plugin error: DTD in XML format (" << filename << " ) could not be loaded"; static_cast(job)->uiDelegate()->showErrorMessage(); } else if (static_cast(job)->isErrorPage()) { // catch failed loading loading via http: KMessageBox::error(nullptr, i18n("The file '%1' could not be opened. " "The server returned an error.", m_urlString), i18n("XML Plugin Error")); } else { PseudoDTD *dtd = new PseudoDTD(); dtd->analyzeDTD(m_urlString, m_dtdString); m_dtds.insert(m_urlString, dtd); assignDTD(dtd, m_viewToAssignTo); // clean up a bit m_viewToAssignTo = nullptr; m_dtdString.clear(); } QGuiApplication::restoreOverrideCursor(); } void PluginKateXMLToolsCompletionModel::slotData(KIO::Job *, const QByteArray &data) { m_dtdString += QString(data); } void PluginKateXMLToolsCompletionModel::assignDTD(PseudoDTD *dtd, KTextEditor::View *view) { m_docDtds.insert(view->document(), dtd); //TODO:perhaps foreach views()? KTextEditor::CodeCompletionInterface *cci = qobject_cast(view); if (cci) { cci->registerCompletionModel(this); cci->setAutomaticInvocationEnabled(true); qDebug() << "PluginKateXMLToolsView: completion model registered"; } else { qWarning() << "PluginKateXMLToolsView: completion interface unavailable"; } } /** * Offer a line edit with completion for possible elements at cursor position and insert the * tag one chosen/entered by the user, plus its closing tag. If there's a text selection, * add the markup around it. */ void PluginKateXMLToolsCompletionModel::slotInsertElement() { if (!KTextEditor::Editor::instance()->application()->activeMainWindow()) { return; } KTextEditor::View *kv = KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView(); if (! kv) { qDebug() << "Warning: no KTextEditor::View"; return; } KTextEditor::Document *doc = kv->document(); PseudoDTD *dtd = m_docDtds[doc]; QString parentElement = getParentElement(*kv, 0); QStringList allowed; if (dtd) { allowed = dtd->allowedElements(parentElement); } QString text; InsertElement dialog(allowed, kv); if (dialog.exec() == QDialog::Accepted) { text = dialog.text(); } if (!text.isEmpty()) { QStringList list = text.split(QChar(' ')); QString pre; QString post; // anders: use if the tag is required to be empty. // In that case maybe we should not remove the selection? or overwrite it? int adjust = 0; // how much to move cursor. // if we know that we have attributes, it goes // just after the tag name, otherwise between tags. if (dtd && dtd->allowedAttributes(list[0]).count()) { adjust++; // the ">" } - if (dtd && dtd->allowedElements(list[0]).contains("__EMPTY")) { + if (dtd && dtd->allowedElements(list[0]).contains(QStringLiteral("__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 != " ") { + if (!rightCh.isEmpty() && rightCh != QLatin1String(">") && rightCh != QLatin1String("/") && rightCh != QLatin1String(" ")) { // 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"); + bool isEmptyTag = m_docDtds[document]->allowedElements(text).contains(QStringLiteral("__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 + if (ch == QLatin1String(">")) { // cursor is outside tag return QString(); } - if (ch == "<") { + if (ch == QLatin1String("<")) { 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 == ">") { + if (ch.at(0).isSpace() || ch == QLatin1String("/") || ch == QLatin1String(">")) { 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 == "=") { + if (isQuote(ch) && chLeft == QLatin1String("=")) { break; - } else if (isQuote(ch) && chLeft != "=") { + } else if (isQuote(ch) && chLeft != QLatin1String("=")) { return QString(); - } else if (ch == "<" || ch == ">") { + } else if (ch == QLatin1String("<") || ch == QLatin1String(">")) { 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(QLatin1String(""); + return (tag.right(2) == QLatin1String("/>")); } /** * 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 == "'"); + return (ch == QLatin1String("\"") || ch == QLatin1String("'")); } // ======================================================================== // 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(), &QLineEdit::textChanged, this, &InsertElement::slotHistoryTextChanged); // button box QDialogButtonBox * box = new QDialogButtonBox(this); box->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); m_okButton = box->button(QDialogButtonBox::Ok); m_okButton->setDefault(true); connect(box, &QDialogButtonBox::accepted, this, &InsertElement::accept); connect(box, &QDialogButtonBox::rejected, this, &InsertElement::reject); // fill layout topLayout->addWidget(label); topLayout->addWidget(m_cmbElements); topLayout->addWidget(box); m_cmbElements->setFocus(); // make sure the ok button is enabled/disabled correctly slotHistoryTextChanged(m_cmbElements->lineEdit()->text()); } InsertElement::~InsertElement() { } void InsertElement::slotHistoryTextChanged(const QString &text) { m_okButton->setEnabled(!text.isEmpty()); } QString InsertElement::text() const { return m_cmbElements->currentText(); } //END InsertElement dialog #include "plugin_katexmltools.moc" // kate: space-indent on; indent-width 4; replace-tabs on; mixed-indent off; diff --git a/addons/xmltools/pseudo_dtd.cpp b/addons/xmltools/pseudo_dtd.cpp index 76e8f87da..9c9719844 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"); + QDomDocument doc(QStringLiteral("dtdIn_xml")); if (! doc.setContent(metaDtd)) { 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") { + if (doc.doctype().name() != QLatin1String("dtd")) { 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(); + listLength += doc.elementsByTagName(QStringLiteral("entity")).count(); + listLength += doc.elementsByTagName(QStringLiteral("element")).count(); // count this twice, as it will be iterated twice ( TODO: optimize that? ): - listLength += doc.elementsByTagName("attlist").count() * 2; + listLength += doc.elementsByTagName(QStringLiteral("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 necessary 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"); + QDomNodeList list = doc->elementsByTagName(QStringLiteral("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"); + QDomNodeList contentModelList = elem.elementsByTagName(QStringLiteral("content-model-expanded")); QDomNode contentModelNode = contentModelList.item(0); QDomElement contentModelElem = contentModelNode.toElement(); if (! contentModelElem.isNull()) { // check for : - QDomNodeList pcdataList = contentModelElem.elementsByTagName("pcdata"); + QDomNodeList pcdataList = contentModelElem.elementsByTagName(QStringLiteral("pcdata")); // check for other sub elements: - QDomNodeList subList = contentModelElem.elementsByTagName("element-name"); + QDomNodeList subList = contentModelElem.elementsByTagName(QStringLiteral("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; + subelementList[subElem.attribute(QStringLiteral("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"); + QDomNodeList emptyList = elem.elementsByTagName(QStringLiteral("empty")); if (emptyList.count()) { - subelementList["__EMPTY"] = true; + subelementList[QStringLiteral("__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"); + QDomNodeList exclusionsList = elem.elementsByTagName(QStringLiteral("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"); + QDomNodeList subList = exclusionsElem.elementsByTagName(QStringLiteral("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")); + QMap::Iterator it = subelementList.find(subElem.attribute(QStringLiteral("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); + m_elementsList.insert(elem.attribute(QStringLiteral("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) +QStringList PseudoDTD::allowedElements(const 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"); + QDomNodeList list = doc->elementsByTagName(QStringLiteral("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"); + QDomNodeList attributeList = elem.elementsByTagName(QStringLiteral("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")); + if (attributeElem.attribute(QStringLiteral("type")) == QLatin1String("#REQUIRED")) { + attrs.requiredAttributes.append(attributeElem.attribute(QStringLiteral("name"))); } else { - attrs.optionalAttributes.append(attributeElem.attribute("name")); + attrs.optionalAttributes.append(attributeElem.attribute(QStringLiteral("name"))); } } } - m_attributesList.insert(elem.attribute("name"), attrs); + m_attributesList.insert(elem.attribute(QStringLiteral("name")), attrs); } } return true; } /** Check which attributes are allowed for an element. */ -QStringList PseudoDTD::allowedAttributes(QString element) +QStringList PseudoDTD::allowedAttributes(const 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"); + QDomNodeList list = doc->elementsByTagName(QStringLiteral("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"); + QDomNodeList attributeList = elem.elementsByTagName(QStringLiteral("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(' '))); + QString value = attributeElem.attribute(QStringLiteral("value")); + attributevaluesTmp.insert(attributeElem.attribute(QStringLiteral("name")), value.split(QChar(' '))); } } - m_attributevaluesList.insert(elem.attribute("name"), attributevaluesTmp); + m_attributevaluesList.insert(elem.attribute(QStringLiteral("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) +QStringList PseudoDTD::attributeValues(const QString &element, const 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"); + QDomNodeList list = doc->elementsByTagName(QStringLiteral("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") { + && elem.attribute(QStringLiteral("type")) != QLatin1String("param")) { // TODO: what's cdata <-> gen ? - QDomNodeList expandedList = elem.elementsByTagName("text-expanded"); + QDomNodeList expandedList = elem.elementsByTagName(QStringLiteral("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); + m_entityList.insert(elem.attribute(QStringLiteral("name")), exp); } else { - m_entityList.insert(elem.attribute("name"), QString()); + m_entityList.insert(elem.attribute(QStringLiteral("name")), QString()); } } } return true; } /** * Get a list of all ( non-parameter ) entities that start with a certain string. */ -QStringList PseudoDTD::entities(QString start) +QStringList PseudoDTD::entities(const 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/addons/xmltools/pseudo_dtd.h b/addons/xmltools/pseudo_dtd.h index 13186b211..c75fb26e8 100644 --- a/addons/xmltools/pseudo_dtd.h +++ b/addons/xmltools/pseudo_dtd.h @@ -1,78 +1,78 @@ /*************************************************************************** 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. ***************************************************************************/ #ifndef PSEUDO_DTD_H #define PSEUDO_DTD_H #include #include #include /** * This class contains the attributes for one element. * To get ALL attributes, concatenate the two lists. */ class ElementAttributes { public: QStringList optionalAttributes; QStringList requiredAttributes; }; class PseudoDTD { public: PseudoDTD(); ~PseudoDTD(); void analyzeDTD(QString &metaDtdUrl, QString &metaDtd); - QStringList allowedElements(QString parentElement); - QStringList allowedAttributes(QString parentElement); - QStringList attributeValues(QString element, QString attribute); - QStringList entities(QString start); + QStringList allowedElements(const QString &parentElement); + QStringList allowedAttributes(const QString &parentElement); + QStringList attributeValues(const QString &element, const QString &attribute); + QStringList entities(const QString &start); QStringList requiredAttributes(const QString &parentElement) const; protected: bool parseElements(QDomDocument *doc, QProgressDialog *progress); bool parseAttributes(QDomDocument *doc, QProgressDialog *progress); bool parseAttributeValues(QDomDocument *doc, QProgressDialog *progress); bool parseEntities(QDomDocument *doc, QProgressDialog *progress); bool m_sgmlSupport; // Entities, e.g. <"nbsp", "160"> QMap m_entityList; // Elements, e.g. <"a", ( "b", "i", "em", "strong" )> QMap m_elementsList; // Attributes e.g. <"a", ( "href", "lang", "title" )> QMap m_attributesList; // Attribute values e.g. <"td", <"align", ( "left", "right", "justify" )>> QMap< QString, QMap > m_attributevaluesList; }; #endif // PSEUDO_DTD_H // kate: space-indent on; indent-width 4; replace-tabs on; mixed-indent off; diff --git a/kate/autotests/session_manager_test.cpp b/kate/autotests/session_manager_test.cpp index d340a6b48..6e1131f87 100644 --- a/kate/autotests/session_manager_test.cpp +++ b/kate/autotests/session_manager_test.cpp @@ -1,168 +1,168 @@ /* This file is part of the KDE project * * 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 "session_manager_test.h" #include "katesessionmanager.h" #include "kateapp.h" #include #include #include #include #include QTEST_MAIN(KateSessionManagerTest) void KateSessionManagerTest::initTestCase() { m_app = new KateApp(QCommandLineParser()); // FIXME: aaaah, why, why, why?! } void KateSessionManagerTest::cleanupTestCase() { delete m_app; } void KateSessionManagerTest::init() { m_tempdir = new QTemporaryDir; QVERIFY(m_tempdir->isValid()); m_manager = new KateSessionManager(this, m_tempdir->path()); } void KateSessionManagerTest::cleanup() { delete m_manager; delete m_tempdir; } void KateSessionManagerTest::basic() { QCOMPARE(m_manager->sessionsDir(), m_tempdir->path()); QCOMPARE(m_manager->sessionList().size(), 0); QCOMPARE(m_manager->activeSession()->isAnonymous(), true); } void KateSessionManagerTest::activateNewNamedSession() { - const QString sessionName = QString::fromLatin1("hello_world"); + const QString sessionName = QStringLiteral("hello_world"); QVERIFY(m_manager->activateSession(sessionName, false, false)); QCOMPARE(m_manager->sessionList().size(), 1); KateSession::Ptr s = m_manager->activeSession(); QCOMPARE(s->name(), sessionName); QCOMPARE(s->isAnonymous(), false); const QString sessionFile = m_tempdir->path() + QLatin1Char('/') + sessionName + QLatin1String(".katesession"); QCOMPARE(s->config()->name(), sessionFile); } void KateSessionManagerTest::anonymousSessionFile() { const QString anonfile = QDir().cleanPath(m_tempdir->path() + QLatin1String("/../anonymous.katesession")); QVERIFY(m_manager->activeSession()->isAnonymous()); QCOMPARE(m_manager->activeSession()->config()->name(), anonfile); } void KateSessionManagerTest::urlizeSessionFile() { - const QString sessionName = QString::fromLatin1("hello world/#"); + const QString sessionName = QStringLiteral("hello world/#"); m_manager->activateSession(sessionName, false, false); KateSession::Ptr s = m_manager->activeSession(); const QString sessionFile = m_tempdir->path() + QLatin1String("/hello%20world%2F%23.katesession"); QCOMPARE(s->config()->name(), sessionFile); } void KateSessionManagerTest::deleteSession() { - m_manager->activateSession(QLatin1String("foo")); + m_manager->activateSession(QStringLiteral("foo")); KateSession::Ptr s = m_manager->activeSession(); - m_manager->activateSession(QLatin1String("bar")); + m_manager->activateSession(QStringLiteral("bar")); QCOMPARE(m_manager->sessionList().size(), 2); m_manager->deleteSession(s); QCOMPARE(m_manager->sessionList().size(), 1); } void KateSessionManagerTest::deleteActiveSession() { - m_manager->activateSession(QLatin1String("foo")); + m_manager->activateSession(QStringLiteral("foo")); KateSession::Ptr s = m_manager->activeSession(); QCOMPARE(m_manager->sessionList().size(), 1); m_manager->deleteSession(s); QCOMPARE(m_manager->sessionList().size(), 1); } void KateSessionManagerTest::renameSession() { - m_manager->activateSession(QLatin1String("foo")); + m_manager->activateSession(QStringLiteral("foo")); KateSession::Ptr s = m_manager->activeSession(); QCOMPARE(m_manager->sessionList().size(), 1); - const QString newName = QString::fromLatin1("bar"); + const QString newName = QStringLiteral("bar"); m_manager->renameSession(s, newName); // non-collision path QCOMPARE(s->name(), newName); QCOMPARE(m_manager->sessionList().size(), 1); QCOMPARE(m_manager->sessionList().first(), s); } void KateSessionManagerTest::saveActiveSessionWithAnynomous() { QVERIFY(m_manager->activeSession()->isAnonymous()); QVERIFY(m_manager->sessionList().size() == 0); QCOMPARE(m_manager->saveActiveSession(), true); QCOMPARE(m_manager->activeSession()->isAnonymous(), true); QCOMPARE(m_manager->activeSession()->name(), QString()); QCOMPARE(m_manager->sessionList().size(), 0); } void KateSessionManagerTest::deletingSessionFilesUnderRunningApp() { - m_manager->activateSession(QLatin1String("foo")); - m_manager->activateSession(QLatin1String("bar")); + m_manager->activateSession(QStringLiteral("foo")); + m_manager->activateSession(QStringLiteral("bar")); QVERIFY(m_manager->sessionList().size() == 2); QVERIFY(m_manager->activeSession()->name() == QLatin1String("bar")); const QString file = m_tempdir->path() + QLatin1String("/foo.katesession"); QVERIFY(QFile(file).remove()); QTRY_COMPARE_WITH_TIMEOUT(m_manager->sessionList().size(), 1, 1000); // that should be enough for KDirWatch to kick in QCOMPARE(m_manager->activeSession()->name(), QLatin1String("bar")); } void KateSessionManagerTest::startNonEmpty() { - m_manager->activateSession(QLatin1String("foo")); - m_manager->activateSession(QLatin1String("bar")); + m_manager->activateSession(QStringLiteral("foo")); + m_manager->activateSession(QStringLiteral("bar")); KateSessionManager m(this, m_tempdir->path()); QCOMPARE(m.sessionList().size(), 2); } diff --git a/kate/autotests/session_test.cpp b/kate/autotests/session_test.cpp index f80e1c5f4..006bde370 100644 --- a/kate/autotests/session_test.cpp +++ b/kate/autotests/session_test.cpp @@ -1,149 +1,149 @@ /* This file is part of the KDE project * * 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 "session_test.h" #include "katesession.h" #include #include #include #include #include QTEST_MAIN(KateSessionTest) void KateSessionTest::initTestCase() {} void KateSessionTest::cleanupTestCase() {} void KateSessionTest::init() { m_tmpfile = new QTemporaryFile; QVERIFY(m_tmpfile->open()); } void KateSessionTest::cleanup() { delete m_tmpfile; } void KateSessionTest::create() { - const QString name = QString::fromLatin1("session name"); + const QString name = QStringLiteral("session name"); KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), name); QCOMPARE(s->name(), name); QCOMPARE((int)s->documents(), 0); QCOMPARE(s->isAnonymous(), false); QCOMPARE(s->config()->name(), m_tmpfile->fileName()); } void KateSessionTest::createAnonymous() { KateSession::Ptr s = KateSession::createAnonymous(m_tmpfile->fileName()); QCOMPARE(s->name(), QString()); QCOMPARE((int)s->documents(), 0); QCOMPARE(s->isAnonymous(), true); QCOMPARE(s->config()->name(), m_tmpfile->fileName()); } void KateSessionTest::createAnonymousFrom() { // Regular - KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QLatin1String("session name")); + KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QStringLiteral("session name")); - const QString groupName = QString::fromLatin1("test group"); + const QString groupName = QStringLiteral("test group"); QTemporaryFile newFile; newFile.open(); KateSession::Ptr ns; s->config()->group(groupName).writeEntry("foo", "bar"); // Create Anon from Other ns = KateSession::createAnonymousFrom(s, newFile.fileName()); QCOMPARE(ns->name(), QString()); QCOMPARE((int)ns->documents(), 0); QCOMPARE(ns->isAnonymous(), true); QCOMPARE(ns->config()->name(), newFile.fileName()); QCOMPARE(ns->config()->group(groupName).readEntry("foo"), QLatin1String("bar")); } void KateSessionTest::createFrom() { - KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QLatin1String("session name")); + KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QStringLiteral("session name")); - const QString newName = QString::fromLatin1("new session name"); - const QString groupName = QString::fromLatin1("test group"); + const QString newName = QStringLiteral("new session name"); + const QString groupName = QStringLiteral("test group"); QTemporaryFile newFile; newFile.open(); KateSession::Ptr ns; s->config()->group(groupName).writeEntry("foo", "bar"); ns = KateSession::createFrom(s, newFile.fileName(), newName); QCOMPARE(ns->name(), newName); QCOMPARE((int)ns->documents(), 0); QCOMPARE(ns->isAnonymous(), false); QCOMPARE(ns->config()->name(), newFile.fileName()); QCOMPARE(ns->config()->group(groupName).readEntry("foo"), QLatin1String("bar")); } void KateSessionTest::documents() { - KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QLatin1String("session name")); + KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QStringLiteral("session name")); s->setDocuments(42); QCOMPARE((int)s->documents(), 42); s->config()->sync(); KConfig c(m_tmpfile->fileName()); QCOMPARE(c.group("Open Documents").readEntry("Count", 0), 42); } void KateSessionTest::setFile() { - KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QLatin1String("session name")); + KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QStringLiteral("session name")); s->config()->group("test").writeEntry("foo", "bar"); QTemporaryFile file2; file2.open(); s->setFile(file2.fileName()); QCOMPARE(s->config()->name(), file2.fileName()); QCOMPARE(s->config()->group("test").readEntry("foo"), QLatin1String("bar")); } void KateSessionTest::timestamp() { QFileInfo i(m_tmpfile->fileName()); - KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QLatin1String("session name")); + KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QStringLiteral("session name")); QCOMPARE(s->timestamp(), i.lastModified()); } void KateSessionTest::setName() { - KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QLatin1String("session name")); - const QString newName = QString::fromLatin1("bar"); + KateSession::Ptr s = KateSession::create(m_tmpfile->fileName(), QStringLiteral("session name")); + const QString newName = QStringLiteral("bar"); s->setName(newName); QCOMPARE(s->name(), newName); QCOMPARE(s->file(), m_tmpfile->fileName()); // on purpose, orthogonal } diff --git a/kate/autotests/sessions_action_test.cpp b/kate/autotests/sessions_action_test.cpp index a6c4929f2..7382cbdc9 100644 --- a/kate/autotests/sessions_action_test.cpp +++ b/kate/autotests/sessions_action_test.cpp @@ -1,98 +1,98 @@ /* This file is part of the KDE project * * 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 "sessions_action_test.h" #include "katesessionsaction.h" #include "katesessionmanager.h" #include "kateapp.h" #include #include #include #include QTEST_MAIN(KateSessionsActionTest) void KateSessionsActionTest::initTestCase() { m_app = new KateApp(QCommandLineParser()); // FIXME: aaaah, why, why, why?! } void KateSessionsActionTest::cleanupTestCase() { delete m_app; } void KateSessionsActionTest::init() { m_tempdir = new QTemporaryDir; QVERIFY(m_tempdir->isValid()); m_manager = new KateSessionManager(this, m_tempdir->path()); - m_ac = new KateSessionsAction(QLatin1String("menu"), this, m_manager); + m_ac = new KateSessionsAction(QStringLiteral("menu"), this, m_manager); } void KateSessionsActionTest::cleanup() { delete m_ac; delete m_manager; delete m_tempdir; } void KateSessionsActionTest::basic() { m_ac->slotAboutToShow(); QCOMPARE(m_ac->isEnabled(), false); QList actions = m_ac->sessionsGroup->actions(); QCOMPARE(actions.size(), 0); } void KateSessionsActionTest::limit() { for (int i = 0; i < 14; i++) { - m_manager->activateSession(QString::fromLatin1("session %1").arg(i)); + m_manager->activateSession(QStringLiteral("session %1").arg(i)); } QCOMPARE(m_manager->activeSession()->isAnonymous(), false); QCOMPARE(m_manager->sessionList().size(), 14); QCOMPARE(m_ac->isEnabled(), true); m_ac->slotAboutToShow(); QList actions = m_ac->sessionsGroup->actions(); QCOMPARE(actions.size(), 10); } void KateSessionsActionTest::timesorted() { /* m_manager->activateSession("one", false, false); m_manager->saveActiveSession(); m_manager->activateSession("two", false, false); m_manager->saveActiveSession(); m_manager->activateSession("three", false, false); m_manager->saveActiveSession(); KateSessionList list = m_manager->sessionList(); QCOMPARE(list.size(), 3); TODO: any idea how to test this simply and not calling utime()? */ } diff --git a/kate/kateapp.cpp b/kate/kateapp.cpp index 90cdd1530..5b9c83f04 100644 --- a/kate/kateapp.cpp +++ b/kate/kateapp.cpp @@ -1,480 +1,480 @@ /* 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 #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()); + qputenv("KATE_PID", QStringLiteral("%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 told 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()) : nullptr; bool tempfileSet = m_args.isSet(QStringLiteral("tempfile")); KTextEditor::Document *doc = nullptr; const QString codec_name = codec ? QString::fromLatin1(codec->name()) : QString(); // Bug 397913: Reverse the order here so the new tabs are opened in same order as the files were passed in on the command line QString positionalArgument; for (int i = m_args.positionalArguments().count() - 1; i >= 0; --i) { positionalArgument = m_args.positionalArguments().at(i); 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); } bool KateApp::isOnActivity(const QString &activity) { for (const auto& window : m_mainWindows) { const KWindowInfo info(window->winId(), nullptr, NET::WM2Activities); const auto activities = info.activities(); // handle special case of "on all activities" if (activities.isEmpty() || activities.contains(activity)) return true; } return false; } KTextEditor::Document *KateApp::openDocUrl(const QUrl &url, const QString &encoding, bool isTempFile) { KateMainWindow *mainWindow = activeKateMainWindow(); if (!mainWindow) { return nullptr; } 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 = 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 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 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 (auto win = activeKateMainWindow()) { // like QtSingleApplication win->setWindowState(win->windowState() & ~Qt::WindowMinimized); win->raise(); win->activateWindow(); } } diff --git a/kate/kateappadaptor.cpp b/kate/kateappadaptor.cpp index ca5e9ce58..42e178d53 100644 --- a/kate/kateappadaptor.cpp +++ b/kate/kateappadaptor.cpp @@ -1,130 +1,130 @@ /* This file is part of the KDE project Copyright (C) 2001 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 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 "kateappadaptor.h" #include "kateapp.h" #include "katesessionmanager.h" #include "katedocmanager.h" #include "katemainwindow.h" #include "katedebug.h" #include KateAppAdaptor::KateAppAdaptor(KateApp *app) : QDBusAbstractAdaptor(app) , m_app(app) {} void KateAppAdaptor::activate() { KateMainWindow *win = m_app->activeKateMainWindow(); if (!win) { return; } // like QtSingleApplication win->setWindowState(win->windowState() & ~Qt::WindowMinimized); win->raise(); win->activateWindow(); } -bool KateAppAdaptor::openUrl(QString url, QString encoding) +bool KateAppAdaptor::openUrl(const QString &url, const QString &encoding) { return m_app->openUrl(QUrl(url), encoding, false); } bool KateAppAdaptor::openUrl(QString url, QString encoding, bool isTempFile) { qCDebug(LOG_KATE) << "openURL"; return m_app->openUrl(QUrl(url), encoding, isTempFile); } bool KateAppAdaptor::isOnActivity(const QString &activity) { return m_app->isOnActivity(activity); } //----------- -QString KateAppAdaptor::tokenOpenUrl(QString url, QString encoding) +QString KateAppAdaptor::tokenOpenUrl(const QString &url, const QString &encoding) { KTextEditor::Document *doc = m_app->openDocUrl(QUrl(url), encoding, false); if (!doc) { return QStringLiteral("ERROR"); } - return QString::fromLatin1("%1").arg((qptrdiff)doc); + return QStringLiteral("%1").arg((qptrdiff)doc); } -QString KateAppAdaptor::tokenOpenUrl(QString url, QString encoding, bool isTempFile) +QString KateAppAdaptor::tokenOpenUrl(const QString &url, const QString &encoding, bool isTempFile) { qCDebug(LOG_KATE) << "openURL"; KTextEditor::Document *doc = m_app->openDocUrl(QUrl(url), encoding, isTempFile); if (!doc) { return QStringLiteral("ERROR"); } - return QString::fromLatin1("%1").arg((qptrdiff)doc); + return QStringLiteral("%1").arg((qptrdiff)doc); } -QString KateAppAdaptor::tokenOpenUrlAt(QString url, int line, int column, QString encoding, bool isTempFile) +QString KateAppAdaptor::tokenOpenUrlAt(const QString &url, int line, int column, const QString &encoding, bool isTempFile) { qCDebug(LOG_KATE) << "openURLAt"; KTextEditor::Document *doc = m_app->openDocUrl(QUrl(url), encoding, isTempFile); if (!doc) { return QStringLiteral("ERROR"); } m_app->setCursor(line, column); - return QString::fromLatin1("%1").arg((qptrdiff)doc); + return QStringLiteral("%1").arg((qptrdiff)doc); } //-------- bool KateAppAdaptor::setCursor(int line, int column) { return m_app->setCursor(line, column); } -bool KateAppAdaptor::openInput(QString text, QString encoding) +bool KateAppAdaptor::openInput(const QString &text, const QString &encoding) { return m_app->openInput(text, encoding); } -bool KateAppAdaptor::activateSession(QString session) +bool KateAppAdaptor::activateSession(const QString &session) { return m_app->sessionManager()->activateSession(session); } int KateAppAdaptor::desktopNumber() { KWindowInfo appInfo(m_app->activeKateMainWindow()->winId(), NET::WMDesktop); return appInfo.desktop(); } QString KateAppAdaptor::activeSession() { return m_app->sessionManager()->activeSession()->name(); } void KateAppAdaptor::emitExiting() { emit exiting(); } void KateAppAdaptor::emitDocumentClosed(const QString &token) { documentClosed(token); } diff --git a/kate/kateappadaptor.h b/kate/kateappadaptor.h index 2d25ee82f..7c3c69764 100644 --- a/kate/kateappadaptor.h +++ b/kate/kateappadaptor.h @@ -1,125 +1,125 @@ /* This file is part of the KDE project Copyright (C) 2001 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 _kateapp_adaptor_h_ #define _kateapp_adaptor_h_ #include class KateApp; class KateAppAdaptor : public QDBusAbstractAdaptor { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.Kate.Application") Q_PROPERTY(QString activeSession READ activeSession) public: KateAppAdaptor(KateApp *app); /** * emit the exiting signal */ void emitExiting(); void emitDocumentClosed(const QString &token); public Q_SLOTS: /** * open a file with given url and encoding * will get view created * @param url url of the file * @param encoding encoding name * @return success */ - bool openUrl(QString url, QString encoding); + bool openUrl(const QString &url, const QString &encoding); /** * checks if the Kate instance is in the specified activity * @param activity activity to check * @return true if it is in the specified activity, false otherwise */ bool isOnActivity(const QString &activity); /** * open a file with given url and encoding * will get view created * @param url url of the file * @param encoding encoding name * @return token or ERROR */ - QString tokenOpenUrl(QString url, QString encoding); + QString tokenOpenUrl(const QString &url, const QString &encoding); /** * Like the above, but adds an option to let the documentManager know * if the file should be deleted when closed. * @p isTempFile should be set to true with the --tempfile option set ONLY, * files opened with this set to true will be deleted when closed. */ bool openUrl(QString url, QString encoding, bool isTempFile); - QString tokenOpenUrl(QString url, QString encoding, bool isTempFile); + QString tokenOpenUrl(const QString &url, const QString &encoding, bool isTempFile); - QString tokenOpenUrlAt(QString url, int line, int column, QString encoding, bool isTempFile); + QString tokenOpenUrlAt(const QString &url, int line, int column, const QString &encoding, bool isTempFile); /** * set cursor of active view in active main window * will clear selection * @param line line for cursor * @param column column for cursor * @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(QString text, QString encoding); + bool openInput(const QString &text, const QString &encoding); /** * activate a given session * @param session session name * @return success */ - bool activateSession(QString session); + bool activateSession(const QString &session); int desktopNumber(); /** * activate this kate instance */ void activate(); Q_SIGNALS: /** * Notify the world that this kate instance is exiting. * All apps should stop using the dbus interface of this instance after this signal got emitted. */ void exiting(); void documentClosed(const QString &token); public: QString activeSession(); private: KateApp *m_app; }; #endif diff --git a/kate/katecolorschemechooser.cpp b/kate/katecolorschemechooser.cpp index e156c74b1..81410cd17 100644 --- a/kate/katecolorschemechooser.cpp +++ b/kate/katecolorschemechooser.cpp @@ -1,100 +1,100 @@ /************************************************************************************* * This file is part of KDevPlatform * * Copyright 2016 Zhigalin Alexander * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) version 3, or any * * later version accepted by the membership of KDE e.V. (or its * * successor approved by the membership of KDE e.V.), which shall * * act as a proxy defined in Section 6 of version 3 of the license. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library. If not, see . * *************************************************************************************/ #include "katecolorschemechooser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "katemainwindow.h" #include "katedebug.h" KateColorSchemeChooser::KateColorSchemeChooser(QObject* parent) : QAction(parent) { auto manager = new KColorSchemeManager(parent); const auto scheme(currentSchemeName()); qCDebug(LOG_KATE) << "Color scheme : " << scheme; auto selectionMenu = manager->createSchemeSelectionMenu(scheme, this); connect(selectionMenu->menu(), &QMenu::triggered, this, &KateColorSchemeChooser::slotSchemeChanged); manager->activateScheme(manager->indexForScheme(scheme)); setMenu(selectionMenu->menu()); menu()->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-color"))); menu()->setTitle(i18n("&Color Theme")); } QString KateColorSchemeChooser::loadCurrentScheme() const { KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup cg(config, "UiSettings"); return cg.readEntry("ColorScheme", currentDesktopDefaultScheme()); } void KateColorSchemeChooser::saveCurrentScheme(const QString &name) { KSharedConfigPtr config = KSharedConfig::openConfig(); KConfigGroup cg(config, "UiSettings"); cg.writeEntry("ColorScheme", name); cg.sync(); } QString KateColorSchemeChooser::currentDesktopDefaultScheme() const { - KSharedConfigPtr config = KSharedConfig::openConfig(QLatin1String("kdeglobals")); + KSharedConfigPtr config = KSharedConfig::openConfig(QStringLiteral("kdeglobals")); KConfigGroup group(config, "General"); return group.readEntry("ColorScheme", QStringLiteral("Breeze")); } QString KateColorSchemeChooser::currentSchemeName() const { if(!menu()) return loadCurrentScheme(); QAction* const action = menu()->activeAction(); if(action) return KLocalizedString::removeAcceleratorMarker(action->text()); return currentDesktopDefaultScheme(); } void KateColorSchemeChooser::slotSchemeChanged(QAction* triggeredAction) { saveCurrentScheme(KLocalizedString::removeAcceleratorMarker(triggeredAction->text())); } diff --git a/kate/katedocmanager.cpp b/kate/katedocmanager.cpp index 3427c7190..e56935fdf 100644 --- a/kate/katedocmanager.cpp +++ b/kate/katedocmanager.cpp @@ -1,612 +1,612 @@ /* 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, &KTextEditor::Document::modifiedChanged, this, &KateDocManager::slotModChanged1); 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] : nullptr; } 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 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 = 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 = nullptr; // always new document if url is empty... if (!u.isEmpty()) { doc = findDocument(u); } if (!doc) { if (untitledDoc) { // reuse the untitled document which is not needed auto & info = m_docInfos.find(untitledDoc).value(); delete info; info = new KateDocumentInfo(docInfo); doc = untitledDoc; } else { doc = createDoc(docInfo); } if (!encoding.isEmpty()) { doc->setEncoding(encoding); } if (!u.isEmpty()) { doc->openUrl(u); loadMetaInfos(doc, 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; } } return doc; } -bool KateDocManager::closeDocuments(const QList documents, bool closeUrl) +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(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)); + KConfigGroup cg(config, QStringLiteral("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(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)); + KConfigGroup cg(config, QStringLiteral("Document %1").arg(i)); 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())); + connect(doc, &KParts::ReadOnlyPart::canceled, this, &KateDocManager::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's meta-information if the checksum 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"); } flags << QStringLiteral ("SkipUrl"); 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())); + disconnect(doc, &KParts::ReadOnlyPart::canceled, this, &KateDocManager::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())); + QTimer::singleShot(0, this, &KateDocManager::showRestoreErrors); } } void KateDocManager::showRestoreErrors() { if (!m_openingErrors.isEmpty()) { KMessageBox::information(nullptr, m_openingErrors, i18n("Errors/Warnings while opening documents")); // clear errors m_openingErrors.clear(); } } diff --git a/kate/katedocmanager.h b/kate/katedocmanager.h index a0cf4dd4a..4f9e70a78 100644 --- a/kate/katedocmanager.h +++ b/kate/katedocmanager.h @@ -1,222 +1,222 @@ /* 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. */ #ifndef __KATE_DOCMANAGER_H__ #define __KATE_DOCMANAGER_H__ #include #include #include #include #include #include #include #include #include #include #include class KateMainWindow; class KateDocumentInfo { public: enum CustomRoles {RestoreOpeningFailedRole }; public: KateDocumentInfo() : modifiedOnDisc(false) , modifiedOnDiscReason(KTextEditor::ModificationInterface::OnDiskUnmodified) , openedByUser(false) , openSuccess(true) {} bool modifiedOnDisc; KTextEditor::ModificationInterface::ModifiedOnDiskReason modifiedOnDiscReason; bool openedByUser; bool openSuccess; }; class KateDocManager : public QObject { Q_OBJECT public: KateDocManager(QObject *parent); ~KateDocManager() override; KTextEditor::Document *createDoc(const KateDocumentInfo &docInfo = KateDocumentInfo()); KateDocumentInfo *documentInfo(KTextEditor::Document *doc); /** Returns the documentNumber of the doc with url URL or -1 if no such doc is found */ KTextEditor::Document *findDocument(const QUrl &url) const; const QList &documentList() const { return m_docList; } KTextEditor::Document *openUrl(const QUrl &, const QString &encoding = QString(), bool isTempFile = false, const KateDocumentInfo &docInfo = KateDocumentInfo()); QList openUrls(const QList &, const QString &encoding = QString(), bool isTempFile = false, const KateDocumentInfo &docInfo = KateDocumentInfo()); bool closeDocument(KTextEditor::Document *, bool closeUrl = true); - bool closeDocuments(const QList documents, bool closeUrl = true); + bool closeDocuments(const QList &documents, bool closeUrl = true); bool closeDocumentList(QList documents); bool closeAllDocuments(bool closeUrl = true); bool closeOtherDocuments(KTextEditor::Document *); QList modifiedDocumentList(); bool queryCloseDocuments(KateMainWindow *w); void saveDocumentList(KConfig *config); void restoreDocumentList(KConfig *config); inline bool getSaveMetaInfos() { return m_saveMetaInfos; } inline void setSaveMetaInfos(bool b) { m_saveMetaInfos = b; } inline int getDaysMetaInfos() { return m_daysMetaInfos; } inline void setDaysMetaInfos(int i) { m_daysMetaInfos = i; } public Q_SLOTS: /** * saves all documents that has at least one view. * documents with no views are ignored :P */ void saveAll(); /** * reloads all documents that has at least one view. * documents with no views are ignored :P */ void reloadAll(); /** * close all documents, which could not be reopened */ void closeOrphaned(); /** * save selected documents from the File List */ void saveSelected(const QList &); Q_SIGNALS: /** * This signal is emitted when the \p document was created. */ void documentCreated(KTextEditor::Document *document); /** * This signal is emitted when the \p document was created. * This is emitted after the initial documentCreated for internal use in view manager */ void documentCreatedViewManager(KTextEditor::Document *document); /** * This signal is emitted before a \p document which should be closed is deleted * The document is still accessible and usable, but it will be deleted * after this signal was send. * * @param document document that will be deleted */ void documentWillBeDeleted(KTextEditor::Document *document); /** * This signal is emitted when the \p document has been deleted. * * Warning !!! DO NOT ACCESS THE DATA REFERENCED BY THE POINTER, IT IS ALREADY INVALID * Use the pointer only to remove mappings in hash or maps */ void documentDeleted(KTextEditor::Document *document); /** * This signal is emitted before the batch of documents is being created. * * You can use it to pause some updates. */ void aboutToCreateDocuments(); /** * This signal is emitted after the batch of documents is created. * * @param documents list of documents that have been created */ void documentsCreated(const QList &documents); /** * 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. */ void aboutToDeleteDocuments(const QList &); /** * This signal 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); private Q_SLOTS: void slotModifiedOnDisc(KTextEditor::Document *doc, bool b, KTextEditor::ModificationInterface::ModifiedOnDiskReason reason); void slotModChanged(KTextEditor::Document *doc); void slotModChanged1(KTextEditor::Document *doc); void showRestoreErrors(); private: bool loadMetaInfos(KTextEditor::Document *doc, const QUrl &url); void saveMetaInfos(const QList &docs); QList m_docList; QHash m_docInfos; KConfig m_metaInfos; bool m_saveMetaInfos; int m_daysMetaInfos; typedef QPair TPair; QMap m_tempFiles; QString m_openingErrors; int m_documentStillToRestore; private Q_SLOTS: void documentOpened(); }; #endif diff --git a/kate/katefileactions.cpp b/kate/katefileactions.cpp index 1a15cb8c5..f4d4e74af 100644 --- a/kate/katefileactions.cpp +++ b/kate/katefileactions.cpp @@ -1,171 +1,171 @@ /* This file is part of the KDE project * * Copyright (C) 2018 Gregor Mi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . **/ #include "katefileactions.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void KateFileActions::copyFilePathToClipboard(KTextEditor::Document* doc) { QApplication::clipboard()->setText(doc->url().toDisplayString(QUrl::PreferLocalFile)); } void KateFileActions::openContainingFolder(KTextEditor::Document* doc) { KIO::highlightInFileManager({doc->url()}); } void KateFileActions::openFilePropertiesDialog(KTextEditor::Document* doc) { KFileItem fileItem(doc->url()); QDialog* dlg = new KPropertiesDialog(fileItem); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->show(); } void KateFileActions::renameDocumentFile(QWidget* parent, KTextEditor::Document* doc) { // TODO: code was copied and adapted from ../addons/filetree/katefiletree.cpp // (-> DUPLICATE CODE, the new code here should be also used there!) if (!doc) { return; } const QUrl oldFileUrl = doc->url(); if (oldFileUrl.isEmpty()) { // NEW return; } const QString oldFileName = doc->url().fileName(); bool ok = false; QString newFileName = QInputDialog::getText(parent, // ADAPTED 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 = parent->connect(job, &KIO::CopyJob::copyingDone, doc, success); if (!job->exec()) { KMessageBox::sorry(parent, i18n("File \"%1\" could not be moved to \"%2\"", oldFileUrl.toDisplayString(), newFileUrl.toDisplayString())); doc->openUrl(oldFileUrl); } } void KateFileActions::deleteDocumentFile(QWidget* parent, KTextEditor::Document* doc) { // TODO: code was copied and adapted from ../addons/filetree/katefiletree.cpp // (-> DUPLICATE CODE, the new code here should be also used there!) if (!doc) { return; } const auto&& url = doc->url(); if (url.isEmpty()) { // NEW return; } bool go = (KMessageBox::warningContinueCancel(parent, i18n("Do you really want to delete file \"%1\"?", url.toDisplayString()), i18n("Delete file"), - KStandardGuiItem::yes(), KStandardGuiItem::no(), QLatin1String("filetreedeletefile") + KStandardGuiItem::yes(), KStandardGuiItem::no(), QStringLiteral("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(parent, i18n("File \"%1\" could not be deleted.", url.toDisplayString())); } } } QStringList KateFileActions::supportedDiffTools() { // LATER: check for program existence and set some boolean value accordingly // Can this be even done in an easy way when we don't use the absolute path to the executable? // See https://stackoverflow.com/questions/42444055/how-to-check-if-a-program-exists-in-path-using-qt QStringList resultList; resultList.push_back(QStringLiteral("kdiff3")); resultList.push_back(QStringLiteral("kompare")); resultList.push_back(QStringLiteral("meld")); return resultList; } bool KateFileActions::compareWithExternalProgram(KTextEditor::Document* documentA, KTextEditor::Document* documentB, const QString& diffExecutable) { Q_ASSERT(documentA); Q_ASSERT(documentB); QProcess process; QStringList arguments; arguments << documentA->url().toLocalFile() << documentB->url().toLocalFile(); return process.startDetached(diffExecutable, arguments); } diff --git a/kate/katemainwindow.cpp b/kate/katemainwindow.cpp index b51bb00e3..535731382 100644 --- a/kate/katemainwindow.cpp +++ b/kate/katemainwindow.cpp @@ -1,1261 +1,1261 @@ /* 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 "katecolorschemechooser.h" #include "katefileactions.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 = 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(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*))); + connect(KateApp::self()->documentManager(), &KateDocManager::documentCreated, this, &KateMainWindow::slotDocumentCreated); 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))); + connect(this, &KateMDI::MainWindow::sigShowPluginConfigPage, this, &KateMainWindow::showPluginConfigPage); // 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(); + toolBar(QStringLiteral("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 = nullptr; // kill the wrapper object, now that all views are dead delete m_wrapper; 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())); + connect(m_paShowTabBar, &QAction::toggled, this, &KateMainWindow::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")); // Load themes actionCollection()->addAction(QStringLiteral("colorscheme_menu"), new KateColorSchemeChooser(actionCollection())); 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())); + connect(a, &QAction::triggered, this, &KateMainWindow::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())); + connect(a, &QAction::triggered, this, &KateMainWindow::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())); + connect(a, &QAction::triggered, this, &KateMainWindow::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())); + connect(a, &QAction::triggered, KateApp::self()->documentManager(), &KateDocManager::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())); + connect(a, &QAction::triggered, KateApp::self()->documentManager(), &KateDocManager::reloadAll); a->setWhatsThis(i18n("Reload all open documents.")); a = actionCollection()->addAction(QStringLiteral("file_copy_filepath")); a->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy"))); a->setText(i18n("Copy File &Path")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { auto&& view = viewManager()->activeView(); KateFileActions::copyFilePathToClipboard(view->document()); }); a->setWhatsThis(i18n("Copies the file path of the current file to clipboard.")); a = actionCollection()->addAction(QStringLiteral("file_open_containing_folder")); a->setIcon(QIcon::fromTheme(QStringLiteral("document-open-folder"))); a->setText(i18n("&Open Containing Folder")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { auto&& view = viewManager()->activeView(); KateFileActions::openContainingFolder(view->document()); }); a->setWhatsThis(i18n("Copies the file path of the current file to clipboard.")); a = actionCollection()->addAction(QStringLiteral("file_rename")); a->setIcon(QIcon::fromTheme(QStringLiteral("edit-rename"))); a->setText(i18nc("@action:inmenu", "Rename File...")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { auto&& view = viewManager()->activeView(); KateFileActions::renameDocumentFile(this, view->document()); }); a->setWhatsThis(i18n("Renames the file belonging to the current document.")); a = actionCollection()->addAction(QStringLiteral("file_delete")); a->setIcon(QIcon::fromTheme(QStringLiteral("edit-delete-shred"))); a->setText(i18nc("@action:inmenu", "Delete File")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { auto&& view = viewManager()->activeView(); KateFileActions::deleteDocumentFile(this, view->document()); }); a->setWhatsThis(i18n("Deletes the file belonging to the current document.")); a = actionCollection()->addAction(QStringLiteral("file_properties")); a->setIcon(QIcon::fromTheme(QStringLiteral("dialog-object-properties"))); a->setText(i18n("Properties")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { auto&& view = viewManager()->activeView(); KateFileActions::openFilePropertiesDialog(view->document()); }); a->setWhatsThis(i18n("Deletes the file belonging to the current document.")); a = actionCollection()->addAction(QStringLiteral("file_compare")); a->setText(i18n("Compare")); connect(a, &QAction::triggered, KateApp::self()->documentManager(), [this]() { QMessageBox::information(this, i18n("Compare"), i18n("Use the Tabbar context menu to compare two documents")); }); a->setWhatsThis(i18n("Shows a hint how to compare documents.")); a = actionCollection()->addAction(QStringLiteral("file_close_orphaned")); a->setText(i18n("Close Orphaned")); - connect(a, SIGNAL(triggered()), KateApp::self()->documentManager(), SLOT(closeOrphaned())); + connect(a, &QAction::triggered, KateApp::self()->documentManager(), &KateDocManager::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())); + connect(a, &QAction::triggered, this, &KateMainWindow::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); + connect(a, &QAction::triggered, this, &KateMainWindow::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())); + connect(a, &QAction::triggered, this, &KateMainWindow::newWindow); a->setWhatsThis(i18n("Create a new Kate view (a new window with the same document list).")); 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))); + connect(m_showFullScreenAction, &QAction::toggled, this, &KateMainWindow::slotFullScreen); 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*))); + connect(documentOpenWith->menu(), &QMenu::aboutToShow, this, &KateMainWindow::mSlotFixOpenWithMenu); + connect(documentOpenWith->menu(), &QMenu::triggered, this, &KateMainWindow::slotOpenWithMenuAction); 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())); + connect(a, &QAction::triggered, this, &KateMainWindow::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(a, &QAction::triggered, this, &KateMainWindow::aboutEditor); - connect(m_viewManager, SIGNAL(viewChanged(KTextEditor::View*)), this, SLOT(slotWindowActivated())); - connect(m_viewManager, SIGNAL(viewChanged(KTextEditor::View*)), this, SLOT(slotUpdateOpenWith())); + connect(m_viewManager, &KateViewManager::viewChanged, this, &KateMainWindow::slotWindowActivated); + connect(m_viewManager, &KateViewManager::viewChanged, this, &KateMainWindow::slotUpdateOpenWith); connect(m_viewManager, &KateViewManager::viewChanged, this, &KateMainWindow::slotUpdateActionsNeedingUrl); - connect(m_viewManager, SIGNAL(viewChanged(KTextEditor::View*)), this, SLOT(slotUpdateBottomViewBar())); + connect(m_viewManager, &KateViewManager::viewChanged, this, &KateMainWindow::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*))); + connect(m_viewManager, &KateViewManager::viewChanged, m_wrapper, &KTextEditor::MainWindow::viewChanged); + connect(m_viewManager, &KateViewManager::viewCreated, m_wrapper, &KTextEditor::MainWindow::viewCreated); + connect(this, &KateMainWindow::unhandledShortcutOverride, m_wrapper, &KTextEditor::MainWindow::unhandledShortcutOverride); 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); + connect(a, &QAction::triggered, KateApp::self()->sessionManager(), &KateSessionManager::sessionNew, 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())); + connect(a, &QAction::triggered, KateApp::self()->sessionManager(), &KateSessionManager::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())); + connect(a, &QAction::triggered, KateApp::self()->sessionManager(), &KateSessionManager::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); + connect(a, &QAction::triggered, KateApp::self()->sessionManager(), &KateSessionManager::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())); + connect(&dlg, &KEditToolBar::newToolBarConfig, this, &KateMainWindow::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 need to reload 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) +void KateMainWindow::slotOpenDocument(const 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); m_modCloseAfterLast = generalGroup.readEntry("Close After Last", 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")); + i18n("Hide menu bar"), QStringLiteral("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::slotUpdateActionsNeedingUrl() { auto&& view = viewManager()->activeView(); const bool hasUrl = view && !view->document()->url().isEmpty(); action("file_copy_filepath")->setEnabled(hasUrl); action("file_open_containing_folder")->setEnabled(hasUrl); action("file_rename")->setEnabled(hasUrl); action("file_delete")->setEnabled(hasUrl); action("file_properties")->setEnabled(hasUrl); } 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() == 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 != nullptr) { QWidget *parent = kVsender->parentWidget(); if (parent != nullptr) { KateViewSpace *vs = qobject_cast(parent->parentWidget()); 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))); + connect(list_job, &KIO::ListJob::entries, + this, &KateMainWindow::slotListRecursiveEntries); } } 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(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 = 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())); + connect(doc, &KTextEditor::Document::documentNameChanged, this, &KateMainWindow::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); + sessName = QStringLiteral("%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)); + KConfigGroup group(config.config(), QStringLiteral("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 == 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 != 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 nullptr; } return m_pluginViews.contains(plugin) ? m_pluginViews.value(plugin) : nullptr; } 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() { /** * toggle back to view manager when when quick open is already shown */ if (m_mainStackedWidget->currentWidget() == m_quickOpen) { m_mainStackedWidget->setCurrentWidget(m_viewManager); centralWidget()->setFocusProxy(m_viewManager); return; } /** * 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 107994c1c..2ed88fa85 100644 --- a/kate/katemainwindow.h +++ b/kate/katemainwindow.h @@ -1,590 +1,590 @@ /* 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 override; QSize minimumSize() const 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() override; /** * 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) override; /*reimp*/ void saveProperties(KConfigGroup &config) override; /*reimp*/ void saveGlobalProperties(KConfig *sessionConfig) override; public: 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() override; void addMenuBarActionToContextMenu(); void removeMenuBarActionFromContextMenu(); /** * read some global options from katerc */ void readOptions(); void dragEnterEvent(QDragEnterEvent *) override; void dropEvent(QDropEvent *) 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 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 slotUpdateActionsNeedingUrl(); - void slotOpenDocument(QUrl); + void slotOpenDocument(const 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; } bool modCloseAfterLast() const { return m_modCloseAfterLast; } void setModCloseAfterLast(bool e) { m_modCloseAfterLast = 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() 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 \p orientation * \param orientation in which line split the view */ void splitView(Qt::Orientation orientation) { m_viewManager->splitViewSpace(nullptr, orientation); } /** * Try to create a view bar for the given view. * Its parameter is the view for which we want a 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; /** * Shutdown Kate after last file is closed */ bool m_modCloseAfterLast; /** * 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(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 = 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) override; void mousePressEvent(QMouseEvent *e) override; }; #endif diff --git a/kate/katemdi.cpp b/kate/katemdi.cpp index fee72c2aa..12cd51b57 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("" +static const QString guiDescription = QStringLiteral("" "" "" " " " " " " "" ""); GUIClient::GUIClient(MainWindow *mw) : QObject(mw) , KXMLGUIClient(mw) , m_mw(mw) { - connect(m_mw->guiFactory(), SIGNAL(clientAdded(KXMLGUIClient*)), - this, SLOT(clientAdded(KXMLGUIClient*))); + connect(m_mw->guiFactory(), &KXMLGUIFactory::clientAdded, + this, &GUIClient::clientAdded); 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; + QString aname = QLatin1String("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(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(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 artifacts */ if (m_widgetToSize[widget].isValid()) { widget->resize(m_widgetToSize[widget]); } /** * resize to right size again and show, else artifacts * 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); + int pos = config.readEntry(QStringLiteral("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); + s.pos = config.readEntry(QStringLiteral("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()); + QList s = config.readEntry(QStringLiteral("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)); + tv->persistent = config.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Persistent").arg(tv->id), false); + tv->setToolVisible(config.readEntry(QStringLiteral("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); + config.writeEntry(QStringLiteral("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); + config.writeEntry(QStringLiteral("Kate-MDI-ToolView-%1-Position").arg(tv->id), int(tv->sidebar()->position())); + config.writeEntry(QStringLiteral("Kate-MDI-ToolView-%1-Sidebar-Position").arg(tv->id), i); + config.writeEntry(QStringLiteral("Kate-MDI-ToolView-%1-Visible").arg(tv->id), tv->toolVisible()); + config.writeEntry(QStringLiteral("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(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))); + connect(m_sidebars[i], &Sidebar::sigShowPluginConfigPage, this, &MainWindow::sigShowPluginConfigPage); } } 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 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)); + pos = (KMultiTabBar::KMultiTabBarPosition) cg.readEntry(QStringLiteral("Kate-MDI-ToolView-%1-Position").arg(identifier), int(pos)); } 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)); + pos = (KMultiTabBar::KMultiTabBarPosition) cg.readEntry(QStringLiteral("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())); + KMultiTabBar::KMultiTabBarPosition newPos = (KMultiTabBar::KMultiTabBarPosition) cg.readEntry(QStringLiteral("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 = 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/katepluginmanager.cpp b/kate/katepluginmanager.cpp index 279427f7f..1dfb4ea63 100644 --- a/kate/katepluginmanager.cpp +++ b/kate/katepluginmanager.cpp @@ -1,362 +1,362 @@ /* 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, * the following list is ordered alphabetically by plugin name * (this is not a technical need; just to have some order) */ QSet defaultPlugins; - defaultPlugins.insert(QLatin1String("cuttlefishplugin")); // this comes with package plasma5-sdk but it won't hurt to list it here (activate by right click in the text area) + defaultPlugins.insert(QStringLiteral("cuttlefishplugin")); // this comes with package plasma5-sdk but it won't hurt to list it here (activate by right click in the text area) #ifndef WIN32 - defaultPlugins.insert(QLatin1String("katefilebrowserplugin")); // currently works badly on Windows - defaultPlugins.insert(QLatin1String("katekonsoleplugin")); // currently does not work on Windows at all + defaultPlugins.insert(QStringLiteral("katefilebrowserplugin")); // currently works badly on Windows + defaultPlugins.insert(QStringLiteral("katekonsoleplugin")); // currently does not work on Windows at all #endif - defaultPlugins.insert(QLatin1String("katefiletreeplugin")); - defaultPlugins.insert(QLatin1String("kateprojectplugin")); - defaultPlugins.insert(QLatin1String("katesearchplugin")); + defaultPlugins.insert(QStringLiteral("katefiletreeplugin")); + defaultPlugins.insert(QStringLiteral("kateprojectplugin")); + defaultPlugins.insert(QStringLiteral("katesearchplugin")); //defaultPlugins.insert(QLatin1String("ktexteditorpreviewplugin")); // the feature is nice and needed, but in its current state we should not present it by default - defaultPlugins.insert(QLatin1String("tabswitcherplugin")); - defaultPlugins.insert(QLatin1String("textfilterplugin")); + defaultPlugins.insert(QStringLiteral("tabswitcherplugin")); + defaultPlugins.insert(QStringLiteral("textfilterplugin")); 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())); + KConfigGroup group(config, QStringLiteral("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)); + KConfigGroup group(config, QStringLiteral("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 = 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())); + KConfigGroup group(config, QStringLiteral("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), 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 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 nullptr; } /** * load, bail out on error */ loadPlugin(m_name2Plugin.value(name)); if (!m_name2Plugin.value(name)->plugin) { 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/katerunninginstanceinfo.h b/kate/katerunninginstanceinfo.h index 70912780b..83f604d4d 100644 --- a/kate/katerunninginstanceinfo.h +++ b/kate/katerunninginstanceinfo.h @@ -1,78 +1,78 @@ /* This file is part of the KDE project Copyright (C) 2009 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_RUNNING_INSTANCE_INFO_ #define _KATE_RUNNING_INSTANCE_INFO_ #include #include #include #include #include class KateRunningInstanceInfo: public QObject { Q_OBJECT public: KateRunningInstanceInfo(const QString &serviceName_): QObject(), valid(false), serviceName(serviceName_), dbus_if(new QDBusInterface(serviceName_, QStringLiteral("/MainApplication"), QString(), //I don't know why it does not work if I specify org.kde.Kate.Application here QDBusConnection::sessionBus(), this)) { if (!dbus_if->isValid()) { std::cerr << qPrintable(QDBusConnection::sessionBus().lastError().message()) << std::endl; } QVariant a_s = dbus_if->property("activeSession"); /* std::cerr< KateRunningInstanceMap; Q_DECL_EXPORT bool fillinRunningKateAppInstances(KateRunningInstanceMap *map); Q_DECL_EXPORT void cleanupRunningKateAppInstanceMap(KateRunningInstanceMap *map); #endif diff --git a/kate/katesavemodifieddialog.cpp b/kate/katesavemodifieddialog.cpp index 0628066e0..41eaf30dc 100644 --- a/kate/katesavemodifieddialog.cpp +++ b/kate/katesavemodifieddialog.cpp @@ -1,261 +1,261 @@ /* This file is part of the KDE project Copyright (C) 2004 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 "katesavemodifieddialog.h" #include "katedebug.h" #include #include #include #include #include #include #include #include #include class AbstractKateSaveModifiedDialogCheckListItem: public QTreeWidgetItem { public: AbstractKateSaveModifiedDialogCheckListItem(const QString &title, const QString &url): QTreeWidgetItem() { setFlags(flags() | Qt::ItemIsUserCheckable); setText(0, title); setText(1, url); setCheckState(0, Qt::Checked); setState(InitialState); } ~AbstractKateSaveModifiedDialogCheckListItem() override {} virtual bool synchronousSave(QWidget *dialogParent) = 0; enum STATE {InitialState, SaveOKState, SaveFailedState}; STATE state() const { return m_state; } void setState(enum STATE state) { m_state = state; switch (state) { case InitialState: setIcon(0, QIcon()); break; case SaveOKState: setIcon(0, QIcon::fromTheme(QStringLiteral("dialog-ok"))); // QStringLiteral("ok") icon should probably be QStringLiteral("dialog-success"), but we don't have that icon in KDE 4.0 break; case SaveFailedState: setIcon(0, QIcon::fromTheme(QStringLiteral("dialog-error"))); break; } } private: STATE m_state; }; class KateSaveModifiedDocumentCheckListItem: public AbstractKateSaveModifiedDialogCheckListItem { public: KateSaveModifiedDocumentCheckListItem(KTextEditor::Document *document) : AbstractKateSaveModifiedDialogCheckListItem(document->documentName(), document->url().toString()) { m_document = document; } ~KateSaveModifiedDocumentCheckListItem() override {} bool synchronousSave(QWidget *dialogParent) override { if (m_document->url().isEmpty()) { const QUrl url = QFileDialog::getSaveFileUrl(dialogParent, i18n("Save As (%1)", m_document->documentName())); if (!url.isEmpty()) { // check for overwriting a file if (url.isLocalFile()) { QFileInfo info(url.path()); if (info.exists()) { if (KMessageBox::Cancel == KMessageBox::warningContinueCancel(dialogParent, i18n("A file named \"%1\" already exists. " "Are you sure you want to overwrite it?" , info.fileName()), i18n("Overwrite File?"), KStandardGuiItem::overwrite(), KStandardGuiItem::cancel(), QString(), KMessageBox::Notify | KMessageBox::Dangerous)) { setState(SaveFailedState); return false; } } } if (!m_document->saveAs(url)) { setState(SaveFailedState); setText(1, m_document->url().toString()); return false; } else { bool sc = m_document->waitSaveComplete(); setText(1, m_document->url().toString()); if (!sc) { setState(SaveFailedState); return false; } else { setState(SaveOKState); return true; } } } else { //setState(SaveFailedState); return false; } } else { //document has an existing location if (!m_document->save()) { setState(SaveFailedState); setText(1, m_document->url().toString()); return false; } else { bool sc = m_document->waitSaveComplete(); setText(1, m_document->url().toString()); if (!sc) { setState(SaveFailedState); return false; } else { setState(SaveOKState); return true; } } } return false; } private: KTextEditor::Document *m_document; }; KateSaveModifiedDialog::KateSaveModifiedDialog(QWidget *parent, QList documents): QDialog(parent) { setWindowTitle(i18n("Save Documents")); setObjectName(QStringLiteral("KateSaveModifiedDialog")); setModal(true); QVBoxLayout *mainLayout = new QVBoxLayout; setLayout(mainLayout); // label QLabel *lbl = new QLabel(i18n("The following documents have been modified. Do you want to save them before closing?"), this); mainLayout->addWidget(lbl); // main view m_list = new QTreeWidget(this); mainLayout->addWidget(m_list); m_list->setColumnCount(2); m_list->setHeaderLabels(QStringList() << i18n("Documents") << i18n("Location")); m_list->setRootIsDecorated(true); foreach(KTextEditor::Document * doc, documents) { m_list->addTopLevelItem(new KateSaveModifiedDocumentCheckListItem(doc)); } m_list->resizeColumnToContents(0); connect(m_list, &QTreeWidget::itemChanged, this, &KateSaveModifiedDialog::slotItemActivated); QPushButton *selectAllButton = new QPushButton(i18n("Se&lect All"), this); mainLayout->addWidget(selectAllButton); connect(selectAllButton, &QPushButton::clicked, this, &KateSaveModifiedDialog::slotSelectAll); // dialog buttons QDialogButtonBox *buttons = new QDialogButtonBox(this); mainLayout->addWidget(buttons); m_saveButton = new QPushButton; KGuiItem::assign(m_saveButton, KStandardGuiItem::save()); buttons->addButton(m_saveButton, QDialogButtonBox::YesRole); connect(m_saveButton, &QPushButton::clicked, this, &KateSaveModifiedDialog::slotSaveSelected); QPushButton *discardButton = new QPushButton; KGuiItem::assign(discardButton, KStandardGuiItem::discard()); buttons->addButton(discardButton, QDialogButtonBox::NoRole); connect(discardButton, &QPushButton::clicked, this, &KateSaveModifiedDialog::slotDoNotSave); QPushButton *cancelButton = new QPushButton; KGuiItem::assign(cancelButton, KStandardGuiItem::cancel()); cancelButton->setDefault(true); cancelButton->setFocus(); buttons->addButton(cancelButton, QDialogButtonBox::RejectRole); connect(cancelButton, &QPushButton::clicked, this, &KateSaveModifiedDialog::reject); } KateSaveModifiedDialog::~KateSaveModifiedDialog() {} void KateSaveModifiedDialog::slotItemActivated(QTreeWidgetItem *, int) { bool enableSaveButton = false; for (int i = 0; i < m_list->topLevelItemCount(); ++i) { if (m_list->topLevelItem(i)->checkState(0) == Qt::Checked) { enableSaveButton = true; break; } } m_saveButton->setEnabled(enableSaveButton); } void KateSaveModifiedDialog::slotSelectAll() { for (int i = 0; i < m_list->topLevelItemCount(); ++i) { m_list->topLevelItem(i)->setCheckState(0, Qt::Checked); } m_saveButton->setEnabled(true); } void KateSaveModifiedDialog::slotSaveSelected() { if (doSave()) { done(QDialog::Accepted); } } void KateSaveModifiedDialog::slotDoNotSave() { done(QDialog::Accepted); } bool KateSaveModifiedDialog::doSave() { for (int i = 0; i < m_list->topLevelItemCount(); ++i) { AbstractKateSaveModifiedDialogCheckListItem *cit = static_cast(m_list->topLevelItem(i)); if (cit->checkState(0) == Qt::Checked && (cit->state() != AbstractKateSaveModifiedDialogCheckListItem::SaveOKState)) { if (!cit->synchronousSave(this /*perhaps that should be the kate mainwindow*/)) { if (cit->state() == AbstractKateSaveModifiedDialogCheckListItem::SaveFailedState) { KMessageBox::sorry(this, i18n("Data you requested to be saved could not be written. Please choose how you want to proceed.")); } return false; } } else if ((cit->checkState(0) != Qt::Checked) && (cit->state() == AbstractKateSaveModifiedDialogCheckListItem::SaveFailedState)) { cit->setState(AbstractKateSaveModifiedDialogCheckListItem::InitialState); } } return true; } -bool KateSaveModifiedDialog::queryClose(QWidget *parent, QList documents) +bool KateSaveModifiedDialog::queryClose(QWidget *parent, const QList &documents) { KateSaveModifiedDialog d(parent, documents); return (d.exec() != QDialog::Rejected); } diff --git a/kate/katesavemodifieddialog.h b/kate/katesavemodifieddialog.h index 38a7ec816..6cbc01e4a 100644 --- a/kate/katesavemodifieddialog.h +++ b/kate/katesavemodifieddialog.h @@ -1,54 +1,54 @@ /* This file is part of the KDE project Copyright (C) 2004 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_SAVE_MODIFIED_DIALOG_ #define _KATE_SAVE_MODIFIED_DIALOG_ #include #include #include class QTreeWidget; class QTreeWidgetItem; class QPushButton; class KateSaveModifiedDialog: public QDialog { Q_OBJECT public: KateSaveModifiedDialog(QWidget *parent, QList documents); ~KateSaveModifiedDialog() override; - static bool queryClose(QWidget *parent, QList documents); + static bool queryClose(QWidget *parent, const QList &documents); protected: bool doSave(); protected Q_SLOTS: void slotSelectAll(); void slotItemActivated(QTreeWidgetItem *, int); void slotSaveSelected(); void slotDoNotSave(); private: QTreeWidgetItem *m_documentRoot; QTreeWidget *m_list; QPushButton *m_saveButton; }; #endif diff --git a/kate/kateviewmanager.cpp b/kate/kateviewmanager.cpp index e977ae1da..3fa854f84 100644 --- a/kate/kateviewmanager.cpp +++ b/kate/kateviewmanager.cpp @@ -1,1244 +1,1244 @@ /* 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, nullptr); addWidget(vs); vs->setActive(true); m_viewSpaceList.append(vs); - connect(this, SIGNAL(viewChanged(KTextEditor::View*)), this, SLOT(slotViewChanged())); + connect(this, &KateViewManager::viewChanged, this, &KateViewManager::slotViewChanged); - connect(KateApp::self()->documentManager(), SIGNAL(documentCreatedViewManager(KTextEditor::Document*)), this, SLOT(documentCreated(KTextEditor::Document*))); + connect(KateApp::self()->documentManager(), &KateDocManager::documentCreatedViewManager, this, &KateViewManager::documentCreated); /** * before document is really deleted: cleanup all views! */ - connect(KateApp::self()->documentManager(), SIGNAL(documentWillBeDeleted(KTextEditor::Document*)) - , this, SLOT(documentWillBeDeleted(KTextEditor::Document*))); + connect(KateApp::self()->documentManager(), &KateDocManager::documentWillBeDeleted + , this, &KateViewManager::documentWillBeDeleted); /** * 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 &))); + connect(KateApp::self()->documentManager(), &KateDocManager::aboutToDeleteDocuments + , this, &KateViewManager::aboutToDeleteDocuments); + connect(KateApp::self()->documentManager(), &KateDocManager::documentsDeleted + , this, &KateViewManager::documentsDeleted); // 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())); + connect(m_splitViewVert, &QAction::triggered, this, &KateViewManager::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())); + connect(m_splitViewHoriz, &QAction::triggered, this, &KateViewManager::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); + connect(m_closeView, &QAction::triggered, this, &KateViewManager::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); + connect(m_closeOtherViews, &QAction::triggered, this, &KateViewManager::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); + connect(m_hideOtherViews, &QAction::triggered, this, &KateViewManager::slotHideOtherViews, 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); + connect(m_toggleSplitterOrientation, &QAction::triggered, this, &KateViewManager::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())); + connect(goNext, &QAction::triggered, this, &KateViewManager::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())); + connect(goPrev, &QAction::triggered, this, &KateViewManager::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())); + connect(a, &QAction::triggered, this, &KateViewManager::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())); + connect(a, &QAction::triggered, this, &KateViewManager::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())); + connect(a, &QAction::triggered, this, &KateViewManager::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())); + connect(a, &QAction::triggered, this, &KateViewManager::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); + fileListWithTooLargeFiles += QStringLiteral("
  • %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.

    " , fileListWithTooLargeFiles); const auto ret = KMessageBox::warningYesNo(this, text, 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) { bool shutdownKate = m_mainWindow->modCloseAfterLast() && KateApp::self()->documentManager()->documentList().size() == 1; // close document if (KateApp::self()->documentManager()->closeDocument(document) && shutdownKate) { KateApp::self()->shutdownKate(m_mainWindow); } } 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() ? nullptr : docs.last(); } KTextEditor::View *KateViewManager::openUrlWithView(const QUrl &url, const QString &encoding) { KTextEditor::Document *doc = KateApp::self()->documentManager()->openUrl(url, encoding); if (!doc) { 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))); + connect(doc, &KTextEditor::Document::documentSavedOrUploaded, this, &KateViewManager::documentSavedOrUploaded); 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*))); + connect(view, &KTextEditor::View::focusIn, this, &KateViewManager::activateSpace); 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 nullptr; } KTextEditor::View *KateViewManager::activeView() { if (m_activeViewRunning) { 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 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(); /** * kill all previous existing sub-splitters, just to be sure * e.g. important if one restores a config in an existing window with some splitters */ while (count() > 0) { delete widget(0); } // 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, 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, 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/kateviewspace.cpp b/kate/kateviewspace.cpp index 21469c732..f8d5c70fb 100644 --- a/kate/kateviewspace.cpp +++ b/kate/kateviewspace.cpp @@ -1,747 +1,747 @@ /* 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 "katefileactions.h" #include "katesessionmanager.h" #include "katedebug.h" #include "katetabbar.h" #include "kactioncollection.h" #include "kateupdatedisabler.h" #include #include #include #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())); + connect(bridge, &QAction::triggered, quickOpen, &QAction::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())); + connect(m_viewManager->mainWindow(), &KateMainWindow::statusBarToggled, this, &KateViewSpace::statusBarToggled); + connect(m_viewManager->mainWindow(), &KateMainWindow::tabBarToggled, this, &KateViewSpace::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())); + connect(KateApp::self()->documentManager(), &KateDocManager::documentCreated, this, &KateViewSpace::updateQuickOpen); + connect(KateApp::self()->documentManager(), &KateDocManager::documentsDeleted, this, &KateViewSpace::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); + QString vgroup = QStringLiteral("%1 %2").arg(m_group, 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::documentNameChanged, + this, &KateViewSpace::updateDocumentName); connect(doc, &KTextEditor::Document::documentUrlChanged, this, &KateViewSpace::updateDocumentUrl); - connect(doc, SIGNAL(modifiedChanged(KTextEditor::Document*)), - this, SLOT(updateDocumentState(KTextEditor::Document*))); + connect(doc, &KTextEditor::Document::modifiedChanged, + this, &KateViewSpace::updateDocumentState); } 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::documentNameChanged, + this, &KateViewSpace::updateDocumentName); disconnect(doc, &KTextEditor::Document::documentUrlChanged, this, &KateViewSpace::updateDocumentUrl); - disconnect(doc, SIGNAL(modifiedChanged(KTextEditor::Document*)), - this, SLOT(updateDocumentState(KTextEditor::Document*))); + disconnect(doc, &KTextEditor::Document::modifiedChanged, + this, &KateViewSpace::updateDocumentState); } 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*))); + connect(doc, &QObject::destroyed, this, &KateViewSpace::documentDestroyed); // 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, 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")); + icon = QIcon::fromTheme(QStringLiteral("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); m_viewManager->slotDocumentClose(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); auto addActionFromCollection = [this](QMenu* menu, const char* action_name) { QAction* action = m_viewManager->mainWindow()->action(action_name); return menu->addAction(action->icon(), action->text()); }; 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 = addActionFromCollection(&menu, "file_copy_filepath"); QAction *aOpenFolder = addActionFromCollection(&menu, "file_open_containing_folder"); QAction *aFileProperties = addActionFromCollection(&menu, "file_properties"); menu.addSeparator(); QAction *aRenameFile = addActionFromCollection(&menu, "file_rename"); QAction *aDeleteFile = addActionFromCollection(&menu, "file_delete"); menu.addSeparator(); QMenu *mCompareWithActive = new QMenu(i18n("Compare with active document"), &menu); mCompareWithActive->setIcon(QIcon::fromTheme(QStringLiteral("kompare"))); menu.addMenu(mCompareWithActive); if (KateApp::self()->documentManager()->documentList().count() < 2) { aCloseOthers->setEnabled(false); } if (doc->url().isEmpty()) { aCopyPath->setEnabled(false); aOpenFolder->setEnabled(false); aRenameFile->setEnabled(false); aDeleteFile->setEnabled(false); aFileProperties->setEnabled(false); mCompareWithActive->setEnabled(false); } auto activeDocument = KTextEditor::Editor::instance()->application()->activeMainWindow()->activeView()->document(); // used for mCompareWithActive which is used with another tab which is not active // both documents must have urls and must not be the same to have the compare feature enabled if (activeDocument->url().isEmpty() || activeDocument == doc) { mCompareWithActive->setEnabled(false); } if (mCompareWithActive->isEnabled()) { for (auto&& diffTool : KateFileActions::supportedDiffTools()) { QAction *compareAction = mCompareWithActive->addAction(diffTool); compareAction->setData(diffTool); } } QAction *choice = menu.exec(globalPos); if (!choice) { return; } if (choice == aCloseTab) { closeTabRequest(id); } else if (choice == aCloseOthers) { KateApp::self()->documentManager()->closeOtherDocuments(doc); } else if (choice == aCopyPath) { KateFileActions::copyFilePathToClipboard(doc); } else if (choice == aOpenFolder) { KateFileActions::openContainingFolder(doc); } else if (choice == aFileProperties) { KateFileActions::openFilePropertiesDialog(doc); } else if (choice == aRenameFile) { KateFileActions::renameDocumentFile(this, doc); } else if (choice == aDeleteFile) { KateFileActions::deleteDocumentFile(this, doc); } else if (choice->parent() == mCompareWithActive) { QString actionData = choice->data().toString(); // name of the executable of the diff program if (!KateFileActions::compareWithExternalProgram(activeDocument, doc, actionData)) { QMessageBox::information(this, i18n("Could not start program"), i18n("The selected program could not be started. Maybe it is not installed."), QMessageBox::StandardButton::Ok); } } } 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()); + group.writeEntry(QStringLiteral("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()); + QString vgroup = QStringLiteral("%1 %2").arg(groupname, (*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); + QString vgroup = QStringLiteral("%1 %2").arg(groupname, 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/main.cpp b/kate/main.cpp index a45f0d735..dca9ffc3e 100644 --- a/kate/main.cpp +++ b/kate/main.cpp @@ -1,640 +1,640 @@ /* 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 #include #include #include #include #include #include #include #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 // Prohibit using sudo or kdesu (but allow using the root user directly) if (getuid() == 0) { if (!qEnvironmentVariableIsEmpty("SUDO_USER")) { std::cout << "Executing Kate with sudo is not possible due to unfixable security vulnerabilities." << std::endl; return EXIT_FAILURE; } else if (!qEnvironmentVariableIsEmpty("KDESU_USER")) { std::cout << "Executing Kate with kdesu is not possible due to unfixable security vulnerabilities." << std::endl; return EXIT_FAILURE; } } #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. */ KCrash::initialize(); /** * 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) */ aboutData.setDesktopFileName(QStringLiteral("org.kde.kate")); /** * authors & co. */ aboutData.addAuthor(i18n("Christoph Cullmann"), i18n("Maintainer"), QStringLiteral("cullmann@kde.org"), QStringLiteral("http://www.cullmann.io")); aboutData.addAuthor(i18n("Dominik Haumann"), i18n("Core Developer"), QStringLiteral("dhaumann@kde.org")); aboutData.addAuthor(i18n("Sven Brauch"), i18n("Developer"), QStringLiteral("mail@svenbrauch.de")); aboutData.addAuthor(i18n("Kåre Särs"), i18n("Developer"), QStringLiteral("kare.sars@iki.fi")); 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("Alexander Neundorf"), i18n("Developer"), QStringLiteral("neundorf@kde.org")); 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"))); + aboutData.setProgramLogo (QImage(QStringLiteral(":/kate/mascot.png"))); /** * set and register app about data */ KAboutData::setApplicationData(aboutData); /** * set the program icon */ - QApplication::setWindowIcon(QIcon::fromTheme(QLatin1String("kate"), app.windowIcon())); + QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("kate"), app.windowIcon())); /** * Create command line parser and feed it with known options */ QCommandLineParser parser; aboutData.setupCommandLine(&parser); // -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 reuse 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; } QString currentActivity; QDBusMessage m = QDBusMessage::createMethodCall( QStringLiteral("org.kde.ActivityManager"), QStringLiteral("/ActivityManager/Activities"), QStringLiteral("org.kde.ActivityManager.Activities"), QStringLiteral("CurrentActivity")); QDBusMessage res = QDBusConnection::sessionBus().call(m); QList answer = res.arguments(); if (answer.size() == 1) { currentActivity = answer.at(0).toString(); } QStringList kateServices; for (KateRunningInstanceMap::const_iterator it = mapSessionRii.constBegin(); it != mapSessionRii.constEnd(); ++it) { QString serviceName = (*it)->serviceName; if (currentActivity.length() != 0) { QDBusMessage m = QDBusMessage::createMethodCall(serviceName, QStringLiteral("/MainApplication"), QStringLiteral("org.kde.Kate.Application"), QStringLiteral("isOnActivity")); QList dbargs; // convert to an url dbargs.append(currentActivity); m.setArguments(dbargs); QDBusMessage res = QDBusConnection::sessionBus().call(m); QList answer = res.arguments(); if (answer.size() == 1) { const bool canBeUsed = answer.at(0).toBool(); // If the Kate instance is in a specific activity, add it to // the list of candidate reusable services if (canBeUsed) { kateServices << serviceName; } } } else { kateServices << 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(); for (int s = 0; s < kateServices.count(); s++) { serviceName = kateServices[s]; if (!serviceName.isEmpty()) { QDBusReply there = sessionBusInterface->isServiceRegistered(serviceName); if (there.isValid() && there.value()) { // 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) { // special case: on all desktops! that is -1 aka NET::OnAllDesktops, see KWindowInfo::desktop() docs const int sessionDesktopNumber = answer.at(0).toInt(); if (sessionDesktopNumber == desktopnumber || sessionDesktopNumber == NET::OnAllDesktops) { // 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... // Bug 397913: Reverse the order here so the new tabs are opened in same order as the files were passed in on the command line for (int i = urls.size() - 1; i >= 0; --i) { const QString &url = urls[i]; 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()) : 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(); // We don't want the session manager to restart us on next login // if we block if (needToBlock) { QObject::connect(qApp, &QGuiApplication::saveStateRequest, qApp, [](QSessionManager &session) { session.setRestartHint(QSessionManager::RestartNever); }, Qt::DirectConnection ); } // 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! */ /** * set some KTextEditor defaults */ { KConfigGroup viewConfig(KSharedConfig::openConfig(), QStringLiteral("KTextEditor View")); if (!viewConfig.exists()) { viewConfig.writeEntry("Line Modification", true); viewConfig.writeEntry("Line Numbers", true); } } /** * 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/katesessionmanager.cpp b/kate/session/katesessionmanager.cpp index 1ed8f9dcf..e0e610d61 100644 --- a/kate/session/katesessionmanager.cpp +++ b/kate/session/katesessionmanager.cpp @@ -1,635 +1,635 @@ /* 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 "katesessionmanagedialog.h" #include "kateapp.h" #include "katepluginmanager.h" #include "katerunninginstanceinfo.h" #include #include #include #include #include #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())); + connect(m_dirWatch, &KDirWatch::dirty, this, &KateSessionManager::updateSessionList); updateSessionList(); } 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"), QDir::Time); for (unsigned int i = 0; i < dir.count(); ++i) { QString name = dir[i]; name.chop(12); // .katesession list << QUrl::fromPercentEncoding(name.toLatin1()); } // write jump list actions to disk in the kate.desktop file updateJumpListActions(list); bool changed = false; // Add new sessions to our list for (const QString session : qAsConst(list)) { if (!m_sessions.contains(session)) { const QString file = sessionFileForName(session); m_sessions.insert(session, KateSession::create(file, session)); changed = true; } } // Remove gone sessions from our list for (const QString session : m_sessions.keys()) { if ((list.indexOf(session) < 0) && (m_sessions.value(session) != activeSession())) { m_sessions.remove(session); changed = true; } } if (changed) { emit sessionListChanged(); } } bool KateSessionManager::activateSession(KateSession::Ptr session, const bool closeAndSaveLast, const bool loadNew) { if (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(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(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)); + KateApp::self()->newMainWindow(cfg, QStringLiteral("MainWindow%1").arg(i)); } else { - KateApp::self()->mainWindow(i)->readProperties(KConfigGroup(cfg, QString::fromLatin1("MainWindow%1").arg(i))); + KateApp::self()->mainWindow(i)->readProperties(KConfigGroup(cfg, QStringLiteral("MainWindow%1").arg(i))); } - KateApp::self()->mainWindow(i)->restoreWindowConfig(KConfigGroup(cfg, QString::fromLatin1("MainWindow%1 Settings").arg(i))); + KateApp::self()->mainWindow(i)->restoreWindowConfig(KConfigGroup(cfg, QStringLiteral("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; // Due to this add to m_sessions will updateSessionList() no signal emit, // but it's importand to add. Otherwise could it be happen that m_activeSession // is not part of m_sessions but a double emit sessionListChanged(); return s; } bool KateSessionManager::deleteSession(KateSession::Ptr session) { if (sessionIsActive(session->name())) { return false; } QFile::remove(session->file()); m_sessions.remove(session->name()); // Due to this remove from m_sessions will updateSessionList() no signal emit, // but this way is there no delay between deletion and information emit sessionListChanged(); return true; } -QString KateSessionManager::copySession(KateSession::Ptr session, const QString &newName) +QString KateSessionManager::copySession(const KateSession::Ptr &session, const QString &newName) { const QString name = askForNewSessionName(session, newName); if (name.isEmpty()) { return name; } const QString newFile = sessionFileForName(name); KateSession::Ptr ns = KateSession::createFrom(session, newFile, name); ns->config()->sync(); return name; } QString KateSessionManager::renameSession(KateSession::Ptr session, const QString &newName) { const QString name = askForNewSessionName(session, newName); if (name.isEmpty()) { return name; } const QString newFile = sessionFileForName(name); 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 QString(); } m_sessions[newName] = m_sessions.take(session->name()); session->setName(newName); session->setFile(newFile); session->config()->sync(); // updateSessionList() will this edit not notice, so force signal emit sessionListChanged(); if (session == activeSession()) { emit sessionChanged(); } return name; } void KateSessionManager::saveSessionTo(KConfig *sc) const { // Clear the session file to avoid to accumulate outdated entries for (auto group : sc->groupList()) { sc->deleteGroup(group); } // 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)); + KConfigGroup cg(sc, QStringLiteral("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))); + KateApp::self()->mainWindow(i)->saveWindowConfig(KConfigGroup(sc, QStringLiteral("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) { if (!activeSession()) { return false; } KConfig *sc = activeSession()->config(); saveSessionTo(sc); if (rememberAsLast && !activeSession()->isAnonymous()) { 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; } return QScopedPointer(new KateSessionManageDialog(nullptr, lastSession))->exec(); } void KateSessionManager::sessionNew() { activateSession(giveSession(QString())); } void KateSessionManager::sessionSave() { saveActiveSession(); // this is the optional point to handle saveSessionAs for anonymous session } void KateSessionManager::sessionSaveAs() { const QString newName = askForNewSessionName(activeSession()); if (newName.isEmpty()) { return; } activeSession()->config()->sync(); KateSession::Ptr ns = KateSession::createFrom(activeSession(), sessionFileForName(newName), newName); m_activeSession = ns; saveActiveSession(); emit sessionChanged(); } QString KateSessionManager::askForNewSessionName(KateSession::Ptr session, const QString &newName) { if (session->name() == newName && !session->isAnonymous()) { return QString(); } const QString messagePrompt = i18n("Session name:"); const KLocalizedString messageExist = ki18n("There is already an existing session with your chosen name: %1\n" "Please choose a different one."); const QString messageEmpty = i18n("To save a session, you must specify a name."); QString messageTotal = messagePrompt; QString name = newName; while (true) { QString preset = name; if (name.isEmpty()) { preset = suggestNewSessionName(session->name()); messageTotal = messageEmpty + QStringLiteral("\n\n") + messagePrompt; } else if (QFile::exists(sessionFileForName(name))) { preset = suggestNewSessionName(name); if (preset.isEmpty()) { // Very unlikely, but as fall back we keep users input preset = name; } messageTotal = messageExist.subs(name).toString() + QStringLiteral("\n\n") + messagePrompt; } else { return name; } QInputDialog dlg(KateApp::self()->activeKateMainWindow()); dlg.setInputMode(QInputDialog::TextInput); if (session->isAnonymous()) { dlg.setWindowTitle(i18n("Specify a name for this session")); } else { dlg.setWindowTitle(i18n("Specify a new name for session: %1", session->name())); } dlg.setLabelText(messageTotal); dlg.setTextValue(preset); dlg.resize(900,100); // FIXME Calc somehow a proper size bool ok = dlg.exec(); name = dlg.textValue(); if (!ok) { return QString(); } } } QString KateSessionManager::suggestNewSessionName(const QString &target) { if (target.isEmpty()) { // Here could also a default name set or the current session name used return QString(); } const QString mask = QStringLiteral("%1 (%2)"); QString name; for (int i = 2; i < 1000000; i++) { // Should be enough to get an unique name name = mask.arg(target).arg(i); if (!QFile::exists(sessionFileForName(name))) { return name; } } return QString(); } void KateSessionManager::sessionManage() { QScopedPointer(new KateSessionManageDialog(KateApp::self()->activeKateMainWindow()))->exec(); } bool KateSessionManager::sessionIsActive(const QString &session) { // Try to avoid unneed action if (activeSession() && activeSession()->name() == session) { return true; } QDBusConnectionInterface *i = QDBusConnection::sessionBus().interface(); if (!i) { return false; } // look up all running kate instances and there sessions QDBusReply servicesReply = i->registeredServiceNames(); QStringList services; if (servicesReply.isValid()) { services = servicesReply.value(); } for (const QString &s : qAsConst(services)) { if (!s.startsWith(QStringLiteral("org.kde.kate-"))) { continue; } KateRunningInstanceInfo rii(s); if (rii.valid && rii.sessionName == session) { return true; } } return false; } 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(); } void KateSessionManager::updateJumpListActions(const QStringList &sessionList) { #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) KService::Ptr service = KService::serviceByStorageId(qApp->desktopFileName()); if (!service) { return; } QScopedPointer df(new KDesktopFile(service->entryPath())); QStringList newActions = df->readActions(); // try to keep existing custom actions intact, only remove our "Session" actions and add them back later newActions.erase(std::remove_if(newActions.begin(), newActions.end(), [](const QString &action) { return action.startsWith(QLatin1String("Session ")); }), newActions.end()); // Limit the number of list entries we like to offer const int maxEntryCount = std::min(sessionList.count(), 10); // sessionList is ordered by time, but we like it alphabetical to avoid even more a needed update QStringList sessionSubList = sessionList.mid(0, maxEntryCount); sessionSubList.sort(); // we compute the new group names in advance so we can tell whether we changed something // and avoid touching the desktop file leading to an expensive ksycoca recreation QStringList sessionActions; sessionActions.reserve(maxEntryCount); for (int i = 0; i < maxEntryCount; ++i) { sessionActions << QStringLiteral("Session %1").arg(QString::fromLatin1(QCryptographicHash::hash(sessionSubList.at(i).toUtf8() , QCryptographicHash::Md5).toHex())); } newActions += sessionActions; // nothing to do if (df->readActions() == newActions) { return; } const QString &localPath = service->locateLocal(); if (service->entryPath() != localPath) { df.reset(df->copyTo(localPath)); } // remove all Session action groups first to not leave behind any cruft for (const QString &action : df->readActions()) { if (action.startsWith(QLatin1String("Session "))) { // TODO is there no deleteGroup(KConfigGroup)? df->deleteGroup(df->actionGroup(action).name()); } } for (int i = 0; i < maxEntryCount; ++i) { const QString &action = sessionActions.at(i); // is a transform of sessionSubList, so count and order is identical const QString &session = sessionSubList.at(i); KConfigGroup grp = df->actionGroup(action); grp.writeEntry(QStringLiteral("Name"), session); grp.writeEntry(QStringLiteral("Exec"), QStringLiteral("kate -s %1").arg(KShell::quoteArg(session))); // TODO proper executable name? } df->desktopGroup().writeXdgListEntry("Actions", newActions); #endif } //END KateSessionManager diff --git a/kate/session/katesessionmanager.h b/kate/session/katesessionmanager.h index dd9b1571b..aea93f612 100644 --- a/kate/session/katesessionmanager.h +++ b/kate/session/katesessionmanager.h @@ -1,251 +1,251 @@ /* 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 friend class KateSessionManageDialog; public: KateSessionManager(QObject *parent = nullptr, const QString &sessionsDir = QString()); ~KateSessionManager() override; /** * allow access to the session list * kept up to date by watching the dir */ KateSessionList sessionList(); /** * activate session by \p 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 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(); /** * Emitted whenever the session list has changed. * @see sessionList() */ void sessionListChanged(); /** * 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); /** * Try to delete the @p session and removes the session from sessions list * @param session the session to delete * @return true on success, false if @p session is currently in use */ bool deleteSession(KateSession::Ptr session); /** * Try to copy the @p session to a new session @p newName. * Will ask by @c askForNewSessionName() for a differend name when @p newName is already in use or is an * empty string. * @param session the session to copy * @param newName is wished name of the new session * @return the new session name on success, otherwise an empty string * @see askForNewSessionName() */ - QString copySession(KateSession::Ptr session, const QString &newName = QString()); + QString copySession(const KateSession::Ptr &session, const QString &newName = QString()); /** * Try to rename the @p session to @p newName. * Will ask by @c askForNewSessionName() for a differend name when @p newName is already in use or is an * empty string. * @param session the session to rename * @param newName is wished new name of the session * @return the new session name on success, otherwise an empty string * @see askForNewSessionName() */ QString renameSession(KateSession::Ptr session, const QString &newName = QString()); /** * 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: /** * Ask the user for a new session name, when needed. * @param session is the session to rename or copy * @param newName is a preset value. Is @p newName not already in use is nothing asked * @return a (currently) not used new session name or an empty string when * user aborted or when @p newName is the current session name. */ QString askForNewSessionName(KateSession::Ptr session, const QString &newName = QString()); /** * Try to generate a new session name from @p target by a number suffix. * @param target is the base name * @return a (currently) not used session name or an empty string */ QString suggestNewSessionName(const QString &target); /** * returns session config file according to policy */ QString sessionFileForName(const QString &name) const; /** * @return true when @p session is active in any Kate instance, otherwise false */ bool sessionIsActive(const QString &session); /** * 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; /** * Writes sessions as jump list actions to the kate.desktop file */ void updateJumpListActions(const QStringList &sessionList); 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.cpp b/kate/session/katesessionsaction.cpp index 39253130c..783c7b196 100644 --- a/kate/session/katesessionsaction.cpp +++ b/kate/session/katesessionsaction.cpp @@ -1,80 +1,80 @@ /* 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 "katesessionsaction.h" #include "kateapp.h" #include "katesessionmanager.h" #include #include KateSessionsAction::KateSessionsAction(const QString &text, QObject *parent, KateSessionManager *manager) : KActionMenu(text, parent) { m_manager = manager ? manager : KateApp::self()->sessionManager(); - connect(menu(), SIGNAL(aboutToShow()), this, SLOT(slotAboutToShow())); + connect(menu(), &QMenu::aboutToShow, this, &KateSessionsAction::slotAboutToShow); sessionsGroup = new QActionGroup(menu()); // reason for Qt::QueuedConnection: when switching session with N mainwindows // to e.g. 1 mainwindow, the last N - 1 mainwindows are deleted. Invoking // a session switch without queued connection deletes a mainwindow in which // the current code path is executed ---> crash. See bug #227008. - connect(sessionsGroup, SIGNAL(triggered(QAction*)), this, SLOT(openSession(QAction*)), Qt::QueuedConnection); + connect(sessionsGroup, &QActionGroup::triggered, this, &KateSessionsAction::openSession, Qt::QueuedConnection); - connect(m_manager, SIGNAL(sessionChanged()), this, SLOT(slotSessionChanged())); + connect(m_manager, &KateSessionManager::sessionChanged, this, &KateSessionsAction::slotSessionChanged); setDisabled(m_manager->sessionList().size() == 0); } void KateSessionsAction::slotAboutToShow() { qDeleteAll(sessionsGroup->actions()); KateSessionList slist = m_manager->sessionList(); std::sort(slist.begin(), slist.end(), KateSession::compareByTimeDesc); slist = slist.mid(0, 10); // take first 10 // sort the reduced list alphabetically (#364089) std::sort(slist.begin(), slist.end(), KateSession::compareByName); foreach(const KateSession::Ptr & session, slist) { QString sessionName = session->name(); sessionName.replace(QStringLiteral("&"), QStringLiteral("&&")); QAction *action = new QAction(sessionName, sessionsGroup); action->setData(QVariant(session->name())); menu()->addAction(action); } } void KateSessionsAction::openSession(QAction *action) { const QString name = action->data().toString(); m_manager->activateSession(name); } void KateSessionsAction::slotSessionChanged() { setDisabled(m_manager->sessionList().size() == 0); } diff --git a/kwrite/kwrite.cpp b/kwrite/kwrite.cpp index d18ed0ffb..b82ec809e 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(nullptr) , m_recentFiles(nullptr) , m_paShowPath(nullptr) , m_paShowMenuBar(nullptr) , m_paShowStatusBar(nullptr) , m_activityResource(nullptr) { if (!doc) { 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())); + connect(m_view->document(), &KTextEditor::Document::documentNameChanged, this, &KWrite::documentNameChanged); + connect(m_view->document(), &KTextEditor::Document::readWriteChanged, this, &KWrite::documentNameChanged); + connect(m_view->document(), &KTextEditor::Document::documentUrlChanged, this, &KWrite::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())); + connect(a, &QAction::triggered, this, &KWrite::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())); + connect(m_paShowPath, &QAction::triggered, this, &KWrite::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())); + connect(a, &QAction::triggered, this, &KWrite::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")); + QStringLiteral("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())); + connect(&dlg, &KEditToolBar::newToolBarConfig, this, &KWrite::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); + QString buf = QStringLiteral("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); + QString buf = QStringLiteral("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); + buf = QStringLiteral("Document %1").arg(z); KConfigGroup cg(config, buf); 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); + buf = QStringLiteral("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/main.cpp b/kwrite/main.cpp index 2f853b928..fc8c6852f 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 // Prohibit using sudo or kdesu (but allow using the root user directly) if (getuid() == 0) { if (!qEnvironmentVariableIsEmpty("SUDO_USER")) { std::cout << "Executing KWrite with sudo is not possible due to unfixable security vulnerabilities." << std::endl; return EXIT_FAILURE; } else if (!qEnvironmentVariableIsEmpty("KDESU_USER")) { std::cout << "Executing KWrite with kdesu is not possible due to unfixable security vulnerabilities." << std::endl; return EXIT_FAILURE; } } #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("Dominik Haumann"), i18n("Core Developer"), QStringLiteral("dhaumann@kde.org")); 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("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())); + QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("accessories-text-editor"), app.windowIcon())); /** * Create command line parser and feed it with known options */ QCommandLineParser parser; aboutData.setupCommandLine(&parser); // -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()) : 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(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 *