[Libreoffice-commits] core.git: include/sfx2 sfx2/source uui/inc uui/source

Mike Kaganski mike.kaganski at collabora.com
Fri Feb 9 04:49:26 UTC 2018


 include/sfx2/docfile.hxx      |   19 ++++-
 include/sfx2/strings.hrc      |    3 
 sfx2/source/doc/docfile.cxx   |   71 +++++++++++++++-------
 sfx2/source/view/viewfrm.cxx  |  134 +++++++++++++++++++++++++++++++-----------
 uui/inc/strings.hrc           |    3 
 uui/source/iahndl-locking.cxx |   12 +++
 uui/source/iahndl.cxx         |    9 +-
 uui/source/openlocked.cxx     |   14 +++-
 uui/source/openlocked.hxx     |    2 
 9 files changed, 194 insertions(+), 73 deletions(-)

New commits:
commit 2a7057250c8f73fdfb4c65a7525d17e9770459df
Author: Mike Kaganski <mike.kaganski at collabora.com>
Date:   Thu Feb 8 18:06:06 2018 +0300

    tdf#108210: Allow to ignore a lock file if there's no filesystem lock
    
    Two cases are handled: when a file is being opened, and when it was
    opened read-only already, and one tries to reopen it in edit mode.
    The option to ignore locking and open the file anyway is only offered
    when there is no filesystem lock present on the file.
    
    Change-Id: I377d3cae4c949ae64d449634acea8fb3f68a5700
    Reviewed-on: https://gerrit.libreoffice.org/49448
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/include/sfx2/docfile.hxx b/include/sfx2/docfile.hxx
index 822c69b1da4f..06a7f9623764 100644
--- a/include/sfx2/docfile.hxx
+++ b/include/sfx2/docfile.hxx
@@ -162,11 +162,13 @@ public:
     bool                Commit();
     bool                IsStorage();
 
-    enum class ShowLockResult { NoLock, Succeeded,Try };
-    ShowLockResult      ShowLockedDocumentDialog( const LockFileEntry& aData, bool bIsLoading, bool bOwnLock, bool bHandleSysLocked);
-    void                LockOrigFileOnDemand( bool bLoading, bool bNoUI );
-    enum class MessageDlg    { LockFileIgnore, LockFileCorrupt };
-    bool                ShowLockFileProblemDialog(MessageDlg nWhichDlg);
+    enum class          LockFileResult
+    {
+        Failed,
+        FailedLockFile, // there was only lock file that prevented success - no syslock or IO error
+        Succeeded,
+    };
+    LockFileResult      LockOrigFileOnDemand( bool bLoading, bool bNoUI, bool bTryIgnoreLockFile = false );
     void                DisableUnlockWebDAV( bool bDisableUnlockWebDAV = true );
     void                UnlockFile( bool bReleaseLockStream );
     /// Lets Transfer_Impl() not fsync the output file.
@@ -275,6 +277,13 @@ public:
 
     static bool         SetWritableForUserOnly( const OUString& aURL );
     static sal_uInt32   CreatePasswordToModifyHash( const OUString& aPasswd, bool bWriter );
+
+private:
+    enum class ShowLockResult { NoLock, Succeeded, Try };
+    ShowLockResult      ShowLockedDocumentDialog(const LockFileEntry& aData, bool bIsLoading, bool bOwnLock, bool bHandleSysLocked);
+    enum class MessageDlg { LockFileIgnore, LockFileCorrupt };
+    bool                ShowLockFileProblemDialog(MessageDlg nWhichDlg);
+
 };
 
 #endif
diff --git a/include/sfx2/strings.hrc b/include/sfx2/strings.hrc
index 889ccf8ab22b..c36a37b4893a 100644
--- a/include/sfx2/strings.hrc
+++ b/include/sfx2/strings.hrc
@@ -235,6 +235,9 @@
 #define STR_CANT_CLOSE                          NC_("STR_CANT_CLOSE", "The document cannot be closed because a\n print job is being carried out.")
 #define STR_ERROR_SEND_MAIL                     NC_("STR_ERROR_SEND_MAIL", "An error occurred in sending the message. Possible errors could be a missing user account or a defective setup.\nPlease check the %PRODUCTNAME settings or your e-mail program settings.")
 #define STR_QUERY_OPENASTEMPLATE                NC_("STR_QUERY_OPENASTEMPLATE", "This document cannot be edited, possibly due to missing access rights. Do you want to edit a copy of the document?")
+#define STR_QUERY_OPENASTEMPLATE_ALLOW_IGNORE   NC_("STR_QUERY_OPENASTEMPLATE_ALLOW_IGNORE", "This document cannot be edited, because it is locked in another session. Do you want to edit a copy of the document?\n\nYou can also try to ignore the lock and open the file for editing.")
+#define STR_QUERY_OPENASTEMPLATE_OPENCOPY_BTN   NC_("STR_QUERY_OPENASTEMPLATE_OPENCOPY_BTN", "Open ~Copy")
+#define STR_QUERY_OPENASTEMPLATE_OPEN_BTN       NC_("STR_QUERY_OPENASTEMPLATE_OPEN_BTN", "~Open")
 #define STR_REPAIREDDOCUMENT                    NC_("STR_REPAIREDDOCUMENT", " (repaired document)")
 #define STR_NONCHECKEDOUT_DOCUMENT              NC_("STR_NONCHECKEDOUT_DOCUMENT", "This document is not checked out on the server.")
 #define STR_READONLY_DOCUMENT                   NC_("STR_READONLY_DOCUMENT", "This document is open in read-only mode.")
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 055cfa41859d..175ab138c5af 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -846,6 +846,8 @@ SfxMedium::ShowLockResult SfxMedium::ShowLockedDocumentDialog( const LockFileEnt
         OUString aInfo;
         ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl;
 
+        sal_Int32 nContinuations = 3;
+
         if ( bOwnLock )
         {
             aInfo = aData[LockFileComponent::EDITTIME];
@@ -869,12 +871,23 @@ SfxMedium::ShowLockResult SfxMedium::ShowLockedDocumentDialog( const LockFileEnt
 
             xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny(
                 document::LockedDocumentRequest( OUString(), uno::Reference< uno::XInterface >(), aDocumentURL, aInfo ) ) );
+
+            // Use a fourth continuation in case there's no filesystem lock:
+            // "Ignore lock file and open the document"
+            if (!bHandleSysLocked)
+                nContinuations = 4;
         }
 
-        uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 );
+        uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations(nContinuations);
         aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() );
         aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() );
         aContinuations[2] = new ::ucbhelper::InteractionDisapprove( xInteractionRequestImpl.get() );
+        if (nContinuations > 3)
+        {
+            // We use InteractionRetry to reflect that user wants to
+            // ignore the (stale?) alien lock file and open the document
+            aContinuations[3] = new ::ucbhelper::InteractionRetry(xInteractionRequestImpl.get());
+        }
         xInteractionRequestImpl->setContinuations( aContinuations );
 
         xHandler->handle( xInteractionRequestImpl.get() );
@@ -890,14 +903,19 @@ SfxMedium::ShowLockResult SfxMedium::ShowLockedDocumentDialog( const LockFileEnt
             // own lock on saving, user has selected to ignore the lock
             // alien lock on loading, user has selected to edit a copy of document
             // TODO/LATER: alien lock on saving, user has selected to do SaveAs to different location
-            if ( bIsLoading && !bOwnLock )
+            if ( !bOwnLock ) // bIsLoading implied from outermost condition
             {
                 // means that a copy of the document should be opened
                 GetItemSet()->Put( SfxBoolItem( SID_TEMPLATE, true ) );
             }
-            else if ( bOwnLock )
+            else
                 nResult = ShowLockResult::Succeeded;
         }
