/** \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 foo, create a file foo.desktop which contains TDevelop/Part in its list of ServiceTypes. - See parts/doctreeview/kdevdoctreeview.desktop for an example. . If you install this file into \$(kde_servicesdir), 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 foo.desktop file: - Set X-TDevelop-Scope= to Global or Project - 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-TDevelop-ProgrammingLanguages= field empty (optional) . - 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). . . An example from the Java Debugger Plugin:
    #######################
    X-TDevelop-Scope=Project
    X-TDevelop-ProgrammingLanguages=Java
    Keywords=
    ##########################
\section createFactory Step 2: Make the plugin accessible by the factory Create a factory class FooFactory 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 of KDevFactory and produce the part there. . See parts/doctreeview/doctreeviewfactory.cpp for an example. \section implementPart Step 3: Implement your part. Your part must be derived from KDevPlugin. - 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. . . \subsection accessIDE How to access other IDE components A part can access other components of the IDE via some accessors of KDevPlugin: - 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(). . In order to see what these components provide, see lib/interfaces/kdev*.h. \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 QDomDocument 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 TDevelop architecture makes a difference here and supports two files which will be stored in the project root directory. They are the project file (*.tdevelop) and the session (*.kdevses) file. The later is for individual settings, not to be thought to be shared. \subsection domProject Project file (*.tdevelop) 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 DomUtil 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. . \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:
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 ~/.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). */