LibreOffice Module sc (master) 1
cellsuno.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <scitems.hxx>
21#include <editeng/eeitem.hxx>
22#include <o3tl/safeint.hxx>
23#include <svx/svdpool.hxx>
24
25#include <utility>
26#include <vcl/svapp.hxx>
27#include <svx/algitem.hxx>
29#include <editeng/boxitem.hxx>
30#include <editeng/editeng.hxx>
31#include <editeng/flditem.hxx>
32#include <editeng/editobj.hxx>
33#include <editeng/unoipset.hxx>
34#include <editeng/langitem.hxx>
35#include <sfx2/linkmgr.hxx>
36#include <svl/numformat.hxx>
37#include <svl/srchitem.hxx>
39#include <svx/unomid.hxx>
40#include <editeng/unoprnms.hxx>
41#include <editeng/unotext.hxx>
42#include <svx/svdpage.hxx>
43#include <sfx2/bindings.hxx>
44#include <svl/zforlist.hxx>
45#include <svl/zformat.hxx>
47#include <float.h>
50
51#include <com/sun/star/awt/XBitmap.hpp>
52#include <com/sun/star/util/CellProtection.hpp>
53#include <com/sun/star/table/CellHoriJustify.hpp>
54#include <com/sun/star/table/CellOrientation.hpp>
55#include <com/sun/star/table/ShadowFormat.hpp>
56#include <com/sun/star/table/TableBorder.hpp>
57#include <com/sun/star/table/TableBorder2.hpp>
58#include <com/sun/star/sheet/CellFlags.hpp>
59#include <com/sun/star/sheet/FormulaResult.hpp>
60#include <com/sun/star/beans/PropertyAttribute.hpp>
61#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
62#include <com/sun/star/lang/Locale.hpp>
63#include <com/sun/star/beans/TolerantPropertySetResultType.hpp>
64#include <com/sun/star/beans/SetPropertyTolerantFailed.hpp>
65#include <com/sun/star/text/WritingMode2.hpp>
66#include <com/sun/star/text/textfield/Type.hpp>
67#include <com/sun/star/sheet/XConditionalFormats.hpp>
68
69#include <autoform.hxx>
70#include <cellvalue.hxx>
71#include <cellmergeoption.hxx>
72#include <cellsuno.hxx>
73#include <cursuno.hxx>
74#include <textuno.hxx>
75#include <editsrc.hxx>
76#include <notesuno.hxx>
77#include <fielduno.hxx>
78#include <docuno.hxx>
79#include <datauno.hxx>
80#include <dapiuno.hxx>
81#include <chartuno.hxx>
82#include <fmtuno.hxx>
83#include <miscuno.hxx>
84#include <convuno.hxx>
85#include <srchuno.hxx>
86#include <nameuno.hxx>
87#include <targuno.hxx>
88#include <tokenuno.hxx>
89#include <eventuno.hxx>
90#include <docsh.hxx>
91#include <markdata.hxx>
92#include <patattr.hxx>
93#include <docpool.hxx>
94#include <docfunc.hxx>
95#include <dbdocfun.hxx>
96#include <olinefun.hxx>
97#include <hints.hxx>
98#include <formulacell.hxx>
99#include <undotab.hxx>
100#include <undoblk.hxx>
101#include <stlsheet.hxx>
102#include <dbdata.hxx>
103#include <attrib.hxx>
104#include <chartarr.hxx>
105#include <chartlis.hxx>
106#include <drwlayer.hxx>
107#include <printfun.hxx>
108#include <prnsave.hxx>
109#include <tablink.hxx>
110#include <dociter.hxx>
111#include <rangeutl.hxx>
112#include <conditio.hxx>
113#include <validat.hxx>
114#include <sc.hrc>
115#include <cellform.hxx>
116#include <globstr.hrc>
117#include <scresid.hxx>
118#include <unonames.hxx>
119#include <styleuno.hxx>
120#include <rangeseq.hxx>
121#include <unowids.hxx>
122#include <paramisc.hxx>
123#include <queryentry.hxx>
124#include <formula/errorcodes.hxx>
125#include <unoreflist.hxx>
126#include <formula/grammar.hxx>
128#include <stringutil.hxx>
129#include <formulaiter.hxx>
130#include <tokenarray.hxx>
131#include <stylehelper.hxx>
132#include <dputil.hxx>
133#include <sortparam.hxx>
134#include <condformatuno.hxx>
135#include <TablePivotCharts.hxx>
136#include <table.hxx>
137#include <refundo.hxx>
138#include <columnspanset.hxx>
139
140#include <memory>
141
142using namespace com::sun::star;
143
144// The names in the maps must be sorted according to strcmp!
146
147// Left/Right/Top/BottomBorder are mapped directly to the core items,
148// not collected/applied to the borders of a range -> ATTR_BORDER can be used directly
149
151{
152 static const SfxItemPropertyMapEntry aCellsPropertyMap_Impl[] =
153 {
154 { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
251 };
252 static SfxItemPropertySet aCellsPropertySet( aCellsPropertyMap_Impl );
253 return &aCellsPropertySet;
254}
255
256// CellRange contains all entries from Cells, plus its own entries
257// with Which-ID 0 (those are needed only for getPropertySetInfo).
258
260{
261 static const SfxItemPropertyMapEntry aRangePropertyMap_Impl[] =
262 {
263 { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
341 { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
348 { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
361 };
362 static SfxItemPropertySet aRangePropertySet( aRangePropertyMap_Impl );
363 return &aRangePropertySet;
364}
365
366// Cell contains entries from CellRange, plus its own entries
367// with Which-ID 0 (those are needed only for getPropertySetInfo).
368
370{
371 static const SfxItemPropertyMapEntry aCellPropertyMap_Impl[] =
372 {
373 { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
432 { SC_UNONAME_FORMRT, SC_WID_UNO_FORMRT, cppu::UnoType<table::CellContentType>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
434 { SC_UNONAME_FORMRT2, SC_WID_UNO_FORMRT2, cppu::UnoType<sal_Int32>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
455 { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
462 { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
477 };
478 static SfxItemPropertySet aCellPropertySet( aCellPropertyMap_Impl );
479 return &aCellPropertySet;
480}
481
482// Column and Row contain all entries from CellRange, plus its own entries
483// with Which-ID 0 (those are needed only for getPropertySetInfo).
484
486{
487 static const SfxItemPropertyMapEntry aColumnPropertyMap_Impl[] =
488 {
489 { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
571 { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
578 { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
591 };
592 static SfxItemPropertySet aColumnPropertySet( aColumnPropertyMap_Impl );
593 return &aColumnPropertySet;
594}
595
597{
598 static const SfxItemPropertyMapEntry aRowPropertyMap_Impl[] =
599 {
600 { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
684 { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
691 { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
703 };
704 static SfxItemPropertySet aRowPropertySet( aRowPropertyMap_Impl );
705 return &aRowPropertySet;
706}
707
709{
710 static const SfxItemPropertyMapEntry aSheetPropertyMap_Impl[] =
711 {
712 { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
783 { SC_UNO_LINKDISPBIT, SC_WID_UNO_LINKDISPBIT,cppu::UnoType<awt::XBitmap>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
784 { SC_UNO_LINKDISPNAME, SC_WID_UNO_LINKDISPNAME,cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
800 { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
810 { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
827 };
828 static SfxItemPropertySet aSheetPropertySet( aSheetPropertyMap_Impl );
829 return &aSheetPropertySet;
830}
831
833{
834 static const SfxItemPropertyMapEntry aEditPropertyMap_Impl[] =
835 {
839 SVX_UNOEDIT_NUMBERING_PROPERTY, // for completeness of service ParagraphProperties
842 };
843 return aEditPropertyMap_Impl;
844}
846{
848 return &aEditPropertySet;
849}
850
851constexpr OUStringLiteral SCCHARPROPERTIES_SERVICE = u"com.sun.star.style.CharacterProperties";
852constexpr OUStringLiteral SCPARAPROPERTIES_SERVICE = u"com.sun.star.style.ParagraphProperties";
853constexpr OUStringLiteral SCCELLPROPERTIES_SERVICE = u"com.sun.star.table.CellProperties";
854constexpr OUStringLiteral SCCELLRANGE_SERVICE = u"com.sun.star.table.CellRange";
855constexpr OUStringLiteral SCCELL_SERVICE = u"com.sun.star.table.Cell";
856constexpr OUStringLiteral SCSHEETCELLRANGES_SERVICE = u"com.sun.star.sheet.SheetCellRanges";
857constexpr OUStringLiteral SCSHEETCELLRANGE_SERVICE = u"com.sun.star.sheet.SheetCellRange";
858constexpr OUStringLiteral SCSPREADSHEET_SERVICE = u"com.sun.star.sheet.Spreadsheet";
859constexpr OUStringLiteral SCSHEETCELL_SERVICE = u"com.sun.star.sheet.SheetCell";
860
861SC_SIMPLE_SERVICE_INFO( ScCellFormatsEnumeration, "ScCellFormatsEnumeration", "com.sun.star.sheet.CellFormatRangesEnumeration" )
862SC_SIMPLE_SERVICE_INFO( ScCellFormatsObj, "ScCellFormatsObj", "com.sun.star.sheet.CellFormatRanges" )
863SC_SIMPLE_SERVICE_INFO( ScUniqueCellFormatsEnumeration, "ScUniqueCellFormatsEnumeration", "com.sun.star.sheet.UniqueCellFormatRangesEnumeration" )
864SC_SIMPLE_SERVICE_INFO( ScUniqueCellFormatsObj, "ScUniqueCellFormatsObj", "com.sun.star.sheet.UniqueCellFormatRanges" )
865SC_SIMPLE_SERVICE_INFO( ScCellRangesBase, "ScCellRangesBase", "stardiv.unknown" )
866SC_SIMPLE_SERVICE_INFO( ScCellsEnumeration, "ScCellsEnumeration", "com.sun.star.sheet.CellsEnumeration" )
867SC_SIMPLE_SERVICE_INFO( ScCellsObj, "ScCellsObj", "com.sun.star.sheet.Cells" )
868SC_SIMPLE_SERVICE_INFO( ScTableColumnObj, "ScTableColumnObj", "com.sun.star.table.TableColumn" )
869SC_SIMPLE_SERVICE_INFO( ScTableRowObj, "ScTableRowObj", "com.sun.star.table.TableRow" )
870
872
874{
875}
876
877void ScLinkListener::Notify( const SfxHint& rHint )
878{
879 aLink.Call( rHint );
880}
881
882static void lcl_CopyProperties( beans::XPropertySet& rDest, beans::XPropertySet& rSource )
883{
884 uno::Reference<beans::XPropertySetInfo> xInfo(rSource.getPropertySetInfo());
885 if (xInfo.is())
886 {
887 const uno::Sequence<beans::Property> aSeq(xInfo->getProperties());
888 for (const beans::Property& rProp : aSeq)
889 {
890 OUString aName(rProp.Name);
891 rDest.setPropertyValue( aName, rSource.getPropertyValue( aName ) );
892 }
893 }
894}
895
896static SCTAB lcl_FirstTab( const ScRangeList& rRanges )
897{
898 if (rRanges.empty())
899 throw std::out_of_range("empty range");
900 const ScRange & rFirst = rRanges[0];
901 return rFirst.aStart.Tab();
902}
903
904static bool lcl_WholeSheet( const ScDocument& rDoc, const ScRangeList& rRanges )
905{
906 if ( rRanges.size() == 1 )
907 {
908 const ScRange & rRange = rRanges[0];
909 if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
910 rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
911 return true;
912 }
913 return false;
914}
915
916namespace {
917template<typename BorderLineType>
918const ::editeng::SvxBorderLine* lcl_getBorderLine(
919 ::editeng::SvxBorderLine& rLine, const BorderLineType& rStruct )
920{
921 // Convert from 1/100mm to Twips.
922 if (!SvxBoxItem::LineToSvxLine( rStruct, rLine, true))
923 return nullptr;
924
925 if ( rLine.GetOutWidth() || rLine.GetInWidth() || rLine.GetDistance() )
926 return &rLine;
927 else
928 return nullptr;
929}
930}
931
932const ::editeng::SvxBorderLine* ScHelperFunctions::GetBorderLine(
933 ::editeng::SvxBorderLine& rLine, const table::BorderLine& rStruct )
934{
935 return lcl_getBorderLine( rLine, rStruct);
936}
937
938const ::editeng::SvxBorderLine* ScHelperFunctions::GetBorderLine(
939 ::editeng::SvxBorderLine& rLine, const table::BorderLine2& rStruct )
940{
941 return lcl_getBorderLine( rLine, rStruct);
942}
943
944namespace {
945template<typename TableBorderType>
946void lcl_fillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const TableBorderType& rBorder )
947{
949 rOuter.SetAllDistances(o3tl::toTwips(rBorder.Distance, o3tl::Length::mm100));
950 rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.TopLine ), SvxBoxItemLine::TOP );
951 rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.BottomLine ), SvxBoxItemLine::BOTTOM );
952 rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.LeftLine ), SvxBoxItemLine::LEFT );
953 rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.RightLine ), SvxBoxItemLine::RIGHT );
954 rInner.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.HorizontalLine ), SvxBoxInfoItemLine::HORI );
955 rInner.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.VerticalLine ), SvxBoxInfoItemLine::VERT );
956 rInner.SetValid( SvxBoxInfoItemValidFlags::TOP, rBorder.IsTopLineValid );
957 rInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, rBorder.IsBottomLineValid );
958 rInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, rBorder.IsLeftLineValid );
959 rInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, rBorder.IsRightLineValid );
960 rInner.SetValid( SvxBoxInfoItemValidFlags::HORI, rBorder.IsHorizontalLineValid );
961 rInner.SetValid( SvxBoxInfoItemValidFlags::VERT, rBorder.IsVerticalLineValid );
962 rInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE, rBorder.IsDistanceValid );
963 rInner.SetTable( true );
964}
965}
966
967void ScHelperFunctions::FillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const table::TableBorder& rBorder )
968{
969 lcl_fillBoxItems( rOuter, rInner, rBorder);
970}
971
972void ScHelperFunctions::FillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const table::TableBorder2& rBorder )
973{
974 lcl_fillBoxItems( rOuter, rInner, rBorder);
975}
976
977void ScHelperFunctions::FillBorderLine( table::BorderLine& rStruct, const ::editeng::SvxBorderLine* pLine )
978{
979 // Convert from Twips to 1/100mm.
980 rStruct = SvxBoxItem::SvxLineToLine( pLine, true);
981}
982
983void ScHelperFunctions::FillBorderLine( table::BorderLine2& rStruct, const ::editeng::SvxBorderLine* pLine )
984{
985 rStruct = SvxBoxItem::SvxLineToLine( pLine, true);
986}
987
988namespace {
989template<typename TableBorderItem>
990void lcl_fillTableBorder( TableBorderItem& rBorder, const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner,
991 bool bInvalidateHorVerDist )
992{
993 ScHelperFunctions::FillBorderLine( rBorder.TopLine, rOuter.GetTop() );
994 ScHelperFunctions::FillBorderLine( rBorder.BottomLine, rOuter.GetBottom() );
995 ScHelperFunctions::FillBorderLine( rBorder.LeftLine, rOuter.GetLeft() );
996 ScHelperFunctions::FillBorderLine( rBorder.RightLine, rOuter.GetRight() );
997 ScHelperFunctions::FillBorderLine( rBorder.HorizontalLine, rInner.GetHori() );
998 ScHelperFunctions::FillBorderLine( rBorder.VerticalLine, rInner.GetVert() );
999
1000 rBorder.Distance = rOuter.GetSmallestDistance();
1001 rBorder.IsTopLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::TOP);
1002 rBorder.IsBottomLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
1003 rBorder.IsLeftLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::LEFT);
1004 rBorder.IsRightLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::RIGHT);
1005 rBorder.IsHorizontalLineValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::HORI);
1006 rBorder.IsVerticalLineValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::VERT);
1007 rBorder.IsDistanceValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
1008}
1009}
1010
1012 const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner, bool bInvalidateHorVerDist )
1013{
1014 table::TableBorder aBorder;
1015 lcl_fillTableBorder( aBorder, rOuter, rInner, bInvalidateHorVerDist);
1016 rAny <<= aBorder;
1017}
1018
1020 const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner, bool bInvalidateHorVerDist )
1021{
1022 table::TableBorder2 aBorder;
1023 lcl_fillTableBorder( aBorder, rOuter, rInner, bInvalidateHorVerDist);
1024 rAny <<= aBorder;
1025}
1026
1028
1030 const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner )
1031{
1032 ScDocument& rDoc = pDocShell->GetDocument();
1033 bool bUndo(rDoc.IsUndoEnabled());
1034 ScDocumentUniquePtr pUndoDoc;
1035 if (bUndo)
1036 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1037 size_t nCount = rRanges.size();
1038 for (size_t i = 0; i < nCount; ++i)
1039 {
1040 ScRange const & rRange = rRanges[ i ];
1041 SCTAB nTab = rRange.aStart.Tab();
1042
1043 if (bUndo)
1044 {
1045 if ( i==0 )
1046 pUndoDoc->InitUndo( rDoc, nTab, nTab );
1047 else
1048 pUndoDoc->AddUndoTab( nTab, nTab );
1049 rDoc.CopyToDocument(rRange, InsertDeleteFlags::ATTRIB, false, *pUndoDoc);
1050 }
1051
1052 ScMarkData aMark(rDoc.GetSheetLimits());
1053 aMark.SetMarkArea( rRange );
1054 aMark.SelectTable( nTab, true );
1055
1056 rDoc.ApplySelectionFrame(aMark, rOuter, &rInner);
1057 // don't need RowHeight if there is only a border
1058 }
1059
1060 if (bUndo)
1061 {
1062 pDocShell->GetUndoManager()->AddUndoAction(
1063 std::make_unique<ScUndoBorder>( pDocShell, rRanges, std::move(pUndoDoc), rOuter, rInner ) );
1064 }
1065
1066 for (size_t i = 0; i < nCount; ++i )
1067 pDocShell->PostPaint( rRanges[ i ], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
1068
1069 pDocShell->SetDocumentModified();
1070}
1071
1074
1075static bool lcl_PutDataArray( ScDocShell& rDocShell, const ScRange& rRange,
1076 const uno::Sequence< uno::Sequence<uno::Any> >& aData )
1077{
1078 ScDocument& rDoc = rDocShell.GetDocument();
1079 ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
1080 SCTAB nTab = rRange.aStart.Tab();
1081 SCCOL nStartCol = rRange.aStart.Col();
1082 SCROW nStartRow = rRange.aStart.Row();
1083 SCCOL nEndCol = rRange.aEnd.Col();
1084 SCROW nEndRow = rRange.aEnd.Row();
1085 bool bUndo(rDoc.IsUndoEnabled());
1086
1087 if ( !rDoc.IsBlockEditable( nTab, nStartCol,nStartRow, nEndCol,nEndRow ) )
1088 {
1090 return false;
1091 }
1092
1093 sal_Int32 nCols = 0;
1094 sal_Int32 nRows = aData.getLength();
1095 if ( nRows )
1096 nCols = aData[0].getLength();
1097
1098 if ( nCols != nEndCol-nStartCol+1 || nRows != nEndRow-nStartRow+1 )
1099 {
1101 return false;
1102 }
1103
1104 ScDocumentUniquePtr pUndoDoc;
1105 if ( bUndo )
1106 {
1107 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1108 pUndoDoc->InitUndo( rDoc, nTab, nTab );
1110 }
1111
1112 rDoc.DeleteAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
1113
1114 bool bError = false;
1115 SCROW nDocRow = nStartRow;
1116 for (const uno::Sequence<uno::Any>& rColSeq : aData)
1117 {
1118 if ( rColSeq.getLength() == nCols )
1119 {
1120 SCCOL nDocCol = nStartCol;
1121 for (const uno::Any& rElement : rColSeq)
1122 {
1123 ScAddress aPos(nDocCol, nDocRow, nTab);
1124
1125 switch( rElement.getValueTypeClass() )
1126 {
1127 case uno::TypeClass_VOID:
1128 {
1129 // void = "no value"
1130 rDoc.SetError( nDocCol, nDocRow, nTab, FormulaError::NotAvailable );
1131 }
1132 break;
1133
1134 // #87871# accept integer types because Basic passes a floating point
1135 // variable as byte, short or long if it's an integer number.
1136 case uno::TypeClass_BYTE:
1137 case uno::TypeClass_SHORT:
1138 case uno::TypeClass_UNSIGNED_SHORT:
1139 case uno::TypeClass_LONG:
1140 case uno::TypeClass_UNSIGNED_LONG:
1141 case uno::TypeClass_FLOAT:
1142 case uno::TypeClass_DOUBLE:
1143 {
1144 double fVal(0.0);
1145 rElement >>= fVal;
1146 rDoc.SetValue(aPos, fVal);
1147 }
1148 break;
1149
1150 case uno::TypeClass_STRING:
1151 {
1152 OUString aUStr;
1153 rElement >>= aUStr;
1154 if ( !aUStr.isEmpty() )
1155 {
1156 // tdf#146454 - check for a multiline string since setting an edit
1157 // or string cell is in magnitudes slower than setting a plain string
1158 if (ScStringUtil::isMultiline(aUStr))
1159 {
1160 rEngine.SetTextCurrentDefaults(aUStr);
1161 rDoc.SetEditText(aPos, rEngine.CreateTextObject());
1162 }
1163 else
1164 {
1165 ScSetStringParam aParam;
1166 aParam.setTextInput();
1167 rDoc.SetString(aPos, aUStr, &aParam);
1168 }
1169 }
1170 }
1171 break;
1172
1173 // accept Sequence<FormulaToken> for formula cells
1174 case uno::TypeClass_SEQUENCE:
1175 {
1176 uno::Sequence< sheet::FormulaToken > aTokens;
1177 if ( rElement >>= aTokens )
1178 {
1179 ScTokenArray aTokenArray(rDoc);
1180 ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, aTokens );
1181 rDoc.SetFormula(aPos, aTokenArray);
1182 }
1183 else
1184 bError = true;
1185 }
1186 break;
1187
1188 default:
1189 bError = true; // invalid type
1190 }
1191 ++nDocCol;
1192 }
1193 }
1194 else
1195 bError = true; // wrong size
1196
1197 ++nDocRow;
1198 }
1199
1200 bool bHeight = rDocShell.AdjustRowHeight( nStartRow, nEndRow, nTab );
1201
1202 if ( pUndoDoc )
1203 {
1204 ScMarkData aDestMark(rDoc.GetSheetLimits());
1205 aDestMark.SelectOneTable( nTab );
1206 rDocShell.GetUndoManager()->AddUndoAction(
1207 std::make_unique<ScUndoPaste>(
1208 &rDocShell, ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab),
1209 aDestMark, std::move(pUndoDoc), nullptr, InsertDeleteFlags::CONTENTS, nullptr, false));
1210 }
1211
1212 if (!bHeight)
1213 rDocShell.PostPaint( rRange, PaintPartFlags::Grid ); // AdjustRowHeight may have painted already
1214
1215 rDocShell.SetDocumentModified();
1216
1217 return !bError;
1218}
1219
1220static bool lcl_PutFormulaArray( ScDocShell& rDocShell, const ScRange& rRange,
1221 const uno::Sequence< uno::Sequence<OUString> >& aData,
1222 const formula::FormulaGrammar::Grammar eGrammar )
1223{
1224 ScDocument& rDoc = rDocShell.GetDocument();
1225 SCTAB nTab = rRange.aStart.Tab();
1226 SCCOL nStartCol = rRange.aStart.Col();
1227 SCROW nStartRow = rRange.aStart.Row();
1228 SCCOL nEndCol = rRange.aEnd.Col();
1229 SCROW nEndRow = rRange.aEnd.Row();
1230 bool bUndo(rDoc.IsUndoEnabled());
1231
1232 if ( !rDoc.IsBlockEditable( nTab, nStartCol,nStartRow, nEndCol,nEndRow ) )
1233 {
1235 return false;
1236 }
1237
1238 sal_Int32 nCols = 0;
1239 sal_Int32 nRows = aData.getLength();
1240 if ( nRows )
1241 nCols = aData[0].getLength();
1242
1243 if ( nCols != nEndCol-nStartCol+1 || nRows != nEndRow-nStartRow+1 )
1244 {
1246 return false;
1247 }
1248
1249 ScDocumentUniquePtr pUndoDoc;
1250 if ( bUndo )
1251 {
1252 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1253 pUndoDoc->InitUndo( rDoc, nTab, nTab );
1254 rDoc.CopyToDocument(rRange, InsertDeleteFlags::CONTENTS, false, *pUndoDoc);
1255 }
1256
1257 rDoc.DeleteAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
1258
1259 bool bError = false;
1260 SCROW nDocRow = nStartRow;
1261 for (const uno::Sequence<OUString>& rColSeq : aData)
1262 {
1263 if ( rColSeq.getLength() == nCols )
1264 {
1265 SCCOL nDocCol = nStartCol;
1266 for (const OUString& aText : rColSeq)
1267 {
1268 ScAddress aPos( nDocCol, nDocRow, nTab );
1269
1270 ScInputStringType aRes =
1272 *rDoc.GetFormatTable(), aText, LANGUAGE_ENGLISH_US);
1273 switch (aRes.meType)
1274 {
1276 rDoc.SetFormula(aPos, aRes.maText, eGrammar);
1277 break;
1279 rDoc.SetValue(aPos, aRes.mfValue);
1280 break;
1282 rDoc.SetTextCell(aPos, aRes.maText);
1283 break;
1284 default:
1285 ;
1286 }
1287
1288 ++nDocCol;
1289 }
1290 }
1291 else
1292 bError = true; // wrong size
1293
1294 ++nDocRow;
1295 }
1296
1297 bool bHeight = rDocShell.AdjustRowHeight( nStartRow, nEndRow, nTab );
1298
1299 if ( pUndoDoc )
1300 {
1301 ScMarkData aDestMark(rDoc.GetSheetLimits());
1302 aDestMark.SelectOneTable( nTab );
1303 rDocShell.GetUndoManager()->AddUndoAction(
1304 std::make_unique<ScUndoPaste>( &rDocShell,
1305 ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab), aDestMark,
1306 std::move(pUndoDoc), nullptr, InsertDeleteFlags::CONTENTS, nullptr, false));
1307 }
1308
1309 if (!bHeight)
1310 rDocShell.PostPaint( rRange, PaintPartFlags::Grid ); // AdjustRowHeight may have painted already
1311
1312 rDocShell.SetDocumentModified();
1313
1314 return !bError;
1315}
1316
1317// used in ScCellRangeObj::getFormulaArray and ScCellObj::GetInputString_Impl
1318static OUString lcl_GetInputString( ScDocument& rDoc, const ScAddress& rPos, bool bEnglish )
1319{
1320 ScRefCellValue aCell(rDoc, rPos);
1321 if (aCell.isEmpty())
1322 return OUString();
1323
1324 OUString aVal;
1325
1326 CellType eType = aCell.getType();
1327 if (eType == CELLTYPE_FORMULA)
1328 {
1329 ScFormulaCell* pForm = aCell.getFormula();
1330 return pForm->GetFormula( formula::FormulaGrammar::mapAPItoGrammar( bEnglish, false));
1331 }
1332
1333 SvNumberFormatter* pFormatter = bEnglish ? ScGlobal::GetEnglishFormatter() :
1334 rDoc.GetFormatTable();
1335 // Since the English formatter was constructed with
1336 // LANGUAGE_ENGLISH_US the "General" format has index key 0,
1337 // we don't have to query.
1338 sal_uInt32 nNumFmt = bEnglish ? 0 : rDoc.GetNumberFormat(rPos);
1339
1340 if (eType == CELLTYPE_EDIT)
1341 {
1342 // GetString on EditCell turns breaks into spaces,
1343 // but we need the breaks here
1344 const EditTextObject* pData = aCell.getEditText();
1345 if (pData)
1346 {
1347 EditEngine& rEngine = rDoc.GetEditEngine();
1348 rEngine.SetText(*pData);
1349 aVal = rEngine.GetText();
1350 }
1351 }
1352 else
1353 aVal = ScCellFormat::GetInputString(aCell, nNumFmt, *pFormatter, rDoc);
1354
1355 // if applicable, prepend ' like in ScTabViewShell::UpdateInputHandler
1357 {
1358 double fDummy;
1359 OUString aTempString = aVal;
1360 bool bIsNumberFormat(pFormatter->IsNumberFormat(aTempString, nNumFmt, fDummy));
1361 if ( bIsNumberFormat )
1362 aTempString = "'" + aTempString;
1363 else if ( aTempString.startsWith("'") )
1364 {
1365 // if the string starts with a "'", add another one because setFormula
1366 // strips one (like text input, except for "text" number formats)
1367 if ( bEnglish || ( pFormatter->GetType(nNumFmt) != SvNumFormatType::TEXT ) )
1368 aTempString = "'" + aTempString;
1369 }
1370 aVal = aTempString;
1371 }
1372 return aVal;
1373}
1374
1375ScCellRangesBase::ScCellRangesBase(ScDocShell* pDocSh, const ScRange& rR) :
1376 pPropSet(lcl_GetCellsPropertySet()),
1377 pDocShell( pDocSh ),
1378 nObjectId( 0 ),
1379 bChartColAsHdr( false ),
1380 bChartRowAsHdr( false ),
1381 bCursorOnly( false ),
1382 bGotDataChangedHint( false ),
1383 aValueListeners( 0 )
1384{
1385 ScRange aCellRange(rR);
1386 aCellRange.PutInOrder();
1387 aRanges.push_back( aCellRange );
1388
1389 if (pDocShell) // Null if created with createInstance
1390 {
1391 ScDocument& rDoc = pDocShell->GetDocument();
1392 rDoc.AddUnoObject(*this);
1393 nObjectId = rDoc.GetNewUnoId();
1394 }
1395}
1396
1397ScCellRangesBase::ScCellRangesBase(ScDocShell* pDocSh, ScRangeList aR) :
1398 pPropSet(lcl_GetCellsPropertySet()),
1399 pDocShell( pDocSh ),
1400 aRanges(std::move( aR )),
1401 nObjectId( 0 ),
1402 bChartColAsHdr( false ),
1403 bChartRowAsHdr( false ),
1404 bCursorOnly( false ),
1405 bGotDataChangedHint( false ),
1406 aValueListeners( 0 )
1407{
1408 if (pDocShell) // Null if created with createInstance
1409 {
1410 ScDocument& rDoc = pDocShell->GetDocument();
1411 rDoc.AddUnoObject(*this);
1412 nObjectId = rDoc.GetNewUnoId();
1413 }
1414}
1415
1416ScCellRangesBase::~ScCellRangesBase()
1417{
1419
1420 // call RemoveUnoObject first, so no notification can happen
1421 // during ForgetCurrentAttrs
1422
1423 if (pDocShell)
1424 pDocShell->GetDocument().RemoveUnoObject(*this);
1425
1426 ForgetCurrentAttrs();
1427 ForgetMarkData();
1428
1429 pValueListener.reset();
1430
1433}
1434
1435void ScCellRangesBase::ForgetCurrentAttrs()
1436{
1437 pCurrentFlat.reset();
1438 pCurrentDeep.reset();
1439 moCurrentDataSet.reset();
1440 moNoDfltCurrentDataSet.reset();
1441
1442 // #i62483# pMarkData can remain unchanged, is deleted only if the range changes (RefChanged)
1443}
1444
1445void ScCellRangesBase::ForgetMarkData()
1446{
1447 pMarkData.reset();
1448}
1449
1450const ScPatternAttr* ScCellRangesBase::GetCurrentAttrsFlat()
1451{
1452 // get and cache direct cell attributes for this object's range
1453
1454 if ( !pCurrentFlat && pDocShell )
1455 {
1456 ScDocument& rDoc = pDocShell->GetDocument();
1457 pCurrentFlat = rDoc.CreateSelectionPattern( *GetMarkData(), false );
1458 }
1459 return pCurrentFlat.get();
1460}
1461
1462const ScPatternAttr* ScCellRangesBase::GetCurrentAttrsDeep()
1463{
1464 // get and cache cell attributes (incl. styles) for this object's range
1465
1466 if ( !pCurrentDeep && pDocShell )
1467 {
1468 ScDocument& rDoc = pDocShell->GetDocument();
1469 pCurrentDeep = rDoc.CreateSelectionPattern( *GetMarkData() );
1470 }
1471 return pCurrentDeep.get();
1472}
1473
1474SfxItemSet* ScCellRangesBase::GetCurrentDataSet(bool bNoDflt)
1475{
1476 if(!moCurrentDataSet)
1477 {
1478 const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
1479 if ( pPattern )
1480 {
1481 // replace Dontcare with Default, so that we always have a reflection
1482 moCurrentDataSet.emplace( pPattern->GetItemSet() );
1483 moNoDfltCurrentDataSet.emplace( pPattern->GetItemSet() );
1484 moCurrentDataSet->ClearInvalidItems();
1485 }
1486 }
1487 if (bNoDflt)
1488 {
1489 if (moNoDfltCurrentDataSet)
1490 return &*moNoDfltCurrentDataSet;
1491 }
1492 else
1493 {
1494 if (moCurrentDataSet)
1495 return &*moCurrentDataSet;
1496 }
1497 return nullptr;
1498}
1499
1500const ScMarkData* ScCellRangesBase::GetMarkData()
1501{
1502 if (!pMarkData)
1503 {
1504 pMarkData.reset( new ScMarkData(GetDocument()->GetSheetLimits(), aRanges) );
1505 }
1506 return pMarkData.get();
1507}
1508
1509void ScCellRangesBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
1510{
1511 const SfxHintId nId = rHint.GetId();
1512 if ( nId == SfxHintId::Dying )
1513 {
1514 // if the document dies, must reset to avoid crash in dtor!
1515 ForgetCurrentAttrs();
1516 pDocShell = nullptr; // invalid
1517
1518 // fdo#72695: if UNO object is already dead, don't revive it with event
1519 if ( m_refCount > 0 && !aValueListeners.empty() )
1520 {
1521 // dispose listeners
1522
1523 lang::EventObject aEvent;
1524 aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
1525 for (uno::Reference<util::XModifyListener> & xValueListener : aValueListeners)
1526 xValueListener->disposing( aEvent );
1527
1528 aValueListeners.clear();
1529
1530 // The listeners can't have the last ref to this, as it's still held
1531 // by the DocShell.
1532 }
1533 }
1534 else if ( nId == SfxHintId::DataChanged )
1535 {
1536 // document content changed -> forget cached attributes
1537 ForgetCurrentAttrs();
1538
1539 if ( bGotDataChangedHint && pDocShell )
1540 {
1541 // This object was notified of content changes, so one call
1542 // for each listener is generated now.
1543 // The calls can't be executed directly because the document's
1544 // UNO broadcaster list must not be modified.
1545 // Instead, add to the document's list of listener calls,
1546 // which will be executed directly after the broadcast of
1547 // SfxHintId::DataChanged.
1548
1549 lang::EventObject aEvent;
1550 aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
1551
1552 // the EventObject holds a Ref to this object until after the listener calls
1553
1554 ScDocument& rDoc = pDocShell->GetDocument();
1555 for (const uno::Reference<util::XModifyListener> & xValueListener : aValueListeners)
1556 rDoc.AddUnoListenerCall( xValueListener, aEvent );
1557
1558 bGotDataChangedHint = false;
1559 }
1560 }
1561 else if ( nId == SfxHintId::ScCalcAll )
1562 {
1563 // broadcast from DoHardRecalc - set bGotDataChangedHint
1564 // (SfxHintId::DataChanged follows separately)
1565
1566 if ( !aValueListeners.empty() )
1567 bGotDataChangedHint = true;
1568 }
1569 else if ( auto pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint) )
1570 {
1571 ScDocument& rDoc = pDocShell->GetDocument();
1572 std::unique_ptr<ScRangeList> pUndoRanges;
1573 if ( rDoc.HasUnoRefUndo() )
1574 pUndoRanges.reset(new ScRangeList( aRanges ));
1575
1576 if ( aRanges.UpdateReference( pRefHint->GetMode(), &rDoc, pRefHint->GetRange(),
1577 pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() ) )
1578 {
1579 if ( pRefHint->GetMode() == URM_INSDEL
1580 && aRanges.size() == 1
1581 && dynamic_cast<ScTableSheetObj*>(this)
1582 )
1583 {
1584 // #101755#; the range size of a sheet does not change
1585 ScRange & rR = aRanges.front();
1586 rR.aStart.SetCol(0);
1587 rR.aStart.SetRow(0);
1588 rR.aEnd.SetCol(rDoc.MaxCol());
1589 rR.aEnd.SetRow(rDoc.MaxRow());
1590 }
1591 RefChanged();
1592
1593 // any change of the range address is broadcast to value (modify) listeners
1594 if ( !aValueListeners.empty() )
1595 bGotDataChangedHint = true;
1596
1597 if ( pUndoRanges )
1598 rDoc.AddUnoRefChange( nObjectId, *pUndoRanges );
1599 }
1600 }
1601 else if ( auto pUndoHint = dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
1602 {
1603 if ( pUndoHint->GetObjectId() == nObjectId )
1604 {
1605 // restore ranges from hint
1606
1607 aRanges = pUndoHint->GetRanges();
1608
1609 RefChanged();
1610 if ( !aValueListeners.empty() )
1611 bGotDataChangedHint = true; // need to broadcast the undo, too
1612 }
1613 }
1614}
1615
1616void ScCellRangesBase::RefChanged()
1617{
1619
1620 if ( pValueListener && !aValueListeners.empty() )
1621 {
1622 pValueListener->EndListeningAll();
1623
1624 ScDocument& rDoc = pDocShell->GetDocument();
1625 for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
1626 rDoc.StartListeningArea( aRanges[ i ], false, pValueListener.get() );
1627 }
1628
1629 ForgetCurrentAttrs();
1630 ForgetMarkData();
1631}
1632
1633ScDocument* ScCellRangesBase::GetDocument() const
1634{
1635 if (pDocShell)
1636 return &pDocShell->GetDocument();
1637 else
1638 return nullptr;
1639}
1640
1641void ScCellRangesBase::InitInsertRange(ScDocShell* pDocSh, const ScRange& rR)
1642{
1643 if ( pDocShell || !pDocSh )
1644 return;
1645
1646 pDocShell = pDocSh;
1647
1648 ScRange aCellRange(rR);
1649 aCellRange.PutInOrder();
1650 aRanges.RemoveAll();
1651 aRanges.push_back( aCellRange );
1652
1653 pDocShell->GetDocument().AddUnoObject(*this);
1654
1655 RefChanged(); // adjust range in range object
1656}
1657
1658void ScCellRangesBase::AddRange(const ScRange& rRange, const bool bMergeRanges)
1659{
1660 if (bMergeRanges)
1661 aRanges.Join(rRange);
1662 else
1663 aRanges.push_back(rRange);
1664 RefChanged();
1665}
1666
1667void ScCellRangesBase::SetNewRange(const ScRange& rNew)
1668{
1669 ScRange aCellRange(rNew);
1670 aCellRange.PutInOrder();
1671
1672 aRanges.RemoveAll();
1673 aRanges.push_back( aCellRange );
1674 RefChanged();
1675}
1676
1677void ScCellRangesBase::SetNewRanges(const ScRangeList& rNew)
1678{
1679 aRanges = rNew;
1680 RefChanged();
1681}
1682
1683void ScCellRangesBase::SetCursorOnly( bool bSet )
1684{
1685 // set for a selection object that is created from the cursor position
1686 // without anything selected (may contain several sheets)
1687
1688 bCursorOnly = bSet;
1689}
1690
1691void ScCellRangesBase::PaintGridRanges_Impl( )
1692{
1693 for (size_t i = 0, nCount = aRanges.size(); i < nCount; ++i)
1694 pDocShell->PostPaint( aRanges[ i ], PaintPartFlags::Grid );
1695}
1696
1697// XSheetOperation
1698
1699double SAL_CALL ScCellRangesBase::computeFunction( sheet::GeneralFunction nFunction )
1700{
1701 SolarMutexGuard aGuard;
1702 ScMarkData aMark(*GetMarkData());
1703 aMark.MarkToSimple();
1704 if (!aMark.IsMarked())
1705 aMark.SetMarkNegative(true); // so we can enter dummy position
1706
1707 ScAddress aDummy; // if not marked, ignored if it is negative
1708 double fVal;
1709 ScSubTotalFunc eFunc = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(nFunction));
1710 ScDocument& rDoc = pDocShell->GetDocument();
1711 if ( !rDoc.GetSelectionFunction( eFunc, aDummy, aMark, fVal ) )
1712 {
1713 throw uno::RuntimeException();
1714 }
1715
1716 return fVal;
1717}
1718
1719void SAL_CALL ScCellRangesBase::clearContents( sal_Int32 nContentFlags )
1720{
1721 SolarMutexGuard aGuard;
1722 if ( !aRanges.empty() )
1723 {
1724 // only for clearContents: EDITATTR is only used if no contents are deleted
1725 InsertDeleteFlags nDelFlags = static_cast<InsertDeleteFlags>(nContentFlags) & InsertDeleteFlags::ALL;
1726 if ( ( nDelFlags & InsertDeleteFlags::EDITATTR ) && ( nDelFlags & InsertDeleteFlags::CONTENTS ) == InsertDeleteFlags::NONE )
1727 nDelFlags |= InsertDeleteFlags::EDITATTR;
1728
1729 pDocShell->GetDocFunc().DeleteContents( *GetMarkData(), nDelFlags, true, true );
1730 }
1731 // otherwise nothing to do
1732}
1733
1734// XPropertyState
1735
1736const SfxItemPropertyMap& ScCellRangesBase::GetItemPropertyMap()
1737{
1738 return pPropSet->getPropertyMap();
1739}
1740
1742 sal_uInt16& rItemWhich )
1743{
1744 // Which-ID of the affected items also when the item can't handle
1745 // the property by itself
1746 if ( !pEntry )
1747 return;
1748
1749 if ( IsScItemWid( pEntry->nWID ) )
1750 rItemWhich = pEntry->nWID;
1751 else
1752 switch ( pEntry->nWID )
1753 {
1754 case SC_WID_UNO_TBLBORD:
1756 rItemWhich = ATTR_BORDER;
1757 break;
1758 case SC_WID_UNO_CONDFMT:
1759 case SC_WID_UNO_CONDLOC:
1760 case SC_WID_UNO_CONDXML:
1761 rItemWhich = ATTR_CONDITIONAL;
1762 break;
1763 case SC_WID_UNO_VALIDAT:
1764 case SC_WID_UNO_VALILOC:
1765 case SC_WID_UNO_VALIXML:
1766 rItemWhich = ATTR_VALIDDATA;
1767 break;
1768 }
1769
1770}
1771
1772beans::PropertyState ScCellRangesBase::GetOnePropertyState( sal_uInt16 nItemWhich, const SfxItemPropertyMapEntry* pEntry )
1773{
1774 beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
1775 if ( nItemWhich ) // item wid (from map or special case)
1776 {
1777 // For items that contain several properties (like background),
1778 // "ambiguous" is returned too often here
1779
1780 // for PropertyState, don't look at styles
1781 const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
1782 if ( pPattern )
1783 {
1784 SfxItemState eState = pPattern->GetItemSet().GetItemState( nItemWhich, false );
1785
1786 if ( nItemWhich == ATTR_VALUE_FORMAT && eState == SfxItemState::DEFAULT )
1787 eState = pPattern->GetItemSet().GetItemState( ATTR_LANGUAGE_FORMAT, false );
1788
1789 if ( eState == SfxItemState::SET )
1790 eRet = beans::PropertyState_DIRECT_VALUE;
1791 else if ( eState == SfxItemState::DEFAULT )
1792 eRet = beans::PropertyState_DEFAULT_VALUE;
1793 else if ( eState == SfxItemState::DONTCARE )
1794 eRet = beans::PropertyState_AMBIGUOUS_VALUE;
1795 else
1796 {
1797 OSL_FAIL("unknown ItemState");
1798 }
1799 }
1800 }
1801 else if ( pEntry )
1802 {
1803 if ( pEntry->nWID == SC_WID_UNO_CHCOLHDR || pEntry->nWID == SC_WID_UNO_CHROWHDR || pEntry->nWID == SC_WID_UNO_ABSNAME )
1804 eRet = beans::PropertyState_DIRECT_VALUE;
1805 else if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
1806 {
1807 // a style is always set, there's no default state
1808 const ScStyleSheet* pStyle = pDocShell->GetDocument().GetSelectionStyle(*GetMarkData());
1809 if (pStyle)
1810 eRet = beans::PropertyState_DIRECT_VALUE;
1811 else
1812 eRet = beans::PropertyState_AMBIGUOUS_VALUE;
1813 }
1814 else if ( pEntry->nWID == SC_WID_UNO_NUMRULES )
1815 eRet = beans::PropertyState_DEFAULT_VALUE; // numbering rules are always default
1816 }
1817 return eRet;
1818}
1819
1820beans::PropertyState SAL_CALL ScCellRangesBase::getPropertyState( const OUString& aPropertyName )
1821{
1822 SolarMutexGuard aGuard;
1823 if ( aRanges.empty() )
1824 throw uno::RuntimeException();
1825
1826 const SfxItemPropertyMap& rMap = GetItemPropertyMap(); // from derived class
1827 sal_uInt16 nItemWhich = 0;
1828 const SfxItemPropertyMapEntry* pEntry = rMap.getByName( aPropertyName );
1829 lcl_GetPropertyWhich( pEntry, nItemWhich );
1830 return GetOnePropertyState( nItemWhich, pEntry );
1831}
1832
1833uno::Sequence<beans::PropertyState> SAL_CALL ScCellRangesBase::getPropertyStates(
1834 const uno::Sequence<OUString>& aPropertyNames )
1835{
1836 SolarMutexGuard aGuard;
1837
1838 const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
1839
1840 uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
1841 std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.getArray(),
1842 [this, &rPropertyMap](const auto& rName) -> beans::PropertyState {
1843 sal_uInt16 nItemWhich = 0;
1844 const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( rName );
1845 lcl_GetPropertyWhich( pEntry, nItemWhich );
1846 return GetOnePropertyState(nItemWhich, pEntry);
1847 });
1848 return aRet;
1849}
1850
1851void SAL_CALL ScCellRangesBase::setPropertyToDefault( const OUString& aPropertyName )
1852{
1853 SolarMutexGuard aGuard;
1854 if ( !pDocShell )
1855 return;
1856
1857 const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
1858 sal_uInt16 nItemWhich = 0;
1859 const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
1860 lcl_GetPropertyWhich( pEntry, nItemWhich );
1861 if ( nItemWhich ) // item wid (from map or special case)
1862 {
1863 if ( !aRanges.empty() ) // empty = nothing to do
1864 {
1868
1869 sal_uInt16 aWIDs[3];
1870 aWIDs[0] = nItemWhich;
1871 if ( nItemWhich == ATTR_VALUE_FORMAT )
1872 {
1873 aWIDs[1] = ATTR_LANGUAGE_FORMAT; // language for number formats
1874 aWIDs[2] = 0;
1875 }
1876 else
1877 aWIDs[1] = 0;
1878 pDocShell->GetDocFunc().ClearItems( *GetMarkData(), aWIDs, true );
1879 }
1880 }
1881 else if ( pEntry )
1882 {
1883 if ( pEntry->nWID == SC_WID_UNO_CHCOLHDR )
1884 bChartColAsHdr = false;
1885 else if ( pEntry->nWID == SC_WID_UNO_CHROWHDR )
1886 bChartRowAsHdr = false;
1887 else if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
1888 {
1889 OUString aStyleName( ScResId( STR_STYLENAME_STANDARD ) );
1890 pDocShell->GetDocFunc().ApplyStyle( *GetMarkData(), aStyleName, true );
1891 }
1892 }
1893}
1894
1895uno::Any SAL_CALL ScCellRangesBase::getPropertyDefault( const OUString& aPropertyName )
1896{
1898
1899 SolarMutexGuard aGuard;
1900 uno::Any aAny;
1901
1902 if ( pDocShell )
1903 {
1904 ScDocument& rDoc = pDocShell->GetDocument();
1905 const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
1906 const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
1907 if ( pEntry )
1908 {
1909 if ( IsScItemWid( pEntry->nWID ) )
1910 {
1911 const ScPatternAttr* pPattern = rDoc.GetDefPattern();
1912 if ( pPattern )
1913 {
1914 const SfxItemSet& rSet = pPattern->GetItemSet();
1915
1916 switch ( pEntry->nWID ) // for item-specific handling
1917 {
1918 case ATTR_VALUE_FORMAT:
1919 // default has no language set
1920 aAny <<= static_cast<sal_Int32>( static_cast<const SfxUInt32Item&>(rSet.Get(pEntry->nWID)).GetValue() );
1921 break;
1922 case ATTR_INDENT:
1923 aAny <<= static_cast<sal_Int16>( convertTwipToMm100(static_cast<const ScIndentItem&>(
1924 rSet.Get(pEntry->nWID)).GetValue()) );
1925 break;
1926 default:
1927 pPropSet->getPropertyValue(aPropertyName, rSet, aAny);
1928 }
1929 }
1930 }
1931 else
1932 switch ( pEntry->nWID )
1933 {
1936 aAny <<= false;
1937 break;
1940 ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Para );
1941 break;
1942 case SC_WID_UNO_TBLBORD:
1944 {
1945 const ScPatternAttr* pPattern = rDoc.GetDefPattern();
1946 if ( pPattern )
1947 {
1948 if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
1950 pPattern->GetItem(ATTR_BORDER),
1951 pPattern->GetItem(ATTR_BORDER_INNER) );
1952 else
1954 pPattern->GetItem(ATTR_BORDER),
1955 pPattern->GetItem(ATTR_BORDER_INNER) );
1956 }
1957 }
1958 break;
1959 case SC_WID_UNO_CONDFMT:
1960 case SC_WID_UNO_CONDLOC:
1961 case SC_WID_UNO_CONDXML:
1962 {
1963 bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
1964 bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
1965 formula::FormulaGrammar::Grammar eGrammar = (bXML ?
1966 rDoc.GetStorageGrammar() :
1968
1969 aAny <<= uno::Reference<sheet::XSheetConditionalEntries>(
1970 new ScTableConditionalFormat( &rDoc, 0, aRanges[0].aStart.Tab(), eGrammar ));
1971 }
1972 break;
1973 case SC_WID_UNO_VALIDAT:
1974 case SC_WID_UNO_VALILOC:
1975 case SC_WID_UNO_VALIXML:
1976 {
1977 bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
1978 bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
1979 formula::FormulaGrammar::Grammar eGrammar = (bXML ?
1980 rDoc.GetStorageGrammar() :
1982
1983 aAny <<= uno::Reference<beans::XPropertySet>(
1984 new ScTableValidationObj( rDoc, 0, eGrammar ));
1985 }
1986 break;
1988 {
1990 }
1991 break;
1992 }
1993 }
1994 }
1995
1996 return aAny;
1997}
1998
1999// XPropertySet
2000
2001uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellRangesBase::getPropertySetInfo()
2002{
2003 SolarMutexGuard aGuard;
2004 static uno::Reference<beans::XPropertySetInfo> aRef(
2005 new SfxItemPropertySetInfo( pPropSet->getPropertyMap() ));
2006 return aRef;
2007}
2008
2009static void lcl_SetCellProperty( const SfxItemPropertyMapEntry& rEntry, const uno::Any& rValue,
2010 ScPatternAttr& rPattern, const ScDocument &rDoc,
2011 sal_uInt16& rFirstItemId, sal_uInt16& rSecondItemId )
2012{
2013 rFirstItemId = rEntry.nWID;
2014 rSecondItemId = 0;
2015
2016 SfxItemSet& rSet = rPattern.GetItemSet();
2017 switch ( rEntry.nWID )
2018 {
2019 case ATTR_VALUE_FORMAT:
2020 {
2021 // language for number formats
2022 SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
2023 sal_uLong nOldFormat = rSet.Get( ATTR_VALUE_FORMAT ).GetValue();
2024 LanguageType eOldLang = rSet.Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
2025 nOldFormat = pFormatter->GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
2026
2027 sal_Int32 nIntVal = 0;
2028 if ( !(rValue >>= nIntVal) )
2029 throw lang::IllegalArgumentException();
2030
2031 sal_uLong nNewFormat = static_cast<sal_uLong>(nIntVal);
2032 rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
2033
2034 const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
2035 LanguageType eNewLang =
2036 pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
2037 if ( eNewLang != eOldLang && eNewLang != LANGUAGE_DONTKNOW )
2038 {
2040
2041 // if only language is changed,
2042 // don't touch number format attribute
2043 sal_uLong nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
2044 if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
2046 {
2047 rFirstItemId = 0; // don't use ATTR_VALUE_FORMAT value
2048 }
2049
2050 rSecondItemId = ATTR_LANGUAGE_FORMAT;
2051 }
2052
2053 }
2054 break;
2055 case ATTR_INDENT:
2056 {
2057 sal_Int16 nIntVal = 0;
2058 if ( !(rValue >>= nIntVal) )
2059 throw lang::IllegalArgumentException();
2060
2062
2063 }
2064 break;
2065 case ATTR_ROTATE_VALUE:
2066 {
2067 sal_Int32 nRotVal = 0;
2068 if ( !(rValue >>= nRotVal) )
2069 throw lang::IllegalArgumentException();
2070
2071 // stored value is always between 0 and 360 deg.
2072 nRotVal %= 36000;
2073 if ( nRotVal < 0 )
2074 nRotVal += 36000;
2075
2076 rSet.Put( ScRotateValueItem( Degree100(nRotVal) ) );
2077
2078 }
2079 break;
2080 case ATTR_STACKED:
2081 {
2082 table::CellOrientation eOrient;
2083 if( rValue >>= eOrient )
2084 {
2085 switch( eOrient )
2086 {
2087 case table::CellOrientation_STANDARD:
2088 rSet.Put( ScVerticalStackCell( false ) );
2089 break;
2090 case table::CellOrientation_TOPBOTTOM:
2091 rSet.Put( ScVerticalStackCell( false ) );
2092 rSet.Put( ScRotateValueItem( 27000_deg100 ) );
2093 rSecondItemId = ATTR_ROTATE_VALUE;
2094 break;
2095 case table::CellOrientation_BOTTOMTOP:
2096 rSet.Put( ScVerticalStackCell( false ) );
2097 rSet.Put( ScRotateValueItem( 9000_deg100 ) );
2098 rSecondItemId = ATTR_ROTATE_VALUE;
2099 break;
2100 case table::CellOrientation_STACKED:
2101 rSet.Put( ScVerticalStackCell( true ) );
2102 break;
2103 default:
2104 {
2105 // added to avoid warnings
2106 }
2107 }
2108 }
2109 }
2110 break;
2111 default:
2112 {
2113 lcl_GetCellsPropertySet()->setPropertyValue(rEntry, rValue, rSet);
2114 }
2115 }
2116}
2117
2118void SAL_CALL ScCellRangesBase::setPropertyValue(
2119 const OUString& aPropertyName, const uno::Any& aValue )
2120{
2121 SolarMutexGuard aGuard;
2122
2123 if ( !pDocShell || aRanges.empty() )
2124 throw uno::RuntimeException();
2125
2126 const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2127 const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
2128 if ( !pEntry )
2129 throw beans::UnknownPropertyException(aPropertyName);
2130
2131 SetOnePropertyValue( pEntry, aValue );
2132}
2133
2134void ScCellRangesBase::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
2135{
2136 if ( !pEntry )
2137 return;
2138
2139 if ( IsScItemWid( pEntry->nWID ) )
2140 {
2141 if ( !aRanges.empty() ) // empty = nothing to do
2142 {
2143 ScDocument& rDoc = pDocShell->GetDocument();
2144
2145 // For parts of compound items with multiple properties (e.g. background)
2146 // the old item has to be first fetched from the document.
2150 // ClearInvalidItems, so that in any case we have an item with the correct type
2151
2152 ScPatternAttr aPattern( *GetCurrentAttrsDeep() );
2153 SfxItemSet& rSet = aPattern.GetItemSet();
2155
2156 sal_uInt16 nFirstItem, nSecondItem;
2157 lcl_SetCellProperty( *pEntry, aValue, aPattern, rDoc, nFirstItem, nSecondItem );
2158
2159 for (sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++)
2160 if ( nWhich != nFirstItem && nWhich != nSecondItem )
2161 rSet.ClearItem(nWhich);
2162
2163 pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), aPattern, true );
2164 }
2165 }
2166 else // implemented here
2167 switch ( pEntry->nWID )
2168 {
2169 case EE_CHAR_ESCAPEMENT: // Specifically for xlsx import
2170 {
2171 sal_Int32 nValue = 0;
2172 aValue >>= nValue;
2173 if (nValue)
2174 {
2175 for (size_t i = 0, n = aRanges.size(); i < n; ++i)
2176 {
2177 ScRange const & rRange = aRanges[i];
2178
2179 /* TODO: Iterate through the range */
2180 ScAddress aAddr = rRange.aStart;
2181 ScDocument& rDoc = pDocShell->GetDocument();
2182 ScRefCellValue aCell(rDoc, aAddr);
2183
2184 OUString aStr = aCell.getString(&rDoc);
2185 EditEngine aEngine( rDoc.GetEnginePool() );
2186 aEngine.SetEditTextObjectPool(rDoc.GetEditPool());
2187
2188 /* EE_CHAR_ESCAPEMENT seems to be set on the cell _only_ when
2189 * there are no other attribs for the cell.
2190 * So, it is safe to overwrite the complete attribute set.
2191 * If there is a need - getting CellType and processing
2192 * the attributes could be considered.
2193 */
2194 SfxItemSet aAttr = aEngine.GetEmptyItemSet();
2195 aEngine.SetText(aStr);
2196 if( nValue < 0 ) // Subscript
2197 aAttr.Put( SvxEscapementItem( SvxEscapement::Subscript, EE_CHAR_ESCAPEMENT ) );
2198 else // Superscript
2199 aAttr.Put( SvxEscapementItem( SvxEscapement::Superscript, EE_CHAR_ESCAPEMENT ) );
2200 aEngine.QuickSetAttribs(aAttr, ESelection(0, 0, 0, aStr.getLength()));
2201
2202 // The cell will own the text object instance.
2203 rDoc.SetEditText(aRanges[0].aStart, aEngine.CreateTextObject());
2204 }
2205 }
2206 }
2207 break;
2209 // chart header flags are set for this object, not stored with document
2210 bChartColAsHdr = ScUnoHelpFunctions::GetBoolFromAny( aValue );
2211 break;
2213 bChartRowAsHdr = ScUnoHelpFunctions::GetBoolFromAny( aValue );
2214 break;
2216 {
2217 OUString aStrVal;
2218 aValue >>= aStrVal;
2220 aStrVal, SfxStyleFamily::Para ));
2221 pDocShell->GetDocFunc().ApplyStyle( *GetMarkData(), aString, true );
2222 }
2223 break;
2224 case SC_WID_UNO_TBLBORD:
2225 {
2226 table::TableBorder aBorder;
2227 if ( !aRanges.empty() && ( aValue >>= aBorder ) ) // empty = nothing to do
2228 {
2229 SvxBoxItem aOuter(ATTR_BORDER);
2231 ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder );
2232
2233 ScHelperFunctions::ApplyBorder( pDocShell, aRanges, aOuter, aInner );
2234 }
2235 }
2236 break;
2238 {
2239 table::TableBorder2 aBorder2;
2240 if ( !aRanges.empty() && ( aValue >>= aBorder2 ) ) // empty = nothing to do
2241 {
2242 SvxBoxItem aOuter(ATTR_BORDER);
2244 ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder2 );
2245
2246 ScHelperFunctions::ApplyBorder( pDocShell, aRanges, aOuter, aInner );
2247 }
2248 }
2249 break;
2250 case SC_WID_UNO_CONDFMT:
2251 case SC_WID_UNO_CONDLOC:
2252 case SC_WID_UNO_CONDXML:
2253 {
2254 uno::Reference<sheet::XSheetConditionalEntries> xInterface(aValue, uno::UNO_QUERY);
2255 if ( !aRanges.empty() && xInterface.is() ) // empty = nothing to do
2256 {
2257 ScTableConditionalFormat* pFormat =
2258 dynamic_cast<ScTableConditionalFormat*>( xInterface.get() );
2259 if (pFormat)
2260 {
2261 ScDocument& rDoc = pDocShell->GetDocument();
2262 bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
2263 bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
2264 formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2267
2268 SCTAB nTab = aRanges.front().aStart.Tab();
2269 // To remove conditional formats for all cells in aRanges we need to:
2270 // Remove conditional format data from cells' attributes
2271 rDoc.RemoveCondFormatData( aRanges, nTab, 0 );
2272 // And also remove ranges from conditional formats list
2273 for (size_t i = 0; i < aRanges.size(); ++i)
2274 {
2275 rDoc.GetCondFormList( aRanges[i].aStart.Tab() )->DeleteArea(
2276 aRanges[i].aStart.Col(), aRanges[i].aStart.Row(),
2277 aRanges[i].aEnd.Col(), aRanges[i].aEnd.Row() );
2278 }
2279
2280 // Then we can apply new conditional format if there is one
2281 if (pFormat->getCount())
2282 {
2283 auto pNew = std::make_unique<ScConditionalFormat>( 0, &rDoc ); // Index will be set on inserting
2284 pFormat->FillFormat( *pNew, rDoc, eGrammar );
2285 pNew->SetRange( aRanges );
2286 pDocShell->GetDocFunc().ReplaceConditionalFormat( 0, std::move(pNew), nTab, aRanges );
2287 }
2288
2289 // and repaint
2290 for (size_t i = 0; i < aRanges.size(); ++i)
2291 pDocShell->PostPaint(aRanges[i], PaintPartFlags::Grid);
2292 pDocShell->SetDocumentModified();
2293 }
2294 }
2295 }
2296 break;
2297 case SC_WID_UNO_VALIDAT:
2298 case SC_WID_UNO_VALILOC:
2299 case SC_WID_UNO_VALIXML:
2300 {
2301 uno::Reference<beans::XPropertySet> xInterface(aValue, uno::UNO_QUERY);
2302 if ( !aRanges.empty() && xInterface.is() ) // empty = nothing to do
2303 {
2304 ScTableValidationObj* pValidObj =
2305 dynamic_cast<ScTableValidationObj*>( xInterface.get() );
2306 if (pValidObj)
2307 {
2308 ScDocument& rDoc = pDocShell->GetDocument();
2309 bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
2310 bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
2311 formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2314
2315 std::unique_ptr<ScValidationData> pNewData(
2316 pValidObj->CreateValidationData( rDoc, eGrammar ));
2317 sal_uInt32 nIndex = rDoc.AddValidationEntry( *pNewData );
2318 pNewData.reset();
2319
2320 ScPatternAttr aPattern( rDoc.GetPool() );
2321 aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nIndex ) );
2322 pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), aPattern, true );
2323 }
2324 }
2325 }
2326 break;
2327 // SC_WID_UNO_NUMRULES is ignored...
2328 }
2329}
2330
2331uno::Any SAL_CALL ScCellRangesBase::getPropertyValue( const OUString& aPropertyName )
2332{
2333 SolarMutexGuard aGuard;
2334
2335 if ( !pDocShell || aRanges.empty() )
2336 throw uno::RuntimeException();
2337
2338 const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2339 const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
2340 if ( !pEntry )
2341 throw beans::UnknownPropertyException(aPropertyName);
2342
2343 uno::Any aAny;
2344 GetOnePropertyValue( pEntry, aAny );
2345 return aAny;
2346}
2347
2348void ScCellRangesBase::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
2349{
2350 if ( !pEntry )
2351 return;
2352
2353 if ( IsScItemWid( pEntry->nWID ) )
2354 {
2355 SfxItemSet* pDataSet = GetCurrentDataSet();
2356 if ( pDataSet )
2357 {
2358 switch ( pEntry->nWID ) // for special handling of items
2359 {
2360 case ATTR_VALUE_FORMAT:
2361 {
2362 ScDocument& rDoc = pDocShell->GetDocument();
2363
2364 sal_uLong nOldFormat =
2365 pDataSet->Get( ATTR_VALUE_FORMAT ).GetValue();
2366 LanguageType eOldLang =
2367 pDataSet->Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
2368 nOldFormat = rDoc.GetFormatTable()->
2369 GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
2370 rAny <<= static_cast<sal_Int32>(nOldFormat);
2371 }
2372 break;
2373 case ATTR_INDENT:
2374 rAny <<= static_cast<sal_Int16>( convertTwipToMm100(static_cast<const ScIndentItem&>(
2375 pDataSet->Get(pEntry->nWID)).GetValue()) );
2376 break;
2377 case ATTR_STACKED:
2378 {
2379 Degree100 nRot = pDataSet->Get(ATTR_ROTATE_VALUE).GetValue();
2380 bool bStacked = static_cast<const ScVerticalStackCell&>(pDataSet->Get(pEntry->nWID)).GetValue();
2382 }
2383 break;
2384 default:
2385 pPropSet->getPropertyValue(*pEntry, *pDataSet, rAny);
2386 }
2387 }
2388 }
2389 else // implemented here
2390 switch ( pEntry->nWID )
2391 {
2393 rAny <<= bChartColAsHdr;
2394 break;
2396 rAny <<= bChartRowAsHdr;
2397 break;
2399 {
2400 OUString aStyleName;
2401 const ScStyleSheet* pStyle = pDocShell->GetDocument().GetSelectionStyle(*GetMarkData());
2402 if (pStyle)
2403 aStyleName = pStyle->GetName();
2405 aStyleName, SfxStyleFamily::Para );
2406 }
2407 break;
2408 case SC_WID_UNO_TBLBORD:
2410 {
2412 if ( !aRanges.empty() )
2413 {
2414 const ScRange & rFirst = aRanges[ 0 ];
2415 SvxBoxItem aOuter(ATTR_BORDER);
2417
2418 ScDocument& rDoc = pDocShell->GetDocument();
2419 ScMarkData aMark(rDoc.GetSheetLimits());
2420 aMark.SetMarkArea( rFirst );
2421 aMark.SelectTable( rFirst.aStart.Tab(), true );
2422 rDoc.GetSelectionFrame( aMark, aOuter, aInner );
2423
2424 if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
2425 ScHelperFunctions::AssignTableBorder2ToAny( rAny, aOuter, aInner);
2426 else
2427 ScHelperFunctions::AssignTableBorderToAny( rAny, aOuter, aInner);
2428 }
2429 }
2430 break;
2431 case SC_WID_UNO_CONDFMT:
2432 case SC_WID_UNO_CONDLOC:
2433 case SC_WID_UNO_CONDXML:
2434 {
2435 const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
2436 if ( pPattern )
2437 {
2438 ScDocument& rDoc = pDocShell->GetDocument();
2439 bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
2440 bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
2441 formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2442 rDoc.GetStorageGrammar() :
2444 const ScCondFormatIndexes& rIndex =
2445 pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
2446 sal_uLong nIndex = 0;
2447 if(!rIndex.empty())
2448 nIndex = rIndex[0];
2449 rAny <<= uno::Reference<sheet::XSheetConditionalEntries>(
2450 new ScTableConditionalFormat( &rDoc, nIndex, aRanges.front().aStart.Tab(), eGrammar ));
2451 }
2452 }
2453 break;
2454 case SC_WID_UNO_VALIDAT:
2455 case SC_WID_UNO_VALILOC:
2456 case SC_WID_UNO_VALIXML:
2457 {
2458 const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
2459 if ( pPattern )
2460 {
2461 ScDocument& rDoc = pDocShell->GetDocument();
2462 bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
2463 bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
2464 formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2465 rDoc.GetStorageGrammar() :
2468 pPattern->GetItem(ATTR_VALIDDATA).GetValue();
2469 rAny <<= uno::Reference<beans::XPropertySet>(
2470 new ScTableValidationObj( rDoc, nIndex, eGrammar ));
2471 }
2472 }
2473 break;
2475 {
2476 // always return empty numbering rules object
2478 }
2479 break;
2480 case SC_WID_UNO_ABSNAME:
2481 {
2482 OUString sRet;
2483 aRanges.Format(sRet, ScRefFlags::RANGE_ABS_3D, pDocShell->GetDocument());
2484 rAny <<= sRet;
2485 }
2486 break;
2488 {
2489 const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
2490 rAny <<= pPattern->GetKey();
2491 }
2492 break;
2493 }
2494}
2495
2496void SAL_CALL ScCellRangesBase::addPropertyChangeListener( const OUString& /* aPropertyName */,
2497 const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
2498{
2499 SolarMutexGuard aGuard;
2500 if ( aRanges.empty() )
2501 throw uno::RuntimeException();
2502
2503 OSL_FAIL("not implemented");
2504}
2505
2506void SAL_CALL ScCellRangesBase::removePropertyChangeListener( const OUString& /* aPropertyName */,
2507 const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
2508{
2509 SolarMutexGuard aGuard;
2510 if ( aRanges.empty() )
2511 throw uno::RuntimeException();
2512
2513 OSL_FAIL("not implemented");
2514}
2515
2516void SAL_CALL ScCellRangesBase::addVetoableChangeListener( const OUString&,
2517 const uno::Reference<beans::XVetoableChangeListener>&)
2518{
2519 OSL_FAIL("not implemented");
2520}
2521
2522void SAL_CALL ScCellRangesBase::removeVetoableChangeListener( const OUString&,
2523 const uno::Reference<beans::XVetoableChangeListener>&)
2524{
2525 OSL_FAIL("not implemented");
2526}
2527
2528// XMultiPropertySet
2529
2530void SAL_CALL ScCellRangesBase::setPropertyValues( const uno::Sequence< OUString >& aPropertyNames,
2531 const uno::Sequence< uno::Any >& aValues )
2532{
2533 SolarMutexGuard aGuard;
2534
2535 sal_Int32 nCount(aPropertyNames.getLength());
2536 sal_Int32 nValues(aValues.getLength());
2537 if (nCount != nValues)
2538 throw lang::IllegalArgumentException();
2539
2540 if ( !(pDocShell && nCount) )
2541 return;
2542
2543 const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2544 const OUString* pNames = aPropertyNames.getConstArray();
2545 const uno::Any* pValues = aValues.getConstArray();
2546
2547 std::unique_ptr<const SfxItemPropertyMapEntry*[]> pEntryArray(new const SfxItemPropertyMapEntry*[nCount]);
2548
2549 sal_Int32 i;
2550 for(i = 0; i < nCount; i++)
2551 {
2552 // first loop: find all properties in map, but handle only CellStyle
2553 // (CellStyle must be set before any other cell properties)
2554
2555 const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( pNames[i] );
2556 pEntryArray[i] = pEntry;
2557 if (pEntry)
2558 {
2559 if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
2560 {
2561 try
2562 {
2563 SetOnePropertyValue( pEntry, pValues[i] );
2564 }
2565 catch ( lang::IllegalArgumentException& )
2566 {
2567 TOOLS_WARN_EXCEPTION( "sc", "exception when setting cell style"); // not supposed to happen
2568 }
2569 }
2570 }
2571 }
2572
2573 ScDocument& rDoc = pDocShell->GetDocument();
2574 std::unique_ptr<ScPatternAttr> pOldPattern;
2575 std::unique_ptr<ScPatternAttr> pNewPattern;
2576
2577 for(i = 0; i < nCount; i++)
2578 {
2579 // second loop: handle other properties
2580
2581 const SfxItemPropertyMapEntry* pEntry = pEntryArray[i];
2582 if ( pEntry )
2583 {
2584 if ( IsScItemWid( pEntry->nWID ) ) // can be handled by SfxItemPropertySet
2585 {
2586 if ( !pOldPattern )
2587 {
2588 pOldPattern.reset(new ScPatternAttr( *GetCurrentAttrsDeep() ));
2589 pOldPattern->GetItemSet().ClearInvalidItems();
2590 pNewPattern.reset(new ScPatternAttr( rDoc.GetPool() ));
2591 }
2592
2593 // collect items in pNewPattern, apply with one call after the loop
2594
2595 sal_uInt16 nFirstItem, nSecondItem;
2596 lcl_SetCellProperty( *pEntry, pValues[i], *pOldPattern, rDoc, nFirstItem, nSecondItem );
2597
2598 // put only affected items into new set
2599 if ( nFirstItem )
2600 pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nFirstItem ) );
2601 if ( nSecondItem )
2602 pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nSecondItem ) );
2603 }
2604 else if ( pEntry->nWID != SC_WID_UNO_CELLSTYL ) // CellStyle is handled above
2605 {
2606 // call virtual method to set a single property
2607 SetOnePropertyValue( pEntry, pValues[i] );
2608 }
2609 }
2610 }
2611
2612 if ( pNewPattern && !aRanges.empty() )
2613 pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), *pNewPattern, true );
2614}
2615
2616uno::Sequence<uno::Any> SAL_CALL ScCellRangesBase::getPropertyValues(
2617 const uno::Sequence< OUString >& aPropertyNames )
2618{
2619 SolarMutexGuard aGuard;
2620
2621 const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2622
2623 uno::Sequence<uno::Any> aRet(aPropertyNames.getLength());
2624 uno::Any* pProperties = aRet.getArray();
2625 for(sal_Int32 i = 0; i < aPropertyNames.getLength(); i++)
2626 {
2627 const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
2628 GetOnePropertyValue( pEntry, pProperties[i] );
2629 }
2630 return aRet;
2631}
2632
2633void SAL_CALL ScCellRangesBase::addPropertiesChangeListener( const uno::Sequence< OUString >& /* aPropertyNames */,
2634 const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
2635{
2636 OSL_FAIL("not implemented");
2637}
2638
2639void SAL_CALL ScCellRangesBase::removePropertiesChangeListener( const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
2640{
2641 OSL_FAIL("not implemented");
2642}
2643
2644void SAL_CALL ScCellRangesBase::firePropertiesChangeEvent( const uno::Sequence< OUString >& /* aPropertyNames */,
2645 const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
2646{
2647 OSL_FAIL("not implemented");
2648}
2649
2650IMPL_LINK( ScCellRangesBase, ValueListenerHdl, const SfxHint&, rHint, void )
2651{
2652 if ( pDocShell && (rHint.GetId() == SfxHintId::ScDataChanged))
2653 {
2654 // This may be called several times for a single change, if several formulas
2655 // in the range are notified. So only a flag is set that is checked when
2656 // SfxHintId::DataChanged is received.
2657
2658 bGotDataChangedHint = true;
2659 }
2660}
2661
2662// XTolerantMultiPropertySet
2663uno::Sequence< beans::SetPropertyTolerantFailed > SAL_CALL ScCellRangesBase::setPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames,
2664 const uno::Sequence< uno::Any >& aValues )
2665{
2666 SolarMutexGuard aGuard;
2667
2668 sal_Int32 nCount(aPropertyNames.getLength());
2669 sal_Int32 nValues(aValues.getLength());
2670 if (nCount != nValues)
2671 throw lang::IllegalArgumentException();
2672
2673 if ( pDocShell && nCount )
2674 {
2675 uno::Sequence < beans::SetPropertyTolerantFailed > aReturns(nCount);
2676 beans::SetPropertyTolerantFailed* pReturns = aReturns.getArray();
2677
2678 const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2679 const OUString* pNames = aPropertyNames.getConstArray();
2680 const uno::Any* pValues = aValues.getConstArray();
2681
2682 std::unique_ptr<const SfxItemPropertyMapEntry*[]> pMapArray(new const SfxItemPropertyMapEntry*[nCount]);
2683
2684 sal_Int32 i;
2685 for(i = 0; i < nCount; i++)
2686 {
2687 // first loop: find all properties in map, but handle only CellStyle
2688 // (CellStyle must be set before any other cell properties)
2689
2690 const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( pNames[i] );
2691 pMapArray[i] = pEntry;
2692 if (pEntry)
2693 {
2694 if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
2695 {
2696 try
2697 {
2698 SetOnePropertyValue( pEntry, pValues[i] );
2699 }
2700 catch ( lang::IllegalArgumentException& )
2701 {
2702 TOOLS_WARN_EXCEPTION( "sc", "exception when setting cell style"); // not supposed to happen
2703 }
2704 }
2705 }
2706 }
2707
2708 ScDocument& rDoc = pDocShell->GetDocument();
2709 std::unique_ptr<ScPatternAttr> pOldPattern;
2710 std::unique_ptr<ScPatternAttr> pNewPattern;
2711
2712 sal_Int32 nFailed(0);
2713 for(i = 0; i < nCount; i++)
2714 {
2715 // second loop: handle other properties
2716
2717 const SfxItemPropertyMapEntry* pEntry = pMapArray[i];
2718 if ( pEntry && ((pEntry->nFlags & beans::PropertyAttribute::READONLY) == 0))
2719 {
2720 if ( IsScItemWid( pEntry->nWID ) ) // can be handled by SfxItemPropertySet
2721 {
2722 if ( !pOldPattern )
2723 {
2724 pOldPattern.reset(new ScPatternAttr( *GetCurrentAttrsDeep() ));
2725 pOldPattern->GetItemSet().ClearInvalidItems();
2726 pNewPattern.reset(new ScPatternAttr( rDoc.GetPool() ));
2727 }
2728
2729 // collect items in pNewPattern, apply with one call after the loop
2730 try
2731 {
2732 sal_uInt16 nFirstItem, nSecondItem;
2733 lcl_SetCellProperty( *pEntry, pValues[i], *pOldPattern, rDoc, nFirstItem, nSecondItem );
2734
2735 // put only affected items into new set
2736 if ( nFirstItem )
2737 pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nFirstItem ) );
2738 if ( nSecondItem )
2739 pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nSecondItem ) );
2740 }
2741 catch ( lang::IllegalArgumentException& )
2742 {
2743 pReturns[nFailed].Name = pNames[i];
2744 pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT;
2745 }
2746 }
2747 else if ( pEntry->nWID != SC_WID_UNO_CELLSTYL ) // CellStyle is handled above
2748 {
2749 // call virtual method to set a single property
2750 try
2751 {
2752 SetOnePropertyValue( pEntry, pValues[i] );
2753 }
2754 catch ( lang::IllegalArgumentException& )
2755 {
2756 pReturns[nFailed].Name = pNames[i];
2757 pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT;
2758 }
2759 }
2760 }
2761 else
2762 {
2763 pReturns[nFailed].Name = pNames[i];
2764 if (pEntry)
2765 pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::PROPERTY_VETO;
2766 else
2767 pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
2768 }
2769 }
2770
2771 if ( pNewPattern && !aRanges.empty() )
2772 pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), *pNewPattern, true );
2773
2774 aReturns.realloc(nFailed);
2775
2776 return aReturns;
2777 }
2778 return uno::Sequence < beans::SetPropertyTolerantFailed >();
2779}
2780
2781uno::Sequence< beans::GetPropertyTolerantResult > SAL_CALL ScCellRangesBase::getPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames )
2782{
2783 SolarMutexGuard aGuard;
2784
2785 sal_Int32 nCount(aPropertyNames.getLength());
2786 uno::Sequence < beans::GetPropertyTolerantResult > aReturns(nCount);
2787 beans::GetPropertyTolerantResult* pReturns = aReturns.getArray();
2788
2789 const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2790
2791 for(sal_Int32 i = 0; i < nCount; i++)
2792 {
2793 const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
2794 if (!pEntry)
2795 {
2796 pReturns[i].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
2797 }
2798 else
2799 {
2800 sal_uInt16 nItemWhich = 0;
2801 lcl_GetPropertyWhich( pEntry, nItemWhich );
2802 pReturns[i].State = GetOnePropertyState( nItemWhich, pEntry );
2803 GetOnePropertyValue( pEntry, pReturns[i].Value );
2804 pReturns[i].Result = beans::TolerantPropertySetResultType::SUCCESS;
2805 }
2806 }
2807 return aReturns;
2808}
2809
2810uno::Sequence< beans::GetDirectPropertyTolerantResult > SAL_CALL ScCellRangesBase::getDirectPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames )
2811{
2812 SolarMutexGuard aGuard;
2813
2814 sal_Int32 nCount(aPropertyNames.getLength());
2815 uno::Sequence < beans::GetDirectPropertyTolerantResult > aReturns(nCount);
2816 beans::GetDirectPropertyTolerantResult* pReturns = aReturns.getArray();
2817
2818 const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2819
2820 sal_Int32 j = 0;
2821 for(sal_Int32 i = 0; i < nCount; i++)
2822 {
2823 const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
2824 if (!pEntry)
2825 {
2826 pReturns[i].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
2827 }
2828 else
2829 {
2830 sal_uInt16 nItemWhich = 0;
2831 lcl_GetPropertyWhich( pEntry, nItemWhich );
2832 pReturns[j].State = GetOnePropertyState( nItemWhich, pEntry );
2833 if (pReturns[j].State == beans::PropertyState_DIRECT_VALUE)
2834 {
2835 GetOnePropertyValue( pEntry, pReturns[j].Value );
2836 pReturns[j].Result = beans::TolerantPropertySetResultType::SUCCESS;
2837 pReturns[j].Name = aPropertyNames[i];
2838 ++j;
2839 }
2840 }
2841 }
2842 if (j < nCount)
2843 aReturns.realloc(j);
2844 return aReturns;
2845}
2846
2847// XIndent
2848
2849void SAL_CALL ScCellRangesBase::decrementIndent()
2850{
2851 SolarMutexGuard aGuard;
2852 if ( pDocShell && !aRanges.empty() )
2853 {
2854 //#97041#; put only MultiMarked ScMarkData in ChangeIndent
2855 ScMarkData aMarkData(*GetMarkData());
2856 aMarkData.MarkToMulti();
2857 pDocShell->GetDocFunc().ChangeIndent( aMarkData, false, true );
2858 }
2859}
2860
2861void SAL_CALL ScCellRangesBase::incrementIndent()
2862{
2863 SolarMutexGuard aGuard;
2864 if ( pDocShell && !aRanges.empty() )
2865 {
2866 //#97041#; put only MultiMarked ScMarkData in ChangeIndent
2867 ScMarkData aMarkData(*GetMarkData());
2868 aMarkData.MarkToMulti();
2869 pDocShell->GetDocFunc().ChangeIndent( aMarkData, true, true );
2870 }
2871}
2872
2873// XChartData
2874
2875std::unique_ptr<ScMemChart> ScCellRangesBase::CreateMemChart_Impl() const
2876{
2877 if ( pDocShell && !aRanges.empty() )
2878 {
2879 ScRangeListRef xChartRanges;
2880 if ( aRanges.size() == 1 )
2881 {
2882 // set useful table limit (only occupied data area)
2883 // (only here - Listeners are registered for the whole area)
2885
2886 const ScDocument & rDoc = pDocShell->GetDocument();
2887 const ScRange & rRange = aRanges[0];
2888 if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
2889 rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
2890 {
2891 SCTAB nTab = rRange.aStart.Tab();
2892
2893 SCCOL nStartX;
2894 SCROW nStartY; // Get start
2895 if (!pDocShell->GetDocument().GetDataStart( nTab, nStartX, nStartY ))
2896 {
2897 nStartX = 0;
2898 nStartY = 0;
2899 }
2900
2901 SCCOL nEndX;
2902 SCROW nEndY; // Get end
2903 if (!pDocShell->GetDocument().GetTableArea( nTab, nEndX, nEndY ))
2904 {
2905 nEndX = 0;
2906 nEndY = 0;
2907 }
2908
2909 xChartRanges = new ScRangeList( ScRange( nStartX, nStartY, nTab, nEndX, nEndY, nTab ) );
2910 }
2911 }
2912 if (!xChartRanges.is()) // otherwise take Ranges directly
2913 xChartRanges = new ScRangeList(aRanges);
2914 ScChartArray aArr( pDocShell->GetDocument(), xChartRanges );
2915
2916 // RowAsHdr = ColHeaders and vice versa
2917 aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr );
2918
2919 return aArr.CreateMemChart();
2920 }
2921 return nullptr;
2922}
2923
2924uno::Sequence< uno::Sequence<double> > SAL_CALL ScCellRangesBase::getData()
2925{
2926 SolarMutexGuard aGuard;
2927 std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
2928 if ( pMemChart )
2929 {
2930 sal_Int32 nColCount = pMemChart->GetColCount();
2931 sal_Int32 nRowCount = static_cast<sal_Int32>(pMemChart->GetRowCount());
2932
2933 uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
2934 uno::Sequence<double>* pRowAry = aRowSeq.getArray();
2935 for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
2936 {
2937 uno::Sequence<double> aColSeq( nColCount );
2938 double* pColAry = aColSeq.getArray();
2939 for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
2940 pColAry[nCol] = pMemChart->GetData( nCol, nRow );
2941
2942 pRowAry[nRow] = aColSeq;
2943 }
2944
2945 return aRowSeq;
2946 }
2947
2948 return {};
2949}
2950
2951ScRangeListRef ScCellRangesBase::GetLimitedChartRanges_Impl( sal_Int32 nDataColumns, sal_Int32 nDataRows ) const
2952{
2953 if ( aRanges.size() == 1 )
2954 {
2955 const ScDocument & rDoc = pDocShell->GetDocument();
2956 const ScRange & rRange = aRanges[0];
2957 if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
2958 rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
2959 {
2960 // if aRanges is a complete sheet, limit to given size
2961
2962 SCTAB nTab = rRange.aStart.Tab();
2963
2964 sal_Int32 nEndColumn = nDataColumns - 1 + ( bChartColAsHdr ? 1 : 0 );
2965 if ( nEndColumn < 0 )
2966 nEndColumn = 0;
2967 if ( nEndColumn > rDoc.MaxCol() )
2968 nEndColumn = rDoc.MaxCol();
2969
2970 sal_Int32 nEndRow = nDataRows - 1 + ( bChartRowAsHdr ? 1 : 0 );
2971 if ( nEndRow < 0 )
2972 nEndRow = 0;
2973 if ( nEndRow > rDoc.MaxRow() )
2974 nEndRow = rDoc.MaxRow();
2975
2976 ScRangeListRef xChartRanges = new ScRangeList( ScRange( 0, 0, nTab, static_cast<SCCOL>(nEndColumn), static_cast<SCROW>(nEndRow), nTab ) );
2977 return xChartRanges;
2978 }
2979 }
2980
2981 return new ScRangeList(aRanges); // as-is
2982}
2983
2984void SAL_CALL ScCellRangesBase::setData( const uno::Sequence< uno::Sequence<double> >& aData )
2985{
2986 SolarMutexGuard aGuard;
2987 bool bDone = false;
2988 sal_Int32 nRowCount = aData.getLength();
2989 sal_Int32 nColCount = nRowCount ? aData[0].getLength() : 0;
2990 ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( nColCount, nRowCount );
2991 if ( pDocShell && xChartRanges.is() )
2992 {
2993 ScDocument& rDoc = pDocShell->GetDocument();
2994 ScChartArray aArr( rDoc, xChartRanges );
2995 aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
2996 const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
2997 if (pPosMap)
2998 {
2999 if ( pPosMap->GetColCount() == static_cast<SCCOL>(nColCount) &&
3000 pPosMap->GetRowCount() == static_cast<SCROW>(nRowCount) )
3001 {
3002 for (sal_Int32 nRow=0; nRow<nRowCount; nRow++)
3003 {
3004 const uno::Sequence<double>& rRowSeq = aData[nRow];
3005 const double* pArray = rRowSeq.getConstArray();
3006 nColCount = rRowSeq.getLength();
3007 for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
3008 {
3009 const ScAddress* pPos = pPosMap->GetPosition(
3010 sal::static_int_cast<SCCOL>(nCol),
3011 sal::static_int_cast<SCROW>(nRow) );
3012 if (pPos)
3013 {
3014 double fVal = pArray[nCol];
3015 if ( fVal == DBL_MIN )
3016 rDoc.SetEmptyCell(*pPos);
3017 else
3018 rDoc.SetValue(*pPos, pArray[nCol]);
3019 }
3020 }
3021 }
3022
3024 PaintGridRanges_Impl();
3025 pDocShell->SetDocumentModified();
3026 ForceChartListener_Impl(); // call listeners for this object synchronously
3027 bDone = true;
3028 }
3029 }
3030 }
3031
3032 if (!bDone)
3033 throw uno::RuntimeException();
3034}
3035
3036uno::Sequence<OUString> SAL_CALL ScCellRangesBase::getRowDescriptions()
3037{
3038 SolarMutexGuard aGuard;
3039 std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
3040 if ( pMemChart )
3041 {
3042 sal_Int32 nRowCount = static_cast<sal_Int32>(pMemChart->GetRowCount());
3043 uno::Sequence<OUString> aSeq( nRowCount );
3044 OUString* pAry = aSeq.getArray();
3045 for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
3046 pAry[nRow] = pMemChart->GetRowText(nRow);
3047
3048 return aSeq;
3049 }
3050 return {};
3051}
3052
3053void SAL_CALL ScCellRangesBase::setRowDescriptions(
3054 const uno::Sequence<OUString>& aRowDescriptions )
3055{
3056 SolarMutexGuard aGuard;
3057 bool bDone = false;
3058 if ( bChartColAsHdr )
3059 {
3060 sal_Int32 nRowCount = aRowDescriptions.getLength();
3061 ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( 1, nRowCount );
3062 if ( pDocShell && xChartRanges.is() )
3063 {
3064 ScDocument& rDoc = pDocShell->GetDocument();
3065 ScChartArray aArr( rDoc, xChartRanges );
3066 aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
3067 const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
3068 if (pPosMap)
3069 {
3070 if ( pPosMap->GetRowCount() == static_cast<SCROW>(nRowCount) )
3071 {
3072 const OUString* pArray = aRowDescriptions.getConstArray();
3073 for (sal_Int32 nRow=0; nRow<nRowCount; nRow++)
3074 {
3075 const ScAddress* pPos = pPosMap->GetRowHeaderPosition(
3076 static_cast<SCSIZE>(nRow) );
3077 if (pPos)
3078 {
3079 const OUString& aStr = pArray[nRow];
3080 if (aStr.isEmpty())
3081 rDoc.SetEmptyCell(*pPos);
3082 else
3083 {
3084 ScSetStringParam aParam;
3085 aParam.setTextInput();
3086 rDoc.SetString(*pPos, aStr, &aParam);
3087 }
3088 }
3089 }
3090
3092 PaintGridRanges_Impl();
3093 pDocShell->SetDocumentModified();
3094 ForceChartListener_Impl(); // call listeners for this object synchronously
3095 bDone = true;
3096 }
3097 }
3098 }
3099 }
3100
3101 if (!bDone)
3102 throw uno::RuntimeException();
3103}
3104
3105uno::Sequence<OUString> SAL_CALL ScCellRangesBase::getColumnDescriptions()
3106{
3107 SolarMutexGuard aGuard;
3108 std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
3109 if ( pMemChart )
3110 {
3111 sal_Int32 nColCount = pMemChart->GetColCount();
3112 uno::Sequence<OUString> aSeq( nColCount );
3113 OUString* pAry = aSeq.getArray();
3114 for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
3115 pAry[nCol] = pMemChart->GetColText(nCol);
3116
3117 return aSeq;
3118 }
3119 return {};
3120}
3121
3122void SAL_CALL ScCellRangesBase::setColumnDescriptions(
3123 const uno::Sequence<OUString>& aColumnDescriptions )
3124{
3125 SolarMutexGuard aGuard;
3126 bool bDone = false;
3127 if ( bChartRowAsHdr )
3128 {
3129 sal_Int32 nColCount = aColumnDescriptions.getLength();
3130 ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( nColCount, 1 );
3131 if ( pDocShell && xChartRanges.is() )
3132 {
3133 ScDocument& rDoc = pDocShell->GetDocument();
3134 ScChartArray aArr( rDoc, xChartRanges );
3135 aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
3136 const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
3137 if (pPosMap)
3138 {
3139 if ( pPosMap->GetColCount() == static_cast<SCCOL>(nColCount) )
3140 {
3141 const OUString* pArray = aColumnDescriptions.getConstArray();
3142 for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
3143 {
3144 const ScAddress* pPos = pPosMap->GetColHeaderPosition(
3145 sal::static_int_cast<SCCOL>(nCol) );
3146 if (pPos)
3147 {
3148 const OUString& aStr = pArray[nCol];
3149 if (aStr.isEmpty())
3150 rDoc.SetEmptyCell(*pPos);
3151 else
3152 {
3153 ScSetStringParam aParam;
3154 aParam.setTextInput();
3155 rDoc.SetString(*pPos, aStr, &aParam);
3156 }
3157 }
3158 }
3159
3161 PaintGridRanges_Impl();
3162 pDocShell->SetDocumentModified();
3163 ForceChartListener_Impl(); // call listeners for this object synchronously
3164 bDone = true;
3165 }
3166 }
3167 }
3168 }
3169
3170 if (!bDone)
3171 throw uno::RuntimeException();
3172}
3173
3174void ScCellRangesBase::ForceChartListener_Impl()
3175{
3176 // call Update immediately so the caller to setData etc. can
3177 // recognize the listener call
3178
3179 if (!pDocShell)
3180 return;
3181
3182 ScChartListenerCollection* pColl = pDocShell->GetDocument().GetChartListenerCollection();
3183 if (!pColl)
3184 return;
3185
3187 for (auto const& it : rListeners)
3188 {
3189 ScChartListener *const p = it.second.get();
3190 assert(p);
3191 if (p->GetUnoSource() == static_cast<chart::XChartData*>(this) && p->IsDirty())
3192 p->Update();
3193 }
3194}
3195
3196void SAL_CALL ScCellRangesBase::addChartDataChangeEventListener( const uno::Reference<
3197 chart::XChartDataChangeEventListener >& aListener )
3198{
3199 SolarMutexGuard aGuard;
3200 if ( !pDocShell || aRanges.empty() )
3201 return;
3202
3204
3205 ScDocument& rDoc = pDocShell->GetDocument();
3206 ScRangeListRef aRangesRef( new ScRangeList(aRanges) );
3208 OUString aName = pColl->getUniqueName(u"__Uno");
3209 if (aName.isEmpty())
3210 // failed to create unique name.
3211 return;
3212
3213 ScChartListener* pListener = new ScChartListener( aName, rDoc, aRangesRef );
3214 pListener->SetUno( aListener, this );
3215 pColl->insert( pListener );
3216 pListener->StartListeningTo();
3217}
3218
3219void SAL_CALL ScCellRangesBase::removeChartDataChangeEventListener( const uno::Reference<
3220 chart::XChartDataChangeEventListener >& aListener )
3221{
3222 SolarMutexGuard aGuard;
3223 if ( pDocShell && !aRanges.empty() )
3224 {
3225 ScDocument& rDoc = pDocShell->GetDocument();
3227 pColl->FreeUno( aListener, this );
3228 }
3229}
3230
3231double SAL_CALL ScCellRangesBase::getNotANumber()
3232{
3233 // use DBL_MIN in ScChartArray, because Chart wants it so
3234 return DBL_MIN;
3235}
3236
3237sal_Bool SAL_CALL ScCellRangesBase::isNotANumber( double nNumber )
3238{
3239 // use DBL_MIN in ScChartArray, because Chart wants it so
3240 return (nNumber == DBL_MIN);
3241}
3242
3243// XModifyBroadcaster
3244
3245void SAL_CALL ScCellRangesBase::addModifyListener(const uno::Reference<util::XModifyListener>& aListener)
3246{
3247 SolarMutexGuard aGuard;
3248 if ( aRanges.empty() )
3249 throw uno::RuntimeException();
3250
3251 aValueListeners.emplace_back( aListener );
3252
3253 if ( aValueListeners.size() == 1 )
3254 {
3255 if (!pValueListener)
3256 pValueListener.reset( new ScLinkListener( LINK( this, ScCellRangesBase, ValueListenerHdl ) ) );
3257
3258 ScDocument& rDoc = pDocShell->GetDocument();
3259 for ( size_t i = 0, nCount = aRanges.size(); i < nCount; i++)
3260 rDoc.StartListeningArea( aRanges[ i ], false, pValueListener.get() );
3261
3262 acquire(); // don't lose this object (one ref for all listeners)
3263 }
3264}
3265
3266void SAL_CALL ScCellRangesBase::removeModifyListener( const uno::Reference<util::XModifyListener>& aListener )
3267{
3268
3269 SolarMutexGuard aGuard;
3270 if ( aRanges.empty() )
3271 throw uno::RuntimeException();
3272
3273 rtl::Reference<ScCellRangesBase> xSelfHold(this); // in case the listeners have the last ref
3274
3275 sal_uInt16 nCount = aValueListeners.size();
3276 for ( sal_uInt16 n=nCount; n--; )
3277 {
3278 uno::Reference<util::XModifyListener>& rObj = aValueListeners[n];
3279 if ( rObj == aListener )
3280 {
3281 aValueListeners.erase( aValueListeners.begin() + n );
3282
3283 if ( aValueListeners.empty() )
3284 {
3285 if (pValueListener)
3286 pValueListener->EndListeningAll();
3287
3288 release(); // release the ref for the listeners
3289 }
3290
3291 break;
3292 }
3293 }
3294}
3295
3296// XCellRangesQuery
3297
3298uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryVisibleCells()
3299{
3300 SolarMutexGuard aGuard;
3301 if (pDocShell)
3302 {
3304 SCTAB nTab = lcl_FirstTab(aRanges);
3305
3306 ScMarkData aMarkData(*GetMarkData());
3307
3308 ScDocument& rDoc = pDocShell->GetDocument();
3309 SCCOL nCol = 0, nLastCol;
3310 while (nCol <= rDoc.MaxCol())
3311 {
3312 if (rDoc.ColHidden(nCol, nTab, nullptr, &nLastCol))
3313 // hidden columns. Deselect them.
3314 aMarkData.SetMultiMarkArea(ScRange(nCol, 0, nTab, nLastCol, rDoc.MaxRow(), nTab), false);
3315
3316 nCol = nLastCol + 1;
3317 }
3318
3319 SCROW nRow = 0, nLastRow;
3320 while (nRow <= rDoc.MaxRow())
3321 {
3322 if (rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow))
3323 // These rows are hidden. Deselect them.
3324 aMarkData.SetMultiMarkArea(ScRange(0, nRow, nTab, rDoc.MaxCol(), nLastRow, nTab), false);
3325
3326 nRow = nLastRow + 1;
3327 }
3328
3329 ScRangeList aNewRanges;
3330 aMarkData.FillRangeListWithMarks( &aNewRanges, false );
3331 return new ScCellRangesObj( pDocShell, aNewRanges );
3332 }
3333
3334 return nullptr;
3335}
3336
3337uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryEmptyCells()
3338{
3339 SolarMutexGuard aGuard;
3340 if (pDocShell)
3341 {
3342 ScDocument& rDoc = pDocShell->GetDocument();
3343
3344 ScMarkData aMarkData(*GetMarkData());
3345
3346 // mark occupied cells
3347 for (size_t i = 0, nCount = aRanges.size(); i < nCount; ++i)
3348 {
3349 ScRange const & rRange = aRanges[ i ];
3350
3351 ScCellIterator aIter(rDoc, rRange);
3352 for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
3353 {
3354 // notes count as non-empty
3355 if (!aIter.isEmpty())
3356 aMarkData.SetMultiMarkArea(aIter.GetPos(), false);
3357 }
3358 }
3359
3360 ScRangeList aNewRanges;
3361 // IsMultiMarked is not enough (will not be reset during deselecting)
3362 //if (aMarkData.HasAnyMultiMarks()) // #i20044# should be set for all empty range
3363 aMarkData.FillRangeListWithMarks( &aNewRanges, false );
3364
3365 return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
3366 }
3367
3368 return nullptr;
3369}
3370
3371uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryContentCells(
3372 sal_Int16 nContentFlags )
3373{
3374 SolarMutexGuard aGuard;
3375 if (pDocShell)
3376 {
3377 ScDocument& rDoc = pDocShell->GetDocument();
3378
3379 ScMarkData aMarkData(rDoc.GetSheetLimits());
3380
3381 // select matching cells
3382 for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
3383 {
3384 ScRange const & rRange = aRanges[ i ];
3385
3386 ScCellIterator aIter(rDoc, rRange);
3387 for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
3388 {
3389 bool bAdd = false;
3390 switch (aIter.getType())
3391 {
3392 case CELLTYPE_STRING:
3393 if ( nContentFlags & sheet::CellFlags::STRING )
3394 bAdd = true;
3395 break;
3396 case CELLTYPE_EDIT:
3397 if ( (nContentFlags & sheet::CellFlags::STRING) || (nContentFlags & sheet::CellFlags::FORMATTED) )
3398 bAdd = true;
3399 break;
3400 case CELLTYPE_FORMULA:
3401 if ( nContentFlags & sheet::CellFlags::FORMULA )
3402 bAdd = true;
3403 break;
3404 case CELLTYPE_VALUE:
3405 if ( (nContentFlags & (sheet::CellFlags::VALUE|sheet::CellFlags::DATETIME))
3406 == (sheet::CellFlags::VALUE|sheet::CellFlags::DATETIME) )
3407 bAdd = true;
3408 else
3409 {
3410 // date/time identification
3411
3412 sal_uLong nIndex = static_cast<sal_uLong>(rDoc.GetAttr(
3413 aIter.GetPos(), ATTR_VALUE_FORMAT)->GetValue());
3414 SvNumFormatType nTyp = rDoc.GetFormatTable()->GetType(nIndex);
3415 if ((nTyp == SvNumFormatType::DATE) || (nTyp == SvNumFormatType::TIME) ||
3416 (nTyp == SvNumFormatType::DATETIME))
3417 {
3418 if ( nContentFlags & sheet::CellFlags::DATETIME )
3419 bAdd = true;
3420 }
3421 else
3422 {
3423 if ( nContentFlags & sheet::CellFlags::VALUE )
3424 bAdd = true;
3425 }
3426 }
3427 break;
3428 default:
3429 {
3430 // added to avoid warnings
3431 }
3432 }
3433
3434 if (bAdd)
3435 aMarkData.SetMultiMarkArea(aIter.GetPos());
3436 }
3437 }
3438
3439 if (nContentFlags & sheet::CellFlags::ANNOTATION)
3440 {
3441 std::vector<sc::NoteEntry> aNotes;
3442 rDoc.GetNotesInRange(aRanges, aNotes);
3443
3444 for (const auto& i : aNotes)
3445 {
3446 aMarkData.SetMultiMarkArea(i.maPos);
3447 }
3448 }
3449
3450 ScRangeList aNewRanges;
3451 if (aMarkData.IsMultiMarked())
3452 aMarkData.FillRangeListWithMarks( &aNewRanges, false );
3453
3454 return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
3455 }
3456
3457 return nullptr;
3458}
3459
3460uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryFormulaCells(
3461 sal_Int32 nResultFlags )
3462{
3463 SolarMutexGuard aGuard;
3464 if (pDocShell)
3465 {
3466 ScDocument& rDoc = pDocShell->GetDocument();
3467
3468 ScMarkData aMarkData(rDoc.GetSheetLimits());
3469
3470 // select matching cells
3471 for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
3472 {
3473 ScRange const & rRange = aRanges[ i ];
3474
3475 ScCellIterator aIter(rDoc, rRange);
3476 for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
3477 {
3478 if (aIter.getType() == CELLTYPE_FORMULA)
3479 {
3480 ScFormulaCell* pFCell = aIter.getFormulaCell();
3481 bool bAdd = false;
3482 if (pFCell->GetErrCode() != FormulaError::NONE)
3483 {
3484 if ( nResultFlags & sheet::FormulaResult::ERROR )
3485 bAdd = true;
3486 }
3487 else if (pFCell->IsValue())
3488 {
3489 if ( nResultFlags & sheet::FormulaResult::VALUE )
3490 bAdd = true;
3491 }
3492 else // String
3493 {
3494 if ( nResultFlags & sheet::FormulaResult::STRING )
3495 bAdd = true;
3496 }
3497
3498 if (bAdd)
3499 aMarkData.SetMultiMarkArea(aIter.GetPos());
3500 }
3501 }
3502 }
3503
3504 ScRangeList aNewRanges;
3505 if (aMarkData.IsMultiMarked())
3506 aMarkData.FillRangeListWithMarks( &aNewRanges, false );
3507
3508 return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
3509 }
3510
3511 return nullptr;
3512}
3513
3514uno::Reference<sheet::XSheetCellRanges> ScCellRangesBase::QueryDifferences_Impl(
3515 const table::CellAddress& aCompare, bool bColumnDiff)
3516{
3517 if (pDocShell)
3518 {
3519 size_t nRangeCount = aRanges.size();
3520 size_t i;
3521 ScDocument& rDoc = pDocShell->GetDocument();
3522 ScMarkData aMarkData(rDoc.GetSheetLimits());
3523
3524 SCCOLROW nCmpPos = bColumnDiff ? static_cast<SCCOLROW>(aCompare.Row) : static_cast<SCCOLROW>(aCompare.Column);
3525
3526 // first select everything, where at all something is in the comparison column
3527 // (in the second step the selection is cancelled for equal cells)
3528
3529 SCTAB nTab = lcl_FirstTab(aRanges);
3530 ScRange aCmpRange, aCellRange;
3531 if (bColumnDiff)
3532 aCmpRange = ScRange( 0,nCmpPos,nTab, rDoc.MaxCol(),nCmpPos,nTab );
3533 else
3534 aCmpRange = ScRange( static_cast<SCCOL>(nCmpPos),0,nTab, static_cast<SCCOL>(nCmpPos),rDoc.MaxRow(),nTab );
3535 ScCellIterator aCmpIter(rDoc, aCmpRange);
3536 for (bool bHasCell = aCmpIter.first(); bHasCell; bHasCell = aCmpIter.next())
3537 {
3538 SCCOLROW nCellPos = bColumnDiff ? static_cast<SCCOLROW>(aCmpIter.GetPos().Col()) : static_cast<SCCOLROW>(aCmpIter.GetPos().Row());
3539 if (bColumnDiff)
3540 aCellRange = ScRange( static_cast<SCCOL>(nCellPos),0,nTab,
3541 static_cast<SCCOL>(nCellPos),rDoc.MaxRow(),nTab );
3542 else
3543 aCellRange = ScRange( 0,nCellPos,nTab, rDoc.MaxCol(),nCellPos,nTab );
3544
3545 for (i=0; i<nRangeCount; i++)
3546 {
3547 ScRange aRange( aRanges[ i ] );
3548 if ( aRange.Intersects( aCellRange ) )
3549 {
3550 if (bColumnDiff)
3551 {
3552 aRange.aStart.SetCol(static_cast<SCCOL>(nCellPos));
3553 aRange.aEnd.SetCol(static_cast<SCCOL>(nCellPos));
3554 }
3555 else
3556 {
3557 aRange.aStart.SetRow(nCellPos);
3558 aRange.aEnd.SetRow(nCellPos);
3559 }
3560 aMarkData.SetMultiMarkArea( aRange );
3561 }
3562 }
3563 }
3564
3565 // compare all not empty cells with the comparison column and accordingly
3566 // select or cancel
3567
3568 ScAddress aCmpAddr;
3569 for (i=0; i<nRangeCount; i++)
3570 {
3571 ScRange const & rRange = aRanges[ i ];
3572
3573 ScCellIterator aIter( rDoc, rRange );
3574 for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
3575 {
3576 if (bColumnDiff)
3577 aCmpAddr = ScAddress( aIter.GetPos().Col(), nCmpPos, aIter.GetPos().Tab() );
3578 else
3579 aCmpAddr = ScAddress( static_cast<SCCOL>(nCmpPos), aIter.GetPos().Row(), aIter.GetPos().Tab() );
3580
3581 ScRange aOneRange(aIter.GetPos());
3582 if (!aIter.equalsWithoutFormat(aCmpAddr))
3583 aMarkData.SetMultiMarkArea( aOneRange );
3584 else
3585 aMarkData.SetMultiMarkArea( aOneRange, false ); // deselect
3586 }
3587 }
3588
3589 ScRangeList aNewRanges;
3590 if (aMarkData.IsMultiMarked())
3591 aMarkData.FillRangeListWithMarks( &aNewRanges, false );
3592
3593 return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
3594 }
3595 return nullptr;
3596}
3597
3598uno::Reference<sheet::XSheetCellRanges > SAL_CALL ScCellRangesBase::queryColumnDifferences(
3599 const table::CellAddress& aCompare )
3600{
3601 SolarMutexGuard aGuard;
3602 return QueryDifferences_Impl( aCompare, true );
3603}
3604
3605uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryRowDifferences(
3606 const table::CellAddress& aCompare )
3607{
3608 SolarMutexGuard aGuard;
3609 return QueryDifferences_Impl( aCompare, false );
3610}
3611
3612uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryIntersection(
3613 const table::CellRangeAddress& aRange )
3614{
3615 SolarMutexGuard aGuard;
3616 ScRange aMask( static_cast<SCCOL>(aRange.StartColumn), static_cast<SCROW>(aRange.StartRow), aRange.Sheet,
3617 static_cast<SCCOL>(aRange.EndColumn), static_cast<SCROW>(aRange.EndRow), aRange.Sheet );
3618
3619 ScRangeList aNew;
3620 for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
3621 {
3622 ScRange aTemp( aRanges[ i ] );
3623 if ( aTemp.Intersects( aMask ) )
3624 aNew.Join( ScRange( std::max( aTemp.aStart.Col(), aMask.aStart.Col() ),
3625 std::max( aTemp.aStart.Row(), aMask.aStart.Row() ),
3626 std::max( aTemp.aStart.Tab(), aMask.aStart.Tab() ),
3627 std::min( aTemp.aEnd.Col(), aMask.aEnd.Col() ),
3628 std::min( aTemp.aEnd.Row(), aMask.aEnd.Row() ),
3629 std::min( aTemp.aEnd.Tab(), aMask.aEnd.Tab() ) ) );
3630 }
3631
3632 return new ScCellRangesObj( pDocShell, aNew ); // can be empty
3633}
3634
3635// XFormulaQuery
3636
3637uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryPrecedents(
3638 sal_Bool bRecursive )
3639{
3640 SolarMutexGuard aGuard;
3641 if ( pDocShell )
3642 {
3643 ScDocument& rDoc = pDocShell->GetDocument();
3644
3645 ScRangeList aNewRanges(aRanges);
3646 bool bFound;
3647 do
3648 {
3649 bFound = false;
3650
3651 // aMarkData uses aNewRanges, not aRanges, so GetMarkData can't be used
3652 ScMarkData aMarkData(rDoc.GetSheetLimits());
3653 aMarkData.MarkFromRangeList( aNewRanges, false );
3654
3655 for (size_t nR = 0, nCount = aNewRanges.size(); nR<nCount; ++nR)
3656 {
3657 ScRange const & rRange = aNewRanges[ nR];
3658 ScCellIterator aIter(rDoc, rRange);
3659 for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
3660 {
3661 if (aIter.getType() != CELLTYPE_FORMULA)
3662 continue;
3663
3664 ScDetectiveRefIter aRefIter(rDoc, aIter.getFormulaCell());
3665 ScRange aRefRange;
3666 while ( aRefIter.GetNextRef( aRefRange) )
3667 {
3668 if ( bRecursive && !bFound && !aMarkData.IsAllMarked( aRefRange ) )
3669 bFound = true;
3670 aMarkData.SetMultiMarkArea(aRefRange);
3671 }
3672 }
3673 }
3674
3675 aMarkData.FillRangeListWithMarks( &aNewRanges, true );
3676 }
3677 while ( bRecursive && bFound );
3678
3679 return new ScCellRangesObj( pDocShell, aNewRanges );
3680 }
3681
3682 return nullptr;
3683}
3684
3685uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryDependents(
3686 sal_Bool bRecursive )
3687{
3688 SolarMutexGuard aGuard;
3689 if ( pDocShell )
3690 {
3691 ScDocument& rDoc = pDocShell->GetDocument();
3692
3693 ScRangeList aNewRanges(aRanges);
3694 bool bFound;
3695 do
3696 {
3697 bFound = false;
3698
3699 // aMarkData uses aNewRanges, not aRanges, so GetMarkData can't be used
3700 ScMarkData aMarkData(rDoc.GetSheetLimits());
3701 aMarkData.MarkFromRangeList( aNewRanges, false );
3702
3703 SCTAB nTab = lcl_FirstTab(aNewRanges);
3704
3705 ScCellIterator aCellIter( rDoc, ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab) );
3706 for (bool bHasCell = aCellIter.first(); bHasCell; bHasCell = aCellIter.next())
3707 {
3708 if (aCellIter.getType() != CELLTYPE_FORMULA)
3709 continue;
3710
3711 bool bMark = false;
3712 ScDetectiveRefIter aIter(rDoc, aCellIter.getFormulaCell());
3713 ScRange aRefRange;
3714 while ( aIter.GetNextRef( aRefRange) && !bMark )
3715 {
3716 size_t nRangesCount = aNewRanges.size();
3717 for (size_t nR = 0; nR < nRangesCount; ++nR)
3718 {
3719 ScRange const & rRange = aNewRanges[ nR ];
3720 if (rRange.Intersects(aRefRange))
3721 {
3722 bMark = true; // depending on part of Range
3723 break;
3724 }
3725 }
3726 }
3727 if (bMark)
3728 {
3729 ScRange aCellRange(aCellIter.GetPos());
3730 if ( bRecursive && !bFound && !aMarkData.IsAllMarked( aCellRange ) )
3731 bFound = true;
3732 aMarkData.SetMultiMarkArea(aCellRange);
3733 }
3734 }
3735
3736 aMarkData.FillRangeListWithMarks( &aNewRanges, true );
3737 }
3738 while ( bRecursive && bFound );
3739
3740 return new ScCellRangesObj( pDocShell, aNewRanges );
3741 }
3742
3743 return nullptr;
3744}
3745
3746// XSearchable
3747
3748uno::Reference<util::XSearchDescriptor> SAL_CALL ScCellRangesBase::createSearchDescriptor()
3749{
3750 return new ScCellSearchObj;
3751}
3752
3753uno::Reference<container::XIndexAccess> SAL_CALL ScCellRangesBase::findAll(
3754 const uno::Reference<util::XSearchDescriptor>& xDesc )
3755{
3756 SolarMutexGuard aGuard;
3757 // should we return Null if nothing is found(?)
3758 uno::Reference<container::XIndexAccess> xRet;
3759 if ( pDocShell && xDesc.is() )
3760 {
3761 ScCellSearchObj* pSearch = dynamic_cast<ScCellSearchObj*>( xDesc.get() );
3762 if (pSearch)
3763 {
3764 SvxSearchItem* pSearchItem = pSearch->GetSearchItem();
3765 if (pSearchItem)
3766 {
3767 ScDocument& rDoc = pDocShell->GetDocument();
3768 pSearchItem->SetCommand( SvxSearchCmd::FIND_ALL );
3769 // always only within this object
3770 pSearchItem->SetSelection( !lcl_WholeSheet(rDoc, aRanges) );
3771
3772 ScMarkData aMark(*GetMarkData());
3773
3774 OUString aDummyUndo;
3775 ScRangeList aMatchedRanges;
3776 SCCOL nCol = 0;
3777 SCROW nRow = 0;
3778 SCTAB nTab = 0;
3779 bool bMatchedRangesWereClamped = false;
3780 bool bFound = rDoc.SearchAndReplace(
3781 *pSearchItem, nCol, nRow, nTab, aMark, aMatchedRanges, aDummyUndo, nullptr, bMatchedRangesWereClamped);
3782 if (bFound)
3783 {
3784 // on findAll always CellRanges no matter how much has been found
3785 xRet.set(new ScCellRangesObj( pDocShell, aMatchedRanges ));
3786 }
3787 }
3788 }
3789 }
3790 return xRet;
3791}
3792
3793uno::Reference<uno::XInterface> ScCellRangesBase::Find_Impl(
3794 const uno::Reference<util::XSearchDescriptor>& xDesc,
3795 const ScAddress* pLastPos )
3796{
3797 uno::Reference<uno::XInterface> xRet;
3798 if ( pDocShell && xDesc.is() )
3799 {
3800 ScCellSearchObj* pSearch = dynamic_cast<ScCellSearchObj*>( xDesc.get() );
3801 if (pSearch)
3802 {
3803 SvxSearchItem* pSearchItem = pSearch->GetSearchItem();
3804 if (pSearchItem)
3805 {
3806 ScDocument& rDoc = pDocShell->GetDocument();
3807 pSearchItem->SetCommand( SvxSearchCmd::FIND );
3808 // only always in this object
3809 pSearchItem->SetSelection( !lcl_WholeSheet(rDoc, aRanges) );
3810
3811 ScMarkData aMark(*GetMarkData());
3812
3813 SCCOL nCol;
3814 SCROW nRow;
3815 SCTAB nTab;
3816 if (pLastPos)
3817 pLastPos->GetVars( nCol, nRow, nTab );
3818 else
3819 {
3820 nTab = lcl_FirstTab(aRanges);
3821 rDoc.GetSearchAndReplaceStart( *pSearchItem, nCol, nRow );
3822 }
3823
3824 OUString aDummyUndo;
3825 ScRangeList aMatchedRanges;
3826 bool bMatchedRangesWereClamped;
3827 bool bFound = rDoc.SearchAndReplace(
3828 *pSearchItem, nCol, nRow, nTab, aMark, aMatchedRanges, aDummyUndo, nullptr, bMatchedRangesWereClamped);
3829 if (bFound)
3830 {
3831 ScAddress aFoundPos( nCol, nRow, nTab );
3832 xRet.set(static_cast<cppu::OWeakObject*>(new ScCellObj( pDocShell, aFoundPos )));
3833 }
3834 }
3835 }
3836 }
3837 return xRet;
3838}
3839
3840uno::Reference<uno::XInterface> SAL_CALL ScCellRangesBase::findFirst(
3841 const uno::Reference<util::XSearchDescriptor>& xDesc )
3842{
3843 SolarMutexGuard aGuard;
3844 return Find_Impl( xDesc, nullptr );
3845}
3846
3847uno::Reference<uno::XInterface> SAL_CALL ScCellRangesBase::findNext(
3848 const uno::Reference<uno::XInterface>& xStartAt,
3849 const uno::Reference<util::XSearchDescriptor >& xDesc )
3850{
3851 SolarMutexGuard aGuard;
3852 if ( xStartAt.is() )
3853 {
3854 ScCellRangesBase* pRangesImp = dynamic_cast<ScCellRangesBase*>( xStartAt.get() );
3855 if ( pRangesImp && pRangesImp->GetDocShell() == pDocShell )
3856 {
3857 const ScRangeList& rStartRanges = pRangesImp->GetRangeList();
3858 if ( rStartRanges.size() == 1 )
3859 {
3860 ScAddress aStartPos = rStartRanges[ 0 ].aStart;
3861 return Find_Impl( xDesc, &aStartPos );
3862 }
3863 }
3864 }
3865 return nullptr;
3866}
3867
3868// XReplaceable
3869
3870uno::Reference<util::XReplaceDescriptor> SAL_CALL ScCellRangesBase::createReplaceDescriptor()
3871{
3872 return new ScCellSearchObj;
3873}
3874
3875sal_Int32 SAL_CALL ScCellRangesBase::replaceAll( const uno::Reference<util::XSearchDescriptor>& xDesc )
3876{
3877 SolarMutexGuard aGuard;
3878 sal_uInt64 nReplaced = 0;
3879 if ( pDocShell && xDesc.is() )
3880 {
3881 ScCellSearchObj* pSearch = dynamic_cast<ScCellSearchObj*>( xDesc.get() );
3882 if (pSearch)
3883 {
3884 SvxSearchItem* pSearchItem = pSearch->GetSearchItem();
3885 if (pSearchItem)
3886 {
3887 ScDocument& rDoc = pDocShell->GetDocument();
3888 bool bUndo(rDoc.IsUndoEnabled());
3889 pSearchItem->SetCommand( SvxSearchCmd::REPLACE_ALL );
3890 // only always in this object
3891 pSearchItem->SetSelection( !lcl_WholeSheet(rDoc, aRanges) );
3892
3893 ScMarkData aMark(*GetMarkData());
3894
3895 SCTAB nTabCount = rDoc.GetTableCount();
3896 bool bProtected = !pDocShell->IsEditable();
3897 for (const auto& rTab : aMark)
3898 {
3899 if (rTab >= nTabCount)
3900 break;
3901 if ( rDoc.IsTabProtected(rTab) )
3902 bProtected = true;
3903 }
3904 if (bProtected)
3905 {
3907 }
3908 else
3909 {
3910 SCTAB nTab = aMark.GetFirstSelected(); // do not use if SearchAndReplace
3911 SCCOL nCol = 0;
3912 SCROW nRow = 0;
3913
3914 OUString aUndoStr;
3915 ScDocumentUniquePtr pUndoDoc;
3916 if (bUndo)
3917 {
3918 pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
3919 pUndoDoc->InitUndo( rDoc, nTab, nTab );
3920 }
3921 for (const auto& rTab : aMark)
3922 {
3923 if (rTab >= nTabCount)
3924 break;
3925 if (rTab != nTab && bUndo)
3926 pUndoDoc->AddUndoTab( rTab, rTab );
3927 }
3928 std::unique_ptr<ScMarkData> pUndoMark;
3929 if (bUndo)
3930 pUndoMark.reset(new ScMarkData(aMark));
3931
3932 bool bFound = false;
3933 if (bUndo)
3934 {
3935 ScRangeList aMatchedRanges;
3936 bool bMatchedRangesWereClamped;
3937 bFound = rDoc.SearchAndReplace(
3938 *pSearchItem, nCol, nRow, nTab, aMark, aMatchedRanges, aUndoStr, pUndoDoc.get(), bMatchedRangesWereClamped );
3939 }
3940 if (bFound)
3941 {
3942 nReplaced = pUndoDoc->GetCellCount();
3943
3944 pDocShell->GetUndoManager()->AddUndoAction(
3945 std::make_unique<ScUndoReplace>( pDocShell, *pUndoMark, nCol, nRow, nTab,
3946 aUndoStr, std::move(pUndoDoc), pSearchItem ) );
3947
3948 pDocShell->PostPaintGridAll();
3949 pDocShell->SetDocumentModified();
3950 }
3951 }
3952 }
3953 }
3954 }
3955 return nReplaced;
3956}
3957
3958ScCellRangesObj::ScCellRangesObj(ScDocShell* pDocSh, const ScRangeList& rR)
3959 : ScCellRangesBase(pDocSh, rR)
3960{
3961}
3962
3963ScCellRangesObj::~ScCellRangesObj()
3964{
3965}
3966
3967void ScCellRangesObj::RefChanged()
3968{
3969 ScCellRangesBase::RefChanged();
3970}
3971
3972uno::Any SAL_CALL ScCellRangesObj::queryInterface( const uno::Type& rType )
3973{
3974 SC_QUERYINTERFACE( sheet::XSheetCellRangeContainer )
3975 SC_QUERYINTERFACE( sheet::XSheetCellRanges )
3976 SC_QUERYINTERFACE( container::XIndexAccess )
3977 SC_QUERY_MULTIPLE( container::XElementAccess, container::XIndexAccess )
3978 SC_QUERYINTERFACE( container::XEnumerationAccess )
3979 SC_QUERYINTERFACE( container::XNameContainer )
3980 SC_QUERYINTERFACE( container::XNameReplace )
3981 SC_QUERYINTERFACE( container::XNameAccess )
3982
3983 return ScCellRangesBase::queryInterface( rType );
3984}
3985
3986void SAL_CALL ScCellRangesObj::acquire() noexcept
3987{
3988 ScCellRangesBase::acquire();
3989}
3990
3991void SAL_CALL ScCellRangesObj::release() noexcept
3992{
3993 ScCellRangesBase::release();
3994}
3995
3996uno::Sequence<uno::Type> SAL_CALL ScCellRangesObj::getTypes()
3997{
3998 static const uno::Sequence<uno::Type> aTypes = comphelper::concatSequences(
3999 ScCellRangesBase::getTypes(),
4000 uno::Sequence<uno::Type>
4001 {
4005 } );
4006 return aTypes;
4007}
4008
4009uno::Sequence<sal_Int8> SAL_CALL ScCellRangesObj::getImplementationId()
4010{
4011 return css::uno::Sequence<sal_Int8>();
4012}
4013
4014// XCellRanges
4015
4016rtl::Reference<ScCellRangeObj> ScCellRangesObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
4017{
4018 ScDocShell* pDocSh = GetDocShell();
4019 const ScRangeList& rRanges = GetRangeList();
4020 if ( pDocSh && nIndex >= 0 && nIndex < sal::static_int_cast<sal_Int32>(rRanges.size()) )
4021 {
4022 ScRange const & rRange = rRanges[ nIndex ];
4023 if ( rRange.aStart == rRange.aEnd )
4024 return new ScCellObj( pDocSh, rRange.aStart );
4025 else
4026 return new ScCellRangeObj( pDocSh, rRange );
4027 }
4028
4029 return nullptr; // no DocShell or wrong index
4030}
4031
4032uno::Sequence<table::CellRangeAddress> SAL_CALL ScCellRangesObj::getRangeAddresses()
4033{
4034 SolarMutexGuard aGuard;
4035 ScDocShell* pDocSh = GetDocShell();
4036 const ScRangeList& rRanges = GetRangeList();
4037 size_t nCount = rRanges.size();
4038 if ( pDocSh && nCount )
4039 {
4040 table::CellRangeAddress aRangeAddress;
4041 uno::Sequence<table::CellRangeAddress> aSeq(nCount);
4042 table::CellRangeAddress* pAry = aSeq.getArray();
4043 for ( size_t i=0; i < nCount; i++)
4044 {
4045 ScUnoConversion::FillApiRange( aRangeAddress, rRanges[ i ] );
4046 pAry[i] = aRangeAddress;
4047 }
4048 return aSeq;
4049 }
4050
4051 return {}; // can be empty
4052}
4053
4054uno::Reference<container::XEnumerationAccess> SAL_CALL ScCellRangesObj::getCells()
4055{
4056 SolarMutexGuard aGuard;
4057
4058 // getCells with empty range list is possible (no exception),
4059 // the resulting enumeration just has no elements
4060 // (same behaviour as a valid range with no cells)
4061 // This is handled in ScCellsEnumeration ctor.
4062
4063 const ScRangeList& rRanges = GetRangeList();
4064 ScDocShell* pDocSh = GetDocShell();
4065 if (pDocSh)
4066 return new ScCellsObj( pDocSh, rRanges );
4067 return nullptr;
4068}
4069
4070OUString SAL_CALL ScCellRangesObj::getRangeAddressesAsString()
4071{
4072 SolarMutexGuard aGuard;
4073 OUString aString;
4074 ScDocShell* pDocSh = GetDocShell();
4075 const ScRangeList& rRanges = GetRangeList();
4076 if (pDocSh)
4077 rRanges.Format( aString, ScRefFlags::VALID | ScRefFlags::TAB_3D, pDocSh->GetDocument() );
4078 return aString;
4079}
4080
4081// XSheetCellRangeContainer
4082
4083void SAL_CALL ScCellRangesObj::addRangeAddress( const table::CellRangeAddress& rRange,
4084 sal_Bool bMergeRanges )
4085{
4086 SolarMutexGuard aGuard;
4087 ScRange aRange(static_cast<SCCOL>(rRange.StartColumn),
4088 static_cast<SCROW>(rRange.StartRow),
4089 static_cast<SCTAB>(rRange.Sheet),
4090 static_cast<SCCOL>(rRange.EndColumn),
4091 static_cast<SCROW>(rRange.EndRow),
4092 static_cast<SCTAB>(rRange.Sheet));
4093 AddRange(aRange, bMergeRanges);
4094}
4095
4096static void lcl_RemoveNamedEntry( std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries, const ScRange& rRange )
4097{
4098 sal_uInt16 nCount = rNamedEntries.size();
4099 for ( sal_uInt16 n=nCount; n--; )
4100 if ( rNamedEntries[n].GetRange() == rRange )
4101 rNamedEntries.erase( rNamedEntries.begin() + n );
4102}
4103
4104void SAL_CALL ScCellRangesObj::removeRangeAddress( const table::CellRangeAddress& rRange )
4105{
4106 SolarMutexGuard aGuard;
4107 const ScRangeList& rRanges = GetRangeList();
4108
4109 ScRangeList aSheetRanges;
4110 ScRangeList aNotSheetRanges;
4111 for (size_t i = 0; i < rRanges.size(); ++i)
4112 {
4113 if (rRanges[ i].aStart.Tab() == rRange.Sheet)
4114 {
4115 aSheetRanges.push_back( rRanges[ i ] );
4116 }
4117 else
4118 {
4119 aNotSheetRanges.push_back( rRanges[ i ] );
4120 }
4121 }
4122 ScMarkData aMarkData(GetDocument()->GetSheetLimits());
4123 aMarkData.MarkFromRangeList( aSheetRanges, false );
4124 ScRange aRange(static_cast<SCCOL>(rRange.StartColumn),
4125 static_cast<SCROW>(rRange.StartRow),
4126 static_cast<SCTAB>(rRange.Sheet),
4127 static_cast<SCCOL>(rRange.EndColumn),
4128 static_cast<SCROW>(rRange.EndRow),
4129 static_cast<SCTAB>(rRange.Sheet));
4130 if (aMarkData.GetTableSelect( aRange.aStart.Tab() ))
4131 {
4132 aMarkData.MarkToMulti();
4133 if (!aMarkData.IsAllMarked( aRange ) )
4134 throw container::NoSuchElementException();
4135
4136 aMarkData.SetMultiMarkArea( aRange, false );
4137 lcl_RemoveNamedEntry(m_aNamedEntries, aRange);
4138
4139 }
4140 SetNewRanges(aNotSheetRanges);
4141 ScRangeList aNew;
4142 aMarkData.FillRangeListWithMarks( &aNew, false );
4143 for ( size_t j = 0; j < aNew.size(); ++j)
4144 {
4145 AddRange(aNew[ j ], false);
4146 }
4147}
4148
4149void SAL_CALL ScCellRangesObj::addRangeAddresses( const uno::Sequence<table::CellRangeAddress >& rRanges,
4150 sal_Bool bMergeRanges )
4151{
4152 SolarMutexGuard aGuard;
4153 for (const table::CellRangeAddress& rRange : rRanges)
4154 {
4155 ScRange aRange(static_cast<SCCOL>(rRange.StartColumn),
4156 static_cast<SCROW>(rRange.StartRow),
4157 static_cast<SCTAB>(rRange.Sheet),
4158 static_cast<SCCOL>(rRange.EndColumn),
4159 static_cast<SCROW>(rRange.EndRow),
4160 static_cast<SCTAB>(rRange.Sheet));
4161 AddRange(aRange, bMergeRanges);
4162 }
4163}
4164
4165void SAL_CALL ScCellRangesObj::removeRangeAddresses( const uno::Sequence<table::CellRangeAddress >& rRangeSeq )
4166{
4167 // use sometimes a better/faster implementation
4168 for (const table::CellRangeAddress& rRange : rRangeSeq)
4169 {
4170 removeRangeAddress(rRange);
4171 }
4172}
4173
4174// XNameContainer
4175
4176static void lcl_RemoveNamedEntry( std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries, std::u16string_view rName )
4177{
4178 sal_uInt16 nCount = rNamedEntries.size();
4179 for ( sal_uInt16 n=nCount; n--; )
4180 if ( rNamedEntries[n].GetName() == rName )
4181 rNamedEntries.erase( rNamedEntries.begin() + n );
4182}
4183
4184void SAL_CALL ScCellRangesObj::insertByName( const OUString& aName, const uno::Any& aElement )
4185{
4186 SolarMutexGuard aGuard;
4187 ScDocShell* pDocSh = GetDocShell();
4188 bool bDone = false;
4189
4191
4192 uno::Reference<uno::XInterface> xInterface(aElement, uno::UNO_QUERY);
4193 if ( pDocSh && xInterface.is() )
4194 {
4195 ScCellRangesBase* pRangesImp = dynamic_cast<ScCellRangesBase*>( xInterface.get() );
4196 if ( pRangesImp && pRangesImp->GetDocShell() == pDocSh )
4197 {
4198 // if explicit name is given and already existing, throw exception
4199
4200 if ( !aName.isEmpty() )
4201 {
4202 size_t nNamedCount = m_aNamedEntries.size();
4203 for (size_t n = 0; n < nNamedCount; n++)
4204 {
4205 if (m_aNamedEntries[n].GetName() == aName)
4206 throw container::ElementExistException();
4207 }
4208 }
4209
4210 ScRangeList aNew(GetRangeList());
4211 const ScRangeList& rAddRanges = pRangesImp->GetRangeList();
4212 size_t nAddCount = rAddRanges.size();
4213 for ( size_t i = 0; i < nAddCount; i++ )
4214 aNew.Join( rAddRanges[ i ] );
4215 SetNewRanges(aNew);
4216 bDone = true;
4217
4218 if ( !aName.isEmpty() && nAddCount == 1 )
4219 {
4220 // if a name is given, also insert into list of named entries
4221 // (only possible for a single range)
4222 // name is not in m_aNamedEntries (tested above)
4223 m_aNamedEntries.emplace_back( ScNamedEntry{aName, rAddRanges[ 0 ]} );
4224 }
4225 }
4226 }
4227
4228 if (!bDone)
4229 {
4230 // invalid element - double names are handled above
4231 throw lang::IllegalArgumentException();
4232 }
4233}
4234
4235static bool lcl_FindRangeByName( const ScRangeList& rRanges, ScDocShell* pDocSh,
4236 std::u16string_view rName, size_t& rIndex )
4237{
4238 if (pDocSh)
4239 {
4240 OUString aRangeStr;
4241 ScDocument& rDoc = pDocSh->GetDocument();
4242 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
4243 {
4244 aRangeStr = rRanges[ i ].Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_3D);
4245 if ( aRangeStr == rName )
4246 {
4247 rIndex = i;
4248 return true;
4249 }
4250 }
4251 }
4252 return false;
4253}
4254
4255static bool lcl_FindRangeOrEntry( const std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries,
4256 const ScRangeList& rRanges, ScDocShell* pDocSh,
4257 const OUString& rName, ScRange& rFound )
4258{
4259 // exact range in list?
4260
4261 size_t nIndex = 0;
4262 if ( lcl_FindRangeByName( rRanges, pDocSh, rName, nIndex ) )
4263 {
4264 rFound = rRanges[ nIndex ];
4265 return true;
4266 }
4267
4268 // range contained in selection? (sheet must be specified)
4269
4270 ScRange aCellRange;
4271 ScRefFlags nParse = aCellRange.ParseAny( rName, pDocSh->GetDocument() );
4272 if ( (nParse & ( ScRefFlags::VALID | ScRefFlags::TAB_3D ))
4274 {
4275 ScMarkData aMarkData(pDocSh->GetDocument().GetSheetLimits());
4276 aMarkData.MarkFromRangeList( rRanges, false );
4277 if ( aMarkData.IsAllMarked( aCellRange ) )
4278 {
4279 rFound = aCellRange;
4280 return true;
4281 }
4282 }
4283
4284 // named entry in this object?
4285
4286 for (const auto & rNamedEntry : rNamedEntries)
4287 if ( rNamedEntry.GetName() == rName )
4288 {
4289 // test if named entry is contained in rRanges
4290
4291 const ScRange& rComp = rNamedEntry.GetRange();
4292 ScMarkData aMarkData(pDocSh->GetDocument().GetSheetLimits());
4293 aMarkData.MarkFromRangeList( rRanges, false );
4294 if ( aMarkData.IsAllMarked( rComp ) )
4295 {
4296 rFound = rComp;
4297 return true;
4298 }
4299 }
4300
4301 return false; // not found
4302}
4303
4304void SAL_CALL ScCellRangesObj::removeByName( const OUString& aName )
4305{
4306 SolarMutexGuard aGuard;
4307 bool bDone = false;
4308 ScDocShell* pDocSh = GetDocShell();
4309 const ScRangeList& rRanges = GetRangeList();
4310 size_t nIndex = 0;
4311 if ( lcl_FindRangeByName( rRanges, pDocSh, aName, nIndex ) )
4312 {
4313 // skip a single range
4314 ScRangeList aNew;
4315 for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
4316 if (i != nIndex)
4317 aNew.push_back( rRanges[ i ] );
4318 SetNewRanges(aNew);
4319 bDone = true;
4320 }
4321 else if (pDocSh)
4322 {
4323 // deselect any ranges (parsed or named entry)
4324 ScRangeList aDiff;
4325 bool bValid = ( aDiff.Parse( aName, pDocSh->GetDocument() ) & ScRefFlags::VALID )
4327 if (!bValid)
4328 {
4329 sal_uInt16 nCount = m_aNamedEntries.size();
4330 for (sal_uInt16 n=0;