+        else if (uno::Reference< task::XInteractionRetry >(xSelected.get(), uno::UNO_QUERY).is())
+        {
+            // User decided to ignore the alien (stale?) lock file without filesystem lock
+            nResult = ShowLockResult::Succeeded;
+        }
         else // if ( XSelected == aContinuations[1] )
         {
             // own lock on loading, user has selected to open readonly
@@ -992,12 +1010,16 @@ namespace
 
 // sets SID_DOC_READONLY if the document cannot be opened for editing
 // if user cancel the loading the ERROR_ABORT is set
-void SfxMedium::LockOrigFileOnDemand( bool bLoading, bool bNoUI )
+SfxMedium::LockFileResult SfxMedium::LockOrigFileOnDemand( bool bLoading, bool bNoUI, bool bTryIgnoreLockFile )
 {
 #if !HAVE_FEATURE_MULTIUSER_ENVIRONMENT
     (void) bLoading;
     (void) bNoUI;
+    (void) bTryIgnoreLockFile;
+    return LockFileResult::Succeeded;
 #else
+    LockFileResult eResult = LockFileResult::Failed;
+
     // check if path scheme is http:// or https://
     // may be this is better if used always, in Android and iOS as well?
     // if this code should be always there, remember to move the relevant code in UnlockFile method as well !
@@ -1069,7 +1091,7 @@ void SfxMedium::LockOrigFileOnDemand( bool bLoading, bool bNoUI )
 
                             if ( !bResult && !bNoUI )
                             {
-                                bUIStatus = ShowLockedDocumentDialog( aLockData, bLoading, false , false );
+                                bUIStatus = ShowLockedDocumentDialog( aLockData, bLoading, false , true );
                             }
                         }
                         catch( ucb::InteractiveNetworkWriteException& )
@@ -1108,23 +1130,28 @@ void SfxMedium::LockOrigFileOnDemand( bool bLoading, bool bNoUI )
             // when the file is locked, get the current file date
             if ( bResult && DocNeedsFileDateCheck() )
                 GetInitFileDate( true );
+
+            if ( bResult )
+                eResult = LockFileResult::Succeeded;
         }
         catch ( const uno::Exception& )
         {
             SAL_WARN( "sfx.doc", "Locking exception: WebDAV while trying to lock the file" );
         }
-        return;
+        return eResult;
     }
 
-    if (!IsLockingUsed() || GetURLObject().HasError())
-        return;
+    if (!IsLockingUsed())
+        return LockFileResult::Succeeded;
+    if (GetURLObject().HasError())
+        return eResult;
 
     try
     {
         if ( pImpl->m_bLocked && bLoading
              && GetURLObject().GetProtocol() == INetProtocol::File )
         {
-            // if the document is already locked the system locking might be temporarely off after storing
+            // if the document is already locked the system locking might be temporarily off after storing
             // check whether the system file locking should be taken again
             GetLockingStream_Impl();
         }
@@ -1176,7 +1203,7 @@ void SfxMedium::LockOrigFileOnDemand( bool bLoading, bool bNoUI )
                         // let the stream be opened to check the system file locking
                         GetMedium_Impl();
                         if (GetError() != ERRCODE_NONE) {
-                            return;
+                            return eResult;
                         }
                     }
 
@@ -1202,15 +1229,6 @@ void SfxMedium::LockOrigFileOnDemand( bool bLoading, bool bNoUI )
                                 {
                                     bResult = aLockFile.CreateOwnLockFile();
                                 }
-                                catch (const ucb::InteractiveIOException&)
-                                {
-                                    if (bLoading && !bNoUI)
-                                    {
-                                        bIoErr = true;
-                                        ShowLockFileProblemDialog(MessageDlg::LockFileIgnore);
-                                        bResult = true;   // always delete the defect lock-file
-                                    }
-                                }
                                 catch (const uno::Exception&)
                                 {
                                     if (bLoading && !bNoUI)
@@ -1270,14 +1288,20 @@ void SfxMedium::LockOrigFileOnDemand( bool bLoading, bool bNoUI )
                                     }
                                 }
 
