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

Generated by: LCOV version 1.10