include/svl/zformat.hxx | 4 + sc/inc/listenercalls.hxx | 6 +- sc/source/core/data/documen4.cxx | 23 +++------ sc/source/core/data/table2.cxx | 18 +++++-- sc/source/ui/app/inputhdl.cxx | 20 ++++++-- sc/source/ui/inc/inputhdl.hxx | 2 sc/source/ui/unoobj/cellsuno.cxx | 4 + sc/source/ui/unoobj/listenercalls.cxx | 2 sc/source/ui/vba/vbarange.cxx | 81 +++++++++++++++++++++------------- sc/source/ui/vba/vbarange.hxx | 3 + svl/source/numbers/zforlist.cxx | 17 +++---- svl/source/numbers/zformat.cxx | 28 +++++++++++ xmloff/source/style/xmlnumfe.cxx | 31 +++++++++++++ xmloff/source/style/xmlnumfi.cxx | 24 +++++----- 14 files changed, 186 insertions(+), 77 deletions(-)
New commits: commit c649ad711ec48d08b0761f420f4584768c82eb74 Author: Eike Rathke <er...@redhat.com> AuthorDate: Tue Jun 21 09:49:31 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Jun 27 13:30:25 2022 +0200 Resolves: tdf#149589 No "+ or - may start formula" when editing content If it was a formula already it would start with = anyway. Change-Id: Ib3c0ebcaf99231d387f1aace8e1a5642061de3a0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136208 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit 909cdd552199d35f7c10be0a8be370158aea0815) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136173 Tested-by: Eike Rathke <er...@redhat.com> Reviewed-by: Caolán McNamara <caol...@redhat.com> diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx index d1a2fea3d482..e2343e052cfe 100644 --- a/sc/source/ui/app/inputhdl.cxx +++ b/sc/source/ui/app/inputhdl.cxx @@ -831,6 +831,7 @@ ScInputHandler::ScInputHandler() bLastIsSymbol( false ), mbDocumentDisposing(false), mbPartialPrefix(false), + mbEditingExistingContent(false), nValidation( 0 ), eAttrAdjust( SvxCellHorJustify::Standard ), aScaleX( 1,1 ), @@ -1769,6 +1770,9 @@ void ScInputHandler::LOKPasteFunctionData(const OUString& rFunctionName) if (pEditEngine) { aFormula = pEditEngine->GetText(0); + /* TODO: LOK: are you sure you want '+' and '-' let start formulas with + * function names? That was meant for "data typist" numeric keyboard + * input. */ bEdit = aFormula.getLength() > 1 && (aFormula[0] == '=' || aFormula[0] == '+' || aFormula[0] == '-'); } @@ -2575,6 +2579,7 @@ bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bIn } else aStr = GetEditText(mpEditEngine.get()); + mbEditingExistingContent = !aStr.isEmpty(); if (aStr.startsWith("{=") && aStr.endsWith("}") ) // Matrix formula? { @@ -2589,8 +2594,7 @@ bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bIn if ( bAutoComplete ) GetColData(); - if ( !aStr.isEmpty() && ( aStr[0] == '=' || aStr[0] == '+' || aStr[0] == '-' ) && - !cTyped && !bCreatingFuncView ) + if (!cTyped && !bCreatingFuncView && StartsLikeFormula(aStr)) InitRangeFinder(aStr); // Formula is being edited -> RangeFinder bNewTable = true; // -> PostEditView Call @@ -2792,6 +2796,13 @@ void ScInputHandler::DataChanged( bool bFromTopNotify, bool bSetModified ) bInOwnChange = false; } +bool ScInputHandler::StartsLikeFormula( std::u16string_view rStr ) const +{ + // For new input '+' and '-' may start the dreaded "lazy data typist" + // formula input, editing existing formula content can only start with '='. + return !rStr.empty() && (rStr[0] == '=' || (!mbEditingExistingContent && (rStr[0] == '+' || rStr[0] == '-'))); +} + void ScInputHandler::UpdateFormulaMode() { SfxApplication* pSfxApp = SfxGetpApp(); @@ -2800,8 +2811,7 @@ void ScInputHandler::UpdateFormulaMode() if (bIsFormula) { const OUString& rText = mpEditEngine->GetText(0); - bIsFormula = !rText.isEmpty() && - (rText[0] == '=' || rText[0] == '+' || rText[0] == '-'); + bIsFormula = StartsLikeFormula(rText); } if ( bIsFormula ) @@ -3407,6 +3417,7 @@ void ScInputHandler::EnterHandler( ScEnterMode nBlockMode, bool bBeforeSavingInL nFormSelStart = nFormSelEnd = 0; aFormText.clear(); + mbEditingExistingContent = false; bInOwnChange = false; bInEnterHandler = false; } @@ -3419,6 +3430,7 @@ void ScInputHandler::CancelHandler() bModified = false; mbPartialPrefix = false; + mbEditingExistingContent = false; // Don't rely on ShowRefFrame switching the active view synchronously // execute the function directly on the correct view's bindings instead diff --git a/sc/source/ui/inc/inputhdl.hxx b/sc/source/ui/inc/inputhdl.hxx index 1450f26c8176..56ed3bb95b1f 100644 --- a/sc/source/ui/inc/inputhdl.hxx +++ b/sc/source/ui/inc/inputhdl.hxx @@ -105,6 +105,7 @@ private: bool mbDocumentDisposing:1; /// To indicate if there is a partial prefix completion. bool mbPartialPrefix:1; + bool mbEditingExistingContent:1; sal_uLong nValidation; SvxCellHorJustify eAttrAdjust; @@ -146,6 +147,7 @@ private: bool StartTable( sal_Unicode cTyped, bool bFromCommand, bool bInputActivated, ScEditEngineDefaulter* pTopEngine ); void RemoveSelection(); + bool StartsLikeFormula( std::u16string_view rStr ) const; void UpdateFormulaMode(); static void InvalidateAttribs(); void ImplCreateEditEngine(); commit 50c0e041c06fccb84a84be6d2f457ad0aa0a3c6f Author: Eike Rathke <er...@redhat.com> AuthorDate: Mon Jun 20 17:13:53 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Jun 27 13:30:25 2022 +0200 Resolves: tdf#147265 Return correct default if currency format is duplicate For the default currency format SvNumberFormatter::GetCurrencyFormatStrings() returned always the last added position, regardless whether that format was added or not, which it isn't if the format code is a duplicate. Let addToCurrencyFormatsList() return the position of the existing format if the duplicate was rejected and use that for default. Change-Id: I148d7379de75cae402b063f7b2f92947e345176f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136187 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit 36cf12d449c892e6bbacb7da5f4b008f7762232b) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136166 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/svl/source/numbers/zforlist.cxx b/svl/source/numbers/zforlist.cxx index fbd05a481df9..6a9934fdbed1 100644 --- a/svl/source/numbers/zforlist.cxx +++ b/svl/source/numbers/zforlist.cxx @@ -4285,12 +4285,16 @@ void SvNumberFormatter::ImpInitCurrencyTable() } -static void addToCurrencyFormatsList( NfWSStringsDtor& rStrArr, const OUString& rFormat ) +static std::ptrdiff_t addToCurrencyFormatsList( NfWSStringsDtor& rStrArr, const OUString& rFormat ) { // Prevent duplicates even over subsequent calls of // GetCurrencyFormatStrings() with the same vector. - if (std::find( rStrArr.begin(), rStrArr.end(), rFormat) == rStrArr.end()) - rStrArr.push_back( rFormat); + NfWSStringsDtor::const_iterator it( std::find( rStrArr.begin(), rStrArr.end(), rFormat)); + if (it != rStrArr.end()) + return it - rStrArr.begin(); + + rStrArr.push_back( rFormat); + return rStrArr.size() - 1; } @@ -4319,9 +4323,7 @@ sal_uInt16 SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor& rStrArr + ";" + aRed + aNegativeBank; - addToCurrencyFormatsList( rStrArr, format2); - - nDefault = rStrArr.size() - 1; + nDefault = addToCurrencyFormatsList( rStrArr, format2); } else { @@ -4374,8 +4376,7 @@ sal_uInt16 SvNumberFormatter::GetCurrencyFormatStrings( NfWSStringsDtor& rStrArr { addToCurrencyFormatsList( rStrArr, format3); } - addToCurrencyFormatsList( rStrArr, format4); - nDefault = rStrArr.size() - 1; + nDefault = addToCurrencyFormatsList( rStrArr, format4); if (rCurr.GetDigits()) { addToCurrencyFormatsList( rStrArr, format5); commit 48de5010d88454e886aa8b280ae51a6ee884b870 Author: Eike Rathke <er...@redhat.com> AuthorDate: Thu Jun 16 21:44:40 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Jun 27 13:30:25 2022 +0200 Resolves: tdf#147822 ScUnoListenerEntry container must be std::list ... instead of std::vector to not get invalidated iterators when the container is resized. Regression from commit f8defe59ff75df2b516ee407f1dac22b0ac72a19 CommitDate: Wed Sep 6 22:45:10 2017 +0200 Replace some lists by vectors in unoobj (sc) which was bad for this case. Change-Id: I8d3a001242865cadc82b359a3198906d26373a41 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136007 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit 7a0a0e23b7e81c1ee0601824a4ee990a2178f98b) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136023 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/sc/inc/listenercalls.hxx b/sc/inc/listenercalls.hxx index ff835a048b1a..acb009937fa1 100644 --- a/sc/inc/listenercalls.hxx +++ b/sc/inc/listenercalls.hxx @@ -19,7 +19,7 @@ #pragma once -#include <vector> +#include <list> #include <com/sun/star/uno/Reference.hxx> #include <com/sun/star/lang/EventObject.hpp> @@ -48,7 +48,9 @@ struct ScUnoListenerEntry class ScUnoListenerCalls { private: - ::std::vector<ScUnoListenerEntry> aEntries; + // Must be list, not vector, to not invalidate iterators, see + // ExecuteAndClear() implementation. + ::std::list<ScUnoListenerEntry> aEntries; public: ScUnoListenerCalls(); diff --git a/sc/source/ui/unoobj/listenercalls.cxx b/sc/source/ui/unoobj/listenercalls.cxx index 2d9a23083ca8..7ff7c7df0956 100644 --- a/sc/source/ui/unoobj/listenercalls.cxx +++ b/sc/source/ui/unoobj/listenercalls.cxx @@ -44,7 +44,7 @@ void ScUnoListenerCalls::ExecuteAndClear() // During each modified() call, Add may be called again. // These new calls are executed here, too. - std::vector<ScUnoListenerEntry>::iterator aItr(aEntries.begin()); + std::list<ScUnoListenerEntry>::iterator aItr(aEntries.begin()); while (aItr != aEntries.end()) { ScUnoListenerEntry aEntry = *aItr; commit 8905d516cfecb2a3d6a4302fee162b9be6e5049f Author: Eike Rathke <er...@redhat.com> AuthorDate: Tue Jun 14 13:55:09 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Jun 27 13:30:25 2022 +0200 Related: tdf#149325 Fix yet another VbaRange empty ScRangeList access Change-Id: If2c44795ab794482b841138bdd55f37c4d30b592 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135824 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit 9470c5531dc928d438a6a7f4d47f2d82f2296cc1) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135874 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx index ca77bae6c093..6ee791bf7212 100644 --- a/sc/source/ui/unoobj/cellsuno.cxx +++ b/sc/source/ui/unoobj/cellsuno.cxx @@ -6717,7 +6717,9 @@ uno::Reference<sheet::XSheetCellCursor> SAL_CALL ScTableSheetObj::createCursorBy if (pRangesImp) { const ScRangeList& rRanges = pRangesImp->GetRangeList(); - OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" ); + SAL_WARN_IF( rRanges.size() != 1, "sc", "ScTableSheetObj::createCursorByRange: Range? Ranges?"); + if (rRanges.empty()) + return nullptr; return new ScCellCursorObj( pDocSh, rRanges[ 0 ] ); } } diff --git a/sc/source/ui/vba/vbarange.cxx b/sc/source/ui/vba/vbarange.cxx index eaba743db01b..92c281cfb8ac 100644 --- a/sc/source/ui/vba/vbarange.cxx +++ b/sc/source/ui/vba/vbarange.cxx @@ -1285,9 +1285,12 @@ uno::Reference< sheet::XSheetCellRange > lclExpandToMerged( const uno::Reference { aOldAddress = aNewAddress; uno::Reference< sheet::XSheetCellCursor > xCursor( xSheet->createCursorByRange( xNewCellRange ), uno::UNO_SET_THROW ); - xCursor->collapseToMergedArea(); - xNewCellRange.set( xCursor, uno::UNO_QUERY_THROW ); - aNewAddress = lclGetRangeAddress( xNewCellRange ); + if (xCursor.is()) + { + xCursor->collapseToMergedArea(); + xNewCellRange.set( xCursor, uno::UNO_QUERY_THROW ); + aNewAddress = lclGetRangeAddress( xNewCellRange ); + } } while( bRecursive && (aOldAddress != aNewAddress) ); return xNewCellRange; commit 84e51f196567b358f0889c9052a8a2b1615541c3 Author: Eike Rathke <er...@redhat.com> AuthorDate: Mon Jun 13 17:00:43 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Jun 27 13:30:25 2022 +0200 tdf#149531 tdf#149325 Eliminate unconditional ScRangeList::front() access This is a combination of 2 commits. Resolves: tdf#149531 Use initial sheet range for VBA Columns and Rows ... if the ScTableSheetObj's ScRangeList is empty. It might even be that was never intended to be used and worked only by accident in the past (pre 6.0), but it's somewhat unclear. It may even get in the way in case it exists and the (first) range was modified, e.g. shrunk by a Delete, as the resulting column or row object could be different from the initial sheet range. xChange-Id: Ib9911df1b23802054a5bb0621bb7f5559ef3f39b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135732 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit 3ad12672e924f7aef394119f9fe5f0b06a900b9e) Related: tdf#149325 Eliminate all unconditional ScRangeList::front() access ... to prevent crashes, and where possible substitute a missing element with the original sheet object range. xChange-Id: I245844e89fa3eb7d6ec07e279bdd23022fd77958 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135773 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit d6331fc7abe545ff0a369c41ab3f55b8f44a2cc1) Change-Id: Ib9911df1b23802054a5bb0621bb7f5559ef3f39b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135739 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sc/source/ui/vba/vbarange.cxx b/sc/source/ui/vba/vbarange.cxx index 91f3dc76f72c..eaba743db01b 100644 --- a/sc/source/ui/vba/vbarange.cxx +++ b/sc/source/ui/vba/vbarange.cxx @@ -871,15 +871,18 @@ protected: ScCellRangesBase* pUnoRangesBase = dynamic_cast< ScCellRangesBase* >( xIf.get() ); if ( pUnoRangesBase ) { - ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); - ScCompiler aCompiler( m_rDoc, aCellRanges.front().aStart, m_eGrammar ); - // compile the string in the format passed in - std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sFormula)); - // convert to API grammar - aCompiler.SetGrammar( formula::FormulaGrammar::GRAM_API ); - OUString sConverted; - aCompiler.CreateStringFromTokenArray(sConverted); - sFormula = EQUALS + sConverted; + const ScRangeList& rCellRanges = pUnoRangesBase->GetRangeList(); + if (!rCellRanges.empty()) + { + ScCompiler aCompiler( m_rDoc, rCellRanges.front().aStart, m_eGrammar ); + // compile the string in the format passed in + std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sFormula)); + // convert to API grammar + aCompiler.SetGrammar( formula::FormulaGrammar::GRAM_API ); + OUString sConverted; + aCompiler.CreateStringFromTokenArray(sConverted); + sFormula = EQUALS + sConverted; + } } } @@ -917,16 +920,19 @@ public: { OUString sVal; aValue >>= sVal; - ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); - // Compile string from API grammar. - ScCompiler aCompiler( m_rDoc, aCellRanges.front().aStart, formula::FormulaGrammar::GRAM_API ); - std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sVal)); - // Convert to desired grammar. - aCompiler.SetGrammar( m_eGrammar ); - OUString sConverted; - aCompiler.CreateStringFromTokenArray(sConverted); - sVal = EQUALS + sConverted; - aValue <<= sVal; + const ScRangeList& rCellRanges = pUnoRangesBase->GetRangeList(); + if (!rCellRanges.empty()) + { + // Compile string from API grammar. + ScCompiler aCompiler( m_rDoc, rCellRanges.front().aStart, formula::FormulaGrammar::GRAM_API ); + std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sVal)); + // Convert to desired grammar. + aCompiler.SetGrammar( m_eGrammar ); + OUString sConverted; + aCompiler.CreateStringFromTokenArray(sConverted); + sVal = EQUALS + sConverted; + aValue <<= sVal; + } } } @@ -1920,7 +1926,8 @@ ScVbaRange::Offset( const ::uno::Any &nRowOff, const uno::Any &nColOff ) return new ScVbaRange( mxParent, mxContext, xRanges ); } // normal range - uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aCellRanges.front() ) ); + const ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( aCellRanges)); + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange)); return new ScVbaRange( mxParent, mxContext, xRange ); } @@ -2371,17 +2378,28 @@ ScVbaRange::Activate() } +ScRange ScVbaRange::obtainRangeEvenIfRangeListIsEmpty( const ScRangeList& rCellRanges ) const +{ + // XXX It may be that using the current range list was never correct, but + // always the initial sheet range would be instead, history is unclear. + + if (!rCellRanges.empty()) + return rCellRanges.front(); + + table::CellRangeAddress aRA( lclGetRangeAddress( mxRange )); + return ScRange( aRA.StartColumn, aRA.StartRow, aRA.Sheet, aRA.EndColumn, aRA.EndRow, aRA.Sheet); +} + uno::Reference< excel::XRange > ScVbaRange::Rows(const uno::Any& aIndex ) { if ( aIndex.hasValue() ) { - sal_Int32 nValue = 0; ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); - ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); - OUString sAddress; + ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( pUnoRangesBase->GetRangeList())); - ScRange aRange = aCellRanges.front(); + sal_Int32 nValue = 0; + OUString sAddress; if( aIndex >>= nValue ) { aRange.aStart.SetRow( aRange.aStart.Row() + --nValue ); @@ -2417,9 +2435,8 @@ uno::Reference< excel::XRange > ScVbaRange::Columns(const uno::Any& aIndex ) { ScCellRangesBase* pUnoRangesBase = getCellRangesBase(); - ScRangeList aCellRanges = pUnoRangesBase->GetRangeList(); + ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( pUnoRangesBase->GetRangeList())); - ScRange aRange = aCellRanges.front(); if ( aIndex.hasValue() ) { OUString sAddress; @@ -2933,7 +2950,8 @@ ScVbaRange::getEntireColumnOrRow( bool bColumn ) return new ScVbaRange( mxParent, mxContext, xRanges, !bColumn, bColumn ); } - uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aCellRanges.front() ) ); + const ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( aCellRanges)); + uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange)); return new ScVbaRange( mxParent, mxContext, xRange, !bColumn, bColumn ); } diff --git a/sc/source/ui/vba/vbarange.hxx b/sc/source/ui/vba/vbarange.hxx index 2e9b71746879..cdeab983fa6d 100644 --- a/sc/source/ui/vba/vbarange.hxx +++ b/sc/source/ui/vba/vbarange.hxx @@ -119,6 +119,9 @@ class ScVbaRange : public ScVbaRange_BASE /** Fires a Worksheet_Change event for this range or range list. */ void fireChangeEvent(); + /// @throws css::uno::RuntimeException + ScRange obtainRangeEvenIfRangeListIsEmpty( const ScRangeList& rCellRanges ) const; + protected: virtual ScCellRangesBase* getCellRangesBase() override; /// @throws css::uno::RuntimeException commit cb49f6a3a10b16828384fc0b3798f8d923e25d29 Author: Eike Rathke <er...@redhat.com> AuthorDate: Fri Jun 10 12:34:00 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Jun 27 13:30:24 2022 +0200 Resolves: tdf#149484 Handle <number:boolean-style> with <number:text> Backport as the current handling when writing such format (even if it doesn't display the text literals) is utterly broken and results in <number:boolean-style style:name="N111"> <number:text>--</number:text> </number:boolean-style> so an implementation correctly reading such (e.g. now upcoming LibreOffice 7.4) would create a format "--" and display that for any value, true or false. This is a combination of 3 commits. Related: tdf#149484 Display BOOLEAN literal string text additions xChange-Id: Ifbaf0b18178091c3a340a7c4bc66f78397aadc18 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135506 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit 2932dc7aa0c1239d39e060e6b7627317f1305549) Resolves: tdf#149484 Read and handle <number:text> in <number:boolean-style> xChange-Id: I1be5f2be908eb88aa4ef7436ea7c09f35b076acf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135507 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit 025231224b8b076e280235cd2b943addd2fb0755) Related: tdf#149484 Write proper <number:boolean-style> with <number:text> xChange-Id: I46b7987dde25840ae0b6e5871b14e3806c6e4ac8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135508 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit 33a8c4bd0e8533ab42894280e7e04c13a47aefa9) Change-Id: I1be5f2be908eb88aa4ef7436ea7c09f35b076acf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135586 Tested-by: Jenkins Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com> diff --git a/include/svl/zformat.hxx b/include/svl/zformat.hxx index cd04f96ac8a1..ae57f5c868ed 100644 --- a/include/svl/zformat.hxx +++ b/include/svl/zformat.hxx @@ -696,6 +696,10 @@ private: SVL_DLLPRIVATE static void ImpAppendEraG( OUStringBuffer& OutStringBuffer, const CalendarWrapper& rCal, sal_Int16 nNatNum ); + SVL_DLLPRIVATE bool ImpGetLogicalOutput( double fNumber, + sal_uInt16 nIx, + OUStringBuffer& OutString ); + SVL_DLLPRIVATE bool ImpGetNumberOutput( double fNumber, sal_uInt16 nIx, OUStringBuffer& OutString ); diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx index 34e439ee4921..fb9cbf50493d 100644 --- a/svl/source/numbers/zformat.cxx +++ b/svl/source/numbers/zformat.cxx @@ -2448,7 +2448,7 @@ bool SvNumberformat::GetOutputString(double fNumber, bool bRes = false; OutString.clear(); *ppColor = nullptr; // No color change - if (eType & SvNumFormatType::LOGICAL) + if (eType & SvNumFormatType::LOGICAL && sFormatstring == rScan.GetKeywords()[NF_KEY_BOOLEAN]) { if (fNumber) { @@ -2614,6 +2614,9 @@ bool SvNumberformat::GetOutputString(double fNumber, case SvNumFormatType::CURRENCY: bRes |= ImpGetNumberOutput(fNumber, nIx, sBuff); break; + case SvNumFormatType::LOGICAL: + bRes |= ImpGetLogicalOutput(fNumber, nIx, sBuff); + break; case SvNumFormatType::FRACTION: bRes |= ImpGetFractionOutput(fNumber, nIx, sBuff); break; @@ -4286,6 +4289,29 @@ bool SvNumberformat::ImpGetDateTimeOutput(double fNumber, return bRes; } +bool SvNumberformat::ImpGetLogicalOutput(double fNumber, + sal_uInt16 nIx, + OUStringBuffer& sStr) +{ + bool bRes = false; + const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); + const sal_uInt16 nCnt = NumFor[nIx].GetCount(); + for (sal_uInt16 j = 0; j < nCnt; ++j) + { + switch (rInfo.nTypeArray[j]) + { + case NF_KEY_BOOLEAN: + sStr.append( fNumber ? rScan.GetTrueString() : rScan.GetFalseString()); + break; + case NF_SYMBOLTYPE_STRING: + sStr.append( rInfo.sStrArray[j]); + break; + } + } + impTransliterate(sStr, NumFor[nIx].GetNatNum()); + return bRes; +} + bool SvNumberformat::ImpGetNumberOutput(double fNumber, sal_uInt16 nIx, OUStringBuffer& sStr) diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx index 4c313538b0df..3b68b5ae3c64 100644 --- a/xmloff/source/style/xmlnumfe.cxx +++ b/xmloff/source/style/xmlnumfe.cxx @@ -1253,6 +1253,37 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt WriteBooleanElement_Impl(); bAnyContent = true; } + else if (eType == XML_BOOLEAN_STYLE) + { + // <number:boolean-style> may contain only <number:boolean> and + // <number:text> elements. + sal_uInt16 nPos = 0; + bool bEnd = false; + while (!bEnd) + { + const short nElemType = rFormat.GetNumForType( nPart, nPos ); + switch (nElemType) + { + case 0: + bEnd = true; // end of format reached + if (bHasText && sTextContent.isEmpty()) + bHasText = false; // don't write trailing empty text + break; + case NF_SYMBOLTYPE_STRING: + { + const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos ); + if (pElemStr) + AddToTextElement_Impl( *pElemStr ); + } + break; + case NF_KEY_BOOLEAN: + WriteBooleanElement_Impl(); + bAnyContent = true; + break; + } + ++nPos; + } + } else { // first loop to collect attributes diff --git a/xmloff/source/style/xmlnumfi.cxx b/xmloff/source/style/xmlnumfi.cxx index 87f653873904..b21a01bea644 100644 --- a/xmloff/source/style/xmlnumfi.cxx +++ b/xmloff/source/style/xmlnumfi.cxx @@ -497,8 +497,11 @@ static bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rPare } // see ImpSvNumberformatScan::Next_Symbol + + // All format types except BOOLEAN may contain minus sign or delimiter. if ( cChar == '-' ) - return true; // all format types may content minus sign or delimiter + return nFormatType != SvXMLStylesTokens::BOOLEAN_STYLE; + if ( ( cChar == ' ' || cChar == '/' || cChar == '.' || @@ -528,11 +531,13 @@ static void lcl_EnquoteIfNecessary( OUStringBuffer& rContent, const SvXMLNumForm { bool bQuote = true; sal_Int32 nLength = rContent.getLength(); + const SvXMLStylesTokens nFormatType = rParent.GetType(); - if ((nLength == 1 && lcl_ValidChar( rContent[0], rParent)) || - (nLength == 2 && - ((rContent[0] == ' ' && rContent[1] == '-') || - (rContent[1] == ' ' && lcl_ValidChar( rContent[0], rParent))))) + if (nFormatType != SvXMLStylesTokens::BOOLEAN_STYLE && + ((nLength == 1 && lcl_ValidChar( rContent[0], rParent)) || + (nLength == 2 && + ((rContent[0] == ' ' && rContent[1] == '-') || + (rContent[1] == ' ' && lcl_ValidChar( rContent[0], rParent)))))) { // Don't quote single separator characters like space or percent, // or separator characters followed by space (used in date formats). @@ -541,7 +546,7 @@ static void lcl_EnquoteIfNecessary( OUStringBuffer& rContent, const SvXMLNumForm // the difference of quotes. bQuote = false; } - else if ( rParent.GetType() == SvXMLStylesTokens::PERCENTAGE_STYLE && nLength > 1 ) + else if ( nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE && nLength > 1 ) { // the percent character in percentage styles must be left out of quoting // (one occurrence is enough even if there are several percent characters in the string) @@ -906,7 +911,7 @@ void SvXMLNumFmtElementContext::endFastElement(sal_Int32 ) } break; case SvXMLStyleTokens::Boolean: - // ignored - only default boolean format is supported + rParent.AddNfKeyword( NF_KEY_BOOLEAN ); break; case SvXMLStyleTokens::Day: @@ -1533,9 +1538,8 @@ sal_Int32 SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter* pFormatter) nIndex = pFormatter->GetFormatIndex( NF_NUMBER_SYSTEM, nFormatLang ); } - // boolean is always the builtin boolean format - // (no other boolean formats are implemented) - if ( nType == SvXMLStylesTokens::BOOLEAN_STYLE ) + if ( nType == SvXMLStylesTokens::BOOLEAN_STYLE && !bHasExtraText && + aMyConditions.empty() && sFormat.toChar() != '[' ) nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, nFormatLang ); // check for default date formats commit 3ac2a496343a5e94b0c2251783aa4932d651c720 Author: Eike Rathke <er...@redhat.com> AuthorDate: Fri Jun 10 00:01:23 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Jun 27 13:30:24 2022 +0200 Resolves: tdf#148072 Restore sheet-local names for Undo of Cut Undo of Cut uses CopyToTable() and not UndoToTab() as Copy does, so copy the sheet-local names also *from* Undo and not only *to* Undo. And mark for ScAreasChanged broadcast. Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135568 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit b7eddf3e9c2db503dde632b35513844806be3c36) Conflicts: sc/source/core/data/table2.cxx Change-Id: Ib07f711a7d407dafdf548873291f1ccc81b85d47 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135587 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx index 32c1e34bbff4..543944c18a25 100644 --- a/sc/source/core/data/table2.cxx +++ b/sc/source/core/data/table2.cxx @@ -1315,13 +1315,21 @@ void ScTable::CopyToTable( if (!ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2)) return; - bool bIsUndoDoc = pDestTab->rDocument.IsUndo(); + const bool bToUndoDoc = pDestTab->rDocument.IsUndo(); + const bool bFromUndoDoc = rDocument.IsUndo(); - if (bIsUndoDoc && (nFlags & InsertDeleteFlags::CONTENTS)) + if ((bToUndoDoc || bFromUndoDoc) && (nFlags & InsertDeleteFlags::CONTENTS) && mpRangeName) { // Copying formulas may create sheet-local named expressions on the // destination sheet. Add existing to Undo first. + // During Undo restore the previous named expressions. pDestTab->SetRangeName( std::unique_ptr<ScRangeName>( new ScRangeName( *GetRangeName()))); + if (!pDestTab->rDocument.IsClipOrUndo()) + { + ScDocShell* pDocSh = static_cast<ScDocShell*>(pDestTab->rDocument.GetDocumentShell()); + if (pDocSh) + pDocSh->SetAreasChangedNeedBroadcast(); + } } if (nFlags != InsertDeleteFlags::NONE) @@ -1333,14 +1341,14 @@ void ScTable::CopyToTable( // quadratically expensive with large groups. So do the grouping just once at the end. sc::DelayFormulaGroupingSwitch delayGrouping( pDestTab->rDocument, true ); for (SCCOL i = nCol1; i <= ClampToAllocatedColumns(nCol2); i++) - aCol[i].CopyToColumn(rCxt, nRow1, nRow2, bIsUndoDoc ? nFlags : nTempFlags, bMarked, + aCol[i].CopyToColumn(rCxt, nRow1, nRow2, bToUndoDoc ? nFlags : nTempFlags, bMarked, pDestTab->CreateColumnIfNotExists(i), pMarkData, bAsLink, bGlobalNamesToLocal); } if (!bColRowFlags) // Column widths/Row heights/Flags return; - if(bIsUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB)) + if (bToUndoDoc && (nFlags & InsertDeleteFlags::ATTRIB)) { pDestTab->mpCondFormatList.reset(new ScConditionalFormatList(pDestTab->rDocument, *mpCondFormatList)); } @@ -1453,7 +1461,7 @@ void ScTable::CopyToTable( CopySparklinesToTable(nCol1, nRow1, nCol2, nRow2, pDestTab); } - if (!bIsUndoDoc && bCopyCaptions && (nFlags & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES))) + if (!bToUndoDoc && bCopyCaptions && (nFlags & (InsertDeleteFlags::NOTE | InsertDeleteFlags::ADDNOTES))) { bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE; CopyCaptionsToTable( nCol1, nRow1, nCol2, nRow2, pDestTab, bCloneCaption); commit c9ffec6cdf1af4c9c1e8c6317a59ad5d63093ac7 Author: Eike Rathke <er...@redhat.com> AuthorDate: Mon May 30 21:38:41 2022 +0200 Commit: Luboš Luňák <l.lu...@collabora.com> CommitDate: Mon Jun 27 13:30:24 2022 +0200 InsertMatrixFormula: correct references for across sheets array formulas Inserting an array/matrix formula across two or more selected/marked sheets generated wrong matrix offset references starting with the second sheet, pointing to the top left of the first array formula. Only the top left cell of the inserted formula on each sheet displayed the correct value. Deleting the array formula on the first sheet then left all matrix offset references on the remaining sheets with #REF! errors and those cells could not be deleted anymore because their original parent cell was gone. Change-Id: If5d53311f9aabdcd7432ff26ab555bb91b0b121d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135147 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins (cherry picked from commit dfd5081ff3973d5d0f216b06dda6360fa490cc9c) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135154 Reviewed-by: Caolán McNamara <caol...@redhat.com> diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx index cf9a2fbd0a83..e893c84acaed 100644 --- a/sc/source/core/data/documen4.cxx +++ b/sc/source/core/data/documen4.cxx @@ -306,13 +306,11 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1, *pCell, *this, ScAddress(nCol1, nRow1, rTab), ScCloneFlags::StartListening)); } - ScAddress aBasePos(nCol1, nRow1, nTab1); ScSingleRefData aRefData; aRefData.InitFlags(); - aRefData.SetColRel( true ); - aRefData.SetRowRel( true ); - aRefData.SetTabRel( true ); - aRefData.SetAddress(GetSheetLimits(), aBasePos, aBasePos); + aRefData.SetRelCol(0); + aRefData.SetRelRow(0); + aRefData.SetRelTab(0); // 2D matrix, always same sheet ScTokenArray aArr(*this); // consists only of one single reference token. formula::FormulaToken* t = aArr.AddMatrixSingleReference(aRefData); @@ -326,26 +324,21 @@ void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1, if (!pTab) continue; - if (nTab != nTab1) - { - aRefData.SetRelTab(nTab - aBasePos.Tab()); - *t->GetSingleRef() = aRefData; - } - - for (SCCOL nCol : GetWritableColumnsRange(nTab1, nCol1, nCol2)) + for (SCCOL nCol : GetWritableColumnsRange(nTab, nCol1, nCol2)) { + aRefData.SetRelCol(nCol1 - nCol); for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) { if (nCol == nCol1 && nRow == nRow1) // Skip the base position. continue; - // Token array must be cloned so that each formula cell receives its own copy. - aPos = ScAddress(nCol, nRow, nTab); // Reference in each cell must point to the origin cell relative to the current cell. - aRefData.SetAddress(GetSheetLimits(), aBasePos, aPos); + aRefData.SetRelRow(nRow1 - nRow); *t->GetSingleRef() = aRefData; + // Token array must be cloned so that each formula cell receives its own copy. std::unique_ptr<ScTokenArray> pTokArr(aArr.Clone()); + aPos = ScAddress(nCol, nRow, nTab); pCell = new ScFormulaCell(*this, aPos, *pTokArr, eGram, ScMatrixMode::Reference); pTab->SetFormulaCell(nCol, nRow, pCell); }