LibreOffice Module sw (master)  1
docsort.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <hintids.hxx>
21 #include <osl/diagnose.h>
25 #include <docary.hxx>
26 #include <fmtanchr.hxx>
27 #include <frmfmt.hxx>
28 #include <doc.hxx>
29 #include <IDocumentUndoRedo.hxx>
32 #include <IDocumentState.hxx>
33 #include <node.hxx>
34 #include <pam.hxx>
35 #include <ndtxt.hxx>
36 #include <swtable.hxx>
37 #include <swundo.hxx>
38 #include <sortopt.hxx>
39 #include <docsort.hxx>
40 #include <UndoSort.hxx>
41 #include <UndoRedline.hxx>
42 #include <hints.hxx>
43 #include <tblsel.hxx>
44 #include <cellatr.hxx>
45 #include <redline.hxx>
46 #include <node2lay.hxx>
47 #include <frameformats.hxx>
48 #include <svl/numformat.hxx>
49 
50 #include <set>
51 #include <utility>
52 
53 using namespace ::com::sun::star::lang;
54 using namespace ::com::sun::star;
55 
57 SwDoc* SwSortElement::pDoc = nullptr;
58 const FlatFndBox* SwSortElement::pBox = nullptr;
60 lang::Locale* SwSortElement::pLocale = nullptr;
61 std::optional<OUString> SwSortElement::xLastAlgorithm;
63 
64 // List of all sorted elements
65 
67 void SwSortElement::Init( SwDoc* pD, const SwSortOptions& rOpt,
68  FlatFndBox const * pFltBx )
69 {
70  OSL_ENSURE( !pDoc && !pOptions && !pBox, "Who forgot to call Finit?" );
71  pDoc = pD;
72  pOptions = new SwSortOptions( rOpt );
73  pBox = pFltBx;
74 
76  if ( nLang.anyOf(
79  nLang = GetAppLanguage();
80  pLocale = new lang::Locale( LanguageTag::convertToLocale( nLang ) );
81 
83 }
84 
86 {
87  delete pOptions;
88  pOptions = nullptr;
89  delete pLocale;
90  pLocale = nullptr;
91  xLastAlgorithm.reset();
92  delete pSortCollator;
93  pSortCollator = nullptr;
94  delete pLclData;
95  pLclData = nullptr;
96  pDoc = nullptr;
97  pBox = nullptr;
98 }
99 
101 {
102 }
103 
104 double SwSortElement::StrToDouble( const OUString& rStr )
105 {
106  if( !pLclData )
108 
109  rtl_math_ConversionStatus eStatus;
110  sal_Int32 nEnd;
111  double nRet = pLclData->stringToDouble( rStr, true, &eStatus, &nEnd );
112 
113  if( rtl_math_ConversionStatus_Ok != eStatus || nEnd == 0 )
114  nRet = 0.0;
115  return nRet;
116 }
117 
118 int SwSortElement::keycompare(const SwSortElement& rCmp, sal_uInt16 nKey) const
119 {
120  int nCmp = 0;
121  // The actual comparison
122  const SwSortElement *pOrig, *pCmp;
123 
124  const SwSortKey& rSrtKey = pOptions->aKeys[ nKey ];
125  if( rSrtKey.eSortOrder == SwSortOrder::Ascending )
126  {
127  pOrig = this;
128  pCmp = &rCmp;
129  }
130  else
131  {
132  pOrig = &rCmp;
133  pCmp = this;
134  }
135 
136  if( rSrtKey.bIsNumeric )
137  {
138  double n1 = pOrig->GetValue( nKey );
139  double n2 = pCmp->GetValue( nKey );
140 
141  nCmp = n1 < n2 ? -1 : n1 == n2 ? 0 : 1;
142  }
143  else
144  {
145  if( !xLastAlgorithm || *xLastAlgorithm != rSrtKey.sSortType )
146  {
147  xLastAlgorithm = rSrtKey.sSortType;
149  *pLocale,
151  }
152 
154  pOrig->GetKey( nKey ), pCmp->GetKey( nKey ));
155  }
156  return nCmp;
157 }
158 
160 {
161  // The actual comparison
162  for(size_t nKey = 0; nKey < pOptions->aKeys.size(); ++nKey)
163  {
164  int nCmp = keycompare(rCmp, nKey);
165 
166  if (nCmp == 0)
167  continue;
168 
169  return nCmp < 0;
170  }
171 
172  return false;
173 }
174 
175 double SwSortElement::GetValue( sal_uInt16 nKey ) const
176 {
177  return StrToDouble( GetKey( nKey ));
178 }
179 
182  : nOrg(rPos.GetIndex()), aPos(rPos)
183 {
184 }
185 
186 OUString SwSortTextElement::GetKey(sal_uInt16 nId) const
187 {
188  SwTextNode* pTextNd = aPos.GetNode().GetTextNode();
189  if( !pTextNd )
190  return OUString();
191 
192  // for TextNodes
193  const OUString& rStr = pTextNd->GetText();
194 
195  sal_Unicode nDeli = pOptions->cDeli;
196  sal_uInt16 nDCount = pOptions->aKeys[nId].nColumnId, i = 1;
197  sal_Int32 nStart = 0;
198 
199  // Find the delimiter
200  while( nStart != -1 && i < nDCount)
201  {
202  nStart = rStr.indexOf( nDeli, nStart );
203  if( -1 != nStart )
204  {
205  nStart++;
206  i++;
207  }
208  }
209 
210  // Found next delimiter or end of String
211  // and copy
212  sal_Int32 nEnd = rStr.indexOf( nDeli, nStart+1 );
213  if (nEnd == -1)
214  return rStr.copy( nStart );
215  return rStr.copy( nStart, nEnd-nStart );
216 }
217 
220  : nRow( nRC )
221 {
222 }
223 
225 OUString SwSortBoxElement::GetKey(sal_uInt16 nKey) const
226 {
227  const FndBox_* pFndBox;
228  sal_uInt16 nCol = pOptions->aKeys[nKey].nColumnId-1;
229 
231  pFndBox = pBox->GetBox(nCol, nRow); // Sort rows
232  else
233  pFndBox = pBox->GetBox(nRow, nCol); // Sort columns
234 
235  // Extract the Text
236  OUStringBuffer aRetStr;
237  if( pFndBox )
238  { // Get StartNode and skip it
239  const SwTableBox* pMyBox = pFndBox->GetBox();
240  OSL_ENSURE(pMyBox, "No atomic Box");
241 
242  if( pMyBox->GetSttNd() )
243  {
244  // Iterate over all the Box's TextNodes
245  const SwNode *pNd = nullptr, *pEndNd = pMyBox->GetSttNd()->EndOfSectionNode();
246  for( sal_uLong nIdx = pMyBox->GetSttIdx() + 1; pNd != pEndNd; ++nIdx )
247  {
248  pNd = pDoc->GetNodes()[ nIdx ];
249  if( pNd->IsTextNode() )
250  aRetStr.append(pNd->GetTextNode()->GetText());
251  }
252  }
253  }
254  return aRetStr.makeStringAndClear();
255 }
256 
257 double SwSortBoxElement::GetValue( sal_uInt16 nKey ) const
258 {
259  const FndBox_* pFndBox;
260  sal_uInt16 nCol = pOptions->aKeys[nKey].nColumnId-1;
261 
263  pFndBox = pBox->GetBox(nCol, nRow); // Sort rows
264  else
265  pFndBox = pBox->GetBox(nRow, nCol); // Sort columns
266 
267  double nVal;
268  if( pFndBox )
269  {
270  const SwFormat *pFormat = pFndBox->GetBox()->GetFrameFormat();
272  nVal = SwSortElement::GetValue( nKey );
273  else
274  nVal = pFormat->GetTableBoxValue().GetValue();
275  }
276  else
277  nVal = 0;
278 
279  return nVal;
280 }
281 
283 bool SwDoc::SortText(const SwPaM& rPaM, const SwSortOptions& rOpt)
284 {
285  // Check if Frame is in the Text
286  const SwPosition *pStart = rPaM.Start(), *pEnd = rPaM.End();
287 
288  // Set index to the Selection's start
289  for ( const auto *pFormat : *GetSpzFrameFormats() )
290  {
291  SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
292  SwPosition const*const pAPos = pAnchor->GetContentAnchor();
293 
294  if (pAPos && (RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) &&
295  pStart->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode )
296  return false;
297  }
298 
299  // Check if only TextNodes are within the Selection
300  {
301  sal_uLong nStart = pStart->nNode.GetIndex(),
302  nEnd = pEnd->nNode.GetIndex();
303  while( nStart <= nEnd )
304  // Iterate over a selected range
305  if( !GetNodes()[ nStart++ ]->IsTextNode() )
306  return false;
307  }
308 
309  bool const bUndo = GetIDocumentUndoRedo().DoesUndo();
310  if( bUndo )
311  {
313  }
314 
315  SwPaM* pRedlPam = nullptr;
316  SwUndoRedlineSort* pRedlUndo = nullptr;
317  SwUndoSort* pUndoSort = nullptr;
318 
319  // To-Do - add 'SwExtraRedlineTable' also ?
320  if( getIDocumentRedlineAccess().IsRedlineOn() || (!getIDocumentRedlineAccess().IsIgnoreRedline() && !getIDocumentRedlineAccess().GetRedlineTable().empty() ))
321  {
322  pRedlPam = new SwPaM( pStart->nNode, pEnd->nNode, -1, 1 );
323  SwContentNode* pCNd = pRedlPam->GetContentNode( false );
324  if( pCNd )
325  pRedlPam->GetMark()->nContent = pCNd->Len();
326 
328  {
329  if( bUndo )
330  {
331  pRedlUndo = new SwUndoRedlineSort( *pRedlPam,rOpt );
332  GetIDocumentUndoRedo().DoUndo(false);
333  }
334  // First copy the range
335  SwNodeIndex aEndIdx( pEnd->nNode, 1 );
336  SwNodeRange aRg( pStart->nNode, aEndIdx );
337  GetNodes().Copy_( aRg, aEndIdx );
338 
339  // range is new from pEnd->nNode+1 to aEndIdx
340  getIDocumentRedlineAccess().DeleteRedline( *pRedlPam, true, RedlineType::Any );
341 
342  pRedlPam->GetMark()->nNode.Assign( pEnd->nNode.GetNode(), 1 );
343  pCNd = pRedlPam->GetContentNode( false );
344  pRedlPam->GetMark()->nContent.Assign( pCNd, 0 );
345 
346  pRedlPam->GetPoint()->nNode.Assign( aEndIdx.GetNode() );
347  pCNd = pRedlPam->GetContentNode();
348  sal_Int32 nCLen = 0;
349  if( !pCNd )
350  {
351  pCNd = GetNodes()[ aEndIdx.GetIndex()-1 ]->GetContentNode();
352  if( pCNd )
353  {
354  nCLen = pCNd->Len();
355  pRedlPam->GetPoint()->nNode.Assign( *pCNd );
356  }
357  }
358  pRedlPam->GetPoint()->nContent.Assign( pCNd, nCLen );
359 
360  if( pRedlUndo )
361  pRedlUndo->SetValues( rPaM );
362  }
363  else
364  {
365  getIDocumentRedlineAccess().DeleteRedline( *pRedlPam, true, RedlineType::Any );
366  delete pRedlPam;
367  pRedlPam = nullptr;
368  }
369  }
370 
371  SwNodeIndex aStart(pStart->nNode);
372  SwSortElement::Init( this, rOpt );
373  std::multiset<SwSortTextElement> aSortSet;
374  while( aStart <= pEnd->nNode )
375  {
376  // Iterate over a selected range
377  aSortSet.insert(SwSortTextElement(aStart));
378  ++aStart;
379  }
380 
381  // Now comes the tricky part: Move Nodes (and always keep Undo in mind)
382  sal_uLong nBeg = pStart->nNode.GetIndex();
383  SwNodeRange aRg( aStart, aStart );
384 
385  if( bUndo && !pRedlUndo )
386  {
387  pUndoSort = new SwUndoSort(rPaM, rOpt);
388  GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndoSort));
389  }
390 
391  GetIDocumentUndoRedo().DoUndo(false);
392 
393  size_t n = 0;
394  for (const auto& rElem : aSortSet)
395  {
396  aStart = nBeg + n;
397  aRg.aStart = rElem.aPos.GetIndex();
398  aRg.aEnd = aRg.aStart.GetIndex() + 1;
399 
400  // Move Nodes
403 
404  // Insert Move in Undo
405  if(pUndoSort)
406  {
407  pUndoSort->Insert(rElem.nOrg, nBeg + n);
408  }
409  ++n;
410  }
411  // Delete all elements from the SortArray
412  aSortSet.clear();
414 
415  if( pRedlPam )
416  {
417  if( pRedlUndo )
418  {
419  pRedlUndo->SetSaveRange( *pRedlPam );
420  // UGLY: temp. enable Undo
422  GetIDocumentUndoRedo().AppendUndo( std::unique_ptr<SwUndo>(pRedlUndo) );
423  GetIDocumentUndoRedo().DoUndo(false);
424  }
425 
426  // nBeg is start of sorted range
427  SwNodeIndex aSttIdx( GetNodes(), nBeg );
428 
429  // the copied range is deleted
430  SwRangeRedline *const pDeleteRedline(
431  new SwRangeRedline( RedlineType::Delete, *pRedlPam ));
432 
433  // pRedlPam points to nodes that may be deleted (hidden) by
434  // AppendRedline, so adjust it beforehand to prevent ASSERT
435  pRedlPam->GetPoint()->nNode = aSttIdx;
436  SwContentNode* pCNd = aSttIdx.GetNode().GetContentNode();
437  pRedlPam->GetPoint()->nContent.Assign( pCNd, 0 );
438 
439  getIDocumentRedlineAccess().AppendRedline(pDeleteRedline, true);
440 
441  // the sorted range is inserted
442  getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Insert, *pRedlPam ), true);
443 
444  if( pRedlUndo )
445  {
446  SwNodeIndex aInsEndIdx( pRedlPam->GetMark()->nNode, -1 );
447  pRedlPam->GetMark()->nNode = aInsEndIdx;
448  SwContentNode *const pPrevNode =
449  pRedlPam->GetMark()->nNode.GetNode().GetContentNode();
450  pRedlPam->GetMark()->nContent.Assign( pPrevNode, pPrevNode->Len() );
451 
452  pRedlUndo->SetValues( *pRedlPam );
453  }
454 
455  delete pRedlPam;
456  pRedlPam = nullptr;
457  }
458  GetIDocumentUndoRedo().DoUndo( bUndo );
459  if( bUndo )
460  {
462  }
463 
464  return true;
465 }
466 
468 bool SwDoc::SortTable(const SwSelBoxes& rBoxes, const SwSortOptions& rOpt)
469 {
470  // Via SwDoc for Undo!
471  OSL_ENSURE( !rBoxes.empty(), "no valid Box list" );
472  SwTableNode* pTableNd = const_cast<SwTableNode*>(rBoxes[0]->GetSttNd()->FindTableNode());
473  if( !pTableNd )
474  return false;
475 
476  // We begin sorting
477  // Find all Boxes/Lines
478  FndBox_ aFndBox( nullptr, nullptr );
479  {
480  FndPara aPara( rBoxes, &aFndBox );
481  ForEach_FndLineCopyCol( pTableNd->GetTable().GetTabLines(), &aPara );
482  }
483 
484  if(aFndBox.GetLines().empty())
485  return false;
486 
488  getIDocumentRedlineAccess().DeleteRedline( *pTableNd, true, RedlineType::Any );
489 
490  FndLines_t::size_type nStart = 0;
491  if( pTableNd->GetTable().GetRowsToRepeat() > 0 && rOpt.eDirection == SwSortDirection::Rows )
492  {
493  // Uppermost selected Cell
494  FndLines_t& rLines = aFndBox.GetLines();
495 
496  while( nStart < rLines.size() )
497  {
498  // Respect Split Merge nesting,
499  // extract the upper most
500  SwTableLine* pLine = rLines[nStart]->GetLine();
501  while ( pLine->GetUpper() )
502  pLine = pLine->GetUpper()->GetUpper();
503 
504  if( pTableNd->GetTable().IsHeadline( *pLine ) )
505  nStart++;
506  else
507  break;
508  }
509  // Are all selected in the HeaderLine? -> no Offset
510  if( nStart == rLines.size() )
511  nStart = 0;
512  }
513 
514  // Switch to relative Formulas
515  SwTableFormulaUpdate aMsgHint( &pTableNd->GetTable() );
516  aMsgHint.m_eFlags = TBL_RELBOXNAME;
518 
519  // Table as a flat array structure
520  FlatFndBox aFlatBox(this, aFndBox);
521 
522  if(!aFlatBox.IsSymmetric())
523  return false;
524 
525  // Delete HTML layout
526  pTableNd->GetTable().SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());
527 
528  // #i37739# A simple 'MakeFrames' after the node sorting
529  // does not work if the table is inside a frame and has no prev/next.
530  SwNode2LayoutSaveUpperFrames aNode2Layout(*pTableNd);
531 
532  // Delete the Table's Frames
533  pTableNd->DelFrames();
534  // ? TL_CHART2: ?
535 
536  SwUndoSort* pUndoSort = nullptr;
537  if (GetIDocumentUndoRedo().DoesUndo())
538  {
539  pUndoSort = new SwUndoSort( rBoxes[0]->GetSttIdx(),
540  rBoxes.back()->GetSttIdx(),
541  *pTableNd, rOpt, aFlatBox.HasItemSets() );
542  GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndoSort));
543  }
544  ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
545 
546  // Insert KeyElements
547  sal_uInt16 nCount = (rOpt.eDirection == SwSortDirection::Rows) ?
548  aFlatBox.GetRows() : aFlatBox.GetCols();
549 
550  // Sort SortList by Key
551  SwSortElement::Init( this, rOpt, &aFlatBox );
552  std::multiset<SwSortBoxElement> aSortList;
553 
554  // When sorting, do not include the first row if the HeaderLine is repeated
555  for( sal_uInt16 i = o3tl::narrowing<sal_uInt16>(nStart); i < nCount; ++i)
556  {
557  aSortList.insert(SwSortBoxElement(i));
558  }
559 
560  // Move after Sorting
561  SwMovedBoxes aMovedList;
562  sal_uInt16 i = 0;
563  for (const auto& rElem : aSortList)
564  {
566  {
567  MoveRow(this, aFlatBox, rElem.nRow, i+nStart, aMovedList, pUndoSort);
568  }
569  else
570  {
571  MoveCol(this, aFlatBox, rElem.nRow, i+nStart, aMovedList, pUndoSort);
572  }
573  ++i;
574  }
575 
576  // Restore table frames:
577  // #i37739# A simple 'MakeFrames' after the node sorting
578  // does not work if the table is inside a frame and has no prev/next.
579  const sal_uLong nIdx = pTableNd->GetIndex();
580  aNode2Layout.RestoreUpperFrames( GetNodes(), nIdx, nIdx + 1 );
581 
582  // TL_CHART2: need to inform chart of probably changed cell names
583  UpdateCharts( pTableNd->GetTable().GetFrameFormat()->GetName() );
584 
585  // Delete all Elements in the SortArray
586  aSortList.clear();
588 
590  return true;
591 }
592 
594 void MoveRow(SwDoc* pDoc, const FlatFndBox& rBox, sal_uInt16 nS, sal_uInt16 nT,
595  SwMovedBoxes& rMovedList, SwUndoSort* pUD)
596 {
597  for( sal_uInt16 i=0; i < rBox.GetCols(); ++i )
598  { // Get old cell position and remember it
599  const FndBox_* pSource = rBox.GetBox(i, nS);
600 
601  // new cell position
602  const FndBox_* pTarget = rBox.GetBox(i, nT);
603 
604  const SwTableBox* pT = pTarget->GetBox();
605  const SwTableBox* pS = pSource->GetBox();
606 
607  bool bMoved = rMovedList.GetPos(pT) != USHRT_MAX;
608 
609  // and move it
610  MoveCell(pDoc, pS, pT, bMoved, pUD);
611 
612  rMovedList.push_back(pS);
613 
614  if( pS != pT )
615  {
616  SwFrameFormat* pTFormat = pT->GetFrameFormat();
617  const SfxItemSet* pSSet = rBox.GetItemSet( i, nS );
618 
619  if( pSSet ||
620  SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_FORMAT ) ||
621  SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_FORMULA ) ||
622  SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_VALUE ) )
623  {
624  pTFormat = const_cast<SwTableBox*>(pT)->ClaimFrameFormat();
625  pTFormat->LockModify();
627  pTFormat->ResetFormatAttr( RES_VERT_ORIENT );
628 
629  if( pSSet )
630  pTFormat->SetFormatAttr( *pSSet );
631  pTFormat->UnlockModify();
632  }
633  }
634  }
635 }
636 
638 void MoveCol(SwDoc* pDoc, const FlatFndBox& rBox, sal_uInt16 nS, sal_uInt16 nT,
639  SwMovedBoxes& rMovedList, SwUndoSort* pUD)
640 {
641  for(sal_uInt16 i=0; i < rBox.GetRows(); ++i)
642  { // Get old cell position and remember it
643  const FndBox_* pSource = rBox.GetBox(nS, i);
644 
645  // new cell position
646  const FndBox_* pTarget = rBox.GetBox(nT, i);
647 
648  // and move it
649  const SwTableBox* pT = pTarget->GetBox();
650  const SwTableBox* pS = pSource->GetBox();
651 
652  // and move it
653  bool bMoved = rMovedList.GetPos(pT) != USHRT_MAX;
654  MoveCell(pDoc, pS, pT, bMoved, pUD);
655 
656  rMovedList.push_back(pS);
657 
658  if( pS != pT )
659  {
660  SwFrameFormat* pTFormat = pT->GetFrameFormat();
661  const SfxItemSet* pSSet = rBox.GetItemSet( nS, i );
662 
663  if( pSSet ||
664  SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_FORMAT ) ||
665  SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_FORMULA ) ||
666  SfxItemState::SET == pTFormat->GetItemState( RES_BOXATR_VALUE ) )
667  {
668  pTFormat = const_cast<SwTableBox*>(pT)->ClaimFrameFormat();
669  pTFormat->LockModify();
671  pTFormat->ResetFormatAttr( RES_VERT_ORIENT );
672 
673  if( pSSet )
674  pTFormat->SetFormatAttr( *pSSet );
675  pTFormat->UnlockModify();
676  }
677  }
678  }
679 }
680 
682 void MoveCell(SwDoc* pDoc, const SwTableBox* pSource, const SwTableBox* pTar,
683  bool bMovedBefore, SwUndoSort* pUD)
684 {
685  OSL_ENSURE(pSource && pTar,"Source or target missing");
686 
687  if(pSource == pTar)
688  return;
689 
690  if(pUD)
691  pUD->Insert( pSource->GetName(), pTar->GetName() );
692 
693  // Set Pam source to the first ContentNode
694  SwNodeRange aRg( *pSource->GetSttNd(), 0, *pSource->GetSttNd() );
695  SwNode* pNd = pDoc->GetNodes().GoNext( &aRg.aStart );
696 
697  // If the Cell (Source) wasn't moved
698  // -> insert an empty Node and move the rest or the Mark
699  // points to the first ContentNode
700  if( pNd->StartOfSectionNode() == pSource->GetSttNd() )
701  pNd = pDoc->GetNodes().MakeTextNode( aRg.aStart,
702  pDoc->GetDfltTextFormatColl() );
703  aRg.aEnd = *pNd->EndOfSectionNode();
704 
705  // If the Target is empty (there is one empty Node)
706  // -> move and delete it
707  SwNodeIndex aTar( *pTar->GetSttNd() );
708  pNd = pDoc->GetNodes().GoNext( &aTar ); // next ContentNode
709  sal_uLong nCount = pNd->EndOfSectionIndex() - pNd->StartOfSectionIndex();
710 
711  bool bDelFirst = false;
712  if( nCount == 2 )
713  {
714  OSL_ENSURE( pNd->GetContentNode(), "No ContentNode");
715  bDelFirst = !pNd->GetContentNode()->Len() && bMovedBefore;
716  }
717 
718  if(!bDelFirst)
719  { // We already have Content -> old Content Section Down
720  SwNodeRange aRgTar( aTar.GetNode(), 0, *pNd->EndOfSectionNode() );
721  pDoc->GetNodes().SectionDown( &aRgTar );
722  }
723 
724  // Insert the Source
725  SwNodeIndex aIns( *pTar->GetSttNd()->EndOfSectionNode() );
726  pDoc->getIDocumentContentOperations().MoveNodeRange( aRg, aIns,
728 
729  // If first Node is empty -> delete it
730  if(bDelFirst)
731  pDoc->GetNodes().Delete( aTar );
732 }
733 
735 FlatFndBox::FlatFndBox(SwDoc* pDocPtr, const FndBox_& rBoxRef) :
736  m_pDoc(pDocPtr),
737  m_nRow(0),
738  m_nCol(0)
739 { // If the array is symmetric
740  m_bSym = CheckLineSymmetry(rBoxRef);
741  if( !m_bSym )
742  return;
743 
744  // Determine column/row count
745  m_nCols = GetColCount(rBoxRef);
746  m_nRows = GetRowCount(rBoxRef);
747 
748  // Create linear array
749  size_t nCount = static_cast<size_t>(m_nRows) * m_nCols;
750  m_pArr = std::make_unique<FndBox_ const *[]>(nCount);
751  memset(m_pArr.get(), 0, sizeof(const FndBox_*) * nCount);
752 
753  FillFlat( rBoxRef );
754 }
755 
757 {
758 }
759 
762 {
763  const FndLines_t &rLines = rBox.GetLines();
764  FndBoxes_t::size_type nBoxes {0};
765 
766  for (FndLines_t::size_type i=0; i < rLines.size(); ++i)
767  {
768  const FndLine_* pLn = rLines[i].get();
769  const FndBoxes_t& rBoxes = pLn->GetBoxes();
770 
771  // Number of Boxes of all Lines is unequal -> no symmetry
772  if( i && nBoxes != rBoxes.size())
773  return false;
774 
775  nBoxes = rBoxes.size();
776  if( !CheckBoxSymmetry( *pLn ) )
777  return false;
778  }
779  return true;
780 }
781 
784 {
785  const FndBoxes_t &rBoxes = rLn.GetBoxes();
786  FndLines_t::size_type nLines {0};
787 
788  for (FndBoxes_t::size_type i = 0; i < rBoxes.size(); ++i)
789  {
790  FndBox_ const*const pBox = rBoxes[i].get();
791  const FndLines_t& rLines = pBox->GetLines();
792 
793  // Number of Lines of all Boxes is unequal -> no symmetry
794  if( i && nLines != rLines.size() )
795  return false;
796 
797  nLines = rLines.size();
798  if( nLines && !CheckLineSymmetry( *pBox ) )
799  return false;
800  }
801  return true;
802 }
803 
805 sal_uInt16 FlatFndBox::GetColCount(const FndBox_& rBox)
806 {
807  const FndLines_t& rLines = rBox.GetLines();
808  // Iterate over Lines
809  if( rLines.empty() )
810  return 1;
811 
812  sal_uInt16 nSum = 0;
813  for (const auto & pLine : rLines)
814  {
815  // The Boxes of a Line
816  sal_uInt16 nCount = 0;
817  const FndBoxes_t& rBoxes = pLine->GetBoxes();
818  for (const auto &rpB : rBoxes)
819  { // Iterate recursively over the Lines
820  nCount += rpB->GetLines().empty() ? 1 : GetColCount(*rpB);
821  }
822 
823  if( nSum < nCount )
824  nSum = nCount;
825  }
826  return nSum;
827 }
828 
830 sal_uInt16 FlatFndBox::GetRowCount(const FndBox_& rBox)
831 {
832  const FndLines_t& rLines = rBox.GetLines();
833  if( rLines.empty() )
834  return 1;
835 
836  sal_uInt16 nLines = 0;
837  for (const auto & pLine : rLines)
838  { // The Boxes of a Line
839  const FndBoxes_t& rBoxes = pLine->GetBoxes();
840  sal_uInt16 nLn = 1;
841  for (const auto &rpB : rBoxes)
842  {
843  if (!rpB->GetLines().empty())
844  { // Iterate recursively over the Lines
845  nLn = std::max(GetRowCount(*rpB), nLn);
846  }
847  }
848 
849  nLines = nLines + nLn;
850  }
851  return nLines;
852 }
853 
855 void FlatFndBox::FillFlat(const FndBox_& rBox, bool bLastBox)
856 {
857  bool bModRow = false;
858  const FndLines_t& rLines = rBox.GetLines();
859 
860  // Iterate over Lines
861  sal_uInt16 nOldRow = m_nRow;
862  for (const auto & pLine : rLines)
863  {
864  // The Boxes of a Line
865  const FndBoxes_t& rBoxes = pLine->GetBoxes();
866  sal_uInt16 nOldCol = m_nCol;
867  for( FndBoxes_t::size_type j = 0; j < rBoxes.size(); ++j )
868  {
869  // Check the Box if it's an atomic one
870  const FndBox_ *const pBox = rBoxes[j].get();
871 
872  if( pBox->GetLines().empty() )
873  {
874  // save it
875  sal_uInt16 nOff = m_nRow * m_nCols + m_nCol;
876  m_pArr[nOff] = pBox;
877 
878  // Save the Formula/Format/Value values
879  const SwFrameFormat* pFormat = pBox->GetBox()->GetFrameFormat();
880  if( SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_FORMAT ) ||
881  SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_FORMULA ) ||
882  SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_VALUE ) )
883  {
884  auto pSet = std::make_unique<SfxItemSet>(
885  m_pDoc->GetAttrPool(),
886  svl::Items<
889  pSet->Put( pFormat->GetAttrSet() );
890  if( m_ppItemSets.empty() )
891  {
892  size_t nCount = static_cast<size_t>(m_nRows) * m_nCols;
893  m_ppItemSets.resize(nCount);
894  }
895  m_ppItemSets[nOff] = std::move(pSet);
896  }
897 
898  bModRow = true;
899  }
900  else
901  {
902  // Iterate recursively over the Lines of a Box
903  FillFlat( *pBox, ( j+1 == rBoxes.size() ) );
904  }
905  m_nCol++;
906  }
907  if(bModRow)
908  m_nRow++;
909  m_nCol = nOldCol;
910  }
911  if(!bLastBox)
912  m_nRow = nOldRow;
913 }
914 
916 const FndBox_* FlatFndBox::GetBox(sal_uInt16 n_Col, sal_uInt16 n_Row) const
917 {
918  sal_uInt16 nOff = n_Row * m_nCols + n_Col;
919  const FndBox_* pTmp = m_pArr[nOff];
920 
921  OSL_ENSURE(n_Col < m_nCols && n_Row < m_nRows && pTmp, "invalid array access");
922  return pTmp;
923 }
924 
925 const SfxItemSet* FlatFndBox::GetItemSet(sal_uInt16 n_Col, sal_uInt16 n_Row) const
926 {
927  OSL_ENSURE( m_ppItemSets.empty() || ( n_Col < m_nCols && n_Row < m_nRows), "invalid array access");
928 
929  return !m_ppItemSets.empty() ? m_ppItemSets[unsigned(n_Row * m_nCols) + n_Col].get() : nullptr;
930 }
931 
932 sal_uInt16 SwMovedBoxes::GetPos(const SwTableBox* pTableBox) const
933 {
934  std::vector<const SwTableBox*>::const_iterator it = std::find(mBoxes.begin(), mBoxes.end(), pTableBox);
935  return it == mBoxes.end() ? USHRT_MAX : it - mBoxes.begin();
936 }
937 
938 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SwSortTextElement(const SwNodeIndex &rPos)
SortingElement for Text.
Definition: docsort.cxx:181
const SwTableBoxNumFormat & GetTableBoxNumFormat(bool=true) const
TableBox attributes - implemented in cellatr.hxx.
Definition: cellatr.hxx:105
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:683
const FndLines_t & GetLines() const
Definition: tblsel.hxx:173
#define LANGUAGE_NONE
virtual sal_Int32 Len() const
Definition: node.cxx:1246
static double StrToDouble(const OUString &rStr)
Definition: docsort.cxx:104
const Value & back() const
Marks a position in the document model.
Definition: pam.hxx:35
sal_Int32 compareString(const OUString &s1, const OUString &s2) const
bool HasItemSets() const
Definition: docsort.hxx:147
SwSortDirection eDirection
Definition: sortopt.hxx:51
void loadCollatorAlgorithm(const OUString &rAlgorithm, const css::lang::Locale &rLocale, sal_Int32 nOption)
constexpr TypedWhichId< SwTableBoxNumFormat > RES_BOXATR_FORMAT(RES_BOXATR_BEGIN)
const OUString & GetText() const
Definition: ndtxt.hxx:215
static constexpr auto Items
sal_uLong GetSttIdx() const
Definition: swtable.cxx:1916
bool m_bSym
Definition: docsort.hxx:144
sal_uInt16 m_nRows
Definition: docsort.hxx:139
SvNumberFormatter * GetNumberFormatter(bool bCreate=true)
Definition: doc.hxx:1411
virtual AppendResult AppendRedline(SwRangeRedline *pNewRedl, bool bCallDelete)=0
Append a new redline.
SwNodeIndex nNode
Definition: pam.hxx:37
sal_Unicode cDeli
Definition: sortopt.hxx:52
int n1
SwNodeIndex aPos
Definition: docsort.hxx:94
void MoveCell(SwDoc *pDoc, const SwTableBox *pSource, const SwTableBox *pTar, bool bMovedBefore, SwUndoSort *pUD)
Move a single Cell.
Definition: docsort.cxx:682
virtual void SetModified()=0
Must be called manually at changes of format.
sal_uIntPtr sal_uLong
static void Finit()
Definition: docsort.cxx:85
bool IsSymmetric() const
Definition: docsort.hxx:119
const SwPosition * GetMark() const
Definition: pam.hxx:209
virtual OUString GetKey(sal_uInt16 nKey) const =0
sal_Int64 n
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
Definition: doc.hxx:188
SwTableLine is one table row in the document model.
Definition: swtable.hxx:357
SwNode & GetNode() const
Definition: ndindex.hxx:119
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
double GetValue() const
Definition: cellatr.hxx:95
constexpr TypedWhichId< SwTableBoxValue > RES_BOXATR_VALUE(152)
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
sal_uInt16 nRow
Definition: docsort.hxx:104
void Copy_(const SwNodeRange &rRg, const SwNodeIndex &rInsPos, bool bNewFrames=true) const
Definition: ndarr.hxx:176
double stringToDouble(const OUString &rString, bool bUseGroupSep, rtl_math_ConversionStatus *pStatus, sal_Int32 *pParseEnd) const
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:744
FlatFndBox(SwDoc *pDocPtr, const FndBox_ &rBox)
Generate two-dimensional array of FndBoxes.
Definition: docsort.cxx:735
void ForEach_FndLineCopyCol(SwTableLines &rLines, FndPara *pFndPara)
This creates a structure mirroring the SwTable structure that contains all rows and non-leaf boxes (a...
Definition: tblsel.cxx:2104
static SwSortOptions * pOptions
Definition: docsort.hxx:61
static LanguageType nLang
Definition: srtdlg.cxx:51
sal_uInt16 GetRowCount(const FndBox_ &rBox)
Maximum count of Rows (Lines)
Definition: docsort.cxx:830
void SetValues(const SwPaM &rPam)
Definition: undobj.cxx:60
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:229
sal_uInt16 GetPos(const SwTableBox *pTableBox) const
Definition: docsort.cxx:932
IDocumentFieldsAccess const & getIDocumentFieldsAccess() const
Definition: doc.cxx:357
void Delete(const SwNodeIndex &rPos, sal_uLong nNodes=1)
delete nodes
Definition: nodes.cxx:1078
constexpr TypedWhichId< SwFormatVertOrient > RES_VERT_ORIENT(102)
sal_uInt16 sal_Unicode
int n2
SwIndex nContent
Definition: pam.hxx:38
bool empty() const
Definition: docary.hxx:264
SwNodeIndex aStart
Definition: ndindex.hxx:132
static LocaleDataWrapper * pLclData
Definition: docsort.hxx:67
virtual OUString GetKey(sal_uInt16 nKey) const override
Definition: docsort.cxx:186
const SwTextFormatColl * GetDfltTextFormatColl() const
Definition: doc.hxx:776
int nCount
sal_uLong GetIndex() const
Definition: ndindex.hxx:152
virtual void UpdateTableFields(SfxPoolItem *pHt)=0
virtual void DoUndo(bool const bDoUndo)=0
Enable/Disable Undo.
const FndBoxes_t & GetBoxes() const
Definition: tblsel.hxx:203
void UpdateCharts(const OUString &rName) const
Definition: docchart.cxx:120
void push_back(const SwTableBox *&rpTableBox)
Definition: docsort.hxx:45
void Insert(const OUString &rOrgPos, const OUString &rNewPos)
Definition: unsort.cxx:243
virtual bool DoesUndo() const =0
Is Undo enabled?
void FillFlat(const FndBox_ &, bool bLastBox=false)
Create a linear array of atomic FndBoxes.
Definition: docsort.cxx:855
bool bIgnoreCase
Definition: sortopt.hxx:55
std::vector< const SwTableBox * > mBoxes
Definition: docsort.hxx:42
bool CheckBoxSymmetry(const FndLine_ &rLn)
Check Box for symmetry (All Boxes of a Line need to have same number of Lines)
Definition: docsort.cxx:783
Base class for various Writer styles.
Definition: format.hxx:46
const FndBox_ * GetBox(sal_uInt16 nCol, sal_uInt16 nRow) const
Access a specific Cell.
Definition: docsort.cxx:916
bool SortText(const SwPaM &, const SwSortOptions &)
Sort Text in the Document.
Definition: docsort.cxx:283
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
OUString GetName() const
Definition: swtable.cxx:1863
virtual void AppendUndo(std::unique_ptr< SwUndo > pUndo)=0
Add new Undo action.
SwDoc * m_pDoc
Definition: docsort.hxx:135
Style of a layout element.
Definition: frmfmt.hxx:59
void SetSaveRange(const SwPaM &rRange)
Definition: unredln.cxx:389
std::vector< SwSortKey > aKeys
Definition: sortopt.hxx:50
virtual SwUndoId StartUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Opens undo block.
void SectionDown(SwNodeRange *pRange, SwStartNodeType=SwNormalStartNode)
create a start/end section pair
Definition: nodes.cxx:905
int i
static css::lang::Locale * pLocale
Definition: docsort.hxx:65
const SwPosition * GetPoint() const
Definition: pam.hxx:207
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:206
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
virtual double GetValue(sal_uInt16 nKey) const
Definition: docsort.cxx:175
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
virtual OUString GetKey(sal_uInt16 nKey) const override
Get Key for a cell.
Definition: docsort.cxx:225
virtual double GetValue(sal_uInt16 nKey) const override
Definition: docsort.cxx:257
bool IsTextFormat(sal_uInt32 nFIndex) const
static bool IsShowOriginal(const RedlineFlags eM)
virtual bool DeleteRedline(const SwPaM &rPam, bool bSaveInUndo, RedlineType nDelType)=0
SwContentNode * GetContentNode()
Definition: node.hxx:616
std::unique_ptr< FndBox_ const *[]> m_pArr
Definition: docsort.hxx:136
FlyAnchors.
Definition: fmtanchr.hxx:34
sal_uInt16 GetCols() const
Definition: docsort.hxx:121
sal_uInt16 m_nCol
Definition: docsort.hxx:142
void MoveRow(SwDoc *pDoc, const FlatFndBox &rBox, sal_uInt16 nS, sal_uInt16 nT, SwMovedBoxes &rMovedList, SwUndoSort *pUD)
Move a row.
Definition: docsort.cxx:594
void UnlockModify()
Definition: calbck.hxx:210
static void Init(SwDoc *, const SwSortOptions &rOpt, FlatFndBox const *=nullptr)
Construct a SortElement for the Sort.
Definition: docsort.cxx:67
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:394
void LockModify()
Definition: calbck.hxx:209
#define LANGUAGE_DONTKNOW
static CollatorWrapper * pSortCollator
Definition: docsort.hxx:64
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
Definition: format.cxx:388
Marks a node in the document model.
Definition: ndindex.hxx:31
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:444
static SwDoc * pDoc
Definition: docsort.hxx:62
bool empty() const
virtual bool MoveNodeRange(SwNodeRange &, SwNodeIndex &, SwMoveFlags)=0
SwSortOrder eSortOrder
Definition: sortopt.hxx:37
bool operator<(const SwSortElement &) const
Definition: docsort.cxx:159
const char * pS
const SwPosition * Start() const
Definition: pam.hxx:212
virtual bool IsIgnoreRedline() const =0
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:450
void RestoreUpperFrames(SwNodes &rNds, sal_uLong nStt, sal_uLong nEnd)
Definition: node2lay.cxx:439
const SwTableBoxValue & GetTableBoxValue(bool=true) const
Definition: cellatr.hxx:109
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
OUString sSortType
Definition: sortopt.hxx:36
virtual bool ResetFormatAttr(sal_uInt16 nWhich1, sal_uInt16 nWhich2=0)
Definition: format.cxx:624
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
static std::optional< OUString > xLastAlgorithm
Definition: docsort.hxx:66
std::vector< std::unique_ptr< FndBox_ > > FndBoxes_t
Definition: tblsel.hxx:152
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:458
sal_uInt16 GetColCount(const FndBox_ &rBox)
Maximum count of Columns (Boxes)
Definition: docsort.cxx:805
sal_uInt16 m_nCols
Definition: docsort.hxx:140
bool CheckLineSymmetry(const FndBox_ &rBox)
All Lines of a Box need to have same number of Boxes.
Definition: docsort.cxx:761
const SwTableBox * GetBox() const
Definition: tblsel.hxx:175
const SfxItemSet * GetItemSet(sal_uInt16 nCol, sal_uInt16 nRow) const
Definition: docsort.cxx:925
LanguageType GetAppLanguage()
Definition: init.cxx:723
void MoveCol(SwDoc *pDoc, const FlatFndBox &rBox, sal_uInt16 nS, sal_uInt16 nT, SwMovedBoxes &rMovedList, SwUndoSort *pUD)
Move a column.
Definition: docsort.cxx:638
SwNodes & GetNodes()
Definition: doc.hxx:409
constexpr TypedWhichId< SwTableBoxFormula > RES_BOXATR_FORMULA(151)
const SwPosition * End() const
Definition: pam.hxx:217
std::vector< std::unique_ptr< SfxItemSet > > m_ppItemSets
Definition: docsort.hxx:137
SwNodeIndex aEnd
Definition: ndindex.hxx:133
static const FlatFndBox * pBox
Definition: docsort.hxx:63
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:405
Reference< XComponentContext > getProcessComponentContext()
std::vector< std::unique_ptr< FndLine_ > > FndLines_t
Definition: tblsel.hxx:155
SwTableBox * GetUpper()
Definition: swtable.hxx:375
LanguageType nLanguage
Definition: sortopt.hxx:53
sal_uInt32 GetValue() const
virtual ~SwSortElement()
Definition: docsort.cxx:100
bool SortTable(const SwSelBoxes &rBoxes, const SwSortOptions &)
Sort Table in the Document.
Definition: docsort.cxx:468
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:120
TableFormulaUpdateFlags m_eFlags
Definition: hints.hxx:268
virtual const SwRedlineTable & GetRedlineTable() const =0
sal_uInt16 GetRows() const
Definition: docsort.hxx:120
SwTableLine * GetUpper()
Definition: swtable.hxx:440
bool IsTextNode() const
Definition: node.hxx:637
SwContentNode * GoNext(SwNodeIndex *) const
Definition: nodes.cxx:1293
sal_uInt16 m_nRow
Definition: docsort.hxx:141
#define SW_COLLATOR_IGNORES
Definition: swtypes.hxx:183
int keycompare(const SwSortElement &rCmp, sal_uInt16 nKey) const
Definition: docsort.cxx:118
bool bIsNumeric
Definition: sortopt.hxx:39
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1319
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:850
bool anyOf(strong_int v) const
SwSortBoxElement(sal_uInt16 nRC)
SortingElement for Tables.
Definition: docsort.cxx:219
SwTextNode * MakeTextNode(const SwNodeIndex &rWhere, SwTextFormatColl *pColl, bool bNewFrames=true)
Implementations of "Make...Node" are in the given .cxx-files.
Definition: ndtxt.cxx:105
SwNodeIndex & Assign(SwNodes const &rNds, sal_uLong)
Definition: ndindex.hxx:272
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)
Base class of the Writer document model elements.
Definition: node.hxx:80