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

Generated by: LCOV version 1.10