Warning, /frameworks/ktexteditor/docs/plugin_hosting.dox is written in an unsupported language. File is not indexed.

0001 /** \page kte_plugin_hosting Hosting KTextEditor plugins
0002 
0003 While the KTextEditor framework provides a powerful text editor in itself, 
0004 further features are available from plugins (KTextEditor::Plugin). At the time of this writing,
0005 all known KTextEditor plugins are maintained by the kate project, but most
0006 can be used in other hosting applications, as well.
0007 
0008 This page is about supporting KTextEditor plugins in your application. For information on
0009 developing the plugins themselves, refer to KTextEditor::Plugin.
0010 
0011 \section kte_basic_plugin_loading Loading simple plugins
0012 The steps needed to find and load basic KTextEditor plugins are roughly as follows:
0013 
0014 \code
0015   QStringList plugins_to_load = QStringList() << "openlinkplugin" << "rainbowparens";
0016   QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("ktexteditor"));
0017   for (const auto &plugin_meta_data : plugins) {
0018     QString identifier = plugin_meta_data.filename().basename();
0019     if (!plugins_to_load.contains(identifier)) {
0020         continue;
0021     }
0022     plugins_to_load.removeOne(identifier); // avoid loading separate versions of the same plugin
0023 
0024     KTextEditor::Plugin *plugin = KPluginFactory::instantiatePlugin<KTextEditor::Plugin>(plugin_meta_data, this, QVariantList() << identifier).plugin;
0025     if (plugin) {
0026       emit KTextEditor::Editor::instance()->application()->pluginCreated(identifier, plugin);
0027       QObject* created = plugin->createView();
0028       if (created) {
0029         emit mainWindow()->main->pluginViewCreated(identifier, created);
0030         KTextEditor::SessionConfigInterface *interface = qobject_cast<KTextEditor::SessionConfigInterface *>(created);
0031         if (interface) {
0032           // NOTE: Some plugins will misbehave, unless readSessionConfig has been called!
0033           KConfigGroup group = KSharedConfig::openConfig()->group(QStringLiteral("KatePlugin:%1:").arg(identifier));
0034           interface->readSessionConfig(group);
0035         }
0036       }
0037     }
0038   }
0039 \endcode
0040 
0041 Note, however, that only a few basic plugins will actually be functional with the above, alone.
0042 For others, we need to implement several additional functions, as detailed, below.
0043 
0044 \section kte_full_plugin_hosting Implementing full plugin hosting
0045 I order to allow plugins to interact with the hosting application (e.g. creating or activating additional windows/widgets),
0046 you need to implement two interfacing classes:
0047 - KTextEditor::Application (singleton)
0048 - KTextEditor::MainWindow
0049 
0050 The latter corresponds to top level windows in your application (it's ok, if your application only supports a single
0051 toplevel window), with the assumption being that several document- and/or tool-windows can existing in each main window.
0052 
0053 The two classes are really just a thin layer to dispatch from API to be used in plugins to the appropiate
0054 functionality in your application. For best runtime compatibility even across different version of KTextEditor, this is
0055 implemented using Qt slots. E.g. KTextEditor::MainWindow::activeView() is defined as:
0056 
0057 \code
0058 KTextEditor::View *MainWindow::activeView()
0059  {
0060      // dispatch to parent
0061      KTextEditor::View *view = nullptr;
0062      QMetaObject::invokeMethod(parent(), "activeView", Qt::DirectConnection, Q_RETURN_ARG(KTextEditor::View*, view));
0063      return view;
0064  }
0065 \endcode
0066 
0067 I.e. this function (and most others in KTextEditor::MainWindow and KTextEditor::Application) simply invokes
0068 a slot by the same name and signature in its parent QObject. This is what you need to provide. The following example should
0069 illustrate the idea:
0070 
0071 \code
0072 class MyKTEMainWindow : public QObject() {
0073     MyKTEMainWindow() {
0074         // create a dispatch object _as a child of this object_
0075         kte_win = new KTextEditor::MainWindow(this);
0076     }
0077     [...]
0078 public slots:
0079     KTextEditor::View* activateView(KTextEditor::Document *document) {
0080         auto view = myFindViewForDoc(document);
0081         myActivateView(view);
0082         return view;
0083     }
0084     [further implementations]
0085 private:
0086     friend class MyKTEApplication;
0087     KTextEditor::MainWindow* kte_win;
0088 }
0089 
0090 class MyKTEApplication : public QObject() {
0091     MyKTEApplicaiton() {
0092         // create a dispatch object _as a child of this object_
0093         kte_app = new KTextEditor::Application(this);
0094         // For simplicity, let's assume a single main window, and create a wrapper for it, here
0095         my_main_win = new MyKTEMainWindow;
0096 
0097         // register with KTextEditor
0098         KTextEditor::Editor::instance()->setApplication(kte_app);
0099     }
0100     [...]
0101 public slots:
0102     KTextEditor::MainWindow* activeMainWindow() {
0103         return my_main_win->kte_win;
0104     }
0105     [further implementations]
0106 private:
0107     KTextEditor::Application* kte_app;
0108     MyKTEMainWindow* my_main_win;
0109 }
0110 \endcode
0111 
0112 @note Due to the lose coupling via Qt slots, you may not need to implement a dispatch slots for every
0113 single member in KTextEditor::Application, and KTextEditor::MainWindow. Naturally, however, plugins will be
0114 more likely to work as expected, the more complete the hosting app implements these interfaces.
0115 
0116 @note Don't forget to integrate the plugin config pages, if desired: @see KTextEditor::Plugin::configPage(), @see KTextEditor::Plugin::configPages().
0117 
0118 \see KTextEditor::Plugin, KTextEditor::Application, KTextEditor::MainWindow
0119 
0120 */