[PATCH] Work in progress to allow for editing of read-only documents

Stephan Bergmann sbergman at redhat.com
Thu May 31 00:25:10 PDT 2012


When e.g. viewing mail attachments (that have been stored r/o to some download
directory by the mail application), it would be nice if the user could easily
temporarily modify them (say, play around with a spreadsheet, changing some
numbers and triggering recalculation of formulas) by clicking the "Edit File"
button and not being asked to create a copy for editing.

This patch tries to make editability of a view independent of the r/o status of
the medium:

* SID_EDITDOC (the "Edit File" button) now only toggles the r/o status of the
  view.  It no longer asks to create a copy for editing if the underlying medium
  is r/o.

* When a modified document is toggled to r/o via SID_EDITDOC, LO still asks the
  user to save or discard the changes.  However, if the underlying medium is
  physically r/o (see next), saving the document opens the "Save As" dialog,
  instead of just doing a "Save" operation (which would fail on the r/o file).

* A new state of "IsOriginallyReadOnly" needed to be added to the medium, to
  keep track whether the medium was originally opened r/o (and is thus assumed
  to be physically r/o), as toggling SID_EDITDOC in the view also changes the
  open mode of the underlying medium.  Instead of trying to fully understand and
  disentangle that horrible mess, I just added yet another state to the mess...

* The title of the document window now contains "(read-only)" if and only if
  either the view is r/o or the medium is originally r/o (or both).

However, while this patch appears to work fine at least for simple cases of
Writer documents, it does not work well yet e.g. for Calc documents.  Opening a
r/o .ods file shows it in r/o view mode, but nonetheless allows for modification
of cell content etc.

Change-Id: Ic81f625eb0494dbd90db2e27403e89d48b2c3f87
---
 sfx2/inc/sfx2/docfile.hxx    |    5 +++++
 sfx2/inc/sfx2/objsh.hxx      |    1 +
 sfx2/source/doc/docfile.cxx  |   20 ++++++++++++++++----
 sfx2/source/doc/objmisc.cxx  |   12 ++++++++----
 sfx2/source/doc/objstor.cxx  |    2 +-
 sfx2/source/doc/objxtor.cxx  |    2 +-
 sfx2/source/view/viewfrm.cxx |   28 ++++++++++++++++------------
 7 files changed, 48 insertions(+), 22 deletions(-)

diff --git a/sfx2/inc/sfx2/docfile.hxx b/sfx2/inc/sfx2/docfile.hxx
index f7f85d5..ca8ad49 100644
--- a/sfx2/inc/sfx2/docfile.hxx
+++ b/sfx2/inc/sfx2/docfile.hxx
@@ -213,6 +213,11 @@ public:
                         GetVersionList( bool _bNoReload = false );
     sal_Bool            IsReadOnly();
 
+    // Whether the medium had originally been opened r/o, independent of later
+    // changes via SetOpenMode; used to keep track of the "true" state of the
+    // medium across toggles via SID_EDITDOC (which do change SetOpenMode):
+    bool                IsOriginallyReadOnly() const;
+
     ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >  GetInputStream();
 
     void                CreateTempFile( sal_Bool bReplace = sal_True );
diff --git a/sfx2/inc/sfx2/objsh.hxx b/sfx2/inc/sfx2/objsh.hxx
index 3c1837b..90acbb7 100644
--- a/sfx2/inc/sfx2/objsh.hxx
+++ b/sfx2/inc/sfx2/objsh.hxx
@@ -273,6 +273,7 @@ public:
     void                        SetReadOnly();
     sal_Bool                    IsReadOnly() const;
     sal_Bool                    IsReadOnlyMedium() const;
+    bool                        IsOriginallyReadOnlyMedium() const;
     void                        SetReadOnlyUI( sal_Bool bReadOnly = sal_True );
     sal_Bool                    IsReadOnlyUI() const;
     void                        SetNoName();
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 4da1556..e77992e 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -312,6 +312,8 @@ public:
 
     uno::Reference< logging::XSimpleLogRing > m_xLogRing;
 
+    bool m_originallyReadOnly;
+
     SfxMedium_Impl( SfxMedium* pAntiImplP );
     ~SfxMedium_Impl();
 };
