LCOV - code coverage report
Current view: top level - sw/source/core/doc - docsort.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 278 452 61.5 %
Date: 2015-06-13 12:38:46 Functions: 27 35 77.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11