diff options
Diffstat (limited to 'sw/source/core/doc/docsort.cxx')
-rw-r--r-- | sw/source/core/doc/docsort.cxx | 1060 |
1 files changed, 1060 insertions, 0 deletions
diff --git a/sw/source/core/doc/docsort.cxx b/sw/source/core/doc/docsort.cxx new file mode 100644 index 000000000000..f0414cc11b6a --- /dev/null +++ b/sw/source/core/doc/docsort.cxx @@ -0,0 +1,1060 @@ +/************************************************************************* + * + * $RCSfile: docsort.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-19 00:08:15 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifdef PRECOMPILED +#include "core_pch.hxx" +#endif + +#pragma hdrstop + +#ifndef _HINTIDS_HXX +#include <hintids.hxx> +#endif + +#ifndef _APP_HXX //autogen +#include <vcl/svapp.hxx> +#endif +#ifndef _SYSTEM_HXX //autogen +#include <vcl/system.hxx> +#endif +#ifndef _INTN_HXX //autogen +#include <tools/intn.hxx> +#endif +#ifndef _DOCARY_HXX +#include <docary.hxx> +#endif +#ifndef _SVX_LANGITEM_HXX //autogen +#include <svx/langitem.hxx> +#endif + +#ifndef _FMTANCHR_HXX //autogen +#include <fmtanchr.hxx> +#endif +#ifndef _FRMFMT_HXX //autogen +#include <frmfmt.hxx> +#endif +#ifndef _DOC_HXX +#include <doc.hxx> +#endif +#ifndef _NODE_HXX +#include <node.hxx> +#endif +#ifndef _PAM_HXX +#include <pam.hxx> +#endif +#ifndef _NDTXT_HXX +#include <ndtxt.hxx> +#endif +#ifndef _SWTABLE_HXX +#include <swtable.hxx> +#endif +#ifndef _SWUNDO_HXX +#include <swundo.hxx> +#endif +#ifndef _SORTOPT_HXX +#include <sortopt.hxx> +#endif +#ifndef _DOCSORT_HXX +#include <docsort.hxx> +#endif +#ifndef _UNDOBJ_HXX +#include <undobj.hxx> +#endif +#ifndef _TBLSEL_HXX +#include <tblsel.hxx> +#endif +#ifndef _HINTS_HXX +#include <hints.hxx> +#endif +#ifndef _CELLATR_HXX +#include <cellatr.hxx> +#endif +#ifndef _REDLINE_HXX +#include <redline.hxx> +#endif + +#ifdef DEBUG +//nur zum debugen +#ifndef _CELLATR_HXX +#include <cellatr.hxx> +#endif +#endif + +SwSortOptions* SwSortElement::pOptions = 0; +SwDoc* SwSortElement::pDoc = 0; +const FlatFndBox* SwSortElement::pBox = 0; +International* SwSortElement::pIntl = 0; + +SV_IMPL_OP_PTRARR_SORT( SwSortElements, SwSortElementPtr ); + + +/*-------------------------------------------------------------------- + Beschreibung: Ein Sortierelement fuers Sort konstruieren + --------------------------------------------------------------------*/ + + +void SwSortElement::Init( SwDoc* pD, const SwSortOptions& rOpt, + FlatFndBox* pFltBx ) +{ + ASSERT( !pDoc && !pOptions && !pBox, "wer hat das Finit vergessen?" ); + pDoc = pD; + pOptions = new SwSortOptions( rOpt ); + pBox = pFltBx; + pIntl = (International*)&Application::GetAppInternational(); + LanguageType eLang = ((const SvxLanguageItem&)pDoc->GetAttrPool(). + GetDefaultItem(RES_CHRATR_LANGUAGE )).GetLanguage(); + + if( !( eLang == ::GetSystemLanguage() && + LANGUAGE_SYSTEM == pIntl->GetLanguage() ) && + eLang != pIntl->GetLanguage() ) + pIntl = new International( eLang ); +} + + +void SwSortElement::Finit() +{ + delete pOptions, pOptions = 0; + pDoc = 0; + pBox = 0; + + if( pIntl != &Application::GetAppInternational() ) + delete pIntl; + pIntl = 0; +} + + +SwSortElement::~SwSortElement() +{ +} + + +double SwSortElement::StrToDouble( const String& rStr ) const +{ + String aStr( rStr ); + sal_Unicode cTSep = pIntl->GetNumThousandSep(); + sal_Unicode cDSep = pIntl->GetNumDecimalSep(); + register sal_Unicode c; + + for( xub_StrLen i = 0; i < aStr.Len(); ++i ) + if( cTSep == ( c = aStr.GetChar( i ) ) ) + aStr.Erase( i--, 1 ); + else if( cDSep == c || ',' == c ) + aStr.SetChar( i, '.' ); + + return aStr.ToDouble(); +} + +/*-------------------------------------------------------------------- + Beschreibung: Operatoren zum Vergleichen + --------------------------------------------------------------------*/ + + +BOOL SwSortElement::operator==(const SwSortElement& rCmp) +{ + return FALSE; +} + +/*-------------------------------------------------------------------- + Beschreibung: Kleiner-Operator fuers sortieren + --------------------------------------------------------------------*/ + + +BOOL SwSortElement::operator<(const SwSortElement& rCmp) +{ + + // der eigentliche Vergleich + // + for(USHORT nKey = 0; nKey < pOptions->aKeys.Count(); ++nKey) + { + const SwSortElement *pOrig, *pCmp; + + const SwSortKey* pSrtKey = pOptions->aKeys[ nKey ]; + if( pSrtKey->eSortOrder == SRT_ASCENDING ) + pOrig = this, pCmp = &rCmp; + else + pOrig = &rCmp, pCmp = this; + + if( SRT_NUMERIC == pSrtKey->eSortKeyType ) + { + double n1 = pOrig->GetValue( nKey ); + double n2 = pCmp->GetValue( nKey ); + + if( n1 == n2 ) + continue; + + return n1 < n2; + } + else + { + StringCompare eCmp = pIntl->Compare( pOrig->GetKey( nKey ), + pCmp->GetKey( nKey )); + if( COMPARE_EQUAL == eCmp ) + continue; + + return COMPARE_LESS == eCmp; + } + } + return FALSE; +} + +double SwSortElement::GetValue( USHORT nKey ) const +{ + return StrToDouble( GetKey( nKey )); +} + +/*-------------------------------------------------------------------- + Beschreibung: SortierElemente fuer Text + --------------------------------------------------------------------*/ + + +SwSortTxtElement::SwSortTxtElement( const SwNodeIndex& rPos ) + : aPos( rPos ), + nOrg( rPos.GetIndex() ) +{ +} + + +SwSortTxtElement::~SwSortTxtElement() +{ +} + + +/*-------------------------------------------------------------------- + Beschreibung: Key ermitteln + --------------------------------------------------------------------*/ + + +String SwSortTxtElement::GetKey(USHORT nId) const +{ + SwTxtNode* pTxtNd = aPos.GetNode().GetTxtNode(); + if( !pTxtNd ) + return aEmptyStr; + + // fuer TextNodes + const String& rStr = pTxtNd->GetTxt(); + + sal_Unicode nDeli = pOptions->nDeli; + USHORT nDCount = pOptions->aKeys[nId]->nColumnId, i = 1; + xub_StrLen nStart = 0; + + // Den Delimitter suchen + while( nStart != STRING_NOTFOUND && i < nDCount) + if( STRING_NOTFOUND != ( nStart = rStr.Search( nDeli, nStart ) ) ) + { + nStart++; + i++; + } + + // naechsten Delimitter gefunden oder Ende des Strings und Kopieren + xub_StrLen nEnd = rStr.Search( nDeli, nStart+1 ); + return rStr.Copy( nStart, nEnd-nStart ); +} + + +/*-------------------------------------------------------------------- + Beschreibung: Sortier-Elemente fuer Tabellen + --------------------------------------------------------------------*/ + +SwSortBoxElement::SwSortBoxElement( USHORT nRC ) + : nRow( nRC ) +{ +} + + +SwSortBoxElement::~SwSortBoxElement() +{ +} + +/*-------------------------------------------------------------------- + Beschreibung: Schluessel zu einer Zelle ermitteln + --------------------------------------------------------------------*/ + + +String SwSortBoxElement::GetKey(USHORT nKey) const +{ + const _FndBox* pFndBox; + USHORT nCol = pOptions->aKeys[nKey]->nColumnId-1; + + if( SRT_ROWS == pOptions->eDirection ) + pFndBox = pBox->GetBox(nCol, nRow); // Zeilen sortieren + else + pFndBox = pBox->GetBox(nRow, nCol); // Spalten sortieren + + // Den Text rausfieseln + String aRetStr; + if( pFndBox ) + { // StartNode holen und ueberlesen + const SwTableBox* pBox = pFndBox->GetBox(); + ASSERT(pBox, "Keine atomare Box"); + + if( pBox->GetSttNd() ) + { + // ueber alle TextNodes der Box + const SwNode *pNd = 0, *pEndNd = pBox->GetSttNd()->EndOfSectionNode(); + for( ULONG nIdx = pBox->GetSttIdx() + 1; pNd != pEndNd; ++nIdx ) + if( ( pNd = pDoc->GetNodes()[ nIdx ])->IsTxtNode() ) + aRetStr += ((SwTxtNode*)pNd)->GetTxt(); + } + } + return aRetStr; +} + +double SwSortBoxElement::GetValue( USHORT nKey ) const +{ + const _FndBox* pFndBox; + USHORT nCol = pOptions->aKeys[nKey]->nColumnId-1; + + if( SRT_ROWS == pOptions->eDirection ) + pFndBox = pBox->GetBox(nCol, nRow); // Zeilen sortieren + else + pFndBox = pBox->GetBox(nRow, nCol); // Spalten sortieren + + double aVal; + if( pFndBox ) + aVal = pFndBox->GetBox()->GetFrmFmt()->GetTblBoxValue().GetValue(); + else + aVal = 0; + + return aVal; +} + +/*-------------------------------------------------------------------- + Beschreibung: Text sortieren im Document + --------------------------------------------------------------------*/ + + +BOOL SwDoc::SortText(const SwPaM& rPaM, const SwSortOptions& rOpt) +{ + // pruefen ob Rahmen im Text + const SwPosition *pStart = rPaM.Start(), *pEnd = rPaM.End(); + // Index auf den Start der Selektion + + SwFrmFmt* pFmt; + const SwFmtAnchor* pAnchor; + const SwPosition* pAPos; + + for( USHORT n = 0; n < GetSpzFrmFmts()->Count(); ++n ) + { + pFmt = (SwFrmFmt*)(*GetSpzFrmFmts())[n]; + pAnchor = &pFmt->GetAnchor(); + + if( FLY_AT_CNTNT == pAnchor->GetAnchorId() && + 0 != (pAPos = pAnchor->GetCntntAnchor() ) && + pStart->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode ) + return FALSE; + } + + // pruefe ob nur TextNodes in der Selection liegen + { + register ULONG nStart = pStart->nNode.GetIndex(), + nEnd = pEnd->nNode.GetIndex(); + while( nStart <= nEnd ) + // Iterieren ueber einen selektierten Bereich + if( !GetNodes()[ nStart++ ]->IsTxtNode() ) + return FALSE; + } + + BOOL bUndo = DoesUndo(); + if( bUndo ) + StartUndo( UNDO_START ); + + SwPaM* pRedlPam = 0; + SwUndoRedlineSort* pRedlUndo = 0; + SwUndoSort* pUndoSort = 0; + + if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() )) + { + pRedlPam = new SwPaM( pStart->nNode, pEnd->nNode, -1, 1 ); + SwCntntNode* pCNd = pRedlPam->GetCntntNode( FALSE ); + if( pCNd ) + pRedlPam->GetMark()->nContent = pCNd->Len(); + + if( IsRedlineOn() && !IsShowOriginal( GetRedlineMode() ) ) + { + if( bUndo ) + { + pRedlUndo = new SwUndoRedlineSort( rPaM, rOpt ); + DoUndo( FALSE ); + } + // erst den Bereich kopieren, dann + SwNodeIndex aEndIdx( pEnd->nNode, 1 ); + SwNodeRange aRg( pStart->nNode, aEndIdx ); + GetNodes()._Copy( aRg, aEndIdx ); + + // Bereich neu ist von pEnd->nNode+1 bis aEndIdx + DeleteRedline( *pRedlPam ); + + pRedlPam->GetMark()->nNode.Assign( pEnd->nNode.GetNode(), 1 ); + pCNd = pRedlPam->GetCntntNode( FALSE ); + pRedlPam->GetMark()->nContent.Assign( pCNd, 0 ); + + pRedlPam->GetPoint()->nNode.Assign( aEndIdx.GetNode() ); + pCNd = pRedlPam->GetCntntNode( TRUE ); + xub_StrLen nCLen = 0; + if( !pCNd && + 0 != (pCNd = GetNodes()[ aEndIdx.GetIndex()-1 ]->GetCntntNode())) + { + nCLen = pCNd->Len(); + pRedlPam->GetPoint()->nNode.Assign( *pCNd ); + } + pRedlPam->GetPoint()->nContent.Assign( pCNd, nCLen ); + + if( pRedlUndo ) + pRedlUndo->SetValues( rPaM ); + } + else + { + DeleteRedline( *pRedlPam ); + delete pRedlPam, pRedlPam = 0; + } + } + + SwNodeIndex aStart(pStart->nNode); + SwSortElement::Init( this, rOpt ); + SwSortElements aSortArr; + while( aStart <= pEnd->nNode ) + { + // Iterieren ueber einen selektierten Bereich + SwSortTxtElement* pSE = new SwSortTxtElement( aStart ); + aSortArr.Insert(pSE); + aStart++; + } + + // Und jetzt der Akt: Verschieben von Nodes und immer schoen auf UNDO + // achten + // + ULONG nBeg = pStart->nNode.GetIndex(), nEnd = aStart.GetIndex(); + SwNodeRange aRg( aStart, aStart ); + + if( bUndo && !pRedlUndo ) + AppendUndo( pUndoSort = new SwUndoSort( rPaM, rOpt ) ); + + DoUndo( FALSE ); + + for( n = 0; n < aSortArr.Count(); ++n ) + { + SwSortTxtElement* pBox = (SwSortTxtElement*)aSortArr[n]; + aStart = nBeg + n; + aRg.aStart = pBox->aPos.GetIndex(); + aRg.aEnd = aRg.aStart.GetIndex() + 1; + + // Nodes verschieben + Move( aRg, aStart ); + + // Undo Verschiebungen einpflegen + if(pUndoSort) + pUndoSort->Insert(pBox->nOrg, nBeg + n); + } + // Alle Elemente aus dem SortArray loeschen + aSortArr.DeleteAndDestroy(0, aSortArr.Count()); + SwSortElement::Finit(); + + if( pRedlPam ) + { + if( pRedlUndo ) + { + pRedlUndo->SetSaveRange( *pRedlPam ); + AppendUndo( pRedlUndo ); + } + + // nBeg ist der Start vom sortierten Bereich + SwNodeIndex aSttIdx( GetNodes(), nBeg ); + + // der Kopierte Bereich ist das Geloeschte + AppendRedline( new SwRedline( REDLINE_DELETE, *pRedlPam )); + + // das sortierte ist das Eingefuegte + pRedlPam->GetPoint()->nNode = aSttIdx; + SwCntntNode* pCNd = aSttIdx.GetNode().GetCntntNode(); + pRedlPam->GetPoint()->nContent.Assign( pCNd, 0 ); + + AppendRedline( new SwRedline( REDLINE_INSERT, *pRedlPam )); + + if( pRedlUndo ) + pRedlUndo->SetOffset( aSttIdx ); + + delete pRedlPam, pRedlPam = 0; + } + DoUndo( bUndo ); + if( bUndo ) + EndUndo( UNDO_END ); + + return TRUE; +} + +/*-------------------------------------------------------------------- + Beschreibung: Tabelle sortieren im Document + --------------------------------------------------------------------*/ + +BOOL SwDoc::SortTbl(const SwSelBoxes& rBoxes, const SwSortOptions& rOpt) +{ + // uebers SwDoc fuer Undo !! + ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" ); + SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode(); + if( !pTblNd ) + return FALSE; + + // Auf gehts sortieren + // suche alle Boxen / Lines + _FndBox aFndBox( 0, 0 ); + { + _FndPara aPara( rBoxes, &aFndBox ); + pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );; + } + + if(!aFndBox.GetLines().Count()) + return FALSE; + + if( !IsIgnoreRedline() && GetRedlineTbl().Count() ) + DeleteRedline( *pTblNd ); + + USHORT nStart = 0; + if(pTblNd->GetTable().IsHeadlineRepeat() && rOpt.eDirection == SRT_ROWS) + { + // Das ist die Kopfzeile + SwTableLine * pHeadLine = pTblNd->GetTable().GetTabLines()[0]; + + // Oberste seleketierte Zeile + _FndLines& rLines = aFndBox.GetLines(); + + while(nStart < rLines.Count() ) + { + // Verschachtelung durch Split Merge beachten, + // die oberste rausholen + SwTableLine* pLine = rLines[nStart]->GetLine(); + while ( pLine->GetUpper() ) + pLine = pLine->GetUpper()->GetUpper(); + + if( pLine == pHeadLine) + nStart++; + else + break; + } + // Alle selektierten in der HeaderLine ? -> kein Offset + if(nStart == rLines.Count()) + nStart = 0; + } + + // umschalten auf relative Formeln + SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() ); + aMsgHnt.eFlags = TBL_RELBOXNAME; + UpdateTblFlds( &aMsgHnt ); + + // Tabelle als flache Array-Struktur + FlatFndBox aFlatBox(this, aFndBox); + + if(!aFlatBox.IsSymmetric()) + return FALSE; + + // MIB 9.7.97: HTML-Layout loeschen + pTblNd->GetTable().SetHTMLTableLayout( 0 ); + + // loesche die Frames der Tabelle + pTblNd->DelFrms(); + // und dann noch fuers Chart die Daten sichern + aFndBox.SaveChartData( pTblNd->GetTable() ); + + // Redo loeschen bevor Undo + BOOL bUndo = DoesUndo(); + SwUndoSort* pUndoSort = 0; + if(bUndo) + { + ClearRedo(); + pUndoSort = new SwUndoSort( rBoxes[0]->GetSttIdx(), + rBoxes[rBoxes.Count()-1]->GetSttIdx(), + *pTblNd, rOpt, aFlatBox.HasItemSets() ); + AppendUndo(pUndoSort); + DoUndo(FALSE); + } + + // SchluesselElemente einsortieren + USHORT nCount = (rOpt.eDirection == SRT_ROWS) ? + aFlatBox.GetRows() : aFlatBox.GetCols(); + + // SortList nach Schluessel sortieren + SwSortElement::Init( this, rOpt, &aFlatBox ); + SwSortElements aSortList; + + // wenn die HeaderLine wiederholt wird und die + // Zeilen sortiert werden 1.Zeile nicht mitsortieren + + for(USHORT i=nStart; i < nCount; ++i) + { + SwSortBoxElement* pEle = new SwSortBoxElement( i ); + aSortList.Insert(pEle); + } + + SwNodeIndex aBehindIdx( *pTblNd->EndOfSectionNode()); + GetNodes().GoNext( &aBehindIdx ); // Index in Cntnt, hinter der Tabelle + + // nach Sortierung verschieben + SwMovedBoxes aMovedList; + for(i=0; i < aSortList.Count(); ++i) + { + SwSortBoxElement* pBox = (SwSortBoxElement*)aSortList[i]; + if(rOpt.eDirection == SRT_ROWS) + MoveRow(this, aFlatBox, pBox->nRow, i + nStart, aMovedList, pUndoSort); + else + MoveCol(this, aFlatBox, pBox->nRow, i + nStart, aMovedList, pUndoSort); + } + + // Neue Frames erzeugen + pTblNd->MakeFrms( &aBehindIdx ); + aFndBox.RestoreChartData( pTblNd->GetTable() ); + + // Alle Elemente aus dem SortArray loeschen + aSortList.DeleteAndDestroy( 0, aSortList.Count() ); + SwSortElement::Finit(); + + // Undo wieder aktivieren + DoUndo(bUndo); + + SetModified(); + return TRUE; +} + +/*-------------------------------------------------------------------- + Beschreibung: Zeilenweise verschieben + --------------------------------------------------------------------*/ + + +void MoveRow(SwDoc* pDoc, const FlatFndBox& rBox, USHORT nS, USHORT nT, + SwMovedBoxes& rMovedList, SwUndoSort* pUD) +{ + for( USHORT i=0; i < rBox.GetCols(); ++i ) + { // Alte Zellen-Pos bestimmen und merken + const _FndBox* pSource = rBox.GetBox(i, nS); + + // neue Zellen-Pos + const _FndBox* pTarget = rBox.GetBox(i, nT); + + const SwTableBox* pT = pTarget->GetBox(); + const SwTableBox* pS = pSource->GetBox(); + + BOOL bMoved = rMovedList.GetPos(pT) != USHRT_MAX; + + // und verschieben + MoveCell(pDoc, pS, pT, bMoved, pUD); + + rMovedList.Insert(pS, rMovedList.Count() ); + + if( pS != pT ) + { + SwFrmFmt* pTFmt = (SwFrmFmt*)pT->GetFrmFmt(); + const SfxItemSet* pSSet = rBox.GetItemSet( i, nS ); + + if( pSSet || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMAT ) || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMULA ) || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_VALUE ) ) + { + pTFmt = ((SwTableBox*)pT)->ClaimFrmFmt(); + pTFmt->LockModify(); + if( pTFmt->ResetAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ) ) + pTFmt->ResetAttr( RES_VERT_ORIENT ); + + if( pSSet ) + pTFmt->SetAttr( *pSSet ); + pTFmt->UnlockModify(); + } + } + } +} + +/*-------------------------------------------------------------------- + Beschreibung: Spaltenweise verschieben + --------------------------------------------------------------------*/ + + +void MoveCol(SwDoc* pDoc, const FlatFndBox& rBox, USHORT nS, USHORT nT, + SwMovedBoxes& rMovedList, SwUndoSort* pUD) +{ + for(USHORT i=0; i < rBox.GetRows(); ++i) + { // Alte Zellen-Pos bestimmen und merken + const _FndBox* pSource = rBox.GetBox(nS, i); + + // neue Zellen-Pos + const _FndBox* pTarget = rBox.GetBox(nT, i); + + // und verschieben + const SwTableBox* pT = pTarget->GetBox(); + const SwTableBox* pS = pSource->GetBox(); + + // und verschieben + BOOL bMoved = rMovedList.GetPos(pT) != USHRT_MAX; + MoveCell(pDoc, pS, pT, bMoved, pUD); + + rMovedList.Insert(pS, rMovedList.Count() ); + + if( pS != pT ) + { + SwFrmFmt* pTFmt = (SwFrmFmt*)pT->GetFrmFmt(); + const SfxItemSet* pSSet = rBox.GetItemSet( nS, i ); + + if( pSSet || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMAT ) || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMULA ) || + SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_VALUE ) ) + { + pTFmt = ((SwTableBox*)pT)->ClaimFrmFmt(); + pTFmt->LockModify(); + if( pTFmt->ResetAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ) ) + pTFmt->ResetAttr( RES_VERT_ORIENT ); + + if( pSSet ) + pTFmt->SetAttr( *pSSet ); + pTFmt->UnlockModify(); + } + } + } +} + +/*-------------------------------------------------------------------- + Beschreibung: Eine einzelne Zelle verschieben + --------------------------------------------------------------------*/ + + +void MoveCell(SwDoc* pDoc, const SwTableBox* pSource, const SwTableBox* pTar, + BOOL bMovedBefore, SwUndoSort* pUD) +{ + ASSERT(pSource && pTar,"Fehlende Quelle oder Ziel"); + + if(pSource == pTar) + return; + + if(pUD) + pUD->Insert( pSource->GetName(), pTar->GetName() ); + + // Pam Quelle auf den ersten ContentNode setzen + SwNodeRange aRg( *pSource->GetSttNd(), 0, *pSource->GetSttNd() ); + SwNode* pNd = pDoc->GetNodes().GoNext( &aRg.aStart ); + + // wurde die Zelle (Source) nicht verschoben + // -> einen Leer-Node einfuegen und den Rest verschieben + // ansonsten steht der Mark auf dem ersten Content-Node + if( pNd->StartOfSectionNode() == pSource->GetSttNd() ) + pNd = pDoc->GetNodes().MakeTxtNode( aRg.aStart, + (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() ); + aRg.aEnd = *pNd->EndOfSectionNode(); + + // Ist das Ziel leer(1 leerer Node vorhanden) + // -> diesen loeschen und move + // Ziel + SwNodeIndex aTar( *pTar->GetSttNd() ); + pNd = pDoc->GetNodes().GoNext( &aTar ); // naechsten ContentNode + ULONG nCount = pNd->EndOfSectionIndex() - pNd->StartOfSectionIndex(); + + BOOL bDelFirst = FALSE; + if( nCount == 2 ) + { + ASSERT( pNd->GetCntntNode(), "Kein ContentNode"); + bDelFirst = !pNd->GetCntntNode()->Len() && bMovedBefore; + } + + if(!bDelFirst) + { // Es besteht schon Inhalt -> alter I n h a l t Section Down + SwNodeRange aRgTar( aTar.GetNode(), 0, *pNd->EndOfSectionNode() ); + pDoc->GetNodes().SectionDown( &aRgTar ); + } + + // Einfuegen der Source + SwNodeIndex aIns( *pTar->GetSttNd()->EndOfSectionNode() ); + pDoc->Move( aRg, aIns ); + + // Falls erster Node leer -> weg damit + if(bDelFirst) + pDoc->GetNodes().Delete( aTar, 1 ); +} + +/*-------------------------------------------------------------------- + Beschreibung: Zweidimensionales Array aus FndBoxes generieren + --------------------------------------------------------------------*/ + + +FlatFndBox::FlatFndBox(SwDoc* pDocPtr, const _FndBox& rBox) : + pDoc(pDocPtr), + pArr(0), + ppItemSets( 0 ), + rBoxRef(rBox), + nRow(0), + nCol(0) +{ // Ist das Array symmetrisch + if((bSym = CheckLineSymmetry(rBoxRef)) != 0) + { + // Spalten/Reihen-Anzahl ermitteln + nCols = GetColCount(rBoxRef); + nRows = GetRowCount(rBoxRef); + + // lineares Array anlegen + pArr = new _FndBoxPtr[ nRows * nCols ]; + _FndBox** ppTmp = (_FndBox**)pArr; + memset( ppTmp, 0, sizeof(_FndBoxPtr) * nRows * nCols ); + + + FillFlat( rBoxRef ); + } +} + + +FlatFndBox::~FlatFndBox() +{ + _FndBox** ppTmp = (_FndBox**)pArr; + __DELETE(nRows * nCols * sizeof(_FndBoxPtr)) ppTmp; + + if( ppItemSets ) + __DELETE(nRows * nCols * sizeof(SfxItemSet*)) ppItemSets; +} + +/*-------------------------------------------------------------------- + Beschreibung: Alle Lines einer Box muessen gleichviel Boxen haben + --------------------------------------------------------------------*/ + + +BOOL FlatFndBox::CheckLineSymmetry(const _FndBox& rBox) +{ + const _FndLines& rLines = rBox.GetLines(); + USHORT nBoxes; + + // UeberLines iterieren + for(USHORT i=0; i < rLines.Count(); ++i) + { // Die Boxen einer Line + _FndLine* pLn = rLines[i]; + const _FndBoxes& rBoxes = pLn->GetBoxes(); + + // Anzahl der Boxen aller Lines ungleich -> keine Symmetrie + if( i && nBoxes != rBoxes.Count()) + return FALSE; + + nBoxes = rBoxes.Count(); + if( !CheckBoxSymmetry( *pLn ) ) + return FALSE; + } + return TRUE; +} + +/*-------------------------------------------------------------------- + Beschreibung: Box auf Symmetrie pruefen + Alle Boxen einer Line muessen gleichviele Lines haben + --------------------------------------------------------------------*/ + + +BOOL FlatFndBox::CheckBoxSymmetry(const _FndLine& rLn) +{ + const _FndBoxes& rBoxes = rLn.GetBoxes(); + USHORT nLines; + + // Ueber Boxes iterieren + for(USHORT i=0; i < rBoxes.Count(); ++i) + { // Die Boxen einer Line + _FndBox* pBox = rBoxes[i]; + const _FndLines& rLines = pBox->GetLines(); + + // Anzahl der Boxen aller Lines ungleich -> keine Symmetrie + if( i && nLines != rLines.Count() ) + return FALSE; + + nLines = rLines.Count(); + if( nLines && !CheckLineSymmetry( *pBox ) ) + return FALSE; + } + return TRUE; +} + +/*-------------------------------------------------------------------- + Beschreibung: max Anzahl der Spalten (Boxes) + --------------------------------------------------------------------*/ + + +USHORT FlatFndBox::GetColCount(const _FndBox& rBox) +{ + const _FndLines& rLines = rBox.GetLines(); + // Ueber Lines iterieren + if( !rLines.Count() ) + return 1; + + USHORT nSum = 0; + for( USHORT i=0; i < rLines.Count(); ++i ) + { + // Die Boxen einer Line + USHORT nCount = 0; + const _FndBoxes& rBoxes = rLines[i]->GetBoxes(); + for( USHORT j=0; j < rBoxes.Count(); ++j ) + // Rekursiv wirder ueber die Lines Iterieren + nCount += rBoxes[j]->GetLines().Count() + ? GetColCount(*rBoxes[j]) : 1; + + if( nSum < nCount ) + nSum = nCount; + } + return nSum; +} + +/*-------------------------------------------------------------------- + Beschreibung: max Anzahl der Zeilen (Lines) + --------------------------------------------------------------------*/ + + +USHORT FlatFndBox::GetRowCount(const _FndBox& rBox) +{ + const _FndLines& rLines = rBox.GetLines(); + if( !rLines.Count() ) + return 1; + + USHORT nLines = 0; + for(USHORT i=0; i < rLines.Count(); ++i) + { // Die Boxen einer Line + const _FndBoxes& rBoxes = rLines[i]->GetBoxes(); + USHORT nLn = 1; + for(USHORT j=0; j < rBoxes.Count(); ++j) + if( rBoxes[j]->GetLines().Count() ) + // Rekursiv ueber die Lines Iterieren + nLn = Max(GetRowCount(*rBoxes[j]), nLn); + + nLines += nLn; + } + return nLines; +} + +/*-------------------------------------------------------------------- + Beschreibung: lineares Array aus atomaren FndBoxes erzeugen + --------------------------------------------------------------------*/ + + +void FlatFndBox::FillFlat(const _FndBox& rBox, BOOL bLastBox) +{ + BOOL bModRow = FALSE; + const _FndLines& rLines = rBox.GetLines(); + + // Ueber Lines iterieren + USHORT nOldRow = nRow; + for( USHORT i=0; i < rLines.Count(); ++i ) + { + // Die Boxen einer Line + const _FndBoxes& rBoxes = rLines[i]->GetBoxes(); + USHORT nOldCol = nCol; + for( USHORT j = 0; j < rBoxes.Count(); ++j ) + { + // Die Box pruefen ob es eine atomare Box ist + const _FndBox* pBox = rBoxes[ j ]; + + if( !pBox->GetLines().Count() ) + { + // peichern + USHORT nOff = nRow * nCols + nCol; + *(pArr + nOff) = pBox; + + // sicher die Formel/Format/Value Werte + const SwFrmFmt* pFmt = pBox->GetBox()->GetFrmFmt(); + if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMAT ) || + SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA ) || + SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE ) ) + { + SfxItemSet* pSet = new SfxItemSet( pDoc->GetAttrPool(), + RES_BOXATR_FORMAT, RES_BOXATR_VALUE, + RES_VERT_ORIENT, RES_VERT_ORIENT, 0 ); + pSet->Put( pFmt->GetAttrSet() ); + if( !ppItemSets ) + { + ppItemSets = new SfxItemSet*[ nRows * nCols ]; + memset( ppItemSets, 0, sizeof(SfxItemSet*) * nRows * nCols ); + } + *(ppItemSets + nOff ) = pSet; + } + + bModRow = TRUE; + } + else + { + // Rekursiv wieder ueber die Lines einer Box Iterieren + FillFlat( *pBox, ( j == rBoxes.Count()-1 ) ); + } + nCol++; + } + if(bModRow) + nRow++; + nCol = nOldCol; + } + if(!bLastBox) + nRow = nOldRow; +} + +/*-------------------------------------------------------------------- + Beschreibung: Zugriff auf eine bestimmte Zelle + --------------------------------------------------------------------*/ + + +const _FndBox* FlatFndBox::GetBox(USHORT nCol, USHORT nRow) const +{ + USHORT nOff = nRow * nCols + nCol; + const _FndBox* pTmp = *(pArr + nOff); + + ASSERT(nCol < nCols && nRow < nRows && pTmp, "unzulaessiger Array-Zugriff"); + return pTmp; +} + +const SfxItemSet* FlatFndBox::GetItemSet(USHORT nCol, USHORT nRow) const +{ + ASSERT( !ppItemSets || ( nCol < nCols && nRow < nRows), "unzulaessiger Array-Zugriff"); + + return ppItemSets ? *(ppItemSets + (nRow * nCols + nCol )) : 0; +} + + |