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