@@ -339,7 +341,8 @@ SfxMedium_Impl::SfxMedium_Impl( SfxMedium* pAntiImplP )
     pTempFile( NULL ),
     nLastStorageError( 0 ),
     m_bRemoveBackup( sal_False ),
-    m_nSignatureState( SIGNATURESTATE_NOSIGNATURES )
+    m_nSignatureState( SIGNATURESTATE_NOSIGNATURES ),
+    m_originallyReadOnly(false)
 {
     aDoneLink.CreateMutex();
 }
@@ -1057,6 +1060,11 @@ sal_Bool SfxMedium::LockOrigFileOnDemand( sal_Bool bLoading, sal_Bool bNoUI )
                         bContentReadonly = IsReadonlyAccordingACL( aPhysPath.GetBuffer() );
                 }
 #endif
+
+                if ( bContentReadonly )
+                {
+                    pImp->m_originallyReadOnly = true;
+                }
             }
 
             // do further checks only if the file not readonly in fs
@@ -2874,15 +2882,14 @@ SfxMedium::SfxMedium( const ::com::sun::star::uno::Sequence< ::com::sun::star::b
         }
     }
 
-    sal_Bool bReadOnly = sal_False;
     SFX_ITEMSET_ARG( pSet, pReadOnlyItem, SfxBoolItem, SID_DOC_READONLY, sal_False );
     if ( pReadOnlyItem && pReadOnlyItem->GetValue() )
-        bReadOnly = sal_True;
+        pImp->m_originallyReadOnly = true;
 
     SFX_ITEMSET_ARG( pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, sal_False );
     if (!pFileNameItem) throw uno::RuntimeException();
     aLogicName = pFileNameItem->GetValue();
-    nStorOpenMode = bReadOnly ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE;
+    nStorOpenMode = pImp->m_originallyReadOnly ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE;
     Init_Impl();
 }
 
@@ -3207,6 +3214,11 @@ sal_Bool SfxMedium::IsReadOnly()
     return bReadOnly;
 }
 
+bool SfxMedium::IsOriginallyReadOnly() const
+{
+    return pImp->m_originallyReadOnly;
+}
+
 //----------------------------------------------------------------
 sal_Bool SfxMedium::SetWritableForUserOnly( const ::rtl::OUString& aURL )
 {
diff --git a/sfx2/source/doc/objmisc.cxx b/sfx2/source/doc/objmisc.cxx
index 037f4bc..4c05bdb 100644
--- a/sfx2/source/doc/objmisc.cxx
+++ b/sfx2/source/doc/objmisc.cxx
@@ -404,6 +404,11 @@ sal_Bool SfxObjectShell::IsReadOnlyMedium() const
     return pMedium->IsReadOnly();
 }
 
+bool SfxObjectShell::IsOriginallyReadOnlyMedium() const
+{
+    return pMedium == 0 || pMedium->IsOriginallyReadOnly();
+}
+
 //-------------------------------------------------------------------------
 
 void SfxObjectShell::SetReadOnlyUI( sal_Bool bReadOnly )
@@ -415,10 +420,9 @@ void SfxObjectShell::SetReadOnlyUI( sal_Bool bReadOnly )
 */
 
 {
-    sal_Bool bWasRO = IsReadOnly();
-    pImp->bReadOnlyUI = bReadOnly;
-    if ( bWasRO != IsReadOnly() )
+    if ( bReadOnly != pImp->bReadOnlyUI )
     {
+        pImp->bReadOnlyUI = bReadOnly;
         Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) );
     }
 }
@@ -453,7 +457,7 @@ void SfxObjectShell::SetReadOnly()
 
 sal_Bool SfxObjectShell::IsReadOnly() const
 {
-    return pImp->bReadOnlyUI || IsReadOnlyMedium();
+    return pImp->bReadOnlyUI || pMedium == 0;
 }
 
 //-------------------------------------------------------------------------
diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx
index 313d95d..a8e3c61 100644
--- a/sfx2/source/doc/objstor.cxx
+++ b/sfx2/source/doc/objstor.cxx
@@ -689,7 +689,7 @@ sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed )
                     if ( !pTemplateItem || !pTemplateItem->GetValue() )
                         bHasName = sal_True;
 
-                    if ( !IsReadOnly() && IsLoadReadonly() )
+                    if ( IsReadOnlyMedium() || IsLoadReadonly() )
                         SetReadOnlyUI();
                 }
                 else
