Ask "Save annotation changes?" if there are unsaved annotations that cannot be saved locally

This patch turns Okular into a ReadWritePart. Annotation editing is always
disabled if we're loaded as ReadOnlyPart, no matter the document type.

REVIEW: 105020
remotes/origin/KDE/4.9 v4.8.80
Fabio D'Urso 14 years ago
parent 7d3a064e15
commit e3f1c388de
  1. 27
      core/document.cpp
  2. 8
      core/document.h
  3. 3
      core/document_p.h
  4. 5
      core/observer.h
  5. 2
      okular_part.desktop
  6. 108
      part.cpp
  7. 27
      part.h
  8. 14
      shell/shell.cpp
  9. 3
      shell/shell.h

@ -2138,6 +2138,9 @@ KUrl Document::currentDocument() const
bool Document::isAllowed( Permission action ) const
{
if ( action == Okular::AllowNotes && !d->m_annotationEditingEnabled )
return false;
#if !OKULAR_FORCE_DRM
if ( KAuthorized::authorize( "skip_drm" ) && !Okular::Settings::obeyDRM() )
return true;
@ -2354,6 +2357,16 @@ void Document::requestTextPage( uint page )
d->m_generator->generateTextPage( kp );
}
void DocumentPrivate::notifyAnnotationChanges( int page )
{
int flags = DocumentObserver::Annotations;
if ( canAddAnnotationsNatively() && m_containsExternalAnnotations )
flags |= DocumentObserver::NeedSaveAs; // Annotations are not saved locally in this case
foreachObserverD( notifyPageChanged( page, flags ) );
}
void Document::addPageAnnotation( int page, Annotation * annotation )
{
Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( d->m_generator );
@ -2376,7 +2389,7 @@ void Document::addPageAnnotation( int page, Annotation * annotation )
proxy->notifyAddition( annotation, page );
// notify observers about the change
foreachObserver( notifyPageChanged( page, DocumentObserver::Annotations ) );
d->notifyAnnotationChanges( page );
if ( annotation->flags() & Annotation::ExternallyDrawn )
{
@ -2432,7 +2445,7 @@ void Document::modifyPageAnnotation( int page, Annotation * annotation, bool app
proxy->notifyModification( annotation, page, appearanceChanged );
// notify observers about the change
foreachObserver( notifyPageChanged( page, DocumentObserver::Annotations ) );
d->notifyAnnotationChanges( page );
if ( appearanceChanged && (annotation->flags() & Annotation::ExternallyDrawn) )
{
@ -2507,7 +2520,7 @@ void Document::removePageAnnotation( int page, Annotation * annotation )
kp->removeAnnotation( annotation ); // Also destroys the object
// in case of success, notify observers about the change
foreachObserver( notifyPageChanged( page, DocumentObserver::Annotations ) );
d->notifyAnnotationChanges( page );
if ( isExternallyDrawn )
{
@ -2555,7 +2568,7 @@ void Document::removePageAnnotations( int page, const QList< Annotation * > &ann
if ( changed )
{
// in case we removed even only one annotation, notify observers about the change
foreachObserver( notifyPageChanged( page, DocumentObserver::Annotations ) );
d->notifyAnnotationChanges( page );
if ( refreshNeeded )
{
@ -3717,6 +3730,12 @@ QPrinter::Orientation Document::orientation() const
return (landscape > portrait) ? QPrinter::Landscape : QPrinter::Portrait;
}
void Document::setAnnotationEditingEnabled( bool enable )
{
d->m_annotationEditingEnabled = enable;
foreachObserver( notifySetup( d->m_pagesVector, 0 ) );
}
void DocumentPrivate::requestDone( PixmapRequest * req )
{
if ( !req )

@ -642,6 +642,14 @@ class OKULAR_EXPORT Document : public QObject
*/
QPrinter::Orientation orientation() const;
/**
* Control annotation editing (creation, modification and removal),
* which is enabled by default.
*
* @since 0.15 (KDE 4.9)
*/
void setAnnotationEditingEnabled( bool enable );
public Q_SLOTS:
/**

@ -86,6 +86,7 @@ class DocumentPrivate
m_archiveData( 0 ),
m_fontsCached( false ),
m_documentInfo( 0 ),
m_annotationEditingEnabled ( true ),
m_annotationBeingMoved( false )
{
calculateMaxTextPages();
@ -115,6 +116,7 @@ class DocumentPrivate
bool openDocumentInternal( const KService::Ptr& offer, bool isstdin, const QString& docFile, const QByteArray& filedata );
bool savePageDocumentInfo( KTemporaryFile *infoFile, int what ) const;
DocumentViewport nextDocumentViewport() const;
void notifyAnnotationChanges( int page );
bool canAddAnnotationsNatively() const;
bool canModifyExternalAnnotations() const;
bool canRemoveExternalAnnotations() const;
@ -233,6 +235,7 @@ class DocumentPrivate
QSet< View * > m_views;
bool m_annotationEditingEnabled;
bool m_annotationBeingMoved; // is an annotation currently being moved?
bool m_containsExternalAnnotations; // set on opening and never changed
bool m_showWarningLimitedAnnotSupport;

@ -72,8 +72,9 @@ class OKULAR_EXPORT DocumentObserver
Bookmark = 2, ///< Bookmarks has been changed
Highlights = 4, ///< Highlighting information has been changed
TextSelection = 8, ///< Text selection has been changed
Annotations = 16, ///< Annotations has been changed
BoundingBox = 32 ///< Bounding boxes have been changed
Annotations = 16, ///< Annotations have been changed
BoundingBox = 32, ///< Bounding boxes have been changed
NeedSaveAs = 64 ///< Set along with Annotations when Save As is needed or annotation changes will be lost @since 0.15 (KDE 4.9)
};
/**

@ -58,7 +58,7 @@ Name[uk]=Okular
Name[x-test]=xxOkularxx
Name[zh_CN]=Okular
Name[zh_TW]=文件檢視_Okular
X-KDE-ServiceTypes=KParts/ReadOnlyPart
X-KDE-ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart
X-KDE-Library=okularpart
Type=Service
MimeType=application/vnd.kde.okular-archive;

@ -151,8 +151,25 @@ class FileKeeper
std::FILE * m_handle;
};
K_PLUGIN_FACTORY( okularPartFactory, registerPlugin< Okular::Part >(); )
K_EXPORT_PLUGIN( okularPartFactory( okularAboutData( "okular", I18N_NOOP( "Okular" ) ) ) )
Okular::PartFactory::PartFactory()
: KPluginFactory(okularAboutData( "okular", I18N_NOOP( "Okular" ) ))
{
}
Okular::PartFactory::~PartFactory()
{
}
QObject *Okular::PartFactory::create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args, const QString &keyword)
{
Q_UNUSED ( keyword );
Okular::Part *object = new Okular::Part( parentWidget, parent, args, componentData() );
object->setReadWrite( QLatin1String(iface) == QLatin1String("KParts::ReadWritePart") );
return object;
}
K_EXPORT_PLUGIN( Okular::PartFactory() )
static QAction* actionForExportFormat( const Okular::ExportFormat& format, QObject *parent = 0 )
{
@ -264,8 +281,9 @@ namespace Okular
Part::Part(QWidget *parentWidget,
QObject *parent,
const QVariantList &args )
: KParts::ReadOnlyPart(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_cliPresentation(false), m_embedMode(detectEmbedMode(parentWidget, parent, args)), m_generatorGuiClient(0), m_keeper( 0 )
{
@ -300,7 +318,7 @@ m_cliPresentation(false), m_embedMode(detectEmbedMode(parentWidget, parent, args
new OkularLiveConnectExtension( this );
// we need an instance
setComponentData(okularPartFactory::componentData());
setComponentData( componentData );
GuiUtils::addIconLoader( iconLoader() );
@ -1025,6 +1043,9 @@ void Part::notifyViewportChanged( bool /*smoothMove*/ )
void Part::notifyPageChanged( int page, int flags )
{
if ( flags & Okular::DocumentObserver::NeedSaveAs )
setModified();
if ( !(flags & Okular::DocumentObserver::Bookmark ) )
return;
@ -1258,6 +1279,10 @@ bool Part::openFile()
bool Part::openUrl(const KUrl &_url)
{
// Close current document if any
if ( !closeUrl() )
return false;
KUrl url( _url );
if ( url.hasHTMLRef() )
{
@ -1281,7 +1306,7 @@ bool Part::openUrl(const KUrl &_url)
}
// this calls in sequence the 'closeUrl' and 'openFile' methods
bool openOk = KParts::ReadOnlyPart::openUrl( url );
bool openOk = KParts::ReadWritePart::openUrl( url );
if ( openOk )
{
@ -1297,9 +1322,36 @@ bool Part::openUrl(const KUrl &_url)
return openOk;
}
bool Part::queryClose()
{
if ( !isReadWrite() || !isModified() )
return true;
bool Part::closeUrl()
const int res = KMessageBox::warningYesNoCancel( widget(),
i18n( "Do you want to save your annotation changes or discard them?" ),
i18n( "Close Document" ),
KStandardGuiItem::saveAs(),
KStandardGuiItem::discard() );
switch ( res )
{
case KMessageBox::Yes: // Save as
slotSaveFileAs();
return !isModified(); // Only allow closing if file was really saved
case KMessageBox::No: // Discard
return true;
default: // Cancel
return false;
}
}
bool Part::closeUrl(bool promptToSave)
{
if ( promptToSave && !queryClose() )
return false;
setModified( false );
if (!m_temporaryLocalFile.isNull() && m_temporaryLocalFile != localFilePath())
{
QFile::remove( m_temporaryLocalFile );
@ -1358,17 +1410,22 @@ bool Part::closeUrl()
#ifdef OKULAR_KEEP_FILE_OPEN
m_keeper->close();
#endif
bool r = KParts::ReadOnlyPart::closeUrl();
bool r = KParts::ReadWritePart::closeUrl();
setUrl(KUrl());
return r;
}
bool Part::closeUrl()
{
return closeUrl( true );
}
void Part::guiActivateEvent(KParts::GUIActivateEvent *event)
{
updateViewActions();
KParts::ReadOnlyPart::guiActivateEvent(event);
KParts::ReadWritePart::guiActivateEvent(event);
}
void Part::close()
@ -1473,7 +1530,12 @@ void Part::slotDoFileDirty()
}
// close and (try to) reopen the document
if ( KParts::ReadOnlyPart::openUrl( url() ) )
KUrl oldUrl = url();
if ( !closeUrl() )
return;
if ( KParts::ReadWritePart::openUrl( oldUrl ) )
{
// on successful opening, restore the previous viewport
if ( m_viewportDirty.pageNumber >= (int) m_document->pages() )
@ -1864,6 +1926,11 @@ void Part::slotFindPrev()
m_findBar->findPrev();
}
bool Part::saveFile()
{
kDebug() << "Okular part doesn't support saving the file in the location from which it was opened";
return false;
}
void Part::slotSaveFileAs()
{
@ -1876,12 +1943,17 @@ void Part::slotSaveFileAs()
if ( !saveUrl.isValid() || saveUrl.isEmpty() )
return;
saveAs( saveUrl );
}
bool Part::saveAs( const KUrl & saveUrl )
{
KTemporaryFile tf;
QString fileName;
if ( !tf.open() )
{
KMessageBox::information( widget(), i18n("Could not open the temporary file for saving." ) );
return;
return false;
}
fileName = tf.fileName();
tf.close();
@ -1897,12 +1969,18 @@ void Part::slotSaveFileAs()
{
KMessageBox::information( widget(), i18n("File could not be saved in '%1'. %2", fileName, errorText ) );
}
return;
return false;
}
KIO::Job *copyJob = KIO::file_copy( fileName, saveUrl, -1, KIO::Overwrite );
if ( !KIO::NetAccess::synchronousRun( copyJob, widget() ) )
{
KMessageBox::information( widget(), i18n("File could not be saved in '%1'. Try to save it to another location.", saveUrl.prettyUrl() ) );
return false;
}
setModified( false );
return true;
}
@ -2577,6 +2655,12 @@ void Part::updateAboutBackendAction()
}
}
void Part::setReadWrite(bool readwrite)
{
m_document->setAnnotationEditingEnabled( readwrite );
ReadWritePart::setReadWrite( readwrite );
}
} // namespace Okular
#include "part.moc"

@ -17,6 +17,7 @@
#define _PART_H_
#include <kparts/part.h>
#include <kpluginfactory.h>
#include <qicon.h>
#include <qlist.h>
#include <qpointer.h>
@ -89,7 +90,7 @@ enum EmbedMode
* @author Wilco Greven <greven@kde.org>
* @version 0.2
*/
class Part : public KParts::ReadOnlyPart, public Okular::DocumentObserver, public KDocumentViewer, public Okular::ViewerInterface
class Part : public KParts::ReadWritePart, public Okular::DocumentObserver, public KDocumentViewer, public Okular::ViewerInterface
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.okular")
@ -104,7 +105,7 @@ class Part : public KParts::ReadOnlyPart, public Okular::DocumentObserver, publi
* which config file should be used by adding a string containing "ConfigFileName=<file name>"
* to 'args'.
**/
Part(QWidget* parentWidget, QObject* parent, const QVariantList& args);
Part(QWidget* parentWidget, QObject* parent, const QVariantList& args, KComponentData componentData);
// Destructor
~Part();
@ -151,11 +152,17 @@ class Part : public KParts::ReadOnlyPart, public Okular::DocumentObserver, publi
void viewerMenuStateChange(bool enabled);
protected:
// reimplemented from KParts::ReadOnlyPart
// reimplemented from KParts::ReadWritePart
bool openFile();
bool openUrl(const KUrl &url);
bool closeUrl();
void guiActivateEvent(KParts::GUIActivateEvent *event);
public:
bool saveFile();
bool queryClose();
bool closeUrl();
bool closeUrl(bool promptToSave);
void setReadWrite(bool readwrite);
bool saveAs(const KUrl & saveUrl);
protected slots:
// connected to actions
@ -319,6 +326,18 @@ class Part : public KParts::ReadOnlyPart, public Okular::DocumentObserver, publi
void slotHandleActivatedSourceReference(const QString& absFileName, int line, int col, bool *handled);
};
class PartFactory : public KPluginFactory
{
Q_OBJECT
public:
PartFactory();
virtual ~PartFactory();
protected:
virtual QObject *create(const char *iface, QWidget *parentWidget, QObject *parent, const QVariantList &args, const QString &keyword);
};
}
#endif

@ -85,7 +85,7 @@ void Shell::init()
// now that the Part is loaded, we cast it to a Part to get
// our hands on it
m_part = factory->create< KParts::ReadOnlyPart >( this );
m_part = factory->create< KParts::ReadWritePart >( this );
if (m_part)
{
// then, setup our actions
@ -234,6 +234,10 @@ QStringList Shell::fileFormats() const
void Shell::fileOpen()
{
// Don't open dialog if current document can't be closed
if ( !m_part->queryClose() )
return;
// this slot is called whenever the File->Open menu is selected,
// the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
// button is clicked
@ -267,7 +271,10 @@ void Shell::fileOpen()
return;
KUrl url = dlg.selectedUrl();
if ( !url.isEmpty() )
{
m_part->closeUrl( false );
openUrl( url );
}
}
void Shell::slotQuit()
@ -331,6 +338,11 @@ QSize Shell::sizeHint() const
return QApplication::desktop()->availableGeometry( this ).size() * 0.75;
}
bool Shell::queryClose()
{
return m_part ? m_part->closeUrl() : true;
}
#include "shell.moc"
/* kate: replace-tabs on; indent-width 4; */

@ -68,6 +68,7 @@ protected:
void readSettings();
void writeSettings();
void setFullScreen( bool );
bool queryClose();
void showEvent(QShowEvent *event);
@ -92,7 +93,7 @@ private:
private:
KCmdLineArgs* m_args;
KParts::ReadOnlyPart* m_part;
KParts::ReadWritePart* m_part;
KDocumentViewer* m_doc;
KRecentFilesAction* m_recent;
QStringList m_fileformats;

Loading…
Cancel
Save