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