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 <tuple> 21 #include <utility> 22 #include <memory> 23 #include <vector> 24 #include <algorithm> 25 26 #include <o3tl/any.hxx> 27 #include <svx/svxids.hrc> 28 #include <editeng/memberids.h> 29 #include <float.h> 30 #include <swtypes.hxx> 31 #include <cmdid.h> 32 #include <unocoll.hxx> 33 #include <unomid.h> 34 #include <unomap.hxx> 35 #include <unotbl.hxx> 36 #include <section.hxx> 37 #include <unocrsr.hxx> 38 #include <hints.hxx> 39 #include <swtblfmt.hxx> 40 #include <doc.hxx> 41 #include <IDocumentUndoRedo.hxx> 42 #include <IDocumentContentOperations.hxx> 43 #include <IDocumentFieldsAccess.hxx> 44 #include <IDocumentState.hxx> 45 #include <IDocumentLayoutAccess.hxx> 46 #include <shellres.hxx> 47 #include <docary.hxx> 48 #include <ndole.hxx> 49 #include <ndtxt.hxx> 50 #include <frame.hxx> 51 #include <vcl/svapp.hxx> 52 #include <fmtfsize.hxx> 53 #include <tblafmt.hxx> 54 #include <tabcol.hxx> 55 #include <cellatr.hxx> 56 #include <fmtpdsc.hxx> 57 #include <pagedesc.hxx> 58 #include <viewsh.hxx> 59 #include <rootfrm.hxx> 60 #include <tabfrm.hxx> 61 #include <redline.hxx> 62 #include <unoport.hxx> 63 #include <unocrsrhelper.hxx> 64 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp> 65 #include <com/sun/star/text/WrapTextMode.hpp> 66 #include <com/sun/star/text/TextContentAnchorType.hpp> 67 #include <com/sun/star/text/TableColumnSeparator.hpp> 68 #include <com/sun/star/text/VertOrientation.hpp> 69 #include <com/sun/star/text/XTextSection.hpp> 70 #include <com/sun/star/table/TableBorder.hpp> 71 #include <com/sun/star/table/TableBorder2.hpp> 72 #include <com/sun/star/table/BorderLine2.hpp> 73 #include <com/sun/star/table/TableBorderDistances.hpp> 74 #include <com/sun/star/beans/PropertyAttribute.hpp> 75 #include <com/sun/star/chart/XChartDataChangeEventListener.hpp> 76 #include <com/sun/star/chart/ChartDataChangeEvent.hpp> 77 #include <com/sun/star/table/CellContentType.hpp> 78 #include <unotextrange.hxx> 79 #include <unotextcursor.hxx> 80 #include <unoparagraph.hxx> 81 #include <svl/zforlist.hxx> 82 #include <editeng/formatbreakitem.hxx> 83 #include <editeng/shaditem.hxx> 84 #include <editeng/lrspitem.hxx> 85 #include <editeng/ulspitem.hxx> 86 #include <fmtornt.hxx> 87 #include <editeng/keepitem.hxx> 88 #include <fmtlsplt.hxx> 89 #include <swundo.hxx> 90 #include <osl/mutex.hxx> 91 #include <SwStyleNameMapper.hxx> 92 #include <frmatr.hxx> 93 #include <sortopt.hxx> 94 #include <rtl/math.hxx> 95 #include <sal/log.hxx> 96 #include <editeng/frmdiritem.hxx> 97 #include <comphelper/interfacecontainer2.hxx> 98 #include <comphelper/servicehelper.hxx> 99 #include <comphelper/string.hxx> 100 #include <cppuhelper/supportsservice.hxx> 101 #include <comphelper/sequence.hxx> 102 #include <comphelper/sequenceashashmap.hxx> 103 #include <swtable.hxx> 104 #include <docsh.hxx> 105 #include <fesh.hxx> 106 #include <itabenum.hxx> 107 108 using namespace ::com::sun::star; 109 using ::editeng::SvxBorderLine; 110 111 namespace 112 { 113 template<typename Tcoretype, typename Tunotype> 114 struct FindUnoInstanceHint final : SfxHint 115 { 116 FindUnoInstanceHint(Tcoretype* pCore) : m_pCore(pCore), m_pResult(nullptr) {}; 117 const Tcoretype* const m_pCore; 118 mutable Tunotype* m_pResult; 119 }; 120 SwFrameFormat* lcl_EnsureCoreConnected(SwFrameFormat* pFormat, cppu::OWeakObject* pObject) 121 { 122 if(!pFormat) 123 throw uno::RuntimeException("Lost connection to core objects", pObject); 124 return pFormat; 125 } 126 SwTable* lcl_EnsureTableNotComplex(SwTable* pTable, cppu::OWeakObject* pObject) 127 { 128 if(pTable->IsTableComplex()) 129 throw uno::RuntimeException("Table too complex", pObject); 130 return pTable; 131 } 132 133 chart::ChartDataChangeEvent createChartEvent(uno::Reference<uno::XInterface> const& xSource) 134 { 135 //TODO: find appropriate settings of the Event 136 chart::ChartDataChangeEvent event; 137 event.Source = xSource; 138 event.Type = chart::ChartDataChangeType_ALL; 139 event.StartColumn = 0; 140 event.EndColumn = 1; 141 event.StartRow = 0; 142 event.EndRow = 1; 143 return event; 144 } 145 146 void lcl_SendChartEvent( 147 uno::Reference<uno::XInterface> const& xSource, 148 ::comphelper::OInterfaceContainerHelper2& rListeners) 149 { 150 rListeners.notifyEach( 151 &chart::XChartDataChangeEventListener::chartDataChanged, 152 createChartEvent(xSource)); 153 } 154 155 void lcl_SendChartEvent( 156 uno::Reference<uno::XInterface> const& xSource, 157 ::cppu::OMultiTypeInterfaceContainerHelper const& rListeners) 158 { 159 auto pContainer(rListeners.getContainer(cppu::UnoType<chart::XChartDataChangeEventListener>::get())); 160 if (pContainer) 161 pContainer->notifyEach( 162 &chart::XChartDataChangeEventListener::chartDataChanged, 163 createChartEvent(xSource)); 164 } 165 } 166 167 #define UNO_TABLE_COLUMN_SUM 10000 168 169 170 static bool lcl_LineToSvxLine(const table::BorderLine& rLine, SvxBorderLine& rSvxLine) 171 { 172 rSvxLine.SetColor(Color(rLine.Color)); 173 174 rSvxLine.GuessLinesWidths( SvxBorderLineStyle::NONE, 175 convertMm100ToTwip( rLine.OuterLineWidth ), 176 convertMm100ToTwip( rLine.InnerLineWidth ), 177 convertMm100ToTwip( rLine.LineDistance ) ); 178 179 return rLine.InnerLineWidth > 0 || rLine.OuterLineWidth > 0; 180 } 181 182 /// @throws lang::IllegalArgumentException 183 /// @throws uno::RuntimeException 184 static void lcl_SetSpecialProperty(SwFrameFormat* pFormat, 185 const SfxItemPropertySimpleEntry* pEntry, 186 const uno::Any& aValue) 187 { 188 // special treatment for "non-items" 189 switch(pEntry->nWID) 190 { 191 case FN_TABLE_HEADLINE_REPEAT: 192 case FN_TABLE_HEADLINE_COUNT: 193 { 194 SwTable* pTable = SwTable::FindTable( pFormat ); 195 UnoActionContext aAction(pFormat->GetDoc()); 196 if( pEntry->nWID == FN_TABLE_HEADLINE_REPEAT) 197 { 198 pFormat->GetDoc()->SetRowsToRepeat( *pTable, aValue.get<bool>() ? 1 : 0 ); 199 } 200 else 201 { 202 sal_Int32 nRepeat = 0; 203 aValue >>= nRepeat; 204 if( nRepeat >= 0 && nRepeat < SAL_MAX_UINT16 ) 205 pFormat->GetDoc()->SetRowsToRepeat( *pTable, static_cast<sal_uInt16>(nRepeat) ); 206 } 207 } 208 break; 209 210 case FN_TABLE_IS_RELATIVE_WIDTH: 211 case FN_TABLE_WIDTH: 212 case FN_TABLE_RELATIVE_WIDTH: 213 { 214 SwFormatFrameSize aSz( pFormat->GetFrameSize() ); 215 if(FN_TABLE_WIDTH == pEntry->nWID) 216 { 217 sal_Int32 nWidth = 0; 218 aValue >>= nWidth; 219 aSz.SetWidthPercent(0); 220 aSz.SetWidth ( convertMm100ToTwip ( nWidth ) ); 221 } 222 else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID) 223 { 224 sal_Int16 nSet = 0; 225 aValue >>= nSet; 226 if(nSet && nSet <=100) 227 aSz.SetWidthPercent( static_cast<sal_uInt8>(nSet) ); 228 } 229 else if(FN_TABLE_IS_RELATIVE_WIDTH == pEntry->nWID) 230 { 231 if(!aValue.get<bool>()) 232 aSz.SetWidthPercent(0); 233 else 234 { 235 lang::IllegalArgumentException aExcept; 236 aExcept.Message = "relative width cannot be switched on with this property"; 237 throw aExcept; 238 } 239 } 240 pFormat->GetDoc()->SetAttr(aSz, *pFormat); 241 } 242 break; 243 244 case RES_PAGEDESC: 245 { 246 OUString sPageStyle; 247 aValue >>= sPageStyle; 248 const SwPageDesc* pDesc = nullptr; 249 if (!sPageStyle.isEmpty()) 250 { 251 SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc); 252 pDesc = SwPageDesc::GetByName(*pFormat->GetDoc(), sPageStyle); 253 } 254 SwFormatPageDesc aDesc( pDesc ); 255 pFormat->GetDoc()->SetAttr(aDesc, *pFormat); 256 } 257 break; 258 259 default: 260 throw lang::IllegalArgumentException(); 261 } 262 } 263 264 static uno::Any lcl_GetSpecialProperty(SwFrameFormat* pFormat, const SfxItemPropertySimpleEntry* pEntry ) 265 { 266 switch(pEntry->nWID) 267 { 268 case FN_TABLE_HEADLINE_REPEAT: 269 case FN_TABLE_HEADLINE_COUNT: 270 { 271 SwTable* pTable = SwTable::FindTable( pFormat ); 272 const sal_uInt16 nRepeat = pTable->GetRowsToRepeat(); 273 if(pEntry->nWID == FN_TABLE_HEADLINE_REPEAT) 274 return uno::makeAny<bool>(nRepeat > 0); 275 return uno::makeAny<sal_Int32>(nRepeat); 276 } 277 278 case FN_TABLE_WIDTH: 279 case FN_TABLE_IS_RELATIVE_WIDTH: 280 case FN_TABLE_RELATIVE_WIDTH: 281 { 282 uno::Any aRet; 283 const SwFormatFrameSize& rSz = pFormat->GetFrameSize(); 284 if(FN_TABLE_WIDTH == pEntry->nWID) 285 rSz.QueryValue(aRet, MID_FRMSIZE_WIDTH|CONVERT_TWIPS); 286 else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID) 287 rSz.QueryValue(aRet, MID_FRMSIZE_REL_WIDTH); 288 else 289 aRet <<= (0 != rSz.GetWidthPercent()); 290 return aRet; 291 } 292 293 case RES_PAGEDESC: 294 { 295 const SfxItemSet& rSet = pFormat->GetAttrSet(); 296 const SfxPoolItem* pItem; 297 if(SfxItemState::SET == rSet.GetItemState(RES_PAGEDESC, false, &pItem)) 298 { 299 const SwPageDesc* pDsc = static_cast<const SwFormatPageDesc*>(pItem)->GetPageDesc(); 300 if(pDsc) 301 return uno::makeAny<OUString>(SwStyleNameMapper::GetProgName(pDsc->GetName(), SwGetPoolIdFromName::PageDesc )); 302 } 303 return uno::makeAny(OUString()); 304 } 305 306 case RES_ANCHOR: 307 return uno::makeAny(text::TextContentAnchorType_AT_PARAGRAPH); 308 309 case FN_UNO_ANCHOR_TYPES: 310 { 311 uno::Sequence<text::TextContentAnchorType> aTypes{text::TextContentAnchorType_AT_PARAGRAPH}; 312 return uno::makeAny(aTypes); 313 } 314 315 case FN_UNO_WRAP : 316 return uno::makeAny(text::WrapTextMode_NONE); 317 318 case FN_PARAM_LINK_DISPLAY_NAME : 319 return uno::makeAny(pFormat->GetName()); 320 321 case FN_UNO_REDLINE_NODE_START: 322 case FN_UNO_REDLINE_NODE_END: 323 { 324 SwTable* pTable = SwTable::FindTable( pFormat ); 325 SwNode* pTableNode = pTable->GetTableNode(); 326 if(FN_UNO_REDLINE_NODE_END == pEntry->nWID) 327 pTableNode = pTableNode->EndOfSectionNode(); 328 for(const SwRangeRedline* pRedline : pFormat->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable()) 329 { 330 const SwNode& rRedPointNode = pRedline->GetNode(); 331 const SwNode& rRedMarkNode = pRedline->GetNode(false); 332 if(&rRedPointNode == pTableNode || &rRedMarkNode == pTableNode) 333 { 334 const SwNode& rStartOfRedline = SwNodeIndex(rRedPointNode) <= SwNodeIndex(rRedMarkNode) ? 335 rRedPointNode : rRedMarkNode; 336 bool bIsStart = &rStartOfRedline == pTableNode; 337 return uno::makeAny(SwXRedlinePortion::CreateRedlineProperties(*pRedline, bIsStart)); 338 } 339 } 340 } 341 } 342 return uno::Any(); 343 } 344 345 /** get position of a cell with a given name 346 * 347 * If everything was OK, the indices for column and row are changed (both >= 0). 348 * In case of errors, at least one of them is < 0. 349 * 350 * Also since the implementations of tables does not really have columns using 351 * this function is appropriate only for tables that are not complex (i.e. 352 * where IsTableComplex() returns false). 353 * 354 * @param rCellName e.g. A1..Z1, a1..z1, AA1..AZ1, Aa1..Az1, BA1..BZ1, Ba1..Bz1, ... 355 * @param [IN,OUT] o_rColumn (0-based) 356 * @param [IN,OUT] o_rRow (0-based) 357 */ 358 //TODO: potential for throwing proper exceptions instead of having every caller to check for errors 359 void SwXTextTable::GetCellPosition(const OUString& rCellName, sal_Int32& o_rColumn, sal_Int32& o_rRow) 360 { 361 o_rColumn = o_rRow = -1; // default return values indicating failure 362 const sal_Int32 nLen = rCellName.getLength(); 363 if(!nLen) 364 { 365 SAL_WARN("sw.uno", "failed to get column or row index"); 366 return; 367 } 368 sal_Int32 nRowPos = 0; 369 while (nRowPos<nLen) 370 { 371 if (rCellName[nRowPos]>='0' && rCellName[nRowPos]<='9') 372 { 373 break; 374 } 375 ++nRowPos; 376 } 377 if (nRowPos>0 && nRowPos<nLen) 378 { 379 sal_Int32 nColIdx = 0; 380 for (sal_Int32 i = 0; i < nRowPos; ++i) 381 { 382 nColIdx *= 52; 383 if (i < nRowPos - 1) 384 ++nColIdx; 385 const sal_Unicode cChar = rCellName[i]; 386 if ('A' <= cChar && cChar <= 'Z') 387 nColIdx += cChar - 'A'; 388 else if ('a' <= cChar && cChar <= 'z') 389 nColIdx += 26 + cChar - 'a'; 390 else 391 { 392 nColIdx = -1; // sth failed 393 break; 394 } 395 } 396 397 o_rColumn = nColIdx; 398 o_rRow = rCellName.copy(nRowPos).toInt32() - 1; // - 1 because indices ought to be 0 based 399 } 400 } 401 402 /** compare position of two cells (check rows first) 403 * 404 * @note this function probably also make sense only 405 * for cell names of non-complex tables 406 * 407 * @param rCellName1 e.g. "A1" (non-empty string with valid cell name) 408 * @param rCellName2 e.g. "A1" (non-empty string with valid cell name) 409 * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2 410 */ 411 int sw_CompareCellsByRowFirst( const OUString &rCellName1, const OUString &rCellName2 ) 412 { 413 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1; 414 SwXTextTable::GetCellPosition( rCellName1, nCol1, nRow1 ); 415 SwXTextTable::GetCellPosition( rCellName2, nCol2, nRow2 ); 416 417 if (nRow1 < nRow2 || (nRow1 == nRow2 && nCol1 < nCol2)) 418 return -1; 419 else if (nCol1 == nCol2 && nRow1 == nRow2) 420 return 0; 421 else 422 return +1; 423 } 424 425 /** compare position of two cells (check columns first) 426 * 427 * @note this function probably also make sense only 428 * for cell names of non-complex tables 429 * 430 * @param rCellName1 e.g. "A1" (non-empty string with valid cell name) 431 * @param rCellName2 e.g. "A1" (non-empty string with valid cell name) 432 * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2 433 */ 434 int sw_CompareCellsByColFirst( const OUString &rCellName1, const OUString &rCellName2 ) 435 { 436 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1; 437 SwXTextTable::GetCellPosition( rCellName1, nCol1, nRow1 ); 438 SwXTextTable::GetCellPosition( rCellName2, nCol2, nRow2 ); 439 440 if (nCol1 < nCol2 || (nCol1 == nCol2 && nRow1 < nRow2)) 441 return -1; 442 else if (nRow1 == nRow2 && nCol1 == nCol2) 443 return 0; 444 else 445 return +1; 446 } 447 448 /** compare position of two cell ranges 449 * 450 * @note this function probably also make sense only 451 * for cell names of non-complex tables 452 * 453 * @param rRange1StartCell e.g. "A1" (non-empty string with valid cell name) 454 * @param rRange1EndCell e.g. "A1" (non-empty string with valid cell name) 455 * @param rRange2StartCell e.g. "A1" (non-empty string with valid cell name) 456 * @param rRange2EndCell e.g. "A1" (non-empty string with valid cell name) 457 * @param bCmpColsFirst if <true> position in columns will be compared first before rows 458 * 459 * @return -1 if cell_range_1 < cell_range_2; 0 if both cell ranges are equal; +1 if cell_range_1 > cell_range_2 460 */ 461 int sw_CompareCellRanges( 462 const OUString &rRange1StartCell, const OUString &rRange1EndCell, 463 const OUString &rRange2StartCell, const OUString &rRange2EndCell, 464 bool bCmpColsFirst ) 465 { 466 int (*pCompareCells)( const OUString &, const OUString & ) = 467 bCmpColsFirst ? &sw_CompareCellsByColFirst : &sw_CompareCellsByRowFirst; 468 469 int nCmpResStartCells = pCompareCells( rRange1StartCell, rRange2StartCell ); 470 if ((-1 == nCmpResStartCells ) || 471 ( 0 == nCmpResStartCells && 472 -1 == pCompareCells( rRange1EndCell, rRange2EndCell ) )) 473 return -1; 474 else if (0 == nCmpResStartCells && 475 0 == pCompareCells( rRange1EndCell, rRange2EndCell )) 476 return 0; 477 else 478 return +1; 479 } 480 481 /** get cell name at a specified coordinate 482 * 483 * @param nColumn column index (0-based) 484 * @param nRow row index (0-based) 485 * @return the cell name 486 */ 487 OUString sw_GetCellName( sal_Int32 nColumn, sal_Int32 nRow ) 488 { 489 if (nColumn < 0 || nRow < 0) 490 return OUString(); 491 OUString sCellName; 492 sw_GetTableBoxColStr( static_cast< sal_uInt16 >(nColumn), sCellName ); 493 return sCellName + OUString::number( nRow + 1 ); 494 } 495 496 /** Find the top left or bottom right corner box in given table. 497 Consider nested lines when finding the box. 498 499 @param rTableLines the table 500 @param i_bTopLeft if true, find top left box, otherwise find bottom 501 right box 502 */ 503 static const SwTableBox* lcl_FindCornerTableBox(const SwTableLines& rTableLines, const bool i_bTopLeft) 504 { 505 const SwTableLines* pLines(&rTableLines); 506 while(true) 507 { 508 assert(!pLines->empty()); 509 if(pLines->empty()) 510 return nullptr; 511 const SwTableLine* pLine(i_bTopLeft ? pLines->front() : pLines->back()); 512 assert(pLine); 513 const SwTableBoxes& rBoxes(pLine->GetTabBoxes()); 514 assert(rBoxes.size() != 0); 515 const SwTableBox* pBox = i_bTopLeft ? rBoxes.front() : rBoxes.back(); 516 assert(pBox); 517 if (pBox->GetSttNd()) 518 return pBox; 519 pLines = &pBox->GetTabLines(); 520 } 521 } 522 523 /** cleanup order in a range 524 * 525 * Sorts the input to a uniform format. I.e. for the four possible representation 526 * A1:C5, C5:A1, A5:C1, C1:A5 527 * the result will be always A1:C5. 528 * 529 * @param [IN,OUT] rCell1 cell name (will be modified to upper-left corner), e.g. "A1" (non-empty string with valid cell name) 530 * @param [IN,OUT] rCell2 cell name (will be modified to lower-right corner), e.g. "A1" (non-empty string with valid cell name) 531 */ 532 void sw_NormalizeRange(OUString &rCell1, OUString &rCell2) 533 { 534 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1; 535 SwXTextTable::GetCellPosition( rCell1, nCol1, nRow1 ); 536 SwXTextTable::GetCellPosition( rCell2, nCol2, nRow2 ); 537 if (nCol2 < nCol1 || nRow2 < nRow1) 538 { 539 rCell1 = sw_GetCellName( std::min(nCol1, nCol2), std::min(nRow1, nRow2) ); 540 rCell2 = sw_GetCellName( std::max(nCol1, nCol2), std::max(nRow1, nRow2) ); 541 } 542 } 543 544 void SwRangeDescriptor::Normalize() 545 { 546 if (nTop > nBottom) 547 std::swap(nBottom, nTop); 548 if (nLeft > nRight) 549 std::swap(nLeft, nRight); 550 } 551 552 static SwXCell* lcl_CreateXCell(SwFrameFormat* pFormat, sal_Int32 nColumn, sal_Int32 nRow) 553 { 554 const OUString sCellName = sw_GetCellName(nColumn, nRow); 555 SwTable* pTable = SwTable::FindTable(pFormat); 556 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName)); 557 if(!pBox) 558 return nullptr; 559 return SwXCell::CreateXCell(pFormat, pBox, pTable); 560 } 561 562 static void lcl_InspectLines(SwTableLines& rLines, std::vector<OUString>& rAllNames) 563 { 564 for(auto pLine : rLines) 565 { 566 for(auto pBox : pLine->GetTabBoxes()) 567 { 568 if(!pBox->GetName().isEmpty() && pBox->getRowSpan() > 0) 569 rAllNames.push_back(pBox->GetName()); 570 SwTableLines& rBoxLines = pBox->GetTabLines(); 571 if(!rBoxLines.empty()) 572 lcl_InspectLines(rBoxLines, rAllNames); 573 } 574 } 575 } 576 577 static bool lcl_FormatTable(SwFrameFormat const * pTableFormat) 578 { 579 bool bHasFrames = false; 580 SwIterator<SwFrame,SwFormat> aIter( *pTableFormat ); 581 for(SwFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next()) 582 { 583 vcl::RenderContext* pRenderContext = pFrame->getRootFrame()->GetCurrShell()->GetOut(); 584 // mba: no TYPEINFO for SwTabFrame 585 if(!pFrame->IsTabFrame()) 586 continue; 587 DisableCallbackAction a(*pFrame->getRootFrame()); 588 SwTabFrame* pTabFrame = static_cast<SwTabFrame*>(pFrame); 589 if(pTabFrame->isFrameAreaDefinitionValid()) 590 pTabFrame->InvalidatePos(); 591 pTabFrame->SetONECalcLowers(); 592 pTabFrame->Calc(pRenderContext); 593 bHasFrames = true; 594 } 595 return bHasFrames; 596 } 597 598 static void lcl_CursorSelect(SwPaM& rCursor, bool bExpand) 599 { 600 if(bExpand) 601 { 602 if(!rCursor.HasMark()) 603 rCursor.SetMark(); 604 } 605 else if(rCursor.HasMark()) 606 rCursor.DeleteMark(); 607 } 608 609 static void lcl_GetTableSeparators(uno::Any& rRet, SwTable const * pTable, SwTableBox const * pBox, bool bRow) 610 { 611 SwTabCols aCols; 612 aCols.SetLeftMin ( 0 ); 613 aCols.SetLeft ( 0 ); 614 aCols.SetRight ( UNO_TABLE_COLUMN_SUM ); 615 aCols.SetRightMax( UNO_TABLE_COLUMN_SUM ); 616 617 pTable->GetTabCols( aCols, pBox, false, bRow ); 618 619 const size_t nSepCount = aCols.Count(); 620 uno::Sequence< text::TableColumnSeparator> aColSeq(nSepCount); 621 text::TableColumnSeparator* pArray = aColSeq.getArray(); 622 bool bError = false; 623 for(size_t i = 0; i < nSepCount; ++i) 624 { 625 pArray[i].Position = static_cast< sal_Int16 >(aCols[i]); 626 pArray[i].IsVisible = !aCols.IsHidden(i); 627 if(!bRow && !pArray[i].IsVisible) 628 { 629 bError = true; 630 break; 631 } 632 } 633 if(!bError) 634 rRet <<= aColSeq; 635 636 } 637 638 static void lcl_SetTableSeparators(const uno::Any& rVal, SwTable* pTable, SwTableBox const * pBox, bool bRow, SwDoc* pDoc) 639 { 640 SwTabCols aOldCols; 641 642 aOldCols.SetLeftMin ( 0 ); 643 aOldCols.SetLeft ( 0 ); 644 aOldCols.SetRight ( UNO_TABLE_COLUMN_SUM ); 645 aOldCols.SetRightMax( UNO_TABLE_COLUMN_SUM ); 646 647 pTable->GetTabCols( aOldCols, pBox, false, bRow ); 648 const size_t nOldCount = aOldCols.Count(); 649 // there is no use in setting tab cols if there is only one column 650 if( !nOldCount ) 651 return; 652 653 auto pSepSeq = 654 o3tl::tryAccess<uno::Sequence<text::TableColumnSeparator>>(rVal); 655 if(!pSepSeq || static_cast<size_t>(pSepSeq->getLength()) != nOldCount) 656 return; 657 SwTabCols aCols(aOldCols); 658 const text::TableColumnSeparator* pArray = pSepSeq->getConstArray(); 659 long nLastValue = 0; 660 //sal_Int32 nTableWidth = aCols.GetRight() - aCols.GetLeft(); 661 for(size_t i = 0; i < nOldCount; ++i) 662 { 663 aCols[i] = pArray[i].Position; 664 if(bool(pArray[i].IsVisible) == aCols.IsHidden(i) || 665 (!bRow && aCols.IsHidden(i)) || 666 aCols[i] < nLastValue || 667 UNO_TABLE_COLUMN_SUM < aCols[i] ) 668 return; // probably this should assert() 669 nLastValue = aCols[i]; 670 } 671 pDoc->SetTabCols(*pTable, aCols, aOldCols, pBox, bRow ); 672 } 673 674 /* non UNO function call to set string in SwXCell */ 675 void sw_setString( SwXCell &rCell, const OUString &rText, 676 bool bKeepNumberFormat = false ) 677 { 678 if(rCell.IsValid()) 679 { 680 SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat(); 681 pBoxFormat->LockModify(); 682 pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMULA ); 683 pBoxFormat->ResetFormatAttr( RES_BOXATR_VALUE ); 684 if (!bKeepNumberFormat) 685 pBoxFormat->SetFormatAttr( SwTableBoxNumFormat(/*default Text*/) ); 686 pBoxFormat->UnlockModify(); 687 } 688 rCell.SwXText::setString(rText); 689 } 690 691 692 /* non UNO function call to set value in SwXCell */ 693 void sw_setValue( SwXCell &rCell, double nVal ) 694 { 695 if(!rCell.IsValid()) 696 return; 697 // first this text (maybe) needs to be deleted 698 sal_uLong nNdPos = rCell.m_pBox->IsValidNumTextNd(); 699 if(ULONG_MAX != nNdPos) 700 sw_setString( rCell, OUString(), true ); // true == keep number format 701 SwDoc* pDoc = rCell.GetDoc(); 702 UnoActionContext aAction(pDoc); 703 SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat(); 704 SfxItemSet aSet(pDoc->GetAttrPool(), svl::Items<RES_BOXATR_FORMAT, RES_BOXATR_VALUE>{}); 705 const SfxPoolItem* pItem; 706 707 //!! do we need to set a new number format? Yes, if 708 // - there is no current number format 709 // - the current number format is not a number format according to the number formatter, but rather a text format 710 if(SfxItemState::SET != pBoxFormat->GetAttrSet().GetItemState(RES_BOXATR_FORMAT, true, &pItem) 711 || pDoc->GetNumberFormatter()->IsTextFormat(static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue())) 712 { 713 aSet.Put(SwTableBoxNumFormat(0)); 714 } 715 716 SwTableBoxValue aVal(nVal); 717 aSet.Put(aVal); 718 pDoc->SetTableBoxFormulaAttrs( *rCell.m_pBox, aSet ); 719 // update table 720 SwTableFormulaUpdate aTableUpdate( SwTable::FindTable( rCell.GetFrameFormat() )); 721 pDoc->getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate ); 722 } 723 724 725 SwXCell::SwXCell(SwFrameFormat* pTableFormat, SwTableBox* pBx, size_t const nPos) : 726 SwXText(pTableFormat->GetDoc(), CursorType::TableText), 727 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)), 728 m_pBox(pBx), 729 m_pStartNode(nullptr), 730 m_pTableFormat(pTableFormat), 731 m_nFndPos(nPos) 732 { 733 StartListening(pTableFormat->GetNotifier()); 734 } 735 736 SwXCell::SwXCell(SwFrameFormat* pTableFormat, const SwStartNode& rStartNode) : 737 SwXText(pTableFormat->GetDoc(), CursorType::TableText), 738 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)), 739 m_pBox(nullptr), 740 m_pStartNode(&rStartNode), 741 m_pTableFormat(pTableFormat), 742 m_nFndPos(NOTFOUND) 743 { 744 StartListening(pTableFormat->GetNotifier()); 745 } 746 747 SwXCell::~SwXCell() 748 { 749 SolarMutexGuard aGuard; 750 EndListeningAll(); 751 } 752 753 namespace 754 { 755 class theSwXCellUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXCellUnoTunnelId > {}; 756 } 757 758 const uno::Sequence< sal_Int8 > & SwXCell::getUnoTunnelId() 759 { 760 return theSwXCellUnoTunnelId::get().getSeq(); 761 } 762 763 sal_Int64 SAL_CALL SwXCell::getSomething( const uno::Sequence< sal_Int8 >& rId ) 764 { 765 if( isUnoTunnelId<SwXCell>(rId) ) 766 { 767 return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this) ); 768 } 769 else 770 return SwXText::getSomething(rId); 771 } 772 773 uno::Sequence< uno::Type > SAL_CALL SwXCell::getTypes( ) 774 { 775 return comphelper::concatSequences( 776 SwXCellBaseClass::getTypes(), 777 SwXText::getTypes() 778 ); 779 } 780 781 uno::Sequence< sal_Int8 > SAL_CALL SwXCell::getImplementationId( ) 782 { 783 return css::uno::Sequence<sal_Int8>(); 784 } 785 786 void SAL_CALL SwXCell::acquire( ) throw() 787 { 788 SwXCellBaseClass::acquire(); 789 } 790 791 void SAL_CALL SwXCell::release( ) throw() 792 { 793 SolarMutexGuard aGuard; 794 795 SwXCellBaseClass::release(); 796 } 797 798 uno::Any SAL_CALL SwXCell::queryInterface( const uno::Type& aType ) 799 { 800 uno::Any aRet = SwXCellBaseClass::queryInterface(aType); 801 if(aRet.getValueType() == cppu::UnoType<void>::get()) 802 aRet = SwXText::queryInterface(aType); 803 return aRet; 804 } 805 806 const SwStartNode *SwXCell::GetStartNode() const 807 { 808 const SwStartNode* pSttNd = nullptr; 809 810 if( m_pStartNode || IsValid() ) 811 pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd(); 812 813 return pSttNd; 814 } 815 816 uno::Reference< text::XTextCursor > 817 SwXCell::CreateCursor() 818 { 819 return createTextCursor(); 820 } 821 822 bool SwXCell::IsValid() const 823 { 824 // FIXME: this is now a const method, to make SwXText::IsValid invisible 825 // but the const_cast here are still ridiculous. TODO: find a better way. 826 SwFrameFormat* pTableFormat = m_pBox ? GetFrameFormat() : nullptr; 827 if(!pTableFormat) 828 { 829 const_cast<SwXCell*>(this)->m_pBox = nullptr; 830 } 831 else 832 { 833 SwTable* pTable = SwTable::FindTable( pTableFormat ); 834 SwTableBox const*const pFoundBox = 835 const_cast<SwXCell*>(this)->FindBox(pTable, m_pBox); 836 if (!pFoundBox) 837 { 838 const_cast<SwXCell*>(this)->m_pBox = nullptr; 839 } 840 } 841 return nullptr != m_pBox; 842 } 843 844 OUString SwXCell::getFormula() 845 { 846 SolarMutexGuard aGuard; 847 if(!IsValid()) 848 return OUString(); 849 SwTableBoxFormula aFormula( m_pBox->GetFrameFormat()->GetTableBoxFormula() ); 850 SwTable* pTable = SwTable::FindTable( GetFrameFormat() ); 851 aFormula.PtrToBoxNm( pTable ); 852 return aFormula.GetFormula(); 853 } 854 855 ///@see sw_setValue (TODO: seems to be copy and paste programming here) 856 void SwXCell::setFormula(const OUString& rFormula) 857 { 858 SolarMutexGuard aGuard; 859 if(!IsValid()) 860 return; 861 // first this text (maybe) needs to be deleted 862 sal_uInt32 nNdPos = m_pBox->IsValidNumTextNd(); 863 if(USHRT_MAX == nNdPos) 864 sw_setString( *this, OUString(), true ); 865 OUString sFormula(comphelper::string::stripStart(rFormula, ' ')); 866 if( !sFormula.isEmpty() && '=' == sFormula[0] ) 867 sFormula = sFormula.copy( 1 ); 868 SwTableBoxFormula aFormula( sFormula ); 869 SwDoc* pMyDoc = GetDoc(); 870 UnoActionContext aAction(pMyDoc); 871 SfxItemSet aSet(pMyDoc->GetAttrPool(), svl::Items<RES_BOXATR_FORMAT, RES_BOXATR_FORMULA>{}); 872 const SfxPoolItem* pItem; 873 SwFrameFormat* pBoxFormat = m_pBox->GetFrameFormat(); 874 if(SfxItemState::SET != pBoxFormat->GetAttrSet().GetItemState(RES_BOXATR_FORMAT, true, &pItem) 875 || pMyDoc->GetNumberFormatter()->IsTextFormat(static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue())) 876 { 877 aSet.Put(SwTableBoxNumFormat(0)); 878 } 879 aSet.Put(aFormula); 880 GetDoc()->SetTableBoxFormulaAttrs( *m_pBox, aSet ); 881 // update table 882 SwTableFormulaUpdate aTableUpdate( SwTable::FindTable( GetFrameFormat() )); 883 pMyDoc->getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate ); 884 } 885 886 double SwXCell::getValue() 887 { 888 SolarMutexGuard aGuard; 889 // #i112652# a table cell may contain NaN as a value, do not filter that 890 double fRet; 891 if(IsValid() && !getString().isEmpty()) 892 fRet = m_pBox->GetFrameFormat()->GetTableBoxValue().GetValue(); 893 else 894 ::rtl::math::setNan( &fRet ); 895 return fRet; 896 } 897 898 void SwXCell::setValue(double rValue) 899 { 900 SolarMutexGuard aGuard; 901 sw_setValue( *this, rValue ); 902 } 903 904 table::CellContentType SwXCell::getType() 905 { 906 SolarMutexGuard aGuard; 907 908 table::CellContentType nRes = table::CellContentType_EMPTY; 909 sal_uInt32 nNdPos = m_pBox->IsFormulaOrValueBox(); 910 switch (nNdPos) 911 { 912 case 0 : nRes = table::CellContentType_TEXT; break; 913 case USHRT_MAX : nRes = table::CellContentType_EMPTY; break; 914 case RES_BOXATR_VALUE : nRes = table::CellContentType_VALUE; break; 915 case RES_BOXATR_FORMULA : nRes = table::CellContentType_FORMULA; break; 916 default : 917 OSL_FAIL( "unexpected case" ); 918 } 919 return nRes; 920 } 921 922 void SwXCell::setString(const OUString& aString) 923 { 924 SolarMutexGuard aGuard; 925 sw_setString( *this, aString ); 926 } 927 928 sal_Int32 SwXCell::getError() 929 { 930 SolarMutexGuard aGuard; 931 OUString sContent = getString(); 932 return sal_Int32(sContent == SwViewShell::GetShellRes()->aCalc_Error); 933 } 934 935 uno::Reference<text::XTextCursor> SwXCell::createTextCursor() 936 { 937 SolarMutexGuard aGuard; 938 if(!m_pStartNode && !IsValid()) 939 throw uno::RuntimeException(); 940 const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd(); 941 SwPosition aPos(*pSttNd); 942 SwXTextCursor* const pXCursor = 943 new SwXTextCursor(*GetDoc(), this, CursorType::TableText, aPos); 944 auto& rUnoCursor(pXCursor->GetCursor()); 945 rUnoCursor.Move(fnMoveForward, GoInNode); 946 return static_cast<text::XWordCursor*>(pXCursor); 947 } 948 949 uno::Reference<text::XTextCursor> SwXCell::createTextCursorByRange(const uno::Reference< text::XTextRange > & xTextPosition) 950 { 951 SolarMutexGuard aGuard; 952 SwUnoInternalPaM aPam(*GetDoc()); 953 if((!m_pStartNode && !IsValid()) || !::sw::XTextRangeToSwPaM(aPam, xTextPosition)) 954 throw uno::RuntimeException(); 955 const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd(); 956 // skip sections 957 SwStartNode* p1 = aPam.GetNode().StartOfSectionNode(); 958 while(p1->IsSectionNode()) 959 p1 = p1->StartOfSectionNode(); 960 if( p1 != pSttNd ) 961 return nullptr; 962 return static_cast<text::XWordCursor*>( 963 new SwXTextCursor(*GetDoc(), this, CursorType::TableText, 964 *aPam.GetPoint(), aPam.GetMark())); 965 } 966 967 uno::Reference< beans::XPropertySetInfo > SwXCell::getPropertySetInfo() 968 { 969 static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo(); 970 return xRef; 971 } 972 973 // If the current property matches the previous parent's property (i.e. no reason for it to be set), 974 // then it may be a ::DEFAULT value, even if it is marked as ::SET 975 static bool lcl_mayBeDefault( const sal_uInt16 nWhich, sal_uInt8 nMemberId, 976 const SfxPoolItem* pPrevItem, const SfxPoolItem& rCurrItem, 977 const bool bDirect ) 978 { 979 bool bMayBeDefault = false; 980 // These are the paragraph/character pairs that I found running unit tests. 981 // UNFORTUNATELY there is no way to see if a property has multiple members. 982 // Since valid members can be nMemberId == 0, we can't do something like "if (nMemberId & ~CONVERT_TWIPS) != 0" 983 // Perhaps the full list can be found in editeng/memberids.h??? 984 switch ( nWhich ) 985 { 986 case RES_BOX: 987 case RES_UL_SPACE: 988 case RES_LR_SPACE: 989 case RES_CHRATR_ESCAPEMENT: 990 case RES_CHRATR_FONT: 991 case RES_CHRATR_CJK_FONT: 992 case RES_CHRATR_CTL_FONT: 993 case RES_CHRATR_FONTSIZE: 994 case RES_CHRATR_CJK_FONTSIZE: 995 case RES_CHRATR_CTL_FONTSIZE: 996 case RES_CHRATR_WEIGHT: 997 case RES_CHRATR_CJK_WEIGHT: 998 case RES_CHRATR_CTL_WEIGHT: 999 case RES_CHRATR_LANGUAGE: 1000 case RES_CHRATR_CJK_LANGUAGE: 1001 case RES_CHRATR_CTL_LANGUAGE: 1002 case RES_CHRATR_POSTURE: 1003 case RES_CHRATR_CJK_POSTURE: 1004 case RES_CHRATR_CTL_POSTURE: 1005 case RES_PARATR_ADJUST: 1006 { 1007 // These properties are paired up, containing multiple properties in one nWhich. 1008 // If one is ::SET, they all report ::SET, even if only initialized with the default value. 1009 // Assume created automatically by another MemberId. 1010 bMayBeDefault = true; 1011 if ( pPrevItem ) 1012 { 1013 uno::Any aPrev; 1014 uno::Any aCurr; 1015 (*pPrevItem).QueryValue(aPrev, nMemberId); 1016 rCurrItem.QueryValue(aCurr, nMemberId); 1017 // If different, it overrides a parent value, so can't be considered a default. 1018 bMayBeDefault = aPrev == aCurr; 1019 } 1020 break; 1021 } 1022 default: 1023 { 1024 // Since DocDefaults are copied into root-level stylesheets (tdf#103961), 1025 // identify the duplicated properties as DocDefault values. 1026 // Assume any style information could have been inherited/copied. 1027 if ( !bDirect ) 1028 bMayBeDefault = !pPrevItem || *pPrevItem == rCurrItem; 1029 } 1030 } 1031 return bMayBeDefault; 1032 } 1033 1034 void SwXCell::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) 1035 { 1036 SolarMutexGuard aGuard; 1037 if(!IsValid()) 1038 return; 1039 // Hack to support hidden property to transfer textDirection 1040 if(rPropertyName == "FRMDirection") 1041 { 1042 SvxFrameDirectionItem aItem(SvxFrameDirection::Environment, RES_FRAMEDIR); 1043 aItem.PutValue(aValue, 0); 1044 m_pBox->GetFrameFormat()->SetFormatAttr(aItem); 1045 } 1046 else if(rPropertyName == "TableRedlineParams") 1047 { 1048 // Get the table row properties 1049 uno::Sequence<beans::PropertyValue> tableCellProperties = aValue.get< uno::Sequence< beans::PropertyValue > >(); 1050 comphelper::SequenceAsHashMap aPropMap(tableCellProperties); 1051 OUString sRedlineType; 1052 if(!(aPropMap.getValue("RedlineType") >>= sRedlineType)) 1053 throw beans::UnknownPropertyException("No redline type property: ", static_cast<cppu::OWeakObject*>(this)); 1054 1055 // Create a 'Table Cell Redline' object 1056 SwUnoCursorHelper::makeTableCellRedline(*m_pBox, sRedlineType, tableCellProperties); 1057 1058 1059 } 1060 else 1061 { 1062 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName)); 1063 if ( !pEntry ) 1064 { 1065 // not a table property: if it is a paragraph/character property, consider applying it to the underlying text. 1066 const SfxItemPropertySet& rParaPropSet = *aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH); 1067 pEntry = rParaPropSet.getPropertyMap().getByName(rPropertyName); 1068 1069 if ( pEntry ) 1070 { 1071 SwNodeIndex aIdx( *GetStartNode(), 1 ); 1072 const SwNode* pEndNd = aIdx.GetNode().EndOfSectionNode(); 1073 while ( &aIdx.GetNode() != pEndNd ) 1074 { 1075 const SwTextNode* pNd = aIdx.GetNode().GetTextNode(); 1076 ++aIdx; 1077 if ( !pNd ) 1078 continue; 1079 1080 const SfxPoolItem* pPrevItem = nullptr; 1081 const SfxPoolItem* pCurrItem = nullptr; 1082 // Table-styles don't override direct formatting 1083 if ( pNd->HasSwAttrSet() && SfxItemState::SET == pNd->GetSwAttrSet().GetItemState(pEntry->nWID, false, &pCurrItem) ) 1084 { 1085 // Some WIDs have several MIDs, so perhaps ::SET refers to another MID and this property was copied from parents? 1086 if ( lcl_mayBeDefault(pEntry->nWID, pEntry->nMemberId, pPrevItem, *pCurrItem, /*bDirect=*/true) ) 1087 pPrevItem = pCurrItem; 1088 else 1089 continue; //don't override direct formatting 1090 } 1091 1092 bool bSet = false; 1093 SwFormat* pFormatColl = pNd->GetFormatColl(); 1094 // Manually walk through the parent properties in order to avoid the default properties. 1095 // Table-styles don't override paragraph-style formatting. 1096 // TODO: ?except for fontsize/justification if compat:overrideTableStyleFontSizeAndJustification? 1097 while ( pFormatColl ) 1098 { 1099 if ( SfxItemState::SET == pFormatColl->GetItemState(pEntry->nWID, /*bSrchInParent=*/false, &pCurrItem) ) 1100 { 1101 if ( lcl_mayBeDefault(pEntry->nWID, pEntry->nMemberId, pPrevItem, *pCurrItem, false) ) 1102 { 1103 // if the property matches DocDefaults, then table-style needs to override it 1104 pPrevItem = pFormatColl->IsDefault() ? nullptr : pCurrItem; 1105 } 1106 else 1107 { 1108 bSet = true; //don't override style formatting 1109 break; 1110 } 1111 } 1112 pFormatColl = pFormatColl->DerivedFrom(); 1113 } 1114 if ( bSet ) 1115 continue; 1116 1117 // Check if previous ::SET came from the pool defaults. 1118 if ( pPrevItem && pNd->GetSwAttrSet().GetPool() ) 1119 { 1120 pCurrItem = &pNd->GetSwAttrSet().GetPool()->GetDefaultItem(pEntry->nWID); 1121 if ( !lcl_mayBeDefault(pEntry->nWID, pEntry->nMemberId, pPrevItem, *pCurrItem, false) ) 1122 continue; 1123 } 1124 1125 // Apply table-style property 1126 // point and mark selecting the whole paragraph 1127 SwPaM aPaM(*pNd, 0, *pNd, pNd->GetText().getLength()); 1128 // for isCHRATR: change the base/auto SwAttr property, but don't remove the DIRECT hints 1129 SwUnoCursorHelper::SetPropertyValue(aPaM, rParaPropSet, rPropertyName, aValue, SetAttrMode::DONTREPLACE); 1130 } 1131 return; 1132 } 1133 } 1134 1135 if(!pEntry) 1136 throw beans::UnknownPropertyException(rPropertyName, static_cast<cppu::OWeakObject*>(this)); 1137 if(pEntry->nWID != FN_UNO_CELL_ROW_SPAN) 1138 { 1139 SwFrameFormat* pBoxFormat = m_pBox->ClaimFrameFormat(); 1140 SwAttrSet aSet(pBoxFormat->GetAttrSet()); 1141 m_pPropSet->setPropertyValue(rPropertyName, aValue, aSet); 1142 pBoxFormat->GetDoc()->SetAttr(aSet, *pBoxFormat); 1143 } 1144 else if(aValue.isExtractableTo(cppu::UnoType<sal_Int32>::get())) 1145 m_pBox->setRowSpan(aValue.get<sal_Int32>()); 1146 } 1147 } 1148 1149 uno::Any SwXCell::getPropertyValue(const OUString& rPropertyName) 1150 { 1151 SolarMutexGuard aGuard; 1152 if(!IsValid()) 1153 return uno::Any(); 1154 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName)); 1155 if(!pEntry) 1156 throw beans::UnknownPropertyException(rPropertyName, static_cast<cppu::OWeakObject*>(this)); 1157 switch(pEntry->nWID) 1158 { 1159 case FN_UNO_CELL_ROW_SPAN: 1160 return uno::makeAny(m_pBox->getRowSpan()); 1161 break; 1162 case FN_UNO_TEXT_SECTION: 1163 { 1164 SwFrameFormat* pTableFormat = GetFrameFormat(); 1165 SwTable* pTable = SwTable::FindTable(pTableFormat); 1166 SwTableNode* pTableNode = pTable->GetTableNode(); 1167 SwSectionNode* pSectionNode = pTableNode->FindSectionNode(); 1168 if(!pSectionNode) 1169 return uno::Any(); 1170 SwSection& rSect = pSectionNode->GetSection(); 1171 return uno::makeAny(SwXTextSections::GetObject(*rSect.GetFormat())); 1172 } 1173 break; 1174 case FN_UNO_CELL_NAME: 1175 return uno::makeAny(m_pBox->GetName()); 1176 break; 1177 case FN_UNO_REDLINE_NODE_START: 1178 case FN_UNO_REDLINE_NODE_END: 1179 { 1180 //redline can only be returned if it's a living object 1181 return SwXText::getPropertyValue(rPropertyName); 1182 } 1183 break; 1184 case FN_UNO_PARENT_TEXT: 1185 { 1186 if (!m_xParentText.is()) 1187 { 1188 const SwStartNode* pSttNd = m_pBox->GetSttNd(); 1189 if (!pSttNd) 1190 return uno::Any(); 1191 1192 const SwTableNode* pTableNode = pSttNd->FindTableNode(); 1193 if (!pTableNode) 1194 return uno::Any(); 1195 1196 SwPosition aPos(*pTableNode); 1197 SwDoc* pDoc = aPos.GetDoc(); 1198 if (!pDoc) 1199 return uno::Any(); 1200 1201 m_xParentText = sw::CreateParentXText(*pDoc, aPos); 1202 } 1203 1204 return uno::makeAny(m_xParentText); 1205 } 1206 break; 1207 default: 1208 { 1209 const SwAttrSet& rSet = m_pBox->GetFrameFormat()->GetAttrSet(); 1210 uno::Any aResult; 1211 m_pPropSet->getPropertyValue(rPropertyName, rSet, aResult); 1212 return aResult; 1213 } 1214 } 1215 } 1216 1217 void SwXCell::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) 1218 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1219 1220 void SwXCell::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) 1221 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1222 1223 void SwXCell::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) 1224 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1225 1226 void SwXCell::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) 1227 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1228 1229 uno::Reference<container::XEnumeration> SwXCell::createEnumeration() 1230 { 1231 SolarMutexGuard aGuard; 1232 if(!IsValid()) 1233 return uno::Reference<container::XEnumeration>(); 1234 const SwStartNode* pSttNd = m_pBox->GetSttNd(); 1235 SwPosition aPos(*pSttNd); 1236 auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos)); 1237 pUnoCursor->Move(fnMoveForward, GoInNode); 1238 // remember table and start node for later travelling 1239 // (used in export of tables in tables) 1240 SwTable const*const pTable(&pSttNd->FindTableNode()->GetTable()); 1241 return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::TableText, pSttNd, pTable); 1242 } 1243 1244 uno::Type SAL_CALL SwXCell::getElementType() 1245 { 1246 return cppu::UnoType<text::XTextRange>::get(); 1247 } 1248 1249 sal_Bool SwXCell::hasElements() 1250 { 1251 return true; 1252 } 1253 1254 void SwXCell::Notify(const SfxHint& rHint) 1255 { 1256 if(rHint.GetId() == SfxHintId::Dying) 1257 { 1258 m_pTableFormat = nullptr; 1259 } 1260 else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableBox, SwXCell>*>(&rHint)) 1261 { 1262 if(!pFindHint->m_pResult && pFindHint->m_pCore == GetTableBox()) 1263 pFindHint->m_pResult = this; 1264 } 1265 } 1266 1267 SwXCell* SwXCell::CreateXCell(SwFrameFormat* pTableFormat, SwTableBox* pBox, SwTable *pTable ) 1268 { 1269 if(!pTableFormat || !pBox) 1270 return nullptr; 1271 if(!pTable) 1272 pTable = SwTable::FindTable(pTableFormat); 1273 SwTableSortBoxes::const_iterator it = pTable->GetTabSortBoxes().find(pBox); 1274 if(it == pTable->GetTabSortBoxes().end()) 1275 return nullptr; 1276 size_t const nPos = it - pTable->GetTabSortBoxes().begin(); 1277 FindUnoInstanceHint<SwTableBox, SwXCell> aHint{pBox}; 1278 pTableFormat->GetNotifier().Broadcast(aHint); 1279 return aHint.m_pResult ? aHint.m_pResult : new SwXCell(pTableFormat, pBox, nPos); 1280 } 1281 1282 /** search if a box exists in a table 1283 * 1284 * @param pTable the table to search in 1285 * @param pBox2 box model to find 1286 * @return the box if existent in pTable, 0 (!!!) if not found 1287 */ 1288 SwTableBox* SwXCell::FindBox(SwTable* pTable, SwTableBox* pBox2) 1289 { 1290 // check if nFndPos happens to point to the right table box 1291 if( m_nFndPos < pTable->GetTabSortBoxes().size() && 1292 pBox2 == pTable->GetTabSortBoxes()[ m_nFndPos ] ) 1293 return pBox2; 1294 1295 // if not, seek the entry (and return, if successful) 1296 SwTableSortBoxes::const_iterator it = pTable->GetTabSortBoxes().find( pBox2 ); 1297 if( it != pTable->GetTabSortBoxes().end() ) 1298 { 1299 m_nFndPos = it - pTable->GetTabSortBoxes().begin(); 1300 return pBox2; 1301 } 1302 1303 // box not found: reset nFndPos pointer 1304 m_nFndPos = NOTFOUND; 1305 return nullptr; 1306 } 1307 1308 double SwXCell::GetForcedNumericalValue() const 1309 { 1310 if(table::CellContentType_TEXT != const_cast<SwXCell*>(this)->getType()) 1311 return getValue(); 1312 // now we'll try to get a useful numerical value 1313 // from the text in the cell... 1314 sal_uInt32 nFIndex; 1315 SvNumberFormatter* pNumFormatter(const_cast<SvNumberFormatter*>(GetDoc()->GetNumberFormatter())); 1316 // look for SwTableBoxNumFormat value in parents as well 1317 const SfxPoolItem* pItem; 1318 auto pBoxFormat(GetTableBox()->GetFrameFormat()); 1319 SfxItemState eState = pBoxFormat->GetAttrSet().GetItemState(RES_BOXATR_FORMAT, true, &pItem); 1320 1321 if (eState == SfxItemState::SET) 1322 { 1323 // please note that the language of the numberformat 1324 // is implicitly coded into the below value as well 1325 nFIndex = static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue(); 1326 1327 // since the current value indicates a text format but the call 1328 // to 'IsNumberFormat' below won't work for text formats 1329 // we need to get rid of the part that indicates the text format. 1330 // According to ER this can be done like this: 1331 nFIndex -= (nFIndex % SV_COUNTRY_LANGUAGE_OFFSET); 1332 } 1333 else 1334 { 1335 // system language is probably not the best possible choice 1336 // but since we have to guess anyway (because the language of at 1337 // the text is NOT the one used for the number format!) 1338 // it is at least conform to what is used in 1339 // SwTableShell::Execute when 1340 // SID_ATTR_NUMBERFORMAT_VALUE is set... 1341 LanguageType eLang = LANGUAGE_SYSTEM; 1342 nFIndex = pNumFormatter->GetStandardIndex( eLang ); 1343 } 1344 double fTmp; 1345 if (!const_cast<SwDoc*>(GetDoc())->IsNumberFormat(const_cast<SwXCell*>(this)->getString(), nFIndex, fTmp)) 1346 ::rtl::math::setNan(&fTmp); 1347 return fTmp; 1348 } 1349 1350 uno::Any SwXCell::GetAny() const 1351 { 1352 if(!m_pBox) 1353 throw uno::RuntimeException(); 1354 // check if table box value item is set 1355 auto pBoxFormat(m_pBox->GetFrameFormat()); 1356 const bool bIsNum = pBoxFormat->GetItemState(RES_BOXATR_VALUE, false) == SfxItemState::SET; 1357 return bIsNum ? uno::makeAny(getValue()) : uno::makeAny(const_cast<SwXCell*>(this)->getString()); 1358 } 1359 1360 OUString SwXCell::getImplementationName() 1361 { return "SwXCell"; } 1362 1363 sal_Bool SwXCell::supportsService(const OUString& rServiceName) 1364 { return cppu::supportsService(this, rServiceName); } 1365 1366 uno::Sequence< OUString > SwXCell::getSupportedServiceNames() 1367 { return {"com.sun.star.text.CellProperties"}; } 1368 1369 OUString SwXTextTableRow::getImplementationName() 1370 { return "SwXTextTableRow"; } 1371 1372 sal_Bool SwXTextTableRow::supportsService(const OUString& rServiceName) 1373 { return cppu::supportsService(this, rServiceName); } 1374 1375 uno::Sequence< OUString > SwXTextTableRow::getSupportedServiceNames() 1376 { return {"com.sun.star.text.TextTableRow"}; } 1377 1378 1379 SwXTextTableRow::SwXTextTableRow(SwFrameFormat* pFormat, SwTableLine* pLn) : 1380 m_pFormat(pFormat), 1381 pLine(pLn), 1382 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_ROW)) 1383 { 1384 StartListening(m_pFormat->GetNotifier()); 1385 } 1386 1387 SwXTextTableRow::~SwXTextTableRow() 1388 { 1389 SolarMutexGuard aGuard; 1390 EndListeningAll(); 1391 } 1392 1393 uno::Reference< beans::XPropertySetInfo > SwXTextTableRow::getPropertySetInfo() 1394 { 1395 static uno::Reference<beans::XPropertySetInfo> xRef = m_pPropSet->getPropertySetInfo(); 1396 return xRef; 1397 } 1398 1399 void SwXTextTableRow::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) 1400 { 1401 SolarMutexGuard aGuard; 1402 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 1403 SwTable* pTable = SwTable::FindTable( pFormat ); 1404 SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, pLine); 1405 if(pLn) 1406 { 1407 // Check for a specific property 1408 if ( rPropertyName == "TableRedlineParams" ) 1409 { 1410 // Get the table row properties 1411 uno::Sequence< beans::PropertyValue > tableRowProperties = aValue.get< uno::Sequence< beans::PropertyValue > >(); 1412 comphelper::SequenceAsHashMap aPropMap( tableRowProperties ); 1413 OUString sRedlineType; 1414 if( !(aPropMap.getValue("RedlineType") >>= sRedlineType) ) 1415 { 1416 throw beans::UnknownPropertyException("No redline type property: ", static_cast < cppu::OWeakObject * > ( this ) ); 1417 } 1418 1419 // Create a 'Table Row Redline' object 1420 SwUnoCursorHelper::makeTableRowRedline( *pLn, sRedlineType, tableRowProperties); 1421 1422 } 1423 else 1424 { 1425 const SfxItemPropertySimpleEntry* pEntry = 1426 m_pPropSet->getPropertyMap().getByName(rPropertyName); 1427 SwDoc* pDoc = pFormat->GetDoc(); 1428 if (!pEntry) 1429 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) ); 1430 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) 1431 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) ); 1432 1433 switch(pEntry->nWID) 1434 { 1435 case FN_UNO_ROW_HEIGHT: 1436 case FN_UNO_ROW_AUTO_HEIGHT: 1437 { 1438 SwFormatFrameSize aFrameSize(pLn->GetFrameFormat()->GetFrameSize()); 1439 if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID) 1440 { 1441 bool bSet = *o3tl::doAccess<bool>(aValue); 1442 aFrameSize.SetHeightSizeType(bSet ? SwFrameSize::Variable : SwFrameSize::Fixed); 1443 } 1444 else 1445 { 1446 sal_Int32 nHeight = 0; 1447 aValue >>= nHeight; 1448 Size aSz(aFrameSize.GetSize()); 1449 aSz.setHeight( convertMm100ToTwip(nHeight) ); 1450 aFrameSize.SetSize(aSz); 1451 } 1452 pDoc->SetAttr(aFrameSize, *pLn->ClaimFrameFormat()); 1453 } 1454 break; 1455 1456 case FN_UNO_TABLE_COLUMN_SEPARATORS: 1457 { 1458 UnoActionContext aContext(pDoc); 1459 SwTable* pTable2 = SwTable::FindTable( pFormat ); 1460 lcl_SetTableSeparators(aValue, pTable2, pLine->GetTabBoxes()[0], true, pDoc); 1461 } 1462 break; 1463 1464 default: 1465 { 1466 SwFrameFormat* pLnFormat = pLn->ClaimFrameFormat(); 1467 SwAttrSet aSet(pLnFormat->GetAttrSet()); 1468 m_pPropSet->setPropertyValue(*pEntry, aValue, aSet); 1469 pDoc->SetAttr(aSet, *pLnFormat); 1470 } 1471 } 1472 } 1473 } 1474 } 1475 1476 uno::Any SwXTextTableRow::getPropertyValue(const OUString& rPropertyName) 1477 { 1478 SolarMutexGuard aGuard; 1479 uno::Any aRet; 1480 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 1481 SwTable* pTable = SwTable::FindTable( pFormat ); 1482 SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, pLine); 1483 if(pLn) 1484 { 1485 const SfxItemPropertySimpleEntry* pEntry = 1486 m_pPropSet->getPropertyMap().getByName(rPropertyName); 1487 if (!pEntry) 1488 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) ); 1489 1490 switch(pEntry->nWID) 1491 { 1492 case FN_UNO_ROW_HEIGHT: 1493 case FN_UNO_ROW_AUTO_HEIGHT: 1494 { 1495 const SwFormatFrameSize& rSize = pLn->GetFrameFormat()->GetFrameSize(); 1496 if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID) 1497 { 1498 aRet <<= SwFrameSize::Variable == rSize.GetHeightSizeType(); 1499 } 1500 else 1501 aRet <<= static_cast<sal_Int32>(convertTwipToMm100(rSize.GetSize().Height())); 1502 } 1503 break; 1504 1505 case FN_UNO_TABLE_COLUMN_SEPARATORS: 1506 { 1507 lcl_GetTableSeparators(aRet, pTable, pLine->GetTabBoxes()[0], true); 1508 } 1509 break; 1510 1511 default: 1512 { 1513 const SwAttrSet& rSet = pLn->GetFrameFormat()->GetAttrSet(); 1514 m_pPropSet->getPropertyValue(*pEntry, rSet, aRet); 1515 } 1516 } 1517 } 1518 return aRet; 1519 } 1520 1521 void SwXTextTableRow::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) 1522 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1523 1524 void SwXTextTableRow::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) 1525 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1526 1527 void SwXTextTableRow::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) 1528 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1529 1530 void SwXTextTableRow::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) 1531 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1532 1533 void SwXTextTableRow::Notify(const SfxHint& rHint) 1534 { 1535 if(rHint.GetId() == SfxHintId::Dying) 1536 { 1537 m_pFormat = nullptr; 1538 } else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableLine, SwXTextTableRow>*>(&rHint)) 1539 { 1540 if(!pFindHint->m_pCore && pFindHint->m_pCore == pLine) 1541 pFindHint->m_pResult = this; 1542 } 1543 } 1544 1545 SwTableLine* SwXTextTableRow::FindLine(SwTable* pTable, SwTableLine const * pLine) 1546 { 1547 for(const auto& pCurrentLine : pTable->GetTabLines()) 1548 if(pCurrentLine == pLine) 1549 return pCurrentLine; 1550 return nullptr; 1551 } 1552 1553 // SwXTextTableCursor 1554 1555 OUString SwXTextTableCursor::getImplementationName() 1556 { return "SwXTextTableCursor"; } 1557 1558 sal_Bool SwXTextTableCursor::supportsService(const OUString& rServiceName) 1559 { return cppu::supportsService(this, rServiceName); } 1560 1561 void SwXTextTableCursor::acquire() throw() 1562 { 1563 SwXTextTableCursor_Base::acquire(); 1564 } 1565 1566 void SwXTextTableCursor::release() throw() 1567 { 1568 SolarMutexGuard aGuard; 1569 SwXTextTableCursor_Base::release(); 1570 } 1571 1572 css::uno::Any SAL_CALL 1573 SwXTextTableCursor::queryInterface( const css::uno::Type& _rType ) 1574 { 1575 css::uno::Any aReturn = SwXTextTableCursor_Base::queryInterface( _rType ); 1576 if ( !aReturn.hasValue() ) 1577 aReturn = OTextCursorHelper::queryInterface( _rType ); 1578 return aReturn; 1579 } 1580 1581 const SwPaM* SwXTextTableCursor::GetPaM() const { return &GetCursor(); } 1582 SwPaM* SwXTextTableCursor::GetPaM() { return &GetCursor(); } 1583 const SwDoc* SwXTextTableCursor::GetDoc() const { return GetFrameFormat()->GetDoc(); } 1584 SwDoc* SwXTextTableCursor::GetDoc() { return GetFrameFormat()->GetDoc(); } 1585 const SwUnoCursor& SwXTextTableCursor::GetCursor() const { return *m_pUnoCursor; } 1586 SwUnoCursor& SwXTextTableCursor::GetCursor() { return *m_pUnoCursor; } 1587 1588 uno::Sequence<OUString> SwXTextTableCursor::getSupportedServiceNames() 1589 { return {"com.sun.star.text.TextTableCursor"}; } 1590 1591 SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat* pFrameFormat, SwTableBox const* pBox) 1592 : m_pFrameFormat(pFrameFormat) 1593 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR)) 1594 { 1595 StartListening(m_pFrameFormat->GetNotifier()); 1596 SwDoc* pDoc = m_pFrameFormat->GetDoc(); 1597 const SwStartNode* pSttNd = pBox->GetSttNd(); 1598 SwPosition aPos(*pSttNd); 1599 m_pUnoCursor = pDoc->CreateUnoCursor(aPos, true); 1600 m_pUnoCursor->Move( fnMoveForward, GoInNode ); 1601 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pUnoCursor); 1602 rTableCursor.MakeBoxSels(); 1603 } 1604 1605 SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat& rTableFormat, const SwTableCursor* pTableSelection) 1606 : m_pFrameFormat(&rTableFormat) 1607 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR)) 1608 { 1609 StartListening(m_pFrameFormat->GetNotifier()); 1610 m_pUnoCursor = pTableSelection->GetDoc()->CreateUnoCursor(*pTableSelection->GetPoint(), true); 1611 if(pTableSelection->HasMark()) 1612 { 1613 m_pUnoCursor->SetMark(); 1614 *m_pUnoCursor->GetMark() = *pTableSelection->GetMark(); 1615 } 1616 const SwSelBoxes& rBoxes = pTableSelection->GetSelectedBoxes(); 1617 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pUnoCursor); 1618 for(auto pBox : rBoxes) 1619 rTableCursor.InsertBox(*pBox); 1620 rTableCursor.MakeBoxSels(); 1621 } 1622 1623 OUString SwXTextTableCursor::getRangeName() 1624 { 1625 SolarMutexGuard aGuard; 1626 SwUnoCursor& rUnoCursor = GetCursor(); 1627 SwUnoTableCursor* pTableCursor = dynamic_cast<SwUnoTableCursor*>(&rUnoCursor); 1628 //!! see also SwChartDataSequence::getSourceRangeRepresentation 1629 if(!pTableCursor) 1630 return OUString(); 1631 pTableCursor->MakeBoxSels(); 1632 const SwStartNode* pNode = pTableCursor->GetPoint()->nNode.GetNode().FindTableBoxStartNode(); 1633 const SwTable* pTable = SwTable::FindTable(GetFrameFormat()); 1634 const SwTableBox* pEndBox = pTable->GetTableBox(pNode->GetIndex()); 1635 if(pTableCursor->HasMark()) 1636 { 1637 pNode = pTableCursor->GetMark()->nNode.GetNode().FindTableBoxStartNode(); 1638 const SwTableBox* pStartBox = pTable->GetTableBox(pNode->GetIndex()); 1639 if(pEndBox != pStartBox) 1640 { 1641 // need to switch start and end? 1642 if(*pTableCursor->GetPoint() < *pTableCursor->GetMark()) 1643 std::swap(pStartBox, pEndBox); 1644 return pStartBox->GetName() + ":" + pEndBox->GetName(); 1645 } 1646 } 1647 return pEndBox->GetName(); 1648 } 1649 1650 sal_Bool SwXTextTableCursor::gotoCellByName(const OUString& sCellName, sal_Bool bExpand) 1651 { 1652 SolarMutexGuard aGuard; 1653 SwUnoCursor& rUnoCursor = GetCursor(); 1654 auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1655 lcl_CursorSelect(rTableCursor, bExpand); 1656 return rTableCursor.GotoTableBox(sCellName); 1657 } 1658 1659 sal_Bool SwXTextTableCursor::goLeft(sal_Int16 Count, sal_Bool bExpand) 1660 { 1661 SolarMutexGuard aGuard; 1662 SwUnoCursor& rUnoCursor = GetCursor(); 1663 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1664 lcl_CursorSelect(rTableCursor, bExpand); 1665 return rTableCursor.Left(Count); 1666 } 1667 1668 sal_Bool SwXTextTableCursor::goRight(sal_Int16 Count, sal_Bool bExpand) 1669 { 1670 SolarMutexGuard aGuard; 1671 SwUnoCursor& rUnoCursor = GetCursor(); 1672 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1673 lcl_CursorSelect(rTableCursor, bExpand); 1674 return rTableCursor.Right(Count); 1675 } 1676 1677 sal_Bool SwXTextTableCursor::goUp(sal_Int16 Count, sal_Bool bExpand) 1678 { 1679 SolarMutexGuard aGuard; 1680 SwUnoCursor& rUnoCursor = GetCursor(); 1681 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1682 lcl_CursorSelect(rTableCursor, bExpand); 1683 return rTableCursor.UpDown(true, Count, nullptr, 0, 1684 *rUnoCursor.GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout()); 1685 } 1686 1687 sal_Bool SwXTextTableCursor::goDown(sal_Int16 Count, sal_Bool bExpand) 1688 { 1689 SolarMutexGuard aGuard; 1690 SwUnoCursor& rUnoCursor = GetCursor(); 1691 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1692 lcl_CursorSelect(rTableCursor, bExpand); 1693 return rTableCursor.UpDown(false, Count, nullptr, 0, 1694 *rUnoCursor.GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout()); 1695 } 1696 1697 void SwXTextTableCursor::gotoStart(sal_Bool bExpand) 1698 { 1699 SolarMutexGuard aGuard; 1700 SwUnoCursor& rUnoCursor = GetCursor(); 1701 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1702 lcl_CursorSelect(rTableCursor, bExpand); 1703 rTableCursor.MoveTable(GotoCurrTable, fnTableStart); 1704 } 1705 1706 void SwXTextTableCursor::gotoEnd(sal_Bool bExpand) 1707 { 1708 SolarMutexGuard aGuard; 1709 SwUnoCursor& rUnoCursor = GetCursor(); 1710 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1711 lcl_CursorSelect(rTableCursor, bExpand); 1712 rTableCursor.MoveTable(GotoCurrTable, fnTableEnd); 1713 } 1714 1715 sal_Bool SwXTextTableCursor::mergeRange() 1716 { 1717 SolarMutexGuard aGuard; 1718 SwUnoCursor& rUnoCursor = GetCursor(); 1719 1720 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1721 { 1722 // HACK: remove pending actions for selecting old style tables 1723 UnoActionRemoveContext aRemoveContext(rTableCursor); 1724 } 1725 rTableCursor.MakeBoxSels(); 1726 bool bResult; 1727 { 1728 UnoActionContext aContext(rUnoCursor.GetDoc()); 1729 bResult = TableMergeErr::Ok == rTableCursor.GetDoc()->MergeTable(rTableCursor); 1730 } 1731 if(bResult) 1732 { 1733 size_t nCount = rTableCursor.GetSelectedBoxesCount(); 1734 while (nCount--) 1735 rTableCursor.DeleteBox(nCount); 1736 } 1737 rTableCursor.MakeBoxSels(); 1738 return bResult; 1739 } 1740 1741 sal_Bool SwXTextTableCursor::splitRange(sal_Int16 Count, sal_Bool Horizontal) 1742 { 1743 SolarMutexGuard aGuard; 1744 if (Count <= 0) 1745 throw uno::RuntimeException("Illegal first argument: needs to be > 0", static_cast<cppu::OWeakObject*>(this)); 1746 SwUnoCursor& rUnoCursor = GetCursor(); 1747 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1748 { 1749 // HACK: remove pending actions for selecting old style tables 1750 UnoActionRemoveContext aRemoveContext(rTableCursor); 1751 } 1752 rTableCursor.MakeBoxSels(); 1753 bool bResult; 1754 { 1755 UnoActionContext aContext(rUnoCursor.GetDoc()); 1756 bResult = rTableCursor.GetDoc()->SplitTable(rTableCursor.GetSelectedBoxes(), !Horizontal, Count); 1757 } 1758 rTableCursor.MakeBoxSels(); 1759 return bResult; 1760 } 1761 1762 uno::Reference< beans::XPropertySetInfo > SwXTextTableCursor::getPropertySetInfo() 1763 { 1764 static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo(); 1765 return xRef; 1766 } 1767 1768 void SwXTextTableCursor::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) 1769 { 1770 SolarMutexGuard aGuard; 1771 SwUnoCursor& rUnoCursor = GetCursor(); 1772 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName)); 1773 if(!pEntry) 1774 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast<cppu::OWeakObject*>(this)); 1775 if(pEntry->nFlags & beans::PropertyAttribute::READONLY) 1776 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast<cppu::OWeakObject*>(this)); 1777 { 1778 auto pSttNode = rUnoCursor.GetNode().StartOfSectionNode(); 1779 const SwTableNode* pTableNode = pSttNode->FindTableNode(); 1780 lcl_FormatTable(pTableNode->GetTable().GetFrameFormat()); 1781 } 1782 auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1783 rTableCursor.MakeBoxSels(); 1784 SwDoc* pDoc = rUnoCursor.GetDoc(); 1785 switch(pEntry->nWID) 1786 { 1787 case FN_UNO_TABLE_CELL_BACKGROUND: 1788 { 1789 std::shared_ptr<SfxPoolItem> aBrush(std::make_shared<SvxBrushItem>(RES_BACKGROUND)); 1790 SwDoc::GetBoxAttr(rUnoCursor, aBrush); 1791 aBrush->PutValue(aValue, pEntry->nMemberId); 1792 pDoc->SetBoxAttr(rUnoCursor, *aBrush); 1793 1794 } 1795 break; 1796 case RES_BOXATR_FORMAT: 1797 { 1798 SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT); 1799 aNumberFormat.PutValue(aValue, 0); 1800 pDoc->SetBoxAttr(rUnoCursor, aNumberFormat); 1801 } 1802 break; 1803 case FN_UNO_PARA_STYLE: 1804 SwUnoCursorHelper::SetTextFormatColl(aValue, rUnoCursor); 1805 break; 1806 default: 1807 { 1808 SfxItemSet aItemSet(pDoc->GetAttrPool(), {{pEntry->nWID, pEntry->nWID}}); 1809 SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(), 1810 aItemSet); 1811 1812 if (!SwUnoCursorHelper::SetCursorPropertyValue( 1813 *pEntry, aValue, rTableCursor.GetSelRing(), aItemSet)) 1814 { 1815 m_pPropSet->setPropertyValue(*pEntry, aValue, aItemSet); 1816 } 1817 SwUnoCursorHelper::SetCursorAttr(rTableCursor.GetSelRing(), 1818 aItemSet, SetAttrMode::DEFAULT, true); 1819 } 1820 } 1821 } 1822 1823 uno::Any SwXTextTableCursor::getPropertyValue(const OUString& rPropertyName) 1824 { 1825 SolarMutexGuard aGuard; 1826 SwUnoCursor& rUnoCursor = GetCursor(); 1827 { 1828 auto pSttNode = rUnoCursor.GetNode().StartOfSectionNode(); 1829 const SwTableNode* pTableNode = pSttNode->FindTableNode(); 1830 lcl_FormatTable(pTableNode->GetTable().GetFrameFormat()); 1831 } 1832 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor); 1833 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName)); 1834 if(!pEntry) 1835 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast<cppu::OWeakObject*>(this)); 1836 rTableCursor.MakeBoxSels(); 1837 uno::Any aResult; 1838 switch(pEntry->nWID) 1839 { 1840 case FN_UNO_TABLE_CELL_BACKGROUND: 1841 { 1842 std::shared_ptr<SfxPoolItem> aBrush(std::make_shared<SvxBrushItem>(RES_BACKGROUND)); 1843 if (SwDoc::GetBoxAttr(rUnoCursor, aBrush)) 1844 aBrush->QueryValue(aResult, pEntry->nMemberId); 1845 } 1846 break; 1847 case RES_BOXATR_FORMAT: 1848 // TODO: GetAttr for table selections in a Doc is missing 1849 throw uno::RuntimeException("Unknown property: " + rPropertyName, static_cast<cppu::OWeakObject*>(this)); 1850 break; 1851 case FN_UNO_PARA_STYLE: 1852 { 1853 auto pFormat(SwUnoCursorHelper::GetCurTextFormatColl(rUnoCursor, false)); 1854 if(pFormat) 1855 aResult <<= pFormat->GetName(); 1856 } 1857 break; 1858 default: 1859 { 1860 SfxItemSet aSet(rTableCursor.GetDoc()->GetAttrPool(), 1861 svl::Items<RES_CHRATR_BEGIN, RES_FRMATR_END-1, 1862 RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER>{}); 1863 SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(), aSet); 1864 m_pPropSet->getPropertyValue(*pEntry, aSet, aResult); 1865 } 1866 } 1867 return aResult; 1868 } 1869 1870 void SwXTextTableCursor::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) 1871 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1872 1873 void SwXTextTableCursor::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) 1874 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1875 1876 void SwXTextTableCursor::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) 1877 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1878 1879 void SwXTextTableCursor::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) 1880 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); }; 1881 1882 void SwXTextTableCursor::Notify( const SfxHint& rHint ) 1883 { 1884 if(rHint.GetId() == SfxHintId::Dying) 1885 m_pFrameFormat = nullptr; 1886 } 1887 1888 1889 // SwXTextTable =========================================================== 1890 1891 namespace { 1892 1893 class SwTableProperties_Impl 1894 { 1895 SwUnoCursorHelper::SwAnyMapHelper aAnyMap; 1896 public: 1897 SwTableProperties_Impl(); 1898 1899 void SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& aVal); 1900 bool GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny); 1901 template<typename Tpoolitem> 1902 inline void AddItemToSet(SfxItemSet& rSet, std::function<Tpoolitem()> aItemFactory, sal_uInt16 nWhich, std::initializer_list<sal_uInt16> vMember, bool bAddTwips = false); 1903 1904 void ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc); 1905 }; 1906 1907 } 1908 1909 SwTableProperties_Impl::SwTableProperties_Impl() 1910 { } 1911 1912 void SwTableProperties_Impl::SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& rVal) 1913 { aAnyMap.SetValue( nWhichId, nMemberId, rVal ); } 1914 1915 bool SwTableProperties_Impl::GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny ) 1916 { return aAnyMap.FillValue( nWhichId, nMemberId, rpAny ); } 1917 1918 template<typename Tpoolitem> 1919 void SwTableProperties_Impl::AddItemToSet(SfxItemSet& rSet, std::function<Tpoolitem()> aItemFactory, sal_uInt16 nWhich, std::initializer_list<sal_uInt16> vMember, bool bAddTwips) 1920 { 1921 std::vector< std::pair<sal_uInt16, const uno::Any* > > vMemberAndAny; 1922 for(sal_uInt16 nMember : vMember) 1923 { 1924 const uno::Any* pAny = nullptr; 1925 GetProperty(nWhich, nMember, pAny); 1926 if(pAny) 1927 vMemberAndAny.emplace_back(nMember, pAny); 1928 } 1929 if(!vMemberAndAny.empty()) 1930 { 1931 Tpoolitem aItem = aItemFactory(); 1932 for(const auto& aMemberAndAny : vMemberAndAny) 1933 aItem->PutValue(*aMemberAndAny.second, aMemberAndAny.first | (bAddTwips ? CONVERT_TWIPS : 0) ); 1934 rSet.Put(*aItem); 1935 } 1936 } 1937 void SwTableProperties_Impl::ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc) 1938 { 1939 SfxItemSet aSet( 1940 rDoc.GetAttrPool(), 1941 svl::Items< 1942 RES_FRM_SIZE, RES_BREAK, 1943 RES_HORI_ORIENT, RES_HORI_ORIENT, 1944 RES_BACKGROUND, RES_BACKGROUND, 1945 RES_SHADOW, RES_SHADOW, 1946 RES_KEEP, RES_KEEP, 1947 RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT>{}); 1948 const uno::Any* pRepHead; 1949 const SwFrameFormat &rFrameFormat = *rTable.GetFrameFormat(); 1950 if(GetProperty(FN_TABLE_HEADLINE_REPEAT, 0xff, pRepHead )) 1951 { 1952 bool bVal(pRepHead->get<bool>()); 1953 const_cast<SwTable&>(rTable).SetRowsToRepeat( bVal ? 1 : 0 ); // TODO: MULTIHEADER 1954 } 1955 1956 AddItemToSet<std::shared_ptr<SvxBrushItem>>(aSet, [&rFrameFormat]() { return rFrameFormat.makeBackgroundBrushItem(); }, RES_BACKGROUND, { 1957 MID_BACK_COLOR, 1958 MID_GRAPHIC_TRANSPARENT, 1959 MID_GRAPHIC_POSITION, 1960 MID_GRAPHIC, 1961 MID_GRAPHIC_FILTER }); 1962 1963 bool bPutBreak = true; 1964 const uno::Any* pPage; 1965 if(GetProperty(FN_UNO_PAGE_STYLE, 0, pPage) || GetProperty(RES_PAGEDESC, 0xff, pPage)) 1966 { 1967 OUString sPageStyle = pPage->get<OUString>(); 1968 if(!sPageStyle.isEmpty()) 1969 { 1970 SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc); 1971 const SwPageDesc* pDesc = SwPageDesc::GetByName(rDoc, sPageStyle); 1972 if(pDesc) 1973 { 1974 SwFormatPageDesc aDesc(pDesc); 1975 const uno::Any* pPgNo; 1976 if(GetProperty(RES_PAGEDESC, MID_PAGEDESC_PAGENUMOFFSET, pPgNo)) 1977 { 1978 aDesc.SetNumOffset(pPgNo->get<sal_Int16>()); 1979 } 1980 aSet.Put(aDesc); 1981 bPutBreak = false; 1982 } 1983 1984 } 1985 } 1986 1987 if(bPutBreak) 1988 AddItemToSet<std::shared_ptr<SvxFormatBreakItem>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SvxFormatBreakItem>(rFrameFormat.GetBreak().Clone()); }, RES_BREAK, {0}); 1989 AddItemToSet<std::shared_ptr<SvxShadowItem>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SvxShadowItem>(rFrameFormat.GetShadow().Clone()); }, RES_SHADOW, {0}, true); 1990 AddItemToSet<std::shared_ptr<SvxFormatKeepItem>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SvxFormatKeepItem>(rFrameFormat.GetKeep().Clone()); }, RES_KEEP, {0}); 1991 AddItemToSet<std::shared_ptr<SwFormatHoriOrient>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SwFormatHoriOrient>(rFrameFormat.GetHoriOrient().Clone()); }, RES_HORI_ORIENT, {MID_HORIORIENT_ORIENT}, true); 1992 1993 const uno::Any* pSzRel(nullptr); 1994 GetProperty(FN_TABLE_IS_RELATIVE_WIDTH, 0xff, pSzRel); 1995 const uno::Any* pRelWidth(nullptr); 1996 GetProperty(FN_TABLE_RELATIVE_WIDTH, 0xff, pRelWidth); 1997 const uno::Any* pWidth(nullptr); 1998 GetProperty(FN_TABLE_WIDTH, 0xff, pWidth); 1999 2000 bool bPutSize = pWidth != nullptr; 2001 SwFormatFrameSize aSz(SwFrameSize::Variable); 2002 if(pWidth) 2003 { 2004 aSz.PutValue(*pWidth, MID_FRMSIZE_WIDTH); 2005 bPutSize = true; 2006 } 2007 if(pSzRel && pSzRel->get<bool>() && pRelWidth) 2008 { 2009 aSz.PutValue(*pRelWidth, MID_FRMSIZE_REL_WIDTH|CONVERT_TWIPS); 2010 bPutSize = true; 2011 } 2012 if(bPutSize) 2013 { 2014 if(!aSz.GetWidth()) 2015 aSz.SetWidth(MINLAY); 2016 aSet.Put(aSz); 2017 } 2018 AddItemToSet<std::shared_ptr<SvxLRSpaceItem>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SvxLRSpaceItem>(rFrameFormat.GetLRSpace().Clone()); }, RES_LR_SPACE, { 2019 MID_L_MARGIN|CONVERT_TWIPS, 2020 MID_R_MARGIN|CONVERT_TWIPS }); 2021 AddItemToSet<std::shared_ptr<SvxULSpaceItem>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SvxULSpaceItem>(rFrameFormat.GetULSpace().Clone()); }, RES_UL_SPACE, { 2022 MID_UP_MARGIN|CONVERT_TWIPS, 2023 MID_LO_MARGIN|CONVERT_TWIPS }); 2024 const::uno::Any* pSplit(nullptr); 2025 if(GetProperty(RES_LAYOUT_SPLIT, 0, pSplit)) 2026 { 2027 SwFormatLayoutSplit aSp(pSplit->get<bool>()); 2028 aSet.Put(aSp); 2029 } 2030 if(aSet.Count()) 2031 { 2032 rDoc.SetAttr(aSet, *rTable.GetFrameFormat()); 2033 } 2034 } 2035 2036 class SwXTextTable::Impl 2037 : public SvtListener 2038 { 2039 private: 2040 SwFrameFormat* m_pFrameFormat; 2041 ::osl::Mutex m_Mutex; // just for OInterfaceContainerHelper2 2042 2043 public: 2044 uno::WeakReference<uno::XInterface> m_wThis; 2045 ::cppu::OMultiTypeInterfaceContainerHelper m_Listeners; 2046 2047 const SfxItemPropertySet * m_pPropSet; 2048 2049 css::uno::WeakReference<css::table::XTableRows> m_xRows; 2050 css::uno::WeakReference<css::table::XTableColumns> m_xColumns; 2051 2052 bool m_bFirstRowAsLabel; 2053 bool m_bFirstColumnAsLabel; 2054 2055 // Descriptor-interface 2056 std::unique_ptr<SwTableProperties_Impl> m_pTableProps; 2057 OUString m_sTableName; 2058 unsigned short m_nRows; 2059 unsigned short m_nColumns; 2060 2061 explicit Impl(SwFrameFormat* const pFrameFormat) 2062 : m_pFrameFormat(pFrameFormat) 2063 , m_Listeners(m_Mutex) 2064 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE)) 2065 , m_bFirstRowAsLabel(false) 2066 , m_bFirstColumnAsLabel(false) 2067 , m_pTableProps(pFrameFormat ? nullptr : new SwTableProperties_Impl) 2068 , m_nRows(pFrameFormat ? 0 : 2) 2069 , m_nColumns(pFrameFormat ? 0 : 2) 2070 { 2071 if(m_pFrameFormat) 2072 StartListening(m_pFrameFormat->GetNotifier()); 2073 } 2074 2075 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; } 2076 void SetFrameFormat(SwFrameFormat& rFrameFormat) 2077 { 2078 EndListeningAll(); 2079 m_pFrameFormat = &rFrameFormat; 2080 StartListening(m_pFrameFormat->GetNotifier()); 2081 } 2082 2083 bool IsDescriptor() const { return m_pTableProps != nullptr; } 2084 2085 // note: lock mutex before calling this to avoid concurrent update 2086 static std::pair<sal_uInt16, sal_uInt16> ThrowIfComplex(SwXTextTable &rThis) 2087 { 2088 sal_uInt16 const nRowCount(rThis.m_pImpl->GetRowCount()); 2089 sal_uInt16 const nColCount(rThis.m_pImpl->GetColumnCount()); 2090 if (!nRowCount || !nColCount) 2091 { 2092 throw uno::RuntimeException("Table too complex", 2093 static_cast<cppu::OWeakObject*>(&rThis)); 2094 } 2095 return std::make_pair(nRowCount, nColCount); 2096 } 2097 2098 sal_uInt16 GetRowCount(); 2099 sal_uInt16 GetColumnCount(); 2100 2101 virtual void Notify(const SfxHint&) override; 2102 2103 }; 2104 2105 namespace 2106 { 2107 class theSwXTextTableUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXTextTableUnoTunnelId > {}; 2108 } 2109 2110 const uno::Sequence< sal_Int8 > & SwXTextTable::getUnoTunnelId() 2111 { return theSwXTextTableUnoTunnelId::get().getSeq(); } 2112 2113 sal_Int64 SAL_CALL SwXTextTable::getSomething( const uno::Sequence< sal_Int8 >& rId ) 2114 { 2115 if(isUnoTunnelId<SwXTextTable>(rId)) 2116 { 2117 return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this)); 2118 } 2119 return 0; 2120 } 2121 2122 2123 SwXTextTable::SwXTextTable() 2124 : m_pImpl(new Impl(nullptr)) 2125 { 2126 } 2127 2128 SwXTextTable::SwXTextTable(SwFrameFormat& rFrameFormat) 2129 : m_pImpl(new Impl(&rFrameFormat)) 2130 { 2131 } 2132 2133 SwXTextTable::~SwXTextTable() 2134 { 2135 } 2136 2137 uno::Reference<text::XTextTable> SwXTextTable::CreateXTextTable(SwFrameFormat* const pFrameFormat) 2138 { 2139 uno::Reference<text::XTextTable> xTable; 2140 if(pFrameFormat) 2141 xTable.set(pFrameFormat->GetXObject(), uno::UNO_QUERY); // cached? 2142 if(xTable.is()) 2143 return xTable; 2144 SwXTextTable* const pNew( pFrameFormat ? new SwXTextTable(*pFrameFormat) : new SwXTextTable()); 2145 xTable.set(pNew); 2146 if(pFrameFormat) 2147 pFrameFormat->SetXObject(xTable); 2148 // need a permanent Reference to initialize m_wThis 2149 pNew->m_pImpl->m_wThis = xTable; 2150 return xTable; 2151 } 2152 2153 SwFrameFormat* SwXTextTable::GetFrameFormat() 2154 { 2155 return m_pImpl->GetFrameFormat(); 2156 } 2157 2158 void SwXTextTable::initialize(sal_Int32 nR, sal_Int32 nC) 2159 { 2160 if (!m_pImpl->IsDescriptor() || nR <= 0 || nC <= 0 || nR >= SAL_MAX_UINT16 || nC >= SAL_MAX_UINT16) 2161 throw uno::RuntimeException(); 2162 m_pImpl->m_nRows = static_cast<sal_uInt16>(nR); 2163 m_pImpl->m_nColumns = static_cast<sal_uInt16>(nC); 2164 } 2165 2166 uno::Reference<table::XTableRows> SAL_CALL SwXTextTable::getRows() 2167 { 2168 SolarMutexGuard aGuard; 2169 uno::Reference<table::XTableRows> xResult(m_pImpl->m_xRows); 2170 if(xResult.is()) 2171 return xResult; 2172 if(SwFrameFormat* pFormat = GetFrameFormat()) 2173 m_pImpl->m_xRows = xResult = new SwXTableRows(*pFormat); 2174 if(!xResult.is()) 2175 throw uno::RuntimeException(); 2176 return xResult; 2177 } 2178 2179 uno::Reference<table::XTableColumns> SAL_CALL SwXTextTable::getColumns() 2180 { 2181 SolarMutexGuard aGuard; 2182 uno::Reference<table::XTableColumns> xResult(m_pImpl->m_xColumns); 2183 if(xResult.is()) 2184 return xResult; 2185 if(SwFrameFormat* pFormat = GetFrameFormat()) 2186 m_pImpl->m_xColumns = xResult = new SwXTableColumns(*pFormat); 2187 if(!xResult.is()) 2188 throw uno::RuntimeException(); 2189 return xResult; 2190 } 2191 2192 uno::Reference<table::XCell> SwXTextTable::getCellByName(const OUString& sCellName) 2193 { 2194 SolarMutexGuard aGuard; 2195 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 2196 SwTable* pTable = SwTable::FindTable(pFormat); 2197 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName)); 2198 if(!pBox) 2199 return nullptr; 2200 return SwXCell::CreateXCell(pFormat, pBox); 2201 } 2202 2203 uno::Sequence<OUString> SwXTextTable::getCellNames() 2204 { 2205 SolarMutexGuard aGuard; 2206 SwFrameFormat* pFormat(GetFrameFormat()); 2207 if(!pFormat) 2208 return {}; 2209 SwTable* pTable = SwTable::FindTable(pFormat); 2210 // exists at the table and at all boxes 2211 SwTableLines& rTableLines = pTable->GetTabLines(); 2212 std::vector<OUString> aAllNames; 2213 lcl_InspectLines(rTableLines, aAllNames); 2214 return comphelper::containerToSequence(aAllNames); 2215 } 2216 2217 uno::Reference<text::XTextTableCursor> SwXTextTable::createCursorByCellName(const OUString& sCellName) 2218 { 2219 SolarMutexGuard aGuard; 2220 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 2221 SwTable* pTable = SwTable::FindTable(pFormat); 2222 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName)); 2223 if(!pBox || pBox->getRowSpan() == 0) 2224 throw uno::RuntimeException(); 2225 return new SwXTextTableCursor(pFormat, pBox); 2226 } 2227 2228 void SAL_CALL 2229 SwXTextTable::attach(const uno::Reference<text::XTextRange> & xTextRange) 2230 { 2231 SolarMutexGuard aGuard; 2232 2233 // attach() must only be called once 2234 if (!m_pImpl->IsDescriptor()) /* already attached ? */ 2235 throw uno::RuntimeException("SwXTextTable: already attached to range.", static_cast<cppu::OWeakObject*>(this)); 2236 2237 uno::Reference<XUnoTunnel> xRangeTunnel(xTextRange, uno::UNO_QUERY); 2238 SwXTextRange* pRange(nullptr); 2239 OTextCursorHelper* pCursor(nullptr); 2240 if(xRangeTunnel.is()) 2241 { 2242 pRange = reinterpret_cast<SwXTextRange*>( 2243 sal::static_int_cast<sal_IntPtr>(xRangeTunnel->getSomething(SwXTextRange::getUnoTunnelId()))); 2244 pCursor = reinterpret_cast<OTextCursorHelper*>( 2245 sal::static_int_cast<sal_IntPtr>(xRangeTunnel->getSomething(OTextCursorHelper::getUnoTunnelId()))); 2246 } 2247 SwDoc* pDoc = pRange ? &pRange->GetDoc() : pCursor ? pCursor->GetDoc() : nullptr; 2248 if (!pDoc || !m_pImpl->m_nRows || !m_pImpl->m_nColumns) 2249 throw lang::IllegalArgumentException(); 2250 SwUnoInternalPaM aPam(*pDoc); 2251 // this now needs to return TRUE 2252 ::sw::XTextRangeToSwPaM(aPam, xTextRange); 2253 { 2254 UnoActionContext aCont(pDoc); 2255 2256 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr); 2257 const SwTable* pTable(nullptr); 2258 if( 0 != aPam.Start()->nContent.GetIndex() ) 2259 { 2260 pDoc->getIDocumentContentOperations().SplitNode(*aPam.Start(), false); 2261 } 2262 //TODO: if it is the last paragraph than add another one! 2263 if(aPam.HasMark()) 2264 { 2265 pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam); 2266 aPam.DeleteMark(); 2267 } 2268 pTable = pDoc->InsertTable(SwInsertTableOptions( SwInsertTableFlags::Headline | SwInsertTableFlags::DefaultBorder | SwInsertTableFlags::SplitLayout, 0 ), 2269 *aPam.GetPoint(), 2270 m_pImpl->m_nRows, 2271 m_pImpl->m_nColumns, 2272 text::HoriOrientation::FULL); 2273 if(pTable) 2274 { 2275 // here, the properties of the descriptor need to be analyzed 2276 m_pImpl->m_pTableProps->ApplyTableAttr(*pTable, *pDoc); 2277 SwFrameFormat* pTableFormat(pTable->GetFrameFormat()); 2278 lcl_FormatTable(pTableFormat); 2279 2280 m_pImpl->SetFrameFormat(*pTableFormat); 2281 2282 if (!m_pImpl->m_sTableName.isEmpty()) 2283 { 2284 sal_uInt16 nIndex = 1; 2285 OUString sTmpNameIndex(m_pImpl->m_sTableName); 2286 while(pDoc->FindTableFormatByName(sTmpNameIndex, true) && nIndex < USHRT_MAX) 2287 { 2288 sTmpNameIndex = m_pImpl->m_sTableName + OUString::number(nIndex++); 2289 } 2290 pDoc->SetTableName( *pTableFormat, sTmpNameIndex); 2291 } 2292 2293 const::uno::Any* pName; 2294 if (m_pImpl->m_pTableProps->GetProperty(FN_UNO_TABLE_NAME, 0, pName)) 2295 setName(pName->get<OUString>()); 2296 m_pImpl->m_pTableProps.reset(); 2297 } 2298 pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); 2299 } 2300 } 2301 2302 uno::Reference<text::XTextRange> SwXTextTable::getAnchor() 2303 { 2304 SolarMutexGuard aGuard; 2305 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 2306 return new SwXTextRange(*pFormat); 2307 } 2308 2309 void SwXTextTable::dispose() 2310 { 2311 SolarMutexGuard aGuard; 2312 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 2313 SwTable* pTable = SwTable::FindTable(pFormat); 2314 SwSelBoxes aSelBoxes; 2315 for(auto& rBox : pTable->GetTabSortBoxes() ) 2316 aSelBoxes.insert(rBox); 2317 pFormat->GetDoc()->DeleteRowCol(aSelBoxes); 2318 } 2319 2320 void SAL_CALL SwXTextTable::addEventListener( 2321 const uno::Reference<lang::XEventListener> & xListener) 2322 { 2323 // no need to lock here as m_pImpl is const and container threadsafe 2324 m_pImpl->m_Listeners.addInterface( 2325 cppu::UnoType<lang::XEventListener>::get(), xListener); 2326 } 2327 2328 void SAL_CALL SwXTextTable::removeEventListener( 2329 const uno::Reference< lang::XEventListener > & xListener) 2330 { 2331 // no need to lock here as m_pImpl is const and container threadsafe 2332 m_pImpl->m_Listeners.removeInterface( 2333 cppu::UnoType<lang::XEventListener>::get(), xListener); 2334 } 2335 2336 uno::Reference<table::XCell> SwXTextTable::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow) 2337 { 2338 SolarMutexGuard aGuard; 2339 SwFrameFormat* pFormat(GetFrameFormat()); 2340 // sheet is unimportant 2341 if(nColumn >= 0 && nRow >= 0 && pFormat) 2342 { 2343 auto pXCell = lcl_CreateXCell(pFormat, nColumn, nRow); 2344 if(pXCell) 2345 return pXCell; 2346 } 2347 throw lang::IndexOutOfBoundsException(); 2348 } 2349 2350 namespace { 2351 2352 uno::Reference<table::XCellRange> GetRangeByName( 2353 SwFrameFormat* pFormat, SwTable const * pTable, 2354 const OUString& rTLName, const OUString& rBRName, 2355 SwRangeDescriptor const & rDesc) 2356 { 2357 const SwTableBox* pTLBox = pTable->GetTableBox(rTLName); 2358 if(!pTLBox) 2359 return nullptr; 2360 const SwStartNode* pSttNd = pTLBox->GetSttNd(); 2361 SwPosition aPos(*pSttNd); 2362 // set cursor to the upper-left cell of the range 2363 auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true)); 2364 pUnoCursor->Move(fnMoveForward, GoInNode); 2365 pUnoCursor->SetRemainInSection(false); 2366 const SwTableBox* pBRBox(pTable->GetTableBox(rBRName)); 2367 if(!pBRBox) 2368 return nullptr; 2369 pUnoCursor->SetMark(); 2370 pUnoCursor->GetPoint()->nNode = *pBRBox->GetSttNd(); 2371 pUnoCursor->Move( fnMoveForward, GoInNode ); 2372 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); 2373 // HACK: remove pending actions for selecting old style tables 2374 UnoActionRemoveContext aRemoveContext(rCursor); 2375 rCursor.MakeBoxSels(); 2376 // pUnoCursor will be provided and will not be deleted 2377 return SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, rDesc).get(); 2378 } 2379 2380 } // namespace 2381 2382 uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByPosition(sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom) 2383 { 2384 SolarMutexGuard aGuard; 2385 SwFrameFormat* pFormat(GetFrameFormat()); 2386 if(pFormat && 2387 nLeft <= nRight && nTop <= nBottom && 2388 nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 ) 2389 { 2390 SwTable* pTable = SwTable::FindTable(pFormat); 2391 if(!pTable->IsTableComplex()) 2392 { 2393 SwRangeDescriptor aDesc; 2394 aDesc.nTop = nTop; 2395 aDesc.nBottom = nBottom; 2396 aDesc.nLeft = nLeft; 2397 aDesc.nRight = nRight; 2398 const OUString sTLName = sw_GetCellName(aDesc.nLeft, aDesc.nTop); 2399 const OUString sBRName = sw_GetCellName(aDesc.nRight, aDesc.nBottom); 2400 // please note that according to the 'if' statement at the begin 2401 // sTLName:sBRName already denotes the normalized range string 2402 return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc); 2403 } 2404 } 2405 throw lang::IndexOutOfBoundsException(); 2406 } 2407 2408 uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByName(const OUString& sRange) 2409 { 2410 SolarMutexGuard aGuard; 2411 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 2412 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), static_cast<cppu::OWeakObject*>(this)); 2413 sal_Int32 nPos = 0; 2414 const OUString sTLName(sRange.getToken(0, ':', nPos)); 2415 const OUString sBRName(sRange.getToken(0, ':', nPos)); 2416 if(sTLName.isEmpty() || sBRName.isEmpty()) 2417 throw uno::RuntimeException(); 2418 SwRangeDescriptor aDesc; 2419 aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1; 2420 SwXTextTable::GetCellPosition(sTLName, aDesc.nLeft, aDesc.nTop ); 2421 SwXTextTable::GetCellPosition(sBRName, aDesc.nRight, aDesc.nBottom ); 2422 2423 // we should normalize the range now (e.g. A5:C1 will become A1:C5) 2424 // since (depending on what is done later) it will be troublesome 2425 // elsewhere when the cursor in the implementation does not 2426 // point to the top-left and bottom-right cells 2427 aDesc.Normalize(); 2428 return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc); 2429 } 2430 2431 uno::Sequence< uno::Sequence< uno::Any > > SAL_CALL SwXTextTable::getDataArray() 2432 { 2433 SolarMutexGuard aGuard; 2434 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); 2435 uno::Reference<sheet::XCellRangeData> const xAllRange( 2436 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), 2437 uno::UNO_QUERY_THROW); 2438 return xAllRange->getDataArray(); 2439 } 2440 2441 void SAL_CALL SwXTextTable::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray) 2442 { 2443 SolarMutexGuard aGuard; 2444 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); 2445 uno::Reference<sheet::XCellRangeData> const xAllRange( 2446 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), 2447 uno::UNO_QUERY_THROW); 2448 return xAllRange->setDataArray(rArray); 2449 } 2450 2451 uno::Sequence< uno::Sequence< double > > SwXTextTable::getData() 2452 { 2453 SolarMutexGuard aGuard; 2454 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); 2455 uno::Reference<chart::XChartDataArray> const xAllRange( 2456 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), 2457 uno::UNO_QUERY_THROW); 2458 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( 2459 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); 2460 return xAllRange->getData(); 2461 } 2462 2463 void SwXTextTable::setData(const uno::Sequence< uno::Sequence< double > >& rData) 2464 { 2465 SolarMutexGuard aGuard; 2466 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); 2467 uno::Reference<chart::XChartDataArray> const xAllRange( 2468 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), 2469 uno::UNO_QUERY_THROW); 2470 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( 2471 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); 2472 xAllRange->setData(rData); 2473 // this is rather inconsistent: setData on XTextTable sends events, but e.g. CellRanges do not 2474 lcl_SendChartEvent(*this, m_pImpl->m_Listeners); 2475 } 2476 2477 uno::Sequence<OUString> SwXTextTable::getRowDescriptions() 2478 { 2479 SolarMutexGuard aGuard; 2480 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); 2481 uno::Reference<chart::XChartDataArray> const xAllRange( 2482 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), 2483 uno::UNO_QUERY_THROW); 2484 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( 2485 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); 2486 return xAllRange->getRowDescriptions(); 2487 } 2488 2489 void SwXTextTable::setRowDescriptions(const uno::Sequence<OUString>& rRowDesc) 2490 { 2491 SolarMutexGuard aGuard; 2492 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); 2493 uno::Reference<chart::XChartDataArray> const xAllRange( 2494 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), 2495 uno::UNO_QUERY_THROW); 2496 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( 2497 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); 2498 xAllRange->setRowDescriptions(rRowDesc); 2499 } 2500 2501 uno::Sequence<OUString> SwXTextTable::getColumnDescriptions() 2502 { 2503 SolarMutexGuard aGuard; 2504 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); 2505 uno::Reference<chart::XChartDataArray> const xAllRange( 2506 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), 2507 uno::UNO_QUERY_THROW); 2508 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( 2509 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); 2510 return xAllRange->getColumnDescriptions(); 2511 } 2512 2513 void SwXTextTable::setColumnDescriptions(const uno::Sequence<OUString>& rColumnDesc) 2514 { 2515 SolarMutexGuard aGuard; 2516 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this)); 2517 uno::Reference<chart::XChartDataArray> const xAllRange( 2518 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1), 2519 uno::UNO_QUERY_THROW); 2520 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels( 2521 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel); 2522 return xAllRange->setColumnDescriptions(rColumnDesc); 2523 } 2524 2525 void SAL_CALL SwXTextTable::addChartDataChangeEventListener( 2526 const uno::Reference<chart::XChartDataChangeEventListener> & xListener) 2527 { 2528 // no need to lock here as m_pImpl is const and container threadsafe 2529 m_pImpl->m_Listeners.addInterface( 2530 cppu::UnoType<chart::XChartDataChangeEventListener>::get(), xListener); 2531 } 2532 2533 void SAL_CALL SwXTextTable::removeChartDataChangeEventListener( 2534 const uno::Reference<chart::XChartDataChangeEventListener> & xListener) 2535 { 2536 // no need to lock here as m_pImpl is const and container threadsafe 2537 m_pImpl->m_Listeners.removeInterface( 2538 cppu::UnoType<chart::XChartDataChangeEventListener>::get(), xListener); 2539 } 2540 2541 sal_Bool SwXTextTable::isNotANumber(double nNumber) 2542 { 2543 // We use DBL_MIN because starcalc does (which uses it because chart 2544 // wants it that way!) 2545 return ( nNumber == DBL_MIN ); 2546 } 2547 2548 double SwXTextTable::getNotANumber() 2549 { 2550 // We use DBL_MIN because starcalc does (which uses it because chart 2551 // wants it that way!) 2552 return DBL_MIN; 2553 } 2554 2555 uno::Sequence< beans::PropertyValue > SwXTextTable::createSortDescriptor() 2556 { 2557 SolarMutexGuard aGuard; 2558 2559 return SwUnoCursorHelper::CreateSortDescriptor(true); 2560 } 2561 2562 void SwXTextTable::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor) 2563 { 2564 SolarMutexGuard aGuard; 2565 SwSortOptions aSortOpt; 2566 SwFrameFormat* pFormat = GetFrameFormat(); 2567 if(pFormat && 2568 SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt)) 2569 { 2570 SwTable* pTable = SwTable::FindTable( pFormat ); 2571 SwSelBoxes aBoxes; 2572 const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes(); 2573 for (size_t n = 0; n < rTBoxes.size(); ++n) 2574 { 2575 SwTableBox* pBox = rTBoxes[ n ]; 2576 aBoxes.insert( pBox ); 2577 } 2578 UnoActionContext aContext( pFormat->GetDoc() ); 2579 pFormat->GetDoc()->SortTable(aBoxes, aSortOpt); 2580 } 2581 } 2582 2583 void SwXTextTable::autoFormat(const OUString& sAutoFormatName) 2584 { 2585 SolarMutexGuard aGuard; 2586 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 2587 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), static_cast<cppu::OWeakObject*>(this)); 2588 SwTableAutoFormatTable aAutoFormatTable; 2589 aAutoFormatTable.Load(); 2590 for (size_t i = aAutoFormatTable.size(); i;) 2591 if( sAutoFormatName == aAutoFormatTable[ --i ].GetName() ) 2592 { 2593 SwSelBoxes aBoxes; 2594 const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes(); 2595 for (size_t n = 0; n < rTBoxes.size(); ++n) 2596 { 2597 SwTableBox* pBox = rTBoxes[ n ]; 2598 aBoxes.insert( pBox ); 2599 } 2600 UnoActionContext aContext( pFormat->GetDoc() ); 2601 pFormat->GetDoc()->SetTableAutoFormat( aBoxes, aAutoFormatTable[i] ); 2602 break; 2603 } 2604 } 2605 2606 uno::Reference< beans::XPropertySetInfo > SwXTextTable::getPropertySetInfo() 2607 { 2608 static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo(); 2609 return xRef; 2610 } 2611 2612 void SwXTextTable::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) 2613 { 2614 SolarMutexGuard aGuard; 2615 SwFrameFormat* pFormat = GetFrameFormat(); 2616 if(!aValue.hasValue()) 2617 throw lang::IllegalArgumentException(); 2618 const SfxItemPropertySimpleEntry* pEntry = 2619 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName); 2620 if( !pEntry ) 2621 throw lang::IllegalArgumentException(); 2622 if(pFormat) 2623 { 2624 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) 2625 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) ); 2626 2627 if(0xBF == pEntry->nMemberId) 2628 { 2629 lcl_SetSpecialProperty(pFormat, pEntry, aValue); 2630 } 2631 else 2632 { 2633 switch(pEntry->nWID) 2634 { 2635 case FN_UNO_TABLE_NAME : 2636 { 2637 OUString sName; 2638 aValue >>= sName; 2639 setName( sName ); 2640 } 2641 break; 2642 2643 case FN_UNO_RANGE_ROW_LABEL: 2644 { 2645 bool bTmp = *o3tl::doAccess<bool>(aValue); 2646 if (m_pImpl->m_bFirstRowAsLabel != bTmp) 2647 { 2648 lcl_SendChartEvent(*this, m_pImpl->m_Listeners); 2649 m_pImpl->m_bFirstRowAsLabel = bTmp; 2650 } 2651 } 2652 break; 2653 2654 case FN_UNO_RANGE_COL_LABEL: 2655 { 2656 bool bTmp = *o3tl::doAccess<bool>(aValue); 2657 if (m_pImpl->m_bFirstColumnAsLabel != bTmp) 2658 { 2659 lcl_SendChartEvent(*this, m_pImpl->m_Listeners); 2660 m_pImpl->m_bFirstColumnAsLabel = bTmp; 2661 } 2662 } 2663 break; 2664 2665 case FN_UNO_TABLE_BORDER: 2666 case FN_UNO_TABLE_BORDER2: 2667 { 2668 table::TableBorder oldBorder; 2669 table::TableBorder2 aBorder; 2670 SvxBorderLine aTopLine; 2671 SvxBorderLine aBottomLine; 2672 SvxBorderLine aLeftLine; 2673 SvxBorderLine aRightLine; 2674 SvxBorderLine aHoriLine; 2675 SvxBorderLine aVertLine; 2676 if (aValue >>= oldBorder) 2677 { 2678 aBorder.IsTopLineValid = oldBorder.IsTopLineValid; 2679 aBorder.IsBottomLineValid = oldBorder.IsBottomLineValid; 2680 aBorder.IsLeftLineValid = oldBorder.IsLeftLineValid; 2681 aBorder.IsRightLineValid = oldBorder.IsRightLineValid; 2682 aBorder.IsHorizontalLineValid = oldBorder.IsHorizontalLineValid; 2683 aBorder.IsVerticalLineValid = oldBorder.IsVerticalLineValid; 2684 aBorder.Distance = oldBorder.Distance; 2685 aBorder.IsDistanceValid = oldBorder.IsDistanceValid; 2686 lcl_LineToSvxLine( 2687 oldBorder.TopLine, aTopLine); 2688 lcl_LineToSvxLine( 2689 oldBorder.BottomLine, aBottomLine); 2690 lcl_LineToSvxLine( 2691 oldBorder.LeftLine, aLeftLine); 2692 lcl_LineToSvxLine( 2693 oldBorder.RightLine, aRightLine); 2694 lcl_LineToSvxLine( 2695 oldBorder.HorizontalLine, aHoriLine); 2696 lcl_LineToSvxLine( 2697 oldBorder.VerticalLine, aVertLine); 2698 } 2699 else if (aValue >>= aBorder) 2700 { 2701 SvxBoxItem::LineToSvxLine( 2702 aBorder.TopLine, aTopLine, true); 2703 SvxBoxItem::LineToSvxLine( 2704 aBorder.BottomLine, aBottomLine, true); 2705 SvxBoxItem::LineToSvxLine( 2706 aBorder.LeftLine, aLeftLine, true); 2707 SvxBoxItem::LineToSvxLine( 2708 aBorder.RightLine, aRightLine, true); 2709 SvxBoxItem::LineToSvxLine( 2710 aBorder.HorizontalLine, aHoriLine, true); 2711 SvxBoxItem::LineToSvxLine( 2712 aBorder.VerticalLine, aVertLine, true); 2713 } 2714 else 2715 { 2716 break; // something else 2717 } 2718 SwDoc* pDoc = pFormat->GetDoc(); 2719 if(!lcl_FormatTable(pFormat)) 2720 break; 2721 SwTable* pTable = SwTable::FindTable( pFormat ); 2722 SwTableLines &rLines = pTable->GetTabLines(); 2723 2724 const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true); 2725 const SwStartNode* pSttNd = pTLBox->GetSttNd(); 2726 SwPosition aPos(*pSttNd); 2727 // set cursor to top left cell 2728 auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true)); 2729 pUnoCursor->Move( fnMoveForward, GoInNode ); 2730 pUnoCursor->SetRemainInSection( false ); 2731 2732 const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false); 2733 pUnoCursor->SetMark(); 2734 pUnoCursor->GetPoint()->nNode = *pBRBox->GetSttNd(); 2735 pUnoCursor->Move( fnMoveForward, GoInNode ); 2736 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); 2737 // HACK: remove pending actions for selecting old style tables 2738 UnoActionRemoveContext aRemoveContext(rCursor); 2739 rCursor.MakeBoxSels(); 2740 2741 SfxItemSet aSet(pDoc->GetAttrPool(), 2742 svl::Items<RES_BOX, RES_BOX, 2743 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>{}); 2744 2745 SvxBoxItem aBox( RES_BOX ); 2746 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER ); 2747 2748 aBox.SetLine(aTopLine.isEmpty() ? nullptr : &aTopLine, SvxBoxItemLine::TOP); 2749 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::TOP, aBorder.IsTopLineValid); 2750 2751 aBox.SetLine(aBottomLine.isEmpty() ? nullptr : &aBottomLine, SvxBoxItemLine::BOTTOM); 2752 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::BOTTOM, aBorder.IsBottomLineValid); 2753 2754 aBox.SetLine(aLeftLine.isEmpty() ? nullptr : &aLeftLine, SvxBoxItemLine::LEFT); 2755 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::LEFT, aBorder.IsLeftLineValid); 2756 2757 aBox.SetLine(aRightLine.isEmpty() ? nullptr : &aRightLine, SvxBoxItemLine::RIGHT); 2758 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::RIGHT, aBorder.IsRightLineValid); 2759 2760 aBoxInfo.SetLine(aHoriLine.isEmpty() ? nullptr : &aHoriLine, SvxBoxInfoItemLine::HORI); 2761 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI, aBorder.IsHorizontalLineValid); 2762 2763 aBoxInfo.SetLine(aVertLine.isEmpty() ? nullptr : &aVertLine, SvxBoxInfoItemLine::VERT); 2764 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT, aBorder.IsVerticalLineValid); 2765 2766 aBox.SetAllDistances(static_cast<sal_uInt16>(convertMm100ToTwip(aBorder.Distance))); 2767 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE, aBorder.IsDistanceValid); 2768 2769 aSet.Put(aBox); 2770 aSet.Put(aBoxInfo); 2771 2772 pDoc->SetTabBorders(rCursor, aSet); 2773 } 2774 break; 2775 2776 case FN_UNO_TABLE_BORDER_DISTANCES: 2777 { 2778 table::TableBorderDistances aTableBorderDistances; 2779 if( !(aValue >>= aTableBorderDistances) || 2780 (!aTableBorderDistances.IsLeftDistanceValid && 2781 !aTableBorderDistances.IsRightDistanceValid && 2782 !aTableBorderDistances.IsTopDistanceValid && 2783 !aTableBorderDistances.IsBottomDistanceValid )) 2784 break; 2785 2786 const sal_uInt16 nLeftDistance = convertMm100ToTwip(aTableBorderDistances.LeftDistance); 2787 const sal_uInt16 nRightDistance = convertMm100ToTwip(aTableBorderDistances.RightDistance); 2788 const sal_uInt16 nTopDistance = convertMm100ToTwip(aTableBorderDistances.TopDistance); 2789 const sal_uInt16 nBottomDistance = convertMm100ToTwip(aTableBorderDistances.BottomDistance); 2790 SwDoc* pDoc = pFormat->GetDoc(); 2791 SwTable* pTable = SwTable::FindTable( pFormat ); 2792 SwTableLines &rLines = pTable->GetTabLines(); 2793 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr); 2794 for(size_t i = 0; i < rLines.size(); ++i) 2795 { 2796 SwTableLine* pLine = rLines[i]; 2797 SwTableBoxes& rBoxes = pLine->GetTabBoxes(); 2798 for(size_t k = 0; k < rBoxes.size(); ++k) 2799 { 2800 SwTableBox* pBox = rBoxes[k]; 2801 const SwFrameFormat* pBoxFormat = pBox->GetFrameFormat(); 2802 const SvxBoxItem& rBox = pBoxFormat->GetBox(); 2803 if( 2804 (aTableBorderDistances.IsLeftDistanceValid && nLeftDistance != rBox.GetDistance( SvxBoxItemLine::LEFT )) || 2805 (aTableBorderDistances.IsRightDistanceValid && nRightDistance != rBox.GetDistance( SvxBoxItemLine::RIGHT )) || 2806 (aTableBorderDistances.IsTopDistanceValid && nTopDistance != rBox.GetDistance( SvxBoxItemLine::TOP )) || 2807 (aTableBorderDistances.IsBottomDistanceValid && nBottomDistance != rBox.GetDistance( SvxBoxItemLine::BOTTOM ))) 2808 { 2809 SvxBoxItem aSetBox( rBox ); 2810 SwFrameFormat* pSetBoxFormat = pBox->ClaimFrameFormat(); 2811 if( aTableBorderDistances.IsLeftDistanceValid ) 2812 aSetBox.SetDistance( nLeftDistance, SvxBoxItemLine::LEFT ); 2813 if( aTableBorderDistances.IsRightDistanceValid ) 2814 aSetBox.SetDistance( nRightDistance, SvxBoxItemLine::RIGHT ); 2815 if( aTableBorderDistances.IsTopDistanceValid ) 2816 aSetBox.SetDistance( nTopDistance, SvxBoxItemLine::TOP ); 2817 if( aTableBorderDistances.IsBottomDistanceValid ) 2818 aSetBox.SetDistance( nBottomDistance, SvxBoxItemLine::BOTTOM ); 2819 pDoc->SetAttr( aSetBox, *pSetBoxFormat ); 2820 } 2821 } 2822 } 2823 pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); 2824 } 2825 break; 2826 2827 case FN_UNO_TABLE_COLUMN_SEPARATORS: 2828 { 2829 UnoActionContext aContext(pFormat->GetDoc()); 2830 SwTable* pTable = SwTable::FindTable( pFormat ); 2831 lcl_SetTableSeparators(aValue, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false, pFormat->GetDoc()); 2832 } 2833 break; 2834 2835 case FN_UNO_TABLE_COLUMN_RELATIVE_SUM:/*_readonly_*/ break; 2836 2837 case FN_UNO_TABLE_TEMPLATE_NAME: 2838 { 2839 SwTable* pTable = SwTable::FindTable(pFormat); 2840 OUString sName; 2841 if (!(aValue >>= sName)) 2842 break; 2843 pTable->SetTableStyleName(sName); 2844 SwDoc* pDoc = pFormat->GetDoc(); 2845 pDoc->GetDocShell()->GetFEShell()->UpdateTableStyleFormatting(pTable->GetTableNode()); 2846 } 2847 break; 2848 2849 default: 2850 { 2851 SwAttrSet aSet(pFormat->GetAttrSet()); 2852 m_pImpl->m_pPropSet->setPropertyValue(*pEntry, aValue, aSet); 2853 pFormat->GetDoc()->SetAttr(aSet, *pFormat); 2854 } 2855 } 2856 } 2857 } 2858 else if (m_pImpl->IsDescriptor()) 2859 { 2860 m_pImpl->m_pTableProps->SetProperty(pEntry->nWID, pEntry->nMemberId, aValue); 2861 } 2862 else 2863 throw uno::RuntimeException(); 2864 } 2865 2866 uno::Any SwXTextTable::getPropertyValue(const OUString& rPropertyName) 2867 { 2868 SolarMutexGuard aGuard; 2869 uno::Any aRet; 2870 SwFrameFormat* pFormat = GetFrameFormat(); 2871 const SfxItemPropertySimpleEntry* pEntry = 2872 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName); 2873 2874 if (!pEntry) 2875 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) ); 2876 2877 if(pFormat) 2878 { 2879 if(0xBF == pEntry->nMemberId) 2880 { 2881 aRet = lcl_GetSpecialProperty(pFormat, pEntry ); 2882 } 2883 else 2884 { 2885 switch(pEntry->nWID) 2886 { 2887 case FN_UNO_TABLE_NAME: 2888 { 2889 aRet <<= getName(); 2890 } 2891 break; 2892 2893 case FN_UNO_ANCHOR_TYPES: 2894 case FN_UNO_TEXT_WRAP: 2895 case FN_UNO_ANCHOR_TYPE: 2896 ::sw::GetDefaultTextContentValue( 2897 aRet, OUString(), pEntry->nWID); 2898 break; 2899 2900 case FN_UNO_RANGE_ROW_LABEL: 2901 { 2902 aRet <<= m_pImpl->m_bFirstRowAsLabel; 2903 } 2904 break; 2905 2906 case FN_UNO_RANGE_COL_LABEL: 2907 aRet <<= m_pImpl->m_bFirstColumnAsLabel; 2908 break; 2909 2910 case FN_UNO_TABLE_BORDER: 2911 case FN_UNO_TABLE_BORDER2: 2912 { 2913 SwDoc* pDoc = pFormat->GetDoc(); 2914 // tables without layout (invisible header/footer?) 2915 if(!lcl_FormatTable(pFormat)) 2916 break; 2917 SwTable* pTable = SwTable::FindTable( pFormat ); 2918 SwTableLines &rLines = pTable->GetTabLines(); 2919 2920 const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true); 2921 const SwStartNode* pSttNd = pTLBox->GetSttNd(); 2922 SwPosition aPos(*pSttNd); 2923 // set cursor to top left cell 2924 auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true)); 2925 pUnoCursor->Move( fnMoveForward, GoInNode ); 2926 pUnoCursor->SetRemainInSection( false ); 2927 2928 const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false); 2929 pUnoCursor->SetMark(); 2930 const SwStartNode* pLastNd = pBRBox->GetSttNd(); 2931 pUnoCursor->GetPoint()->nNode = *pLastNd; 2932 2933 pUnoCursor->Move( fnMoveForward, GoInNode ); 2934 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); 2935 // HACK: remove pending actions for selecting old style tables 2936 UnoActionRemoveContext aRemoveContext(rCursor); 2937 rCursor.MakeBoxSels(); 2938 2939 SfxItemSet aSet(pDoc->GetAttrPool(), 2940 svl::Items<RES_BOX, RES_BOX, 2941 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>{}); 2942 aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER )); 2943 SwDoc::GetTabBorders(rCursor, aSet); 2944 const SvxBoxInfoItem& rBoxInfoItem = aSet.Get(SID_ATTR_BORDER_INNER); 2945 const SvxBoxItem& rBox = aSet.Get(RES_BOX); 2946 2947 if (FN_UNO_TABLE_BORDER == pEntry->nWID) 2948 { 2949 table::TableBorder aTableBorder; 2950 aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true); 2951 aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP); 2952 aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true); 2953 aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM); 2954 aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true); 2955 aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT); 2956 aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true); 2957 aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT ); 2958 aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true); 2959 aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI); 2960 aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true); 2961 aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT); 2962 aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance()); 2963 aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE); 2964 aRet <<= aTableBorder; 2965 } 2966 else 2967 { 2968 table::TableBorder2 aTableBorder; 2969 aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true); 2970 aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP); 2971 aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true); 2972 aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM); 2973 aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true); 2974 aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT); 2975 aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true); 2976 aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT ); 2977 aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true); 2978 aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI); 2979 aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true); 2980 aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT); 2981 aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance()); 2982 aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE); 2983 aRet <<= aTableBorder; 2984 } 2985 } 2986 break; 2987 2988 case FN_UNO_TABLE_BORDER_DISTANCES : 2989 { 2990 table::TableBorderDistances aTableBorderDistances( 0, true, 0, true, 0, true, 0, true ) ; 2991 SwTable* pTable = SwTable::FindTable( pFormat ); 2992 const SwTableLines &rLines = pTable->GetTabLines(); 2993 bool bFirst = true; 2994 sal_uInt16 nLeftDistance = 0; 2995 sal_uInt16 nRightDistance = 0; 2996 sal_uInt16 nTopDistance = 0; 2997 sal_uInt16 nBottomDistance = 0; 2998 2999 for(size_t i = 0; i < rLines.size(); ++i) 3000 { 3001 const SwTableLine* pLine = rLines[i]; 3002 const SwTableBoxes& rBoxes = pLine->GetTabBoxes(); 3003 for(size_t k = 0; k < rBoxes.size(); ++k) 3004 { 3005 const SwTableBox* pBox = rBoxes[k]; 3006 SwFrameFormat* pBoxFormat = pBox->GetFrameFormat(); 3007 const SvxBoxItem& rBox = pBoxFormat->GetBox(); 3008 if( bFirst ) 3009 { 3010 nLeftDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT )); 3011 nRightDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT )); 3012 nTopDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP )); 3013 nBottomDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM )); 3014 bFirst = false; 3015 } 3016 else 3017 { 3018 if( aTableBorderDistances.IsLeftDistanceValid && 3019 nLeftDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT ))) 3020 aTableBorderDistances.IsLeftDistanceValid = false; 3021 if( aTableBorderDistances.IsRightDistanceValid && 3022 nRightDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT ))) 3023 aTableBorderDistances.IsRightDistanceValid = false; 3024 if( aTableBorderDistances.IsTopDistanceValid && 3025 nTopDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP ))) 3026 aTableBorderDistances.IsTopDistanceValid = false; 3027 if( aTableBorderDistances.IsBottomDistanceValid && 3028 nBottomDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM ))) 3029 aTableBorderDistances.IsBottomDistanceValid = false; 3030 } 3031 3032 } 3033 if( !aTableBorderDistances.IsLeftDistanceValid && 3034 !aTableBorderDistances.IsRightDistanceValid && 3035 !aTableBorderDistances.IsTopDistanceValid && 3036 !aTableBorderDistances.IsBottomDistanceValid ) 3037 break; 3038 } 3039 if( aTableBorderDistances.IsLeftDistanceValid) 3040 aTableBorderDistances.LeftDistance = nLeftDistance; 3041 if( aTableBorderDistances.IsRightDistanceValid) 3042 aTableBorderDistances.RightDistance = nRightDistance; 3043 if( aTableBorderDistances.IsTopDistanceValid) 3044 aTableBorderDistances.TopDistance = nTopDistance; 3045 if( aTableBorderDistances.IsBottomDistanceValid) 3046 aTableBorderDistances.BottomDistance = nBottomDistance; 3047 3048 aRet <<= aTableBorderDistances; 3049 } 3050 break; 3051 3052 case FN_UNO_TABLE_COLUMN_SEPARATORS: 3053 { 3054 SwTable* pTable = SwTable::FindTable( pFormat ); 3055 lcl_GetTableSeparators(aRet, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false); 3056 } 3057 break; 3058 3059 case FN_UNO_TABLE_COLUMN_RELATIVE_SUM: 3060 aRet <<= sal_Int16(UNO_TABLE_COLUMN_SUM); 3061 break; 3062 3063 case RES_ANCHOR: 3064 // AnchorType is readonly and might be void (no return value) 3065 break; 3066 3067 case FN_UNO_TEXT_SECTION: 3068 { 3069 SwTable* pTable = SwTable::FindTable( pFormat ); 3070 SwTableNode* pTableNode = pTable->GetTableNode(); 3071 SwSectionNode* pSectionNode = pTableNode->FindSectionNode(); 3072 if(pSectionNode) 3073 { 3074 SwSection& rSect = pSectionNode->GetSection(); 3075 uno::Reference< text::XTextSection > xSect = 3076 SwXTextSections::GetObject( *rSect.GetFormat() ); 3077 aRet <<= xSect; 3078 } 3079 } 3080 break; 3081 3082 case FN_UNO_TABLE_TEMPLATE_NAME: 3083 { 3084 SwTable* pTable = SwTable::FindTable(pFormat); 3085 aRet <<= pTable->GetTableStyleName(); 3086 } 3087 break; 3088 3089 default: 3090 { 3091 const SwAttrSet& rSet = pFormat->GetAttrSet(); 3092 m_pImpl->m_pPropSet->getPropertyValue(*pEntry, rSet, aRet); 3093 } 3094 } 3095 } 3096 } 3097 else if (m_pImpl->IsDescriptor()) 3098 { 3099 const uno::Any* pAny = nullptr; 3100 if (!m_pImpl->m_pTableProps->GetProperty(pEntry->nWID, pEntry->nMemberId, pAny)) 3101 throw lang::IllegalArgumentException(); 3102 else if(pAny) 3103 aRet = *pAny; 3104 } 3105 else 3106 throw uno::RuntimeException(); 3107 return aRet; 3108 } 3109 3110 void SwXTextTable::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) 3111 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); } 3112 3113 void SwXTextTable::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/) 3114 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); } 3115 3116 void SwXTextTable::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) 3117 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); } 3118 3119 void SwXTextTable::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/) 3120 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); } 3121 3122 OUString SwXTextTable::getName() 3123 { 3124 SolarMutexGuard aGuard; 3125 SwFrameFormat* pFormat = GetFrameFormat(); 3126 if (!pFormat && !m_pImpl->IsDescriptor()) 3127 throw uno::RuntimeException(); 3128 if(pFormat) 3129 { 3130 return pFormat->GetName(); 3131 } 3132 return m_pImpl->m_sTableName; 3133 } 3134 3135 void SwXTextTable::setName(const OUString& rName) 3136 { 3137 SolarMutexGuard aGuard; 3138 SwFrameFormat* pFormat = GetFrameFormat(); 3139 if ((!pFormat && !m_pImpl->IsDescriptor()) || 3140 rName.isEmpty() || 3141 rName.indexOf('.')>=0 || 3142 rName.indexOf(' ')>=0 ) 3143 throw uno::RuntimeException(); 3144 3145 if(pFormat) 3146 { 3147 const OUString aOldName( pFormat->GetName() ); 3148 const SwFrameFormats* pFrameFormats = pFormat->GetDoc()->GetTableFrameFormats(); 3149 for (size_t i = pFrameFormats->size(); i;) 3150 { 3151 const SwFrameFormat* pTmpFormat = (*pFrameFormats)[--i]; 3152 if( !pTmpFormat->IsDefault() && 3153 pTmpFormat->GetName() == rName && 3154 pFormat->GetDoc()->IsUsed( *pTmpFormat )) 3155 { 3156 throw uno::RuntimeException(); 3157 } 3158 } 3159 3160 pFormat->SetName( rName ); 3161 3162 SwStartNode *pStNd; 3163 SwNodeIndex aIdx( *pFormat->GetDoc()->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 ); 3164 while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) ) 3165 { 3166 ++aIdx; 3167 SwNode *const pNd = & aIdx.GetNode(); 3168 if ( pNd->IsOLENode() && 3169 aOldName == static_cast<const SwOLENode*>(pNd)->GetChartTableName() ) 3170 { 3171 static_cast<SwOLENode*>(pNd)->SetChartTableName( rName ); 3172 3173 SwTable* pTable = SwTable::FindTable( pFormat ); 3174 //TL_CHART2: chart needs to be notfied about name changes 3175 pFormat->GetDoc()->UpdateCharts( pTable->GetFrameFormat()->GetName() ); 3176 } 3177 aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 ); 3178 } 3179 pFormat->GetDoc()->getIDocumentState().SetModified(); 3180 } 3181 else 3182 m_pImpl->m_sTableName = rName; 3183 } 3184 3185 sal_uInt16 SwXTextTable::Impl::GetRowCount() 3186 { 3187 sal_uInt16 nRet = 0; 3188 SwFrameFormat* pFormat = GetFrameFormat(); 3189 if(pFormat) 3190 { 3191 SwTable* pTable = SwTable::FindTable( pFormat ); 3192 if(!pTable->IsTableComplex()) 3193 { 3194 nRet = pTable->GetTabLines().size(); 3195 } 3196 } 3197 return nRet; 3198 } 3199 3200 sal_uInt16 SwXTextTable::Impl::GetColumnCount() 3201 { 3202 SwFrameFormat* pFormat = GetFrameFormat(); 3203 sal_uInt16 nRet = 0; 3204 if(pFormat) 3205 { 3206 SwTable* pTable = SwTable::FindTable( pFormat ); 3207 if(!pTable->IsTableComplex()) 3208 { 3209 SwTableLines& rLines = pTable->GetTabLines(); 3210 SwTableLine* pLine = rLines.front(); 3211 nRet = pLine->GetTabBoxes().size(); 3212 } 3213 } 3214 return nRet; 3215 } 3216 3217 void SwXTextTable::Impl::Notify(const SfxHint& rHint) 3218 { 3219 if(rHint.GetId() == SfxHintId::Dying) 3220 { 3221 m_pFrameFormat = nullptr; 3222 EndListeningAll(); 3223 } 3224 uno::Reference<uno::XInterface> const xThis(m_wThis); 3225 if (xThis.is()) 3226 { // fdo#72695: if UNO object is already dead, don't revive it with event 3227 if(!m_pFrameFormat) 3228 { 3229 lang::EventObject const ev(xThis); 3230 m_Listeners.disposeAndClear(ev); 3231 } 3232 else 3233 { 3234 lcl_SendChartEvent(xThis.get(), m_Listeners); 3235 } 3236 } 3237 } 3238 3239 OUString SAL_CALL SwXTextTable::getImplementationName() 3240 { return "SwXTextTable"; } 3241 3242 sal_Bool SwXTextTable::supportsService(const OUString& rServiceName) 3243 { return cppu::supportsService(this, rServiceName); } 3244 3245 uno::Sequence<OUString> SwXTextTable::getSupportedServiceNames() 3246 { 3247 return { 3248 "com.sun.star.document.LinkTarget", 3249 "com.sun.star.text.TextTable", 3250 "com.sun.star.text.TextContent", 3251 "com.sun.star.text.TextSortable" }; 3252 } 3253 3254 3255 class SwXCellRange::Impl 3256 : public SvtListener 3257 { 3258 private: 3259 ::osl::Mutex m_Mutex; // just for OInterfaceContainerHelper2 3260 SwFrameFormat* m_pFrameFormat; 3261 3262 public: 3263 uno::WeakReference<uno::XInterface> m_wThis; 3264 ::comphelper::OInterfaceContainerHelper2 m_ChartListeners; 3265 3266 sw::UnoCursorPointer m_pTableCursor; 3267 3268 SwRangeDescriptor m_RangeDescriptor; 3269 const SfxItemPropertySet* m_pPropSet; 3270 3271 bool m_bFirstRowAsLabel; 3272 bool m_bFirstColumnAsLabel; 3273 3274 Impl(sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat, SwRangeDescriptor const& rDesc) 3275 : m_pFrameFormat(&rFrameFormat) 3276 , m_ChartListeners(m_Mutex) 3277 , m_pTableCursor(pCursor) 3278 , m_RangeDescriptor(rDesc) 3279 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_RANGE)) 3280 , m_bFirstRowAsLabel(false) 3281 , m_bFirstColumnAsLabel(false) 3282 { 3283 StartListening(rFrameFormat.GetNotifier()); 3284 m_RangeDescriptor.Normalize(); 3285 } 3286 3287 SwFrameFormat* GetFrameFormat() 3288 { 3289 return m_pFrameFormat; 3290 } 3291 3292 std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32> GetLabelCoordinates(bool bRow); 3293 3294 uno::Sequence<OUString> GetLabelDescriptions(SwXCellRange & rThis, bool bRow); 3295 3296 void SetLabelDescriptions(SwXCellRange & rThis, 3297 const css::uno::Sequence<OUString>& rDesc, bool bRow); 3298 3299 sal_Int32 GetRowCount() const; 3300 sal_Int32 GetColumnCount() const; 3301 3302 virtual void Notify(const SfxHint& ) override; 3303 3304 }; 3305 3306 namespace 3307 { 3308 class theSwXCellRangeUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXCellRangeUnoTunnelId > {}; 3309 } 3310 3311 const uno::Sequence< sal_Int8 > & SwXCellRange::getUnoTunnelId() 3312 { 3313 return theSwXCellRangeUnoTunnelId::get().getSeq(); 3314 } 3315 3316 sal_Int64 SAL_CALL SwXCellRange::getSomething( const uno::Sequence< sal_Int8 >& rId ) 3317 { 3318 if( isUnoTunnelId<SwXCellRange>(rId) ) 3319 { 3320 return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this) ); 3321 } 3322 return 0; 3323 } 3324 3325 3326 OUString SwXCellRange::getImplementationName() 3327 { return "SwXCellRange"; } 3328 3329 sal_Bool SwXCellRange::supportsService(const OUString& rServiceName) 3330 { return cppu::supportsService(this, rServiceName); } 3331 3332 uno::Sequence<OUString> SwXCellRange::getSupportedServiceNames() 3333 { 3334 return { 3335 "com.sun.star.text.CellRange", 3336 "com.sun.star.style.CharacterProperties", 3337 "com.sun.star.style.CharacterPropertiesAsian", 3338 "com.sun.star.style.CharacterPropertiesComplex", 3339 "com.sun.star.style.ParagraphProperties", 3340 "com.sun.star.style.ParagraphPropertiesAsian", 3341 "com.sun.star.style.ParagraphPropertiesComplex" }; 3342 } 3343 3344 SwXCellRange::SwXCellRange(sw::UnoCursorPointer const& pCursor, 3345 SwFrameFormat& rFrameFormat, SwRangeDescriptor const & rDesc) 3346 : m_pImpl(new Impl(pCursor, rFrameFormat, rDesc)) 3347 { 3348 } 3349 3350 SwXCellRange::~SwXCellRange() 3351 { 3352 } 3353 3354 rtl::Reference<SwXCellRange> SwXCellRange::CreateXCellRange( 3355 sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat, 3356 SwRangeDescriptor const & rDesc) 3357 { 3358 SwXCellRange *const pCellRange(new SwXCellRange(pCursor, rFrameFormat, rDesc)); 3359 uno::Reference<table::XCellRange> xCellRange(pCellRange); 3360 // need a permanent Reference to initialize m_wThis 3361 pCellRange->m_pImpl->m_wThis = xCellRange; 3362 return pCellRange; 3363 } 3364 3365 void SwXCellRange::SetLabels(bool bFirstRowAsLabel, bool bFirstColumnAsLabel) 3366 { 3367 m_pImpl->m_bFirstRowAsLabel = bFirstRowAsLabel; 3368 m_pImpl->m_bFirstColumnAsLabel = bFirstColumnAsLabel; 3369 } 3370 3371 std::vector< uno::Reference< table::XCell > > SwXCellRange::GetCells() 3372 { 3373 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); 3374 const sal_Int32 nRowCount(m_pImpl->GetRowCount()); 3375 const sal_Int32 nColCount(m_pImpl->GetColumnCount()); 3376 std::vector< uno::Reference< table::XCell > > vResult; 3377 vResult.reserve(static_cast<size_t>(nRowCount)*static_cast<size_t>(nColCount)); 3378 for(sal_Int32 nRow = 0; nRow < nRowCount; ++nRow) 3379 for(sal_Int32 nCol = 0; nCol < nColCount; ++nCol) 3380 vResult.emplace_back(lcl_CreateXCell(pFormat, m_pImpl->m_RangeDescriptor.nLeft + nCol, m_pImpl->m_RangeDescriptor.nTop + nRow)); 3381 return vResult; 3382 } 3383 3384 uno::Reference<table::XCell> SAL_CALL 3385 SwXCellRange::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow) 3386 { 3387 SolarMutexGuard aGuard; 3388 uno::Reference< table::XCell > aRet; 3389 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); 3390 if(pFormat) 3391 { 3392 if(nColumn >= 0 && nRow >= 0 && 3393 m_pImpl->GetColumnCount() > nColumn && m_pImpl->GetRowCount() > nRow ) 3394 { 3395 SwXCell* pXCell = lcl_CreateXCell(pFormat, 3396 m_pImpl->m_RangeDescriptor.nLeft + nColumn, 3397 m_pImpl->m_RangeDescriptor.nTop + nRow); 3398 if(pXCell) 3399 aRet = pXCell; 3400 } 3401 } 3402 if(!aRet.is()) 3403 throw lang::IndexOutOfBoundsException(); 3404 return aRet; 3405 } 3406 3407 uno::Reference<table::XCellRange> SAL_CALL 3408 SwXCellRange::getCellRangeByPosition( 3409 sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom) 3410 { 3411 SolarMutexGuard aGuard; 3412 uno::Reference< table::XCellRange > aRet; 3413 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); 3414 if (pFormat && m_pImpl->GetColumnCount() > nRight 3415 && m_pImpl->GetRowCount() > nBottom && 3416 nLeft <= nRight && nTop <= nBottom 3417 && nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 ) 3418 { 3419 SwTable* pTable = SwTable::FindTable( pFormat ); 3420 if(!pTable->IsTableComplex()) 3421 { 3422 SwRangeDescriptor aNewDesc; 3423 aNewDesc.nTop = nTop + m_pImpl->m_RangeDescriptor.nTop; 3424 aNewDesc.nBottom = nBottom + m_pImpl->m_RangeDescriptor.nTop; 3425 aNewDesc.nLeft = nLeft + m_pImpl->m_RangeDescriptor.nLeft; 3426 aNewDesc.nRight = nRight + m_pImpl->m_RangeDescriptor.nLeft; 3427 aNewDesc.Normalize(); 3428 const OUString sTLName = sw_GetCellName(aNewDesc.nLeft, aNewDesc.nTop); 3429 const OUString sBRName = sw_GetCellName(aNewDesc.nRight, aNewDesc.nBottom); 3430 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName ); 3431 if(pTLBox) 3432 { 3433 const SwStartNode* pSttNd = pTLBox->GetSttNd(); 3434 SwPosition aPos(*pSttNd); 3435 // set cursor in the upper-left cell of the range 3436 auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true)); 3437 pUnoCursor->Move( fnMoveForward, GoInNode ); 3438 pUnoCursor->SetRemainInSection( false ); 3439 const SwTableBox* pBRBox = pTable->GetTableBox( sBRName ); 3440 if(pBRBox) 3441 { 3442 pUnoCursor->SetMark(); 3443 pUnoCursor->GetPoint()->nNode = *pBRBox->GetSttNd(); 3444 pUnoCursor->Move( fnMoveForward, GoInNode ); 3445 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); 3446 // HACK: remove pending actions for selecting old style tables 3447 UnoActionRemoveContext aRemoveContext(rCursor); 3448 rCursor.MakeBoxSels(); 3449 // pUnoCursor will be provided and will not be deleted 3450 aRet = SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, aNewDesc).get(); 3451 } 3452 } 3453 } 3454 } 3455 if(!aRet.is()) 3456 throw lang::IndexOutOfBoundsException(); 3457 return aRet; 3458 } 3459 3460 uno::Reference<table::XCellRange> SAL_CALL 3461 SwXCellRange::getCellRangeByName(const OUString& rRange) 3462 { 3463 SolarMutexGuard aGuard; 3464 sal_Int32 nPos = 0; 3465 const OUString sTLName(rRange.getToken(0, ':', nPos)); 3466 const OUString sBRName(rRange.getToken(0, ':', nPos)); 3467 if(sTLName.isEmpty() || sBRName.isEmpty()) 3468 throw uno::RuntimeException(); 3469 SwRangeDescriptor aDesc; 3470 aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1; 3471 SwXTextTable::GetCellPosition( sTLName, aDesc.nLeft, aDesc.nTop ); 3472 SwXTextTable::GetCellPosition( sBRName, aDesc.nRight, aDesc.nBottom ); 3473 aDesc.Normalize(); 3474 return getCellRangeByPosition( 3475 aDesc.nLeft - m_pImpl->m_RangeDescriptor.nLeft, 3476 aDesc.nTop - m_pImpl->m_RangeDescriptor.nTop, 3477 aDesc.nRight - m_pImpl->m_RangeDescriptor.nLeft, 3478 aDesc.nBottom - m_pImpl->m_RangeDescriptor.nTop); 3479 } 3480 3481 uno::Reference< beans::XPropertySetInfo > SwXCellRange::getPropertySetInfo() 3482 { 3483 static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo(); 3484 return xRef; 3485 } 3486 3487 void SAL_CALL 3488 SwXCellRange::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue) 3489 { 3490 SolarMutexGuard aGuard; 3491 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); 3492 if(pFormat) 3493 { 3494 const SfxItemPropertySimpleEntry *const pEntry = 3495 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName); 3496 if(!pEntry) 3497 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) ); 3498 3499 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY) 3500 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) ); 3501 3502 SwDoc *const pDoc = m_pImpl->m_pTableCursor->GetDoc(); 3503 SwUnoTableCursor& rCursor(dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor)); 3504 { 3505 // HACK: remove pending actions for selecting old style tables 3506 UnoActionRemoveContext aRemoveContext(rCursor); 3507 } 3508 rCursor.MakeBoxSels(); 3509 switch(pEntry->nWID ) 3510 { 3511 case FN_UNO_TABLE_CELL_BACKGROUND: 3512 { 3513 std::shared_ptr<SfxPoolItem> aBrush(std::make_shared<SvxBrushItem>(RES_BACKGROUND)); 3514 SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush); 3515 aBrush->PutValue(aValue, pEntry->nMemberId); 3516 pDoc->SetBoxAttr(*m_pImpl->m_pTableCursor, *aBrush); 3517 3518 } 3519 break; 3520 case RES_BOX : 3521 { 3522 SfxItemSet aSet(pDoc->GetAttrPool(), 3523 svl::Items<RES_BOX, RES_BOX, 3524 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>{}); 3525 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER ); 3526 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::ALL, false); 3527 SvxBoxInfoItemValidFlags nValid = SvxBoxInfoItemValidFlags::NONE; 3528 switch(pEntry->nMemberId & ~CONVERT_TWIPS) 3529 { 3530 case LEFT_BORDER : nValid = SvxBoxInfoItemValidFlags::LEFT; break; 3531 case RIGHT_BORDER: nValid = SvxBoxInfoItemValidFlags::RIGHT; break; 3532 case TOP_BORDER : nValid = SvxBoxInfoItemValidFlags::TOP; break; 3533 case BOTTOM_BORDER: nValid = SvxBoxInfoItemValidFlags::BOTTOM; break; 3534 case LEFT_BORDER_DISTANCE : 3535 case RIGHT_BORDER_DISTANCE: 3536 case TOP_BORDER_DISTANCE : 3537 case BOTTOM_BORDER_DISTANCE: 3538 nValid = SvxBoxInfoItemValidFlags::DISTANCE; 3539 break; 3540 } 3541 aBoxInfo.SetValid(nValid); 3542 3543 aSet.Put(aBoxInfo); 3544 SwDoc::GetTabBorders(rCursor, aSet); 3545 3546 aSet.Put(aBoxInfo); 3547 SvxBoxItem aBoxItem(aSet.Get(RES_BOX)); 3548 static_cast<SfxPoolItem&>(aBoxItem).PutValue(aValue, pEntry->nMemberId); 3549 aSet.Put(aBoxItem); 3550 pDoc->SetTabBorders(*m_pImpl->m_pTableCursor, aSet); 3551 } 3552 break; 3553 case RES_BOXATR_FORMAT: 3554 { 3555 SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT); 3556 static_cast<SfxPoolItem&>(aNumberFormat).PutValue(aValue, 0); 3557 pDoc->SetBoxAttr(rCursor, aNumberFormat); 3558 } 3559 break; 3560 case FN_UNO_RANGE_ROW_LABEL: 3561 { 3562 bool bTmp = *o3tl::doAccess<bool>(aValue); 3563 if (m_pImpl->m_bFirstRowAsLabel != bTmp) 3564 { 3565 lcl_SendChartEvent(*this, m_pImpl->m_ChartListeners); 3566 m_pImpl->m_bFirstRowAsLabel = bTmp; 3567 } 3568 } 3569 break; 3570 case FN_UNO_RANGE_COL_LABEL: 3571 { 3572 bool bTmp = *o3tl::doAccess<bool>(aValue); 3573 if (m_pImpl->m_bFirstColumnAsLabel != bTmp) 3574 { 3575 lcl_SendChartEvent(*this, m_pImpl->m_ChartListeners); 3576 m_pImpl->m_bFirstColumnAsLabel = bTmp; 3577 } 3578 } 3579 break; 3580 case RES_VERT_ORIENT: 3581 { 3582 sal_Int16 nAlign = -1; 3583 aValue >>= nAlign; 3584 if( nAlign >= text::VertOrientation::NONE && nAlign <= text::VertOrientation::BOTTOM) 3585 pDoc->SetBoxAlign( rCursor, nAlign ); 3586 } 3587 break; 3588 default: 3589 { 3590 SfxItemSet aItemSet( pDoc->GetAttrPool(), {{pEntry->nWID, pEntry->nWID}} ); 3591 SwUnoCursorHelper::GetCursorAttr(rCursor.GetSelRing(), 3592 aItemSet); 3593 3594 if (!SwUnoCursorHelper::SetCursorPropertyValue( 3595 *pEntry, aValue, rCursor.GetSelRing(), aItemSet)) 3596 { 3597 m_pImpl->m_pPropSet->setPropertyValue(*pEntry, aValue, aItemSet); 3598 } 3599 SwUnoCursorHelper::SetCursorAttr(rCursor.GetSelRing(), 3600 aItemSet, SetAttrMode::DEFAULT, true); 3601 } 3602 } 3603 3604 } 3605 } 3606 3607 uno::Any SAL_CALL SwXCellRange::getPropertyValue(const OUString& rPropertyName) 3608 { 3609 SolarMutexGuard aGuard; 3610 uno::Any aRet; 3611 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); 3612 if(pFormat) 3613 { 3614 const SfxItemPropertySimpleEntry *const pEntry = 3615 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName); 3616 if(!pEntry) 3617 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) ); 3618 3619 switch(pEntry->nWID ) 3620 { 3621 case FN_UNO_TABLE_CELL_BACKGROUND: 3622 { 3623 std::shared_ptr<SfxPoolItem> aBrush(std::make_shared<SvxBrushItem>(RES_BACKGROUND)); 3624 if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush)) 3625 aBrush->QueryValue(aRet, pEntry->nMemberId); 3626 3627 } 3628 break; 3629 case RES_BOX : 3630 { 3631 SwDoc *const pDoc = m_pImpl->m_pTableCursor->GetDoc(); 3632 SfxItemSet aSet(pDoc->GetAttrPool(), 3633 svl::Items<RES_BOX, RES_BOX, 3634 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>{}); 3635 aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER )); 3636 SwDoc::GetTabBorders(*m_pImpl->m_pTableCursor, aSet); 3637 const SvxBoxItem& rBoxItem = aSet.Get(RES_BOX); 3638 rBoxItem.QueryValue(aRet, pEntry->nMemberId); 3639 } 3640 break; 3641 case RES_BOXATR_FORMAT: 3642 OSL_FAIL("not implemented"); 3643 break; 3644 case FN_UNO_PARA_STYLE: 3645 { 3646 SwFormatColl *const pTmpFormat = 3647 SwUnoCursorHelper::GetCurTextFormatColl(*m_pImpl->m_pTableCursor, false); 3648 OUString sRet; 3649 if (pTmpFormat) 3650 sRet = pTmpFormat->GetName(); 3651 aRet <<= sRet; 3652 } 3653 break; 3654 case FN_UNO_RANGE_ROW_LABEL: 3655 aRet <<= m_pImpl->m_bFirstRowAsLabel; 3656 break; 3657 case FN_UNO_RANGE_COL_LABEL: 3658 aRet <<= m_pImpl->m_bFirstColumnAsLabel; 3659 break; 3660 case RES_VERT_ORIENT: 3661 { 3662 std::shared_ptr<SfxPoolItem> aVertOrient; 3663 if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aVertOrient)) 3664 { 3665 aVertOrient->QueryValue( aRet, pEntry->nMemberId ); 3666 } 3667 } 3668 break; 3669 default: 3670 { 3671 SfxItemSet aSet( 3672 m_pImpl->m_pTableCursor->GetDoc()->GetAttrPool(), 3673 svl::Items< 3674 RES_CHRATR_BEGIN, RES_FRMATR_END - 1, 3675 RES_UNKNOWNATR_CONTAINER, 3676 RES_UNKNOWNATR_CONTAINER>{}); 3677 // first look at the attributes of the cursor 3678 SwUnoTableCursor *const pCursor = 3679 dynamic_cast<SwUnoTableCursor*>(&(*m_pImpl->m_pTableCursor)); 3680 SwUnoCursorHelper::GetCursorAttr(pCursor->GetSelRing(), aSet); 3681 m_pImpl->m_pPropSet->getPropertyValue(*pEntry, aSet, aRet); 3682 } 3683 } 3684 3685 } 3686 return aRet; 3687 } 3688 3689 void SwXCellRange::addPropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) 3690 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); } 3691 3692 void SwXCellRange::removePropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) 3693 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); } 3694 3695 void SwXCellRange::addVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) 3696 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); } 3697 3698 void SwXCellRange::removeVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) 3699 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); } 3700 3701 ///@see SwXCellRange::getData 3702 uno::Sequence<uno::Sequence<uno::Any>> SAL_CALL SwXCellRange::getDataArray() 3703 { 3704 SolarMutexGuard aGuard; 3705 const sal_Int32 nRowCount = m_pImpl->GetRowCount(); 3706 const sal_Int32 nColCount = m_pImpl->GetColumnCount(); 3707 if(!nRowCount || !nColCount) 3708 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this)); 3709 lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 3710 uno::Sequence< uno::Sequence< uno::Any > > aRowSeq(nRowCount); 3711 auto vCells(GetCells()); 3712 auto pCurrentCell(vCells.begin()); 3713 for(auto& rRow : aRowSeq) 3714 { 3715 rRow = uno::Sequence< uno::Any >(nColCount); 3716 for(auto& rCellAny : rRow) 3717 { 3718 auto pCell(static_cast<SwXCell*>(pCurrentCell->get())); 3719 if(!pCell) 3720 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this)); 3721 rCellAny = pCell->GetAny(); 3722 ++pCurrentCell; 3723 } 3724 } 3725 return aRowSeq; 3726 } 3727 3728 ///@see SwXCellRange::setData 3729 void SAL_CALL SwXCellRange::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray) 3730 { 3731 SolarMutexGuard aGuard; 3732 const sal_Int32 nRowCount = m_pImpl->GetRowCount(); 3733 const sal_Int32 nColCount = m_pImpl->GetColumnCount(); 3734 if(!nRowCount || !nColCount) 3735 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this)); 3736 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); 3737 if(!pFormat) 3738 return; 3739 if(rArray.getLength() != nRowCount) 3740 throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rArray.getLength()), static_cast<cppu::OWeakObject*>(this)); 3741 auto vCells(GetCells()); 3742 auto pCurrentCell(vCells.begin()); 3743 for(const auto& rColSeq : rArray) 3744 { 3745 if(rColSeq.getLength() != nColCount) 3746 throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rColSeq.getLength()), static_cast<cppu::OWeakObject*>(this)); 3747 for(const auto& aValue : rColSeq) 3748 { 3749 auto pCell(static_cast<SwXCell*>(pCurrentCell->get())); 3750 if(!pCell || !pCell->GetTableBox()) 3751 throw uno::RuntimeException("Box for cell missing", static_cast<cppu::OWeakObject*>(this)); 3752 if(aValue.isExtractableTo(cppu::UnoType<OUString>::get())) 3753 sw_setString(*pCell, aValue.get<OUString>()); 3754 else if(aValue.isExtractableTo(cppu::UnoType<double>::get())) 3755 sw_setValue(*pCell, aValue.get<double>()); 3756 else 3757 sw_setString(*pCell, OUString(), true); 3758 ++pCurrentCell; 3759 } 3760 } 3761 } 3762 3763 uno::Sequence<uno::Sequence<double>> SAL_CALL 3764 SwXCellRange::getData() 3765 { 3766 SolarMutexGuard aGuard; 3767 const sal_Int32 nRowCount = m_pImpl->GetRowCount(); 3768 const sal_Int32 nColCount = m_pImpl->GetColumnCount(); 3769 if(!nRowCount || !nColCount) 3770 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this)); 3771 if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel) 3772 { 3773 uno::Reference<chart::XChartDataArray> const xDataRange( 3774 getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0, 3775 (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0, 3776 nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW); 3777 return xDataRange->getData(); 3778 } 3779 uno::Sequence< uno::Sequence< double > > vRows(nRowCount); 3780 auto vCells(GetCells()); 3781 auto pCurrentCell(vCells.begin()); 3782 for(auto& rRow : vRows) 3783 { 3784 rRow = uno::Sequence<double>(nColCount); 3785 for(auto& rValue : rRow) 3786 { 3787 if(!(*pCurrentCell)) 3788 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this)); 3789 rValue = (*pCurrentCell)->getValue(); 3790 ++pCurrentCell; 3791 } 3792 } 3793 return vRows; 3794 } 3795 3796 void SAL_CALL 3797 SwXCellRange::setData(const uno::Sequence< uno::Sequence<double> >& rData) 3798 { 3799 SolarMutexGuard aGuard; 3800 const sal_Int32 nRowCount = m_pImpl->GetRowCount(); 3801 const sal_Int32 nColCount = m_pImpl->GetColumnCount(); 3802 if(!nRowCount || !nColCount) 3803 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this)); 3804 if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel) 3805 { 3806 uno::Reference<chart::XChartDataArray> const xDataRange( 3807 getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0, 3808 (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0, 3809 nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW); 3810 return xDataRange->setData(rData); 3811 } 3812 lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 3813 if(rData.getLength() != nRowCount) 3814 throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rData.getLength()), static_cast<cppu::OWeakObject*>(this)); 3815 auto vCells(GetCells()); 3816 auto pCurrentCell(vCells.begin()); 3817 for(const auto& rRow : rData) 3818 { 3819 if(rRow.getLength() != nColCount) 3820 throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rRow.getLength()), static_cast<cppu::OWeakObject*>(this)); 3821 for(const auto& rValue : rRow) 3822 { 3823 uno::Reference<table::XCell>(*pCurrentCell, uno::UNO_SET_THROW)->setValue(rValue); 3824 ++pCurrentCell; 3825 } 3826 } 3827 } 3828 3829 std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32> 3830 SwXCellRange::Impl::GetLabelCoordinates(bool bRow) 3831 { 3832 sal_uInt32 nLeft, nTop, nRight, nBottom; 3833 nLeft = nTop = nRight = nBottom = 0; 3834 if(bRow) 3835 { 3836 nTop = m_bFirstRowAsLabel ? 1 : 0; 3837 nBottom = GetRowCount() - 1; 3838 } 3839 else 3840 { 3841 nLeft = m_bFirstColumnAsLabel ? 1 : 0; 3842 nRight = GetColumnCount() - 1; 3843 } 3844 return std::make_tuple(nLeft, nTop, nRight, nBottom); 3845 } 3846 3847 uno::Sequence<OUString> 3848 SwXCellRange::Impl::GetLabelDescriptions(SwXCellRange & rThis, bool bRow) 3849 { 3850 SolarMutexGuard aGuard; 3851 sal_uInt32 nLeft, nTop, nRight, nBottom; 3852 std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow); 3853 if(!nRight && !nBottom) 3854 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(&rThis)); 3855 lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(&rThis)); 3856 if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel)) 3857 return {}; // without labels we have no descriptions 3858 auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom)); 3859 auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells()); 3860 uno::Sequence<OUString> vResult(vCells.size()); 3861 std::transform(vCells.begin(), vCells.end(), vResult.begin(), 3862 [](uno::Reference<table::XCell> xCell) -> OUString { return uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->getString(); }); 3863 return vResult; 3864 } 3865 3866 uno::Sequence<OUString> SAL_CALL SwXCellRange::getRowDescriptions() 3867 { 3868 return m_pImpl->GetLabelDescriptions(*this, true); 3869 } 3870 3871 uno::Sequence<OUString> SAL_CALL SwXCellRange::getColumnDescriptions() 3872 { 3873 return m_pImpl->GetLabelDescriptions(*this, false); 3874 } 3875 3876 void SwXCellRange::Impl::SetLabelDescriptions(SwXCellRange & rThis, 3877 const uno::Sequence<OUString>& rDesc, bool bRow) 3878 { 3879 SolarMutexGuard aGuard; 3880 lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(&rThis)); 3881 if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel)) 3882 return; // if there are no labels we cannot set descriptions 3883 sal_uInt32 nLeft, nTop, nRight, nBottom; 3884 std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow); 3885 if(!nRight && !nBottom) 3886 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(&rThis)); 3887 auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom)); 3888 if (!xLabelRange.is()) 3889 throw uno::RuntimeException("Missing Cell Range", static_cast<cppu::OWeakObject*>(&rThis)); 3890 auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells()); 3891 if (sal::static_int_cast<sal_uInt32>(rDesc.getLength()) != vCells.size()) 3892 throw uno::RuntimeException("Too few or too many descriptions", static_cast<cppu::OWeakObject*>(&rThis)); 3893 auto pDescIterator(rDesc.begin()); 3894 for(auto& xCell : vCells) 3895 uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->setString(*pDescIterator++); 3896 } 3897 3898 void SAL_CALL SwXCellRange::setRowDescriptions( 3899 const uno::Sequence<OUString>& rRowDesc) 3900 { 3901 m_pImpl->SetLabelDescriptions(*this, rRowDesc, true); 3902 } 3903 3904 void SAL_CALL SwXCellRange::setColumnDescriptions( 3905 const uno::Sequence<OUString>& rColumnDesc) 3906 { 3907 m_pImpl->SetLabelDescriptions(*this, rColumnDesc, false); 3908 } 3909 3910 void SAL_CALL SwXCellRange::addChartDataChangeEventListener( 3911 const uno::Reference<chart::XChartDataChangeEventListener> & xListener) 3912 { 3913 // no need to lock here as m_pImpl is const and container threadsafe 3914 m_pImpl->m_ChartListeners.addInterface(xListener); 3915 } 3916 3917 void SAL_CALL SwXCellRange::removeChartDataChangeEventListener( 3918 const uno::Reference<chart::XChartDataChangeEventListener> & xListener) 3919 { 3920 // no need to lock here as m_pImpl is const and container threadsafe 3921 m_pImpl->m_ChartListeners.removeInterface(xListener); 3922 } 3923 3924 sal_Bool SwXCellRange::isNotANumber(double /*fNumber*/) 3925 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); } 3926 3927 double SwXCellRange::getNotANumber() 3928 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); } 3929 3930 uno::Sequence< beans::PropertyValue > SwXCellRange::createSortDescriptor() 3931 { 3932 SolarMutexGuard aGuard; 3933 return SwUnoCursorHelper::CreateSortDescriptor(true); 3934 } 3935 3936 void SAL_CALL SwXCellRange::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor) 3937 { 3938 SolarMutexGuard aGuard; 3939 SwSortOptions aSortOpt; 3940 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); 3941 if(pFormat && SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt)) 3942 { 3943 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor); 3944 rTableCursor.MakeBoxSels(); 3945 UnoActionContext aContext(pFormat->GetDoc()); 3946 pFormat->GetDoc()->SortTable(rTableCursor.GetSelectedBoxes(), aSortOpt); 3947 } 3948 } 3949 3950 sal_Int32 SwXCellRange::Impl::GetColumnCount() const 3951 { 3952 return m_RangeDescriptor.nRight - m_RangeDescriptor.nLeft + 1; 3953 } 3954 3955 sal_Int32 SwXCellRange::Impl::GetRowCount() const 3956 { 3957 return m_RangeDescriptor.nBottom - m_RangeDescriptor.nTop + 1; 3958 } 3959 3960 const SwUnoCursor* SwXCellRange::GetTableCursor() const 3961 { 3962 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat(); 3963 return pFormat ? &(*m_pImpl->m_pTableCursor) : nullptr; 3964 } 3965 3966 void SwXCellRange::Impl::Notify( const SfxHint& rHint ) 3967 { 3968 uno::Reference<uno::XInterface> const xThis(m_wThis); 3969 if(rHint.GetId() == SfxHintId::Dying) 3970 { 3971 m_pFrameFormat = nullptr; 3972 m_pTableCursor.reset(nullptr); 3973 } 3974 if (xThis.is()) 3975 { // fdo#72695: if UNO object is already dead, don't revive it with event 3976 if(m_pFrameFormat) 3977 lcl_SendChartEvent(xThis.get(), m_ChartListeners); 3978 else 3979 m_ChartListeners.disposeAndClear(lang::EventObject(xThis)); 3980 } 3981 } 3982 3983 class SwXTableRows::Impl : public SvtListener 3984 { 3985 private: 3986 SwFrameFormat* m_pFrameFormat; 3987 3988 public: 3989 explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat) 3990 { 3991 StartListening(rFrameFormat.GetNotifier()); 3992 } 3993 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; } 3994 virtual void Notify(const SfxHint&) override; 3995 }; 3996 3997 // SwXTableRows 3998 3999 OUString SwXTableRows::getImplementationName() 4000 { return "SwXTableRows"; } 4001 4002 sal_Bool SwXTableRows::supportsService(const OUString& rServiceName) 4003 { return cppu::supportsService(this, rServiceName); } 4004 4005 uno::Sequence< OUString > SwXTableRows::getSupportedServiceNames() 4006 { return { "com.sun.star.text.TableRows" }; } 4007 4008 4009 SwXTableRows::SwXTableRows(SwFrameFormat& rFrameFormat) : 4010 m_pImpl(new SwXTableRows::Impl(rFrameFormat)) 4011 { } 4012 4013 SwXTableRows::~SwXTableRows() 4014 { } 4015 4016 SwFrameFormat* SwXTableRows::GetFrameFormat() 4017 { 4018 return m_pImpl->GetFrameFormat(); 4019 } 4020 4021 sal_Int32 SwXTableRows::getCount() 4022 { 4023 SolarMutexGuard aGuard; 4024 SwFrameFormat* pFrameFormat = GetFrameFormat(); 4025 if(!pFrameFormat) 4026 throw uno::RuntimeException(); 4027 SwTable* pTable = SwTable::FindTable(pFrameFormat); 4028 return pTable->GetTabLines().size(); 4029 } 4030 4031 ///@see SwXCell::CreateXCell (TODO: seems to be copy and paste programming here) 4032 uno::Any SwXTableRows::getByIndex(sal_Int32 nIndex) 4033 { 4034 SolarMutexGuard aGuard; 4035 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this))); 4036 if(nIndex < 0) 4037 throw lang::IndexOutOfBoundsException(); 4038 SwTable* pTable = SwTable::FindTable( pFrameFormat ); 4039 if(static_cast<size_t>(nIndex) >= pTable->GetTabLines().size()) 4040 throw lang::IndexOutOfBoundsException(); 4041 SwTableLine* pLine = pTable->GetTabLines()[nIndex]; 4042 FindUnoInstanceHint<SwTableLine,SwXTextTableRow> aHint{pLine}; 4043 pFrameFormat->GetNotifier().Broadcast(aHint); 4044 if(!aHint.m_pResult) 4045 aHint.m_pResult = new SwXTextTableRow(pFrameFormat, pLine); 4046 uno::Reference<beans::XPropertySet> xRet = static_cast<beans::XPropertySet*>(aHint.m_pResult); 4047 return uno::makeAny(xRet); 4048 } 4049 4050 uno::Type SAL_CALL SwXTableRows::getElementType() 4051 { 4052 return cppu::UnoType<beans::XPropertySet>::get(); 4053 } 4054 4055 sal_Bool SwXTableRows::hasElements() 4056 { 4057 SolarMutexGuard aGuard; 4058 SwFrameFormat* pFrameFormat = GetFrameFormat(); 4059 if(!pFrameFormat) 4060 throw uno::RuntimeException(); 4061 // a table always has rows 4062 return true; 4063 } 4064 4065 void SwXTableRows::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount) 4066 { 4067 SolarMutexGuard aGuard; 4068 if (nCount == 0) 4069 return; 4070 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this))); 4071 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this)); 4072 const size_t nRowCount = pTable->GetTabLines().size(); 4073 if (nCount <= 0 || !(0 <= nIndex && static_cast<size_t>(nIndex) <= nRowCount)) 4074 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this)); 4075 const OUString sTLName = sw_GetCellName(0, nIndex); 4076 const SwTableBox* pTLBox = pTable->GetTableBox(sTLName); 4077 bool bAppend = false; 4078 if(!pTLBox) 4079 { 4080 bAppend = true; 4081 // to append at the end the cursor must be in the last line 4082 SwTableLines& rLines = pTable->GetTabLines(); 4083 SwTableLine* pLine = rLines.back(); 4084 SwTableBoxes& rBoxes = pLine->GetTabBoxes(); 4085 pTLBox = rBoxes.front(); 4086 } 4087 if(!pTLBox) 4088 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this)); 4089 const SwStartNode* pSttNd = pTLBox->GetSttNd(); 4090 SwPosition aPos(*pSttNd); 4091 // set cursor to the upper-left cell of the range 4092 UnoActionContext aAction(pFrameFormat->GetDoc()); 4093 std::shared_ptr<SwUnoTableCursor> const pUnoCursor( 4094 std::dynamic_pointer_cast<SwUnoTableCursor>( 4095 pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true))); 4096 pUnoCursor->Move( fnMoveForward, GoInNode ); 4097 { 4098 // remove actions - TODO: why? 4099 UnoActionRemoveContext aRemoveContext(pUnoCursor->GetDoc()); 4100 } 4101 pFrameFormat->GetDoc()->InsertRow(*pUnoCursor, static_cast<sal_uInt16>(nCount), bAppend); 4102 } 4103 4104 void SwXTableRows::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount) 4105 { 4106 SolarMutexGuard aGuard; 4107 if (nCount == 0) 4108 return; 4109 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this))); 4110 if(nIndex < 0 || nCount <=0 ) 4111 throw uno::RuntimeException(); 4112 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this)); 4113 OUString sTLName = sw_GetCellName(0, nIndex); 4114 const SwTableBox* pTLBox = pTable->GetTableBox(sTLName); 4115 if(!pTLBox) 4116 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this)); 4117 const SwStartNode* pSttNd = pTLBox->GetSttNd(); 4118 SwPosition aPos(*pSttNd); 4119 // set cursor to the upper-left cell of the range 4120 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true)); 4121 pUnoCursor->Move(fnMoveForward, GoInNode); 4122 pUnoCursor->SetRemainInSection( false ); 4123 const OUString sBLName = sw_GetCellName(0, nIndex + nCount - 1); 4124 const SwTableBox* pBLBox = pTable->GetTableBox( sBLName ); 4125 if(!pBLBox) 4126 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this)); 4127 pUnoCursor->SetMark(); 4128 pUnoCursor->GetPoint()->nNode = *pBLBox->GetSttNd(); 4129 pUnoCursor->Move(fnMoveForward, GoInNode); 4130 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); 4131 { 4132 // HACK: remove pending actions for selecting old style tables 4133 UnoActionRemoveContext aRemoveContext(rCursor); 4134 } 4135 rCursor.MakeBoxSels(); 4136 { // these braces are important 4137 UnoActionContext aAction(pFrameFormat->GetDoc()); 4138 pFrameFormat->GetDoc()->DeleteRow(*pUnoCursor); 4139 pUnoCursor.reset(); 4140 } 4141 { 4142 // invalidate all actions - TODO: why? 4143 UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc()); 4144 } 4145 } 4146 4147 void SwXTableRows::Impl::Notify( const SfxHint& rHint) 4148 { 4149 if(rHint.GetId() == SfxHintId::Dying) 4150 m_pFrameFormat = nullptr; 4151 } 4152 4153 // SwXTableColumns 4154 4155 class SwXTableColumns::Impl : public SvtListener 4156 { 4157 SwFrameFormat* m_pFrameFormat; 4158 public: 4159 explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat) 4160 { 4161 StartListening(rFrameFormat.GetNotifier()); 4162 } 4163 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; } 4164 virtual void Notify(const SfxHint&) override; 4165 }; 4166 4167 OUString SwXTableColumns::getImplementationName() 4168 { return "SwXTableColumns"; } 4169 4170 sal_Bool SwXTableColumns::supportsService(const OUString& rServiceName) 4171 { return cppu::supportsService(this, rServiceName); } 4172 4173 uno::Sequence< OUString > SwXTableColumns::getSupportedServiceNames() 4174 { return { "com.sun.star.text.TableColumns"}; } 4175 4176 4177 SwXTableColumns::SwXTableColumns(SwFrameFormat& rFrameFormat) : 4178 m_pImpl(new SwXTableColumns::Impl(rFrameFormat)) 4179 { } 4180 4181 SwXTableColumns::~SwXTableColumns() 4182 { } 4183 4184 SwFrameFormat* SwXTableColumns::GetFrameFormat() const 4185 { 4186 return m_pImpl->GetFrameFormat(); 4187 } 4188 4189 sal_Int32 SwXTableColumns::getCount() 4190 { 4191 SolarMutexGuard aGuard; 4192 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this))); 4193 SwTable* pTable = SwTable::FindTable( pFrameFormat ); 4194 // if(!pTable->IsTableComplex()) 4195 // throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this)); 4196 SwTableLines& rLines = pTable->GetTabLines(); 4197 SwTableLine* pLine = rLines.front(); 4198 return pLine->GetTabBoxes().size(); 4199 } 4200 4201 uno::Any SwXTableColumns::getByIndex(sal_Int32 nIndex) 4202 { 4203 SolarMutexGuard aGuard; 4204 if(nIndex < 0 || getCount() <= nIndex) 4205 throw lang::IndexOutOfBoundsException(); 4206 return uno::makeAny(uno::Reference<uno::XInterface>()); // i#21699 not supported 4207 } 4208 4209 uno::Type SAL_CALL SwXTableColumns::getElementType() 4210 { 4211 return cppu::UnoType<uno::XInterface>::get(); 4212 } 4213 4214 sal_Bool SwXTableColumns::hasElements() 4215 { 4216 SolarMutexGuard aGuard; 4217 lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)); 4218 return true; 4219 } 4220 4221 ///@see SwXTableRows::insertByIndex (TODO: seems to be copy and paste programming here) 4222 void SwXTableColumns::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount) 4223 { 4224 SolarMutexGuard aGuard; 4225 if (nCount == 0) 4226 return; 4227 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this))); 4228 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this)); 4229 SwTableLines& rLines = pTable->GetTabLines(); 4230 SwTableLine* pLine = rLines.front(); 4231 const size_t nColCount = pLine->GetTabBoxes().size(); 4232 if (nCount <= 0 || !(0 <= nIndex && static_cast<size_t>(nIndex) <= nColCount)) 4233 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this)); 4234 const OUString sTLName = sw_GetCellName(nIndex, 0); 4235 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName ); 4236 bool bAppend = false; 4237 if(!pTLBox) 4238 { 4239 bAppend = true; 4240 // to append at the end the cursor must be in the last line 4241 SwTableBoxes& rBoxes = pLine->GetTabBoxes(); 4242 pTLBox = rBoxes.back(); 4243 } 4244 if(!pTLBox) 4245 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this)); 4246 const SwStartNode* pSttNd = pTLBox->GetSttNd(); 4247 SwPosition aPos(*pSttNd); 4248 UnoActionContext aAction(pFrameFormat->GetDoc()); 4249 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true)); 4250 pUnoCursor->Move(fnMoveForward, GoInNode); 4251 4252 { 4253 // remove actions - TODO: why? 4254 UnoActionRemoveContext aRemoveContext(pUnoCursor->GetDoc()); 4255 } 4256 4257 pFrameFormat->GetDoc()->InsertCol(*pUnoCursor, static_cast<sal_uInt16>(nCount), bAppend); 4258 } 4259 4260 ///@see SwXTableRows::removeByIndex (TODO: seems to be copy and paste programming here) 4261 void SwXTableColumns::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount) 4262 { 4263 SolarMutexGuard aGuard; 4264 if (nCount == 0) 4265 return; 4266 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this))); 4267 if(nIndex < 0 || nCount <=0 ) 4268 throw uno::RuntimeException(); 4269 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this)); 4270 const OUString sTLName = sw_GetCellName(nIndex, 0); 4271 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName ); 4272 if(!pTLBox) 4273 throw uno::RuntimeException("Cell not found", static_cast<cppu::OWeakObject*>(this)); 4274 const SwStartNode* pSttNd = pTLBox->GetSttNd(); 4275 SwPosition aPos(*pSttNd); 4276 // set cursor to the upper-left cell of the range 4277 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true)); 4278 pUnoCursor->Move(fnMoveForward, GoInNode); 4279 pUnoCursor->SetRemainInSection(false); 4280 const OUString sTRName = sw_GetCellName(nIndex + nCount - 1, 0); 4281 const SwTableBox* pTRBox = pTable->GetTableBox(sTRName); 4282 if(!pTRBox) 4283 throw uno::RuntimeException("Cell not found", static_cast<cppu::OWeakObject*>(this)); 4284 pUnoCursor->SetMark(); 4285 pUnoCursor->GetPoint()->nNode = *pTRBox->GetSttNd(); 4286 pUnoCursor->Move(fnMoveForward, GoInNode); 4287 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor); 4288 { 4289 // HACK: remove pending actions for selecting old style tables 4290 UnoActionRemoveContext aRemoveContext(rCursor); 4291 } 4292 rCursor.MakeBoxSels(); 4293 { // these braces are important 4294 UnoActionContext aAction(pFrameFormat->GetDoc()); 4295 pFrameFormat->GetDoc()->DeleteCol(*pUnoCursor); 4296 pUnoCursor.reset(); 4297 } 4298 { 4299 // invalidate all actions - TODO: why? 4300 UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc()); 4301 } 4302 } 4303 4304 void SwXTableColumns::Impl::Notify(const SfxHint& rHint) 4305 { 4306 if(rHint.GetId() == SfxHintId::Dying) 4307 m_pFrameFormat = nullptr; 4308 } 4309 4310 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 4311
