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