Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit b6c5ba1b authored by Pino Toscano's avatar Pino Toscano

Add API to load and save "document archives", ie an .okular archive with...

Add API to load and save "document archives", ie an .okular archive with document and metadata (currently annotations).
Few missing to be done in it:
- more checks when saving
- make it use a proper mimetype

CCBUG: 151614

svn path=/trunk/KDE/kdegraphics/okular/; revision=884597
parent cd6f369f
......@@ -45,6 +45,7 @@
#include <kstandarddirs.h>
#include <ktemporaryfile.h>
#include <ktoolinvocation.h>
#include <kzip.h>
// local includes
#include "action.h"
......@@ -69,9 +70,12 @@
#include "sourcereference.h"
#include "sourcereference_p.h"
#include "texteditors_p.h"
#include "utils_p.h"
#include "view.h"
#include "view_p.h"
#include <memory>
#include <config-okular.h>
using namespace Okular;
......@@ -86,6 +90,16 @@ struct AllocatedPixmap
AllocatedPixmap( int i, int p, qulonglong m ) : id( i ), page( p ), memory( m ) {}
};
struct ArchiveData
{
ArchiveData()
{
}
KTemporaryFile document;
QString metadataFileName;
};
struct RunningSearch
{
// store search properties
......@@ -671,6 +685,36 @@ bool DocumentPrivate::openDocumentInternal( const KService::Ptr& offer, bool iss
return openOk;
}
bool DocumentPrivate::savePageDocumentInfo( KTemporaryFile *infoFile, int what ) const
{
if ( infoFile->open() )
{
// 1. Create DOM
QDomDocument doc( "documentInfo" );
QDomProcessingInstruction xmlPi = doc.createProcessingInstruction(
QString::fromLatin1( "xml" ), QString::fromLatin1( "version=\"1.0\" encoding=\"utf-8\"" ) );
doc.appendChild( xmlPi );
QDomElement root = doc.createElement( "documentInfo" );
doc.appendChild( root );
// 2.1. Save page attributes (bookmark state, annotations, ... ) to DOM
QDomElement pageList = doc.createElement( "pageList" );
root.appendChild( pageList );
// <page list><page number='x'>.... </page> save pages that hold data
QVector< Page * >::const_iterator pIt = m_pagesVector.constBegin(), pEnd = m_pagesVector.constEnd();
for ( ; pIt != pEnd; ++pIt )
(*pIt)->d->saveLocalContents( pageList, doc, PageItems( what ) );
// 3. Save DOM to XML file
QString xml = doc.toString();
QTextStream os( infoFile );
os.setCodec( "UTF-8" );
os << xml;
return true;
}
return false;
}
void DocumentPrivate::saveDocumentInfo() const
{
if ( m_xmlFileName.isEmpty() )
......@@ -1461,7 +1505,7 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
// determine the related "xml document-info" filename
d->m_url = url;
d->m_docFileName = docFile;
if ( url.isLocalFile() )
if ( url.isLocalFile() && !d->m_archiveData )
{
QString fn = url.fileName();
document_size = fileReadTest.size();
......@@ -1566,7 +1610,14 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
d->m_generatorName = offer->name();
// 2. load Additional Data (our bookmarks and metadata) about the document
d->loadDocumentInfo();
if ( d->m_archiveData )
{
d->loadDocumentInfo( d->m_archiveData->metadataFileName );
}
else
{
d->loadDocumentInfo();
}
d->m_bookmarkManager->setUrl( d->m_url );
// 3. setup observers inernal lists and data
......@@ -1702,6 +1753,8 @@ void Document::closeDocument()
d->m_xmlFileName = QString();
delete d->m_tempFile;
d->m_tempFile = 0;
delete d->m_archiveData;
d->m_archiveData = 0;
d->m_docSize = -1;
d->m_exportCached = false;
d->m_exportFormats.clear();
......@@ -3090,6 +3143,152 @@ QByteArray Document::fontData(const FontInfo &font) const
return result;
}
bool Document::openDocumentArchive( const QString & docFile, const KUrl & url )
{
const KMimeType::Ptr mime = KMimeType::findByPath( docFile, 0, false /* content too */ );
if ( !mime->is( "application/zip" ) ) // ### use correct mimetype
return false;
KZip okularArchive( docFile );
if ( !okularArchive.open( QIODevice::ReadOnly ) )
return false;
const KArchiveDirectory * mainDir = okularArchive.directory();
const KArchiveEntry * mainEntry = mainDir->entry( "content.xml" );
if ( !mainEntry || !mainEntry->isFile() )
return false;
std::auto_ptr< QIODevice > mainEntryDevice( static_cast< const KZipFileEntry * >( mainEntry )->createDevice() );
QDomDocument doc;
if ( !doc.setContent( mainEntryDevice.get() ) )
return false;
mainEntryDevice.reset();
QDomElement root = doc.documentElement();
if ( root.tagName() != "OkularArchive" )
return false;
QString documentFileName;
QString metadataFileName;
QDomElement el = root.firstChild().toElement();
for ( ; !el.isNull(); el = el.nextSibling().toElement() )
{
if ( el.tagName() == "Files" )
{
QDomElement fileEl = el.firstChild().toElement();
for ( ; !fileEl.isNull(); fileEl = fileEl.nextSibling().toElement() )
{
if ( fileEl.tagName() == "DocumentFileName" )
documentFileName = fileEl.text();
else if ( fileEl.tagName() == "MetadataFileName" )
metadataFileName = fileEl.text();
}
}
}
if ( documentFileName.isEmpty() )
return false;
const KArchiveEntry * docEntry = mainDir->entry( documentFileName );
if ( !docEntry || !docEntry->isFile() )
return false;
std::auto_ptr< ArchiveData > archiveData( new ArchiveData() );
const int dotPos = documentFileName.indexOf( '.' );
if ( dotPos != -1 )
archiveData->document.setSuffix( documentFileName.mid( dotPos ) );
if ( !archiveData->document.open() )
return false;
QString tempFileName = archiveData->document.fileName();
{
std::auto_ptr< QIODevice > docEntryDevice( static_cast< const KZipFileEntry * >( docEntry )->createDevice() );
copyQIODevice( docEntryDevice.get(), &archiveData->document );
archiveData->document.close();
}
std::auto_ptr< KTemporaryFile > tempMetadataFileName;
const KArchiveEntry * metadataEntry = mainDir->entry( metadataFileName );
if ( metadataEntry && metadataEntry->isFile() )
{
std::auto_ptr< QIODevice > metadataEntryDevice( static_cast< const KZipFileEntry * >( metadataEntry )->createDevice() );
tempMetadataFileName.reset( new KTemporaryFile() );
tempMetadataFileName->setSuffix( ".xml" );
tempMetadataFileName->setAutoRemove( false );
if ( tempMetadataFileName->open() )
{
copyQIODevice( metadataEntryDevice.get(), tempMetadataFileName.get() );
archiveData->metadataFileName = tempMetadataFileName->fileName();
tempMetadataFileName->close();
}
}
const KMimeType::Ptr docMime = KMimeType::findByPath( tempFileName, 0, true /* local file */ );
d->m_archiveData = archiveData.get();
bool ret = openDocument( tempFileName, url, docMime );
if ( ret )
{
archiveData.release();
}
else
{
d->m_archiveData = 0;
}
return ret;
}
bool Document::saveDocumentArchive( const QString &fileName )
{
if ( !d->m_generator )
return false;
QString docFileName = d->m_url.fileName();
if ( docFileName == QLatin1String( "-" ) )
return false;
KZip okularArchive( fileName );
if ( !okularArchive.open( QIODevice::WriteOnly ) )
return false;
const KUser user;
const KUserGroup userGroup( user.gid() );
QDomDocument contentDoc( "OkularArchive" );
QDomProcessingInstruction xmlPi = contentDoc.createProcessingInstruction(
QString::fromLatin1( "xml" ), QString::fromLatin1( "version=\"1.0\" encoding=\"utf-8\"" ) );
contentDoc.appendChild( xmlPi );
QDomElement root = contentDoc.createElement( "OkularArchive" );
contentDoc.appendChild( root );
QDomElement filesNode = contentDoc.createElement( "Files" );
root.appendChild( filesNode );
QDomElement fileNameNode = contentDoc.createElement( "DocumentFileName" );
filesNode.appendChild( fileNameNode );
fileNameNode.appendChild( contentDoc.createTextNode( docFileName ) );
QDomElement metadataFileNameNode = contentDoc.createElement( "MetadataFileName" );
filesNode.appendChild( metadataFileNameNode );
metadataFileNameNode.appendChild( contentDoc.createTextNode( "metadata.xml" ) );
KTemporaryFile metadataFile;
if ( !d->savePageDocumentInfo( &metadataFile, AnnotationPageItems ) )
return false;
const QByteArray contentDocXml = contentDoc.toByteArray();
okularArchive.writeFile( "content.xml", user.loginName(), userGroup.name(),
contentDocXml.constData(), contentDocXml.length() );
okularArchive.addLocalFile( d->m_docFileName, docFileName );
okularArchive.addLocalFile( metadataFile.fileName(), "metadata.xml" );
if ( !okularArchive.close() )
return false;
return true;
}
void DocumentPrivate::requestDone( PixmapRequest * req )
{
if ( !req )
......
......@@ -558,6 +558,20 @@ class OKULAR_EXPORT Document : public QObject
*/
QByteArray fontData(const FontInfo &font) const;
/**
* Opens a document archive.
*
* @since 0.8 (KDE 4.2)
*/
bool openDocumentArchive( const QString & docFile, const KUrl & url );
/**
* Saves a document archive.
*
* @since 0.8 (KDE 4.2)
*/
bool saveDocumentArchive( const QString &fileName );
public Q_SLOTS:
/**
* This slot is called whenever the user changes the @p rotation of
......
......@@ -32,6 +32,7 @@ class QTimer;
class KTemporaryFile;
struct AllocatedPixmap;
struct ArchiveData;
struct RunningSearch;
namespace Okular {
......@@ -82,6 +83,7 @@ class DocumentPrivate
m_generatorsLoaded( false ),
m_closingLoop( 0 ),
m_scripter( 0 ),
m_archiveData( 0 ),
m_fontsCached( false )
{
calculateMaxTextPages();
......@@ -109,6 +111,7 @@ class DocumentPrivate
ConfigInterface* generatorConfig( GeneratorInfo& info );
SaveInterface* generatorSave( GeneratorInfo& info );
bool openDocumentInternal( const KService::Ptr& offer, bool isstdin, const QString& docFile, const QByteArray& filedata );
bool savePageDocumentInfo( KTemporaryFile *infoFile, int what ) const;
// private slots
void saveDocumentInfo() const;
......@@ -211,6 +214,8 @@ class DocumentPrivate
Scripter *m_scripter;
ArchiveData *m_archiveData;
QPointer< FontExtractionThread > m_fontThread;
bool m_fontsCached;
FontInfo::List m_fontsCache;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment