Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <com/sun/star/chart2/XChartDocument.hpp>
21 : #include <fesh.hxx>
22 : #include <hintids.hxx>
23 : #include <hints.hxx>
24 :
25 : #include <vcl/svapp.hxx>
26 : #include <vcl/window.hxx>
27 : #include <editeng/boxitem.hxx>
28 : #include <swwait.hxx>
29 : #include <fmtfsize.hxx>
30 : #include <frmatr.hxx>
31 : #include <editsh.hxx>
32 : #include <doc.hxx>
33 : #include <IDocumentUndoRedo.hxx>
34 : #include <IDocumentChartDataProviderAccess.hxx>
35 : #include <IDocumentFieldsAccess.hxx>
36 : #include <IDocumentState.hxx>
37 : #include <cntfrm.hxx>
38 : #include <pam.hxx>
39 : #include <ndtxt.hxx>
40 : #include <fldbas.hxx>
41 : #include <swtable.hxx>
42 : #include <swundo.hxx>
43 : #include <tblsel.hxx>
44 : #include <edimp.hxx>
45 : #include <tabfrm.hxx>
46 : #include <cellfrm.hxx>
47 : #include <cellatr.hxx>
48 : #include <swtblfmt.hxx>
49 : #include <swddetbl.hxx>
50 : #include <mdiexp.hxx>
51 : #include <unochart.hxx>
52 :
53 : using namespace ::com::sun::star;
54 : using namespace ::com::sun::star::uno;
55 :
56 : //Added for bug #i119954# Application crashed if undo/redo covert nest table to text
57 : bool ConvertTableToText( const SwTableNode *pTableNode, sal_Unicode cCh );
58 :
59 0 : void ConvertNestedTablesToText( const SwTableLines &rTableLines, sal_Unicode cCh )
60 : {
61 0 : for (size_t n = 0; n < rTableLines.size(); ++n)
62 : {
63 0 : SwTableLine* pTableLine = rTableLines[ n ];
64 0 : for (size_t i = 0; i < pTableLine->GetTabBoxes().size(); ++i)
65 : {
66 0 : SwTableBox* pTableBox = pTableLine->GetTabBoxes()[ i ];
67 0 : if (pTableBox->GetTabLines().empty())
68 : {
69 0 : SwNodeIndex nodeIndex( *pTableBox->GetSttNd(), 1 );
70 0 : SwNodeIndex endNodeIndex( *pTableBox->GetSttNd()->EndOfSectionNode() );
71 0 : for( ; nodeIndex < endNodeIndex ; ++nodeIndex )
72 : {
73 0 : if ( SwTableNode* pTableNode = nodeIndex.GetNode().GetTableNode() )
74 0 : ConvertTableToText( pTableNode, cCh );
75 0 : }
76 : }
77 : else
78 : {
79 0 : ConvertNestedTablesToText( pTableBox->GetTabLines(), cCh );
80 : }
81 : }
82 : }
83 0 : }
84 :
85 0 : bool ConvertTableToText( const SwTableNode *pConstTableNode, sal_Unicode cCh )
86 : {
87 0 : SwTableNode *pTableNode = const_cast< SwTableNode* >( pConstTableNode );
88 0 : ConvertNestedTablesToText( pTableNode->GetTable().GetTabLines(), cCh );
89 0 : return pTableNode->GetDoc()->TableToText( pTableNode, cCh );
90 : }
91 : //End for bug #i119954#
92 :
93 1 : const SwTable& SwEditShell::InsertTable( const SwInsertTableOptions& rInsTableOpts,
94 : sal_uInt16 nRows, sal_uInt16 nCols,
95 : sal_Int16 eAdj,
96 : const SwTableAutoFormat* pTAFormat )
97 : {
98 1 : StartAllAction();
99 1 : SwPosition* pPos = GetCrsr()->GetPoint();
100 :
101 1 : bool bEndUndo = 0 != pPos->nContent.GetIndex();
102 1 : if( bEndUndo )
103 : {
104 0 : StartUndo( UNDO_START );
105 0 : GetDoc()->getIDocumentContentOperations().SplitNode( *pPos, false );
106 : }
107 :
108 : // If called from a shell the adjust item is propagated
109 : // from pPos to the new content nodes in the table.
110 : const SwTable *pTable = GetDoc()->InsertTable( rInsTableOpts, *pPos,
111 : nRows, nCols,
112 : eAdj, pTAFormat,
113 1 : 0, true );
114 1 : if( bEndUndo )
115 0 : EndUndo( UNDO_END );
116 :
117 1 : EndAllAction();
118 1 : return *pTable;
119 : }
120 :
121 0 : bool SwEditShell::TextToTable( const SwInsertTableOptions& rInsTableOpts,
122 : sal_Unicode cCh,
123 : sal_Int16 eAdj,
124 : const SwTableAutoFormat* pTAFormat )
125 : {
126 0 : SwWait aWait( *GetDoc()->GetDocShell(), true );
127 0 : bool bRet = false;
128 0 : StartAllAction();
129 0 : for(SwPaM& rPaM : GetCrsr()->GetRingContainer())
130 : {
131 0 : if( rPaM.HasMark() )
132 : bRet |= 0 != GetDoc()->TextToTable( rInsTableOpts, rPaM, cCh,
133 0 : eAdj, pTAFormat );
134 : }
135 0 : EndAllAction();
136 0 : return bRet;
137 : }
138 :
139 0 : bool SwEditShell::TableToText( sal_Unicode cCh )
140 : {
141 0 : SwWait aWait( *GetDoc()->GetDocShell(), true );
142 0 : bool bRet = false;
143 0 : SwPaM* pCrsr = GetCrsr();
144 : const SwTableNode* pTableNd =
145 0 : GetDoc()->IsIdxInTable( pCrsr->GetPoint()->nNode );
146 0 : if( IsTableMode() )
147 : {
148 0 : ClearMark();
149 0 : pCrsr = GetCrsr();
150 : }
151 0 : else if( !pTableNd || pCrsr->GetNext() != pCrsr )
152 0 : return bRet;
153 :
154 : // TL_CHART2:
155 : // tell the charts about the table to be deleted and have them use their own data
156 0 : GetDoc()->getIDocumentChartDataProviderAccess().CreateChartInternalDataProviders( &pTableNd->GetTable() );
157 :
158 0 : StartAllAction();
159 :
160 : // move current Cursor out of the listing area
161 0 : SwNodeIndex aTabIdx( *pTableNd );
162 0 : pCrsr->DeleteMark();
163 0 : pCrsr->GetPoint()->nNode = *pTableNd->EndOfSectionNode();
164 0 : pCrsr->GetPoint()->nContent.Assign( 0, 0 );
165 : // move sPoint and Mark out of the area!
166 0 : pCrsr->SetMark();
167 0 : pCrsr->DeleteMark();
168 :
169 : //Modified for bug #i119954# Application crashed if undo/redo covert nest table to text
170 0 : StartUndo();
171 0 : bRet = ConvertTableToText( pTableNd, cCh );
172 0 : EndUndo();
173 : //End for bug #i119954#
174 0 : pCrsr->GetPoint()->nNode = aTabIdx;
175 :
176 0 : SwContentNode* pCNd = pCrsr->GetContentNode();
177 0 : if( !pCNd )
178 0 : pCrsr->Move( fnMoveForward, fnGoContent );
179 : else
180 0 : pCrsr->GetPoint()->nContent.Assign( pCNd, 0 );
181 :
182 0 : EndAllAction();
183 0 : return bRet;
184 : }
185 :
186 0 : bool SwEditShell::IsTextToTableAvailable() const
187 : {
188 0 : bool bOnlyText = false;
189 0 : for(SwPaM& rPaM : GetCrsr()->GetRingContainer())
190 : {
191 0 : if( rPaM.HasMark() && *rPaM.GetPoint() != *rPaM.GetMark() )
192 : {
193 0 : bOnlyText = true;
194 :
195 : // check if selection is in listing
196 0 : sal_uLong nStt = rPaM.GetMark()->nNode.GetIndex(),
197 0 : nEnd = rPaM.GetPoint()->nNode.GetIndex();
198 0 : if( nStt > nEnd ) { sal_uLong n = nStt; nStt = nEnd; nEnd = n; }
199 :
200 0 : for( ; nStt <= nEnd; ++nStt )
201 0 : if( !GetDoc()->GetNodes()[ nStt ]->IsTextNode() )
202 : {
203 0 : bOnlyText = false;
204 0 : break;
205 : }
206 :
207 0 : if( !bOnlyText )
208 0 : break;
209 : }
210 : }
211 :
212 0 : return bOnlyText;
213 : }
214 :
215 0 : void SwEditShell::InsertDDETable( const SwInsertTableOptions& rInsTableOpts,
216 : SwDDEFieldType* pDDEType,
217 : sal_uInt16 nRows, sal_uInt16 nCols,
218 : sal_Int16 eAdj )
219 : {
220 0 : SwPosition* pPos = GetCrsr()->GetPoint();
221 :
222 0 : StartAllAction();
223 :
224 0 : bool bEndUndo = 0 != pPos->nContent.GetIndex();
225 0 : if( bEndUndo )
226 : {
227 0 : StartUndo( UNDO_START );
228 0 : GetDoc()->getIDocumentContentOperations().SplitNode( *pPos, false );
229 : }
230 :
231 : const SwInsertTableOptions aInsTableOpts( rInsTableOpts.mnInsMode | tabopts::DEFAULT_BORDER,
232 0 : rInsTableOpts.mnRowsToRepeat );
233 : SwTable* pTable = const_cast<SwTable*>(GetDoc()->InsertTable( aInsTableOpts, *pPos,
234 0 : nRows, nCols, eAdj ));
235 :
236 0 : SwTableNode* pTableNode = const_cast<SwTableNode*>(pTable->GetTabSortBoxes()[ 0 ]->
237 0 : GetSttNd()->FindTableNode());
238 0 : SwDDETable* pDDETable = new SwDDETable( *pTable, pDDEType );
239 0 : pTableNode->SetNewTable( pDDETable ); // setze die DDE-Tabelle
240 :
241 0 : if( bEndUndo )
242 0 : EndUndo( UNDO_END );
243 :
244 0 : EndAllAction();
245 0 : }
246 :
247 : /** update fields of a listing */
248 215 : void SwEditShell::UpdateTable()
249 : {
250 215 : const SwTableNode* pTableNd = IsCrsrInTable();
251 :
252 : // Keine Arme keine Kekse
253 215 : if( pTableNd )
254 : {
255 215 : StartAllAction();
256 215 : if( DoesUndo() )
257 215 : StartUndo();
258 215 : EndAllTableBoxEdit();
259 215 : SwTableFormulaUpdate aTableUpdate( &pTableNd->GetTable() );
260 215 : GetDoc()->getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate );
261 215 : if( DoesUndo() )
262 215 : EndUndo();
263 215 : EndAllAction();
264 : }
265 215 : }
266 :
267 : // get/set Change Mode
268 :
269 0 : TableChgMode SwEditShell::GetTableChgMode() const
270 : {
271 : TableChgMode eMode;
272 0 : const SwTableNode* pTableNd = IsCrsrInTable();
273 0 : if( pTableNd )
274 0 : eMode = pTableNd->GetTable().GetTableChgMode();
275 : else
276 0 : eMode = GetTableChgDefaultMode();
277 0 : return eMode;
278 : }
279 :
280 0 : void SwEditShell::SetTableChgMode( TableChgMode eMode )
281 : {
282 0 : const SwTableNode* pTableNd = IsCrsrInTable();
283 :
284 0 : if( pTableNd )
285 : {
286 0 : const_cast<SwTable&>(pTableNd->GetTable()).SetTableChgMode( eMode );
287 0 : if( !GetDoc()->getIDocumentState().IsModified() ) // Bug 57028
288 : {
289 0 : GetDoc()->GetIDocumentUndoRedo().SetUndoNoResetModified();
290 : }
291 0 : GetDoc()->getIDocumentState().SetModified();
292 : }
293 0 : }
294 :
295 0 : bool SwEditShell::GetTableBoxFormulaAttrs( SfxItemSet& rSet ) const
296 : {
297 0 : SwSelBoxes aBoxes;
298 0 : if( IsTableMode() )
299 0 : ::GetTableSelCrs( *this, aBoxes );
300 : else
301 : {
302 : do {
303 0 : SwFrm *pFrm = GetCurrFrm();
304 0 : do {
305 0 : pFrm = pFrm->GetUpper();
306 0 : } while ( pFrm && !pFrm->IsCellFrm() );
307 0 : if ( pFrm )
308 : {
309 0 : SwTableBox *pBox = const_cast<SwTableBox*>(static_cast<const SwTableBox*>(static_cast<SwCellFrm*>(pFrm)->GetTabBox()));
310 0 : aBoxes.insert( pBox );
311 : }
312 : } while( false );
313 : }
314 :
315 0 : for (size_t n = 0; n < aBoxes.size(); ++n)
316 : {
317 0 : const SwTableBox* pSelBox = aBoxes[ n ];
318 0 : const SwTableBoxFormat* pTableFormat = static_cast<SwTableBoxFormat*>(pSelBox->GetFrameFormat());
319 0 : if( !n )
320 : {
321 : // Convert formulae into external presentation
322 0 : const SwTable& rTable = pSelBox->GetSttNd()->FindTableNode()->GetTable();
323 :
324 0 : SwTableFormulaUpdate aTableUpdate( &rTable );
325 0 : aTableUpdate.eFlags = TBL_BOXNAME;
326 0 : static_cast<SwDoc*>(GetDoc())->getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate );
327 :
328 0 : rSet.Put( pTableFormat->GetAttrSet() );
329 : }
330 : else
331 0 : rSet.MergeValues( pTableFormat->GetAttrSet() );
332 : }
333 0 : return 0 != rSet.Count();
334 : }
335 :
336 0 : void SwEditShell::SetTableBoxFormulaAttrs( const SfxItemSet& rSet )
337 : {
338 0 : SET_CURR_SHELL( this );
339 0 : SwSelBoxes aBoxes;
340 0 : if( IsTableMode() )
341 0 : ::GetTableSelCrs( *this, aBoxes );
342 : else
343 : {
344 : do {
345 0 : SwFrm *pFrm = GetCurrFrm();
346 0 : do {
347 0 : pFrm = pFrm->GetUpper();
348 0 : } while ( pFrm && !pFrm->IsCellFrm() );
349 0 : if ( pFrm )
350 : {
351 0 : SwTableBox *pBox = const_cast<SwTableBox*>(static_cast<const SwTableBox*>(static_cast<SwCellFrm*>(pFrm)->GetTabBox()));
352 0 : aBoxes.insert( pBox );
353 : }
354 : } while( false );
355 : }
356 :
357 : // When setting a formula, do not check further!
358 0 : if( SfxItemState::SET == rSet.GetItemState( RES_BOXATR_FORMULA ))
359 0 : ClearTableBoxContent();
360 :
361 0 : StartAllAction();
362 0 : GetDoc()->GetIDocumentUndoRedo().StartUndo( UNDO_START, NULL );
363 0 : for (size_t n = 0; n < aBoxes.size(); ++n)
364 : {
365 0 : GetDoc()->SetTableBoxFormulaAttrs( *aBoxes[ n ], rSet );
366 : }
367 0 : GetDoc()->GetIDocumentUndoRedo().EndUndo( UNDO_END, NULL );
368 0 : EndAllAction();
369 0 : }
370 :
371 0 : bool SwEditShell::IsTableBoxTextFormat() const
372 : {
373 0 : if( IsTableMode() )
374 0 : return false;
375 :
376 0 : const SwTableBox *pBox = 0;
377 : {
378 0 : SwFrm *pFrm = GetCurrFrm();
379 0 : do {
380 0 : pFrm = pFrm->GetUpper();
381 0 : } while ( pFrm && !pFrm->IsCellFrm() );
382 0 : if ( pFrm )
383 0 : pBox = static_cast<const SwTableBox*>(static_cast<SwCellFrm*>(pFrm)->GetTabBox());
384 : }
385 :
386 0 : if( !pBox )
387 0 : return false;
388 :
389 0 : sal_uInt32 nFormat = 0;
390 : const SfxPoolItem* pItem;
391 0 : if( SfxItemState::SET == pBox->GetFrameFormat()->GetAttrSet().GetItemState(
392 0 : RES_BOXATR_FORMAT, true, &pItem ))
393 : {
394 0 : nFormat = static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue();
395 0 : return GetDoc()->GetNumberFormatter()->IsTextFormat( nFormat ) ||
396 0 : static_cast<sal_uInt32>(css::util::NumberFormat::TEXT) == nFormat;
397 : }
398 :
399 0 : sal_uLong nNd = pBox->IsValidNumTextNd();
400 0 : if( ULONG_MAX == nNd )
401 0 : return true;
402 :
403 0 : const OUString& rText = GetDoc()->GetNodes()[ nNd ]->GetTextNode()->GetText();
404 0 : if( rText.isEmpty() )
405 0 : return false;
406 :
407 : double fVal;
408 0 : return !GetDoc()->GetNumberFormatter()->IsNumberFormat( rText, nFormat, fVal );
409 : }
410 :
411 0 : OUString SwEditShell::GetTableBoxText() const
412 : {
413 0 : OUString sRet;
414 0 : if( !IsTableMode() )
415 : {
416 0 : const SwTableBox *pBox = 0;
417 : {
418 0 : SwFrm *pFrm = GetCurrFrm();
419 0 : do {
420 0 : pFrm = pFrm->GetUpper();
421 0 : } while ( pFrm && !pFrm->IsCellFrm() );
422 0 : if ( pFrm )
423 0 : pBox = static_cast<const SwTableBox*>(static_cast<SwCellFrm*>(pFrm)->GetTabBox());
424 : }
425 :
426 : sal_uLong nNd;
427 0 : if( pBox && ULONG_MAX != ( nNd = pBox->IsValidNumTextNd() ) )
428 0 : sRet = GetDoc()->GetNodes()[ nNd ]->GetTextNode()->GetText();
429 : }
430 0 : return sRet;
431 : }
432 :
433 0 : bool SwEditShell::SplitTable( sal_uInt16 eMode )
434 : {
435 0 : bool bRet = false;
436 0 : SwPaM *pCrsr = GetCrsr();
437 0 : if( pCrsr->GetNode().FindTableNode() )
438 : {
439 0 : StartAllAction();
440 0 : GetDoc()->GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
441 :
442 0 : bRet = GetDoc()->SplitTable( *pCrsr->GetPoint(), eMode, true );
443 :
444 0 : GetDoc()->GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
445 0 : ClearFEShellTabCols();
446 0 : EndAllAction();
447 : }
448 0 : return bRet;
449 : }
450 :
451 0 : bool SwEditShell::MergeTable( bool bWithPrev, sal_uInt16 nMode )
452 : {
453 0 : bool bRet = false;
454 0 : SwPaM *pCrsr = GetCrsr();
455 0 : if( pCrsr->GetNode().FindTableNode() )
456 : {
457 0 : StartAllAction();
458 0 : GetDoc()->GetIDocumentUndoRedo().StartUndo(UNDO_EMPTY, NULL);
459 :
460 0 : bRet = GetDoc()->MergeTable( *pCrsr->GetPoint(), bWithPrev, nMode );
461 :
462 0 : GetDoc()->GetIDocumentUndoRedo().EndUndo(UNDO_EMPTY, NULL);
463 0 : ClearFEShellTabCols();
464 0 : EndAllAction();
465 : }
466 0 : return bRet;
467 : }
468 :
469 0 : bool SwEditShell::CanMergeTable( bool bWithPrev, bool* pChkNxtPrv ) const
470 : {
471 0 : bool bRet = false;
472 0 : const SwPaM *pCrsr = GetCrsr();
473 0 : const SwTableNode* pTableNd = pCrsr->GetNode().FindTableNode();
474 0 : if( pTableNd && !pTableNd->GetTable().ISA( SwDDETable ))
475 : {
476 0 : bool bNew = pTableNd->GetTable().IsNewModel();
477 0 : const SwNodes& rNds = GetDoc()->GetNodes();
478 0 : if( pChkNxtPrv )
479 : {
480 0 : const SwTableNode* pChkNd = rNds[ pTableNd->GetIndex() - 1 ]->FindTableNode();
481 0 : if( pChkNd && !pChkNd->GetTable().ISA( SwDDETable ) &&
482 0 : bNew == pChkNd->GetTable().IsNewModel() &&
483 : // Consider table in table case
484 0 : pChkNd->EndOfSectionIndex() == pTableNd->GetIndex() - 1 )
485 0 : *pChkNxtPrv = true, bRet = true; // using Prev is possible
486 : else
487 : {
488 0 : pChkNd = rNds[ pTableNd->EndOfSectionIndex() + 1 ]->GetTableNode();
489 0 : if( pChkNd && !pChkNd->GetTable().ISA( SwDDETable ) &&
490 0 : bNew == pChkNd->GetTable().IsNewModel() )
491 0 : *pChkNxtPrv = false, bRet = true; // using Next is possible
492 : }
493 : }
494 : else
495 : {
496 0 : const SwTableNode* pTmpTableNd = 0;
497 :
498 0 : if( bWithPrev )
499 : {
500 0 : pTmpTableNd = rNds[ pTableNd->GetIndex() - 1 ]->FindTableNode();
501 : // Consider table in table case
502 0 : if ( pTmpTableNd && pTmpTableNd->EndOfSectionIndex() != pTableNd->GetIndex() - 1 )
503 0 : pTmpTableNd = 0;
504 : }
505 : else
506 0 : pTmpTableNd = rNds[ pTableNd->EndOfSectionIndex() + 1 ]->GetTableNode();
507 :
508 0 : bRet = pTmpTableNd && !pTmpTableNd->GetTable().ISA( SwDDETable ) &&
509 0 : bNew == pTmpTableNd->GetTable().IsNewModel();
510 : }
511 : }
512 0 : return bRet;
513 : }
514 :
515 : /** create InsertDB as table Undo */
516 0 : void SwEditShell::AppendUndoForInsertFromDB( bool bIsTable )
517 : {
518 0 : GetDoc()->AppendUndoForInsertFromDB( *GetCrsr(), bIsTable );
519 177 : }
520 :
521 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|