xref: /aoo41x/main/sw/source/core/doc/docsort.cxx (revision efeef26f)
1*efeef26fSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*efeef26fSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*efeef26fSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*efeef26fSAndrew Rist  * distributed with this work for additional information
6*efeef26fSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*efeef26fSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*efeef26fSAndrew Rist  * "License"); you may not use this file except in compliance
9*efeef26fSAndrew Rist  * with the License.  You may obtain a copy of the License at
10*efeef26fSAndrew Rist  *
11*efeef26fSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*efeef26fSAndrew Rist  *
13*efeef26fSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*efeef26fSAndrew Rist  * software distributed under the License is distributed on an
15*efeef26fSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*efeef26fSAndrew Rist  * KIND, either express or implied.  See the License for the
17*efeef26fSAndrew Rist  * specific language governing permissions and limitations
18*efeef26fSAndrew Rist  * under the License.
19*efeef26fSAndrew Rist  *
20*efeef26fSAndrew Rist  *************************************************************/
21*efeef26fSAndrew Rist 
22*efeef26fSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sw.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <hintids.hxx>
28cdf0e10cSrcweir #include <rtl/math.hxx>
29cdf0e10cSrcweir #include <unotools/collatorwrapper.hxx>
30cdf0e10cSrcweir #include <unotools/localedatawrapper.hxx>
31cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32cdf0e10cSrcweir #include <com/sun/star/i18n/CollatorOptions.hpp>
33cdf0e10cSrcweir #include <comphelper/processfactory.hxx>
34cdf0e10cSrcweir #include <editeng/unolingu.hxx>
35cdf0e10cSrcweir #include <docary.hxx>
36cdf0e10cSrcweir #include <fmtanchr.hxx>
37cdf0e10cSrcweir #include <frmfmt.hxx>
38cdf0e10cSrcweir #include <doc.hxx>
39cdf0e10cSrcweir #include <IDocumentUndoRedo.hxx>
40cdf0e10cSrcweir #include <node.hxx>
41cdf0e10cSrcweir #include <pam.hxx>
42cdf0e10cSrcweir #include <ndtxt.hxx>
43cdf0e10cSrcweir #include <swtable.hxx>
44cdf0e10cSrcweir #include <swundo.hxx>
45cdf0e10cSrcweir #include <sortopt.hxx>
46cdf0e10cSrcweir #include <docsort.hxx>
47cdf0e10cSrcweir #include <UndoSort.hxx>
48cdf0e10cSrcweir #include <UndoRedline.hxx>
49cdf0e10cSrcweir #include <hints.hxx>
50cdf0e10cSrcweir #include <tblsel.hxx>
51cdf0e10cSrcweir #include <cellatr.hxx>
52cdf0e10cSrcweir #include <redline.hxx>
53cdf0e10cSrcweir #include <node2lay.hxx>
54cdf0e10cSrcweir #include <unochart.hxx>
55cdf0e10cSrcweir 
56cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1
57cdf0e10cSrcweir //nur zum debugen
58cdf0e10cSrcweir #include <cellatr.hxx>
59cdf0e10cSrcweir #endif
60cdf0e10cSrcweir 
61cdf0e10cSrcweir using namespace ::com::sun::star::lang;
62cdf0e10cSrcweir 
63cdf0e10cSrcweir SwSortOptions*		SwSortElement::pOptions = 0;
64cdf0e10cSrcweir SwDoc* 				SwSortElement::pDoc = 0;
65cdf0e10cSrcweir const FlatFndBox*	SwSortElement::pBox = 0;
66cdf0e10cSrcweir CollatorWrapper* 	SwSortElement::pSortCollator = 0;
67cdf0e10cSrcweir Locale* 			SwSortElement::pLocale = 0;
68cdf0e10cSrcweir String* 			SwSortElement::pLastAlgorithm = 0;
69cdf0e10cSrcweir LocaleDataWrapper* 	SwSortElement::pLclData = 0;
70cdf0e10cSrcweir 
71cdf0e10cSrcweir SV_IMPL_OP_PTRARR_SORT( SwSortElements, SwSortElementPtr );
72cdf0e10cSrcweir 
73cdf0e10cSrcweir 
74cdf0e10cSrcweir /*--------------------------------------------------------------------
75cdf0e10cSrcweir 	Beschreibung: Ein Sortierelement fuers Sort konstruieren
76cdf0e10cSrcweir  --------------------------------------------------------------------*/
77cdf0e10cSrcweir 
78cdf0e10cSrcweir 
Init(SwDoc * pD,const SwSortOptions & rOpt,FlatFndBox * pFltBx)79cdf0e10cSrcweir void SwSortElement::Init( SwDoc* pD, const SwSortOptions& rOpt,
80cdf0e10cSrcweir 							FlatFndBox* pFltBx )
81cdf0e10cSrcweir {
82cdf0e10cSrcweir 	ASSERT( !pDoc && !pOptions && !pBox, "wer hat das Finit vergessen?" );
83cdf0e10cSrcweir 	pDoc = pD;
84cdf0e10cSrcweir 	pOptions = new SwSortOptions( rOpt );
85cdf0e10cSrcweir 	pBox = pFltBx;
86cdf0e10cSrcweir 
87cdf0e10cSrcweir 	LanguageType nLang = rOpt.nLanguage;
88cdf0e10cSrcweir 	switch ( nLang )
89cdf0e10cSrcweir 	{
90cdf0e10cSrcweir 	case LANGUAGE_NONE:
91cdf0e10cSrcweir 	case LANGUAGE_DONTKNOW:
92cdf0e10cSrcweir 		nLang = (LanguageType)GetAppLanguage();
93cdf0e10cSrcweir 		break;
94cdf0e10cSrcweir 	}
95cdf0e10cSrcweir 	pLocale = new Locale( SvxCreateLocale( nLang ) );
96cdf0e10cSrcweir 
97cdf0e10cSrcweir 	pSortCollator = new CollatorWrapper(
98cdf0e10cSrcweir 								::comphelper::getProcessServiceFactory() );
99cdf0e10cSrcweir //	pSortCollator->loadCollatorAlgorithm( sAlgorithm, aLocale,
100cdf0e10cSrcweir //						rOpt.bIgnoreCase ? SW_COLLATOR_IGNORES : 0 );
101cdf0e10cSrcweir }
102cdf0e10cSrcweir 
103cdf0e10cSrcweir 
Finit()104cdf0e10cSrcweir void SwSortElement::Finit()
105cdf0e10cSrcweir {
106cdf0e10cSrcweir 	delete pOptions, pOptions = 0;
107cdf0e10cSrcweir 	delete pLocale, pLocale = 0;
108cdf0e10cSrcweir 	delete pLastAlgorithm, pLastAlgorithm = 0;
109cdf0e10cSrcweir 	delete pSortCollator, pSortCollator = 0;
110cdf0e10cSrcweir 	delete pLclData, pLclData = 0;
111cdf0e10cSrcweir 	pDoc = 0;
112cdf0e10cSrcweir 	pBox = 0;
113cdf0e10cSrcweir }
114cdf0e10cSrcweir 
115cdf0e10cSrcweir 
~SwSortElement()116cdf0e10cSrcweir SwSortElement::~SwSortElement()
117cdf0e10cSrcweir {
118cdf0e10cSrcweir }
119cdf0e10cSrcweir 
120cdf0e10cSrcweir 
StrToDouble(const String & rStr) const121cdf0e10cSrcweir double SwSortElement::StrToDouble( const String& rStr ) const
122cdf0e10cSrcweir {
123cdf0e10cSrcweir 	if( !pLclData )
124cdf0e10cSrcweir 		pLclData = new LocaleDataWrapper(
125cdf0e10cSrcweir 					::comphelper::getProcessServiceFactory(), *pLocale );
126cdf0e10cSrcweir 
127cdf0e10cSrcweir     rtl_math_ConversionStatus eStatus;
128cdf0e10cSrcweir     sal_Int32 nEnd;
129cdf0e10cSrcweir 	double nRet = ::rtl::math::stringToDouble( rStr,
130cdf0e10cSrcweir 									pLclData->getNumDecimalSep().GetChar(0),
131cdf0e10cSrcweir 									pLclData->getNumThousandSep().GetChar(0),
132cdf0e10cSrcweir 									&eStatus, &nEnd );
133cdf0e10cSrcweir 
134cdf0e10cSrcweir 	if( rtl_math_ConversionStatus_Ok != eStatus || nEnd == 0 )
135cdf0e10cSrcweir 		nRet = 0.0;
136cdf0e10cSrcweir 	return nRet;
137cdf0e10cSrcweir }
138cdf0e10cSrcweir 
139cdf0e10cSrcweir /*--------------------------------------------------------------------
140cdf0e10cSrcweir 	Beschreibung: Operatoren zum Vergleichen
141cdf0e10cSrcweir  --------------------------------------------------------------------*/
142cdf0e10cSrcweir 
143cdf0e10cSrcweir 
operator ==(const SwSortElement &)144cdf0e10cSrcweir sal_Bool SwSortElement::operator==(const SwSortElement& )
145cdf0e10cSrcweir {
146cdf0e10cSrcweir 	return sal_False;
147cdf0e10cSrcweir }
148cdf0e10cSrcweir 
149cdf0e10cSrcweir /*--------------------------------------------------------------------
150cdf0e10cSrcweir 	Beschreibung: Kleiner-Operator fuers sortieren
151cdf0e10cSrcweir  --------------------------------------------------------------------*/
152cdf0e10cSrcweir 
operator <(const SwSortElement & rCmp)153cdf0e10cSrcweir sal_Bool SwSortElement::operator<(const SwSortElement& rCmp)
154cdf0e10cSrcweir {
155cdf0e10cSrcweir 
156cdf0e10cSrcweir 	// der eigentliche Vergleich
157cdf0e10cSrcweir 	//
158cdf0e10cSrcweir 	for(sal_uInt16 nKey = 0; nKey < pOptions->aKeys.Count(); ++nKey)
159cdf0e10cSrcweir 	{
160cdf0e10cSrcweir 		const SwSortElement *pOrig, *pCmp;
161cdf0e10cSrcweir 
162cdf0e10cSrcweir 		const SwSortKey* pSrtKey = pOptions->aKeys[ nKey ];
163cdf0e10cSrcweir 		if( pSrtKey->eSortOrder == SRT_ASCENDING )
164cdf0e10cSrcweir 			pOrig = this, pCmp = &rCmp;
165cdf0e10cSrcweir 		else
166cdf0e10cSrcweir 			pOrig = &rCmp, pCmp = this;
167cdf0e10cSrcweir 
168cdf0e10cSrcweir 		if( pSrtKey->bIsNumeric )
169cdf0e10cSrcweir 		{
170cdf0e10cSrcweir 			double n1 = pOrig->GetValue( nKey );
171cdf0e10cSrcweir 			double n2 = pCmp->GetValue( nKey );
172cdf0e10cSrcweir 
173cdf0e10cSrcweir 			if( n1 == n2 )
174cdf0e10cSrcweir 				continue;
175cdf0e10cSrcweir 
176cdf0e10cSrcweir 			return n1 < n2;
177cdf0e10cSrcweir 		}
178cdf0e10cSrcweir 		else
179cdf0e10cSrcweir 		{
180cdf0e10cSrcweir 			if( !pLastAlgorithm || *pLastAlgorithm != pSrtKey->sSortType )
181cdf0e10cSrcweir 			{
182cdf0e10cSrcweir 				if( pLastAlgorithm )
183cdf0e10cSrcweir 					*pLastAlgorithm = pSrtKey->sSortType;
184cdf0e10cSrcweir 				else
185cdf0e10cSrcweir 					pLastAlgorithm = new String( pSrtKey->sSortType );
186cdf0e10cSrcweir 				pSortCollator->loadCollatorAlgorithm( *pLastAlgorithm,
187cdf0e10cSrcweir 						*pLocale,
188cdf0e10cSrcweir 						pOptions->bIgnoreCase ? SW_COLLATOR_IGNORES : 0 );
189cdf0e10cSrcweir 			}
190cdf0e10cSrcweir 
191cdf0e10cSrcweir 			sal_Int32 nCmp = pSortCollator->compareString(
192cdf0e10cSrcweir 						pOrig->GetKey( nKey ), pCmp->GetKey( nKey ));
193cdf0e10cSrcweir 			if( 0 == nCmp )
194cdf0e10cSrcweir 				continue;
195cdf0e10cSrcweir 
196cdf0e10cSrcweir 			return -1 == nCmp;
197cdf0e10cSrcweir 		}
198cdf0e10cSrcweir 	}
199cdf0e10cSrcweir 	return sal_False;
200cdf0e10cSrcweir }
201cdf0e10cSrcweir 
GetValue(sal_uInt16 nKey) const202cdf0e10cSrcweir double SwSortElement::GetValue( sal_uInt16 nKey ) const
203cdf0e10cSrcweir {
204cdf0e10cSrcweir 	return StrToDouble( GetKey( nKey ));
205cdf0e10cSrcweir }
206cdf0e10cSrcweir 
207cdf0e10cSrcweir /*--------------------------------------------------------------------
208cdf0e10cSrcweir 	Beschreibung: SortierElemente fuer Text
209cdf0e10cSrcweir  --------------------------------------------------------------------*/
210cdf0e10cSrcweir 
211cdf0e10cSrcweir 
SwSortTxtElement(const SwNodeIndex & rPos)212cdf0e10cSrcweir SwSortTxtElement::SwSortTxtElement(const SwNodeIndex& rPos)
213cdf0e10cSrcweir 	: nOrg(rPos.GetIndex()), aPos(rPos)
214cdf0e10cSrcweir {
215cdf0e10cSrcweir }
216cdf0e10cSrcweir 
217cdf0e10cSrcweir 
~SwSortTxtElement()218cdf0e10cSrcweir SwSortTxtElement::~SwSortTxtElement()
219cdf0e10cSrcweir {
220cdf0e10cSrcweir }
221cdf0e10cSrcweir 
222cdf0e10cSrcweir 
223cdf0e10cSrcweir /*--------------------------------------------------------------------
224cdf0e10cSrcweir 	Beschreibung: Key ermitteln
225cdf0e10cSrcweir  --------------------------------------------------------------------*/
226cdf0e10cSrcweir 
227cdf0e10cSrcweir 
GetKey(sal_uInt16 nId) const228cdf0e10cSrcweir String SwSortTxtElement::GetKey(sal_uInt16 nId) const
229cdf0e10cSrcweir {
230cdf0e10cSrcweir 	SwTxtNode* pTxtNd = aPos.GetNode().GetTxtNode();
231cdf0e10cSrcweir 	if( !pTxtNd )
232cdf0e10cSrcweir 		return aEmptyStr;
233cdf0e10cSrcweir 
234cdf0e10cSrcweir 	// fuer TextNodes
235cdf0e10cSrcweir 	const String& rStr = pTxtNd->GetTxt();
236cdf0e10cSrcweir 
237cdf0e10cSrcweir 	sal_Unicode nDeli = pOptions->cDeli;
238cdf0e10cSrcweir 	sal_uInt16 nDCount = pOptions->aKeys[nId]->nColumnId, i = 1;
239cdf0e10cSrcweir 	xub_StrLen nStart = 0;
240cdf0e10cSrcweir 
241cdf0e10cSrcweir 	// Den Delimitter suchen
242cdf0e10cSrcweir 	while( nStart != STRING_NOTFOUND && i < nDCount)
243cdf0e10cSrcweir 		if( STRING_NOTFOUND != ( nStart = rStr.Search( nDeli, nStart ) ) )
244cdf0e10cSrcweir 		{
245cdf0e10cSrcweir 			nStart++;
246cdf0e10cSrcweir 			i++;
247cdf0e10cSrcweir 		}
248cdf0e10cSrcweir 
249cdf0e10cSrcweir 	// naechsten Delimitter gefunden oder Ende des Strings und Kopieren
250cdf0e10cSrcweir 	xub_StrLen nEnd = rStr.Search( nDeli, nStart+1 );
251cdf0e10cSrcweir 	return rStr.Copy( nStart, nEnd-nStart );
252cdf0e10cSrcweir }
253cdf0e10cSrcweir 
254cdf0e10cSrcweir 
255cdf0e10cSrcweir /*--------------------------------------------------------------------
256cdf0e10cSrcweir 	Beschreibung: Sortier-Elemente fuer Tabellen
257cdf0e10cSrcweir  --------------------------------------------------------------------*/
258cdf0e10cSrcweir 
SwSortBoxElement(sal_uInt16 nRC)259cdf0e10cSrcweir SwSortBoxElement::SwSortBoxElement( sal_uInt16 nRC )
260cdf0e10cSrcweir 	: nRow( nRC )
261cdf0e10cSrcweir {
262cdf0e10cSrcweir }
263cdf0e10cSrcweir 
264cdf0e10cSrcweir 
~SwSortBoxElement()265cdf0e10cSrcweir SwSortBoxElement::~SwSortBoxElement()
266cdf0e10cSrcweir {
267cdf0e10cSrcweir }
268cdf0e10cSrcweir 
269cdf0e10cSrcweir /*--------------------------------------------------------------------
270cdf0e10cSrcweir 	Beschreibung: Schluessel zu einer Zelle ermitteln
271cdf0e10cSrcweir  --------------------------------------------------------------------*/
272cdf0e10cSrcweir 
273cdf0e10cSrcweir 
GetKey(sal_uInt16 nKey) const274cdf0e10cSrcweir String SwSortBoxElement::GetKey(sal_uInt16 nKey) const
275cdf0e10cSrcweir {
276cdf0e10cSrcweir 	const _FndBox* pFndBox;
277cdf0e10cSrcweir 	sal_uInt16 nCol = pOptions->aKeys[nKey]->nColumnId-1;
278cdf0e10cSrcweir 
279cdf0e10cSrcweir 	if( SRT_ROWS == pOptions->eDirection )
280cdf0e10cSrcweir 		pFndBox = pBox->GetBox(nCol, nRow);			// Zeilen sortieren
281cdf0e10cSrcweir 	else
282cdf0e10cSrcweir 		pFndBox = pBox->GetBox(nRow, nCol);			// Spalten sortieren
283cdf0e10cSrcweir 
284cdf0e10cSrcweir 	// Den Text rausfieseln
285cdf0e10cSrcweir 	String aRetStr;
286cdf0e10cSrcweir 	if( pFndBox )
287cdf0e10cSrcweir 	{	// StartNode holen und ueberlesen
288cdf0e10cSrcweir 		const SwTableBox* pMyBox = pFndBox->GetBox();
289cdf0e10cSrcweir 		ASSERT(pMyBox, "Keine atomare Box");
290cdf0e10cSrcweir 
291cdf0e10cSrcweir 		if( pMyBox->GetSttNd() )
292cdf0e10cSrcweir 		{
293cdf0e10cSrcweir 			// ueber alle TextNodes der Box
294cdf0e10cSrcweir 			const SwNode *pNd = 0, *pEndNd = pMyBox->GetSttNd()->EndOfSectionNode();
295cdf0e10cSrcweir 			for( sal_uLong nIdx = pMyBox->GetSttIdx() + 1; pNd != pEndNd; ++nIdx )
296cdf0e10cSrcweir 				if( ( pNd = pDoc->GetNodes()[ nIdx ])->IsTxtNode() )
297cdf0e10cSrcweir 					aRetStr += ((SwTxtNode*)pNd)->GetTxt();
298cdf0e10cSrcweir 		}
299cdf0e10cSrcweir 	}
300cdf0e10cSrcweir 	return aRetStr;
301cdf0e10cSrcweir }
302cdf0e10cSrcweir 
GetValue(sal_uInt16 nKey) const303cdf0e10cSrcweir double SwSortBoxElement::GetValue( sal_uInt16 nKey ) const
304cdf0e10cSrcweir {
305cdf0e10cSrcweir 	const _FndBox* pFndBox;
306cdf0e10cSrcweir 	sal_uInt16 nCol = pOptions->aKeys[nKey]->nColumnId-1;
307cdf0e10cSrcweir 
308cdf0e10cSrcweir 	if( SRT_ROWS == pOptions->eDirection )
309cdf0e10cSrcweir 		pFndBox = pBox->GetBox(nCol, nRow);			// Zeilen sortieren
310cdf0e10cSrcweir 	else
311cdf0e10cSrcweir 		pFndBox = pBox->GetBox(nRow, nCol);			// Spalten sortieren
312cdf0e10cSrcweir 
313cdf0e10cSrcweir     double nVal;
314cdf0e10cSrcweir     if( pFndBox )
315cdf0e10cSrcweir     {
316cdf0e10cSrcweir         const SwFmt *pFmt = pFndBox->GetBox()->GetFrmFmt();
317cdf0e10cSrcweir         if (pFmt->GetTblBoxNumFmt().GetValue() & NUMBERFORMAT_TEXT)
318cdf0e10cSrcweir             nVal = SwSortElement::GetValue( nKey );
319cdf0e10cSrcweir         else
320cdf0e10cSrcweir             nVal = pFmt->GetTblBoxValue().GetValue();
321cdf0e10cSrcweir     }
322cdf0e10cSrcweir     else
323cdf0e10cSrcweir         nVal = 0;
324cdf0e10cSrcweir 
325cdf0e10cSrcweir     return nVal;
326cdf0e10cSrcweir }
327cdf0e10cSrcweir 
328cdf0e10cSrcweir /*--------------------------------------------------------------------
329cdf0e10cSrcweir 	Beschreibung: Text sortieren im Document
330cdf0e10cSrcweir  --------------------------------------------------------------------*/
331cdf0e10cSrcweir 
332cdf0e10cSrcweir 
SortText(const SwPaM & rPaM,const SwSortOptions & rOpt)333cdf0e10cSrcweir sal_Bool SwDoc::SortText(const SwPaM& rPaM, const SwSortOptions& rOpt)
334cdf0e10cSrcweir {
335cdf0e10cSrcweir 	// pruefen ob Rahmen im Text
336cdf0e10cSrcweir 	const SwPosition *pStart = rPaM.Start(), *pEnd = rPaM.End();
337cdf0e10cSrcweir 	// Index auf den Start der Selektion
338cdf0e10cSrcweir 
339cdf0e10cSrcweir     for ( sal_uInt16 n = 0; n < GetSpzFrmFmts()->Count(); ++n )
340cdf0e10cSrcweir     {
341cdf0e10cSrcweir         SwFrmFmt *const pFmt = static_cast<SwFrmFmt*>((*GetSpzFrmFmts())[n]);
342cdf0e10cSrcweir         SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
343cdf0e10cSrcweir         SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
344cdf0e10cSrcweir 
345cdf0e10cSrcweir         if (pAPos && (FLY_AT_PARA == pAnchor->GetAnchorId()) &&
346cdf0e10cSrcweir 			pStart->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode )
347cdf0e10cSrcweir 			return sal_False;
348cdf0e10cSrcweir 	}
349cdf0e10cSrcweir 
350cdf0e10cSrcweir 	// pruefe ob nur TextNodes in der Selection liegen
351cdf0e10cSrcweir 	{
352cdf0e10cSrcweir 		sal_uLong nStart = pStart->nNode.GetIndex(),
353cdf0e10cSrcweir 						nEnd = pEnd->nNode.GetIndex();
354cdf0e10cSrcweir 		while( nStart <= nEnd )
355cdf0e10cSrcweir 			// Iterieren ueber einen selektierten Bereich
356cdf0e10cSrcweir 			if( !GetNodes()[ nStart++ ]->IsTxtNode() )
357cdf0e10cSrcweir 				return sal_False;
358cdf0e10cSrcweir 	}
359cdf0e10cSrcweir 
360cdf0e10cSrcweir     bool const bUndo = GetIDocumentUndoRedo().DoesUndo();
361cdf0e10cSrcweir 	if( bUndo )
362cdf0e10cSrcweir     {
363cdf0e10cSrcweir         GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL );
364cdf0e10cSrcweir     }
365cdf0e10cSrcweir 
366cdf0e10cSrcweir 	SwPaM* pRedlPam = 0;
367cdf0e10cSrcweir 	SwUndoRedlineSort* pRedlUndo = 0;
368cdf0e10cSrcweir 	SwUndoSort* pUndoSort = 0;
369cdf0e10cSrcweir 
370cdf0e10cSrcweir 	if( IsRedlineOn() || (!IsIgnoreRedline() && pRedlineTbl->Count() ))
371cdf0e10cSrcweir 	{
372cdf0e10cSrcweir 		pRedlPam = new SwPaM( pStart->nNode, pEnd->nNode, -1, 1 );
373cdf0e10cSrcweir 		SwCntntNode* pCNd = pRedlPam->GetCntntNode( sal_False );
374cdf0e10cSrcweir 		if( pCNd )
375cdf0e10cSrcweir 			pRedlPam->GetMark()->nContent = pCNd->Len();
376cdf0e10cSrcweir 
377cdf0e10cSrcweir 		if( IsRedlineOn() && !IsShowOriginal( GetRedlineMode() ) )
378cdf0e10cSrcweir 		{
379cdf0e10cSrcweir 			if( bUndo )
380cdf0e10cSrcweir 			{
381cdf0e10cSrcweir 				pRedlUndo = new SwUndoRedlineSort( *pRedlPam,rOpt );
382cdf0e10cSrcweir                 GetIDocumentUndoRedo().DoUndo(false);
383cdf0e10cSrcweir             }
384cdf0e10cSrcweir 			// erst den Bereich kopieren, dann
385cdf0e10cSrcweir 			SwNodeIndex aEndIdx( pEnd->nNode, 1 );
386cdf0e10cSrcweir 			SwNodeRange aRg( pStart->nNode, aEndIdx );
387cdf0e10cSrcweir 			GetNodes()._Copy( aRg, aEndIdx );
388cdf0e10cSrcweir 
389cdf0e10cSrcweir 			// Bereich neu ist von pEnd->nNode+1 bis aEndIdx
390cdf0e10cSrcweir 			DeleteRedline( *pRedlPam, true, USHRT_MAX );
391cdf0e10cSrcweir 
392cdf0e10cSrcweir 			pRedlPam->GetMark()->nNode.Assign( pEnd->nNode.GetNode(), 1 );
393cdf0e10cSrcweir 			pCNd = pRedlPam->GetCntntNode( sal_False );
394cdf0e10cSrcweir 			pRedlPam->GetMark()->nContent.Assign( pCNd, 0 );
395cdf0e10cSrcweir 
396cdf0e10cSrcweir 			pRedlPam->GetPoint()->nNode.Assign( aEndIdx.GetNode() );
397cdf0e10cSrcweir 			pCNd = pRedlPam->GetCntntNode( sal_True );
398cdf0e10cSrcweir 			xub_StrLen nCLen = 0;
399cdf0e10cSrcweir 			if( !pCNd &&
400cdf0e10cSrcweir 				0 != (pCNd = GetNodes()[ aEndIdx.GetIndex()-1 ]->GetCntntNode()))
401cdf0e10cSrcweir 			{
402cdf0e10cSrcweir 				nCLen = pCNd->Len();
403cdf0e10cSrcweir 				pRedlPam->GetPoint()->nNode.Assign( *pCNd );
404cdf0e10cSrcweir 			}
405cdf0e10cSrcweir 			pRedlPam->GetPoint()->nContent.Assign( pCNd, nCLen );
406cdf0e10cSrcweir 
407cdf0e10cSrcweir 			if( pRedlUndo )
408cdf0e10cSrcweir 				pRedlUndo->SetValues( rPaM );
409cdf0e10cSrcweir 		}
410cdf0e10cSrcweir 		else
411cdf0e10cSrcweir 		{
412cdf0e10cSrcweir 			DeleteRedline( *pRedlPam, true, USHRT_MAX );
413cdf0e10cSrcweir 			delete pRedlPam, pRedlPam = 0;
414cdf0e10cSrcweir 		}
415cdf0e10cSrcweir 	}
416cdf0e10cSrcweir 
417cdf0e10cSrcweir 	SwNodeIndex aStart(pStart->nNode);
418cdf0e10cSrcweir 	SwSortElement::Init( this, rOpt );
419cdf0e10cSrcweir 	SwSortElements aSortArr;
420cdf0e10cSrcweir 	while( aStart <= pEnd->nNode )
421cdf0e10cSrcweir 	{
422cdf0e10cSrcweir 		// Iterieren ueber einen selektierten Bereich
423cdf0e10cSrcweir 		SwSortTxtElement* pSE = new SwSortTxtElement( aStart );
424cdf0e10cSrcweir 		aSortArr.Insert(pSE);
425cdf0e10cSrcweir 		aStart++;
426cdf0e10cSrcweir 	}
427cdf0e10cSrcweir 
428cdf0e10cSrcweir 	// Und jetzt der Akt: Verschieben von Nodes und immer schoen auf UNDO
429cdf0e10cSrcweir 	// achten
430cdf0e10cSrcweir 	//
431cdf0e10cSrcweir 	sal_uLong nBeg = pStart->nNode.GetIndex();
432cdf0e10cSrcweir 	SwNodeRange aRg( aStart, aStart );
433cdf0e10cSrcweir 
434cdf0e10cSrcweir 	if( bUndo && !pRedlUndo )
435cdf0e10cSrcweir     {
436cdf0e10cSrcweir         pUndoSort = new SwUndoSort(rPaM, rOpt);
437cdf0e10cSrcweir         GetIDocumentUndoRedo().AppendUndo(pUndoSort);
438cdf0e10cSrcweir     }
439cdf0e10cSrcweir 
440cdf0e10cSrcweir     GetIDocumentUndoRedo().DoUndo(false);
441cdf0e10cSrcweir 
442cdf0e10cSrcweir     for ( sal_uInt16 n = 0; n < aSortArr.Count(); ++n )
443cdf0e10cSrcweir     {
444cdf0e10cSrcweir 		SwSortTxtElement* pBox = (SwSortTxtElement*)aSortArr[n];
445cdf0e10cSrcweir 		aStart 		= nBeg + n;
446cdf0e10cSrcweir 		aRg.aStart 	= pBox->aPos.GetIndex();
447cdf0e10cSrcweir 		aRg.aEnd 	= aRg.aStart.GetIndex() + 1;
448cdf0e10cSrcweir 
449cdf0e10cSrcweir 		// Nodes verschieben
450cdf0e10cSrcweir         MoveNodeRange( aRg, aStart,
451cdf0e10cSrcweir             IDocumentContentOperations::DOC_MOVEDEFAULT );
452cdf0e10cSrcweir 
453cdf0e10cSrcweir 		// Undo Verschiebungen einpflegen
454cdf0e10cSrcweir 		if(pUndoSort)
455cdf0e10cSrcweir 			pUndoSort->Insert(pBox->nOrg, nBeg + n);
456cdf0e10cSrcweir 	}
457cdf0e10cSrcweir 	// Alle Elemente aus dem SortArray loeschen
458cdf0e10cSrcweir 	aSortArr.DeleteAndDestroy(0, aSortArr.Count());
459cdf0e10cSrcweir 	SwSortElement::Finit();
460cdf0e10cSrcweir 
461cdf0e10cSrcweir 	if( pRedlPam )
462cdf0e10cSrcweir 	{
463cdf0e10cSrcweir 		if( pRedlUndo )
464cdf0e10cSrcweir 		{
465cdf0e10cSrcweir 			pRedlUndo->SetSaveRange( *pRedlPam );
466cdf0e10cSrcweir             // UGLY: temp. enable Undo
467cdf0e10cSrcweir             GetIDocumentUndoRedo().DoUndo(true);
468cdf0e10cSrcweir             GetIDocumentUndoRedo().AppendUndo( pRedlUndo );
469cdf0e10cSrcweir             GetIDocumentUndoRedo().DoUndo(false);
470cdf0e10cSrcweir         }
471cdf0e10cSrcweir 
472cdf0e10cSrcweir         // nBeg is start of sorted range
473cdf0e10cSrcweir 		SwNodeIndex aSttIdx( GetNodes(), nBeg );
474cdf0e10cSrcweir 
475cdf0e10cSrcweir         // the copied range is deleted
476cdf0e10cSrcweir         SwRedline *const pDeleteRedline(
477cdf0e10cSrcweir             new SwRedline( nsRedlineType_t::REDLINE_DELETE, *pRedlPam ));
478cdf0e10cSrcweir 
479cdf0e10cSrcweir         // pRedlPam points to nodes that may be deleted (hidden) by
480cdf0e10cSrcweir         // AppendRedline, so adjust it beforehand to prevent ASSERT
481cdf0e10cSrcweir 		pRedlPam->GetPoint()->nNode = aSttIdx;
482cdf0e10cSrcweir 		SwCntntNode* pCNd = aSttIdx.GetNode().GetCntntNode();
483cdf0e10cSrcweir 		pRedlPam->GetPoint()->nContent.Assign( pCNd, 0 );
484cdf0e10cSrcweir 
485cdf0e10cSrcweir         AppendRedline(pDeleteRedline, true);
486cdf0e10cSrcweir 
487cdf0e10cSrcweir         // the sorted range is inserted
488cdf0e10cSrcweir 		AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, *pRedlPam ), true);
489cdf0e10cSrcweir 
490cdf0e10cSrcweir 		if( pRedlUndo )
491cdf0e10cSrcweir 		{
492cdf0e10cSrcweir 			SwNodeIndex aInsEndIdx( pRedlPam->GetMark()->nNode, -1 );
493cdf0e10cSrcweir 			pRedlPam->GetMark()->nNode = aInsEndIdx;
494cdf0e10cSrcweir             SwCntntNode *const pPrevNode =
495cdf0e10cSrcweir                 pRedlPam->GetMark()->nNode.GetNode().GetCntntNode();
496cdf0e10cSrcweir             pRedlPam->GetMark()->nContent.Assign( pPrevNode, pPrevNode->Len() );
497cdf0e10cSrcweir 
498cdf0e10cSrcweir 			pRedlUndo->SetValues( *pRedlPam );
499cdf0e10cSrcweir 		}
500cdf0e10cSrcweir 
501cdf0e10cSrcweir 		if( pRedlUndo )
502cdf0e10cSrcweir 			pRedlUndo->SetOffset( aSttIdx );
503cdf0e10cSrcweir 
504cdf0e10cSrcweir 		delete pRedlPam, pRedlPam = 0;
505cdf0e10cSrcweir     }
506cdf0e10cSrcweir     GetIDocumentUndoRedo().DoUndo( bUndo );
507cdf0e10cSrcweir 	if( bUndo )
508cdf0e10cSrcweir     {
509cdf0e10cSrcweir         GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
510cdf0e10cSrcweir     }
511cdf0e10cSrcweir 
512cdf0e10cSrcweir 	return sal_True;
513cdf0e10cSrcweir }
514cdf0e10cSrcweir 
515cdf0e10cSrcweir /*--------------------------------------------------------------------
516cdf0e10cSrcweir 	Beschreibung: Tabelle sortieren im Document
517cdf0e10cSrcweir  --------------------------------------------------------------------*/
518cdf0e10cSrcweir 
SortTbl(const SwSelBoxes & rBoxes,const SwSortOptions & rOpt)519cdf0e10cSrcweir sal_Bool SwDoc::SortTbl(const SwSelBoxes& rBoxes, const SwSortOptions& rOpt)
520cdf0e10cSrcweir {
521cdf0e10cSrcweir 	// uebers SwDoc fuer Undo !!
522cdf0e10cSrcweir 	ASSERT( rBoxes.Count(), "keine gueltige Box-Liste" );
523cdf0e10cSrcweir 	SwTableNode* pTblNd = (SwTableNode*)rBoxes[0]->GetSttNd()->FindTableNode();
524cdf0e10cSrcweir 	if( !pTblNd )
525cdf0e10cSrcweir 		return sal_False;
526cdf0e10cSrcweir 
527cdf0e10cSrcweir 	// Auf gehts sortieren
528cdf0e10cSrcweir 	// suche alle Boxen / Lines
529cdf0e10cSrcweir 	_FndBox aFndBox( 0, 0 );
530cdf0e10cSrcweir 	{
531cdf0e10cSrcweir 		_FndPara aPara( rBoxes, &aFndBox );
532cdf0e10cSrcweir 		pTblNd->GetTable().GetTabLines().ForEach( &_FndLineCopyCol, &aPara );;
533cdf0e10cSrcweir 	}
534cdf0e10cSrcweir 
535cdf0e10cSrcweir 	if(!aFndBox.GetLines().Count())
536cdf0e10cSrcweir 		return sal_False;
537cdf0e10cSrcweir 
538cdf0e10cSrcweir 	if( !IsIgnoreRedline() && GetRedlineTbl().Count() )
539cdf0e10cSrcweir 		DeleteRedline( *pTblNd, true, USHRT_MAX );
540cdf0e10cSrcweir 
541cdf0e10cSrcweir 	sal_uInt16 nStart = 0;
542cdf0e10cSrcweir     if( pTblNd->GetTable().GetRowsToRepeat() > 0 && rOpt.eDirection == SRT_ROWS )
543cdf0e10cSrcweir 	{
544cdf0e10cSrcweir         // Oberste seleketierte Zeile
545cdf0e10cSrcweir 		_FndLines& rLines = aFndBox.GetLines();
546cdf0e10cSrcweir 
547cdf0e10cSrcweir         while( nStart < rLines.Count() )
548cdf0e10cSrcweir 		{
549cdf0e10cSrcweir 			// Verschachtelung durch Split Merge beachten,
550cdf0e10cSrcweir 			// die oberste rausholen
551cdf0e10cSrcweir 			SwTableLine* pLine = rLines[nStart]->GetLine();
552cdf0e10cSrcweir 			while ( pLine->GetUpper() )
553cdf0e10cSrcweir 				pLine = pLine->GetUpper()->GetUpper();
554cdf0e10cSrcweir 
555cdf0e10cSrcweir             if( pTblNd->GetTable().IsHeadline( *pLine ) )
556cdf0e10cSrcweir 				nStart++;
557cdf0e10cSrcweir 			else
558cdf0e10cSrcweir 				break;
559cdf0e10cSrcweir 		}
560cdf0e10cSrcweir 		// Alle selektierten in der HeaderLine ?  -> kein Offset
561cdf0e10cSrcweir         if( nStart == rLines.Count() )
562cdf0e10cSrcweir 			nStart = 0;
563cdf0e10cSrcweir 	}
564cdf0e10cSrcweir 
565cdf0e10cSrcweir 	// umschalten auf relative Formeln
566cdf0e10cSrcweir 	SwTableFmlUpdate aMsgHnt( &pTblNd->GetTable() );
567cdf0e10cSrcweir 	aMsgHnt.eFlags = TBL_RELBOXNAME;
568cdf0e10cSrcweir 	UpdateTblFlds( &aMsgHnt );
569cdf0e10cSrcweir 
570cdf0e10cSrcweir 	// Tabelle als flache Array-Struktur
571cdf0e10cSrcweir 	FlatFndBox aFlatBox(this, aFndBox);
572cdf0e10cSrcweir 
573cdf0e10cSrcweir 	if(!aFlatBox.IsSymmetric())
574cdf0e10cSrcweir 		return sal_False;
575cdf0e10cSrcweir 
576cdf0e10cSrcweir 	// MIB 9.7.97: HTML-Layout loeschen
577cdf0e10cSrcweir 	pTblNd->GetTable().SetHTMLTableLayout( 0 );
578cdf0e10cSrcweir 
579cdf0e10cSrcweir     // --> FME 2004-11-26 #i37739# A simple 'MakeFrms' after the node sorting
580cdf0e10cSrcweir     // does not work if the table is inside a frame and has no prev/next.
581cdf0e10cSrcweir     SwNode2Layout aNode2Layout( *pTblNd );
582cdf0e10cSrcweir     // <--
583cdf0e10cSrcweir 
584cdf0e10cSrcweir     // loesche die Frames der Tabelle
585cdf0e10cSrcweir 	pTblNd->DelFrms();
586cdf0e10cSrcweir     // ? TL_CHART2: ?
587cdf0e10cSrcweir 
588cdf0e10cSrcweir 	SwUndoSort* pUndoSort = 0;
589cdf0e10cSrcweir     if (GetIDocumentUndoRedo().DoesUndo())
590cdf0e10cSrcweir     {
591cdf0e10cSrcweir 		pUndoSort =	new SwUndoSort( rBoxes[0]->GetSttIdx(),
592cdf0e10cSrcweir 									rBoxes[rBoxes.Count()-1]->GetSttIdx(),
593cdf0e10cSrcweir 								   *pTblNd, rOpt, aFlatBox.HasItemSets() );
594cdf0e10cSrcweir         GetIDocumentUndoRedo().AppendUndo(pUndoSort);
595cdf0e10cSrcweir     }
596cdf0e10cSrcweir     ::sw::UndoGuard const undoGuard(GetIDocumentUndoRedo());
597cdf0e10cSrcweir 
598cdf0e10cSrcweir 	// SchluesselElemente einsortieren
599cdf0e10cSrcweir 	sal_uInt16 nCount = (rOpt.eDirection == SRT_ROWS) ?
600cdf0e10cSrcweir 					aFlatBox.GetRows() : aFlatBox.GetCols();
601cdf0e10cSrcweir 
602cdf0e10cSrcweir 	// SortList nach Schluessel sortieren
603cdf0e10cSrcweir 	SwSortElement::Init( this, rOpt, &aFlatBox );
604cdf0e10cSrcweir 	SwSortElements aSortList;
605cdf0e10cSrcweir 
606cdf0e10cSrcweir 	// wenn die HeaderLine wiederholt wird und die
607cdf0e10cSrcweir 	// Zeilen sortiert werden 1.Zeile nicht mitsortieren
608cdf0e10cSrcweir 	sal_uInt16 i;
609cdf0e10cSrcweir 
610cdf0e10cSrcweir 	for( i = nStart; i < nCount; ++i)
611cdf0e10cSrcweir 	{
612cdf0e10cSrcweir 		SwSortBoxElement* pEle = new SwSortBoxElement( i );
613cdf0e10cSrcweir 		aSortList.Insert(pEle);
614cdf0e10cSrcweir 	}
615cdf0e10cSrcweir 
616cdf0e10cSrcweir     // nach Sortierung verschieben
617cdf0e10cSrcweir 	SwMovedBoxes aMovedList;
618cdf0e10cSrcweir 	for(i=0; i < aSortList.Count(); ++i)
619cdf0e10cSrcweir 	{
620cdf0e10cSrcweir 		SwSortBoxElement* pBox = (SwSortBoxElement*)aSortList[i];
621cdf0e10cSrcweir 		if(rOpt.eDirection == SRT_ROWS)
622cdf0e10cSrcweir 			MoveRow(this, aFlatBox, pBox->nRow, i + nStart, aMovedList, pUndoSort);
623cdf0e10cSrcweir 		else
624cdf0e10cSrcweir 			MoveCol(this, aFlatBox, pBox->nRow, i + nStart, aMovedList, pUndoSort);
625cdf0e10cSrcweir 	}
626cdf0e10cSrcweir 
627cdf0e10cSrcweir     // Restore table frames:
628cdf0e10cSrcweir     // --> FME 2004-11-26 #i37739# A simple 'MakeFrms' after the node sorting
629cdf0e10cSrcweir     // does not work if the table is inside a frame and has no prev/next.
630cdf0e10cSrcweir     const sal_uLong nIdx = pTblNd->GetIndex();
631cdf0e10cSrcweir     aNode2Layout.RestoreUpperFrms( GetNodes(), nIdx, nIdx + 1 );
632cdf0e10cSrcweir     // <--
633cdf0e10cSrcweir 
634cdf0e10cSrcweir     // TL_CHART2: need to inform chart of probably changed cell names
635cdf0e10cSrcweir     UpdateCharts( pTblNd->GetTable().GetFrmFmt()->GetName() );
636cdf0e10cSrcweir 
637cdf0e10cSrcweir 	// Alle Elemente aus dem SortArray loeschen
638cdf0e10cSrcweir 	aSortList.DeleteAndDestroy( 0, aSortList.Count() );
639cdf0e10cSrcweir 	SwSortElement::Finit();
640cdf0e10cSrcweir 
641cdf0e10cSrcweir 	SetModified();
642cdf0e10cSrcweir 	return sal_True;
643cdf0e10cSrcweir }
644cdf0e10cSrcweir 
645cdf0e10cSrcweir /*--------------------------------------------------------------------
646cdf0e10cSrcweir 	Beschreibung: Zeilenweise verschieben
647cdf0e10cSrcweir  --------------------------------------------------------------------*/
648cdf0e10cSrcweir 
649cdf0e10cSrcweir 
MoveRow(SwDoc * pDoc,const FlatFndBox & rBox,sal_uInt16 nS,sal_uInt16 nT,SwMovedBoxes & rMovedList,SwUndoSort * pUD)650cdf0e10cSrcweir void MoveRow(SwDoc* pDoc, const FlatFndBox& rBox, sal_uInt16 nS, sal_uInt16 nT,
651cdf0e10cSrcweir 			 SwMovedBoxes& rMovedList, SwUndoSort* pUD)
652cdf0e10cSrcweir {
653cdf0e10cSrcweir 	for( sal_uInt16 i=0; i < rBox.GetCols(); ++i )
654cdf0e10cSrcweir 	{	// Alte Zellen-Pos bestimmen und merken
655cdf0e10cSrcweir 		const _FndBox* pSource = rBox.GetBox(i, nS);
656cdf0e10cSrcweir 
657cdf0e10cSrcweir 		// neue Zellen-Pos
658cdf0e10cSrcweir 		const _FndBox* pTarget = rBox.GetBox(i, nT);
659cdf0e10cSrcweir 
660cdf0e10cSrcweir 		const SwTableBox* pT = pTarget->GetBox();
661cdf0e10cSrcweir 		const SwTableBox* pS = pSource->GetBox();
662cdf0e10cSrcweir 
663cdf0e10cSrcweir 		sal_Bool bMoved = rMovedList.GetPos(pT) != USHRT_MAX;
664cdf0e10cSrcweir 
665cdf0e10cSrcweir 		// und verschieben
666cdf0e10cSrcweir 		MoveCell(pDoc, pS, pT, bMoved, pUD);
667cdf0e10cSrcweir 
668cdf0e10cSrcweir 		rMovedList.Insert(pS, rMovedList.Count() );
669cdf0e10cSrcweir 
670cdf0e10cSrcweir 		if( pS != pT )
671cdf0e10cSrcweir 		{
672cdf0e10cSrcweir 			SwFrmFmt* pTFmt = (SwFrmFmt*)pT->GetFrmFmt();
673cdf0e10cSrcweir 			const SfxItemSet* pSSet = rBox.GetItemSet( i, nS );
674cdf0e10cSrcweir 
675cdf0e10cSrcweir 			if( pSSet ||
676cdf0e10cSrcweir 				SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMAT ) ||
677cdf0e10cSrcweir 				SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMULA ) ||
678cdf0e10cSrcweir 				SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_VALUE ) )
679cdf0e10cSrcweir 			{
680cdf0e10cSrcweir 				pTFmt = ((SwTableBox*)pT)->ClaimFrmFmt();
681cdf0e10cSrcweir 				pTFmt->LockModify();
682cdf0e10cSrcweir                 if( pTFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ) )
683cdf0e10cSrcweir                     pTFmt->ResetFmtAttr( RES_VERT_ORIENT );
684cdf0e10cSrcweir 
685cdf0e10cSrcweir 				if( pSSet )
686cdf0e10cSrcweir                     pTFmt->SetFmtAttr( *pSSet );
687cdf0e10cSrcweir 				pTFmt->UnlockModify();
688cdf0e10cSrcweir 			}
689cdf0e10cSrcweir 		}
690cdf0e10cSrcweir 	}
691cdf0e10cSrcweir }
692cdf0e10cSrcweir 
693cdf0e10cSrcweir /*--------------------------------------------------------------------
694cdf0e10cSrcweir 	Beschreibung: Spaltenweise verschieben
695cdf0e10cSrcweir  --------------------------------------------------------------------*/
696cdf0e10cSrcweir 
697cdf0e10cSrcweir 
MoveCol(SwDoc * pDoc,const FlatFndBox & rBox,sal_uInt16 nS,sal_uInt16 nT,SwMovedBoxes & rMovedList,SwUndoSort * pUD)698cdf0e10cSrcweir void MoveCol(SwDoc* pDoc, const FlatFndBox& rBox, sal_uInt16 nS, sal_uInt16 nT,
699cdf0e10cSrcweir 			 SwMovedBoxes& rMovedList, SwUndoSort* pUD)
700cdf0e10cSrcweir {
701cdf0e10cSrcweir 	for(sal_uInt16 i=0; i < rBox.GetRows(); ++i)
702cdf0e10cSrcweir 	{	// Alte Zellen-Pos bestimmen und merken
703cdf0e10cSrcweir 		const _FndBox* pSource = rBox.GetBox(nS, i);
704cdf0e10cSrcweir 
705cdf0e10cSrcweir 		// neue Zellen-Pos
706cdf0e10cSrcweir 		const _FndBox* pTarget = rBox.GetBox(nT, i);
707cdf0e10cSrcweir 
708cdf0e10cSrcweir 		// und verschieben
709cdf0e10cSrcweir 		const SwTableBox* pT = pTarget->GetBox();
710cdf0e10cSrcweir 		const SwTableBox* pS = pSource->GetBox();
711cdf0e10cSrcweir 
712cdf0e10cSrcweir 		// und verschieben
713cdf0e10cSrcweir 		sal_Bool bMoved = rMovedList.GetPos(pT) != USHRT_MAX;
714cdf0e10cSrcweir 		MoveCell(pDoc, pS, pT, bMoved, pUD);
715cdf0e10cSrcweir 
716cdf0e10cSrcweir 		rMovedList.Insert(pS, rMovedList.Count() );
717cdf0e10cSrcweir 
718cdf0e10cSrcweir 		if( pS != pT )
719cdf0e10cSrcweir 		{
720cdf0e10cSrcweir 			SwFrmFmt* pTFmt = (SwFrmFmt*)pT->GetFrmFmt();
721cdf0e10cSrcweir 			const SfxItemSet* pSSet = rBox.GetItemSet( nS, i );
722cdf0e10cSrcweir 
723cdf0e10cSrcweir 			if( pSSet ||
724cdf0e10cSrcweir 				SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMAT ) ||
725cdf0e10cSrcweir 				SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_FORMULA ) ||
726cdf0e10cSrcweir 				SFX_ITEM_SET == pTFmt->GetItemState( RES_BOXATR_VALUE ) )
727cdf0e10cSrcweir 			{
728cdf0e10cSrcweir 				pTFmt = ((SwTableBox*)pT)->ClaimFrmFmt();
729cdf0e10cSrcweir 				pTFmt->LockModify();
730cdf0e10cSrcweir                 if( pTFmt->ResetFmtAttr( RES_BOXATR_FORMAT, RES_BOXATR_VALUE ) )
731cdf0e10cSrcweir                     pTFmt->ResetFmtAttr( RES_VERT_ORIENT );
732cdf0e10cSrcweir 
733cdf0e10cSrcweir 				if( pSSet )
734cdf0e10cSrcweir                     pTFmt->SetFmtAttr( *pSSet );
735cdf0e10cSrcweir 				pTFmt->UnlockModify();
736cdf0e10cSrcweir 			}
737cdf0e10cSrcweir 		}
738cdf0e10cSrcweir 	}
739cdf0e10cSrcweir }
740cdf0e10cSrcweir 
741cdf0e10cSrcweir /*--------------------------------------------------------------------
742cdf0e10cSrcweir 	Beschreibung: Eine einzelne Zelle verschieben
743cdf0e10cSrcweir  --------------------------------------------------------------------*/
744cdf0e10cSrcweir 
745cdf0e10cSrcweir 
MoveCell(SwDoc * pDoc,const SwTableBox * pSource,const SwTableBox * pTar,sal_Bool bMovedBefore,SwUndoSort * pUD)746cdf0e10cSrcweir void MoveCell(SwDoc* pDoc, const SwTableBox* pSource, const SwTableBox* pTar,
747cdf0e10cSrcweir 			  sal_Bool bMovedBefore, SwUndoSort* pUD)
748cdf0e10cSrcweir {
749cdf0e10cSrcweir 	ASSERT(pSource && pTar,"Fehlende Quelle oder Ziel");
750cdf0e10cSrcweir 
751cdf0e10cSrcweir 	if(pSource == pTar)
752cdf0e10cSrcweir 		return;
753cdf0e10cSrcweir 
754cdf0e10cSrcweir 	if(pUD)
755cdf0e10cSrcweir 		pUD->Insert( pSource->GetName(), pTar->GetName() );
756cdf0e10cSrcweir 
757cdf0e10cSrcweir 	// Pam Quelle auf den ersten ContentNode setzen
758cdf0e10cSrcweir 	SwNodeRange aRg( *pSource->GetSttNd(), 0, *pSource->GetSttNd() );
759cdf0e10cSrcweir 	SwNode* pNd = pDoc->GetNodes().GoNext( &aRg.aStart );
760cdf0e10cSrcweir 
761cdf0e10cSrcweir 	// wurde die Zelle (Source) nicht verschoben
762cdf0e10cSrcweir 	// -> einen Leer-Node einfuegen und den Rest verschieben
763cdf0e10cSrcweir 	// ansonsten steht der Mark auf dem ersten Content-Node
764cdf0e10cSrcweir 	if( pNd->StartOfSectionNode() == pSource->GetSttNd() )
765cdf0e10cSrcweir 		pNd = pDoc->GetNodes().MakeTxtNode( aRg.aStart,
766cdf0e10cSrcweir 				(SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
767cdf0e10cSrcweir 	aRg.aEnd = *pNd->EndOfSectionNode();
768cdf0e10cSrcweir 
769cdf0e10cSrcweir 	// Ist das Ziel leer(1 leerer Node vorhanden)
770cdf0e10cSrcweir 	// -> diesen loeschen und move
771cdf0e10cSrcweir 	// Ziel
772cdf0e10cSrcweir 	SwNodeIndex	aTar( *pTar->GetSttNd() );
773cdf0e10cSrcweir 	pNd = pDoc->GetNodes().GoNext( &aTar );     // naechsten ContentNode
774cdf0e10cSrcweir 	sal_uLong nCount = pNd->EndOfSectionIndex() - pNd->StartOfSectionIndex();
775cdf0e10cSrcweir 
776cdf0e10cSrcweir 	sal_Bool bDelFirst = sal_False;
777cdf0e10cSrcweir 	if( nCount == 2 )
778cdf0e10cSrcweir 	{
779cdf0e10cSrcweir 		ASSERT( pNd->GetCntntNode(), "Kein ContentNode");
780cdf0e10cSrcweir 		bDelFirst = !pNd->GetCntntNode()->Len() && bMovedBefore;
781cdf0e10cSrcweir 	}
782cdf0e10cSrcweir 
783cdf0e10cSrcweir 	if(!bDelFirst)
784cdf0e10cSrcweir 	{	// Es besteht schon Inhalt -> alter I n h a l t  Section Down
785cdf0e10cSrcweir 		SwNodeRange aRgTar( aTar.GetNode(), 0, *pNd->EndOfSectionNode() );
786cdf0e10cSrcweir 		pDoc->GetNodes().SectionDown( &aRgTar );
787cdf0e10cSrcweir 	}
788cdf0e10cSrcweir 
789cdf0e10cSrcweir 	// Einfuegen der Source
790cdf0e10cSrcweir 	SwNodeIndex aIns( *pTar->GetSttNd()->EndOfSectionNode() );
791cdf0e10cSrcweir     pDoc->MoveNodeRange( aRg, aIns,
792cdf0e10cSrcweir         IDocumentContentOperations::DOC_MOVEDEFAULT );
793cdf0e10cSrcweir 
794cdf0e10cSrcweir 	// Falls erster Node leer -> weg damit
795cdf0e10cSrcweir 	if(bDelFirst)
796cdf0e10cSrcweir 		pDoc->GetNodes().Delete( aTar, 1 );
797cdf0e10cSrcweir }
798cdf0e10cSrcweir 
799cdf0e10cSrcweir /*--------------------------------------------------------------------
800cdf0e10cSrcweir 	Beschreibung: Zweidimensionales Array aus FndBoxes generieren
801cdf0e10cSrcweir  --------------------------------------------------------------------*/
802cdf0e10cSrcweir 
803cdf0e10cSrcweir 
FlatFndBox(SwDoc * pDocPtr,const _FndBox & rBox)804cdf0e10cSrcweir FlatFndBox::FlatFndBox(SwDoc* pDocPtr, const _FndBox& rBox) :
805cdf0e10cSrcweir 	pDoc(pDocPtr),
806cdf0e10cSrcweir 	rBoxRef(rBox),
807cdf0e10cSrcweir 	pArr(0),
808cdf0e10cSrcweir 	ppItemSets(0),
809cdf0e10cSrcweir 	nRow(0),
810cdf0e10cSrcweir 	nCol(0)
811cdf0e10cSrcweir { // Ist das Array symmetrisch
812cdf0e10cSrcweir 	if((bSym = CheckLineSymmetry(rBoxRef)) != 0)
813cdf0e10cSrcweir 	{
814cdf0e10cSrcweir 		// Spalten/Reihen-Anzahl ermitteln
815cdf0e10cSrcweir 		nCols = GetColCount(rBoxRef);
816cdf0e10cSrcweir 		nRows = GetRowCount(rBoxRef);
817cdf0e10cSrcweir 
818cdf0e10cSrcweir 		// lineares Array anlegen
819cdf0e10cSrcweir 		pArr = new _FndBoxPtr[ nRows * nCols ];
820cdf0e10cSrcweir 		_FndBox** ppTmp = (_FndBox**)pArr;
821cdf0e10cSrcweir 		memset( ppTmp, 0, sizeof(_FndBoxPtr) * nRows * nCols );
822cdf0e10cSrcweir 
823cdf0e10cSrcweir 
824cdf0e10cSrcweir 		FillFlat( rBoxRef );
825cdf0e10cSrcweir 	}
826cdf0e10cSrcweir }
827cdf0e10cSrcweir 
828cdf0e10cSrcweir 
~FlatFndBox()829cdf0e10cSrcweir FlatFndBox::~FlatFndBox()
830cdf0e10cSrcweir {
831cdf0e10cSrcweir 	_FndBox** ppTmp = (_FndBox**)pArr;
832cdf0e10cSrcweir 	delete [] ppTmp;
833cdf0e10cSrcweir 
834cdf0e10cSrcweir 	if( ppItemSets )
835cdf0e10cSrcweir 		delete [] ppItemSets;
836cdf0e10cSrcweir }
837cdf0e10cSrcweir 
838cdf0e10cSrcweir /*--------------------------------------------------------------------
839cdf0e10cSrcweir 	Beschreibung:	Alle Lines einer Box muessen gleichviel Boxen haben
840cdf0e10cSrcweir  --------------------------------------------------------------------*/
841cdf0e10cSrcweir 
842cdf0e10cSrcweir 
CheckLineSymmetry(const _FndBox & rBox)843cdf0e10cSrcweir sal_Bool FlatFndBox::CheckLineSymmetry(const _FndBox& rBox)
844cdf0e10cSrcweir {
845cdf0e10cSrcweir 	const _FndLines &rLines = rBox.GetLines();
846cdf0e10cSrcweir 	sal_uInt16 nBoxes(0);
847cdf0e10cSrcweir 
848cdf0e10cSrcweir 	// UeberLines iterieren
849cdf0e10cSrcweir 	for(sal_uInt16 i=0; i < rLines.Count(); ++i)
850cdf0e10cSrcweir 	{	// Die Boxen einer Line
851cdf0e10cSrcweir 		_FndLine* pLn = rLines[i];
852cdf0e10cSrcweir 		const _FndBoxes& rBoxes = pLn->GetBoxes();
853cdf0e10cSrcweir 
854cdf0e10cSrcweir 		// Anzahl der Boxen aller Lines ungleich -> keine Symmetrie
855cdf0e10cSrcweir 		if( i  && nBoxes != rBoxes.Count())
856cdf0e10cSrcweir 			return sal_False;
857cdf0e10cSrcweir 
858cdf0e10cSrcweir 		nBoxes = rBoxes.Count();
859cdf0e10cSrcweir 		if( !CheckBoxSymmetry( *pLn ) )
860cdf0e10cSrcweir 			return sal_False;
861cdf0e10cSrcweir 	}
862cdf0e10cSrcweir 	return sal_True;
863cdf0e10cSrcweir }
864cdf0e10cSrcweir 
865cdf0e10cSrcweir /*--------------------------------------------------------------------
866cdf0e10cSrcweir 	Beschreibung:	Box auf Symmetrie pruefen
867cdf0e10cSrcweir 					Alle Boxen einer Line muessen gleichviele Lines haben
868cdf0e10cSrcweir  --------------------------------------------------------------------*/
869cdf0e10cSrcweir 
870cdf0e10cSrcweir 
CheckBoxSymmetry(const _FndLine & rLn)871cdf0e10cSrcweir sal_Bool FlatFndBox::CheckBoxSymmetry(const _FndLine& rLn)
872cdf0e10cSrcweir {
873cdf0e10cSrcweir 	const _FndBoxes &rBoxes = rLn.GetBoxes();
874cdf0e10cSrcweir 	sal_uInt16 nLines(0);
875cdf0e10cSrcweir 
876cdf0e10cSrcweir 	// Ueber Boxes iterieren
877cdf0e10cSrcweir 	for(sal_uInt16 i=0; i < rBoxes.Count(); ++i)
878cdf0e10cSrcweir 	{	// Die Boxen einer Line
879cdf0e10cSrcweir 		_FndBox* pBox = rBoxes[i];
880cdf0e10cSrcweir 		const _FndLines& rLines = pBox->GetLines();
881cdf0e10cSrcweir 
882cdf0e10cSrcweir 		// Anzahl der Boxen aller Lines ungleich -> keine Symmetrie
883cdf0e10cSrcweir 		if( i && nLines != rLines.Count() )
884cdf0e10cSrcweir 			return sal_False;
885cdf0e10cSrcweir 
886cdf0e10cSrcweir 		nLines = rLines.Count();
887cdf0e10cSrcweir 		if( nLines && !CheckLineSymmetry( *pBox ) )
888cdf0e10cSrcweir 			return sal_False;
889cdf0e10cSrcweir 	}
890cdf0e10cSrcweir 	return sal_True;
891cdf0e10cSrcweir }
892cdf0e10cSrcweir 
893cdf0e10cSrcweir /*--------------------------------------------------------------------
894cdf0e10cSrcweir 	Beschreibung: max Anzahl der Spalten (Boxes)
895cdf0e10cSrcweir  --------------------------------------------------------------------*/
896cdf0e10cSrcweir 
897cdf0e10cSrcweir 
GetColCount(const _FndBox & rBox)898cdf0e10cSrcweir sal_uInt16 FlatFndBox::GetColCount(const _FndBox& rBox)
899cdf0e10cSrcweir {
900cdf0e10cSrcweir 	const _FndLines& rLines = rBox.GetLines();
901cdf0e10cSrcweir 	// Ueber Lines iterieren
902cdf0e10cSrcweir 	if( !rLines.Count() )
903cdf0e10cSrcweir 		return 1;
904cdf0e10cSrcweir 
905cdf0e10cSrcweir 	sal_uInt16 nSum = 0;
906cdf0e10cSrcweir 	for( sal_uInt16 i=0; i < rLines.Count(); ++i )
907cdf0e10cSrcweir 	{
908cdf0e10cSrcweir 		// Die Boxen einer Line
909cdf0e10cSrcweir 		sal_uInt16 nCount = 0;
910cdf0e10cSrcweir 		const _FndBoxes& rBoxes = rLines[i]->GetBoxes();
911cdf0e10cSrcweir 		for( sal_uInt16 j=0; j < rBoxes.Count(); ++j )
912cdf0e10cSrcweir 				//	Rekursiv wirder ueber die Lines Iterieren
913cdf0e10cSrcweir 			nCount += rBoxes[j]->GetLines().Count()
914cdf0e10cSrcweir 						? GetColCount(*rBoxes[j]) : 1;
915cdf0e10cSrcweir 
916cdf0e10cSrcweir 		if( nSum < nCount )
917cdf0e10cSrcweir 			nSum = nCount;
918cdf0e10cSrcweir 	}
919cdf0e10cSrcweir 	return nSum;
920cdf0e10cSrcweir }
921cdf0e10cSrcweir 
922cdf0e10cSrcweir /*--------------------------------------------------------------------
923cdf0e10cSrcweir 	Beschreibung: max Anzahl der Zeilen (Lines)
924cdf0e10cSrcweir  --------------------------------------------------------------------*/
925cdf0e10cSrcweir 
926cdf0e10cSrcweir 
GetRowCount(const _FndBox & rBox)927cdf0e10cSrcweir sal_uInt16 FlatFndBox::GetRowCount(const _FndBox& rBox)
928cdf0e10cSrcweir {
929cdf0e10cSrcweir 	const _FndLines& rLines = rBox.GetLines();
930cdf0e10cSrcweir 	if( !rLines.Count() )
931cdf0e10cSrcweir 		return 1;
932cdf0e10cSrcweir 
933cdf0e10cSrcweir 	sal_uInt16 nLines = 0;
934cdf0e10cSrcweir 	for(sal_uInt16 i=0; i < rLines.Count(); ++i)
935cdf0e10cSrcweir 	{	// Die Boxen einer Line
936cdf0e10cSrcweir 		const _FndBoxes& rBoxes = rLines[i]->GetBoxes();
937cdf0e10cSrcweir 		sal_uInt16 nLn = 1;
938cdf0e10cSrcweir 		for(sal_uInt16 j=0; j < rBoxes.Count(); ++j)
939cdf0e10cSrcweir 			if( rBoxes[j]->GetLines().Count() )
940cdf0e10cSrcweir 				//	Rekursiv ueber die Lines Iterieren
941cdf0e10cSrcweir 				nLn = Max(GetRowCount(*rBoxes[j]), nLn);
942cdf0e10cSrcweir 
943cdf0e10cSrcweir 		nLines = nLines + nLn;
944cdf0e10cSrcweir 	}
945cdf0e10cSrcweir 	return nLines;
946cdf0e10cSrcweir }
947cdf0e10cSrcweir 
948cdf0e10cSrcweir /*--------------------------------------------------------------------
949cdf0e10cSrcweir 	Beschreibung: lineares Array aus atomaren FndBoxes erzeugen
950cdf0e10cSrcweir  --------------------------------------------------------------------*/
951cdf0e10cSrcweir 
952cdf0e10cSrcweir 
FillFlat(const _FndBox & rBox,sal_Bool bLastBox)953cdf0e10cSrcweir void FlatFndBox::FillFlat(const _FndBox& rBox, sal_Bool bLastBox)
954cdf0e10cSrcweir {
955cdf0e10cSrcweir 	sal_Bool bModRow = sal_False;
956cdf0e10cSrcweir 	const _FndLines& rLines = rBox.GetLines();
957cdf0e10cSrcweir 
958cdf0e10cSrcweir 	// Ueber Lines iterieren
959cdf0e10cSrcweir 	sal_uInt16 nOldRow = nRow;
960cdf0e10cSrcweir 	for( sal_uInt16 i=0; i < rLines.Count(); ++i )
961cdf0e10cSrcweir 	{
962cdf0e10cSrcweir 		// Die Boxen einer Line
963cdf0e10cSrcweir 		const _FndBoxes& rBoxes = rLines[i]->GetBoxes();
964cdf0e10cSrcweir 		sal_uInt16 nOldCol = nCol;
965cdf0e10cSrcweir 		for( sal_uInt16 j = 0; j < rBoxes.Count(); ++j )
966cdf0e10cSrcweir 		{
967cdf0e10cSrcweir 			// Die Box pruefen ob es eine atomare Box ist
968cdf0e10cSrcweir 			const _FndBox* 	 pBox 	= rBoxes[ j ];
969cdf0e10cSrcweir 
970cdf0e10cSrcweir 			if( !pBox->GetLines().Count() )
971cdf0e10cSrcweir 			{
972cdf0e10cSrcweir 				// peichern
973cdf0e10cSrcweir 				sal_uInt16 nOff = nRow * nCols + nCol;
974cdf0e10cSrcweir 				*(pArr + nOff) = pBox;
975cdf0e10cSrcweir 
976cdf0e10cSrcweir 				// sicher die Formel/Format/Value Werte
977cdf0e10cSrcweir 				const SwFrmFmt* pFmt = pBox->GetBox()->GetFrmFmt();
978cdf0e10cSrcweir 				if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMAT ) ||
979cdf0e10cSrcweir 					SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA ) ||
980cdf0e10cSrcweir 					SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE ) )
981cdf0e10cSrcweir 				{
982cdf0e10cSrcweir 					SfxItemSet* pSet = new SfxItemSet( pDoc->GetAttrPool(),
983cdf0e10cSrcweir 									RES_BOXATR_FORMAT, RES_BOXATR_VALUE,
984cdf0e10cSrcweir 									RES_VERT_ORIENT, RES_VERT_ORIENT, 0 );
985cdf0e10cSrcweir 					pSet->Put( pFmt->GetAttrSet() );
986cdf0e10cSrcweir 					if( !ppItemSets )
987cdf0e10cSrcweir 					{
988cdf0e10cSrcweir 						ppItemSets = new SfxItemSet*[ nRows * nCols ];
989cdf0e10cSrcweir 						memset( ppItemSets, 0, sizeof(SfxItemSet*) * nRows * nCols );
990cdf0e10cSrcweir 					}
991cdf0e10cSrcweir 					*(ppItemSets + nOff ) = pSet;
992cdf0e10cSrcweir 				}
993cdf0e10cSrcweir 
994cdf0e10cSrcweir 				bModRow = sal_True;
995cdf0e10cSrcweir 			}
996cdf0e10cSrcweir 			else
997cdf0e10cSrcweir 			{
998cdf0e10cSrcweir 				// Rekursiv wieder ueber die Lines einer Box Iterieren
999cdf0e10cSrcweir 				FillFlat( *pBox, ( j == rBoxes.Count()-1 ) );
1000cdf0e10cSrcweir 			}
1001cdf0e10cSrcweir 			nCol++;
1002cdf0e10cSrcweir 		}
1003cdf0e10cSrcweir 		if(bModRow)
1004cdf0e10cSrcweir 			nRow++;
1005cdf0e10cSrcweir 		nCol = nOldCol;
1006cdf0e10cSrcweir 	}
1007cdf0e10cSrcweir 	if(!bLastBox)
1008cdf0e10cSrcweir 		nRow = nOldRow;
1009cdf0e10cSrcweir }
1010cdf0e10cSrcweir 
1011cdf0e10cSrcweir /*--------------------------------------------------------------------
1012cdf0e10cSrcweir 	Beschreibung: Zugriff auf eine bestimmte Zelle
1013cdf0e10cSrcweir  --------------------------------------------------------------------*/
1014cdf0e10cSrcweir 
1015cdf0e10cSrcweir 
GetBox(sal_uInt16 n_Col,sal_uInt16 n_Row) const1016cdf0e10cSrcweir const _FndBox* FlatFndBox::GetBox(sal_uInt16 n_Col, sal_uInt16 n_Row) const
1017cdf0e10cSrcweir {
1018cdf0e10cSrcweir 	sal_uInt16 nOff = n_Row * nCols + n_Col;
1019cdf0e10cSrcweir 	const _FndBox* pTmp = *(pArr + nOff);
1020cdf0e10cSrcweir 
1021cdf0e10cSrcweir 	ASSERT(n_Col < nCols && n_Row < nRows && pTmp, "unzulaessiger Array-Zugriff");
1022cdf0e10cSrcweir 	return pTmp;
1023cdf0e10cSrcweir }
1024cdf0e10cSrcweir 
GetItemSet(sal_uInt16 n_Col,sal_uInt16 n_Row) const1025cdf0e10cSrcweir const SfxItemSet* FlatFndBox::GetItemSet(sal_uInt16 n_Col, sal_uInt16 n_Row) const
1026cdf0e10cSrcweir {
1027cdf0e10cSrcweir 	ASSERT( !ppItemSets || ( n_Col < nCols && n_Row < nRows), "unzulaessiger Array-Zugriff");
1028cdf0e10cSrcweir 
1029cdf0e10cSrcweir 	return ppItemSets ? *(ppItemSets + (n_Row * nCols + n_Col )) : 0;
1030cdf0e10cSrcweir }
1031cdf0e10cSrcweir 
1032cdf0e10cSrcweir 
1033