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