summaryrefslogtreecommitdiff
path: root/sfx2
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2018-02-08 18:06:06 +0300
committerAron Budea <aron.budea@collabora.com>2018-02-09 20:30:04 +0100
commit04901aeeb521aa576a741a89f080f6ac76acf071 (patch)
tree57174b02ef285a92404b566463ef004bf79dfb81 /sfx2
parent95994da7e162a972b25c69023c42756735cc9d8d (diff)
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@libreoffice.org> Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/49470 Reviewed-by: Aron Budea <aron.budea@collabora.com> Tested-by: Aron Budea <aron.budea@collabora.com> (cherry picked from commit e189dd061bb0817e1f9e872c9b8dc82b72bfffc5)
Diffstat (limited to 'sfx2')
-rw-r--r--sfx2/source/doc/docfile.cxx71
-rw-r--r--sfx2/source/view/view.hrc7
-rw-r--r--sfx2/source/view/view.src12
-rw-r--r--sfx2/source/view/viewfrm.cxx133
4 files changed, 165 insertions, 58 deletions
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index b1ce8b84655b..a7b8af14c13a 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -864,6 +864,8 @@ SfxMedium::ShowLockResult SfxMedium::ShowLockedDocumentDialog( const LockFileEnt
OUString aInfo;
::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl;
+ sal_Int32 nContinuations = 3;
+
if ( bOwnLock )
{
aInfo = aData[LockFileComponent::EDITTIME];
@@ -887,12 +889,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() );
@@ -908,14 +921,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
@@ -1010,12 +1028,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 !
@@ -1086,7 +1108,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& )
@@ -1125,23 +1147,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();
}
@@ -1209,7 +1236,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;
}
}
@@ -1235,15 +1262,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)
@@ -1303,14 +1321,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;
}
}
}
@@ -1344,11 +1368,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/view.hrc b/sfx2/source/view/view.hrc
index 548c43592561..af4c02fe59f1 100644
--- a/sfx2/source/view/view.hrc
+++ b/sfx2/source/view/view.hrc
@@ -35,8 +35,11 @@
#define STR_ERROR_SAVE_TEMPLATE (RID_SFX_VIEW_START+33)
-#define STR_QUERY_OPENASTEMPLATE (RID_SFX_VIEW_START+41)
-#define STR_CANT_CLOSE (RID_SFX_VIEW_START+42)
+#define STR_QUERY_OPENASTEMPLATE (RID_SFX_VIEW_START+41)
+#define STR_QUERY_OPENASTEMPLATE_ALLOW_IGNORE (RID_SFX_VIEW_START+42)
+#define STR_QUERY_OPENASTEMPLATE_OPENCOPY_BTN (RID_SFX_VIEW_START+43)
+#define STR_QUERY_OPENASTEMPLATE_OPEN_BTN (RID_SFX_VIEW_START+44)
+#define STR_CANT_CLOSE (RID_SFX_VIEW_START+45)
#endif
diff --git a/sfx2/source/view/view.src b/sfx2/source/view/view.src
index 0826609e5339..47caed97e475 100644
--- a/sfx2/source/view/view.src
+++ b/sfx2/source/view/view.src
@@ -77,6 +77,18 @@ String STR_QUERY_OPENASTEMPLATE
{
Text [ en-US ] = "This document cannot be edited, possibly due to missing access rights. Do you want to edit a copy of the document?" ;
};
+String STR_QUERY_OPENASTEMPLATE_ALLOW_IGNORE
+{
+ Text [ en-US ] = "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." ;
+};
+String STR_QUERY_OPENASTEMPLATE_OPENCOPY_BTN
+{
+ Text [ en-US ] = "Open ~Copy" ;
+};
+String STR_QUERY_OPENASTEMPLATE_OPEN_BTN
+{
+ Text [ en-US ] = "~Open" ;
+};
String STR_REPAIREDDOCUMENT
{
Text [ en-US ] = " (repaired document)" ;
diff --git a/sfx2/source/view/viewfrm.cxx b/sfx2/source/view/viewfrm.cxx
index 840ba418e3e7..8d0fb19f3faf 100644
--- a/sfx2/source/view/viewfrm.cxx
+++ b/sfx2/source/view/viewfrm.cxx
@@ -137,6 +137,7 @@ using ::com::sun::star::container::XIndexContainer;
#include <sfx2/minfitem.hxx>
#include "../appl/app.hrc"
#include "impviewframe.hxx"
+#include <vcl/msgbox.hxx>
#define SfxViewFrame
#include "sfxslots.hxx"
@@ -154,6 +155,7 @@ void SfxViewFrame::InitInterface_Impl()
#endif
}
+namespace {
/// Asks the user if editing a read-only document is really wanted.
class SfxEditDocumentDialog : public MessageDialog
{
@@ -186,8 +188,31 @@ void SfxEditDocumentDialog::dispose()
MessageDialog::dispose();
}
+class SfxQueryOpenAsTemplate : public QueryBox
+{
+public:
+ SfxQueryOpenAsTemplate(vcl::Window* pParent, WinBits nStyle, bool bAllowIgnoreLock);
+};
+
+SfxQueryOpenAsTemplate::SfxQueryOpenAsTemplate(vcl::Window* pParent, WinBits 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(SfxObjectShellRef xObjSh)
+bool IsSignPDF(SfxObjectShellRef xObjSh)
{
if (!xObjSh.Is())
return false;
@@ -203,7 +228,7 @@ static bool IsSignPDF(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() );
@@ -251,6 +276,7 @@ static bool AskPasswordToModify_Impl( const uno::Reference< task::XInteractionHa
return bResult;
}
+}
void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
{
@@ -283,6 +309,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);
@@ -332,7 +375,7 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
}
}
nOpenMode = SFX_STREAM_READONLY;
- pSh->SetReadOnlyUI();
+ aReadOnlyUIGuard.m_bSetRO = true;
}
else
{
@@ -352,10 +395,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() )
@@ -364,12 +405,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() )
@@ -416,31 +453,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 )
+ {
+ 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 ) ) );
- pMed->CompleteReOpen();
- if ( nOpenMode & StreamMode::WRITE )
- pMed->LockOrigFileOnDemand( false, true );
+ 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(), 0, 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 )
{
@@ -460,10 +524,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, VCL_BUTTONS_YES_NO);
- if ( RET_YES == aBox->Execute() )
+ if ( bOpenTemplate )
{
SfxApplication* pApp = SfxGetpApp();
SfxAllItemSet aSet( pApp->GetPool() );
@@ -486,10 +547,12 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
GetDispatcher()->Execute( SID_OPENDOC, SfxCallMode::ASYNCHRON, aSet );
return;
}
- else
- nErr = 0;
+ nErr = 0;
}
+ // Keep the read-only UI
+ aReadOnlyUIGuard.m_bSetRO = true;
+
ErrorHandler::HandleError( nErr );
rReq.SetReturnValue(
SfxBoolItem( rReq.GetSlot(), false ) );