merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / doc / docsort.cxx
blob5414b7286932132e500fa6ac5ae0aec510ebe512
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: docsort.cxx,v $
10 * $Revision: 1.20 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
33 #include <hintids.hxx>
34 #include <rtl/math.hxx>
35 #include <unotools/collatorwrapper.hxx>
36 #include <unotools/localedatawrapper.hxx>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/i18n/CollatorOptions.hpp>
39 #include <comphelper/processfactory.hxx>
40 #include <svx/unolingu.hxx>
41 #include <docary.hxx>
42 #include <fmtanchr.hxx>
43 #include <frmfmt.hxx>
44 #include <doc.hxx>
45 #include <node.hxx>
46 #include <pam.hxx>
47 #include <ndtxt.hxx>
48 #include <swtable.hxx>
49 #include <swundo.hxx>
50 #include <sortopt.hxx>
51 #ifndef _DOCSORT_HXX
52 #include <docsort.hxx>
53 #endif
54 #include <undobj.hxx>
55 #include <tblsel.hxx>
56 #include <cellatr.hxx>
57 #include <redline.hxx>
58 #include <node2lay.hxx>
59 #include <unochart.hxx>
61 #if OSL_DEBUG_LEVEL > 1
62 //nur zum debugen
63 #include <cellatr.hxx>
64 #endif
66 using namespace ::com::sun::star::lang;
68 SwSortOptions* SwSortElement::pOptions = 0;
69 SwDoc* SwSortElement::pDoc = 0;
70 const FlatFndBox* SwSortElement::pBox = 0;
71 CollatorWrapper* SwSortElement::pSortCollator = 0;
72 Locale* SwSortElement::pLocale = 0;
73 String* SwSortElement::pLastAlgorithm = 0;
74 LocaleDataWrapper* SwSortElement::pLclData = 0;
76 SV_IMPL_OP_PTRARR_SORT( SwSortElements, SwSortElementPtr );
79 /*--------------------------------------------------------------------
80 Beschreibung: Ein Sortierelement fuers Sort konstruieren
81 --------------------------------------------------------------------*/
84 void SwSortElement::Init( SwDoc* pD, const SwSortOptions& rOpt,
85 FlatFndBox* pFltBx )
87 ASSERT( !pDoc && !pOptions && !pBox, "wer hat das Finit vergessen?" );
88 pDoc = pD;
89 pOptions = new SwSortOptions( rOpt );
90 pBox = pFltBx;
92 LanguageType nLang = rOpt.nLanguage;
93 switch ( nLang )
95 case LANGUAGE_NONE:
96 case LANGUAGE_DONTKNOW:
97 nLang = (LanguageType)GetAppLanguage();
98 break;
100 pLocale = new Locale( SvxCreateLocale( nLang ) );
102 pSortCollator = new CollatorWrapper(
103 ::comphelper::getProcessServiceFactory() );
104 // pSortCollator->loadCollatorAlgorithm( sAlgorithm, aLocale,
105 // rOpt.bIgnoreCase ? SW_COLLATOR_IGNORES : 0 );
109 void SwSortElement::Finit()
111 delete pOptions, pOptions = 0;
112 delete pLocale, pLocale = 0;
113 delete pLastAlgorithm, pLastAlgorithm = 0;
114 delete pSortCollator, pSortCollator = 0;
115 delete pLclData, pLclData = 0;
116 pDoc = 0;
117 pBox = 0;
121 SwSortElement::~SwSortElement()
126 double SwSortElement::StrToDouble( const String& rStr ) const
128 if( !pLclData )
129 pLclData = new LocaleDataWrapper(
130 ::comphelper::getProcessServiceFactory(), *pLocale );
132 rtl_math_ConversionStatus eStatus;
133 sal_Int32 nEnd;
134 double nRet = ::rtl::math::stringToDouble( rStr,
135 pLclData->getNumDecimalSep().GetChar(0),
136 pLclData->getNumThousandSep().GetChar(0),
137 &eStatus, &nEnd );
139 if( rtl_math_ConversionStatus_Ok != eStatus || nEnd == 0 )
140 nRet = 0.0;
141 return nRet;
144 /*--------------------------------------------------------------------
145 Beschreibung: Operatoren zum Vergleichen
146 --------------------------------------------------------------------*/
149 BOOL SwSortElement::operator==(const SwSortElement& )
151 return FALSE;
154 /*--------------------------------------------------------------------
155 Beschreibung: Kleiner-Operator fuers sortieren
156 --------------------------------------------------------------------*/
158 BOOL SwSortElement::operator<(const SwSortElement& rCmp)
161 // der eigentliche Vergleich
163 for(USHORT nKey = 0; nKey < pOptions->aKeys.Count(); ++nKey)
165 const SwSortElement *pOrig, *pCmp;
167 const SwSortKey* pSrtKey = pOptions->aKeys[ nKey ];
168 if( pSrtKey->eSortOrder == SRT_ASCENDING )
169 pOrig = this, pCmp = &rCmp;
170 else
171 pOrig = &rCmp, pCmp = this;
173 if( pSrtKey->bIsNumeric )
175 double n1 = pOrig->GetValue( nKey );
176 double n2 = pCmp->GetValue( nKey );
178 if( n1 == n2 )
179 continue;
181 return n1 < n2;
183 else
185 if( !pLastAlgorithm || *pLastAlgorithm != pSrtKey->sSortType )
187 if( pLastAlgorithm )
188 *pLastAlgorithm = pSrtKey->sSortType;
189 else
190 pLastAlgorithm = new String( pSrtKey->sSortType );
191 pSortCollator->loadCollatorAlgorithm( *pLastAlgorithm,
192 *pLocale,
193 pOptions->bIgnoreCase ? SW_COLLATOR_IGNORES : 0 );
196 sal_Int32 nCmp = pSortCollator->compareString(
197 pOrig->GetKey( nKey ), pCmp->GetKey( nKey ));
198 if( 0 == nCmp )
199 continue;
201 return -1 == nCmp;
204 return FALSE;
207 double SwSortElement::GetValue( USHORT nKey ) const
209 return StrToDouble( GetKey( nKey ));
212 /*--------------------------------------------------------------------
213 Beschreibung: SortierElemente fuer Text
214 --------------------------------------------------------------------*/
217 SwSortTxtElement::SwSortTxtElement(const SwNodeIndex& rPos)
218 : nOrg(rPos.GetIndex()), aPos(rPos)
223 SwSortTxtElement::~SwSortTxtElement()
228 /*--------------------------------------------------------------------
229 Beschreibung: Key ermitteln
230 --------------------------------------------------------------------*/
233 String SwSortTxtElement::GetKey(USHORT nId) const
235 SwTxtNode* pTxtNd = aPos.GetNode().GetTxtNode();
236 if( !pTxtNd )
237 return aEmptyStr;
239 // fuer TextNodes
240 const String& rStr = pTxtNd->GetTxt();
242 sal_Unicode nDeli = pOptions->cDeli;
243 USHORT nDCount = pOptions->aKeys[nId]->nColumnId, i = 1;
244 xub_StrLen nStart = 0;
246 // Den Delimitter suchen
247 while( nStart != STRING_NOTFOUND && i < nDCount)
248 if( STRING_NOTFOUND != ( nStart = rStr.Search( nDeli, nStart ) ) )
250 nStart++;
251 i++;
254 // naechsten Delimitter gefunden oder Ende des Strings und Kopieren
255 xub_StrLen nEnd = rStr.Search( nDeli, nStart+1 );
256 return rStr.Copy( nStart, nEnd-nStart );
260 /*--------------------------------------------------------------------
261 Beschreibung: Sortier-Elemente fuer Tabellen
262 --------------------------------------------------------------------*/
264 SwSortBoxElement::SwSortBoxElement( USHORT nRC )
265 : nRow( nRC )
270 SwSortBoxElement::~SwSortBoxElement()
274 /*--------------------------------------------------------------------
275 Beschreibung: Schluessel zu einer Zelle ermitteln
276 --------------------------------------------------------------------*/
279 String SwSortBoxElement::GetKey(USHORT nKey) const
281 const _FndBox* pFndBox;
282 USHORT nCol = pOptions->aKeys[nKey]->nColumnId-1;
284 if( SRT_ROWS == pOptions->eDirection )
285 pFndBox = pBox->GetBox(nCol, nRow); // Zeilen sortieren
286 else
287 pFndBox = pBox->GetBox(nRow, nCol); // Spalten sortieren
289 // Den Text rausfieseln
290 String aRetStr;
291 if( pFndBox )
292 { // StartNode holen und ueberlesen
293 const SwTableBox* pMyBox = pFndBox->GetBox();
294 ASSERT(pMyBox, "Keine atomare Box");
296 if( pMyBox->GetSttNd() )
298 // ueber alle TextNodes der Box
299 const SwNode *pNd = 0, *pEndNd = pMyBox->GetSttNd()->EndOfSectionNode();
300 for( ULONG nIdx = pMyBox->GetSttIdx() + 1; pNd != pEndNd; ++nIdx )
301 if( ( pNd = pDoc->GetNodes()[ nIdx ])->IsTxtNode() )
302 aRetStr += ((SwTxtNode*)pNd)->GetTxt();
305 return aRetStr;
308 double SwSortBoxElement::GetValue( USHORT nKey ) const
310 const _FndBox* pFndBox;
311 USHORT nCol = pOptions->aKeys[nKey]->nColumnId-1;
313 if( SRT_ROWS == pOptions->eDirection )
314 pFndBox = pBox->GetBox(nCol, nRow); // Zeilen sortieren
315 else
316 pFndBox = pBox->GetBox(nRow, nCol); // Spalten sortieren
318 double nVal;
319 if( pFndBox )
321 const SwFmt *pFmt = pFndBox->GetBox()->GetFrmFmt();
322 if (pFmt->GetTblBoxNumFmt().GetValue() & NUMBERFORMAT_TEXT)
323 nVal = SwSortElement::GetValue( nKey );
324 else
325 nVal = pFmt->GetTblBoxValue().GetValue();
327 else
328 nVal = 0;
330 return nVal;
333 /*--------------------------------------------------------------------
334 Beschreibung: Text sortieren im Document
335 --------------------------------------------------------------------*/
338 BOOL SwDoc::SortText(const SwPaM& rPaM, const SwSortOptions& rOpt)
340 // pruefen ob Rahmen im Text
341 const SwPosition *pStart = rPaM.Start(), *pEnd = rPaM.End();
342 // Index auf den Start der Selektion
344 SwFrmFmt* pFmt;
345 const SwFmtAnchor* pAnchor;
346 const SwPosition* pAPos;
347 USHORT n;
349 for( n = 0; n < GetSpzFrmFmts()->Count(); ++n )
351 pFmt = (SwFrmFmt*)(*GetSpzFrmFmts())[n];
352 pAnchor = &pFmt->GetAnchor();
354 if( FLY_AT_CNTNT == pAnchor->GetAnchorId() &&
355 0 != (pAPos = pAnchor->GetCntntAnchor() ) &&
356 pStart->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode )
357 return FALSE;
360 // pruefe ob nur TextNodes in der Selection liegen
362 ULONG nStart = pStart->nNode.GetIndex(),
363 nEnd = pEnd->nNode.GetIndex();
364 while( nStart <= nEnd )
365 // Iterieren ueber einen selektierten Bereich
366 if( !GetNodes()[ nStart++ ]->IsTxtNode() )
367 return FALSE;
370 BOOL bUndo = DoesUndo();
371 if( bUndo )
372 StartUndo( UNDO_START, NULL );
374 SwPaM* pRedlPam = 0;
375 SwUndoRedlineSort* pRedlUndo = 0;
376 SwUndoSort* pUndoSort = 0;
378 if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() ))
380 pRedlPam = new SwPaM( pStart->nNode, pEnd->nNode, -1, 1 );
381 SwCntntNode* pCNd = pRedlPam->GetCntntNode( FALSE );
382 if( pCNd )
383 pRedlPam->GetMark()->nContent = pCNd->Len();
385 if( IsRedlineOn() && !IsShowOriginal( GetRedlineMode() ) )
387 if( bUndo )
389 pRedlUndo = new SwUndoRedlineSort( rPaM, rOpt );
390 DoUndo( FALSE );
392 // erst den Bereich kopieren, dann
393 SwNodeIndex aEndIdx( pEnd->nNode, 1 );
394 SwNodeRange aRg( pStart->nNode, aEndIdx );
395 GetNodes()._Copy( aRg, aEndIdx );
397 // Bereich neu ist von pEnd->nNode+1 bis aEndIdx
398 DeleteRedline( *pRedlPam, true, USHRT_MAX );
400 pRedlPam->GetMark()->nNode.Assign( pEnd->nNode.GetNode(), 1 );
401 pCNd = pRedlPam->GetCntntNode( FALSE );
402 pRedlPam->GetMark()->nContent.Assign( pCNd, 0 );
404 pRedlPam->GetPoint()->nNode.Assign( aEndIdx.GetNode() );
405 pCNd = pRedlPam->GetCntntNode( TRUE );
406 xub_StrLen nCLen = 0;
407 if( !pCNd &&
408 0 != (pCNd = GetNodes()[ aEndIdx.GetIndex()-1 ]->GetCntntNode()))
410 nCLen = pCNd->Len();
411 pRedlPam->GetPoint()->nNode.Assign( *pCNd );
413 pRedlPam->GetPoint()->nContent.Assign( pCNd, nCLen );
415 if( pRedlUndo )
416 pRedlUndo->SetValues( rPaM );
418 else
420 DeleteRedline( *pRedlPam, true, USHRT_MAX );
421 delete pRedlPam, pRedlPam = 0;
425 SwNodeIndex aStart(pStart->nNode);
426 SwSortElement::Init( this, rOpt );
427 SwSortElements aSortArr;
428 while( aStart <= pEnd->nNode )
430 // Iterieren ueber einen selektierten Bereich
431 SwSortTxtElement* pSE = new SwSortTxtElement( aStart );
432 aSortArr.Insert(pSE);
433 aStart++;
436 // Und jetzt der Akt: Verschieben von Nodes und immer schoen auf UNDO
437 // achten
439 ULONG nBeg = pStart->nNode.GetIndex();
440 SwNodeRange aRg( aStart, aStart );
442 if( bUndo && !pRedlUndo )
443 AppendUndo( pUndoSort = new SwUndoSort( rPaM, rOpt ) );
445 DoUndo( FALSE );
447 for( n = 0; n < aSortArr.Count(); ++n )
449 SwSortTxtElement* pBox = (SwSortTxtElement*)aSortArr[n];
450 aStart = nBeg + n;
451 aRg.aStart = pBox->aPos.GetIndex();
452 aRg.aEnd = aRg.aStart.GetIndex() + 1;
454 // Nodes verschieben
455 MoveNodeRange( aRg, aStart,
456 IDocumentContentOperations::DOC_MOVEDEFAULT );
458 // Undo Verschiebungen einpflegen
459 if(pUndoSort)
460 pUndoSort->Insert(pBox->nOrg, nBeg + n);
462 // Alle Elemente aus dem SortArray loeschen
463 aSortArr.DeleteAndDestroy(0, aSortArr.Count());
464 SwSortElement::Finit();
466 if( pRedlPam )
468 if( pRedlUndo )
470 pRedlUndo->SetSaveRange( *pRedlPam );
471 AppendUndo( pRedlUndo );
474 // nBeg ist der Start vom sortierten Bereich
475 SwNodeIndex aSttIdx( GetNodes(), nBeg );
477 // der Kopierte Bereich ist das Geloeschte
478 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_DELETE, *pRedlPam ), true);
480 // das sortierte ist das Eingefuegte
481 pRedlPam->GetPoint()->nNode = aSttIdx;
482 SwCntntNode* pCNd = aSttIdx.GetNode().GetCntntNode();
483 pRedlPam->GetPoint()->nContent.Assign( pCNd, 0 );
485 AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, *pRedlPam ), true);
487 if( pRedlUndo )
488 pRedlUndo->SetOffset( aSttIdx );
490 delete pRedlPam, pRedlPam = 0;
492 DoUndo( bUndo );
493 if( bUndo )
494 EndUndo( UNDO_END, NULL );
496 return TRUE;
499 /*--------------------------------------------------------------------
500 Beschreibung: Tabelle sortieren im Document
501 --------------------------------------------------------------------*/
503 BOOL SwDoc::SortTbl(const SwSelBoxes& rBoxes, const SwSortOptions& rOpt)
505 // uebers SwDoc fuer Undo !!
506 ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
507 SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
508 if( !pTblNd )
509 return FALSE;
511 // Auf gehts sortieren
512 // suche alle Boxen / Lines
513 _FndBox aFndBox( 0, 0 );
515 _FndPara aPara( rBoxes, &aFndBox );
516 pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );;
519 if(!aFndBox.GetLines().Count())
520 return FALSE;
522 if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
523 DeleteRedline( *pTblNd, true, USHRT_MAX );
525 USHORT nStart = 0;
526 if( pTblNd->GetTable().GetRowsToRepeat() > 0 && rOpt.eDirection == SRT_ROWS )
528 // Oberste seleketierte Zeile
529 _FndLines& rLines = aFndBox.GetLines();
531 while( nStart < rLines.Count() )
533 // Verschachtelung durch Split Merge beachten,
534 // die oberste rausholen
535 SwTableLine* pLine = rLines[nStart]->GetLine();
536 while ( pLine->GetUpper() )
537 pLine = pLine->GetUpper()->GetUpper();
539 if( pTblNd->GetTable().IsHeadline( *pLine ) )
540 nStart++;
541 else
542 break;
544 // Alle selektierten in der HeaderLine ? -> kein Offset
545 if( nStart == rLines.Count() )
546 nStart = 0;
549 // umschalten auf relative Formeln
550 SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
551 aMsgHnt.eFlags = TBL_RELBOXNAME;
552 UpdateTblFlds( &aMsgHnt );
554 // Tabelle als flache Array-Struktur
555 FlatFndBox aFlatBox(this, aFndBox);
557 if(!aFlatBox.IsSymmetric())
558 return FALSE;
560 // MIB 9.7.97: HTML-Layout loeschen
561 pTblNd->GetTable().SetHTMLTableLayout( 0 );
563 // --> FME 2004-11-26 #i37739# A simple 'MakeFrms' after the node sorting
564 // does not work if the table is inside a frame and has no prev/next.
565 SwNode2Layout aNode2Layout( *pTblNd );
566 // <--
568 // loesche die Frames der Tabelle
569 pTblNd->DelFrms();
570 // ? TL_CHART2: ?
572 // Redo loeschen bevor Undo
573 BOOL bUndo = DoesUndo();
574 SwUndoSort* pUndoSort = 0;
575 if(bUndo)
577 ClearRedo();
578 pUndoSort = new SwUndoSort( rBoxes[0]->GetSttIdx(),
579 rBoxes[rBoxes.Count()-1]->GetSttIdx(),
580 *pTblNd, rOpt, aFlatBox.HasItemSets() );
581 AppendUndo(pUndoSort);
582 DoUndo(FALSE);
585 // SchluesselElemente einsortieren
586 USHORT nCount = (rOpt.eDirection == SRT_ROWS) ?
587 aFlatBox.GetRows() : aFlatBox.GetCols();
589 // SortList nach Schluessel sortieren
590 SwSortElement::Init( this, rOpt, &aFlatBox );
591 SwSortElements aSortList;
593 // wenn die HeaderLine wiederholt wird und die
594 // Zeilen sortiert werden 1.Zeile nicht mitsortieren
595 USHORT i;
597 for( i = nStart; i < nCount; ++i)
599 SwSortBoxElement* pEle = new SwSortBoxElement( i );
600 aSortList.Insert(pEle);
603 // nach Sortierung verschieben
604 SwMovedBoxes aMovedList;
605 for(i=0; i < aSortList.Count(); ++i)
607 SwSortBoxElement* pBox = (SwSortBoxElement*)aSortList[i];
608 if(rOpt.eDirection == SRT_ROWS)
609 MoveRow(this, aFlatBox, pBox->nRow, i + nStart, aMovedList, pUndoSort);
610 else
611 MoveCol(this, aFlatBox, pBox->nRow, i + nStart, aMovedList, pUndoSort);
614 // Restore table frames:
615 // --> FME 2004-11-26 #i37739# A simple 'MakeFrms' after the node sorting
616 // does not work if the table is inside a frame and has no prev/next.
617 const ULONG nIdx = pTblNd->GetIndex();
618 aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
619 // <--
621 // TL_CHART2: need to inform chart of probably changed cell names
622 UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() );
624 // Alle Elemente aus dem SortArray loeschen
625 aSortList.DeleteAndDestroy( 0, aSortList.Count() );
626 SwSortElement::Finit();
628 // Undo wieder aktivieren
629 DoUndo(bUndo);
631 SetModified();
632 return TRUE;
635 /*--------------------------------------------------------------------
636 Beschreibung: Zeilenweise verschieben
637 --------------------------------------------------------------------*/
640 void MoveRow(SwDoc* pDoc, const FlatFndBox& rBox, USHORT nS, USHORT nT,
641 SwMovedBoxes& rMovedList, SwUndoSort* pUD)
643 for( USHORT i=0; i < rBox.GetCols(); ++i )
644 { // Alte Zellen-Pos bestimmen und merken
645 const _FndBox* pSource = rBox.GetBox(i, nS);
647 // neue Zellen-Pos
648 const _FndBox* pTarget = rBox.GetBox(i, nT);
650 const SwTableBox* pT = pTarget->GetBox();
651 const SwTableBox* pS = pSource->GetBox();
653 BOOL bMoved = rMovedList.GetPos(pT) != USHRT_MAX;
655 // und verschieben
656 MoveCell(pDoc, pS, pT, bMoved, pUD);
658 rMovedList.Insert(pS, rMovedList.Count() );
660 if( pS != pT )
662 SwFrmFmt* pTFmt = (SwFrmFmt*)pT->GetFrmFmt();
663 const SfxItemSet* pSSet = rBox.GetItemSet( i, nS );
665 if( pSSet ||
666 SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMAT ) ||
667 SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMULA ) ||
668 SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_VALUE ) )
670 pTFmt = ((SwTableBox*)pT)->ClaimFrmFmt();
671 pTFmt->LockModify();
672 if( pTFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ) )
673 pTFmt->ResetFmtAttr( RES_VERT_ORIENT );
675 if( pSSet )
676 pTFmt->SetFmtAttr( *pSSet );
677 pTFmt->UnlockModify();
683 /*--------------------------------------------------------------------
684 Beschreibung: Spaltenweise verschieben
685 --------------------------------------------------------------------*/
688 void MoveCol(SwDoc* pDoc, const FlatFndBox& rBox, USHORT nS, USHORT nT,
689 SwMovedBoxes& rMovedList, SwUndoSort* pUD)
691 for(USHORT i=0; i < rBox.GetRows(); ++i)
692 { // Alte Zellen-Pos bestimmen und merken
693 const _FndBox* pSource = rBox.GetBox(nS, i);
695 // neue Zellen-Pos
696 const _FndBox* pTarget = rBox.GetBox(nT, i);
698 // und verschieben
699 const SwTableBox* pT = pTarget->GetBox();
700 const SwTableBox* pS = pSource->GetBox();
702 // und verschieben
703 BOOL bMoved = rMovedList.GetPos(pT) != USHRT_MAX;
704 MoveCell(pDoc, pS, pT, bMoved, pUD);
706 rMovedList.Insert(pS, rMovedList.Count() );
708 if( pS != pT )
710 SwFrmFmt* pTFmt = (SwFrmFmt*)pT->GetFrmFmt();
711 const SfxItemSet* pSSet = rBox.GetItemSet( nS, i );
713 if( pSSet ||
714 SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMAT ) ||
715 SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMULA ) ||
716 SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_VALUE ) )
718 pTFmt = ((SwTableBox*)pT)->ClaimFrmFmt();
719 pTFmt->LockModify();
720 if( pTFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ) )
721 pTFmt->ResetFmtAttr( RES_VERT_ORIENT );
723 if( pSSet )
724 pTFmt->SetFmtAttr( *pSSet );
725 pTFmt->UnlockModify();
731 /*--------------------------------------------------------------------
732 Beschreibung: Eine einzelne Zelle verschieben
733 --------------------------------------------------------------------*/
736 void MoveCell(SwDoc* pDoc, const SwTableBox* pSource, const SwTableBox* pTar,
737 BOOL bMovedBefore, SwUndoSort* pUD)
739 ASSERT(pSource && pTar,"Fehlende Quelle oder Ziel");
741 if(pSource == pTar)
742 return;
744 if(pUD)
745 pUD->Insert( pSource->GetName(), pTar->GetName() );
747 // Pam Quelle auf den ersten ContentNode setzen
748 SwNodeRange aRg( *pSource->GetSttNd(), 0, *pSource->GetSttNd() );
749 SwNode* pNd = pDoc->GetNodes().GoNext( &aRg.aStart );
751 // wurde die Zelle (Source) nicht verschoben
752 // -> einen Leer-Node einfuegen und den Rest verschieben
753 // ansonsten steht der Mark auf dem ersten Content-Node
754 if( pNd->StartOfSectionNode() == pSource->GetSttNd() )
755 pNd = pDoc->GetNodes().MakeTxtNode( aRg.aStart,
756 (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
757 aRg.aEnd = *pNd->EndOfSectionNode();
759 // Ist das Ziel leer(1 leerer Node vorhanden)
760 // -> diesen loeschen und move
761 // Ziel
762 SwNodeIndex aTar( *pTar->GetSttNd() );
763 pNd = pDoc->GetNodes().GoNext( &aTar ); // naechsten ContentNode
764 ULONG nCount = pNd->EndOfSectionIndex() - pNd->StartOfSectionIndex();
766 BOOL bDelFirst = FALSE;
767 if( nCount == 2 )
769 ASSERT( pNd->GetCntntNode(), "Kein ContentNode");
770 bDelFirst = !pNd->GetCntntNode()->Len() && bMovedBefore;
773 if(!bDelFirst)
774 { // Es besteht schon Inhalt -> alter I n h a l t Section Down
775 SwNodeRange aRgTar( aTar.GetNode(), 0, *pNd->EndOfSectionNode() );
776 pDoc->GetNodes().SectionDown( &aRgTar );
779 // Einfuegen der Source
780 SwNodeIndex aIns( *pTar->GetSttNd()->EndOfSectionNode() );
781 pDoc->MoveNodeRange( aRg, aIns,
782 IDocumentContentOperations::DOC_MOVEDEFAULT );
784 // Falls erster Node leer -> weg damit
785 if(bDelFirst)
786 pDoc->GetNodes().Delete( aTar, 1 );
789 /*--------------------------------------------------------------------
790 Beschreibung: Zweidimensionales Array aus FndBoxes generieren
791 --------------------------------------------------------------------*/
794 FlatFndBox::FlatFndBox(SwDoc* pDocPtr, const _FndBox& rBox) :
795 pDoc(pDocPtr),
796 rBoxRef(rBox),
797 pArr(0),
798 ppItemSets(0),
799 nRow(0),
800 nCol(0)
801 { // Ist das Array symmetrisch
802 if((bSym = CheckLineSymmetry(rBoxRef)) != 0)
804 // Spalten/Reihen-Anzahl ermitteln
805 nCols = GetColCount(rBoxRef);
806 nRows = GetRowCount(rBoxRef);
808 // lineares Array anlegen
809 pArr = new _FndBoxPtr[ nRows * nCols ];
810 _FndBox** ppTmp = (_FndBox**)pArr;
811 memset( ppTmp, 0, sizeof(_FndBoxPtr) * nRows * nCols );
814 FillFlat( rBoxRef );
819 FlatFndBox::~FlatFndBox()
821 _FndBox** ppTmp = (_FndBox**)pArr;
822 delete [] ppTmp;
824 if( ppItemSets )
825 delete [] ppItemSets;
828 /*--------------------------------------------------------------------
829 Beschreibung: Alle Lines einer Box muessen gleichviel Boxen haben
830 --------------------------------------------------------------------*/
833 BOOL FlatFndBox::CheckLineSymmetry(const _FndBox& rBox)
835 const _FndLines &rLines = rBox.GetLines();
836 USHORT nBoxes(0);
838 // UeberLines iterieren
839 for(USHORT i=0; i < rLines.Count(); ++i)
840 { // Die Boxen einer Line
841 _FndLine* pLn = rLines[i];
842 const _FndBoxes& rBoxes = pLn->GetBoxes();
844 // Anzahl der Boxen aller Lines ungleich -> keine Symmetrie
845 if( i && nBoxes != rBoxes.Count())
846 return FALSE;
848 nBoxes = rBoxes.Count();
849 if( !CheckBoxSymmetry( *pLn ) )
850 return FALSE;
852 return TRUE;
855 /*--------------------------------------------------------------------
856 Beschreibung: Box auf Symmetrie pruefen
857 Alle Boxen einer Line muessen gleichviele Lines haben
858 --------------------------------------------------------------------*/
861 BOOL FlatFndBox::CheckBoxSymmetry(const _FndLine& rLn)
863 const _FndBoxes &rBoxes = rLn.GetBoxes();
864 USHORT nLines(0);
866 // Ueber Boxes iterieren
867 for(USHORT i=0; i < rBoxes.Count(); ++i)
868 { // Die Boxen einer Line
869 _FndBox* pBox = rBoxes[i];
870 const _FndLines& rLines = pBox->GetLines();
872 // Anzahl der Boxen aller Lines ungleich -> keine Symmetrie
873 if( i && nLines != rLines.Count() )
874 return FALSE;
876 nLines = rLines.Count();
877 if( nLines && !CheckLineSymmetry( *pBox ) )
878 return FALSE;
880 return TRUE;
883 /*--------------------------------------------------------------------
884 Beschreibung: max Anzahl der Spalten (Boxes)
885 --------------------------------------------------------------------*/
888 USHORT FlatFndBox::GetColCount(const _FndBox& rBox)
890 const _FndLines& rLines = rBox.GetLines();
891 // Ueber Lines iterieren
892 if( !rLines.Count() )
893 return 1;
895 USHORT nSum = 0;
896 for( USHORT i=0; i < rLines.Count(); ++i )
898 // Die Boxen einer Line
899 USHORT nCount = 0;
900 const _FndBoxes& rBoxes = rLines[i]->GetBoxes();
901 for( USHORT j=0; j < rBoxes.Count(); ++j )
902 // Rekursiv wirder ueber die Lines Iterieren
903 nCount += rBoxes[j]->GetLines().Count()
904 ? GetColCount(*rBoxes[j]) : 1;
906 if( nSum < nCount )
907 nSum = nCount;
909 return nSum;
912 /*--------------------------------------------------------------------
913 Beschreibung: max Anzahl der Zeilen (Lines)
914 --------------------------------------------------------------------*/
917 USHORT FlatFndBox::GetRowCount(const _FndBox& rBox)
919 const _FndLines& rLines = rBox.GetLines();
920 if( !rLines.Count() )
921 return 1;
923 USHORT nLines = 0;
924 for(USHORT i=0; i < rLines.Count(); ++i)
925 { // Die Boxen einer Line
926 const _FndBoxes& rBoxes = rLines[i]->GetBoxes();
927 USHORT nLn = 1;
928 for(USHORT j=0; j < rBoxes.Count(); ++j)
929 if( rBoxes[j]->GetLines().Count() )
930 // Rekursiv ueber die Lines Iterieren
931 nLn = Max(GetRowCount(*rBoxes[j]), nLn);
933 nLines = nLines + nLn;
935 return nLines;
938 /*--------------------------------------------------------------------
939 Beschreibung: lineares Array aus atomaren FndBoxes erzeugen
940 --------------------------------------------------------------------*/
943 void FlatFndBox::FillFlat(const _FndBox& rBox, BOOL bLastBox)
945 BOOL bModRow = FALSE;
946 const _FndLines& rLines = rBox.GetLines();
948 // Ueber Lines iterieren
949 USHORT nOldRow = nRow;
950 for( USHORT i=0; i < rLines.Count(); ++i )
952 // Die Boxen einer Line
953 const _FndBoxes& rBoxes = rLines[i]->GetBoxes();
954 USHORT nOldCol = nCol;
955 for( USHORT j = 0; j < rBoxes.Count(); ++j )
957 // Die Box pruefen ob es eine atomare Box ist
958 const _FndBox* pBox = rBoxes[ j ];
960 if( !pBox->GetLines().Count() )
962 // peichern
963 USHORT nOff = nRow * nCols + nCol;
964 *(pArr + nOff) = pBox;
966 // sicher die Formel/Format/Value Werte
967 const SwFrmFmt* pFmt = pBox->GetBox()->GetFrmFmt();
968 if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMAT ) ||
969 SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA ) ||
970 SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE ) )
972 SfxItemSet* pSet = new SfxItemSet( pDoc->GetAttrPool(),
973 RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
974 RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
975 pSet->Put( pFmt->GetAttrSet() );
976 if( !ppItemSets )
978 ppItemSets = new SfxItemSet*[ nRows * nCols ];
979 memset( ppItemSets, 0, sizeof(SfxItemSet*) * nRows * nCols );
981 *(ppItemSets + nOff ) = pSet;
984 bModRow = TRUE;
986 else
988 // Rekursiv wieder ueber die Lines einer Box Iterieren
989 FillFlat( *pBox, ( j == rBoxes.Count()-1 ) );
991 nCol++;
993 if(bModRow)
994 nRow++;
995 nCol = nOldCol;
997 if(!bLastBox)
998 nRow = nOldRow;
1001 /*--------------------------------------------------------------------
1002 Beschreibung: Zugriff auf eine bestimmte Zelle
1003 --------------------------------------------------------------------*/
1006 const _FndBox* FlatFndBox::GetBox(USHORT n_Col, USHORT n_Row) const
1008 USHORT nOff = n_Row * nCols + n_Col;
1009 const _FndBox* pTmp = *(pArr + nOff);
1011 ASSERT(n_Col < nCols && n_Row < nRows && pTmp, "unzulaessiger Array-Zugriff");
1012 return pTmp;
1015 const SfxItemSet* FlatFndBox::GetItemSet(USHORT n_Col, USHORT n_Row) const
1017 ASSERT( !ppItemSets || ( n_Col < nCols && n_Row < nRows), "unzulaessiger Array-Zugriff");
1019 return ppItemSets ? *(ppItemSets + (n_Row * nCols + n_Col )) : 0;