summaryrefslogtreecommitdiffstats
path: root/doc/api/HowToAddPlugins.dox
blob: 3f9d1b2060f2295f98e20c408c80a2ed7ce46495 (plain)
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/** \file HowToAddPlugins.dox
  * \brief How to extend TDevelop via plugins
  */

/** \page howToAddPlugins How to extend TDevelop via plugins

\section createDesktop Step 1: Make your plugin loadable

For a plugin <code>foo</code>, create a file <code>foo.desktop</code> which contains TDevelop/Part in its list of ServiceTypes.

  - See <code>parts/doctreeview/kdevdoctreeview.desktop</code> for an example.
  .

If you install this file into <code>\$(kde_servicesdir)</code>, your plugin will automatically be loaded.

\subsection changeLoading How to change the default loading

You can change the default loading by changing some settings in your <code>foo.desktop</code> file:

  - Set <code>X-TDevelop-Scope=</code> to <code>Global</code> or
    <code>Project</code>
    - <b>Note:</b> This property is <i>not</i> optional
	.
  - You can add a list of programming languages which are supported by your
    plugin
	- If your plugin works with all languages leave the
	  <code>X-TDevelop-ProgrammingLanguages=</code> field empty
	  <i>(optional)</i>
	.
  - You can add a list of keywords.
    - The plugin will only be loaded if all keywords match with the
	<code>Keywords=</code> field in the projectfile <i>(optional)</i>.
	.
  .

An example from the Java Debugger Plugin:

<code><pre>
    #######################
    X-TDevelop-Scope=Project
    X-TDevelop-ProgrammingLanguages=Java
    Keywords=
    ##########################
</pre></code>
    

\section createFactory Step 2: Make the plugin accessible by the factory

Create a factory class <code>FooFactory</code> which inherits
<code>KDevFactory</code>. Put a section

<code><pre>
    extern "C" {
        void *init_libfoo()
        {
            return new FooFactory;
        }
    }
</pre></code>

into the source file, so that the factory can be accessed by KDE's library
loader. Keep in mind that the name of the method <code>init_libfoo()</code> is
required for a library with the name <code>libfoo.so</code>.

This may be simplified by the use of the
<code>K_EXPORT_COMPONENT_FACTORY</code> macro which is defined in
<code>klibloader.h</code>:

<code>
K_EXPORT_COMPONENT_FACTORY( libfoo, FooFactory );
</code>

  - <i>Note:</i> Your factory must reimplement the
    <code>createPartObject()</code> method of <code>KDevFactory</code> and
	produce the part there.
  .

See <code>parts/doctreeview/doctreeviewfactory.cpp</code> for an example.


\section implementPart Step 3: Implement your part.

Your part must be derived from <code>KDevPlugin</code>.

  - KDevPlugin takes two arguments:
    - 1) A <i>parent</i> argument. This also comes from
	  <code>createPartObject()</code>.
	- 2) A <i>name</i>, which in turn is given to the <code>QObject</code>
	  constructor.
	.
  .

\subsection accessIDE How to access other IDE components

A part can access other components of the IDE via some accessors
of <code>KDevPlugin</code>:

  - The <i>application core</i> via <code>core()</code>,
  - the <i>build tools</i> via <code>project()</code>,
  - the <i>programming language specific stuff</i> via
    <code>languageSupport()</code>,
  - the <i>make frontend</i> via <code>makeFrontend()</code>,
  - the part which displays <i>appication output</i> via
    <code>appFrontend()</code>,
    and finally
  - the <i>symbol database</i> via <code>classStore()</code>.
  .

In order to see what these components provide, see <code>lib/interfaces/kdev*.h</code>.

\subsection userPrefs How to store user preferences

Parts can also store user preferences on a per-project basis. To this
end, they can access a <code>QDomDocument</code> representing the project file
(which is stored as xml) via <code>document()</code>.

Take attention to the issue that the project file usually is shared in a team of
developers (e.g. via version control application CVS). So some user preferences might be
very individual, and some may be valid for all of the team - project-wide so to speak.

That's why the TDevelop architecture makes a difference here and supports two files
which will be stored in the project root directory. They are the project file (*.kdevelop)
and the session (*.kdevses) file. The later is for individual settings, not to be thought
to be shared.

\subsection domProject Project file (*.kdevelop)

For your convenience, you don't have to use the quite complex DOM API. Strings
can very easily be read from and written to this document using the
<code>DomUtil</code> class. Here, entries are identified by a 'path' in the
document. You can think of the DOM document as representing a file system
rooted in the <code>dom</code> document node.

For example, the <code>autoproject</code> part uses the statement

<code><pre>
    QString cflags = DomUtil::readEntry( *part->document(),
                                         "/kdevautoproject/cflags" );
</pre></code>

to read the <code>CFLAGS</code> variable set by the user, and uses the statement similar to

<code><pre>
    DomUtil::writeEntry( *part->document(),
                         "kdevautoproject/cflags",
                         "--no-exceptions" );
</pre></code>

to write it back.

  - <i>Note:</i> In order to avoid conflicts between different plugins, you
    should use your part name as top-level 'directory' in the configuration
	tree.
  .

\subsection sessionAccess Project session file (*.kdevses)

The base class of all TDevelop plugins is KDevPlugin. It provides two virtual methods 
restorePartialProjectSession(..) and savePartialProjectSession(..)
that you should reimplement in your special plugin to attach to session loading and saving.

When TDevelop loads or closes a project, the program's project session manager
(class ProjectSession) calls them for each plugin. That manager gives a QDOM node to the
plugin where it can read out or build up its partial DOM subtree with the session settings.
That subtree will be stored in the .kdevses file by that session manager.

For example each programmer has set breakpoints in different files than the other ones of
the team. So the debugger plugin saves them to project session file:

<code><pre>
void DebuggerPart::savePartialProjectSession(QDomElement* el)
{
    gdbBreakpointWidget->savePartialProjectSession(el);
}
void GDBBreakpointWidget::savePartialProjectSession(QDomElement* el)
{
    QDomDocument domDoc = el->ownerDocument();
    if (domDoc.isNull()) return;
    QDomElement breakpointListEl = domDoc.createElement("breakpointList");
    for ( int row = 0; row < m_table->numRows(); row++ )
    {
        BreakpointTableRow* btr = (BreakpointTableRow *) m_table->item(row, Control);
        Breakpoint* bp = btr->breakpoint();
        QDomElement breakpointEl = domDoc.createElement("breakpoint"+QString::number(row));
        breakpointEl.setAttribute("type", bp->type());
        breakpointEl.setAttribute("location", bp->location(false));
        breakpointEl.setAttribute("enabled", bp->isEnabled());
        breakpointEl.setAttribute("condition", bp->conditional());
        breakpointListEl.appendChild(breakpointEl);
    }
    if (!breakpointListEl.isNull()) el->appendChild(breakpointListEl);
}

}
</pre></code>

Note that the .kdevses is related to a project. User settings equal for all projects don't
belong to here. You save them to ~/.trinity/share/config/tdeveloprc via class TDEConfig of the
tdecore library.

Document your part in the way described at \ref howToDocument (doc/api/HowToDocument.dox file).

*/