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