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

Generated by: LCOV version 1.10