1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <address.hxx>
21 #include <config_features.h>
23 #include <scitems.hxx>
25 #include <sfx2/app.hxx>
26 #include <svx/algitem.hxx>
27 #include <editeng/boxitem.hxx>
28 #include <editeng/editobj.hxx>
29 #include <editeng/langitem.hxx>
30 #include <editeng/justifyitem.hxx>
31 #include <o3tl/unit_conversion.hxx>
32 #include <sfx2/bindings.hxx>
33 #include <svl/numformat.hxx>
34 #include <svl/zforlist.hxx>
35 #include <svl/zformat.hxx>
36 #include <vcl/weld.hxx>
37 #include <vcl/virdev.hxx>
39 #include <unotools/charclass.hxx>
40 #include <vcl/uitest/logger.hxx>
41 #include <vcl/uitest/eventdescription.hxx>
42 #include <osl/diagnose.h>
44 #include <viewfunc.hxx>
45 #include <tabvwsh.hxx>
48 #include <patattr.hxx>
50 #include <undocell.hxx>
51 #include <undoblk.hxx>
52 #include <refundo.hxx>
53 #include <olinetab.hxx>
54 #include <rangenam.hxx>
55 #include <globstr.hrc>
57 #include <stlsheet.hxx>
58 #include <editutil.hxx>
59 #include <formulacell.hxx>
60 #include <scresid.hxx>
61 #include <inputhdl.hxx>
63 #include <inputopt.hxx>
64 #include <compiler.hxx>
65 #include <docfunc.hxx>
66 #include <appoptio.hxx>
67 #include <sizedev.hxx>
68 #include <editable.hxx>
69 #include <scui_def.hxx>
70 #include <funcdesc.hxx>
72 #include <cellsuno.hxx>
73 #include <tokenarray.hxx>
74 #include <rowheightcontext.hxx>
75 #include <comphelper/lok.hxx>
76 #include <conditio.hxx>
77 #include <columnspanset.hxx>
78 #include <stringutil.hxx>
79 #include <SparklineList.hxx>
83 static void ShowFilteredRows(ScDocument
& rDoc
, SCTAB nTab
, SCCOLROW nStartNo
, SCCOLROW nEndNo
,
86 SCROW nFirstRow
= nStartNo
;
87 SCROW nLastRow
= nStartNo
;
90 if (!rDoc
.RowFiltered(nFirstRow
, nTab
, nullptr, &nLastRow
))
91 rDoc
.ShowRows(nFirstRow
, nLastRow
< nEndNo
? nLastRow
: nEndNo
, nTab
, bShow
);
92 nFirstRow
= nLastRow
+ 1;
93 } while (nFirstRow
<= nEndNo
);
96 static void lcl_PostRepaintCondFormat( const ScConditionalFormat
*pCondFmt
, ScDocShell
*pDocSh
)
100 const ScRangeList
& rRanges
= pCondFmt
->GetRange();
102 pDocSh
->PostPaint( rRanges
, PaintPartFlags::All
);
106 static void lcl_PostRepaintSparkLine(sc::SparklineList
* pSparklineList
, const ScRange
& rRange
,
111 for (auto& rSparkLineGroup
: pSparklineList
->getSparklineGroups())
113 for (auto& rSparkline
: pSparklineList
->getSparklinesFor(rSparkLineGroup
))
115 if (rSparkline
->getInputRange().Contains(rRange
))
118 ScRange(rSparkline
->getColumn(), rSparkline
->getRow(), rRange
.aStart
.Tab()),
119 PaintPartFlags::All
, SC_PF_TESTMERGE
);
126 ScViewFunc::ScViewFunc( vcl::Window
* pParent
, ScDocShell
& rDocSh
, ScTabViewShell
* pViewShell
) :
127 ScTabView( pParent
, rDocSh
, pViewShell
),
128 bFormatValid( false )
132 ScViewFunc::~ScViewFunc()
138 struct FormulaProcessingContext
140 std::shared_ptr
<ScAddress
> aPos
;
141 std::shared_ptr
<ScCompiler
> aComp
;
142 std::shared_ptr
<ScDocShellModificator
> aModificator
;
143 std::shared_ptr
<ScTokenArray
> pArr
;
144 std::shared_ptr
<ScTokenArray
> pArrFirst
;
146 std::shared_ptr
<EditTextObject
> xTextObject
;
148 ScViewFunc
& rViewFunc
;
150 OUString aCorrectedFormula
;
162 ScViewData
& GetViewData() const
164 return rViewFunc
.GetViewData();
167 ScDocFunc
& GetDocFunc() const
169 return GetViewData().GetDocFunc();
172 ScDocument
& GetDoc() const
174 return GetViewData().GetDocument();
178 void collectUIInformation(std::map
<OUString
, OUString
>&& aParameters
, const OUString
& rAction
)
180 EventDescription aDescription
;
181 aDescription
.aID
= "grid_window";
182 aDescription
.aAction
= rAction
;
183 aDescription
.aParameters
= std::move(aParameters
);
184 aDescription
.aParent
= "MainWindow";
185 aDescription
.aKeyWord
= "ScGridWinUIObject";
187 UITestLogger::getInstance().logEvent(aDescription
);
192 void ScViewFunc::StartFormatArea()
195 if (!ScModule::get()->GetInputOptions().GetExtendFormat())
198 // start only with single cell (marked or cursor position)
200 bool bOk
= (GetViewData().GetSimpleArea( aMarkRange
) == SC_MARK_SIMPLE
);
201 if ( bOk
&& aMarkRange
.aStart
!= aMarkRange
.aEnd
)
207 aFormatSource
= aMarkRange
.aStart
;
208 aFormatArea
= ScRange( aFormatSource
);
211 bFormatValid
= false; // discard old range
214 bool ScViewFunc::TestFormatArea( SCCOL nCol
, SCROW nRow
, SCTAB nTab
, bool bAttrChanged
)
217 if (!ScModule::get()->GetInputOptions().GetExtendFormat())
220 // Test: treat input with numberformat (bAttrChanged) always as new Attribute
221 // (discard old Area ). If not wanted, discard if-statement
228 //! Test if cell empty ???
231 ScRange aNewRange
= aFormatArea
;
232 if ( bFormatValid
&& nTab
== aFormatSource
.Tab() )
234 if ( nRow
>= aFormatArea
.aStart
.Row() && nRow
<= aFormatArea
.aEnd
.Row() )
237 if ( nCol
>= aFormatArea
.aStart
.Col() && nCol
<= aFormatArea
.aEnd
.Col() )
239 bFound
= true; // do not change range
242 if ( nCol
+1 == aFormatArea
.aStart
.Col() )
245 aNewRange
.aStart
.SetCol( nCol
);
248 if ( nCol
== aFormatArea
.aEnd
.Col()+1 )
251 aNewRange
.aEnd
.SetCol( nCol
);
254 if ( nCol
>= aFormatArea
.aStart
.Col() && nCol
<= aFormatArea
.aEnd
.Col() )
257 if ( nRow
+1 == aFormatArea
.aStart
.Row() )
260 aNewRange
.aStart
.SetRow( nRow
);
263 if ( nRow
== aFormatArea
.aEnd
.Row()+1 )
266 aNewRange
.aEnd
.SetRow( nRow
);
272 aFormatArea
= aNewRange
; // extend
274 bFormatValid
= false; // outside of range -> break
279 void ScViewFunc::DoAutoAttributes( SCCOL nCol
, SCROW nRow
, SCTAB nTab
,
282 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
283 ScDocument
& rDoc
= pDocSh
->GetDocument();
285 const ScPatternAttr
* pSource
= rDoc
.GetPattern(
286 aFormatSource
.Col(), aFormatSource
.Row(), nTab
);
287 if ( !pSource
->GetItem(ATTR_MERGE
).IsMerged() )
289 ScRange
aRange( nCol
, nRow
, nTab
, nCol
, nRow
, nTab
);
290 ScMarkData
aMark(rDoc
.GetSheetLimits());
291 aMark
.SetMarkArea( aRange
);
293 ScDocFunc
&rFunc
= GetViewData().GetDocFunc();
295 // pOldPattern is only valid until call to ApplyAttributes!
296 const ScPatternAttr
* pOldPattern
= rDoc
.GetPattern( nCol
, nRow
, nTab
);
297 const ScStyleSheet
* pSrcStyle
= pSource
->GetStyleSheet();
298 if ( pSrcStyle
&& pSrcStyle
!= pOldPattern
->GetStyleSheet() )
299 rFunc
.ApplyStyle( aMark
, pSrcStyle
->GetName(), false );
301 rFunc
.ApplyAttributes( aMark
, *pSource
, false );
304 if ( bAttrChanged
) // value entered with number format?
305 aFormatSource
.Set( nCol
, nRow
, nTab
); // then set a new source
308 // additional routines
310 void ScViewData::setupSizeDeviceProviderForColWidth(ScSizeDeviceProvider
& rProv
, Fraction
& rZoomX
, Fraction
& rZoomY
, double& rPPTX
, double &rPPTY
)
312 if (rProv
.IsPrinter())
314 rPPTX
= rProv
.GetPPTX();
315 rPPTY
= rProv
.GetPPTY();
316 rZoomX
= rZoomY
= Fraction(1, 1);
327 sal_uInt16
ScViewFunc::GetOptimalColWidth( SCCOL nCol
, SCTAB nTab
, bool bFormula
)
329 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
330 ScDocument
& rDoc
= pDocSh
->GetDocument();
331 ScMarkData
& rMark
= GetViewData().GetMarkData();
333 ScSizeDeviceProvider
aProv(pDocSh
);
335 Fraction aZoomX
, aZoomY
;
337 GetViewData().setupSizeDeviceProviderForColWidth(aProv
, aZoomX
, aZoomY
, nPPTX
, nPPTY
);
339 sal_uInt16 nTwips
= rDoc
.GetOptimalColWidth( nCol
, nTab
, aProv
.GetDevice(),
340 nPPTX
, nPPTY
, aZoomX
, aZoomY
, bFormula
, &rMark
);
344 bool ScViewFunc::SelectionEditable( bool* pOnlyNotBecauseOfMatrix
/* = NULL */ )
347 ScDocument
& rDoc
= GetViewData().GetDocument();
348 ScMarkData
& rMark
= GetViewData().GetMarkData();
349 if (rMark
.IsMarked() || rMark
.IsMultiMarked())
350 bRet
= rDoc
.IsSelectionEditable( rMark
, pOnlyNotBecauseOfMatrix
);
353 SCCOL nCol
= GetViewData().GetCurX();
354 SCROW nRow
= GetViewData().GetCurY();
355 SCTAB nTab
= GetViewData().GetTabNo();
356 bRet
= rDoc
.IsBlockEditable( nTab
, nCol
, nRow
, nCol
, nRow
,
357 pOnlyNotBecauseOfMatrix
);
362 static bool lcl_FunctionKnown( sal_uInt16 nOpCode
)
364 const ScFunctionList
* pFuncList
= ScGlobal::GetStarCalcFunctionList();
367 sal_uLong nCount
= pFuncList
->GetCount();
368 for (sal_uLong i
=0; i
<nCount
; i
++)
369 if ( pFuncList
->GetFunction(i
)->nFIndex
== nOpCode
)
375 static bool lcl_AddFunction( ScAppOptions
& rAppOpt
, sal_uInt16 nOpCode
)
377 sal_uInt16 nOldCount
= rAppOpt
.GetLRUFuncListCount();
378 sal_uInt16
* pOldList
= rAppOpt
.GetLRUFuncList();
380 for (nPos
=0; nPos
<nOldCount
; nPos
++)
381 if (pOldList
[nPos
] == nOpCode
) // is the function already in the list?
384 return false; // already at the top -> no change
386 // count doesn't change, so the original array is modified
388 for (sal_uInt16 nCopy
=nPos
; nCopy
>0; nCopy
--)
389 pOldList
[nCopy
] = pOldList
[nCopy
-1];
390 pOldList
[0] = nOpCode
;
392 return true; // list has changed
395 if ( !lcl_FunctionKnown( nOpCode
) )
396 return false; // not in function list -> no change
398 sal_uInt16 nNewCount
= std::min( static_cast<sal_uInt16
>(nOldCount
+ 1), sal_uInt16(LRU_MAX
) );
399 sal_uInt16 nNewList
[LRU_MAX
];
400 nNewList
[0] = nOpCode
;
401 for (nPos
=1; nPos
<nNewCount
; nPos
++)
402 nNewList
[nPos
] = pOldList
[nPos
-1];
403 rAppOpt
.SetLRUFuncList( nNewList
, nNewCount
);
405 return true; // list has changed
408 namespace HelperNotifyChanges
410 static void NotifyIfChangesListeners(const ScDocShell
&rDocShell
, const ScMarkData
& rMark
,
411 SCCOL nCol
, SCROW nRow
, const OUString
& rType
= u
"cell-change"_ustr
)
413 ScModelObj
* pModelObj
= rDocShell
.GetModel();
415 ScRangeList aChangeRanges
;
416 for (const auto& rTab
: rMark
)
417 aChangeRanges
.push_back( ScRange( nCol
, nRow
, rTab
) );
419 if (getMustPropagateChangesModel(pModelObj
))
420 Notify(*pModelObj
, aChangeRanges
, rType
);
423 Notify(*pModelObj
, aChangeRanges
, isDataAreaInvalidateType(rType
)
424 ? u
"data-area-invalidate"_ustr
: u
"data-area-extend"_ustr
);
431 class AutoCorrectQuery
: public weld::MessageDialogController
434 std::unique_ptr
<weld::TextView
> m_xError
;
436 AutoCorrectQuery(weld::Window
* pParent
, const OUString
& rFormula
)
437 : weld::MessageDialogController(pParent
, u
"modules/scalc/ui/warnautocorrect.ui"_ustr
, u
"WarnAutoCorrect"_ustr
, u
"grid"_ustr
)
438 , m_xError(m_xBuilder
->weld_text_view(u
"error"_ustr
))
440 m_xDialog
->set_default_response(RET_YES
);
442 const int nMaxWidth
= m_xError
->get_approximate_digit_width() * 65;
443 const int nMaxHeight
= m_xError
->get_height_rows(6);
444 m_xError
->set_size_request(nMaxWidth
, nMaxHeight
);
446 m_xError
->set_text(rFormula
);
452 void runAutoCorrectQueryAsync(const std::shared_ptr
<FormulaProcessingContext
>& context
);
454 void performAutoFormatAndUpdate(std::u16string_view rString
, const ScMarkData
& rMark
, SCCOL nCol
,
455 SCROW nRow
, SCTAB nTab
, bool bNumFmtChanged
, bool bRecord
,
456 const std::shared_ptr
<ScDocShellModificator
>& pModificator
,
457 ScViewFunc
& rViewFunc
)
459 bool bAutoFormat
= rViewFunc
.TestFormatArea(nCol
, nRow
, nTab
, bNumFmtChanged
);
462 rViewFunc
.DoAutoAttributes(nCol
, nRow
, nTab
, bNumFmtChanged
);
464 ScViewData
& rViewData
= rViewFunc
.GetViewData();
465 ScDocShell
* pDocSh
= rViewData
.GetDocShell();
466 pDocSh
->UpdateOle(rViewData
);
468 const OUString
aType(rString
.empty() ? u
"delete-content" : u
"cell-change");
469 HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh
, rMark
, nCol
, nRow
, aType
);
473 ScDocFunc
&rFunc
= rViewData
.GetDocFunc();
474 rFunc
.EndListAction();
477 pModificator
->SetDocumentModified();
478 ScDocument
& rDoc
= rViewData
.GetDocument();
479 lcl_PostRepaintCondFormat(rDoc
.GetCondFormat(nCol
, nRow
, nTab
), pDocSh
);
480 lcl_PostRepaintSparkLine(rDoc
.GetSparklineList(nTab
), ScRange(nCol
, nRow
, nTab
), pDocSh
);
483 void finalizeFormulaProcessing(const std::shared_ptr
<FormulaProcessingContext
>& context
)
485 // to be used in multiple tabs, the formula must be compiled anew
486 // via ScFormulaCell copy-ctor because of RangeNames,
487 // the same code-array for all cells is not possible.
488 // If the array has an error, (it) must be RPN-erased in the newly generated
489 // cells and the error be set explicitly, so that
490 // via FormulaCell copy-ctor and Interpreter it will be, when possible,
491 // ironed out again, too intelligent... e.g.: =1))
492 FormulaError nError
= context
->pArr
->GetCodeError();
493 if ( nError
== FormulaError::NONE
)
495 // update list of recent functions with all functions that
496 // are not within parentheses
498 ScModule
* pScMod
= ScModule::get();
499 ScAppOptions aAppOpt
= pScMod
->GetAppOptions();
500 bool bOptChanged
= false;
502 formula::FormulaToken
** ppToken
= context
->pArr
->GetArray();
503 sal_uInt16 nTokens
= context
->pArr
->GetLen();
504 sal_uInt16 nLevel
= 0;
505 for (sal_uInt16 nTP
=0; nTP
<nTokens
; nTP
++)
507 formula::FormulaToken
* pTok
= ppToken
[nTP
];
508 OpCode eOp
= pTok
->GetOpCode();
511 else if ( eOp
== ocClose
&& nLevel
)
513 if ( nLevel
== 0 && pTok
->IsFunction() &&
514 lcl_AddFunction( aAppOpt
, sal::static_int_cast
<sal_uInt16
>( eOp
) ) )
520 pScMod
->SetAppOptions(aAppOpt
);
523 if (context
->bMatrixExpand
)
525 // If the outer function/operator returns an array/matrix then
526 // enter a matrix formula. ScViewFunc::EnterMatrix() takes care
527 // of selection/mark of the result dimensions or preselected
528 // mark. If the user wanted less or a single cell then should
529 // mark such prior to entering the formula.
530 const formula::FormulaToken
* pToken
= context
->pArr
->LastRPNToken();
531 if (pToken
&& (formula::FormulaCompiler::IsMatrixFunction( pToken
->GetOpCode())
532 || pToken
->IsInForceArray()))
534 // Discard this (still empty here) Undo action,
535 // EnterMatrix() will create its own.
536 if (context
->bRecord
)
537 context
->GetDocFunc().EndListAction();
539 // Use corrected formula string.
540 context
->rViewFunc
.EnterMatrix( context
->aFormula
, context
->GetDoc().GetGrammar());
547 ScFormulaCell
aCell(context
->GetDoc(), *context
->aPos
, std::move(*context
->pArr
), formula::FormulaGrammar::GRAM_DEFAULT
, ScMatrixMode::NONE
);
550 SvNumberFormatter
* pFormatter
= context
->GetDoc().GetFormatTable();
551 for (const auto& rTab
: context
->aMark
)
554 context
->aPos
->SetTab( i
);
555 const sal_uInt32 nIndex
= context
->GetDoc().GetAttr(
556 context
->nCol
, context
->nRow
, i
, ATTR_VALUE_FORMAT
)->GetValue();
557 const SvNumFormatType nType
= pFormatter
->GetType( nIndex
);
558 if (nType
== SvNumFormatType::TEXT
||
559 ((context
->aString
[0] == '+' || context
->aString
[0] == '-') && nError
!= FormulaError::NONE
&& context
->aString
== context
->aFormula
))
561 if ( context
->xTextObject
)
563 // A clone of context->xTextObject will be stored in the cell.
564 context
->GetDocFunc().SetEditCell(*(context
->aPos
), *context
->xTextObject
, true);
567 context
->GetDocFunc().SetStringCell(*(context
->aPos
), context
->aFormula
, true);
571 ScFormulaCell
* pCell
= new ScFormulaCell( aCell
, context
->GetDoc(), *(context
->aPos
) );
572 if ( nError
!= FormulaError::NONE
)
574 pCell
->GetCode()->DelRPN();
575 pCell
->SetErrCode( nError
);
576 if(pCell
->GetCode()->IsHyperLink())
577 pCell
->GetCode()->SetHyperLink(false);
579 if (nType
== SvNumFormatType::LOGICAL
)
581 // Reset to General so the actual format can be determined
582 // after the cell has been interpreted. A sticky boolean
583 // number format is highly likely unwanted... see tdf#75650.
584 // General of same locale as current number format.
585 const SvNumberformat
* pEntry
= pFormatter
->GetEntry( nIndex
);
586 const LanguageType nLang
= (pEntry
? pEntry
->GetLanguage() : ScGlobal::eLnge
);
587 const sal_uInt32 nFormat
= pFormatter
->GetStandardFormat( SvNumFormatType::NUMBER
, nLang
);
588 ScPatternAttr
aPattern(context
->GetDoc().getCellAttributeHelper());
589 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_VALUE_FORMAT
, nFormat
));
590 ScMarkData
aMark(context
->GetDoc().GetSheetLimits());
591 aMark
.SelectTable( i
, true);
592 aMark
.SetMarkArea( ScRange( *(context
->aPos
)));
593 context
->GetDocFunc().ApplyAttributes( aMark
, aPattern
, false);
594 context
->bNumFmtChanged
= true;
596 context
->GetDocFunc().SetFormulaCell(*(context
->aPos
), pCell
, true);
600 performAutoFormatAndUpdate(context
->aString
, context
->aMark
, context
->nCol
,
601 context
->nRow
, context
->nTab
, context
->bNumFmtChanged
,
602 context
->bRecord
, context
->aModificator
, context
->rViewFunc
);
605 void parseAndCorrectFormula(std::shared_ptr
<FormulaProcessingContext
> context
)
607 bool bAddEqual
= false;
608 context
->pArr
= context
->aComp
->CompileString(context
->aFormula
);
609 bool bCorrected
= context
->aComp
->IsCorrected();
612 context
->pArrFirst
= context
->pArr
;
613 context
->pArr
= context
->aComp
->CompileString(context
->aComp
->GetCorrectedFormula());
616 if (context
->pArr
->GetCodeError() == FormulaError::NONE
) {
618 context
->aComp
->CompileTokenArray();
619 bCorrected
|= context
->aComp
->IsCorrected();
623 context
->aCorrectedFormula
= bAddEqual
? "=" + context
->aComp
->GetCorrectedFormula()
624 : context
->aComp
->GetCorrectedFormula();
625 if (context
->aCorrectedFormula
.getLength() == 1) {
626 // empty formula, just '='
627 if (context
->pArrFirst
)
628 context
->pArr
= context
->pArrFirst
;
632 runAutoCorrectQueryAsync(context
);
636 finalizeFormulaProcessing(context
);
639 void runAutoCorrectQueryAsync(const std::shared_ptr
<FormulaProcessingContext
>& context
)
641 auto aQueryBox
= std::make_shared
<AutoCorrectQuery
>(context
->GetViewData().GetDialogParent(), context
->aCorrectedFormula
);
642 weld::DialogController::runAsync(aQueryBox
, [context
] (int nResult
)
644 if (nResult
== RET_YES
) {
645 context
->aFormula
= context
->aCorrectedFormula
;
646 parseAndCorrectFormula(context
);
648 if (context
->pArrFirst
)
649 context
->pArr
= context
->pArrFirst
;
651 finalizeFormulaProcessing(context
);
660 void ScViewFunc::EnterData( SCCOL nCol
, SCROW nRow
, SCTAB nTab
,
661 const OUString
& rString
,
662 const EditTextObject
* pData
,
665 ScDocument
& rDoc
= GetViewData().GetDocument();
666 ScMarkData
aMark(GetViewData().GetMarkData());
667 bool bRecord
= rDoc
.IsUndoEnabled();
670 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
671 ScDocFunc
&rFunc
= GetViewData().GetDocFunc();
672 std::shared_ptr
<ScDocShellModificator
> xModificator
= std::make_shared
<ScDocShellModificator
>(*pDocSh
);
674 ScEditableTester
aTester( rDoc
, nCol
,nRow
, nCol
,nRow
, aMark
);
675 if (!aTester
.IsEditable())
677 ErrorMessage(aTester
.GetMessageId());
678 PaintArea(nCol
, nRow
, nCol
, nRow
); // possibly the edit-engine is still painted there
683 rFunc
.EnterListAction( STR_UNDO_ENTERDATA
);
685 bool bFormula
= false;
687 // do not check formula if it is a text cell
688 sal_uInt32 format
= rDoc
.GetNumberFormat( nCol
, nRow
, nTab
);
689 SvNumberFormatter
* pFormatter
= rDoc
.GetFormatTable();
690 // a single '=' character is handled as string (needed for special filters)
691 if ( pFormatter
->GetType(format
) != SvNumFormatType::TEXT
&& rString
.getLength() > 1 )
693 if ( rString
[0] == '=' )
698 else if ( rString
[0] == '+' || rString
[0] == '-' )
700 // if there is more than one leading '+' or '-' character, remove the additional ones
701 sal_Int32 nIndex
= 1;
702 sal_Int32 nLen
= rString
.getLength();
703 while ( nIndex
< nLen
&& ( rString
[ nIndex
] == '+' || rString
[ nIndex
] == '-' ) )
707 OUString aString
= rString
.replaceAt( 1, nIndex
- 1, u
"" );
709 // if the remaining part without the leading '+' or '-' character
710 // is non-empty and not a number, handle as formula
711 if ( aString
.getLength() > 1 )
714 if ( !pFormatter
->IsNumberFormat( aString
, format
, fNumber
) )
722 bool bNumFmtChanged
= false;
724 { // formula, compile with autoCorrection
725 i
= aMark
.GetFirstSelected();
726 auto xPosPtr
= std::make_shared
<ScAddress
>(nCol
, nRow
, i
);
727 auto xCompPtr
= std::make_shared
<ScCompiler
>(rDoc
, *xPosPtr
, rDoc
.GetGrammar(), true, false);
728 std::unique_ptr
<EditTextObject
> xTextObject(pData
? pData
->Clone() : nullptr);
730 //2do: enable/disable autoCorrection via calcoptions
731 xCompPtr
->SetAutoCorrection( true );
732 if ( rString
[0] == '+' || rString
[0] == '-' )
734 xCompPtr
->SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_BREAK
);
737 OUString
aFormula( rString
);
739 FormulaProcessingContext context_instance
{
740 std::move(xPosPtr
), std::move(xCompPtr
), std::move(xModificator
), nullptr,
741 nullptr, std::move(xTextObject
), std::move(aMark
), *this,
742 OUString(), aFormula
, rString
, nCol
,
743 nRow
, nTab
, bMatrixExpand
, bNumFmtChanged
,
747 parseAndCorrectFormula(std::make_shared
<FormulaProcessingContext
>(context_instance
));
751 ScFieldEditEngine
& rEngine
= rDoc
.GetEditEngine();
752 for (const auto& rTab
: aMark
)
754 bool bNumFmtSet
= false;
755 const ScAddress
aScAddress(nCol
, nRow
, rTab
);
757 // tdf#104902 - handle embedded newline
758 if (ScStringUtil::isMultiline(rString
))
760 rEngine
.SetTextCurrentDefaults(rString
);
761 rDoc
.SetEditText(aScAddress
, rEngine
.CreateTextObject());
762 pDocSh
->AdjustRowHeight(nRow
, nRow
, rTab
);
766 rFunc
.SetNormalString(bNumFmtSet
, aScAddress
, rString
, false);
771 /* FIXME: if set on any sheet results in changed only on
772 * sheet nTab for TestFormatArea() and DoAutoAttributes() */
773 bNumFmtChanged
= true;
776 performAutoFormatAndUpdate(rString
, aMark
, nCol
, nRow
, nTab
, bNumFmtChanged
, bRecord
, xModificator
, *this);
780 // enter value in single cell (on nTab only)
782 void ScViewFunc::EnterValue( SCCOL nCol
, SCROW nRow
, SCTAB nTab
, const double& rValue
)
784 ScDocument
& rDoc
= GetViewData().GetDocument();
785 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
790 bool bUndo(rDoc
.IsUndoEnabled());
791 ScDocShellModificator
aModificator( *pDocSh
);
793 ScEditableTester
aTester( rDoc
, nTab
, nCol
,nRow
, nCol
,nRow
);
794 if (aTester
.IsEditable())
796 ScAddress
aPos( nCol
, nRow
, nTab
);
797 ScCellValue aUndoCell
;
799 aUndoCell
.assign(rDoc
, aPos
);
801 rDoc
.SetValue( nCol
, nRow
, nTab
, rValue
);
803 // because of ChangeTrack after change in document
806 pDocSh
->GetUndoManager()->AddUndoAction(
807 std::make_unique
<ScUndoEnterValue
>(pDocSh
, aPos
, aUndoCell
, rValue
));
810 pDocSh
->PostPaintCell( aPos
);
811 pDocSh
->UpdateOle(GetViewData());
812 aModificator
.SetDocumentModified();
815 ErrorMessage(aTester
.GetMessageId());
818 void ScViewFunc::EnterData( SCCOL nCol
, SCROW nRow
, SCTAB nTab
,
819 const EditTextObject
& rData
, bool bTestSimple
)
821 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
822 ScMarkData
& rMark
= GetViewData().GetMarkData();
823 ScDocument
& rDoc
= pDocSh
->GetDocument();
824 bool bRecord
= rDoc
.IsUndoEnabled();
826 ScDocShellModificator
aModificator( *pDocSh
);
828 ScEditableTester
aTester( rDoc
, nTab
, nCol
,nRow
, nCol
,nRow
);
829 if (aTester
.IsEditable())
832 // test for attribute
834 bool bSimple
= false;
835 bool bCommon
= false;
836 std::unique_ptr
<ScPatternAttr
> pCellAttrs
;
839 const ScPatternAttr
* pOldPattern
= rDoc
.GetPattern( nCol
, nRow
, nTab
);
840 ScTabEditEngine
aEngine( *pOldPattern
, rDoc
.GetEnginePool(), &rDoc
);
841 aEngine
.SetTextCurrentDefaults(rData
);
843 if (bTestSimple
) // test, if simple string without attribute
845 ScEditAttrTester
aAttrTester( &aEngine
);
846 bSimple
= !aAttrTester
.NeedsObject();
847 bCommon
= aAttrTester
.NeedsCellAttr();
849 // formulas have to be recognized even if they're formatted
850 // (but common attributes are still collected)
854 OUString
aParStr(aEngine
.GetText( 0 ));
855 if ( aParStr
[0] == '=' )
859 if (bCommon
) // attribute for tab
861 pCellAttrs
.reset(new ScPatternAttr( *pOldPattern
));
862 pCellAttrs
->GetFromEditItemSet( &aAttrTester
.GetAttribs() );
863 //! remove common attributes from EditEngine?
867 // #i97726# always get text for "repeat" of undo action
868 aString
= ScEditUtil::GetMultilineString(aEngine
);
872 std::unique_ptr
<EditTextObject
> pUndoData
;
873 ScUndoEnterData::ValuesType aOldValues
;
875 if (bRecord
&& !bSimple
)
877 for (const auto& rTab
: rMark
)
879 ScUndoEnterData::Value aOldValue
;
880 aOldValue
.mnTab
= rTab
;
881 aOldValue
.maCell
.assign(rDoc
, ScAddress(nCol
, nRow
, rTab
));
882 aOldValues
.push_back(aOldValue
);
885 pUndoData
= rData
.Clone();
891 rDoc
.ApplyPattern(nCol
,nRow
,nTab
,*pCellAttrs
); //! undo
896 AdjustRowHeight(nRow
,nRow
,true);
898 EnterData( nCol
, nRow
, nTab
, aString
, nullptr, true /*bMatrixExpand*/);
902 for (const auto& rTab
: rMark
)
904 ScAddress
aPos(nCol
, nRow
, rTab
);
905 rDoc
.SetEditText(aPos
, rData
, rDoc
.GetEditPool());
909 { // because of ChangeTrack current first
910 pDocSh
->GetUndoManager()->AddUndoAction(
911 std::make_unique
<ScUndoEnterData
>(pDocSh
, ScAddress(nCol
,nRow
,nTab
), aOldValues
, aString
, std::move(pUndoData
)));
916 AdjustRowHeight(nRow
,nRow
,true);
918 for (const auto& rTab
: rMark
)
919 pDocSh
->PostPaintCell( nCol
, nRow
, rTab
);
923 pDocSh
->UpdateOle(GetViewData());
925 bool bIsEmpty
= rData
.GetParagraphCount() == 0
926 || (rData
.GetParagraphCount() == 1 && !rData
.HasText(0));
927 const OUString
aType(bIsEmpty
? u
"delete-content" : u
"cell-change");
928 HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh
, rMark
, nCol
, nRow
, aType
);
930 aModificator
.SetDocumentModified();
932 lcl_PostRepaintCondFormat( rDoc
.GetCondFormat( nCol
, nRow
, nTab
), pDocSh
);
936 ErrorMessage(aTester
.GetMessageId());
937 PaintArea( nCol
, nRow
, nCol
, nRow
); // possibly the edit-engine is still painted there
941 void ScViewFunc::EnterDataAtCursor( const OUString
& rString
)
943 SCCOL nPosX
= GetViewData().GetCurX();
944 SCROW nPosY
= GetViewData().GetCurY();
945 SCTAB nTab
= GetViewData().GetTabNo();
947 EnterData( nPosX
, nPosY
, nTab
, rString
);
948 // tdf#154174: update repeated data in the cell
949 GetViewData().GetViewShell()->UpdateInputHandler();
952 void ScViewFunc::EnterMatrix( const OUString
& rString
, ::formula::FormulaGrammar::Grammar eGram
)
954 ScViewData
& rData
= GetViewData();
955 const SCCOL nCol
= rData
.GetCurX();
956 const SCROW nRow
= rData
.GetCurY();
957 const ScMarkData
& rMark
= rData
.GetMarkData();
958 if ( !rMark
.IsMarked() && !rMark
.IsMultiMarked() )
960 // nothing marked -> temporarily calculate block
961 // with size of result formula to get the size
963 ScDocument
& rDoc
= rData
.GetDocument();
964 SCTAB nTab
= rData
.GetTabNo();
965 ScFormulaCell
aFormCell( rDoc
, ScAddress(nCol
,nRow
,nTab
), rString
, eGram
, ScMatrixMode::Formula
);
969 aFormCell
.GetResultDimensions( nSizeX
, nSizeY
);
970 if ( nSizeX
!= 0 && nSizeY
!= 0 &&
971 nCol
+nSizeX
-1 <= sal::static_int_cast
<SCSIZE
>(rDoc
.MaxCol()) &&
972 nRow
+nSizeY
-1 <= sal::static_int_cast
<SCSIZE
>(rDoc
.MaxRow()) )
974 ScRange
aResult( nCol
, nRow
, nTab
,
975 sal::static_int_cast
<SCCOL
>(nCol
+nSizeX
-1),
976 sal::static_int_cast
<SCROW
>(nRow
+nSizeY
-1), nTab
);
977 MarkRange( aResult
, false );
982 if (rData
.GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
984 ScDocShell
* pDocSh
= rData
.GetDocShell();
985 bool bSuccess
= pDocSh
->GetDocFunc().EnterMatrix(
986 aRange
, &rMark
, nullptr, rString
, false, false, OUString(), eGram
);
988 pDocSh
->UpdateOle(GetViewData());
990 PaintArea(nCol
, nRow
, nCol
, nRow
); // possibly the edit-engine is still painted there
993 ErrorMessage(STR_NOMULTISELECT
);
996 SvtScriptType
ScViewFunc::GetSelectionScriptType()
998 SvtScriptType nScript
= SvtScriptType::NONE
;
1000 ScDocument
& rDoc
= GetViewData().GetDocument();
1001 const ScMarkData
& rMark
= GetViewData().GetMarkData();
1002 if ( !rMark
.IsMarked() && !rMark
.IsMultiMarked() )
1004 // no selection -> cursor
1006 nScript
= rDoc
.GetScriptType( GetViewData().GetCurX(),
1007 GetViewData().GetCurY(), GetViewData().GetTabNo());
1011 ScRangeList aRanges
;
1012 rMark
.FillRangeListWithMarks( &aRanges
, false );
1013 nScript
= rDoc
.GetRangeScriptType(aRanges
);
1016 if (nScript
== SvtScriptType::NONE
)
1017 nScript
= ScGlobal::GetDefaultScriptType();
1022 static void ShrinkToDataArea(ScMarkData
& rFuncMark
, ScDocument
& rDoc
);
1024 const ScPatternAttr
* ScViewFunc::GetSelectionPattern()
1026 // Don't use UnmarkFiltered in slot state functions, for performance reasons.
1027 // The displayed state is always that of the whole selection including filtered rows.
1029 ScMarkData aMark
= GetViewData().GetMarkData();
1030 ScDocument
& rDoc
= GetViewData().GetDocument();
1032 // tdf#155368 if the selection is the whole sheet, we need to shrink the mark area, otherwise
1033 // we will not return a consistent result
1034 // (consistent compared to what happens in ScViewFunc::ApplySelectionPattern)
1035 ShrinkToDataArea( aMark
, rDoc
);
1037 if ( aMark
.IsMarked() || aMark
.IsMultiMarked() )
1039 // MarkToMulti is no longer necessary for rDoc.GetSelectionPattern
1040 const ScPatternAttr
* pAttr
= rDoc
.GetSelectionPattern( aMark
);
1045 SCCOL nCol
= GetViewData().GetCurX();
1046 SCROW nRow
= GetViewData().GetCurY();
1047 SCTAB nTab
= GetViewData().GetTabNo();
1049 // copy sheet selection
1050 aMark
.SetMarkArea( ScRange( nCol
, nRow
, nTab
) );
1051 const ScPatternAttr
* pAttr
= rDoc
.GetSelectionPattern( aMark
);
1056 void ScViewFunc::GetSelectionFrame(
1057 std::shared_ptr
<SvxBoxItem
>& rLineOuter
,
1058 std::shared_ptr
<SvxBoxInfoItem
>& rLineInner
)
1060 ScDocument
& rDoc
= GetViewData().GetDocument();
1061 const ScMarkData
& rMark
= GetViewData().GetMarkData();
1063 if ( rMark
.IsMarked() || rMark
.IsMultiMarked() )
1065 rDoc
.GetSelectionFrame( rMark
, *rLineOuter
, *rLineInner
);
1069 const ScPatternAttr
* pAttrs
=
1070 rDoc
.GetPattern( GetViewData().GetCurX(),
1071 GetViewData().GetCurY(),
1072 GetViewData().GetTabNo() );
1074 rLineOuter
.reset(pAttrs
->GetItem(ATTR_BORDER
).Clone());
1075 rLineInner
.reset(pAttrs
->GetItem(ATTR_BORDER_INNER
).Clone());
1077 rLineInner
->SetTable(false);
1078 rLineInner
->SetDist(true);
1079 rLineInner
->SetMinDist(false);
1083 // apply attribute - undo OK
1085 // complete set ( ATTR_STARTINDEX, ATTR_ENDINDEX )
1087 void ScViewFunc::ApplyAttributes( const SfxItemSet
& rDialogSet
,
1088 const SfxItemSet
& rOldSet
,
1089 bool bAdjustBlockHeight
)
1091 // not editable because of matrix only? attribute OK nonetheless
1092 bool bOnlyNotBecauseOfMatrix
;
1093 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix
) && !bOnlyNotBecauseOfMatrix
)
1095 ErrorMessage(STR_PROTECTIONERR
);
1099 ScDocument
& rDoc
= GetViewData().GetDocument();
1100 ScPatternAttr
aOldAttrs(rDoc
.getCellAttributeHelper(), &rOldSet
);
1101 ScPatternAttr
aNewAttrs(rDoc
.getCellAttributeHelper(), &rDialogSet
);
1102 aNewAttrs
.DeleteUnchanged( &aOldAttrs
);
1104 if ( rDialogSet
.GetItemState( ATTR_VALUE_FORMAT
) == SfxItemState::SET
)
1105 { // don't reset to default SYSTEM GENERAL if not intended
1106 sal_uInt32 nOldFormat
=
1107 rOldSet
.Get( ATTR_VALUE_FORMAT
).GetValue();
1108 sal_uInt32 nNewFormat
=
1109 rDialogSet
.Get( ATTR_VALUE_FORMAT
).GetValue();
1110 if ( nNewFormat
!= nOldFormat
)
1112 SvNumberFormatter
* pFormatter
=
1113 GetViewData().GetDocument().GetFormatTable();
1114 const SvNumberformat
* pOldEntry
= pFormatter
->GetEntry( nOldFormat
);
1115 LanguageType eOldLang
=
1116 pOldEntry
? pOldEntry
->GetLanguage() : LANGUAGE_DONTKNOW
;
1117 const SvNumberformat
* pNewEntry
= pFormatter
->GetEntry( nNewFormat
);
1118 LanguageType eNewLang
=
1119 pNewEntry
? pNewEntry
->GetLanguage() : LANGUAGE_DONTKNOW
;
1120 if ( eNewLang
!= eOldLang
)
1122 aNewAttrs
.GetItemSet().Put(
1123 SvxLanguageItem( eNewLang
, ATTR_LANGUAGE_FORMAT
) );
1125 // only the language has changed -> do not touch numberformat-attribute
1126 sal_uInt32 nNewMod
= nNewFormat
% SV_COUNTRY_LANGUAGE_OFFSET
;
1127 if ( nNewMod
== ( nOldFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) &&
1128 nNewMod
<= SV_MAX_COUNT_STANDARD_FORMATS
)
1129 aNewAttrs
.GetItemSet().ClearItem( ATTR_VALUE_FORMAT
);
1134 if (rDialogSet
.HasItem(ATTR_FONT_LANGUAGE
))
1135 // font language has changed. Redo the online spelling.
1138 const SvxBoxItem
& rOldOuter
= rOldSet
.Get(ATTR_BORDER
);
1139 const SvxBoxItem
& rNewOuter
= rDialogSet
.Get(ATTR_BORDER
);
1140 const SvxBoxInfoItem
& rOldInner
= rOldSet
.Get(ATTR_BORDER_INNER
);
1141 const SvxBoxInfoItem
& rNewInner
= rDialogSet
.Get(ATTR_BORDER_INNER
);
1142 SfxItemSet
& rNewSet
= aNewAttrs
.GetItemSet();
1144 // protect referenced Items from disappearing (was: don't delete yet)
1145 const SfxPoolItemHolder
aHoldOuter(*rDialogSet
.GetPool() , &rNewOuter
);
1146 const SfxPoolItemHolder
aHoldInner(*rDialogSet
.GetPool() , &rNewInner
);
1150 rNewSet
.ClearItem( ATTR_BORDER
);
1151 rNewSet
.ClearItem( ATTR_BORDER_INNER
);
1154 * establish whether border attribute is to be set:
1156 * 2. is one of the borders not-DontCare (since 238.f: IsxxValid())
1160 bool bFrame
= (rDialogSet
.GetItemState( ATTR_BORDER
) != SfxItemState::DEFAULT
)
1161 || (rDialogSet
.GetItemState( ATTR_BORDER_INNER
) != SfxItemState::DEFAULT
);
1163 if (SfxPoolItem::areSame(rNewOuter
, rOldOuter
) && SfxPoolItem::areSame(rNewInner
, rOldInner
))
1166 // this should be intercepted by the pool: ?!??!??
1168 if (bFrame
&& rNewOuter
== rOldOuter
&& rNewInner
== rOldInner
)
1172 && ( rNewInner
.IsValid(SvxBoxInfoItemValidFlags::LEFT
)
1173 || rNewInner
.IsValid(SvxBoxInfoItemValidFlags::RIGHT
)
1174 || rNewInner
.IsValid(SvxBoxInfoItemValidFlags::TOP
)
1175 || rNewInner
.IsValid(SvxBoxInfoItemValidFlags::BOTTOM
)
1176 || rNewInner
.IsValid(SvxBoxInfoItemValidFlags::HORI
)
1177 || rNewInner
.IsValid(SvxBoxInfoItemValidFlags::VERT
) );
1180 ApplySelectionPattern( aNewAttrs
); // standard only
1183 // if new items are default-items, overwrite the old items:
1185 bool bDefNewOuter
= IsStaticDefaultItem(&rNewOuter
);
1186 bool bDefNewInner
= IsStaticDefaultItem(&rNewInner
);
1188 ApplyPatternLines( aNewAttrs
,
1189 bDefNewOuter
? rOldOuter
: rNewOuter
,
1190 bDefNewInner
? &rOldInner
: &rNewInner
);
1193 // adjust height only if needed
1194 if (bAdjustBlockHeight
)
1195 AdjustBlockHeight();
1197 // CellContentChanged is called in ApplySelectionPattern / ApplyPatternLines
1200 void ScViewFunc::ApplyAttr( const SfxPoolItem
& rAttrItem
, bool bAdjustBlockHeight
)
1202 // not editable because of matrix only? attribute OK nonetheless
1203 bool bOnlyNotBecauseOfMatrix
;
1204 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix
) && !bOnlyNotBecauseOfMatrix
)
1206 ErrorMessage(STR_PROTECTIONERR
);
1210 ScDocument
& rDoc
= GetViewData().GetDocument();
1211 ScPatternAttr
aNewAttrs(rDoc
.getCellAttributeHelper());
1213 aNewAttrs
.GetItemSet().Put( rAttrItem
);
1214 // if justify is set (with Buttons), always indentation 0
1215 if ( rAttrItem
.Which() == ATTR_HOR_JUSTIFY
)
1216 aNewAttrs
.GetItemSet().Put( ScIndentItem( 0 ) );
1217 ApplySelectionPattern( aNewAttrs
);
1219 // Prevent useless compute
1220 if (bAdjustBlockHeight
)
1221 AdjustBlockHeight();
1223 // CellContentChanged is called in ApplySelectionPattern
1226 // patterns and borders
1228 void ScViewFunc::ApplyPatternLines( const ScPatternAttr
& rAttr
, const SvxBoxItem
& rNewOuter
,
1229 const SvxBoxInfoItem
* pNewInner
)
1231 ScDocument
& rDoc
= GetViewData().GetDocument();
1232 ScMarkData
aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered
1233 ScViewUtil::UnmarkFiltered( aFuncMark
, rDoc
);
1234 bool bRecord
= true;
1235 if (!rDoc
.IsUndoEnabled())
1238 bool bRemoveAdjCellBorder
= rNewOuter
.IsRemoveAdjacentCellBorder();
1239 ScRange aMarkRange
, aMarkRangeWithEnvelope
;
1240 aFuncMark
.MarkToSimple();
1241 bool bMulti
= aFuncMark
.IsMultiMarked();
1243 aMarkRange
= aFuncMark
.GetMultiMarkArea();
1244 else if (aFuncMark
.IsMarked())
1245 aMarkRange
= aFuncMark
.GetMarkArea();
1248 aMarkRange
= ScRange( GetViewData().GetCurX(),
1249 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1251 InitOwnBlockMode( aMarkRange
);
1252 aFuncMark
.SetMarkArea(aMarkRange
);
1255 if( bRemoveAdjCellBorder
)
1256 aFuncMark
.GetSelectionCover( aMarkRangeWithEnvelope
);
1258 aMarkRangeWithEnvelope
= aMarkRange
;
1260 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
1262 ScDocShellModificator
aModificator( *pDocSh
);
1266 ScDocumentUniquePtr
pUndoDoc(new ScDocument( SCDOCMODE_UNDO
));
1267 SCTAB nStartTab
= aMarkRange
.aStart
.Tab();
1268 SCTAB nTabCount
= rDoc
.GetTableCount();
1269 bool bCopyOnlyMarked
= false;
1270 if( !bRemoveAdjCellBorder
)
1271 bCopyOnlyMarked
= bMulti
;
1272 pUndoDoc
->InitUndo( rDoc
, nStartTab
, nStartTab
);
1273 for (const auto& rTab
: aFuncMark
)
1274 if (rTab
!= nStartTab
)
1275 pUndoDoc
->AddUndoTab( rTab
, rTab
);
1277 ScRange aCopyRange
= aMarkRangeWithEnvelope
;
1278 aCopyRange
.aStart
.SetTab(0);
1279 aCopyRange
.aEnd
.SetTab(nTabCount
-1);
1280 rDoc
.CopyToDocument( aCopyRange
, InsertDeleteFlags::ATTRIB
, bCopyOnlyMarked
, *pUndoDoc
, &aFuncMark
);
1282 pDocSh
->GetUndoManager()->AddUndoAction(
1283 std::make_unique
<ScUndoSelectionAttr
>(
1285 aMarkRange
.aStart
.Col(), aMarkRange
.aStart
.Row(), aMarkRange
.aStart
.Tab(),
1286 aMarkRange
.aEnd
.Col(), aMarkRange
.aEnd
.Row(), aMarkRange
.aEnd
.Tab(),
1287 std::move(pUndoDoc
), bCopyOnlyMarked
, &rAttr
, &rNewOuter
, pNewInner
, &aMarkRangeWithEnvelope
) );
1290 sal_uInt16 nExt
= SC_PF_TESTMERGE
;
1291 pDocSh
->UpdatePaintExt( nExt
, aMarkRangeWithEnvelope
); // content before the change
1293 rDoc
.ApplySelectionFrame(aFuncMark
, rNewOuter
, pNewInner
);
1295 pDocSh
->UpdatePaintExt( nExt
, aMarkRangeWithEnvelope
); // content after the change
1297 aFuncMark
.MarkToMulti();
1298 rDoc
.ApplySelectionPattern( rAttr
, aFuncMark
);
1300 pDocSh
->PostPaint( aMarkRange
, PaintPartFlags::Grid
, nExt
);
1301 pDocSh
->UpdateOle(GetViewData());
1302 aModificator
.SetDocumentModified();
1303 CellContentChanged();
1308 // tdf#147842 if the marked area is the entire sheet, then shrink it to the data area.
1309 // Otherwise ctrl-A, perform-action, will take a very long time as it tries to modify
1310 // cells that we are not using.
1311 static void ShrinkToDataArea(ScMarkData
& rFuncMark
, ScDocument
& rDoc
)
1313 // do not make it marked if it is not already marked
1314 if (!rFuncMark
.IsMarked())
1316 if (rFuncMark
.IsMultiMarked())
1318 ScRange aMarkArea
= rFuncMark
.GetMarkArea();
1319 const ScSheetLimits
& rLimits
= rDoc
.GetSheetLimits();
1320 if (aMarkArea
.aStart
.Row() != 0 || aMarkArea
.aStart
.Col() != 0)
1322 if (aMarkArea
.aEnd
.Row() != rLimits
.MaxRow() || aMarkArea
.aEnd
.Col() != rLimits
.MaxCol())
1324 if (aMarkArea
.aStart
.Tab() != aMarkArea
.aEnd
.Tab())
1326 SCCOL nStartCol
= aMarkArea
.aStart
.Col();
1327 SCROW nStartRow
= aMarkArea
.aStart
.Row();
1328 SCCOL nEndCol
= aMarkArea
.aEnd
.Col();
1329 SCROW nEndRow
= aMarkArea
.aEnd
.Row();
1330 rDoc
.ShrinkToDataArea(aMarkArea
.aStart
.Tab(), nStartCol
, nStartRow
, nEndCol
, nEndRow
);
1331 aMarkArea
.aStart
.SetCol(nStartCol
);
1332 aMarkArea
.aStart
.SetRow(nStartRow
);
1333 aMarkArea
.aEnd
.SetCol(nEndCol
);
1334 aMarkArea
.aEnd
.SetRow(nEndRow
);
1335 rFuncMark
.ResetMark();
1336 rFuncMark
.SetMarkArea(aMarkArea
);
1341 void ScViewFunc::ApplySelectionPattern( const ScPatternAttr
& rAttr
, bool bCursorOnly
)
1343 ScViewData
& rViewData
= GetViewData();
1344 ScDocShell
* pDocSh
= rViewData
.GetDocShell();
1345 ScDocument
& rDoc
= pDocSh
->GetDocument();
1346 ScMarkData
aFuncMark( rViewData
.GetMarkData() ); // local copy for UnmarkFiltered
1347 ScViewUtil::UnmarkFiltered( aFuncMark
, rDoc
);
1349 bool bRecord
= true;
1350 if (!rDoc
.IsUndoEnabled())
1353 // State from old ItemSet doesn't matter for paint flags, as any change will be
1354 // from SfxItemState::SET in the new ItemSet (default is ignored in ApplyPattern).
1355 // New alignment is checked (check in PostPaint isn't enough) in case a right
1356 // alignment is changed to left.
1357 const SfxItemSet
& rNewSet
= rAttr
.GetItemSet();
1358 bool bSetLines
= rNewSet
.GetItemState( ATTR_BORDER
) == SfxItemState::SET
||
1359 rNewSet
.GetItemState( ATTR_SHADOW
) == SfxItemState::SET
;
1360 bool bSetAlign
= rNewSet
.GetItemState( ATTR_HOR_JUSTIFY
) == SfxItemState::SET
;
1362 sal_uInt16 nExtFlags
= 0;
1364 nExtFlags
|= SC_PF_LINES
;
1366 nExtFlags
|= SC_PF_WHOLEROWS
;
1368 ScDocShellModificator
aModificator( *pDocSh
);
1370 bool bMulti
= aFuncMark
.IsMultiMarked();
1371 aFuncMark
.MarkToMulti();
1372 bool bOnlyTab
= (!aFuncMark
.IsMultiMarked() && !bCursorOnly
&& aFuncMark
.GetSelectCount() > 1);
1375 SCCOL nCol
= rViewData
.GetCurX();
1376 SCROW nRow
= rViewData
.GetCurY();
1377 SCTAB nTab
= rViewData
.GetTabNo();
1378 aFuncMark
.SetMarkArea(ScRange(nCol
,nRow
,nTab
));
1379 aFuncMark
.MarkToMulti();
1382 ScRangeList aChangeRanges
;
1384 if (aFuncMark
.IsMultiMarked() && !bCursorOnly
)
1386 const ScRange
& aMarkRange
= aFuncMark
.GetMultiMarkArea();
1387 SCTAB nTabCount
= rDoc
.GetTableCount();
1388 for (const auto& rTab
: aFuncMark
)
1390 ScRange
aChangeRange( aMarkRange
);
1391 aChangeRange
.aStart
.SetTab( rTab
);
1392 aChangeRange
.aEnd
.SetTab( rTab
);
1393 aChangeRanges
.push_back( aChangeRange
);
1396 SCCOL nStartCol
= aMarkRange
.aStart
.Col();
1397 SCROW nStartRow
= aMarkRange
.aStart
.Row();
1398 SCTAB nStartTab
= aMarkRange
.aStart
.Tab();
1399 SCCOL nEndCol
= aMarkRange
.aEnd
.Col();
1400 SCROW nEndRow
= aMarkRange
.aEnd
.Row();
1401 SCTAB nEndTab
= aMarkRange
.aEnd
.Tab();
1403 ScEditDataArray
* pEditDataArray
= nullptr;
1406 ScRange aCopyRange
= aMarkRange
;
1407 aCopyRange
.aStart
.SetTab(0);
1408 aCopyRange
.aEnd
.SetTab(nTabCount
-1);
1410 ScDocumentUniquePtr
pUndoDoc(new ScDocument( SCDOCMODE_UNDO
));
1411 pUndoDoc
->InitUndo( rDoc
, nStartTab
, nStartTab
);
1412 for (const auto& rTab
: aFuncMark
)
1413 if (rTab
!= nStartTab
)
1414 pUndoDoc
->AddUndoTab( rTab
, rTab
);
1415 rDoc
.CopyToDocument( aCopyRange
, InsertDeleteFlags::ATTRIB
, bMulti
, *pUndoDoc
, &aFuncMark
);
1417 aFuncMark
.MarkToMulti();
1419 ScUndoSelectionAttr
* pUndoAttr
= new ScUndoSelectionAttr(
1420 pDocSh
, aFuncMark
, nStartCol
, nStartRow
, nStartTab
,
1421 nEndCol
, nEndRow
, nEndTab
, std::move(pUndoDoc
), bMulti
, &rAttr
);
1422 pDocSh
->GetUndoManager()->AddUndoAction(std::unique_ptr
<ScUndoSelectionAttr
>(pUndoAttr
));
1423 pEditDataArray
= pUndoAttr
->GetDataArray();
1426 rDoc
.ApplySelectionPattern( rAttr
, aFuncMark
, pEditDataArray
);
1428 pDocSh
->PostPaint( nStartCol
, nStartRow
, nStartTab
,
1429 nEndCol
, nEndRow
, nEndTab
,
1430 PaintPartFlags::Grid
, nExtFlags
| SC_PF_TESTMERGE
);
1431 pDocSh
->UpdateOle(GetViewData());
1432 aModificator
.SetDocumentModified();
1433 CellContentChanged();
1435 else // single cell - simpler undo
1437 SCCOL nCol
= rViewData
.GetCurX();
1438 SCROW nRow
= rViewData
.GetCurY();
1439 SCTAB nTab
= rViewData
.GetTabNo();
1441 std::unique_ptr
<EditTextObject
> pOldEditData
;
1442 std::unique_ptr
<EditTextObject
> pNewEditData
;
1443 ScAddress
aPos(nCol
, nRow
, nTab
);
1444 ScRefCellValue
aCell(rDoc
, aPos
);
1445 if (aCell
.getType() == CELLTYPE_EDIT
)
1447 const EditTextObject
* pEditObj
= aCell
.getEditText();
1448 pOldEditData
= pEditObj
->Clone();
1449 rDoc
.RemoveEditTextCharAttribs(aPos
, rAttr
);
1450 pEditObj
= rDoc
.GetEditText(aPos
);
1451 pNewEditData
= pEditObj
->Clone();
1454 aChangeRanges
.push_back(ScRange(aPos
));
1455 std::optional
<ScPatternAttr
> pOldPat(*rDoc
.GetPattern( nCol
, nRow
, nTab
));
1457 rDoc
.ApplyPattern( nCol
, nRow
, nTab
, rAttr
);
1459 const ScPatternAttr
* pNewPat
= rDoc
.GetPattern( nCol
, nRow
, nTab
);
1463 std::unique_ptr
<ScUndoCursorAttr
> pUndo(new ScUndoCursorAttr(
1464 pDocSh
, nCol
, nRow
, nTab
, &*pOldPat
, pNewPat
, &rAttr
));
1465 pUndo
->SetEditData(std::move(pOldEditData
), std::move(pNewEditData
));
1466 pDocSh
->GetUndoManager()->AddUndoAction(std::move(pUndo
));
1468 pOldPat
.reset(); // is copied in undo (Pool)
1470 pDocSh
->PostPaint( nCol
,nRow
,nTab
, nCol
,nRow
,nTab
, PaintPartFlags::Grid
, nExtFlags
| SC_PF_TESTMERGE
);
1471 pDocSh
->UpdateOle(GetViewData());
1472 aModificator
.SetDocumentModified();
1473 CellContentChanged();
1476 ScModelObj
* pModelObj
= pDocSh
->GetModel();
1478 if (HelperNotifyChanges::getMustPropagateChangesModel(pModelObj
))
1480 css::uno::Sequence
< css::beans::PropertyValue
> aProperties
;
1481 sal_Int32 nCount
= 0;
1482 const SfxItemPropertyMap
& rMap
= ScCellObj::GetCellPropertyMap();
1483 for ( sal_uInt16 nWhich
= ATTR_PATTERN_START
; nWhich
<= ATTR_PATTERN_END
; ++nWhich
)
1485 const SfxPoolItem
* pItem
= nullptr;
1486 if ( rNewSet
.GetItemState( nWhich
, true, &pItem
) == SfxItemState::SET
&& pItem
)
1488 for ( const auto & rPair
: rMap
.getPropertyEntries())
1490 const SfxItemPropertyMapEntry
* pEntry
= rPair
.second
;
1491 if ( pEntry
->nWID
== nWhich
)
1494 pItem
->QueryValue( aVal
, pEntry
->nMemberId
);
1495 aProperties
.realloc( nCount
+ 1 );
1496 auto pProperties
= aProperties
.getArray();
1497 pProperties
[ nCount
].Name
= pEntry
->aName
;
1498 pProperties
[ nCount
].Value
= std::move(aVal
);
1504 HelperNotifyChanges::Notify(*pModelObj
, aChangeRanges
, u
"attribute"_ustr
, aProperties
);
1510 void ScViewFunc::ApplyUserItemSet( const SfxItemSet
& rItemSet
)
1512 // ItemSet from UI, may have different pool
1514 bool bOnlyNotBecauseOfMatrix
;
1515 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix
) && !bOnlyNotBecauseOfMatrix
)
1517 ErrorMessage(STR_PROTECTIONERR
);
1521 ScPatternAttr
aNewAttrs(GetViewData().GetDocument().getCellAttributeHelper());
1522 SfxItemSet
& rNewSet
= aNewAttrs
.GetItemSet();
1523 rNewSet
.Put( rItemSet
, false );
1524 ApplySelectionPattern( aNewAttrs
);
1526 AdjustBlockHeight();
1529 const SfxStyleSheet
* ScViewFunc::GetStyleSheetFromMarked()
1531 // Don't use UnmarkFiltered in slot state functions, for performance reasons.
1532 // The displayed state is always that of the whole selection including filtered rows.
1534 const ScStyleSheet
* pSheet
= nullptr;
1535 ScViewData
& rViewData
= GetViewData();
1536 ScDocument
& rDoc
= rViewData
.GetDocument();
1537 ScMarkData
& rMark
= rViewData
.GetMarkData();
1539 if ( rMark
.IsMarked() || rMark
.IsMultiMarked() )
1540 pSheet
= rDoc
.GetSelectionStyle( rMark
); // MarkToMulti isn't necessary
1542 pSheet
= rDoc
.GetStyle( rViewData
.GetCurX(),
1543 rViewData
.GetCurY(),
1544 rViewData
.GetTabNo() );
1549 void ScViewFunc::SetStyleSheetToMarked( const SfxStyleSheet
* pStyleSheet
)
1551 // not editable because of matrix only? attribute OK nonetheless
1552 bool bOnlyNotBecauseOfMatrix
;
1553 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix
) && !bOnlyNotBecauseOfMatrix
)
1555 ErrorMessage(STR_PROTECTIONERR
);
1559 if ( !pStyleSheet
) return;
1561 ScViewData
& rViewData
= GetViewData();
1562 ScDocShell
* pDocSh
= rViewData
.GetDocShell();
1563 ScDocument
& rDoc
= pDocSh
->GetDocument();
1564 ScMarkData
aFuncMark( rViewData
.GetMarkData() ); // local copy for UnmarkFiltered
1565 ScViewUtil::UnmarkFiltered( aFuncMark
, rDoc
);
1566 SCTAB nTabCount
= rDoc
.GetTableCount();
1567 bool bRecord
= true;
1568 if (!rDoc
.IsUndoEnabled())
1571 ScDocShellModificator
aModificator( *pDocSh
);
1573 if ( aFuncMark
.IsMarked() || aFuncMark
.IsMultiMarked() )
1575 aFuncMark
.MarkToMulti();
1576 const ScRange
& aMarkRange
= aFuncMark
.GetMultiMarkArea();
1580 SCTAB nTab
= rViewData
.GetTabNo();
1581 ScDocumentUniquePtr
pUndoDoc(new ScDocument( SCDOCMODE_UNDO
));
1582 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
);
1583 for (const auto& rTab
: aFuncMark
)
1585 pUndoDoc
->AddUndoTab( rTab
, rTab
);
1587 ScRange aCopyRange
= aMarkRange
;
1588 aCopyRange
.aStart
.SetTab(0);
1589 aCopyRange
.aEnd
.SetTab(nTabCount
-1);
1590 rDoc
.CopyToDocument( aCopyRange
, InsertDeleteFlags::ATTRIB
, true, *pUndoDoc
, &aFuncMark
);
1591 aFuncMark
.MarkToMulti();
1593 OUString aName
= pStyleSheet
->GetName();
1594 pDocSh
->GetUndoManager()->AddUndoAction(
1595 std::make_unique
<ScUndoSelectionStyle
>( pDocSh
, aFuncMark
, aMarkRange
, aName
, std::move(pUndoDoc
) ) );
1598 rDoc
.ApplySelectionStyle( static_cast<const ScStyleSheet
&>(*pStyleSheet
), aFuncMark
);
1600 if (!AdjustBlockHeight())
1601 rViewData
.GetDocShell()->PostPaint( aMarkRange
, PaintPartFlags::Grid
);
1603 aFuncMark
.MarkToSimple();
1607 SCCOL nCol
= rViewData
.GetCurX();
1608 SCROW nRow
= rViewData
.GetCurY();
1609 SCTAB nTab
= rViewData
.GetTabNo();
1613 ScDocumentUniquePtr
pUndoDoc(new ScDocument( SCDOCMODE_UNDO
));
1614 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
);
1615 for (const auto& rTab
: aFuncMark
)
1617 pUndoDoc
->AddUndoTab( rTab
, rTab
);
1619 ScRange
aCopyRange( nCol
, nRow
, 0, nCol
, nRow
, nTabCount
-1 );
1620 rDoc
.CopyToDocument( aCopyRange
, InsertDeleteFlags::ATTRIB
, false, *pUndoDoc
);
1622 ScRange
aMarkRange ( nCol
, nRow
, nTab
);
1623 ScMarkData aUndoMark
= aFuncMark
;
1624 aUndoMark
.SetMultiMarkArea( aMarkRange
);
1626 OUString aName
= pStyleSheet
->GetName();
1627 pDocSh
->GetUndoManager()->AddUndoAction(
1628 std::make_unique
<ScUndoSelectionStyle
>( pDocSh
, aUndoMark
, aMarkRange
, aName
, std::move(pUndoDoc
) ) );
1631 for (const auto& rTab
: aFuncMark
)
1632 rDoc
.ApplyStyle( nCol
, nRow
, rTab
, static_cast<const ScStyleSheet
&>(*pStyleSheet
) );
1634 if (!AdjustBlockHeight())
1635 rViewData
.GetDocShell()->PostPaintCell( nCol
, nRow
, nTab
);
1639 aModificator
.SetDocumentModified();
1644 void ScViewFunc::RemoveStyleSheetInUse( const SfxStyleSheetBase
* pStyleSheet
)
1646 if ( !pStyleSheet
) return;
1648 ScViewData
& rViewData
= GetViewData();
1649 ScDocument
& rDoc
= rViewData
.GetDocument();
1650 ScDocShell
* pDocSh
= rViewData
.GetDocShell();
1652 ScDocShellModificator
aModificator( *pDocSh
);
1654 ScopedVclPtrInstance
< VirtualDevice
> pVirtDev
;
1655 pVirtDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
1656 rDoc
.StyleSheetChanged( pStyleSheet
, true, pVirtDev
,
1657 rViewData
.GetPPTX(),
1658 rViewData
.GetPPTY(),
1659 rViewData
.GetZoomX(),
1660 rViewData
.GetZoomY() );
1662 pDocSh
->PostPaint( 0,0,0, rDoc
.MaxCol(), rDoc
.MaxRow(), MAXTAB
, PaintPartFlags::Grid
|PaintPartFlags::Left
);
1663 aModificator
.SetDocumentModified();
1665 ScInputHandler
* pHdl
= ScModule::get()->GetInputHdl();
1667 pHdl
->ForgetLastPattern();
1670 void ScViewFunc::UpdateStyleSheetInUse( const SfxStyleSheetBase
* pStyleSheet
)
1672 if ( !pStyleSheet
) return;
1674 ScViewData
& rViewData
= GetViewData();
1675 ScDocument
& rDoc
= rViewData
.GetDocument();
1676 ScDocShell
* pDocSh
= rViewData
.GetDocShell();
1678 ScDocShellModificator
aModificator( *pDocSh
);
1680 ScopedVclPtrInstance
< VirtualDevice
> pVirtDev
;
1681 pVirtDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
1682 rDoc
.StyleSheetChanged( pStyleSheet
, false, pVirtDev
,
1683 rViewData
.GetPPTX(),
1684 rViewData
.GetPPTY(),
1685 rViewData
.GetZoomX(),
1686 rViewData
.GetZoomY() );
1688 pDocSh
->PostPaint( 0,0,0, rDoc
.MaxCol(), rDoc
.MaxRow(), MAXTAB
, PaintPartFlags::Grid
|PaintPartFlags::Left
);
1689 aModificator
.SetDocumentModified();
1691 ScInputHandler
* pHdl
= ScModule::get()->GetInputHdl();
1693 pHdl
->ForgetLastPattern();
1697 void ScViewFunc::OnLOKInsertDeleteColumn(SCCOL nStartCol
, tools::Long nOffset
)
1699 if (!comphelper::LibreOfficeKit::isActive() || nOffset
== 0)
1702 SCTAB nCurrentTabIndex
= GetViewData().GetTabNo();
1703 SfxViewShell
* pCurrentViewShell
= GetViewData().GetViewShell();
1704 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
1707 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(pViewShell
);
1708 if (pTabViewShell
&& pTabViewShell
->GetDocId() == pCurrentViewShell
->GetDocId())
1710 if (ScPositionHelper
* pPosHelper
= pTabViewShell
->GetViewData().GetLOKWidthHelper(nCurrentTabIndex
))
1711 pPosHelper
->invalidateByIndex(nStartCol
);
1713 // if we remove a column the cursor position and the current selection
1714 // in other views could need to be moved on the left by one column.
1715 if (pTabViewShell
!= this)
1717 if (pTabViewShell
->getPart() == nCurrentTabIndex
)
1719 SCCOL nX
= pTabViewShell
->GetViewData().GetCurX();
1722 tools::Long offset
= nOffset
;
1723 if (nOffset
+ nStartCol
> nX
)
1724 offset
= nX
- nStartCol
;
1725 else if (nOffset
< 0 && nStartCol
- nOffset
> nX
)
1726 offset
= -1 * (nX
- nStartCol
);
1728 ScInputHandler
* pInputHdl
= pTabViewShell
->GetInputHandler();
1729 SCROW nY
= pTabViewShell
->GetViewData().GetCurY();
1730 pTabViewShell
->SetCursor(nX
+ offset
, nY
);
1731 if (pInputHdl
&& pInputHdl
->IsInputMode())
1733 pInputHdl
->SetModified();
1737 ScMarkData
aMultiMark( pTabViewShell
->GetViewData().GetMarkData() );
1738 aMultiMark
.SetMarking( false );
1740 if (aMultiMark
.IsMultiMarked() || aMultiMark
.IsMarked())
1742 aMultiMark
.ShiftCols(pTabViewShell
->GetViewData().GetDocument(), nStartCol
, nOffset
);
1743 pTabViewShell
->SetMarkData(aMultiMark
);
1748 SCROW nX
= pTabViewShell
->GetViewData().GetCurXForTab(nCurrentTabIndex
);
1749 if (nX
> nStartCol
|| (nX
== nStartCol
&& nOffset
> 0))
1751 pTabViewShell
->GetViewData().SetCurXForTab(nX
+ nOffset
, nCurrentTabIndex
);
1756 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
1760 void ScViewFunc::OnLOKInsertDeleteRow(SCROW nStartRow
, tools::Long nOffset
)
1762 if (!comphelper::LibreOfficeKit::isActive() || nOffset
== 0)
1765 SCTAB nCurrentTabIndex
= GetViewData().GetTabNo();
1766 SfxViewShell
* pCurrentViewShell
= GetViewData().GetViewShell();
1767 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
1770 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(pViewShell
);
1771 if (pTabViewShell
&& pTabViewShell
->GetDocId() == pCurrentViewShell
->GetDocId())
1773 if (ScPositionHelper
* pPosHelper
= pTabViewShell
->GetViewData().GetLOKHeightHelper(nCurrentTabIndex
))
1774 pPosHelper
->invalidateByIndex(nStartRow
);
1776 // if we remove a row the cursor position and the current selection
1777 // in other views could need to be moved up by one row.
1778 if (pTabViewShell
!= this)
1780 if (pTabViewShell
->getPart() == nCurrentTabIndex
)
1782 SCROW nY
= pTabViewShell
->GetViewData().GetCurY();
1785 tools::Long offset
= nOffset
;
1786 if (nOffset
+ nStartRow
> nY
)
1787 offset
= nY
- nStartRow
;
1788 else if (nOffset
< 0 && nStartRow
- nOffset
> nY
)
1789 offset
= -1 * (nY
- nStartRow
);
1791 ScInputHandler
* pInputHdl
= pTabViewShell
->GetInputHandler();
1792 SCCOL nX
= pTabViewShell
->GetViewData().GetCurX();
1793 pTabViewShell
->SetCursor(nX
, nY
+ offset
);
1794 if (pInputHdl
&& pInputHdl
->IsInputMode())
1796 pInputHdl
->SetModified();
1800 ScMarkData
aMultiMark( pTabViewShell
->GetViewData().GetMarkData() );
1801 aMultiMark
.SetMarking( false );
1803 if (aMultiMark
.IsMultiMarked() || aMultiMark
.IsMarked())
1805 aMultiMark
.ShiftRows(pTabViewShell
->GetViewData().GetDocument(), nStartRow
, nOffset
);
1806 pTabViewShell
->SetMarkData(aMultiMark
);
1811 SCROW nY
= pTabViewShell
->GetViewData().GetCurYForTab(nCurrentTabIndex
);
1812 if (nY
> nStartRow
|| (nY
== nStartRow
&& nOffset
> 0))
1814 pTabViewShell
->GetViewData().SetCurYForTab(nY
+ nOffset
, nCurrentTabIndex
);
1819 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
1823 void ScViewFunc::OnLOKSetWidthOrHeight(SCCOLROW nStart
, bool bWidth
)
1825 if (!comphelper::LibreOfficeKit::isActive())
1828 SCTAB nCurTab
= GetViewData().GetTabNo();
1829 SfxViewShell
* pCurrentViewShell
= GetViewData().GetViewShell();
1830 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
1833 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(pViewShell
);
1834 if (pTabViewShell
&& pTabViewShell
->GetDocId() == pCurrentViewShell
->GetDocId())
1838 if (ScPositionHelper
* pPosHelper
= pTabViewShell
->GetViewData().GetLOKWidthHelper(nCurTab
))
1839 pPosHelper
->invalidateByIndex(nStart
);
1843 if (ScPositionHelper
* pPosHelper
= pTabViewShell
->GetViewData().GetLOKHeightHelper(nCurTab
))
1844 pPosHelper
->invalidateByIndex(nStart
);
1847 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
1851 // insert cells - undo OK
1853 bool ScViewFunc::InsertCells( InsCellCmd eCmd
, bool bRecord
, bool bPartOfPaste
, size_t nCount
)
1856 ScMarkType eMarkType
= GetViewData().GetSimpleArea(aRange
);
1857 if (eMarkType
== SC_MARK_SIMPLE
|| eMarkType
== SC_MARK_SIMPLE_FILTERED
)
1859 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
1860 const ScMarkData
& rMark
= GetViewData().GetMarkData();
1861 bool bSuccess
= pDocSh
->GetDocFunc().InsertCells( aRange
, &rMark
, eCmd
, bRecord
, false, bPartOfPaste
, nCount
);
1864 ResetAutoSpellForContentChange();
1865 bool bInsertCols
= ( eCmd
== INS_INSCOLS_BEFORE
|| eCmd
== INS_INSCOLS_AFTER
);
1866 bool bInsertRows
= ( eCmd
== INS_INSROWS_BEFORE
|| eCmd
== INS_INSROWS_AFTER
);
1868 pDocSh
->UpdateOle(GetViewData());
1869 CellContentChanged();
1871 if ( bInsertCols
|| bInsertRows
)
1873 OUString aOperation
= bInsertRows
?
1874 u
"insert-rows"_ustr
:
1875 u
"insert-columns"_ustr
;
1876 HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh
, aRange
, aOperation
);
1879 if (comphelper::LibreOfficeKit::isActive())
1882 ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), COLUMN_HEADER
, GetViewData().GetTabNo());
1885 ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER
, GetViewData().GetTabNo());
1887 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
1888 bInsertCols
, bInsertRows
, true /* bSizes*/,
1889 true /* bHidden */, true /* bFiltered */,
1890 true /* bGroups */, GetViewData().GetTabNo());
1895 ErrorMessage(STR_ERR_INSERT_CELLS
);
1898 OUString aStartAddress
= aRange
.aStart
.GetColRowString();
1899 OUString aEndAddress
= aRange
.aEnd
.GetColRowString();
1900 collectUIInformation({{"RANGE", aStartAddress
+ ":" + aEndAddress
}}, u
"INSERT_CELLS"_ustr
);
1905 ErrorMessage(STR_NOMULTISELECT
);
1910 // delete cells - undo OK
1912 void ScViewFunc::DeleteCells( DelCellCmd eCmd
)
1915 if ( GetViewData().GetSimpleArea( aRange
) == SC_MARK_SIMPLE
)
1917 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
1918 const ScMarkData
& rMark
= GetViewData().GetMarkData();
1920 #if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
1921 // #i94841# [Collaboration] if deleting rows is rejected, the content is sometimes wrong
1922 if ( pDocSh
->IsDocShared() && ( eCmd
== DelCellCmd::Rows
|| eCmd
== DelCellCmd::Cols
) )
1924 ScRange
aDelRange( aRange
.aStart
);
1925 SCCOLROW nCount
= 0;
1926 if ( eCmd
== DelCellCmd::Rows
)
1928 nCount
= sal::static_int_cast
< SCCOLROW
>( aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1 );
1932 nCount
= sal::static_int_cast
< SCCOLROW
>( aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1 );
1934 while ( nCount
> 0 )
1936 pDocSh
->GetDocFunc().DeleteCells( aDelRange
, &rMark
, eCmd
, false );
1943 pDocSh
->GetDocFunc().DeleteCells( aRange
, &rMark
, eCmd
, false );
1946 ResetAutoSpellForContentChange();
1947 pDocSh
->UpdateOle(GetViewData());
1948 CellContentChanged();
1950 if ( eCmd
== DelCellCmd::Rows
|| eCmd
== DelCellCmd::Cols
)
1952 OUString aOperation
= ( eCmd
== DelCellCmd::Rows
) ?
1953 u
"delete-rows"_ustr
:
1954 u
"delete-columns"_ustr
;
1955 HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh
, aRange
, aOperation
);
1958 // put cursor directly behind deleted range
1959 SCCOL nCurX
= GetViewData().GetCurX();
1960 SCROW nCurY
= GetViewData().GetCurY();
1961 if ( eCmd
==DelCellCmd::CellsLeft
|| eCmd
==DelCellCmd::Cols
)
1962 nCurX
= aRange
.aStart
.Col();
1964 nCurY
= aRange
.aStart
.Row();
1965 SetCursor( nCurX
, nCurY
);
1967 if (comphelper::LibreOfficeKit::isActive())
1969 bool bColsDeleted
= (eCmd
== DelCellCmd::Cols
);
1970 bool bRowsDeleted
= (eCmd
== DelCellCmd::Rows
);
1972 ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), COLUMN_HEADER
, GetViewData().GetTabNo());
1975 ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER
, GetViewData().GetTabNo());
1977 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
1978 bColsDeleted
, bRowsDeleted
, true /* bSizes*/,
1979 true /* bHidden */, true /* bFiltered */,
1980 true /* bGroups */, GetViewData().GetTabNo());
1985 if (eCmd
== DelCellCmd::Cols
)
1986 DeleteMulti( false );
1987 else if (eCmd
== DelCellCmd::Rows
)
1988 DeleteMulti( true );
1990 ErrorMessage(STR_NOMULTISELECT
);
1993 OUString aStartAddress
= aRange
.aStart
.GetColRowString();
1994 OUString aEndAddress
= aRange
.aEnd
.GetColRowString();
1995 collectUIInformation({{"RANGE", aStartAddress
+ ":" + aEndAddress
}}, u
"DELETE_CELLS"_ustr
);
2000 void ScViewFunc::DeleteMulti( bool bRows
)
2002 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
2003 ScDocShellModificator
aModificator( *pDocSh
);
2004 SCTAB nTab
= GetViewData().GetTabNo();
2005 ScDocument
& rDoc
= pDocSh
->GetDocument();
2006 ScMarkData
aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered
2007 ScViewUtil::UnmarkFiltered( aFuncMark
, rDoc
);
2009 bool bRecord
= true;
2010 if (!rDoc
.IsUndoEnabled())
2013 std::vector
<sc::ColRowSpan
> aSpans
;
2015 aSpans
= aFuncMark
.GetMarkedRowSpans();
2017 aSpans
= aFuncMark
.GetMarkedColSpans();
2021 SCCOLROW nCurPos
= bRows
? GetViewData().GetCurY() : GetViewData().GetCurX();
2022 aSpans
.emplace_back(nCurPos
, nCurPos
);
2027 TranslateId pErrorId
;
2028 bool bNeedRefresh
= false;
2029 for (size_t i
= 0, n
= aSpans
.size(); i
< n
&& !pErrorId
; ++i
)
2031 SCCOLROW nStart
= aSpans
[i
].mnStart
;
2032 SCCOLROW nEnd
= aSpans
[i
].mnEnd
;
2034 SCCOL nStartCol
, nEndCol
;
2035 SCROW nStartRow
, nEndRow
;
2039 nEndCol
= rDoc
.MaxCol();
2040 nStartRow
= static_cast<SCROW
>(nStart
);
2041 nEndRow
= static_cast<SCROW
>(nEnd
);
2045 nStartCol
= static_cast<SCCOL
>(nStart
);
2046 nEndCol
= static_cast<SCCOL
>(nEnd
);
2048 nEndRow
= rDoc
.MaxRow();
2051 // cell protection (only needed for first range, as all following cells are moved)
2054 // test to the end of the sheet
2055 ScEditableTester
aTester( rDoc
, nTab
, nStartCol
, nStartRow
, rDoc
.MaxCol(), rDoc
.MaxRow() );
2056 if (!aTester
.IsEditable())
2057 pErrorId
= aTester
.GetMessageId();
2061 SCCOL nMergeStartX
= nStartCol
;
2062 SCROW nMergeStartY
= nStartRow
;
2063 SCCOL nMergeEndX
= nEndCol
;
2064 SCROW nMergeEndY
= nEndRow
;
2065 rDoc
.ExtendMerge( nMergeStartX
, nMergeStartY
, nMergeEndX
, nMergeEndY
, nTab
);
2066 rDoc
.ExtendOverlapped( nMergeStartX
, nMergeStartY
, nMergeEndX
, nMergeEndY
, nTab
);
2068 if ( nMergeStartX
!= nStartCol
|| nMergeStartY
!= nStartRow
)
2070 // Disallow deleting parts of a merged cell.
2071 // Deleting the start is allowed (merge is removed), so the end doesn't have to be checked.
2073 pErrorId
= STR_MSSG_DELETECELLS_0
;
2075 if ( nMergeEndX
!= nEndCol
|| nMergeEndY
!= nEndRow
)
2077 // detect if the start of a merged cell is deleted, so the merge flags can be refreshed
2079 bNeedRefresh
= true;
2085 ErrorMessage(pErrorId
);
2091 weld::WaitObject
aWait(GetViewData().GetDialogParent()); // important for TrackFormulas in UpdateReference
2093 ResetAutoSpellForContentChange();
2095 ScDocumentUniquePtr pUndoDoc
;
2096 std::unique_ptr
<ScRefUndoData
> pUndoData
;
2099 pUndoDoc
.reset(new ScDocument( SCDOCMODE_UNDO
));
2100 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, !bRows
, bRows
); // row height
2102 for (const sc::ColRowSpan
& rSpan
: aSpans
)
2104 SCCOLROW nStart
= rSpan
.mnStart
;
2105 SCCOLROW nEnd
= rSpan
.mnEnd
;
2107 rDoc
.CopyToDocument( 0,nStart
,nTab
, rDoc
.MaxCol(), nEnd
,nTab
, InsertDeleteFlags::ALL
,false,*pUndoDoc
);
2109 rDoc
.CopyToDocument( static_cast<SCCOL
>(nStart
),0,nTab
,
2110 static_cast<SCCOL
>(nEnd
), rDoc
.MaxRow(), nTab
,
2111 InsertDeleteFlags::ALL
,false,*pUndoDoc
);
2114 // all Formulas because of references
2115 SCTAB nTabCount
= rDoc
.GetTableCount();
2116 pUndoDoc
->AddUndoTab( 0, nTabCount
-1 );
2117 rDoc
.CopyToDocument( 0,0,0, rDoc
.MaxCol(), rDoc
.MaxRow(), MAXTAB
, InsertDeleteFlags::FORMULA
,false,*pUndoDoc
);
2119 pUndoData
.reset(new ScRefUndoData( &rDoc
));
2121 rDoc
.BeginDrawUndo();
2124 std::vector
<sc::ColRowSpan
>::const_reverse_iterator ri
= aSpans
.rbegin(), riEnd
= aSpans
.rend();
2125 aFuncMark
.SelectOneTable(nTab
);
2126 for (; ri
!= riEnd
; ++ri
)
2128 SCCOLROW nEnd
= ri
->mnEnd
;
2129 SCCOLROW nStart
= ri
->mnStart
;
2133 rDoc
.DeleteObjectsInArea(0, nStart
, rDoc
.MaxCol(), nEnd
, aFuncMark
, true);
2134 rDoc
.DeleteRow(0, nTab
, rDoc
.MaxCol(), nTab
, nStart
, static_cast<SCSIZE
>(nEnd
- nStart
+ 1));
2138 rDoc
.DeleteObjectsInArea(nStart
, 0, nEnd
, rDoc
.MaxRow(), aFuncMark
, true);
2139 rDoc
.DeleteCol(0, nTab
, rDoc
.MaxRow(), nTab
, static_cast<SCCOL
>(nStart
), static_cast<SCSIZE
>(nEnd
- nStart
+ 1));
2145 SCCOLROW nFirstStart
= aSpans
[0].mnStart
;
2146 SCCOL nStartCol
= bRows
? 0 : static_cast<SCCOL
>(nFirstStart
);
2147 SCROW nStartRow
= bRows
? static_cast<SCROW
>(nFirstStart
) : 0;
2148 SCCOL nEndCol
= rDoc
.MaxCol();
2149 SCROW nEndRow
= rDoc
.MaxRow();
2151 rDoc
.RemoveFlagsTab( nStartCol
, nStartRow
, nEndCol
, nEndRow
, nTab
, ScMF::Hor
| ScMF::Ver
);
2152 rDoc
.ExtendMerge( nStartCol
, nStartRow
, nEndCol
, nEndRow
, nTab
, true );
2157 pDocSh
->GetUndoManager()->AddUndoAction(
2158 std::make_unique
<ScUndoDeleteMulti
>(
2159 pDocSh
, bRows
, bNeedRefresh
, nTab
, std::vector(aSpans
), std::move(pUndoDoc
), std::move(pUndoData
)));
2162 if (!AdjustRowHeight(0, rDoc
.MaxRow(), true))
2167 0, aSpans
[0].mnStart
, nTab
,
2168 rDoc
.MaxCol(), rDoc
.MaxRow(), nTab
, (PaintPartFlags::Grid
| PaintPartFlags::Left
));
2173 static_cast<SCCOL
>(aSpans
[0].mnStart
), 0, nTab
,
2174 rDoc
.MaxCol(), rDoc
.MaxRow(), nTab
, (PaintPartFlags::Grid
| PaintPartFlags::Top
));
2178 aModificator
.SetDocumentModified();
2180 CellContentChanged();
2182 // put cursor directly behind the first deleted range
2183 SCCOL nCurX
= GetViewData().GetCurX();
2184 SCROW nCurY
= GetViewData().GetCurY();
2186 nCurY
= aSpans
[0].mnStart
;
2188 nCurX
= static_cast<SCCOL
>(aSpans
[0].mnStart
);
2189 SetCursor( nCurX
, nCurY
);
2191 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged
) );
2196 void ScViewFunc::DeleteContents( InsertDeleteFlags nFlags
)
2198 ScViewData
& rViewData
= GetViewData();
2199 rViewData
.SetPasteMode( ScPasteFlags::NONE
);
2200 rViewData
.GetViewShell()->UpdateCopySourceOverlay();
2202 // not editable because of matrix only? attribute OK nonetheless
2203 bool bOnlyNotBecauseOfMatrix
;
2204 bool bEditable
= SelectionEditable( &bOnlyNotBecauseOfMatrix
);
2207 if ( !(bOnlyNotBecauseOfMatrix
&&
2208 ((nFlags
& (InsertDeleteFlags::ATTRIB
| InsertDeleteFlags::EDITATTR
)) == nFlags
)) )
2210 ErrorMessage(bOnlyNotBecauseOfMatrix
? STR_MATRIXFRAGMENTERR
: STR_PROTECTIONERR
);
2216 bool bSimple
= false;
2218 ScDocument
& rDoc
= GetViewData().GetDocument();
2219 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
2220 ScMarkData
aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered
2221 ScViewUtil::UnmarkFiltered( aFuncMark
, rDoc
);
2224 if (!rDoc
.IsUndoEnabled())
2227 if ( !aFuncMark
.IsMarked() && !aFuncMark
.IsMultiMarked() )
2229 aMarkRange
.aStart
.SetCol(GetViewData().GetCurX());
2230 aMarkRange
.aStart
.SetRow(GetViewData().GetCurY());
2231 aMarkRange
.aStart
.SetTab(GetViewData().GetTabNo());
2232 aMarkRange
.aEnd
= aMarkRange
.aStart
;
2233 if ( rDoc
.HasAttrib( aMarkRange
, HasAttrFlags::Merged
) )
2235 aFuncMark
.SetMarkArea( aMarkRange
);
2241 HideAllCursors(); // for if summary is cancelled
2243 ScDocFunc
& rDocFunc
= pDocSh
->GetDocFunc();
2245 // Can we really be sure that we can pass the bApi parameter as false to DeleteCell() and
2246 // DeleteContents() here? (Meaning that this is interactive use.) Is this never invoked from
2247 // scripting and whatnot?
2249 rDocFunc
.DeleteCell(aMarkRange
.aStart
, aFuncMark
, nFlags
, bRecord
, /*bApi=*/ false);
2251 rDocFunc
.DeleteContents(aFuncMark
, nFlags
, bRecord
, /*bApi=*/ false);
2253 pDocSh
->UpdateOle(GetViewData());
2255 if (ScModelObj
* pModelObj
= pDocSh
->GetModel())
2257 ScRangeList aChangeRanges
;
2260 aChangeRanges
.push_back( aMarkRange
);
2264 aFuncMark
.FillRangeListWithMarks( &aChangeRanges
, false );
2267 if (HelperNotifyChanges::getMustPropagateChangesModel(pModelObj
))
2268 HelperNotifyChanges::Notify(*pModelObj
, aChangeRanges
, u
"delete-content"_ustr
);
2270 HelperNotifyChanges::Notify(*pModelObj
, aChangeRanges
, u
"data-area-invalidate"_ustr
);
2273 CellContentChanged();
2276 if ( nFlags
& InsertDeleteFlags::ATTRIB
)
2278 if ( nFlags
& InsertDeleteFlags::CONTENTS
)
2279 bFormatValid
= false;
2281 StartFormatArea(); // delete attribute is also attribute-change
2283 OUString aStartAddress
= aMarkRange
.aStart
.GetColRowString();
2284 OUString aEndAddress
= aMarkRange
.aEnd
.GetColRowString();
2285 collectUIInformation({{"RANGE", aStartAddress
+ ":" + aEndAddress
}}, u
"DELETE"_ustr
);
2288 // column width/row height (via header) - undo OK
2290 void ScViewFunc::SetWidthOrHeight(
2291 bool bWidth
, const std::vector
<sc::ColRowSpan
>& rRanges
, ScSizeMode eMode
,
2292 sal_uInt16 nSizeTwips
, bool bRecord
, const ScMarkData
* pMarkData
)
2294 if (rRanges
.empty())
2297 // Use view's mark if none specified, but do not modify the original data,
2298 // i.e. no MarkToMulti() on that.
2299 ScMarkData
aMarkData( pMarkData
? *pMarkData
: GetViewData().GetMarkData());
2301 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
2302 ScDocument
& rDoc
= pDocSh
->GetDocument();
2303 SCCOL nCurX
= GetViewData().GetCurX();
2304 SCROW nCurY
= GetViewData().GetCurY();
2305 SCTAB nFirstTab
= aMarkData
.GetFirstSelected();
2306 SCTAB nCurTab
= GetViewData().GetTabNo();
2307 if (bRecord
&& !rDoc
.IsUndoEnabled())
2310 ScDocShellModificator
aModificator( *pDocSh
);
2312 bool bAllowed
= true;
2313 for (const SCTAB
& nTab
: aMarkData
)
2315 bAllowed
= std::all_of(rRanges
.begin(), rRanges
.end(),
2316 [&bWidth
, &rDoc
, &nTab
](const sc::ColRowSpan
& rRange
) {
2318 bool bIsBlockEditable
;
2320 bIsBlockEditable
= rDoc
.IsBlockEditable(nTab
, rRange
.mnStart
, 0, rRange
.mnEnd
, rDoc
.MaxRow(), &bOnlyMatrix
);
2322 bIsBlockEditable
= rDoc
.IsBlockEditable(nTab
, 0, rRange
.mnStart
, rDoc
.MaxCol(), rRange
.mnEnd
, &bOnlyMatrix
);
2323 return bIsBlockEditable
|| bOnlyMatrix
;
2329 // Allow users to resize cols/rows in readonly docs despite the r/o state.
2330 // It is frustrating to be unable to see content in mis-sized cells.
2331 if( !bAllowed
&& !pDocSh
->IsReadOnly() )
2333 ErrorMessage(STR_PROTECTIONERR
);
2337 SCCOLROW nStart
= rRanges
.front().mnStart
;
2338 SCCOLROW nEnd
= rRanges
.back().mnEnd
;
2340 OnLOKSetWidthOrHeight(nStart
, bWidth
);
2342 bool bFormula
= false;
2343 if ( eMode
== SC_SIZE_OPTIMAL
)
2345 const ScViewOptions
& rOpts
= GetViewData().GetOptions();
2346 bFormula
= rOpts
.GetOption( VOPT_FORMULAS
);
2349 ScDocumentUniquePtr pUndoDoc
;
2350 std::unique_ptr
<ScOutlineTable
> pUndoTab
;
2351 std::vector
<sc::ColRowSpan
> aUndoRanges
;
2355 rDoc
.BeginDrawUndo(); // Drawing Updates
2357 pUndoDoc
.reset(new ScDocument( SCDOCMODE_UNDO
));
2358 for (const SCTAB
& nTab
: aMarkData
)
2362 if ( nTab
== nFirstTab
)
2363 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, true );
2365 pUndoDoc
->AddUndoTab( nTab
, nTab
, true );
2366 rDoc
.CopyToDocument( static_cast<SCCOL
>(nStart
), 0, nTab
,
2367 static_cast<SCCOL
>(nEnd
), rDoc
.MaxRow(), nTab
, InsertDeleteFlags::NONE
,
2372 if ( nTab
== nFirstTab
)
2373 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, false, true );
2375 pUndoDoc
->AddUndoTab( nTab
, nTab
, false, true );
2376 rDoc
.CopyToDocument( 0, nStart
, nTab
, rDoc
.MaxCol(), nEnd
, nTab
, InsertDeleteFlags::NONE
, false, *pUndoDoc
);
2380 aUndoRanges
= rRanges
;
2382 //! outlines from all tab?
2383 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nCurTab
);
2385 pUndoTab
.reset(new ScOutlineTable( *pTable
));
2388 if ( eMode
==SC_SIZE_OPTIMAL
|| eMode
==SC_SIZE_VISOPT
)
2389 aMarkData
.MarkToMulti();
2391 bool bShow
= nSizeTwips
> 0 || eMode
!= SC_SIZE_DIRECT
;
2392 bool bOutline
= false;
2394 for (const SCTAB
& nTab
: aMarkData
)
2396 for (const sc::ColRowSpan
& rRange
: rRanges
)
2398 SCCOLROW nStartNo
= rRange
.mnStart
;
2399 SCCOLROW nEndNo
= rRange
.mnEnd
;
2401 if ( !bWidth
) // height always blockwise
2403 if ( eMode
==SC_SIZE_OPTIMAL
|| eMode
==SC_SIZE_VISOPT
)
2405 bool bAll
= ( eMode
==SC_SIZE_OPTIMAL
);
2406 bool bFiltered
= false;
2409 // delete CRFlags::ManualSize for all in range,
2410 // then SetOptimalHeight with bShrink = FALSE
2411 for (SCROW nRow
= nStartNo
; nRow
<= nEndNo
; ++nRow
)
2413 SCROW nLastRow
= nRow
;
2414 if (rDoc
.RowHidden(nRow
, nTab
, nullptr, &nLastRow
))
2420 CRFlags nOld
= rDoc
.GetRowFlags(nRow
, nTab
);
2421 if (nOld
& CRFlags::ManualSize
)
2422 rDoc
.SetRowFlags(nRow
, nTab
, nOld
& ~CRFlags::ManualSize
);
2427 SCROW nLastRow
= nStartNo
;
2428 if (rDoc
.RowFiltered(nStartNo
, nTab
, nullptr, &nLastRow
)
2429 || nLastRow
< nEndNo
)
2434 double nPPTX
= GetViewData().GetPPTX();
2435 double nPPTY
= GetViewData().GetPPTY();
2436 Fraction aZoomX
= GetViewData().GetZoomX();
2437 Fraction aZoomY
= GetViewData().GetZoomY();
2439 ScSizeDeviceProvider
aProv(pDocSh
);
2440 if (aProv
.IsPrinter())
2442 nPPTX
= aProv
.GetPPTX();
2443 nPPTY
= aProv
.GetPPTY();
2444 aZoomX
= aZoomY
= Fraction( 1, 1 );
2447 sc::RowHeightContext
aCxt(rDoc
.MaxRow(), nPPTX
, nPPTY
, aZoomX
, aZoomY
, aProv
.GetDevice());
2448 aCxt
.setForceAutoSize(bAll
);
2449 aCxt
.setExtraHeight(nSizeTwips
);
2450 rDoc
.SetOptimalHeight(aCxt
, nStartNo
, nEndNo
, nTab
, true);
2453 ShowFilteredRows(rDoc
, nTab
, nStartNo
, nEndNo
, bShow
);
2455 // Manual-Flag already (re)set in SetOptimalHeight in case of bAll=sal_True
2456 // (set for Extra-Height, else reset).
2458 else if ( eMode
==SC_SIZE_DIRECT
)
2462 rDoc
.SetRowHeightRange( nStartNo
, nEndNo
, nTab
, nSizeTwips
);
2463 rDoc
.SetManualHeight( nStartNo
, nEndNo
, nTab
, true ); // height was set manually
2466 // tdf#36383 - Skip consecutive rows hidden by AutoFilter
2467 ShowFilteredRows(rDoc
, nTab
, nStartNo
, nEndNo
, nSizeTwips
!= 0);
2469 if (!bShow
&& nStartNo
<= nCurY
&& nCurY
<= nEndNo
&& nTab
== nCurTab
)
2474 else if ( eMode
==SC_SIZE_SHOW
)
2476 rDoc
.ShowRows( nStartNo
, nEndNo
, nTab
, true );
2479 else // column width
2481 for (SCCOL nCol
=static_cast<SCCOL
>(nStartNo
); nCol
<=static_cast<SCCOL
>(nEndNo
); nCol
++)
2483 const bool bIsColHidden
= rDoc
.ColHidden(nCol
, nTab
);
2484 if ( eMode
!= SC_SIZE_VISOPT
|| !bIsColHidden
)
2486 sal_uInt16 nThisSize
= nSizeTwips
;
2488 if ( eMode
==SC_SIZE_OPTIMAL
|| eMode
==SC_SIZE_VISOPT
)
2489 nThisSize
= nSizeTwips
+ GetOptimalColWidth( nCol
, nTab
, bFormula
);
2491 rDoc
.SetColWidth( nCol
, nTab
, nThisSize
);
2493 // tdf#131073 - Don't show hidden cols after setting optimal col width
2494 if (eMode
== SC_SIZE_OPTIMAL
)
2495 rDoc
.ShowCol(nCol
, nTab
, !bIsColHidden
);
2497 rDoc
.ShowCol( nCol
, nTab
, bShow
);
2499 if (!bShow
&& nCol
== nCurX
&& nTab
== nCurTab
)
2510 if ( rDoc
.UpdateOutlineCol( static_cast<SCCOL
>(nStartNo
),
2511 static_cast<SCCOL
>(nEndNo
), nTab
, bShow
) )
2516 if ( rDoc
.UpdateOutlineRow( nStartNo
, nEndNo
, nTab
, bShow
) )
2520 rDoc
.SetDrawPageSize(nTab
);
2528 pDocSh
->GetUndoManager()->AddUndoAction(
2529 std::make_unique
<ScUndoWidthOrHeight
>(
2530 pDocSh
, aMarkData
, nStart
, nCurTab
, nEnd
, nCurTab
,
2531 std::move(pUndoDoc
), std::move(aUndoRanges
), std::move(pUndoTab
), eMode
, nSizeTwips
, bWidth
));
2536 MoveCursorRel( 1, 0, SC_FOLLOW_LINE
, false );
2541 MoveCursorRel( 0, 1, SC_FOLLOW_LINE
, false );
2544 // fdo#36247 Ensure that the drawing layer's map mode scaling factors match
2545 // the new heights and widths.
2546 GetViewData().GetView()->RefreshZoom();
2548 for (const SCTAB
& nTab
: aMarkData
)
2549 rDoc
.UpdatePageBreaks( nTab
);
2551 bool bAffectsVisibility
= (eMode
!= SC_SIZE_ORIGINAL
&& eMode
!= SC_SIZE_VISOPT
);
2552 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
2553 bWidth
/* bColumns */, !bWidth
/* bRows */,
2554 true /* bSizes*/, bAffectsVisibility
/* bHidden */, bAffectsVisibility
/* bFiltered */,
2555 false /* bGroups */, nCurTab
);
2556 GetViewData().GetView()->UpdateScrollBars(bWidth
? COLUMN_HEADER
: ROW_HEADER
);
2559 for (const SCTAB
& nTab
: aMarkData
)
2563 if (rDoc
.HasAttrib( static_cast<SCCOL
>(nStart
),0,nTab
,
2564 static_cast<SCCOL
>(nEnd
), rDoc
.MaxRow(), nTab
,
2565 HasAttrFlags::Merged
| HasAttrFlags::Overlapped
))
2567 if (nStart
> 0) // go upwards because of Lines and cursor
2569 pDocSh
->PostPaint( static_cast<SCCOL
>(nStart
), 0, nTab
,
2570 rDoc
.MaxCol(), rDoc
.MaxRow(), nTab
, PaintPartFlags::Grid
| PaintPartFlags::Top
);
2574 if (rDoc
.HasAttrib( 0,nStart
,nTab
, rDoc
.MaxCol(), nEnd
,nTab
, HasAttrFlags::Merged
| HasAttrFlags::Overlapped
))
2578 pDocSh
->PostPaint( 0, nStart
, nTab
, rDoc
.MaxCol(), rDoc
.MaxRow(), nTab
, PaintPartFlags::Grid
| PaintPartFlags::Left
);
2582 pDocSh
->UpdateOle(GetViewData());
2583 if( !pDocSh
->IsReadOnly() )
2584 aModificator
.SetDocumentModified();
2590 ScModelObj
* pModelObj
= pDocSh
->GetModel();
2592 if (!HelperNotifyChanges::getMustPropagateChangesModel(pModelObj
))
2595 ScRangeList aChangeRanges
;
2596 for (const SCTAB
& nTab
: aMarkData
)
2598 for (const sc::ColRowSpan
& rRange
: rRanges
)
2600 SCCOL nStartCol
= rRange
.mnStart
;
2601 SCCOL nEndCol
= rRange
.mnEnd
;
2602 for ( SCCOL nCol
= nStartCol
; nCol
<= nEndCol
; ++nCol
)
2604 aChangeRanges
.push_back( ScRange( nCol
, 0, nTab
) );
2608 HelperNotifyChanges::Notify(*pModelObj
, aChangeRanges
, u
"column-resize"_ustr
);
2611 // column width/row height (via marked range)
2613 void ScViewFunc::SetMarkedWidthOrHeight( bool bWidth
, ScSizeMode eMode
, sal_uInt16 nSizeTwips
)
2615 ScMarkData
& rMark
= GetViewData().GetMarkData();
2617 rMark
.MarkToMulti();
2618 if (!rMark
.IsMultiMarked())
2620 SCCOL nCol
= GetViewData().GetCurX();
2621 SCROW nRow
= GetViewData().GetCurY();
2622 SCTAB nTab
= GetViewData().GetTabNo();
2623 const ScRange
aMarkRange( nCol
, nRow
, nTab
);
2625 InitOwnBlockMode( aMarkRange
);
2626 rMark
.SetMultiMarkArea( aMarkRange
);
2630 std::vector
<sc::ColRowSpan
> aRanges
=
2631 bWidth
? rMark
.GetMarkedColSpans() : rMark
.GetMarkedRowSpans();
2633 SetWidthOrHeight(bWidth
, aRanges
, eMode
, nSizeTwips
);
2635 rMark
.MarkToSimple();
2638 void ScViewFunc::ModifyCellSize( ScDirection eDir
, bool bOptimal
)
2640 ScModule
* pScMod
= ScModule::get();
2641 bool bAnyEdit
= pScMod
->IsInputMode();
2642 SCCOL nCol
= GetViewData().GetCurX();
2643 SCROW nRow
= GetViewData().GetCurY();
2644 SCTAB nTab
= GetViewData().GetTabNo();
2645 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
2646 ScDocument
& rDoc
= pDocSh
->GetDocument();
2648 bool bAllowed
, bOnlyMatrix
;
2649 if ( eDir
== DIR_LEFT
|| eDir
== DIR_RIGHT
)
2650 bAllowed
= rDoc
.IsBlockEditable( nTab
, nCol
,0, nCol
,rDoc
.MaxRow(), &bOnlyMatrix
);
2652 bAllowed
= rDoc
.IsBlockEditable( nTab
, 0,nRow
, rDoc
.MaxCol(), nRow
, &bOnlyMatrix
);
2653 if ( !bAllowed
&& !bOnlyMatrix
)
2655 ErrorMessage(STR_PROTECTIONERR
);
2661 //! step size adjustable
2662 // step size is also minimum
2663 constexpr sal_uInt16 nStepX
= STD_COL_WIDTH
/ 5;
2664 const sal_uInt16 nStepY
= rDoc
.GetSheetOptimalMinRowHeight(nTab
);
2666 sal_uInt16 nWidth
= rDoc
.GetColWidth( nCol
, nTab
);
2667 sal_uInt16 nHeight
= rDoc
.GetRowHeight( nRow
, nTab
);
2668 std::vector
<sc::ColRowSpan
> aRange(1, sc::ColRowSpan(0,0));
2669 if ( eDir
== DIR_LEFT
|| eDir
== DIR_RIGHT
)
2671 if (bOptimal
) // width of this single cell
2675 // when editing the actual entered width
2676 ScInputHandler
* pHdl
= pScMod
->GetInputHdl( GetViewData().GetViewShell() );
2679 tools::Long nEdit
= pHdl
->GetTextSize().Width(); // in 0.01 mm
2681 const ScPatternAttr
* pPattern
= rDoc
.GetPattern( nCol
, nRow
, nTab
);
2682 const SvxMarginItem
& rMItem
= pPattern
->GetItem(ATTR_MARGIN
);
2683 sal_uInt16 nMargin
= rMItem
.GetLeftMargin() + rMItem
.GetRightMargin();
2684 if ( pPattern
->GetItem( ATTR_HOR_JUSTIFY
).GetValue() == SvxCellHorJustify::Left
)
2685 nMargin
= sal::static_int_cast
<sal_uInt16
>(
2686 nMargin
+ pPattern
->GetItem(ATTR_INDENT
).GetValue() );
2688 nWidth
= std::round(o3tl::convert(nEdit
* pDocSh
->GetOutputFactor(),
2689 o3tl::Length::mm100
, o3tl::Length::twip
))
2690 + nMargin
+ STD_EXTRA_WIDTH
;
2695 double nPPTX
= GetViewData().GetPPTX();
2696 double nPPTY
= GetViewData().GetPPTY();
2697 Fraction aZoomX
= GetViewData().GetZoomX();
2698 Fraction aZoomY
= GetViewData().GetZoomY();
2700 ScSizeDeviceProvider
aProv(pDocSh
);
2701 if (aProv
.IsPrinter())
2703 nPPTX
= aProv
.GetPPTX();
2704 nPPTY
= aProv
.GetPPTY();
2705 aZoomX
= aZoomY
= Fraction( 1, 1 );
2708 tools::Long nPixel
= rDoc
.GetNeededSize( nCol
, nRow
, nTab
, aProv
.GetDevice(),
2709 nPPTX
, nPPTY
, aZoomX
, aZoomY
, true );
2710 sal_uInt16 nTwips
= static_cast<sal_uInt16
>( nPixel
/ nPPTX
);
2712 nWidth
= nTwips
+ STD_EXTRA_WIDTH
;
2714 nWidth
= STD_COL_WIDTH
;
2717 else // increment / decrement
2719 if ( eDir
== DIR_RIGHT
)
2720 nWidth
= sal::static_int_cast
<sal_uInt16
>( nWidth
+ nStepX
);
2721 else if ( nWidth
> nStepX
)
2722 nWidth
= sal::static_int_cast
<sal_uInt16
>( nWidth
- nStepX
);
2723 if ( nWidth
< nStepX
) nWidth
= nStepX
;
2724 if ( nWidth
> MAX_COL_WIDTH
) nWidth
= MAX_COL_WIDTH
;
2726 aRange
[0].mnStart
= nCol
;
2727 aRange
[0].mnEnd
= nCol
;
2728 SetWidthOrHeight(true, aRange
, SC_SIZE_DIRECT
, nWidth
);
2730 // adjust height of this row if width demands/allows this
2734 const ScPatternAttr
* pPattern
= rDoc
.GetPattern( nCol
, nRow
, nTab
);
2736 pPattern
->GetItem( ATTR_LINEBREAK
).GetValue() ||
2737 pPattern
->GetItem( ATTR_HOR_JUSTIFY
).GetValue() == SvxCellHorJustify::Block
;
2739 AdjustRowHeight( nRow
, nRow
, true );
2747 eMode
= SC_SIZE_OPTIMAL
;
2752 eMode
= SC_SIZE_DIRECT
;
2753 if ( eDir
== DIR_BOTTOM
)
2754 nHeight
= sal::static_int_cast
<sal_uInt16
>( nHeight
+ nStepY
);
2755 else if ( nHeight
> nStepY
)
2756 nHeight
= sal::static_int_cast
<sal_uInt16
>( nHeight
- nStepY
);
2757 if ( nHeight
< nStepY
) nHeight
= nStepY
;
2758 if ( nHeight
> MAX_ROW_HEIGHT
) nHeight
= MAX_ROW_HEIGHT
;
2760 aRange
[0].mnStart
= nRow
;
2761 aRange
[0].mnEnd
= nRow
;
2762 SetWidthOrHeight(false, aRange
, eMode
, nHeight
);
2768 if ( rDoc
.HasAttrib( nCol
, nRow
, nTab
, nCol
, nRow
, nTab
, HasAttrFlags::NeedHeight
) )
2770 ScInputHandler
* pHdl
= pScMod
->GetInputHdl( GetViewData().GetViewShell() );
2772 pHdl
->SetModified(); // so that the height is adjusted with Enter
2779 void ScViewFunc::ProtectSheet( SCTAB nTab
, const ScTableProtection
& rProtect
)
2781 if (nTab
== TABLEID_DOC
)
2784 ScMarkData
& rMark
= GetViewData().GetMarkData();
2785 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
2786 ScDocument
& rDoc
= pDocSh
->GetDocument();
2787 ScDocFunc
&rFunc
= pDocSh
->GetDocFunc();
2788 bool bUndo(rDoc
.IsUndoEnabled());
2790 // modifying several tabs is handled here
2794 OUString aUndo
= ScResId( STR_UNDO_PROTECT_TAB
);
2795 pDocSh
->GetUndoManager()->EnterListAction( aUndo
, aUndo
, 0, GetViewData().GetViewShell()->GetViewShellId() );
2798 for (const auto& rTab
: rMark
)
2800 rFunc
.ProtectSheet(rTab
, rProtect
);
2804 pDocSh
->GetUndoManager()->LeaveListAction();
2806 UpdateLayerLocks(); //! broadcast to all views
2809 void ScViewFunc::ProtectDoc( const OUString
& rPassword
)
2811 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
2812 ScDocFunc
&rFunc
= pDocSh
->GetDocFunc();
2814 rFunc
.Protect( TABLEID_DOC
, rPassword
);
2816 UpdateLayerLocks(); //! broadcast to all views
2819 bool ScViewFunc::Unprotect( SCTAB nTab
, const OUString
& rPassword
)
2821 ScMarkData
& rMark
= GetViewData().GetMarkData();
2822 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
2823 ScDocument
& rDoc
= pDocSh
->GetDocument();
2824 ScDocFunc
&rFunc
= pDocSh
->GetDocFunc();
2825 bool bChanged
= false;
2826 bool bUndo (rDoc
.IsUndoEnabled());
2828 if ( nTab
== TABLEID_DOC
|| rMark
.GetSelectCount() <= 1 )
2830 bChanged
= rFunc
.Unprotect( nTab
, rPassword
, false );
2831 if (bChanged
&& nTab
!= TABLEID_DOC
)
2832 SetTabProtectionSymbol(nTab
, false);
2836 // modifying several tabs is handled here
2840 OUString aUndo
= ScResId( STR_UNDO_UNPROTECT_TAB
);
2841 pDocSh
->GetUndoManager()->EnterListAction( aUndo
, aUndo
, 0, GetViewData().GetViewShell()->GetViewShellId() );
2844 for (const auto& rTab
: rMark
)
2846 if ( rFunc
.Unprotect( rTab
, rPassword
, false ) )
2849 SetTabProtectionSymbol( rTab
, false);
2854 pDocSh
->GetUndoManager()->LeaveListAction();
2858 UpdateLayerLocks(); //! broadcast to all views
2863 void ScViewFunc::SetNoteText( const ScAddress
& rPos
, const OUString
& rNoteText
)
2865 GetViewData().GetDocShell()->GetDocFunc().SetNoteText( rPos
, rNoteText
, false );
2868 void ScViewFunc::ReplaceNote( const ScAddress
& rPos
, const OUString
& rNoteText
, const OUString
* pAuthor
, const OUString
* pDate
)
2870 GetViewData().GetDocShell()->GetDocFunc().ReplaceNote( rPos
, rNoteText
, pAuthor
, pDate
, false );
2873 void ScViewFunc::SetNumberFormat( SvNumFormatType nFormatType
, sal_uLong nAdd
)
2875 // not editable because of matrix only? attribute OK nonetheless
2876 bool bOnlyNotBecauseOfMatrix
;
2877 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix
) && !bOnlyNotBecauseOfMatrix
)
2879 ErrorMessage(STR_PROTECTIONERR
);
2883 sal_uInt32 nNumberFormat
= 0;
2884 ScViewData
& rViewData
= GetViewData();
2885 ScDocument
& rDoc
= rViewData
.GetDocument();
2886 SvNumberFormatter
* pNumberFormatter
= rDoc
.GetFormatTable();
2887 LanguageType eLanguage
= ScGlobal::eLnge
;
2888 ScPatternAttr
aNewAttrs(rDoc
.getCellAttributeHelper());
2890 // always take language from cursor position, even if there is a selection
2892 sal_uInt32 nCurrentNumberFormat
= rDoc
.GetNumberFormat( rViewData
.GetCurX(),
2893 rViewData
.GetCurY(),
2894 rViewData
.GetTabNo());
2895 const SvNumberformat
* pEntry
= pNumberFormatter
->GetEntry( nCurrentNumberFormat
);
2897 eLanguage
= pEntry
->GetLanguage(); // else keep ScGlobal::eLnge
2899 nNumberFormat
= pNumberFormatter
->GetStandardFormat( nFormatType
, eLanguage
) + nAdd
;
2901 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
2902 rSet
.Put( SfxUInt32Item( ATTR_VALUE_FORMAT
, nNumberFormat
) );
2903 // ATTR_LANGUAGE_FORMAT not
2904 ApplySelectionPattern( aNewAttrs
);
2907 void ScViewFunc::SetNumFmtByStr( const OUString
& rCode
)
2909 // not editable because of matrix only? attribute OK nonetheless
2910 bool bOnlyNotBecauseOfMatrix
;
2911 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix
) && !bOnlyNotBecauseOfMatrix
)
2913 ErrorMessage(STR_PROTECTIONERR
);
2917 ScViewData
& rViewData
= GetViewData();
2918 ScDocument
& rDoc
= rViewData
.GetDocument();
2919 SvNumberFormatter
* pFormatter
= rDoc
.GetFormatTable();
2921 // language always from cursor position
2923 sal_uInt32 nCurrentNumberFormat
= rDoc
.GetNumberFormat( rViewData
.GetCurX(), rViewData
.GetCurY(),
2924 rViewData
.GetTabNo());
2925 const SvNumberformat
* pEntry
= pFormatter
->GetEntry( nCurrentNumberFormat
);
2926 LanguageType eLanguage
= pEntry
? pEntry
->GetLanguage() : ScGlobal::eLnge
;
2928 // determine index for String
2931 sal_uInt32 nNumberFormat
= pFormatter
->GetEntryKey( rCode
, eLanguage
);
2932 if ( nNumberFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
2936 OUString aFormat
= rCode
; // will be changed
2937 sal_Int32 nErrPos
= 0;
2938 SvNumFormatType nType
= SvNumFormatType::ALL
; //! ???
2939 bOk
= pFormatter
->PutEntry( aFormat
, nErrPos
, nType
, nNumberFormat
, eLanguage
);
2942 if ( bOk
) // valid format?
2944 ScPatternAttr
aNewAttrs(rDoc
.getCellAttributeHelper());
2945 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
2946 rSet
.Put( SfxUInt32Item( ATTR_VALUE_FORMAT
, nNumberFormat
) );
2947 rSet
.Put( SvxLanguageItem( eLanguage
, ATTR_LANGUAGE_FORMAT
) );
2948 ApplySelectionPattern( aNewAttrs
);
2951 //! else return error / issue warning ???
2954 void ScViewFunc::ChangeNumFmtDecimals( bool bIncrement
)
2956 // not editable because of matrix only? attribute OK nonetheless
2957 bool bOnlyNotBecauseOfMatrix
;
2958 if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix
) && !bOnlyNotBecauseOfMatrix
)
2960 ErrorMessage(STR_PROTECTIONERR
);
2964 ScDocument
& rDoc
= GetViewData().GetDocument();
2965 SvNumberFormatter
* pFormatter
= rDoc
.GetFormatTable();
2967 SCCOL nCol
= GetViewData().GetCurX();
2968 SCROW nRow
= GetViewData().GetCurY();
2969 SCTAB nTab
= GetViewData().GetTabNo();
2971 sal_uInt32 nOldFormat
= rDoc
.GetNumberFormat( nCol
, nRow
, nTab
);
2972 const SvNumberformat
* pOldEntry
= pFormatter
->GetEntry( nOldFormat
);
2975 OSL_FAIL("numberformat not found !!!");
2979 // what have we got here?
2981 sal_uInt32 nNewFormat
= nOldFormat
;
2982 bool bError
= false;
2984 LanguageType eLanguage
= pOldEntry
->GetLanguage();
2985 bool bThousand
, bNegRed
;
2986 sal_uInt16 nPrecision
, nLeading
;
2987 pOldEntry
->GetFormatSpecialInfo( bThousand
, bNegRed
, nPrecision
, nLeading
);
2989 SvNumFormatType nOldType
= pOldEntry
->GetType();
2990 if ( SvNumFormatType::ALL
== ( nOldType
& (
2991 SvNumFormatType::NUMBER
| SvNumFormatType::CURRENCY
| SvNumFormatType::PERCENT
| SvNumFormatType::SCIENTIFIC
| SvNumFormatType::TIME
) ) )
2993 // date, fraction, logical, text can not be changed
2997 //! SvNumberformat has a Member bStandard, but doesn't disclose it
2998 bool bWasStandard
= ( nOldFormat
== pFormatter
->GetStandardIndex( eLanguage
) );
2999 OUString sExponentialStandardFormat
= u
""_ustr
;
3002 // with "Standard" the decimal places depend on cell content
3003 // 0 if empty or text -> no decimal places
3004 double nVal
= rDoc
.GetValue( ScAddress( nCol
, nRow
, nTab
) );
3006 // the ways of the Numberformatters are unfathomable, so try:
3009 pOldEntry
->GetOutputString( nVal
, aOut
, &pCol
, pFormatter
->GetNatNum(), pFormatter
->GetROLanguageData() );
3012 // 'E' for exponential is fixed in Numberformatter
3013 sal_Int32 nIndexE
= aOut
.indexOf('E');
3016 sExponentialStandardFormat
= aOut
.copy( nIndexE
).replace( '-', '+' );
3017 for ( sal_Int32 i
=1 ; i
<sExponentialStandardFormat
.getLength() ; i
++ )
3019 if ( sExponentialStandardFormat
[i
] >= '1' && sExponentialStandardFormat
[i
] <= '9' )
3020 sExponentialStandardFormat
= sExponentialStandardFormat
.replaceAt( i
, 1, u
"0" );
3022 aOut
= aOut
.copy( 0, nIndexE
); // remove exponential part
3024 OUString
aDecSep( pFormatter
->GetFormatDecimalSep( nOldFormat
) );
3025 sal_Int32 nPos
= aOut
.indexOf( aDecSep
);
3027 nPrecision
= aOut
.getLength() - nPos
- aDecSep
.getLength();
3032 if ( (nOldType
& SvNumFormatType::SCIENTIFIC
) && !bThousand
&&
3033 (pOldEntry
->GetFormatIntegerDigits()%3 == 0) && pOldEntry
->GetFormatIntegerDigits() > 0 )
3042 ++nPrecision
; // increment
3044 bError
= true; // 20 is maximum
3049 --nPrecision
; // decrement
3051 bError
= true; // 0 is minimum
3057 OUString aNewPicture
= pFormatter
->GenerateFormat(nOldFormat
, eLanguage
,
3059 nPrecision
, nLeading
)
3060 + sExponentialStandardFormat
;
3062 nNewFormat
= pFormatter
->GetEntryKey( aNewPicture
, eLanguage
);
3063 if ( nNewFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
3065 sal_Int32 nErrPos
= 0;
3066 SvNumFormatType nNewType
= SvNumFormatType::ALL
;
3067 bool bOk
= pFormatter
->PutEntry( aNewPicture
, nErrPos
,
3068 nNewType
, nNewFormat
, eLanguage
);
3069 OSL_ENSURE( bOk
, "incorrect numberformat generated" );
3077 ScPatternAttr
aNewAttrs(rDoc
.getCellAttributeHelper());
3078 SfxItemSet
& rSet
= aNewAttrs
.GetItemSet();
3079 rSet
.Put( SfxUInt32Item( ATTR_VALUE_FORMAT
, nNewFormat
) );
3080 // ATTR_LANGUAGE_FORMAT not
3081 ApplySelectionPattern( aNewAttrs
);
3085 void ScViewFunc::ChangeIndent( bool bIncrement
)
3087 ScViewData
& rViewData
= GetViewData();
3088 ScDocShell
* pDocSh
= rViewData
.GetDocShell();
3089 ScMarkData
& rMark
= rViewData
.GetMarkData();
3091 ScMarkData aWorkMark
= rMark
;
3092 ScViewUtil::UnmarkFiltered( aWorkMark
, pDocSh
->GetDocument() );
3093 aWorkMark
.MarkToMulti();
3094 if (!aWorkMark
.IsMultiMarked())
3096 SCCOL nCol
= rViewData
.GetCurX();
3097 SCROW nRow
= rViewData
.GetCurY();
3098 SCTAB nTab
= rViewData
.GetTabNo();
3099 aWorkMark
.SetMultiMarkArea( ScRange(nCol
,nRow
,nTab
) );
3102 bool bSuccess
= pDocSh
->GetDocFunc().ChangeIndent( aWorkMark
, bIncrement
, false );
3105 pDocSh
->UpdateOle(rViewData
);
3108 // stuff for sidebar panels
3109 SfxBindings
& rBindings
= GetViewData().GetBindings();
3110 rBindings
.Invalidate( SID_H_ALIGNCELL
);
3111 rBindings
.Invalidate( SID_ATTR_ALIGN_INDENT
);
3115 bool ScViewFunc::InsertName( const OUString
& rName
, const OUString
& rSymbol
,
3116 const OUString
& rType
)
3118 // Type = P,R,C,F (and combinations)
3122 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
3123 ScDocument
& rDoc
= pDocSh
->GetDocument();
3124 SCTAB nTab
= GetViewData().GetTabNo();
3125 ScRangeName
* pList
= rDoc
.GetRangeName();
3127 ScRangeData::Type nType
= ScRangeData::Type::Name
;
3128 auto pNewEntry
= std::make_unique
<ScRangeData
>(
3129 rDoc
, rName
, rSymbol
, ScAddress( GetViewData().GetCurX(),
3130 GetViewData().GetCurY(), nTab
), nType
);
3131 OUString aUpType
= rType
.toAsciiUpperCase();
3132 if ( aUpType
.indexOf( 'P' ) != -1 )
3133 nType
|= ScRangeData::Type::PrintArea
;
3134 if ( aUpType
.indexOf( 'R' ) != -1 )
3135 nType
|= ScRangeData::Type::RowHeader
;
3136 if ( aUpType
.indexOf( 'C' ) != -1 )
3137 nType
|= ScRangeData::Type::ColHeader
;
3138 if ( aUpType
.indexOf( 'F' ) != -1 )
3139 nType
|= ScRangeData::Type::Criteria
;
3140 pNewEntry
->AddType(nType
);
3142 if ( pNewEntry
->GetErrCode() == FormulaError::NONE
) // text valid?
3144 ScDocShellModificator
aModificator( *pDocSh
);
3146 rDoc
.PreprocessRangeNameUpdate();
3148 // input available yet? Then remove beforehand (=change)
3149 ScRangeData
* pData
= pList
->findByUpperName(ScGlobal::getCharClass().uppercase(rName
));
3152 pNewEntry
->SetIndex(pData
->GetIndex());
3153 pList
->erase(*pData
);
3156 // don't delete, insert took ownership, even on failure!
3157 if ( pList
->insert( pNewEntry
.release() ) )
3160 rDoc
.CompileHybridFormula();
3162 aModificator
.SetDocumentModified();
3163 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged
) );
3169 void ScViewFunc::CreateNames( CreateNameFlags nFlags
)
3173 if ( GetViewData().GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
3174 bDone
= GetViewData().GetDocShell()->GetDocFunc().CreateNames( aRange
, nFlags
, false );
3177 ErrorMessage(STR_CREATENAME_MARKERR
);
3180 CreateNameFlags
ScViewFunc::GetCreateNameFlags()
3182 CreateNameFlags nFlags
= CreateNameFlags::NONE
;
3184 SCCOL nStartCol
, nEndCol
;
3185 SCROW nStartRow
, nEndRow
;
3187 if (GetViewData().GetSimpleArea(nStartCol
,nStartRow
,nDummy
,nEndCol
,nEndRow
,nDummy
) == SC_MARK_SIMPLE
)
3189 ScDocument
& rDoc
= GetViewData().GetDocument();
3190 SCTAB nTab
= GetViewData().GetTabNo();
3196 SCCOL nFirstCol
= nStartCol
;
3197 SCCOL nLastCol
= nEndCol
;
3198 if (nStartCol
+1 < nEndCol
) { ++nFirstCol
; --nLastCol
; }
3199 for (i
=nFirstCol
; i
<=nLastCol
&& bOk
; i
++)
3200 if (!rDoc
.HasStringData( i
,nStartRow
,nTab
))
3203 nFlags
|= CreateNameFlags::Top
;
3204 else // Bottom only if not Top
3207 for (i
=nFirstCol
; i
<=nLastCol
&& bOk
; i
++)
3208 if (!rDoc
.HasStringData( i
,nEndRow
,nTab
))
3211 nFlags
|= CreateNameFlags::Bottom
;
3215 SCROW nFirstRow
= nStartRow
;
3216 SCROW nLastRow
= nEndRow
;
3217 if (nStartRow
+1 < nEndRow
) { ++nFirstRow
; --nLastRow
; }
3218 for (j
=nFirstRow
; j
<=nLastRow
&& bOk
; j
++)
3219 if (!rDoc
.HasStringData( nStartCol
,j
,nTab
))
3222 nFlags
|= CreateNameFlags::Left
;
3223 else // Right only if not Left
3226 for (j
=nFirstRow
; j
<=nLastRow
&& bOk
; j
++)
3227 if (!rDoc
.HasStringData( nEndCol
,j
,nTab
))
3230 nFlags
|= CreateNameFlags::Right
;
3234 if (nStartCol
== nEndCol
)
3235 nFlags
&= ~CreateNameFlags( CreateNameFlags::Left
| CreateNameFlags::Right
);
3236 if (nStartRow
== nEndRow
)
3237 nFlags
&= ~CreateNameFlags( CreateNameFlags::Top
| CreateNameFlags::Bottom
);
3242 void ScViewFunc::InsertNameList()
3244 ScAddress
aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
3245 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
3246 if ( pDocSh
->GetDocFunc().InsertNameList( aPos
, false ) )
3247 pDocSh
->UpdateOle(GetViewData());
3250 void ScViewFunc::UpdateSelectionArea( const ScMarkData
& rSel
, ScPatternAttr
* pAttr
)
3252 ScDocShell
* pDocShell
= GetViewData().GetDocShell();
3254 if (rSel
.IsMultiMarked() )
3255 aMarkRange
= rSel
.GetMultiMarkArea();
3257 aMarkRange
= rSel
.GetMarkArea();
3259 bool bSetLines
= false;
3260 bool bSetAlign
= false;
3263 const SfxItemSet
& rNewSet
= pAttr
->GetItemSet();
3264 bSetLines
= rNewSet
.GetItemState( ATTR_BORDER
) == SfxItemState::SET
||
3265 rNewSet
.GetItemState( ATTR_SHADOW
) == SfxItemState::SET
;
3266 bSetAlign
= rNewSet
.GetItemState( ATTR_HOR_JUSTIFY
) == SfxItemState::SET
;
3269 sal_uInt16 nExtFlags
= 0;
3271 nExtFlags
|= SC_PF_LINES
;
3273 nExtFlags
|= SC_PF_WHOLEROWS
;
3275 SCCOL nStartCol
= aMarkRange
.aStart
.Col();
3276 SCROW nStartRow
= aMarkRange
.aStart
.Row();
3277 SCTAB nStartTab
= aMarkRange
.aStart
.Tab();
3278 SCCOL nEndCol
= aMarkRange
.aEnd
.Col();
3279 SCROW nEndRow
= aMarkRange
.aEnd
.Row();
3280 SCTAB nEndTab
= aMarkRange
.aEnd
.Tab();
3281 pDocShell
->PostPaint( nStartCol
, nStartRow
, nStartTab
,
3282 nEndCol
, nEndRow
, nEndTab
,
3283 PaintPartFlags::Grid
, nExtFlags
| SC_PF_TESTMERGE
);
3284 ScTabViewShell
* pTabViewShell
= GetViewData().GetViewShell();
3285 pTabViewShell
->AdjustBlockHeight(false, const_cast<ScMarkData
*>(&rSel
));
3288 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */