Hot-swap backing file instead of reloading (if the generator supports it)

remotes/origin/dont-use-docdata-for-annots-and-forms
Fabio D'Urso 12 years ago
parent d0af66f082
commit 43a3756e1c
  1. 70
      core/document.cpp
  2. 35
      core/document.h
  3. 5
      core/generator.cpp
  4. 14
      core/generator.h
  5. 8
      generators/kimgio/generator_kimgio.cpp
  6. 1
      generators/kimgio/generator_kimgio.h
  7. 58
      part.cpp
  8. 1
      part.h

@ -3998,6 +3998,76 @@ const KComponentData* Document::componentData() const
return kcd;
}
bool Document::canSwapBackingFile() const
{
if ( !d->m_generator )
return false;
Q_ASSERT( !d->m_generatorName.isEmpty() );
QHash< QString, GeneratorInfo >::iterator genIt = d->m_loadedGenerators.find( d->m_generatorName );
Q_ASSERT( genIt != d->m_loadedGenerators.end() );
return genIt->generator->hasFeature( Generator::SwapBackingFile );
}
bool Document::swapBackingFile( const QString &newFileName, const KUrl & url )
{
if ( !d->m_generator )
return false;
Q_ASSERT( !d->m_generatorName.isEmpty() );
QHash< QString, GeneratorInfo >::iterator genIt = d->m_loadedGenerators.find( d->m_generatorName );
Q_ASSERT( genIt != d->m_loadedGenerators.end() );
if ( !genIt->generator->hasFeature( Generator::SwapBackingFile ) )
return false;
kDebug(OkularDebug) << "Swapping backing file to" << newFileName;
if (genIt->generator->swapBackingFile( newFileName ))
{
d->m_url = url;
return true;
}
else
{
return false;
}
}
bool Document::swapBackingFileArchive( const QString &newFileName, const KUrl & url )
{
if ( !d->m_generator )
return false;
Q_ASSERT( !d->m_generatorName.isEmpty() );
QHash< QString, GeneratorInfo >::iterator genIt = d->m_loadedGenerators.find( d->m_generatorName );
Q_ASSERT( genIt != d->m_loadedGenerators.end() );
if ( !genIt->generator->hasFeature( Generator::SwapBackingFile ) )
return false;
kDebug(OkularDebug) << "Swapping backing archive to" << newFileName;
ArchiveData *newArchive = DocumentPrivate::unpackDocumentArchive( newFileName );
if ( !newArchive )
return false;
const QString tempFileName = newArchive->document.fileName();
kDebug(OkularDebug) << "Swapping backing file to" << tempFileName;
if (genIt->generator->swapBackingFile( tempFileName ))
{
delete d->m_archiveData;
d->m_archiveData = newArchive;
d->m_url = url;
return true;
}
else
{
return false;
}
}
bool Document::canSaveChanges() const
{
if ( !d->m_generator )

@ -613,6 +613,41 @@ class OKULAR_EXPORT Document : public QObject
*/
const KComponentData* componentData() const;
/**
* Returns whether the generator supports hot-swapping the current file
* with another identical file
*
* @since 0.20 (KDE 4.14)
*/
bool canSwapBackingFile() const;
/**
* Reload the document from a new location, without any visible effect
* to the user.
*
* The new file must be identical to the current one or, if the document
* has been modified (eg the user edited forms and annotations), the new
* document must have these changes too. For example, you can call
* saveChanges first to write changes to a file and then swapBackingFile
* to switch to the new location.
*
* @since 0.20 (KDE 4.14)
*/
bool swapBackingFile( const QString &newFileName, const KUrl & url );
/**
* Same as swapBackingFile, but newFileName must be a .okular file.
*
* The new file must be identical to the current one or, if the document
* has been modified (eg the user edited forms and annotations), the new
* document must have these changes too. For example, you can call
* saveDocumentArchive first to write changes to a file and then
* swapBackingFileArchive to switch to the new location.
*
* @since 0.20 (KDE 4.14)
*/
bool swapBackingFileArchive( const QString &newFileName, const KUrl & url );
/**
* Saving capabilities. Their availability varies according to the
* underlying generator and/or the document type.

@ -196,6 +196,11 @@ Document::OpenResult Generator::loadDocumentFromDataWithPassword( const QByteArr
return loadDocumentFromData( fileData, pagesVector ) ? Document::OpenSuccess : Document::OpenError;
}
bool Generator::swapBackingFile( QString const &newFileName )
{
return false;
}
bool Generator::closeDocument()
{
Q_D( Generator );

@ -207,7 +207,8 @@ class OKULAR_EXPORT Generator : public QObject
PrintNative, ///< Whether the Generator supports native cross-platform printing (QPainter-based).
PrintPostscript, ///< Whether the Generator supports postscript-based file printing.
PrintToFile, ///< Whether the Generator supports export to PDF & PS through the Print Dialog
TiledRendering ///< Whether the Generator can render tiles @since 0.16 (KDE 4.10)
TiledRendering, ///< Whether the Generator can render tiles @since 0.16 (KDE 4.10)
SwapBackingFile ///< Whether the Generator can hot-swap the file it's reading from @since 0.20 (KDE 4.14)
};
/**
@ -268,6 +269,17 @@ class OKULAR_EXPORT Generator : public QObject
*/
virtual Document::OpenResult loadDocumentFromDataWithPassword( const QByteArray & fileData, QVector< Page * > & pagesVector, const QString &password );
/**
* Changes the path of the file we are reading from. The new path must
* point to a copy of the same document.
*
* @note the Generator has to have the feature @ref SwapBackingFile enabled
*
* @since 0.20 (KDE 4.14)
*
* @returns true on success, false otherwise.
*/
virtual bool swapBackingFile( const QString &newFileName );
/**
* This method is called when the document is closed and not used

@ -56,6 +56,7 @@ KIMGIOGenerator::KIMGIOGenerator( QObject *parent, const QVariantList &args )
setFeature( TiledRendering );
setFeature( PrintNative );
setFeature( PrintToFile );
setFeature( SwapBackingFile );
/*
setComponentData( *ownComponentData() );
@ -130,6 +131,13 @@ bool KIMGIOGenerator::loadDocumentFromData( const QByteArray & fileData, QVector
return true;
}
bool KIMGIOGenerator::swapBackingFile( QString const &newFileName )
{
// NOP: We don't actually need to do anything because all data has already
// been loaded in RAM
return true;
}
bool KIMGIOGenerator::doCloseDocument()
{
m_img = QImage();

@ -25,6 +25,7 @@ class KIMGIOGenerator : public Okular::Generator
// [INHERITED] load a document and fill up the pagesVector
bool loadDocument( const QString & fileName, QVector<Okular::Page*> & pagesVector );
bool loadDocumentFromData( const QByteArray & fileData, QVector<Okular::Page*> & pagesVector );
bool swapBackingFile( QString const &newFileName );
// [INHERITED] print document using already configured kprinter
bool print( QPrinter& printer );

@ -303,7 +303,7 @@ QObject *parent,
const QVariantList &args,
KComponentData componentData )
: KParts::ReadWritePart(parent),
m_tempfile( 0 ), m_fileWasRemoved( false ), m_showMenuBarAction( 0 ), m_showFullScreenAction( 0 ), m_actionsSearched( false ),
m_tempfile( 0 ), m_swapInsteadOfOpening( false ), m_fileWasRemoved( false ), m_showMenuBarAction( 0 ), m_showFullScreenAction( 0 ), m_actionsSearched( false ),
m_cliPresentation(false), m_cliPrint(false), m_embedMode(detectEmbedMode(parentWidget, parent, args)), m_generatorGuiClient(0), m_keeper( 0 )
{
// first, we check if a config file name has been specified
@ -1265,6 +1265,26 @@ bool Part::openFile()
uncompressOk = handleCompressed( fileNameToOpen, localFilePath(), compressedMime );
mime = KMimeType::findByPath( fileNameToOpen );
}
if ( m_swapInsteadOfOpening )
{
m_swapInsteadOfOpening = false;
if ( !uncompressOk )
return false;
if ( mime->is( "application/vnd.kde.okular-archive" ) )
{
isDocumentArchive = true;
return m_document->swapBackingFileArchive( fileNameToOpen, url() );
}
else
{
isDocumentArchive = false;
return m_document->swapBackingFile( fileNameToOpen, url() );
}
}
Document::OpenResult openResult = Document::OpenError;
isDocumentArchive = false;
if ( uncompressOk )
@ -1542,6 +1562,13 @@ bool Part::closeUrl(bool promptToSave)
if ( promptToSave && !queryClose() )
return false;
if ( m_swapInsteadOfOpening )
{
// If we're swapping the backing file, we don't want to close the
// current one when openUrl() calls us internally
return true; // pretend it worked
}
setModified( false );
if (!m_temporaryLocalFile.isNull() && m_temporaryLocalFile != localFilePath())
@ -2396,7 +2423,34 @@ bool Part::saveAs( const KUrl & saveUrl, bool saveAsOkularArchive )
// Load new file instead of the old one
if ( url() != saveUrl )
slotAttemptReload( true, saveUrl );
{
if ( m_document->canSwapBackingFile() )
{
// If the generator supports hot-swapping of the backing file
// tell openFile to swap the backing file instead of opening a new one
m_swapInsteadOfOpening = true;
// this calls openFile internally, which in turn actually calls
// m_document->swapBackingFile() instead of the regular loadDocument
const bool success = openUrl( saveUrl );
// restore it back to false -- this has already been done by
// openFile, but let's do it again for extra safety
m_swapInsteadOfOpening = false;
// In case of file swapping errors, close everything to avoid inconsistencies
if ( !success )
{
closeUrl();
}
}
else
{
// If the generator doesn't support swapping file, then just reload
// the document from the new location
slotAttemptReload( true, saveUrl );
}
}
// Restore watcher
if ( url().isLocalFile() )

@ -259,6 +259,7 @@ class OKULAR_PART_EXPORT Part : public KParts::ReadWritePart, public Okular::Doc
Okular::Document * m_document;
QString m_temporaryLocalFile;
bool isDocumentArchive;
bool m_swapInsteadOfOpening; // if set, the next open operation will replace the backing file (used when reloading just saved files)
// main widgets
Sidebar *m_sidebar;

Loading…
Cancel
Save