diff --git a/kpresenter/part/CMakeLists.txt b/kpresenter/part/CMakeLists.txt
index 168f173..c375ce8 100644
--- a/kpresenter/part/CMakeLists.txt
+++ b/kpresenter/part/CMakeLists.txt
@@ -16,6 +16,7 @@ set( kpresenterprivate_LIB_SRCS
      KPrFactory.cpp
      KPrDocument.cpp
      KPrView.cpp
+     KPrViewAdaptor.cpp
      KPrViewModePresentation.cpp
      KPrViewModeNotes.cpp
      KPrViewModePreviewPageEffect.cpp
diff --git a/kpresenter/part/KPrAnimationDirector.cpp b/kpresenter/part/KPrAnimationDirector.cpp
index 7648718..c052d0f 100644
--- a/kpresenter/part/KPrAnimationDirector.cpp
+++ b/kpresenter/part/KPrAnimationDirector.cpp
@@ -139,11 +139,26 @@ KoViewConverter * KPrAnimationDirector::viewConverter()
     return &m_zoomHandler;
 }
 
+int KPrAnimationDirector::numPages() const
+{
+    return m_pages.size();
+}
+
 int KPrAnimationDirector::currentPage() const
 {
     return m_pageIndex;
 }
 
+int KPrAnimationDirector::numStepsInPage() const
+{
+    return m_steps.size();
+}
+
+int KPrAnimationDirector::currentStep() const
+{
+    return m_stepIndex;
+}
+
 bool KPrAnimationDirector::navigate( Navigation navigation )
 {
     bool finished = false;
diff --git a/kpresenter/part/KPrAnimationDirector.h b/kpresenter/part/KPrAnimationDirector.h
index 590dbfa..c1e285c 100644
--- a/kpresenter/part/KPrAnimationDirector.h
+++ b/kpresenter/part/KPrAnimationDirector.h
@@ -64,11 +64,26 @@ public:
     KoViewConverter * viewConverter();
 
     /**
+     * get the number of pages
+     */
+    int numPages() const;
+
+    /**
      * get the current page number
      */
     int currentPage() const;
 
     /**
+     * get the number of steps in this page
+     */
+    int numStepsInPage() const;
+
+    /**
+     * get the current step
+     */
+    int currentStep() const;
+
+    /**
      * do the next step in the presentation
      *
      * @return true if slideshow is finished and should be exited, false otherwise
diff --git a/kpresenter/part/KPrDocument.cpp b/kpresenter/part/KPrDocument.cpp
index ef2b294..35e849b 100644
--- a/kpresenter/part/KPrDocument.cpp
+++ b/kpresenter/part/KPrDocument.cpp
@@ -277,6 +277,7 @@ KPrCustomSlideShows* KPrDocument::customSlideShows()
 void KPrDocument::setCustomSlideShows( KPrCustomSlideShows* replacement )
 {
     m_customSlideShows = replacement;
+    emit customSlideShowsModified();
 }
 
 int KPrDocument::presentationMonitor()
@@ -316,7 +317,10 @@ QString KPrDocument::activeCustomSlideShow() const
 
 void KPrDocument::setActiveCustomSlideShow( const QString &customSlideShow )
 {
-    m_activeCustomSlideShow = customSlideShow;
+    if ( customSlideShow != m_activeCustomSlideShow ) {
+        m_activeCustomSlideShow = customSlideShow;
+        emit activeCustomSlideShowChanged( customSlideShow );
+    }
 }
 
 #include "KPrDocument.moc"
diff --git a/kpresenter/part/KPrDocument.h b/kpresenter/part/KPrDocument.h
index 514b090..d3aaabe 100644
--- a/kpresenter/part/KPrDocument.h
+++ b/kpresenter/part/KPrDocument.h
@@ -130,6 +130,21 @@ public:
      */
     virtual KoPageApp::PageType pageType() const;
 
+signals:
+    /**
+     * Emitted when the active custom slide show changes.
+     * This is to allow for signalling dbus interfaces.
+     *
+     * @param customSlideShow the new active custom slide show
+     */
+    void activeCustomSlideShowChanged( const QString &customSlideShow );
+
+    /**
+     * Emitted when the custom slide shows have been modified.
+     * This is to allow for signalling dbus interfaces.
+     */
+    void customSlideShowsModified();
+
 protected:
     /// reimplemented
     virtual KoView * createViewInstance( QWidget *parent );
diff --git a/kpresenter/part/KPrView.cpp b/kpresenter/part/KPrView.cpp
index 346e6ca..ca43508 100644
--- a/kpresenter/part/KPrView.cpp
+++ b/kpresenter/part/KPrView.cpp
@@ -34,6 +34,7 @@
 #include "KPrPage.h"
 #include "KPrMasterPage.h"
 #include "KPrPageApplicationData.h"
+#include "KPrViewAdaptor.h"
 #include "KPrViewModePresentation.h"
 #include "KPrViewModeNotes.h"
 #include "KPrShapeManagerDisplayMasterStrategy.h"
@@ -55,6 +56,7 @@ KPrView::KPrView( KPrDocument *document, QWidget *parent )
 , m_presentationMode( new KPrViewModePresentation( this, m_canvas ))
 , m_normalMode( m_viewMode )
 , m_notesMode( new KPrViewModeNotes(this, m_canvas))
+, m_dbus( new KPrViewAdaptor( this ) )
 {
     initGUI();
     initActions();
@@ -90,6 +92,26 @@ KoViewConverter * KPrView::viewConverter( KoPACanvas * canvas )
     return viewMode()->viewConverter( canvas );
 }
 
+KPrDocument * KPrView::kprDocument() const
+{
+    return static_cast<KPrDocument *>( m_doc );
+}
+
+KPrViewAdaptor * KPrView::dbusObject() const
+{
+    return m_dbus;
+}
+
+KPrViewModePresentation * KPrView::presentationMode() const
+{
+    return m_presentationMode;
+}
+
+bool KPrView::isPresentationRunning() const
+{
+    return ( viewMode() == m_presentationMode );
+}
+
 void KPrView::initGUI()
 {
     // add page effect docker to the main window
@@ -164,6 +186,13 @@ void KPrView::startPresentationFromBeginning()
     startPresentation();
 }
 
+void KPrView::stopPresentation()
+{
+    if ( isPresentationRunning() ) {
+        m_presentationMode->activateSavedViewMode();
+    }
+}
+
 void KPrView::createAnimation()
 {
     static int animationcount = 0;
@@ -172,8 +201,7 @@ void KPrView::createAnimation()
     foreach( KoShape * shape, selectedShapes )
     {
         KPrShapeAnimation * animation = new KPrAnimationMoveAppear( shape, animationcount );
-        KPrDocument * doc = dynamic_cast<KPrDocument *>( m_doc );
-        Q_ASSERT( doc );
+        KPrDocument * doc = static_cast<KPrDocument *>( m_doc );
         KPrAnimationCreateCommand * command = new KPrAnimationCreateCommand( doc, animation );
         m_canvas->addCommand( command );
     }
diff --git a/kpresenter/part/KPrView.h b/kpresenter/part/KPrView.h
index 9b9e299..98e0182 100644
--- a/kpresenter/part/KPrView.h
+++ b/kpresenter/part/KPrView.h
@@ -27,6 +27,7 @@
 #include <KoPAView.h>
 
 class KPrDocument;
+class KPrViewAdaptor;
 class KPrViewModeNotes;
 class KPrViewModePresentation;
 class KPrViewModePresenterView;
@@ -42,13 +43,23 @@ public:
 
     virtual KoViewConverter * viewConverter( KoPACanvas * canvas);
 
+    KPrDocument * kprDocument() const;
+    virtual KPrViewAdaptor * dbusObject() const;
+
+    KPrViewModePresentation * presentationMode() const;
+    bool isPresentationRunning() const;
+
+
+public slots:
+    void startPresentation();
+    void startPresentationFromBeginning();
+    void stopPresentation();
+
 protected:
     void initGUI();
     void initActions();
 
 protected slots:
-    void startPresentation();
-    void startPresentationFromBeginning();
     void createAnimation();
     void showNormal();
     void showNotes();
@@ -66,6 +77,8 @@ private:
     KPrViewModePresentation *m_presentationMode;
     KoPAViewMode *m_normalMode;
     KPrViewModeNotes *m_notesMode;
+
+    KPrViewAdaptor *m_dbus;
 };
 
 #endif /* KPRVIEW_H */
diff --git a/kpresenter/part/KPrViewAdaptor.cpp b/kpresenter/part/KPrViewAdaptor.cpp
new file mode 100644
index 0000000..097f86f
--- /dev/null
+++ b/kpresenter/part/KPrViewAdaptor.cpp
@@ -0,0 +1,260 @@
+/*  This file is part of the KDE project
+    Copyright (C) 2008 James Hogan <james@albanarts.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA  02110-1301  USA
+*/
+
+#include "KPrViewAdaptor.h"
+#include "KPrView.h"
+#include "KPrViewModePresentation.h"
+#include "KPrAnimationDirector.h"
+#include "KPrDocument.h"
+#include "KPrNotes.h"
+#include "KPrPage.h"
+#include <KoTextShapeData.h>
+
+#include <KUrl>
+
+#include <QTextDocument>
+
+KPrViewAdaptor::KPrViewAdaptor( KPrView* view )
+: KoViewAdaptor( view )
+, m_view( view )
+{
+    KPrDocument *doc = m_view->kprDocument();
+    connect( doc, SIGNAL( activeCustomSlideShowChanged( const QString & ) ), this, SIGNAL( activeCustomSlideShowChanged( const QString & ) ) );
+    connect( doc, SIGNAL( customSlideShowsModified() ), this, SIGNAL( customSlideShowsModified() ) );
+
+    // We need to know when the presentation is started and stopped, and when it is navigated
+    connect( m_view->presentationMode(), SIGNAL( activated() ), this, SLOT( presentationActivated() ) );
+    connect( m_view->presentationMode(), SIGNAL( deactivated() ), this, SIGNAL( presentationStopped() ) );
+    connect( m_view->presentationMode(), SIGNAL( pageChanged( int, int ) ), this, SIGNAL( presentationPageChanged( int, int ) ) );
+    connect( m_view->presentationMode(), SIGNAL( stepChanged( int ) ), this, SIGNAL( presentationStepChanged( int ) ) );
+}
+
+KPrViewAdaptor::~KPrViewAdaptor()
+{
+}
+
+// custom slideshows
+
+QStringList KPrViewAdaptor::customSlideShows() const
+{
+    KPrDocument *doc = m_view->kprDocument();
+    return doc->customSlideShows()->names();
+}
+
+QString KPrViewAdaptor::activeCustomSlideShow() const
+{
+    KPrDocument *doc = m_view->kprDocument();
+    return doc->activeCustomSlideShow();
+}
+
+bool KPrViewAdaptor::setActiveCustomSlideShow( const QString &name )
+{
+    // Check that the custom slideshow exists
+    if ( name.isEmpty() || customSlideShows().contains( name ) ) {
+        KPrDocument *doc = m_view->kprDocument();
+        doc->setActiveCustomSlideShow( name );
+        return true;
+    }
+    else {
+        return false;
+    }
+}
+
+// slides in the custom slideshow
+
+int KPrViewAdaptor::numCustomSlideShowSlides() const
+{
+    KPrDocument *doc = m_view->kprDocument();
+    return doc->slideShow().size();
+}
+
+QString KPrViewAdaptor::pageName( int page ) const
+{
+    KPrDocument *doc = m_view->kprDocument();
+
+    QList<KoPAPageBase *> slideShow = doc->slideShow();
+    if ( page >= 0 && page < slideShow.size() ) {
+        return slideShow[page]->name();
+    }
+    return QString();
+}
+
+QString KPrViewAdaptor::pageNotes( int page, const QString &format ) const
+{
+    KPrDocument *doc = m_view->kprDocument();
+
+    QList<KoPAPageBase *> slideShow = doc->slideShow();
+    if ( page >= 0 && page < slideShow.size() ) {
+        KPrPage *prPage = dynamic_cast<KPrPage *>( slideShow[page] );
+        Q_ASSERT( prPage );
+        KPrNotes *pageNotes = prPage->pageNotes();
+        KoShape *textShape = pageNotes->textShape();
+        KoTextShapeData *textShapeData = dynamic_cast<KoTextShapeData *>( textShape->userData() );
+        Q_ASSERT( textShapeData );
+
+        if ( format == "plain" ) {
+            return textShapeData->document()->toPlainText();
+        }
+        else if ( format == "html" ) {
+            return textShapeData->document()->toHtml();
+        }
+    }
+    return QString();
+}
+
+bool KPrViewAdaptor::exportPageThumbnail( int page, int width, int height,
+                                          const QString &filename, const QString &format, int quality )
+{
+    KPrDocument *doc = m_view->kprDocument();
+
+    QList<KoPAPageBase *> slideShow = doc->slideShow();
+    if ( page >= 0 && page < slideShow.size() ) {
+        KoPAPageBase *pageObject = slideShow[page];
+        Q_ASSERT( pageObject );
+        return m_view->exportPageThumbnail( pageObject, KUrl( filename ),
+                                            QSize( QMAX( 0, width ), QMAX( 0, height ) ),
+                                            format.isEmpty() ? "PNG" : format.toLatin1(),
+                                            QMAX( -1, QMIN( 100, quality ) ) );
+    }
+    else {
+        return false;
+    }
+}
+    
+// Presentation control
+
+void KPrViewAdaptor::presentationStart()
+{
+    m_view->startPresentation();
+}
+
+void KPrViewAdaptor::presentationStartFromFirst()
+{
+    m_view->startPresentationFromBeginning();
+}
+
+void KPrViewAdaptor::presentationStop()
+{
+    m_view->stopPresentation();
+}
+
+void KPrViewAdaptor::presentationPrev()
+{
+    if ( m_view->isPresentationRunning() ) {
+        m_view->presentationMode()->navigate( KPrAnimationDirector::PreviousStep );
+    }
+}
+
+void KPrViewAdaptor::presentationNext()
+{
+    if ( m_view->isPresentationRunning() ) {
+        m_view->presentationMode()->navigate( KPrAnimationDirector::NextStep );
+    }
+}
+
+void KPrViewAdaptor::presentationPrevSlide()
+{
+    if ( m_view->isPresentationRunning() ) {
+        m_view->presentationMode()->navigate( KPrAnimationDirector::PreviousPage );
+    }
+}
+
+void KPrViewAdaptor::presentationNextSlide()
+{
+    if ( m_view->isPresentationRunning() ) {
+        m_view->presentationMode()->navigate( KPrAnimationDirector::NextPage );
+    }
+}
+
+void KPrViewAdaptor::presentationFirst()
+{
+    if ( m_view->isPresentationRunning() ) {
+        m_view->presentationMode()->navigate( KPrAnimationDirector::FirstPage );
+    }
+}
+
+void KPrViewAdaptor::presentationLast()
+{
+    if ( m_view->isPresentationRunning() ) {
+        m_view->presentationMode()->navigate( KPrAnimationDirector::LastPage );
+    }
+}
+
+void KPrViewAdaptor::gotoPresentationPage( int pg )
+{
+    if ( m_view->isPresentationRunning() ) {
+        m_view->presentationMode()->navigateToPage( pg );
+    }
+}
+
+// Presentation accessors
+
+bool KPrViewAdaptor::isPresentationRunning() const
+{
+    return m_view->isPresentationRunning();
+}
+
+int KPrViewAdaptor::currentPresentationPage() const
+{
+    if ( m_view->isPresentationRunning() ) {
+        return m_view->presentationMode()->currentPage();
+    }
+    else {
+        return -1;
+    }
+}
+
+int KPrViewAdaptor::currentPresentationStep() const
+{
+    if ( m_view->isPresentationRunning() ) {
+        return m_view->presentationMode()->currentStep();
+    }
+    else {
+        return -1;
+    }
+}
+
+int KPrViewAdaptor::numStepsInPresentationPage() const
+{
+    if ( m_view->isPresentationRunning() ) {
+        return m_view->presentationMode()->numStepsInPage();
+    }
+    else {
+        return -1;
+    }
+}
+
+int KPrViewAdaptor::numPresentationPages() const
+{
+    if ( m_view->isPresentationRunning() ) {
+        return m_view->presentationMode()->numPages();
+    }
+    else {
+        return -1;
+    }
+}
+
+/**
+ * Fired when the presentation is activated.
+ */
+void KPrViewAdaptor::presentationActivated()
+{
+    emit presentationStarted( numPresentationPages() );
+}
+
diff --git a/kpresenter/part/KPrViewAdaptor.h b/kpresenter/part/KPrViewAdaptor.h
new file mode 100644
index 0000000..01f79c5
--- /dev/null
+++ b/kpresenter/part/KPrViewAdaptor.h
@@ -0,0 +1,158 @@
+/*  This file is part of the KDE project
+    Copyright (C) 2008 James Hogan <james@albanarts.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA  02110-1301  USA
+*/
+
+#ifndef KPRVIEWADAPTOR_H
+#define KPRVIEWADAPTOR_H
+
+#include <KoViewAdaptor.h>
+
+class KPrView;
+
+class KPrViewAdaptor : public KoViewAdaptor
+{
+    Q_OBJECT
+    Q_CLASSINFO( "D-Bus Interface", "org.kde.koffice.presentation.view" )
+
+public:
+    explicit KPrViewAdaptor( KPrView* view );
+    virtual ~KPrViewAdaptor();
+
+public slots:
+
+    // custom slideshows
+    QStringList customSlideShows() const;
+    QString activeCustomSlideShow() const;
+    bool setActiveCustomSlideShow( const QString &name );
+
+    // slides in the custom slideshow
+
+    int numCustomSlideShowSlides() const;
+
+    /**
+     * Get the name of a page.
+     *
+     * If the page does not have a name an empty string is returned.
+     * It is common in this case to use the string i18n( "Page %1", @p page + 1 ).
+     *
+     * @param page The page index within the current slideshow.
+     * @returns The name of page with index @p page in the current slideshow.
+     */
+    QString pageName( int page ) const;
+
+    /**
+     * Get the notes associated with a page of the slideshow.
+     *
+     * The notes can be obtained in plain text or HTML.
+     *
+     * @param page The page index within the current slideshow.
+     * @param format The format of the return value.  Possible values are "plain" and "html".
+     * @returns The notes associated with page @p page in the format specified by @p format.
+     *          An empty string is returned when @p format is not recognised or @p page is invalid.
+     */
+    QString pageNotes( int page, const QString &format ) const;
+
+    /**
+     * Save page to an image file.
+     *
+     * Export a page of the current presentation to disk
+     * using a bitmap file like e.g. PNG
+     * This method uses a QPixmap::save() call.
+     *
+     * @param page the page index within the current slideshow
+     * @param width the desired image width in px
+     * @param height the desired image height in px
+     * @param filename the name of the image file to be created (see QPixmap::save())
+     * @param format the format of the image file (see QPixmap::save())
+     * @param quality the quality of the image in [0,100] or -1 to use default (see QPixmap::save())
+     *
+     * @returns whether the image was successfully saved
+     */
+    bool exportPageThumbnail( int page, int width, int height,
+                              const QString &filename, const QString &format, int quality );
+
+    // Presentation control
+    void presentationStart();
+    void presentationStartFromFirst();
+    void presentationStop();
+    void presentationPrev();
+    void presentationNext();
+    void presentationPrevSlide();
+    void presentationNextSlide();
+    void presentationFirst();
+    void presentationLast();
+    void gotoPresentationPage( int pg );
+
+    // Presentation accessors
+    bool isPresentationRunning() const;
+    int currentPresentationPage() const;
+    int currentPresentationStep() const;
+    int numStepsInPresentationPage() const;
+    int numPresentationPages() const;
+
+signals:
+    /**
+     * Emitted when the active custom slide show changes.
+     *
+     * @param customSlideShow the new active custom slide show
+     */
+    void activeCustomSlideShowChanged( const QString &customSlideShow );
+
+    /**
+     * Emitted when the custom slide shows have been modified.
+     */
+    void customSlideShowsModified();
+
+    /**
+     * Emitted when the slideshow is started.
+     *
+     * @param numSlides Number of slides in the slideshow
+     */
+    void presentationStarted( int numSlides );
+
+    /**
+     * Emitted when the slideshow is finished.
+     */
+    void presentationStopped();
+
+    /**
+     * Emitted when the presentation page is changed.
+     *
+     * @param page new page index within the current slideshow
+     * @param stepsInPage the number of steps in the new page
+     */
+    void presentationPageChanged( int page, int stepsInPage );
+
+    /**
+     * Emitted when the presentation step is changed.
+     *
+     * @param step new step index within the page
+     */
+    void presentationStepChanged( int step );
+
+private slots:
+    /**
+     * Fired when the presentation is activated.
+     */
+    void presentationActivated();
+
+private:
+    KPrView* m_view;
+};
+
+#endif
diff --git a/kpresenter/part/KPrViewModePresentation.cpp b/kpresenter/part/KPrViewModePresentation.cpp
index 5d5243e..228f79b 100644
--- a/kpresenter/part/KPrViewModePresentation.cpp
+++ b/kpresenter/part/KPrViewModePresentation.cpp
@@ -189,10 +189,16 @@ void KPrViewModePresentation::activate( KoPAViewMode * previousViewMode )
     }
 
     m_tool->activate( false );
