[Libreoffice-commits] core.git: Branch 'private/swe/libreoffice-5-2+backports' - 6 commits - framework/Library_fwe.mk framework/source include/framework include/vcl sc/CppunitTest_sc_cond_format_merge.mk sc/inc sc/Module_sc.mk sc/qa sc/source sd/source uui/source vcl/source
Mike Kaganski
mike.kaganski at collabora.com
Fri Dec 1 07:10:37 UTC 2017
Rebased ref, commits from common ancestor:
commit 7431394ad3a72ef960eb52f8718752f59e617567
Author: Mike Kaganski <mike.kaganski at 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 <ci at libreoffice.org>
Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/45570
Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Tested-by: Thorsten Behrens <Thorsten.Behrens at 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 <tml at 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.Behrens at CIB.de>
Tested-by: Thorsten Behrens <Thorsten.Behrens at 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 <tml at 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.Behrens at CIB.de>
Tested-by: Thorsten Behrens <Thorsten.Behrens at 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.klos at 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 <ci at libreoffice.org>
Reviewed-by: Szymon Kłos <szymon.klos at collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/45555
Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Tested-by: Thorsten Behrens <Thorsten.Behrens at 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.klos at 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 <ci at libreoffice.org>
Reviewed-by: Szymon Kłos <szymon.klos at collabora.com>
Reviewed-on: https://gerrit.libreoffice.org/45554
Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Tested-by: Thorsten Behrens <Thorsten.Behrens at 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 <caolanm at 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 <caolanm at redhat.com>
Tested-by: Caolán McNamara <caolanm at 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 <caolanm at redhat.com>
Tested-by: Caolán McNamara <caolanm at redhat.com>
Reviewed-on: https://gerrit.libreoffice.org/45400
Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>
Tested-by: Thorsten Behrens <Thorsten.Behrens at 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() )
More information about the Libreoffice-commits
mailing list