LibreOffice Module sc (master)  1
cellsuno.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <scitems.hxx>
21 #include <editeng/eeitem.hxx>
22 #include <o3tl/safeint.hxx>
23 #include <svx/svdpool.hxx>
24 
25 #include <vcl/svapp.hxx>
26 #include <svx/algitem.hxx>
27 #include <editeng/borderline.hxx>
28 #include <editeng/boxitem.hxx>
29 #include <editeng/brushitem.hxx>
30 #include <editeng/editeng.hxx>
31 #include <editeng/flditem.hxx>
32 #include <editeng/justifyitem.hxx>
33 #include <editeng/editobj.hxx>
34 #include <editeng/unoipset.hxx>
35 #include <editeng/langitem.hxx>
36 #include <sfx2/linkmgr.hxx>
37 #include <svl/srchitem.hxx>
38 #include <svl/sharedstringpool.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>
48 
49 #include <com/sun/star/awt/XBitmap.hpp>
50 #include <com/sun/star/util/CellProtection.hpp>
51 #include <com/sun/star/table/CellHoriJustify.hpp>
52 #include <com/sun/star/table/CellOrientation.hpp>
53 #include <com/sun/star/table/ShadowFormat.hpp>
54 #include <com/sun/star/table/TableBorder.hpp>
55 #include <com/sun/star/table/TableBorder2.hpp>
56 #include <com/sun/star/sheet/CellFlags.hpp>
57 #include <com/sun/star/sheet/FormulaResult.hpp>
58 #include <com/sun/star/beans/PropertyAttribute.hpp>
59 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
60 #include <com/sun/star/lang/Locale.hpp>
61 #include <com/sun/star/beans/TolerantPropertySetResultType.hpp>
62 #include <com/sun/star/beans/SetPropertyTolerantFailed.hpp>
63 #include <com/sun/star/text/WritingMode2.hpp>
64 #include <com/sun/star/text/textfield/Type.hpp>
65 #include <com/sun/star/sheet/XConditionalFormats.hpp>
66 
67 #include <autoform.hxx>
68 #include <cellvalue.hxx>
69 #include <cellmergeoption.hxx>
70 #include <cellsuno.hxx>
71 #include <cursuno.hxx>
72 #include <textuno.hxx>
73 #include <editsrc.hxx>
74 #include <notesuno.hxx>
75 #include <fielduno.hxx>
76 #include <docuno.hxx>
77 #include <datauno.hxx>
78 #include <dapiuno.hxx>
79 #include <chartuno.hxx>
80 #include <fmtuno.hxx>
81 #include <miscuno.hxx>
82 #include <convuno.hxx>
83 #include <srchuno.hxx>
84 #include <nameuno.hxx>
85 #include <targuno.hxx>
86 #include <tokenuno.hxx>
87 #include <eventuno.hxx>
88 #include <docsh.hxx>
89 #include <markdata.hxx>
90 #include <patattr.hxx>
91 #include <docpool.hxx>
92 #include <docfunc.hxx>
93 #include <dbdocfun.hxx>
94 #include <olinefun.hxx>
95 #include <hints.hxx>
96 #include <formulacell.hxx>
97 #include <undotab.hxx>
98 #include <undoblk.hxx>
99 #include <stlsheet.hxx>
100 #include <dbdata.hxx>
101 #include <attrib.hxx>
102 #include <chartarr.hxx>
103 #include <chartlis.hxx>
104 #include <drwlayer.hxx>
105 #include <printfun.hxx>
106 #include <prnsave.hxx>
107 #include <tablink.hxx>
108 #include <dociter.hxx>
109 #include <rangeutl.hxx>
110 #include <conditio.hxx>
111 #include <validat.hxx>
112 #include <sc.hrc>
113 #include <cellform.hxx>
114 #include <globstr.hrc>
115 #include <scresid.hxx>
116 #include <unonames.hxx>
117 #include <styleuno.hxx>
118 #include <rangeseq.hxx>
119 #include <unowids.hxx>
120 #include <paramisc.hxx>
121 #include <queryentry.hxx>
122 #include <formula/errorcodes.hxx>
123 #include <unoreflist.hxx>
124 #include <formula/grammar.hxx>
126 #include <stringutil.hxx>
127 #include <formulaiter.hxx>
128 #include <tokenarray.hxx>
129 #include <stylehelper.hxx>
130 #include <dputil.hxx>
131 #include <sortparam.hxx>
132 #include <condformatuno.hxx>
133 #include <TablePivotCharts.hxx>
134 #include <table.hxx>
135 #include <refundo.hxx>
136 #include <columnspanset.hxx>
137 
138 #include <memory>
139 
140 using namespace com::sun::star;
141 
142 namespace {
143 
144 class ScNamedEntry
145 {
146  OUString aName;
147  ScRange aRange;
148 
149 public:
150  ScNamedEntry(const OUString& rN, const ScRange& rR) :
151  aName(rN), aRange(rR) {}
152 
153  const OUString& GetName() const { return aName; }
154  const ScRange& GetRange() const { return aRange; }
155 };
156 
157 }
158 
159 // The names in the maps must be sorted according to strcmp!
161 
162 // Left/Right/Top/BottomBorder are mapped directly to the core items,
163 // not collected/applied to the borders of a range -> ATTR_BORDER can be used directly
164 
166 {
167  static const SfxItemPropertyMapEntry aCellsPropertyMap_Impl[] =
168  {
169  {OUString(SC_UNONAME_ABSNAME), SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
266  { OUString(), 0, css::uno::Type(), 0, 0 }
267  };
268  static SfxItemPropertySet aCellsPropertySet( aCellsPropertyMap_Impl );
269  return &aCellsPropertySet;
270 }
271 
272 // CellRange contains all entries from Cells, plus its own entries
273 // with Which-ID 0 (those are needed only for getPropertySetInfo).
274 
276 {
277  static const SfxItemPropertyMapEntry aRangePropertyMap_Impl[] =
278  {
279  {OUString(SC_UNONAME_ABSNAME), SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
357  {OUString(SC_UNONAME_POS), SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
364  {OUString(SC_UNONAME_SIZE), SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
377  { OUString(), 0, css::uno::Type(), 0, 0 }
378  };
379  static SfxItemPropertySet aRangePropertySet( aRangePropertyMap_Impl );
380  return &aRangePropertySet;
381 }
382 
383 // Cell contains entries from CellRange, plus its own entries
384 // with Which-ID 0 (those are needed only for getPropertySetInfo).
385 
387 {
388  static const SfxItemPropertyMapEntry aCellPropertyMap_Impl[] =
389  {
390  {OUString(SC_UNONAME_ABSNAME), SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
449  {OUString(SC_UNONAME_FORMRT), SC_WID_UNO_FORMRT, cppu::UnoType<table::CellContentType>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
450  {OUString(SC_UNONAME_CELLCONTENTTYPE), SC_WID_UNO_CELLCONTENTTYPE, cppu::UnoType<table::CellContentType>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
451  {OUString(SC_UNONAME_FORMRT2), SC_WID_UNO_FORMRT2, cppu::UnoType<sal_Int32>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
472  {OUString(SC_UNONAME_POS), SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
479  {OUString(SC_UNONAME_SIZE), SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
494  { OUString(), 0, css::uno::Type(), 0, 0 }
495  };
496  static SfxItemPropertySet aCellPropertySet( aCellPropertyMap_Impl );
497  return &aCellPropertySet;
498 }
499 
500 // Column and Row contain all entries from CellRange, plus its own entries
501 // with Which-ID 0 (those are needed only for getPropertySetInfo).
502 
504 {
505  static const SfxItemPropertyMapEntry aColumnPropertyMap_Impl[] =
506  {
507  {OUString(SC_UNONAME_ABSNAME), SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
589  {OUString(SC_UNONAME_POS), SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
596  {OUString(SC_UNONAME_SIZE), SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
609  { OUString(), 0, css::uno::Type(), 0, 0 }
610  };
611  static SfxItemPropertySet aColumnPropertySet( aColumnPropertyMap_Impl );
612  return &aColumnPropertySet;
613 }
614 
616 {
617  static const SfxItemPropertyMapEntry aRowPropertyMap_Impl[] =
618  {
619  {OUString(SC_UNONAME_ABSNAME), SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
703  {OUString(SC_UNONAME_POS), SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
710  {OUString(SC_UNONAME_SIZE), SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
722  { OUString(), 0, css::uno::Type(), 0, 0 }
723  };
724  static SfxItemPropertySet aRowPropertySet( aRowPropertyMap_Impl );
725  return &aRowPropertySet;
726 }
727 
729 {
730  static const SfxItemPropertyMapEntry aSheetPropertyMap_Impl[] =
731  {
732  {OUString(SC_UNONAME_ABSNAME), SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
803  {OUString(SC_UNO_LINKDISPBIT), SC_WID_UNO_LINKDISPBIT,cppu::UnoType<awt::XBitmap>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
804  {OUString(SC_UNO_LINKDISPNAME), SC_WID_UNO_LINKDISPNAME,cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
820  {OUString(SC_UNONAME_POS), SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
830  {OUString(SC_UNONAME_SIZE), SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
847  { OUString(), 0, css::uno::Type(), 0, 0 }
848  };
849  static SfxItemPropertySet aSheetPropertySet( aSheetPropertyMap_Impl );
850  return &aSheetPropertySet;
851 }
852 
854 {
855  static const SfxItemPropertyMapEntry aEditPropertyMap_Impl[] =
856  {
860  SVX_UNOEDIT_NUMBERING_PROPERTIE, // for completeness of service ParagraphProperties
863  { OUString(), 0, css::uno::Type(), 0, 0 }
864  };
865  return aEditPropertyMap_Impl;
866 }
868 {
870  return &aEditPropertySet;
871 }
872 
873 using sc::HMMToTwips;
874 using sc::TwipsToHMM;
875 
876 #define SCCHARPROPERTIES_SERVICE "com.sun.star.style.CharacterProperties"
877 #define SCPARAPROPERTIES_SERVICE "com.sun.star.style.ParagraphProperties"
878 #define SCCELLPROPERTIES_SERVICE "com.sun.star.table.CellProperties"
879 #define SCCELLRANGE_SERVICE "com.sun.star.table.CellRange"
880 #define SCCELL_SERVICE "com.sun.star.table.Cell"
881 #define SCSHEETCELLRANGES_SERVICE "com.sun.star.sheet.SheetCellRanges"
882 #define SCSHEETCELLRANGE_SERVICE "com.sun.star.sheet.SheetCellRange"
883 #define SCSPREADSHEET_SERVICE "com.sun.star.sheet.Spreadsheet"
884 #define SCSHEETCELL_SERVICE "com.sun.star.sheet.SheetCell"
885 
886 SC_SIMPLE_SERVICE_INFO( ScCellFormatsEnumeration, "ScCellFormatsEnumeration", "com.sun.star.sheet.CellFormatRangesEnumeration" )
887 SC_SIMPLE_SERVICE_INFO( ScCellFormatsObj, "ScCellFormatsObj", "com.sun.star.sheet.CellFormatRanges" )
888 SC_SIMPLE_SERVICE_INFO( ScUniqueCellFormatsEnumeration, "ScUniqueCellFormatsEnumeration", "com.sun.star.sheet.UniqueCellFormatRangesEnumeration" )
889 SC_SIMPLE_SERVICE_INFO( ScUniqueCellFormatsObj, "ScUniqueCellFormatsObj", "com.sun.star.sheet.UniqueCellFormatRanges" )
890 SC_SIMPLE_SERVICE_INFO( ScCellRangesBase, "ScCellRangesBase", "stardiv.unknown" )
891 SC_SIMPLE_SERVICE_INFO( ScCellsEnumeration, "ScCellsEnumeration", "com.sun.star.sheet.CellsEnumeration" )
892 SC_SIMPLE_SERVICE_INFO( ScCellsObj, "ScCellsObj", "com.sun.star.sheet.Cells" )
893 SC_SIMPLE_SERVICE_INFO( ScTableColumnObj, "ScTableColumnObj", "com.sun.star.table.TableColumn" )
894 SC_SIMPLE_SERVICE_INFO( ScTableRowObj, "ScTableRowObj", "com.sun.star.table.TableRow" )
895 
897 
899 {
900 }
901 
902 void ScLinkListener::Notify( const SfxHint& rHint )
903 {
904  aLink.Call( rHint );
905 }
906 
908 {
909  uno::Reference<beans::XPropertySetInfo> xInfo(rSource.getPropertySetInfo());
910  if (xInfo.is())
911  {
912  const uno::Sequence<beans::Property> aSeq(xInfo->getProperties());
913  for (const beans::Property& rProp : aSeq)
914  {
915  OUString aName(rProp.Name);
916  rDest.setPropertyValue( aName, rSource.getPropertyValue( aName ) );
917  }
918  }
919 }
920 
921 static SCTAB lcl_FirstTab( const ScRangeList& rRanges )
922 {
923  if (rRanges.empty())
924  throw std::out_of_range("empty range");
925  const ScRange & rFirst = rRanges[0];
926  return rFirst.aStart.Tab();
927 }
928 
929 static bool lcl_WholeSheet( const ScDocument* pDoc, const ScRangeList& rRanges )
930 {
931  if ( rRanges.size() == 1 )
932  {
933  const ScRange & rRange = rRanges[0];
934  if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == pDoc->MaxCol() &&
935  rRange.aStart.Row() == 0 && rRange.aEnd.Row() == pDoc->MaxRow() )
936  return true;
937  }
938  return false;
939 }
940 
941 namespace {
942 template<typename BorderLineType>
943 const ::editeng::SvxBorderLine* lcl_getBorderLine(
944  ::editeng::SvxBorderLine& rLine, const BorderLineType& rStruct )
945 {
946  // Convert from 1/100mm to Twips.
947  if (!SvxBoxItem::LineToSvxLine( rStruct, rLine, true))
948  return nullptr;
949 
950  if ( rLine.GetOutWidth() || rLine.GetInWidth() || rLine.GetDistance() )
951  return &rLine;
952  else
953  return nullptr;
954 }
955 }
956 
957 const ::editeng::SvxBorderLine* ScHelperFunctions::GetBorderLine(
958  ::editeng::SvxBorderLine& rLine, const table::BorderLine& rStruct )
959 {
960  return lcl_getBorderLine( rLine, rStruct);
961 }
962 
963 const ::editeng::SvxBorderLine* ScHelperFunctions::GetBorderLine(
964  ::editeng::SvxBorderLine& rLine, const table::BorderLine2& rStruct )
965 {
966  return lcl_getBorderLine( rLine, rStruct);
967 }
968 
969 namespace {
970 template<typename TableBorderType>
971 void lcl_fillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const TableBorderType& rBorder )
972 {
974  rOuter.SetAllDistances(static_cast<sal_uInt16>(HMMToTwips(rBorder.Distance)));
975  rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.TopLine ), SvxBoxItemLine::TOP );
976  rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.BottomLine ), SvxBoxItemLine::BOTTOM );
977  rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.LeftLine ), SvxBoxItemLine::LEFT );
978  rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.RightLine ), SvxBoxItemLine::RIGHT );
979  rInner.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.HorizontalLine ), SvxBoxInfoItemLine::HORI );
980  rInner.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.VerticalLine ), SvxBoxInfoItemLine::VERT );
981  rInner.SetValid( SvxBoxInfoItemValidFlags::TOP, rBorder.IsTopLineValid );
982  rInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, rBorder.IsBottomLineValid );
983  rInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, rBorder.IsLeftLineValid );
984  rInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, rBorder.IsRightLineValid );
985  rInner.SetValid( SvxBoxInfoItemValidFlags::HORI, rBorder.IsHorizontalLineValid );
986  rInner.SetValid( SvxBoxInfoItemValidFlags::VERT, rBorder.IsVerticalLineValid );
987  rInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE, rBorder.IsDistanceValid );
988  rInner.SetTable( true );
989 }
990 }
991 
992 void ScHelperFunctions::FillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const table::TableBorder& rBorder )
993 {
994  lcl_fillBoxItems( rOuter, rInner, rBorder);
995 }
996 
997 void ScHelperFunctions::FillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const table::TableBorder2& rBorder )
998 {
999  lcl_fillBoxItems( rOuter, rInner, rBorder);
1000 }
1001 
1002 void ScHelperFunctions::FillBorderLine( table::BorderLine& rStruct, const ::editeng::SvxBorderLine* pLine )
1003 {
1004  // Convert from Twips to 1/100mm.
1005  table::BorderLine2 aStruct( SvxBoxItem::SvxLineToLine( pLine, true));
1006  rStruct = aStruct;
1007 }
1008 
1009 void ScHelperFunctions::FillBorderLine( table::BorderLine2& rStruct, const ::editeng::SvxBorderLine* pLine )
1010 {
1011  rStruct = SvxBoxItem::SvxLineToLine( pLine, true);
1012 }
1013 
1014 namespace {
1015 template<typename TableBorderItem>
1016 void lcl_fillTableBorder( TableBorderItem& rBorder, const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner,
1017  bool bInvalidateHorVerDist )
1018 {
1019  ScHelperFunctions::FillBorderLine( rBorder.TopLine, rOuter.GetTop() );
1020  ScHelperFunctions::FillBorderLine( rBorder.BottomLine, rOuter.GetBottom() );
1021  ScHelperFunctions::FillBorderLine( rBorder.LeftLine, rOuter.GetLeft() );
1022  ScHelperFunctions::FillBorderLine( rBorder.RightLine, rOuter.GetRight() );
1023  ScHelperFunctions::FillBorderLine( rBorder.HorizontalLine, rInner.GetHori() );
1024  ScHelperFunctions::FillBorderLine( rBorder.VerticalLine, rInner.GetVert() );
1025 
1026  rBorder.Distance = rOuter.GetSmallestDistance();
1027  rBorder.IsTopLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::TOP);
1028  rBorder.IsBottomLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
1029  rBorder.IsLeftLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::LEFT);
1030  rBorder.IsRightLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::RIGHT);
1031  rBorder.IsHorizontalLineValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::HORI);
1032  rBorder.IsVerticalLineValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::VERT);
1033  rBorder.IsDistanceValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
1034 }
1035 }
1036 
1038  const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner, bool bInvalidateHorVerDist )
1039 {
1040  table::TableBorder aBorder;
1041  lcl_fillTableBorder( aBorder, rOuter, rInner, bInvalidateHorVerDist);
1042  rAny <<= aBorder;
1043 }
1044 
1046  const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner, bool bInvalidateHorVerDist )
1047 {
1048  table::TableBorder2 aBorder;
1049  lcl_fillTableBorder( aBorder, rOuter, rInner, bInvalidateHorVerDist);
1050  rAny <<= aBorder;
1051 }
1052 
1054 
1055 void ScHelperFunctions::ApplyBorder( ScDocShell* pDocShell, const ScRangeList& rRanges,
1056  const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner )
1057 {
1058  ScDocument& rDoc = pDocShell->GetDocument();
1059  bool bUndo(rDoc.IsUndoEnabled());
1060  ScDocumentUniquePtr pUndoDoc;
1061  if (bUndo)
1062  pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1063  size_t nCount = rRanges.size();
1064  for (size_t i = 0; i < nCount; ++i)
1065  {
1066  ScRange const & rRange = rRanges[ i ];
1067  SCTAB nTab = rRange.aStart.Tab();
1068 
1069  if (bUndo)
1070  {
1071  if ( i==0 )
1072  pUndoDoc->InitUndo( &rDoc, nTab, nTab );
1073  else
1074  pUndoDoc->AddUndoTab( nTab, nTab );
1075  rDoc.CopyToDocument(rRange, InsertDeleteFlags::ATTRIB, false, *pUndoDoc);
1076  }
1077 
1078  ScMarkData aMark(rDoc.GetSheetLimits());
1079  aMark.SetMarkArea( rRange );
1080  aMark.SelectTable( nTab, true );
1081 
1082  rDoc.ApplySelectionFrame(aMark, rOuter, &rInner);
1083  // don't need RowHeight if there is only a border
1084  }
1085 
1086  if (bUndo)
1087  {
1088  pDocShell->GetUndoManager()->AddUndoAction(
1089  std::make_unique<ScUndoBorder>( pDocShell, rRanges, std::move(pUndoDoc), rOuter, rInner ) );
1090  }
1091 
1092  for (size_t i = 0; i < nCount; ++i )
1093  pDocShell->PostPaint( rRanges[ i ], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
1094 
1095  pDocShell->SetDocumentModified();
1096 }
1097 
1100 
1101 static bool lcl_PutDataArray( ScDocShell& rDocShell, const ScRange& rRange,
1102  const uno::Sequence< uno::Sequence<uno::Any> >& aData )
1103 {
1104  ScDocument& rDoc = rDocShell.GetDocument();
1105  SCTAB nTab = rRange.aStart.Tab();
1106  SCCOL nStartCol = rRange.aStart.Col();
1107  SCROW nStartRow = rRange.aStart.Row();
1108  SCCOL nEndCol = rRange.aEnd.Col();
1109  SCROW nEndRow = rRange.aEnd.Row();
1110  bool bUndo(rDoc.IsUndoEnabled());
1111 
1112  if ( !rDoc.IsBlockEditable( nTab, nStartCol,nStartRow, nEndCol,nEndRow ) )
1113  {
1115  return false;
1116  }
1117 
1118  long nCols = 0;
1119  long nRows = aData.getLength();
1120  if ( nRows )
1121  nCols = aData[0].getLength();
1122 
1123  if ( nCols != nEndCol-nStartCol+1 || nRows != nEndRow-nStartRow+1 )
1124  {
1126  return false;
1127  }
1128 
1129  ScDocumentUniquePtr pUndoDoc;
1130  if ( bUndo )
1131  {
1132  pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1133  pUndoDoc->InitUndo( &rDoc, nTab, nTab );
1135  }
1136 
1137  rDoc.DeleteAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
1138 
1139  bool bError = false;
1140  SCROW nDocRow = nStartRow;
1141  for (const uno::Sequence<uno::Any>& rColSeq : aData)
1142  {
1143  if ( rColSeq.getLength() == nCols )
1144  {
1145  SCCOL nDocCol = nStartCol;
1146  for (const uno::Any& rElement : rColSeq)
1147  {
1148  ScAddress aPos(nDocCol, nDocRow, nTab);
1149 
1150  switch( rElement.getValueTypeClass() )
1151  {
1152  case uno::TypeClass_VOID:
1153  {
1154  // void = "no value"
1155  rDoc.SetError( nDocCol, nDocRow, nTab, FormulaError::NotAvailable );
1156  }
1157  break;
1158 
1159  // #87871# accept integer types because Basic passes a floating point
1160  // variable as byte, short or long if it's an integer number.
1161  case uno::TypeClass_BYTE:
1162  case uno::TypeClass_SHORT:
1163  case uno::TypeClass_UNSIGNED_SHORT:
1164  case uno::TypeClass_LONG:
1165  case uno::TypeClass_UNSIGNED_LONG:
1166  case uno::TypeClass_FLOAT:
1167  case uno::TypeClass_DOUBLE:
1168  {
1169  double fVal(0.0);
1170  rElement >>= fVal;
1171  rDoc.SetValue(aPos, fVal);
1172  }
1173  break;
1174 
1175  case uno::TypeClass_STRING:
1176  {
1177  OUString aUStr;
1178  rElement >>= aUStr;
1179  if ( !aUStr.isEmpty() )
1180  {
1181  ScSetStringParam aParam;
1182  aParam.setTextInput();
1183  rDoc.SetString(aPos, aUStr, &aParam);
1184  }
1185  }
1186  break;
1187 
1188  // accept Sequence<FormulaToken> for formula cells
1189  case uno::TypeClass_SEQUENCE:
1190  {
1191  uno::Sequence< sheet::FormulaToken > aTokens;
1192  if ( rElement >>= aTokens )
1193  {
1194  ScTokenArray aTokenArray(&rDoc);
1195  ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, aTokens );
1196  rDoc.SetFormula(aPos, aTokenArray);
1197  }
1198  else
1199  bError = true;
1200  }
1201  break;
1202 
1203  default:
1204  bError = true; // invalid type
1205  }
1206  ++nDocCol;
1207  }
1208  }
1209  else
1210  bError = true; // wrong size
1211 
1212  ++nDocRow;
1213  }
1214 
1215  bool bHeight = rDocShell.AdjustRowHeight( nStartRow, nEndRow, nTab );
1216 
1217  if ( pUndoDoc )
1218  {
1219  ScMarkData aDestMark(rDoc.GetSheetLimits());
1220  aDestMark.SelectOneTable( nTab );
1221  rDocShell.GetUndoManager()->AddUndoAction(
1222  std::make_unique<ScUndoPaste>(
1223  &rDocShell, ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab),
1224  aDestMark, std::move(pUndoDoc), nullptr, InsertDeleteFlags::CONTENTS, nullptr, false));
1225  }
1226 
1227  if (!bHeight)
1228  rDocShell.PostPaint( rRange, PaintPartFlags::Grid ); // AdjustRowHeight may have painted already
1229 
1230  rDocShell.SetDocumentModified();
1231 
1232  return !bError;
1233 }
1234 
1235 static bool lcl_PutFormulaArray( ScDocShell& rDocShell, const ScRange& rRange,
1236  const uno::Sequence< uno::Sequence<OUString> >& aData,
1237  const formula::FormulaGrammar::Grammar eGrammar )
1238 {
1239  ScDocument& rDoc = rDocShell.GetDocument();
1240  SCTAB nTab = rRange.aStart.Tab();
1241  SCCOL nStartCol = rRange.aStart.Col();
1242  SCROW nStartRow = rRange.aStart.Row();
1243  SCCOL nEndCol = rRange.aEnd.Col();
1244  SCROW nEndRow = rRange.aEnd.Row();
1245  bool bUndo(rDoc.IsUndoEnabled());
1246 
1247  if ( !rDoc.IsBlockEditable( nTab, nStartCol,nStartRow, nEndCol,nEndRow ) )
1248  {
1250  return false;
1251  }
1252 
1253  long nCols = 0;
1254  long nRows = aData.getLength();
1255  if ( nRows )
1256  nCols = aData[0].getLength();
1257 
1258  if ( nCols != nEndCol-nStartCol+1 || nRows != nEndRow-nStartRow+1 )
1259  {
1261  return false;
1262  }
1263 
1264  ScDocumentUniquePtr pUndoDoc;
1265  if ( bUndo )
1266  {
1267  pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1268  pUndoDoc->InitUndo( &rDoc, nTab, nTab );
1269  rDoc.CopyToDocument(rRange, InsertDeleteFlags::CONTENTS, false, *pUndoDoc);
1270  }
1271 
1272  rDoc.DeleteAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
1273 
1274  bool bError = false;
1275  SCROW nDocRow = nStartRow;
1276  for (const uno::Sequence<OUString>& rColSeq : aData)
1277  {
1278  if ( rColSeq.getLength() == nCols )
1279  {
1280  SCCOL nDocCol = nStartCol;
1281  for (const OUString& aText : rColSeq)
1282  {
1283  ScAddress aPos( nDocCol, nDocRow, nTab );
1284 
1285  ScInputStringType aRes =
1287  *rDoc.GetFormatTable(), aText, LANGUAGE_ENGLISH_US);
1288  switch (aRes.meType)
1289  {
1291  rDoc.SetFormula(aPos, aRes.maText, eGrammar);
1292  break;
1294  rDoc.SetValue(aPos, aRes.mfValue);
1295  break;
1297  rDoc.SetTextCell(aPos, aRes.maText);
1298  break;
1299  default:
1300  ;
1301  }
1302 
1303  ++nDocCol;
1304  }
1305  }
1306  else
1307  bError = true; // wrong size
1308 
1309  ++nDocRow;
1310  }
1311 
1312  bool bHeight = rDocShell.AdjustRowHeight( nStartRow, nEndRow, nTab );
1313 
1314  if ( pUndoDoc )
1315  {
1316  ScMarkData aDestMark(rDoc.GetSheetLimits());
1317  aDestMark.SelectOneTable( nTab );
1318  rDocShell.GetUndoManager()->AddUndoAction(
1319  std::make_unique<ScUndoPaste>( &rDocShell,
1320  ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab), aDestMark,
1321  std::move(pUndoDoc), nullptr, InsertDeleteFlags::CONTENTS, nullptr, false));
1322  }
1323 
1324  if (!bHeight)
1325  rDocShell.PostPaint( rRange, PaintPartFlags::Grid ); // AdjustRowHeight may have painted already
1326 
1327  rDocShell.SetDocumentModified();
1328 
1329  return !bError;
1330 }
1331 
1332 // used in ScCellRangeObj::getFormulaArray and ScCellObj::GetInputString_Impl
1333 static OUString lcl_GetInputString( ScDocument& rDoc, const ScAddress& rPos, bool bEnglish )
1334 {
1335  ScRefCellValue aCell(rDoc, rPos);
1336  if (aCell.isEmpty())
1337  return EMPTY_OUSTRING;
1338 
1339  OUString aVal;
1340 
1341  CellType eType = aCell.meType;
1342  if (eType == CELLTYPE_FORMULA)
1343  {
1344  ScFormulaCell* pForm = aCell.mpFormula;
1345  pForm->GetFormula( aVal, formula::FormulaGrammar::mapAPItoGrammar( bEnglish, false));
1346  return aVal;
1347  }
1348 
1349  SvNumberFormatter* pFormatter = bEnglish ? ScGlobal::GetEnglishFormatter() :
1350  rDoc.GetFormatTable();
1351  // Since the English formatter was constructed with
1352  // LANGUAGE_ENGLISH_US the "General" format has index key 0,
1353  // we don't have to query.
1354  sal_uInt32 nNumFmt = bEnglish ? 0 : rDoc.GetNumberFormat(rPos);
1355 
1356  if (eType == CELLTYPE_EDIT)
1357  {
1358  // GetString on EditCell turns breaks into spaces,
1359  // but we need the breaks here
1360  const EditTextObject* pData = aCell.mpEditText;
1361  if (pData)
1362  {
1363  EditEngine& rEngine = rDoc.GetEditEngine();
1364  rEngine.SetText(*pData);
1365  aVal = rEngine.GetText();
1366  }
1367  }
1368  else
1369  ScCellFormat::GetInputString(aCell, nNumFmt, aVal, *pFormatter, &rDoc);
1370 
1371  // if applicable, prepend ' like in ScTabViewShell::UpdateInputHandler
1372  if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
1373  {
1374  double fDummy;
1375  OUString aTempString = aVal;
1376  bool bIsNumberFormat(pFormatter->IsNumberFormat(aTempString, nNumFmt, fDummy));
1377  if ( bIsNumberFormat )
1378  aTempString = "'" + aTempString;
1379  else if ( aTempString.startsWith("'") )
1380  {
1381  // if the string starts with a "'", add another one because setFormula
1382  // strips one (like text input, except for "text" number formats)
1383  if ( bEnglish || ( pFormatter->GetType(nNumFmt) != SvNumFormatType::TEXT ) )
1384  aTempString = "'" + aTempString;
1385  }
1386  aVal = aTempString;
1387  }
1388  return aVal;
1389 }
1390 
1392  pPropSet(lcl_GetCellsPropertySet()),
1393  pDocShell( pDocSh ),
1394  nObjectId( 0 ),
1395  bChartColAsHdr( false ),
1396  bChartRowAsHdr( false ),
1397  bCursorOnly( false ),
1398  bGotDataChangedHint( false ),
1399  aValueListeners( 0 )
1400 {
1401  // this is a hack to get m_wThis initialized; ideally there would be
1402  // factory functions doing this but there are so many subclasses of this...
1403  osl_atomic_increment(&m_refCount);
1404  {
1405  m_wThis = uno::Reference<uno::XInterface>(
1406  static_cast<cppu::OWeakObject*>(this));
1407  }
1408  osl_atomic_decrement(&m_refCount);
1409 
1410  ScRange aCellRange(rR);
1411  aCellRange.PutInOrder();
1412  aRanges.push_back( aCellRange );
1413 
1414  if (pDocShell) // Null if created with createInstance
1415  {
1416  ScDocument& rDoc = pDocShell->GetDocument();
1417  rDoc.AddUnoObject(*this);
1418  nObjectId = rDoc.GetNewUnoId();
1419  }
1420 }
1421 
1423  pPropSet(lcl_GetCellsPropertySet()),
1424  pDocShell( pDocSh ),
1425  aRanges( rR ),
1426  nObjectId( 0 ),
1427  bChartColAsHdr( false ),
1428  bChartRowAsHdr( false ),
1429  bCursorOnly( false ),
1430  bGotDataChangedHint( false ),
1431  aValueListeners( 0 )
1432 {
1433  // this is a hack to get m_wThis initialized; ideally there would be
1434  // factory functions doing this but there are so many subclasses of this...
1435  osl_atomic_increment(&m_refCount);
1436  {
1437  m_wThis = uno::Reference<uno::XInterface>(
1438  static_cast<cppu::OWeakObject*>(this));
1439  }
1440  osl_atomic_decrement(&m_refCount);
1441 
1442  if (pDocShell) // Null if created with createInstance
1443  {
1444  ScDocument& rDoc = pDocShell->GetDocument();
1445  rDoc.AddUnoObject(*this);
1446  nObjectId = rDoc.GetNewUnoId();
1447  }
1448 }
1449 
1451 {
1452  SolarMutexGuard g;
1453 
1454  // call RemoveUnoObject first, so no notification can happen
1455  // during ForgetCurrentAttrs
1456 
1457  if (pDocShell)
1459 
1461  ForgetMarkData();
1462 
1463  pValueListener.reset();
1464 
1467 }
1468 
1470 {
1471  pCurrentFlat.reset();
1472  pCurrentDeep.reset();
1473  pCurrentDataSet.reset();
1474  pNoDfltCurrentDataSet.reset();
1475  pCurrentDataSet = nullptr;
1476  pNoDfltCurrentDataSet = nullptr;
1477 
1478  // #i62483# pMarkData can remain unchanged, is deleted only if the range changes (RefChanged)
1479 }
1480 
1482 {
1483  pMarkData.reset();
1484 }
1485 
1487 {
1488  // get and cache direct cell attributes for this object's range
1489 
1490  if ( !pCurrentFlat && pDocShell )
1491  {
1492  ScDocument& rDoc = pDocShell->GetDocument();
1493  pCurrentFlat = rDoc.CreateSelectionPattern( *GetMarkData(), false );
1494  }
1495  return pCurrentFlat.get();
1496 }
1497 
1499 {
1500  // get and cache cell attributes (incl. styles) for this object's range
1501 
1502  if ( !pCurrentDeep && pDocShell )
1503  {
1504  ScDocument& rDoc = pDocShell->GetDocument();
1506  }
1507  return pCurrentDeep.get();
1508 }
1509 
1511 {
1512  if(!pCurrentDataSet)
1513  {
1514  const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
1515  if ( pPattern )
1516  {
1517  // replace Dontcare with Default, so that we always have a reflection
1518  pCurrentDataSet.reset( new SfxItemSet( pPattern->GetItemSet() ) );
1519  pNoDfltCurrentDataSet.reset( new SfxItemSet( pPattern->GetItemSet() ) );
1520  pCurrentDataSet->ClearInvalidItems();
1521  }
1522  }
1523  return bNoDflt ? pNoDfltCurrentDataSet.get() : pCurrentDataSet.get();
1524 }
1525 
1527 {
1528  if (!pMarkData)
1529  {
1530  pMarkData.reset( new ScMarkData(GetDocument()->GetSheetLimits(), aRanges) );
1531  }
1532  return pMarkData.get();
1533 }
1534 
1536 {
1537  uno::Reference<uno::XInterface> const xThis(m_wThis);
1538  if (!xThis.is())
1539  { // fdo#72695: if UNO object is already dead, don't revive it with event
1540  if (SfxHintId::Dying == rHint.GetId())
1541  { // if the document dies, must reset to avoid crash in dtor!
1543  pDocShell = nullptr;
1544  }
1545  return;
1546  }
1547  if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
1548  {
1549  const ScUpdateRefHint& rRef = static_cast<const ScUpdateRefHint&>(rHint);
1550 
1551  ScDocument& rDoc = pDocShell->GetDocument();
1552  std::unique_ptr<ScRangeList> pUndoRanges;
1553  if ( rDoc.HasUnoRefUndo() )
1554  pUndoRanges.reset(new ScRangeList( aRanges ));
1555 
1556  if ( aRanges.UpdateReference( rRef.GetMode(), &rDoc, rRef.GetRange(),
1557  rRef.GetDx(), rRef.GetDy(), rRef.GetDz() ) )
1558  {
1559  if ( rRef.GetMode() == URM_INSDEL
1560  && aRanges.size() == 1
1561  && comphelper::getUnoTunnelImplementation<ScTableSheetObj>(xThis)
1562  )
1563  {
1564  // #101755#; the range size of a sheet does not change
1565  ScRange & rR = aRanges.front();
1566  rR.aStart.SetCol(0);
1567  rR.aStart.SetRow(0);
1568  rR.aEnd.SetCol(rDoc.MaxCol());
1569  rR.aEnd.SetRow(rDoc.MaxRow());
1570  }
1571  RefChanged();
1572 
1573  // any change of the range address is broadcast to value (modify) listeners
1574  if ( !aValueListeners.empty() )
1575  bGotDataChangedHint = true;
1576 
1577  if ( pUndoRanges )
1578  rDoc.AddUnoRefChange( nObjectId, *pUndoRanges );
1579  }
1580  }
1581  else if ( dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
1582  {
1583  const ScUnoRefUndoHint& rUndoHint = static_cast<const ScUnoRefUndoHint&>(rHint);
1584  if ( rUndoHint.GetObjectId() == nObjectId )
1585  {
1586  // restore ranges from hint
1587 
1588  aRanges = rUndoHint.GetRanges();
1589 
1590  RefChanged();
1591  if ( !aValueListeners.empty() )
1592  bGotDataChangedHint = true; // need to broadcast the undo, too
1593  }
1594  }
1595  else
1596  {
1597  const SfxHintId nId = rHint.GetId();
1598  if ( nId == SfxHintId::Dying )
1599  {
1601  pDocShell = nullptr; // invalid
1602 
1603  if ( !aValueListeners.empty() )
1604  {
1605  // dispose listeners
1606 
1607  lang::EventObject aEvent;
1608  aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
1609  for (uno::Reference<util::XModifyListener> & xValueListener : aValueListeners)
1610  xValueListener->disposing( aEvent );
1611 
1612  aValueListeners.clear();
1613 
1614  // The listeners can't have the last ref to this, as it's still held
1615  // by the DocShell.
1616  }
1617  }
1618  else if ( nId == SfxHintId::DataChanged )
1619  {
1620  // document content changed -> forget cached attributes
1622 
1623  if ( bGotDataChangedHint && pDocShell )
1624  {
1625  // This object was notified of content changes, so one call
1626  // for each listener is generated now.
1627  // The calls can't be executed directly because the document's
1628  // UNO broadcaster list must not be modified.
1629  // Instead, add to the document's list of listener calls,
1630  // which will be executed directly after the broadcast of
1631  // SfxHintId::DataChanged.
1632 
1633  lang::EventObject aEvent;
1634  aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
1635 
1636  // the EventObject holds a Ref to this object until after the listener calls
1637 
1638  ScDocument& rDoc = pDocShell->GetDocument();
1639  for (const uno::Reference<util::XModifyListener> & xValueListener : aValueListeners)
1640  rDoc.AddUnoListenerCall( xValueListener, aEvent );
1641 
1642  bGotDataChangedHint = false;
1643  }
1644  }
1645  else if ( nId == SfxHintId::ScCalcAll )
1646  {
1647  // broadcast from DoHardRecalc - set bGotDataChangedHint
1648  // (SfxHintId::DataChanged follows separately)
1649 
1650  if ( !aValueListeners.empty() )
1651  bGotDataChangedHint = true;
1652  }
1653  }
1654 }
1655 
1657 {
1659 
1660  if ( pValueListener && !aValueListeners.empty() )
1661  {
1662  pValueListener->EndListeningAll();
1663 
1664  ScDocument& rDoc = pDocShell->GetDocument();
1665  for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
1666  rDoc.StartListeningArea( aRanges[ i ], false, pValueListener.get() );
1667  }
1668 
1670  ForgetMarkData();
1671 }
1672 
1674 {
1675  if (pDocShell)
1676  return &pDocShell->GetDocument();
1677  else
1678  return nullptr;
1679 }
1680 
1682 {
1683  if ( !pDocShell && pDocSh )
1684  {
1685  pDocShell = pDocSh;
1686 
1687  ScRange aCellRange(rR);
1688  aCellRange.PutInOrder();
1689  aRanges.RemoveAll();
1690  aRanges.push_back( aCellRange );
1691 
1693 
1694  RefChanged(); // adjust range in range object
1695  }
1696 }
1697 
1698 void ScCellRangesBase::AddRange(const ScRange& rRange, const bool bMergeRanges)
1699 {
1700  if (bMergeRanges)
1701  aRanges.Join(rRange);
1702  else
1703  aRanges.push_back(rRange);
1704  RefChanged();
1705 }
1706 
1708 {
1709  ScRange aCellRange(rNew);
1710  aCellRange.PutInOrder();
1711 
1712  aRanges.RemoveAll();
1713  aRanges.push_back( aCellRange );
1714  RefChanged();
1715 }
1716 
1718 {
1719  aRanges = rNew;
1720  RefChanged();
1721 }
1722 
1724 {
1725  // set for a selection object that is created from the cursor position
1726  // without anything selected (may contain several sheets)
1727 
1728  bCursorOnly = bSet;
1729 }
1730 
1732 {
1733  for (size_t i = 0, nCount = aRanges.size(); i < nCount; ++i)
1735 }
1736 
1737 // XSheetOperation
1738 
1739 double SAL_CALL ScCellRangesBase::computeFunction( sheet::GeneralFunction nFunction )
1740 {
1741  SolarMutexGuard aGuard;
1742  ScMarkData aMark(*GetMarkData());
1743  aMark.MarkToSimple();
1744  if (!aMark.IsMarked())
1745  aMark.SetMarkNegative(true); // so we can enter dummy position
1746 
1747  ScAddress aDummy; // if not marked, ignored if it is negative
1748  double fVal;
1749  ScSubTotalFunc eFunc = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(nFunction));
1750  ScDocument& rDoc = pDocShell->GetDocument();
1751  if ( !rDoc.GetSelectionFunction( eFunc, aDummy, aMark, fVal ) )
1752  {
1753  throw uno::RuntimeException();
1754  }
1755 
1756  return fVal;
1757 }
1758 
1759 void SAL_CALL ScCellRangesBase::clearContents( sal_Int32 nContentFlags )
1760 {
1761  SolarMutexGuard aGuard;
1762  if ( !aRanges.empty() )
1763  {
1764  // only for clearContents: EDITATTR is only used if no contents are deleted
1765  InsertDeleteFlags nDelFlags = static_cast<InsertDeleteFlags>(nContentFlags) & InsertDeleteFlags::ALL;
1766  if ( ( nDelFlags & InsertDeleteFlags::EDITATTR ) && ( nDelFlags & InsertDeleteFlags::CONTENTS ) == InsertDeleteFlags::NONE )
1767  nDelFlags |= InsertDeleteFlags::EDITATTR;
1768 
1769  pDocShell->GetDocFunc().DeleteContents( *GetMarkData(), nDelFlags, true, true );
1770  }
1771  // otherwise nothing to do
1772 }
1773 
1774 // XPropertyState
1775 
1777 {
1778  return pPropSet->getPropertyMap();
1779 }
1780 
1782  sal_uInt16& rItemWhich )
1783 {
1784  // Which-ID of the affected items also when the item can't handle
1785  // the property by itself
1786  if ( pEntry )
1787  {
1788  if ( IsScItemWid( pEntry->nWID ) )
1789  rItemWhich = pEntry->nWID;
1790  else
1791  switch ( pEntry->nWID )
1792  {
1793  case SC_WID_UNO_TBLBORD:
1794  case SC_WID_UNO_TBLBORD2:
1795  rItemWhich = ATTR_BORDER;
1796  break;
1797  case SC_WID_UNO_CONDFMT:
1798  case SC_WID_UNO_CONDLOC:
1799  case SC_WID_UNO_CONDXML:
1800  rItemWhich = ATTR_CONDITIONAL;
1801  break;
1802  case SC_WID_UNO_VALIDAT:
1803  case SC_WID_UNO_VALILOC:
1804  case SC_WID_UNO_VALIXML:
1805  rItemWhich = ATTR_VALIDDATA;
1806  break;
1807  }
1808  }
1809 
1810 }
1811 
1812 beans::PropertyState ScCellRangesBase::GetOnePropertyState( sal_uInt16 nItemWhich, const SfxItemPropertySimpleEntry* pEntry )
1813 {
1814  beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
1815  if ( nItemWhich ) // item wid (from map or special case)
1816  {
1817  // For items that contain several properties (like background),
1818  // "ambiguous" is returned too often here
1819 
1820  // for PropertyState, don't look at styles
1821  const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
1822  if ( pPattern )
1823  {
1824  SfxItemState eState = pPattern->GetItemSet().GetItemState( nItemWhich, false );
1825 
1826  if ( nItemWhich == ATTR_VALUE_FORMAT && eState == SfxItemState::DEFAULT )
1827  eState = pPattern->GetItemSet().GetItemState( ATTR_LANGUAGE_FORMAT, false );
1828 
1829  if ( eState == SfxItemState::SET )
1830  eRet = beans::PropertyState_DIRECT_VALUE;
1831  else if ( eState == SfxItemState::DEFAULT )
1832  eRet = beans::PropertyState_DEFAULT_VALUE;
1833  else if ( eState == SfxItemState::DONTCARE )
1834  eRet = beans::PropertyState_AMBIGUOUS_VALUE;
1835  else
1836  {
1837  OSL_FAIL("unknown ItemState");
1838  }
1839  }
1840  }
1841  else if ( pEntry )
1842  {
1843  if ( pEntry->nWID == SC_WID_UNO_CHCOLHDR || pEntry->nWID == SC_WID_UNO_CHROWHDR || pEntry->nWID == SC_WID_UNO_ABSNAME )
1844  eRet = beans::PropertyState_DIRECT_VALUE;
1845  else if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
1846  {
1847  // a style is always set, there's no default state
1849  if (pStyle)
1850  eRet = beans::PropertyState_DIRECT_VALUE;
1851  else
1852  eRet = beans::PropertyState_AMBIGUOUS_VALUE;
1853  }
1854  else if ( pEntry->nWID == SC_WID_UNO_NUMRULES )
1855  eRet = beans::PropertyState_DEFAULT_VALUE; // numbering rules are always default
1856  }
1857  return eRet;
1858 }
1859 
1860 beans::PropertyState SAL_CALL ScCellRangesBase::getPropertyState( const OUString& aPropertyName )
1861 {
1862  SolarMutexGuard aGuard;
1863  if ( aRanges.empty() )
1864  throw uno::RuntimeException();
1865 
1866  const SfxItemPropertyMap& rMap = GetItemPropertyMap(); // from derived class
1867  sal_uInt16 nItemWhich = 0;
1868  const SfxItemPropertySimpleEntry* pEntry = rMap.getByName( aPropertyName );
1869  lcl_GetPropertyWhich( pEntry, nItemWhich );
1870  return GetOnePropertyState( nItemWhich, pEntry );
1871 }
1872 
1873 uno::Sequence<beans::PropertyState> SAL_CALL ScCellRangesBase::getPropertyStates(
1874  const uno::Sequence<OUString>& aPropertyNames )
1875 {
1876  SolarMutexGuard aGuard;
1877 
1878  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
1879 
1880  uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
1881  std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.begin(),
1882  [this, &rPropertyMap](const auto& rName) -> beans::PropertyState {
1883  sal_uInt16 nItemWhich = 0;
1884  const SfxItemPropertySimpleEntry* pEntry = rPropertyMap.getByName( rName );
1885  lcl_GetPropertyWhich( pEntry, nItemWhich );
1886  return GetOnePropertyState(nItemWhich, pEntry);
1887  });
1888  return aRet;
1889 }
1890 
1891 void SAL_CALL ScCellRangesBase::setPropertyToDefault( const OUString& aPropertyName )
1892 {
1893  SolarMutexGuard aGuard;
1894  if ( pDocShell )
1895  {
1896  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
1897  sal_uInt16 nItemWhich = 0;
1898  const SfxItemPropertySimpleEntry* pEntry = rPropertyMap.getByName( aPropertyName );
1899  lcl_GetPropertyWhich( pEntry, nItemWhich );
1900  if ( nItemWhich ) // item wid (from map or special case)
1901  {
1902  if ( !aRanges.empty() ) // empty = nothing to do
1903  {
1907 
1908  sal_uInt16 aWIDs[3];
1909  aWIDs[0] = nItemWhich;
1910  if ( nItemWhich == ATTR_VALUE_FORMAT )
1911  {
1912  aWIDs[1] = ATTR_LANGUAGE_FORMAT; // language for number formats
1913  aWIDs[2] = 0;
1914  }
1915  else
1916  aWIDs[1] = 0;
1917  pDocShell->GetDocFunc().ClearItems( *GetMarkData(), aWIDs, true );
1918  }
1919  }
1920  else if ( pEntry )
1921  {
1922  if ( pEntry->nWID == SC_WID_UNO_CHCOLHDR )
1923  bChartColAsHdr = false;
1924  else if ( pEntry->nWID == SC_WID_UNO_CHROWHDR )
1925  bChartRowAsHdr = false;
1926  else if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
1927  {
1928  OUString aStyleName( ScResId( STR_STYLENAME_STANDARD_CELL ) );
1929  pDocShell->GetDocFunc().ApplyStyle( *GetMarkData(), aStyleName, true );
1930  }
1931  }
1932  }
1933 }
1934 
1935 uno::Any SAL_CALL ScCellRangesBase::getPropertyDefault( const OUString& aPropertyName )
1936 {
1938 
1939  SolarMutexGuard aGuard;
1940  uno::Any aAny;
1941 
1942  if ( pDocShell )
1943  {
1944  ScDocument& rDoc = pDocShell->GetDocument();
1945  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
1946  const SfxItemPropertySimpleEntry* pEntry = rPropertyMap.getByName( aPropertyName );
1947  if ( pEntry )
1948  {
1949  if ( IsScItemWid( pEntry->nWID ) )
1950  {
1951  const ScPatternAttr* pPattern = rDoc.GetDefPattern();
1952  if ( pPattern )
1953  {
1954  const SfxItemSet& rSet = pPattern->GetItemSet();
1955 
1956  switch ( pEntry->nWID ) // for item-specific handling
1957  {
1958  case ATTR_VALUE_FORMAT:
1959  // default has no language set
1960  aAny <<= static_cast<sal_Int32>( static_cast<const SfxUInt32Item&>(rSet.Get(pEntry->nWID)).GetValue() );
1961  break;
1962  case ATTR_INDENT:
1963  aAny <<= static_cast<sal_Int16>( TwipsToHMM(static_cast<const ScIndentItem&>(
1964  rSet.Get(pEntry->nWID)).GetValue()) );
1965  break;
1966  default:
1967  pPropSet->getPropertyValue(aPropertyName, rSet, aAny);
1968  }
1969  }
1970  }
1971  else
1972  switch ( pEntry->nWID )
1973  {
1974  case SC_WID_UNO_CHCOLHDR:
1975  case SC_WID_UNO_CHROWHDR:
1976  aAny <<= false;
1977  break;
1978  case SC_WID_UNO_CELLSTYL:
1980  ScResId(STR_STYLENAME_STANDARD_CELL), SfxStyleFamily::Para );
1981  break;
1982  case SC_WID_UNO_TBLBORD:
1983  case SC_WID_UNO_TBLBORD2:
1984  {
1985  const ScPatternAttr* pPattern = rDoc.GetDefPattern();
1986  if ( pPattern )
1987  {
1988  if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
1990  pPattern->GetItem(ATTR_BORDER),
1991  pPattern->GetItem(ATTR_BORDER_INNER) );
1992  else
1994  pPattern->GetItem(ATTR_BORDER),
1995  pPattern->GetItem(ATTR_BORDER_INNER) );
1996  }
1997  }
1998  break;
1999  case SC_WID_UNO_CONDFMT:
2000  case SC_WID_UNO_CONDLOC:
2001  case SC_WID_UNO_CONDXML:
2002  {
2003  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
2004  bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
2005  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2006  rDoc.GetStorageGrammar() :
2007  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2008 
2009  aAny <<= uno::Reference<sheet::XSheetConditionalEntries>(
2010  new ScTableConditionalFormat( &rDoc, 0, aRanges[0].aStart.Tab(), eGrammar ));
2011  }
2012  break;
2013  case SC_WID_UNO_VALIDAT:
2014  case SC_WID_UNO_VALILOC:
2015  case SC_WID_UNO_VALIXML:
2016  {
2017  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
2018  bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
2019  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2020  rDoc.GetStorageGrammar() :
2021  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2022 
2023  aAny <<= uno::Reference<beans::XPropertySet>(
2024  new ScTableValidationObj( &rDoc, 0, eGrammar ));
2025  }
2026  break;
2027  case SC_WID_UNO_NUMRULES:
2028  {
2030  }
2031  break;
2032  }
2033  }
2034  }
2035 
2036  return aAny;
2037 }
2038 
2039 // XPropertySet
2040 
2041 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellRangesBase::getPropertySetInfo()
2042 {
2043  SolarMutexGuard aGuard;
2044  static uno::Reference<beans::XPropertySetInfo> aRef(
2046  return aRef;
2047 }
2048 
2049 static void lcl_SetCellProperty( const SfxItemPropertySimpleEntry& rEntry, const uno::Any& rValue,
2050  ScPatternAttr& rPattern, const ScDocument &rDoc,
2051  sal_uInt16& rFirstItemId, sal_uInt16& rSecondItemId )
2052 {
2053  rFirstItemId = rEntry.nWID;
2054  rSecondItemId = 0;
2055 
2056  SfxItemSet& rSet = rPattern.GetItemSet();
2057  switch ( rEntry.nWID )
2058  {
2059  case ATTR_VALUE_FORMAT:
2060  {
2061  // language for number formats
2062  SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
2063  sal_uLong nOldFormat = rSet.Get( ATTR_VALUE_FORMAT ).GetValue();
2064  LanguageType eOldLang = rSet.Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
2065  nOldFormat = pFormatter->GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
2066 
2067  sal_Int32 nIntVal = 0;
2068  if ( !(rValue >>= nIntVal) )
2069  throw lang::IllegalArgumentException();
2070 
2071  sal_uLong nNewFormat = static_cast<sal_uLong>(nIntVal);
2072  rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
2073 
2074  const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
2075  LanguageType eNewLang =
2076  pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
2077  if ( eNewLang != eOldLang && eNewLang != LANGUAGE_DONTKNOW )
2078  {
2079  rSet.Put( SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
2080 
2081  // if only language is changed,
2082  // don't touch number format attribute
2083  sal_uLong nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
2084  if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
2085  nNewMod <= SV_MAX_COUNT_STANDARD_FORMATS )
2086  {
2087  rFirstItemId = 0; // don't use ATTR_VALUE_FORMAT value
2088  }
2089 
2090  rSecondItemId = ATTR_LANGUAGE_FORMAT;
2091  }
2092 
2093  }
2094  break;
2095  case ATTR_INDENT:
2096  {
2097  sal_Int16 nIntVal = 0;
2098  if ( !(rValue >>= nIntVal) )
2099  throw lang::IllegalArgumentException();
2100 
2101  rSet.Put( ScIndentItem( static_cast<sal_uInt16>(HMMToTwips(nIntVal)) ) );
2102 
2103  }
2104  break;
2105  case ATTR_ROTATE_VALUE:
2106  {
2107  sal_Int32 nRotVal = 0;
2108  if ( !(rValue >>= nRotVal) )
2109  throw lang::IllegalArgumentException();
2110 
2111  // stored value is always between 0 and 360 deg.
2112  nRotVal %= 36000;
2113  if ( nRotVal < 0 )
2114  nRotVal += 36000;
2115 
2116  rSet.Put( ScRotateValueItem( nRotVal ) );
2117 
2118  }
2119  break;
2120  case ATTR_STACKED:
2121  {
2122  table::CellOrientation eOrient;
2123  if( rValue >>= eOrient )
2124  {
2125  switch( eOrient )
2126  {
2127  case table::CellOrientation_STANDARD:
2128  rSet.Put( ScVerticalStackCell( false ) );
2129  break;
2130  case table::CellOrientation_TOPBOTTOM:
2131  rSet.Put( ScVerticalStackCell( false ) );
2132  rSet.Put( ScRotateValueItem( 27000 ) );
2133  rSecondItemId = ATTR_ROTATE_VALUE;
2134  break;
2135  case table::CellOrientation_BOTTOMTOP:
2136  rSet.Put( ScVerticalStackCell( false ) );
2137  rSet.Put( ScRotateValueItem( 9000 ) );
2138  rSecondItemId = ATTR_ROTATE_VALUE;
2139  break;
2140  case table::CellOrientation_STACKED:
2141  rSet.Put( ScVerticalStackCell( true ) );
2142  break;
2143  default:
2144  {
2145  // added to avoid warnings
2146  }
2147  }
2148  }
2149  }
2150  break;
2151  default:
2152  {
2153  lcl_GetCellsPropertySet()->setPropertyValue(rEntry, rValue, rSet);
2154  }
2155  }
2156 }
2157 
2159  const OUString& aPropertyName, const uno::Any& aValue )
2160 {
2161  SolarMutexGuard aGuard;
2162 
2163  if ( !pDocShell || aRanges.empty() )
2164  throw uno::RuntimeException();
2165 
2166  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2167  const SfxItemPropertySimpleEntry* pEntry = rPropertyMap.getByName( aPropertyName );
2168  if ( !pEntry )
2169  throw beans::UnknownPropertyException(aPropertyName);
2170 
2171  SetOnePropertyValue( pEntry, aValue );
2172 }
2173 
2175 {
2176  if ( pEntry )
2177  {
2178  if ( IsScItemWid( pEntry->nWID ) )
2179  {
2180  if ( !aRanges.empty() ) // empty = nothing to do
2181  {
2182  ScDocument& rDoc = pDocShell->GetDocument();
2183 
2184  // For parts of compound items with multiple properties (e.g. background)
2185  // the old item has to be first fetched from the document.
2189  // ClearInvalidItems, so that in any case we have an item with the correct type
2190 
2191  ScPatternAttr aPattern( *GetCurrentAttrsDeep() );
2192  SfxItemSet& rSet = aPattern.GetItemSet();
2193  rSet.ClearInvalidItems();
2194 
2195  sal_uInt16 nFirstItem, nSecondItem;
2196  lcl_SetCellProperty( *pEntry, aValue, aPattern, rDoc, nFirstItem, nSecondItem );
2197 
2198  for (sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++)
2199  if ( nWhich != nFirstItem && nWhich != nSecondItem )
2200  rSet.ClearItem(nWhich);
2201 
2202  pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), aPattern, true );
2203  }
2204  }
2205  else // implemented here
2206  switch ( pEntry->nWID )
2207  {
2208  case EE_CHAR_ESCAPEMENT: // Specifically for xlsx import
2209  {
2210  sal_Int32 nValue = 0;
2211  aValue >>= nValue;
2212  if (nValue)
2213  {
2214  for (size_t i = 0, n = aRanges.size(); i < n; ++i)
2215  {
2216  ScRange const & rRange = aRanges[i];
2217 
2218  /* TODO: Iterate through the range */
2219  ScAddress aAddr = rRange.aStart;
2220  ScDocument& rDoc = pDocShell->GetDocument();
2221  ScRefCellValue aCell(rDoc, aAddr);
2222 
2223  OUString aStr = aCell.getString(&rDoc);
2224  EditEngine aEngine( rDoc.GetEnginePool() );
2225  aEngine.SetEditTextObjectPool(rDoc.GetEditPool());
2226 
2227  /* EE_CHAR_ESCAPEMENT seems to be set on the cell _only_ when
2228  * there are no other attribs for the cell.
2229  * So, it is safe to overwrite the complete attribute set.
2230  * If there is a need - getting CellType and processing
2231  * the attributes could be considered.
2232  */
2233  SfxItemSet aAttr = aEngine.GetEmptyItemSet();
2234  aEngine.SetText(aStr);
2235  if( nValue < 0 ) // Subscript
2236  aAttr.Put( SvxEscapementItem( SvxEscapement::Subscript, EE_CHAR_ESCAPEMENT ) );
2237  else // Superscript
2238  aAttr.Put( SvxEscapementItem( SvxEscapement::Superscript, EE_CHAR_ESCAPEMENT ) );
2239  aEngine.QuickSetAttribs(aAttr, ESelection(0, 0, 0, aStr.getLength()));
2240 
2241  // The cell will own the text object instance.
2242  rDoc.SetEditText(aRanges[0].aStart, aEngine.CreateTextObject());
2243  }
2244  }
2245  }
2246  break;
2247  case SC_WID_UNO_CHCOLHDR:
2248  // chart header flags are set for this object, not stored with document
2250  break;
2251  case SC_WID_UNO_CHROWHDR:
2253  break;
2254  case SC_WID_UNO_CELLSTYL:
2255  {
2256  OUString aStrVal;
2257  aValue >>= aStrVal;
2259  aStrVal, SfxStyleFamily::Para ));
2260  pDocShell->GetDocFunc().ApplyStyle( *GetMarkData(), aString, true );
2261  }
2262  break;
2263  case SC_WID_UNO_TBLBORD:
2264  {
2265  table::TableBorder aBorder;
2266  if ( !aRanges.empty() && ( aValue >>= aBorder ) ) // empty = nothing to do
2267  {
2268  SvxBoxItem aOuter(ATTR_BORDER);
2270  ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder );
2271 
2272  ScHelperFunctions::ApplyBorder( pDocShell, aRanges, aOuter, aInner );
2273  }
2274  }
2275  break;
2276  case SC_WID_UNO_TBLBORD2:
2277  {
2278  table::TableBorder2 aBorder2;
2279  if ( !aRanges.empty() && ( aValue >>= aBorder2 ) ) // empty = nothing to do
2280  {
2281  SvxBoxItem aOuter(ATTR_BORDER);
2283  ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder2 );
2284 
2285  ScHelperFunctions::ApplyBorder( pDocShell, aRanges, aOuter, aInner );
2286  }
2287  }
2288  break;
2289  case SC_WID_UNO_CONDFMT:
2290  case SC_WID_UNO_CONDLOC:
2291  case SC_WID_UNO_CONDXML:
2292  {
2293  uno::Reference<sheet::XSheetConditionalEntries> xInterface(aValue, uno::UNO_QUERY);
2294  if ( !aRanges.empty() && xInterface.is() ) // empty = nothing to do
2295  {
2296  ScTableConditionalFormat* pFormat =
2297  comphelper::getUnoTunnelImplementation<ScTableConditionalFormat>( xInterface );
2298  if (pFormat)
2299  {
2300  ScDocument& rDoc = pDocShell->GetDocument();
2301  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
2302  bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
2303  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2305  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2306 
2307  SCTAB nTab = aRanges.front().aStart.Tab();
2308  // To remove conditional formats for all cells in aRanges we need to:
2309  // Remove conditional format data from cells' attributes
2310  rDoc.RemoveCondFormatData( aRanges, nTab, 0 );
2311  // And also remove ranges from conditional formats list
2312  for (size_t i = 0; i < aRanges.size(); ++i)
2313  {
2314  rDoc.GetCondFormList( aRanges[i].aStart.Tab() )->DeleteArea(
2315  aRanges[i].aStart.Col(), aRanges[i].aStart.Row(),
2316  aRanges[i].aEnd.Col(), aRanges[i].aEnd.Row() );
2317  }
2318 
2319  // Then we can apply new conditional format if there is one
2320  if (pFormat->getCount())
2321  {
2322  auto pNew = std::make_unique<ScConditionalFormat>( 0, &rDoc ); // Index will be set on inserting
2323  pFormat->FillFormat( *pNew, &rDoc, eGrammar );
2324  pNew->SetRange( aRanges );
2325  pDocShell->GetDocFunc().ReplaceConditionalFormat( 0, std::move(pNew), nTab, aRanges );
2326  }
2327 
2328  // and repaint
2329  for (size_t i = 0; i < aRanges.size(); ++i)
2332  }
2333  }
2334  }
2335  break;
2336  case SC_WID_UNO_VALIDAT:
2337  case SC_WID_UNO_VALILOC:
2338  case SC_WID_UNO_VALIXML:
2339  {
2340  uno::Reference<beans::XPropertySet> xInterface(aValue, uno::UNO_QUERY);
2341  if ( !aRanges.empty() && xInterface.is() ) // empty = nothing to do
2342  {
2343  ScTableValidationObj* pValidObj =
2344  comphelper::getUnoTunnelImplementation<ScTableValidationObj>( xInterface );
2345  if (pValidObj)
2346  {
2347  ScDocument& rDoc = pDocShell->GetDocument();
2348  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
2349  bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
2350  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2352  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2353 
2354  std::unique_ptr<ScValidationData> pNewData(
2355  pValidObj->CreateValidationData( &rDoc, eGrammar ));
2356  sal_uLong nIndex = rDoc.AddValidationEntry( *pNewData );
2357  pNewData.reset();
2358 
2359  ScPatternAttr aPattern( rDoc.GetPool() );
2360  aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nIndex ) );
2361  pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), aPattern, true );
2362  }
2363  }
2364  }
2365  break;
2366  // SC_WID_UNO_NUMRULES is ignored...
2367  }
2368  }
2369 }
2370 
2371 uno::Any SAL_CALL ScCellRangesBase::getPropertyValue( const OUString& aPropertyName )
2372 {
2373  SolarMutexGuard aGuard;
2374 
2375  if ( !pDocShell || aRanges.empty() )
2376  throw uno::RuntimeException();
2377 
2378  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2379  const SfxItemPropertySimpleEntry* pEntry = rPropertyMap.getByName( aPropertyName );
2380  if ( !pEntry )
2381  throw beans::UnknownPropertyException(aPropertyName);
2382 
2383  uno::Any aAny;
2384  GetOnePropertyValue( pEntry, aAny );
2385  return aAny;
2386 }
2387 
2389 {
2390  if ( pEntry )
2391  {
2392  if ( IsScItemWid( pEntry->nWID ) )
2393  {
2394  SfxItemSet* pDataSet = GetCurrentDataSet();
2395  if ( pDataSet )
2396  {
2397  switch ( pEntry->nWID ) // for special handling of items
2398  {
2399  case ATTR_VALUE_FORMAT:
2400  {
2401  ScDocument& rDoc = pDocShell->GetDocument();
2402 
2403  sal_uLong nOldFormat =
2404  pDataSet->Get( ATTR_VALUE_FORMAT ).GetValue();
2405  LanguageType eOldLang =
2406  pDataSet->Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
2407  nOldFormat = rDoc.GetFormatTable()->
2408  GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
2409  rAny <<= static_cast<sal_Int32>(nOldFormat);
2410  }
2411  break;
2412  case ATTR_INDENT:
2413  rAny <<= static_cast<sal_Int16>( TwipsToHMM(static_cast<const ScIndentItem&>(
2414  pDataSet->Get(pEntry->nWID)).GetValue()) );
2415  break;
2416  case ATTR_STACKED:
2417  {
2418  sal_Int32 nRot = pDataSet->Get(ATTR_ROTATE_VALUE).GetValue();
2419  bool bStacked = static_cast<const ScVerticalStackCell&>(pDataSet->Get(pEntry->nWID)).GetValue();
2420  SvxOrientationItem( nRot, bStacked, 0 ).QueryValue( rAny );
2421  }
2422  break;
2423  default:
2424  pPropSet->getPropertyValue(*pEntry, *pDataSet, rAny);
2425  }
2426  }
2427  }
2428  else // implemented here
2429  switch ( pEntry->nWID )
2430  {
2431  case SC_WID_UNO_CHCOLHDR:
2432  rAny <<= bChartColAsHdr;
2433  break;
2434  case SC_WID_UNO_CHROWHDR:
2435  rAny <<= bChartRowAsHdr;
2436  break;
2437  case SC_WID_UNO_CELLSTYL:
2438  {
2439  OUString aStyleName;
2441  if (pStyle)
2442  aStyleName = pStyle->GetName();
2444  aStyleName, SfxStyleFamily::Para );
2445  }
2446  break;
2447  case SC_WID_UNO_TBLBORD:
2448  case SC_WID_UNO_TBLBORD2:
2449  {
2451  if ( !aRanges.empty() )
2452  {
2453  const ScRange & rFirst = aRanges[ 0 ];
2454  SvxBoxItem aOuter(ATTR_BORDER);
2456 
2457  ScDocument& rDoc = pDocShell->GetDocument();
2458  ScMarkData aMark(rDoc.GetSheetLimits());
2459  aMark.SetMarkArea( rFirst );
2460  aMark.SelectTable( rFirst.aStart.Tab(), true );
2461  rDoc.GetSelectionFrame( aMark, aOuter, aInner );
2462 
2463  if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
2464  ScHelperFunctions::AssignTableBorder2ToAny( rAny, aOuter, aInner);
2465  else
2466  ScHelperFunctions::AssignTableBorderToAny( rAny, aOuter, aInner);
2467  }
2468  }
2469  break;
2470  case SC_WID_UNO_CONDFMT:
2471  case SC_WID_UNO_CONDLOC:
2472  case SC_WID_UNO_CONDXML:
2473  {
2474  const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
2475  if ( pPattern )
2476  {
2477  ScDocument& rDoc = pDocShell->GetDocument();
2478  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
2479  bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
2480  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2481  rDoc.GetStorageGrammar() :
2482  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2483  const ScCondFormatIndexes& rIndex =
2484  pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
2485  sal_uLong nIndex = 0;
2486  if(!rIndex.empty())
2487  nIndex = rIndex[0];
2488  rAny <<= uno::Reference<sheet::XSheetConditionalEntries>(
2489  new ScTableConditionalFormat( &rDoc, nIndex, aRanges.front().aStart.Tab(), eGrammar ));
2490  }
2491  }
2492  break;
2493  case SC_WID_UNO_VALIDAT:
2494  case SC_WID_UNO_VALILOC:
2495  case SC_WID_UNO_VALIXML:
2496  {
2497  const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
2498  if ( pPattern )
2499  {
2500  ScDocument& rDoc = pDocShell->GetDocument();
2501  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
2502  bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
2503  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2504  rDoc.GetStorageGrammar() :
2505  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2506  sal_uLong nIndex =
2507  pPattern->GetItem(ATTR_VALIDDATA).GetValue();
2508  rAny <<= uno::Reference<beans::XPropertySet>(
2509  new ScTableValidationObj( &rDoc, nIndex, eGrammar ));
2510  }
2511  }
2512  break;
2513  case SC_WID_UNO_NUMRULES:
2514  {
2515  // always return empty numbering rules object
2517  }
2518  break;
2519  case SC_WID_UNO_ABSNAME:
2520  {
2521  OUString sRet;
2523  rAny <<= sRet;
2524  }
2525  break;
2526  case SC_WID_UNO_FORMATID:
2527  {
2528  const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
2529  rAny <<= pPattern->GetKey();
2530  }
2531  break;
2532  }
2533  }
2534 }
2535 
2536 void SAL_CALL ScCellRangesBase::addPropertyChangeListener( const OUString& /* aPropertyName */,
2537  const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
2538 {
2539  SolarMutexGuard aGuard;
2540  if ( aRanges.empty() )
2541  throw uno::RuntimeException();
2542 
2543  OSL_FAIL("not implemented");
2544 }
2545 
2546 void SAL_CALL ScCellRangesBase::removePropertyChangeListener( const OUString& /* aPropertyName */,
2547  const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
2548 {
2549  SolarMutexGuard aGuard;
2550  if ( aRanges.empty() )
2551  throw uno::RuntimeException();
2552 
2553  OSL_FAIL("not implemented");
2554 }
2555 
2556 void SAL_CALL ScCellRangesBase::addVetoableChangeListener( const OUString&,
2557  const uno::Reference<beans::XVetoableChangeListener>&)
2558 {
2559  OSL_FAIL("not implemented");
2560 }
2561 
2562 void SAL_CALL ScCellRangesBase::removeVetoableChangeListener( const OUString&,
2563  const uno::Reference<beans::XVetoableChangeListener>&)
2564 {
2565  OSL_FAIL("not implemented");
2566 }
2567 
2568 // XMultiPropertySet
2569 
2570 void SAL_CALL ScCellRangesBase::setPropertyValues( const uno::Sequence< OUString >& aPropertyNames,
2571  const uno::Sequence< uno::Any >& aValues )
2572 {
2573  SolarMutexGuard aGuard;
2574 
2575  sal_Int32 nCount(aPropertyNames.getLength());
2576  sal_Int32 nValues(aValues.getLength());
2577  if (nCount != nValues)
2578  throw lang::IllegalArgumentException();
2579 
2580  if ( pDocShell && nCount )
2581  {
2582  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2583  const OUString* pNames = aPropertyNames.getConstArray();
2584  const uno::Any* pValues = aValues.getConstArray();
2585 
2586  std::unique_ptr<const SfxItemPropertySimpleEntry*[]> pEntryArray(new const SfxItemPropertySimpleEntry*[nCount]);
2587 
2588  sal_Int32 i;
2589  for(i = 0; i < nCount; i++)
2590  {
2591  // first loop: find all properties in map, but handle only CellStyle
2592  // (CellStyle must be set before any other cell properties)
2593 
2594  const SfxItemPropertySimpleEntry* pEntry = rPropertyMap.getByName( pNames[i] );
2595  pEntryArray[i] = pEntry;
2596  if (pEntry)
2597  {
2598  if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
2599  {
2600  try
2601  {
2602  SetOnePropertyValue( pEntry, pValues[i] );
2603  }
2604  catch ( lang::IllegalArgumentException& )
2605  {
2606  OSL_FAIL("exception when setting cell style"); // not supposed to happen
2607  }
2608  }
2609  }
2610  }
2611 
2612  ScDocument& rDoc = pDocShell->GetDocument();
2613  std::unique_ptr<ScPatternAttr> pOldPattern;
2614  std::unique_ptr<ScPatternAttr> pNewPattern;
2615 
2616  for(i = 0; i < nCount; i++)
2617  {
2618  // second loop: handle other properties
2619 
2620  const SfxItemPropertySimpleEntry* pEntry = pEntryArray[i];
2621  if ( pEntry )
2622  {
2623  if ( IsScItemWid( pEntry->nWID ) ) // can be handled by SfxItemPropertySet
2624  {
2625  if ( !pOldPattern )
2626  {
2627  pOldPattern.reset(new ScPatternAttr( *GetCurrentAttrsDeep() ));
2628  pOldPattern->GetItemSet().ClearInvalidItems();
2629  pNewPattern.reset(new ScPatternAttr( rDoc.GetPool() ));
2630  }
2631 
2632  // collect items in pNewPattern, apply with one call after the loop
2633 
2634  sal_uInt16 nFirstItem, nSecondItem;
2635  lcl_SetCellProperty( *pEntry, pValues[i], *pOldPattern, rDoc, nFirstItem, nSecondItem );
2636 
2637  // put only affected items into new set
2638  if ( nFirstItem )
2639  pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nFirstItem ) );
2640  if ( nSecondItem )
2641  pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nSecondItem ) );
2642  }
2643  else if ( pEntry->nWID != SC_WID_UNO_CELLSTYL ) // CellStyle is handled above
2644  {
2645  // call virtual method to set a single property
2646  SetOnePropertyValue( pEntry, pValues[i] );
2647  }
2648  }
2649  }
2650 
2651  if ( pNewPattern && !aRanges.empty() )
2652  pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), *pNewPattern, true );
2653  }
2654 }
2655 
2656 uno::Sequence<uno::Any> SAL_CALL ScCellRangesBase::getPropertyValues(
2657  const uno::Sequence< OUString >& aPropertyNames )
2658 {
2659  SolarMutexGuard aGuard;
2660 
2661  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2662 
2663  uno::Sequence<uno::Any> aRet(aPropertyNames.getLength());
2664  uno::Any* pProperties = aRet.getArray();
2665  for(sal_Int32 i = 0; i < aPropertyNames.getLength(); i++)
2666  {
2667  const SfxItemPropertySimpleEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
2668  GetOnePropertyValue( pEntry, pProperties[i] );
2669  }
2670  return aRet;
2671 }
2672 
2673 void SAL_CALL ScCellRangesBase::addPropertiesChangeListener( const uno::Sequence< OUString >& /* aPropertyNames */,
2674  const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
2675 {
2676  OSL_FAIL("not implemented");
2677 }
2678 
2679 void SAL_CALL ScCellRangesBase::removePropertiesChangeListener( const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
2680 {
2681  OSL_FAIL("not implemented");
2682 }
2683 
2684 void SAL_CALL ScCellRangesBase::firePropertiesChangeEvent( const uno::Sequence< OUString >& /* aPropertyNames */,
2685  const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
2686 {
2687  OSL_FAIL("not implemented");
2688 }
2689 
2690 IMPL_LINK( ScCellRangesBase, ValueListenerHdl, const SfxHint&, rHint, void )
2691 {
2692  if ( pDocShell && (rHint.GetId() == SfxHintId::ScDataChanged))
2693  {
2694  // This may be called several times for a single change, if several formulas
2695  // in the range are notified. So only a flag is set that is checked when
2696  // SfxHintId::DataChanged is received.
2697 
2698  bGotDataChangedHint = true;
2699  }
2700 }
2701 
2702 // XTolerantMultiPropertySet
2703 uno::Sequence< beans::SetPropertyTolerantFailed > SAL_CALL ScCellRangesBase::setPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames,
2704  const uno::Sequence< uno::Any >& aValues )
2705 {
2706  SolarMutexGuard aGuard;
2707 
2708  sal_Int32 nCount(aPropertyNames.getLength());
2709  sal_Int32 nValues(aValues.getLength());
2710  if (nCount != nValues)
2711  throw lang::IllegalArgumentException();
2712 
2713  if ( pDocShell && nCount )
2714  {
2715  uno::Sequence < beans::SetPropertyTolerantFailed > aReturns(nCount);
2716  beans::SetPropertyTolerantFailed* pReturns = aReturns.getArray();
2717 
2718  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2719  const OUString* pNames = aPropertyNames.getConstArray();
2720  const uno::Any* pValues = aValues.getConstArray();
2721 
2722  std::unique_ptr<const SfxItemPropertySimpleEntry*[]> pMapArray(new const SfxItemPropertySimpleEntry*[nCount]);
2723 
2724  sal_Int32 i;
2725  for(i = 0; i < nCount; i++)
2726  {
2727  // first loop: find all properties in map, but handle only CellStyle
2728  // (CellStyle must be set before any other cell properties)
2729 
2730  const SfxItemPropertySimpleEntry* pEntry = rPropertyMap.getByName( pNames[i] );
2731  pMapArray[i] = pEntry;
2732  if (pEntry)
2733  {
2734  if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
2735  {
2736  try
2737  {
2738  SetOnePropertyValue( pEntry, pValues[i] );
2739  }
2740  catch ( lang::IllegalArgumentException& )
2741  {
2742  OSL_FAIL("exception when setting cell style"); // not supposed to happen
2743  }
2744  }
2745  }
2746  }
2747 
2748  ScDocument& rDoc = pDocShell->GetDocument();
2749  std::unique_ptr<ScPatternAttr> pOldPattern;
2750  std::unique_ptr<ScPatternAttr> pNewPattern;
2751 
2752  sal_Int32 nFailed(0);
2753  for(i = 0; i < nCount; i++)
2754  {
2755  // second loop: handle other properties
2756 
2757  const SfxItemPropertySimpleEntry* pEntry = pMapArray[i];
2758  if ( pEntry && ((pEntry->nFlags & beans::PropertyAttribute::READONLY) == 0))
2759  {
2760  if ( IsScItemWid( pEntry->nWID ) ) // can be handled by SfxItemPropertySet
2761  {
2762  if ( !pOldPattern )
2763  {
2764  pOldPattern.reset(new ScPatternAttr( *GetCurrentAttrsDeep() ));
2765  pOldPattern->GetItemSet().ClearInvalidItems();
2766  pNewPattern.reset(new ScPatternAttr( rDoc.GetPool() ));
2767  }
2768 
2769  // collect items in pNewPattern, apply with one call after the loop
2770 
2771  sal_uInt16 nFirstItem, nSecondItem;
2772  try
2773  {
2774  lcl_SetCellProperty( *pEntry, pValues[i], *pOldPattern, rDoc, nFirstItem, nSecondItem );
2775 
2776  // put only affected items into new set
2777  if ( nFirstItem )
2778  pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nFirstItem ) );
2779  if ( nSecondItem )
2780  pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nSecondItem ) );
2781  }
2782  catch ( lang::IllegalArgumentException& )
2783  {
2784  pReturns[nFailed].Name = pNames[i];
2785  pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT;
2786  }
2787  }
2788  else if ( pEntry->nWID != SC_WID_UNO_CELLSTYL ) // CellStyle is handled above
2789  {
2790  // call virtual method to set a single property
2791  try
2792  {
2793  SetOnePropertyValue( pEntry, pValues[i] );
2794  }
2795  catch ( lang::IllegalArgumentException& )
2796  {
2797  pReturns[nFailed].Name = pNames[i];
2798  pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT;
2799  }
2800  }
2801  }
2802  else
2803  {
2804  pReturns[nFailed].Name = pNames[i];
2805  if (pEntry)
2806  pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::PROPERTY_VETO;
2807  else
2808  pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
2809  }
2810  }
2811 
2812  if ( pNewPattern && !aRanges.empty() )
2813  pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), *pNewPattern, true );
2814 
2815  aReturns.realloc(nFailed);
2816 
2817  return aReturns;
2818  }
2819  return uno::Sequence < beans::SetPropertyTolerantFailed >();
2820 }
2821 
2822 uno::Sequence< beans::GetPropertyTolerantResult > SAL_CALL ScCellRangesBase::getPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames )
2823 {
2824  SolarMutexGuard aGuard;
2825 
2826  sal_Int32 nCount(aPropertyNames.getLength());
2827  uno::Sequence < beans::GetPropertyTolerantResult > aReturns(nCount);
2828  beans::GetPropertyTolerantResult* pReturns = aReturns.getArray();
2829 
2830  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2831 
2832  for(sal_Int32 i = 0; i < nCount; i++)
2833  {
2834  const SfxItemPropertySimpleEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
2835  if (!pEntry)
2836  {
2837  pReturns[i].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
2838  }
2839  else
2840  {
2841  sal_uInt16 nItemWhich = 0;
2842  lcl_GetPropertyWhich( pEntry, nItemWhich );
2843  pReturns[i].State = GetOnePropertyState( nItemWhich, pEntry );
2844  GetOnePropertyValue( pEntry, pReturns[i].Value );
2845  pReturns[i].Result = beans::TolerantPropertySetResultType::SUCCESS;
2846  }
2847  }
2848  return aReturns;
2849 }
2850 
2851 uno::Sequence< beans::GetDirectPropertyTolerantResult > SAL_CALL ScCellRangesBase::getDirectPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames )
2852 {
2853  SolarMutexGuard aGuard;
2854 
2855  sal_Int32 nCount(aPropertyNames.getLength());
2856  uno::Sequence < beans::GetDirectPropertyTolerantResult > aReturns(nCount);
2857  beans::GetDirectPropertyTolerantResult* pReturns = aReturns.getArray();
2858 
2859  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2860 
2861  sal_Int32 j = 0;
2862  for(sal_Int32 i = 0; i < nCount; i++)
2863  {
2864  const SfxItemPropertySimpleEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
2865  if (!pEntry)
2866  {
2867  pReturns[i].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
2868  }
2869  else
2870  {
2871  sal_uInt16 nItemWhich = 0;
2872  lcl_GetPropertyWhich( pEntry, nItemWhich );
2873  pReturns[j].State = GetOnePropertyState( nItemWhich, pEntry );
2874  if (pReturns[j].State == beans::PropertyState_DIRECT_VALUE)
2875  {
2876  GetOnePropertyValue( pEntry, pReturns[j].Value );
2877  pReturns[j].Result = beans::TolerantPropertySetResultType::SUCCESS;
2878  pReturns[j].Name = aPropertyNames[i];
2879  ++j;
2880  }
2881  }
2882  }
2883  if (j < nCount)
2884  aReturns.realloc(j);
2885  return aReturns;
2886 }
2887 
2888 // XIndent
2889 
2891 {
2892  SolarMutexGuard aGuard;
2893  if ( pDocShell && !aRanges.empty() )
2894  {
2895  //#97041#; put only MultiMarked ScMarkData in ChangeIndent
2896  ScMarkData aMarkData(*GetMarkData());
2897  aMarkData.MarkToMulti();
2898  pDocShell->GetDocFunc().ChangeIndent( aMarkData, false, true );
2899  }
2900 }
2901 
2903 {
2904  SolarMutexGuard aGuard;
2905  if ( pDocShell && !aRanges.empty() )
2906  {
2907  //#97041#; put only MultiMarked ScMarkData in ChangeIndent
2908  ScMarkData aMarkData(*GetMarkData());
2909  aMarkData.MarkToMulti();
2910  pDocShell->GetDocFunc().ChangeIndent( aMarkData, true, true );
2911  }
2912 }
2913 
2914 // XChartData
2915 
2916 std::unique_ptr<ScMemChart> ScCellRangesBase::CreateMemChart_Impl() const
2917 {
2918  if ( pDocShell && !aRanges.empty() )
2919  {
2920  ScRangeListRef xChartRanges;
2921  if ( aRanges.size() == 1 )
2922  {
2923  // set useful table limit (only occupied data area)
2924  // (only here - Listeners are registered for the whole area)
2926 
2927  const ScDocument & rDoc = pDocShell->GetDocument();
2928  const ScRange & rRange = aRanges[0];
2929  if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
2930  rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
2931  {
2932  SCTAB nTab = rRange.aStart.Tab();
2933 
2934  SCCOL nStartX;
2935  SCROW nStartY; // Get start
2936  if (!pDocShell->GetDocument().GetDataStart( nTab, nStartX, nStartY ))
2937  {
2938  nStartX = 0;
2939  nStartY = 0;
2940  }
2941 
2942  SCCOL nEndX;
2943  SCROW nEndY; // Get end
2944  if (!pDocShell->GetDocument().GetTableArea( nTab, nEndX, nEndY ))
2945  {
2946  nEndX = 0;
2947  nEndY = 0;
2948  }
2949 
2950  xChartRanges = new ScRangeList( ScRange( nStartX, nStartY, nTab, nEndX, nEndY, nTab ) );
2951  }
2952  }
2953  if (!xChartRanges.is()) // otherwise take Ranges directly
2954  xChartRanges = new ScRangeList(aRanges);
2955  ScChartArray aArr( &pDocShell->GetDocument(), xChartRanges );
2956 
2957  // RowAsHdr = ColHeaders and vice versa
2958  aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr );
2959 
2960  return aArr.CreateMemChart();
2961  }
2962  return nullptr;
2963 }
2964 
2965 uno::Sequence< uno::Sequence<double> > SAL_CALL ScCellRangesBase::getData()
2966 {
2967  SolarMutexGuard aGuard;
2968  std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
2969  if ( pMemChart )
2970  {
2971  sal_Int32 nColCount = pMemChart->GetColCount();
2972  sal_Int32 nRowCount = static_cast<sal_Int32>(pMemChart->GetRowCount());
2973 
2974  uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
2975  uno::Sequence<double>* pRowAry = aRowSeq.getArray();
2976  for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
2977  {
2978  uno::Sequence<double> aColSeq( nColCount );
2979  double* pColAry = aColSeq.getArray();
2980  for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
2981  pColAry[nCol] = pMemChart->GetData( nCol, nRow );
2982 
2983  pRowAry[nRow] = aColSeq;
2984  }
2985 
2986  return aRowSeq;
2987  }
2988 
2989  return uno::Sequence< uno::Sequence<double> >(0);
2990 }
2991 
2992 ScRangeListRef ScCellRangesBase::GetLimitedChartRanges_Impl( long nDataColumns, long nDataRows ) const
2993 {
2994  if ( aRanges.size() == 1 )
2995  {
2996  const ScDocument & rDoc = pDocShell->GetDocument();
2997  const ScRange & rRange = aRanges[0];
2998  if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
2999  rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
3000  {
3001  // if aRanges is a complete sheet, limit to given size
3002 
3003  SCTAB nTab = rRange.aStart.Tab();
3004 
3005  long nEndColumn = nDataColumns - 1 + ( bChartColAsHdr ? 1 : 0 );
3006  if ( nEndColumn < 0 )
3007  nEndColumn = 0;
3008  if ( nEndColumn > rDoc.MaxCol() )
3009  nEndColumn = rDoc.MaxCol();
3010 
3011  long nEndRow = nDataRows - 1 + ( bChartRowAsHdr ? 1 : 0 );
3012  if ( nEndRow < 0 )
3013  nEndRow = 0;
3014  if ( nEndRow > rDoc.MaxRow() )
3015  nEndRow = rDoc.MaxRow();
3016 
3017  ScRangeListRef xChartRanges = new ScRangeList( ScRange( 0, 0, nTab, static_cast<SCCOL>(nEndColumn), static_cast<SCROW>(nEndRow), nTab ) );
3018  return xChartRanges;
3019  }
3020  }
3021 
3022  return new ScRangeList(aRanges); // as-is
3023 }
3024 
3025 void SAL_CALL ScCellRangesBase::setData( const uno::Sequence< uno::Sequence<double> >& aData )
3026 {
3027  SolarMutexGuard aGuard;
3028  bool bDone = false;
3029  long nRowCount = aData.getLength();
3030  long nColCount = nRowCount ? aData[0].getLength() : 0;
3031  ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( nColCount, nRowCount );
3032  if ( pDocShell && xChartRanges.is() )
3033  {
3034  ScDocument& rDoc = pDocShell->GetDocument();
3035  ScChartArray aArr( &rDoc, xChartRanges );
3036  aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
3037  const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
3038  if (pPosMap)
3039  {
3040  if ( pPosMap->GetColCount() == static_cast<SCCOL>(nColCount) &&
3041  pPosMap->GetRowCount() == static_cast<SCROW>(nRowCount) )
3042  {
3043  for (long nRow=0; nRow<nRowCount; nRow++)
3044  {
3045  const uno::Sequence<double>& rRowSeq = aData[nRow];
3046  const double* pArray = rRowSeq.getConstArray();
3047  nColCount = rRowSeq.getLength();
3048  for (long nCol=0; nCol<nColCount; nCol++)
3049  {
3050  const ScAddress* pPos = pPosMap->GetPosition(
3051  sal::static_int_cast<SCCOL>(nCol),
3052  sal::static_int_cast<SCROW>(nRow) );
3053  if (pPos)
3054  {
3055  double fVal = pArray[nCol];
3056  if ( fVal == DBL_MIN )
3057  rDoc.SetEmptyCell(*pPos);
3058  else
3059  rDoc.SetValue(*pPos, pArray[nCol]);
3060  }
3061  }
3062  }
3063 
3067  ForceChartListener_Impl(); // call listeners for this object synchronously
3068  bDone = true;
3069  }
3070  }
3071  }
3072 
3073  if (!bDone)
3074  throw uno::RuntimeException();
3075 }
3076 
3077 uno::Sequence<OUString> SAL_CALL ScCellRangesBase::getRowDescriptions()
3078 {
3079  SolarMutexGuard aGuard;
3080  std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
3081  if ( pMemChart )
3082  {
3083  sal_Int32 nRowCount = static_cast<sal_Int32>(pMemChart->GetRowCount());
3084  uno::Sequence<OUString> aSeq( nRowCount );
3085  OUString* pAry = aSeq.getArray();
3086  for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
3087  pAry[nRow] = pMemChart->GetRowText(nRow);
3088 
3089  return aSeq;
3090  }
3091  return uno::Sequence<OUString>(0);
3092 }
3093 
3095  const uno::Sequence<OUString>& aRowDescriptions )
3096 {
3097  SolarMutexGuard aGuard;
3098  bool bDone = false;
3099  if ( bChartColAsHdr )
3100  {
3101  long nRowCount = aRowDescriptions.getLength();
3102  ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( 1, nRowCount );
3103  if ( pDocShell && xChartRanges.is() )
3104  {
3105  ScDocument& rDoc = pDocShell->GetDocument();
3106  ScChartArray aArr( &rDoc, xChartRanges );
3107  aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
3108  const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
3109  if (pPosMap)
3110  {
3111  if ( pPosMap->GetRowCount() == static_cast<SCROW>(nRowCount) )
3112  {
3113  const OUString* pArray = aRowDescriptions.getConstArray();
3114  for (long nRow=0; nRow<nRowCount; nRow++)
3115  {
3116  const ScAddress* pPos = pPosMap->GetRowHeaderPosition(
3117  static_cast<SCSIZE>(nRow) );
3118  if (pPos)
3119  {
3120  const OUString& aStr = pArray[nRow];
3121  if (aStr.isEmpty())
3122  rDoc.SetEmptyCell(*pPos);
3123  else
3124  {
3125  ScSetStringParam aParam;
3126  aParam.setTextInput();
3127  rDoc.SetString(*pPos, aStr, &aParam);
3128  }
3129  }
3130  }
3131 
3135  ForceChartListener_Impl(); // call listeners for this object synchronously
3136  bDone = true;
3137  }
3138  }
3139  }
3140  }
3141 
3142  if (!bDone)
3143  throw uno::RuntimeException();
3144 }
3145 
3146 uno::Sequence<OUString> SAL_CALL ScCellRangesBase::getColumnDescriptions()
3147 {
3148  SolarMutexGuard aGuard;
3149  std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
3150  if ( pMemChart )
3151  {
3152  sal_Int32 nColCount = pMemChart->GetColCount();
3153  uno::Sequence<OUString> aSeq( nColCount );
3154  OUString* pAry = aSeq.getArray();
3155  for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
3156  pAry[nCol] = pMemChart->GetColText(nCol);
3157 
3158  return aSeq;
3159  }
3160  return uno::Sequence<OUString>(0);
3161 }
3162 
3164  const uno::Sequence<OUString>& aColumnDescriptions )
3165 {
3166  SolarMutexGuard aGuard;
3167  bool bDone = false;
3168  if ( bChartRowAsHdr )
3169  {
3170  long nColCount = aColumnDescriptions.getLength();
3171  ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( nColCount, 1 );
3172  if ( pDocShell && xChartRanges.is() )
3173  {
3174  ScDocument& rDoc = pDocShell->GetDocument();
3175  ScChartArray aArr( &rDoc, xChartRanges );
3176  aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
3177  const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
3178  if (pPosMap)
3179  {
3180  if ( pPosMap->GetColCount() == static_cast<SCCOL>(nColCount) )
3181  {
3182  const OUString* pArray = aColumnDescriptions.getConstArray();
3183  for (long nCol=0; nCol<nColCount; nCol++)
3184  {
3185  const ScAddress* pPos = pPosMap->GetColHeaderPosition(
3186  sal::static_int_cast<SCCOL>(nCol) );
3187  if (pPos)
3188  {
3189  const OUString& aStr = pArray[nCol];
3190  if (aStr.isEmpty())
3191  rDoc.SetEmptyCell(*pPos);
3192  else
3193  {
3194  ScSetStringParam aParam;
3195  aParam.setTextInput();
3196  rDoc.SetString(*pPos, aStr, &aParam);
3197  }
3198  }
3199  }
3200 
3204  ForceChartListener_Impl(); // call listeners for this object synchronously
3205  bDone = true;
3206  }
3207  }
3208  }
3209  }
3210 
3211  if (!bDone)
3212  throw uno::RuntimeException();
3213 }
3214 
3216 {
3217  // call Update immediately so the caller to setData etc. can
3218  // recognize the listener call
3219 
3220  if (!pDocShell)
3221  return;
3222 
3224  if (!pColl)
3225  return;
3226 
3228  for (auto const& it : rListeners)
3229  {
3230  ScChartListener *const p = it.second.get();
3231  assert(p);
3232  if (p->GetUnoSource() == static_cast<chart::XChartData*>(this) && p->IsDirty())
3233  p->Update();
3234  }
3235 }
3236 
3237 void SAL_CALL ScCellRangesBase::addChartDataChangeEventListener( const uno::Reference<
3238  chart::XChartDataChangeEventListener >& aListener )
3239 {
3240  SolarMutexGuard aGuard;
3241  if ( pDocShell && !aRanges.empty() )
3242  {
3244 
3245  ScDocument& rDoc = pDocShell->GetDocument();
3246  ScRangeListRef aRangesRef( new ScRangeList(aRanges) );
3248  OUString aName = pColl->getUniqueName("__Uno");
3249  if (aName.isEmpty())
3250  // failed to create unique name.
3251  return;
3252 
3253  ScChartListener* pListener = new ScChartListener( aName, &rDoc, aRangesRef );
3254  pListener->SetUno( aListener, this );
3255  pColl->insert( pListener );
3256  pListener->StartListeningTo();
3257  }
3258 }
3259 
3260 void SAL_CALL ScCellRangesBase::removeChartDataChangeEventListener( const uno::Reference<
3261  chart::XChartDataChangeEventListener >& aListener )
3262 {
3263  SolarMutexGuard aGuard;
3264  if ( pDocShell && !aRanges.empty() )
3265  {
3266  ScDocument& rDoc = pDocShell->GetDocument();
3268  pColl->FreeUno( aListener, this );
3269  }
3270 }
3271 
3273 {
3274  // use DBL_MIN in ScChartArray, because Chart wants it so
3275  return DBL_MIN;
3276 }
3277 
3278 sal_Bool SAL_CALL ScCellRangesBase::isNotANumber( double nNumber )
3279 {
3280  // use DBL_MIN in ScChartArray, because Chart wants it so
3281  return (nNumber == DBL_MIN);
3282 }
3283 
3284 // XModifyBroadcaster
3285 
3286 void SAL_CALL ScCellRangesBase::addModifyListener(const uno::Reference<util::XModifyListener>& aListener)
3287 {
3288  SolarMutexGuard aGuard;
3289  if ( aRanges.empty() )
3290  throw uno::RuntimeException();
3291 
3292  aValueListeners.emplace_back( aListener );
3293 
3294  if ( aValueListeners.size() == 1 )
3295  {
3296  if (!pValueListener)
3297  pValueListener.reset( new ScLinkListener( LINK( this, ScCellRangesBase, ValueListenerHdl ) ) );
3298 
3299  ScDocument& rDoc = pDocShell->GetDocument();
3300  for ( size_t i = 0, nCount = aRanges.size(); i < nCount; i++)
3301  rDoc.StartListeningArea( aRanges[ i ], false, pValueListener.get() );
3302 
3303  acquire(); // don't lose this object (one ref for all listeners)
3304  }
3305 }
3306 
3307 void SAL_CALL ScCellRangesBase::removeModifyListener( const uno::Reference<util::XModifyListener>& aListener )
3308 {
3309 
3310  SolarMutexGuard aGuard;
3311  if ( aRanges.empty() )
3312  throw uno::RuntimeException();
3313 
3314  rtl::Reference<ScCellRangesBase> xSelfHold(this); // in case the listeners have the last ref
3315 
3316  sal_uInt16 nCount = aValueListeners.size();
3317  for ( sal_uInt16 n=nCount; n--; )
3318  {
3319  uno::Reference<util::XModifyListener>& rObj = aValueListeners[n];
3320  if ( rObj == aListener )
3321  {
3322  aValueListeners.erase( aValueListeners.begin() + n );
3323 
3324  if ( aValueListeners.empty() )
3325  {
3326  if (pValueListener)
3327  pValueListener->EndListeningAll();
3328 
3329  release(); // release the ref for the listeners
3330  }
3331 
3332  break;
3333  }
3334  }
3335 }
3336 
3337 // XCellRangesQuery
3338 
3339 uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryVisibleCells()
3340 {
3341  SolarMutexGuard aGuard;
3342  if (pDocShell)
3343  {
3345  SCTAB nTab = lcl_FirstTab(aRanges);
3346 
3347  ScMarkData aMarkData(*GetMarkData());
3348 
3349  ScDocument& rDoc = pDocShell->GetDocument();
3350  SCCOL nCol = 0, nLastCol;
3351  while (nCol <= rDoc.MaxCol())
3352  {
3353  if (rDoc.ColHidden(nCol, nTab, nullptr, &nLastCol))
3354  // hidden columns. Deselect them.
3355  aMarkData.SetMultiMarkArea(ScRange(nCol, 0, nTab, nLastCol, rDoc.MaxRow(), nTab), false);
3356 
3357  nCol = nLastCol + 1;
3358  }
3359 
3360  SCROW nRow = 0, nLastRow;
3361  while (nRow <= rDoc.MaxRow())
3362  {
3363  if (rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow))
3364  // These rows are hidden. Deselect them.
3365  aMarkData.SetMultiMarkArea(ScRange(0, nRow, nTab, rDoc.MaxCol(), nLastRow, nTab), false);
3366 
3367  nRow = nLastRow + 1;
3368  }
3369 
3370  ScRangeList aNewRanges;
3371  aMarkData.FillRangeListWithMarks( &aNewRanges, false );
3372  return new ScCellRangesObj( pDocShell, aNewRanges );
3373  }
3374 
3375  return nullptr;
3376 }
3377 
3378 uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryEmptyCells()
3379 {
3380  SolarMutexGuard aGuard;
3381  if (pDocShell)
3382  {
3383  ScDocument& rDoc = pDocShell->GetDocument();
3384 
3385  ScMarkData aMarkData(*GetMarkData());
3386 
3387  // mark occupied cells
3388  for (size_t i = 0, nCount = aRanges.size(); i < nCount; ++i)
3389  {
3390  ScRange const & rRange = aRanges[ i ];
3391 
3392  ScCellIterator aIter( &rDoc, rRange );
3393  for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
3394  {
3395  // notes count as non-empty
3396  if (!aIter.isEmpty())
3397  aMarkData.SetMultiMarkArea(aIter.GetPos(), false);
3398  }
3399  }
3400 
3401  ScRangeList aNewRanges;
3402  // IsMultiMarked is not enough (will not be reset during deselecting)
3403  //if (aMarkData.HasAnyMultiMarks()) // #i20044# should be set for all empty range
3404  aMarkData.FillRangeListWithMarks( &aNewRanges, false );
3405 
3406  return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
3407  }
3408 
3409  return nullptr;
3410 }
3411 
3412 uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryContentCells(
3413  sal_Int16 nContentFlags )
3414 {
3415  SolarMutexGuard aGuard;
3416  if (pDocShell)
3417  {
3418  ScDocument& rDoc = pDocShell->GetDocument();
3419 
3420  ScMarkData aMarkData(rDoc.GetSheetLimits());
3421 
3422  // select matching cells
3423  for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
3424  {
3425  ScRange const & rRange = aRanges[ i ];
3426 
3427  ScCellIterator aIter( &rDoc, rRange );
3428  for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())