summaryrefslogtreecommitdiff
path: root/sfx2
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2018-02-08 18:06:06 +0300
committerAndras Timar <andras.timar@collabora.com>2018-03-25 18:28:35 +0200
commit32e187572335e6490b356d2535c0c6792094a023 (patch)
tree05e59e4f1aa115c447bc5f807c6f7264e829e45d /sfx2
parent318f4e7d06681a664e7cb52589f130fa5628a350 (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> (cherry picked from commit 2a7057250c8f73fdfb4c65a7525d17e9770459df)
Diffstat (limited to 'sfx2')
-rw-r--r--sfx2/source/doc/docfile.cxx71
-rw-r--r--sfx2/source/view/viewfrm.cxx134
2 files changed, 149 insertions, 56 deletions
diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx
index 757336c6ac1c..2d06bdf86ef6 100644
--- a/sfx2/source/doc/docfile.cxx
+++ b/sfx2/source/doc/docfile.cxx
@@ -844,6 +844,8 @@ SfxMedium::ShowLockResult SfxMedium::ShowLockedDocumentDialog( const LockFileEnt
OUString aInfo;
::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl;
+ sal_Int32 nContinuations = 3;
+
if ( bOwnLock )
{
aInfo = aData[LockFileComponent::EDITTIME];
@@ -867,12 +869,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() );
@@ -888,14 +901,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
@@ -990,12 +1008,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 !
@@ -1067,7 +1089,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& )
@@ -1106,23 +1128,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();
}
@@ -1174,7 +1201,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;
}
}
@@ -1200,15 +1227,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)
@@ -1268,14 +1286,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;
}
}
}
@@ -1309,11 +1333,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 8f4d56792435..07a1c3b5fad4 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 )
{
@@ -262,6 +288,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);
@@ -311,7 +354,7 @@ void SfxViewFrame::ExecReload_Impl( SfxRequest& rReq )
}
}
nOpenMode = SFX_STREAM_READONLY;
- pSh->SetReadOnlyUI();
+ aReadOnlyUIGuard.m_bSetRO = true;
}
else
{
@@ -331,10 +374,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() )
@@ -343,12 +384,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() )
@@ -395,31 +432,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 )
{
@@ -439,10 +503,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() );
@@ -465,10 +526,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 ) );