-                                if ( !bResult && !bNoUI && !bIoErr)
+                                if ( !bResult && !bIoErr)
                                 {
-                                    bUIStatus = ShowLockedDocumentDialog( aData, bLoading, bOwnLock, bHandleSysLocked );
+                                    if (!bNoUI)
+                                        bUIStatus = ShowLockedDocumentDialog(aData, bLoading, bOwnLock, bHandleSysLocked);
+                                    else if (bLoading && bTryIgnoreLockFile && !bHandleSysLocked)
+                                        bUIStatus = ShowLockResult::Succeeded;
+
                                     if ( bUIStatus == ShowLockResult::Succeeded )
                                     {
                                         // take the ownership over the lock file
                                         bResult = aLockFile.OverwriteOwnLockFile();
                                     }
+                                    else if (bLoading && !bHandleSysLocked)
+                                        eResult = LockFileResult::FailedLockFile;
                                 }
                             }
                         }
@@ -1311,11 +1335,16 @@ void SfxMedium::LockOrigFileOnDemand( bool bLoading, bool bNoUI )
         // when the file is locked, get the current file date
         if ( bResult && DocNeedsFileDateCheck() )
             GetInitFileDate( true );
+
+        if ( bResult )
+            eResult = LockFileResult::Succeeded;
     }
     catch( const uno::Exception& )
     {
         SAL_WARN( "sfx.doc", "Locking exception: high probability, that the content has not been created" );
     }
+
+    return eResult;
 #endif
 }
 
diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx
index 7a5a536bb46e..7fee9f85800f 100644
--- a/sfx2/source/view/viewfrm.cxx
+++ b/sfx2/source/view/viewfrm.cxx
@@ -134,6 +134,7 @@ using ::com::sun::star::container::XIndexContainer;
 #include <sfx2/minfitem.hxx>
 #include <sfx2/strings.hrc>
 #include "impviewframe.hxx"
+#include <vcl/msgbox.hxx>
 
 #define SfxViewFrame
 #include <sfxslots.hxx>
@@ -151,6 +152,7 @@ void SfxViewFrame::InitInterface_Impl()
 #endif
 }
 
+namespace {
 /// Asks the user if editing a read-only document is really wanted.
 class SfxEditDocumentDialog : public MessageDialog
 {
@@ -183,8 +185,31 @@ void SfxEditDocumentDialog::dispose()
     MessageDialog::dispose();
 }
 
+class SfxQueryOpenAsTemplate : public QueryBox
+{
+public:
+    SfxQueryOpenAsTemplate(vcl::Window* pParent, MessBoxStyle nStyle, bool bAllowIgnoreLock);
+};
+
+SfxQueryOpenAsTemplate::SfxQueryOpenAsTemplate(vcl::Window* pParent, MessBoxStyle nStyle, bool bAllowIgnoreLock)
+    : QueryBox(pParent, nStyle, SfxResId(bAllowIgnoreLock ? STR_QUERY_OPENASTEMPLATE_ALLOW_IGNORE : STR_QUERY_OPENASTEMPLATE))
+{
+    AddButton(SfxResId(STR_QUERY_OPENASTEMPLATE_OPENCOPY_BTN), RET_YES,
+        ButtonDialogFlags::Default | ButtonDialogFlags::OK | ButtonDialogFlags::Focus);
+    SetButtonHelpText(RET_YES, OUString());
+
+    if (bAllowIgnoreLock)
+    {
+        AddButton(SfxResId(STR_QUERY_OPENASTEMPLATE_OPEN_BTN), RET_IGNORE);
+        SetButtonHelpText(RET_IGNORE, OUString());
+    }
+
+    AddButton(StandardButtonType::Cancel, RET_CANCEL);
+    SetButtonHelpText(RET_CANCEL, OUString());
+}
+
 /// Is this read-only object shell opened via .uno:SignPDF?
-static bool IsSignPDF(const SfxObjectShellRef& xObjSh)
+bool IsSignPDF(const SfxObjectShellRef& xObjSh)
 {
     if (!xObjSh.is())
         return false;
@@ -200,7 +225,7 @@ static bool IsSignPDF(const SfxObjectShellRef& xObjSh)
     return false;
 }
 
-static bool AskPasswordToModify_Impl( const uno::Reference< task::XInteractionHandler >& xHandler, const OUString& aPath, const std::shared_ptr<const SfxFilter>& pFilter, sal_uInt32 nPasswordHash, const uno::Sequence< beans::PropertyValue >& aInfo )
+bool AskPasswordToModify_Impl( const uno::Reference< task::XInteractionHandler >& xHandler, const OUString& aPath, const std::shared_ptr<const SfxFilter>& pFilter, sal_uInt32 nPasswordHash, const uno::Sequence< beans::PropertyValue >& aInfo )
 {
     // TODO/LATER: In future the info should replace the direct hash completely
     bool bResult = ( !nPasswordHash && !aInfo.getLength() );
@@ -248,6 +273,7 @@ static bool AskPasswordToModify_Impl( const uno::Reference< task::XInteractionHa
 
     return bResult;
 }
+}
 
 void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
 {
@@ -263,6 +289,23 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
             if( !pSh || !pSh->HasName() || !(pSh->Get_Impl()->nLoadedFlags & SfxLoadedFlags::MAINDOCUMENT ))
                 break;
 
+            // Only change read-only UI and remove info bar when we succeed
+            struct ReadOnlyUIGuard
+            {
+                SfxViewFrame* m_pFrame;
+                SfxObjectShell* m_pSh;
+                bool m_bSetRO;
+                ~ReadOnlyUIGuard()
+                {
+                    if (m_bSetRO != m_pSh->IsReadOnlyUI())
+                    {
+                        m_pSh->SetReadOnlyUI(m_bSetRO);
+                        if (!m_bSetRO)
+                            m_pFrame->RemoveInfoBar("readonly");
+                    }
+                }
+            } aReadOnlyUIGuard{ this, pSh, pSh->IsReadOnlyUI() };
+
             SfxMedium* pMed = pSh->GetMedium();
 
             const SfxBoolItem* pItem = SfxItemSet::GetItem<SfxBoolItem>(pSh->GetMedium()->GetItemSet(), SID_VIEWONLY, false);
@@ -312,7 +355,7 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                     }
                 }
                 nOpenMode = SFX_STREAM_READONLY;
