diff options
Diffstat (limited to 'sc/source/ui/unoobj/datauno.cxx')
-rw-r--r-- | sc/source/ui/unoobj/datauno.cxx | 2390 |
1 files changed, 2390 insertions, 0 deletions
diff --git a/sc/source/ui/unoobj/datauno.cxx b/sc/source/ui/unoobj/datauno.cxx new file mode 100644 index 000000000..effa5ed50 --- /dev/null +++ b/sc/source/ui/unoobj/datauno.cxx @@ -0,0 +1,2390 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <datauno.hxx> + +#include <svl/hint.hxx> +#include <svl/numformat.hxx> +#include <svl/sharedstringpool.hxx> +#include <vcl/svapp.hxx> +#include <unotools/charclass.hxx> +#include <osl/diagnose.h> + +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/util/SortField.hpp> +#include <com/sun/star/table/TableSortField.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/table/TableOrientation.hpp> +#include <com/sun/star/table/CellRangeAddress.hpp> +#include <com/sun/star/sheet/DataImportMode.hpp> +#include <com/sun/star/sheet/FilterFieldType.hpp> +#include <com/sun/star/sheet/FilterOperator2.hpp> +#include <com/sun/star/sheet/TableFilterField2.hpp> + +#include <dapiuno.hxx> +#include <cellsuno.hxx> +#include <miscuno.hxx> +#include <targuno.hxx> +#include <rangeutl.hxx> +#include <dbdata.hxx> +#include <docsh.hxx> +#include <dbdocfun.hxx> +#include <unonames.hxx> +#include <globalnames.hxx> +#include <convuno.hxx> +#include <hints.hxx> +#include <attrib.hxx> +#include <dpshttab.hxx> +#include <queryentry.hxx> +#include <dputil.hxx> +#include <sortparam.hxx> +#include <dpobject.hxx> +#include <filterentries.hxx> + +#include <comphelper/extract.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <svx/dataaccessdescriptor.hxx> + +#include <memory> + +using namespace com::sun::star; +using namespace css::sheet; + +// everything without Which-ID, map only for PropertySetInfo + +static const SfxItemPropertyMapEntry* lcl_GetSubTotalPropertyMap() +{ + // some old property names are for 5.2 compatibility + + static const SfxItemPropertyMapEntry aSubTotalPropertyMap_Impl[] = + { + { SC_UNONAME_BINDFMT, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_CASE, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_ENABSORT, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_ENUSLIST, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_FORMATS, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_INSBRK, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_ISCASE, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_MAXFLD, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0}, + { SC_UNONAME_SORTASC, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_ULIST, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_UINDEX, 0, cppu::UnoType<sal_Int32>::get(), 0, 0}, + { SC_UNONAME_USINDEX, 0, cppu::UnoType<sal_Int32>::get(), 0, 0}, + { u"", 0, css::uno::Type(), 0, 0 } + }; + return aSubTotalPropertyMap_Impl; +} + +static const SfxItemPropertyMapEntry* lcl_GetFilterPropertyMap() +{ + static const SfxItemPropertyMapEntry aFilterPropertyMap_Impl[] = + { + { SC_UNONAME_CONTHDR, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_COPYOUT, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_ISCASE, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_MAXFLD, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0}, + { SC_UNONAME_ORIENT, 0, cppu::UnoType<table::TableOrientation>::get(), 0, 0}, + { SC_UNONAME_OUTPOS, 0, cppu::UnoType<table::CellAddress>::get(), 0, 0}, + { SC_UNONAME_SAVEOUT, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_SKIPDUP, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_USEREGEX, 0, cppu::UnoType<bool>::get(), 0, 0}, + { u"", 0, css::uno::Type(), 0, 0 } + }; + return aFilterPropertyMap_Impl; +} + +static const SfxItemPropertyMapEntry* lcl_GetDBRangePropertyMap() +{ + static const SfxItemPropertyMapEntry aDBRangePropertyMap_Impl[] = + { + { SC_UNONAME_AUTOFLT, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_FLTCRT, 0, cppu::UnoType<table::CellRangeAddress>::get(), 0, 0}, + { SC_UNONAME_FROMSELECT,0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_ISUSER, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0 }, + { SC_UNONAME_KEEPFORM, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNO_LINKDISPBIT, 0, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0 }, + { SC_UNO_LINKDISPNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 }, + { SC_UNONAME_MOVCELLS, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_REFPERIOD, 0, cppu::UnoType<sal_Int32>::get(), 0, 0}, + { SC_UNONAME_STRIPDAT, 0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_TOKENINDEX,0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 }, + { SC_UNONAME_USEFLTCRT,0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_TOTALSROW,0, cppu::UnoType<bool>::get(), 0, 0}, + { SC_UNONAME_CONTHDR ,0, cppu::UnoType<bool>::get(), 0, 0}, + { u"", 0, css::uno::Type(), 0, 0 } + }; + return aDBRangePropertyMap_Impl; +} + +SC_SIMPLE_SERVICE_INFO( ScConsolidationDescriptor, "ScConsolidationDescriptor", "com.sun.star.sheet.ConsolidationDescriptor" ) +SC_SIMPLE_SERVICE_INFO( ScDatabaseRangesObj, "ScDatabaseRangesObj", "com.sun.star.sheet.DatabaseRanges" ) +SC_SIMPLE_SERVICE_INFO( ScFilterDescriptorBase, "ScFilterDescriptorBase", "com.sun.star.sheet.SheetFilterDescriptor" ) +SC_SIMPLE_SERVICE_INFO( ScSubTotalDescriptorBase, "ScSubTotalDescriptorBase", "com.sun.star.sheet.SubTotalDescriptor" ) +SC_SIMPLE_SERVICE_INFO( ScSubTotalFieldObj, "ScSubTotalFieldObj", "com.sun.star.sheet.SubTotalField" ) + +sheet::GeneralFunction ScDataUnoConversion::SubTotalToGeneral( ScSubTotalFunc eSubTotal ) +{ + sheet::GeneralFunction eGeneral; + switch (eSubTotal) + { + case SUBTOTAL_FUNC_NONE: eGeneral = sheet::GeneralFunction_NONE; break; + case SUBTOTAL_FUNC_AVE: eGeneral = sheet::GeneralFunction_AVERAGE; break; + case SUBTOTAL_FUNC_CNT: eGeneral = sheet::GeneralFunction_COUNTNUMS; break; + case SUBTOTAL_FUNC_CNT2: eGeneral = sheet::GeneralFunction_COUNT; break; + case SUBTOTAL_FUNC_MAX: eGeneral = sheet::GeneralFunction_MAX; break; + case SUBTOTAL_FUNC_MIN: eGeneral = sheet::GeneralFunction_MIN; break; + case SUBTOTAL_FUNC_PROD: eGeneral = sheet::GeneralFunction_PRODUCT; break; + case SUBTOTAL_FUNC_STD: eGeneral = sheet::GeneralFunction_STDEV; break; + case SUBTOTAL_FUNC_STDP: eGeneral = sheet::GeneralFunction_STDEVP; break; + case SUBTOTAL_FUNC_SUM: eGeneral = sheet::GeneralFunction_SUM; break; + case SUBTOTAL_FUNC_VAR: eGeneral = sheet::GeneralFunction_VAR; break; + case SUBTOTAL_FUNC_VARP: eGeneral = sheet::GeneralFunction_VARP; break; + default: + OSL_FAIL("SubTotalToGeneral: wrong enum"); + eGeneral = sheet::GeneralFunction_NONE; + break; + } + return eGeneral; +} + +void ScImportDescriptor::FillProperties( uno::Sequence<beans::PropertyValue>& rSeq, const ScImportParam& rParam ) +{ + OSL_ENSURE( rSeq.getLength() == GetPropertyCount(), "wrong Count" ); + + beans::PropertyValue* pArray = rSeq.getArray(); + + sheet::DataImportMode eMode = sheet::DataImportMode_NONE; + if ( rParam.bImport ) + { + if ( rParam.bSql ) + eMode = sheet::DataImportMode_SQL; + else if ( rParam.nType == ScDbQuery ) + eMode = sheet::DataImportMode_QUERY; + else + eMode = sheet::DataImportMode_TABLE; // type always ScDbQuery or ScDbTable + } + + svx::ODataAccessDescriptor aDescriptor; + aDescriptor.setDataSource(rParam.aDBName); + if (aDescriptor.has( svx::DataAccessDescriptorProperty::DataSource )) + { + pArray[0].Name = SC_UNONAME_DBNAME; + pArray[0].Value <<= rParam.aDBName; + } + else if (aDescriptor.has( svx::DataAccessDescriptorProperty::ConnectionResource )) + { + pArray[0].Name = SC_UNONAME_CONRES; + pArray[0].Value <<= rParam.aDBName; + } + + pArray[1].Name = SC_UNONAME_SRCTYPE; + pArray[1].Value <<= eMode; + + pArray[2].Name = SC_UNONAME_SRCOBJ; + pArray[2].Value <<= rParam.aStatement; + + pArray[3].Name = SC_UNONAME_ISNATIVE; + pArray[3].Value <<= rParam.bNative; +} + +void ScImportDescriptor::FillImportParam( ScImportParam& rParam, const uno::Sequence<beans::PropertyValue>& rSeq ) +{ + OUString aStrVal; + for (const beans::PropertyValue& rProp : rSeq) + { + OUString aPropName(rProp.Name); + + if (aPropName == SC_UNONAME_ISNATIVE) + rParam.bNative = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value ); + else if (aPropName == SC_UNONAME_DBNAME) + { + if ( rProp.Value >>= aStrVal ) + rParam.aDBName = aStrVal; + } + else if (aPropName == SC_UNONAME_CONRES) + { + if ( rProp.Value >>= aStrVal ) + rParam.aDBName = aStrVal; + } + else if (aPropName == SC_UNONAME_SRCOBJ) + { + if ( rProp.Value >>= aStrVal ) + rParam.aStatement = aStrVal; + } + else if (aPropName == SC_UNONAME_SRCTYPE) + { + //! test for correct enum type? + sheet::DataImportMode eMode = static_cast<sheet::DataImportMode>(ScUnoHelpFunctions::GetEnumFromAny( rProp.Value )); + switch (eMode) + { + case sheet::DataImportMode_NONE: + rParam.bImport = false; + break; + case sheet::DataImportMode_SQL: + rParam.bImport = true; + rParam.bSql = true; + break; + case sheet::DataImportMode_TABLE: + rParam.bImport = true; + rParam.bSql = false; + rParam.nType = ScDbTable; + break; + case sheet::DataImportMode_QUERY: + rParam.bImport = true; + rParam.bSql = false; + rParam.nType = ScDbQuery; + break; + default: + OSL_FAIL("wrong mode"); + rParam.bImport = false; + } + } + } +} + +void ScSortDescriptor::FillProperties( uno::Sequence<beans::PropertyValue>& rSeq, const ScSortParam& rParam ) +{ + OSL_ENSURE( rSeq.getLength() == GetPropertyCount(), "wrong count" ); + + beans::PropertyValue* pArray = rSeq.getArray(); + + // gather Uno values together + + table::CellAddress aOutPos; + aOutPos.Sheet = rParam.nDestTab; + aOutPos.Column = rParam.nDestCol; + aOutPos.Row = rParam.nDestRow; + + sal_uInt16 nSortCount = 0; + while ( nSortCount < rParam.GetSortKeyCount() && rParam.maKeyState[nSortCount].bDoSort ) + ++nSortCount; + + uno::Sequence<table::TableSortField> aFields(nSortCount); + if (nSortCount) + { + table::TableSortField* pFieldArray = aFields.getArray(); + for (sal_uInt16 i=0; i<nSortCount; i++) + { + pFieldArray[i].Field = rParam.maKeyState[i].nField; + pFieldArray[i].IsAscending = rParam.maKeyState[i].bAscending; + pFieldArray[i].FieldType = table::TableSortFieldType_AUTOMATIC; // always automatic + pFieldArray[i].IsCaseSensitive = rParam.bCaseSens; + pFieldArray[i].CollatorLocale = rParam.aCollatorLocale; + pFieldArray[i].CollatorAlgorithm = rParam.aCollatorAlgorithm; + } + } + + // fill the sequence + + pArray[0].Name = SC_UNONAME_ISSORTCOLUMNS; + pArray[0].Value <<= !rParam.bByRow; + + pArray[1].Name = SC_UNONAME_CONTHDR; + pArray[1].Value <<= rParam.bHasHeader; + + pArray[2].Name = SC_UNONAME_MAXFLD; + pArray[2].Value <<= static_cast<sal_Int32>( rParam.GetSortKeyCount() ); + + pArray[3].Name = SC_UNONAME_SORTFLD; + pArray[3].Value <<= aFields; + + pArray[4].Name = SC_UNONAME_BINDFMT; + pArray[4].Value <<= rParam.aDataAreaExtras.mbCellFormats; + + pArray[5].Name = SC_UNONAME_COPYOUT; + pArray[5].Value <<= !rParam.bInplace; + + pArray[6].Name = SC_UNONAME_OUTPOS; + pArray[6].Value <<= aOutPos; + + pArray[7].Name = SC_UNONAME_ISULIST; + pArray[7].Value <<= rParam.bUserDef; + + pArray[8].Name = SC_UNONAME_UINDEX; + pArray[8].Value <<= static_cast<sal_Int32>( rParam.nUserIndex ); +} + +void ScSortDescriptor::FillSortParam( ScSortParam& rParam, const uno::Sequence<beans::PropertyValue>& rSeq ) +{ + sal_Int32 nSortSize = static_cast<sal_Int32>(rParam.GetSortKeyCount()); + + for (const beans::PropertyValue& rProp : rSeq) + { + OUString aPropName(rProp.Name); + + if (aPropName == SC_UNONAME_ORIENT) + { + //! test for correct enum type? + table::TableOrientation eOrient = static_cast<table::TableOrientation>(ScUnoHelpFunctions::GetEnumFromAny( rProp.Value )); + rParam.bByRow = ( eOrient != table::TableOrientation_COLUMNS ); + } + else if (aPropName == SC_UNONAME_ISSORTCOLUMNS) + { + rParam.bByRow = !::cppu::any2bool(rProp.Value); + } + else if (aPropName == SC_UNONAME_CONTHDR) + rParam.bHasHeader = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value ); + else if (aPropName == SC_UNONAME_MAXFLD) + { + sal_Int32 nVal; + if ( (rProp.Value >>= nVal) && nVal > nSortSize ) + { + //! specify exceptions + //! throw lang::IllegalArgumentException(); + } + } + else if (aPropName == SC_UNONAME_SORTFLD) + { + uno::Sequence<util::SortField> aSeq; + uno::Sequence<table::TableSortField> aNewSeq; + if ( rProp.Value >>= aSeq ) + { + sal_Int32 nCount = aSeq.getLength(); + sal_Int32 i; + if ( nCount > static_cast<sal_Int32>( rParam.GetSortKeyCount() ) ) + { + // tdf#105301 - increase the size of the sorting keys + nSortSize = nCount; + rParam.maKeyState.resize(nCount); + } + const util::SortField* pFieldArray = aSeq.getConstArray(); + for (i=0; i<nCount; i++) + { + rParam.maKeyState[i].nField = static_cast<SCCOLROW>( pFieldArray[i].Field ); + rParam.maKeyState[i].bAscending = pFieldArray[i].SortAscending; + + // FieldType is ignored + rParam.maKeyState[i].bDoSort = true; + } + for (i=nCount; i<nSortSize; i++) + rParam.maKeyState[i].bDoSort = false; + } + else if ( rProp.Value >>= aNewSeq ) + { + sal_Int32 nCount = aNewSeq.getLength(); + sal_Int32 i; + if ( nCount > nSortSize ) + { + nCount = nSortSize; + rParam.maKeyState.resize(nCount); + } + const table::TableSortField* pFieldArray = aNewSeq.getConstArray(); + for (i=0; i<nCount; i++) + { + rParam.maKeyState[i].nField = static_cast<SCCOLROW>( pFieldArray[i].Field ); + rParam.maKeyState[i].bAscending = pFieldArray[i].IsAscending; + + // only one is possible, sometime we should make it possible to have different for every entry + rParam.bCaseSens = pFieldArray[i].IsCaseSensitive; + rParam.aCollatorLocale = pFieldArray[i].CollatorLocale; + rParam.aCollatorAlgorithm = pFieldArray[i].CollatorAlgorithm; + + // FieldType is ignored + rParam.maKeyState[i].bDoSort = true; + } + for (i=nCount; i<nSortSize; i++) + rParam.maKeyState[i].bDoSort = false; + } + } + else if (aPropName == SC_UNONAME_ISCASE) + { + rParam.bCaseSens = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value ); + } + else if (aPropName == SC_UNONAME_BINDFMT) + rParam.aDataAreaExtras.mbCellFormats = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value ); + else if (aPropName == SC_UNONAME_COPYOUT) + rParam.bInplace = !ScUnoHelpFunctions::GetBoolFromAny( rProp.Value ); + else if (aPropName == SC_UNONAME_OUTPOS) + { + table::CellAddress aAddress; + if ( rProp.Value >>= aAddress ) + { + rParam.nDestTab = aAddress.Sheet; + rParam.nDestCol = static_cast<SCCOL>(aAddress.Column); + rParam.nDestRow = static_cast<SCROW>(aAddress.Row); + } + } + else if (aPropName == SC_UNONAME_ISULIST) + rParam.bUserDef = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value ); + else if (aPropName == SC_UNONAME_UINDEX) + { + sal_Int32 nVal = 0; + if ( rProp.Value >>= nVal ) + rParam.nUserIndex = static_cast<sal_uInt16>(nVal); + } + else if (aPropName == SC_UNONAME_COLLLOC) + { + rProp.Value >>= rParam.aCollatorLocale; + } + else if (aPropName == SC_UNONAME_COLLALG) + { + OUString sStr; + if ( rProp.Value >>= sStr ) + rParam.aCollatorAlgorithm = sStr; + } + } +} + +ScSubTotalFieldObj::ScSubTotalFieldObj( ScSubTotalDescriptorBase* pDesc, sal_uInt16 nP ) : + xParent( pDesc ), + nPos( nP ) +{ + OSL_ENSURE(pDesc, "ScSubTotalFieldObj: Parent is 0"); +} + +ScSubTotalFieldObj::~ScSubTotalFieldObj() +{ +} + +// XSubTotalField + +sal_Int32 SAL_CALL ScSubTotalFieldObj::getGroupColumn() +{ + SolarMutexGuard aGuard; + ScSubTotalParam aParam; + xParent->GetData(aParam); + + return aParam.nField[nPos]; +} + +void SAL_CALL ScSubTotalFieldObj::setGroupColumn( sal_Int32 nGroupColumn ) +{ + SolarMutexGuard aGuard; + ScSubTotalParam aParam; + xParent->GetData(aParam); + + aParam.nField[nPos] = static_cast<SCCOL>(nGroupColumn); + + xParent->PutData(aParam); +} + +uno::Sequence<sheet::SubTotalColumn> SAL_CALL ScSubTotalFieldObj::getSubTotalColumns() +{ + SolarMutexGuard aGuard; + ScSubTotalParam aParam; + xParent->GetData(aParam); + + SCCOL nCount = aParam.nSubTotals[nPos]; + uno::Sequence<sheet::SubTotalColumn> aSeq(nCount); + sheet::SubTotalColumn* pAry = aSeq.getArray(); + for (SCCOL i=0; i<nCount; i++) + { + pAry[i].Column = aParam.pSubTotals[nPos][i]; + pAry[i].Function = ScDataUnoConversion::SubTotalToGeneral( + aParam.pFunctions[nPos][i] ); + } + return aSeq; +} + +void SAL_CALL ScSubTotalFieldObj::setSubTotalColumns( + const uno::Sequence<sheet::SubTotalColumn>& aSubTotalColumns ) +{ + SolarMutexGuard aGuard; + ScSubTotalParam aParam; + xParent->GetData(aParam); + + sal_uInt32 nColCount = aSubTotalColumns.getLength(); + if ( nColCount <= sal::static_int_cast<sal_uInt32>(SCCOL_MAX) ) + { + SCCOL nCount = static_cast<SCCOL>(nColCount); + aParam.nSubTotals[nPos] = nCount; + if (nCount != 0) + { + aParam.pSubTotals[nPos].reset(new SCCOL[nCount]); + aParam.pFunctions[nPos].reset(new ScSubTotalFunc[nCount]); + + const sheet::SubTotalColumn* pAry = aSubTotalColumns.getConstArray(); + for (SCCOL i=0; i<nCount; i++) + { + aParam.pSubTotals[nPos][i] = static_cast<SCCOL>(pAry[i].Column); + aParam.pFunctions[nPos][i] = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(pAry[i].Function)); + } + } + else + { + aParam.pSubTotals[nPos].reset(); + aParam.pFunctions[nPos].reset(); + } + } + //! otherwise exception or so? (too many columns) + + xParent->PutData(aParam); +} + +ScSubTotalDescriptorBase::ScSubTotalDescriptorBase() : + aPropSet( lcl_GetSubTotalPropertyMap() ) +{ +} + +ScSubTotalDescriptorBase::~ScSubTotalDescriptorBase() +{ +} + +// XSubTotalDescriptor + +rtl::Reference<ScSubTotalFieldObj> ScSubTotalDescriptorBase::GetObjectByIndex_Impl(sal_uInt16 nIndex) +{ + if ( nIndex < getCount() ) + return new ScSubTotalFieldObj( this, nIndex ); + return nullptr; +} + +void SAL_CALL ScSubTotalDescriptorBase::clear() +{ + SolarMutexGuard aGuard; + ScSubTotalParam aParam; + GetData(aParam); + + for (bool & rn : aParam.bGroupActive) + rn = false; + + //! notify the field objects??? + + PutData(aParam); +} + +void SAL_CALL ScSubTotalDescriptorBase::addNew( + const uno::Sequence<sheet::SubTotalColumn>& aSubTotalColumns, + sal_Int32 nGroupColumn ) +{ + SolarMutexGuard aGuard; + ScSubTotalParam aParam; + GetData(aParam); + + sal_uInt16 nPos = 0; + while ( nPos < MAXSUBTOTAL && aParam.bGroupActive[nPos] ) + ++nPos; + + sal_uInt32 nColCount = aSubTotalColumns.getLength(); + + if ( nPos >= MAXSUBTOTAL || nColCount > sal::static_int_cast<sal_uInt32>(SCCOL_MAX) ) + // too many fields / columns + throw uno::RuntimeException(); // no other exceptions specified + + aParam.bGroupActive[nPos] = true; + aParam.nField[nPos] = static_cast<SCCOL>(nGroupColumn); + + aParam.pSubTotals[nPos].reset(); + aParam.pFunctions[nPos].reset(); + + SCCOL nCount = static_cast<SCCOL>(nColCount); + aParam.nSubTotals[nPos] = nCount; + if (nCount != 0) + { + aParam.pSubTotals[nPos].reset(new SCCOL[nCount]); + aParam.pFunctions[nPos].reset(new ScSubTotalFunc[nCount]); + + const sheet::SubTotalColumn* pAry = aSubTotalColumns.getConstArray(); + for (SCCOL i=0; i<nCount; i++) + { + aParam.pSubTotals[nPos][i] = static_cast<SCCOL>(pAry[i].Column); + aParam.pFunctions[nPos][i] = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(pAry[i].Function)); + } + } + else + { + aParam.pSubTotals[nPos].reset(); + aParam.pFunctions[nPos].reset(); + } + + PutData(aParam); +} + +// flags/settings as properties + +// XEnumerationAccess + +uno::Reference<container::XEnumeration> SAL_CALL ScSubTotalDescriptorBase::createEnumeration() +{ + SolarMutexGuard aGuard; + return new ScIndexEnumeration(this, "com.sun.star.sheet.SubTotalFieldsEnumeration"); +} + +// XIndexAccess + +sal_Int32 SAL_CALL ScSubTotalDescriptorBase::getCount() +{ + SolarMutexGuard aGuard; + ScSubTotalParam aParam; + GetData(aParam); + + sal_uInt16 nCount = 0; + while ( nCount < MAXSUBTOTAL && aParam.bGroupActive[nCount] ) + ++nCount; + return nCount; +} + +uno::Any SAL_CALL ScSubTotalDescriptorBase::getByIndex( sal_Int32 nIndex ) +{ + SolarMutexGuard aGuard; + uno::Reference<sheet::XSubTotalField> xField(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex))); + if (!xField.is()) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(xField); +} + +uno::Type SAL_CALL ScSubTotalDescriptorBase::getElementType() +{ + return cppu::UnoType<sheet::XSubTotalField>::get(); +} + +sal_Bool SAL_CALL ScSubTotalDescriptorBase::hasElements() +{ + SolarMutexGuard aGuard; + return ( getCount() != 0 ); +} + +// XPropertySet + +uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSubTotalDescriptorBase::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + static uno::Reference<beans::XPropertySetInfo> aRef( + new SfxItemPropertySetInfo( aPropSet.getPropertyMap() )); + return aRef; +} + +void SAL_CALL ScSubTotalDescriptorBase::setPropertyValue( + const OUString& aPropertyName, const uno::Any& aValue ) +{ + SolarMutexGuard aGuard; + ScSubTotalParam aParam; + GetData(aParam); + + // some old property names are for 5.2 compatibility + + if (aPropertyName == SC_UNONAME_CASE || aPropertyName == SC_UNONAME_ISCASE ) + aParam.bCaseSens = ScUnoHelpFunctions::GetBoolFromAny( aValue ); + else if (aPropertyName == SC_UNONAME_FORMATS || aPropertyName == SC_UNONAME_BINDFMT ) + aParam.bIncludePattern = ScUnoHelpFunctions::GetBoolFromAny( aValue ); + else if (aPropertyName == SC_UNONAME_ENABSORT ) + aParam.bDoSort = ScUnoHelpFunctions::GetBoolFromAny( aValue ); + else if (aPropertyName == SC_UNONAME_SORTASC ) + aParam.bAscending = ScUnoHelpFunctions::GetBoolFromAny( aValue ); + else if (aPropertyName == SC_UNONAME_INSBRK ) + aParam.bPagebreak = ScUnoHelpFunctions::GetBoolFromAny( aValue ); + else if (aPropertyName == SC_UNONAME_ULIST || aPropertyName == SC_UNONAME_ENUSLIST ) + aParam.bUserDef = ScUnoHelpFunctions::GetBoolFromAny( aValue ); + else if (aPropertyName == SC_UNONAME_UINDEX || aPropertyName == SC_UNONAME_USINDEX ) + { + sal_Int32 nVal = 0; + if ( aValue >>= nVal ) + aParam.nUserIndex = static_cast<sal_uInt16>(nVal); + } + else if (aPropertyName == SC_UNONAME_MAXFLD ) + { + sal_Int32 nVal = 0; + if ( (aValue >>= nVal) && nVal > sal::static_int_cast<sal_Int32>(MAXSUBTOTAL) ) + { + throw lang::IllegalArgumentException(); + } + } + + PutData(aParam); +} + +uno::Any SAL_CALL ScSubTotalDescriptorBase::getPropertyValue( const OUString& aPropertyName ) +{ + SolarMutexGuard aGuard; + ScSubTotalParam aParam; + GetData(aParam); + + uno::Any aRet; + + // some old property names are for 5.2 compatibility + + if (aPropertyName == SC_UNONAME_CASE || aPropertyName == SC_UNONAME_ISCASE ) + aRet <<= aParam.bCaseSens; + else if (aPropertyName == SC_UNONAME_FORMATS || aPropertyName == SC_UNONAME_BINDFMT ) + aRet <<= aParam.bIncludePattern; + else if (aPropertyName == SC_UNONAME_ENABSORT ) + aRet <<= aParam.bDoSort; + else if (aPropertyName == SC_UNONAME_SORTASC ) + aRet <<= aParam.bAscending; + else if (aPropertyName == SC_UNONAME_INSBRK ) + aRet <<= aParam.bPagebreak; + else if (aPropertyName == SC_UNONAME_ULIST || aPropertyName == SC_UNONAME_ENUSLIST ) + aRet <<= aParam.bUserDef; + else if (aPropertyName == SC_UNONAME_UINDEX || aPropertyName == SC_UNONAME_USINDEX ) + aRet <<= static_cast<sal_Int32>(aParam.nUserIndex); + else if (aPropertyName == SC_UNONAME_MAXFLD ) + aRet <<= sal_Int32(MAXSUBTOTAL); + + return aRet; +} + +SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSubTotalDescriptorBase ) + +// XUnoTunnel + +UNO3_GETIMPLEMENTATION_IMPL(ScSubTotalDescriptorBase); + +ScSubTotalDescriptor::ScSubTotalDescriptor() +{ +} + +ScSubTotalDescriptor::~ScSubTotalDescriptor() +{ +} + +void ScSubTotalDescriptor::GetData( ScSubTotalParam& rParam ) const +{ + rParam = aStoredParam; // query for interface +} + +void ScSubTotalDescriptor::PutData( const ScSubTotalParam& rParam ) +{ + aStoredParam = rParam; // set by the interface +} + +void ScSubTotalDescriptor::SetParam( const ScSubTotalParam& rNew ) +{ + aStoredParam = rNew; // set from outside +} + +ScRangeSubTotalDescriptor::ScRangeSubTotalDescriptor(ScDatabaseRangeObj* pPar) : + mxParent(pPar) +{ +} + +ScRangeSubTotalDescriptor::~ScRangeSubTotalDescriptor() +{ +} + +void ScRangeSubTotalDescriptor::GetData( ScSubTotalParam& rParam ) const +{ + if (mxParent.is()) + mxParent->GetSubTotalParam( rParam ); +} + +void ScRangeSubTotalDescriptor::PutData( const ScSubTotalParam& rParam ) +{ + if (mxParent.is()) + mxParent->SetSubTotalParam( rParam ); +} + +ScConsolidationDescriptor::ScConsolidationDescriptor() +{ +} + +ScConsolidationDescriptor::~ScConsolidationDescriptor() +{ +} + +void ScConsolidationDescriptor::SetParam( const ScConsolidateParam& rNew ) +{ + aParam = rNew; +} + +// XConsolidationDescriptor + +sheet::GeneralFunction SAL_CALL ScConsolidationDescriptor::getFunction() +{ + SolarMutexGuard aGuard; + return ScDataUnoConversion::SubTotalToGeneral(aParam.eFunction); +} + +void SAL_CALL ScConsolidationDescriptor::setFunction( sheet::GeneralFunction nFunction ) +{ + SolarMutexGuard aGuard; + aParam.eFunction = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(nFunction)); +} + +uno::Sequence<table::CellRangeAddress> SAL_CALL ScConsolidationDescriptor::getSources() +{ + SolarMutexGuard aGuard; + sal_uInt16 nCount = aParam.nDataAreaCount; + if (!aParam.pDataAreas) + nCount = 0; + table::CellRangeAddress aRange; + uno::Sequence<table::CellRangeAddress> aSeq(nCount); + table::CellRangeAddress* pAry = aSeq.getArray(); + for (sal_uInt16 i=0; i<nCount; i++) + { + ScArea const & rArea = aParam.pDataAreas[i]; + aRange.Sheet = rArea.nTab; + aRange.StartColumn = rArea.nColStart; + aRange.StartRow = rArea.nRowStart; + aRange.EndColumn = rArea.nColEnd; + aRange.EndRow = rArea.nRowEnd; + pAry[i] = aRange; + } + return aSeq; +} + +void SAL_CALL ScConsolidationDescriptor::setSources( + const uno::Sequence<table::CellRangeAddress>& aSources ) +{ + SolarMutexGuard aGuard; + sal_uInt16 nCount = static_cast<sal_uInt16>(aSources.getLength()); + if (nCount) + { + const table::CellRangeAddress* pAry = aSources.getConstArray(); + std::unique_ptr<ScArea[]> pNew(new ScArea[nCount]); + sal_uInt16 i; + for (i=0; i<nCount; i++) + pNew[i] = ScArea( pAry[i].Sheet, + static_cast<SCCOL>(pAry[i].StartColumn), pAry[i].StartRow, + static_cast<SCCOL>(pAry[i].EndColumn), pAry[i].EndRow ); + + aParam.SetAreas( std::move(pNew), nCount ); // copy everything + } + else + aParam.ClearDataAreas(); +} + +table::CellAddress SAL_CALL ScConsolidationDescriptor::getStartOutputPosition() +{ + SolarMutexGuard aGuard; + table::CellAddress aPos; + aPos.Column = aParam.nCol; + aPos.Row = aParam.nRow; + aPos.Sheet = aParam.nTab; + return aPos; +} + +void SAL_CALL ScConsolidationDescriptor::setStartOutputPosition( + const table::CellAddress& aStartOutputPosition ) +{ + SolarMutexGuard aGuard; + aParam.nCol = static_cast<SCCOL>(aStartOutputPosition.Column); + aParam.nRow = static_cast<SCROW>(aStartOutputPosition.Row); + aParam.nTab = aStartOutputPosition.Sheet; +} + +sal_Bool SAL_CALL ScConsolidationDescriptor::getUseColumnHeaders() +{ + SolarMutexGuard aGuard; + return aParam.bByCol; +} + +void SAL_CALL ScConsolidationDescriptor::setUseColumnHeaders( sal_Bool bUseColumnHeaders ) +{ + SolarMutexGuard aGuard; + aParam.bByCol = bUseColumnHeaders; +} + +sal_Bool SAL_CALL ScConsolidationDescriptor::getUseRowHeaders() +{ + SolarMutexGuard aGuard; + return aParam.bByRow; +} + +void SAL_CALL ScConsolidationDescriptor::setUseRowHeaders( sal_Bool bUseRowHeaders ) +{ + SolarMutexGuard aGuard; + aParam.bByRow = bUseRowHeaders; +} + +sal_Bool SAL_CALL ScConsolidationDescriptor::getInsertLinks() +{ + SolarMutexGuard aGuard; + return aParam.bReferenceData; +} + +void SAL_CALL ScConsolidationDescriptor::setInsertLinks( sal_Bool bInsertLinks ) +{ + SolarMutexGuard aGuard; + aParam.bReferenceData = bInsertLinks; +} + +ScFilterDescriptorBase::ScFilterDescriptorBase(ScDocShell* pDocShell) : + aPropSet( lcl_GetFilterPropertyMap() ), + pDocSh(pDocShell) +{ + if (pDocSh) + pDocSh->GetDocument().AddUnoObject(*this); +} + +ScFilterDescriptorBase::~ScFilterDescriptorBase() +{ + SolarMutexGuard g; + + if (pDocSh) + pDocSh->GetDocument().RemoveUnoObject(*this); +} + +void ScFilterDescriptorBase::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + if ( rHint.GetId() == SfxHintId::Dying ) + { + pDocSh = nullptr; // invalid + } +} + +// XSheetFilterDescriptor and XSheetFilterDescriptor2 + +uno::Sequence<sheet::TableFilterField> SAL_CALL ScFilterDescriptorBase::getFilterFields() +{ + SolarMutexGuard aGuard; + ScQueryParam aParam; + GetData(aParam); + + SCSIZE nEntries = aParam.GetEntryCount(); // allocated entries in Param + SCSIZE nCount = 0; // active + while ( nCount < nEntries && + aParam.GetEntry(nCount).bDoQuery ) + ++nCount; + + sheet::TableFilterField aField; + uno::Sequence<sheet::TableFilterField> aSeq(static_cast<sal_Int32>(nCount)); + sheet::TableFilterField* pAry = aSeq.getArray(); + for (SCSIZE i=0; i<nCount; i++) + { + const ScQueryEntry& rEntry = aParam.GetEntry(i); + if (rEntry.GetQueryItems().empty()) + continue; + + const ScQueryEntry::Item& rItem = rEntry.GetQueryItems().front(); + + aField.Connection = (rEntry.eConnect == SC_AND) ? sheet::FilterConnection_AND : + sheet::FilterConnection_OR; + aField.Field = rEntry.nField; + aField.IsNumeric = rItem.meType != ScQueryEntry::ByString; + aField.StringValue = rItem.maString.getString(); + aField.NumericValue = rItem.mfVal; + + switch (rEntry.eOp) // ScQueryOp + { + case SC_EQUAL: + { + aField.Operator = sheet::FilterOperator_EQUAL; + if (rEntry.IsQueryByEmpty()) + { + aField.Operator = sheet::FilterOperator_EMPTY; + aField.NumericValue = 0; + } + else if (rEntry.IsQueryByNonEmpty()) + { + aField.Operator = sheet::FilterOperator_NOT_EMPTY; + aField.NumericValue = 0; + } + } + break; + case SC_LESS: aField.Operator = sheet::FilterOperator_LESS; break; + case SC_GREATER: aField.Operator = sheet::FilterOperator_GREATER; break; + case SC_LESS_EQUAL: aField.Operator = sheet::FilterOperator_LESS_EQUAL; break; + case SC_GREATER_EQUAL: aField.Operator = sheet::FilterOperator_GREATER_EQUAL; break; + case SC_NOT_EQUAL: aField.Operator = sheet::FilterOperator_NOT_EQUAL; break; + case SC_TOPVAL: aField.Operator = sheet::FilterOperator_TOP_VALUES; break; + case SC_BOTVAL: aField.Operator = sheet::FilterOperator_BOTTOM_VALUES; break; + case SC_TOPPERC: aField.Operator = sheet::FilterOperator_TOP_PERCENT; break; + case SC_BOTPERC: aField.Operator = sheet::FilterOperator_BOTTOM_PERCENT; break; + default: + OSL_FAIL("wrong filter enum"); + aField.Operator = sheet::FilterOperator_EMPTY; + } + pAry[i] = aField; + } + return aSeq; +} + +namespace { + +template<typename T> +void convertQueryEntryToUno(const ScQueryEntry& rEntry, T& rField) +{ + rField.Connection = (rEntry.eConnect == SC_AND) ? sheet::FilterConnection_AND : sheet::FilterConnection_OR; + rField.Field = rEntry.nField; + + switch (rEntry.eOp) // ScQueryOp + { + case SC_EQUAL: rField.Operator = sheet::FilterOperator2::EQUAL; break; + case SC_LESS: rField.Operator = sheet::FilterOperator2::LESS; break; + case SC_GREATER: rField.Operator = sheet::FilterOperator2::GREATER; break; + case SC_LESS_EQUAL: rField.Operator = sheet::FilterOperator2::LESS_EQUAL; break; + case SC_GREATER_EQUAL: rField.Operator = sheet::FilterOperator2::GREATER_EQUAL; break; + case SC_NOT_EQUAL: rField.Operator = sheet::FilterOperator2::NOT_EQUAL; break; + case SC_TOPVAL: rField.Operator = sheet::FilterOperator2::TOP_VALUES; break; + case SC_BOTVAL: rField.Operator = sheet::FilterOperator2::BOTTOM_VALUES; break; + case SC_TOPPERC: rField.Operator = sheet::FilterOperator2::TOP_PERCENT; break; + case SC_BOTPERC: rField.Operator = sheet::FilterOperator2::BOTTOM_PERCENT; break; + case SC_CONTAINS: rField.Operator = sheet::FilterOperator2::CONTAINS; break; + case SC_DOES_NOT_CONTAIN: rField.Operator = sheet::FilterOperator2::DOES_NOT_CONTAIN; break; + case SC_BEGINS_WITH: rField.Operator = sheet::FilterOperator2::BEGINS_WITH; break; + case SC_DOES_NOT_BEGIN_WITH: rField.Operator = sheet::FilterOperator2::DOES_NOT_BEGIN_WITH; break; + case SC_ENDS_WITH: rField.Operator = sheet::FilterOperator2::ENDS_WITH; break; + case SC_DOES_NOT_END_WITH: rField.Operator = sheet::FilterOperator2::DOES_NOT_END_WITH; break; + default: + OSL_FAIL("Unknown filter operator value."); + rField.Operator = sheet::FilterOperator2::EMPTY; + } +} + +template<typename T> +void convertUnoToQueryEntry(const T& rField, ScQueryEntry& rEntry) +{ + rEntry.bDoQuery = true; + rEntry.eConnect = (rField.Connection == sheet::FilterConnection_AND) ? SC_AND : SC_OR; + rEntry.nField = rField.Field; + + switch (rField.Operator) // FilterOperator + { + case sheet::FilterOperator2::EQUAL: rEntry.eOp = SC_EQUAL; break; + case sheet::FilterOperator2::LESS: rEntry.eOp = SC_LESS; break; + case sheet::FilterOperator2::GREATER: rEntry.eOp = SC_GREATER; break; + case sheet::FilterOperator2::LESS_EQUAL: rEntry.eOp = SC_LESS_EQUAL; break; + case sheet::FilterOperator2::GREATER_EQUAL: rEntry.eOp = SC_GREATER_EQUAL; break; + case sheet::FilterOperator2::NOT_EQUAL: rEntry.eOp = SC_NOT_EQUAL; break; + case sheet::FilterOperator2::TOP_VALUES: rEntry.eOp = SC_TOPVAL; break; + case sheet::FilterOperator2::BOTTOM_VALUES: rEntry.eOp = SC_BOTVAL; break; + case sheet::FilterOperator2::TOP_PERCENT: rEntry.eOp = SC_TOPPERC; break; + case sheet::FilterOperator2::BOTTOM_PERCENT: rEntry.eOp = SC_BOTPERC; break; + case sheet::FilterOperator2::CONTAINS: rEntry.eOp = SC_CONTAINS; break; + case sheet::FilterOperator2::DOES_NOT_CONTAIN: rEntry.eOp = SC_DOES_NOT_CONTAIN; break; + case sheet::FilterOperator2::BEGINS_WITH: rEntry.eOp = SC_BEGINS_WITH; break; + case sheet::FilterOperator2::DOES_NOT_BEGIN_WITH: rEntry.eOp = SC_DOES_NOT_BEGIN_WITH;break; + case sheet::FilterOperator2::ENDS_WITH: rEntry.eOp = SC_ENDS_WITH; break; + case sheet::FilterOperator2::DOES_NOT_END_WITH: rEntry.eOp = SC_DOES_NOT_END_WITH; break; + case sheet::FilterOperator2::EMPTY: + rEntry.SetQueryByEmpty(); + break; + case sheet::FilterOperator2::NOT_EMPTY: + rEntry.SetQueryByNonEmpty(); + break; + default: + OSL_FAIL("Unknown filter operator type."); + rEntry.eOp = SC_EQUAL; + } +} + +void fillQueryParam( + ScQueryParam& rParam, ScDocument* pDoc, + const uno::Sequence<sheet::TableFilterField2>& aFilterFields) +{ + size_t nCount = static_cast<size_t>(aFilterFields.getLength()); + rParam.Resize(nCount); + + const sheet::TableFilterField2* pAry = aFilterFields.getConstArray(); + svl::SharedStringPool& rPool = pDoc->GetSharedStringPool(); + for (size_t i = 0; i < nCount; ++i) + { + ScQueryEntry& rEntry = rParam.GetEntry(i); + convertUnoToQueryEntry(pAry[i], rEntry); + + if (pAry[i].Operator != sheet::FilterOperator2::EMPTY && pAry[i].Operator != sheet::FilterOperator2::NOT_EMPTY) + { + ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems(); + rItems.resize(1); + ScQueryEntry::Item& rItem = rItems.front(); + rItem.meType = pAry[i].IsNumeric ? ScQueryEntry::ByValue : ScQueryEntry::ByString; + rItem.mfVal = pAry[i].NumericValue; + rItem.maString = rPool.intern(pAry[i].StringValue); + + if (rItem.meType == ScQueryEntry::ByValue) + { + OUString aStr; + pDoc->GetFormatTable()->GetInputLineString(rItem.mfVal, 0, aStr); + rItem.maString = rPool.intern(aStr); + } + } + } + + size_t nParamCount = rParam.GetEntryCount(); // if below eight Param isn't resized + for (size_t i = nCount; i < nParamCount; ++i) + rParam.GetEntry(i).bDoQuery = false; // reset surplus fields +} + +void fillQueryParam( + ScQueryParam& rParam, ScDocument* pDoc, + const uno::Sequence<sheet::TableFilterField3>& aFilterFields) +{ + size_t nCount = static_cast<size_t>(aFilterFields.getLength()); + rParam.Resize(nCount); + + svl::SharedStringPool& rPool = pDoc->GetSharedStringPool(); + const sheet::TableFilterField3* pAry = aFilterFields.getConstArray(); + for (size_t i = 0; i < nCount; ++i) + { + ScQueryEntry& rEntry = rParam.GetEntry(i); + convertUnoToQueryEntry(pAry[i], rEntry); + + if (pAry[i].Operator != sheet::FilterOperator2::EMPTY && pAry[i].Operator != sheet::FilterOperator2::NOT_EMPTY) + { + ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems(); + rItems.clear(); + const uno::Sequence<sheet::FilterFieldValue>& rVals = pAry[i].Values; + for (const auto& rVal : rVals) + { + ScQueryEntry::Item aItem; + switch (rVal.FilterType) + { + case FilterFieldType::NUMERIC: + aItem.meType = ScQueryEntry::ByValue; + break; + case FilterFieldType::STRING: + aItem.meType = ScQueryEntry::ByString; + break; + case FilterFieldType::DATE: + aItem.meType = ScQueryEntry::ByDate; + break; + case FilterFieldType::TEXT_COLOR: + aItem.meType = ScQueryEntry::ByTextColor; + break; + case FilterFieldType::BACKGROUND_COLOR: + aItem.meType = ScQueryEntry::ByBackgroundColor; + break; + } + aItem.mfVal = rVal.NumericValue; + aItem.maString = rPool.intern(rVal.StringValue); + + if (aItem.meType == ScQueryEntry::ByValue) + { + OUString aStr; + pDoc->GetFormatTable()->GetInputLineString(aItem.mfVal, 0, aStr); + aItem.maString = rPool.intern(aStr); + } + else if (aItem.meType == ScQueryEntry::ByTextColor + || aItem.meType == ScQueryEntry::ByBackgroundColor) + { + aItem.maColor = Color(ColorTransparency, rVal.ColorValue); + } + + // filter all dates starting with the given date filter YYYY or YYYY-MM and filter all datetimes + // starting with the given datetime filter YYYY-MM-DD, YYYY-MM-DD HH, or YYYY-MM-DD HH:MM + if( aItem.meType == ScQueryEntry::ByDate && aItem.maString.getLength() < 19 ) + { + ScFilterEntries aFilterEntries; + pDoc->GetFilterEntries(rEntry.nField, rParam.nRow1, rParam.nTab, aFilterEntries); + for( const auto& rFilter : aFilterEntries ) + { + if( rFilter.GetString().startsWith(rVal.StringValue) ) + { + aItem.maString = rPool.intern(rFilter.GetString()); + rItems.push_back(aItem); + } + } + } + else + { + rItems.push_back(aItem); + } + } + } + } + + size_t nParamCount = rParam.GetEntryCount(); // if below eight Param isn't resized + for (size_t i = nCount; i < nParamCount; ++i) + rParam.GetEntry(i).bDoQuery = false; // reset surplus fields +} + +} + +uno::Sequence<sheet::TableFilterField2> SAL_CALL ScFilterDescriptorBase::getFilterFields2() +{ + SolarMutexGuard aGuard; + ScQueryParam aParam; + GetData(aParam); + + SCSIZE nEntries = aParam.GetEntryCount(); // allocated entries in Param + SCSIZE nCount = 0; // active + while ( nCount < nEntries && + aParam.GetEntry(nCount).bDoQuery ) + ++nCount; + + sheet::TableFilterField2 aField; + uno::Sequence<sheet::TableFilterField2> aSeq(static_cast<sal_Int32>(nCount)); + sheet::TableFilterField2* pAry = aSeq.getArray(); + for (SCSIZE i=0; i<nCount; i++) + { + const ScQueryEntry& rEntry = aParam.GetEntry(i); + convertQueryEntryToUno(rEntry, aField); + + bool bByEmpty = false; + if (aField.Operator == sheet::FilterOperator2::EQUAL) + { + if (rEntry.IsQueryByEmpty()) + { + aField.Operator = sheet::FilterOperator2::EMPTY; + aField.NumericValue = 0; + bByEmpty = true; + } + else if (rEntry.IsQueryByNonEmpty()) + { + aField.Operator = sheet::FilterOperator2::NOT_EMPTY; + aField.NumericValue = 0; + bByEmpty = true; + } + } + + if (!bByEmpty && !rEntry.GetQueryItems().empty()) + { + const ScQueryEntry::Item& rItem = rEntry.GetQueryItems().front(); + aField.IsNumeric = rItem.meType != ScQueryEntry::ByString; + aField.StringValue = rItem.maString.getString(); + aField.NumericValue = rItem.mfVal; + } + + pAry[i] = aField; + } + return aSeq; +} + +uno::Sequence<sheet::TableFilterField3> SAL_CALL ScFilterDescriptorBase::getFilterFields3() +{ + SolarMutexGuard aGuard; + ScQueryParam aParam; + GetData(aParam); + + SCSIZE nEntries = aParam.GetEntryCount(); // allocated entries in Param + SCSIZE nCount = 0; // active + while ( nCount < nEntries && + aParam.GetEntry(nCount).bDoQuery ) + ++nCount; + + sheet::TableFilterField3 aField; + uno::Sequence<sheet::TableFilterField3> aSeq(static_cast<sal_Int32>(nCount)); + sheet::TableFilterField3* pAry = aSeq.getArray(); + for (SCSIZE i = 0; i < nCount; ++i) + { + const ScQueryEntry& rEntry = aParam.GetEntry(i); + convertQueryEntryToUno(rEntry, aField); + + bool bByEmpty = false; + if (aField.Operator == sheet::FilterOperator2::EQUAL) + { + if (rEntry.IsQueryByEmpty()) + { + aField.Operator = sheet::FilterOperator2::EMPTY; + aField.Values.realloc(1); + aField.Values.getArray()[0].NumericValue = 0; + bByEmpty = true; + } + else if (rEntry.IsQueryByNonEmpty()) + { + aField.Operator = sheet::FilterOperator2::NOT_EMPTY; + aField.Values.realloc(1); + aField.Values.getArray()[0].NumericValue = 0; + bByEmpty = true; + } + } + + if (!bByEmpty) + { + const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems(); + size_t nItemCount = rItems.size(); + aField.Values.realloc(nItemCount); + auto pValues = aField.Values.getArray(); + size_t j = 0; + for (const auto& rItem : rItems) + { + pValues[j].IsNumeric = rItem.meType != ScQueryEntry::ByString; + pValues[j].StringValue = rItem.maString.getString(); + pValues[j].NumericValue = rItem.mfVal; + ++j; + } + } + + pAry[i] = aField; + } + return aSeq; +} + +void SAL_CALL ScFilterDescriptorBase::setFilterFields( + const uno::Sequence<sheet::TableFilterField>& aFilterFields ) +{ + SolarMutexGuard aGuard; + ScQueryParam aParam; + GetData(aParam); + + SCSIZE nCount = static_cast<SCSIZE>(aFilterFields.getLength()); + aParam.Resize( nCount ); + + ScDocument& rDoc = pDocSh->GetDocument(); + svl::SharedStringPool& rPool = rDoc.GetSharedStringPool(); + const sheet::TableFilterField* pAry = aFilterFields.getConstArray(); + SCSIZE i; + for (i=0; i<nCount; i++) + { + ScQueryEntry& rEntry = aParam.GetEntry(i); + ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems(); + rItems.resize(1); + ScQueryEntry::Item& rItem = rItems.front(); + rEntry.bDoQuery = true; + rEntry.eConnect = (pAry[i].Connection == sheet::FilterConnection_AND) ? SC_AND : SC_OR; + rEntry.nField = pAry[i].Field; + rItem.meType = pAry[i].IsNumeric ? ScQueryEntry::ByValue : ScQueryEntry::ByString; + rItem.mfVal = pAry[i].NumericValue; + rItem.maString = rPool.intern(pAry[i].StringValue); + + if (rItem.meType != ScQueryEntry::ByString) + { + OUString aStr; + rDoc.GetFormatTable()->GetInputLineString(rItem.mfVal, 0, aStr); + rItem.maString = rPool.intern(aStr); + } + + switch (pAry[i].Operator) // FilterOperator + { + case sheet::FilterOperator_EQUAL: rEntry.eOp = SC_EQUAL; break; + case sheet::FilterOperator_LESS: rEntry.eOp = SC_LESS; break; + case sheet::FilterOperator_GREATER: rEntry.eOp = SC_GREATER; break; + case sheet::FilterOperator_LESS_EQUAL: rEntry.eOp = SC_LESS_EQUAL; break; + case sheet::FilterOperator_GREATER_EQUAL: rEntry.eOp = SC_GREATER_EQUAL; break; + case sheet::FilterOperator_NOT_EQUAL: rEntry.eOp = SC_NOT_EQUAL; break; + case sheet::FilterOperator_TOP_VALUES: rEntry.eOp = SC_TOPVAL; break; + case sheet::FilterOperator_BOTTOM_VALUES: rEntry.eOp = SC_BOTVAL; break; + case sheet::FilterOperator_TOP_PERCENT: rEntry.eOp = SC_TOPPERC; break; + case sheet::FilterOperator_BOTTOM_PERCENT: rEntry.eOp = SC_BOTPERC; break; + case sheet::FilterOperator_EMPTY: + rEntry.SetQueryByEmpty(); + break; + case sheet::FilterOperator_NOT_EMPTY: + rEntry.SetQueryByNonEmpty(); + break; + default: + OSL_FAIL("Wrong query enum"); + rEntry.eOp = SC_EQUAL; + } + } + + SCSIZE nParamCount = aParam.GetEntryCount(); // if below eight Param isn't resized + for (i=nCount; i<nParamCount; i++) + aParam.GetEntry(i).bDoQuery = false; // reset surplus fields + + PutData(aParam); +} + +void SAL_CALL ScFilterDescriptorBase::setFilterFields2( + const uno::Sequence<sheet::TableFilterField2>& aFilterFields ) +{ + SolarMutexGuard aGuard; + ScQueryParam aParam; + GetData(aParam); + fillQueryParam(aParam, &pDocSh->GetDocument(), aFilterFields); + PutData(aParam); +} + +void SAL_CALL ScFilterDescriptorBase::setFilterFields3( + const uno::Sequence<sheet::TableFilterField3>& aFilterFields ) +{ + SolarMutexGuard aGuard; + ScQueryParam aParam; + GetData(aParam); + fillQueryParam(aParam, &pDocSh->GetDocument(), aFilterFields); + PutData(aParam); +} + +// Rest sind Properties + +// XPropertySet + +uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFilterDescriptorBase::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + static uno::Reference<beans::XPropertySetInfo> aRef( + new SfxItemPropertySetInfo( aPropSet.getPropertyMap() )); + return aRef; +} + +void SAL_CALL ScFilterDescriptorBase::setPropertyValue( + const OUString& aPropertyName, const uno::Any& aValue ) +{ + SolarMutexGuard aGuard; + ScQueryParam aParam; + GetData(aParam); + + if (aPropertyName == SC_UNONAME_CONTHDR) + aParam.bHasHeader = ScUnoHelpFunctions::GetBoolFromAny( aValue ); + else if (aPropertyName == SC_UNONAME_COPYOUT) + aParam.bInplace = !(ScUnoHelpFunctions::GetBoolFromAny( aValue )); + else if (aPropertyName == SC_UNONAME_ISCASE) + aParam.bCaseSens = ScUnoHelpFunctions::GetBoolFromAny( aValue ); + else if (aPropertyName == SC_UNONAME_MAXFLD) + { + // silently ignored + } + else if (aPropertyName == SC_UNONAME_ORIENT) + { + //! test for correct enum type? + table::TableOrientation eOrient = static_cast<table::TableOrientation>(ScUnoHelpFunctions::GetEnumFromAny( aValue )); + aParam.bByRow = ( eOrient != table::TableOrientation_COLUMNS ); + } + else if (aPropertyName == SC_UNONAME_OUTPOS) + { + table::CellAddress aAddress; + if ( aValue >>= aAddress ) + { + aParam.nDestTab = aAddress.Sheet; + aParam.nDestCol = static_cast<SCCOL>(aAddress.Column); + aParam.nDestRow = static_cast<SCROW>(aAddress.Row); + } + } + else if (aPropertyName == SC_UNONAME_SAVEOUT) + aParam.bDestPers = ScUnoHelpFunctions::GetBoolFromAny( aValue ); + else if (aPropertyName == SC_UNONAME_SKIPDUP) + aParam.bDuplicate = !(ScUnoHelpFunctions::GetBoolFromAny( aValue )); + else if (aPropertyName == SC_UNONAME_USEREGEX) + aParam.eSearchType = ScUnoHelpFunctions::GetBoolFromAny( aValue ) ? utl::SearchParam::SearchType::Regexp : + utl::SearchParam::SearchType::Normal; + + PutData(aParam); +} + +uno::Any SAL_CALL ScFilterDescriptorBase::getPropertyValue( const OUString& aPropertyName ) +{ + SolarMutexGuard aGuard; + ScQueryParam aParam; + GetData(aParam); + + uno::Any aRet; + + if (aPropertyName == SC_UNONAME_CONTHDR ) + aRet <<= aParam.bHasHeader; + else if (aPropertyName == SC_UNONAME_COPYOUT ) + aRet <<= !(aParam.bInplace); + else if (aPropertyName == SC_UNONAME_ISCASE ) + aRet <<= aParam.bCaseSens; + else if (aPropertyName == SC_UNONAME_MAXFLD ) + aRet <<= static_cast<sal_Int32>(aParam.GetEntryCount()); + else if (aPropertyName == SC_UNONAME_ORIENT ) + { + table::TableOrientation eOrient = aParam.bByRow ? table::TableOrientation_ROWS : + table::TableOrientation_COLUMNS; + aRet <<= eOrient; + } + else if (aPropertyName == SC_UNONAME_OUTPOS ) + { + table::CellAddress aOutPos; + aOutPos.Sheet = aParam.nDestTab; + aOutPos.Column = aParam.nDestCol; + aOutPos.Row = aParam.nDestRow; + aRet <<= aOutPos; + } + else if (aPropertyName == SC_UNONAME_SAVEOUT ) + aRet <<= aParam.bDestPers; + else if (aPropertyName == SC_UNONAME_SKIPDUP ) + aRet <<= !(aParam.bDuplicate); + else if (aPropertyName == SC_UNONAME_USEREGEX ) + aRet <<= (aParam.eSearchType == utl::SearchParam::SearchType::Regexp); + + return aRet; +} + +SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFilterDescriptorBase ) + +ScFilterDescriptor::ScFilterDescriptor(ScDocShell* pDocShell) + : + ScFilterDescriptorBase(pDocShell) +{ +} + +ScFilterDescriptor::~ScFilterDescriptor() +{ +} + +void ScFilterDescriptor::GetData( ScQueryParam& rParam ) const +{ + rParam = aStoredParam; // query for interface +} + +void ScFilterDescriptor::PutData( const ScQueryParam& rParam ) +{ + aStoredParam = rParam; // set by the interface +} + +void ScFilterDescriptor::SetParam( const ScQueryParam& rNew ) +{ + aStoredParam = rNew; // set from outside +} + +ScRangeFilterDescriptor::ScRangeFilterDescriptor(ScDocShell* pDocShell, ScDatabaseRangeObj* pPar) : + ScFilterDescriptorBase(pDocShell), + mxParent(pPar) +{ +} + +ScRangeFilterDescriptor::~ScRangeFilterDescriptor() +{ +} + +void ScRangeFilterDescriptor::GetData( ScQueryParam& rParam ) const +{ + if (mxParent.is()) + mxParent->GetQueryParam( rParam ); +} + +void ScRangeFilterDescriptor::PutData( const ScQueryParam& rParam ) +{ + if (mxParent.is()) + mxParent->SetQueryParam( rParam ); +} + +ScDataPilotFilterDescriptor::ScDataPilotFilterDescriptor(ScDocShell* pDocShell, ScDataPilotDescriptorBase* pPar) : + ScFilterDescriptorBase(pDocShell), + mxParent(pPar) +{ +} + +ScDataPilotFilterDescriptor::~ScDataPilotFilterDescriptor() +{ +} + +void ScDataPilotFilterDescriptor::GetData( ScQueryParam& rParam ) const +{ + if (mxParent.is()) + { + ScDPObject* pDPObj = mxParent->GetDPObject(); + if (pDPObj && pDPObj->IsSheetData()) + rParam = pDPObj->GetSheetDesc()->GetQueryParam(); + } +} + +void ScDataPilotFilterDescriptor::PutData( const ScQueryParam& rParam ) +{ + if (!mxParent.is()) + return; + + ScDPObject* pDPObj = mxParent->GetDPObject(); + if (pDPObj) + { + ScSheetSourceDesc aSheetDesc(&mxParent->GetDocShell()->GetDocument()); + if (pDPObj->IsSheetData()) + aSheetDesc = *pDPObj->GetSheetDesc(); + aSheetDesc.SetQueryParam(rParam); + pDPObj->SetSheetDesc(aSheetDesc); + mxParent->SetDPObject(pDPObj); + } +} + +ScDatabaseRangeObj::ScDatabaseRangeObj(ScDocShell* pDocSh, const OUString& rNm) : + pDocShell( pDocSh ), + aName( rNm ), + aPropSet( lcl_GetDBRangePropertyMap() ), + bIsUnnamed(false), + aTab( 0 ) +{ + pDocShell->GetDocument().AddUnoObject(*this); +} + +ScDatabaseRangeObj::ScDatabaseRangeObj(ScDocShell* pDocSh, const SCTAB nTab) : + pDocShell( pDocSh ), + aName(STR_DB_LOCAL_NONAME), + aPropSet( lcl_GetDBRangePropertyMap() ), + bIsUnnamed(true), + aTab( nTab ) +{ + pDocShell->GetDocument().AddUnoObject(*this); +} + +ScDatabaseRangeObj::~ScDatabaseRangeObj() +{ + SolarMutexGuard g; + + if (pDocShell) + pDocShell->GetDocument().RemoveUnoObject(*this); +} + +void ScDatabaseRangeObj::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + + if ( rHint.GetId() == SfxHintId::Dying ) + pDocShell = nullptr; + else if ( auto pRefreshHint = dynamic_cast<const ScDBRangeRefreshedHint*>(&rHint) ) + { + ScDBData* pDBData = GetDBData_Impl(); + ScImportParam aParam; + pDBData->GetImportParam(aParam); + if (aParam == pRefreshHint->GetImportParam()) + Refreshed_Impl(); + } +} + +// Help functions + +ScDBData* ScDatabaseRangeObj::GetDBData_Impl() const +{ + ScDBData* pRet = nullptr; + if (pDocShell) + { + if (bIsUnnamed) + { + pRet = pDocShell->GetDocument().GetAnonymousDBData(aTab); + } + else + { + ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection(); + if (pNames) + { + ScDBData* p = pNames->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aName)); + if (p) + pRet = p; + } + } + } + return pRet; +} + +// XNamed + +OUString SAL_CALL ScDatabaseRangeObj::getName() +{ + SolarMutexGuard aGuard; + return aName; +} + +void SAL_CALL ScDatabaseRangeObj::setName( const OUString& aNewName ) +{ + SolarMutexGuard aGuard; + if (pDocShell) + { + ScDBDocFunc aFunc(*pDocShell); + bool bOk = aFunc.RenameDBRange( aName, aNewName ); + if (bOk) + aName = aNewName; + } +} + +// XDatabaseRange + +table::CellRangeAddress SAL_CALL ScDatabaseRangeObj::getDataArea() +{ + SolarMutexGuard aGuard; + table::CellRangeAddress aAddress; + ScDBData* pData = GetDBData_Impl(); + if (pData) + { + ScRange aRange; + pData->GetArea(aRange); + aAddress.Sheet = aRange.aStart.Tab(); + aAddress.StartColumn = aRange.aStart.Col(); + aAddress.StartRow = aRange.aStart.Row(); + aAddress.EndColumn = aRange.aEnd.Col(); + aAddress.EndRow = aRange.aEnd.Row(); + } + return aAddress; +} + +void SAL_CALL ScDatabaseRangeObj::setDataArea( const table::CellRangeAddress& aDataArea ) +{ + SolarMutexGuard aGuard; + ScDBData* pData = GetDBData_Impl(); + if ( pDocShell && pData ) + { + ScDBData aNewData( *pData ); + //! MoveTo ??? + aNewData.SetArea( aDataArea.Sheet, static_cast<SCCOL>(aDataArea.StartColumn), static_cast<SCROW>(aDataArea.StartRow), + static_cast<SCCOL>(aDataArea.EndColumn), static_cast<SCROW>(aDataArea.EndRow) ); + ScDBDocFunc aFunc(*pDocShell); + aFunc.ModifyDBData(aNewData); + } +} + +uno::Sequence<beans::PropertyValue> SAL_CALL ScDatabaseRangeObj::getSortDescriptor() +{ + SolarMutexGuard aGuard; + ScSortParam aParam; + const ScDBData* pData = GetDBData_Impl(); + if (pData) + { + pData->GetSortParam(aParam); + + // SortDescriptor contains the counted fields inside the area + ScRange aDBRange; + pData->GetArea(aDBRange); + SCCOLROW nFieldStart = aParam.bByRow ? static_cast<SCCOLROW>(aDBRange.aStart.Col()) : static_cast<SCCOLROW>(aDBRange.aStart.Row()); + for (sal_uInt16 i=0; i<aParam.GetSortKeyCount(); i++) + if ( aParam.maKeyState[i].bDoSort && aParam.maKeyState[i].nField >= nFieldStart ) + aParam.maKeyState[i].nField -= nFieldStart; + } + + uno::Sequence<beans::PropertyValue> aSeq( ScSortDescriptor::GetPropertyCount() ); + ScSortDescriptor::FillProperties( aSeq, aParam ); + return aSeq; +} + +void ScDatabaseRangeObj::GetQueryParam(ScQueryParam& rQueryParam) const +{ + const ScDBData* pData = GetDBData_Impl(); + if (!pData) + return; + + pData->GetQueryParam(rQueryParam); + + // FilterDescriptor contains the counted fields inside the area + ScRange aDBRange; + pData->GetArea(aDBRange); + SCCOLROW nFieldStart = rQueryParam.bByRow ? static_cast<SCCOLROW>(aDBRange.aStart.Col()) : static_cast<SCCOLROW>(aDBRange.aStart.Row()); + SCSIZE nCount = rQueryParam.GetEntryCount(); + for (SCSIZE i=0; i<nCount; i++) + { + ScQueryEntry& rEntry = rQueryParam.GetEntry(i); + if (rEntry.bDoQuery && rEntry.nField >= nFieldStart) + rEntry.nField -= nFieldStart; + } +} + +void ScDatabaseRangeObj::SetQueryParam(const ScQueryParam& rQueryParam) +{ + const ScDBData* pData = GetDBData_Impl(); + if (!pData) + return; + + // FilterDescriptor contains the counted fields inside the area + ScQueryParam aParam(rQueryParam); + ScRange aDBRange; + pData->GetArea(aDBRange); + SCCOLROW nFieldStart = aParam.bByRow ? static_cast<SCCOLROW>(aDBRange.aStart.Col()) : static_cast<SCCOLROW>(aDBRange.aStart.Row()); + + SCSIZE nCount = aParam.GetEntryCount(); + for (SCSIZE i=0; i<nCount; i++) + { + ScQueryEntry& rEntry = aParam.GetEntry(i); + if (rEntry.bDoQuery) + rEntry.nField += nFieldStart; + } + + ScDBData aNewData( *pData ); + aNewData.SetQueryParam(aParam); + aNewData.SetHeader(aParam.bHasHeader); // not in ScDBData::SetQueryParam + ScDBDocFunc aFunc(*pDocShell); + aFunc.ModifyDBData(aNewData); +} + +uno::Reference<sheet::XSheetFilterDescriptor> SAL_CALL ScDatabaseRangeObj::getFilterDescriptor() +{ + SolarMutexGuard aGuard; + return new ScRangeFilterDescriptor(pDocShell, this); +} + +void ScDatabaseRangeObj::GetSubTotalParam(ScSubTotalParam& rSubTotalParam) const +{ + const ScDBData* pData = GetDBData_Impl(); + if (!pData) + return; + + pData->GetSubTotalParam(rSubTotalParam); + + // FilterDescriptor contains the counted fields inside the area + ScRange aDBRange; + pData->GetArea(aDBRange); + SCCOL nFieldStart = aDBRange.aStart.Col(); + for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++) + { + if ( rSubTotalParam.bGroupActive[i] ) + { + if ( rSubTotalParam.nField[i] >= nFieldStart ) + rSubTotalParam.nField[i] = sal::static_int_cast<SCCOL>( rSubTotalParam.nField[i] - nFieldStart ); + for (SCCOL j=0; j<rSubTotalParam.nSubTotals[i]; j++) + if ( rSubTotalParam.pSubTotals[i][j] >= nFieldStart ) + rSubTotalParam.pSubTotals[i][j] = + sal::static_int_cast<SCCOL>( rSubTotalParam.pSubTotals[i][j] - nFieldStart ); + } + } +} + +void ScDatabaseRangeObj::SetSubTotalParam(const ScSubTotalParam& rSubTotalParam) +{ + const ScDBData* pData = GetDBData_Impl(); + if (!pData) + return; + + // FilterDescriptor contains the counted fields inside the area + ScSubTotalParam aParam(rSubTotalParam); + ScRange aDBRange; + pData->GetArea(aDBRange); + SCCOL nFieldStart = aDBRange.aStart.Col(); + for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++) + { + if ( aParam.bGroupActive[i] ) + { + aParam.nField[i] = sal::static_int_cast<SCCOL>( aParam.nField[i] + nFieldStart ); + for (SCCOL j=0; j<aParam.nSubTotals[i]; j++) + aParam.pSubTotals[i][j] = sal::static_int_cast<SCCOL>( aParam.pSubTotals[i][j] + nFieldStart ); + } + } + + ScDBData aNewData( *pData ); + aNewData.SetSubTotalParam(aParam); + ScDBDocFunc aFunc(*pDocShell); + aFunc.ModifyDBData(aNewData); +} + +uno::Reference<sheet::XSubTotalDescriptor> SAL_CALL ScDatabaseRangeObj::getSubTotalDescriptor() +{ + SolarMutexGuard aGuard; + return new ScRangeSubTotalDescriptor(this); +} + +uno::Sequence<beans::PropertyValue> SAL_CALL ScDatabaseRangeObj::getImportDescriptor() +{ + SolarMutexGuard aGuard; + ScImportParam aParam; + const ScDBData* pData = GetDBData_Impl(); + if (pData) + pData->GetImportParam(aParam); + + uno::Sequence<beans::PropertyValue> aSeq( ScImportDescriptor::GetPropertyCount() ); + ScImportDescriptor::FillProperties( aSeq, aParam ); + return aSeq; +} + +// XRefreshable + +void SAL_CALL ScDatabaseRangeObj::refresh() +{ + SolarMutexGuard aGuard; + ScDBData* pData = GetDBData_Impl(); + if ( !(pDocShell && pData) ) + return; + + ScDBDocFunc aFunc(*pDocShell); + + // repeat import? + bool bContinue = true; + ScImportParam aImportParam; + pData->GetImportParam( aImportParam ); + if (aImportParam.bImport && !pData->HasImportSelection()) + { + SCTAB nTab; + SCCOL nDummyCol; + SCROW nDummyRow; + pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow ); + bContinue = aFunc.DoImport( nTab, aImportParam, nullptr ); //! Api-Flag as parameter + } + + // if no error then internal operations (sort, query, subtotal) + if (bContinue) + aFunc.RepeatDB( pData->GetName(), true, bIsUnnamed, aTab ); +} + +void SAL_CALL ScDatabaseRangeObj::addRefreshListener( + const uno::Reference<util::XRefreshListener >& xListener ) +{ + SolarMutexGuard aGuard; + aRefreshListeners.emplace_back( xListener ); + + // hold one additional ref to keep this object alive as long as there are listeners + if ( aRefreshListeners.size() == 1 ) + acquire(); +} + +void SAL_CALL ScDatabaseRangeObj::removeRefreshListener( + const uno::Reference<util::XRefreshListener >& xListener ) +{ + SolarMutexGuard aGuard; + sal_uInt16 nCount = aRefreshListeners.size(); + for ( sal_uInt16 n=nCount; n--; ) + { + uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n]; + if ( rObj == xListener ) + { + aRefreshListeners.erase( aRefreshListeners.begin() + n ); + if ( aRefreshListeners.empty() ) + release(); // release ref for listeners + break; + } + } +} + +void ScDatabaseRangeObj::Refreshed_Impl() +{ + lang::EventObject aEvent; + aEvent.Source = static_cast<cppu::OWeakObject*>(this); + for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners) + xRefreshListener->refreshed( aEvent ); +} + +// XCellRangeSource + +uno::Reference<table::XCellRange> SAL_CALL ScDatabaseRangeObj::getReferredCells() +{ + SolarMutexGuard aGuard; + ScDBData* pData = GetDBData_Impl(); + if ( pData ) + { + //! static function to create ScCellObj/ScCellRange on ScCellRangeObj ??? + ScRange aRange; + + pData->GetArea(aRange); + if ( aRange.aStart == aRange.aEnd ) + return new ScCellObj( pDocShell, aRange.aStart ); + else + return new ScCellRangeObj( pDocShell, aRange ); + } + return nullptr; +} + +// XPropertySet + +uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDatabaseRangeObj::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + static uno::Reference<beans::XPropertySetInfo> aRef( + new SfxItemPropertySetInfo( aPropSet.getPropertyMap() )); + return aRef; +} + +void SAL_CALL ScDatabaseRangeObj::setPropertyValue( + const OUString& aPropertyName, const uno::Any& aValue ) +{ + SolarMutexGuard aGuard; + ScDBData* pData = GetDBData_Impl(); + if ( !(pDocShell && pData) ) + return; + + ScDBData aNewData( *pData ); + bool bDo = true; + + if ( aPropertyName == SC_UNONAME_KEEPFORM ) + aNewData.SetKeepFmt( ScUnoHelpFunctions::GetBoolFromAny( aValue ) ); + else if ( aPropertyName == SC_UNONAME_MOVCELLS ) + aNewData.SetDoSize( ScUnoHelpFunctions::GetBoolFromAny( aValue ) ); + else if ( aPropertyName == SC_UNONAME_STRIPDAT ) + aNewData.SetStripData( ScUnoHelpFunctions::GetBoolFromAny( aValue ) ); + else if (aPropertyName == SC_UNONAME_AUTOFLT ) + { + bool bAutoFilter(ScUnoHelpFunctions::GetBoolFromAny( aValue )); + aNewData.SetAutoFilter(bAutoFilter); + ScRange aRange; + aNewData.GetArea(aRange); + ScDocument& rDoc = pDocShell->GetDocument(); + if (bAutoFilter) + rDoc.ApplyFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(), + aRange.aEnd.Col(), aRange.aStart.Row(), + aRange.aStart.Tab(), ScMF::Auto ); + else if (!bAutoFilter) + rDoc.RemoveFlagsTab(aRange.aStart.Col(), aRange.aStart.Row(), + aRange.aEnd.Col(), aRange.aStart.Row(), + aRange.aStart.Tab(), ScMF::Auto ); + ScRange aPaintRange(aRange.aStart, aRange.aEnd); + aPaintRange.aEnd.SetRow(aPaintRange.aStart.Row()); + pDocShell->PostPaint(aPaintRange, PaintPartFlags::Grid); + } + else if (aPropertyName == SC_UNONAME_USEFLTCRT ) + { + if (ScUnoHelpFunctions::GetBoolFromAny( aValue )) + { + // only here to set bIsAdvanced in ScDBData + ScRange aRange; + (void)aNewData.GetAdvancedQuerySource(aRange); + aNewData.SetAdvancedQuerySource(&aRange); + } + else + aNewData.SetAdvancedQuerySource(nullptr); + } + else if (aPropertyName == SC_UNONAME_FLTCRT ) + { + table::CellRangeAddress aRange; + if (aValue >>= aRange) + { + ScRange aCoreRange; + ScUnoConversion::FillScRange(aCoreRange, aRange); + + aNewData.SetAdvancedQuerySource(&aCoreRange); + } + } + else if (aPropertyName == SC_UNONAME_FROMSELECT ) + { + aNewData.SetImportSelection(::cppu::any2bool(aValue)); + } + else if (aPropertyName == SC_UNONAME_REFPERIOD ) + { + sal_Int32 nRefresh = 0; + if (aValue >>= nRefresh) + { + ScDocument& rDoc = pDocShell->GetDocument(); + aNewData.SetRefreshDelay(nRefresh); + if (rDoc.GetDBCollection()) + { + aNewData.SetRefreshHandler( rDoc.GetDBCollection()->GetRefreshHandler() ); + aNewData.SetRefreshControl( &rDoc.GetRefreshTimerControlAddress() ); + } + } + } + else if (aPropertyName == SC_UNONAME_CONRES ) + { + } + else if ( aPropertyName == SC_UNONAME_TOTALSROW ) + aNewData.SetTotals( ScUnoHelpFunctions::GetBoolFromAny( aValue ) ); + else if ( aPropertyName == SC_UNONAME_CONTHDR ) + aNewData.SetHeader( ScUnoHelpFunctions::GetBoolFromAny( aValue ) ); + else + bDo = false; + + if (bDo) + { + ScDBDocFunc aFunc(*pDocShell); + aFunc.ModifyDBData(aNewData); + } +} + +uno::Any SAL_CALL ScDatabaseRangeObj::getPropertyValue( const OUString& aPropertyName ) +{ + SolarMutexGuard aGuard; + uno::Any aRet; + ScDBData* pData = GetDBData_Impl(); + if ( pData ) + { + if ( aPropertyName == SC_UNONAME_KEEPFORM ) + aRet <<= pData->IsKeepFmt(); + else if ( aPropertyName == SC_UNONAME_MOVCELLS ) + aRet <<= pData->IsDoSize(); + else if ( aPropertyName == SC_UNONAME_STRIPDAT ) + aRet <<= pData->IsStripData(); + else if ( aPropertyName == SC_UNONAME_ISUSER ) + { + // all database ranges except "unnamed" are user defined + aRet <<= (pData->GetName() != STR_DB_LOCAL_NONAME); + } + else if ( aPropertyName == SC_UNO_LINKDISPBIT ) + { + // no target bitmaps for individual entries (would be all equal) + // ScLinkTargetTypeObj::SetLinkTargetBitmap( aRet, SC_LINKTARGETTYPE_DBAREA ); + } + else if ( aPropertyName == SC_UNO_LINKDISPNAME ) + aRet <<= aName; + else if (aPropertyName == SC_UNONAME_AUTOFLT ) + { + bool bAutoFilter(GetDBData_Impl()->HasAutoFilter()); + + aRet <<= bAutoFilter; + } + else if (aPropertyName == SC_UNONAME_USEFLTCRT ) + { + ScRange aRange; + bool bIsAdvancedSource(GetDBData_Impl()->GetAdvancedQuerySource(aRange)); + + aRet <<= bIsAdvancedSource; + } + else if (aPropertyName == SC_UNONAME_FLTCRT ) + { + table::CellRangeAddress aRange; + ScRange aCoreRange; + if (GetDBData_Impl()->GetAdvancedQuerySource(aCoreRange)) + ScUnoConversion::FillApiRange(aRange, aCoreRange); + + aRet <<= aRange; + } + else if (aPropertyName == SC_UNONAME_FROMSELECT ) + { + aRet <<= GetDBData_Impl()->HasImportSelection(); + } + else if (aPropertyName == SC_UNONAME_REFPERIOD ) + { + sal_Int32 nRefresh(GetDBData_Impl()->GetRefreshDelaySeconds()); + aRet <<= nRefresh; + } + else if (aPropertyName == SC_UNONAME_CONRES ) + { + } + else if (aPropertyName == SC_UNONAME_TOKENINDEX ) + { + // get index for use in formula tokens (read-only) + aRet <<= static_cast<sal_Int32>(GetDBData_Impl()->GetIndex()); + } + else if (aPropertyName == SC_UNONAME_TOTALSROW ) + { + bool bTotals(GetDBData_Impl()->HasTotals()); + + aRet <<= bTotals; + } + else if (aPropertyName == SC_UNONAME_CONTHDR ) + { + bool bHeader(GetDBData_Impl()->HasHeader()); + + aRet <<= bHeader; + } + } + return aRet; +} + +SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDatabaseRangeObj ) + +// XServiceInfo +OUString SAL_CALL ScDatabaseRangeObj::getImplementationName() +{ + return "ScDatabaseRangeObj"; +} + +sal_Bool SAL_CALL ScDatabaseRangeObj::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> SAL_CALL ScDatabaseRangeObj::getSupportedServiceNames() +{ + return {"com.sun.star.sheet.DatabaseRange", + SCLINKTARGET_SERVICE}; +} + +ScDatabaseRangesObj::ScDatabaseRangesObj(ScDocShell* pDocSh) : + pDocShell( pDocSh ) +{ + pDocShell->GetDocument().AddUnoObject(*this); +} + +ScDatabaseRangesObj::~ScDatabaseRangesObj() +{ + SolarMutexGuard g; + + if (pDocShell) + pDocShell->GetDocument().RemoveUnoObject(*this); +} + +void ScDatabaseRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + // reference update does not matter here + + if ( rHint.GetId() == SfxHintId::Dying ) + { + pDocShell = nullptr; + } +} + +// XDatabaseRanges + +rtl::Reference<ScDatabaseRangeObj> ScDatabaseRangesObj::GetObjectByIndex_Impl(size_t nIndex) +{ + if (!pDocShell) + return nullptr; + + ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection(); + if (!pNames) + return nullptr; + + const ScDBCollection::NamedDBs& rDBs = pNames->getNamedDBs(); + if (rDBs.empty() || nIndex >= rDBs.size()) + return nullptr; + + ScDBCollection::NamedDBs::const_iterator itr = rDBs.begin(); + ::std::advance(itr, nIndex); // boundary check is done above. + return new ScDatabaseRangeObj(pDocShell, (*itr)->GetName()); +} + +rtl::Reference<ScDatabaseRangeObj> ScDatabaseRangesObj::GetObjectByName_Impl(const OUString& aName) +{ + if ( pDocShell && hasByName(aName) ) + { + return new ScDatabaseRangeObj( pDocShell, aName ); + } + return nullptr; +} + +void SAL_CALL ScDatabaseRangesObj::addNewByName( const OUString& aName, + const table::CellRangeAddress& aRange ) +{ + SolarMutexGuard aGuard; + bool bDone = false; + if (pDocShell) + { + ScDBDocFunc aFunc(*pDocShell); + + ScRange aNameRange( static_cast<SCCOL>(aRange.StartColumn), static_cast<SCROW>(aRange.StartRow), aRange.Sheet, + static_cast<SCCOL>(aRange.EndColumn), static_cast<SCROW>(aRange.EndRow), aRange.Sheet ); + bDone = aFunc.AddDBRange( aName, aNameRange ); + } + if (!bDone) + throw uno::RuntimeException(); // no other exceptions specified +} + +void SAL_CALL ScDatabaseRangesObj::removeByName( const OUString& aName ) +{ + SolarMutexGuard aGuard; + bool bDone = false; + if (pDocShell) + { + ScDBDocFunc aFunc(*pDocShell); + bDone = aFunc.DeleteDBRange( aName ); + } + if (!bDone) + throw uno::RuntimeException(); // no other exceptions specified +} + +// XEnumerationAccess + +uno::Reference<container::XEnumeration> SAL_CALL ScDatabaseRangesObj::createEnumeration() +{ + SolarMutexGuard aGuard; + return new ScIndexEnumeration(this, "com.sun.star.sheet.DatabaseRangesEnumeration"); +} + +// XIndexAccess + +sal_Int32 SAL_CALL ScDatabaseRangesObj::getCount() +{ + SolarMutexGuard aGuard; + + //! need to omit "unnamed"? + + if (pDocShell) + { + ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection(); + if (pNames) + return static_cast<sal_Int32>(pNames->getNamedDBs().size()); + } + return 0; +} + +uno::Any SAL_CALL ScDatabaseRangesObj::getByIndex( sal_Int32 nIndex ) +{ + SolarMutexGuard aGuard; + if (nIndex < 0) + throw lang::IndexOutOfBoundsException(); + + uno::Reference<sheet::XDatabaseRange> xRange(GetObjectByIndex_Impl(static_cast<size_t>(nIndex))); + if (!xRange.is()) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(xRange); +} + +uno::Type SAL_CALL ScDatabaseRangesObj::getElementType() +{ + return cppu::UnoType<sheet::XDatabaseRange>::get(); +} + +sal_Bool SAL_CALL ScDatabaseRangesObj::hasElements() +{ + SolarMutexGuard aGuard; + return ( getCount() != 0 ); +} + +// XNameAccess + +uno::Any SAL_CALL ScDatabaseRangesObj::getByName( const OUString& aName ) +{ + SolarMutexGuard aGuard; + uno::Reference<sheet::XDatabaseRange> xRange(GetObjectByName_Impl(aName)); + if (!xRange.is()) + throw container::NoSuchElementException(); + + return uno::Any(xRange); +} + +uno::Sequence<OUString> SAL_CALL ScDatabaseRangesObj::getElementNames() +{ + SolarMutexGuard aGuard; + + //! need to omit "unnamed"? + + if (pDocShell) + { + ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection(); + if (pNames) + { + const ScDBCollection::NamedDBs& rDBs = pNames->getNamedDBs(); + uno::Sequence<OUString> aSeq(rDBs.size()); + auto aSeqRange = asNonConstRange(aSeq); + size_t i = 0; + for (const auto& rDB : rDBs) + { + aSeqRange[i] = rDB->GetName(); + ++i; + } + + return aSeq; + } + } + return {}; +} + +sal_Bool SAL_CALL ScDatabaseRangesObj::hasByName( const OUString& aName ) +{ + SolarMutexGuard aGuard; + + //! need to omit "unnamed"? + + if (pDocShell) + { + ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection(); + if (pNames) + return pNames->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aName)) != nullptr; + } + return false; +} + +ScUnnamedDatabaseRangesObj::ScUnnamedDatabaseRangesObj(ScDocShell* pDocSh) : + pDocShell( pDocSh ) +{ + pDocShell->GetDocument().AddUnoObject(*this); +} + +ScUnnamedDatabaseRangesObj::~ScUnnamedDatabaseRangesObj() +{ + SolarMutexGuard g; + + if (pDocShell) + pDocShell->GetDocument().RemoveUnoObject(*this); +} + +void ScUnnamedDatabaseRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + // reference update does not matter here + + if ( rHint.GetId() == SfxHintId::Dying ) + { + pDocShell = nullptr; + } +} + +// XUnnamedDatabaseRanges + +void ScUnnamedDatabaseRangesObj::setByTable( const table::CellRangeAddress& aRange ) +{ + SolarMutexGuard aGuard; + bool bDone = false; + if (pDocShell) + { + if ( pDocShell->GetDocument().GetTableCount() <= aRange.Sheet ) + throw lang::IndexOutOfBoundsException(); + + ScDBDocFunc aFunc(*pDocShell); + ScRange aUnnamedRange( static_cast<SCCOL>(aRange.StartColumn), static_cast<SCROW>(aRange.StartRow), aRange.Sheet, + static_cast<SCCOL>(aRange.EndColumn), static_cast<SCROW>(aRange.EndRow), aRange.Sheet ); + bDone = aFunc.AddDBRange( STR_DB_LOCAL_NONAME, aUnnamedRange ); + } + if (!bDone) + throw uno::RuntimeException(); // no other exceptions specified +} + +uno::Any ScUnnamedDatabaseRangesObj::getByTable( sal_Int32 nTab ) +{ + SolarMutexGuard aGuard; + if (!pDocShell) + throw uno::RuntimeException(); + + if ( pDocShell->GetDocument().GetTableCount() <= nTab ) + throw lang::IndexOutOfBoundsException(); + uno::Reference<sheet::XDatabaseRange> xRange( + new ScDatabaseRangeObj(pDocShell, static_cast<SCTAB>(nTab))); + if (!xRange.is()) + throw container::NoSuchElementException(); + + return uno::Any(xRange); +} + +sal_Bool ScUnnamedDatabaseRangesObj::hasByTable( sal_Int32 nTab ) +{ + SolarMutexGuard aGuard; + if (pDocShell) + { + if (pDocShell->GetDocument().GetTableCount() <= nTab) + throw lang::IndexOutOfBoundsException(); + if (pDocShell->GetDocument().GetAnonymousDBData(static_cast<SCTAB>(nTab))) + return true; + return false; + } + else + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |