Rebased ref, commits from common ancestor: commit 7431394ad3a72ef960eb52f8718752f59e617567 Author: Mike Kaganski <mike.kagan...@collabora.com> Date: Sun Feb 12 01:58:23 2017 +0300
tdf#76183: refresh objects' positions on optimal height recalc Since commit b10833d4db6046f2d32ea44a60cb19a626d80447, it's required to detect when objects' placement should be adjusted, and call SetDrawPageSize manually. Unit test included [not in this backport, though] Change-Id: I933ba4802b212400cc47ed0fb7e1f8f44049bb81 Reviewed-on: https://gerrit.libreoffice.org/34165 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/45570 Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de> Tested-by: Thorsten Behrens <thorsten.behr...@cib.de> diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx index e314e3b35273..c42f04e1bb31 100644 --- a/sc/source/ui/docshell/docfunc.cxx +++ b/sc/source/ui/docshell/docfunc.cxx @@ -151,6 +151,9 @@ bool ScDocFunc::AdjustRowHeight( const ScRange& rRange, bool bPaint ) sc::RowHeightContext aCxt(aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, aProv.GetDevice()); bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartRow, nEndRow, nTab); + // tdf#76183: recalculate objects' positions + if (bChanged) + rDoc.SetDrawPageSize(nTab); if ( bPaint && bChanged ) rDocShell.PostPaint(ScRange(0, nStartRow, nTab, MAXCOL, MAXROW, nTab), diff --git a/sc/source/ui/docshell/docsh5.cxx b/sc/source/ui/docshell/docsh5.cxx index 32857f2b3dee..427dd9ab3525 100644 --- a/sc/source/ui/docshell/docsh5.cxx +++ b/sc/source/ui/docshell/docsh5.cxx @@ -394,7 +394,12 @@ bool ScDocShell::AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) bool bChange = aDocument.SetOptimalHeight(aCxt, nStartRow,nEndRow, nTab); if (bChange) + { + // tdf#76183: recalculate objects' positions + aDocument.SetDrawPageSize(nTab); + PostPaint( 0,nStartRow,nTab, MAXCOL,MAXROW,nTab, PAINT_GRID|PAINT_LEFT ); + } return bChange; } diff --git a/sc/source/ui/undo/undobase.cxx b/sc/source/ui/undo/undobase.cxx index 0133f9afd41a..9aa01565096b 100644 --- a/sc/source/ui/undo/undobase.cxx +++ b/sc/source/ui/undo/undobase.cxx @@ -308,10 +308,14 @@ bool ScBlockUndo::AdjustHeight() aCxt, aBlockRange.aStart.Row(), aBlockRange.aEnd.Row(), aBlockRange.aStart.Tab()); if (bRet) + { + // tdf#76183: recalculate objects' positions + rDoc.SetDrawPageSize(aBlockRange.aStart.Tab()); + pDocShell->PostPaint( 0, aBlockRange.aStart.Row(), aBlockRange.aStart.Tab(), MAXCOL, MAXROW, aBlockRange.aEnd.Tab(), PAINT_GRID | PAINT_LEFT ); - + } return bRet; } @@ -408,9 +412,14 @@ void ScMultiBlockUndo::AdjustHeight() bool bRet = rDoc.SetOptimalHeight(aCxt, r.aStart.Row(), r.aEnd.Row(), r.aStart.Tab()); if (bRet) + { + // tdf#76183: recalculate objects' positions + rDoc.SetDrawPageSize(r.aStart.Tab()); + pDocShell->PostPaint( 0, r.aStart.Row(), r.aStart.Tab(), MAXCOL, MAXROW, r.aEnd.Tab(), PAINT_GRID | PAINT_LEFT); + } } } diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx index 157540535667..ca234549ab83 100644 --- a/sc/source/ui/undo/undoblk.cxx +++ b/sc/source/ui/undo/undoblk.cxx @@ -1177,6 +1177,8 @@ void ScUndoDragDrop::PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const if (rDoc.SetOptimalHeight(aCxt, aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab())) { + // tdf#76183: recalculate objects' positions + rDoc.SetDrawPageSize(aRange.aStart.Tab()); aRange.aStart.SetCol(0); aRange.aEnd.SetCol(MAXCOL); aRange.aEnd.SetRow(MAXROW); diff --git a/sc/source/ui/undo/undoblk3.cxx b/sc/source/ui/undo/undoblk3.cxx index ff43c28e0934..5de441787b0e 100644 --- a/sc/source/ui/undo/undoblk3.cxx +++ b/sc/source/ui/undo/undoblk3.cxx @@ -884,7 +884,7 @@ void ScUndoAutoFormat::Redo() rDoc.SetRowFlags( nRow, nTab, nOld & ~CR_MANUALSIZE ); } - rDoc.SetOptimalHeight(aCxt, nStartY, nEndY, nTab); + bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartY, nEndY, nTab); for (SCCOL nCol=nStartX; nCol<=nEndX; nCol++) if (!rDoc.ColHidden(nCol, nTab)) @@ -895,6 +895,10 @@ void ScUndoAutoFormat::Redo() rDoc.SetColWidth( nCol, nTab, nThisSize ); rDoc.ShowCol( nCol, nTab, true ); } + + // tdf#76183: recalculate objects' positions + if (bChanged) + rDoc.SetDrawPageSize(nTab); } pDocShell->PostPaint( 0, 0, nStartZ, diff --git a/sc/source/ui/view/viewfun2.cxx b/sc/source/ui/view/viewfun2.cxx index 7e2e8b316708..6b2b17ae7f61 100644 --- a/sc/source/ui/view/viewfun2.cxx +++ b/sc/source/ui/view/viewfun2.cxx @@ -147,6 +147,9 @@ bool ScViewFunc::AdjustBlockHeight( bool bPaint, ScMarkData* pMarkData ) bAnyChanged = bChanged = true; } } + // tdf#76183: recalculate objects' positions + if (bChanged) + rDoc.SetDrawPageSize(nTab); if ( bPaint && bChanged ) pDocSh->PostPaint( 0, nPaintY, nTab, MAXCOL, MAXROW, nTab, PAINT_GRID | PAINT_LEFT ); @@ -181,6 +184,10 @@ bool ScViewFunc::AdjustRowHeight( SCROW nStartRow, SCROW nEndRow ) sc::RowHeightContext aCxt(nPPTX, nPPTY, aZoomX, aZoomY, aProv.GetDevice()); bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartRow, nEndRow, nTab); + // tdf#76183: recalculate objects' positions + if (bChanged) + rDoc.SetDrawPageSize(nTab); + if (bChanged && ( nStartRow == nEndRow )) { sal_uInt16 nNewPixel = (sal_uInt16) (rDoc.GetRowHeight(nStartRow,nTab) * nPPTY); commit 07ea76f4997b71c514b599e7acd220f073c74ddd Author: Tor Lillqvist <t...@collabora.com> Date: Sun Nov 26 23:28:05 2017 +0200 Deduplicate conditional formats loaded from .ods If there are several separate conditional format elements that can be represented as just one (with several ranges), try to do that. A particular customer document used to take 3 minutes 20 seconds to load, and it contained so many (tens of thousands) conditional formats that the Format> Conditional Formatting> Manage... dialog was practically impossible to use. Now loading that document takes 15 seconds and there are just a handful of separate conditional formats. Also add a simple unit test to verify the deduplication. Change-Id: I7c468af99956d4646ee5507390f1476caff52325 Reviewed-on: https://gerrit.libreoffice.org/45479 Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de> Tested-by: Thorsten Behrens <thorsten.behr...@cib.de> diff --git a/sc/CppunitTest_sc_cond_format_merge.mk b/sc/CppunitTest_sc_cond_format_merge.mk new file mode 100644 index 000000000000..bfb7dc2bba3f --- /dev/null +++ b/sc/CppunitTest_sc_cond_format_merge.mk @@ -0,0 +1,116 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,sc_cond_format_merge)) + +$(eval $(call gb_CppunitTest_add_exception_objects,sc_cond_format_merge, \ + sc/qa/unit/cond_format_merge \ +)) + +$(eval $(call gb_CppunitTest_use_externals,sc_cond_format_merge, \ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,sc_cond_format_merge, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sc \ + scqahelper \ + sfx \ + sot \ + subsequenttest \ + svl \ + svt \ + svx \ + svxcore \ + test \ + tk \ + tl \ + ucbhelper \ + unotest \ + utl \ + vbahelper \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_set_include,sc_cond_format_merge,\ + -I$(SRCDIR)/sc/source/ui/inc \ + -I$(SRCDIR)/sc/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,sc_cond_format_merge)) + +$(eval $(call gb_CppunitTest_use_ure,sc_cond_format_merge)) +$(eval $(call gb_CppunitTest_use_vcl,sc_cond_format_merge)) + +$(eval $(call gb_CppunitTest_use_components,sc_cond_format_merge,\ + basic/util/sb \ + chart2/source/chartcore \ + chart2/source/controller/chartcontroller \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + dbaccess/util/dba \ + embeddedobj/util/embobj \ + eventattacher/source/evtatt \ + filter/source/config/cache/filterconfig1 \ + filter/source/storagefilterdetect/storagefd \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scaddins/source/analysis/analysis \ + scaddins/source/datefunc/date \ + scripting/source/basprov/basprov \ + scripting/util/scriptframe \ + sc/util/sc \ + sc/util/scd \ + sc/util/scfilt \ + $(call gb_Helper_optional,SCRIPTING, \ + sc/util/vbaobj) \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + svtools/util/svt \ + svx/util/svx \ + svx/util/svxcore \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,sc_cond_format_merge)) + +$(eval $(call gb_CppunitTest_use_unittest_configuration,sc_cond_format_merge)) + +# vim: set noet sw=4 ts=4: diff --git a/sc/Module_sc.mk b/sc/Module_sc.mk index 7175f01a2658..26f967d7b267 100644 --- a/sc/Module_sc.mk +++ b/sc/Module_sc.mk @@ -52,6 +52,7 @@ $(eval $(call gb_Module_add_check_targets,sc,\ )) $(eval $(call gb_Module_add_slowcheck_targets,sc, \ + CppunitTest_sc_cond_format_merge \ CppunitTest_sc_condformats \ CppunitTest_sc_new_cond_format_api \ CppunitTest_sc_subsequent_filters_test \ diff --git a/sc/inc/conditio.hxx b/sc/inc/conditio.hxx index 104fe4293ebf..2f6b266f7468 100644 --- a/sc/inc/conditio.hxx +++ b/sc/inc/conditio.hxx @@ -233,6 +233,8 @@ public: bool operator== ( const ScConditionEntry& r ) const; + bool EqualIgnoringSrcPos( const ScConditionEntry& r ) const; + virtual void SetParent( ScConditionalFormat* pNew ) override; bool IsCellValid( ScRefCellValue& rCell, const ScAddress& rPos ) const; @@ -241,6 +243,7 @@ public: void SetOperation(ScConditionMode eMode); bool IsIgnoreBlank() const { return ( nOptions & SC_COND_NOBLANKS ) == 0; } void SetIgnoreBlank(bool bSet); + OUString GetSrcString() const { return aSrcString; } const ScAddress& GetSrcPos() const { return aSrcPos; } ScAddress GetValidSrcPos() const; // adjusted to allow textual representation of expressions diff --git a/sc/qa/extras/testdocuments/cond_format_merge.ods b/sc/qa/extras/testdocuments/cond_format_merge.ods new file mode 100644 index 000000000000..43b676d22080 Binary files /dev/null and b/sc/qa/extras/testdocuments/cond_format_merge.ods differ diff --git a/sc/qa/unit/cond_format_merge.cxx b/sc/qa/unit/cond_format_merge.cxx new file mode 100644 index 000000000000..0ce3f21909bd --- /dev/null +++ b/sc/qa/unit/cond_format_merge.cxx @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/sheet/XConditionalFormats.hpp> +#include <com/sun/star/sheet/XSpreadsheet.hpp> +#include <test/bootstrapfixture.hxx> +#include <test/calc_unoapi_test.hxx> + +#include <global.hxx> +#include <document.hxx> + +#include "helper/qahelper.hxx" + +using namespace css; + +class ScCondFormatMergeTest : public CalcUnoApiTest +{ +public: + ScCondFormatMergeTest(); + + void testCondFormatMerge(); + + CPPUNIT_TEST_SUITE(ScCondFormatMergeTest); + CPPUNIT_TEST(testCondFormatMerge); + CPPUNIT_TEST_SUITE_END(); +}; + +ScCondFormatMergeTest::ScCondFormatMergeTest() + : CalcUnoApiTest("sc/qa/extras/testdocuments/") +{ +} + +void ScCondFormatMergeTest::testCondFormatMerge() +{ + OUString aFileURL; + createFileURL("cond_format_merge.ods", aFileURL); + uno::Reference<lang::XComponent> mxComponent = loadFromDesktop(aFileURL); + + CPPUNIT_ASSERT_MESSAGE("Component not loaded", mxComponent.is()); + + // get the first sheet + uno::Reference<sheet::XSpreadsheetDocument> xDoc(mxComponent, uno::UNO_QUERY_THROW); + uno::Reference<container::XIndexAccess> xIndex(xDoc->getSheets(), uno::UNO_QUERY_THROW); + uno::Reference<sheet::XSpreadsheet> xSheet(xIndex->getByIndex(0), uno::UNO_QUERY_THROW); + + uno::Reference<beans::XPropertySet> xProps(xSheet, uno::UNO_QUERY_THROW); + uno::Any aAny = xProps->getPropertyValue("ConditionalFormats"); + uno::Reference<sheet::XConditionalFormats> xCondFormats; + + CPPUNIT_ASSERT(aAny >>= xCondFormats); + CPPUNIT_ASSERT(xCondFormats.is()); + + CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xCondFormats->getLength()); + + uno::Sequence<uno::Reference<sheet::XConditionalFormat>> xCondFormatSeq + = xCondFormats->getConditionalFormats(); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xCondFormatSeq.getLength()); + + int nRanges = 0; + for (sal_Int32 i = 0, n = xCondFormatSeq.getLength(); i < n; ++i) + { + CPPUNIT_ASSERT(xCondFormatSeq[i].is()); + + uno::Reference<sheet::XConditionalFormat> xCondFormat = xCondFormatSeq[i]; + CPPUNIT_ASSERT(xCondFormat.is()); + + uno::Reference<beans::XPropertySet> xPropSet(xCondFormat, uno::UNO_QUERY_THROW); + + aAny = xPropSet->getPropertyValue("Range"); + uno::Reference<sheet::XSheetCellRanges> xCellRanges; + CPPUNIT_ASSERT(aAny >>= xCellRanges); + CPPUNIT_ASSERT(xCellRanges.is()); + + uno::Sequence<table::CellRangeAddress> aRanges = xCellRanges->getRangeAddresses(); + CPPUNIT_ASSERT_GREATEREQUAL(sal_Int32(1), aRanges.getLength()); + + table::CellRangeAddress aRange0 = aRanges[0]; + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), aRange0.Sheet); + CPPUNIT_ASSERT_EQUAL(aRange0.StartColumn, aRange0.EndColumn); + + table::CellRangeAddress aRange1; + + switch (aRange0.StartColumn) + { + case 3: + switch (aRange0.StartRow) + { + case 0: // D1:D2,D5::D8 + nRanges++; + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aRange0.EndRow); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aRanges.getLength()); + aRange1 = aRanges[1]; + CPPUNIT_ASSERT_EQUAL(sal_Int16(0), aRange1.Sheet); + CPPUNIT_ASSERT_EQUAL(aRange1.StartColumn, aRange1.EndColumn); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), aRange1.StartColumn); + CPPUNIT_ASSERT_EQUAL(sal_Int32(4), aRange1.StartRow); + CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aRange1.EndRow); + break; + default: + CPPUNIT_FAIL("Unexpected range in column D"); + } + break; + case 5: + switch (aRange0.StartRow) + { + case 0: // F1:F2 + nRanges++; + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aRange0.EndRow); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aRanges.getLength()); + break; + case 2: // F3 + nRanges++; + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aRange0.EndRow); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aRanges.getLength()); + break; + case 3: // F4 + nRanges++; + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), aRange0.EndRow); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aRanges.getLength()); + break; + case 4: // F5 + nRanges++; + CPPUNIT_ASSERT_EQUAL(sal_Int32(4), aRange0.EndRow); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aRanges.getLength()); + break; + default: + CPPUNIT_FAIL("Unexpected range in column F"); + } + break; + default: + CPPUNIT_FAIL("Unexpected range"); + } + } + + CPPUNIT_ASSERT_EQUAL(5, nRanges); + + closeDocument(mxComponent); + mxComponent.clear(); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(ScCondFormatMergeTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx index 68fa98beb206..d3d996d93239 100644 --- a/sc/source/core/data/conditio.cxx +++ b/sc/source/core/data/conditio.cxx @@ -694,6 +694,25 @@ bool ScConditionEntry::operator== ( const ScConditionEntry& r ) const return bEq; } +bool ScConditionEntry::EqualIgnoringSrcPos( const ScConditionEntry& r ) const +{ + bool bEq = (eOp == r.eOp && nOptions == r.nOptions && + lcl_IsEqual( pFormula1, r.pFormula1 ) && + lcl_IsEqual( pFormula2, r.pFormula2 )); + if (bEq) + { + // Here, ignore the aSrcPoses and aSrcStrings + + // If not formulas, compare values + if ( !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) ) + bEq = false; + if ( !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) ) + bEq = false; + } + + return bEq; +} + void ScConditionEntry::Interpret( const ScAddress& rPos ) { // Create formula cells diff --git a/sc/source/filter/xml/xmlcondformat.cxx b/sc/source/filter/xml/xmlcondformat.cxx index 7e0e0c063ce1..f9704a1afb09 100644 --- a/sc/source/filter/xml/xmlcondformat.cxx +++ b/sc/source/filter/xml/xmlcondformat.cxx @@ -19,6 +19,7 @@ #include "docfunc.hxx" #include "XMLConverter.hxx" #include "stylehelper.hxx" +#include "tokenarray.hxx" ScXMLConditionalFormatsContext::ScXMLConditionalFormatsContext( ScXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName): @@ -38,7 +39,7 @@ SvXMLImportContext* ScXMLConditionalFormatsContext::CreateChildContext( sal_uInt switch (nToken) { case XML_TOK_CONDFORMATS_CONDFORMAT: - pContext = new ScXMLConditionalFormatContext( GetScImport(), nPrefix, rLocalName, xAttrList ); + pContext = new ScXMLConditionalFormatContext( GetScImport(), nPrefix, rLocalName, xAttrList, *this ); break; } @@ -54,11 +55,18 @@ void ScXMLConditionalFormatsContext::EndElement() bool bDeleted = !pCondFormatList->CheckAllEntries(); SAL_WARN_IF(bDeleted, "sc", "conditional formats have been deleted because they contained empty range info"); + + for (const auto& i : mvCondFormatData) + { + pDoc->AddCondFormatData( i.mpFormat->GetRange(), i.mnTab, i.mpFormat->GetKey() ); + } } ScXMLConditionalFormatContext::ScXMLConditionalFormatContext( ScXMLImport& rImport, sal_uInt16 nPrfx, - const OUString& rLName, const css::uno::Reference< css::xml::sax::XAttributeList>& xAttrList): - SvXMLImportContext( rImport, nPrfx, rLName ) + const OUString& rLName, const css::uno::Reference< css::xml::sax::XAttributeList>& xAttrList, + ScXMLConditionalFormatsContext& rParent ): + SvXMLImportContext( rImport, nPrfx, rLName ), + mrParent( rParent ) { OUString sRange; @@ -120,16 +128,225 @@ SvXMLImportContext* ScXMLConditionalFormatContext::CreateChildContext( sal_uInt1 return pContext; } +static bool HasRelRefIgnoringSheet0Relative( ScDocument* pDoc, ScTokenArray* pTokens, sal_uInt16 nRecursion = 0 ) +{ + if (pTokens) + { + formula::FormulaToken* t; + for( t = pTokens->First(); t; t = pTokens->Next() ) + { + switch( t->GetType() ) + { + case formula::svDoubleRef: + { + ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2; + if ( rRef2.IsColRel() || rRef2.IsRowRel() || (rRef2.IsFlag3D() && rRef2.IsTabRel()) ) + return true; + SAL_FALLTHROUGH; + } + + case formula::svSingleRef: + { + ScSingleRefData& rRef1 = *t->GetSingleRef(); + if ( rRef1.IsColRel() || rRef1.IsRowRel() || (rRef1.IsFlag3D() && rRef1.IsTabRel()) ) + return true; + } + break; + + case formula::svIndex: + { + if( t->GetOpCode() == ocName ) // DB areas always absolute + if( ScRangeData* pRangeData = pDoc->FindRangeNameBySheetAndIndex( t->GetSheet(), t->GetIndex()) ) + if( (nRecursion < 42) && HasRelRefIgnoringSheet0Relative( pDoc, pRangeData->GetCode(), nRecursion + 1 ) ) + return true; + } + break; + + // #i34474# function result dependent on cell position + case formula::svByte: + { + switch( t->GetOpCode() ) + { + case ocRow: // ROW() returns own row index + case ocColumn: // COLUMN() returns own column index + case ocSheet: // SHEET() returns own sheet index + case ocCell: // CELL() may return own cell address + return true; + default: + break; + } + } + break; + + default: + break; + } + } + } + return false; +} + +static bool HasOneSingleFullyRelativeReference( ScTokenArray* pTokens, ScSingleRefData& rOffset ) +{ + int nCount = 0; + if (pTokens) + { + formula::FormulaToken* t; + for( t = pTokens->First(); t; t = pTokens->Next() ) + { + switch( t->GetType() ) + { + case formula::svSingleRef: + { + ScSingleRefData& rRef1 = *t->GetSingleRef(); + if ( rRef1.IsColRel() && rRef1.IsRowRel() && !rRef1.IsFlag3D() && rRef1.IsTabRel() ) + { + nCount++; + if (nCount == 1) + { + rOffset = rRef1; + } + } + } + break; + + default: + break; + } + } + } + return nCount == 1; +} + void ScXMLConditionalFormatContext::EndElement() { ScDocument* pDoc = GetScImport().GetDocument(); SCTAB nTab = GetScImport().GetTables().GetCurrentSheet(); ScConditionalFormat* pFormat = mxFormat.release(); + + bool bEligibleForCache = true; + bool bSingleRelativeReference = false; + ScSingleRefData aOffsetForSingleRelRef; + ScTokenArray* pTokens = nullptr; + for (size_t nFormatEntryIx = 0; nFormatEntryIx < pFormat->size(); ++nFormatEntryIx) + { + auto pFormatEntry = pFormat->GetEntry(nFormatEntryIx); + auto pCondFormatEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry); + + if (pCondFormatEntry->GetOperation() != SC_COND_EQUAL && + pCondFormatEntry->GetOperation() != SC_COND_DIRECT) + { + bEligibleForCache = false; + break; + } + + ScAddress aSrcPos; + OUString aSrcString = pCondFormatEntry->GetSrcString(); + if ( !aSrcString.isEmpty() ) + aSrcPos.Parse( aSrcString, pDoc ); + ScCompiler aComp( pDoc, aSrcPos ); + aComp.SetGrammar( formula::FormulaGrammar::GRAM_ODFF ); + pTokens = aComp.CompileString( pCondFormatEntry->GetExpression(aSrcPos, 0), "" ); + if (HasRelRefIgnoringSheet0Relative( pDoc, pTokens )) + { + // In general not eligible, but some might be. We handle one very special case: When the + // conditional format has one entry, the reference position is the first cell of the + // range, and with a single fully relative reference in its expression. (Possibly these + // conditions could be loosened, but I am too tired to think on that right now.) + if (pFormat->size() == 1 && + pFormat->GetRange().size() == 1 && + pFormat->GetRange()[0]->aStart == aSrcPos && + HasOneSingleFullyRelativeReference( pTokens, aOffsetForSingleRelRef )) + { + bSingleRelativeReference = true; + } + else + { + bEligibleForCache = false; + break; + } + } + } + + if (bEligibleForCache) + { + for (auto& aCacheEntry : mrParent.maCache) + if (aCacheEntry.mnAge < SAL_MAX_INT64) + aCacheEntry.mnAge++; + + for (auto& aCacheEntry : mrParent.maCache) + { + if (!aCacheEntry.mpFormat) + continue; + + if (aCacheEntry.mpFormat->size() != pFormat->size()) + continue; + + // Check if the conditional format is identical to an existing one (but with different range) and can be shared + for (size_t nFormatEntryIx = 0; nFormatEntryIx < pFormat->size(); ++nFormatEntryIx) + { + auto pCacheFormatEntry = aCacheEntry.mpFormat->GetEntry(nFormatEntryIx); + auto pFormatEntry = pFormat->GetEntry(nFormatEntryIx); + if (pCacheFormatEntry->GetType() != pFormatEntry->GetType() || + pFormatEntry->GetType() != condformat::CONDITION) + break; + + auto pCacheCondFormatEntry = static_cast<const ScCondFormatEntry*>(pCacheFormatEntry); + auto pCondFormatEntry = static_cast<const ScCondFormatEntry*>(pFormatEntry); + + if (pCacheCondFormatEntry->GetStyle() != pCondFormatEntry->GetStyle()) + break; + + // Note That comparing the formulas of the ScConditionEntry at this stage is + // comparing just the *strings* of the formulas. For the bSingleRelativeReference + // case we compare the tokenized ("compiled") formulas. + if (bSingleRelativeReference) + { + if (aCacheEntry.mbSingleRelativeReference && + pTokens->EqualTokens(aCacheEntry.mpTokens.get())) + ; + else + break; + } + else if (!pCacheCondFormatEntry->EqualIgnoringSrcPos(*pCondFormatEntry)) + { + break; + } + // If we get here on the last round through the for loop, we have a cache hit + if (nFormatEntryIx == pFormat->size() - 1) + { + // Mark cache entry as fresh, do necessary mangling of it and just return + aCacheEntry.mnAge = 0; + for (size_t k = 0; k < pFormat->GetRange().size(); ++k) + aCacheEntry.mpFormat->GetRangeList().Join(*(pFormat->GetRange()[k])); + return; + } + } + } + + // Not found in cache, replace oldest cache entry + sal_Int64 nOldestAge = -1; + size_t nIndexOfOldest = 0; + for (auto& aCacheEntry : mrParent.maCache) + { + if (aCacheEntry.mnAge > nOldestAge) + { + nOldestAge = aCacheEntry.mnAge; + nIndexOfOldest = (&aCacheEntry - &mrParent.maCache.front()); + } + } + mrParent.maCache[nIndexOfOldest].mpFormat = pFormat; + mrParent.maCache[nIndexOfOldest].mbSingleRelativeReference = bSingleRelativeReference; + mrParent.maCache[nIndexOfOldest].mpTokens.reset(pTokens); + mrParent.maCache[nIndexOfOldest].mnAge = 0; + } + sal_uLong nIndex = pDoc->AddCondFormat(pFormat, nTab); - pFormat->SetKey(nIndex); + (void) nIndex; // Avoid 'unused variable' warning when assert() expands to empty + assert(pFormat->GetKey() == nIndex); - pDoc->AddCondFormatData( pFormat->GetRange(), nTab, nIndex); + mrParent.mvCondFormatData.push_back( { pFormat, nTab } ); } ScXMLConditionalFormatContext::~ScXMLConditionalFormatContext() diff --git a/sc/source/filter/xml/xmlcondformat.hxx b/sc/source/filter/xml/xmlcondformat.hxx index ca42c0b6eed5..7a94d6d7fe4a 100644 --- a/sc/source/filter/xml/xmlcondformat.hxx +++ b/sc/source/filter/xml/xmlcondformat.hxx @@ -10,9 +10,11 @@ #ifndef INCLUDED_SC_SOURCE_FILTER_XML_XMLCONDFORMAT_HXX #define INCLUDED_SC_SOURCE_FILTER_XML_XMLCONDFORMAT_HXX +#include <array> #include <xmloff/xmlictxt.hxx> #include "xmlimprt.hxx" #include "rangelst.hxx" +#include "tokenarray.hxx" class ScColorScaleFormat; class ScColorScaleEntry; @@ -23,6 +25,21 @@ struct ScIconSetFormatData; class ScXMLConditionalFormatsContext : public SvXMLImportContext { +private: + struct CacheEntry + { + ScConditionalFormat* mpFormat = nullptr; + bool mbSingleRelativeReference; + std::unique_ptr<const ScTokenArray> mpTokens; + sal_Int64 mnAge = SAL_MAX_INT64; + }; + + struct CondFormatData + { + ScConditionalFormat* mpFormat; + SCTAB mnTab; + }; + const ScXMLImport& GetScImport() const { return static_cast<const ScXMLImport&>(GetImport()); } ScXMLImport& GetScImport() { return static_cast<ScXMLImport&>(GetImport()); } public: @@ -36,6 +53,10 @@ public: const css::uno::Reference<css::xml::sax::XAttributeList>& xAttrList ) override; virtual void EndElement() override; + + std::array<CacheEntry, 4> maCache; + + std::vector<CondFormatData> mvCondFormatData; }; class ScXMLConditionalFormatContext : public SvXMLImportContext @@ -45,7 +66,8 @@ class ScXMLConditionalFormatContext : public SvXMLImportContext public: ScXMLConditionalFormatContext( ScXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName, - const css::uno::Reference<css::xml::sax::XAttributeList>& xAttrList); + const css::uno::Reference<css::xml::sax::XAttributeList>& xAttrList, + ScXMLConditionalFormatsContext& rParent ); virtual ~ScXMLConditionalFormatContext(); @@ -58,6 +80,8 @@ private: std::unique_ptr<ScConditionalFormat> mxFormat; ScRangeList maRange; + + ScXMLConditionalFormatsContext& mrParent; }; class ScXMLColorScaleFormatContext : public SvXMLImportContext commit 2aaa0c7dfbc431a0d9cd8946f0e016003da08bd1 Author: Tor Lillqvist <t...@collabora.com> Date: Tue Nov 28 12:38:03 2017 +0200 Do as the FIXME suggested Not exactly, though. The FIXME said "Make this a comparison operator at the TokenArray?" but I think that would be misleading as the code in question specifically does not check the TokenArrays for being completely identical; it intentionally ignores the RPN part. So make it a member function 'EqualTokens' instead. Change-Id: I15d840c422844fa144415a76c1f8fcbd6cae3c83 Reviewed-on: https://gerrit.libreoffice.org/45462 Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de> Tested-by: Thorsten Behrens <thorsten.behr...@cib.de> diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx index b2b4edd896b3..e37d8e97cf1d 100644 --- a/sc/inc/tokenarray.hxx +++ b/sc/inc/tokenarray.hxx @@ -58,6 +58,9 @@ public: /// Assignment with references to FormulaToken entries (not copied!) ScTokenArray( const ScTokenArray& ); virtual ~ScTokenArray(); + + bool EqualTokens( const ScTokenArray* pArr2 ) const; + void ClearScTokenArray(); ScTokenArray* Clone() const; /// True copy! diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx index 7fd1ef53ac69..68fa98beb206 100644 --- a/sc/source/core/data/conditio.cxx +++ b/sc/source/core/data/conditio.cxx @@ -663,26 +663,11 @@ void ScConditionEntry::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt ) StartListening(); } -//FIXME: Make this a comparison operator at the TokenArray? static bool lcl_IsEqual( const ScTokenArray* pArr1, const ScTokenArray* pArr2 ) { // We only compare the non-RPN array if ( pArr1 && pArr2 ) - { - sal_uInt16 nLen = pArr1->GetLen(); - if ( pArr2->GetLen() != nLen ) - return false; - - FormulaToken** ppToken1 = pArr1->GetArray(); - FormulaToken** ppToken2 = pArr2->GetArray(); - for (sal_uInt16 i=0; i<nLen; i++) - { - if ( ppToken1[i] != ppToken2[i] && - !(*ppToken1[i] == *ppToken2[i]) ) - return false; // Difference - } - return true; // All entries are the same - } + return pArr1->EqualTokens( pArr2 ); else return !pArr1 && !pArr2; // Both 0? -> the same } diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index 6671a5ab5dbc..ce2c7cd8b6cd 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -1770,6 +1770,23 @@ ScTokenArray& ScTokenArray::operator=( const ScTokenArray& rArr ) return *this; } +bool ScTokenArray::EqualTokens( const ScTokenArray* pArr2) const +{ + // We only compare the non-RPN array + if ( pArr2->nLen != nLen ) + return false; + + FormulaToken** ppToken1 = GetArray(); + FormulaToken** ppToken2 = pArr2->GetArray(); + for (sal_uInt16 i=0; i<nLen; i++) + { + if ( ppToken1[i] != ppToken2[i] && + !(*ppToken1[i] == *ppToken2[i]) ) + return false; // Difference + } + return true; // All entries are the same +} + void ScTokenArray::ClearScTokenArray() { Clear(); commit d26c8dab20e8b4b9ff09cada937abe6150c56840 Author: Szymon KÅos <szymon.k...@collabora.com> Date: Wed Nov 29 14:10:13 2017 +0100 tdf#76646 don't open link on Ctrl-click if not required Change-Id: Ie081f8144e50f576b9f8acb2ddd5b1c891533964 Reviewed-on: https://gerrit.libreoffice.org/45499 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Szymon KÅos <szymon.k...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/45555 Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de> Tested-by: Thorsten Behrens <thorsten.behr...@cib.de> diff --git a/sd/source/ui/func/fusel.cxx b/sd/source/ui/func/fusel.cxx index 425a4d9c857d..fa5fa58349bc 100644 --- a/sd/source/ui/func/fusel.cxx +++ b/sd/source/ui/func/fusel.cxx @@ -274,6 +274,8 @@ bool FuSelection::MouseButtonDown(const MouseEvent& rMEvt) SvtSecurityOptions aSecOpt; if (!rMEvt.IsMod1() && aSecOpt.IsOptionSet(SvtSecurityOptions::E_CTRLCLICK_HYPERLINK)) return true; + if (rMEvt.IsMod1() && !aSecOpt.IsOptionSet(SvtSecurityOptions::E_CTRLCLICK_HYPERLINK)) + return true; SfxStringItem aStrItem(SID_FILE_NAME, aVEvt.pURLField->GetURL()); SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName()); commit 51bf4f1bbdd0ea4817b2bbf8e09ecce6d6816b80 Author: Szymon KÅos <szymon.k...@collabora.com> Date: Tue Nov 28 20:15:47 2017 +0100 tdf#76646 Ctrl-click required for hyperlinks in draw/impress If "Ctrl-click required to follow hyperlinks" is set in Options -> LibreOffice -> Security -> Options open the link only with Ctrl key pressed. Change-Id: Icf57b4deedabd51f31f04021ba3f6bddc3829931 Reviewed-on: https://gerrit.libreoffice.org/45437 Tested-by: Jenkins <c...@libreoffice.org> Reviewed-by: Szymon KÅos <szymon.k...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/45554 Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de> Tested-by: Thorsten Behrens <thorsten.behr...@cib.de> diff --git a/sd/source/ui/func/fusel.cxx b/sd/source/ui/func/fusel.cxx index 2979c9099416..425a4d9c857d 100644 --- a/sd/source/ui/func/fusel.cxx +++ b/sd/source/ui/func/fusel.cxx @@ -27,6 +27,7 @@ #include <svtools/imapobj.hxx> #include <svl/urihelper.hxx> #include <unotools/localfilehelper.hxx> +#include <unotools/securityoptions.hxx> #include <svx/svxids.hrc> #include <svx/xfillit0.hxx> #include <sfx2/app.hxx> @@ -269,6 +270,11 @@ bool FuSelection::MouseButtonDown(const MouseEvent& rMEvt) aVEvt.eEvent == SDREVENT_EXECUTEURL ) { mpWindow->ReleaseMouse(); + + SvtSecurityOptions aSecOpt; + if (!rMEvt.IsMod1() && aSecOpt.IsOptionSet(SvtSecurityOptions::E_CTRLCLICK_HYPERLINK)) + return true; + SfxStringItem aStrItem(SID_FILE_NAME, aVEvt.pURLField->GetURL()); SfxStringItem aReferer(SID_REFERER, mpDocSh->GetMedium()->GetName()); SfxBoolItem aBrowseItem( SID_BROWSE, true ); commit e0dc344395393c8a9364952a5d241c12fa8b8f54 Author: Caolán McNamara <caol...@redhat.com> Date: Thu Nov 2 17:23:00 2017 +0000 Resolves: tdf#113160 changing all warning dialogs to non-modal is unsafe existing code doesn't expect that so stuff crashes partial revert of... commit db6b703d391838c481fd090065f6d329edcd4efa Date: Thu Aug 24 18:32:38 2017 +0200 Allow non-modal Dialogs during FileImport/Load Change-Id: I152feb849186cf035664a700d3f94ee049cdf6d3 Reviewed-on: https://gerrit.libreoffice.org/44227 Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> Related: tdf#113160 set a temporary dialog parent during type detection to get warning dialogs that don't block the existing windows but whose lifecycle can be controlled to avoid crashes during exit Change-Id: I57965301c3d8a031acb33e83bf7715fe132385d0 Reviewed-on: https://gerrit.libreoffice.org/45044 Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> Reviewed-on: https://gerrit.libreoffice.org/45400 Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de> Tested-by: Thorsten Behrens <thorsten.behr...@cib.de> diff --git a/framework/Library_fwe.mk b/framework/Library_fwe.mk index 0559236b2bad..d94cb100a975 100644 --- a/framework/Library_fwe.mk +++ b/framework/Library_fwe.mk @@ -46,6 +46,7 @@ $(eval $(call gb_Library_use_libraries,fwe,\ svl \ svt \ tl \ + tk \ utl \ vcl \ $(gb_UWINAPI) \ diff --git a/framework/source/dispatch/closedispatcher.cxx b/framework/source/dispatch/closedispatcher.cxx index 9aa25190a544..96df4fe9d9e5 100644 --- a/framework/source/dispatch/closedispatcher.cxx +++ b/framework/source/dispatch/closedispatcher.cxx @@ -36,8 +36,6 @@ #include <vcl/window.hxx> #include <vcl/svapp.hxx> #include <vcl/syswin.hxx> -#include <osl/mutex.hxx> -#include <vcl/dialog.hxx> #include <unotools/moduleoptions.hxx> #include <comphelper/processfactory.hxx> @@ -363,14 +361,6 @@ IMPL_LINK_NOARG_TYPED(CloseDispatcher, impl_asyncCallback, LinkParamNone*, void) } } - // if we still have dialogs open, temporary suppress termination - if (bTerminateApp && Dialog::AreDialogsOpen()) - { - Application::SetShutdownDelayed(); - bCloseFrame = true; - bTerminateApp = false; - } - // Do it now ... bool bSuccess = false; if (bCloseFrame) diff --git a/framework/source/fwe/interaction/preventduplicateinteraction.cxx b/framework/source/fwe/interaction/preventduplicateinteraction.cxx index 818fdfe2122a..9e43e1b1d44f 100644 --- a/framework/source/fwe/interaction/preventduplicateinteraction.cxx +++ b/framework/source/fwe/interaction/preventduplicateinteraction.cxx @@ -19,6 +19,7 @@ #include <framework/preventduplicateinteraction.hxx> +#include <comphelper/processfactory.hxx> #include <osl/diagnose.h> #include <com/sun/star/task/InteractionHandler.hpp> @@ -53,7 +54,9 @@ void PreventDuplicateInteraction::useDefaultUUIHandler() aLock.clear(); // <- SAFE - css::uno::Reference< css::task::XInteractionHandler > xHandler( css::task::InteractionHandler::createWithParent( m_xContext, nullptr ), css::uno::UNO_QUERY_THROW ); + m_xWarningDialogsParent.reset(new WarningDialogsParentScope(m_xContext)); + css::uno::Reference<css::task::XInteractionHandler> xHandler(css::task::InteractionHandler::createWithParent( + m_xContext, m_xWarningDialogsParent->GetDialogParent()), css::uno::UNO_QUERY_THROW); // SAFE -> aLock.reset(); @@ -236,6 +239,11 @@ bool PreventDuplicateInteraction::getInteractionInfo(const css::uno::Type& return false; } +IMPL_STATIC_LINK_NOARG_TYPED(WarningDialogsParent, TerminateDesktop, void*, void) +{ + css::frame::Desktop::create(comphelper::getProcessComponentContext())->terminate(); +} + } // namespace framework /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/loadenv/loadenv.cxx b/framework/source/loadenv/loadenv.cxx index c789f4d6e957..5e51c42bee83 100644 --- a/framework/source/loadenv/loadenv.cxx +++ b/framework/source/loadenv/loadenv.cxx @@ -378,10 +378,6 @@ void LoadEnv::startLoading() if (!bStarted) bStarted = impl_loadContent(); - // This may have triggered Dialogs (error cases) that may have - // delayed the shutdown, so give delayed shutdown a chance - Application::TriggerShutdownDelayed(); - // not started => general error // We can't say - what was the reason for. if (!bStarted) @@ -1077,7 +1073,7 @@ bool LoadEnv::impl_loadContent() if (!bHidden && !bMinimized && !bPreview && !xProgress.is()) { - // Note: its an optional interface! + // Note: it's an optional interface! css::uno::Reference< css::task::XStatusIndicatorFactory > xProgressFactory(xTargetFrame, css::uno::UNO_QUERY); if (xProgressFactory.is()) { diff --git a/include/framework/preventduplicateinteraction.hxx b/include/framework/preventduplicateinteraction.hxx index cf6ac0058eda..00c76089da2a 100644 --- a/include/framework/preventduplicateinteraction.hxx +++ b/include/framework/preventduplicateinteraction.hxx @@ -24,17 +24,127 @@ #include <vector> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/TerminationVetoException.hpp> +#include <com/sun/star/frame/XTerminateListener2.hpp> #include <com/sun/star/task/XInteractionHandler2.hpp> #include <com/sun/star/task/XInteractionRequest.hpp> +#include <cppuhelper/compbase.hxx> #include <cppuhelper/implbase.hxx> +#include <sfx2/app.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/dialog.hxx> +#include <vcl/svapp.hxx> +#include <vcl/wrkwin.hxx> + namespace com { namespace sun { namespace star { namespace uno { class XComponentContext; } } } } namespace framework{ +inline void closedialogs(SystemWindow& rTopLevel, bool bCloseRoot) +{ + for (vcl::Window *pChild = rTopLevel.GetWindow(GetWindowType::FirstTopWindowChild); pChild; pChild = rTopLevel.GetWindow(GetWindowType::NextTopWindowSibling)) + closedialogs(dynamic_cast<SystemWindow&>(*pChild), true); + if (bCloseRoot) + rTopLevel.Close(); +} + +// This is intended to be the parent for any warning dialogs launched +// during the load of a document so that those dialogs are modal to +// this window and don't block any existing windows. +// +// If there are dialog children open on exit then veto termination, +// close the topmost dialog and retry termination. +class WarningDialogsParent : + public cppu::WeakComponentImplHelper<css::frame::XTerminateListener> +{ +private: + osl::Mutex m_aLock; + VclPtr<WorkWindow> m_xWin; + css::uno::Reference<css::awt::XWindow> m_xInterface; + +private: + + DECL_STATIC_LINK_TYPED(WarningDialogsParent, TerminateDesktop, void*, void); + + void closewarningdialogs() + { + if (!m_xWin) + return; + SolarMutexGuard aSolarGuard; + closedialogs(dynamic_cast<SystemWindow&>(*m_xWin), false); + } + +public: + + using cppu::WeakComponentImplHelperBase::disposing; + virtual void SAL_CALL disposing(const css::lang::EventObject&) throw (::css::uno::RuntimeException, ::std::exception) override + { + } + + // XTerminateListener + virtual void SAL_CALL queryTermination(const css::lang::EventObject&) throw (::css::frame::TerminationVetoException, ::css::uno::RuntimeException, ::std::exception) override + { + closewarningdialogs(); + Application::PostUserEvent(LINK(this, WarningDialogsParent, TerminateDesktop)); + throw css::frame::TerminationVetoException(); + } + + virtual void SAL_CALL notifyTermination(const css::lang::EventObject&) throw (::css::uno::RuntimeException, ::std::exception) override + { + } + +public: + WarningDialogsParent() + : cppu::WeakComponentImplHelper<css::frame::XTerminateListener>(m_aLock) + { + SolarMutexGuard aSolarGuard; + m_xWin = VclPtr<WorkWindow>::Create(nullptr, WB_STDWORK); + m_xWin->SetText("dialog parent for warning dialogs during load"); + m_xInterface = VCLUnoHelper::GetInterface(m_xWin); + } + + virtual ~WarningDialogsParent() override + { + closewarningdialogs(); + m_xWin.disposeAndClear(); + } + + const css::uno::Reference<css::awt::XWindow>& GetDialogParent() const + { + return m_xInterface; + } +}; + +class WarningDialogsParentScope +{ +private: + css::uno::Reference<css::frame::XDesktop> m_xDesktop; + rtl::Reference<WarningDialogsParent> m_xListener; + +public: + WarningDialogsParentScope(const css::uno::Reference<css::uno::XComponentContext>& rContext) + : m_xDesktop(css::frame::Desktop::create(rContext), css::uno::UNO_QUERY_THROW) + , m_xListener(new WarningDialogsParent) + { + m_xDesktop->addTerminateListener(m_xListener.get()); + } + + const css::uno::Reference<css::awt::XWindow>& GetDialogParent() const + { + return m_xListener->GetDialogParent(); + } + + ~WarningDialogsParentScope() + { + m_xDesktop->removeTerminateListener(m_xListener.get()); + } +}; + /** @short Prevent us from showing the same interaction more than once during the same transaction. @@ -101,6 +211,8 @@ class FWE_DLLPUBLIC PreventDuplicateInteraction : private ThreadHelpBase2 if it's not blocked. */ css::uno::Reference< css::task::XInteractionHandler > m_xHandler; + std::unique_ptr<WarningDialogsParentScope> m_xWarningDialogsParent; + /** This list describe which and how incoming interactions must be handled. Further it contains all collected information after this interaction object was used.*/ diff --git a/include/vcl/dialog.hxx b/include/vcl/dialog.hxx index 87588d50c85d..34e03fc03a99 100644 --- a/include/vcl/dialog.hxx +++ b/include/vcl/dialog.hxx @@ -38,11 +38,8 @@ public: /** Use given parent or get a default one using GetDefaultParent(...) */ Default, - /** Suppress Parent so that Parent is not blocked (kind of modal mode) */ - NoParent, - - /** Suppress Parent (no modal, see above) and additionally center on default parent */ - NoParentCentered + /** No Parent */ + NoParent }; private: @@ -124,8 +121,7 @@ public: void EndDialog( long nResult = 0 ); - static void EndAllDialogs( vcl::Window* pParent=nullptr ); - static bool AreDialogsOpen(); + static void EndAllDialogs( vcl::Window const * pParent ); void GetDrawWindowBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const; diff --git a/include/vcl/msgbox.hxx b/include/vcl/msgbox.hxx index 0f526f618fe6..f3351664574c 100644 --- a/include/vcl/msgbox.hxx +++ b/include/vcl/msgbox.hxx @@ -47,8 +47,7 @@ protected: public: MessBox( vcl::Window* pParent, WinBits nStyle, - const OUString& rTitle, const OUString& rMessage, - Dialog::InitFlag eInitFlag = Dialog::InitFlag::NoParentCentered); + const OUString& rTitle, const OUString& rMessage); virtual ~MessBox(); virtual void dispose() override; diff --git a/include/vcl/svapp.hxx b/include/vcl/svapp.hxx index 2be63c268198..34b659fa7f33 100644 --- a/include/vcl/svapp.hxx +++ b/include/vcl/svapp.hxx @@ -1451,12 +1451,6 @@ public: // For vclbootstrapprotector: static void setDeInitHook(Link<LinkParamNone*,void> const & hook); - // for delayed shutdown: set using SetShutdownDelayed, then - // trigger using TriggerShutdownDelayed which may actually shutdown - // when SetShutdownDelayed is set - static void SetShutdownDelayed(); - static void TriggerShutdownDelayed(); - private: DECL_STATIC_LINK_TYPED( Application, PostEventHandler, void*, void ); }; diff --git a/uui/source/iahndl.cxx b/uui/source/iahndl.cxx index b53f5b474323..e94947ecc233 100644 --- a/uui/source/iahndl.cxx +++ b/uui/source/iahndl.cxx @@ -998,33 +998,10 @@ executeMessageBox( vcl::Window * pParent, OUString const & rTitle, OUString const & rMessage, - WinBits nButtonMask, - Dialog::InitFlag eInitFlag) + WinBits nStyle) { SolarMutexGuard aGuard; - ScopedVclPtrInstance< MessBox > xBox(pParent, nButtonMask, rTitle, rMessage, eInitFlag); - - if (Dialog::InitFlag::NoParentCentered == eInitFlag) - { - vcl::Window* pDefaultParent = Dialog::GetDefaultParent(nButtonMask); - - if (pDefaultParent) - { - // need to 'Show' to have the following tasks do someting, does - // not work without and may even stumble on nullptrs/errors - xBox->Show(); - - // center on parent window - const Point aP(pDefaultParent->GetPosPixel()); - const Size aS(pDefaultParent->GetSizePixel()); - const Size aMySize(xBox->GetSizePixel()); - - xBox->SetPosPixel( - Point( - aP.X() + ((aS.Width() - aMySize.Width()) >> 1), - aP.Y() + ((aS.Height() - aMySize.Height()) >> 1))); - } - } + ScopedVclPtrInstance< MessBox > xBox(pParent, nStyle, rTitle, rMessage); sal_uInt16 aResult = xBox->Execute(); switch( aResult ) @@ -1175,8 +1152,7 @@ UUIInteractionHelper::handleGenericErrorRequest( aTitle += " - " ; aTitle += aErrTitle; - executeMessageBox( - getParentProperty(), aTitle, aErrorString, WB_OK, Dialog::InitFlag::NoParentCentered); + executeMessageBox(getParentProperty(), aTitle, aErrorString, WB_OK); } else ErrorHandler::HandleError(nErrorCode); @@ -1299,8 +1275,7 @@ UUIInteractionHelper::handleBrokenPackageRequest( " " + utl::ConfigManager::getProductVersion() ); - switch ( - executeMessageBox( getParentProperty(), title, aMessage, nButtonMask, Dialog::InitFlag::NoParentCentered) ) + switch (executeMessageBox(getParentProperty(), title, aMessage, nButtonMask)) { case ERRCODE_BUTTON_OK: OSL_ENSURE( xAbort.is(), "unexpected situation" ); diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx index fc6fefc7d958..6af3c7c1c7cf 100644 --- a/vcl/source/app/svapp.cxx +++ b/vcl/source/app/svapp.cxx @@ -1816,20 +1816,4 @@ void Application::setDeInitHook(Link<LinkParamNone*,void> const & hook) { pSVData->maAppData.mbInAppMain = true; } -void Application::SetShutdownDelayed() -{ - ImplSVData * pSVData = ImplGetSVData(); - pSVData->maAppData.mbShutdownDelayed = true; -} - -void Application::TriggerShutdownDelayed() -{ - ImplSVData * pSVData = ImplGetSVData(); - - if (pSVData->maAppData.mbShutdownDelayed && !Dialog::AreDialogsOpen()) - { - Application::PostUserEvent(LINK(nullptr, ImplSVAppData, ImplPrepareExitMsg)); - } -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx index 95fed10ab0a6..d0aa084e777e 100644 --- a/vcl/source/window/dialog.cxx +++ b/vcl/source/window/dialog.cxx @@ -406,7 +406,7 @@ void Dialog::ImplInit( vcl::Window* pParent, WinBits nStyle, InitFlag eFlag ) // Now, all Dialogs are per default system windows !!! nStyle |= WB_SYSTEMWINDOW; - if (InitFlag::NoParent == eFlag || InitFlag::NoParentCentered == eFlag) + if (InitFlag::NoParent == eFlag) { pParent = nullptr; } @@ -992,7 +992,7 @@ long Dialog::GetResult() const return mpDialogImpl->mnResult; } -void Dialog::EndAllDialogs( vcl::Window* pParent ) +void Dialog::EndAllDialogs( vcl::Window const * pParent ) { ImplSVData* pSVData = ImplGetSVData(); Dialog* pTempModDialog; @@ -1009,14 +1009,6 @@ void Dialog::EndAllDialogs( vcl::Window* pParent ) } } -bool Dialog::AreDialogsOpen() -{ - ImplSVData* pSVData = ImplGetSVData(); - Dialog* pModDialog = pSVData->maWinData.mpLastExecuteDlg; - - return (nullptr != pModDialog); -} - void Dialog::SetModalInputMode( bool bModal ) { if ( bModal == mbModalMode ) diff --git a/vcl/source/window/msgbox.cxx b/vcl/source/window/msgbox.cxx index f6fd26773624..172c9870889c 100644 --- a/vcl/source/window/msgbox.cxx +++ b/vcl/source/window/msgbox.cxx @@ -138,12 +138,14 @@ void MessBox::ImplInitButtons() } MessBox::MessBox( vcl::Window* pParent, WinBits nStyle, - const OUString& rTitle, const OUString& rMessage, Dialog::InitFlag eInitFlag) : + const OUString& rTitle, const OUString& rMessage) : ButtonDialog( WINDOW_MESSBOX ), - maMessText( rMessage ) + maMessText( rMessage ), + mbHelpBtn( false ), + mbCheck( false ) { ImplInitMessBoxData(); - ImplInit( pParent, nStyle | WB_MOVEABLE | WB_HORZ | WB_CENTER, eInitFlag); + ImplInit( pParent, nStyle | WB_MOVEABLE | WB_HORZ | WB_CENTER); ImplInitButtons(); if ( !rTitle.isEmpty() )
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits