mirror of
https://invent.kde.org/graphics/okular
synced 2024-10-02 14:14:10 +00:00
core: support for migration of annots and forms out of docdata/
This commit is contained in:
parent
3e1b1ff04c
commit
e059d2652c
|
@ -606,22 +606,22 @@ qulonglong DocumentPrivate::getFreeMemory( qulonglong *freeSwap )
|
|||
#endif
|
||||
}
|
||||
|
||||
void DocumentPrivate::loadDocumentInfo( LoadDocumentInfoFlags loadWhat )
|
||||
bool DocumentPrivate::loadDocumentInfo( LoadDocumentInfoFlags loadWhat )
|
||||
// note: load data and stores it internally (document or pages). observers
|
||||
// are still uninitialized at this point so don't access them
|
||||
{
|
||||
//kDebug(OkularDebug).nospace() << "Using '" << d->m_xmlFileName << "' as document info file.";
|
||||
if ( m_xmlFileName.isEmpty() )
|
||||
return;
|
||||
return false;
|
||||
|
||||
QFile infoFile( m_xmlFileName );
|
||||
loadDocumentInfo( infoFile, loadWhat );
|
||||
return loadDocumentInfo( infoFile, loadWhat );
|
||||
}
|
||||
|
||||
void DocumentPrivate::loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags loadWhat )
|
||||
bool DocumentPrivate::loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags loadWhat )
|
||||
{
|
||||
if ( !infoFile.exists() || !infoFile.open( QIODevice::ReadOnly ) )
|
||||
return;
|
||||
return false;
|
||||
|
||||
// Load DOM from XML file
|
||||
QDomDocument doc( "documentInfo" );
|
||||
|
@ -629,15 +629,16 @@ void DocumentPrivate::loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags l
|
|||
{
|
||||
kDebug(OkularDebug) << "Can't load XML pair! Check for broken xml.";
|
||||
infoFile.close();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
infoFile.close();
|
||||
|
||||
QDomElement root = doc.documentElement();
|
||||
if ( root.tagName() != "documentInfo" )
|
||||
return;
|
||||
return false;
|
||||
|
||||
KUrl documentUrl( root.attribute( "url" ) );
|
||||
bool loadedAnything = false; // set if something gets actually loaded
|
||||
|
||||
// Parse the DOM tree
|
||||
QDomNode topLevelNode = root.firstChild();
|
||||
|
@ -645,7 +646,7 @@ void DocumentPrivate::loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags l
|
|||
{
|
||||
QString catName = topLevelNode.toElement().tagName();
|
||||
|
||||
// Restore page attributes (bookmark, annotations, ...) from the DOM
|
||||
// Restore page attributes (form data, annotations, ...) from the DOM
|
||||
if ( catName == "pageList" && ( loadWhat & LoadPageInfo ) )
|
||||
{
|
||||
QDomNode pageNode = topLevelNode.firstChild();
|
||||
|
@ -660,7 +661,10 @@ void DocumentPrivate::loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags l
|
|||
|
||||
// pass the domElement to the right page, to read config data from
|
||||
if ( ok && pageNumber >= 0 && pageNumber < (int)m_pagesVector.count() )
|
||||
m_pagesVector[ pageNumber ]->d->restoreLocalContents( pageElement );
|
||||
{
|
||||
if ( m_pagesVector[ pageNumber ]->d->restoreLocalContents( pageElement ) )
|
||||
loadedAnything = true;
|
||||
}
|
||||
}
|
||||
pageNode = pageNode.nextSibling();
|
||||
}
|
||||
|
@ -689,6 +693,7 @@ void DocumentPrivate::loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags l
|
|||
QString vpString = historyElement.attribute( "viewport" );
|
||||
m_viewportIterator = m_viewportHistory.insert( m_viewportHistory.end(),
|
||||
DocumentViewport( vpString ) );
|
||||
loadedAnything = true;
|
||||
}
|
||||
historyNode = historyNode.nextSibling();
|
||||
}
|
||||
|
@ -704,6 +709,7 @@ void DocumentPrivate::loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags l
|
|||
if ( ok && newrotation != 0 )
|
||||
{
|
||||
setRotationInternal( newrotation, false );
|
||||
loadedAnything = true;
|
||||
}
|
||||
}
|
||||
else if ( infoElement.tagName() == "views" )
|
||||
|
@ -720,6 +726,7 @@ void DocumentPrivate::loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags l
|
|||
if ( view->name() == viewName )
|
||||
{
|
||||
loadViewsInfo( view, viewElement );
|
||||
loadedAnything = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -733,6 +740,8 @@ void DocumentPrivate::loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags l
|
|||
|
||||
topLevelNode = topLevelNode.nextSibling();
|
||||
} // </documentInfo>
|
||||
|
||||
return loadedAnything;
|
||||
}
|
||||
|
||||
void DocumentPrivate::loadViewsInfo( View *view, const QDomElement &e )
|
||||
|
@ -1198,8 +1207,8 @@ void DocumentPrivate::saveDocumentInfo() const
|
|||
doc.appendChild( root );
|
||||
|
||||
// 2.1. Save page attributes (bookmark state, annotations, ... ) to DOM
|
||||
// -> skipped for archives, because they store such info in their internal metadata.xml
|
||||
if ( !m_archiveData )
|
||||
// -> do this there are not-yet-migrated annots or forms in docdata/
|
||||
if ( m_docdataMigrationNeeded )
|
||||
{
|
||||
QDomElement pageList = doc.createElement( "pageList" );
|
||||
root.appendChild( pageList );
|
||||
|
@ -2219,6 +2228,7 @@ Document::OpenResult Document::openDocument( const QString & docFile, const KUrl
|
|||
p->d->m_doc = d;
|
||||
|
||||
d->m_metadataLoadingCompleted = false;
|
||||
d->m_docdataMigrationNeeded = false;
|
||||
|
||||
// 2. load Additional Data (bookmarks, local annotations and metadata) about the document
|
||||
if ( d->m_archiveData )
|
||||
|
@ -2228,7 +2238,9 @@ Document::OpenResult Document::openDocument( const QString & docFile, const KUrl
|
|||
}
|
||||
else
|
||||
{
|
||||
d->loadDocumentInfo( LoadAllInfo );
|
||||
if ( d->loadDocumentInfo( LoadPageInfo ) )
|
||||
d->m_docdataMigrationNeeded = true;
|
||||
d->loadDocumentInfo( LoadGeneralInfo );
|
||||
}
|
||||
|
||||
d->m_metadataLoadingCompleted = true;
|
||||
|
@ -2460,6 +2472,7 @@ void Document::closeDocument()
|
|||
AudioPlayer::instance()->d->m_currentDocument = KUrl();
|
||||
|
||||
d->m_undoStack->clear();
|
||||
d->m_docdataMigrationNeeded = false;
|
||||
}
|
||||
|
||||
void Document::addObserver( DocumentObserver * pObserver )
|
||||
|
@ -2707,7 +2720,9 @@ KUrl Document::currentDocument() const
|
|||
|
||||
bool Document::isAllowed( Permission action ) const
|
||||
{
|
||||
if ( action == Okular::AllowNotes && !d->m_annotationEditingEnabled )
|
||||
if ( action == Okular::AllowNotes && ( d->m_docdataMigrationNeeded || !d->m_annotationEditingEnabled ) )
|
||||
return false;
|
||||
if ( action == Okular::AllowFillForms && d->m_docdataMigrationNeeded )
|
||||
return false;
|
||||
|
||||
#if !OKULAR_FORCE_DRM
|
||||
|
@ -4432,6 +4447,20 @@ void Document::walletDataForFile( const QString &fileName, QString *walletName,
|
|||
}
|
||||
}
|
||||
|
||||
bool Document::isDocdataMigrationNeeded() const
|
||||
{
|
||||
return d->m_docdataMigrationNeeded;
|
||||
}
|
||||
|
||||
void Document::docdataMigrationDone()
|
||||
{
|
||||
if (d->m_docdataMigrationNeeded)
|
||||
{
|
||||
d->m_docdataMigrationNeeded = false;
|
||||
foreachObserver( notifySetup( d->m_pagesVector, 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentPrivate::requestDone( PixmapRequest * req )
|
||||
{
|
||||
if ( !req )
|
||||
|
|
|
@ -886,6 +886,25 @@ class OKULAR_EXPORT Document : public QObject
|
|||
*/
|
||||
void walletDataForFile( const QString &fileName, QString *walletName, QString *walletFolder, QString *walletKey ) const;
|
||||
|
||||
/**
|
||||
* Since version 0.21, okular does not allow editing annotations and
|
||||
* form data if they are stored in the docdata directory (like older
|
||||
* okular versions did by default).
|
||||
* If this flag is set, then annotations and forms cannot be edited.
|
||||
*
|
||||
* @since 0.21
|
||||
*/
|
||||
bool isDocdataMigrationNeeded() const;
|
||||
|
||||
/**
|
||||
* Delete annotations and form data from the docdata folder. Call it if
|
||||
* isDocdataMigrationNeeded() was true and you've just saved them to an
|
||||
* external file.
|
||||
*
|
||||
* @since 0.21
|
||||
*/
|
||||
void docdataMigrationDone();
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* This slot is called whenever the user changes the @p rotation of
|
||||
|
|
|
@ -106,7 +106,8 @@ class DocumentPrivate
|
|||
m_archiveData( 0 ),
|
||||
m_fontsCached( false ),
|
||||
m_annotationEditingEnabled ( true ),
|
||||
m_annotationBeingMoved( false )
|
||||
m_annotationBeingMoved( false ),
|
||||
m_docdataMigrationNeeded( false )
|
||||
{
|
||||
calculateMaxTextPages();
|
||||
}
|
||||
|
@ -123,8 +124,8 @@ class DocumentPrivate
|
|||
void calculateMaxTextPages();
|
||||
qulonglong getTotalMemory();
|
||||
qulonglong getFreeMemory( qulonglong *freeSwap = 0 );
|
||||
void loadDocumentInfo( LoadDocumentInfoFlags loadWhat );
|
||||
void loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags loadWhat );
|
||||
bool loadDocumentInfo( LoadDocumentInfoFlags loadWhat );
|
||||
bool loadDocumentInfo( QFile &infoFile, LoadDocumentInfoFlags loadWhat );
|
||||
void loadViewsInfo( View *view, const QDomElement &e );
|
||||
void saveViewsInfo( View *view, QDomElement &e ) const;
|
||||
QString giveAbsolutePath( const QString & fileName ) const;
|
||||
|
@ -280,6 +281,13 @@ class DocumentPrivate
|
|||
|
||||
QUndoStack *m_undoStack;
|
||||
QDomNode m_prevPropsOfAnnotBeingModified;
|
||||
|
||||
// Since 0.21, we no longer support saving annotations and form data in
|
||||
// the docdata/ directory and we ask the user to migrate them to an
|
||||
// external file as soon as possible, otherwise the document will be
|
||||
// shown in read-only mode. This flag is set if the docdata/ XML file
|
||||
// for the current document contains any annotation or form.
|
||||
bool m_docdataMigrationNeeded;
|
||||
};
|
||||
|
||||
class DocumentInfoPrivate
|
||||
|
|
|
@ -785,8 +785,10 @@ void Page::deleteAnnotations()
|
|||
m_annotations.clear();
|
||||
}
|
||||
|
||||
void PagePrivate::restoreLocalContents( const QDomNode & pageNode )
|
||||
bool PagePrivate::restoreLocalContents( const QDomNode & pageNode )
|
||||
{
|
||||
bool loadedAnything = false; // set if something actually gets loaded
|
||||
|
||||
// iterate over all chilren (annotationList, ...)
|
||||
QDomNode childNode = pageNode.firstChild();
|
||||
while ( childNode.isElement() )
|
||||
|
@ -821,6 +823,7 @@ void PagePrivate::restoreLocalContents( const QDomNode & pageNode )
|
|||
{
|
||||
m_doc->performAddPageAnnotation(m_number, annotation);
|
||||
kDebug(OkularDebug) << "restored annot:" << annotation->uniqueName();
|
||||
loadedAnything = true;
|
||||
}
|
||||
else
|
||||
kWarning(OkularDebug).nospace() << "page (" << m_number << "): can't restore an annotation from XML.";
|
||||
|
@ -868,9 +871,12 @@ void PagePrivate::restoreLocalContents( const QDomNode & pageNode )
|
|||
|
||||
QString value = formElement.attribute( "value" );
|
||||
(*wantedIt)->d_ptr->setValue( value );
|
||||
loadedAnything = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return loadedAnything;
|
||||
}
|
||||
|
||||
void PagePrivate::saveLocalContents( QDomNode & parentNode, QDomDocument & document, PageItems what ) const
|
||||
|
|
|
@ -68,7 +68,7 @@ class PagePrivate
|
|||
/**
|
||||
* Loads the local contents (e.g. annotations) of the page.
|
||||
*/
|
||||
void restoreLocalContents( const QDomNode & pageNode );
|
||||
bool restoreLocalContents( const QDomNode & pageNode );
|
||||
|
||||
/**
|
||||
* Saves the local contents (e.g. annotations) of the page.
|
||||
|
|
|
@ -11,9 +11,12 @@
|
|||
|
||||
#include <threadweaver/ThreadWeaver.h>
|
||||
|
||||
#include "../core/annotations.h"
|
||||
#include "../core/document.h"
|
||||
#include "../core/document_p.h"
|
||||
#include "../core/generator.h"
|
||||
#include "../core/observer.h"
|
||||
#include "../core/page.h"
|
||||
#include "../core/rotationjob_p.h"
|
||||
#include "../settings_core.h"
|
||||
|
||||
|
@ -24,6 +27,7 @@ class DocumentTest
|
|||
|
||||
private slots:
|
||||
void testCloseDuringRotationJob();
|
||||
void testDocdataMigration();
|
||||
};
|
||||
|
||||
// Test that we don't crash if the document is closed while a RotationJob
|
||||
|
@ -58,5 +62,53 @@ void DocumentTest::testCloseDuringRotationJob()
|
|||
qApp->processEvents();
|
||||
}
|
||||
|
||||
// Test that, if there's a XML file in docdata referring to a document, we
|
||||
// detect that it must be migrated, that it doesn't get wiped out if you close
|
||||
// the document without migrating and that it does get wiped out after migrating
|
||||
void DocumentTest::testDocdataMigration()
|
||||
{
|
||||
Okular::SettingsCore::instance( "documenttest" );
|
||||
|
||||
const KUrl testFileUrl("file://" KDESRCDIR "data/file1.pdf");
|
||||
const QString testFilePath = testFileUrl.toLocalFile();
|
||||
const qint64 testFileSize = QFileInfo(testFilePath).size();
|
||||
|
||||
// Copy XML file to the docdata/ directory
|
||||
const QString docDataPath = Okular::DocumentPrivate::docDataFileName(testFileUrl, testFileSize);
|
||||
QFile::remove(docDataPath);
|
||||
QVERIFY( QFile::copy(KDESRCDIR "data/file1-docdata.xml", docDataPath) );
|
||||
|
||||
// Open our document
|
||||
Okular::Document *m_document = new Okular::Document( 0 );
|
||||
const KMimeType::Ptr mime = KMimeType::findByPath( testFilePath );
|
||||
QCOMPARE( m_document->openDocument( testFilePath, testFileUrl, mime ), Okular::Document::OpenSuccess );
|
||||
|
||||
// Check that the annotation from file1-docdata.xml was loaded
|
||||
QCOMPARE( m_document->page( 0 )->annotations().size(), 1 );
|
||||
QCOMPARE( m_document->page( 0 )->annotations().first()->uniqueName(), QString("testannot") );
|
||||
|
||||
// Check that we detect that it must be migrated
|
||||
QCOMPARE( m_document->isDocdataMigrationNeeded(), true );
|
||||
m_document->closeDocument();
|
||||
|
||||
// Reopen the document and check that the annotation is still present
|
||||
// (because we have not migrated)
|
||||
QCOMPARE( m_document->openDocument( testFilePath, testFileUrl, mime ), Okular::Document::OpenSuccess );
|
||||
QCOMPARE( m_document->page( 0 )->annotations().size(), 1 );
|
||||
QCOMPARE( m_document->page( 0 )->annotations().first()->uniqueName(), QString("testannot") );
|
||||
QCOMPARE( m_document->isDocdataMigrationNeeded(), true );
|
||||
|
||||
// Pretend the user has done the migration
|
||||
m_document->docdataMigrationDone();
|
||||
QCOMPARE( m_document->isDocdataMigrationNeeded(), false );
|
||||
m_document->closeDocument();
|
||||
|
||||
// Now the docdata file should have no annotations, let's check
|
||||
QCOMPARE( m_document->openDocument( testFilePath, testFileUrl, mime ), Okular::Document::OpenSuccess );
|
||||
QCOMPARE( m_document->page( 0 )->annotations().size(), 0 );
|
||||
QCOMPARE( m_document->isDocdataMigrationNeeded(), false );
|
||||
m_document->closeDocument();
|
||||
}
|
||||
|
||||
QTEST_KDEMAIN( DocumentTest, GUI )
|
||||
#include "documenttest.moc"
|
||||
|
|
Loading…
Reference in a new issue