diff --git a/kwrite/CMakeLists.txt b/kwrite/CMakeLists.txt index 3bcb7cc81..f95836403 100644 --- a/kwrite/CMakeLists.txt +++ b/kwrite/CMakeLists.txt @@ -1,72 +1,72 @@ # KWrite project (kwrite) # Load the frameworks we need find_package(KF5 REQUIRED COMPONENTS DBusAddons) # collect icons set(KWRITE_ICONS_PNG ${CMAKE_CURRENT_SOURCE_DIR}/icons/16-apps-kwrite.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/22-apps-kwrite.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/32-apps-kwrite.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/48-apps-kwrite.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/64-apps-kwrite.png ${CMAKE_CURRENT_SOURCE_DIR}/icons/128-apps-kwrite.png ) set(KWRITE_ICONS_SVG ${CMAKE_CURRENT_SOURCE_DIR}/icons/sc-apps-kwrite.svgz ) # collect the sources -set (KWRITE_APPLICATION_SRCS main.cpp kwrite.cpp) +set (KWRITE_APPLICATION_SRCS main.cpp kwrite.cpp kwriteapplication.cpp) qt5_add_resources(KWRITE_APPLICATION_SRCS data/kwrite.qrc) # add icons to application sources, to have them bundled ecm_add_app_icon(KWRITE_APPLICATION_SRCS ICONS ${KWRITE_ICONS_PNG}) # build KWrite application add_executable(kwrite ${KWRITE_APPLICATION_SRCS}) target_link_libraries(kwrite PUBLIC KF5::TextEditor KF5::I18n KF5::DBusAddons KF5::Crash ) if(KF5Activities_FOUND) target_link_libraries(kwrite PUBLIC KF5::Activities) endif() # own plist magic for mac os if(APPLE) # own plist template set_target_properties (kwrite PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/data/MacOSXBundleInfo.plist.in) # the MacOSX bundle display name property (CFBundleDisplayName) is not currently supported by cmake, # so has to be set for all targets in this cmake file set(MACOSX_BUNDLE_DISPLAY_NAME KWrite) set_target_properties(kwrite PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "org.kde.KWrite") set_target_properties(kwrite PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "KWrite") set_target_properties(kwrite PROPERTIES MACOSX_BUNDLE_DISPLAY_NAME "KWrite") set_target_properties(kwrite PROPERTIES MACOSX_BUNDLE_INFO_STRING "KWrite - Text Editor") set_target_properties(kwrite PROPERTIES MACOSX_BUNDLE_LONG_VERSION_STRING "KWrite ${KDE_APPLICATIONS_VERSION}") set_target_properties(kwrite PROPERTIES MACOSX_BUNDLE_SHORT_VERSION_STRING "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}") set_target_properties(kwrite PROPERTIES MACOSX_BUNDLE_BUNDLE_VERSION "${KDE_APPLICATIONS_VERSION}") set_target_properties(kwrite PROPERTIES MACOSX_BUNDLE_COPYRIGHT "2000-2016 The KWrite Authors") endif() # install executable install(TARGETS kwrite ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) # desktop file install(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/data/org.kde.kwrite.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) # appdata install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/org.kde.kwrite.appdata.xml DESTINATION ${CMAKE_INSTALL_METAINFODIR}) # install icons ecm_install_icons(ICONS ${KWRITE_ICONS_PNG} ${KWRITE_ICONS_SVG} DESTINATION ${ICON_INSTALL_DIR} THEME hicolor) diff --git a/kwrite/kwrite.cpp b/kwrite/kwrite.cpp index b82ec809e..651e86cff 100644 --- a/kwrite/kwrite.cpp +++ b/kwrite/kwrite.cpp @@ -1,560 +1,529 @@ /* 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 #include #ifdef KActivities_FOUND #include #endif #include #include #include #include #include #include #include #include #include #include -QList KWrite::docList; -QList KWrite::winList; +#include "kwriteapplication.h" -KWrite::KWrite(KTextEditor::Document *doc) +KWrite::KWrite(KTextEditor::Document *doc, KWriteApplication *app) : m_view(nullptr) , m_recentFiles(nullptr) , m_paShowPath(nullptr) , m_paShowMenuBar(nullptr) , m_paShowStatusBar(nullptr) , m_activityResource(nullptr) + , m_app(app) + , m_mainWindow(this) { 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_app->addDocument(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(), &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() { + m_app->removeWindow(this); 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); + m_app->removeDocument(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, &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, &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, &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(); + m_app->newWindow(); } 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(); + KWrite *t = m_app->newWindow(); 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()); + m_app->newWindow(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"), 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, &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); + config.writeEntry("DocumentNumber", m_app->documents().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 = 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 = 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 = 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 = QStringLiteral("Window %1").arg(z); - KConfigGroup cg(config, buf); - t = new KWrite(docList.at(cg.readEntry("DocumentNumber", 0) - 1)); - t->restore(config, z); - } + m_app->saveProperties(config); } 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); } + +QList KWrite::views() +{ + QList list; + list.append(m_view); + return list; +} + + +KTextEditor::View *KWrite::activateView(KTextEditor::Document *document) +{ + if (m_view->document() == document) { + return m_view; + } + + return nullptr; +} diff --git a/kwrite/kwrite.h b/kwrite/kwrite.h index 85649f6d0..b7aece7e7 100644 --- a/kwrite/kwrite.h +++ b/kwrite/kwrite.h @@ -1,147 +1,147 @@ /* This file is part of the KDE project Copyright (C) 2001 Christoph Cullmann Copyright (C) 2001 Joseph Wenninger Copyright (C) 2001 Anders Lund This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KWRITE_MAIN_H #define KWRITE_MAIN_H #include #include +#include #include #include #include #include class QLabel; namespace KActivities { class ResourceInstance; } class KToggleAction; class KRecentFilesAction; class KSqueezedTextLabel; +class KWriteApplication; class KWrite : public KParts::MainWindow { Q_OBJECT public: - KWrite(KTextEditor::Document * = nullptr); + KWrite(KTextEditor::Document * = nullptr, KWriteApplication *app = nullptr); ~KWrite() override; void loadURL(const QUrl &url); - KTextEditor::View *view() const { - return m_view; - } - - static bool noWindows() { - return winList.isEmpty(); - } - private: void setupActions(); void addMenuBarActionToContextMenu(); void removeMenuBarActionFromContextMenu(); bool queryClose() override; void dragEnterEvent(QDragEnterEvent *) override; void dropEvent(QDropEvent *) override; public Q_SLOTS: void slotNew(); void slotFlush(); void slotOpen(); void slotOpen(const QUrl &url); void newView(); void toggleStatusBar(); void toggleMenuBar(bool showMessage = true); void editKeys(); void editToolbars(); void aboutEditor(); void modifiedChanged(); private Q_SLOTS: void slotNewToolbarConfig(); public Q_SLOTS: void slotDropEvent(QDropEvent *); void slotEnableActions(bool enable); /** * adds a changed URL to the recent files */ void urlChanged(); /** * Overwrite size hint for better default window sizes * @return size hint */ QSize sizeHint () const override; //config file functions public: void readConfig(KSharedConfigPtr); void writeConfig(KSharedConfigPtr); void readConfig(); void writeConfig(); //session management public: void restore(KConfig *, int); - static void restore(); + +public: + KTextEditor::MainWindow *mainWindow() { return &m_mainWindow; } + +public Q_SLOTS: + QWidget *window() { return this; } + QList views(); + KTextEditor::View *activeView() { return m_view; } + KTextEditor::View *activateView(KTextEditor::Document *document); private: void readProperties(const KConfigGroup &) override; void saveProperties(KConfigGroup &) override; void saveGlobalProperties(KConfig *) override; private: KTextEditor::View *m_view; KRecentFilesAction *m_recentFiles; KToggleAction *m_paShowPath; KToggleAction *m_paShowMenuBar; KToggleAction *m_paShowStatusBar; QAction *m_closeAction; KActivities::ResourceInstance *m_activityResource; - - static QList docList; - static QList winList; + KWriteApplication *m_app; + KTextEditor::MainWindow m_mainWindow; public Q_SLOTS: void documentNameChanged(); - + protected: /** * Event filter for QApplication to handle mac os like file open */ bool eventFilter(QObject *obj, QEvent *event) override; }; #endif - diff --git a/kwrite/kwriteapplication.cpp b/kwrite/kwriteapplication.cpp new file mode 100644 index 000000000..84b217b58 --- /dev/null +++ b/kwrite/kwriteapplication.cpp @@ -0,0 +1,145 @@ +/* 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 "kwriteapplication.h" +#include "kwrite.h" + +#include +#include + +KWriteApplication::KWriteApplication::KWriteApplication() +{ + m_application = new KTextEditor::Application(this); + KTextEditor::Editor::instance()->setApplication(m_application); +} + +KWriteApplication::~KWriteApplication() +{ + delete m_application; +} + +KWrite * KWriteApplication::newWindow(KTextEditor::Document* doc) +{ + KWrite *k = new KWrite(doc, this); + m_kwrites.append(k); + return k; +} + +void KWriteApplication::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 = QStringLiteral("Document %1").arg(z); + KConfigGroup cg(config, buf); + doc = KTextEditor::Editor::instance()->createDocument(nullptr); + doc->readSessionConfig(cg); + addDocument(doc); + } + + for (int z = 1; z <= windows; z++) { + buf = QStringLiteral("Window %1").arg(z); + KConfigGroup cg(config, buf); + t = newWindow(m_documents.at(cg.readEntry("DocumentNumber", 0) - 1)); + t->restore(config, z); + } +} + +void KWriteApplication::saveProperties(KConfig* config) +{ + config->group("Number").writeEntry("NumberOfDocuments", m_documents.count()); + + for (int z = 1; z <= m_documents.count(); z++) { + QString buf = QStringLiteral("Document %1").arg(z); + KConfigGroup cg(config, buf); + KTextEditor::Document *doc = m_documents.at(z - 1); + doc->writeSessionConfig(cg); + } + + for (int z = 1; z <= m_kwrites.count(); z++) { + QString buf = QStringLiteral("Window %1").arg(z); + KConfigGroup cg(config, buf); + cg.writeEntry("DocumentNumber", m_documents.indexOf(m_kwrites.at(z - 1)->activeView()->document()) + 1); + } +} + +bool KWriteApplication::quit() +{ + QList copy(m_kwrites); + for(auto kwrite: copy) { + if (!kwrite->close()) { + return false; + } + + m_kwrites.removeAll(kwrite); + delete kwrite; + } + return true; +} + +KTextEditor::MainWindow *KWriteApplication::activeMainWindow() +{ + for(auto kwrite: m_kwrites) { + if (kwrite->isActiveWindow()) { + return kwrite->mainWindow(); + } + } + + return nullptr; +} + +QList KWriteApplication::mainWindows() +{ + QList windows; + for(auto kwrite: m_kwrites) { + windows.append(kwrite->mainWindow()); + } + + return windows; +} + +bool KWriteApplication::closeDocument(KTextEditor::Document* document) +{ + QList copy(m_kwrites); + for(auto kwrite: copy) { + if (kwrite->activeView()->document() == document) { + if (!kwrite->close()) { + return false; + } + m_kwrites.removeAll(kwrite); + delete kwrite; + } + } + + return true; +} diff --git a/kwrite/kwriteapplication.h b/kwrite/kwriteapplication.h new file mode 100644 index 000000000..ac87804a2 --- /dev/null +++ b/kwrite/kwriteapplication.h @@ -0,0 +1,63 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Christoph Cullmann + Copyright (C) 2001 Joseph Wenninger + Copyright (C) 2001 Anders Lund + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KWRITE_APPLICATION_H +#define KWRITE_APPLICATION_H + +#include +#include +#include +#include + +class KWrite; + +class KWriteApplication : public QObject +{ + Q_OBJECT + +public: + KWriteApplication(); + ~KWriteApplication(); + + void addDocument(KTextEditor::Document *doc) { m_documents.append(doc); } + void removeDocument(KTextEditor::Document *doc) { m_documents.removeAll(doc); } + void removeWindow(KWrite *kwrite) { m_kwrites.removeAll(kwrite); } + + bool noWindows() { return m_kwrites.isEmpty(); } + + KWrite *newWindow(KTextEditor::Document *doc = nullptr); + + void restore(); + void saveProperties(KConfig *config); + +public Q_SLOTS: + QList documents() { return m_documents; } + bool quit(); + KTextEditor::MainWindow *activeMainWindow(); + QList mainWindows(); + bool closeDocument(KTextEditor::Document *document); + +private: + KTextEditor::Application *m_application; + QList m_documents; + QList m_kwrites; +}; + +#endif diff --git a/kwrite/main.cpp b/kwrite/main.cpp index 3f3a2e3f6..97287139a 100644 --- a/kwrite/main.cpp +++ b/kwrite/main.cpp @@ -1,311 +1,314 @@ /* 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 "kwriteapplication.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 #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-2019 The Kate Authors"), QString(), QStringLiteral("https://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("https://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(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); + KWriteApplication kapp; + if (app.isSessionRestored()) { - KWrite::restore(); + kapp.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; + KWrite *t = kapp.newWindow(); 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(); + KTextEditor::Document *doc = t->activeView()->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)); + if (nav && t->activeView()) { + t->activeView()->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(); + KWrite *t = kapp.newWindow(); if (codec) { - t->view()->document()->setEncoding(QString::fromLatin1(codec->name())); + t->activeView()->document()->setEncoding(QString::fromLatin1(codec->name())); } t->loadURL(info.url); if (info.cursor.isValid()) { - t->view()->setCursorPosition(info.cursor); + t->activeView()->setCursorPosition(info.cursor); } else if (info.url.hasQuery()) { QUrlQuery q(info.url); QString lineStr = q.queryItemValue(QStringLiteral("line")); QString columnStr = q.queryItemValue(QStringLiteral("column")); line = lineStr.toInt(); if (line > 0) line--; column = columnStr.toInt(); if (column > 0) column--; - t->view()->setCursorPosition(KTextEditor::Cursor(line, column)); + t->activeView()->setCursorPosition(KTextEditor::Cursor(line, column)); } } 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(); + if (kapp.noWindows()) { + kapp.newWindow(); } /** * 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(); }