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 ) || !document() )
00113 return 0L;
00114
00115 QWMatrix m( _matrix );
00116 m = matrix() * m;
00117 m.scale( xScaling(), yScaling() );
00118
00119 return document()->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 = document()->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 = document()->loadFromStore( store, m_tmpURL );
00295 }
00296 internalURL = true;
00297 document()->setStoreInternal( true );
00298 }
00299 else
00300 {
00301
00302 document()->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 = document()->openURL( url );
00319
00320 }
00321 else
00322 res = document()->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" + errorMessage );
00339 else
00340 d->m_doc->setProperty( "unavailReason", i18n( "External document not found:\n%1" ).arg( tmpURL ) );
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( document() ) &&
00361 !parent->isSingleViewMode() )
00362 manager->addPart( document(), 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::saveOasisToStore( KoStore* store, KoXmlWriter* manifestWriter )
00388 {
00389 if ( document()->isStoredExtern() )
00390 return true;
00391
00392
00393
00394 assert( document()->url().protocol() == INTERNAL_PROTOCOL );
00395 const QString name = document()->url().path();
00396 kdDebug() << k_funcinfo << "saving " << name << endl;
00397
00398 if ( document()->nativeOasisMimeType().isEmpty() ) {
00399
00400
00401 if ( !document()->saveToStore( store, name ) )
00402 return false;
00403 }
00404 else
00405 {
00406
00407 store->pushDirectory();
00408 store->enterDirectory( name );
00409
00410 if ( !document()->saveOasis( store, manifestWriter ) ) {
00411 kdWarning(30003) << "KoDocumentChild::saveOasis failed" << endl;
00412 return false;
00413 }
00414
00415 store->popDirectory();
00416 }
00417
00418 return true;
00419 }
00420
00421 void KoDocumentChild::saveOasisAttributes( KoXmlWriter &xmlWriter, const QString& name )
00422 {
00423 if ( !document()->isStoredExtern() )
00424 {
00425
00426
00427 KURL u;
00428 u.setProtocol( INTERNAL_PROTOCOL );
00429 u.setPath( name );
00430 kdDebug() << k_funcinfo << u << endl;
00431 document()->setURL( u );
00432 }
00433
00434
00435 xmlWriter.addAttribute( "xlink:type", "simple" );
00436 xmlWriter.addAttribute( "xlink:show", "embed" );
00437 xmlWriter.addAttribute( "xlink:actuate", "onLoad" );
00438
00439 const QString ref = document()->isStoredExtern() ? document()->url().url() : "./"+ name;
00440 kdDebug(30003) << "KoDocumentChild::saveOasis saving reference to embedded document as " << ref << endl;
00441 xmlWriter.addAttribute( "xlink:href", "#" + ref );
00442 }
00443
00444 QDomElement KoDocumentChild::save( QDomDocument& doc, bool uppercase )
00445 {
00446 if( document() )
00447 {
00448 QDomElement e = doc.createElement( ( uppercase ? "OBJECT" : "object" ) );
00449 if ( document()->url().protocol() != INTERNAL_PROTOCOL ) {
00450 e.setAttribute( "url", document()->url().url() );
00451 kdDebug() << "KoDocumentChild::save url=" << document()->url().url() << endl;
00452 }
00453 else {
00454 e.setAttribute( "url", document()->url().path().mid( 1 ) );
00455 kdDebug() << "KoDocumentChild::save url=" << document()->url().path().mid( 1 ) << endl;
00456 }
00457 e.setAttribute( "mime", document()->nativeFormatMimeType() );
00458 kdDebug() << "KoDocumentChild::save mime=" << document()->nativeFormatMimeType() << endl;
00459 QDomElement rect = doc.createElement( ( uppercase ? "RECT" : "rect" ) );
00460 rect.setAttribute( "x", geometry().left() );
00461 rect.setAttribute( "y", geometry().top() );
00462 rect.setAttribute( "w", geometry().width() );
00463 rect.setAttribute( "h", geometry().height() );
00464 e.appendChild(rect);
00465 return e;
00466 }
00467 return QDomElement();
00468 }
00469
00470 bool KoDocumentChild::isStoredExtern() const
00471 {
00472 assert( document() );
00473 return document()->isStoredExtern();
00474 }
00475
00476 KURL KoDocumentChild::url() const
00477 {
00478 return ( document() ? document()->url() : KURL() );
00479 }
00480
00481 KoDocumentChild::~KoDocumentChild()
00482 {
00483 if ( d->m_doc ) {
00484 delete d->m_doc;
00485 d->m_doc=0L;
00486 }
00487 delete d;
00488 }
00489
00490 bool KoDocumentChild::isDeleted() const
00491 {
00492 return d->m_deleted;
00493 }
00494
00495 void KoDocumentChild::setDeleted( bool on )
00496 {
00497 d->m_deleted = on;
00498 }
00499
00500 #include "koDocumentChild.moc"