00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024
00025 #include <assert.h>
00026 #include <unistd.h>
00027
00028 #include <qbuffer.h>
00029
00030 #include <koDocument.h>
00031 #include <koDocument_p.h>
00032 #include <KoDocumentIface.h>
00033 #include <koDocumentChild.h>
00034 #include <koView.h>
00035 #include <koMainWindow.h>
00036 #include <koStoreDevice.h>
00037 #include <koFilterManager.h>
00038 #include <koDocumentInfo.h>
00039 #include <kprinter.h>
00040
00041 #include <kio/netaccess.h>
00042 #include <kio/job.h>
00043 #include <kparts/partmanager.h>
00044 #include <klocale.h>
00045 #include <kmimetype.h>
00046 #include <kapplication.h>
00047 #include <kdebug.h>
00048 #include <kmessagebox.h>
00049 #include <kdeversion.h>
00050 #include <kfileitem.h>
00051 #if ! KDE_IS_VERSION(3,1,90)
00052 #include <kdebugclasses.h>
00053 #endif
00054
00055 #include <qfile.h>
00056 #include <qmap.h>
00057 #include <qpainter.h>
00058 #include <qtimer.h>
00059 #include <qimage.h>
00060 #include <kiconloader.h>
00061 #include <qdir.h>
00062 #include <qfileinfo.h>
00063 #include <qcursor.h>
00064
00065
00066
00067
00068 #define STORE_PROTOCOL "tar"
00069
00070
00071 #define INTERNAL_PROTOCOL "intern"
00072 #define INTERNAL_PREFIX "intern:/"
00073
00074
00075 QPtrList<KoDocument> *KoDocument::s_documentList=0L;
00076
00077 using namespace std;
00078 class KoViewWrapperWidget;
00079
00080
00081
00082
00083
00084
00085
00086 const int KoDocument::s_defaultAutoSave = 300;
00087
00088 class KoDocument::Private
00089 {
00090 public:
00091 Private() :
00092 m_dcopObject( 0L ),
00093 filterManager( 0L ),
00094 m_specialOutputFlag( 0 ),
00095 m_isImporting( false ), m_isExporting( false ),
00096 m_numOperations( 0 ),
00097 modifiedAfterAutosave( false ),
00098 m_autosaving( false ),
00099 m_shouldCheckAutoSaveFile( true ),
00100 m_autoErrorHandlingEnabled( true ),
00101 m_backupFile( true ),
00102 m_backupPath( QString::null ),
00103 m_doNotSaveExtDoc( false ),
00104 m_current( false ),
00105 m_storeInternal( false ),
00106 m_initDocFlags( KoDocument::InitDocAppStarting )
00107 {
00108 m_confirmNonNativeSave[0] = true;
00109 m_confirmNonNativeSave[1] = true;
00110 }
00111
00112 QPtrList<KoView> m_views;
00113 QPtrList<KoDocumentChild> m_children;
00114 QPtrList<KoMainWindow> m_shells;
00115 QValueList<QDomDocument> m_viewBuildDocuments;
00116
00117 KoViewWrapperWidget *m_wrapperWidget;
00118 KoDocumentIface * m_dcopObject;
00119 KoDocumentInfo *m_docInfo;
00120
00121 KoFilterManager * filterManager;
00122
00123 QCString mimeType;
00124 QCString outputMimeType;
00125 bool m_confirmNonNativeSave [2];
00126
00127
00128 int m_specialOutputFlag;
00129 bool m_isImporting, m_isExporting;
00130
00131 QTimer m_autoSaveTimer;
00132 QString lastErrorMessage;
00133 int m_autoSaveDelay;
00134 int m_numOperations;
00135 bool modifiedAfterAutosave;
00136 bool m_bSingleViewMode;
00137 bool m_autosaving;
00138 bool m_shouldCheckAutoSaveFile;
00139 bool m_autoErrorHandlingEnabled;
00140 bool m_backupFile;
00141 QString m_backupPath;
00142 bool m_doNotSaveExtDoc;
00143 bool m_current;
00144 bool m_storeInternal;
00145 InitDocFlags m_initDocFlags;
00146 };
00147
00148
00149 class KoViewWrapperWidget : public QWidget
00150 {
00151 public:
00152 KoViewWrapperWidget( QWidget *parent, const char *name )
00153 : QWidget( parent, name )
00154 {
00155 KGlobal::locale()->insertCatalogue("koffice");
00156
00157 KGlobal::iconLoader()->addAppDir("koffice");
00158 m_view = 0L;
00159
00160 setFocusPolicy( ClickFocus );
00161 }
00162
00163 virtual ~KoViewWrapperWidget() {
00164 setFocusProxy( 0 );
00165 }
00166
00167 virtual void resizeEvent( QResizeEvent * )
00168 {
00169 QObject *wid = child( 0, "QWidget" );
00170 if ( wid )
00171 static_cast<QWidget *>(wid)->setGeometry( 0, 0, width(), height() );
00172 }
00173
00174 virtual void childEvent( QChildEvent *ev )
00175 {
00176 if ( ev->type() == QEvent::ChildInserted )
00177 resizeEvent( 0L );
00178 }
00179
00180
00181 void setKoView( KoView * view ) {
00182 m_view = view;
00183 setFocusProxy( m_view );
00184 }
00185 KoView * koView() const { return m_view; }
00186 private:
00187 KoView* m_view;
00188 };
00189
00190 KoBrowserExtension::KoBrowserExtension( KoDocument * doc, const char * name )
00191 : KParts::BrowserExtension( doc, name )
00192 {
00193 emit enableAction( "print", true );
00194 }
00195
00196 void KoBrowserExtension::print()
00197 {
00198 KoDocument * doc = static_cast<KoDocument *>( parent() );
00199 KoViewWrapperWidget * wrapper = static_cast<KoViewWrapperWidget *>( doc->widget() );
00200 KoView * view = wrapper->koView();
00201
00202 KPrinter printer;
00203
00204 view->setupPrinter( printer );
00205 if ( printer.setup( view ) )
00206 view->print( printer );
00207 }
00208
00209 KoDocument::KoDocument( QWidget * parentWidget, const char *widgetName, QObject* parent, const char* name, bool singleViewMode )
00210 : KParts::ReadWritePart( parent, name )
00211 {
00212 if(s_documentList==0L)
00213 s_documentList=new QPtrList<KoDocument>;
00214 s_documentList->append(this);
00215
00216 d = new Private;
00217 m_bEmpty = TRUE;
00218 connect( &d->m_autoSaveTimer, SIGNAL( timeout() ), this, SLOT( slotAutoSave() ) );
00219 setAutoSave( s_defaultAutoSave );
00220 d->m_bSingleViewMode = singleViewMode;
00221
00222
00223
00224 if ( parent )
00225 {
00226 if ( parent->inherits( "KoDocument" ) )
00227 d->m_bSingleViewMode = ((KoDocument *)parent)->isSingleViewMode();
00228 else if ( parent->inherits( "KParts::Part" ) )
00229 d->m_bSingleViewMode = true;
00230 }
00231
00232 if ( singleViewMode )
00233 {
00234 d->m_wrapperWidget = new KoViewWrapperWidget( parentWidget, widgetName );
00235 setWidget( d->m_wrapperWidget );
00236 kdDebug(30003) << "creating KoBrowserExtension" << endl;
00237 (void) new KoBrowserExtension( this );
00238 }
00239
00240 d->m_docInfo = new KoDocumentInfo( this, "document info" );
00241
00242 m_pageLayout.ptWidth = 0;
00243 m_pageLayout.ptHeight = 0;
00244 m_pageLayout.ptTop = 0;
00245 m_pageLayout.ptBottom = 0;
00246 m_pageLayout.ptLeft = 0;
00247 m_pageLayout.ptRight = 0;
00248
00249
00250 if ( !singleViewMode )
00251 connect( this, SIGNAL( started( KIO::Job* ) ), SLOT( slotStarted( KIO::Job* ) ) );
00252 }
00253
00254 KoDocument::~KoDocument()
00255 {
00256 d->m_autoSaveTimer.stop();
00257
00258 QPtrListIterator<KoDocumentChild> childIt( d->m_children );
00259 for (; childIt.current(); ++childIt )
00260 disconnect( childIt.current(), SIGNAL( destroyed() ),
00261 this, SLOT( slotChildDestroyed() ) );
00262
00263
00264
00265 QPtrListIterator<KoView> vIt( d->m_views );
00266 for (; vIt.current(); ++vIt )
00267 vIt.current()->setDocumentDeleted();
00268
00269 d->m_children.setAutoDelete( true );
00270 d->m_children.clear();
00271
00272 d->m_shells.setAutoDelete( true );
00273 d->m_shells.clear();
00274
00275 delete d->m_dcopObject;
00276 delete d->filterManager;
00277 delete d;
00278 s_documentList->removeRef(this);
00279
00280 if(s_documentList->isEmpty()) {
00281 delete s_documentList;
00282 s_documentList=0;
00283 }
00284 }
00285
00286 bool KoDocument::isSingleViewMode() const
00287 {
00288 return d->m_bSingleViewMode;
00289 }
00290
00291 bool KoDocument::isEmbedded() const
00292 {
00293 return dynamic_cast<KoDocument *>( parent() ) != 0;
00294 }
00295
00296 KoView *KoDocument::createView( QWidget *parent, const char *name )
00297 {
00298 KoView *view=createViewInstance(parent, name);
00299 addView(view);
00300 return view;
00301 }
00302
00303 bool KoDocument::exp0rt( const KURL & _url )
00304 {
00305 bool ret;
00306
00307 d->m_isExporting = true;
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317 KURL oldURL = m_url;
00318 QString oldFile = m_file;
00319
00320 bool wasModified = isModified ();
00321 QCString oldMimeType = mimeType ();
00322
00323
00324
00325 ret = saveAs( _url );
00326
00327
00328
00329
00330
00331
00332 kdDebug(30003) << "Restoring KoDocument state to before export" << endl;
00333
00334
00335
00336 m_url = oldURL;
00337 m_file = oldFile;
00338
00339
00340
00341 if (ret)
00342 {
00343 setModified (wasModified);
00344 d->mimeType = oldMimeType;
00345 }
00346
00347
00348 d->m_isExporting = false;
00349
00350 return ret;
00351 }
00352
00353 bool KoDocument::saveFile()
00354 {
00355 kdDebug(30003) << "KoDocument::saveFile() doc='" << url().url() <<"'"<< endl;
00356 if ( !kapp->inherits( "KoApplication" ) )
00357 {
00358 d->lastErrorMessage = i18n( "Internal error: not a KOffice application, saving not allowed." );
00359 return false;
00360 }
00361
00362 QCString _native_format = nativeFormatMimeType();
00363
00364 QCString outputMimeType = d->outputMimeType;
00365 Q_ASSERT( !outputMimeType.isEmpty() );
00366 if ( outputMimeType.isEmpty() )
00367 outputMimeType = _native_format;
00368
00369 QApplication::setOverrideCursor( waitCursor );
00370
00371 if ( backupFile() ) {
00372 KIO::UDSEntry entry;
00373 #if KDE_IS_VERSION(3,1,90)
00374 if ( KIO::NetAccess::stat( url(), entry, shells().current() ) ) {
00375 #else
00376 if ( KIO::NetAccess::stat( url(), entry ) ) {
00377 #endif
00378 emit sigStatusBarMessage( i18n("Making backup...") );
00379 KURL backup;
00380 if ( d->m_backupPath.isEmpty())
00381 backup = url();
00382 else
00383 backup = d->m_backupPath +"/"+url().fileName();
00384 backup.setPath( backup.path() + QString::fromLatin1("~") );
00385 KFileItem item( entry, url() );
00386 Q_ASSERT( item.name() == url().fileName() );
00387 #if KDE_IS_VERSION(3,1,90)
00388 KIO::NetAccess::file_copy( url(), backup, item.permissions(), true , false , shells().current() );
00389 #else
00390 KIO::NetAccess::del( backup );
00391 KIO::NetAccess::copy( url(), backup );
00392
00393 if ( backup.isLocalFile() )
00394 ::chmod( QFile::encodeName( backup.path() ), item.permissions() );
00395 #endif
00396 }
00397 }
00398
00399 emit sigStatusBarMessage( i18n("Saving...") );
00400 bool ret = false;
00401 bool suppressErrorDialog = false;
00402 if ( outputMimeType != _native_format ) {
00403 kdDebug(30003) << "Saving to format " << outputMimeType << " in " << m_file << endl;
00404
00405 if ( !d->filterManager )
00406 d->filterManager = new KoFilterManager( this );
00407
00408 KoFilter::ConversionStatus status = d->filterManager->exp0rt( m_file, outputMimeType );
00409 ret = status == KoFilter::OK;
00410 suppressErrorDialog = (status == KoFilter::UserCancelled || status == KoFilter::BadConversionGraph );
00411 } else {
00412
00413 ret = saveNativeFormat( m_file );
00414 }
00415
00416 if ( ret ) {
00417 removeAutoSaveFiles();
00418
00419
00420 setAutoSave( d->m_autoSaveDelay );
00421 }
00422
00423 QApplication::restoreOverrideCursor();
00424 if ( !ret )
00425 {
00426 if ( !suppressErrorDialog )
00427 {
00428 if ( d->lastErrorMessage.isEmpty() )
00429 KMessageBox::error( 0L, i18n( "Could not save\n%1" ).arg( m_file ) );
00430 else if ( d->lastErrorMessage != "USER_CANCELED" )
00431 {
00432 KMessageBox::error( 0L, i18n( "Could not save %1\nReason: %2" ).arg( m_file).arg( d->lastErrorMessage ) );
00433 }
00434 }
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446 resetURL();
00447 }
00448
00449 if ( ret )
00450 {
00451 d->mimeType = outputMimeType;
00452 setConfirmNonNativeSave ( isExporting (), false );
00453 }
00454 emit sigClearStatusBarMessage();
00455
00456 return ret;
00457 }
00458
00459 QCString KoDocument::mimeType() const
00460 {
00461 return d->mimeType;
00462 }
00463
00464 void KoDocument::setMimeType( const QCString & mimeType )
00465 {
00466 d->mimeType = mimeType;
00467 }
00468
00469 void KoDocument::setOutputMimeType( const QCString & mimeType, int specialOutputFlag )
00470 {
00471 d->outputMimeType = mimeType;
00472 d->m_specialOutputFlag = specialOutputFlag;
00473 }
00474
00475 QCString KoDocument::outputMimeType() const
00476 {
00477 return d->outputMimeType;
00478 }
00479
00480 int KoDocument::specialOutputFlag() const
00481 {
00482 return d->m_specialOutputFlag;
00483 }
00484
00485 bool KoDocument::confirmNonNativeSave( const bool exporting ) const
00486 {
00487
00488
00489 return d->m_confirmNonNativeSave [ exporting ? 1 : 0 ];
00490 }
00491
00492 void KoDocument::setConfirmNonNativeSave( const bool exporting, const bool on )
00493 {
00494 d->m_confirmNonNativeSave [ exporting ? 1 : 0] = on;
00495 }
00496
00497 bool KoDocument::isImporting() const
00498 {
00499 return d->m_isImporting;
00500 }
00501
00502 bool KoDocument::isExporting() const
00503 {
00504 return d->m_isExporting;
00505 }
00506
00507 void KoDocument::setCheckAutoSaveFile( bool b )
00508 {
00509 d->m_shouldCheckAutoSaveFile = b;
00510 }
00511
00512 void KoDocument::setAutoErrorHandlingEnabled( bool b )
00513 {
00514 d->m_autoErrorHandlingEnabled = b;
00515 }
00516
00517 bool KoDocument::isAutoErrorHandlingEnabled()
00518 {
00519 return d->m_autoErrorHandlingEnabled;
00520 }
00521
00522 void KoDocument::slotAutoSave()
00523 {
00524
00525 if ( isModified() && d->modifiedAfterAutosave )
00526 {
00527 connect( this, SIGNAL( sigProgress( int ) ), shells().current(), SLOT( slotProgress( int ) ) );
00528 emit sigStatusBarMessage( i18n("Autosaving...") );
00529 d->m_autosaving = true;
00530 bool ret = saveNativeFormat( autoSaveFile( m_file ) );
00531 setModified( true );
00532 if ( ret )
00533 d->modifiedAfterAutosave=false;
00534 d->m_autosaving = false;
00535 emit sigClearStatusBarMessage();
00536 disconnect( this, SIGNAL( sigProgress( int ) ), shells().current(), SLOT( slotProgress( int ) ) );
00537
00538
00539
00540 }
00541 }
00542
00543 KAction *KoDocument::action( const QDomElement &element ) const
00544 {
00545
00546 KAction* act = KParts::ReadWritePart::action( element );
00547 if ( act )
00548 return act;
00549
00550 Q_ASSERT( d->m_bSingleViewMode );
00551
00552 if ( !d->m_views.isEmpty() )
00553 return d->m_views.getFirst()->action( element );
00554 else
00555 return 0L;
00556 }
00557
00558 QDomDocument KoDocument::domDocument() const
00559 {
00560
00561
00562 Q_ASSERT( d->m_bSingleViewMode );
00563 if ( d->m_views.isEmpty() )
00564 return QDomDocument();
00565 else
00566 return d->m_views.getFirst()->domDocument();
00567 }
00568
00569 void KoDocument::setManager( KParts::PartManager *manager )
00570 {
00571 KParts::ReadWritePart::setManager( manager );
00572 if ( d->m_bSingleViewMode && d->m_views.count() == 1 )
00573 d->m_views.getFirst()->setPartManager( manager );
00574
00575 if ( manager )
00576 {
00577 QPtrListIterator<KoDocumentChild> it( d->m_children );
00578 for (; it.current(); ++it )
00579 if ( it.current()->document() )
00580 manager->addPart( it.current()->document(), false );
00581 }
00582 }
00583
00584 void KoDocument::setReadWrite( bool readwrite )
00585 {
00586 KParts::ReadWritePart::setReadWrite( readwrite );
00587
00588 QPtrListIterator<KoView> vIt( d->m_views );
00589 for (; vIt.current(); ++vIt )
00590 vIt.current()->updateReadWrite( readwrite );
00591
00592 QPtrListIterator<KoDocumentChild> dIt( d->m_children );
00593 for (; dIt.current(); ++dIt )
00594 if ( dIt.current()->document() )
00595 dIt.current()->document()->setReadWrite( readwrite );
00596
00597 setAutoSave( d->m_autoSaveDelay );
00598 }
00599
00600 void KoDocument::setAutoSave( int delay )
00601 {
00602 d->m_autoSaveDelay = delay;
00603 if ( isReadWrite() && !isEmbedded() && d->m_autoSaveDelay > 0 )
00604 d->m_autoSaveTimer.start( d->m_autoSaveDelay * 1000 );
00605 else
00606 d->m_autoSaveTimer.stop();
00607 }
00608
00609 void KoDocument::addView( KoView *view )
00610 {
00611 if ( !view )
00612 return;
00613
00614 d->m_views.append( view );
00615 view->updateReadWrite( isReadWrite() );
00616 }
00617
00618 void KoDocument::removeView( KoView *view )
00619 {
00620 d->m_views.removeRef( view );
00621 }
00622
00623 const QPtrList<KoView>& KoDocument::views() const
00624 {
00625 return d->m_views;
00626 }
00627
00628 int KoDocument::viewCount() const
00629 {
00630 return d->m_views.count();
00631 }
00632
00633 void KoDocument::insertChild( KoDocumentChild *child )
00634 {
00635 setModified( true );
00636
00637 d->m_children.append( child );
00638
00639 connect( child, SIGNAL( changed( KoChild * ) ),
00640 this, SLOT( slotChildChanged( KoChild * ) ) );
00641 connect( child, SIGNAL( destroyed() ),
00642 this, SLOT( slotChildDestroyed() ) );
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652 if ( manager() && !isSingleViewMode() && child->document() )
00653 manager()->addPart( child->document(), false );
00654 }
00655
00656 void KoDocument::slotChildChanged( KoChild *c )
00657 {
00658 assert( c->inherits( "KoDocumentChild" ) );
00659 emit childChanged( static_cast<KoDocumentChild *>( c ) );
00660 }
00661
00662 void KoDocument::slotChildDestroyed()
00663 {
00664 setModified( true );
00665
00666 const KoDocumentChild *child = static_cast<const KoDocumentChild *>( sender() );
00667 d->m_children.removeRef( child );
00668 }
00669
00670 const QPtrList<KoDocumentChild>& KoDocument::children() const
00671 {
00672 return d->m_children;
00673 }
00674
00675 KParts::Part *KoDocument::hitTest( QWidget *widget, const QPoint &globalPos )
00676 {
00677 QPtrListIterator<KoView> it( d->m_views );
00678 for (; it.current(); ++it )
00679 if ( (QWidget *)it.current() == widget )
00680 {
00681 QPoint canvasPos( it.current()->canvas()->mapFromGlobal( globalPos ) );
00682 canvasPos.rx() += it.current()->canvasXOffset();
00683 canvasPos.ry() += it.current()->canvasYOffset();
00684
00685 KParts::Part *part = it.current()->hitTest( canvasPos );
00686 if ( part )
00687 return part;
00688 }
00689
00690 return 0L;
00691 }
00692
00693 KoDocument *KoDocument::hitTest( const QPoint &pos, const QWMatrix &matrix )
00694 {
00695 QPtrListIterator<KoDocumentChild> it( d->m_children );
00696 for (; it.current(); ++it )
00697 {
00698 KoDocument *doc = it.current()->hitTest( pos, matrix );
00699 if ( doc )
00700 return doc;
00701 }
00702
00703 return this;
00704 }
00705
00706 KoDocumentChild *KoDocument::child( KoDocument *doc )
00707 {
00708 QPtrListIterator<KoDocumentChild> it( d->m_children );
00709 for (; it.current(); ++it )
00710 if ( it.current()->document() == doc )
00711 return it.current();
00712
00713 return 0L;
00714 }
00715
00716 KoDocumentInfo *KoDocument::documentInfo() const
00717 {
00718 return d->m_docInfo;
00719 }
00720
00721 void KoDocument::setViewBuildDocument( KoView *view, const QDomDocument &doc )
00722 {
00723 if ( d->m_views.find( view ) == -1 )
00724 return;
00725
00726 uint viewIdx = d->m_views.at();
00727
00728 if ( d->m_viewBuildDocuments.count() == viewIdx )
00729 d->m_viewBuildDocuments.append( doc );
00730 else if ( d->m_viewBuildDocuments.count() > viewIdx )
00731 d->m_viewBuildDocuments[ viewIdx ] = doc;
00732 }
00733
00734 QDomDocument KoDocument::viewBuildDocument( KoView *view )
00735 {
00736 QDomDocument res;
00737
00738 if ( d->m_views.find( view ) == -1 )
00739 return res;
00740
00741 uint viewIdx = d->m_views.at();
00742
00743 if ( viewIdx >= d->m_viewBuildDocuments.count() )
00744 return res;
00745
00746 res = d->m_viewBuildDocuments[ viewIdx ];
00747
00748
00749 d->m_viewBuildDocuments[ viewIdx ] = QDomDocument();
00750
00751 return res;
00752 }
00753
00754 void KoDocument::paintEverything( QPainter &painter, const QRect &rect, bool transparent, KoView *view, double zoomX, double zoomY )
00755 {
00756 paintContent( painter, rect, transparent, zoomX, zoomY );
00757 paintChildren( painter, rect, view, zoomX, zoomY );
00758 }
00759
00760 void KoDocument::paintChildren( QPainter &painter, const QRect &, KoView *view, double zoomX, double zoomY )
00761 {
00762 QPtrListIterator<KoDocumentChild> it( d->m_children );
00763 for (; it.current(); ++it )
00764 {
00765
00766 painter.save();
00767 paintChild( it.current(), painter, view, zoomX, zoomY );
00768 painter.restore();
00769 }
00770 }
00771
00772 void KoDocument::paintChild( KoDocumentChild *child, QPainter &painter, KoView *view, double zoomX, double zoomY )
00773 {
00774 if ( child->isDeleted() )
00775 return;
00776
00777
00778
00779 child->transform( painter );
00780 child->document()->paintEverything( painter, child->contentRect(), child->isTransparent(), view, zoomX, zoomY );
00781
00782 if ( view && view->partManager() )
00783 {
00784
00785 KParts::PartManager *manager = view->partManager();
00786
00787 painter.scale( 1.0 / child->xScaling(), 1.0 / child->yScaling() );
00788
00789 int w = int( (double)child->contentRect().width() * child->xScaling() );
00790 int h = int( (double)child->contentRect().height() * child->yScaling() );
00791 if ( ( manager->selectedPart() == (KParts::Part *)child->document() &&
00792 manager->selectedWidget() == (QWidget *)view ) ||
00793 ( manager->activePart() == (KParts::Part *)child->document() &&
00794 manager->activeWidget() == (QWidget *)view ) )
00795 {
00796
00797 painter.setClipping( FALSE );
00798
00799 painter.setPen( black );
00800 painter.fillRect( -5, -5, w + 10, 5, white );
00801 painter.fillRect( -5, h, w + 10, 5, white );
00802 painter.fillRect( -5, -5, 5, h + 10, white );
00803 painter.fillRect( w, -5, 5, h + 10, white );
00804 painter.fillRect( -5, -5, w + 10, 5, BDiagPattern );
00805 painter.fillRect( -5, h, w + 10, 5, BDiagPattern );
00806 painter.fillRect( -5, -5, 5, h + 10, BDiagPattern );
00807 painter.fillRect( w, -5, 5, h + 10, BDiagPattern );
00808
00809 if ( manager->selectedPart() == (KParts::Part *)child->document() &&
00810 manager->selectedWidget() == (QWidget *)view )
00811 {
00812 QColor color;
00813 if ( view->koDocument() == this )
00814 color = black;
00815 else
00816 color = gray;
00817 painter.fillRect( -5, -5, 5, 5, color );
00818 painter.fillRect( -5, h, 5, 5, color );
00819 painter.fillRect( w, h, 5, 5, color );
00820 painter.fillRect( w, -5, 5, 5, color );
00821 painter.fillRect( w / 2 - 3, -5, 5, 5, color );
00822 painter.fillRect( w / 2 - 3, h, 5, 5, color );
00823 painter.fillRect( -5, h / 2 - 3, 5, 5, color );
00824 painter.fillRect( w, h / 2 - 3, 5, 5, color );
00825 }
00826
00827 painter.setClipping( TRUE );
00828 }
00829 }
00830 }
00831
00832 bool KoDocument::isModified()
00833 {
00834 if ( KParts::ReadWritePart::isModified() )
00835 {
00836
00837 return true;
00838 }
00839
00840 QPtrListIterator<KoDocumentChild> it = children();
00841 for (; it.current(); ++it )
00842 {
00843 if ( !it.current()->isStoredExtern() && !it.current()->isDeleted() )
00844 {
00845 KoDocument *doc = it.current()->document();
00846 if ( doc && doc->isModified() )
00847 return true;
00848 }
00849 }
00850 return false;
00851 }
00852
00853 bool KoDocument::saveChildren( KoStore* _store )
00854 {
00855
00856 int i = 0;
00857 QPtrListIterator<KoDocumentChild> it( children() );
00858 for( ; it.current(); ++it ) {
00859 KoDocument* childDoc = it.current()->document();
00860 if (childDoc && !it.current()->isDeleted())
00861 {
00862 if ( !childDoc->isStoredExtern() )
00863 {
00864
00865 if ( !childDoc->saveToStore( _store, QString::number( i++ ) ) )
00866 return FALSE;
00867
00868 if (!isExporting ())
00869 childDoc->setModified( false );
00870 }
00871
00872 }
00873 }
00874 return true;
00875 }
00876
00877 bool KoDocument::saveExternalChildren()
00878 {
00879 if ( d->m_doNotSaveExtDoc )
00880 {
00881
00882 d->m_doNotSaveExtDoc = false;
00883 return true;
00884 }
00885
00886
00887 KoDocument *doc;
00888 KoDocumentChild *ch;
00889 QPtrListIterator<KoDocumentChild> it = children();
00890 for (; (ch = it.current()); ++it )
00891 {
00892 if ( !ch->isDeleted() )
00893 {
00894 doc = ch->document();
00895 if ( doc->isStoredExtern() && doc->isModified() )
00896 {
00897 kdDebug(30003)<<" save external doc='"<<url().url()<<"'"<<endl;
00898 doc->setDoNotSaveExtDoc();
00899 if ( !doc->save() )
00900 return false;
00901 }
00902
00903
00904 if ( !doc->saveExternalChildren() )
00905 return false;
00906 }
00907 }
00908 return true;
00909 }
00910
00911 bool KoDocument::saveNativeFormat( const QString & _file )
00912 {
00913 QString file( _file );
00914 d->lastErrorMessage = QString::null;
00915
00916
00917 KoStore::Backend backend = KoStore::Auto;
00918 if ( d->m_specialOutputFlag == SaveAsKOffice1dot1 )
00919 {
00920 kdDebug(30003) << "Saving as KOffice-1.1 format, using a tar.gz" << endl;
00921 backend = KoStore::Tar;
00923 }
00924 else if ( d->m_specialOutputFlag == SaveAsDirectoryStore )
00925 {
00926 backend = KoStore::Directory;
00927 kdDebug(30003) << "Saving as uncompressed XML, using directory store." << endl;
00928 }
00929
00930 kdDebug(30003) << "KoDocument::saveNativeFormat nativeFormatMimeType=" << nativeFormatMimeType() << endl;
00931 KoStore* store = KoStore::createStore( file, KoStore::Write, nativeFormatMimeType(), backend );
00932 if ( store->bad() )
00933 {
00934 d->lastErrorMessage = i18n( "Couldn't open the file for saving" );
00935 delete store;
00936 return false;
00937 }
00938
00939
00940 if ( !saveChildren( store ) )
00941 {
00942 if ( d->lastErrorMessage.isEmpty() )
00943 d->lastErrorMessage = i18n( "Error while saving embedded documents" );
00944 delete store;
00945 return false;
00946 }
00947
00948 kdDebug(30003) << "Saving root" << endl;
00949 if ( store->open( "root" ) )
00950 {
00951 KoStoreDevice dev( store );
00952 if ( !saveToStream( &dev ) )
00953 {
00954 kdDebug(30003) << "saveToStream failed" << endl;
00955 delete store;
00956 return false;
00957 }
00958 if ( !store->close() )
00959 return false;
00960 }
00961 else
00962 {
00963 d->lastErrorMessage = i18n( "Not able to write 'maindoc.xml'." );
00964 delete store;
00965 return false;
00966 }
00967 if ( store->open( "documentinfo.xml" ) )
00968 {
00969 QDomDocument doc = d->m_docInfo->save();
00970 KoStoreDevice dev( store );
00971
00972 QCString s = doc.toCString();
00973 (void)dev.writeBlock( s.data(), s.size()-1 );
00974 (void)store->close();
00975 }
00976 if ( store->open( "preview.png" ) )
00977 {
00978 savePreview( store );
00979 (void)store->close();
00980 }
00981
00982 bool ret = completeSaving( store );
00983 kdDebug(30003) << "Saving done of url: " << url().url() << endl;
00984 delete store;
00985
00986 if ( !saveExternalChildren() )
00987 {
00988 return false;
00989 }
00990 return ret;
00991 }
00992
00993 bool KoDocument::saveToStream( QIODevice * dev )
00994 {
00995 QDomDocument doc = saveXML();
00996
00997 QCString s = doc.toCString();
00998
00999
01000 int nwritten = dev->writeBlock( s.data(), s.size()-1 );
01001 if ( nwritten != (int)s.size()-1 )
01002 kdWarning(30003) << "KoDocument::saveToStream wrote " << nwritten << " - expected " << s.size()-1 << endl;
01003 return nwritten == (int)s.size()-1;
01004 }
01005
01006 bool KoDocument::saveToStore( KoStore* _store, const QString & _path )
01007 {
01008 kdDebug(30003) << "Saving document to store " << _path << endl;
01009
01010
01011 if ( _path.startsWith( STORE_PROTOCOL ) )
01012 m_url = KURL( _path );
01013 else
01014 m_url = KURL( INTERNAL_PREFIX + _path );
01015
01016
01017 _store->pushDirectory();
01018 _store->enterDirectory( _path );
01019
01020
01021 if ( !saveChildren( _store ) )
01022 return false;
01023
01024
01025 if ( _store->open( "root" ) )
01026 {
01027 KoStoreDevice dev( _store );
01028 if ( !saveToStream( &dev ) )
01029 {
01030 _store->close();
01031 return false;
01032 }
01033 if ( !_store->close() )
01034 return false;
01035 }
01036
01037 if ( !completeSaving( _store ) )
01038 return false;
01039
01040
01041 _store->popDirectory();
01042
01043 kdDebug(30003) << "Saved document to store" << endl;
01044
01045 return true;
01046 }
01047
01048 void KoDocument::savePreview( KoStore* store )
01049 {
01050 QPixmap pix = generatePreview(QSize(256, 256));
01051
01052 QImageIO imageIO;
01053 imageIO.setImage( pix.convertToImage().convertDepth(8, Qt::AvoidDither | Qt::DiffuseDither) );
01054
01055
01056 QByteArray imageData;
01057 QBuffer buffer(imageData);
01058 buffer.open(IO_WriteOnly);
01059 imageIO.setIODevice(&buffer);
01060 imageIO.setFormat("PNG");
01061 imageIO.write();
01062 buffer.close();
01063
01064 store->write( imageData );
01065 }
01066
01067 QPixmap KoDocument::generatePreview( const QSize& size )
01068 {
01069 double docWidth, docHeight;
01070 int pixmapSize = QMAX(size.width(), size.height());
01071
01072 if (m_pageLayout.ptWidth > 1.0) {
01073 docWidth = m_pageLayout.ptWidth / 72 * QPaintDevice::x11AppDpiX();
01074 docHeight = m_pageLayout.ptHeight / 72 * QPaintDevice::x11AppDpiX();
01075
01076 } else {
01077
01078 docWidth = 500.0;
01079 docHeight = 500.0;
01080 }
01081
01082 double ratio = docWidth / docHeight;
01083
01084 QPixmap pix;
01085 int previewWidth, previewHeight;
01086 if (ratio > 1.0)
01087 {
01088 previewWidth = (int) pixmapSize;
01089 previewHeight = (int) (pixmapSize / ratio);
01090 }
01091 else
01092 {
01093 previewWidth = (int) (pixmapSize * ratio);
01094 previewHeight = (int) pixmapSize;
01095 }
01096
01097 pix.resize((int)docWidth, (int)docHeight);
01098
01099 pix.fill( QColor( 245, 245, 245 ) );
01100
01101 QRect rc(0, 0, pix.width(), pix.height());
01102
01103 QPainter p;
01104 p.begin(&pix);
01105 paintEverything(p, rc, false);
01106 p.end();
01107
01108 pix.convertFromImage(pix.convertToImage().smoothScale(previewWidth, previewHeight));
01109
01110 return pix;
01111 }
01112
01113 QString KoDocument::autoSaveFile( const QString & path ) const
01114 {
01115
01116 KMimeType::Ptr mime = KMimeType::mimeType( nativeFormatMimeType() );
01117 QString extension = mime->property( "X-KDE-NativeExtension" ).toString();
01118 if ( path.isEmpty() )
01119 {
01120
01121
01122
01123 QString ret = QDir::homeDirPath() + "/." + QString::fromLatin1(instance()->instanceName()) + ".autosave" + extension;
01124 return ret;
01125 }
01126 else
01127 {
01128 KURL url( path );
01129 Q_ASSERT( url.isLocalFile() );
01130 QString dir = url.directory(false);
01131 QString filename = url.fileName();
01132 return dir + "." + filename + ".autosave" + extension;
01133 }
01134 }
01135
01136 bool KoDocument::checkAutoSaveFile()
01137 {
01138 QString asf = autoSaveFile( QString::null );
01139
01140 if ( QFile::exists( asf ) )
01141 {
01142 QDateTime date = QFileInfo(asf).lastModified();
01143 QString dateStr = date.toString(Qt::LocalDate);
01144 int res = KMessageBox::warningYesNoCancel(
01145 0, i18n( "An autosaved file for an unnamed document exists in %1.\nThis file is dated %2\nDo you want to open it?" )
01146 .arg(asf).arg( dateStr) );
01147 switch(res) {
01148 case KMessageBox::Yes : {
01149 KURL url;
01150 url.setPath( asf );
01151 bool ret = openURL( url );
01152 if ( ret )
01153 resetURL();
01154 return ret;
01155 }
01156 case KMessageBox::No :
01157 unlink( QFile::encodeName( asf ) );
01158 return false;
01159 default:
01160 return false;
01161 }
01162 }
01163 return false;
01164 }
01165
01166 bool KoDocument::import( const KURL & _url )
01167 {
01168 bool ret;
01169
01170 kdDebug (30003) << "KoDocument::import url=" << _url.url() << endl;
01171 d->m_isImporting = true;
01172
01173
01174 ret = openURL (_url);
01175
01176
01177
01178 if (ret)
01179 {
01180 kdDebug (30003) << "KoDocument::import success, resetting url" << endl;
01181 resetURL ();
01182 setTitleModified ();
01183 }
01184
01185 d->m_isImporting = false;
01186
01187 return ret;
01188 }
01189
01190 bool KoDocument::openURL( const KURL & _url )
01191 {
01192 kdDebug(30003) << "KoDocument::openURL url=" << _url.url() << endl;
01193 d->lastErrorMessage = QString::null;
01194
01195
01196 if ( !_url.isValid() )
01197 {
01198 d->lastErrorMessage = i18n( "Malformed URL\n%1" ).arg( _url.url() );
01199 return false;
01200 }
01201 if ( !closeURL() )
01202 return false;
01203 KURL url( _url );
01204 bool autosaveOpened = false;
01205 if ( url.isLocalFile() && d->m_shouldCheckAutoSaveFile )
01206 {
01207 QString file = url.path();
01208 QString asf = autoSaveFile( file );
01209 if ( QFile::exists( asf ) )
01210 {
01211
01212
01213 int res = KMessageBox::warningYesNoCancel( 0,
01214 i18n( "An autosaved file exists for this document.\nDo you want to open it instead?" ));
01215 switch(res) {
01216 case KMessageBox::Yes :
01217 url.setPath( asf );
01218 autosaveOpened = true;
01219 break;
01220 case KMessageBox::No :
01221 unlink( QFile::encodeName( asf ) );
01222 break;
01223 default:
01224 return false;
01225 }
01226 }
01227 }
01228 bool ret = KParts::ReadWritePart::openURL( url );
01229
01230 if ( autosaveOpened )
01231 resetURL();
01232 else
01233 {
01234
01235
01236
01237
01238 QPtrListIterator<KoMainWindow> it( d->m_shells );
01239 for (; it.current(); ++it )
01240 it.current()->addRecentURL( _url );
01241 }
01242 return ret;
01243 }
01244
01245 bool KoDocument::openFile()
01246 {
01247
01248 if ( ! QFile::exists(m_file) )
01249 {
01250 QApplication::restoreOverrideCursor();
01251 if ( d->m_autoErrorHandlingEnabled )
01252
01253 KMessageBox::error(0L, i18n("The file %1 doesn't exist.").arg(m_file) );
01254 return false;
01255 }
01256
01257 QApplication::setOverrideCursor( waitCursor );
01258
01259 if ( d->m_bSingleViewMode && !d->m_views.isEmpty() )
01260 {
01261
01262 KoView* v = d->m_views.first();
01263 removeView( v );
01264 delete v;
01265 Q_ASSERT( d->m_views.isEmpty() );
01266 }
01267
01268 d->m_specialOutputFlag = 0;
01269 QCString _native_format = nativeFormatMimeType();
01270
01271 KURL u;
01272 u.setPath( m_file );
01273 QString typeName = KMimeType::findByURL( u, 0, true )->name();
01274
01275
01276 if ( typeName == "application/x-trash" )
01277 {
01278 QString path = u.path();
01279 QStringList patterns = KMimeType::mimeType( typeName )->patterns();
01280
01281 for( QStringList::Iterator it = patterns.begin(); it != patterns.end(); ++it ) {
01282 QString ext = *it;
01283 if ( !ext.isEmpty() && ext[0] == '*' )
01284 {
01285 ext.remove(0, 1);
01286 if ( path.endsWith( ext ) ) {
01287 path.truncate( path.length() - ext.length() );
01288 break;
01289 }
01290 }
01291 }
01292 typeName = KMimeType::findByPath( path, 0, true )->name();
01293 }
01294
01295
01296 if ( u.fileName() == "maindoc.xml" || typeName == "inode/directory" )
01297 {
01298 typeName = _native_format;
01299 d->m_specialOutputFlag = SaveAsDirectoryStore;
01300 kdDebug(30003) << "KoDocument::openFile loading maindoc.xml, using directory store for " << m_file << endl;
01301 }
01302 kdDebug(30003) << "KoDocument::openFile " << m_file << " type:" << typeName << endl;
01303
01304 QString importedFile = m_file;
01305
01306 if ( typeName == KMimeType::defaultMimeType() ) {
01307 kdError(30003) << "No mimetype found for " << m_file << endl;
01308 QApplication::restoreOverrideCursor();
01309 if ( d->m_autoErrorHandlingEnabled )
01310 KMessageBox::error( 0L, i18n( "Could not open\n%1" ).arg( url().prettyURL( 0, KURL::StripFileProtocol ) ) );
01311 return false;
01312 }
01313
01314 if ( typeName.latin1() != _native_format ) {
01315 if ( !d->filterManager )
01316 d->filterManager = new KoFilterManager( this );
01317 KoFilter::ConversionStatus status;
01318 importedFile = d->filterManager->import( m_file, status );
01319 if ( status != KoFilter::OK )
01320 {
01321 QApplication::restoreOverrideCursor();
01322 if ( status != KoFilter::UserCancelled &&
01323 status != KoFilter::BadConversionGraph &&
01324 d->m_autoErrorHandlingEnabled )
01325
01326 KMessageBox::error( 0L, i18n( "Could not open\n%1" ).arg( url().prettyURL( 0, KURL::StripFileProtocol ) ) );
01327
01328 return false;
01329 }
01330 kdDebug(30003) << "KoDocument::openFile - importedFile '" << importedFile
01331 << "', status: " << static_cast<int>( status ) << endl;
01332 }
01333
01334 QApplication::restoreOverrideCursor();
01335
01336 bool ok = true;
01337
01338 if (!importedFile.isEmpty())
01339 {
01340
01341 if ( !loadNativeFormat( importedFile ) )
01342 {
01343 ok = false;
01344 if ( d->m_autoErrorHandlingEnabled )
01345 {
01346 if ( d->lastErrorMessage.isEmpty() )
01347 KMessageBox::error( 0L, i18n( "Could not open\n%1" ).arg( url().prettyURL( 0, KURL::StripFileProtocol ) ) );
01348 else if ( d->lastErrorMessage != "USER_CANCELED" )
01349 KMessageBox::error( 0L, i18n( "Could not open %1\nReason: %2" ).arg( url().prettyURL( 0, KURL::StripFileProtocol )).arg( d->lastErrorMessage ) );
01350 }
01351 }
01352 }
01353
01354 if ( importedFile != m_file )
01355 {
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367 #if 0
01368 if ( isReadWrite() )
01369 resetURL();
01370 #endif
01371
01372
01373 if(!importedFile.isEmpty())
01374 unlink( QFile::encodeName(importedFile) );
01375 }
01376
01377 if ( ok && d->m_bSingleViewMode )
01378 {
01379
01380 KXMLGUIFactory* guiFactory = factory();
01381 if( guiFactory )
01382 guiFactory->removeClient( this );
01383
01384 KoView *view = createView( d->m_wrapperWidget );
01385 d->m_wrapperWidget->setKoView( view );
01386 view->show();
01387
01388
01389
01390 if ( guiFactory )
01391 guiFactory->addClient( this );
01392 }
01393
01394 if ( ok )
01395 {
01396 d->mimeType = typeName.latin1 ();
01397
01398 d->outputMimeType = d->mimeType;
01399
01400 const bool needConfirm = (d->mimeType != _native_format);
01401 setConfirmNonNativeSave ( false, needConfirm );
01402 setConfirmNonNativeSave ( true, needConfirm );
01403 }
01404
01405 return ok;
01406 }
01407
01408 bool KoDocument::loadNativeFormat( const QString & file )
01409 {
01410 if ( !QFileInfo( file).isFile () )
01411 {
01412 d->lastErrorMessage = i18n( "%1 is not a file." ).arg(file);
01413 return false;
01414 }
01415
01416 QApplication::setOverrideCursor( waitCursor );
01417
01418 kdDebug(30003) << "KoDocument::loadNativeFormat( " << file << " )" << endl;
01419
01420 QFile in;
01421 bool isRawXML = false;
01422 if ( d->m_specialOutputFlag != SaveAsDirectoryStore )
01423 {
01424 in.setName(file);
01425 if ( !in.open( IO_ReadOnly ) )
01426 {
01427 QApplication::restoreOverrideCursor();
01428 d->lastErrorMessage = i18n( "Couldn't open the file for reading (check read permissions)." );
01429 return false;
01430 }
01431
01432
01433 char buf[5];
01434 if ( in.readBlock( buf, 4 ) < 4 )
01435 {
01436 QApplication::restoreOverrideCursor();
01437 in.close();
01438 d->lastErrorMessage = i18n( "Couldn't read the beginning of the file." );
01439 return false;
01440 }
01441 isRawXML = (strncasecmp( buf, "<?xm", 4 ) == 0);
01442
01443 }
01444
01445 if ( isRawXML )
01446 {
01447 in.at(0);
01448 QString errorMsg;
01449 int errorLine;
01450 int errorColumn;
01451 QDomDocument doc;
01452 bool res;
01453 if ( doc.setContent( &in , &errorMsg, &errorLine, &errorColumn ) )
01454 {
01455 res = loadXML( &in, doc );
01456 if ( res )
01457 res = completeLoading( 0L );
01458 }
01459 else
01460 {
01461 kdError (30003) << "Parsing Error! Aborting! (in KoDocument::loadNativeFormat (QFile))" << endl
01462 << " Line: " << errorLine << " Column: " << errorColumn << endl
01463 << " Message: " << errorMsg << endl;
01464 d->lastErrorMessage = i18n( "parsing error in the main document at line %1, column %2\nError message: %3" )
01465 .arg( errorLine ).arg( errorColumn ).arg( i18n ( "QXml", errorMsg.utf8() ) );
01466 res=false;
01467 }
01468
01469 QApplication::restoreOverrideCursor();
01470 in.close();
01471 m_bEmpty = false;
01472 return res;
01473 } else
01474 {
01475 in.close();
01476 KoStore::Backend backend = (d->m_specialOutputFlag == SaveAsDirectoryStore) ? KoStore::Directory : KoStore::Auto;
01477 KoStore * store = KoStore::createStore( file, KoStore::Read, "", backend );
01478
01479 if ( store->bad() )
01480 {
01481 d->lastErrorMessage = i18n( "Not a valid KOffice file." );
01482 delete store;
01483 QApplication::restoreOverrideCursor();
01484 return false;
01485 }
01486
01487 if ( store->open( "root" ) )
01488 {
01489 QString errorMsg;
01490 int errorLine;
01491 int errorColumn;
01492 QDomDocument doc;
01493 if ( !doc.setContent( store->device(), &errorMsg, &errorLine, &errorColumn ) )
01494 {
01495 kdError (30003) << "Parsing Error! Aborting! (in KoDocument::loadNativeFormat (KoStore))" << endl
01496 << " Line: " << errorLine << " Column: " << errorColumn << endl
01497 << " Message: " << errorMsg << endl;
01498 d->lastErrorMessage = i18n( "parsing error in the main document at line %1, column %2\nError message: %3" )
01499 .arg( errorLine ).arg( errorColumn ).arg( i18n ( errorMsg.utf8() ) );
01500 delete store;
01501 QApplication::restoreOverrideCursor();
01502 return false;
01503 }
01504 if ( !loadXML( store->device(), doc ) )
01505 {
01506 delete store;
01507 QApplication::restoreOverrideCursor();
01508 return false;
01509 }
01510 store->close();
01511 } else
01512 {
01513 kdError(30003) << "ERROR: No maindoc.xml" << endl;
01514 d->lastErrorMessage = i18n( "Invalid document: no file 'maindoc.xml'." );
01515 delete store;
01516 QApplication::restoreOverrideCursor();
01517 return false;
01518 }
01519
01520 if ( !loadChildren( store ) )
01521 {
01522 kdError(30003) << "ERROR: Could not load children" << endl;
01523
01524 #if 0
01525 if ( d->lastErrorMessage.isEmpty() )
01526 d->lastErrorMessage = i18n( "Couldn't load embedded objects." );
01527 delete store;
01528 QApplication::restoreOverrideCursor();
01529 return false;
01530 #endif
01531 }
01532 if ( store->open( "documentinfo.xml" ) )
01533 {
01534 QDomDocument doc;
01535 doc.setContent( store->device() );
01536 d->m_docInfo->load( doc );
01537 store->close();
01538 }
01539 else
01540 {
01541
01542 delete d->m_docInfo;
01543 d->m_docInfo = new KoDocumentInfo( this, "document info" );
01544 }
01545
01546 bool res = completeLoading( store );
01547 delete store;
01548 QApplication::restoreOverrideCursor();
01549 m_bEmpty = false;
01550 return res;
01551 }
01552 }
01553
01554 bool KoDocument::loadFromStore( KoStore* _store, const QString& url )
01555 {
01556 if ( _store->open( url ) )
01557 {
01558 QDomDocument doc;
01559 doc.setContent( _store->device() );
01560 if ( !loadXML( _store->device(), doc ) )
01561 {
01562 _store->close();
01563 return false;
01564 }
01565 _store->close();
01566 }
01567
01568 _store->pushDirectory();
01569
01570 if ( url.startsWith( STORE_PROTOCOL ) )
01571 m_url = KURL( url );
01572 else {
01573 m_url = KURL( INTERNAL_PREFIX + url );
01574 _store->enterDirectory( url );
01575 }
01576
01577 if ( !loadChildren( _store ) )
01578 {
01579 kdError(30003) << "ERROR: Could not load children" << endl;
01580 #if 0
01581 return false;
01582 #endif
01583 }
01584
01585 bool result = completeLoading( _store );
01586
01587
01588 _store->popDirectory();
01589
01590 return result;
01591 }
01592
01593 bool KoDocument::isInOperation()
01594 {
01595 return d->m_numOperations > 0;
01596 }
01597
01598 void KoDocument::emitBeginOperation()
01599 {
01600
01601
01602 if (!isInOperation())
01603 emit sigBeginOperation();
01604 d->m_numOperations++;
01605 }
01606
01607 void KoDocument::emitEndOperation()
01608 {
01609 d->m_numOperations--;
01610
01611
01612 if (d->m_numOperations == 0)
01613 emit sigEndOperation();
01614 else if (d->m_numOperations < 0)
01615
01616 d->m_numOperations = 0;
01617 }
01618
01619
01620 bool KoDocument::isStoredExtern()
01621 {
01622 return !storeInternal() && hasExternURL();
01623 }
01624
01625 void KoDocument::setModified( bool mod )
01626 {
01627
01628
01629
01630 d->modifiedAfterAutosave=mod;
01631 if ( isAutosaving() )
01632 return;
01633 if ( mod == KParts::ReadWritePart::isModified() )
01634 return;
01635
01636 KParts::ReadWritePart::setModified( mod );
01637
01638 if ( mod )
01639 m_bEmpty = FALSE;
01640
01641
01642 setTitleModified();
01643 }
01644
01645 void KoDocument::setDoNotSaveExtDoc( bool on )
01646 {
01647 d->m_doNotSaveExtDoc = on;
01648 }
01649
01650 int KoDocument::queryCloseDia()
01651 {
01652
01653
01654 QString name;
01655 if ( documentInfo() )
01656 {
01657 name = documentInfo()->title();
01658 }
01659 if ( name.isEmpty() )
01660 name = url().fileName();
01661
01662 if ( name.isEmpty() )
01663 name = i18n( "Untitled" );
01664
01665 int res = KMessageBox::warningYesNoCancel( 0L,
01666 i18n( "<p>The document <b>'%1'</b> has been modified.</p><p>Do you want to save it?</p>" ).arg(name));
01667
01668 switch(res)
01669 {
01670 case KMessageBox::Yes :
01671 setDoNotSaveExtDoc();
01672 save();
01673 setModified( false );
01674 break;
01675 case KMessageBox::No :
01676 removeAutoSaveFiles();
01677 setModified( false );
01678 break;
01679 default :
01680 return res;
01681 }
01682 return res;
01683 }
01684
01685 int KoDocument::queryCloseExternalChildren()
01686 {
01687
01688 setDoNotSaveExtDoc(false);
01689 QPtrListIterator<KoDocumentChild> it( children() );
01690 for (; it.current(); ++it )
01691 {
01692 if ( !it.current()->isDeleted() )
01693 {
01694 KoDocument *doc = it.current()->document();
01695 if ( doc )
01696 {
01697 if ( doc->isStoredExtern() )
01698 {
01699 if ( doc->isModified() )
01700 {
01701 kdDebug(30003)<<k_funcinfo<<" found modified child: "<<doc->url().url()<<" extern="<<doc->isStoredExtern()<<endl;
01702 if ( doc->queryCloseDia() == KMessageBox::Cancel )
01703 return KMessageBox::Cancel;
01704 }
01705 }
01706 if ( doc->queryCloseExternalChildren() == KMessageBox::Cancel )
01707 return KMessageBox::Cancel;
01708 }
01709 }
01710 }
01711 return KMessageBox::Ok;
01712 }
01713
01714 void KoDocument::setTitleModified( const QString caption, bool mod )
01715 {
01716
01717 KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
01718 if ( doc )
01719 {
01720 doc->setTitleModified( caption, mod );
01721 return;
01722 }
01723
01724 QPtrListIterator<KoMainWindow> it( d->m_shells );
01725 for (; it.current(); ++it )
01726 {
01727 it.current()->updateCaption( caption, mod );
01728 it.current()->updateReloadFileAction(this);
01729 }
01730 }
01731
01732 void KoDocument::setTitleModified()
01733 {
01734
01735 KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
01736 QString caption;
01737 if ( (url().isEmpty() || isStoredExtern()) && d->m_current )
01738 {
01739
01740 if ( documentInfo() )
01741 {
01742 KoDocumentInfoPage * page = documentInfo()->page( QString::fromLatin1("about") );
01743 if (page)
01744 caption = static_cast<KoDocumentInfoAbout *>(page)->title();
01745 }
01746 if ( caption.isEmpty() )
01747 caption = url().prettyURL( 0, KURL::StripFileProtocol );
01748
01749
01750 if ( doc )
01751 {
01752 doc->setTitleModified( caption, isModified() );
01753 return;
01754 }
01755 else
01756 {
01757
01758 setTitleModified( caption, isModified() );
01759 return;
01760 }
01761 }
01762 if ( doc )
01763 {
01764
01765 doc->setTitleModified();
01766 }
01767 }
01768
01769 bool KoDocument::loadChildren( KoStore* )
01770 {
01771 return true;
01772 }
01773
01774 bool KoDocument::completeLoading( KoStore* )
01775 {
01776 return true;
01777 }
01778
01779 bool KoDocument::completeSaving( KoStore* )
01780 {
01781 return true;
01782 }
01783
01784 QDomDocument KoDocument::createDomDocument( const QString& tagName, const QString& version ) const
01785 {
01786 return createDomDocument( instance()->instanceName(), tagName, version );
01787 }
01788
01789
01790 QDomDocument KoDocument::createDomDocument( const QString& appName, const QString& tagName, const QString& version )
01791 {
01792 QDomImplementation impl;
01793 QString url = QString("http://www.koffice.org/DTD/%1-%1.dtd").arg(appName).arg(version);
01794 QDomDocumentType dtype = impl.createDocumentType( tagName,
01795 QString("-//KDE//DTD %1 %1//EN").arg(appName).arg(version),
01796 url );
01797
01798 QString namespaceURN = QString("http://www.koffice.org/DTD/%1").arg(appName);
01799 QDomDocument doc = impl.createDocument( namespaceURN, tagName, dtype );
01800 doc.insertBefore( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ), doc.documentElement() );
01801 return doc;
01802 }
01803
01804 QDomDocument KoDocument::saveXML()
01805 {
01806 kdError(30003) << "KoDocument::saveXML not implemented" << endl;
01807 d->lastErrorMessage = i18n( "Internal error: saveXML not implemented" );
01808 return QDomDocument();
01809 }
01810
01811 KService::Ptr KoDocument::nativeService()
01812 {
01813 if ( !m_nativeService )
01814 m_nativeService = readNativeService( instance() );
01815
01816 return m_nativeService;
01817 }
01818
01819 QCString KoDocument::nativeFormatMimeType() const
01820 {
01821 KService::Ptr service = const_cast<KoDocument *>(this)->nativeService();
01822 if ( !service )
01823 return QCString();
01824 return service->property( "X-KDE-NativeMimeType" ).toString().latin1();
01825 }
01826
01827
01828 KService::Ptr KoDocument::readNativeService( KInstance *instance )
01829 {
01830 QString instname = instance ? instance->instanceName() : kapp->instanceName();
01831
01832
01833 QString servicepartname = instname + "part.desktop";
01834 KService::Ptr service = KService::serviceByDesktopPath( servicepartname );
01835 if ( service )
01836 kdDebug(30003) << servicepartname << " found." << endl;
01837 if ( !service )
01838 {
01839
01840
01841
01842
01843
01844 service = KService::serviceByDesktopPath( QString::fromLatin1("Office/%1.desktop").arg(instname) );
01845 }
01846 if ( !service )
01847 service = KService::serviceByDesktopName( instname );
01848
01849 #if KDE_IS_VERSION( 3, 1, 90 )
01850
01851 if ( !service )
01852 service = KService::serviceByStorageId( QString::fromLatin1( "kde-" ) + instname );
01853 #endif
01854
01855 if ( !service )
01856 return service;
01857
01858
01859 if ( service->property( "X-KDE-NativeMimeType" ).toString().isEmpty() )
01860 {
01861
01862 if ( KServiceType::serviceType( "KOfficePart" ) == 0L )
01863 kdError(30003) << "The serviceType KOfficePart is missing. Check that you have a kofficepart.desktop file in the share/servicetypes directory." << endl;
01864 else if ( instname != "koshell" )
01865 kdWarning(30003) << service->desktopEntryPath() << ": no X-KDE-NativeMimeType entry!" << endl;
01866 }
01867
01868 return service;
01869 }
01870
01871 QCString KoDocument::readNativeFormatMimeType( KInstance *instance )
01872 {
01873 KService::Ptr service = readNativeService( instance );
01874 if ( !service )
01875 return QCString();
01876 return service->property( "X-KDE-NativeMimeType" ).toString().latin1();
01877 }
01878
01879 void KoDocument::addShell( KoMainWindow *shell )
01880 {
01881 if ( d->m_shells.findRef( shell ) == -1 )
01882 {
01883
01884 d->m_shells.append( shell );
01885 }
01886 }
01887
01888 void KoDocument::removeShell( KoMainWindow *shell )
01889 {
01890
01891 d->m_shells.removeRef( shell );
01892 }
01893
01894 const QPtrList<KoMainWindow>& KoDocument::shells() const
01895 {
01896 return d->m_shells;
01897 }
01898
01899 int KoDocument::shellCount() const
01900 {
01901 return d->m_shells.count();
01902 }
01903
01904 DCOPObject * KoDocument::dcopObject()
01905 {
01906 if ( !d->m_dcopObject )
01907 d->m_dcopObject = new KoDocumentIface( this );
01908 return d->m_dcopObject;
01909 }
01910
01911 QCString KoDocument::dcopObjectId() const
01912 {
01913 return const_cast<KoDocument *>(this)->dcopObject()->objId();
01914 }
01915
01916 void KoDocument::setErrorMessage( const QString& errMsg )
01917 {
01918 d->lastErrorMessage = errMsg;
01919 }
01920
01921 bool KoDocument::isAutosaving()
01922 {
01923 return d->m_autosaving;
01924 }
01925
01926 void KoDocument::removeAutoSaveFiles()
01927 {
01928
01929 QString asf = autoSaveFile( m_file );
01930 if ( QFile::exists( asf ) )
01931 unlink( QFile::encodeName( asf ) );
01932 asf = autoSaveFile( QString::null );
01933 if ( QFile::exists( asf ) )
01934 unlink( QFile::encodeName( asf ) );
01935 }
01936
01937 void KoDocument::setBackupFile( bool _b )
01938 {
01939 d->m_backupFile = _b;
01940 }
01941
01942 bool KoDocument::backupFile()const
01943 {
01944 return d->m_backupFile;
01945 }
01946
01947
01948 void KoDocument::setBackupPath( const QString & _path)
01949 {
01950 d->m_backupPath = _path;
01951 }
01952
01953 QString KoDocument::backupPath()const
01954 {
01955 return d->m_backupPath;
01956 }
01957
01958 void KoDocument::setCurrent( bool on )
01959 {
01960
01961 KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
01962 if ( doc )
01963 {
01964 if ( !isStoredExtern() )
01965 {
01966
01967 doc->setCurrent( true );
01968 return;
01969 }
01970
01971 d->m_current = on;
01972 if ( !on )
01973 {
01974 doc->setCurrent( true );
01975 return;
01976 }
01977 doc->forceCurrent( false );
01978 }
01979 else
01980 d->m_current = on;
01981
01982 setTitleModified();
01983 }
01984
01985 void KoDocument::forceCurrent( bool on )
01986 {
01987
01988 d->m_current = on;
01989 KoDocument *doc = dynamic_cast<KoDocument *>( parent() );
01990 if ( doc )
01991 {
01992 doc->forceCurrent( false );
01993 }
01994 }
01995
01996 bool KoDocument::isCurrent() const
01997 {
01998 return d->m_current;
01999 }
02000
02001 bool KoDocument::storeInternal() const
02002 {
02003 return d->m_storeInternal;
02004 }
02005
02006 void KoDocument::setStoreInternal( bool i )
02007 {
02008 d->m_storeInternal = i;
02009
02010 }
02011
02012 bool KoDocument::hasExternURL()
02013 {
02014 return !url().protocol().isEmpty() && url().protocol() != STORE_PROTOCOL && url().protocol() != INTERNAL_PROTOCOL;
02015 }
02016
02017 KoDocument::InitDocFlags KoDocument::initDocFlags() const
02018 {
02019 return d->m_initDocFlags;
02020 }
02021
02022 void KoDocument::setInitDocFlags( InitDocFlags flags )
02023 {
02024 d->m_initDocFlags = flags;
02025 }
02026
02027 void KoDocument::slotStarted( KIO::Job* job )
02028 {
02029 if ( job )
02030 {
02031 job->setWindow( d->m_shells.current() );
02032 }
02033 }
02034
02035 #include "koDocument_p.moc"
02036 #include "koDocument.moc"