-                pSh->SetReadOnlyUI();
+                aReadOnlyUIGuard.m_bSetRO = true;
             }
             else
             {
@@ -332,10 +375,8 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                     pSh->SetModifyPasswordEntered();
                 }
 
-                // Remove infobar if document was read-only (after password check)
-                RemoveInfoBar("readonly");
-
                 nOpenMode = pSh->IsOriginallyReadOnlyMedium() ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE;
+                aReadOnlyUIGuard.m_bSetRO = false;
 
                 // if only the view was in the readonly mode then there is no need to do the reload
                 if ( !pSh->IsReadOnlyMedium() )
@@ -344,12 +385,8 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                     // open mode among other things, so call SetOpenMode before
                     // SetReadOnlyUI:
                     pMed->SetOpenMode( nOpenMode );
-                    pSh->SetReadOnlyUI( false );
                     return;
                 }
-
-
-                pSh->SetReadOnlyUI( false );
             }
 
             if ( rReq.IsAPI() )
@@ -396,31 +433,58 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
             // <- tdf#82744
             {
                 bool bOK = false;
-                if ( !pVersionItem )
-                {
-                    bool bHasStorage = pMed->HasStorage_Impl();
-                    // switching edit mode could be possible without reload
-                    if ( bHasStorage && pMed->GetStorage() == pSh->GetStorage() )
+                bool bRetryIgnoringLock = false;
+                bool bOpenTemplate = false;
+                do {
+                    if ( !pVersionItem )
                     {
-                        // TODO/LATER: faster creation of copy
-                        if ( !pSh->ConnectTmpStorage_Impl( pMed->GetStorage(), pMed ) )
-                            return;
-                    }
+                        if (bRetryIgnoringLock)
+                            pMed->ResetError();
 
-                    pMed->CloseAndRelease();
-                    pMed->GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, !( nOpenMode & StreamMode::WRITE ) ) );
-                    pMed->SetOpenMode( nOpenMode );
+                        bool bHasStorage = pMed->HasStorage_Impl();
+                        // switching edit mode could be possible without reload
+                        if ( bHasStorage && pMed->GetStorage() == pSh->GetStorage() )
+                        {
+                            // TODO/LATER: faster creation of copy
+                            if ( !pSh->ConnectTmpStorage_Impl( pMed->GetStorage(), pMed ) )
+                                return;
+                        }
+
+                        pMed->CloseAndRelease();
+                        pMed->GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, !( nOpenMode & StreamMode::WRITE ) ) );
+                        pMed->SetOpenMode( nOpenMode );
 
