KoPADocument.cpp 12.5 KB
Newer Older
1
/* This file is part of the KDE project
2
   Copyright (C) 2006-2007 Thorsten Zachmann <zachmann@kde.org>
3
   Copyright (C) 2007 Thomas Zander <zander@kde.org>
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library 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
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include "KoPADocument.h"

23 24 25
#include <KoStore.h>
#include <KoStoreDevice.h>
#include <KoXmlWriter.h>
26
#include <KoXmlReader.h>
27
#include <KoOdfStylesReader.h>
28
#include <KoOdfReadStore.h>
29
#include <KoOdfWriteStore.h>
30
#include <KoOasisLoadingContext.h>
31
#include <KoShapeManager.h>
32
#include <KoShapeLayer.h>
33 34
#include <KoTextShapeData.h>
#include <KoTextDocumentLayout.h>
35
#include <KoInlineTextObjectManager.h>
36
#include <KoShapeStyleWriter.h>
37
#include <KoStyleManager.h>
38 39
#include <KoPathShape.h>
#include <KoLineBorder.h>
40 41
#include <KoDom.h>
#include <KoXmlNS.h>
42 43 44 45 46

#include "KoPACanvas.h"
#include "KoPAView.h"
#include "KoPAPage.h"
#include "KoPAMasterPage.h"
47
#include "KoPASavingContext.h"
48
#include "KoPALoadingContext.h"
49

50 51
#include <kdebug.h>

52 53
#include <typeinfo>

54 55 56 57 58 59 60 61 62
class KoPADocument::Private {
public:

    QList<KoPAPageBase*> pages;
    QList<KoPAPageBase*> masterPages;
    KoInlineTextObjectManager *inlineTextObjectManager;
    KoStyleManager *styleManager;
};

63
KoPADocument::KoPADocument( QWidget* parentWidget, QObject* parent, bool singleViewMode )
64 65
: KoDocument( parentWidget, parent, singleViewMode ),
    d(new Private())
66
{
67 68
    d->inlineTextObjectManager = new KoInlineTextObjectManager(this);
    d->styleManager = new KoStyleManager(this);
69 70 71 72
}

KoPADocument::~KoPADocument()
{
73 74
    qDeleteAll( d->pages );
    qDeleteAll( d->masterPages );
75
    delete d;
76 77
}

78
void KoPADocument::paintContent( QPainter &painter, const QRect &rect)
79
{
Ariya Hidayat's avatar
Ariya Hidayat committed
80 81
    Q_UNUSED( painter );
    Q_UNUSED( rect );
82 83 84 85
}

bool KoPADocument::loadXML( QIODevice *, const KoXmlDocument & doc )
{
Ariya Hidayat's avatar
Ariya Hidayat committed
86 87
    Q_UNUSED( doc );

88 89 90 91 92
    //Perhaps not necessary if we use filter import/export for old file format
    //only needed as it is in the base class will be removed.
    return true;
}

93
bool KoPADocument::loadOdf( KoOdfReadStore & odfStore )
94
{
95
    emit sigProgress( 0 );
96
    KoOasisLoadingContext loadingContext( this, odfStore.styles(), odfStore.store() );
97 98
    KoPALoadingContext paContext( loadingContext );

99
    KoXmlElement content = odfStore.contentDoc().documentElement();
100 101 102 103 104 105 106
    KoXmlElement realBody ( KoDom::namedItemNS( content, KoXmlNS::office, "body" ) );

    if ( realBody.isNull() ) {
        kError() << "No body tag found!" << endl;
        return false;
    }

107
    KoXmlElement body = KoDom::namedItemNS(realBody, KoXmlNS::office, odfTagName( false ));
108 109

    if ( body.isNull() ) {
110
        kError() << "No office:" << odfTagName( false ) << " tag found!" << endl;
111 112
        return false;
    }
113

114 115 116
    d->masterPages = loadOdfMasterPages( odfStore.styles().masterPages(), paContext );
    d->pages = loadOdfPages( body, paContext );
    if ( d->pages.size() > 1 ) {
117
        setActionEnabled( KoPAView::ActionDeletePage, false );
118 119
    }

120
    emit sigProgress( 100 );
121 122 123 124 125
    return true;
}

bool KoPADocument::saveOasis( KoStore* store, KoXmlWriter* manifestWriter )
{
126
    KoOdfWriteStore oasisStore( store );
Thorsten Zachmann's avatar
Thorsten Zachmann committed
127 128 129
    KoXmlWriter* contentWriter = oasisStore.contentWriter();
    if ( !contentWriter )
        return false;
130 131

    KoGenStyles mainStyles;
Thorsten Zachmann's avatar
Thorsten Zachmann committed
132
    KoXmlWriter * bodyWriter = oasisStore.bodyWriter();
Thorsten Zachmann's avatar
Thorsten Zachmann committed
133

134 135
    KoPASavingContext paContext( *bodyWriter, mainStyles, 1, KoShapeSavingContext::Store );

136
    if ( !saveOasisPages( paContext, d->pages, d->masterPages ) ) {
Thorsten Zachmann's avatar
Thorsten Zachmann committed
137 138 139 140 141 142 143 144 145 146 147 148 149
        return false;
    }

    mainStyles.saveOdfAutomaticStyles( contentWriter, false );

    oasisStore.closeContentWriter();

    //add manifest line for content.xml
    manifestWriter->addManifestEntry( "content.xml", "text/xml" );

    return mainStyles.saveOdfStylesDotXml( store, manifestWriter );
}

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
QList<KoPAPageBase *> KoPADocument::loadOdfMasterPages( const QHash<QString, KoXmlElement*> masterStyles, KoPALoadingContext & context )
{
    QList<KoPAPageBase *> masterPages;

    QHash<QString, KoXmlElement*>::const_iterator it( masterStyles.constBegin() );
    for ( ; it != masterStyles.constEnd(); ++it )
    {
        qDebug() << "Master:" << it.key();
        KoPAMasterPage * masterPage = newMasterPage();
        masterPage->loadOdf( *( it.value() ), context );
        masterPages.append( masterPage );
        context.addMasterPage( it.key(), masterPage );
    }
    return masterPages;
}

Thorsten Zachmann's avatar
Thorsten Zachmann committed
166
QList<KoPAPageBase *> KoPADocument::loadOdfPages( const KoXmlElement & body, KoPALoadingContext & context )
167 168 169 170 171 172 173 174 175 176 177 178 179 180
{
    QList<KoPAPageBase *> pages;
    KoXmlElement element;
    forEachElement( element, body )
    {
        if ( element.tagName() == "page" && element.namespaceURI() == KoXmlNS::draw ) {
            KoPAPage* page = newPage();
            page->loadOdf( element, context );
            pages.append( page );
        }
    }
    return pages;
}

181
bool KoPADocument::saveOasisPages( KoPASavingContext &paContext, QList<KoPAPageBase *> &pages, QList<KoPAPageBase *> &masterPages )
Thorsten Zachmann's avatar
Thorsten Zachmann committed
182
{
183 184
    paContext.addOption( KoPASavingContext::DrawId );
    paContext.addOption( KoPASavingContext::AutoStyleInStyleXml );
185 186

    // save master pages
187
    foreach( KoPAPageBase *page, masterPages ) {
188
        page->saveOdf( paContext );
189 190
    }

191 192 193
    KoXmlWriter & bodyWriter = paContext.xmlWriter();
    bodyWriter.startElement( "office:body" );
    bodyWriter.startElement( odfTagName( true ) );
194

195
    paContext.removeOption( KoPASavingContext::AutoStyleInStyleXml );
196 197

    // save pages
198
    foreach ( KoPAPageBase *page, pages ) {
199
        page->saveOdf( paContext );
200 201 202
        paContext.incrementPage();
    }

203 204
    bodyWriter.endElement(); // office:odfTagName()
    bodyWriter.endElement(); // office:body
205

Thorsten Zachmann's avatar
Thorsten Zachmann committed
206
    return true;
207 208
}

209
KoPAPageBase* KoPADocument::pageByIndex( int index, bool masterPage ) const
210
{
211 212
    if ( masterPage )
    {
213
        return d->masterPages.at( index );
214 215 216
    }
    else
    {
217
        return d->pages.at( index );
218
    }
219
}
Anne-Marie Mahfouf's avatar
Anne-Marie Mahfouf committed
220

221 222
KoPAPageBase* KoPADocument::pageByNavigation( KoPAPageBase * currentPage, KoPageApp::PageNavigation pageNavigation ) const
{
223
    const QList<KoPAPageBase*>& pages = dynamic_cast<KoPAMasterPage *>( currentPage ) ? d->masterPages : d->pages;
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259

    Q_ASSERT( ! pages.isEmpty() );

    KoPAPageBase * newPage = currentPage;

    switch ( pageNavigation )
    {
        case KoPageApp::PageFirst:
            newPage = pages.first();
            break;
        case KoPageApp::PageLast:
            newPage = pages.last();
            break;
        case KoPageApp::PagePrevious:
        {
            int index = pages.indexOf( currentPage ) - 1;
            if ( index >= 0 )
            {
                newPage = pages.at( index );
            }
        }   break;
        case KoPageApp::PageNext:
            // fall through
        default:
        {
            int index = pages.indexOf( currentPage ) + 1;
            if ( index < pages.size() )
            {
                newPage = pages.at( index );
            }
            break;
        }
    }

    return newPage;
}
260

261
void KoPADocument::addShape( KoShape * shape )
262
{
263 264 265
    if(!shape)
        return;

266 267 268 269 270 271 272
    KoTextShapeData *data = qobject_cast<KoTextShapeData*> (shape->userData());
    if (data) { // its a text shape.
        KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout*> (data->document()->documentLayout());
        if(lay)
            lay->setStyleManager(d->styleManager);
    }

273
    // the KoShapeController sets the active layer as parent
274
    KoPAPageBase * page( pageByShape( shape ) );
275

Thorsten Zachmann's avatar
Thorsten Zachmann committed
276
    bool isMaster = dynamic_cast<KoPAMasterPage*>( page ) != 0;
277

278
    foreach( KoView *view, views() )
279
    {
280
        KoPAView * kopaView = static_cast<KoPAView*>( view );
281 282 283 284 285 286 287 288
        KoPAPage * p;
        if ( page == kopaView->activePage() ) {
            kopaView->kopaCanvas()->shapeManager()->add( shape );
        }
        else if ( isMaster && ( p = dynamic_cast<KoPAPage*>( kopaView->activePage() ) ) != 0 ) {
            if ( p->masterPage() == page ) {
                kopaView->kopaCanvas()->masterShapeManager()->add( shape );
            }
289 290
        }
    }
291 292

    postAddShape( page, shape );
293 294
}

295 296 297 298 299
void KoPADocument::postAddShape( KoPAPageBase * page, KoShape * shape )
{
    Q_UNUSED( page );
    Q_UNUSED( shape );
}
300

301
void KoPADocument::removeShape( KoShape *shape )
302
{
303 304 305
    if(!shape)
        return;

306
    KoPAPageBase * page( pageByShape( shape ) );
307

Thorsten Zachmann's avatar
Thorsten Zachmann committed
308
    bool isMaster = dynamic_cast<KoPAMasterPage*>( page ) != 0;
309

Thorsten Zachmann's avatar
Thorsten Zachmann committed
310
    foreach( KoView *view, views() )
311
    {
312
        KoPAView * kopaView = static_cast<KoPAView*>( view );
313 314 315 316 317 318 319 320
        KoPAPage * p;
        if ( page == kopaView->activePage() ) {
            kopaView->kopaCanvas()->shapeManager()->remove( shape );
        }
        else if ( isMaster && ( p = dynamic_cast<KoPAPage*>( kopaView->activePage() ) ) != 0 ) {
            if ( p->masterPage() == page ) {
                kopaView->kopaCanvas()->masterShapeManager()->remove( shape );
            }
321 322
        }
    }
323 324 325 326 327 328 329 330

    postRemoveShape( page, shape );
}

void KoPADocument::postRemoveShape( KoPAPageBase * page, KoShape * shape )
{
    Q_UNUSED( page );
    Q_UNUSED( shape );
331 332
}

333
KoPAPageBase * KoPADocument::pageByShape( KoShape * shape ) const
334 335 336 337 338 339 340 341 342 343
{
    KoShape * parent = shape;
    KoPAPageBase * page = 0;
    while ( !page && ( parent = parent->parent() ) )
    {
        page = dynamic_cast<KoPAPageBase*>( parent );
    }
    return page;
}

344 345
void KoPADocument::setActionEnabled( int actions, bool enable )
{
Thorsten Zachmann's avatar
Thorsten Zachmann committed
346
    foreach( KoView *view, views() )
347 348 349 350 351 352
    {
        KoPAView * kopaView = static_cast<KoPAView*>( view );
        kopaView->setActionEnabled( actions, enable );
    }
}

353 354 355 356 357
void KoPADocument::insertPage( KoPAPageBase* page, int index )
{
    if ( !page )
        return;

358
    QList<KoPAPageBase*>& pages = dynamic_cast<KoPAMasterPage *>( page ) ? d->masterPages : d->pages;
359 360 361 362 363 364 365

    if ( index > pages.size() || index < 0 )
    {
        index = pages.size();
    }

    pages.insert( index, page );
Thorsten Zachmann's avatar
Thorsten Zachmann committed
366

367 368 369
    if ( pages.size() == 2 ) {
        setActionEnabled( KoPAView::ActionDeletePage, true );
    }
370 371
}

372
void KoPADocument::insertPage( KoPAPageBase* page, KoPAPageBase* after )
373 374 375 376
{
    if ( !page )
        return;

377
    QList<KoPAPageBase*>& pages = dynamic_cast<KoPAMasterPage *>( page ) ? d->masterPages : d->pages;
378

379
    int index = 0;
380

381
    if ( after != 0 )
382
    {
383
        index = pages.indexOf( after ) + 1;
384

385 386
        // Append the page if after wasn't found in pages
        if ( index == 0 )
387
            index = pages.count();
388 389
    }

390
    pages.insert( index, page );
391 392 393 394

    if ( pages.size() == 2 ) {
        setActionEnabled( KoPAView::ActionDeletePage, true );
    }
Thorsten Zachmann's avatar
Thorsten Zachmann committed
395

396
    // move active view to new page
397 398
}

399
int KoPADocument::takePage( KoPAPageBase *page )
400
{
401
    Q_ASSERT( page );
402

403
    QList<KoPAPageBase *>& pages = dynamic_cast<KoPAMasterPage *>( page ) ? d->masterPages : d->pages;
404

405 406
    int index = pages.indexOf( page );

407 408 409
    // it should not be possible to delete the last page
    Q_ASSERT( pages.size() > 1 );

410 411
    if ( index != -1 ) {
        pages.removeAt( index );
412 413 414 415 416 417 418 419 420 421 422

        // change to previous page when the page is the active one if the first one is delete go to the next one
        int newIndex = index == 0 ? 0 : index - 1;
        KoPAPageBase * newActivePage = pages.at( newIndex );
        foreach( KoView *view, views() )
        {
            KoPAView * kopaView = static_cast<KoPAView*>( view );
            if ( page == kopaView->activePage() ) {
                kopaView->setActivePage( newActivePage );
            }
        }
423
    }
424 425 426 427

    if ( pages.size() == 1 ) {
        setActionEnabled( KoPAView::ActionDeletePage, false );
    }
428
    return index;
429 430
}

431
QList<KoPAPageBase*> KoPADocument::pages( bool masterPages ) const
432
{
433
    return masterPages ? d->masterPages : d->pages;
434 435
}

436
KoPAPage * KoPADocument::newPage( KoPAMasterPage * masterPage )
437
{
438
    return new KoPAPage( masterPage );
439 440 441 442 443 444 445
}

KoPAMasterPage * KoPADocument::newMasterPage()
{
    return new KoPAMasterPage();
}

446 447 448 449 450
/// return the inlineTextObjectManager for this document.
KoInlineTextObjectManager *KoPADocument::inlineTextObjectManager() const {
    return d->inlineTextObjectManager;
}

451

452
#include "KoPADocument.moc"