File: plugin_hosting.qdoc

package info (click to toggle)
kf6-ktexteditor 6.20.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 41,660 kB
  • sloc: cpp: 93,292; javascript: 20,908; xml: 237; sh: 20; ansic: 16; makefile: 8
file content (125 lines) | stat: -rw-r--r-- 5,309 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*! \page kte_plugin_hosting.html

\target kte_plugin_hosting
\title Hosting KTextEditor Plugins

While the KTextEditor framework provides a powerful text editor in itself, 
further features are available from plugins (KTextEditor::Plugin). At the time of this writing,
all known KTextEditor plugins are maintained by the kate project, but most
can be used in other hosting applications, as well.

This page is about supporting KTextEditor plugins in your application. For information on
developing the plugins themselves, refer to KTextEditor::Plugin.

\target kte_basic_plugin_loading
\section1 Loading simple plugins
The steps needed to find and load basic KTextEditor plugins are roughly as follows:

\code
  QStringList plugins_to_load = QStringList() << "openlinkplugin" << "rainbowparens";
  QList<KPluginMetaData> plugins = KPluginMetaData::findPlugins(QStringLiteral("ktexteditor"));
  for (const auto &plugin_meta_data : plugins) {
    QString identifier = plugin_meta_data.filename().basename();
    if (!plugins_to_load.contains(identifier)) {
        continue;
    }
    plugins_to_load.removeOne(identifier); // avoid loading separate versions of the same plugin

    KTextEditor::Plugin *plugin = KPluginFactory::instantiatePlugin<KTextEditor::Plugin>(plugin_meta_data, this, QVariantList() << identifier).plugin;
    if (plugin) {
      emit KTextEditor::Editor::instance()->application()->pluginCreated(identifier, plugin);
      QObject* created = plugin->createView();
      if (created) {
        emit mainWindow()->main->pluginViewCreated(identifier, created);
        KTextEditor::SessionConfigInterface *interface = qobject_cast<KTextEditor::SessionConfigInterface *>(created);
        if (interface) {
          // NOTE: Some plugins will misbehave, unless readSessionConfig has been called!
          KConfigGroup group = KSharedConfig::openConfig()->group(QStringLiteral("KatePlugin:%1:").arg(identifier));
          interface->readSessionConfig(group);
        }
      }
    }
  }
\endcode

Note, however, that only a few basic plugins will actually be functional with the above, alone.
For others, we need to implement several additional functions, as detailed, below.

\target kte_full_plugin_hosting 
\section1 Implementing full plugin hosting
In order to allow plugins to interact with the hosting application (e.g. creating or activating additional windows/widgets),
you need to implement two interfacing classes:
- KTextEditor::Application (singleton)
- KTextEditor::MainWindow

The latter corresponds to top level windows in your application (it's ok, if your application only supports a single
toplevel window), with the assumption being that several document- and/or tool-windows can existing in each main window.

The two classes are really just a thin layer to dispatch from API to be used in plugins to the appropriate
functionality in your application. For best runtime compatibility even across different version of KTextEditor, this is
implemented using Qt slots. E.g. KTextEditor::MainWindow::activeView() is defined as:

\code
KTextEditor::View *MainWindow::activeView()
 {
     // dispatch to parent
     KTextEditor::View *view = nullptr;
     QMetaObject::invokeMethod(parent(), "activeView", Qt::DirectConnection, Q_RETURN_ARG(KTextEditor::View*, view));
     return view;
 }
\endcode

I.e. this function (and most others in KTextEditor::MainWindow and KTextEditor::Application) simply invokes
a slot by the same name and signature in its parent QObject. This is what you need to provide. The following example should
illustrate the idea:

\code
class MyKTEMainWindow : public QObject {
    MyKTEMainWindow() {
        // create a dispatch object _as a child of this object_
        kte_win = new KTextEditor::MainWindow(this);
    }
    [...]
public slots:
    KTextEditor::View* activateView(KTextEditor::Document *document) {
        auto view = myFindViewForDoc(document);
        myActivateView(view);
        return view;
    }
    [further implementations]
private:
    friend class MyKTEApplication;
    KTextEditor::MainWindow* kte_win;
}

class MyKTEApplication : public QObject {
    MyKTEApplicaiton() {
        // create a dispatch object _as a child of this object_
        kte_app = new KTextEditor::Application(this);
        // For simplicity, let's assume a single main window, and create a wrapper for it, here
        my_main_win = new MyKTEMainWindow;

        // register with KTextEditor
        KTextEditor::Editor::instance()->setApplication(kte_app);
    }
    [...]
public slots:
    KTextEditor::MainWindow* activeMainWindow() {
        return my_main_win->kte_win;
    }
    [further implementations]
private:
    KTextEditor::Application* kte_app;
    MyKTEMainWindow* my_main_win;
}
\endcode

\note Due to the lose coupling via Qt slots, you may not need to implement a dispatch slots for every
single member in KTextEditor::Application, and KTextEditor::MainWindow. Naturally, however, plugins will be
more likely to work as expected, the more complete the hosting app implements these interfaces.

\note Don't forget to integrate the plugin config pages, if desired: @see KTextEditor::Plugin::configPage(), @see KTextEditor::Plugin::configPages().

\sa KTextEditor::Plugin, KTextEditor::Application, KTextEditor::MainWindow

*/