-                    pMed->CompleteReOpen();
-                    if ( nOpenMode & StreamMode::WRITE )
-                        pMed->LockOrigFileOnDemand( false, true );
+                        pMed->CompleteReOpen();
+                        if ( nOpenMode & StreamMode::WRITE )
+                        {
+                             auto eResult = pMed->LockOrigFileOnDemand( true, true, bRetryIgnoringLock );
+                             bRetryIgnoringLock = eResult == SfxMedium::LockFileResult::FailedLockFile;
+                        }
+
+                        // LockOrigFileOnDemand might set the readonly flag itself, it should be set back
+                        pMed->GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, !( nOpenMode & StreamMode::WRITE ) ) );
+
+                        if ( !pMed->GetErrorCode() )
+                            bOK = true;
+                    }
 
-                    // LockOrigFileOnDemand might set the readonly flag itself, it should be set back
-                    pMed->GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, !( nOpenMode & StreamMode::WRITE ) ) );
+                    if( !bOK )
+                    {
+                        if (nOpenMode == SFX_STREAM_READWRITE && !rReq.IsAPI())
+                        {
+                            // css::sdbcx::User offering to open it as a template
+                            ScopedVclPtrInstance<SfxQueryOpenAsTemplate> aBox(&GetWindow(), MessBoxStyle::NONE, bRetryIgnoringLock);
 
-                    if ( !pMed->GetErrorCode() )
-                        bOK = true;
+                            short nUserAnswer = aBox->Execute();
+                            bOpenTemplate = RET_YES == nUserAnswer;
+                            // Always reset this here to avoid infinite loop
+                            bRetryIgnoringLock = RET_IGNORE == nUserAnswer;
+                        }
+                        else
+                            bRetryIgnoringLock = false;
+                    }
                 }
