Commit e93d5bda authored by Albert Astals Cid's avatar Albert Astals Cid
Browse files

Move KWallet code from pdf backend to ui

This helps with the widget dependency removal in the core/backends
parent 56c10183
......@@ -55,6 +55,7 @@ DocumentItem::~DocumentItem()
void DocumentItem::setPath(const QString &path)
{
//TODO: remote urls
//TODO: password
m_document->openDocument(path, KUrl(path), KMimeType::findByUrl(KUrl(path)));
m_tocModel->fill(m_document->documentSynopsis());
......
......@@ -903,7 +903,7 @@ SaveInterface* DocumentPrivate::generatorSave( GeneratorInfo& info )
return info.save;
}
bool DocumentPrivate::openDocumentInternal( const KService::Ptr& offer, bool isstdin, const QString& docFile, const QByteArray& filedata )
Document::OpenResult DocumentPrivate::openDocumentInternal( const KService::Ptr& offer, bool isstdin, const QString& docFile, const QByteArray& filedata, const QString& password )
{
QString propName = offer->name();
QHash< QString, GeneratorInfo >::const_iterator genIt = m_loadedGenerators.constFind( propName );
......@@ -917,7 +917,7 @@ bool DocumentPrivate::openDocumentInternal( const KService::Ptr& offer, bool iss
{
m_generator = loadGeneratorLibrary( offer );
if ( !m_generator )
return false;
return Document::OpenError;
genIt = m_loadedGenerators.constFind( propName );
Q_ASSERT( genIt != m_loadedGenerators.constEnd() );
catalogName = genIt.value().catalogName;
......@@ -938,16 +938,16 @@ bool DocumentPrivate::openDocumentInternal( const KService::Ptr& offer, bool iss
m_generator->setDPI(Utils::realDpi(m_widget));
bool openOk = false;
Document::OpenResult openResult = Document::OpenError;
if ( !isstdin )
{
openOk = m_generator->loadDocument( docFile, m_pagesVector );
openResult = m_generator->loadDocumentWithPassword( docFile, m_pagesVector, password );
}
else if ( !filedata.isEmpty() )
{
if ( m_generator->hasFeature( Generator::ReadRawData ) )
{
openOk = m_generator->loadDocumentFromData( filedata, m_pagesVector );
openResult = m_generator->loadDocumentFromDataWithPassword( filedata, m_pagesVector, password );
}
else
{
......@@ -962,13 +962,13 @@ bool DocumentPrivate::openDocumentInternal( const KService::Ptr& offer, bool iss
m_tempFile->write( filedata );
QString tmpFileName = m_tempFile->fileName();
m_tempFile->close();
openOk = m_generator->loadDocument( tmpFileName, m_pagesVector );
openResult = m_generator->loadDocumentWithPassword( tmpFileName, m_pagesVector, password );
}
}
}
QApplication::restoreOverrideCursor();
if ( !openOk || m_pagesVector.size() <= 0 )
if ( openResult != Document::OpenSuccess || m_pagesVector.size() <= 0 )
{
if ( !catalogName.isEmpty() )
KGlobal::locale()->removeCatalog( catalogName );
......@@ -983,11 +983,11 @@ bool DocumentPrivate::openDocumentInternal( const KService::Ptr& offer, bool iss
m_tempFile = 0;
// TODO: emit a message telling the document is empty
openOk = false;
if ( openResult == Document::OpenSuccess )
openResult = Document::OpenError;
}
return openOk;
return openResult;
}
bool DocumentPrivate::savePageDocumentInfo( KTemporaryFile *infoFile, int what ) const
......@@ -1044,12 +1044,12 @@ void DocumentPrivate::warnLimitedAnnotSupport()
{
// Shown if the user is editing annotations in a file whose metadata is
// not stored locally (.okular archives belong to this category)
KMessageBox::information( m_parent->widget(), i18n("Your annotation changes will not be saved automatically. Use File -> Save As...\nor your changes will be lost once the document is closed"), QString(), "annotNeedSaveAs" );
KMessageBox::information( m_widget, i18n("Your annotation changes will not be saved automatically. Use File -> Save As...\nor your changes will be lost once the document is closed"), QString(), "annotNeedSaveAs" );
}
else if ( !canAddAnnotationsNatively() )
{
// If the generator doesn't support native annotations
KMessageBox::information( m_parent->widget(), i18n("Your annotations are saved internally by Okular.\nYou can export the annotated document using File -> Export As -> Document Archive"), QString(), "annotExportAsArchive" );
KMessageBox::information( m_widget, i18n("Your annotations are saved internally by Okular.\nYou can export the annotated document using File -> Export As -> Document Archive"), QString(), "annotExportAsArchive" );
}
}
......@@ -1661,7 +1661,7 @@ void DocumentPrivate::doContinueDirectionMatchSearch(void *doContinueDirectionMa
if ( searchStruct->currentPage >= pageCount || searchStruct->currentPage < 0 )
{
const QString question = searchStruct->forward ? i18n("End of document reached.\nContinue from the beginning?") : i18n("Beginning of document reached.\nContinue from the bottom?");
if ( searchStruct->noDialogs || KMessageBox::questionYesNo(m_parent->widget(), question, QString(), KStandardGuiItem::cont(), KStandardGuiItem::cancel()) == KMessageBox::Yes )
if ( searchStruct->noDialogs || KMessageBox::questionYesNo(m_widget, question, QString(), KStandardGuiItem::cont(), KStandardGuiItem::cancel()) == KMessageBox::Yes )
searchStruct->currentPage = searchStruct->forward ? 0 : pageCount - 1;
else
doContinue = false;
......@@ -1745,7 +1745,7 @@ void DocumentPrivate::doProcessSearchMatch( RegularAreaRect *match, RunningSearc
}
#if 0
else if ( !noDialogs )
KMessageBox::information( m_parent->widget(), i18n( "No matches found for '%1'.", text ) );
KMessageBox::information( m_widget, i18n( "No matches found for '%1'.", text ) );
#endif
// notify observers about highlights changes
......@@ -2108,7 +2108,7 @@ private:
const KMimeType::Ptr &_mime;
};
bool Document::openDocument( const QString & docFile, const KUrl& url, const KMimeType::Ptr &_mime )
Document::OpenResult Document::openDocument( const QString & docFile, const KUrl& url, const KMimeType::Ptr &_mime, const QString & password )
{
KMimeType::Ptr mime = _mime;
QByteArray filedata;
......@@ -2118,14 +2118,14 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
if ( !isstdin )
{
if ( mime.count() <= 0 )
return false;
return OpenError;
// docFile is always local so we can use QFileInfo on it
QFileInfo fileReadTest( docFile );
if ( fileReadTest.isFile() && !fileReadTest.isReadable() )
{
d->m_docFileName.clear();
return false;
return OpenError;
}
// determine the related "xml document-info" filename
d->m_url = url;
......@@ -2145,7 +2145,7 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
{
// ### copy or move?
if ( !QFile::copy( oldkpdffile, newokularfile ) )
return false;
return OpenError;
}
}
d->m_xmlFileName = newokularfile;
......@@ -2158,7 +2158,7 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
filedata = qstdin.readAll();
mime = KMimeType::findByContent( filedata );
if ( !mime || mime->name() == QLatin1String( "application/octet-stream" ) )
return false;
return OpenError;
document_size = filedata.size();
triedMimeFromFileContent = true;
}
......@@ -2193,7 +2193,7 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
{
emit error( i18n( "Can not find a plugin which is able to handle the document being passed." ), -1 );
kWarning(OkularDebug).nospace() << "No plugin for mimetype '" << mime->name() << "'.";
return false;
return OpenError;
}
int hRank=0;
// best ranked offer search
......@@ -2211,10 +2211,10 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
list << offers.at(i)->name();
}
ChooseEngineDialog choose( list, mime, widget() );
ChooseEngineDialog choose( list, mime, d->m_widget );
if ( choose.exec() == QDialog::Rejected )
return false;
return OpenError;
hRank = choose.selectedGenerator();
}
......@@ -2222,8 +2222,8 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
KService::Ptr offer = offers.at( hRank );
// 1. load Document
bool openOk = d->openDocumentInternal( offer, isstdin, docFile, filedata );
if ( !openOk && !triedMimeFromFileContent )
OpenResult openResult = d->openDocumentInternal( offer, isstdin, docFile, filedata, password );
if ( openResult == OpenError && !triedMimeFromFileContent )
{
KMimeType::Ptr newmime = KMimeType::findByFileContent( docFile );
triedMimeFromFileContent = true;
......@@ -2234,13 +2234,13 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
if ( !offers.isEmpty() )
{
offer = offers.first();
openOk = d->openDocumentInternal( offer, isstdin, docFile, filedata );
openResult = d->openDocumentInternal( offer, isstdin, docFile, filedata, password );
}
}
}
if ( !openOk )
if ( openResult != OpenSuccess )
{
return false;
return openResult;
}
d->m_generatorName = offer->name();
......@@ -2327,7 +2327,7 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
}
}
return true;
return OpenSuccess;
}
......@@ -2556,11 +2556,6 @@ void Document::reparseConfig()
}
QWidget *Document::widget() const
{
return d->m_widget;
}
bool Document::isOpened() const
{
return d->m_generator;
......@@ -3673,7 +3668,7 @@ void Document::processAction( const Action * action )
{
// this case is a link pointing to an executable with a parameter
// that also is an executable, possibly a hand-crafted pdf
KMessageBox::information( widget(), i18n("The document is trying to execute an external application and, for your safety, Okular does not allow that.") );
KMessageBox::information( d->m_widget, i18n("The document is trying to execute an external application and, for your safety, Okular does not allow that.") );
return;
}
}
......@@ -3681,7 +3676,7 @@ void Document::processAction( const Action * action )
{
// this case is a link pointing to an executable with no parameters
// core developers find unacceptable executing it even after asking the user
KMessageBox::information( widget(), i18n("The document is trying to execute an external application and, for your safety, Okular does not allow that.") );
KMessageBox::information( d->m_widget, i18n("The document is trying to execute an external application and, for your safety, Okular does not allow that.") );
return;
}
}
......@@ -3694,7 +3689,7 @@ void Document::processAction( const Action * action )
KRun::run( *ptr, lst, 0 );
}
else
KMessageBox::information( widget(), i18n( "No application found for opening file of mimetype %1.", mime->name() ) );
KMessageBox::information( d->m_widget, i18n( "No application found for opening file of mimetype %1.", mime->name() ) );
} break;
case Action::DocAction: {
......@@ -3774,7 +3769,7 @@ void Document::processAction( const Action * action )
}
// Albert: this is not a leak!
new KRun( realUrl, widget() );
new KRun( realUrl, d->m_widget );
}
} break;
......@@ -4134,30 +4129,30 @@ QByteArray Document::fontData(const FontInfo &font) const
return result;
}
bool Document::openDocumentArchive( const QString & docFile, const KUrl & url )
Document::OpenResult Document::openDocumentArchive( const QString & docFile, const KUrl & url, const QString & password )
{
const KMimeType::Ptr mime = KMimeType::findByPath( docFile, 0, false /* content too */ );
if ( !mime->is( "application/vnd.kde.okular-archive" ) )
return false;
return OpenError;
KZip okularArchive( docFile );
if ( !okularArchive.open( QIODevice::ReadOnly ) )
return false;
return OpenError;
const KArchiveDirectory * mainDir = okularArchive.directory();
const KArchiveEntry * mainEntry = mainDir->entry( "content.xml" );
if ( !mainEntry || !mainEntry->isFile() )
return false;
return OpenError;
std::auto_ptr< QIODevice > mainEntryDevice( static_cast< const KZipFileEntry * >( mainEntry )->createDevice() );
QDomDocument doc;
if ( !doc.setContent( mainEntryDevice.get() ) )
return false;
return OpenError;
mainEntryDevice.reset();
QDomElement root = doc.documentElement();
if ( root.tagName() != "OkularArchive" )
return false;
return OpenError;
QString documentFileName;
QString metadataFileName;
......@@ -4177,18 +4172,18 @@ bool Document::openDocumentArchive( const QString & docFile, const KUrl & url )
}
}
if ( documentFileName.isEmpty() )
return false;
return OpenError;
const KArchiveEntry * docEntry = mainDir->entry( documentFileName );
if ( !docEntry || !docEntry->isFile() )
return false;
return OpenError;
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;
return OpenError;
QString tempFileName = archiveData->document.fileName();
{
......@@ -4216,9 +4211,9 @@ bool Document::openDocumentArchive( const QString & docFile, const KUrl & url )
const KMimeType::Ptr docMime = KMimeType::findByPath( tempFileName, 0, true /* local file */ );
d->m_archiveData = archiveData.get();
d->m_archivedFileName = documentFileName;
bool ret = openDocument( tempFileName, url, docMime );
const OpenResult ret = openDocument( tempFileName, url, docMime, password );
if ( ret )
if ( ret == OpenSuccess )
{
archiveData.release();
}
......
......@@ -96,10 +96,22 @@ class OKULAR_EXPORT Document : public QObject
*/
~Document();
/**
* Describes the result of an open document operation.
* @since 0.20 (KDE 4.14)
*/
enum OpenResult
{
OpenSuccess, //< The document was opened successfully
OpenError, //< The document failed to open
OpenNeedsPassword //< The document needs a password to be opened or the one provided is not the correct
};
/**
* Opens the document.
* @since 0.20 (KDE 4.14)
*/
bool openDocument( const QString & docFile, const KUrl & url, const KMimeType::Ptr &mime );
OpenResult openDocument( const QString & docFile, const KUrl & url, const KMimeType::Ptr &mime, const QString &password = QString() );
/**
* Closes the document.
......@@ -121,11 +133,6 @@ class OKULAR_EXPORT Document : public QObject
*/
void reparseConfig();
/**
* Returns the widget to be used for relaying GUI things (messageboxes, ...)
*/
QWidget *widget() const;
/**
* Returns whether the document is currently opened.
*/
......@@ -680,9 +687,9 @@ class OKULAR_EXPORT Document : public QObject
/**
* Opens a document archive.
*
* @since 0.8 (KDE 4.2)
* @since 0.20 (KDE 4.14)
*/
bool openDocumentArchive( const QString & docFile, const KUrl & url );
OpenResult openDocumentArchive( const QString & docFile, const KUrl & url, const QString &password = QString() );
/**
* Saves a document archive.
......
......@@ -135,7 +135,7 @@ class DocumentPrivate
void setRotationInternal( int r, bool notify );
ConfigInterface* generatorConfig( GeneratorInfo& info );
SaveInterface* generatorSave( GeneratorInfo& info );
bool openDocumentInternal( const KService::Ptr& offer, bool isstdin, const QString& docFile, const QByteArray& filedata );
Document::OpenResult openDocumentInternal( const KService::Ptr& offer, bool isstdin, const QString& docFile, const QByteArray& filedata, const QString& password );
bool savePageDocumentInfo( KTemporaryFile *infoFile, int what ) const;
DocumentViewport nextDocumentViewport() const;
void notifyAnnotationChanges( int page );
......
......@@ -175,11 +175,26 @@ Generator::~Generator()
delete d_ptr;
}
bool Generator::loadDocument( const QString & fileName, QVector< Page * > & pagesVector )
{
return false;
}
bool Generator::loadDocumentFromData( const QByteArray &, QVector< Page * > & )
{
return false;
}
Document::OpenResult Generator::loadDocumentWithPassword( const QString & fileName, QVector< Page * > & pagesVector, const QString & )
{
return loadDocument( fileName, pagesVector ) ? Document::OpenSuccess : Document::OpenError;
}
Document::OpenResult Generator::loadDocumentFromDataWithPassword( const QByteArray & fileData, QVector< Page * > & pagesVector, const QString & )
{
return loadDocumentFromData( fileData, pagesVector ) ? Document::OpenSuccess : Document::OpenError;
}
bool Generator::closeDocument()
{
Q_D( Generator );
......
......@@ -13,6 +13,7 @@
#define _OKULAR_GENERATOR_H_
#include "okular_export.h"
#include "document.h"
#include "fontinfo.h"
#include "global.h"
#include "pagesize.h"
......@@ -40,7 +41,6 @@ class KIcon;
namespace Okular {
class Document;
class DocumentFonts;
class DocumentInfo;
class DocumentObserver;
......@@ -224,20 +224,47 @@ class OKULAR_EXPORT Generator : public QObject
* Loads the document with the given @p fileName and fills the
* @p pagesVector with the parsed pages.
*
* @note If you implement the WithPassword variants you don't need to implement this one
*
* @returns true on success, false otherwise.
*/
virtual bool loadDocument( const QString & fileName, QVector< Page * > & pagesVector ) = 0;
virtual bool loadDocument( const QString & fileName, QVector< Page * > & pagesVector );
/**
* Loads the document from the raw data @p fileData and fills the
* @p pagesVector with the parsed pages.
*
* @note If you implement the WithPassword variants you don't need to implement this one
*
* @note the Generator has to have the feature @ref ReadRawData enabled
*
* @returns true on success, false otherwise.
*/
virtual bool loadDocumentFromData( const QByteArray & fileData, QVector< Page * > & pagesVector );
/**
* Loads the document with the given @p fileName and @p password and fills the
* @p pagesVector with the parsed pages.
*
* @note Do not implement this if your format doesn't support passwords, it'll cleanly call loadDocument()
*
* @returns a LoadResult defining the result of the operation
*/
virtual Document::OpenResult loadDocumentWithPassword( const QString & fileName, QVector< Page * > & pagesVector, const QString &password );
/**
* Loads the document from the raw data @p fileData and @p password and fills the
* @p pagesVector with the parsed pages.
*
* @note Do not implement this if your format doesn't support passwords, it'll cleanly call loadDocumentFromData()
*
* @note the Generator has to have the feature @ref ReadRawData enabled
*
* @returns a LoadResult defining the result of the operation
*/
virtual Document::OpenResult loadDocumentFromDataWithPassword( const QByteArray & fileData, QVector< Page * > & pagesVector, const QString &password );
/**
* This method is called when the document is closed and not used
* any longer.
......
......@@ -121,7 +121,7 @@ static KJSObject docGetDataObjects( KJSContext *ctx, void *object )
static KJSObject docGetExternal( KJSContext *, void *object )
{
DocumentPrivate *doc = reinterpret_cast< DocumentPrivate* >( object );
QWidget *widget = doc->m_parent->widget();
QWidget *widget = doc->m_widget;
const bool isShell = ( widget
&& widget->parentWidget()
......
......@@ -28,8 +28,6 @@
#include <kconfigdialog.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kpassworddialog.h>
#include <kwallet.h>
#include <ktemporaryfile.h>
#include <kdebug.h>
#include <kglobal.h>
......@@ -453,19 +451,19 @@ PDFGenerator::~PDFGenerator()
}
//BEGIN Generator inherited functions
bool PDFGenerator::loadDocument( const QString & filePath, QVector<Okular::Page*> & pagesVector )
Okular::Document::OpenResult PDFGenerator::loadDocumentWithPassword( const QString & filePath, QVector<Okular::Page*> & pagesVector, const QString &password )
{
#ifndef NDEBUG
if ( pdfdoc )
{
kDebug(PDFDebug) << "PDFGenerator: multiple calls to loadDocument. Check it.";
return false;
return Okular::Document::OpenError;
}
#endif
// create PDFDoc for the given file
pdfdoc = Poppler::Document::load( filePath, 0, 0 );
bool success = init(pagesVector, filePath.section('/', -1, -1));
if (success)
Okular::Document::OpenResult success = init(pagesVector, password);
if (success == Okular::Document::OpenSuccess)
{
// no need to check for the existence of a synctex file, no parser will be
// created if none exists
......@@ -478,97 +476,42 @@ bool PDFGenerator::loadDocument( const QString & filePath, QVector<Okular::Page*
return success;
}
bool PDFGenerator::loadDocumentFromData( const QByteArray & fileData, QVector<Okular::Page*> & pagesVector )
Okular::Document::OpenResult PDFGenerator::loadDocumentFromDataWithPassword( const QByteArray & fileData, QVector<Okular::Page*> & pagesVector, const QString &password )
{
#ifndef NDEBUG
if ( pdfdoc )
{
kDebug(PDFDebug) << "PDFGenerator: multiple calls to loadDocument. Check it.";
return false;
return Okular::Document::OpenError;
}
#endif
// create PDFDoc for the given file
pdfdoc = Poppler::Document::loadFromData( fileData, 0, 0 );
return init(pagesVector, QString());
return init(pagesVector, password);
}
bool PDFGenerator::init(QVector<Okular::Page*> & pagesVector, const QString &walletKey)
Okular::Document::OpenResult PDFGenerator::init(QVector<Okular::Page*> & pagesVector, const QString &password)
{
// if the file didn't open correctly it might be encrypted, so ask for a pass
bool firstInput = true;
bool triedWallet = false;
KWallet::Wallet * wallet = 0;
bool keep = true;
while ( pdfdoc && pdfdoc->isLocked() )
{
QString password;
// 1.A. try to retrieve the first password from the kde wallet system
if ( !triedWallet && !walletKey.isNull() )
{
QString walletName = KWallet::Wallet::NetworkWallet();
WId parentwid = 0;
if ( document() && document()->widget() )
parentwid = document()->widget()->effectiveWinId();
wallet = KWallet::Wallet::openWallet( walletName, parentwid );
if ( wallet )
{
// use the KPdf folder (and create if missing)
if ( !wallet->hasFolder( "KPdf" ) )
wallet->createFolder( "KPdf" );
wallet->setFolder( "KPdf" );
// look for the pass in that folder
QString retrievedPass;
if ( !wallet->readPassword( walletKey, retrievedPass ) )
password = retrievedPass;
}
triedWallet = true;
}
// 1.B. if not retrieved, ask the password using the kde password dialog
if ( password.isNull() )
{
QString prompt;
if ( firstInput )
prompt = i18n( "Please enter the password to read the document:" );
else
prompt = i18n( "Incorrect password. Try again:" );
firstInput = false;
// if the user presses cancel, abort opening
KPasswordDialog dlg( document()->widget(), wallet ? KPasswordDialog::ShowKeepPassword : KPasswordDialog::KPasswordDialogFlags() );
dlg.setCaption( i18n( "Document Password" ) );
dlg.setPrompt( prompt );
if( !dlg.exec() )
break;
password = dlg.password();
if ( wallet )
keep = dlg.keepPassword();
}
if ( !pdfdoc )
return Okular::Document::OpenError;
// 2. reopen the document using the password
if ( pdfdoc->isLocked() )
{
pdfdoc->unlock( password.toLatin1(), password.toLatin1() );
// 3. if the password is correct and the user chose to remember it, store it to the wallet
if ( !pdfdoc->isLocked() && wallet && /*safety check*/ wallet->isOpen() && keep )
{
wallet->writePassword( walletKey, password );
if ( pdfdoc->isLocked() ) {
delete pdfdoc;
pdfdoc = 0;
return Okular::Document::OpenNeedsPassword;
}
}
if ( !pdfdoc || pdfdoc->isLocked() )
{