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
This commit is contained in:
Miklos Vajna
2016-08-10 17:42:54 +02:00
parent 4d993ae8f2
commit e9bcd34751
8 changed files with 103 additions and 6 deletions

View File

@@ -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();

View File

@@ -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,

View File

@@ -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() )
{

View File

@@ -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.
*/

View File

@@ -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.

View File

@@ -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;

View File

@@ -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();

View File

@@ -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: