1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: docsort.cxx,v $
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>
42 #include <fmtanchr.hxx>
48 #include <swtable.hxx>
50 #include <sortopt.hxx>
52 #include <docsort.hxx>
56 #include <cellatr.hxx>
57 #include <redline.hxx>
58 #include <node2lay.hxx>
59 #include <unochart.hxx>
61 #if OSL_DEBUG_LEVEL > 1
63 #include <cellatr.hxx>
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
,
87 ASSERT( !pDoc
&& !pOptions
&& !pBox
, "wer hat das Finit vergessen?" );
89 pOptions
= new SwSortOptions( rOpt
);
92 LanguageType nLang
= rOpt
.nLanguage
;
96 case LANGUAGE_DONTKNOW
:
97 nLang
= (LanguageType
)GetAppLanguage();
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;
121 SwSortElement::~SwSortElement()
126 double SwSortElement::StrToDouble( const String
& rStr
) const
129 pLclData
= new LocaleDataWrapper(
130 ::comphelper::getProcessServiceFactory(), *pLocale
);
132 rtl_math_ConversionStatus eStatus
;
134 double nRet
= ::rtl::math::stringToDouble( rStr
,
135 pLclData
->getNumDecimalSep().GetChar(0),
136 pLclData
->getNumThousandSep().GetChar(0),
139 if( rtl_math_ConversionStatus_Ok
!= eStatus
|| nEnd
== 0 )
144 /*--------------------------------------------------------------------
145 Beschreibung: Operatoren zum Vergleichen
146 --------------------------------------------------------------------*/
149 BOOL
SwSortElement::operator==(const SwSortElement
& )
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
;
171 pOrig
= &rCmp
, pCmp
= this;
173 if( pSrtKey
->bIsNumeric
)
175 double n1
= pOrig
->GetValue( nKey
);
176 double n2
= pCmp
->GetValue( nKey
);
185 if( !pLastAlgorithm
|| *pLastAlgorithm
!= pSrtKey
->sSortType
)
188 *pLastAlgorithm
= pSrtKey
->sSortType
;
190 pLastAlgorithm
= new String( pSrtKey
->sSortType
);
191 pSortCollator
->loadCollatorAlgorithm( *pLastAlgorithm
,
193 pOptions
->bIgnoreCase
? SW_COLLATOR_IGNORES
: 0 );
196 sal_Int32 nCmp
= pSortCollator
->compareString(
197 pOrig
->GetKey( nKey
), pCmp
->GetKey( nKey
));
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();
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
) ) )
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
)
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
287 pFndBox
= pBox
->GetBox(nRow
, nCol
); // Spalten sortieren
289 // Den Text rausfieseln
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();
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
316 pFndBox
= pBox
->GetBox(nRow
, nCol
); // Spalten sortieren
321 const SwFmt
*pFmt
= pFndBox
->GetBox()->GetFrmFmt();
322 if (pFmt
->GetTblBoxNumFmt().GetValue() & NUMBERFORMAT_TEXT
)
323 nVal
= SwSortElement::GetValue( nKey
);
325 nVal
= pFmt
->GetTblBoxValue().GetValue();
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
345 const SwFmtAnchor
* pAnchor
;
346 const SwPosition
* pAPos
;
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
)
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() )
370 BOOL bUndo
= DoesUndo();
372 StartUndo( UNDO_START
, NULL
);
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
);
383 pRedlPam
->GetMark()->nContent
= pCNd
->Len();
385 if( IsRedlineOn() && !IsShowOriginal( GetRedlineMode() ) )
389 pRedlUndo
= new SwUndoRedlineSort( rPaM
, rOpt
);
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;
408 0 != (pCNd
= GetNodes()[ aEndIdx
.GetIndex()-1 ]->GetCntntNode()))
411 pRedlPam
->GetPoint()->nNode
.Assign( *pCNd
);
413 pRedlPam
->GetPoint()->nContent
.Assign( pCNd
, nCLen
);
416 pRedlUndo
->SetValues( rPaM
);
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
);
436 // Und jetzt der Akt: Verschieben von Nodes und immer schoen auf UNDO
439 ULONG nBeg
= pStart
->nNode
.GetIndex();
440 SwNodeRange
aRg( aStart
, aStart
);
442 if( bUndo
&& !pRedlUndo
)
443 AppendUndo( pUndoSort
= new SwUndoSort( rPaM
, rOpt
) );
447 for( n
= 0; n
< aSortArr
.Count(); ++n
)
449 SwSortTxtElement
* pBox
= (SwSortTxtElement
*)aSortArr
[n
];
451 aRg
.aStart
= pBox
->aPos
.GetIndex();
452 aRg
.aEnd
= aRg
.aStart
.GetIndex() + 1;
455 MoveNodeRange( aRg
, aStart
,
456 IDocumentContentOperations::DOC_MOVEDEFAULT
);
458 // Undo Verschiebungen einpflegen
460 pUndoSort
->Insert(pBox
->nOrg
, nBeg
+ n
);
462 // Alle Elemente aus dem SortArray loeschen
463 aSortArr
.DeleteAndDestroy(0, aSortArr
.Count());
464 SwSortElement::Finit();
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);
488 pRedlUndo
->SetOffset( aSttIdx
);
490 delete pRedlPam
, pRedlPam
= 0;
494 EndUndo( UNDO_END
, NULL
);
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();
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())
522 if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
523 DeleteRedline( *pTblNd
, true, USHRT_MAX
);
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
) )
544 // Alle selektierten in der HeaderLine ? -> kein Offset
545 if( nStart
== rLines
.Count() )
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())
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
);
568 // loesche die Frames der Tabelle
572 // Redo loeschen bevor Undo
573 BOOL bUndo
= DoesUndo();
574 SwUndoSort
* pUndoSort
= 0;
578 pUndoSort
= new SwUndoSort( rBoxes
[0]->GetSttIdx(),
579 rBoxes
[rBoxes
.Count()-1]->GetSttIdx(),
580 *pTblNd
, rOpt
, aFlatBox
.HasItemSets() );
581 AppendUndo(pUndoSort
);
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
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
);
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 );
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
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
);
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
;
656 MoveCell(pDoc
, pS
, pT
, bMoved
, pUD
);
658 rMovedList
.Insert(pS
, rMovedList
.Count() );
662 SwFrmFmt
* pTFmt
= (SwFrmFmt
*)pT
->GetFrmFmt();
663 const SfxItemSet
* pSSet
= rBox
.GetItemSet( i
, nS
);
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();
672 if( pTFmt
->ResetFmtAttr( RES_BOXATR_FORMAT
, RES_BOXATR_VALUE
) )
673 pTFmt
->ResetFmtAttr( RES_VERT_ORIENT
);
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
);
696 const _FndBox
* pTarget
= rBox
.GetBox(nT
, i
);
699 const SwTableBox
* pT
= pTarget
->GetBox();
700 const SwTableBox
* pS
= pSource
->GetBox();
703 BOOL bMoved
= rMovedList
.GetPos(pT
) != USHRT_MAX
;
704 MoveCell(pDoc
, pS
, pT
, bMoved
, pUD
);
706 rMovedList
.Insert(pS
, rMovedList
.Count() );
710 SwFrmFmt
* pTFmt
= (SwFrmFmt
*)pT
->GetFrmFmt();
711 const SfxItemSet
* pSSet
= rBox
.GetItemSet( nS
, i
);
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();
720 if( pTFmt
->ResetFmtAttr( RES_BOXATR_FORMAT
, RES_BOXATR_VALUE
) )
721 pTFmt
->ResetFmtAttr( RES_VERT_ORIENT
);
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");
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
762 SwNodeIndex
aTar( *pTar
->GetSttNd() );
763 pNd
= pDoc
->GetNodes().GoNext( &aTar
); // naechsten ContentNode
764 ULONG nCount
= pNd
->EndOfSectionIndex() - pNd
->StartOfSectionIndex();
766 BOOL bDelFirst
= FALSE
;
769 ASSERT( pNd
->GetCntntNode(), "Kein ContentNode");
770 bDelFirst
= !pNd
->GetCntntNode()->Len() && bMovedBefore
;
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
786 pDoc
->GetNodes().Delete( aTar
, 1 );
789 /*--------------------------------------------------------------------
790 Beschreibung: Zweidimensionales Array aus FndBoxes generieren
791 --------------------------------------------------------------------*/
794 FlatFndBox::FlatFndBox(SwDoc
* pDocPtr
, const _FndBox
& rBox
) :
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
);
819 FlatFndBox::~FlatFndBox()
821 _FndBox
** ppTmp
= (_FndBox
**)pArr
;
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();
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())
848 nBoxes
= rBoxes
.Count();
849 if( !CheckBoxSymmetry( *pLn
) )
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();
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() )
876 nLines
= rLines
.Count();
877 if( nLines
&& !CheckLineSymmetry( *pBox
) )
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() )
896 for( USHORT i
=0; i
< rLines
.Count(); ++i
)
898 // Die Boxen einer Line
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;
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() )
924 for(USHORT i
=0; i
< rLines
.Count(); ++i
)
925 { // Die Boxen einer Line
926 const _FndBoxes
& rBoxes
= rLines
[i
]->GetBoxes();
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
;
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() )
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() );
978 ppItemSets
= new SfxItemSet
*[ nRows
* nCols
];
979 memset( ppItemSets
, 0, sizeof(SfxItemSet
*) * nRows
* nCols
);
981 *(ppItemSets
+ nOff
) = pSet
;
988 // Rekursiv wieder ueber die Lines einer Box Iterieren
989 FillFlat( *pBox
, ( j
== rBoxes
.Count()-1 ) );
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");
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;