00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "KoDocumentChild.h"
00022 #include "KoOasisStore.h"
00023 #include <KoDocument.h>
00024 #include <KoQueryTrader.h>
00025 #include <KoXmlWriter.h>
00026 #include <KoXmlNS.h>
00027 #include <KoUnit.h>
00028 #include <KoStore.h>
00029 #include <KoStoreDevice.h>
00030
00031 #include <kparts/partmanager.h>
00032
00033 #include <kmimetype.h>
00034 #include <klocale.h>
00035 #include <kmessagebox.h>
00036 #include <kdebug.h>
00037
00038 #include <qapplication.h>
00039
00040 #include <assert.h>
00041
00042
00043
00044
00045 #define STORE_PROTOCOL "tar"
00046 #define INTERNAL_PROTOCOL "intern"
00047
00048
00049
00050
00051
00052
00053
00054
00055 class KoDocumentChildPrivate
00056 {
00057 public:
00058 KoDocumentChildPrivate()
00059 {
00060 }
00061 ~KoDocumentChildPrivate()
00062 {
00063 }
00064
00065 KoDocument *m_parent;
00066 KoDocument *m_doc;
00067 bool m_deleted;
00068 };
00069
00070 KoDocumentChild::KoDocumentChild( KoDocument* parent, KoDocument* doc, const QRect& geometry )
00071 : KoChild( parent )
00072 {
00073 d = new KoDocumentChildPrivate;
00074 d->m_parent = parent;
00075 d->m_doc = doc;
00076 setGeometry( geometry );
00077 d->m_deleted = false;
00078 if ( doc )
00079 doc->setStoreInternal( !doc->hasExternURL() );
00080 }
00081
00082 KoDocumentChild::KoDocumentChild( KoDocument* parent )
00083 : KoChild( parent )
00084 {
00085 d = new KoDocumentChildPrivate;
00086 d->m_parent = parent;
00087 d->m_doc = 0L;
00088 d->m_deleted = false;
00089 }
00090
00091 void KoDocumentChild::setDocument( KoDocument *doc, const QRect &geometry )
00092 {
00093 kdDebug()<<k_funcinfo<<"doc: "<<doc->url().url()<<endl;
00094 d->m_doc = doc;
00095 setGeometry( geometry );
00096
00097 updateMatrix();
00098 }
00099
00100 KoDocument *KoDocumentChild::document() const
00101 {
00102 return d->m_doc;
00103 }
00104
00105 KoDocument* KoDocumentChild::parentDocument() const
00106 {
00107 return d->m_parent;
00108 }
00109
00110 KoDocument* KoDocumentChild::hitTest( const QPoint &p, const QWMatrix &_matrix )
00111 {
00112 if ( !region( _matrix ).contains( p ) || !d->m_doc )
00113 return 0L;
00114
00115 QWMatrix m( _matrix );
00116 m = matrix() * m;
00117 m.scale( xScaling(), yScaling() );
00118
00119 return d->m_doc->hitTest( p, m );
00120 }
00121
00122 void KoDocumentChild::loadOasis( const QDomElement &frameElement, const QDomElement& objectElement )
00123 {
00124 double x, y, w, h;
00125 x = KoUnit::parseValue( frameElement.attributeNS( KoXmlNS::svg, "x", QString::null ) );
00126 y = KoUnit::parseValue( frameElement.attributeNS( KoXmlNS::svg, "y", QString::null ) );
00127 w = KoUnit::parseValue( frameElement.attributeNS( KoXmlNS::svg, "width", QString::null ) );
00128 h = KoUnit::parseValue( frameElement.attributeNS( KoXmlNS::svg, "height", QString::null ) );
00129 m_tmpGeometry = QRect((int)x, (int)y, (int)w, (int)h);
00130 setGeometry(m_tmpGeometry);
00131
00132 QString url = objectElement.attributeNS( KoXmlNS::xlink, "href", QString::null );
00133 if ( url[0] == '#' )
00134 url = url.mid( 1 );
00135 if ( url.startsWith( "./" ) )
00136 m_tmpURL = QString( INTERNAL_PROTOCOL ) + ":/" + url.mid( 2 );
00137 else
00138 m_tmpURL = url;
00139 kdDebug() << k_funcinfo << m_tmpURL << endl;
00140 }
00141
00142
00143 bool KoDocumentChild::load( const QDomElement& element, bool uppercase )
00144 {
00145 if ( element.hasAttribute( "url" ) )
00146 m_tmpURL = element.attribute("url");
00147 if ( element.hasAttribute("mime") )
00148 m_tmpMimeType = element.attribute("mime");
00149
00150 if ( m_tmpURL.isEmpty() )
00151 {
00152 kdDebug(30003) << "Empty 'url' attribute in OBJECT" << endl;
00153 return false;
00154 }
00155 if ( m_tmpMimeType.isEmpty() )
00156 {
00157 kdDebug(30003) << "Empty 'mime' attribute in OBJECT" << endl;
00158 return false;
00159 }
00160
00161 bool brect = FALSE;
00162 QDomNode n = element.firstChild();
00163 for( ; !n.isNull(); n = n.nextSibling() )
00164 {
00165 QDomElement e = n.toElement();
00166 if ( e.isNull() ) continue;
00167 if ( e.tagName() == "rect" || ( uppercase && e.tagName() == "RECT" ) )
00168 {
00169 brect = true;
00170 int x, y, w, h;
00171 x=y=w=h=0;
00172 if ( e.hasAttribute( "x" ) )
00173 x = e.attribute( "x" ).toInt(&brect);
00174 if ( e.hasAttribute( "y" ) )
00175 y = e.attribute( "y" ).toInt(&brect);
00176 if ( e.hasAttribute( "w" ) )
00177 w = e.attribute( "w" ).toInt(&brect);
00178 if ( e.hasAttribute( "h" ) )
00179 h = e.attribute( "h" ).toInt(&brect);
00180 m_tmpGeometry = QRect(x, y, w, h);
00181 setGeometry(m_tmpGeometry);
00182 }
00183 }
00184
00185 if ( !brect )
00186 {
00187 kdDebug(30003) << "Missing RECT in OBJECT" << endl;
00188 return false;
00189 }
00190
00191 return true;
00192 }
00193
00194 bool KoDocumentChild::loadDocument( KoStore* store )
00195 {
00196 assert( !m_tmpURL.isEmpty() );
00197
00198 kdDebug(30003) << "KoDocumentChild::loadDocument: trying to load " << m_tmpURL << endl;
00199
00200
00201 if ( m_tmpMimeType == "application/x-killustrator" )
00202 m_tmpMimeType = "application/x-kontour";
00203
00204 KoDocumentEntry e = KoDocumentEntry::queryByMimeType( m_tmpMimeType );
00205 if ( e.isEmpty() )
00206 {
00207 kdWarning(30003) << "Could not create child document with type " << m_tmpMimeType << endl;
00208 bool res = createUnavailDocument( store, true, m_tmpMimeType );
00209 if ( res )
00210 {
00211
00212 QString mimeName = m_tmpMimeType;
00213 KMimeType::Ptr mime = KMimeType::mimeType( m_tmpMimeType );
00214 if ( mime->name() != KMimeType::defaultMimeType() )
00215 mimeName = mime->comment();
00216 d->m_doc->setProperty( "unavailReason", i18n( "No handler found for %1" ).arg( mimeName ) );
00217 }
00218 return res;
00219 }
00220
00221 return loadDocumentInternal( store, e, true , false );
00222 }
00223
00224 bool KoDocumentChild::loadOasisDocument( KoStore* store, const QDomDocument& manifestDoc )
00225 {
00226 QString path = m_tmpURL;
00227 if ( m_tmpURL.startsWith( INTERNAL_PROTOCOL ) ) {
00228 path = store->currentDirectory();
00229 if ( !path.isEmpty() )
00230 path += '/';
00231 QString relPath = KURL( m_tmpURL ).path();
00232 path += relPath.mid( 1 );
00233 }
00234 if ( !path.endsWith( "/" ) )
00235 path += '/';
00236 const QString mimeType = KoOasisStore::mimeForPath( manifestDoc, path );
00237 kdDebug() << k_funcinfo << "path for manifest file=" << path << " mimeType=" << mimeType << endl;
00238 if ( mimeType.isEmpty() ) {
00239 kdError(30003) << "Manifest doesn't have media-type for " << path << endl;
00240 return false;
00241 }
00242
00243 KoDocumentEntry e = KoDocumentEntry::queryByMimeType( mimeType );
00244 if ( e.isEmpty() )
00245 {
00246 kdWarning(30003) << "Could not create child document with type " << mimeType << endl;
00247 bool res = createUnavailDocument( store, true, mimeType );
00248 if ( res )
00249 {
00250
00251 QString mimeName = mimeType;
00252 KMimeType::Ptr mime = KMimeType::mimeType( mimeType );
00253 if ( mime->name() != KMimeType::defaultMimeType() )
00254 mimeName = mime->comment();
00255 d->m_doc->setProperty( "unavailReason", i18n( "No handler found for %1" ).arg( mimeName ) );
00256 }
00257 return res;
00258 }
00259
00260 const bool oasis = mimeType.startsWith( "application/vnd.oasis.opendocument" );
00261 if ( !oasis ) {
00262 m_tmpURL += "/maindoc.xml";
00263 kdDebug() << " m_tmpURL adjusted to " << m_tmpURL << endl;
00264 }
00265 return loadDocumentInternal( store, e, true , oasis );
00266 }
00267
00268 bool KoDocumentChild::loadDocumentInternal( KoStore* store, const KoDocumentEntry& e, bool doOpenURL, bool oasis )
00269 {
00270 kdDebug(30003) << "KoDocumentChild::loadDocumentInternal doOpenURL=" << doOpenURL << " m_tmpURL=" << m_tmpURL << endl;
00271 KoDocument * doc = e.createDoc( d->m_parent );
00272 if (!doc) {
00273 kdWarning(30003) << "createDoc failed" << endl;
00274 return false;
00275 }
00276 setDocument( doc, m_tmpGeometry );
00277
00278 bool res = true;
00279 if ( doOpenURL )
00280 {
00281 bool internalURL = false;
00282 if ( m_tmpURL.startsWith( STORE_PROTOCOL ) || m_tmpURL.startsWith( INTERNAL_PROTOCOL ) || KURL::isRelativeURL( m_tmpURL ) )
00283 {
00284 if ( oasis ) {
00285 store->pushDirectory();
00286 assert( m_tmpURL.startsWith( INTERNAL_PROTOCOL ) );
00287 QString relPath = KURL( m_tmpURL ).path().mid( 1 );
00288 store->enterDirectory( relPath );
00289 res = d->m_doc->loadOasisFromStore( store );
00290 store->popDirectory();
00291 } else {
00292 if ( m_tmpURL.startsWith( INTERNAL_PROTOCOL ) )
00293 m_tmpURL = KURL( m_tmpURL ).path().mid( 1 );
00294 res = d->m_doc->loadFromStore( store, m_tmpURL );
00295 }
00296 internalURL = true;
00297 d->m_doc->setStoreInternal( true );
00298 }
00299 else
00300 {
00301
00302 d->m_doc->setStoreInternal( false );
00303 KURL url( m_tmpURL );
00304 if ( !url.isLocalFile() )
00305 {
00306 QApplication::restoreOverrideCursor();
00307
00308 int result = KMessageBox::warningYesNoCancel(
00309 0, i18n( "This document contains an external link to a remote document\n%1").arg(m_tmpURL),
00310 i18n( "Confirmation Required" ), i18n( "Download" ), i18n( "Skip" ) );
00311
00312 if ( result == KMessageBox::Cancel )
00313 {
00314 d->m_parent->setErrorMessage("USER_CANCELED");
00315 return false;
00316 }
00317 if ( result == KMessageBox::Yes )
00318 res = d->m_doc->openURL( url );
00319
00320 }
00321 else
00322 res = d->m_doc->openURL( url );
00323 }
00324 if ( !res )
00325 {
00326
00327 QString errorMessage = d->m_doc->errorMessage();
00328 delete d->m_doc;
00329 d->m_doc = 0;
00330 QString tmpURL = m_tmpURL;
00331
00332 res = createUnavailDocument( store, false , m_tmpMimeType );
00333 if ( res )
00334 {
00335 d->m_doc->setProperty( "realURL", tmpURL );
00336 d->m_doc->setStoreInternal( true );
00337 if ( internalURL )
00338 d->m_doc->setProperty( "unavailReason", i18n( "Could not load embedded object:\n%1" ).arg( errorMessage ) );
00339 else
00340 d->m_doc->setProperty( "unavailReason", i18n( "Could not load external document %1:\n%2" ).arg( tmpURL, errorMessage ) );
00341 }
00342 return res;
00343 }
00344
00345 QApplication::setOverrideCursor( waitCursor );
00346 }
00347
00348 m_tmpURL = QString::null;
00349
00350
00351
00352 if ( parentDocument() )
00353 {
00354 KoDocument *parent = parentDocument();
00355
00356 if ( parent->manager() && parent->manager()->parts() )
00357 {
00358 KParts::PartManager *manager = parent->manager();
00359
00360 if ( !manager->parts()->containsRef( d->m_doc ) &&
00361 !parent->isSingleViewMode() )
00362 manager->addPart( d->m_doc, false );
00363 }
00364 }
00365
00366 QApplication::restoreOverrideCursor();
00367
00368 return res;
00369 }
00370
00371 bool KoDocumentChild::createUnavailDocument( KoStore* store, bool doOpenURL, const QString& mimeType )
00372 {
00373
00374 KService::Ptr serv = KService::serviceByDesktopName( "kounavail" );
00375 if ( serv == 0L )
00376 {
00377 kdWarning(30003) << "ERROR: service kounavail not found " << endl;
00378 return false;
00379 }
00380 KoDocumentEntry e( serv );
00381 if ( !loadDocumentInternal( store, e, doOpenURL, false ) )
00382 return false;
00383 d->m_doc->setProperty( "mimetype", mimeType );
00384 return true;
00385 }
00386
00387 bool KoDocumentChild::saveOasis( KoStore* store, KoXmlWriter* manifestWriter )
00388 {
00389 QString path;
00390 if ( d->m_doc->isStoredExtern() )
00391 {
00392 kdDebug(30003)<<k_funcinfo<<" external (don't save) url:" << d->m_doc->url().url()<<endl;
00393 path = d->m_doc->url().url();
00394 }
00395 else
00396 {
00397
00398
00399 assert( d->m_doc->url().protocol() == INTERNAL_PROTOCOL );
00400 const QString name = d->m_doc->url().path();
00401 kdDebug() << k_funcinfo << "saving " << name << endl;
00402
00403 if ( d->m_doc->nativeOasisMimeType().isEmpty() ) {
00404
00405 kdDebug() << k_funcinfo << "Embedded object doesn't support OASIS OpenDocument, save in the old format." << endl;
00406
00407 if ( !d->m_doc->saveToStore( store, name ) )
00408 return false;
00409 }
00410 else
00411 {
00412
00413 store->pushDirectory();
00414 store->enterDirectory( name );
00415
00416 if ( !d->m_doc->saveOasis( store, manifestWriter ) ) {
00417 kdWarning(30003) << "KoDocumentChild::saveOasis failed" << endl;
00418 return false;
00419 }
00420
00421 store->popDirectory();
00422 }
00423
00424 assert( d->m_doc->url().protocol() == INTERNAL_PROTOCOL );
00425 path = store->currentDirectory();
00426 if ( !path.isEmpty() )
00427 path += '/';
00428 path += d->m_doc->url().path();
00429 if ( path.startsWith( "/" ) )
00430 path = path.mid( 1 );
00431 }
00432
00433
00434 if ( !path.endsWith( "/" ) )
00435 path += '/';
00436 QCString mimetype = d->m_doc->nativeOasisMimeType();
00437 if ( mimetype.isEmpty() )
00438 mimetype = d->m_doc->nativeFormatMimeType();
00439 manifestWriter->addManifestEntry( path, mimetype );
00440
00441 return true;
00442 }
00443
00444 void KoDocumentChild::saveOasisAttributes( KoXmlWriter &xmlWriter, const QString& name )
00445 {
00446 if ( !d->m_doc->isStoredExtern() )
00447 {
00448
00449
00450 KURL u;
00451 u.setProtocol( INTERNAL_PROTOCOL );
00452 u.setPath( name );
00453 kdDebug() << k_funcinfo << u << endl;
00454 d->m_doc->setURL( u );
00455 }
00456
00457
00458 xmlWriter.addAttribute( "xlink:type", "simple" );
00459 xmlWriter.addAttribute( "xlink:show", "embed" );
00460 xmlWriter.addAttribute( "xlink:actuate", "onLoad" );
00461
00462 const QString ref = d->m_doc->isStoredExtern() ? d->m_doc->url().url() : "./"+ name;
00463 kdDebug(30003) << "KoDocumentChild::saveOasis saving reference to embedded document as " << ref << endl;
00464 xmlWriter.addAttribute( "xlink:href", ref );
00465 }
00466
00467 QDomElement KoDocumentChild::save( QDomDocument& doc, bool uppercase )
00468 {
00469 if( d->m_doc )
00470 {
00471 QDomElement e = doc.createElement( ( uppercase ? "OBJECT" : "object" ) );
00472 if ( d->m_doc->url().protocol() != INTERNAL_PROTOCOL ) {
00473 e.setAttribute( "url", d->m_doc->url().url() );
00474 kdDebug() << "KoDocumentChild::save url=" << d->m_doc->url().url() << endl;
00475 }
00476 else {
00477 e.setAttribute( "url", d->m_doc->url().path().mid( 1 ) );
00478 kdDebug() << "KoDocumentChild::save url=" << d->m_doc->url().path().mid( 1 ) << endl;
00479 }
00480 e.setAttribute( "mime", d->m_doc->nativeFormatMimeType() );
00481 kdDebug() << "KoDocumentChild::save mime=" << d->m_doc->nativeFormatMimeType() << endl;
00482 QDomElement rect = doc.createElement( ( uppercase ? "RECT" : "rect" ) );
00483 rect.setAttribute( "x", geometry().left() );
00484 rect.setAttribute( "y", geometry().top() );
00485 rect.setAttribute( "w", geometry().width() );
00486 rect.setAttribute( "h", geometry().height() );
00487 e.appendChild(rect);
00488 return e;
00489 }
00490 return QDomElement();
00491 }
00492
00493 bool KoDocumentChild::isStoredExtern() const
00494 {
00495 assert( d->m_doc );
00496 return d->m_doc->isStoredExtern();
00497 }
00498
00499 KURL KoDocumentChild::url() const
00500 {
00501 return ( d->m_doc ? d->m_doc->url() : KURL() );
00502 }
00503
00504 KoDocumentChild::~KoDocumentChild()
00505 {
00506 if ( d->m_doc ) {
00507 delete d->m_doc;
00508 d->m_doc=0L;
00509 }
00510 delete d;
00511 }
00512
00513 bool KoDocumentChild::isDeleted() const
00514 {
00515 return d->m_deleted;
00516 }
00517
00518 void KoDocumentChild::setDeleted( bool on )
00519 {
00520 d->m_deleted = on;
00521 }
00522
00523 #include "KoDocumentChild.moc"