+
+    emit activated();
+    emit pageChanged( m_animationDirector->currentPage(), m_animationDirector->numStepsInPage() );
+    emit stepChanged( m_animationDirector->currentStep() );
 }
 
 void KPrViewModePresentation::deactivate()
 {
+    emit deactivated();
+
     KoPAPageBase * page = m_view->activePage();
     if ( m_endOfSlideShowPage ) {
         if ( page == m_endOfSlideShowPage ) {
@@ -249,13 +255,45 @@ KPrAnimationDirector * KPrViewModePresentation::animationDirector()
     return m_animationDirector;
 }
 
+int KPrViewModePresentation::numPages() const
+{
+    Q_ASSERT( 0 != m_animationDirector );
+    return m_animationDirector->numPages();
+}
+
+int KPrViewModePresentation::currentPage() const
+{
+    Q_ASSERT( 0 != m_animationDirector );
+    return m_animationDirector->currentPage();
+}
+
+int KPrViewModePresentation::numStepsInPage() const
+{
+    Q_ASSERT( 0 != m_animationDirector );
+    return m_animationDirector->numStepsInPage();
+}
+
+int KPrViewModePresentation::currentStep() const
+{
+    Q_ASSERT( 0 != m_animationDirector );
+    return m_animationDirector->currentStep();
+}
+
 void KPrViewModePresentation::navigate( KPrAnimationDirector::Navigation navigation )
 {
+    Q_ASSERT( 0 != m_animationDirector );
+    int previousPage = m_animationDirector->currentPage();
     bool finished = m_animationDirector->navigate( navigation );
     if ( m_pvAnimationDirector ) {
         finished = m_pvAnimationDirector->navigate( navigation ) && finished;
     }
 
+    int newPage = m_animationDirector->currentPage();
+    if ( previousPage != newPage ) {
+        emit pageChanged( m_animationDirector->currentPage(), m_animationDirector->numStepsInPage() );
+    }
+    emit stepChanged( m_animationDirector->currentStep() );
+
     if ( finished ) {
         activateSavedViewMode();
     }
@@ -263,9 +301,13 @@ void KPrViewModePresentation::navigate( KPrAnimationDirector::Navigation navigat
 
 void KPrViewModePresentation::navigateToPage( int index )
 {
+    Q_ASSERT( 0 != m_animationDirector );
     m_animationDirector->navigateToPage( index );
     if ( m_pvAnimationDirector ) {
         m_pvAnimationDirector->navigateToPage( index );
     }
+
+    emit pageChanged( m_animationDirector->currentPage(), m_animationDirector->numStepsInPage() );
+    emit stepChanged( m_animationDirector->currentStep() );
 }
 
diff --git a/kpresenter/part/KPrViewModePresentation.h b/kpresenter/part/KPrViewModePresentation.h
index cb6e5d5..c707177 100644
--- a/kpresenter/part/KPrViewModePresentation.h
+++ b/kpresenter/part/KPrViewModePresentation.h
@@ -32,6 +32,8 @@ class KPrEndOfSlideShowPage;
 
 class KPrViewModePresentation : public KoPAViewMode
 {
+    Q_OBJECT
+
 public:
     KPrViewModePresentation( KoPAView * view, KoPACanvas * m_canvas );
     ~KPrViewModePresentation();
@@ -73,12 +75,67 @@ public:
     KPrAnimationDirector * animationDirector();
 
     /**
+     * Get the number of pages.
+     *
+     * This assumes that the presentation is active.
+     */
+    int numPages() const;
+
+    /**
+     * Get the current page number.
+     *
+     * This assumes that the presentation is active.
+     */
+    int currentPage() const;
+
+    /**
+     * Get the number of steps in this page.
+     *
+     * This assumes that the presentation is active.
+     */
+    int numStepsInPage() const;
+
+    /**
+     * get the current step.
+     *
+     * This assumes that the presentation is active.
+     */
+    int currentStep() const;
+
+    /**
      * Navigate in the presentation.
      */
     void navigate( KPrAnimationDirector::Navigation navigation );
 
     void navigateToPage( int index );
 
+signals:
+
+    /**
+     * Emitted when the presentation is activated.
+     */
+    void activated();
+
+    /**
+     * Emitted when the presentation is about to be deactivated.
+     */
+    void deactivated();
+
+    /**
+     * Emitted when the page changes.
+     *
+     * @param page new page index within the current slideshow
+     * @param stepsInPage the number of steps in the new page
+     */
+    void pageChanged( int page, int stepsInPage );
+
+    /**
+     * Emitted when the step changes.
+     *
+     * @param step new step index within the page
+     */
+    void stepChanged( int step );
+
 protected:
     KoPAViewMode * m_savedViewMode;
     QWidget * m_savedParent;
diff --git a/libs/kopageapp/KoPAView.cpp b/libs/kopageapp/KoPAView.cpp
index 6e4030d..fd70517 100644
--- a/libs/kopageapp/KoPAView.cpp
+++ b/libs/kopageapp/KoPAView.cpp
@@ -76,6 +76,8 @@
 #include <kstatusbar.h>
 #include <kparts/event.h>
 #include <kparts/partmanager.h>
+#include <ktemporaryfile.h>
+#include <kio/netaccess.h>
 
 KoPAView::KoPAView( KoPADocument *document, QWidget *parent )
 : KoView( document, parent )
@@ -606,6 +608,47 @@ void KoPAView::setActionEnabled( int actions, bool enable )
     }
 }
 
+bool KoPAView::exportPageThumbnail( KoPAPageBase * page, const KUrl& url, const QSize& size,
+                                    const char * format, int quality )
+{
+    bool res = false;
+    QPixmap pix = page->thumbnail( size );
+    if ( !pix.isNull() ) {
+        // Depending on the desired target size due to rounding
+        // errors during zoom the resulting pixmap *might* be
+        // 1 pixel or 2 pixels wider/higher than desired: we just
+        // remove the additional columns/rows.  This can be done
+        // since KPresenter is leaving a minimal border below/at
+        // the right of the image anyway.
+        if ( size != pix.size() ) {
+            pix = pix.copy( 0, 0, size.width(), size.height() );
+        }
+        // save the pixmap to the desired file
+        KUrl fileUrl( url );
+        if ( fileUrl.protocol().isEmpty() ) {
+            fileUrl.setProtocol( "file" );
+        }
+        const bool bLocalFile = fileUrl.isLocalFile();
+        KTemporaryFile* tmpFile = bLocalFile ? 0 : new KTemporaryFile();
+        if( bLocalFile || tmpFile->open() ) {
+            QFile file( bLocalFile ? fileUrl.path() : tmpFile->fileName() );
+            if ( file.open( IO_ReadWrite ) ) {
+                res = pix.save( &file, format, quality );
+                file.close();
+            }
+            if ( !bLocalFile ) {
+                if ( res ) {
+                    res = KIO::NetAccess::upload( tmpFile->fileName(), fileUrl, this );
+                }
+            }
+        }
+        if ( !bLocalFile ) {
+            delete tmpFile;
+        }
+   }
+   return res;
+}
+
 KoPADocumentStructureDocker* KoPAView::documentStructureDocker() const
 {
     return m_documentStructureDocker;
diff --git a/libs/kopageapp/KoPAView.h b/libs/kopageapp/KoPAView.h
index b2dde20..2d38a9b 100644
--- a/libs/kopageapp/KoPAView.h
+++ b/libs/kopageapp/KoPAView.h
@@ -39,6 +39,7 @@ class KoPADocumentStructureDocker;
 class KoShapeManager;
 class KoZoomAction;
 class KoZoomController;
+class KUrl;
 class QTextDocument;
 
 /// Creates a view with a KoPACanvas and rulers
@@ -118,6 +119,23 @@ public:
      */
     void doUpdateActivePage( KoPAPageBase * page );
 
+    /**
+     * Save thumbnail to an image file.
+     *
+     * Export a thumbnail to disk using a pixmap file like e.g. PNG
+     * This method uses a QPixmap::save() call.
+     *
+     * @param filename the name of the image file to be created (see QPixmap::save())
+     * @param width the desired image width in px
+     * @param height the desired image height in px
+     * @param format the format of the image file (see QPixmap::save())
+     * @param quality the quality of the image in [0,100] or -1 to use default (see QPixmap::save())
+     *
+     * @returns whether the image was successfully saved
+     */
+    bool exportPageThumbnail( KoPAPageBase * page, const KUrl& url, const QSize& size = QSize( 512, 512 ),
+                              const char * format = 0, int quality = -1 );
+
 public slots:
     /// Set the active page and updates the UI
     void updateActivePage( KoPAPageBase * page );
diff --git a/libs/main/KoApplication.h b/libs/main/KoApplication.h
index db0a0d2..e769c2d 100644
--- a/libs/main/KoApplication.h
+++ b/libs/main/KoApplication.h
@@ -74,6 +74,20 @@ public:
      */
     static bool isStarting();
 
+signals:
+    /// KoDocument needs to be able to emit document signals from here.
+    friend class KoDocument;
+
+    /**
+     * emitted when a new document is opened.
+     */
+    void documentOpened(const QString &ref);
+
+    /**
+     * emitted when an old document is closed.
+     */
+    void documentClosed(const QString &ref);
+
 private:
     bool initHack();
     KoApplicationPrivate * const d;
diff --git a/libs/main/KoApplicationAdaptor.h b/libs/main/KoApplicationAdaptor.h
index ca663da..67f6661 100644
--- a/libs/main/KoApplicationAdaptor.h
+++ b/libs/main/KoApplicationAdaptor.h
@@ -66,6 +66,17 @@ public Q_SLOTS: // METHODS
      * (see KoMainWindowIface)
      */
     Q_SCRIPTABLE QStringList getWindows();
+
+signals:
+    /**
+     * emitted when a new document is opened.
+     */
+    void documentOpened(const QString &ref);
+
+    /**
+     * emitted when an old document is closed.
+     */
+    void documentClosed(const QString &ref);
 };
 
 #endif
diff --git a/libs/main/KoDocument.cpp b/libs/main/KoDocument.cpp
index 496ec85..01bae1e 100644
--- a/libs/main/KoDocument.cpp
+++ b/libs/main/KoDocument.cpp
@@ -35,6 +35,7 @@
 #include "KoEmbeddedDocumentSaver.h"
 #include "KoXmlNS.h"
 #include "KoOpenPane.h"
+#include "KoApplication.h"
 
 #include <KoXmlWriter.h>
 
@@ -657,11 +658,25 @@ void KoDocument::addView(KoView *view)
 
     d->m_views.append(view);
     view->updateReadWrite(isReadWrite());
+
+    if (d->m_views.size() == 1) {
+        KoApplication* app = qobject_cast<KoApplication*>(KApplication::kApplication());
+        if (0 != app) {
+            emit app->documentOpened('/'+objectName());
+        }
+    }
 }
 
 void KoDocument::removeView(KoView *view)
 {
     d->m_views.removeAll(view);
+
+    if (d->m_views.isEmpty()) {
+        KoApplication* app = qobject_cast<KoApplication*>(KApplication::kApplication());
+        if (0 != app) {
+            emit app->documentClosed('/'+objectName());
+        }
+    }
 }
 
 QList<KoView*> KoDocument::views() const
