xref: /trunk/main/sw/source/core/doc/gctable.cxx (revision efeef26f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <hintids.hxx>
29 #include <editeng/boxitem.hxx>
30 #include <tblrwcl.hxx>
31 #include <swtblfmt.hxx>
32 
33 
GetLineTB(const SvxBoxItem * pBox,sal_Bool bTop)34 inline const SvxBorderLine* GetLineTB( const SvxBoxItem* pBox, sal_Bool bTop )
35 {
36 	return bTop ? pBox->GetTop() : pBox->GetBottom();
37 }
38 
39 
CheckLeftBorderOfFormat(const SwFrmFmt & rFmt)40 sal_Bool _SwGCBorder_BoxBrd::CheckLeftBorderOfFormat( const SwFrmFmt& rFmt )
41 {
42 	const SvxBorderLine* pBrd;
43 	const SfxPoolItem* pItem;
44 	if( SFX_ITEM_SET == rFmt.GetItemState( RES_BOX, sal_True, &pItem ) &&
45 		0 != ( pBrd = ((SvxBoxItem*)pItem)->GetLeft() ) )
46 	{
47 		if( *pBrdLn == *pBrd )
48 			bAnyBorderFnd = sal_True;
49 		return sal_True;
50 	}
51 	return sal_False;
52 }
53 
54 
55 
lcl_GCBorder_ChkBoxBrd_L(const SwTableLine * & rpLine,void * pPara)56 sal_Bool lcl_GCBorder_ChkBoxBrd_L( const SwTableLine*& rpLine, void* pPara )
57 {
58 	const SwTableBox* pBox = rpLine->GetTabBoxes()[ 0 ];
59 	return lcl_GCBorder_ChkBoxBrd_B( pBox, pPara );
60 }
61 
lcl_GCBorder_ChkBoxBrd_B(const SwTableBox * & rpBox,void * pPara)62 sal_Bool lcl_GCBorder_ChkBoxBrd_B( const SwTableBox*& rpBox, void* pPara )
63 {
64 	sal_Bool bRet = sal_True;
65 	if( rpBox->GetTabLines().Count() )
66 	{
67 		for( sal_uInt16 n = 0, nLines = rpBox->GetTabLines().Count();
68 				n < nLines && bRet; ++n )
69 		{
70 			const SwTableLine* pLine = rpBox->GetTabLines()[ n ];
71 			bRet = lcl_GCBorder_ChkBoxBrd_L( pLine, pPara );
72 		}
73 	}
74 	else
75 	{
76 		_SwGCBorder_BoxBrd* pBPara = (_SwGCBorder_BoxBrd*)pPara;
77 		bRet = pBPara->CheckLeftBorderOfFormat( *rpBox->GetFrmFmt() );
78 	}
79 	return bRet;
80 }
81 
lcl_GCBorder_GetLastBox_L(const SwTableLine * & rpLine,void * pPara)82 sal_Bool lcl_GCBorder_GetLastBox_L( const SwTableLine*& rpLine, void* pPara )
83 {
84 	const SwTableBoxes& rBoxes = rpLine->GetTabBoxes();
85 	const SwTableBox* pBox = rBoxes[ rBoxes.Count()-1 ];
86 	::lcl_GCBorder_GetLastBox_B( pBox, pPara );
87 	return sal_True;
88 }
89 
lcl_GCBorder_GetLastBox_B(const SwTableBox * & rpBox,void * pPara)90 sal_Bool lcl_GCBorder_GetLastBox_B( const SwTableBox*& rpBox, void* pPara )
91 {
92 	SwTableLines& rLines = (SwTableLines&)rpBox->GetTabLines();
93 	if( rLines.Count() )
94 		rLines.ForEach( &lcl_GCBorder_GetLastBox_L, pPara );
95 	else
96 		((SwTableBoxes*)pPara)->Insert( rpBox, ((SwTableBoxes*)pPara)->Count() );
97 	return sal_True;
98 }
99 
100 // suche das "Ende" der vorgegebene BorderLine. Returnt wird die "Layout"Pos!
lcl_FindEndPosOfBorder(const SwCollectTblLineBoxes & rCollTLB,const SvxBorderLine & rBrdLn,sal_uInt16 & rStt,sal_Bool bTop)101 sal_uInt16 lcl_FindEndPosOfBorder( const SwCollectTblLineBoxes& rCollTLB,
102 						const SvxBorderLine& rBrdLn, sal_uInt16& rStt, sal_Bool bTop )
103 {
104 	sal_uInt16 nPos, nLastPos = 0;
105 	for( sal_uInt16 nEnd = rCollTLB.Count(); rStt < nEnd; ++rStt )
106 	{
107 		const SfxPoolItem* pItem;
108 		const SvxBorderLine* pBrd;
109 		const SwTableBox& rBox = rCollTLB.GetBox( rStt, &nPos );
110 
111 		if( SFX_ITEM_SET != rBox.GetFrmFmt()->GetItemState(RES_BOX,sal_True, &pItem )
112 			|| 0 == ( pBrd = GetLineTB( (SvxBoxItem*)pItem, bTop ))
113 			|| !( *pBrd == rBrdLn ))
114 			break;
115 		nLastPos = nPos;
116 	}
117 	return nLastPos;
118 }
119 
lcl_GCBorder_GetBorder(const SwTableBox & rBox,sal_Bool bTop,const SfxPoolItem ** ppItem)120 inline const SvxBorderLine* lcl_GCBorder_GetBorder( const SwTableBox& rBox,
121 												sal_Bool bTop,
122 												const SfxPoolItem** ppItem )
123 {
124 	return SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState( RES_BOX, sal_True, ppItem )
125 			? GetLineTB( (SvxBoxItem*)*ppItem, bTop )
126 			: 0;
127 }
128 
lcl_GCBorder_DelBorder(const SwCollectTblLineBoxes & rCollTLB,sal_uInt16 & rStt,sal_Bool bTop,const SvxBorderLine & rLine,const SfxPoolItem * pItem,sal_uInt16 nEndPos,SwShareBoxFmts * pShareFmts)129 void lcl_GCBorder_DelBorder( const SwCollectTblLineBoxes& rCollTLB,
130 								sal_uInt16& rStt, sal_Bool bTop,
131 								const SvxBorderLine& rLine,
132 								const SfxPoolItem* pItem,
133 								sal_uInt16 nEndPos,
134 								SwShareBoxFmts* pShareFmts )
135 {
136 	SwTableBox* pBox = (SwTableBox*)&rCollTLB.GetBox( rStt );
137 	sal_uInt16 nNextPos;
138 	const SvxBorderLine* pLn = &rLine;
139 
140 	do {
141 		if( pLn && *pLn == rLine )
142 		{
143 			SvxBoxItem aBox( *(SvxBoxItem*)pItem );
144 			if( bTop )
145 				aBox.SetLine( 0, BOX_LINE_TOP );
146 			else
147 				aBox.SetLine( 0, BOX_LINE_BOTTOM );
148 
149 			if( pShareFmts )
150 				pShareFmts->SetAttr( *pBox, aBox );
151 			else
152                 pBox->ClaimFrmFmt()->SetFmtAttr( aBox );
153 		}
154 
155 		if( ++rStt >= rCollTLB.Count() )
156 			break;
157 
158 		pBox = (SwTableBox*)&rCollTLB.GetBox( rStt, &nNextPos );
159 		if( nNextPos > nEndPos )
160 			break;
161 
162 		pLn = lcl_GCBorder_GetBorder( *pBox, bTop, &pItem );
163 
164 	} while( sal_True );
165 }
166 
167 
lcl_GC_Line_Border(const SwTableLine * & rpLine,void * pPara)168 sal_Bool lcl_GC_Line_Border( const SwTableLine*& rpLine, void* pPara )
169 {
170 	_SwGCLineBorder* pGCPara = (_SwGCLineBorder*)pPara;
171 
172 	// zuerst die rechte Kante mit der linken Kante der naechsten Box
173 	// innerhalb dieser Line
174 	{
175 		_SwGCBorder_BoxBrd aBPara;
176 		const SvxBorderLine* pBrd;
177 		const SfxPoolItem* pItem;
178 		const SwTableBoxes& rBoxes = rpLine->GetTabBoxes();
179 		for( sal_uInt16 n = 0, nBoxes = rBoxes.Count() - 1; n < nBoxes; ++n )
180 		{
181 			SwTableBoxes aBoxes;
182 			{
183 				const SwTableBox* pBox = rBoxes[ n ];
184 				if( pBox->GetSttNd() )
185 					aBoxes.Insert( pBox, 0 );
186 				else
187 					lcl_GCBorder_GetLastBox_B( pBox, &aBoxes );
188 			}
189 
190 			SwTableBox* pBox;
191 			for( sal_uInt16 i = aBoxes.Count(); i; )
192 				if( SFX_ITEM_SET == (pBox = aBoxes[ --i ])->GetFrmFmt()->
193 					GetItemState( RES_BOX, sal_True, &pItem ) &&
194 					0 != ( pBrd = ((SvxBoxItem*)pItem)->GetRight() ) )
195 				{
196 					aBPara.SetBorder( *pBrd );
197 					const SwTableBox* pNextBox = rBoxes[n+1];
198 					if( lcl_GCBorder_ChkBoxBrd_B( pNextBox, &aBPara ) &&
199 						aBPara.IsAnyBorderFound() )
200 					{
201 						SvxBoxItem aBox( *(SvxBoxItem*)pItem );
202 						aBox.SetLine( 0, BOX_LINE_RIGHT );
203 						if( pGCPara->pShareFmts )
204 							pGCPara->pShareFmts->SetAttr( *pBox, aBox );
205 						else
206                             pBox->ClaimFrmFmt()->SetFmtAttr( aBox );
207 					}
208 				}
209 
210 			aBoxes.Remove( 0, aBoxes.Count() );
211 		}
212 	}
213 
214 	// und jetzt die eigene untere Kante mit der nachfolgenden oberen Kante
215 	if( !pGCPara->IsLastLine() )
216 	{
217 		SwCollectTblLineBoxes aBottom( sal_False );
218 		SwCollectTblLineBoxes aTop( sal_True );
219 
220 		::lcl_Line_CollectBox( rpLine, &aBottom );
221 
222 		const SwTableLine* pNextLine = (*pGCPara->pLines)[ pGCPara->nLinePos+1 ];
223 		::lcl_Line_CollectBox( pNextLine, &aTop );
224 
225 		// dann entferne mal alle "doppelten" gleichen Lines
226 		sal_uInt16 nBtmPos, nTopPos,
227 				nSttBtm = 0, nSttTop = 0,
228 				nEndBtm = aBottom.Count(), nEndTop = aTop.Count();
229 
230 		const SwTableBox *pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos ),
231 						 *pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
232 		const SfxPoolItem *pBtmItem = 0, *pTopItem = 0;
233 		const SvxBorderLine *pBtmLine(0), *pTopLine(0);
234 		sal_Bool bGetTopItem = sal_True, bGetBtmItem = sal_True;
235 
236 		do {
237 			if( bGetBtmItem )
238 				pBtmLine = lcl_GCBorder_GetBorder( *pBtmBox, sal_False, &pBtmItem );
239 			if( bGetTopItem )
240 				pTopLine = lcl_GCBorder_GetBorder( *pTopBox, sal_True, &pTopItem );
241 
242 			if( pTopLine && pBtmLine && *pTopLine == *pBtmLine )
243 			{
244 				// dann kann einer entfernt werden, aber welche?
245 				sal_uInt16 nSavSttBtm = nSttBtm, nSavSttTop = nSttTop;
246 				sal_uInt16 nBtmEndPos = ::lcl_FindEndPosOfBorder( aBottom,
247 												*pTopLine, nSttBtm, sal_False );
248 				if( !nBtmEndPos ) nBtmEndPos = nBtmPos;
249 				sal_uInt16 nTopEndPos = ::lcl_FindEndPosOfBorder( aTop,
250 												*pTopLine, nSttTop, sal_True );
251 				if( !nTopEndPos ) nTopEndPos = nTopPos;
252 
253 
254 				if( nTopEndPos <= nBtmEndPos )
255 				{
256 					// dann die TopBorder bis zur BottomEndPos loeschen
257 					nSttTop = nSavSttTop;
258 					if( nTopPos <= nBtmEndPos )
259 						lcl_GCBorder_DelBorder( aTop, --nSttTop, sal_True,
260 											*pBtmLine, pTopItem, nBtmEndPos,
261 											pGCPara->pShareFmts );
262 					else
263 						nSttBtm = nSavSttBtm;
264 				}
265 				else
266 				{
267 					// sonst die BottomBorder bis zur TopEndPos loeschen
268 					nSttBtm = nSavSttBtm;
269 					if( nBtmPos <= nTopEndPos )
270 						lcl_GCBorder_DelBorder( aBottom, --nSttBtm, sal_False,
271 											*pTopLine, pBtmItem, nTopEndPos,
272 											pGCPara->pShareFmts );
273 					else
274 						nSttTop = nSavSttTop;
275 				}
276 				nTopPos = nBtmPos;
277 			}
278 
279 			if( nTopPos == nBtmPos )
280 			{
281 				if( nSttBtm >= nEndBtm || nSttTop >= nEndTop )
282 					break;
283 
284 				pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
285 				pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
286 				bGetTopItem = bGetBtmItem = sal_True;
287 			}
288 			else if( nTopPos < nBtmPos )
289 			{
290 				if( nSttTop >= nEndTop )
291 					break;
292 				pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
293 				bGetTopItem = sal_True;
294 				bGetBtmItem = sal_False;
295 			}
296 			else
297 			{
298 				if( nSttBtm >= nEndBtm )
299 					break;
300 				pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
301 				bGetTopItem = sal_False;
302 				bGetBtmItem = sal_True;
303 			}
304 
305 		} while( sal_True );
306 	}
307 
308 	((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_GC_Box_Border, pPara );
309 
310 	++pGCPara->nLinePos;
311 
312 	return sal_True;
313 }
314 
lcl_GC_Box_Border(const SwTableBox * & rpBox,void * pPara)315 sal_Bool lcl_GC_Box_Border( const SwTableBox*& rpBox, void* pPara )
316 {
317 	if( rpBox->GetTabLines().Count() )
318 	{
319 		_SwGCLineBorder aPara( *rpBox );
320 		aPara.pShareFmts = ((_SwGCLineBorder*)pPara)->pShareFmts;
321 		((SwTableBox*)rpBox)->GetTabLines().ForEach( &lcl_GC_Line_Border, &aPara );
322 	}
323 	return sal_True;
324 }
325 
326 struct _GCLinePara
327 {
328 	SwTableLines* pLns;
329 	SwShareBoxFmts* pShareFmts;
330 
_GCLinePara_GCLinePara331 	_GCLinePara( SwTableLines& rLns, _GCLinePara* pPara = 0 )
332 		: pLns( &rLns ), pShareFmts( pPara ? pPara->pShareFmts : 0 )
333 	{}
334 };
335 
lcl_MergeGCBox(const SwTableBox * & rpTblBox,void * pPara)336 sal_Bool lcl_MergeGCBox( const SwTableBox*& rpTblBox, void* pPara )
337 {
338 	SwTableBox*& rpBox = (SwTableBox*&)rpTblBox;
339 	sal_uInt16 n, nLen = rpBox->GetTabLines().Count();
340 	if( nLen )
341 	{
342 		// ACHTUNG: die Anzahl der Lines kann sich aendern!
343 		_GCLinePara aPara( rpBox->GetTabLines(), (_GCLinePara*)pPara );
344 		for( n = 0; n < rpBox->GetTabLines().Count() &&
345 			lcl_MergeGCLine( *(rpBox->GetTabLines().GetData() + n), &aPara );
346 			++n )
347 			;
348 
349 		if( 1 == rpBox->GetTabLines().Count() )
350 		{
351 			// Box mit einer Line, dann verschiebe alle Boxen der Line
352 			// hinter diese Box in der Parent-Line und loesche diese Box
353 			SwTableLine* pInsLine = rpBox->GetUpper();
354 			SwTableLine* pCpyLine = rpBox->GetTabLines()[0];
355 			sal_uInt16 nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, rpBox );
356 			for( n = 0; n < pCpyLine->GetTabBoxes().Count(); ++n )
357 				pCpyLine->GetTabBoxes()[n]->SetUpper( pInsLine );
358 
359 			pInsLine->GetTabBoxes().Insert( &pCpyLine->GetTabBoxes(), nInsPos+1 );
360 			pCpyLine->GetTabBoxes().Remove( 0, n );
361 			// loesche alte die Box mit der Line
362 			pInsLine->GetTabBoxes().DeleteAndDestroy( nInsPos );
363 
364 			return sal_False;		// neu aufsetzen
365 		}
366 	}
367 	return sal_True;
368 }
369 
lcl_MergeGCLine(const SwTableLine * & rpLine,void * pPara)370 sal_Bool lcl_MergeGCLine( const SwTableLine*& rpLine, void* pPara )
371 {
372 	SwTableLine* pLn = (SwTableLine*)rpLine;
373 	sal_uInt16 nLen = pLn->GetTabBoxes().Count();
374 	if( nLen )
375 	{
376 		_GCLinePara* pGCPara = (_GCLinePara*)pPara;
377 		while( 1 == nLen )
378 		{
379 			// es gibt eine Box mit Lines
380 			SwTableBox* pBox = pLn->GetTabBoxes()[0];
381 			if( !pBox->GetTabLines().Count() )
382 				break;
383 
384 			SwTableLine* pLine = pBox->GetTabLines()[0];
385 
386 			// pLine wird zu der aktuellen, also der rpLine,
387 			// die restlichen werden ins LinesArray hinter der akt.
388 			// verschoben.
389 			// Das LinesArray ist im pPara!
390 			nLen = pBox->GetTabLines().Count();
391 
392 			SwTableLines& rLns = *pGCPara->pLns;
393 			const SwTableLine* pTmp = pLn;
394 			sal_uInt16 nInsPos = rLns.GetPos( pTmp );
395 			ASSERT( USHRT_MAX != nInsPos, "Line nicht gefunden!" );
396 
397 			SwTableBox* pUpper = pLn->GetUpper();
398 
399 			rLns.Remove( nInsPos, 1 );		// die Line dem aus Array loeschen
400 			rLns.Insert( &pBox->GetTabLines(), nInsPos );
401 
402 			// JP 31.03.99: Bug 60000 - die Attribute der zu loeschenden
403 			// Line an die "eingefuegten" uebertragen
404 			const SfxPoolItem* pItem;
405 			if( SFX_ITEM_SET == pLn->GetFrmFmt()->GetItemState(
406 									RES_BACKGROUND, sal_True, &pItem ))
407 			{
408 				SwTableLines& rBoxLns = pBox->GetTabLines();
409 				for( sal_uInt16 nLns = 0; nLns < nLen; ++nLns )
410 					if( SFX_ITEM_SET != rBoxLns[ nLns ]->GetFrmFmt()->
411 							GetItemState( RES_BACKGROUND, sal_True ))
412 						pGCPara->pShareFmts->SetAttr( *rBoxLns[ nLns ], *pItem );
413 			}
414 
415 			pBox->GetTabLines().Remove( 0, nLen );	// Lines aus Array loeschen
416 
417 			delete pLn;
418 
419 			// Abhaengigkeit neu setzen
420 			while( nLen-- )
421 				rLns[ nInsPos++ ]->SetUpper( pUpper );
422 
423 			pLn = pLine;						// und neu setzen
424 			nLen = pLn->GetTabBoxes().Count();
425 		}
426 
427 		// ACHTUNG: die Anzahl der Boxen kann sich aendern!
428 		for( nLen = 0; nLen < pLn->GetTabBoxes().Count(); ++nLen )
429 			if( !lcl_MergeGCBox( *(pLn->GetTabBoxes().GetData() + nLen ), pPara ))
430 				--nLen;
431 	}
432 	return sal_True;
433 }
434 
435 		// Struktur ein wenig aufraeumen
GCLines()436 void SwTable::GCLines()
437 {
438 	// ACHTUNG: die Anzahl der Lines kann sich aendern!
439 	_GCLinePara aPara( GetTabLines() );
440 	SwShareBoxFmts aShareFmts;
441 	aPara.pShareFmts = &aShareFmts;
442 	for( sal_uInt16 n = 0; n < GetTabLines().Count() &&
443 			lcl_MergeGCLine( *(GetTabLines().GetData() + n ), &aPara ); ++n )
444 		;
445 }
446 
447 
448