File indexing completed on 2024-04-28 05:49:27

0001 /*
0002     SPDX-FileCopyrightText: 2001 Christoph Cullmann <cullmann@kde.org>
0003     SPDX-FileCopyrightText: 2002 Joseph Wenninger <jowenn@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #pragma once
0009 
0010 #include <ktexteditor/application.h>
0011 
0012 #ifdef WITH_KUSERFEEDBACK
0013 #include <KUserFeedback/Provider>
0014 #endif
0015 
0016 #include "kateappadaptor.h"
0017 #include "katedocmanager.h"
0018 #include "katepluginmanager.h"
0019 #include "kateprivate_export.h"
0020 #include "katesessionmanager.h"
0021 #include "katestashmanager.h"
0022 
0023 #include <KConfig>
0024 #include <QList>
0025 
0026 class KAboutData;
0027 class KateSessionManager;
0028 class KateMainWindow;
0029 class KatePluginManager;
0030 class KateDocManager;
0031 class KateAppCommands;
0032 class KateAppAdaptor;
0033 class QCommandLineParser;
0034 
0035 /**
0036  * Kate Application
0037  * This class represents the core kate application object
0038  */
0039 class KATE_PRIVATE_EXPORT KateApp : public QObject
0040 {
0041     Q_OBJECT
0042 
0043     /**
0044      * constructors & accessor to app object + plugin interface for it
0045      */
0046 public:
0047     /**
0048      * Do the needed setup steps before we create our QApplication.
0049      * @param detach shall we detach from the terminal?
0050      */
0051     static void initPreApplicationCreation(bool detach);
0052 
0053     /**
0054      * Was the application started inside a terminal?
0055      */
0056     static bool isInsideTerminal();
0057 
0058     /**
0059      *  Are we full featured Kate or the simplified KWrite?
0060      */
0061     enum ApplicationMode { ApplicationKate, ApplicationKWrite };
0062 
0063     /**
0064      * application constructor
0065      * @param arg command line parser, reference will be stored, needs to survive as long as application object is alive
0066      * @param mode application mode, either Kate or KWrite
0067      * @param sessionDir directory used to store the session config files
0068      */
0069     KateApp(const QCommandLineParser &arg, const ApplicationMode mode, const QString &sessionsDir);
0070 
0071     /**
0072      * return current application mode
0073      */
0074     static ApplicationMode mode()
0075     {
0076         return KateApp::self()->m_mode;
0077     }
0078 
0079     /**
0080      * return current application mode
0081      */
0082     static bool isKate()
0083     {
0084         return mode() == KateApp::ApplicationKate;
0085     }
0086 
0087     /**
0088      * return current application mode
0089      */
0090     static bool isKWrite()
0091     {
0092         return mode() == KateApp::ApplicationKWrite;
0093     }
0094 
0095     /**
0096      * Fill in the authors and credits for the application.
0097      * Use by Kate & KWrite
0098      */
0099     static void fillAuthorsAndCredits(KAboutData &aboutData);
0100 
0101     /**
0102      * get kate inited
0103      * @return false, if application should exit
0104      */
0105     bool init();
0106 
0107     /**
0108      * application destructor
0109      */
0110     ~KateApp() override;
0111 
0112     /**
0113      * static accessor to avoid casting ;)
0114      * @return app instance
0115      */
0116     static KateApp *self();
0117 
0118     /**
0119      * KTextEditor::Application wrapper
0120      * @return KTextEditor::Application wrapper.
0121      */
0122     KTextEditor::Application *wrapper()
0123     {
0124         return &m_wrapper;
0125     }
0126 
0127 #ifdef WITH_KUSERFEEDBACK
0128     /**
0129      * Get our global user feedback provider
0130      * @return user feedback provider
0131      */
0132     KUserFeedback::Provider &userFeedbackProvider()
0133     {
0134         return m_userFeedbackProvider;
0135     }
0136 #endif
0137 
0138     /**
0139      * kate init
0140      */
0141 private:
0142     /**
0143      * restore a old kate session
0144      */
0145     void restoreKate();
0146 
0147     /**
0148      * try to start kate
0149      * @return success, if false, kate should exit
0150      */
0151     bool startupKate();
0152 
0153     /**
0154      * kate shutdown
0155      */
0156 public:
0157     /**
0158      * shutdown kate application
0159      * @param win mainwindow which is used for dialogs
0160      */
0161     void shutdownKate(KateMainWindow *win);
0162 
0163     /**
0164      * other accessors for global unique instances
0165      */
0166 public:
0167     /**
0168      * accessor to plugin manager
0169      * @return plugin manager instance
0170      */
0171     KatePluginManager *pluginManager();
0172 
0173     /**
0174      * accessor to document manager
0175      * @return document manager instance
0176      */
0177     KateDocManager *documentManager();
0178 
0179     /**
0180      * accessor to session manager
0181      * @return session manager instance
0182      */
0183     KateSessionManager *sessionManager();
0184 
0185     /**
0186      *
0187      */
0188     KateStashManager *stashManager();
0189 
0190     /**
0191      * window management
0192      */
0193 public:
0194     /**
0195      * create a new main window, use given config if any for restore
0196      * @param sconfig session config object
0197      * @param sgroup session group for this window
0198      * @param userTriggered did the user trigger creation of this new window
0199      * @return new constructed main window
0200      */
0201     static KateMainWindow *newMainWindow(KConfig *sconfig = nullptr, const QString &sgroup = QString(), bool userTriggered = false);
0202 
0203     /**
0204      * add the mainwindow given
0205      * should be called in mainwindow constructor
0206      * @param mainWindow window to remove
0207      */
0208     void addMainWindow(KateMainWindow *mainWindow);
0209 
0210     /**
0211      * removes the mainwindow given, DOES NOT DELETE IT
0212      * should be called in mainwindow destructor
0213      * @param mainWindow window to remove
0214      */
0215     void removeMainWindow(KateMainWindow *mainWindow);
0216 
0217     /**
0218      * give back current active main window
0219      * can only be 0 at app start or exit
0220      * @return current active main window
0221      */
0222     KateMainWindow *activeKateMainWindow();
0223 
0224     /**
0225      * give back number of existing main windows
0226      * @return number of main windows
0227      */
0228     int mainWindowsCount() const;
0229 
0230     /**
0231      * give back the window you want
0232      * @param n window index
0233      * @return requested main window
0234      */
0235     KateMainWindow *mainWindow(int n);
0236 
0237     int mainWindowID(KateMainWindow *window);
0238 
0239     /**
0240      * Has the given document tabs/views inside main windows
0241      * other then the given one?
0242      *
0243      * @param doc document to check
0244      * @param window window to check
0245      * @return is this document visible as tab/view/... in any other window?
0246      */
0247     bool documentVisibleInOtherWindows(KTextEditor::Document *doc, KateMainWindow *window) const;
0248 
0249     /**
0250      * some stuff for the DBus API
0251      */
0252 public:
0253     /**
0254      * open url with given encoding
0255      * used by kate if --use given
0256      * @param url filename
0257      * @param encoding encoding name
0258      * @param isTempFile whether the file is temporary
0259      * @param activateView activate the view of the opened document?
0260      * @param c cursor position to set if not invalid
0261      * @return opened document or nullptr
0262      */
0263     KTextEditor::Document *
0264     openDocUrl(const QUrl &url, const QString &encoding, bool isTempFile, bool activateView = true, KTextEditor::Cursor c = KTextEditor::Cursor::invalid());
0265 
0266     /**
0267      * position cursor in current active view
0268      * will clear selection
0269      * @param line line to set
0270      * @param column column to set
0271      * @return success
0272      */
0273     bool setCursor(int line, int column);
0274 
0275     /**
0276      * Checks if --line and/or --column args were provided and
0277      * returns the cursor for it
0278      */
0279     KTextEditor::Cursor cursorFromArgs();
0280 
0281     /**
0282      * Checks if line or column were provided in query string
0283      * (e.g. file:///file1?line=3&column=4) and returns the cursor
0284      * If cursor was not set it will return invalid cursor
0285      *
0286      * @param url the url to check
0287      */
0288     KTextEditor::Cursor cursorFromQueryString(const QUrl &url);
0289 
0290     /**
0291      * @return true if --line or --column command line args were provided
0292      */
0293     bool hasCursorInArgs();
0294 
0295     /**
0296      * helper to handle stdin input
0297      * open a new document/view, fill it with the text given
0298      * @param text text to fill in the new doc/view
0299      * @param encoding encoding to set for the document, if any
0300      * @return success
0301      */
0302     bool openInput(const QString &text, const QString &encoding);
0303 
0304     //
0305     // KTextEditor::Application interface, called by wrappers via invokeMethod
0306     //
0307 public Q_SLOTS:
0308     /**
0309      * Get a list of all main windows.
0310      * @return all main windows
0311      */
0312     QList<KTextEditor::MainWindow *> mainWindows();
0313 
0314     /**
0315      * Accessor to the active main window.
0316      * \return a pointer to the active mainwindow
0317      */
0318     KTextEditor::MainWindow *activeMainWindow();
0319 
0320     /**
0321      * Get a list of all documents that are managed by the application.
0322      * This might contain less documents than the editor has in his documents () list.
0323      * @return all documents the application manages
0324      */
0325     QList<KTextEditor::Document *> documents()
0326     {
0327         return m_docManager.documentList();
0328     }
0329 
0330     /**
0331      * Get the document with the URL \p url.
0332      * if multiple documents match the searched url, return the first found one...
0333      * \param url the document's URL
0334      * \return the document with the given \p url or NULL, if none found
0335      */
0336     KTextEditor::Document *findUrl(const QUrl &url)
0337     {
0338         return m_docManager.findDocument(url);
0339     }
0340 
0341     /**
0342      * Open the document \p url with the given \p encoding.
0343      * if the url is empty, a new empty document will be created
0344      * \param url the document's url
0345      * \param encoding the preferred encoding. If encoding is QString() the
0346      *        encoding will be guessed or the default encoding will be used.
0347      * \return a pointer to the created document
0348      */
0349     KTextEditor::Document *openUrl(const QUrl &url, const QString &encoding = QString())
0350     {
0351         return m_docManager.openUrl(url, encoding);
0352     }
0353 
0354     /**
0355      * Close the given \p document. If the document is modified, user will be asked if he wants that.
0356      * \param document the document to be closed
0357      * \return \e true on success, otherwise \e false
0358      */
0359     bool closeDocument(KTextEditor::Document *document)
0360     {
0361         return closeDocuments({document});
0362     }
0363 
0364     /**
0365      * Close a list of documents. If any of them are modified, user will be asked if he wants that.
0366      * Use this, if you want to close multiple documents at once, as the application might
0367      * be able to group the "do you really want that" dialogs into one.
0368      * \param documents list of documents to be closed
0369      * \return \e true on success, otherwise \e false
0370      */
0371     bool closeDocuments(const QList<KTextEditor::Document *> &documents);
0372 
0373     /**
0374      * Get a plugin for the plugin with with identifier \p name.
0375      * \param name the plugin's name
0376      * \return pointer to the plugin if a plugin with \p name is loaded, otherwise nullptr
0377      */
0378     KTextEditor::Plugin *plugin(const QString &name);
0379 
0380     /**
0381      * Ask app to quit. The app might interact with the user and decide that
0382      * quitting is not possible and return false.
0383      *
0384      * \return true if the app could quit
0385      */
0386     bool quit()
0387     {
0388         shutdownKate(activeKateMainWindow());
0389         return true;
0390     }
0391 
0392     /**
0393      * last time some QEvent::ActivationChange occured
0394      * used to determine which instance to reuse, if we have multiple
0395      */
0396     qint64 lastActivationChange() const
0397     {
0398         return m_lastActivationChange;
0399     }
0400 
0401     /**
0402      * A message is received from an external instance, if we use QtSingleApplication
0403      *
0404      * \p instanceId the instance id we got the message from
0405      * \p message is a serialized message (at the moment just the file list separated by ';')
0406      */
0407     void remoteMessageReceived(quint32 instanceId, QByteArray message);
0408 
0409 Q_SIGNALS:
0410     /**
0411      * Emitted when the configuration got changed via the global config dialog.
0412      * Allows widgets to listen on this and adapt, the KSharedConfig::openConfig()
0413      * is already updated.
0414      */
0415     void configurationChanged();
0416 
0417 protected:
0418     /**
0419      * Event filter for QApplication to handle mac os like file open
0420      */
0421     bool eventFilter(QObject *obj, QEvent *event) override;
0422 
0423 private Q_SLOTS:
0424     /**
0425      * Handle destroy of documents created via openDocUrl.
0426      * Needed to e.g. emit token signal and cleanup temporary files.
0427      */
0428     void openDocUrlDocumentDestroyed(QObject *document);
0429 
0430 private:
0431     /**
0432      * kate's command line args
0433      */
0434     const QCommandLineParser &m_args;
0435 
0436     /**
0437      * application mode, kate or kwrite
0438      */
0439     const ApplicationMode m_mode;
0440 
0441     /**
0442      * files opened via --tempfile, must be deleted on program exit
0443      * need to be constructed before document manager as the destructor of that might
0444      * access it via the destroyed signal of the document
0445      */
0446     QHash<QObject *, QStringList> m_tempFilesToDelete;
0447 
0448     /**
0449      * known main windows
0450      */
0451     QList<KateMainWindow *> m_mainWindows;
0452 
0453     /**
0454      * Wrapper of application for KTextEditor
0455      */
0456     KTextEditor::Application m_wrapper;
0457 
0458     /**
0459      * dbus interface, must survive longer than m_docManager
0460      * e.g. the destroyed signal of the document might access this
0461      */
0462     KateAppAdaptor m_adaptor;
0463 
0464     /**
0465      * document manager
0466      */
0467     KateDocManager m_docManager;
0468 
0469     /**
0470      * plugin manager
0471      */
0472     KatePluginManager m_pluginManager;
0473 
0474     /**
0475      * session manager
0476      */
0477     KateSessionManager m_sessionManager;
0478 
0479     KateStashManager m_stashManager;
0480 
0481 #ifdef WITH_KUSERFEEDBACK
0482     /**
0483      * user feedback provider
0484      */
0485     KUserFeedback::Provider m_userFeedbackProvider;
0486 #endif
0487 
0488     /**
0489      * last time some QEvent::ActivationChange occured
0490      * used to determine which instance to reuse, if we have multiple
0491      */
0492     qint64 m_lastActivationChange;
0493 };