lib Library API Documentation

koDocumentChild.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
00003    Copyright (C) 2004-2005 David Faure <faure@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018    Boston, MA 02111-1307, USA.
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 // Define the protocol used here for embedded documents' URL
00043 // This used to "store" but KURL didn't like it,
00044 // so let's simply make it "tar" !
00045 #define STORE_PROTOCOL "tar"
00046 #define INTERNAL_PROTOCOL "intern"
00047 // Warning, keep it sync in koStore.cc and koDocument.cc
00048 
00049 /**********************************************************
00050  *
00051  * KoDocumentChild
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); // #### double->int conversion
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     // Backwards compatibility
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             // Try to turn the mimetype name into its comment
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 /*open url*/, false /*not oasis*/ );
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 ); // remove leading '/'
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             // Try to turn the mimetype name into its comment
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 /*open url*/, 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             // Reference to an external document. Hmmm...
00302             document()->setStoreInternal( false );
00303             KURL url( m_tmpURL );
00304             if ( !url.isLocalFile() )
00305             {
00306                 QApplication::restoreOverrideCursor();
00307                 // For security reasons we need to ask confirmation if the url is remote
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                 // and if == No, res will still be false so we'll use a kounavail below
00320             }
00321             else
00322                 res = document()->openURL( url );
00323         }
00324         if ( !res )
00325         {
00326             // Keep the error message from the attempted loading
00327             QString errorMessage = d->m_doc->errorMessage();
00328             delete d->m_doc;
00329             d->m_doc = 0;
00330             QString tmpURL = m_tmpURL; // keep a copy, createUnavailDocument will erase it
00331             // Not found -> use a kounavail instead
00332             res = createUnavailDocument( store, false /* the URL doesn't exist, don't try to open it */, m_tmpMimeType );
00333             if ( res )
00334             {
00335                 d->m_doc->setProperty( "realURL", tmpURL ); // so that it gets saved correctly
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         // Still waiting...
00345         QApplication::setOverrideCursor( waitCursor );
00346     }
00347 
00348     m_tmpURL = QString::null;
00349 
00350     // see KoDocument::insertChild for an explanation what's going on
00351     // now :-)
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     // We don't need a trader query here. We're looking for a very specific component.
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; // nothing to do
00391 
00392     // The name comes from KoDocumentChild (which was set while saving the
00393     // parent document).
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         // Embedded object doesn't support OASIS OpenDocument, save in the old format.
00400 
00401         if ( !document()->saveToStore( store, name ) )
00402             return false;
00403     }
00404     else
00405     {
00406         // To make the children happy cd to the correct directory
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         // Now that we're done leave the directory again
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         // set URL in document so that KoDocument::saveChildrenOasis will save
00426         // the actual embedded object with the right name in the store.
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     //<draw:object draw:style-name="standard" draw:id="1" draw:layer="layout" svg:width="14.973cm" svg:height="4.478cm" svg:x="11.641cm" svg:y="14.613cm" xlink:href="#./Object 1" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>
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"
KDE Logo
This file is part of the documentation for lib Library Version 1.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Feb 13 09:40:00 2006 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003