diff --git a/sfx2/source/doc/objxtor.cxx b/sfx2/source/doc/objxtor.cxx
index 9e20d83..dd1dbc1 100644
--- a/sfx2/source/doc/objxtor.cxx
+++ b/sfx2/source/doc/objxtor.cxx
@@ -661,7 +661,7 @@ sal_uInt16 SfxObjectShell::PrepareClose
             {
                 SfxBoolItem aWarnItem( SID_FAIL_ON_WARNING, bUI );
                 const SfxPoolItem* ppArgs[] = { &aWarnItem, 0 };
-                pPoolItem = pFrame->GetBindings().ExecuteSynchron( SID_SAVEDOC, ppArgs );
+                pPoolItem = pFrame->GetBindings().ExecuteSynchron( IsReadOnlyMedium() ? SID_SAVEASDOC : SID_SAVEDOC, ppArgs );
             }
 
             if ( !pPoolItem || pPoolItem->ISA(SfxVoidItem) || ( pPoolItem->ISA(SfxBoolItem) && !( (const SfxBoolItem*) pPoolItem )->GetValue() ) )
diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx
index 0538bce..155c194 100644
--- a/sfx2/source/view/viewfrm.cxx
+++ b/sfx2/source/view/viewfrm.cxx
@@ -405,6 +405,7 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                     }
                 }
                 nOpenMode = SFX_STREAM_READONLY;
+                pSh->SetReadOnlyUI(true);
             }
             else
             {
@@ -424,12 +425,20 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                     pSh->SetModifyPasswordEntered();
                 }
 
-                nOpenMode = SFX_STREAM_READWRITE;
-                pSh->SetReadOnlyUI( sal_False );
+                nOpenMode = pSh->IsOriginallyReadOnlyMedium() ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE;
 
                 // if only the view was in the readonly mode then there is no need to do the reload
-                if ( !pSh->IsReadOnly() )
+                if ( !pSh->IsReadOnlyMedium() )
+                {
+                    // SetReadOnlyUI causes recomputation of window title, using
+                    // open mode among other things, so call SetOpenMode before
+                    // SetReadOnlyUI:
+                    pMed->SetOpenMode( nOpenMode );
+                    pSh->SetReadOnlyUI( sal_False );
                     return;
+                }
+
+                pSh->SetReadOnlyUI( sal_False );
             }
 
             if ( rReq.IsAPI() )
@@ -580,8 +589,6 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                             SID_FILE_NAME, sal_False);
             // Open as editable?
             sal_Bool bForEdit = !pSh->IsReadOnly();
-            if ( rReq.GetSlot() == SID_EDITDOC )
-                bForEdit = !bForEdit;
 
             // If possible ask the User
             sal_Bool bDo = ( GetViewShell()->PrepareClose() != sal_False );
@@ -650,9 +657,9 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                     // let the current security settings be checked again
                     pNewSet->Put( SfxUInt16Item( SID_MACROEXECMODE, document::MacroExecMode::USE_CONFIG ) );
 
-                    if ( rReq.GetSlot() == SID_EDITDOC || !bForEdit )
+                    if ( pSh->IsOriginallyReadOnlyMedium() )
                         // edit mode is switched or reload of readonly document
-                        pNewSet->Put( SfxBoolItem( SID_DOC_READONLY, !bForEdit ) );
+                        pNewSet->Put( SfxBoolItem( SID_DOC_READONLY, true ) );
                     else
                         // Reload of file opened for writing
                         pNewSet->ClearItem( SID_DOC_READONLY );
@@ -778,12 +785,9 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                         xNewObj->SetModifyPasswordEntered( sal_False );
                         xNewObj->SetReadOnly();
                     }
-                    else if ( rReq.GetSlot() == SID_EDITDOC && bForEdit && !xNewObj->IsReadOnlyMedium() )
+                    else if ( rReq.GetSlot() == SID_EDITDOC )
                     {
-                        // the filter might request setting of the document to readonly state
-                        // but in case of SID_EDITDOC it should not happen if the document
-                        // can be opened for editing
-                        xNewObj->SetReadOnlyUI( sal_False );
+                        xNewObj->SetReadOnlyUI( !bForEdit );
                     }
 
                     if ( xNewObj->IsDocShared() )
-- 
1.7.10.2


--------------080700050804020305090907--


More information about the LibreOffice mailing list