Marble/OnlineServices: Difference between revisions

    From KDE TechBase
    No edit summary
    m (Text replace - "</code>" to "</syntaxhighlight>")
    (4 intermediate revisions by 3 users not shown)
    Line 5: Line 5:
    name=Creating your first Marble Online Services Plugin|
    name=Creating your first Marble Online Services Plugin|


    pre=[http://mindview.net/Books/TICPP/ThinkingInCPP2e.html C++], [http://www.trolltech.com/products/qt/ Qt], [[Getting_Started/Build/KDE4|KDE4 development environment]]|
    pre=[http://mindview.net/Books/TICPP/ThinkingInCPP2e.html C++], [http://www.trolltech.com/products/qt/ Qt], [[Getting_Started/Build|KDE development environment]]|


    next=|  
    next=|  
    Line 30: Line 30:
    We will now look at the header file to see what functions we have to implement.
    We will now look at the header file to see what functions we have to implement.
    '''TutorialItem.h'''
    '''TutorialItem.h'''
    <code cppqt>
    <syntaxhighlight lang="cpp-qt">
    // This is to prevent this header to be included multiple times
    #ifndef TUTORIALITEM_H
    #ifndef TUTORIALITEM_H
    #define TUTORIALITEM_H
    #define TUTORIALITEM_H
     
    #include "AbstractDataPluginItem.h"
    #include "AbstractDataPluginItem.h"
     
    class QFont;
    class QFont;
     
    namespace Marble
    namespace Marble
    {
    {
    Line 45: Line 44:
    {
    {
         Q_OBJECT
         Q_OBJECT
       
      public:
      public:
         TutorialItem( QObject *parent );
         TutorialItem( QObject *parent );
       
         ~TutorialItem();
         ~TutorialItem();
       
         // Returns the item type of the item.
         // Returns the item type of the item.
         QString itemType() const;
         QString itemType() const;
       
         // Returns true if the item is paintable
         // Returns true if the item is paintable
         bool initialized();
         bool initialized();
       
         // Here the item gets painted
         // Here the item gets painted
         void paint( GeoPainter *painter, ViewportParams *viewport,
         void paint( GeoPainter *painter, ViewportParams *viewport,
                     const QString& renderPos, GeoSceneLayer * layer = 0 );
                     const QString& renderPos, GeoSceneLayer * layer = 0 );
       
         bool operator<( const AbstractDataPluginItem *other ) const;
         bool operator<( const AbstractDataPluginItem *other ) const;
       
         // The text we want to show on the map
         // The text we want to show on the map
         QString text() const;  
         QString text() const;
         void setText( const QString& text );
         void setText( const QString& text );
       
      private:
      private:
         QString m_text;
         QString m_text;
       
         static QFont s_font;
         static QFont s_font;
    };
    };
       
    }
    }
    #endif // TUTORIALITEM_H
    #endif // TUTORIALITEM_H
    </code>
    </syntaxhighlight>


    As you have probably seen, it will be very easy to implement this as we have only one function (paint()) besides some getters and setters.
    As you have probably seen, it will be very easy to implement this as we have only one function (paint()) besides some getters and setters.
    Line 81: Line 80:
    Let's have a look at the implementation.
    Let's have a look at the implementation.
    '''TutorialItem.cpp'''
    '''TutorialItem.cpp'''
    <code cppqt>
    <syntaxhighlight lang="cpp-qt">
    // Self
    // Self
    #include "TutorialItem.h"
    #include "TutorialItem.h"
     
    // Marble
    // Marble
    #include "GeoPainter.h"
    #include "GeoPainter.h"
    #include "ViewportParams.h"
    #include "ViewportParams.h"
     
    // Qt
    // Qt
    #include <QtCore/QDebug>
    #include <QtGui/QFontMetrics>
    #include <QtGui/QFontMetrics>
     
    using namespace Marble;
    using namespace Marble;
     
    // That's the font we will use to paint.
    // That's the font we will use to paint.
    QFont TutorialItem::s_font = QFont( "Sans Serif", 8 );
    QFont TutorialItem::s_font = QFont( "Sans Serif", 8 );
     
    TutorialItem::TutorialItem( QObject *parent )
    TutorialItem::TutorialItem( QObject *parent )
         : AbstractDataPluginItem( parent )
         : AbstractDataPluginItem( parent )
    Line 103: Line 103:
         setSize( QSize( 0, 0 ) );
         setSize( QSize( 0, 0 ) );
    }
    }
     
    TutorialItem::~TutorialItem()
    TutorialItem::~TutorialItem()
    {
    {
    }
    }
     
    QString TutorialItem::itemType() const
    QString TutorialItem::itemType() const
    {
    {
    Line 113: Line 113:
         return "tutorialItem";
         return "tutorialItem";
    }
    }
       
    bool TutorialItem::initialized()
    bool TutorialItem::initialized()
    {
    {
    Line 122: Line 122:
             return true;
             return true;
    }
    }
     
    bool TutorialItem::operator<( const AbstractDataPluginItem *other ) const
    bool TutorialItem::operator<( const AbstractDataPluginItem *other ) const
    {
    {
    Line 129: Line 129:
         return this->id() < other->id();
         return this->id() < other->id();
    }
    }
     
    QString TutorialItem::text() const
    QString TutorialItem::text() const
    {
    {
         return m_text;
         return m_text;
    }
    }
     
    void TutorialItem::setText( const QString& text )
    void TutorialItem::setText( const QString& text )
    {
    {
    Line 145: Line 145:
         m_text = text;
         m_text = text;
    }
    }
     
    void TutorialItem::paint( GeoPainter *painter, ViewportParams *viewport,
    void TutorialItem::paint( GeoPainter *painter, ViewportParams *viewport,
                              const QString& renderPos, GeoSceneLayer * layer )
                              const QString& renderPos, GeoSceneLayer * layer )
    {
    {
         Q_UNUSED( renderPos )
         Q_UNUSED( renderPos )
         Q_UNUSED( layer )
         Q_UNUSED( layer )
       
         // Save the old painter state.
         // Save the old painter state.
         painter->save();
         painter->save();
    Line 159: Line 159:
         painter->setFont( s_font );
         painter->setFont( s_font );
         // Draw the text into the given rect.
         // Draw the text into the given rect.
         painter->drawText( QRect( QPoint( 0, 0 ), size() ), 0, m_text );
         painter->drawText( QRect( QPoint( 0, 0 ), size().toSize() ), 0, m_text );
         // Restore the old painter state.
         // Restore the old painter state.
         painter->restore();
         painter->restore();
    }
    }
     
    // This is needed for all QObjects (see MOC)
    // This is needed for all QObjects (see MOC)
    #include "TutorialItem.moc"
    #include "TutorialItem.moc"
    </code>
    </syntaxhighlight>


    Wasn't that easy? Continue with the next section.
    Wasn't that easy? Continue with the next section.
    Line 173: Line 173:
    We will continue developing the core component, the model. Let's first look at the header file:
    We will continue developing the core component, the model. Let's first look at the header file:
    '''TutorialModel.h'''
    '''TutorialModel.h'''
    <code cppqt>
    <syntaxhighlight lang="cpp-qt">
    #ifndef TUTORIALMODEL_H
    #ifndef TUTORIALMODEL_H
    #define TUTORIALMODEL_H
    #define TUTORIALMODEL_H
    Line 191: Line 191:
       
       
      public:
      public:
         TutorialModel( QObject *parent = 0 );
         TutorialModel( PluginManager *pluginManager,
                      QObject *parent = 0 );
         ~TutorialModel();
         ~TutorialModel();
       
       
    Line 207: Line 208:
       
       
    #endif // TUTORIALMODEL_H
    #endif // TUTORIALMODEL_H
    </code>
    </syntaxhighlight>


    You see that we have to implement the function getAdditionalItems(). getAdditionalItems() is called when the viewport has been changed significantly, so new items have to be generated.
    You see that we have to implement the function getAdditionalItems(). getAdditionalItems() is called when the viewport has been changed significantly, so new items have to be generated.
    Line 213: Line 214:


    '''TutorialModel.cpp'''
    '''TutorialModel.cpp'''
    <code cppqt>
    <syntaxhighlight lang="cpp-qt">
    // Self
    // Self
    #include "TutorialModel.h"
    #include "TutorialModel.h"
     
    // Plugin
    // Plugin
    #include "TutorialItem.h"
    #include "TutorialItem.h"
     
    // Marble
    // Marble
    #include "global.h"
    #include "global.h"
    #include "MarbleDataFacade.h"
    #include "MarbleDataFacade.h"
    #include "GeoDataCoordinates.h"
    #include "GeoDataCoordinates.h"
     
    // Qt
    // Qt
    #include <QtCore/QDebug>
    #include <QtCore/QString>
    #include <QtCore/QString>
     
    using namespace Marble;
    using namespace Marble;
     
     
    TutorialModel::TutorialModel( QObject *parent )
    TutorialModel::TutorialModel( PluginManager *pluginManager,
         : AbstractDataPluginModel( "tutorial", parent )  
                                  QObject *parent )
         : AbstractDataPluginModel( "tutorial", pluginManager, parent )
    {
    {
    }
    }
     
    TutorialModel::~TutorialModel() {
    TutorialModel::~TutorialModel() {
    }
    }
    Line 247: Line 250:
             return;
             return;
         }
         }
       
         // We will only create one item in our first tutorial.
         // We will only create one item in our first tutorial.
         // Every item has to get an id. We have to check if the item already exists.
         // Every item has to get an id. We have to check if the item already exists.
    Line 259: Line 262:
             item->setId( "tutorial1" );
             item->setId( "tutorial1" );
             // The text we want to show, of course "Hello World!"
             // The text we want to show, of course "Hello World!"
             item->setText( "Hello World!" );
             item->setText( "Hello Marble!" );
             // Add the item to the list of items, so it will be displayed.
             // Add the item to the list of items, so it will be displayed.
             addItemToList( item );
             addItemToList( item );
         }
         }
    }
    }
     
    #include "TutorialModel.moc"
    #include "TutorialModel.moc"
    </code>
    </syntaxhighlight>


    If you want to download files from a web server to get lists of items, you will want to use '''void downloadDescriptionFile( const QUrl& url )''' and you have to reimplement '''void parseFile( const QByteArray& file )''', which parses the downloaded description file and adds new items to the list.
    If you want to download files from a web server to get lists of items, you will want to use '''void downloadDescriptionFile( const QUrl& url )''' and you have to reimplement '''void parseFile( const QByteArray& file )''', which parses the downloaded description file and adds new items to the list.
    Line 278: Line 281:


    '''TutorialPlugin.h'''
    '''TutorialPlugin.h'''
    <code cppqt>
    <syntaxhighlight lang="cpp-qt">
    #ifndef TUTORIALPLUGIN_H
    #ifndef TUTORIALPLUGIN_H
    #define TUTORIALPLUGIN_H
    #define TUTORIALPLUGIN_H
     
    #include "AbstractDataPlugin.h"
    #include "AbstractDataPlugin.h"
    #include "RenderPlugin.h"
    #include "RenderPlugin.h"
    #include "RenderPluginInterface.h"
    #include "RenderPluginInterface.h"
     
    #include <QtGui/QIcon>
    #include <QtGui/QIcon>
     
    namespace Marble {
    namespace Marble {
     
    class TutorialPlugin : public AbstractDataPlugin {
    class TutorialPlugin : public AbstractDataPlugin {
         Q_OBJECT
         Q_OBJECT
         Q_INTERFACES( Marble::RenderPluginInterface )
         Q_INTERFACES( Marble::RenderPluginInterface )
         MARBLE_PLUGIN( TutorialPlugin )
         MARBLE_PLUGIN( TutorialPlugin )
       
      public:
      public:
         TutorialPlugin();
         TutorialPlugin();
       
         void initialize();
         virtual void initialize();
          
     
         virtual bool isInitialized() const;
         QString name() const;
         QString name() const;
       
         QString guiString() const;
         QString guiString() const;
       
         QString description() const;
         QString description() const;
       
         QIcon icon() const;
         QIcon icon() const;
    private:
        bool m_isInitialized;
    };
    };
    }


    }
    #endif
    </code>
    </syntaxhighlight>


    And the implementation:
    And the implementation:
    '''TutorialPlugin.cpp'''
    '''TutorialPlugin.cpp'''
    <code cppqt>
    <syntaxhighlight lang="cpp-qt">
    // Self
    // Self
    #include "TutorialPlugin.h"
    #include "TutorialPlugin.h"
     
    #include "TutorialModel.h"
    #include "TutorialModel.h"


    // Qt
    #include <QtCore/QDebug>
    using namespace Marble;
    using namespace Marble;
     
    TutorialPlugin::TutorialPlugin()
    TutorialPlugin::TutorialPlugin()
        : m_isInitialized( false )
    {
    {
         setNameId( "tutorial" );
         setNameId( "tutorial" );
       
         // Plugin is enabled by default
         // Plugin is enabled by default
         setEnabled( true );
         setEnabled( true );
         // Plugin is not visible by default
         // Plugin is invisible by default
         setVisible( false );
         setVisible( false );
    }
    }
       
    void TutorialPlugin::initialize() {
    void TutorialPlugin::initialize() {
         setModel( new TutorialModel( this ) );
         setModel( new TutorialModel( pluginManager(), this ) );
         // Setting the number of items on the screen.
         // Setting the number of items on the screen.
         setNumberOfItems( numberOfItemsOnScreen );
         setNumberOfItems( numberOfItemsOnScreen );
        m_isInitialized = true;
    }
    }


    bool TutorialPlugin::isInitialized() const {
        return m_isInitialized;
    }
    QString TutorialPlugin::name() const {
    QString TutorialPlugin::name() const {
         return tr( "Tutorial Items" );
         return tr( "Tutorial Items" );
    }
    }
     
    QString TutorialPlugin::guiString() const {
    QString TutorialPlugin::guiString() const {
         return tr( "&Tutorial" );
         return tr( "&Tutorial" );
    }
    }
     
    QString TutorialPlugin::description() const {
    QString TutorialPlugin::description() const {
         return tr( "Shows tutorial items on the map." );
         return tr( "Shows tutorial items on the map." );
    }
    }
       
    QIcon TutorialPlugin::icon() const {
    QIcon TutorialPlugin::icon() const {
         return QIcon();
         return QIcon();
    Line 355: Line 375:
    // Because we want to create a plugin, we have to do the following line.
    // Because we want to create a plugin, we have to do the following line.
    Q_EXPORT_PLUGIN2(TutorialPlugin, Marble::TutorialPlugin)
    Q_EXPORT_PLUGIN2(TutorialPlugin, Marble::TutorialPlugin)
     
    #include "TutorialPlugin.moc"
    #include "TutorialPlugin.moc"
    </code>
    </syntaxhighlight>


    == CMake ==
    == CMake ==
    I build the plugin, as you will probably do, in a subdirectory of '''marble/src/plugins/render'''. This needs the following file:
    You can build the plugin anywhere. This needs the following file:
    '''CMakeLists.txt'''
    '''CMakeLists.txt'''
    <code bash>
    <syntaxhighlight lang="bash">
    PROJECT( TutorialPlugin )
    PROJECT( TutorialPlugin )
    cmake_minimum_required( VERSION 2.4.8 )
    find_package(Qt4 REQUIRED)
    find_package(Marble REQUIRED)


    INCLUDE_DIRECTORIES(
    INCLUDE_DIRECTORIES(
      ${CMAKE_CURRENT_SOURCE_DIR}/src/plugins/render/tutorialPlugin
      ${CMAKE_CURRENT_SOURCE_DIR}
      ${CMAKE_BINARY_DIR}/src/plugins/render/tutorialPlugin
      ${CMAKE_BINARY_DIR}
      ${QT_INCLUDE_DIR}
      ${QT_INCLUDE_DIR}
    ${MARBLE_INCLUDE_DIR}
    )
    )
     
    set( tutorial_SRCS TutorialPlugin.cpp
    set( tutorial_SRCS TutorialPlugin.cpp
                       TutorialModel.cpp
                       TutorialModel.cpp
                       TutorialItem.cpp )
                       TutorialItem.cpp )


    marble_add_plugin( Tutorial ${tutorial_SRCS} )
    </code>


    This will need the line
    qt4_automoc( ${tutorial_SRCS} )
    <code bash>
    add_library( Tutorial MODULE ${tutorial_SRCS} )
    add_subdirectory( tutorialPlugin )
    target_link_libraries( Tutorial ${QT_QTCORE_LIBRARY}
    </code>
                                    ${QT_QTGUI_LIBRARY}
    in '''marble/src/plugins/render'''.
                                    ${${_target_name}_LIBS}
                                    ${MARBLE_LIBRARIES} )
    install( TARGETS Tutorial DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/kde4/plugins/marble/ )
     
    set_target_properties( ${_target_name} PROPERTIES
                          INSTALL_RPATH_USE_LINK_PATH TRUE
                          SKIP_BUILD_RPATH TRUE
                          BUILD_WITH_INSTALL_RPATH TRUE
                        )
    </syntaxhighlight>
     
    The following commands will build the plugin then.
     
    <syntaxhighlight lang="bash">
    mkdir build
    cd build
    cmake ../
    make
    sudo make install
    </syntaxhighlight>


    Now you can recompile and reinstall marble, so the plugin will be installed at the correct place. Starting Marble will result in an additional menu entry in "View"->"Online Services". If selected, you will see the string "Hello World!" displayed near Kiel, Germany.
    If you use the qt-only version, you'll probably need to change the install path. We are currently working on a solution for that problem.

    Revision as of 20:57, 29 June 2011

    Creating your first Marble Online Services Plugin
    Tutorial Series   Marble Tutorial
    Previous   C++, Qt, KDE development environment
    What's Next  
    Further Reading   CMake

    Abstract

    You will here learn to create your own online service plugins. If you don't know what is meant by online service, you will see these in the Marble menu at "View"->"Online Services". You'll need KDE 4.3 to build this tutorial. If you want to write plugins for Marble, it could be useful to do this in KDE's subversion. Please contact the Marble developers for this (IRC, E-Mail).

    Structure

    An online services plugin or data plugin consist of three classes at least. The class to display the information is the Data Item (the base class is AbstractDataPluginItem). It stores the information for single places on the map and displays them.

    The Model (base class AbstractDataPluginModel) stores all items. Storing the items will be done by AbstractDataPluginModel itself. Your only job is to get information for new items when the displayed part of the earth changes. This can include downloading so called "Description files" from the servers of an online service and parsing them. These "Description files" contain lists of items in a specific part of the earth (specified by a LatLonAltBox).

    The class based on AbstractDataPlugin is the representation class of our plugin. It provides the name and the idea of the plugin. You also have to set your model there.

    Item

    We will write our item first as it depends on nothing else. As you should already know the item stores the data and paints it on the screen. One item has an exact position on the globe as longitude, latitude and altitude. The item we will write shows a text at the specific position.

    We will now look at the header file to see what functions we have to implement. TutorialItem.h

    #ifndef TUTORIALITEM_H
    #define TUTORIALITEM_H
     
    #include "AbstractDataPluginItem.h"
     
    class QFont;
     
    namespace Marble
    {
     
    class TutorialItem : public AbstractDataPluginItem
    {
        Q_OBJECT
     
     public:
        TutorialItem( QObject *parent );
     
        ~TutorialItem();
     
        // Returns the item type of the item.
        QString itemType() const;
     
        // Returns true if the item is paintable
        bool initialized();
     
        // Here the item gets painted
        void paint( GeoPainter *painter, ViewportParams *viewport,
                    const QString& renderPos, GeoSceneLayer * layer = 0 );
     
        bool operator<( const AbstractDataPluginItem *other ) const;
     
        // The text we want to show on the map
        QString text() const;
        void setText( const QString& text );
     
     private:
        QString m_text;
     
        static QFont s_font;
    };
     
    }
    #endif // TUTORIALITEM_H
    

    As you have probably seen, it will be very easy to implement this as we have only one function (paint()) besides some getters and setters.

    Let's have a look at the implementation. TutorialItem.cpp

    // Self
    #include "TutorialItem.h"
     
    // Marble
    #include "GeoPainter.h"
    #include "ViewportParams.h"
     
    // Qt
    #include <QtCore/QDebug>
    #include <QtGui/QFontMetrics>
     
    using namespace Marble;
     
    // That's the font we will use to paint.
    QFont TutorialItem::s_font = QFont( "Sans Serif", 8 );
     
    TutorialItem::TutorialItem( QObject *parent )
        : AbstractDataPluginItem( parent )
    {
        // The size of an item without a text is 0
        setSize( QSize( 0, 0 ) );
    }
     
    TutorialItem::~TutorialItem()
    {
    }
     
    QString TutorialItem::itemType() const
    {
        // Our itemType:
        return "tutorialItem";
    }
     
    bool TutorialItem::initialized()
    {
        // The item is initialized if it has a text
        if ( m_text.isEmpty() ) 
            return false;
        else
            return true;
    }
     
    bool TutorialItem::operator<( const AbstractDataPluginItem *other ) const
    {
        // That's not a very nice priority estimation, you'll hopefully find
        // a better one for your plugin.
        return this->id() < other->id();
    }
     
    QString TutorialItem::text() const
    {
        return m_text;
    }
     
    void TutorialItem::setText( const QString& text )
    {
        // On a text change our size may also change, so we have to set the new
        // item size. Marble needs to know how large an item is to find the correct
        // bounding rect. The given position will always be in the middle of the 
        // item for now.
        QFontMetrics metrics( s_font );
        setSize( metrics.size( 0, text ) );
        m_text = text;
    }
     
    void TutorialItem::paint( GeoPainter *painter, ViewportParams *viewport,
                              const QString& renderPos, GeoSceneLayer * layer )
    {
        Q_UNUSED( renderPos )
        Q_UNUSED( layer )
     
        // Save the old painter state.
        painter->save();
        // We want to paint a black string.
        painter->setPen( QPen( QColor( Qt::black ) ) );
        // We will use our standard font.
        painter->setFont( s_font );
        // Draw the text into the given rect.
        painter->drawText( QRect( QPoint( 0, 0 ), size().toSize() ), 0, m_text );
        // Restore the old painter state.
        painter->restore();
    }
     
    // This is needed for all QObjects (see MOC)
    #include "TutorialItem.moc"
    

    Wasn't that easy? Continue with the next section.

    Model

    We will continue developing the core component, the model. Let's first look at the header file: TutorialModel.h

    #ifndef TUTORIALMODEL_H
    #define TUTORIALMODEL_H
     
    #include "AbstractDataPluginModel.h"
     
    namespace Marble {
     
    class MarbleDataFacade;
     
    // The maximum number of items we want to show on the screen.
    const quint32 numberOfItemsOnScreen = 20;
     
    class TutorialModel : public AbstractDataPluginModel
    {
        Q_OBJECT
     
     public:
        TutorialModel( PluginManager *pluginManager,
                       QObject *parent = 0 );
        ~TutorialModel();
     
     protected:
        /**
         * Generates the download url for the description file from the web service depending on
         * the @p box surrounding the view and the @p number of files to show.
         **/
        void getAdditionalItems( const GeoDataLatLonAltBox& box,
                                 MarbleDataFacade *facade,
                                 qint32 number = 10 );
    };
     
    }
     
    #endif // TUTORIALMODEL_H
    

    You see that we have to implement the function getAdditionalItems(). getAdditionalItems() is called when the viewport has been changed significantly, so new items have to be generated. For getAdditionalItems() we will go the easy way for now. We will simply add one item with a static position. That's a very simple method to test your painting code.

    TutorialModel.cpp

    // Self
    #include "TutorialModel.h"
    
    // Plugin
    #include "TutorialItem.h"
    
    // Marble
    #include "global.h"
    #include "MarbleDataFacade.h"
    #include "GeoDataCoordinates.h"
    
    // Qt
    #include <QtCore/QDebug>
    #include <QtCore/QString>
    
    using namespace Marble;
    
    
    TutorialModel::TutorialModel( PluginManager *pluginManager,
                                  QObject *parent  )
        : AbstractDataPluginModel( "tutorial", pluginManager, parent )
    {
    }
    
    TutorialModel::~TutorialModel() {
    }
    
    void TutorialModel::getAdditionalItems( const GeoDataLatLonAltBox& box,
                                             MarbleDataFacade *facade,
                                             qint32 number )
    {
        // This plugin only supports Tutorial items for earth
        if( facade->target() != "earth" ) {
            return;
        }
     
        // We will only create one item in our first tutorial.
        // Every item has to get an id. We have to check if the item already exists.
        if ( !itemExists( "tutorial1" ) ) {
            // If it does not exists, create it
            GeoDataCoordinates coor( 10.22 * DEG2RAD, 54.4 * DEG2RAD );
            // The parent of the new item is this object
            TutorialItem *item = new TutorialItem( this );
            item->setCoordinate( coor );
            item->setTarget( "earth" );
            item->setId( "tutorial1" );
            // The text we want to show, of course "Hello World!"
            item->setText( "Hello Marble!" );
            // Add the item to the list of items, so it will be displayed.
            addItemToList( item );
        }
    }
    
    #include "TutorialModel.moc"
    

    If you want to download files from a web server to get lists of items, you will want to use void downloadDescriptionFile( const QUrl& url ) and you have to reimplement void parseFile( const QByteArray& file ), which parses the downloaded description file and adds new items to the list.

    If you want to download files per item (for example if you want to display images), you can use void downloadItemData( const QUrl& url, const QString& type, AbstractDataPluginItem *item ). This will also add the items to the list of items. The type is something you have to invent yourself. It has to be unique in your plugin. The function void addDownloadedFile( const QString& url, const QString& type ) of our item is called when the download has been finished. This is what you need to implement.

    To see examples of the usage of these functions, look at wikipedia-plugin and photo-plugin.

    Main Plugin Class

    Now to the boring part of the tutorial: The main class.

    TutorialPlugin.h

    #ifndef TUTORIALPLUGIN_H
    #define TUTORIALPLUGIN_H
     
    #include "AbstractDataPlugin.h"
    #include "RenderPlugin.h"
    #include "RenderPluginInterface.h"
     
    #include <QtGui/QIcon>
     
    namespace Marble {
     
    class TutorialPlugin : public AbstractDataPlugin {
        Q_OBJECT
        Q_INTERFACES( Marble::RenderPluginInterface )
        MARBLE_PLUGIN( TutorialPlugin )
     
     public:
        TutorialPlugin();
     
        virtual void initialize();
    
        virtual bool isInitialized() const;
     
        QString name() const;
     
        QString guiString() const;
     
        QString description() const;
     
        QIcon icon() const;
    
     private:
        bool m_isInitialized;
    };
     
    }
    
    #endif
    

    And the implementation: TutorialPlugin.cpp

    // Self
    #include "TutorialPlugin.h"
     
    #include "TutorialModel.h"
    
    // Qt
    #include <QtCore/QDebug>
     
    using namespace Marble;
     
    TutorialPlugin::TutorialPlugin()
        : m_isInitialized( false )
    {
        setNameId( "tutorial" );
     
        // Plugin is enabled by default
        setEnabled( true );
        // Plugin is invisible by default
        setVisible( false );
    }
     
    void TutorialPlugin::initialize() {
        setModel( new TutorialModel( pluginManager(), this ) );
        // Setting the number of items on the screen.
        setNumberOfItems( numberOfItemsOnScreen );
    
        m_isInitialized = true;
    }
    
    bool TutorialPlugin::isInitialized() const {
        return m_isInitialized;
    }
     
    QString TutorialPlugin::name() const {
        return tr( "Tutorial Items" );
    }
     
    QString TutorialPlugin::guiString() const {
        return tr( "&Tutorial" );
    }
     
    QString TutorialPlugin::description() const {
        return tr( "Shows tutorial items on the map." );
    }
     
    QIcon TutorialPlugin::icon() const {
        return QIcon();
    }
    // Because we want to create a plugin, we have to do the following line.
    Q_EXPORT_PLUGIN2(TutorialPlugin, Marble::TutorialPlugin)
     
    #include "TutorialPlugin.moc"
    

    CMake

    You can build the plugin anywhere. This needs the following file: CMakeLists.txt

    PROJECT( TutorialPlugin )
    
    cmake_minimum_required( VERSION 2.4.8 )
    
    find_package(Qt4 REQUIRED)
    find_package(Marble REQUIRED)
    
    INCLUDE_DIRECTORIES(
     ${CMAKE_CURRENT_SOURCE_DIR}
     ${CMAKE_BINARY_DIR}
     ${QT_INCLUDE_DIR}
     ${MARBLE_INCLUDE_DIR}
    )
     
    set( tutorial_SRCS TutorialPlugin.cpp
                       TutorialModel.cpp
                       TutorialItem.cpp )
    
    
    qt4_automoc( ${tutorial_SRCS} )
    add_library( Tutorial MODULE ${tutorial_SRCS} )
    target_link_libraries( Tutorial ${QT_QTCORE_LIBRARY}
                                    ${QT_QTGUI_LIBRARY}
                                    ${${_target_name}_LIBS}
                                    ${MARBLE_LIBRARIES} )
    install( TARGETS Tutorial DESTINATION ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/kde4/plugins/marble/ )
    
    set_target_properties( ${_target_name} PROPERTIES
                           INSTALL_RPATH_USE_LINK_PATH TRUE
                           SKIP_BUILD_RPATH TRUE
                           BUILD_WITH_INSTALL_RPATH TRUE
                         )
    

    The following commands will build the plugin then.

    mkdir build
    cd build
    cmake ../
    make
    sudo make install
    

    If you use the qt-only version, you'll probably need to change the install path. We are currently working on a solution for that problem.