00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "KoDocument.h"
00022
00023 #include "KoDom.h"
00024 #include "KoDocument_p.h"
00025 #include "KoDocumentAdaptor.h"
00026 #include <QtDBus/QtDBus>
00027 #include "KoDocumentChild.h"
00028 #include "KoView.h"
00029 #include "KoMainWindow.h"
00030 #include "KoFilterManager.h"
00031 #include "KoDocumentInfo.h"
00032 #include "KoOasisStyles.h"
00033 #include "KoOasisStore.h"
00034 #include "KoXmlNS.h"
00035 #include "KoOpenPane.h"
00036
00037 #include <KoStoreDevice.h>
00038 #include <KoXmlWriter.h>
00039
00040 #include <kapplication.h>
00041 #include <kdialog.h>
00042 #include <kdebug.h>
00043 #include <kdeversion.h>
00044 #include <kfileitem.h>
00045 #include <kiconloader.h>
00046 #include <kio/job.h>
00047 #include <kio/jobuidelegate.h>
00048 #include <kio/netaccess.h>
00049 #include <klocale.h>
00050 #include <kmessagebox.h>
00051 #include <kmimetype.h>
00052 #include <kparts/partmanager.h>
00053 #include <kprinter.h>
00054 #include <ksavefile.h>
00055 #include <kxmlguifactory.h>
00056
00057 #include <QBuffer>
00058 #include <QCursor>
00059 #include <QDir>
00060 #include <QFile>
00061 #include <QFileInfo>
00062 #include <QImage>
00063 #include <QMap>
00064 #include <QPainter>
00065 #include <QTimer>
00066 #include <QXmlSimpleReader>
00067 #include <QLayout>
00068 #include <QByteArray>
00069 #include <QPixmap>
00070 #include <QChildEvent>
00071 #include <Q3PtrList>
00072 #include <QEvent>
00073 #include <QResizeEvent>
00074 #include <QDateTime>
00075 #include <config.h>
00076 #include <assert.h>
00077
00078
00079
00080
00081
00082 #define STORE_PROTOCOL "tar"
00083
00084
00085 #define INTERNAL_PROTOCOL "intern"
00086 #define INTERNAL_PREFIX "intern:/"
00087
00088
00089 Q3PtrList<KoDocument> *KoDocument::s_documentList=0L;
00090
00091 using namespace std;
00092 class KoViewWrapperWidget;
00093
00094
00095
00096
00097
00098
00099
00100 const int KoDocument::s_defaultAutoSave = 300;
00101
00102
00103
00104 QString KoDocument::newObjectName()
00105 {
00106 static int s_docIFNumber = 0;
00107 QString name; name.setNum( s_docIFNumber++ ); name.prepend("document_");
00108 return name;
00109 }
00110
00111 class KoDocument::Private
00112 {
00113 public:
00114 Private() :
00115
00116 filterManager( 0L ),
00117 m_specialOutputFlag( 0 ),
00118 m_isImporting( false ), m_isExporting( false ),
00119 m_numOperations( 0 ),
00120 modifiedAfterAutosave( false ),
00121 m_autosaving( false ),
00122 m_shouldCheckAutoSaveFile( true ),
00123 m_autoErrorHandlingEnabled( true ),
00124 m_backupFile( true ),
00125 m_backupPath( QString::null ),
00126 m_doNotSaveExtDoc( false ),
00127 m_current( false ),
00128 m_storeInternal( false ),
00129 m_bLoading( false ),
00130 m_startUpWidget( 0 )
00131 {
00132 m_confirmNonNativeSave[0] = true;
00133 m_confirmNonNativeSave[1] = true;
00134 if ( KGlobal::locale()->measureSystem() == KLocale::Imperial ) {
00135 m_unit = KoUnit::U_INCH;
00136 } else {
00137 m_unit = KoUnit::U_CM;
00138 }
00139 }
00140
00141 QList<KoView*> m_views;
00142 Q3PtrList<KoDocumentChild> m_children;
00143 Q3PtrList<KoMainWindow> m_shells;
00144 QList<QDomDocument> m_viewBuildDocuments;
00145
00146 KoViewWrapperWidget *m_wrapperWidget;
00147
00148 KoDocumentInfo *m_docInfo;
00149
00150 KoUnit::Unit m_unit;
00151
00152 KoFilterManager * filterManager;
00153
00154 QByteArray mimeType;
00155 QByteArray outputMimeType;
00156 bool m_confirmNonNativeSave [2];
00157
00158
00159 int m_specialOutputFlag;
00160 bool m_isImporting, m_isExporting;
00161
00162 QTimer m_autoSaveTimer;
00163 QString lastErrorMessage;
00164 int m_autoSaveDelay;
00165 int m_numOperations;
00166 bool modifiedAfterAutosave;
00167 bool m_bSingleViewMode;
00168 bool m_autosaving;
00169 bool m_shouldCheckAutoSaveFile;
00170 bool m_autoErrorHandlingEnabled;
00171 bool m_backupFile;
00172 QString m_backupPath;
00173 bool m_doNotSaveExtDoc;
00174 bool m_current;
00175 bool m_storeInternal;
00176 bool m_bLoading;
00177
00178 KoOpenPane* m_startUpWidget;
00179 QString m_templateType;
00180 QList<KoVersionInfo> m_versionInfo;
00181 };
00182
00183
00184 class KoViewWrapperWidget : public QWidget
00185 {
00186 public:
00187 KoViewWrapperWidget( QWidget *parent )
00188 : QWidget( parent )
00189 {
00190 KGlobal::locale()->insertCatalog("koffice");
00191
00192 KGlobal::iconLoader()->addAppDir("koffice");
00193 m_view = 0L;
00194
00195 setFocusPolicy( Qt::ClickFocus );
00196 }
00197
00198 virtual ~KoViewWrapperWidget() {
00199 setFocusProxy( 0 );
00200 }
00201
00202 virtual void resizeEvent( QResizeEvent * )
00203 {
00204 QWidget *wid = findChild<QWidget *>( "" );
00205 wid->setGeometry( 0, 0, width(), height() );
00206 }
00207
00208 virtual void childEvent( QChildEvent *ev )
00209 {
00210 if ( ev->type() == QEvent::ChildAdded )
00211 resizeEvent( 0L );
00212 }
00213
00214
00215 void setKoView( KoView * view ) {
00216 m_view = view;
00217 setFocusProxy( m_view );
00218 }
00219 KoView * koView() const { return m_view; }
00220 private:
00221 KoView* m_view;
00222 };
00223
00224 KoBrowserExtension::KoBrowserExtension( KoDocument * doc )
00225 : KParts::BrowserExtension( doc)
00226 {
00227 emit enableAction( "print", true );
00228 }
00229
00230 void KoBrowserExtension::print()
00231 {
00232 KoDocument * doc = static_cast<KoDocument *>( parent() );
00233 KoViewWrapperWidget * wrapper = static_cast<KoViewWrapperWidget *>( doc->widget() );
00234 KoView * view = wrapper->koView();
00235
00236 KPrinter printer;
00237
00238 view->setupPrinter( printer );
00239 if ( printer.setup( view ) )
00240 view->print( printer );
00241 }
00242
00243 KoDocument::KoDocument( QWidget * parentWidget, QObject* parent, bool singleViewMode )
00244 : KParts::ReadWritePart( parent )
00245 {
00246 if(s_documentList==0L)
00247 s_documentList=new Q3PtrList<KoDocument>;
00248 s_documentList->append(this);
00249
00250 d = new Private;
00251 m_bEmpty = true;
00252 connect( &d->m_autoSaveTimer, SIGNAL( timeout() ), this, SLOT( slotAutoSave() ) );
00253 setAutoSave( s_defaultAutoSave );
00254 d->m_bSingleViewMode = singleViewMode;
00255
00256 setObjectName( newObjectName() );
00257 new KoDocumentAdaptor(this);
00258 QDBusConnection::sessionBus().registerObject( '/' + objectName(), this);
00259
00260
00261
00262 if ( parent )
00263 {
00264 if ( parent->inherits( "KoDocument" ) )
00265 d->m_bSingleViewMode = ((KoDocument *)parent)->isSingleViewMode();
00266 else if ( parent->inherits( "KParts::Part" ) )
00267 d->m_bSingleViewMode = true;
00268 }
00269
00270 if ( singleViewMode )
00271 {
00272 d->m_wrapperWidget = new KoViewWrapperWidget( parentWidget );
00273 setWidget( d->m_wrapperWidget );
00274 kDebug(30003) << "creating KoBrowserExtension" << endl;
00275 (void) new KoBrowserExtension( this );
00276 }
00277
00278 d->m_docInfo = new KoDocumentInfo( this );
00279
00280 m_pageLayout.ptWidth = 0;
00281 m_pageLayout.ptHeight = 0;
00282 m_pageLayout.ptTop = 0;
00283 m_pageLayout.ptBottom = 0;
00284 m_pageLayout.ptLeft = 0;
00285 m_pageLayout.ptRight = 0;
00286
00287
00288 if ( !singleViewMode )
00289 connect( this, SIGNAL( started( KIO::Job* ) ), SLOT( slotStarted( KIO::Job* ) ) );
00290 }
00291
00292 KoDocument::~KoDocument()
00293 {
00294 d->m_autoSaveTimer.stop();
00295
00296 Q3PtrListIterator<KoDocumentChild> childIt( d->m_children );
00297 for (; childIt.current(); ++childIt )
00298 disconnect( childIt.current(), SIGNAL( destroyed() ),
00299 this, SLOT( slotChildDestroyed() ) );
00300
00301
00302
00303 foreach ( KoView* view, d->m_views )
00304 view->setDocumentDeleted();
00305
00306 delete d->m_startUpWidget;
00307 d->m_startUpWidget = 0;
00308
00309 d->m_children.setAutoDelete( true );
00310 d->m_children.clear();
00311
00312 d->m_shells.setAutoDelete( true );
00313 d->m_shells.clear();
00314
00315
00316 delete d->filterManager;
00317 delete d;
00318 s_documentList->removeRef(this);
00319
00320 if(s_documentList->isEmpty()) {
00321 delete s_documentList;
00322 s_documentList=0;
00323 }
00324 }
00325
00326 bool KoDocument::isSingleViewMode() const
00327 {
00328 return d->m_bSingleViewMode;
00329 }
00330
00331 bool KoDocument::isEmbedded() const
00332 {
00333 return dynamic_cast<KoDocument *>( parent() ) != 0;
00334 }
00335
00336 KoView *KoDocument::createView( QWidget *parent )
00337 {
00338 KoView *view=createViewInstance(parent);
00339 addView(view);
00340 return view;
00341 }
00342
00343 bool KoDocument::exp0rt( const KUrl & _url )
00344 {
00345 bool ret;
00346
00347 d->m_isExporting = true;
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357 KUrl oldURL = m_url;
00358 QString oldFile = m_file;
00359
00360 bool wasModified = isModified ();
00361 QByteArray oldMimeType = mimeType ();
00362
00363
00364
00365 ret = saveAs( _url );
00366
00367
00368
00369
00370
00371
00372 kDebug(30003) << "Restoring KoDocument state to before export" << endl;
00373
00374
00375
00376 m_url = oldURL;
00377 m_file = oldFile;
00378
00379
00380
00381 if (ret)
00382 {
00383 setModified (wasModified);
00384 d->mimeType = oldMimeType;
00385 }
00386
00387
00388 d->m_isExporting = false;
00389
00390 return ret;
00391 }
00392
00393 bool KoDocument::saveFile()
00394 {
00395 kDebug(30003) << "KoDocument::saveFile() doc='" << url().url() <<"'"<< endl;
00396
00397
00398 const bool wasModified = isModified ();
00399
00400
00401 QByteArray outputMimeType = d->outputMimeType;
00402
00403 if ( outputMimeType.isEmpty() )
00404 outputMimeType = d->outputMimeType = nativeFormatMimeType();
00405
00406 QApplication::setOverrideCursor( Qt::WaitCursor );
00407
00408 if ( backupFile() ) {
00409 if ( url().isLocalFile() )
00410 KSaveFile::backupFile( url().path(), d->m_backupPath );
00411 else {
00412 KIO::UDSEntry entry;
00413 if ( KIO::NetAccess::stat( url(), entry, shells().current() ) ) {
00414 emit sigStatusBarMessage( i18n("Making backup...") );
00415 KUrl backup;
00416 if ( d->m_backupPath.isEmpty())
00417 backup = url();
00418 else
00419 backup = d->m_backupPath +'/'+url().fileName();
00420 backup.setPath( backup.path() + QString::fromLatin1("~") );
00421 KFileItem item( entry, url() );
00422 Q_ASSERT( item.name() == url().fileName() );
00423 KIO::NetAccess::file_copy( url(), backup, item.permissions(), true , false , shells().current() );
00424 }
00425 }
00426 }
00427
00428 emit sigStatusBarMessage( i18n("Saving...") );
00429 bool ret = false;
00430 bool suppressErrorDialog = false;
00431 if ( !isNativeFormat( outputMimeType ) ) {
00432 kDebug(30003) << "Saving to format " << outputMimeType << " in " << m_file << endl;
00433
00434 if ( !d->filterManager )
00435 d->filterManager = new KoFilterManager( this );
00436
00437 KoFilter::ConversionStatus status = d->filterManager->exp0rt( m_file, outputMimeType );
00438 ret = status == KoFilter::OK;
00439 suppressErrorDialog = (status == KoFilter::UserCancelled || status == KoFilter::BadConversionGraph );
00440 } else {
00441
00442 Q_ASSERT( !m_file.isEmpty() );
00443 ret = saveNativeFormat( m_file );
00444 }
00445
00446 if ( ret ) {
00447 removeAutoSaveFiles();
00448
00449
00450 setAutoSave( d->m_autoSaveDelay );
00451 }
00452
00453 QApplication::restoreOverrideCursor();
00454 if ( !ret )
00455 {
00456 if ( !suppressErrorDialog )
00457 {
00458 showSavingErrorDialog();
00459 }
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471 resetURL();
00472
00473
00474 setModified( wasModified );
00475 }
00476
00477 if ( ret )
00478 {
00479 d->mimeType = outputMimeType;
00480 setConfirmNonNativeSave ( isExporting (), false );
00481 }
00482 emit sigClearStatusBarMessage();
00483
00484 return ret;
00485 }
00486
00487 QByteArray KoDocument::mimeType() const
00488 {
00489 return d->mimeType;
00490 }
00491
00492 void KoDocument::setMimeType( const QByteArray & mimeType )
00493 {
00494 d->mimeType = mimeType;
00495 }
00496
00497 void KoDocument::setOutputMimeType( const QByteArray & mimeType, int specialOutputFlag )
00498 {
00499 d->outputMimeType = mimeType;
00500 d->m_specialOutputFlag = specialOutputFlag;
00501 }
00502
00503 QByteArray KoDocument::outputMimeType() const
00504 {
00505 return d->outputMimeType;
00506 }
00507
00508 int KoDocument::specialOutputFlag() const
00509 {
00510 return d->m_specialOutputFlag;
00511 }
00512
00513 bool KoDocument::confirmNonNativeSave( const bool exporting ) const
00514 {
00515
00516
00517 return d->m_confirmNonNativeSave [ exporting ? 1 : 0 ];
00518 }
00519
00520 void KoDocument::setConfirmNonNativeSave( const bool exporting, const bool on )
00521 {
00522 d->m_confirmNonNativeSave [ exporting ? 1 : 0] = on;
00523 }
00524
00525 bool KoDocument::wantExportConfirmation() const
00526 {
00527 return true;
00528 }
00529
00530 bool KoDocument::isImporting() const
00531 {
00532 return d->m_isImporting;
00533 }
00534
00535 bool KoDocument::isExporting() const
00536 {
00537 return d->m_isExporting;
00538 }
00539
00540 void KoDocument::setCheckAutoSaveFile( bool b )
00541 {
00542 d->m_shouldCheckAutoSaveFile = b;
00543 }
00544
00545 void KoDocument::setAutoErrorHandlingEnabled( bool b )
00546 {
00547 d->m_autoErrorHandlingEnabled = b;
00548 }
00549
00550 bool KoDocument::isAutoErrorHandlingEnabled() const
00551 {
00552 return d->m_autoErrorHandlingEnabled;
00553 }
00554
00555 void KoDocument::slotAutoSave()
00556 {
00557 if ( isModified() && d->modifiedAfterAutosave && !d->m_bLoading )
00558 {
00559 connect( this, SIGNAL( sigProgress( int ) ), shells().current(), SLOT( slotProgress( int ) ) );
00560 emit sigStatusBarMessage( i18n("Autosaving...") );
00561 d->m_autosaving = true;
00562 bool ret = saveNativeFormat( autoSaveFile( m_file ) );
00563 setModified( true );
00564 if ( ret ) {
00565 d->modifiedAfterAutosave = false;
00566 d->m_autoSaveTimer.stop();
00567 }
00568 d->m_autosaving = false;
00569 emit sigClearStatusBarMessage();
00570 disconnect( this, SIGNAL( sigProgress( int ) ), shells().current(), SLOT( slotProgress( int ) ) );
00571 if ( !ret )
00572 emit sigStatusBarMessage( i18n("Error during autosave! Partition full?") );
00573 }
00574 }
00575
00576 KAction *KoDocument::action( const QDomElement &element ) const
00577 {
00578
00579 KAction* act = KParts::ReadWritePart::action( element );
00580 if ( act )
00581 return act;
00582
00583 Q_ASSERT( d->m_bSingleViewMode );
00584
00585 if ( !d->m_views.isEmpty() )
00586 return d->m_views.first()->action( element );
00587 else
00588 return 0L;
00589 }
00590
00591 QDomDocument KoDocument::domDocument() const
00592 {
00593
00594
00595 Q_ASSERT( d->m_bSingleViewMode );
00596 if ( d->m_views.isEmpty() )
00597 return QDomDocument();
00598 else
00599 return d->m_views.first()->domDocument();
00600 }
00601
00602 void KoDocument::setManager( KParts::PartManager *manager )
00603 {
00604 KParts::ReadWritePart::setManager( manager );
00605 if ( d->m_bSingleViewMode && d->m_views.count() == 1 )
00606 d->m_views.first()->setPartManager( manager );
00607
00608 if ( manager )
00609 {
00610 Q3PtrListIterator<KoDocumentChild> it( d->m_children );
00611 for (; it.current(); ++it )
00612 if ( it.current()->document() )
00613 manager->addPart( it.current()->document(), false );
00614 }
00615 }
00616
00617 void KoDocument::setReadWrite( bool readwrite )
00618 {
00619 KParts::ReadWritePart::setReadWrite( readwrite );
00620
00621 foreach ( KoView* view, d->m_views )
00622 view->updateReadWrite( readwrite );
00623
00624 Q3PtrListIterator<KoDocumentChild> dIt( d->m_children );
00625 for (; dIt.current(); ++dIt )
00626 if ( dIt.current()->document() )
00627 dIt.current()->document()->setReadWrite( readwrite );
00628
00629 Q3PtrListIterator<KoMainWindow> it( d->m_shells );
00630 for (; it.current(); ++it )
00631 it.current()->setReadWrite( readwrite );
00632
00633 setAutoSave( d->m_autoSaveDelay );
00634 }
00635
00636 void KoDocument::setAutoSave( int delay )
00637 {
00638 d->m_autoSaveDelay = delay;
00639 if ( isReadWrite() && !isEmbedded() && d->m_autoSaveDelay > 0 )
00640 d->m_autoSaveTimer.start( d->m_autoSaveDelay * 1000 );
00641 else
00642 d->m_autoSaveTimer.stop();
00643 }
00644
00645 void KoDocument::addView( KoView *view )
00646 {
00647 if ( !view )
00648 return;
00649
00650 d->m_views.append( view );
00651 view->updateReadWrite( isReadWrite() );
00652 }
00653
00654 void KoDocument::removeView( KoView *view )
00655 {
00656 d->m_views.removeAll( view );
00657 }
00658
00659 const QList<KoView*>& KoDocument::views() const
00660 {
00661 return d->m_views;
00662 }
00663
00664 int KoDocument::viewCount() const
00665 {
00666 return d->m_views.count();
00667 }
00668
00669 void KoDocument::insertChild( KoDocumentChild *child )
00670 {
00671 setModified( true );
00672
00673 d->m_children.append( child );
00674
00675 connect( child, SIGNAL( changed( KoChild * ) ),
00676 this, SLOT( slotChildChanged( KoChild * ) ) );
00677 connect( child, SIGNAL( destroyed() ),
00678 this, SLOT( slotChildDestroyed() ) );
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688 if ( manager() && !isSingleViewMode() && child->document() )
00689 manager()->addPart( child->document(), false );
00690 }
00691
00692 void KoDocument::slotChildChanged( KoChild *c )
00693 {
00694 assert( c->inherits( "KoDocumentChild" ) );
00695 emit childChanged( static_cast<KoDocumentChild *>( c ) );
00696 }
00697
00698 void KoDocument::slotChildDestroyed()
00699 {
00700 setModified( true );
00701
00702 const KoDocumentChild *child = static_cast<const KoDocumentChild *>( sender() );
00703 d->m_children.removeRef( child );
00704 }
00705
00706 const Q3PtrList<KoDocumentChild>& KoDocument::children() const
00707 {
00708 return d->m_children;
00709 }
00710
00711 KParts::Part *KoDocument::hitTest( QWidget *widget, const QPoint &globalPos )
00712 {
00713 foreach ( KoView* view, d->m_views )
00714 if ( static_cast<QWidget *>(view) == widget )
00715 {
00716 QPoint canvasPos( view->canvas()->mapFromGlobal( globalPos ) );
00717 canvasPos.rx() += view->canvasXOffset();
00718 canvasPos.ry() += view->canvasYOffset();
00719
00720 KParts::Part *part = view->hitTest( canvasPos );
00721 if ( part )
00722 return part;
00723 }
00724
00725 return 0L;
00726 }
00727
00728 KoDocument* KoDocument::hitTest( const QPoint &pos, KoView* view, const QMatrix &matrix )
00729 {
00730
00731 Q3PtrListIterator<KoDocumentChild> it( d->m_children );
00732 for (; it.current(); ++it )
00733 {
00734 KoDocument *doc = it.current()->hitTest( pos, view, matrix );
00735 if ( doc )
00736 return doc;
00737 }
00738
00739
00740 return this;
00741 }
00742
00743 KoDocumentChild *KoDocument::child( KoDocument *doc )
00744 {
00745 Q3PtrListIterator<KoDocumentChild> it( d->m_children );
00746 for (; it.current(); ++it )
00747 if ( it.current()->document() == doc )
00748 return it.current();
00749
00750 return 0L;
00751 }
00752
00753 KoDocumentInfo *KoDocument::documentInfo() const
00754 {
00755 return d->m_docInfo;
00756 }
00757
00758 void KoDocument::setViewBuildDocument( KoView *view, const QDomDocument &doc )
00759 {
00760 int viewIdx = d->m_views.indexOf( view );
00761 if ( viewIdx == -1 )
00762 return;
00763
00764 if ( d->m_viewBuildDocuments.count() == viewIdx )
00765 d->m_viewBuildDocuments.append( doc );
00766 else if ( d->m_viewBuildDocuments.count() > viewIdx )
00767 d->m_viewBuildDocuments[ viewIdx ] = doc;
00768 }
00769
00770 QDomDocument KoDocument::viewBuildDocument( KoView *view )
00771 {
00772 QDomDocument res;
00773
00774 int viewIdx = d->m_views.indexOf( view );
00775 if ( viewIdx == -1 )
00776 return res;
00777
00778 if ( viewIdx >= d->m_viewBuildDocuments.count() )
00779 return res;
00780
00781 res = d->m_viewBuildDocuments[ viewIdx ];
00782
00783
00784 d->m_viewBuildDocuments[ viewIdx ] = QDomDocument();
00785
00786 return res;
00787 }
00788
00789 void KoDocument::paintEverything( QPainter &painter, const QRect &rect, bool transparent, KoView *view, double zoomX, double zoomY )
00790 {
00791 paintContent( painter, rect, transparent, zoomX, zoomY );
00792 paintChildren( painter, rect, view, zoomX, zoomY );
00793 }
00794
00795 void KoDocument::paintChildren( QPainter &painter, const QRect &, KoView *view, double zoomX, double zoomY )
00796 {
00797 Q3PtrListIterator<KoDocumentChild> it( d->m_children );
00798 for (; it.current(); ++it )
00799 {
00800
00801 painter.save();
00802 paintChild( it.current(), painter, view, zoomX, zoomY );
00803 painter.restore();
00804 }
00805 }
00806
00807 void KoDocument::paintChild( KoDocumentChild *child, QPainter &painter, KoView *view, double zoomX, double zoomY )
00808 {
00809 if ( child->isDeleted() )
00810 return;
00811
00812
00813
00814 child->transform( painter );
00815 child->document()->paintEverything( painter, child->contentRect(), child->isTransparent(), view, zoomX, zoomY );
00816
00817 if ( view && view->partManager() )
00818 {
00819
00820 KParts::PartManager *manager = view->partManager();
00821
00822 painter.scale( 1.0 / child->xScaling(), 1.0 / child->yScaling() );
00823
00824 int w = int( (double)child->contentRect().width() * child->xScaling() );
00825 int h = int( (double)child->contentRect().height() * child->yScaling() );
00826 if ( ( manager->selectedPart() == (KParts::Part *)child->document() &&
00827 manager->selectedWidget() == (QWidget *)view ) ||
00828 ( manager->activePart() == (KParts::Part *)child->document() &&
00829 manager->activeWidget() == (QWidget *)view ) )
00830 {
00831
00832 painter.setClipping( false );
00833
00834 painter.setPen( Qt::black );
00835 painter.fillRect( -5, -5, w + 10, 5, Qt::white );
00836 painter.fillRect( -5, h, w + 10, 5, Qt::white );
00837 painter.fillRect( -5, -5, 5, h + 10, Qt::white );
00838 painter.fillRect( w, -5, 5, h + 10, Qt::white );
00839 painter.fillRect( -5, -5, w + 10, 5, Qt::BDiagPattern );
00840 painter.fillRect( -5, h, w + 10, 5, Qt::BDiagPattern );
00841 painter.fillRect( -5, -5, 5, h + 10, Qt::BDiagPattern );
00842 painter.fillRect( w, -5, 5, h + 10, Qt::BDiagPattern );
00843
00844 if ( manager->selectedPart() == (KParts::Part *)child->document() &&
00845 manager->selectedWidget() == (QWidget *)view )
00846 {
00847 QColor color;
00848 if ( view->koDocument() == this )
00849 color = Qt::black;
00850 else
00851 color = Qt::gray;
00852 painter.fillRect( -5, -5, 5, 5, color );
00853 painter.fillRect( -5, h, 5, 5, color );
00854 painter.fillRect( w, h, 5, 5, color );
00855 painter.fillRect( w, -5, 5, 5, color );
00856 painter.fillRect( w / 2 - 3, -5, 5, 5, color );
00857 painter.fillRect( w / 2 - 3, h, 5, 5, color );
00858 painter.fillRect( -5, h / 2 - 3, 5, 5, color );
00859 painter.fillRect( w, h / 2 - 3, 5, 5, color );
00860 }
00861
00862 painter.setClipping( true );
00863 }
00864 }
00865 }
00866
00867 bool KoDocument::isModified() const
00868 {
00869 if ( KParts::ReadWritePart::isModified() )
00870 {
00871
00872 return true;
00873 }
00874
00875 Q3PtrListIterator<KoDocumentChild> it = children();
00876 for (; it.current(); ++it )
00877 {
00878 KoDocument *doc = it.current()->document();
00879 if ( doc && !it.current()->isStoredExtern() && !it.current()->isDeleted() && doc->isModified() )
00880 return true;
00881 }
00882 return false;
00883 }
00884
00885 bool KoDocument::saveChildren( KoStore* _store )
00886 {
00887
00888 int i = 0;
00889 Q3PtrListIterator<KoDocumentChild> it( children() );
00890 for( ; it.current(); ++it ) {
00891 KoDocument* childDoc = it.current()->document();
00892 if (childDoc && !it.current()->isDeleted())
00893 {
00894 if ( !childDoc->isStoredExtern() )
00895 {
00896
00897 if ( !childDoc->saveToStore( _store, QString::number( i++ ) ) )
00898 return false;
00899
00900 if (!isExporting ())
00901 childDoc->setModified( false );
00902 }
00903
00904 }
00905 }
00906 return true;
00907 }
00908
00909 bool KoDocument::saveChildrenOasis( KoStore* store, KoXmlWriter* manifestWriter )
00910 {
00911
00912 Q3PtrListIterator<KoDocumentChild> it( children() );
00913 for( ; it.current(); ++it ) {
00914 KoDocument* childDoc = it.current()->document();
00915 if ( childDoc && !it.current()->isDeleted() )
00916 {
00917 if ( !it.current()->saveOasis( store, manifestWriter ) )
00918 return false;
00919 if ( !childDoc->isStoredExtern() && !isExporting () )
00920 childDoc->setModified( false );
00921 }
00922 }
00923 return true;
00924 }
00925
00926 bool KoDocument::saveExternalChildren()
00927 {
00928 if ( d->m_doNotSaveExtDoc )
00929 {
00930
00931 d->m_doNotSaveExtDoc = false;
00932 return true;
00933 }
00934
00935
00936 KoDocumentChild *ch;
00937 Q3PtrListIterator<KoDocumentChild> it = children();
00938 for (; (ch = it.current()); ++it )
00939 {
00940 if ( !ch->isDeleted() )
00941 {
00942 KoDocument* doc = ch->document();
00943 if ( doc && doc->isStoredExtern() && doc->isModified() )
00944 {
00945 kDebug(30003)<<" save external doc='"<<url().url()<<"'"<<endl;
00946 doc->setDoNotSaveExtDoc();
00947 if ( !doc->save() )
00948 return false;
00949 }
00950
00951
00952 if ( doc && !doc->saveExternalChildren() )
00953 return false;
00954 }
00955 }
00956 return true;
00957 }
00958
00959 bool KoDocument::saveNativeFormat( const QString & file )
00960 {
00961 d->lastErrorMessage.clear();
00962
00963
00964 KoStore::Backend backend = KoStore::Auto;
00965 #if 0
00966 if ( d->m_specialOutputFlag == SaveAsKOffice1dot1 )
00967 {
00968 kDebug(30003) << "Saving as KOffice-1.1 format, using a tar.gz" << endl;
00969 backend = KoStore::Tar;
00971 }
00972 else
00973 #endif
00974 if ( d->m_specialOutputFlag == SaveAsDirectoryStore )
00975 {
00976 backend = KoStore::Directory;
00977 kDebug(30003) << "Saving as uncompressed XML, using directory store." << endl;
00978 }
00979 else if ( d->m_specialOutputFlag == SaveAsFlatXML )
00980 {
00981 kDebug(30003) << "Saving as a flat XML file." << endl;
00982 QFile f( file );
00983 if ( f.open( QIODevice::WriteOnly | QIODevice::Text ) )
00984 {
00985 bool success = saveToStream( &f );
00986 f.close();
00987 return success;
00988 }
00989 else
00990 return false;
00991 }
00992
00993 kDebug(30003) << "KoDocument::saveNativeFormat nativeFormatMimeType=" << nativeFormatMimeType() << endl;
00994
00995
00996 QByteArray mimeType = d->outputMimeType;
00997 QByteArray nativeOasisMime = nativeOasisMimeType();
00998 bool oasis = !mimeType.isEmpty() && ( mimeType == nativeOasisMime || mimeType == nativeOasisMime + "-template" );
00999
01000
01001 KoStore* store = KoStore::createStore( file, KoStore::Write, mimeType, backend );
01002 if ( store->bad() )
01003 {
01004 d->lastErrorMessage = i18n( "Could not create the file for saving" );
01005 delete store;
01006 return false;
01007 }
01008
01009 if ( oasis )
01010 {
01011 kDebug(30003) << "Saving to OASIS format" << endl;
01012
01013 store->disallowNameExpansion();
01014 KoOasisStore oasisStore( store );
01015 KoXmlWriter* manifestWriter = oasisStore.manifestWriter( mimeType );
01016
01017 if ( !saveOasis( store, manifestWriter ) )
01018 {
01019 kDebug(30003) << "saveOasis failed" << endl;
01020 delete store;
01021 return false;
01022 }
01023
01024
01025 if ( !saveChildrenOasis( store, manifestWriter ) )
01026 {
01027 kDebug(30003) << "saveChildrenOasis failed" << endl;
01028 delete store;
01029 return false;
01030 }
01031
01032 if ( store->open( "meta.xml" ) )
01033 {
01034 if ( !d->m_docInfo->saveOasis( store ) || !store->close() ) {
01035 delete store;
01036 return false;
01037 }
01038 manifestWriter->addManifestEntry( "meta.xml", "text/xml" );
01039 }
01040 else
01041 {
01042 d->lastErrorMessage = i18n( "Not able to write '%1'. Partition full?", QString("meta.xml") );
01043 delete store;
01044 return false;
01045 }
01046
01047 if ( store->open( "Thumbnails/thumbnail.png" ) )
01048 {
01049 if ( !saveOasisPreview( store, manifestWriter ) || !store->close() ) {
01050 d->lastErrorMessage = i18n( "Error while trying to write '%1'. Partition full?", QString("Thumbnails/thumbnail.png") );
01051 delete store;
01052 return false;
01053 }
01054
01055 }
01056 else
01057 {
01058 d->lastErrorMessage = i18n( "Not able to write '%1'. Partition full?", QString("Thumbnails/thumbnail.png") );
01059 delete store;
01060 return false;
01061 }
01062
01063 if ( !d->m_versionInfo.isEmpty() )
01064 {
01065 if ( store->open( "VersionList.xml" ) )
01066 {
01067 KoStoreDevice dev( store );
01068 KoXmlWriter* xmlWriter = KoDocument::createOasisXmlWriter( &dev,
01069 "VL:version-list" );
01070 for (int i = 0; i < d->m_versionInfo.size(); ++i)
01071 {
01072 KoVersionInfo *version = &d->m_versionInfo[i];
01073 xmlWriter->startElement( "VL:version-entry" );
01074 xmlWriter->addAttribute( "VL:title", version->title );
01075 xmlWriter->addAttribute( "VL:comment", version->comment );
01076 xmlWriter->addAttribute( "VL:creator", version->saved_by );
01077 xmlWriter->addAttribute( "dc:date-time", version->date.toString(Qt::ISODate) );
01078 xmlWriter->endElement();
01079 }
01080 xmlWriter->endElement();
01081 xmlWriter->endDocument();
01082 delete xmlWriter;
01083 store->close();
01084 manifestWriter->addManifestEntry( "VersionList.xml", "text/xml" );
01085
01086 for (int i = 0; i < d->m_versionInfo.size(); ++i)
01087 {
01088 KoVersionInfo *version = &d->m_versionInfo[i];
01089 store->addDataToFile( version->data, "Versions/" + version->title );
01090 }
01091 }
01092 else
01093 {
01094 d->lastErrorMessage = i18n( "Not able to write '%1'. Partition full?", QString("VersionList.xml") );
01095 delete store;
01096 return false;
01097 }
01098 }
01099
01100
01101 if ( !oasisStore.closeManifestWriter() )
01102 {
01103 d->lastErrorMessage = i18n( "Error while trying to write '%1'. Partition full?", QString("META-INF/manifest.xml") );
01104 delete store;
01105 return false;
01106 }
01107
01108 delete store;
01109 }
01110 else
01111 {
01112
01113 if ( !saveChildren( store ) && !oasis )
01114 {
01115 if ( d->lastErrorMessage.isEmpty() )
01116 d->lastErrorMessage = i18n( "Error while saving embedded documents" );
01117 delete store;
01118 return false;
01119 }
01120
01121 kDebug(30003) << "Saving root" << endl;
01122 if ( store->open( "root" ) )
01123 {
01124 KoStoreDevice dev( store );
01125 if ( !saveToStream( &dev ) || !store->close() )
01126 {
01127 kDebug(30003) << "saveToStream failed" << endl;
01128 delete store;
01129 return false;
01130 }
01131 }
01132 else
01133 {
01134 d->lastErrorMessage = i18n( "Not able to write '%1'. Partition full?", QString( "maindoc.xml") );
01135 delete store;
01136 return false;
01137 }
01138 if ( store->open( "documentinfo.xml" ) )
01139 {
01140 QDomDocument doc = d->m_docInfo->save();
01141 KoStoreDevice dev( store );
01142
01143 QByteArray s = doc.toByteArray();
01144 (void)dev.write( s.data(), s.size() );
01145 (void)store->close();
01146 }
01147
01148 if ( store->open( "preview.png" ) )
01149 {
01150
01151 savePreview( store );
01152 (void)store->close();
01153 }
01154
01155 if ( !completeSaving( store ) )
01156 {
01157 delete store;
01158 return false;
01159 }
01160 kDebug(30003) << "Saving done of url: " << url().url() << endl;
01161 delete store;
01162 }
01163 if ( !saveExternalChildren() )
01164 {
01165 return false;
01166 }
01167 return true;
01168 }
01169
01170 bool KoDocument::saveToStream( QIODevice * dev )
01171 {
01172 QDomDocument doc = saveXML();
01173
01174 QByteArray s = doc.toByteArray();
01175 dev->open( QIODevice::WriteOnly );
01176 int nwritten = dev->write( s.data(), s.size() );
01177 if ( nwritten != (int)s.size() )
01178 kWarning(30003) << "KoDocument::saveToStream wrote " << nwritten << " - expected " << s.size() << endl;
01179 return nwritten == (int)s.size();
01180 }
01181
01182
01183 bool KoDocument::saveToStore( KoStore* _store, const QString & _path )
01184 {
01185 kDebug(30003) << "Saving document to store " << _path << endl;
01186
01187
01188 if ( _path.startsWith( STORE_PROTOCOL ) )
01189 m_url = KUrl( _path );
01190 else
01191 m_url = KUrl( INTERNAL_PREFIX + _path );
01192
01193
01194 _store->pushDirectory();
01195 _store->enterDirectory( _path );
01196
01197
01198 if ( !saveChildren( _store ) )
01199 return false;
01200
01201
01202 if ( _store->open( "root" ) )
01203 {
01204 KoStoreDevice dev( _store );
01205 if ( !saveToStream( &dev ) )
01206 {
01207 _store->close();
01208 return false;
01209 }
01210 if ( !_store->close() )
01211 return false;
01212 }
01213
01214 if ( !completeSaving( _store ) )
01215 return false;
01216
01217
01218 _store->popDirectory();
01219
01220 kDebug(30003) << "Saved document to store" << endl;
01221
01222 return true;
01223 }
01224
01225 bool KoDocument::saveOasisPreview( KoStore* store, KoXmlWriter* manifestWriter )
01226 {
01227 const QPixmap pix = generatePreview( QSize( 128, 128 ) );
01228 QImage preview ( pix.toImage().convertToFormat( QImage::Format_ARGB32, Qt::ColorOnly ) );
01229
01230
01231 KoStoreDevice io ( store );
01232 if ( !io.open( QIODevice::WriteOnly ) )
01233 return false;
01234 if ( ! preview.save( &io, "PNG", 0 ) )
01235 return false;
01236 io.close();
01237 manifestWriter->addManifestEntry( "Thumbnails/", "" );
01238 manifestWriter->addManifestEntry( "Thumbnails/thumbnail.png", "" );
01239 return true;
01240 }
01241
01242 bool KoDocument::savePreview( KoStore* store )
01243 {
01244 QPixmap pix = generatePreview(QSize(256, 256));
01245
01246 const QImage preview( pix.toImage().convertToFormat( QImage::Format_Indexed8, Qt::AvoidDither | Qt::DiffuseDither ) );
01247 KoStoreDevice io ( store );
01248 if ( !io.open( QIODevice::WriteOnly ) )
01249 return false;
01250 if ( ! preview.save( &io, "PNG" ) )
01251 return false;
01252 io.close();
01253 return true;
01254 }
01255
01256 QPixmap KoDocument::generatePreview( const QSize& size )
01257 {
01258 double docWidth, docHeight;
01259 int pixmapSize = qMax(size.width(), size.height());
01260
01261 if (m_pageLayout.ptWidth > 1.0) {
01262 docWidth = m_pageLayout.ptWidth / 72 * KoGlobal::dpiX();
01263 docHeight = m_pageLayout.ptHeight / 72 * KoGlobal::dpiY();
01264
01265 } else {
01266
01267 docWidth = 500.0;
01268 docHeight = 500.0;
01269 }
01270
01271 double ratio = docWidth / docHeight;
01272
01273 int previewWidth, previewHeight;
01274 if (ratio > 1.0)
01275 {
01276 previewWidth = (int) pixmapSize;
01277 previewHeight = (int) (pixmapSize / ratio);
01278 }
01279 else
01280 {
01281 previewWidth = (int) (pixmapSize * ratio);
01282 previewHeight = (int) pixmapSize;
01283 }
01284
01285 QPixmap pix( (int)docWidth, (int)docHeight );
01286
01287 pix.fill( QColor( 245, 245, 245 ) );
01288
01289 QRect rc(0, 0, pix.width(), pix.height());
01290
01291 QPainter p;
01292 p.begin(&pix);
01293 paintEverything(p, rc, false);
01294 p.end();
01295
01296 return pix.scaled(QSize(previewWidth, previewHeight), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
01297 }
01298
01299 QString KoDocument::autoSaveFile( const QString & path ) const
01300 {
01301
01302 KMimeType::Ptr mime = KMimeType::mimeType( nativeFormatMimeType() );
01303 Q_ASSERT(mime);
01304 QString extension = mime->property( "X-KDE-NativeExtension" ).toString();
01305 if ( path.isEmpty() )
01306 {
01307
01308
01309
01310 QString ret = QDir::homePath() + "/." + QString::fromLatin1(instance()->instanceName()) + ".autosave" + extension;
01311 return ret;
01312 }
01313 else
01314 {
01315 KUrl url = KUrl::fromPath( path );
01316 Q_ASSERT( url.isLocalFile() );
01317 QString dir = url.directory(KUrl::AppendTrailingSlash);
01318 QString filename = url.fileName();
01319 return dir + '.' + filename + ".autosave" + extension;
01320 }
01321 }
01322
01323 bool KoDocument::checkAutoSaveFile()
01324 {
01325 QString asf = autoSaveFile( QString::null );
01326
01327 if ( QFile::exists( asf ) )
01328 {
01329 QDateTime date = QFileInfo(asf).lastModified();
01330 QString dateStr = date.toString(Qt::LocalDate);
01331 int res = KMessageBox::warningYesNoCancel(
01332 0, i18n( "An autosaved file for an unnamed document exists in %1.\nThis file is dated %2\nDo you want to open it?",
01333 asf, dateStr ) );
01334 switch(res) {
01335 case KMessageBox::Yes : {
01336 KUrl url;
01337 url.setPath( asf );
01338 bool ret = openURL( url );
01339 if ( ret )
01340 resetURL();
01341 return ret;
01342 }
01343 case KMessageBox::No :
01344 QFile::remove( asf );
01345 return false;
01346 default:
01347 return false;
01348 }
01349 }
01350 return false;
01351 }
01352
01353 bool KoDocument::import( const KUrl & _url )
01354 {
01355 bool ret;
01356
01357 kDebug (30003) << "KoDocument::import url=" << _url.url() << endl;
01358 d->m_isImporting = true;
01359
01360
01361 ret = openURL (_url);
01362
01363
01364
01365 if (ret)
01366 {
01367 kDebug (30003) << "KoDocument::import success, resetting url" << endl;
01368 resetURL ();
01369 setTitleModified ();
01370 }
01371
01372 d->m_isImporting = false;
01373
01374 return ret;
01375 }
01376
01377 bool KoDocument::openURL( const KUrl & _url )
01378 {
01379 kDebug(30003) << "KoDocument::openURL url=" << _url.url() << endl;
01380 d->lastErrorMessage.clear();
01381
01382
01383 if ( !_url.isValid() )
01384 {
01385 d->lastErrorMessage = i18n( "Malformed URL\n%1",_url.url() );
01386 return false;
01387 }
01388 if ( !closeUrl() )
01389 return false;
01390
01391 KUrl url( _url );
01392 bool autosaveOpened = false;
01393 d->m_bLoading = true;
01394 if ( url.isLocalFile() && d->m_shouldCheckAutoSaveFile )
01395 {
01396 QString file = url.path();
01397 QString asf = autoSaveFile( file );
01398 if ( QFile::exists( asf ) )
01399 {
01400
01401
01402 int res = KMessageBox::warningYesNoCancel( 0,
01403 i18n( "An autosaved file exists for this document.\nDo you want to open it instead?" ));
01404 switch(res) {
01405 case KMessageBox::Yes :
01406 url.setPath( asf );
01407 autosaveOpened = true;
01408 break;
01409 case KMessageBox::No :
01410 QFile::remove( asf );
01411 break;
01412 default:
01413 d->m_bLoading = false;
01414 return false;
01415 }
01416 }
01417 }
01418
01419 bool ret = KParts::ReadWritePart::openUrl( url );
01420
01421 if ( autosaveOpened )
01422 resetURL();
01423 else
01424 {
01425
01426
01427
01428
01429 Q3PtrListIterator<KoMainWindow> it( d->m_shells );
01430 for (; it.current(); ++it )
01431 it.current()->addRecentURL( _url );
01432 }
01433 return ret;
01434 }
01435
01436 bool KoDocument::openFile()
01437 {
01438
01439 if ( !QFile::exists(m_file) )
01440 {
01441 QApplication::restoreOverrideCursor();
01442 if ( d->m_autoErrorHandlingEnabled )
01443
01444 KMessageBox::error(0L, i18n("The file %1 does not exist.", m_file) );
01445 d->m_bLoading = false;
01446 return false;
01447 }
01448
01449 QApplication::setOverrideCursor( Qt::WaitCursor );
01450
01451 d->m_specialOutputFlag = 0;
01452 QByteArray _native_format = nativeFormatMimeType();
01453
01454 KUrl u;
01455 u.setPath( m_file );
01456 QString typeName = KMimeType::findByUrl( u, 0, true )->name();
01457
01458
01459 if ( typeName == "application/x-trash" )
01460 {
01461 QString path = u.path();
01462 KMimeType::Ptr mime = KMimeType::mimeType( typeName );
01463 QStringList patterns = mime ? mime->patterns() : QStringList();
01464
01465 for( QStringList::Iterator it = patterns.begin(); it != patterns.end(); ++it ) {
01466 QString ext = *it;
01467 if ( !ext.isEmpty() && ext[0] == '*' )
01468 {
01469 ext.remove(0, 1);
01470 if ( path.endsWith( ext ) ) {
01471 path.truncate( path.length() - ext.length() );
01472 break;
01473 }
01474 }
01475 }
01476 typeName = KMimeType::findByPath( path, 0, true )->name();
01477 }
01478
01479
01480 if ( u.fileName() == "maindoc.xml" || typeName == "inode/directory" )
01481 {
01482 typeName = _native_format;
01483 d->m_specialOutputFlag = SaveAsDirectoryStore;
01484 kDebug(30003) << "KoDocument::openFile loading maindoc.xml, using directory store for " << m_file << endl;
01485 }
01486 kDebug(30003) << "KoDocument::openFile " << m_file << " type:" << typeName << endl;
01487
01488 QString importedFile = m_file;
01489
01490 if ( !isNativeFormat( typeName.toLatin1() ) ) {
01491 if ( !d->filterManager )
01492 d->filterManager = new KoFilterManager( this );
01493 KoFilter::ConversionStatus status;
01494 importedFile = d->filterManager->import( m_file, status );
01495 if ( status != KoFilter::OK )
01496 {
01497 QApplication::restoreOverrideCursor();
01498
01499 QString msg;
01500 switch( status )
01501 {
01502 case KoFilter::OK: break;
01503
01504 case KoFilter::CreationError:
01505 msg = i18n( "Creation error" ); break;
01506
01507 case KoFilter::FileNotFound:
01508 msg = i18n( "File not found" ); break;
01509
01510 case KoFilter::StorageCreationError:
01511 msg = i18n( "Cannot create storage" ); break;
01512
01513 case KoFilter::BadMimeType:
01514 msg = i18n( "Bad MIME type" ); break;
01515
01516 case KoFilter::EmbeddedDocError:
01517 msg = i18n( "Error in embedded document" ); break;
01518
01519 case KoFilter::WrongFormat:
01520 msg = i18n( "Format not recognized" ); break;
01521
01522 case KoFilter::NotImplemented:
01523 msg = i18n( "Not implemented" ); break;
01524
01525 case KoFilter::ParsingError:
01526 msg = i18n( "Parsing error" ); break;
01527
01528 case KoFilter::PasswordProtected:
01529 msg = i18n( "Document is password protected" ); break;
01530
01531 case KoFilter::InternalError:
01532 case KoFilter::UnexpectedEOF:
01533 case KoFilter::UnexpectedOpcode:
01534 case KoFilter::StupidError:
01535 case KoFilter::UsageError:
01536 msg = i18n( "Internal error" ); break;
01537
01538 case KoFilter::OutOfMemory:
01539 msg = i18n( "Out of memory" ); break;
01540
01541 case KoFilter::UserCancelled:
01542 case KoFilter::BadConversionGraph:
01543
01544 break;
01545
01546 default: msg = i18n( "Unknown error" ); break;
01547 }
01548
01549 if( d->m_autoErrorHandlingEnabled && !msg.isEmpty())
01550 {
01551 QString docUrl = url().pathOrUrl();
01552 QString errorMsg( i18n( "Could not open\n%2.\nReason: %1", msg, docUrl ) );
01553 KMessageBox::error( 0, errorMsg );
01554 }
01555
01556 d->m_bLoading = false;
01557 return false;
01558 }
01559 kDebug(30003) << "KoDocument::openFile - importedFile '" << importedFile
01560 << "', status: " << static_cast<int>( status ) << endl;
01561 }
01562
01563 QApplication::restoreOverrideCursor();
01564
01565 bool ok = true;
01566
01567 if (!importedFile.isEmpty())
01568 {
01569
01570 if ( !loadNativeFormat( importedFile ) )
01571 {
01572 ok = false;
01573 if ( d->m_autoErrorHandlingEnabled )
01574 {
01575 showLoadingErrorDialog();
01576 }
01577 }
01578 }
01579
01580 if ( importedFile != m_file )
01581 {
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593 #if 0
01594 if ( isReadWrite() )
01595 resetURL();
01596 #endif
01597
01598
01599 if(!importedFile.isEmpty()) {
01600 QFile::remove( importedFile );
01601 }
01602 }
01603
01604 if ( ok && d->m_bSingleViewMode )
01605 {
01606
01607 KXMLGUIFactory* guiFactory = factory();
01608 if( guiFactory )
01609 guiFactory->removeClient( this );
01610
01611 if ( !d->m_views.isEmpty() )
01612 {
01613
01614 KoView* v = d->m_views.first();
01615 if( guiFactory )
01616 guiFactory->removeClient( v );
01617 removeView( v );
01618 delete v;
01619 Q_ASSERT( d->m_views.isEmpty() );
01620 }
01621
01622 KoView *view = createView( d->m_wrapperWidget );
01623 d->m_wrapperWidget->setKoView( view );
01624 view->show();
01625
01626
01627
01628 if ( guiFactory )
01629 guiFactory->addClient( this );
01630 }
01631
01632 if ( ok )
01633 {
01634 setMimeTypeAfterLoading( typeName );
01635 }
01636 d->m_bLoading = false;
01637 return ok;
01638 }
01639
01640
01641 void KoDocument::setMimeTypeAfterLoading( const QString& mimeType )
01642 {
01643 d->mimeType = mimeType.toLatin1();
01644
01645 d->outputMimeType = d->mimeType;
01646
01647 const bool needConfirm = !isNativeFormat( d->mimeType );
01648 setConfirmNonNativeSave( false, needConfirm );
01649 setConfirmNonNativeSave( true, needConfirm );
01650 }
01651
01652
01653 bool KoDocument::oldLoadAndParse(KoStore* store, const QString& filename, KoXmlDocument& doc)
01654 {
01655
01656
01657 if (!store->open(filename))
01658 {
01659 kWarning(30003) << "Entry " << filename << " not found!" << endl;
01660 d->lastErrorMessage = i18n( "Could not find %1",filename );
01661 return false;
01662 }
01663
01664 QString errorMsg;
01665 int errorLine, errorColumn;
01666 bool ok = doc.setContent( store->device(), &errorMsg, &errorLine, &errorColumn );
01667 if ( !ok )
01668 {
01669 kError(30003) << "Parsing error in " << filename << "! Aborting!" << endl
01670 << " In line: " << errorLine << ", column: " << errorColumn << endl
01671 << " Error message: " << errorMsg << endl;
01672 d->lastErrorMessage = i18n( "Parsing error in %1 at line %2, column %3\nError message: %4"
01673 ,filename ,errorLine, errorColumn ,
01674 QCoreApplication::translate("QXml", errorMsg.toUtf8(), 0,
01675 QCoreApplication::UnicodeUTF8));
01676 store->close();
01677 return false;
01678 }
01679 kDebug(30003) << "File " << filename << " loaded and parsed" << endl;
01680 return true;
01681 }
01682
01683 bool KoDocument::loadNativeFormat( const QString & file )
01684 {
01685 QFileInfo fileInfo( file );
01686 if ( !fileInfo.exists() )
01687 {
01688 d->lastErrorMessage = i18n("The file %1 does not exist.", file);
01689 return false;
01690 }
01691 if ( !fileInfo.isFile() )
01692 {
01693 d->lastErrorMessage = i18n( "%1 is not a file." , file);
01694 return false;
01695 }
01696
01697 QApplication::setOverrideCursor( Qt::WaitCursor );
01698
01699 kDebug(30003) << "KoDocument::loadNativeFormat( " << file << " )" << endl;
01700
01701 QFile in;
01702 bool isRawXML = false;
01703 if ( d->m_specialOutputFlag != SaveAsDirectoryStore )
01704 {
01705 in.setFileName(file);
01706 if ( !in.open( QIODevice::ReadOnly ) )
01707 {
01708 QApplication::restoreOverrideCursor();
01709 d->lastErrorMessage = i18n( "Could not open the file for reading (check read permissions)." );
01710 return false;
01711 }
01712
01713 char buf[6];
01714 buf[5]=0;
01715 int pos=0;
01716 do {
01717 if ( in.read( buf+pos , 1 ) < 1 )
01718 {
01719 QApplication::restoreOverrideCursor();
01720 in.close();
01721 d->lastErrorMessage = i18n( "Could not read the beginning of the file." );
01722 return false;
01723 }
01724
01725 if(QChar( buf[pos] ).isSpace())
01726 continue;
01727 pos++;
01728 } while ( pos < 5 );
01729 isRawXML = (strncasecmp( buf, "<?xml", 5 ) == 0);
01730 if(! isRawXML)
01731
01732 isRawXML = (strncasecmp( buf, "<math", 5 ) == 0);
01733
01734 }
01735
01736 if ( isRawXML )
01737 {
01738 in.seek( 0 );
01739 QString errorMsg;
01740 int errorLine;
01741 int errorColumn;
01742 KoXmlDocument doc;
01743 bool res;
01744 if ( doc.setContent( &in, &errorMsg, &errorLine, &errorColumn ) )
01745 {
01746 res = loadXML( &in, doc );
01747 if ( res )
01748 res = completeLoading( 0L );
01749 }
01750 else
01751 {
01752 kError (30003) << "Parsing Error! Aborting! (in KoDocument::loadNativeFormat (QFile))" << endl
01753 << " Line: " << errorLine << " Column: " << errorColumn << endl
01754 << " Message: " << errorMsg << endl;
01755 d->lastErrorMessage = i18n( "parsing error in the main document at line %1, column %2\nError message: %3", errorLine, errorColumn, i18n ( errorMsg.toUtf8() ) );
01756 res=false;
01757 }
01758
01759 QApplication::restoreOverrideCursor();
01760 in.close();
01761 m_bEmpty = false;
01762 return res;
01763 } else
01764 {
01765 in.close();
01766
01767 return loadNativeFormatFromStore( file );
01768 }
01769 }
01770
01771 bool KoDocument::loadNativeFormatFromStore( const QString& file )
01772 {
01773 KoStore::Backend backend = (d->m_specialOutputFlag == SaveAsDirectoryStore) ? KoStore::Directory : KoStore::Auto;
01774 KoStore * store = KoStore::createStore( file, KoStore::Read, "", backend );
01775
01776 if ( store->bad() )
01777 {
01778 d->lastErrorMessage = i18n( "Not a valid KOffice file: %1", file );
01779 delete store;
01780 QApplication::restoreOverrideCursor();
01781 return false;
01782 }
01783
01784 return loadNativeFormatFromStoreInternal( store );
01785 }
01786
01787 bool KoDocument::loadNativeFormatFromStore( QByteArray &data )
01788 {
01789 KoStore::Backend backend = (d->m_specialOutputFlag == SaveAsDirectoryStore) ? KoStore::Directory : KoStore::Auto;
01790 QBuffer buffer( &data );
01791 KoStore * store = KoStore::createStore( &buffer, KoStore::Read, "", backend );
01792
01793 if ( store->bad() )
01794 return false;
01795
01796 return loadNativeFormatFromStoreInternal( store );
01797 }
01798
01799 bool KoDocument::loadNativeFormatFromStoreInternal( KoStore * store )
01800 {
01801 bool oasis = true;
01802
01803 if ( store->hasFile( "content.xml" ) )
01804 {
01805 store->disallowNameExpansion();
01806
01807 KoOasisStore oasisStore( store );
01808
01809
01810 if ( !loadOasisFromStore( store ) ) {
01811 delete store;
01812 QApplication::restoreOverrideCursor();
01813 return false;
01814 }
01815
01816 } else if ( store->hasFile( "root" ) )
01817 {
01818 oasis = false;
01819
01820 KoXmlDocument doc;
01821 bool ok = oldLoadAndParse( store, "root", doc );
01822 if ( ok )
01823 ok = loadXML( store->device(), doc );
01824 if ( !ok )
01825 {
01826 delete store;
01827 QApplication::restoreOverrideCursor();
01828 return false;
01829 }
01830 store->close();
01831
01832 if ( !loadChildren( store ) )
01833 {
01834 kError(30003) << "ERROR: Could not load children" << endl;
01835
01836 }
01837
01838 } else
01839 {
01840 kError(30003) << "ERROR: No maindoc.xml" << endl;
01841 d->lastErrorMessage = i18n( "Invalid document: no file 'maindoc.xml'." );
01842 delete store;
01843 QApplication::restoreOverrideCursor();
01844 return false;
01845 }
01846
01847 if ( oasis && store->hasFile( "meta.xml" ) ) {
01848 KoXmlDocument metaDoc;
01849 KoOasisStore oasisStore( store );
01850 if ( oasisStore.loadAndParse( "meta.xml", metaDoc, d->lastErrorMessage ) ) {
01851 d->m_docInfo->loadOasis( metaDoc );
01852 }
01853 }
01854 else if ( !oasis && store->hasFile( "documentinfo.xml" ) )
01855 {
01856 KoXmlDocument doc;
01857 if ( oldLoadAndParse( store, "documentinfo.xml", doc ) ) {
01858 store->close();
01859 d->m_docInfo->load( doc );
01860 }
01861 }
01862 else
01863 {
01864
01865 delete d->m_docInfo;
01866 d->m_docInfo = new KoDocumentInfo( this );
01867 }
01868
01869 if ( oasis && store->hasFile( "VersionList.xml" ) ) {
01870 KMessageBox::information( 0, i18n("This document contains several versions. Go to File->Versions to open an old version."), QString(), "informVersionsAtLoading" );
01871 KoXmlDocument versionInfo;
01872 KoOasisStore oasisStore( store );
01873 if ( oasisStore.loadAndParse( "VersionList.xml", versionInfo, d->lastErrorMessage ) )
01874 {
01875 KoXmlNode list = KoDom::namedItemNS( versionInfo, KoXmlNS::VL, "version-list" );
01876 KoXmlElement e;
01877 forEachElement( e, list )
01878 {
01879 if ( e.localName() == "version-entry" && e.namespaceURI() == KoXmlNS::VL )
01880 {
01881 KoVersionInfo version;
01882 version.comment = e.attribute( "comment");
01883 version.title = e.attribute( "title");
01884 version.saved_by = e.attribute( "creator");
01885 version.date = QDateTime::fromString( e.attribute( "date-time"), Qt::ISODate );
01886 store->extractFile( "Versions/"+version.title, version.data );
01887 d->m_versionInfo.append( version );
01888 }
01889 }
01890 }
01891 }
01892
01893 bool res = completeLoading( store );
01894 delete store;
01895 QApplication::restoreOverrideCursor();
01896 m_bEmpty = false;
01897 return res;
01898 }
01899
01900
01901 bool KoDocument::loadFromStore( KoStore* _store, const QString& url )
01902 {
01903 if ( _store->open( url ) )
01904 {
01905 KoXmlDocument doc;
01906 doc.setContent( _store->device() );
01907 if ( !loadXML( _store->device(), doc ) )
01908 {
01909 _store->close();
01910 return false;
01911 }
01912 _store->close();
01913 } else {
01914 kWarning() << "couldn't open " << url << endl;
01915 }
01916
01917 _store->pushDirectory();
01918
01919 if ( url.startsWith( STORE_PROTOCOL ) ) {
01920 m_url = KUrl( url );
01921 } else {
01922 m_url = KUrl( INTERNAL_PREFIX + url );
01923 _store->enterDirectory( url );
01924 }
01925
01926 if ( !loadChildren( _store ) )
01927 {
01928 kError(30003) << "ERROR: Could not load children" << endl;
01929 #if 0
01930 return false;
01931 #endif
01932 }
01933
01934 bool result = completeLoading( _store );
01935
01936
01937 _store->popDirectory();
01938
01939 return result;
01940 }
01941
01942 bool KoDocument::loadOasisFromStore( KoStore* store )
01943 {
01944 KoOasisStyles oasisStyles;
01945 KoXmlDocument contentDoc;
01946 KoXmlDocument settingsDoc;
01947 KoOasisStore oasisStore( store );
01948 bool ok = oasisStore.loadAndParse( "content.xml", contentDoc, d->lastErrorMessage );
01949 if ( !ok )
01950 return false;
01951
01952 KoXmlDocument stylesDoc;
01953 (void)oasisStore.loadAndParse( "styles.xml", stylesDoc, d->lastErrorMessage );
01954
01955 oasisStyles.createStyleMap( stylesDoc, true );
01956
01957 oasisStyles.createStyleMap( contentDoc, false );
01958
01959
01960
01961
01962
01963
01964
01965
01966 if ( store->hasFile( "settings.xml" ) ) {
01967 (void)oasisStore.loadAndParse( "settings.xml", settingsDoc, d->lastErrorMessage );
01968 }
01969 if ( !loadOasis( contentDoc, oasisStyles, settingsDoc, store ) )
01970 return false;
01971
01972 return true;
01973 }
01974
01975 bool KoDocument::addVersion( const QString& comment )
01976 {
01977 kDebug(30003) << "Saving the new version...." << endl;
01978
01979 KoStore::Backend backend = KoStore::Auto;
01980 if ( d->m_specialOutputFlag != 0 )
01981 return false;
01982
01983 QByteArray mimeType = d->outputMimeType;
01984 QByteArray nativeOasisMime = nativeOasisMimeType();
01985 bool oasis = !mimeType.isEmpty() && ( mimeType == nativeOasisMime || mimeType == nativeOasisMime + "-template" );
01986
01987 if ( !oasis)
01988 return false;
01989
01990
01991
01992 QByteArray data;
01993 QBuffer buffer( &data );
01994 KoStore* store = KoStore::createStore( &buffer, KoStore::Write, mimeType, backend );
01995 if ( store->bad() )
01996 {
01997 delete store;
01998 return false;
01999 }
02000
02001 kDebug(30003) << "Saving to OASIS format" << endl;
02002
02003 store->disallowNameExpansion();
02004 KoOasisStore oasisStore( store );
02005 KoXmlWriter* manifestWriter = oasisStore.manifestWriter( mimeType );
02006
02007 if ( !saveOasis( store, manifestWriter ) )
02008 {
02009 kDebug(30003) << "saveOasis failed" << endl;
02010 delete store;
02011 return false;
02012 }
02013
02014
02015 if ( !saveChildrenOasis( store, manifestWriter ) )
02016 {
02017 kDebug(30003) << "saveChildrenOasis failed" << endl;
02018 delete store;
02019 return false;
02020 }
02021
02022
02023 if ( !oasisStore.closeManifestWriter() )
02024 {
02025 d->lastErrorMessage = i18n( "Error while trying to write '%1'. Partition full?", QString("META-INF/manifest.xml") );
02026 delete store;
02027 return false;
02028 }
02029
02030 delete store;
02031
02032 if ( !saveExternalChildren() )
02033 return false;
02034
02035 KoVersionInfo version;
02036 version.comment = comment;
02037 version.title = "Version" + QString::number( d->m_versionInfo.count()+1);
02038 version.saved_by = documentInfo()->authorInfo("creator");
02039 version.date = QDateTime::currentDateTime();
02040 version.data = data;
02041 d->m_versionInfo.append( version );
02042
02043 save();
02044 return true;
02045 }
02046
02047 bool KoDocument::isInOperation() const
02048 {
02049 return d->m_numOperations > 0;
02050 }
02051
02052 void KoDocument::emitBeginOperation()
02053 {
02054
02055
02056 if (!isInOperation())
02057 emit sigBeginOperation();
02058 d->m_numOperations++;
02059 }
02060
02061 void KoDocument::emitEndOperation()
02062 {
02063 d->m_numOperations--;
02064
02065
02066 if (d->m_numOperations == 0)
02067 emit sigEndOperation();
02068 else if (d->m_numOperations < 0)
02069
02070 d->m_numOperations = 0;
02071 }
02072
02073
02074 bool KoDocument::isStoredExtern() const
02075 {
02076 return !storeInternal() && hasExternURL();
02077 }
02078
02079 void KoDocument::setModified( bool mod )
02080 {
02081 if ( isAutosaving() )
02082 return;
02083
02084
02085
02086
02087 if ( mod && !d->modifiedAfterAutosave ) {
02088
02089 setAutoSave( d->m_autoSaveDelay );
02090 }
02091 d->modifiedAfterAutosave = mod;
02092
02093 if ( mod == isModified() )
02094 return;
02095
02096 KParts::ReadWritePart::setModified( mod );
02097
02098 if ( mod ) {
02099 m_bEmpty = false;
02100 } else {
02101
02102 Q3PtrListIterator<KoDocumentChild> it = children();
02103 for (; it.current(); ++it )
02104 {
02105 KoDocument *doc = it.current()->document();
02106 if ( doc && !it.current()->isStoredExtern() && !it.current()->isDeleted() && doc->isModified() )
02107 doc->setModified( false );
02108 }
02109 }
02110
02111
02112 setTitleModified();
02113 emit modified( mod );
02114 }
02115
02116 void KoDocument::setDoNotSaveExtDoc( bool on )
02117 {
02118 d->m_doNotSaveExtDoc = on;
02119 }
02120
02121 int KoDocument::queryCloseDia()
02122 {
02123
02124
02125 QString name;
02126 if ( documentInfo() )
02127 {
02128 name = documentInfo()->aboutInfo( "title" );
02129 }
02130 if ( name.isEmpty() )
02131 name = url().fileName();
02132
02133 if ( name.isEmpty() )
02134 name = i18n( "Untitled" );
02135
02136 int res = KMessageBox::warningYesNoCancel( 0L,
02137 i18n( "<p>The document <b>'%1'</b> has been modified.</p><p>Do you want to save it?</p>", name ) );
02138
02139 switch(res)
02140 {
02141 case KMessageBox::Yes :
02142 setDoNotSaveExtDoc();
02143 save();
02144 setModified( false );
02145 break;
02146 case KMessageBox::No :
02147 removeAutoSaveFiles();
02148 setModified( false );
02149 break;
02150 default :
02151 return res;
02152 }
02153 return res;
02154 }
02155
02156 int KoDocument::queryCloseExternalChildren()
02157 {
02158
02159 setDoNotSaveExtDoc(false);
02160 Q3PtrListIterator<KoDocumentChild> it( children() );
02161 for (; it.current(); ++it )
02162 {
02163 if ( !it.current()->isDeleted() )
02164 {
02165 KoDocument *doc = it.current()->document();
02166 if ( doc )
02167 {
02168 bool foo = doc->isStoredExtern();
02169 kDebug(36001) << "========== isStoredExtern() returned "
02170 << foo << " ==========" << endl;
02171
02172 if ( foo )
02173 {
02174 {
02175 kDebug(30003)<<k_funcinfo<<" found modified child: "<<doc->url().url()<<" extern="<<doc->isStoredExtern()<<endl;
02176 if ( doc->queryCloseDia() == KMessageBox::Cancel )
02177 return KMessageBox::Cancel;
02178 }
02179 }
02180 if ( doc->queryCloseExternalChildren() == KMessageBox::Cancel )
02181 return KMessageBox::Cancel;
02182 }
02183 }
02184 }
02185 return KMessageBox::Ok;
02186 }
02187
02188 void KoDocument::setTitleModified( const QString caption, bool mod )
02189 {
02190
02191 KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
02192 if ( doc )
02193 {
02194 doc->setTitleModified( caption, mod );
02195 return;
02196 }
02197
02198 Q3PtrListIterator<KoMainWindow> it( d->m_shells );
02199 for (; it.current(); ++it )
02200 {
02201 it.current()->updateCaption();
02202 it.current()->updateReloadFileAction(this);
02203 it.current()->updateVersionsFileAction(this);
02204 }
02205 }
02206
02207 void KoDocument::setTitleModified()
02208 {
02209
02210 KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
02211 QString caption;
02212 if ( (url().isEmpty() || isStoredExtern()) && d->m_current )
02213 {
02214
02215 if ( documentInfo() )
02216 {
02217 caption = documentInfo()->aboutInfo( "title" );
02218 }
02219 if ( caption.isEmpty() )
02220 caption = url().pathOrUrl();
02221
02222
02223 if ( doc )
02224 {
02225 doc->setTitleModified( caption, isModified() );
02226 return;
02227 }
02228 else
02229 {
02230
02231 setTitleModified( caption, isModified() );
02232 return;
02233 }
02234 }
02235 if ( doc )
02236 {
02237
02238 doc->setTitleModified();
02239 }
02240 }
02241
02242 bool KoDocument::loadChildren( KoStore* )
02243 {
02244 return true;
02245 }
02246
02247 bool KoDocument::completeLoading( KoStore* )
02248 {
02249 return true;
02250 }
02251
02252 bool KoDocument::completeSaving( KoStore* )
02253 {
02254 return true;
02255 }
02256
02257 QDomDocument KoDocument::createDomDocument( const QString& tagName, const QString& version ) const
02258 {
02259 return createDomDocument( instance()->instanceName(), tagName, version );
02260 }
02261
02262
02263 QDomDocument KoDocument::createDomDocument( const QString& appName, const QString& tagName, const QString& version )
02264 {
02265 QDomImplementation impl;
02266 QString url = QString("http://www.koffice.org/DTD/%1-%2.dtd").arg(appName).arg(version);
02267 QDomDocumentType dtype = impl.createDocumentType( tagName,
02268 QString("-//KDE//DTD %1 %2//EN").arg(appName).arg(version),
02269 url );
02270
02271 QString namespaceURN = QString("http://www.koffice.org/DTD/%1").arg(appName);
02272 QDomDocument doc = impl.createDocument( namespaceURN, tagName, dtype );
02273 doc.insertBefore( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ), doc.documentElement() );
02274 return doc;
02275 }
02276
02277 KoXmlWriter* KoDocument::createOasisXmlWriter( QIODevice* dev, const char* rootElementName )
02278 {
02279 KoXmlWriter* writer = new KoXmlWriter( dev );
02280 writer->startDocument( rootElementName );
02281 writer->startElement( rootElementName );
02282
02283 if ( qstrcmp( rootElementName, "VL:version-list" ) == 0 ) {
02284 writer->addAttribute( "xmlns:VL", KoXmlNS::VL );
02285 writer->addAttribute( "xmlns:dc", KoXmlNS::dc );
02286 return writer;
02287 }
02288
02289 writer->addAttribute( "xmlns:office", KoXmlNS::office );
02290 writer->addAttribute( "xmlns:meta", KoXmlNS::meta );
02291
02292 if ( qstrcmp( rootElementName, "office:document-meta" ) != 0 ) {
02293 writer->addAttribute( "xmlns:config", KoXmlNS::config );
02294 writer->addAttribute( "xmlns:text", KoXmlNS::text );
02295 writer->addAttribute( "xmlns:table", KoXmlNS::table );
02296 writer->addAttribute( "xmlns:draw", KoXmlNS::draw );
02297 writer->addAttribute( "xmlns:presentation", KoXmlNS::presentation );
02298 writer->addAttribute( "xmlns:dr3d", KoXmlNS::dr3d );
02299 writer->addAttribute( "xmlns:chart", KoXmlNS::chart );
02300 writer->addAttribute( "xmlns:form", KoXmlNS::form );
02301 writer->addAttribute( "xmlns:script", KoXmlNS::script );
02302 writer->addAttribute( "xmlns:style", KoXmlNS::style );
02303 writer->addAttribute( "xmlns:number", KoXmlNS::number );
02304 writer->addAttribute( "xmlns:math", KoXmlNS::math );
02305 writer->addAttribute( "xmlns:svg", KoXmlNS::svg );
02306 writer->addAttribute( "xmlns:fo", KoXmlNS::fo );
02307 writer->addAttribute( "xmlns:koffice", KoXmlNS::koffice );
02308 }
02309
02310
02311 writer->addAttribute( "xmlns:dc", KoXmlNS::dc );
02312 writer->addAttribute( "xmlns:xlink", KoXmlNS::xlink );
02313 return writer;
02314 }
02315
02316 QDomDocument KoDocument::saveXML()
02317 {
02318 kError(30003) << "KoDocument::saveXML not implemented" << endl;
02319 d->lastErrorMessage = i18n( "Internal error: saveXML not implemented" );
02320 return QDomDocument();
02321 }
02322
02323 KService::Ptr KoDocument::nativeService()
02324 {
02325 if ( !m_nativeService )
02326 m_nativeService = readNativeService( instance() );
02327
02328 return m_nativeService;
02329 }
02330
02331 QByteArray KoDocument::nativeFormatMimeType() const
02332 {
02333 KService::Ptr service = const_cast<KoDocument *>(this)->nativeService();
02334 if ( !service )
02335 return QByteArray();
02336 QByteArray nativeMimeType = service->property( "X-KDE-NativeMimeType" ).toString().toLatin1();
02337 if ( nativeMimeType.isEmpty() ) {
02338
02339 if ( !service->serviceTypes().contains( "KOfficePart" ) )
02340 kWarning(30003) << "Wrong desktop file, KOfficePart isn't mentionned" << endl;
02341 else if ( !KServiceType::serviceType( "KOfficePart" ) )
02342 kWarning(30003) << "The KOfficePart service type isn't installed!" << endl;
02343 }
02344 return nativeMimeType;
02345 }
02346
02347 QByteArray KoDocument::nativeOasisMimeType() const
02348 {
02349 KService::Ptr service = const_cast<KoDocument *>(this)->nativeService();
02350 if ( !service )
02351 return QByteArray();
02352 return service->property( "X-KDE-NativeOasisMimeType" ).toString().toLatin1();
02353 }
02354
02355
02356
02357 KService::Ptr KoDocument::readNativeService( KInstance *instance )
02358 {
02359 QString instname = instance ? instance->instanceName() : kapp->instanceName();
02360
02361
02362 QString servicepartname = instname + "part.desktop";
02363 KService::Ptr service = KService::serviceByDesktopPath( servicepartname );
02364 if ( service )
02365 kDebug(30003) << servicepartname << " found." << endl;
02366 if ( !service )
02367 {
02368
02369
02370
02371
02372
02373 service = KService::serviceByDesktopPath( QString::fromLatin1("Office/%1.desktop").arg(instname) );
02374 }
02375 if ( !service )
02376 service = KService::serviceByDesktopName( instname );
02377
02378 return service;
02379 }
02380
02381 QByteArray KoDocument::readNativeFormatMimeType( KInstance *instance )
02382 {
02383 KService::Ptr service = readNativeService( instance );
02384 if ( !service )
02385 return QByteArray();
02386
02387 if ( service->property( "X-KDE-NativeMimeType" ).toString().isEmpty() )
02388 {
02389
02390 KServiceType::Ptr ptr = KServiceType::serviceType( "KOfficePart" );
02391 if ( !ptr )
02392 kError(30003) << "The serviceType KOfficePart is missing. Check that you have a kofficepart.desktop file in the share/servicetypes directory." << endl;
02393 else {
02394 QString instname = instance ? instance->instanceName() : kapp->instanceName();
02395 if ( instname != "koshell" )
02396 kWarning(30003) << service->desktopEntryPath() << ": no X-KDE-NativeMimeType entry!" << endl;
02397 }
02398 }
02399
02400 return service->property( "X-KDE-NativeMimeType" ).toString().toLatin1();
02401 }
02402
02403 QStringList KoDocument::readExtraNativeMimeTypes( KInstance *instance )
02404 {
02405 KService::Ptr service = readNativeService( instance );
02406 if ( !service )
02407 return QStringList();
02408 return service->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
02409 }
02410
02411 void KoDocument::setupXmlReader( QXmlSimpleReader& reader, bool namespaceProcessing )
02412 {
02413 if ( namespaceProcessing )
02414 {
02415 reader.setFeature( "http://xml.org/sax/features/namespaces", true );
02416 reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", false );
02417 }
02418 else
02419 {
02420 reader.setFeature( "http://xml.org/sax/features/namespaces", false );
02421 reader.setFeature( "http://xml.org/sax/features/namespace-prefixes", true );
02422 }
02423 reader.setFeature( "http://trolltech.com/xml/features/report-whitespace-only-CharData", true );
02424 }
02425
02426
02427 bool KoDocument::isNativeFormat( const QByteArray& mimetype ) const
02428 {
02429 if ( mimetype == nativeFormatMimeType() )
02430 return true;
02431 return extraNativeMimeTypes().contains( mimetype );
02432 }
02433
02434 QStringList KoDocument::extraNativeMimeTypes() const
02435 {
02436 QStringList lst;
02437
02438
02439
02440 KService::Ptr service = const_cast<KoDocument *>(this)->nativeService();
02441 if ( !service )
02442 return lst;
02443 return service->property( "X-KDE-ExtraNativeMimeTypes" ).toStringList();
02444 }
02445
02446 int KoDocument::supportedSpecialFormats() const
02447 {
02448
02449
02450
02451 return SaveAsDirectoryStore;
02452 }
02453
02454 void KoDocument::addShell( KoMainWindow *shell )
02455 {
02456 if ( d->m_shells.findRef( shell ) == -1 )
02457 {
02458
02459 d->m_shells.append( shell );
02460 }
02461 }
02462
02463 void KoDocument::removeShell( KoMainWindow *shell )
02464 {
02465
02466 d->m_shells.removeRef( shell );
02467 }
02468
02469 const Q3PtrList<KoMainWindow>& KoDocument::shells() const
02470 {
02471 return d->m_shells;
02472 }
02473
02474 int KoDocument::shellCount() const
02475 {
02476 return d->m_shells.count();
02477 }
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491 void KoDocument::setErrorMessage( const QString& errMsg )
02492 {
02493 d->lastErrorMessage = errMsg;
02494 }
02495
02496 QString KoDocument::errorMessage() const
02497 {
02498 return d->lastErrorMessage;
02499 }
02500
02501 void KoDocument::showSavingErrorDialog()
02502 {
02503 if ( d->lastErrorMessage.isEmpty() )
02504 {
02505 KMessageBox::error( 0L, i18n( "Could not save\n%1", m_file ) );
02506 }
02507 else if ( d->lastErrorMessage != "USER_CANCELED" )
02508 {
02509 KMessageBox::error( 0L, i18n( "Could not save %1\nReason: %2", m_file, d->lastErrorMessage ) );
02510 }
02511 }
02512
02513 void KoDocument::showLoadingErrorDialog()
02514 {
02515 if ( d->lastErrorMessage.isEmpty() )
02516 {
02517 KMessageBox::error( 0L, i18n( "Could not open\n%1", url().pathOrUrl() ) );
02518 }
02519 else if ( d->lastErrorMessage != "USER_CANCELED" )
02520 {
02521 KMessageBox::error( 0L, i18n( "Could not open %1\nReason: %2", url().pathOrUrl(), d->lastErrorMessage ) );
02522 }
02523 }
02524
02525 bool KoDocument::isAutosaving() const
02526 {
02527 return d->m_autosaving;
02528 }
02529
02530 bool KoDocument::isLoading() const
02531 {
02532 return d->m_bLoading;
02533 }
02534
02535 void KoDocument::removeAutoSaveFiles()
02536 {
02537
02538 QString asf = autoSaveFile( m_file );
02539 if ( QFile::exists( asf ) )
02540 QFile::remove( asf );
02541 asf = autoSaveFile( QString::null );
02542 if ( QFile::exists( asf ) )
02543 QFile::remove( asf );
02544 }
02545
02546 void KoDocument::setBackupFile( bool _b )
02547 {
02548 d->m_backupFile = _b;
02549 }
02550
02551 bool KoDocument::backupFile()const
02552 {
02553 return d->m_backupFile;
02554 }
02555
02556
02557 void KoDocument::setBackupPath( const QString & _path)
02558 {
02559 d->m_backupPath = _path;
02560 }
02561
02562 QString KoDocument::backupPath()const
02563 {
02564 return d->m_backupPath;
02565 }
02566
02567 void KoDocument::setCurrent( bool on )
02568 {
02569
02570 KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
02571 if ( doc )
02572 {
02573 if ( !isStoredExtern() )
02574 {
02575
02576 doc->setCurrent( true );
02577 return;
02578 }
02579
02580 d->m_current = on;
02581 if ( !on )
02582 {
02583 doc->setCurrent( true );
02584 return;
02585 }
02586 doc->forceCurrent( false );
02587 }
02588 else
02589 d->m_current = on;
02590
02591 setTitleModified();
02592 }
02593
02594 void KoDocument::forceCurrent( bool on )
02595 {
02596
02597 d->m_current = on;
02598 KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
02599 if ( doc )
02600 {
02601 doc->forceCurrent( false );
02602 }
02603 }
02604
02605 bool KoDocument::isCurrent() const
02606 {
02607 return d->m_current;
02608 }
02609
02610 bool KoDocument::storeInternal() const
02611 {
02612 return d->m_storeInternal;
02613 }
02614
02615 void KoDocument::setStoreInternal( bool i )
02616 {
02617 d->m_storeInternal = i;
02618
02619 }
02620
02621 bool KoDocument::hasExternURL() const
02622 {
02623 return !url().protocol().isEmpty() && url().protocol() != STORE_PROTOCOL && url().protocol() != INTERNAL_PROTOCOL;
02624 }
02625
02626 void KoDocument::slotStarted( KIO::Job* job )
02627 {
02628 if ( job && job->ui() )
02629 {
02630 job->ui()->setWindow( d->m_shells.current() );
02631 }
02632 }
02633
02634 static const struct {
02635 const char* localName;
02636 const char* documentType;
02637 } TN2DTArray[] = {
02638 { "text", I18N_NOOP( "a word processing" ) },
02639 { "spreadsheet", I18N_NOOP( "a spreadsheet" ) },
02640 { "presentation", I18N_NOOP( "a presentation" ) },
02641 { "chart", I18N_NOOP( "a chart" ) },
02642 { "drawing", I18N_NOOP( "a drawing" ) }
02643 };
02644 static const unsigned int numTN2DT = sizeof( TN2DTArray ) / sizeof( *TN2DTArray );
02645
02646 QString KoDocument::tagNameToDocumentType( const QString& localName )
02647 {
02648 for ( unsigned int i = 0 ; i < numTN2DT ; ++i )
02649 if ( localName == TN2DTArray[i].localName )
02650 return i18n( TN2DTArray[i].documentType );
02651 return localName;
02652 }
02653
02654 QList<KoTextDocument *> KoDocument::allTextDocuments() const
02655 {
02656 return QList<KoTextDocument *>();
02657 }
02658
02659 KoPageLayout KoDocument::pageLayout(int ) const
02660 {
02661 return m_pageLayout;
02662 }
02663
02664 KoUnit::Unit KoDocument::unit() const
02665 {
02666 return d->m_unit;
02667 }
02668
02669 void KoDocument::setUnit( KoUnit::Unit unit )
02670 {
02671 if ( d->m_unit != unit )
02672 {
02673 d->m_unit = unit;
02674 emit unitChanged( unit );
02675 }
02676 }
02677
02678 QString KoDocument::unitName() const
02679 {
02680 return KoUnit::unitName( unit() );
02681 }
02682
02683 void KoDocument::showStartUpWidget( KoMainWindow* parent, bool alwaysShow )
02684 {
02685 if(!alwaysShow) {
02686 KConfigGroup cfgGrp( instance()->config(), "TemplateChooserDialog" );
02687 QString fullTemplateName = cfgGrp.readPathEntry( "AlwaysUseTemplate" );
02688
02689 if( !fullTemplateName.isEmpty() ) {
02690 openTemplate( fullTemplateName );
02691 shells().getFirst()->setRootDocument( this );
02692 return;
02693 }
02694 }
02695
02696 if(d->m_startUpWidget){
02697 d->m_startUpWidget->show();
02698 } else {
02699 d->m_startUpWidget = createOpenPane( parent->centralWidget(), instance(), templateType() );
02700 }
02701
02702 parent->setDocToOpen( this );
02703 parent->factory()->container("mainToolBar", parent)->hide();
02704 }
02705
02706 void KoDocument::openExistingFile( const KUrl& url )
02707 {
02708 bool ok = openURL( url );
02709 setModified( false );
02710
02711 if( ok )
02712 QTimer::singleShot( 0, this, SLOT( deleteOpenPane() ) );
02713 }
02714
02715 void KoDocument::openTemplate( const KUrl& url )
02716 {
02717 bool ok = loadNativeFormat( url.path() );
02718 setModified( false );
02719
02720 if ( ok ) {
02721 deleteOpenPane();
02722 resetURL();
02723 setEmpty();
02724 } else {
02725 showLoadingErrorDialog();
02726 initEmpty();
02727 }
02728 }
02729
02730 void KoDocument::initEmpty()
02731 {
02732 setEmpty();
02733 setModified(false);
02734 }
02735
02736 void KoDocument::startCustomDocument() {
02737 deleteOpenPane();
02738 }
02739
02740 KoOpenPane* KoDocument::createOpenPane( QWidget* parent, KInstance* instance,
02741 const QString& templateType )
02742 {
02743 KoOpenPane* openPane = new KoOpenPane( parent, instance, templateType );
02744 QWidget *customDoc = createCustomDocumentWidget(openPane);
02745 if(customDoc) {
02746 openPane->setCustomDocumentWidget( customDoc );
02747 connect( customDoc, SIGNAL( documentSelected() ), this, SLOT( startCustomDocument() ) );
02748 }
02749 openPane->show();
02750
02751 connect( openPane, SIGNAL( openExistingFile( const KUrl& ) ),
02752 this, SLOT( openExistingFile( const KUrl& ) ) );
02753 connect( openPane, SIGNAL( openTemplate( const KUrl& ) ),
02754 this, SLOT( openTemplate( const KUrl& ) ) );
02755
02756 return openPane;
02757 }
02758
02759 void KoDocument::setTemplateType( const QString& _templateType )
02760 {
02761 d->m_templateType = _templateType;
02762 }
02763
02764 QString KoDocument::templateType() const
02765 {
02766 return d->m_templateType;
02767 }
02768
02769 void KoDocument::deleteOpenPane()
02770 {
02771 if( d->m_startUpWidget ) {
02772 d->m_startUpWidget->hide();
02773 QTimer::singleShot(1000, this, SLOT(deleteOpenPaneDelayed()));
02774
02775 shells().getFirst()->factory()->container("mainToolBar", shells().getFirst())->show();
02776 shells().getFirst()->setRootDocument( this );
02777 } else {
02778 emit closeEmbedInitDialog();
02779 }
02780 }
02781
02782 void KoDocument::deleteOpenPaneDelayed()
02783 {
02784 delete d->m_startUpWidget;
02785 d->m_startUpWidget = 0;
02786 }
02787
02788 QWidget* KoDocument::createCustomDocumentWidget(QWidget *) {
02789 return 0;
02790 }
02791
02792 bool KoDocument::showEmbedInitDialog(QWidget* parent)
02793 {
02794 KDialog dlg( parent );
02795 dlg.setCaption( i18n("Embedding Object") );
02796 KoOpenPane* pane = createOpenPane(&dlg, instance(), templateType());
02797 pane->layout()->setMargin(0);
02798 dlg.setMainWidget(pane);
02799 KConfig cfg("EmbedInitDialog");
02800 dlg.restoreDialogSize( &cfg );
02801 connect(this, SIGNAL(closeEmbedInitDialog()), &dlg, SLOT(slotOk()));
02802
02803 bool ok = dlg.exec() == QDialog::Accepted;
02804
02805 dlg.saveDialogSize(&cfg);
02806
02807 return ok;
02808 }
02809
02810 QList<KoVersionInfo> & KoDocument::versionList()
02811 {
02812 return d->m_versionInfo;
02813 }
02814
02815 #include "KoDocument_p.moc"
02816 #include "KoDocument.moc"