summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2016-08-10 17:42:54 +0200
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-08-10 20:30:20 +0200
commite9bcd3475131b24b0b8818cfdfa256854ca5a59d (patch)
treeb7381ac319805bfa68a6394ea734fe27333077ad
parent4d993ae8f267e35f7c030861a92226c940bb46cc (diff)
sw undo: add a Repair argument to the .uno:Undo/Redo commands
Undo/redo is limited to undo actions created by the same view in the LOK case, this argument removes this limit. This can be used by a client for "document repair" purposes, where undo/redo of others' changes is intentional. The sfx command dispatch has support for FASTCALL slots (a state function is not called, the command is always enabled) and also has support for state functions, but those functions only get the ID of the slots, not its parameters. What is needed here is a command that's disabled by default, but in case a Repair argument is used, then it's unconditionally enabled. So handle that case in the sfx dispatcher directly for now. Change-Id: I96c1130bf51abcdd722684b1fa4a8277f92fd555
-rw-r--r--libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx5
-rw-r--r--sfx2/sdi/sfx.sdi4
-rw-r--r--sfx2/source/control/dispatch.cxx18
-rw-r--r--sw/inc/IDocumentUndoRedo.hxx5
-rw-r--r--sw/qa/extras/tiledrendering/tiledrendering.cxx41
-rw-r--r--sw/source/core/inc/UndoManager.hxx4
-rw-r--r--sw/source/core/undo/docundo.cxx15
-rw-r--r--sw/source/uibase/shells/basesh.cxx17
8 files changed, 103 insertions, 6 deletions
diff --git a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
index 6c8e2d54dd50..a53bd00c5d7c 100644
--- a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
+++ b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
@@ -535,6 +535,11 @@ static void documentRepair(GtkWidget* pButton, gpointer /*pItem*/)
boost::property_tree::ptree aTree;
aTree.put(boost::property_tree::ptree::path_type(aKey + "/type", '/'), "unsigned short");
aTree.put(boost::property_tree::ptree::path_type(aKey + "/value", '/'), nIndex + 1);
+
+ // Without this, we could only undo our own commands.
+ aTree.put(boost::property_tree::ptree::path_type("Repair/type", '/'), "boolean");
+ aTree.put(boost::property_tree::ptree::path_type("Repair/value", '/'), true);
+
std::stringstream aStream;
boost::property_tree::write_json(aStream, aTree);
std::string aArguments = aStream.str();
diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi
index f5e366abcdb1..5275aef5d335 100644
--- a/sfx2/sdi/sfx.sdi
+++ b/sfx2/sdi/sfx.sdi
@@ -3428,7 +3428,7 @@ SfxBoolItem MacroRecordingFloat SID_RECORDING_FLOATWINDOW
SfxVoidItem Redo SID_REDO
-( SfxUInt16Item Redo SID_REDO )
+( SfxUInt16Item Redo SID_REDO, SfxBoolItem Repair SID_REPAIRPACKAGE )
[
AutoUpdate = FALSE,
FastCall = FALSE,
@@ -4555,7 +4555,7 @@ SfxVoidItem BasicIDEShowWindow SID_BASICIDE_SHOWWINDOW
SfxVoidItem Undo SID_UNDO
-( SfxUInt16Item Undo SID_UNDO )
+( SfxUInt16Item Undo SID_UNDO, SfxBoolItem Repair SID_REPAIRPACKAGE )
[
AutoUpdate = FALSE,
FastCall = FALSE,
diff --git a/sfx2/source/control/dispatch.cxx b/sfx2/source/control/dispatch.cxx
index 0d973a911205..c464fba861a0 100644
--- a/sfx2/source/control/dispatch.cxx
+++ b/sfx2/source/control/dispatch.cxx
@@ -313,6 +313,22 @@ bool SfxDispatcher::IsAppDispatcher() const
return !xImp->pFrame;
}
+/// Decides if the request is FASTCALL or not, depending on arguments.
+bool lcl_IsConditionalFastCall(SfxRequest &rReq)
+{
+ sal_uInt16 nId = rReq.GetSlot();
+ bool bRet = false;
+
+ if (nId == SID_UNDO || nId == SID_REDO)
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if (pArgs && pArgs->HasItem(SID_REPAIRPACKAGE))
+ bRet = true;
+ }
+
+ return bRet;
+}
+
/** Helper function to check whether a slot can be executed and
check the execution itself
*/
@@ -321,7 +337,7 @@ void SfxDispatcher::Call_Impl(SfxShell& rShell, const SfxSlot &rSlot, SfxRequest
SFX_STACK(SfxDispatcher::Call_Impl);
// The slot may be called (meaning enabled)
- if ( rSlot.IsMode(SfxSlotMode::FASTCALL) || rShell.CanExecuteSlot_Impl(rSlot) )
+ if ( rSlot.IsMode(SfxSlotMode::FASTCALL) || rShell.CanExecuteSlot_Impl(rSlot) || lcl_IsConditionalFastCall(rReq))
{
if ( GetFrame() )
{
diff --git a/sw/inc/IDocumentUndoRedo.hxx b/sw/inc/IDocumentUndoRedo.hxx
index 6c044f618a5b..2266f3018afc 100644
--- a/sw/inc/IDocumentUndoRedo.hxx
+++ b/sw/inc/IDocumentUndoRedo.hxx
@@ -64,6 +64,11 @@ public:
*/
virtual bool DoesDrawUndo() const = 0;
+ /// Enable repair mode.
+ virtual void DoRepair(bool bRepair) = 0;
+ /// Is repair mode active?
+ virtual bool DoesRepair() const = 0;
+
/** Set the position at which the document is in the "unmodified" state
to the current position in the Undo stack.
*/
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 1219d0143e27..504de6c5321f 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -62,6 +62,7 @@ public:
void testUndoInvalidations();
void testUndoLimiting();
void testUndoDispatch();
+ void testUndoRepairDispatch();
void testShapeTextUndoShells();
void testShapeTextUndoGroupShells();
@@ -91,6 +92,7 @@ public:
CPPUNIT_TEST(testUndoInvalidations);
CPPUNIT_TEST(testUndoLimiting);
CPPUNIT_TEST(testUndoDispatch);
+ CPPUNIT_TEST(testUndoRepairDispatch);
CPPUNIT_TEST(testShapeTextUndoShells);
CPPUNIT_TEST(testShapeTextUndoGroupShells);
CPPUNIT_TEST_SUITE_END();
@@ -960,6 +962,45 @@ void SwTiledRenderingTest::testUndoDispatch()
comphelper::LibreOfficeKit::setActive(false);
}
+void SwTiledRenderingTest::testUndoRepairDispatch()
+{
+ // Load a document and create two views.
+ comphelper::LibreOfficeKit::setActive();
+ SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
+ int nView1 = SfxLokHelper::getView();
+ SfxLokHelper::createView();
+ pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+ int nView2 = SfxLokHelper::getView();
+
+ // Insert a character in the first view.
+ SfxLokHelper::setView(nView1);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'c', 0);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'c', 0);
+
+ // Assert that by default the second view can't undo the action.
+ SfxLokHelper::setView(nView2);
+ SwDoc* pDoc = pXTextDocument->GetDocShell()->GetDoc();
+ sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rUndoManager.GetUndoActionCount());
+ comphelper::dispatchCommand(".uno:Undo", {});
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rUndoManager.GetUndoActionCount());
+
+ // But the same is allowed in repair mode.
+ SfxLokHelper::setView(nView2);
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rUndoManager.GetUndoActionCount());
+ uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
+ {
+ {"Repair", uno::makeAny(true)}
+ }));
+ comphelper::dispatchCommand(".uno:Undo", aPropertyValues);
+ Scheduler::ProcessEventsToIdle();
+ // This was 1: repair mode couldn't undo the action, either.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), rUndoManager.GetUndoActionCount());
+
+ comphelper::LibreOfficeKit::setActive(false);
+}
+
void SwTiledRenderingTest::testShapeTextUndoShells()
{
// Load a document and create a view.
diff --git a/sw/source/core/inc/UndoManager.hxx b/sw/source/core/inc/UndoManager.hxx
index 5092e95a34ab..00132625bdcd 100644
--- a/sw/source/core/inc/UndoManager.hxx
+++ b/sw/source/core/inc/UndoManager.hxx
@@ -49,6 +49,8 @@ public:
virtual bool DoesGroupUndo() const override;
virtual void DoDrawUndo(bool const bDoUndo) override;
virtual bool DoesDrawUndo() const override;
+ void DoRepair(bool bRepair) override;
+ bool DoesRepair() const override;
virtual void SetUndoNoModifiedPosition() override;
virtual void LockUndoNoModifiedPosition() override;
virtual void UnLockUndoNoModifiedPosition() override;
@@ -100,6 +102,8 @@ private:
bool m_bGroupUndo : 1; // TRUE: Undo grouping enabled
bool m_bDrawUndo : 1; // TRUE: Draw Undo enabled
+ /// If true, then repair mode is enabled.
+ bool m_bRepair;
bool m_bLockUndoNoModifiedPosition : 1;
/// position in Undo-Array at which Doc was saved (and is not modified)
UndoStackMark m_UndoSaveMark;
diff --git a/sw/source/core/undo/docundo.cxx b/sw/source/core/undo/docundo.cxx
index ba4aeff8d575..127d92827b1e 100644
--- a/sw/source/core/undo/docundo.cxx
+++ b/sw/source/core/undo/docundo.cxx
@@ -58,6 +58,7 @@ UndoManager::UndoManager(std::shared_ptr<SwNodes> xUndoNodes,
, m_xUndoNodes(xUndoNodes)
, m_bGroupUndo(true)
, m_bDrawUndo(true)
+ , m_bRepair(false)
, m_bLockUndoNoModifiedPosition(false)
, m_UndoSaveMark(MARK_INVALID)
{
@@ -138,6 +139,16 @@ bool UndoManager::DoesDrawUndo() const
return m_bDrawUndo;
}
+void UndoManager::DoRepair(bool bRepair)
+{
+ m_bRepair = bRepair;
+}
+
+bool UndoManager::DoesRepair() const
+{
+ return m_bRepair;
+}
+
bool UndoManager::IsUndoNoResetModified() const
{
return MARK_INVALID == m_UndoSaveMark;
@@ -308,7 +319,7 @@ UndoManager::GetLastUndoInfo(
SfxUndoAction *const pAction( SdrUndoManager::GetUndoAction() );
- if (comphelper::LibreOfficeKit::isActive())
+ if (comphelper::LibreOfficeKit::isActive() && !m_bRepair)
{
// If an other view created the undo action, prevent undoing it from this view.
sal_Int32 nViewShellId = pView ? pView->GetViewShellId() : m_pDocShell->GetView()->GetViewShellId();
@@ -361,7 +372,7 @@ bool UndoManager::GetFirstRedoInfo(OUString *const o_pStr,
return false;
}
- if (comphelper::LibreOfficeKit::isActive())
+ if (comphelper::LibreOfficeKit::isActive() && !m_bRepair)
{
// If an other view created the undo action, prevent redoing it from this view.
sal_Int32 nViewShellId = pView ? pView->GetViewShellId() : m_pDocShell->GetView()->GetViewShellId();
diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx
index 6f802bed355f..7c281a5a4721 100644
--- a/sw/source/uibase/shells/basesh.cxx
+++ b/sw/source/uibase/shells/basesh.cxx
@@ -94,6 +94,7 @@
#include <fmtinfmt.hxx>
#include <doc.hxx>
#include <IDocumentSettingAccess.hxx>
+#include <IDocumentUndoRedo.hxx>
#include "swabstdlg.hxx"
#include "dialog.hrc"
#include "fldui.hrc"
@@ -108,8 +109,8 @@
#include <com/sun/star/gallery/GalleryItemType.hpp>
#include <memory>
-//UUUU
#include <svx/unobrushitemhelper.hxx>
+#include <comphelper/scopeguard.hxx>
FlyMode SwBaseShell::eFrameMode = FLY_DRAG_END;
@@ -483,9 +484,23 @@ void SwBaseShell::ExecUndo(SfxRequest &rReq)
if( pArgs && SfxItemState::SET == pArgs->GetItemState( nId, false, &pItem ))
nCnt = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
+ // Repair mode: allow undo/redo of all undo actions, even if access would
+ // be limited based on the view shell ID.
+ bool bRepair = false;
+ if (pArgs && pArgs->GetItemState(SID_REPAIRPACKAGE, false, &pItem) == SfxItemState::SET)
+ bRepair = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
// #i106349#: save pointer: undo/redo may delete the shell, i.e., this!
SfxViewFrame *const pViewFrame( GetView().GetViewFrame() );
+ IDocumentUndoRedo& rUndoRedo = rWrtShell.GetIDocumentUndoRedo();
+ bool bWasRepair = rUndoRedo.DoesRepair();
+ rUndoRedo.DoRepair(bRepair);
+ comphelper::ScopeGuard aGuard([&rUndoRedo, bWasRepair]()
+ {
+ rUndoRedo.DoRepair(bWasRepair);
+ });
+
switch( nId )
{
case SID_UNDO: