How to extend KDevelop via plugins
Step 1: Make your plugin loadable
For a pluginfoo
, create a file foo.desktop
which contains KDevelop/Part in its list of ServiceTypes.
- See
parts/doctreeview/kdevdoctreeview.desktop
for an example.
$(kde_servicesdir)
, your plugin will automatically be loaded.How to change the default loading
You can change the default loading by changing some settings in yourfoo.desktop
file:
- Set
X-KDevelop-Scope=
toGlobal
orProject
- Note: This property is not optional
- You can add a list of programming languages which are supported by your plugin
- If your plugin works with all languages leave the
X-KDevelop-ProgrammingLanguages=
field empty (optional)
- If your plugin works with all languages leave the
- You can add a list of keywords.
- The plugin will only be loaded if all keywords match with the
Keywords=
field in the projectfile (optional).
- The plugin will only be loaded if all keywords match with the
#######################
X-KDevelop-Scope=Project
X-KDevelop-ProgrammingLanguages=Java
Keywords=
##########################
Step 2: Make the plugin accessible by the factory
Create a factory classFooFactory
which inherits KDevFactory
. Put a section
extern "C" {
void *init_libfoo()
{
return new FooFactory;
}
}
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 init_libfoo()
is required for a library with the name libfoo.so
.
This may be simplified by the use of the K_EXPORT_COMPONENT_FACTORY
macro which is defined in klibloader.h
:
K_EXPORT_COMPONENT_FACTORY( libfoo, FooFactory );
- Note: Your factory must reimplement the
createPartObject()
method ofKDevFactory
and produce the part there.
parts/doctreeview/doctreeviewfactory.cpp
for an example.Step 3: Implement your part.
Your part must be derived fromKDevPlugin
.
- KDevPlugin takes two arguments:
- 1) A parent argument. This also comes from
createPartObject()
. - 2) A name, which in turn is given to the
QObject
constructor.
- 1) A parent argument. This also comes from
How to access other IDE components
A part can access other components of the IDE via some accessors ofKDevPlugin
:
- The application core via
core()
, - the build tools via
project()
, - the programming language specific stuff via
languageSupport()
, - the make frontend via
makeFrontend()
, - the part which displays appication output via
appFrontend()
, and finally - the symbol database via
classStore()
.
lib/interfaces/kdev*.h
.How to store user preferences
Parts can also store user preferences on a per-project basis. To this end, they can access aQDomDocument
representing the project file (which is stored as xml) via document()
.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 KDevelop 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.
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 theDomUtil
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 dom
document node.
For example, the autoproject
part uses the statement
QString cflags = DomUtil::readEntry( *part->document(),
"/kdevautoproject/cflags" );
to read the CFLAGS
variable set by the user, and uses the statement similar to
DomUtil::writeEntry( *part->document(),
"kdevautoproject/cflags",
"--no-exceptions" );
to write it back.
- Note: In order to avoid conflicts between different plugins, you should use your part name as top-level 'directory' in the configuration tree.
Project session file (*.kdevses)
The base class of all KDevelop 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 KDevelop 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:
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);
}
}
Note that the .kdevses is related to a project. User settings equal for all projects don't belong to here. You save them to ~/.kde/share/config/kdeveloprc via class KConfig of the kdecore library.
Document your part in the way described at How to document KDevelop parts (doc/api/HowToDocument.dox file).