+                while ( !bOK && bRetryIgnoringLock );
 
                 if( !bOK )
                 {
@@ -440,10 +504,7 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
 
                     if ( nOpenMode == SFX_STREAM_READWRITE && !rReq.IsAPI() )
                     {
-                        // css::sdbcx::User offering to open it as a template
-                        ScopedVclPtrInstance<MessageDialog> aBox(&GetWindow(), SfxResId(STR_QUERY_OPENASTEMPLATE),
-                                           VclMessageType::Question, VclButtonsType::YesNo);
-                        if ( RET_YES == aBox->Execute() )
+                        if ( bOpenTemplate )
                         {
                             SfxApplication* pApp = SfxGetpApp();
                             SfxAllItemSet aSet( pApp->GetPool() );
@@ -466,10 +527,13 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
                             GetDispatcher()->Execute( SID_OPENDOC, SfxCallMode::ASYNCHRON, aSet );
                             return;
                         }
-                        else
-                            nErr = ERRCODE_NONE;
+
+                        nErr = ERRCODE_NONE;
                     }
 
+                    // Keep the read-only UI
+                    aReadOnlyUIGuard.m_bSetRO = true;
+
                     ErrorHandler::HandleError( nErr );
                     rReq.SetReturnValue(
                         SfxBoolItem( rReq.GetSlot(), false ) );
diff --git a/uui/inc/strings.hrc b/uui/inc/strings.hrc
index 760402c1d57b..590a582eba06 100644
--- a/uui/inc/strings.hrc
+++ b/uui/inc/strings.hrc
@@ -47,7 +47,8 @@
 #define STR_LOCKFAILED_OPENREADONLY_BTN         NC_("STR_LOCKFAILED_OPENREADONLY_BTN", "Open ~Read-Only")
 
 #define STR_OPENLOCKED_TITLE                    NC_("STR_OPENLOCKED_TITLE", "Document in Use")
-#define STR_OPENLOCKED_MSG                      NC_("STR_OPENLOCKED_MSG", "Document file '$(ARG1)' is locked for editing by:\n\n$(ARG2)\n\nOpen document read-only or open a copy of the document for editing.\n\n")
+#define STR_OPENLOCKED_MSG                      NC_("STR_OPENLOCKED_MSG", "Document file '$(ARG1)' is locked for editing by:\n\n$(ARG2)\n\nOpen document read-only or open a copy of the document for editing.\n\n$(ARG3)")
+#define STR_OPENLOCKED_ALLOWIGNORE_MSG          NC_("STR_OPENLOCKED_ALLOWIGNORE_MSG", "You may also ignore the file locking and open the document for editing.\n\n")
 #define STR_OPENLOCKED_OPENREADONLY_BTN         NC_("STR_OPENLOCKED_OPENREADONLY_BTN", "Open ~Read-Only")
 #define STR_OPENLOCKED_OPENCOPY_BTN             NC_("STR_OPENLOCKED_OPENCOPY_BTN", "Open ~Copy")
 #define STR_UNKNOWNUSER                         NC_("STR_UNKNOWNUSER", "Unknown User")
diff --git a/uui/source/iahndl-locking.cxx b/uui/source/iahndl-locking.cxx
index 53b0e6a2fc77..08b5b5c7fd99 100644
--- a/uui/source/iahndl-locking.cxx
+++ b/uui/source/iahndl-locking.cxx
@@ -29,6 +29,7 @@
 #include <com/sun/star/task/XInteractionDisapprove.hpp>
 #include <com/sun/star/task/XInteractionAbort.hpp>
 #include <com/sun/star/task/XInteractionRequest.hpp>
+#include <com/sun/star/task/XInteractionRetry.hpp>
 
 #include <unotools/resmgr.hxx>
 #include <vcl/svapp.hxx>
@@ -66,7 +67,9 @@ handleLockedDocumentRequest_(
     uno::Reference< task::XInteractionApprove > xApprove;
     uno::Reference< task::XInteractionDisapprove > xDisapprove;
     uno::Reference< task::XInteractionAbort > xAbort;
-    getContinuations(rContinuations, &xApprove, &xDisapprove, &xAbort);
+    // In case an option to ignore lock and open the file is available
+    uno::Reference< task::XInteractionRetry > xRetry;
+    getContinuations(rContinuations, &xApprove, &xDisapprove, &xAbort, &xRetry);
 
     if ( !xApprove.is() || !xDisapprove.is() || !xAbort.is() )
         return;
@@ -86,11 +89,14 @@ handleLockedDocumentRequest_(
             aArguments.push_back( !aInfo.isEmpty()
                                   ? aInfo
                                   : Translate::get( STR_UNKNOWNUSER, aResLocale) );
+            aArguments.push_back( xRetry.is()
+                                  ? Translate::get( STR_OPENLOCKED_ALLOWIGNORE_MSG, aResLocale )
+                                  : "" );
             aMessage = Translate::get(STR_OPENLOCKED_MSG, aResLocale);
             aMessage = UUIInteractionHelper::replaceMessageWithArguments(
                 aMessage, aArguments );
 
-            ScopedVclPtrInstance< OpenLockedQueryBox > xDialog(pParent, aResLocale, aMessage);
+            ScopedVclPtrInstance< OpenLockedQueryBox > xDialog(pParent, aResLocale, aMessage, xRetry.is());
             nResult = xDialog->Execute();
         }
         else if ( nMode == UUI_DOC_SAVE_LOCK )
@@ -128,6 +134,8 @@ handleLockedDocumentRequest_(
             xApprove->select();
         else if ( nResult == RET_NO )
             xDisapprove->select();
+        else if ( nResult == RET_IGNORE && xRetry.is() )
+            xRetry->select();
         else
             xAbort->select();
     }
diff --git a/uui/source/iahndl.cxx b/uui/source/iahndl.cxx
index 3d9d331476e6..f03372de3f54 100644
--- a/uui/source/iahndl.cxx
+++ b/uui/source/iahndl.cxx
@@ -238,10 +238,11 @@ UUIInteractionHelper::replaceMessageWithArguments(
     OUString aMessage = _aMessage;
 
     SAL_WARN_IF(rArguments.size() == 0, "uui", "replaceMessageWithArguments: No arguments passed!");
-    if (rArguments.size() > 0)
-        aMessage = aMessage.replaceAll("$(ARG1)", rArguments[0]);
-    if (rArguments.size() > 1)
-        aMessage = aMessage.replaceAll("$(ARG2)", rArguments[1]);
+    for (size_t i = 0; i < rArguments.size(); ++i)
+    {
+        const OUString sReplaceTemplate = "$(ARG" + OUString::number(i+1) + ")";
+        aMessage = aMessage.replaceAll(sReplaceTemplate, rArguments[i]);
+    }
 
     return aMessage;
 }
diff --git a/uui/source/openlocked.cxx b/uui/source/openlocked.cxx
index 074242b964b8..3267610b78d1 100644
--- a/uui/source/openlocked.cxx
+++ b/uui/source/openlocked.cxx
@@ -21,7 +21,7 @@
 #include "openlocked.hxx"
 #include <unotools/resmgr.hxx>
 
-OpenLockedQueryBox::OpenLockedQueryBox( vcl::Window* pParent, const std::locale& rResLocale, const OUString& aMessage ) :
+OpenLockedQueryBox::OpenLockedQueryBox( vcl::Window* pParent, const std::locale& rResLocale, const OUString& aMessage, bool bEnableOverride ) :
     MessBox(pParent, MessBoxStyle::NONE, 0,
             Translate::get(STR_OPENLOCKED_TITLE, rResLocale),
             aMessage )
@@ -30,13 +30,19 @@ OpenLockedQueryBox::OpenLockedQueryBox( vcl::Window* pParent, const std::locale&
 
     AddButton(Translate::get(STR_OPENLOCKED_OPENREADONLY_BTN, rResLocale), RET_YES,
             ButtonDialogFlags::Default | ButtonDialogFlags::OK | ButtonDialogFlags::Focus);
+    SetButtonHelpText(RET_YES, OUString());
 
     AddButton(Translate::get(STR_OPENLOCKED_OPENCOPY_BTN, rResLocale), RET_NO);
+    SetButtonHelpText(RET_NO, OUString());
 
-    AddButton( StandardButtonType::Cancel, RET_CANCEL, ButtonDialogFlags::Cancel );
-    SetButtonHelpText( RET_YES, OUString() );
-    SetButtonHelpText( RET_NO, OUString() );
+    if (bEnableOverride)
+    {
+        // Present option to ignore the (stale?) lock file and open the document
+        AddButton(Translate::get(STR_ALREADYOPEN_OPEN_BTN, rResLocale), RET_IGNORE);
+        SetButtonHelpText(RET_IGNORE, OUString());
+    }
 
+    AddButton( StandardButtonType::Cancel, RET_CANCEL, ButtonDialogFlags::Cancel );
 }
 
 OpenLockedQueryBox::~OpenLockedQueryBox()
diff --git a/uui/source/openlocked.hxx b/uui/source/openlocked.hxx
index 8584c45c2c7e..bb80a3c64146 100644
--- a/uui/source/openlocked.hxx
+++ b/uui/source/openlocked.hxx
@@ -24,7 +24,7 @@
 class OpenLockedQueryBox : public MessBox
 {
 public:
-    OpenLockedQueryBox(vcl::Window* pParent, const std::locale& rResLocale, const OUString& rMessage);
+    OpenLockedQueryBox(vcl::Window* pParent, const std::locale& rResLocale, const OUString& rMessage, bool bEnableOverride);
     virtual ~OpenLockedQueryBox() override;
 };
 


More information about the Libreoffice-commits mailing list