xref: /trunk/main/sw/source/core/edit/edtab.cxx (revision 8ef2f12b)
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 #include <com/sun/star/chart2/XChartDocument.hpp>
28 #include <hintids.hxx>
29 #include <hints.hxx>
30 
31 #define _SVSTDARR_ULONGS
32 #include <svl/svstdarr.hxx>
33 
34 #include <vcl/svapp.hxx>
35 #include <vcl/window.hxx>
36 #include <editeng/boxitem.hxx>
37 #include <swwait.hxx>
38 #include <fmtfsize.hxx>
39 #include <frmatr.hxx>
40 #include <editsh.hxx>
41 #include <doc.hxx>
42 #include <IDocumentUndoRedo.hxx>
43 #include <cntfrm.hxx>
44 #include <pam.hxx>
45 #include <ndtxt.hxx>
46 #include <fldbas.hxx>
47 #include <swtable.hxx>
48 #include <swundo.hxx>
49 #include <tblsel.hxx>
50 #include <edimp.hxx>
51 #include <tabfrm.hxx>
52 #include <cellfrm.hxx>
53 #include <cellatr.hxx>
54 #include <swtblfmt.hxx>
55 #include <swddetbl.hxx>
56 #include <mdiexp.hxx>
57 #include <unochart.hxx>
58 
59 using namespace ::com::sun::star;
60 using namespace ::com::sun::star::uno;
61 
62 extern void ClearFEShellTabCols();
63 
64 //Added for bug 119954:Application crashed if undo/redo covert nest table to text
65 sal_Bool ConvertTableToText( const SwTableNode *pTableNode, sal_Unicode cCh );
66 
ConvertNestedTablesToText(const SwTableLines & rTableLines,sal_Unicode cCh)67 void	ConvertNestedTablesToText( const SwTableLines &rTableLines, sal_Unicode cCh )
68 {
69 	for( sal_uInt16 n = 0; n < rTableLines.Count(); ++n )
70 	{
71 		SwTableLine* pTableLine = rTableLines[ n ];
72 		for( sal_uInt16 i = 0; i < pTableLine->GetTabBoxes().Count(); ++i )
73 		{
74 			SwTableBox* pTableBox = pTableLine->GetTabBoxes()[ i ];
75 			if ( !pTableBox->GetTabLines().Count() )
76 			{
77 				SwNodeIndex nodeIndex( *pTableBox->GetSttNd(), 1 );
78 				SwNodeIndex endNodeIndex( *pTableBox->GetSttNd()->EndOfSectionNode() );
79 				for( ; nodeIndex < endNodeIndex ; nodeIndex++ )
80 				{
81 					if ( SwTableNode* pTableNode = nodeIndex.GetNode().GetTableNode() )
82 						ConvertTableToText( pTableNode, cCh );
83 				}
84 			}
85 			else
86 			{
87 				ConvertNestedTablesToText( pTableBox->GetTabLines(), cCh );
88 			}
89 		}
90 	}
91 }
92 
ConvertTableToText(const SwTableNode * pConstTableNode,sal_Unicode cCh)93 sal_Bool ConvertTableToText( const SwTableNode *pConstTableNode, sal_Unicode cCh )
94 {
95 	SwTableNode *pTableNode = const_cast< SwTableNode* >( pConstTableNode );
96 	ConvertNestedTablesToText( pTableNode->GetTable().GetTabLines(), cCh );
97 	return pTableNode->GetDoc()->TableToText( pTableNode, cCh );
98 }
99 //End for bug 119954
InsertTable(const SwInsertTableOptions & rInsTblOpts,sal_uInt16 nRows,sal_uInt16 nCols,sal_Int16 eAdj,const SwTableAutoFmt * pTAFmt)100 const SwTable& SwEditShell::InsertTable( const SwInsertTableOptions& rInsTblOpts,
101                                          sal_uInt16 nRows, sal_uInt16 nCols,
102                                          sal_Int16 eAdj,
103                                          const SwTableAutoFmt* pTAFmt )
104 {
105 	StartAllAction();
106 	SwPosition* pPos = GetCrsr()->GetPoint();
107 
108 	sal_Bool bEndUndo = 0 != pPos->nContent.GetIndex();
109 	if( bEndUndo )
110 	{
111 		StartUndo( UNDO_START );
112 		GetDoc()->SplitNode( *pPos, false );
113 	}
114 
115     /* #109161# If called from a shell the adjust item is propagated
116         from pPos to the new content nodes in the table.
117      */
118     const SwTable *pTable = GetDoc()->InsertTable( rInsTblOpts, *pPos,
119                                                    nRows, nCols,
120                                                    eAdj, pTAFmt,
121                                                    0, sal_True );
122 	if( bEndUndo )
123 		EndUndo( UNDO_END );
124 
125 	EndAllAction();
126 	return *pTable;
127 }
128 
TextToTable(const SwInsertTableOptions & rInsTblOpts,sal_Unicode cCh,sal_Int16 eAdj,const SwTableAutoFmt * pTAFmt)129 sal_Bool SwEditShell::TextToTable( const SwInsertTableOptions& rInsTblOpts,
130                                sal_Unicode cCh,
131                                sal_Int16 eAdj,
132                                const SwTableAutoFmt* pTAFmt )
133 {
134 	SwWait aWait( *GetDoc()->GetDocShell(), true );
135 	sal_Bool bRet = sal_False;
136 	StartAllAction();
137 	FOREACHPAM_START(this)
138 		if( PCURCRSR->HasMark() )
139             bRet |= 0 != GetDoc()->TextToTable( rInsTblOpts, *PCURCRSR, cCh,
140                                                 eAdj, pTAFmt );
141 	FOREACHPAM_END()
142 	EndAllAction();
143 	return bRet;
144 }
145 
TableToText(sal_Unicode cCh)146 sal_Bool SwEditShell::TableToText( sal_Unicode cCh )
147 {
148 	SwWait aWait( *GetDoc()->GetDocShell(), true );
149 	sal_Bool bRet = sal_False;
150 	SwPaM* pCrsr = GetCrsr();
151 	const SwTableNode* pTblNd =
152 			GetDoc()->IsIdxInTbl( pCrsr->GetPoint()->nNode );
153 	if( IsTableMode() )
154 	{
155 		ClearMark();
156 		pCrsr = GetCrsr();
157 	}
158 	else if( !pTblNd || pCrsr->GetNext() != pCrsr )
159 		return bRet;
160 
161     // TL_CHART2:
162     // tell the charts about the table to be deleted and have them use their own data
163     GetDoc()->CreateChartInternalDataProviders( &pTblNd->GetTable() );
164 
165 	StartAllAction();
166 
167 	// verschiebe den akt. Cursor aus dem Tabellen Bereich
168 	// angemeldet ist
169 	SwNodeIndex aTabIdx( *pTblNd );
170 	pCrsr->DeleteMark();
171 	pCrsr->GetPoint()->nNode = *pTblNd->EndOfSectionNode();
172 	pCrsr->GetPoint()->nContent.Assign( 0, 0 );
173 	// SPoint und Mark aus dem Bereich verschieben !!!
174 	pCrsr->SetMark();
175 	pCrsr->DeleteMark();
176 
177 	//Modified for bug 119954:Application crashed if undo/redo covert nest table to text
178 	StartUndo();//UNDO_START
179 	bRet = ConvertTableToText( pTblNd, cCh );
180 	EndUndo();//UNDO_END
181 	//End  for bug 119954
182 	pCrsr->GetPoint()->nNode = aTabIdx;
183 
184 	SwCntntNode* pCNd = pCrsr->GetCntntNode();
185 	if( !pCNd )
186 		pCrsr->Move( fnMoveForward, fnGoCntnt );
187 	else
188 		pCrsr->GetPoint()->nContent.Assign( pCNd, 0 );
189 
190 	EndAllAction();
191 	return bRet;
192 }
193 
IsTextToTableAvailable() const194 sal_Bool SwEditShell::IsTextToTableAvailable() const
195 {
196 	sal_Bool bOnlyText = sal_False;
197 	FOREACHPAM_START(this)
198 		if( PCURCRSR->HasMark() && *PCURCRSR->GetPoint() != *PCURCRSR->GetMark() )
199 		{
200 			bOnlyText = sal_True;
201 
202 			// pruefe ob in der Selection eine Tabelle liegt
203 			sal_uLong nStt = PCURCRSR->GetMark()->nNode.GetIndex(),
204 				  nEnd = PCURCRSR->GetPoint()->nNode.GetIndex();
205 			if( nStt > nEnd )	{ sal_uLong n = nStt; nStt = nEnd; nEnd = n; }
206 
207 			for( ; nStt <= nEnd; ++nStt )
208 				if( !GetDoc()->GetNodes()[ nStt ]->IsTxtNode() )
209 				{
210 					bOnlyText = sal_False;
211 					break;
212 				}
213 
214 			if( !bOnlyText )
215 				break;
216 		}
217 	FOREACHPAM_END()
218 
219 	return bOnlyText;
220 }
221 
InsertDDETable(const SwInsertTableOptions & rInsTblOpts,SwDDEFieldType * pDDEType,sal_uInt16 nRows,sal_uInt16 nCols,sal_Int16 eAdj)222 void SwEditShell::InsertDDETable( const SwInsertTableOptions& rInsTblOpts,
223                                   SwDDEFieldType* pDDEType,
224                                   sal_uInt16 nRows, sal_uInt16 nCols,
225                                   sal_Int16 eAdj )
226 {
227 	SwPosition* pPos = GetCrsr()->GetPoint();
228 
229 	StartAllAction();
230 
231 	sal_Bool bEndUndo = 0 != pPos->nContent.GetIndex();
232 	if( bEndUndo )
233 	{
234 		StartUndo( UNDO_START );
235 		GetDoc()->SplitNode( *pPos, false );
236 	}
237 
238     const SwInsertTableOptions aInsTblOpts( rInsTblOpts.mnInsMode | tabopts::DEFAULT_BORDER,
239                                             rInsTblOpts.mnRowsToRepeat );
240     SwTable* pTbl = (SwTable*)GetDoc()->InsertTable( aInsTblOpts, *pPos,
241                                                      nRows, nCols, eAdj );
242 
243     SwTableNode* pTblNode = (SwTableNode*)pTbl->GetTabSortBoxes()[ 0 ]->
244 												GetSttNd()->FindTableNode();
245 	SwDDETable* pDDETbl = new SwDDETable( *pTbl, pDDEType );
246 	pTblNode->SetNewTable( pDDETbl );		// setze die DDE-Tabelle
247 
248 	if( bEndUndo )
249 		EndUndo( UNDO_END );
250 
251 	EndAllAction();
252 }
253 
254 /*--------------------------------------------------------------------
255 	Beschreibung: Tabellenfelder einer Tabelle updaten
256  --------------------------------------------------------------------*/
UpdateTable()257 void SwEditShell::UpdateTable()
258 {
259 	const SwTableNode* pTblNd = IsCrsrInTbl();
260 
261 	// Keine Arme keine Kekse
262 	if( pTblNd )
263 	{
264 		StartAllAction();
265         if( DoesUndo() )
266             StartUndo();
267 		EndAllTblBoxEdit();
268 		SwTableFmlUpdate aTblUpdate( (SwTable*)&pTblNd->GetTable() );
269 		GetDoc()->UpdateTblFlds( &aTblUpdate );
270         if( DoesUndo() )
271             EndUndo();
272 		EndAllAction();
273 	}
274 }
275 
276 	// Change Modus erfragen/setzen
GetTblChgMode() const277 TblChgMode SwEditShell::GetTblChgMode() const
278 {
279     TblChgMode eMode;
280 	const SwTableNode* pTblNd = IsCrsrInTbl();
281 	if( pTblNd )
282         eMode = pTblNd->GetTable().GetTblChgMode();
283 	else
284         eMode = GetTblChgDefaultMode();
285     return eMode;
286 }
287 
SetTblChgMode(TblChgMode eMode)288 void SwEditShell::SetTblChgMode( TblChgMode eMode )
289 {
290 	const SwTableNode* pTblNd = IsCrsrInTbl();
291 
292 	// Keine Arme keine Kekse
293 	if( pTblNd )
294 	{
295         ((SwTable&)pTblNd->GetTable()).SetTblChgMode( eMode );
296 		if( !GetDoc()->IsModified() )	// Bug 57028
297         {
298             GetDoc()->GetIDocumentUndoRedo().SetUndoNoResetModified();
299         }
300 		GetDoc()->SetModified();
301 	}
302 }
303 
GetTblBoxFormulaAttrs(SfxItemSet & rSet) const304 sal_Bool SwEditShell::GetTblBoxFormulaAttrs( SfxItemSet& rSet ) const
305 {
306 	SwSelBoxes aBoxes;
307 	if( IsTableMode() )
308 		::GetTblSelCrs( *this, aBoxes );
309 	else
310 	{
311         do {
312 			SwFrm *pFrm = GetCurrFrm();
313 			do {
314 				pFrm = pFrm->GetUpper();
315 			} while ( pFrm && !pFrm->IsCellFrm() );
316 			if ( pFrm )
317 			{
318 				SwTableBox *pBox = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox();
319 				aBoxes.Insert( pBox );
320 			}
321         } while( sal_False );
322     }
323 
324 	for( sal_uInt16 n = 0; n < aBoxes.Count(); ++n )
325 	{
326 		const SwTableBox* pSelBox = aBoxes[ n ];
327 		const SwTableBoxFmt* pTblFmt = (SwTableBoxFmt*)pSelBox->GetFrmFmt();
328 		if( !n )
329 		{
330 			// Formeln in die externe Darstellung bringen!
331 			const SwTable& rTbl = pSelBox->GetSttNd()->FindTableNode()->GetTable();
332 
333 			SwTableFmlUpdate aTblUpdate( (SwTable*)&rTbl );
334 			aTblUpdate.eFlags = TBL_BOXNAME;
335 			((SwDoc*)GetDoc())->UpdateTblFlds( &aTblUpdate );
336 
337 			rSet.Put( pTblFmt->GetAttrSet() );
338 		}
339 		else
340 			rSet.MergeValues( pTblFmt->GetAttrSet() );
341 	}
342 	return 0 != rSet.Count();
343 }
344 
SetTblBoxFormulaAttrs(const SfxItemSet & rSet)345 void SwEditShell::SetTblBoxFormulaAttrs( const SfxItemSet& rSet )
346 {
347 	SET_CURR_SHELL( this );
348 	SwSelBoxes aBoxes;
349 	if( IsTableMode() )
350 		::GetTblSelCrs( *this, aBoxes );
351 	else
352 	{
353         do {
354 			SwFrm *pFrm = GetCurrFrm();
355 			do {
356 				pFrm = pFrm->GetUpper();
357 			} while ( pFrm && !pFrm->IsCellFrm() );
358 			if ( pFrm )
359 			{
360 				SwTableBox *pBox = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox();
361 				aBoxes.Insert( pBox );
362 			}
363         } while( sal_False );
364     }
365 
366 	// beim setzen einer Formel keine Ueberpruefung mehr vornehmen!
367 	if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMULA ))
368 		ClearTblBoxCntnt();
369 
370 	StartAllAction();
371     GetDoc()->GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL );
372 	for( sal_uInt16 n = 0; n < aBoxes.Count(); ++n )
373 		GetDoc()->SetTblBoxFormulaAttrs( *aBoxes[ n ], rSet );
374     GetDoc()->GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
375 	EndAllAction();
376 }
377 
IsTableBoxTextFormat() const378 sal_Bool SwEditShell::IsTableBoxTextFormat() const
379 {
380 	if( IsTableMode() )
381 		return sal_False;
382 
383 	SwTableBox *pBox = 0;
384     {
385 		SwFrm *pFrm = GetCurrFrm();
386 		do {
387 			pFrm = pFrm->GetUpper();
388 		} while ( pFrm && !pFrm->IsCellFrm() );
389 		if ( pFrm )
390 			pBox = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox();
391 	}
392 
393 	if( !pBox )
394 		return sal_False;
395 
396 	sal_uInt32 nFmt;
397 	const SfxPoolItem* pItem;
398 	if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetAttrSet().GetItemState(
399 		RES_BOXATR_FORMAT, sal_True, &pItem ))
400 	{
401 		nFmt = ((SwTblBoxNumFormat*)pItem)->GetValue();
402 		return GetDoc()->GetNumberFormatter()->IsTextFormat( nFmt ) ||
403 				NUMBERFORMAT_TEXT == nFmt;
404 	}
405 
406 	sal_uLong nNd = pBox->IsValidNumTxtNd();
407 	if( ULONG_MAX == nNd )
408 		return sal_True;
409 
410 	const String& rTxt = GetDoc()->GetNodes()[ nNd ]->GetTxtNode()->GetTxt();
411 	if( !rTxt.Len() )
412 		return sal_False;
413 
414 	double fVal;
415 	return !GetDoc()->GetNumberFormatter()->IsNumberFormat( rTxt, nFmt, fVal );
416 }
417 
GetTableBoxText() const418 String SwEditShell::GetTableBoxText() const
419 {
420 	String sRet;
421 	if( !IsTableMode() )
422 	{
423 		SwTableBox *pBox = 0;
424         {
425 			SwFrm *pFrm = GetCurrFrm();
426 			do {
427 				pFrm = pFrm->GetUpper();
428 			} while ( pFrm && !pFrm->IsCellFrm() );
429 			if ( pFrm )
430 				pBox = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox();
431 		}
432 
433 		sal_uLong nNd;
434 		if( pBox && ULONG_MAX != ( nNd = pBox->IsValidNumTxtNd() ) )
435 			sRet = GetDoc()->GetNodes()[ nNd ]->GetTxtNode()->GetTxt();
436 	}
437 	return sRet;
438 }
439 
SplitTable(sal_uInt16 eMode)440 sal_Bool SwEditShell::SplitTable( sal_uInt16 eMode )
441 {
442 	sal_Bool bRet = sal_False;
443 	SwPaM *pCrsr = GetCrsr();
444 	if( pCrsr->GetNode()->FindTableNode() )
445 	{
446 		StartAllAction();
447         GetDoc()->GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
448 
449 		bRet = GetDoc()->SplitTable( *pCrsr->GetPoint(), eMode, sal_True );
450 
451         GetDoc()->GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
452 		ClearFEShellTabCols();
453 		EndAllAction();
454 	}
455 	return bRet;
456 }
457 
MergeTable(sal_Bool bWithPrev,sal_uInt16 nMode)458 sal_Bool SwEditShell::MergeTable( sal_Bool bWithPrev, sal_uInt16 nMode )
459 {
460 	sal_Bool bRet = sal_False;
461 	SwPaM *pCrsr = GetCrsr();
462 	if( pCrsr->GetNode()->FindTableNode() )
463 	{
464 		StartAllAction();
465         GetDoc()->GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
466 
467 		bRet = GetDoc()->MergeTable( *pCrsr->GetPoint(), bWithPrev, nMode );
468 
469         GetDoc()->GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
470 		ClearFEShellTabCols();
471 		EndAllAction();
472 	}
473 	return bRet;
474 }
475 
CanMergeTable(sal_Bool bWithPrev,sal_Bool * pChkNxtPrv) const476 sal_Bool SwEditShell::CanMergeTable( sal_Bool bWithPrev, sal_Bool* pChkNxtPrv ) const
477 {
478 	sal_Bool bRet = sal_False;
479 	const SwPaM *pCrsr = GetCrsr();
480 	const SwTableNode* pTblNd = pCrsr->GetNode()->FindTableNode();
481 	if( pTblNd && !pTblNd->GetTable().ISA( SwDDETable ))
482 	{
483         sal_Bool bNew = pTblNd->GetTable().IsNewModel();
484 		const SwNodes& rNds = GetDoc()->GetNodes();
485 		if( pChkNxtPrv )
486 		{
487             const SwTableNode* pChkNd = rNds[ pTblNd->GetIndex() - 1 ]->FindTableNode();
488 			if( pChkNd && !pChkNd->GetTable().ISA( SwDDETable ) &&
489                 bNew == pChkNd->GetTable().IsNewModel() &&
490                 // --> FME 2004-09-17 #117418# Consider table in table case
491                 pChkNd->EndOfSectionIndex() == pTblNd->GetIndex() - 1 )
492                 // <--
493 				*pChkNxtPrv = sal_True, bRet = sal_True;		// mit Prev ist moeglich
494 			else
495 			{
496 				pChkNd = rNds[ pTblNd->EndOfSectionIndex() + 1 ]->GetTableNode();
497 				if( pChkNd && !pChkNd->GetTable().ISA( SwDDETable ) &&
498                     bNew == pChkNd->GetTable().IsNewModel() )
499 					*pChkNxtPrv = sal_False, bRet = sal_True;		// mit Next ist moeglich
500 			}
501 		}
502 		else
503 		{
504             const SwTableNode* pTmpTblNd = 0;
505 
506             if( bWithPrev )
507             {
508                 pTmpTblNd = rNds[ pTblNd->GetIndex() - 1 ]->FindTableNode();
509                 // --> FME 2004-09-17 #117418# Consider table in table case
510                 if ( pTmpTblNd && pTmpTblNd->EndOfSectionIndex() != pTblNd->GetIndex() - 1 )
511                     pTmpTblNd = 0;
512                 // <--
513             }
514             else
515                 pTmpTblNd = rNds[ pTblNd->EndOfSectionIndex() + 1 ]->GetTableNode();
516 
517             bRet = pTmpTblNd && !pTmpTblNd->GetTable().ISA( SwDDETable ) &&
518                    bNew == pTmpTblNd->GetTable().IsNewModel();
519 		}
520 	}
521 	return bRet;
522 }
523 
524 		// setze das InsertDB als Tabelle Undo auf:
AppendUndoForInsertFromDB(sal_Bool bIsTable)525 void SwEditShell::AppendUndoForInsertFromDB( sal_Bool bIsTable )
526 {
527 	GetDoc()->AppendUndoForInsertFromDB( *GetCrsr(), bIsTable );
528 }
529 
530