Pressing Delete or typing a value into the master cell of a multi-cell matrix used to refuse this with a pop-up error message. Now both gestures replace the whole matrix: Delete clears it, typing puts the new value at the master and the reference cells are removed. The matrix is torn down before the write so no reference cells are left orphaned. DeleteContentOperation expands a single-cell mark on a master to the full matrix range before its editable check, so the protection check no longer sees a fragment. Single cell writes go through a new demolish-matrix-master helper before writing, wrapped in a list action so undo rolls the whole gesture back together. Change-Id: Ie61f30f32a028ed358e6cd208e1580665a81b615 Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/3007 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Miklos Vajna <vmiklos@collabora.com> (cherry picked from commit 839e3e00f4262b7fad163c14f164524307657dd2) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/205918 Tested-by: Xisco Fauli <xiscofauli@libreoffice.org> Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
125 lines
4.1 KiB
C++
125 lines
4.1 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include <operation/SetNormalStringOperation.hxx>
|
|
|
|
#include <docfuncutil.hxx>
|
|
#include <docfunc.hxx>
|
|
#include <address.hxx>
|
|
#include <editable.hxx>
|
|
#include <undocell.hxx>
|
|
#include <validat.hxx>
|
|
#include <detfunc.hxx>
|
|
|
|
#include <memory>
|
|
|
|
namespace sc
|
|
{
|
|
SetNormalStringOperation::SetNormalStringOperation(ScDocFunc& rDocFunc, ScDocShell& rDocShell,
|
|
const ScAddress& rPosition,
|
|
const OUString& rText, bool bApi)
|
|
: Operation(OperationType::SetNormalString, true, bApi)
|
|
, mrDocFunc(rDocFunc)
|
|
, mrDocShell(rDocShell)
|
|
, mrPosition(rPosition)
|
|
, mrText(rText)
|
|
{
|
|
}
|
|
|
|
bool SetNormalStringOperation::runImplementation()
|
|
{
|
|
ScDocShellModificator aModificator(mrDocShell);
|
|
ScDocument& rDoc = mrDocShell.GetDocument();
|
|
|
|
bool bUndo(rDoc.IsUndoEnabled());
|
|
|
|
ScAddress aPosition = convertAddress(mrPosition);
|
|
|
|
ScEditableTester aTester = ScEditableTester::CreateAndTestBlock(
|
|
rDoc, aPosition.Tab(), aPosition.Col(), aPosition.Row(), aPosition.Col(), aPosition.Row());
|
|
if (!aTester.IsEditableOrMatrixCell(rDoc, aPosition))
|
|
{
|
|
if (!mbApi)
|
|
mrDocShell.ErrorMessage(aTester.GetMessageId());
|
|
return false;
|
|
}
|
|
|
|
// If the target is a multi-cell matrix master, tear the whole matrix
|
|
// down before the write so the new value doesn't leave reference cells
|
|
// orphaned.
|
|
DocFuncUtil::demolishMatrixMaster(mrDocFunc, rDoc, aPosition, mbApi);
|
|
|
|
bool bEditDeleted = (rDoc.GetCellType(aPosition) == CELLTYPE_EDIT);
|
|
ScUndoEnterData::ValuesType aOldValues;
|
|
|
|
if (bUndo)
|
|
{
|
|
ScUndoEnterData::Value aOldValue;
|
|
|
|
aOldValue.mnTab = aPosition.Tab();
|
|
aOldValue.maCell.assign(rDoc, aPosition);
|
|
|
|
const ScPatternAttr* pPattern
|
|
= rDoc.GetPattern(aPosition.Col(), aPosition.Row(), aPosition.Tab());
|
|
if (const SfxUInt32Item* pItem
|
|
= pPattern->GetItemSet().GetItemIfSet(ATTR_VALUE_FORMAT, false))
|
|
{
|
|
aOldValue.mbHasFormat = true;
|
|
aOldValue.mnFormat = pItem->GetValue();
|
|
}
|
|
else
|
|
aOldValue.mbHasFormat = false;
|
|
|
|
aOldValues.push_back(aOldValue);
|
|
}
|
|
|
|
tools::Long nBefore(mrDocShell.GetTwipWidthHint(aPosition));
|
|
mbIsNumberFormatSet = rDoc.SetString(aPosition.Col(), aPosition.Row(), aPosition.Tab(), mrText);
|
|
tools::Long nAfter(mrDocShell.GetTwipWidthHint(aPosition));
|
|
|
|
ScUndoEnterData* pUndoEnterData = nullptr;
|
|
if (bUndo)
|
|
{
|
|
// because of ChangeTracking, UndoAction can be created only after SetString was called
|
|
auto pUndoAction
|
|
= std::make_unique<ScUndoEnterData>(mrDocShell, aPosition, aOldValues, mrText, nullptr);
|
|
pUndoEnterData = pUndoAction.get();
|
|
mrDocShell.GetUndoManager()->AddUndoAction(std::move(pUndoAction));
|
|
}
|
|
|
|
if (bEditDeleted || rDoc.HasAttrib(ScRange(aPosition), HasAttrFlags::NeedHeight))
|
|
mrDocFunc.AdjustRowHeight(ScRange(aPosition), true, mbApi);
|
|
|
|
syncCellToSheetViews(aPosition, pUndoEnterData);
|
|
|
|
mrDocShell.PostPaintCell(aPosition, std::max(nBefore, nAfter));
|
|
aModificator.SetDocumentModified();
|
|
|
|
// notify input handler here the same way as in PutCell
|
|
if (mbApi)
|
|
mrDocFunc.NotifyInputHandler(aPosition);
|
|
|
|
const SfxUInt32Item& rItem = rDoc.GetAttr(aPosition, ATTR_VALIDDATA);
|
|
const ScValidationData* pData = rDoc.GetValidationEntry(rItem.GetValue());
|
|
if (pData)
|
|
{
|
|
ScRefCellValue aCell(rDoc, aPosition);
|
|
if (pData->IsDataValid(aCell, aPosition))
|
|
ScDetectiveFunc(rDoc, aPosition.Tab())
|
|
.DeleteCirclesAt(aPosition.Col(), aPosition.Row());
|
|
}
|
|
|
|
mrDocShell.ResolveSpilledOutputs();
|
|
|
|
return true;
|
|
}
|
|
} // end sc namespace
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|