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