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/srchitem.hxx>
36 #include <svl/sharedstringpool.hxx>
37 #include <svx/unomid.hxx>
38 #include <editeng/unoprnms.hxx>
39 #include <editeng/unotext.hxx>
40 #include <svx/svdpage.hxx>
41 #include <sfx2/bindings.hxx>
42 #include <svl/zforlist.hxx>
43 #include <svl/zformat.hxx>
45 #include <float.h>
46 #include <tools/diagnose_ex.h>
47 #include <tools/UnitConversion.hxx>
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  {u"" SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
266  { u"", 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  {u"" SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
357  {u"" SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
364  {u"" SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
377  { u"", 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  {u"" SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
449  {u"" SC_UNONAME_FORMRT, SC_WID_UNO_FORMRT, cppu::UnoType<table::CellContentType>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
451  {u"" SC_UNONAME_FORMRT2, SC_WID_UNO_FORMRT2, cppu::UnoType<sal_Int32>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
472  {u"" SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
479  {u"" SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
494  { u"", 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  {u"" SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
589  {u"" SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
596  {u"" SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
609  { u"", 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  {u"" SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
703  {u"" SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
710  {u"" SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
722  { u"", 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  {u"" SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
803  {u"" SC_UNO_LINKDISPBIT, SC_WID_UNO_LINKDISPBIT,cppu::UnoType<awt::XBitmap>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
804  {u"" SC_UNO_LINKDISPNAME, SC_WID_UNO_LINKDISPNAME,cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
820  {u"" SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
830  {u"" SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
847  { u"", 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  { u"", 0, css::uno::Type(), 0, 0 }
864  };
865  return aEditPropertyMap_Impl;
866 }
868 {
870  return &aEditPropertySet;
871 }
872 
873 #define SCCHARPROPERTIES_SERVICE "com.sun.star.style.CharacterProperties"
874 #define SCPARAPROPERTIES_SERVICE "com.sun.star.style.ParagraphProperties"
875 #define SCCELLPROPERTIES_SERVICE "com.sun.star.table.CellProperties"
876 #define SCCELLRANGE_SERVICE "com.sun.star.table.CellRange"
877 #define SCCELL_SERVICE "com.sun.star.table.Cell"
878 #define SCSHEETCELLRANGES_SERVICE "com.sun.star.sheet.SheetCellRanges"
879 #define SCSHEETCELLRANGE_SERVICE "com.sun.star.sheet.SheetCellRange"
880 #define SCSPREADSHEET_SERVICE "com.sun.star.sheet.Spreadsheet"
881 #define SCSHEETCELL_SERVICE "com.sun.star.sheet.SheetCell"
882 
883 SC_SIMPLE_SERVICE_INFO( ScCellFormatsEnumeration, "ScCellFormatsEnumeration", "com.sun.star.sheet.CellFormatRangesEnumeration" )
884 SC_SIMPLE_SERVICE_INFO( ScCellFormatsObj, "ScCellFormatsObj", "com.sun.star.sheet.CellFormatRanges" )
885 SC_SIMPLE_SERVICE_INFO( ScUniqueCellFormatsEnumeration, "ScUniqueCellFormatsEnumeration", "com.sun.star.sheet.UniqueCellFormatRangesEnumeration" )
886 SC_SIMPLE_SERVICE_INFO( ScUniqueCellFormatsObj, "ScUniqueCellFormatsObj", "com.sun.star.sheet.UniqueCellFormatRanges" )
887 SC_SIMPLE_SERVICE_INFO( ScCellRangesBase, "ScCellRangesBase", "stardiv.unknown" )
888 SC_SIMPLE_SERVICE_INFO( ScCellsEnumeration, "ScCellsEnumeration", "com.sun.star.sheet.CellsEnumeration" )
889 SC_SIMPLE_SERVICE_INFO( ScCellsObj, "ScCellsObj", "com.sun.star.sheet.Cells" )
890 SC_SIMPLE_SERVICE_INFO( ScTableColumnObj, "ScTableColumnObj", "com.sun.star.table.TableColumn" )
891 SC_SIMPLE_SERVICE_INFO( ScTableRowObj, "ScTableRowObj", "com.sun.star.table.TableRow" )
892 
894 
896 {
897 }
898 
899 void ScLinkListener::Notify( const SfxHint& rHint )
900 {
901  aLink.Call( rHint );
902 }
903 
905 {
906  uno::Reference<beans::XPropertySetInfo> xInfo(rSource.getPropertySetInfo());
907  if (xInfo.is())
908  {
909  const uno::Sequence<beans::Property> aSeq(xInfo->getProperties());
910  for (const beans::Property& rProp : aSeq)
911  {
912  OUString aName(rProp.Name);
913  rDest.setPropertyValue( aName, rSource.getPropertyValue( aName ) );
914  }
915  }
916 }
917 
918 static SCTAB lcl_FirstTab( const ScRangeList& rRanges )
919 {
920  if (rRanges.empty())
921  throw std::out_of_range("empty range");
922  const ScRange & rFirst = rRanges[0];
923  return rFirst.aStart.Tab();
924 }
925 
926 static bool lcl_WholeSheet( const ScDocument& rDoc, const ScRangeList& rRanges )
927 {
928  if ( rRanges.size() == 1 )
929  {
930  const ScRange & rRange = rRanges[0];
931  if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
932  rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
933  return true;
934  }
935  return false;
936 }
937 
938 namespace {
939 template<typename BorderLineType>
940 const ::editeng::SvxBorderLine* lcl_getBorderLine(
941  ::editeng::SvxBorderLine& rLine, const BorderLineType& rStruct )
942 {
943  // Convert from 1/100mm to Twips.
944  if (!SvxBoxItem::LineToSvxLine( rStruct, rLine, true))
945  return nullptr;
946 
947  if ( rLine.GetOutWidth() || rLine.GetInWidth() || rLine.GetDistance() )
948  return &rLine;
949  else
950  return nullptr;
951 }
952 }
953 
954 const ::editeng::SvxBorderLine* ScHelperFunctions::GetBorderLine(
955  ::editeng::SvxBorderLine& rLine, const table::BorderLine& rStruct )
956 {
957  return lcl_getBorderLine( rLine, rStruct);
958 }
959 
960 const ::editeng::SvxBorderLine* ScHelperFunctions::GetBorderLine(
961  ::editeng::SvxBorderLine& rLine, const table::BorderLine2& rStruct )
962 {
963  return lcl_getBorderLine( rLine, rStruct);
964 }
965 
966 namespace {
967 template<typename TableBorderType>
968 void lcl_fillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const TableBorderType& rBorder )
969 {
971  rOuter.SetAllDistances(static_cast<sal_uInt16>(convertMm100ToTwip(rBorder.Distance)));
972  rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.TopLine ), SvxBoxItemLine::TOP );
973  rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.BottomLine ), SvxBoxItemLine::BOTTOM );
974  rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.LeftLine ), SvxBoxItemLine::LEFT );
975  rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.RightLine ), SvxBoxItemLine::RIGHT );
976  rInner.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.HorizontalLine ), SvxBoxInfoItemLine::HORI );
977  rInner.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.VerticalLine ), SvxBoxInfoItemLine::VERT );
978  rInner.SetValid( SvxBoxInfoItemValidFlags::TOP, rBorder.IsTopLineValid );
979  rInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, rBorder.IsBottomLineValid );
980  rInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, rBorder.IsLeftLineValid );
981  rInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, rBorder.IsRightLineValid );
982  rInner.SetValid( SvxBoxInfoItemValidFlags::HORI, rBorder.IsHorizontalLineValid );
983  rInner.SetValid( SvxBoxInfoItemValidFlags::VERT, rBorder.IsVerticalLineValid );
984  rInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE, rBorder.IsDistanceValid );
985  rInner.SetTable( true );
986 }
987 }
988 
989 void ScHelperFunctions::FillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const table::TableBorder& rBorder )
990 {
991  lcl_fillBoxItems( rOuter, rInner, rBorder);
992 }
993 
994 void ScHelperFunctions::FillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const table::TableBorder2& rBorder )
995 {
996  lcl_fillBoxItems( rOuter, rInner, rBorder);
997 }
998 
999 void ScHelperFunctions::FillBorderLine( table::BorderLine& rStruct, const ::editeng::SvxBorderLine* pLine )
1000 {
1001  // Convert from Twips to 1/100mm.
1002  table::BorderLine2 aStruct( SvxBoxItem::SvxLineToLine( pLine, true));
1003  rStruct = aStruct;
1004 }
1005 
1006 void ScHelperFunctions::FillBorderLine( table::BorderLine2& rStruct, const ::editeng::SvxBorderLine* pLine )
1007 {
1008  rStruct = SvxBoxItem::SvxLineToLine( pLine, true);
1009 }
1010 
1011 namespace {
1012 template<typename TableBorderItem>
1013 void lcl_fillTableBorder( TableBorderItem& rBorder, const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner,
1014  bool bInvalidateHorVerDist )
1015 {
1016  ScHelperFunctions::FillBorderLine( rBorder.TopLine, rOuter.GetTop() );
1017  ScHelperFunctions::FillBorderLine( rBorder.BottomLine, rOuter.GetBottom() );
1018  ScHelperFunctions::FillBorderLine( rBorder.LeftLine, rOuter.GetLeft() );
1019  ScHelperFunctions::FillBorderLine( rBorder.RightLine, rOuter.GetRight() );
1020  ScHelperFunctions::FillBorderLine( rBorder.HorizontalLine, rInner.GetHori() );
1021  ScHelperFunctions::FillBorderLine( rBorder.VerticalLine, rInner.GetVert() );
1022 
1023  rBorder.Distance = rOuter.GetSmallestDistance();
1024  rBorder.IsTopLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::TOP);
1025  rBorder.IsBottomLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
1026  rBorder.IsLeftLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::LEFT);
1027  rBorder.IsRightLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::RIGHT);
1028  rBorder.IsHorizontalLineValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::HORI);
1029  rBorder.IsVerticalLineValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::VERT);
1030  rBorder.IsDistanceValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
1031 }
1032 }
1033 
1035  const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner, bool bInvalidateHorVerDist )
1036 {
1037  table::TableBorder aBorder;
1038  lcl_fillTableBorder( aBorder, rOuter, rInner, bInvalidateHorVerDist);
1039  rAny <<= aBorder;
1040 }
1041 
1043  const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner, bool bInvalidateHorVerDist )
1044 {
1045  table::TableBorder2 aBorder;
1046  lcl_fillTableBorder( aBorder, rOuter, rInner, bInvalidateHorVerDist);
1047  rAny <<= aBorder;
1048 }
1049 
1051 
1052 void ScHelperFunctions::ApplyBorder( ScDocShell* pDocShell, const ScRangeList& rRanges,
1053  const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner )
1054 {
1055  ScDocument& rDoc = pDocShell->GetDocument();
1056  bool bUndo(rDoc.IsUndoEnabled());
1057  ScDocumentUniquePtr pUndoDoc;
1058  if (bUndo)
1059  pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1060  size_t nCount = rRanges.size();
1061  for (size_t i = 0; i < nCount; ++i)
1062  {
1063  ScRange const & rRange = rRanges[ i ];
1064  SCTAB nTab = rRange.aStart.Tab();
1065 
1066  if (bUndo)
1067  {
1068  if ( i==0 )
1069  pUndoDoc->InitUndo( rDoc, nTab, nTab );
1070  else
1071  pUndoDoc->AddUndoTab( nTab, nTab );
1072  rDoc.CopyToDocument(rRange, InsertDeleteFlags::ATTRIB, false, *pUndoDoc);
1073  }
1074 
1075  ScMarkData aMark(rDoc.GetSheetLimits());
1076  aMark.SetMarkArea( rRange );
1077  aMark.SelectTable( nTab, true );
1078 
1079  rDoc.ApplySelectionFrame(aMark, rOuter, &rInner);
1080  // don't need RowHeight if there is only a border
1081  }
1082 
1083  if (bUndo)
1084  {
1085  pDocShell->GetUndoManager()->AddUndoAction(
1086  std::make_unique<ScUndoBorder>( pDocShell, rRanges, std::move(pUndoDoc), rOuter, rInner ) );
1087  }
1088 
1089  for (size_t i = 0; i < nCount; ++i )
1090  pDocShell->PostPaint( rRanges[ i ], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
1091 
1092  pDocShell->SetDocumentModified();
1093 }
1094 
1097 
1098 static bool lcl_PutDataArray( ScDocShell& rDocShell, const ScRange& rRange,
1099  const uno::Sequence< uno::Sequence<uno::Any> >& aData )
1100 {
1101  ScDocument& rDoc = rDocShell.GetDocument();
1102  SCTAB nTab = rRange.aStart.Tab();
1103  SCCOL nStartCol = rRange.aStart.Col();
1104  SCROW nStartRow = rRange.aStart.Row();
1105  SCCOL nEndCol = rRange.aEnd.Col();
1106  SCROW nEndRow = rRange.aEnd.Row();
1107  bool bUndo(rDoc.IsUndoEnabled());
1108 
1109  if ( !rDoc.IsBlockEditable( nTab, nStartCol,nStartRow, nEndCol,nEndRow ) )
1110  {
1112  return false;
1113  }
1114 
1115  sal_Int32 nCols = 0;
1116  sal_Int32 nRows = aData.getLength();
1117  if ( nRows )
1118  nCols = aData[0].getLength();
1119 
1120  if ( nCols != nEndCol-nStartCol+1 || nRows != nEndRow-nStartRow+1 )
1121  {
1123  return false;
1124  }
1125 
1126  ScDocumentUniquePtr pUndoDoc;
1127  if ( bUndo )
1128  {
1129  pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1130  pUndoDoc->InitUndo( rDoc, nTab, nTab );
1132  }
1133 
1134  rDoc.DeleteAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
1135 
1136  bool bError = false;
1137  SCROW nDocRow = nStartRow;
1138  for (const uno::Sequence<uno::Any>& rColSeq : aData)
1139  {
1140  if ( rColSeq.getLength() == nCols )
1141  {
1142  SCCOL nDocCol = nStartCol;
1143  for (const uno::Any& rElement : rColSeq)
1144  {
1145  ScAddress aPos(nDocCol, nDocRow, nTab);
1146 
1147  switch( rElement.getValueTypeClass() )
1148  {
1149  case uno::TypeClass_VOID:
1150  {
1151  // void = "no value"
1152  rDoc.SetError( nDocCol, nDocRow, nTab, FormulaError::NotAvailable );
1153  }
1154  break;
1155 
1156  // #87871# accept integer types because Basic passes a floating point
1157  // variable as byte, short or long if it's an integer number.
1158  case uno::TypeClass_BYTE:
1159  case uno::TypeClass_SHORT:
1160  case uno::TypeClass_UNSIGNED_SHORT:
1161  case uno::TypeClass_LONG:
1162  case uno::TypeClass_UNSIGNED_LONG:
1163  case uno::TypeClass_FLOAT:
1164  case uno::TypeClass_DOUBLE:
1165  {
1166  double fVal(0.0);
1167  rElement >>= fVal;
1168  rDoc.SetValue(aPos, fVal);
1169  }
1170  break;
1171 
1172  case uno::TypeClass_STRING:
1173  {
1174  OUString aUStr;
1175  rElement >>= aUStr;
1176  if ( !aUStr.isEmpty() )
1177  {
1178  ScSetStringParam aParam;
1179  aParam.setTextInput();
1180  rDoc.SetString(aPos, aUStr, &aParam);
1181  }
1182  }
1183  break;
1184 
1185  // accept Sequence<FormulaToken> for formula cells
1186  case uno::TypeClass_SEQUENCE:
1187  {
1188  uno::Sequence< sheet::FormulaToken > aTokens;
1189  if ( rElement >>= aTokens )
1190  {
1191  ScTokenArray aTokenArray(rDoc);
1192  ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, aTokens );
1193  rDoc.SetFormula(aPos, aTokenArray);
1194  }
1195  else
1196  bError = true;
1197  }
1198  break;
1199 
1200  default:
1201  bError = true; // invalid type
1202  }
1203  ++nDocCol;
1204  }
1205  }
1206  else
1207  bError = true; // wrong size
1208 
1209  ++nDocRow;
1210  }
1211 
1212  bool bHeight = rDocShell.AdjustRowHeight( nStartRow, nEndRow, nTab );
1213 
1214  if ( pUndoDoc )
1215  {
1216  ScMarkData aDestMark(rDoc.GetSheetLimits());
1217  aDestMark.SelectOneTable( nTab );
1218  rDocShell.GetUndoManager()->AddUndoAction(
1219  std::make_unique<ScUndoPaste>(
1220  &rDocShell, ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab),
1221  aDestMark, std::move(pUndoDoc), nullptr, InsertDeleteFlags::CONTENTS, nullptr, false));
1222  }
1223 
1224  if (!bHeight)
1225  rDocShell.PostPaint( rRange, PaintPartFlags::Grid ); // AdjustRowHeight may have painted already
1226 
1227  rDocShell.SetDocumentModified();
1228 
1229  return !bError;
1230 }
1231 
1232 static bool lcl_PutFormulaArray( ScDocShell& rDocShell, const ScRange& rRange,
1233  const uno::Sequence< uno::Sequence<OUString> >& aData,
1234  const formula::FormulaGrammar::Grammar eGrammar )
1235 {
1236  ScDocument& rDoc = rDocShell.GetDocument();
1237  SCTAB nTab = rRange.aStart.Tab();
1238  SCCOL nStartCol = rRange.aStart.Col();
1239  SCROW nStartRow = rRange.aStart.Row();
1240  SCCOL nEndCol = rRange.aEnd.Col();
1241  SCROW nEndRow = rRange.aEnd.Row();
1242  bool bUndo(rDoc.IsUndoEnabled());
1243 
1244  if ( !rDoc.IsBlockEditable( nTab, nStartCol,nStartRow, nEndCol,nEndRow ) )
1245  {
1247  return false;
1248  }
1249 
1250  sal_Int32 nCols = 0;
1251  sal_Int32 nRows = aData.getLength();
1252  if ( nRows )
1253  nCols = aData[0].getLength();
1254 
1255  if ( nCols != nEndCol-nStartCol+1 || nRows != nEndRow-nStartRow+1 )
1256  {
1258  return false;
1259  }
1260 
1261  ScDocumentUniquePtr pUndoDoc;
1262  if ( bUndo )
1263  {
1264  pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1265  pUndoDoc->InitUndo( rDoc, nTab, nTab );
1266  rDoc.CopyToDocument(rRange, InsertDeleteFlags::CONTENTS, false, *pUndoDoc);
1267  }
1268 
1269  rDoc.DeleteAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
1270 
1271  bool bError = false;
1272  SCROW nDocRow = nStartRow;
1273  for (const uno::Sequence<OUString>& rColSeq : aData)
1274  {
1275  if ( rColSeq.getLength() == nCols )
1276  {
1277  SCCOL nDocCol = nStartCol;
1278  for (const OUString& aText : rColSeq)
1279  {
1280  ScAddress aPos( nDocCol, nDocRow, nTab );
1281 
1282  ScInputStringType aRes =
1284  *rDoc.GetFormatTable(), aText, LANGUAGE_ENGLISH_US);
1285  switch (aRes.meType)
1286  {
1288  rDoc.SetFormula(aPos, aRes.maText, eGrammar);
1289  break;
1291  rDoc.SetValue(aPos, aRes.mfValue);
1292  break;
1294  rDoc.SetTextCell(aPos, aRes.maText);
1295  break;
1296  default:
1297  ;
1298  }
1299 
1300  ++nDocCol;
1301  }
1302  }
1303  else
1304  bError = true; // wrong size
1305 
1306  ++nDocRow;
1307  }
1308 
1309  bool bHeight = rDocShell.AdjustRowHeight( nStartRow, nEndRow, nTab );
1310 
1311  if ( pUndoDoc )
1312  {
1313  ScMarkData aDestMark(rDoc.GetSheetLimits());
1314  aDestMark.SelectOneTable( nTab );
1315  rDocShell.GetUndoManager()->AddUndoAction(
1316  std::make_unique<ScUndoPaste>( &rDocShell,
1317  ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab), aDestMark,
1318  std::move(pUndoDoc), nullptr, InsertDeleteFlags::CONTENTS, nullptr, false));
1319  }
1320 
1321  if (!bHeight)
1322  rDocShell.PostPaint( rRange, PaintPartFlags::Grid ); // AdjustRowHeight may have painted already
1323 
1324  rDocShell.SetDocumentModified();
1325 
1326  return !bError;
1327 }
1328 
1329 // used in ScCellRangeObj::getFormulaArray and ScCellObj::GetInputString_Impl
1330 static OUString lcl_GetInputString( ScDocument& rDoc, const ScAddress& rPos, bool bEnglish )
1331 {
1332  ScRefCellValue aCell(rDoc, rPos);
1333  if (aCell.isEmpty())
1334  return EMPTY_OUSTRING;
1335 
1336  OUString aVal;
1337 
1338  CellType eType = aCell.meType;
1339  if (eType == CELLTYPE_FORMULA)
1340  {
1341  ScFormulaCell* pForm = aCell.mpFormula;
1342  pForm->GetFormula( aVal, formula::FormulaGrammar::mapAPItoGrammar( bEnglish, false));
1343  return aVal;
1344  }
1345 
1346  SvNumberFormatter* pFormatter = bEnglish ? ScGlobal::GetEnglishFormatter() :
1347  rDoc.GetFormatTable();
1348  // Since the English formatter was constructed with
1349  // LANGUAGE_ENGLISH_US the "General" format has index key 0,
1350  // we don't have to query.
1351  sal_uInt32 nNumFmt = bEnglish ? 0 : rDoc.GetNumberFormat(rPos);
1352 
1353  if (eType == CELLTYPE_EDIT)
1354  {
1355  // GetString on EditCell turns breaks into spaces,
1356  // but we need the breaks here
1357  const EditTextObject* pData = aCell.mpEditText;
1358  if (pData)
1359  {
1360  EditEngine& rEngine = rDoc.GetEditEngine();
1361  rEngine.SetText(*pData);
1362  aVal = rEngine.GetText();
1363  }
1364  }
1365  else
1366  ScCellFormat::GetInputString(aCell, nNumFmt, aVal, *pFormatter, rDoc);
1367 
1368  // if applicable, prepend ' like in ScTabViewShell::UpdateInputHandler
1369  if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
1370  {
1371  double fDummy;
1372  OUString aTempString = aVal;
1373  bool bIsNumberFormat(pFormatter->IsNumberFormat(aTempString, nNumFmt, fDummy));
1374  if ( bIsNumberFormat )
1375  aTempString = "'" + aTempString;
1376  else if ( aTempString.startsWith("'") )
1377  {
1378  // if the string starts with a "'", add another one because setFormula
1379  // strips one (like text input, except for "text" number formats)
1380  if ( bEnglish || ( pFormatter->GetType(nNumFmt) != SvNumFormatType::TEXT ) )
1381  aTempString = "'" + aTempString;
1382  }
1383  aVal = aTempString;
1384  }
1385  return aVal;
1386 }
1387 
1389  pPropSet(lcl_GetCellsPropertySet()),
1390  pDocShell( pDocSh ),
1391  nObjectId( 0 ),
1392  bChartColAsHdr( false ),
1393  bChartRowAsHdr( false ),
1394  bCursorOnly( false ),
1395  bGotDataChangedHint( false ),
1396  aValueListeners( 0 )
1397 {
1398  // this is a hack to get m_wThis initialized; ideally there would be
1399  // factory functions doing this but there are so many subclasses of this...
1400  osl_atomic_increment(&m_refCount);
1401  {
1402  m_wThis = uno::Reference<uno::XInterface>(
1403  static_cast<cppu::OWeakObject*>(this));
1404  }
1405  osl_atomic_decrement(&m_refCount);
1406 
1407  ScRange aCellRange(rR);
1408  aCellRange.PutInOrder();
1409  aRanges.push_back( aCellRange );
1410 
1411  if (pDocShell) // Null if created with createInstance
1412  {
1413  ScDocument& rDoc = pDocShell->GetDocument();
1414  rDoc.AddUnoObject(*this);
1415  nObjectId = rDoc.GetNewUnoId();
1416  }
1417 }
1418 
1420  pPropSet(lcl_GetCellsPropertySet()),
1421  pDocShell( pDocSh ),
1422  aRanges( rR ),
1423  nObjectId( 0 ),
1424  bChartColAsHdr( false ),
1425  bChartRowAsHdr( false ),
1426  bCursorOnly( false ),
1427  bGotDataChangedHint( false ),
1428  aValueListeners( 0 )
1429 {
1430  // this is a hack to get m_wThis initialized; ideally there would be
1431  // factory functions doing this but there are so many subclasses of this...
1432  osl_atomic_increment(&m_refCount);
1433  {
1434  m_wThis = uno::Reference<uno::XInterface>(
1435  static_cast<cppu::OWeakObject*>(this));
1436  }
1437  osl_atomic_decrement(&m_refCount);
1438 
1439  if (pDocShell) // Null if created with createInstance
1440  {
1441  ScDocument& rDoc = pDocShell->GetDocument();
1442  rDoc.AddUnoObject(*this);
1443  nObjectId = rDoc.GetNewUnoId();
1444  }
1445 }
1446 
1448 {
1449  SolarMutexGuard g;
1450 
1451  // call RemoveUnoObject first, so no notification can happen
1452  // during ForgetCurrentAttrs
1453 
1454  if (pDocShell)
1456 
1458  ForgetMarkData();
1459 
1460  pValueListener.reset();
1461 
1464 }
1465 
1467 {
1468  pCurrentFlat.reset();
1469  pCurrentDeep.reset();
1470  pCurrentDataSet.reset();
1471  pNoDfltCurrentDataSet.reset();
1472  pCurrentDataSet = nullptr;
1473  pNoDfltCurrentDataSet = nullptr;
1474 
1475  // #i62483# pMarkData can remain unchanged, is deleted only if the range changes (RefChanged)
1476 }
1477 
1479 {
1480  pMarkData.reset();
1481 }
1482 
1484 {
1485  // get and cache direct cell attributes for this object's range
1486 
1487  if ( !pCurrentFlat && pDocShell )
1488  {
1489  ScDocument& rDoc = pDocShell->GetDocument();
1490  pCurrentFlat = rDoc.CreateSelectionPattern( *GetMarkData(), false );
1491  }
1492  return pCurrentFlat.get();
1493 }
1494 
1496 {
1497  // get and cache cell attributes (incl. styles) for this object's range
1498 
1499  if ( !pCurrentDeep && pDocShell )
1500  {
1501  ScDocument& rDoc = pDocShell->GetDocument();
1503  }
1504  return pCurrentDeep.get();
1505 }
1506 
1508 {
1509  if(!pCurrentDataSet)
1510  {
1511  const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
1512  if ( pPattern )
1513  {
1514  // replace Dontcare with Default, so that we always have a reflection
1515  pCurrentDataSet.reset( new SfxItemSet( pPattern->GetItemSet() ) );
1516  pNoDfltCurrentDataSet.reset( new SfxItemSet( pPattern->GetItemSet() ) );
1517  pCurrentDataSet->ClearInvalidItems();
1518  }
1519  }
1520  return bNoDflt ? pNoDfltCurrentDataSet.get() : pCurrentDataSet.get();
1521 }
1522 
1524 {
1525  if (!pMarkData)
1526  {
1527  pMarkData.reset( new ScMarkData(GetDocument()->GetSheetLimits(), aRanges) );
1528  }
1529  return pMarkData.get();
1530 }
1531 
1533 {
1534  uno::Reference<uno::XInterface> const xThis(m_wThis);
1535  if (!xThis.is())
1536  { // fdo#72695: if UNO object is already dead, don't revive it with event
1537  if (SfxHintId::Dying == rHint.GetId())
1538  { // if the document dies, must reset to avoid crash in dtor!
1540  pDocShell = nullptr;
1541  }
1542  return;
1543  }
1544  if ( auto pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint) )
1545  {
1546  ScDocument& rDoc = pDocShell->GetDocument();
1547  std::unique_ptr<ScRangeList> pUndoRanges;
1548  if ( rDoc.HasUnoRefUndo() )
1549  pUndoRanges.reset(new ScRangeList( aRanges ));
1550 
1551  if ( aRanges.UpdateReference( pRefHint->GetMode(), &rDoc, pRefHint->GetRange(),
1552  pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() ) )
1553  {
1554  if ( pRefHint->GetMode() == URM_INSDEL
1555  && aRanges.size() == 1
1556  && comphelper::getUnoTunnelImplementation<ScTableSheetObj>(xThis)
1557  )
1558  {
1559  // #101755#; the range size of a sheet does not change
1560  ScRange & rR = aRanges.front();
1561  rR.aStart.SetCol(0);
1562  rR.aStart.SetRow(0);
1563  rR.aEnd.SetCol(rDoc.MaxCol());
1564  rR.aEnd.SetRow(rDoc.MaxRow());
1565  }
1566  RefChanged();
1567 
1568  // any change of the range address is broadcast to value (modify) listeners
1569  if ( !aValueListeners.empty() )
1570  bGotDataChangedHint = true;
1571 
1572  if ( pUndoRanges )
1573  rDoc.AddUnoRefChange( nObjectId, *pUndoRanges );
1574  }
1575  }
1576  else if ( auto pUndoHint = dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
1577  {
1578  if ( pUndoHint->GetObjectId() == nObjectId )
1579  {
1580  // restore ranges from hint
1581 
1582  aRanges = pUndoHint->GetRanges();
1583 
1584  RefChanged();
1585  if ( !aValueListeners.empty() )
1586  bGotDataChangedHint = true; // need to broadcast the undo, too
1587  }
1588  }
1589  else
1590  {
1591  const SfxHintId nId = rHint.GetId();
1592  if ( nId == SfxHintId::Dying )
1593  {
1595  pDocShell = nullptr; // invalid
1596 
1597  if ( !aValueListeners.empty() )
1598  {
1599  // dispose listeners
1600 
1601  lang::EventObject aEvent;
1602  aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
1603  for (uno::Reference<util::XModifyListener> & xValueListener : aValueListeners)
1604  xValueListener->disposing( aEvent );
1605 
1606  aValueListeners.clear();
1607 
1608  // The listeners can't have the last ref to this, as it's still held
1609  // by the DocShell.
1610  }
1611  }
1612  else if ( nId == SfxHintId::DataChanged )
1613  {
1614  // document content changed -> forget cached attributes
1616 
1617  if ( bGotDataChangedHint && pDocShell )
1618  {
1619  // This object was notified of content changes, so one call
1620  // for each listener is generated now.
1621  // The calls can't be executed directly because the document's
1622  // UNO broadcaster list must not be modified.
1623  // Instead, add to the document's list of listener calls,
1624  // which will be executed directly after the broadcast of
1625  // SfxHintId::DataChanged.
1626 
1627  lang::EventObject aEvent;
1628  aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
1629 
1630  // the EventObject holds a Ref to this object until after the listener calls
1631 
1632  ScDocument& rDoc = pDocShell->GetDocument();
1633  for (const uno::Reference<util::XModifyListener> & xValueListener : aValueListeners)
1634  rDoc.AddUnoListenerCall( xValueListener, aEvent );
1635 
1636  bGotDataChangedHint = false;
1637  }
1638  }
1639  else if ( nId == SfxHintId::ScCalcAll )
1640  {
1641  // broadcast from DoHardRecalc - set bGotDataChangedHint
1642  // (SfxHintId::DataChanged follows separately)
1643 
1644  if ( !aValueListeners.empty() )
1645  bGotDataChangedHint = true;
1646  }
1647  }
1648 }
1649 
1651 {
1653 
1654  if ( pValueListener && !aValueListeners.empty() )
1655  {
1656  pValueListener->EndListeningAll();
1657 
1658  ScDocument& rDoc = pDocShell->GetDocument();
1659  for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
1660  rDoc.StartListeningArea( aRanges[ i ], false, pValueListener.get() );
1661  }
1662 
1664  ForgetMarkData();
1665 }
1666 
1668 {
1669  if (pDocShell)
1670  return &pDocShell->GetDocument();
1671  else
1672  return nullptr;
1673 }
1674 
1676 {
1677  if ( pDocShell || !pDocSh )
1678  return;
1679 
1680  pDocShell = pDocSh;
1681 
1682  ScRange aCellRange(rR);
1683  aCellRange.PutInOrder();
1684  aRanges.RemoveAll();
1685  aRanges.push_back( aCellRange );
1686 
1688 
1689  RefChanged(); // adjust range in range object
1690 }
1691 
1692 void ScCellRangesBase::AddRange(const ScRange& rRange, const bool bMergeRanges)
1693 {
1694  if (bMergeRanges)
1695  aRanges.Join(rRange);
1696  else
1697  aRanges.push_back(rRange);
1698  RefChanged();
1699 }
1700 
1702 {
1703  ScRange aCellRange(rNew);
1704  aCellRange.PutInOrder();
1705 
1706  aRanges.RemoveAll();
1707  aRanges.push_back( aCellRange );
1708  RefChanged();
1709 }
1710 
1712 {
1713  aRanges = rNew;
1714  RefChanged();
1715 }
1716 
1718 {
1719  // set for a selection object that is created from the cursor position
1720  // without anything selected (may contain several sheets)
1721 
1722  bCursorOnly = bSet;
1723 }
1724 
1726 {
1727  for (size_t i = 0, nCount = aRanges.size(); i < nCount; ++i)
1729 }
1730 
1731 // XSheetOperation
1732 
1733 double SAL_CALL ScCellRangesBase::computeFunction( sheet::GeneralFunction nFunction )
1734 {
1735  SolarMutexGuard aGuard;
1736  ScMarkData aMark(*GetMarkData());
1737  aMark.MarkToSimple();
1738  if (!aMark.IsMarked())
1739  aMark.SetMarkNegative(true); // so we can enter dummy position
1740 
1741  ScAddress aDummy; // if not marked, ignored if it is negative
1742  double fVal;
1743  ScSubTotalFunc eFunc = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(nFunction));
1744  ScDocument& rDoc = pDocShell->GetDocument();
1745  if ( !rDoc.GetSelectionFunction( eFunc, aDummy, aMark, fVal ) )
1746  {
1747  throw uno::RuntimeException();
1748  }
1749 
1750  return fVal;
1751 }
1752 
1753 void SAL_CALL ScCellRangesBase::clearContents( sal_Int32 nContentFlags )
1754 {
1755  SolarMutexGuard aGuard;
1756  if ( !aRanges.empty() )
1757  {
1758  // only for clearContents: EDITATTR is only used if no contents are deleted
1759  InsertDeleteFlags nDelFlags = static_cast<InsertDeleteFlags>(nContentFlags) & InsertDeleteFlags::ALL;
1760  if ( ( nDelFlags & InsertDeleteFlags::EDITATTR ) && ( nDelFlags & InsertDeleteFlags::CONTENTS ) == InsertDeleteFlags::NONE )
1761  nDelFlags |= InsertDeleteFlags::EDITATTR;
1762 
1763  pDocShell->GetDocFunc().DeleteContents( *GetMarkData(), nDelFlags, true, true );
1764  }
1765  // otherwise nothing to do
1766 }
1767 
1768 // XPropertyState
1769 
1771 {
1772  return pPropSet->getPropertyMap();
1773 }
1774 
1776  sal_uInt16& rItemWhich )
1777 {
1778  // Which-ID of the affected items also when the item can't handle
1779  // the property by itself
1780  if ( !pEntry )
1781  return;
1782 
1783  if ( IsScItemWid( pEntry->nWID ) )
1784  rItemWhich = pEntry->nWID;
1785  else
1786  switch ( pEntry->nWID )
1787  {
1788  case SC_WID_UNO_TBLBORD:
1789  case SC_WID_UNO_TBLBORD2:
1790  rItemWhich = ATTR_BORDER;
1791  break;
1792  case SC_WID_UNO_CONDFMT:
1793  case SC_WID_UNO_CONDLOC:
1794  case SC_WID_UNO_CONDXML:
1795  rItemWhich = ATTR_CONDITIONAL;
1796  break;
1797  case SC_WID_UNO_VALIDAT:
1798  case SC_WID_UNO_VALILOC:
1799  case SC_WID_UNO_VALIXML:
1800  rItemWhich = ATTR_VALIDDATA;
1801  break;
1802  }
1803 
1804 }
1805 
1806 beans::PropertyState ScCellRangesBase::GetOnePropertyState( sal_uInt16 nItemWhich, const SfxItemPropertyMapEntry* pEntry )
1807 {
1808  beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
1809  if ( nItemWhich ) // item wid (from map or special case)
1810  {
1811  // For items that contain several properties (like background),
1812  // "ambiguous" is returned too often here
1813 
1814  // for PropertyState, don't look at styles
1815  const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
1816  if ( pPattern )
1817  {
1818  SfxItemState eState = pPattern->GetItemSet().GetItemState( nItemWhich, false );
1819 
1820  if ( nItemWhich == ATTR_VALUE_FORMAT && eState == SfxItemState::DEFAULT )
1821  eState = pPattern->GetItemSet().GetItemState( ATTR_LANGUAGE_FORMAT, false );
1822 
1823  if ( eState == SfxItemState::SET )
1824  eRet = beans::PropertyState_DIRECT_VALUE;
1825  else if ( eState == SfxItemState::DEFAULT )
1826  eRet = beans::PropertyState_DEFAULT_VALUE;
1827  else if ( eState == SfxItemState::DONTCARE )
1828  eRet = beans::PropertyState_AMBIGUOUS_VALUE;
1829  else
1830  {
1831  OSL_FAIL("unknown ItemState");
1832  }
1833  }
1834  }
1835  else if ( pEntry )
1836  {
1837  if ( pEntry->nWID == SC_WID_UNO_CHCOLHDR || pEntry->nWID == SC_WID_UNO_CHROWHDR || pEntry->nWID == SC_WID_UNO_ABSNAME )
1838  eRet = beans::PropertyState_DIRECT_VALUE;
1839  else if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
1840  {
1841  // a style is always set, there's no default state
1843  if (pStyle)
1844  eRet = beans::PropertyState_DIRECT_VALUE;
1845  else
1846  eRet = beans::PropertyState_AMBIGUOUS_VALUE;
1847  }
1848  else if ( pEntry->nWID == SC_WID_UNO_NUMRULES )
1849  eRet = beans::PropertyState_DEFAULT_VALUE; // numbering rules are always default
1850  }
1851  return eRet;
1852 }
1853 
1854 beans::PropertyState SAL_CALL ScCellRangesBase::getPropertyState( const OUString& aPropertyName )
1855 {
1856  SolarMutexGuard aGuard;
1857  if ( aRanges.empty() )
1858  throw uno::RuntimeException();
1859 
1860  const SfxItemPropertyMap& rMap = GetItemPropertyMap(); // from derived class
1861  sal_uInt16 nItemWhich = 0;
1862  const SfxItemPropertyMapEntry* pEntry = rMap.getByName( aPropertyName );
1863  lcl_GetPropertyWhich( pEntry, nItemWhich );
1864  return GetOnePropertyState( nItemWhich, pEntry );
1865 }
1866 
1867 uno::Sequence<beans::PropertyState> SAL_CALL ScCellRangesBase::getPropertyStates(
1868  const uno::Sequence<OUString>& aPropertyNames )
1869 {
1870  SolarMutexGuard aGuard;
1871 
1872  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
1873 
1874  uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
1875  std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.begin(),
1876  [this, &rPropertyMap](const auto& rName) -> beans::PropertyState {
1877  sal_uInt16 nItemWhich = 0;
1878  const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( rName );
1879  lcl_GetPropertyWhich( pEntry, nItemWhich );
1880  return GetOnePropertyState(nItemWhich, pEntry);
1881  });
1882  return aRet;
1883 }
1884 
1885 void SAL_CALL ScCellRangesBase::setPropertyToDefault( const OUString& aPropertyName )
1886 {
1887  SolarMutexGuard aGuard;
1888  if ( !pDocShell )
1889  return;
1890 
1891  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
1892  sal_uInt16 nItemWhich = 0;
1893  const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
1894  lcl_GetPropertyWhich( pEntry, nItemWhich );
1895  if ( nItemWhich ) // item wid (from map or special case)
1896  {
1897  if ( !aRanges.empty() ) // empty = nothing to do
1898  {
1902 
1903  sal_uInt16 aWIDs[3];
1904  aWIDs[0] = nItemWhich;
1905  if ( nItemWhich == ATTR_VALUE_FORMAT )
1906  {
1907  aWIDs[1] = ATTR_LANGUAGE_FORMAT; // language for number formats
1908  aWIDs[2] = 0;
1909  }
1910  else
1911  aWIDs[1] = 0;
1912  pDocShell->GetDocFunc().ClearItems( *GetMarkData(), aWIDs, true );
1913  }
1914  }
1915  else if ( pEntry )
1916  {
1917  if ( pEntry->nWID == SC_WID_UNO_CHCOLHDR )
1918  bChartColAsHdr = false;
1919  else if ( pEntry->nWID == SC_WID_UNO_CHROWHDR )
1920  bChartRowAsHdr = false;
1921  else if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
1922  {
1923  OUString aStyleName( ScResId( STR_STYLENAME_STANDARD ) );
1924  pDocShell->GetDocFunc().ApplyStyle( *GetMarkData(), aStyleName, true );
1925  }
1926  }
1927 }
1928 
1929 uno::Any SAL_CALL ScCellRangesBase::getPropertyDefault( const OUString& aPropertyName )
1930 {
1932 
1933  SolarMutexGuard aGuard;
1934  uno::Any aAny;
1935 
1936  if ( pDocShell )
1937  {
1938  ScDocument& rDoc = pDocShell->GetDocument();
1939  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
1940  const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
1941  if ( pEntry )
1942  {
1943  if ( IsScItemWid( pEntry->nWID ) )
1944  {
1945  const ScPatternAttr* pPattern = rDoc.GetDefPattern();
1946  if ( pPattern )
1947  {
1948  const SfxItemSet& rSet = pPattern->GetItemSet();
1949 
1950  switch ( pEntry->nWID ) // for item-specific handling
1951  {
1952  case ATTR_VALUE_FORMAT:
1953  // default has no language set
1954  aAny <<= static_cast<sal_Int32>( static_cast<const SfxUInt32Item&>(rSet.Get(pEntry->nWID)).GetValue() );
1955  break;
1956  case ATTR_INDENT:
1957  aAny <<= static_cast<sal_Int16>( convertTwipToMm100(static_cast<const ScIndentItem&>(
1958  rSet.Get(pEntry->nWID)).GetValue()) );
1959  break;
1960  default:
1961  pPropSet->getPropertyValue(aPropertyName, rSet, aAny);
1962  }
1963  }
1964  }
1965  else
1966  switch ( pEntry->nWID )
1967  {
1968  case SC_WID_UNO_CHCOLHDR:
1969  case SC_WID_UNO_CHROWHDR:
1970  aAny <<= false;
1971  break;
1972  case SC_WID_UNO_CELLSTYL:
1974  ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Para );
1975  break;
1976  case SC_WID_UNO_TBLBORD:
1977  case SC_WID_UNO_TBLBORD2:
1978  {
1979  const ScPatternAttr* pPattern = rDoc.GetDefPattern();
1980  if ( pPattern )
1981  {
1982  if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
1984  pPattern->GetItem(ATTR_BORDER),
1985  pPattern->GetItem(ATTR_BORDER_INNER) );
1986  else
1988  pPattern->GetItem(ATTR_BORDER),
1989  pPattern->GetItem(ATTR_BORDER_INNER) );
1990  }
1991  }
1992  break;
1993  case SC_WID_UNO_CONDFMT:
1994  case SC_WID_UNO_CONDLOC:
1995  case SC_WID_UNO_CONDXML:
1996  {
1997  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
1998  bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
1999  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2000  rDoc.GetStorageGrammar() :
2001  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2002 
2003  aAny <<= uno::Reference<sheet::XSheetConditionalEntries>(
2004  new ScTableConditionalFormat( &rDoc, 0, aRanges[0].aStart.Tab(), eGrammar ));
2005  }
2006  break;
2007  case SC_WID_UNO_VALIDAT:
2008  case SC_WID_UNO_VALILOC:
2009  case SC_WID_UNO_VALIXML:
2010  {
2011  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
2012  bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
2013  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2014  rDoc.GetStorageGrammar() :
2015  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2016 
2017  aAny <<= uno::Reference<beans::XPropertySet>(
2018  new ScTableValidationObj( rDoc, 0, eGrammar ));
2019  }
2020  break;
2021  case SC_WID_UNO_NUMRULES:
2022  {
2024  }
2025  break;
2026  }
2027  }
2028  }
2029 
2030  return aAny;
2031 }
2032 
2033 // XPropertySet
2034 
2035 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellRangesBase::getPropertySetInfo()
2036 {
2037  SolarMutexGuard aGuard;
2038  static uno::Reference<beans::XPropertySetInfo> aRef(
2040  return aRef;
2041 }
2042 
2043 static void lcl_SetCellProperty( const SfxItemPropertyMapEntry& rEntry, const uno::Any& rValue,
2044  ScPatternAttr& rPattern, const ScDocument &rDoc,
2045  sal_uInt16& rFirstItemId, sal_uInt16& rSecondItemId )
2046 {
2047  rFirstItemId = rEntry.nWID;
2048  rSecondItemId = 0;
2049 
2050  SfxItemSet& rSet = rPattern.GetItemSet();
2051  switch ( rEntry.nWID )
2052  {
2053  case ATTR_VALUE_FORMAT:
2054  {
2055  // language for number formats
2056  SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
2057  sal_uLong nOldFormat = rSet.Get( ATTR_VALUE_FORMAT ).GetValue();
2058  LanguageType eOldLang = rSet.Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
2059  nOldFormat = pFormatter->GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
2060 
2061  sal_Int32 nIntVal = 0;
2062  if ( !(rValue >>= nIntVal) )
2063  throw lang::IllegalArgumentException();
2064 
2065  sal_uLong nNewFormat = static_cast<sal_uLong>(nIntVal);
2066  rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
2067 
2068  const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
2069  LanguageType eNewLang =
2070  pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
2071  if ( eNewLang != eOldLang && eNewLang != LANGUAGE_DONTKNOW )
2072  {
2073  rSet.Put( SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
2074 
2075  // if only language is changed,
2076  // don't touch number format attribute
2077  sal_uLong nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
2078  if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
2079  nNewMod <= SV_MAX_COUNT_STANDARD_FORMATS )
2080  {
2081  rFirstItemId = 0; // don't use ATTR_VALUE_FORMAT value
2082  }
2083 
2084  rSecondItemId = ATTR_LANGUAGE_FORMAT;
2085  }
2086 
2087  }
2088  break;
2089  case ATTR_INDENT:
2090  {
2091  sal_Int16 nIntVal = 0;
2092  if ( !(rValue >>= nIntVal) )
2093  throw lang::IllegalArgumentException();
2094 
2095  rSet.Put(ScIndentItem(static_cast<sal_uInt16>(convertMm100ToTwip(nIntVal))));
2096 
2097  }
2098  break;
2099  case ATTR_ROTATE_VALUE:
2100  {
2101  sal_Int32 nRotVal = 0;
2102  if ( !(rValue >>= nRotVal) )
2103  throw lang::IllegalArgumentException();
2104 
2105  // stored value is always between 0 and 360 deg.
2106  nRotVal %= 36000;
2107  if ( nRotVal < 0 )
2108  nRotVal += 36000;
2109 
2110  rSet.Put( ScRotateValueItem( Degree100(nRotVal) ) );
2111 
2112  }
2113  break;
2114  case ATTR_STACKED:
2115  {
2116  table::CellOrientation eOrient;
2117  if( rValue >>= eOrient )
2118  {
2119  switch( eOrient )
2120  {
2121  case table::CellOrientation_STANDARD:
2122  rSet.Put( ScVerticalStackCell( false ) );
2123  break;
2124  case table::CellOrientation_TOPBOTTOM:
2125  rSet.Put( ScVerticalStackCell( false ) );
2126  rSet.Put( ScRotateValueItem( 27000_deg100 ) );
2127  rSecondItemId = ATTR_ROTATE_VALUE;
2128  break;
2129  case table::CellOrientation_BOTTOMTOP:
2130  rSet.Put( ScVerticalStackCell( false ) );
2131  rSet.Put( ScRotateValueItem( 9000_deg100 ) );
2132  rSecondItemId = ATTR_ROTATE_VALUE;
2133  break;
2134  case table::CellOrientation_STACKED:
2135  rSet.Put( ScVerticalStackCell( true ) );
2136  break;
2137  default:
2138  {
2139  // added to avoid warnings
2140  }
2141  }
2142  }
2143  }
2144  break;
2145  default:
2146  {
2147  lcl_GetCellsPropertySet()->setPropertyValue(rEntry, rValue, rSet);
2148  }
2149  }
2150 }
2151 
2153  const OUString& aPropertyName, const uno::Any& aValue )
2154 {
2155  SolarMutexGuard aGuard;
2156 
2157  if ( !pDocShell || aRanges.empty() )
2158  throw uno::RuntimeException();
2159 
2160  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2161  const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
2162  if ( !pEntry )
2163  throw beans::UnknownPropertyException(aPropertyName);
2164 
2165  SetOnePropertyValue( pEntry, aValue );
2166 }
2167 
2169 {
2170  if ( !pEntry )
2171  return;
2172 
2173  if ( IsScItemWid( pEntry->nWID ) )
2174  {
2175  if ( !aRanges.empty() ) // empty = nothing to do
2176  {
2177  ScDocument& rDoc = pDocShell->GetDocument();
2178 
2179  // For parts of compound items with multiple properties (e.g. background)
2180  // the old item has to be first fetched from the document.
2184  // ClearInvalidItems, so that in any case we have an item with the correct type
2185 
2186  ScPatternAttr aPattern( *GetCurrentAttrsDeep() );
2187  SfxItemSet& rSet = aPattern.GetItemSet();
2188  rSet.ClearInvalidItems();
2189 
2190  sal_uInt16 nFirstItem, nSecondItem;
2191  lcl_SetCellProperty( *pEntry, aValue, aPattern, rDoc, nFirstItem, nSecondItem );
2192 
2193  for (sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++)
2194  if ( nWhich != nFirstItem && nWhich != nSecondItem )
2195  rSet.ClearItem(nWhich);
2196 
2197  pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), aPattern, true );
2198  }
2199  }
2200  else // implemented here
2201  switch ( pEntry->nWID )
2202  {
2203  case EE_CHAR_ESCAPEMENT: // Specifically for xlsx import
2204  {
2205  sal_Int32 nValue = 0;
2206  aValue >>= nValue;
2207  if (nValue)
2208  {
2209  for (size_t i = 0, n = aRanges.size(); i < n; ++i)
2210  {
2211  ScRange const & rRange = aRanges[i];
2212 
2213  /* TODO: Iterate through the range */
2214  ScAddress aAddr = rRange.aStart;
2215  ScDocument& rDoc = pDocShell->GetDocument();
2216  ScRefCellValue aCell(rDoc, aAddr);
2217 
2218  OUString aStr = aCell.getString(&rDoc);
2219  EditEngine aEngine( rDoc.GetEnginePool() );
2220  aEngine.SetEditTextObjectPool(rDoc.GetEditPool());
2221 
2222  /* EE_CHAR_ESCAPEMENT seems to be set on the cell _only_ when
2223  * there are no other attribs for the cell.
2224  * So, it is safe to overwrite the complete attribute set.
2225  * If there is a need - getting CellType and processing
2226  * the attributes could be considered.
2227  */
2228  SfxItemSet aAttr = aEngine.GetEmptyItemSet();
2229  aEngine.SetText(aStr);
2230  if( nValue < 0 ) // Subscript
2231  aAttr.Put( SvxEscapementItem( SvxEscapement::Subscript, EE_CHAR_ESCAPEMENT ) );
2232  else // Superscript
2233  aAttr.Put( SvxEscapementItem( SvxEscapement::Superscript, EE_CHAR_ESCAPEMENT ) );
2234  aEngine.QuickSetAttribs(aAttr, ESelection(0, 0, 0, aStr.getLength()));
2235 
2236  // The cell will own the text object instance.
2237  rDoc.SetEditText(aRanges[0].aStart, aEngine.CreateTextObject());
2238  }
2239  }
2240  }
2241  break;
2242  case SC_WID_UNO_CHCOLHDR:
2243  // chart header flags are set for this object, not stored with document
2245  break;
2246  case SC_WID_UNO_CHROWHDR:
2248  break;
2249  case SC_WID_UNO_CELLSTYL:
2250  {
2251  OUString aStrVal;
2252  aValue >>= aStrVal;
2254  aStrVal, SfxStyleFamily::Para ));
2255  pDocShell->GetDocFunc().ApplyStyle( *GetMarkData(), aString, true );
2256  }
2257  break;
2258  case SC_WID_UNO_TBLBORD:
2259  {
2260  table::TableBorder aBorder;
2261  if ( !aRanges.empty() && ( aValue >>= aBorder ) ) // empty = nothing to do
2262  {
2263  SvxBoxItem aOuter(ATTR_BORDER);
2265  ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder );
2266 
2267  ScHelperFunctions::ApplyBorder( pDocShell, aRanges, aOuter, aInner );
2268  }
2269  }
2270  break;
2271  case SC_WID_UNO_TBLBORD2:
2272  {
2273  table::TableBorder2 aBorder2;
2274  if ( !aRanges.empty() && ( aValue >>= aBorder2 ) ) // empty = nothing to do
2275  {
2276  SvxBoxItem aOuter(ATTR_BORDER);
2278  ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder2 );
2279 
2280  ScHelperFunctions::ApplyBorder( pDocShell, aRanges, aOuter, aInner );
2281  }
2282  }
2283  break;
2284  case SC_WID_UNO_CONDFMT:
2285  case SC_WID_UNO_CONDLOC:
2286  case SC_WID_UNO_CONDXML:
2287  {
2288  uno::Reference<sheet::XSheetConditionalEntries> xInterface(aValue, uno::UNO_QUERY);
2289  if ( !aRanges.empty() && xInterface.is() ) // empty = nothing to do
2290  {
2291  ScTableConditionalFormat* pFormat =
2292  comphelper::getUnoTunnelImplementation<ScTableConditionalFormat>( xInterface );
2293  if (pFormat)
2294  {
2295  ScDocument& rDoc = pDocShell->GetDocument();
2296  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
2297  bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
2298  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2300  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2301 
2302  SCTAB nTab = aRanges.front().aStart.Tab();
2303  // To remove conditional formats for all cells in aRanges we need to:
2304  // Remove conditional format data from cells' attributes
2305  rDoc.RemoveCondFormatData( aRanges, nTab, 0 );
2306  // And also remove ranges from conditional formats list
2307  for (size_t i = 0; i < aRanges.size(); ++i)
2308  {
2309  rDoc.GetCondFormList( aRanges[i].aStart.Tab() )->DeleteArea(
2310  aRanges[i].aStart.Col(), aRanges[i].aStart.Row(),
2311  aRanges[i].aEnd.Col(), aRanges[i].aEnd.Row() );
2312  }
2313 
2314  // Then we can apply new conditional format if there is one
2315  if (pFormat->getCount())
2316  {
2317  auto pNew = std::make_unique<ScConditionalFormat>( 0, &rDoc ); // Index will be set on inserting
2318  pFormat->FillFormat( *pNew, rDoc, eGrammar );
2319  pNew->SetRange( aRanges );
2320  pDocShell->GetDocFunc().ReplaceConditionalFormat( 0, std::move(pNew), nTab, aRanges );
2321  }
2322 
2323  // and repaint
2324  for (size_t i = 0; i < aRanges.size(); ++i)
2327  }
2328  }
2329  }
2330  break;
2331  case SC_WID_UNO_VALIDAT:
2332  case SC_WID_UNO_VALILOC:
2333  case SC_WID_UNO_VALIXML:
2334  {
2335  uno::Reference<beans::XPropertySet> xInterface(aValue, uno::UNO_QUERY);
2336  if ( !aRanges.empty() && xInterface.is() ) // empty = nothing to do
2337  {
2338  ScTableValidationObj* pValidObj =
2339  comphelper::getUnoTunnelImplementation<ScTableValidationObj>( xInterface );
2340  if (pValidObj)
2341  {
2342  ScDocument& rDoc = pDocShell->GetDocument();
2343  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
2344  bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
2345  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2347  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2348 
2349  std::unique_ptr<ScValidationData> pNewData(
2350  pValidObj->CreateValidationData( rDoc, eGrammar ));
2351  sal_uLong nIndex = rDoc.AddValidationEntry( *pNewData );
2352  pNewData.reset();
2353 
2354  ScPatternAttr aPattern( rDoc.GetPool() );
2355  aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nIndex ) );
2356  pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), aPattern, true );
2357  }
2358  }
2359  }
2360  break;
2361  // SC_WID_UNO_NUMRULES is ignored...
2362  }
2363 }
2364 
2365 uno::Any SAL_CALL ScCellRangesBase::getPropertyValue( const OUString& aPropertyName )
2366 {
2367  SolarMutexGuard aGuard;
2368 
2369  if ( !pDocShell || aRanges.empty() )
2370  throw uno::RuntimeException();
2371 
2372  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2373  const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
2374  if ( !pEntry )
2375  throw beans::UnknownPropertyException(aPropertyName);
2376 
2377  uno::Any aAny;
2378  GetOnePropertyValue( pEntry, aAny );
2379  return aAny;
2380 }
2381 
2383 {
2384  if ( !pEntry )
2385  return;
2386 
2387  if ( IsScItemWid( pEntry->nWID ) )
2388  {
2389  SfxItemSet* pDataSet = GetCurrentDataSet();
2390  if ( pDataSet )
2391  {
2392  switch ( pEntry->nWID ) // for special handling of items
2393  {
2394  case ATTR_VALUE_FORMAT:
2395  {
2396  ScDocument& rDoc = pDocShell->GetDocument();
2397 
2398  sal_uLong nOldFormat =
2399  pDataSet->Get( ATTR_VALUE_FORMAT ).GetValue();
2400  LanguageType eOldLang =
2401  pDataSet->Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
2402  nOldFormat = rDoc.GetFormatTable()->
2403  GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
2404  rAny <<= static_cast<sal_Int32>(nOldFormat);
2405  }
2406  break;
2407  case ATTR_INDENT:
2408  rAny <<= static_cast<sal_Int16>( convertTwipToMm100(static_cast<const ScIndentItem&>(
2409  pDataSet->Get(pEntry->nWID)).GetValue()) );
2410  break;
2411  case ATTR_STACKED:
2412  {
2413  Degree100 nRot = pDataSet->Get(ATTR_ROTATE_VALUE).GetValue();
2414  bool bStacked = static_cast<const ScVerticalStackCell&>(pDataSet->Get(pEntry->nWID)).GetValue();
2415  SvxOrientationItem( nRot, bStacked, 0 ).QueryValue( rAny );
2416  }
2417  break;
2418  default:
2419  pPropSet->getPropertyValue(*pEntry, *pDataSet, rAny);
2420  }
2421  }
2422  }
2423  else // implemented here
2424  switch ( pEntry->nWID )
2425  {
2426  case SC_WID_UNO_CHCOLHDR:
2427  rAny <<= bChartColAsHdr;
2428  break;
2429  case SC_WID_UNO_CHROWHDR:
2430  rAny <<= bChartRowAsHdr;
2431  break;
2432  case SC_WID_UNO_CELLSTYL:
2433  {
2434  OUString aStyleName;
2436  if (pStyle)
2437  aStyleName = pStyle->GetName();
2439  aStyleName, SfxStyleFamily::Para );
2440  }
2441  break;
2442  case SC_WID_UNO_TBLBORD:
2443  case SC_WID_UNO_TBLBORD2:
2444  {
2446  if ( !aRanges.empty() )
2447  {
2448  const ScRange & rFirst = aRanges[ 0 ];
2449  SvxBoxItem aOuter(ATTR_BORDER);
2451 
2452  ScDocument& rDoc = pDocShell->GetDocument();
2453  ScMarkData aMark(rDoc.GetSheetLimits());
2454  aMark.SetMarkArea( rFirst );
2455  aMark.SelectTable( rFirst.aStart.Tab(), true );
2456  rDoc.GetSelectionFrame( aMark, aOuter, aInner );
2457 
2458  if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
2459  ScHelperFunctions::AssignTableBorder2ToAny( rAny, aOuter, aInner);
2460  else
2461  ScHelperFunctions::AssignTableBorderToAny( rAny, aOuter, aInner);
2462  }
2463  }
2464  break;
2465  case SC_WID_UNO_CONDFMT:
2466  case SC_WID_UNO_CONDLOC:
2467  case SC_WID_UNO_CONDXML:
2468  {
2469  const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
2470  if ( pPattern )
2471  {
2472  ScDocument& rDoc = pDocShell->GetDocument();
2473  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
2474  bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
2475  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2476  rDoc.GetStorageGrammar() :
2477  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2478  const ScCondFormatIndexes& rIndex =
2479  pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
2480  sal_uLong nIndex = 0;
2481  if(!rIndex.empty())
2482  nIndex = rIndex[0];
2483  rAny <<= uno::Reference<sheet::XSheetConditionalEntries>(
2484  new ScTableConditionalFormat( &rDoc, nIndex, aRanges.front().aStart.Tab(), eGrammar ));
2485  }
2486  }
2487  break;
2488  case SC_WID_UNO_VALIDAT:
2489  case SC_WID_UNO_VALILOC:
2490  case SC_WID_UNO_VALIXML:
2491  {
2492  const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
2493  if ( pPattern )
2494  {
2495  ScDocument& rDoc = pDocShell->GetDocument();
2496  bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
2497  bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
2498  formula::FormulaGrammar::Grammar eGrammar = (bXML ?
2499  rDoc.GetStorageGrammar() :
2500  formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
2501  sal_uLong nIndex =
2502  pPattern->GetItem(ATTR_VALIDDATA).GetValue();
2503  rAny <<= uno::Reference<beans::XPropertySet>(
2504  new ScTableValidationObj( rDoc, nIndex, eGrammar ));
2505  }
2506  }
2507  break;
2508  case SC_WID_UNO_NUMRULES:
2509  {
2510  // always return empty numbering rules object
2512  }
2513  break;
2514  case SC_WID_UNO_ABSNAME:
2515  {
2516  OUString sRet;
2518  rAny <<= sRet;
2519  }
2520  break;
2521  case SC_WID_UNO_FORMATID:
2522  {
2523  const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
2524  rAny <<= pPattern->GetKey();
2525  }
2526  break;
2527  }
2528 }
2529 
2530 void SAL_CALL ScCellRangesBase::addPropertyChangeListener( const OUString& /* aPropertyName */,
2531  const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
2532 {
2533  SolarMutexGuard aGuard;
2534  if ( aRanges.empty() )
2535  throw uno::RuntimeException();
2536 
2537  OSL_FAIL("not implemented");
2538 }
2539 
2540 void SAL_CALL ScCellRangesBase::removePropertyChangeListener( const OUString& /* aPropertyName */,
2541  const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
2542 {
2543  SolarMutexGuard aGuard;
2544  if ( aRanges.empty() )
2545  throw uno::RuntimeException();
2546 
2547  OSL_FAIL("not implemented");
2548 }
2549 
2550 void SAL_CALL ScCellRangesBase::addVetoableChangeListener( const OUString&,
2551  const uno::Reference<beans::XVetoableChangeListener>&)
2552 {
2553  OSL_FAIL("not implemented");
2554 }
2555 
2556 void SAL_CALL ScCellRangesBase::removeVetoableChangeListener( const OUString&,
2557  const uno::Reference<beans::XVetoableChangeListener>&)
2558 {
2559  OSL_FAIL("not implemented");
2560 }
2561 
2562 // XMultiPropertySet
2563 
2564 void SAL_CALL ScCellRangesBase::setPropertyValues( const uno::Sequence< OUString >& aPropertyNames,
2565  const uno::Sequence< uno::Any >& aValues )
2566 {
2567  SolarMutexGuard aGuard;
2568 
2569  sal_Int32 nCount(aPropertyNames.getLength());
2570  sal_Int32 nValues(aValues.getLength());
2571  if (nCount != nValues)
2572  throw lang::IllegalArgumentException();
2573 
2574  if ( !(pDocShell && nCount) )
2575  return;
2576 
2577  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2578  const OUString* pNames = aPropertyNames.getConstArray();
2579  const uno::Any* pValues = aValues.getConstArray();
2580 
2581  std::unique_ptr<const SfxItemPropertyMapEntry*[]> pEntryArray(new const SfxItemPropertyMapEntry*[nCount]);
2582 
2583  sal_Int32 i;
2584  for(i = 0; i < nCount; i++)
2585  {
2586  // first loop: find all properties in map, but handle only CellStyle
2587  // (CellStyle must be set before any other cell properties)
2588 
2589  const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( pNames[i] );
2590  pEntryArray[i] = pEntry;
2591  if (pEntry)
2592  {
2593  if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
2594  {
2595  try
2596  {
2597  SetOnePropertyValue( pEntry, pValues[i] );
2598  }
2599  catch ( lang::IllegalArgumentException& )
2600  {
2601  TOOLS_WARN_EXCEPTION( "sc", "exception when setting cell style"); // not supposed to happen
2602  }
2603  }
2604  }
2605  }
2606 
2607  ScDocument& rDoc = pDocShell->GetDocument();
2608  std::unique_ptr<ScPatternAttr> pOldPattern;
2609  std::unique_ptr<ScPatternAttr> pNewPattern;
2610 
2611  for(i = 0; i < nCount; i++)
2612  {
2613  // second loop: handle other properties
2614 
2615  const SfxItemPropertyMapEntry* pEntry = pEntryArray[i];
2616  if ( pEntry )
2617  {
2618  if ( IsScItemWid( pEntry->nWID ) ) // can be handled by SfxItemPropertySet
2619  {
2620  if ( !pOldPattern )
2621  {
2622  pOldPattern.reset(new ScPatternAttr( *GetCurrentAttrsDeep() ));
2623  pOldPattern->GetItemSet().ClearInvalidItems();
2624  pNewPattern.reset(new ScPatternAttr( rDoc.GetPool() ));
2625  }
2626 
2627  // collect items in pNewPattern, apply with one call after the loop
2628 
2629  sal_uInt16 nFirstItem, nSecondItem;
2630  lcl_SetCellProperty( *pEntry, pValues[i], *pOldPattern, rDoc, nFirstItem, nSecondItem );
2631 
2632  // put only affected items into new set
2633  if ( nFirstItem )
2634  pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nFirstItem ) );
2635  if ( nSecondItem )
2636  pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nSecondItem ) );
2637  }
2638  else if ( pEntry->nWID != SC_WID_UNO_CELLSTYL ) // CellStyle is handled above
2639  {
2640  // call virtual method to set a single property
2641  SetOnePropertyValue( pEntry, pValues[i] );
2642  }
2643  }
2644  }
2645 
2646  if ( pNewPattern && !aRanges.empty() )
2647  pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), *pNewPattern, true );
2648 }
2649 
2650 uno::Sequence<uno::Any> SAL_CALL ScCellRangesBase::getPropertyValues(
2651  const uno::Sequence< OUString >& aPropertyNames )
2652 {
2653  SolarMutexGuard aGuard;
2654 
2655  const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
2656 
2657  uno::Sequence<uno::Any> aRet(aPropertyNames.getLength());
2658  uno::Any* pProperties = aRet.getArray();
2659  for(sal_Int32 i = 0; i < aPropertyNames.getLength(); i++)
2660  {
2661  const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
2662  GetOnePropertyValue( pEntry, pProperties[i] );
2663  }
2664  return aRet;
2665 }
2666 
2667 void SAL_CALL ScCellRangesBase::addPropertiesChangeListener( const uno::Sequence< OUString >& /* aPropertyNames */,
2668  const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
2669 {
2670  OSL_FAIL("not implemented");
2671 }
2672 
2673 void SAL_CALL ScCellRangesBase::removePropertiesChangeListener( const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
2674 {
2675  OSL_FAIL("not implemented");
2676 }
2677 
2678 void SAL_CALL ScCellRangesBase::firePropertiesChangeEvent( const uno::Sequence< OUString >& /* aPropertyNames */,
2679  const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
2680 {
2681  OSL_FAIL("not implemented");
2682 }
2683 
2684 IMPL_LINK( ScCellRangesBase, ValueListenerHdl, const SfxHint&, rHint, void )
2685 {
2686  if ( pDocShell && (rHint.GetId() == SfxHintId::ScDataChanged))
2687  {
2688  // This may be called several times for a single change, if several formulas
2689  // in the range are notified. So only a flag is set that is checked when
2690  // SfxHintId::DataChanged is received.
2691 
2692  bGotDataChangedHint = true;
2693  }
2694 }
2695 
2696 // XTolerantM