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 <hintids.hxx>
21 :
22 : #include <vcl/svapp.hxx>
23 : #include <editeng/protitem.hxx>
24 : #include <crsrsh.hxx>
25 : #include <doc.hxx>
26 : #include <cntfrm.hxx>
27 : #include <editsh.hxx>
28 : #include <pam.hxx>
29 : #include <swtable.hxx>
30 : #include <docary.hxx>
31 : #include <frmatr.hxx>
32 : #include <frmfmt.hxx>
33 : #include <viscrs.hxx>
34 : #include <callnk.hxx>
35 : #include <tabfrm.hxx>
36 : #include <ndtxt.hxx>
37 : #include <shellres.hxx>
38 : #include <cellatr.hxx>
39 : #include <cellfrm.hxx>
40 : #include <rowfrm.hxx>
41 :
42 : /// set cursor into next/previous cell
43 0 : sal_Bool SwCrsrShell::GoNextCell( sal_Bool bAppendLine )
44 : {
45 0 : sal_Bool bRet = sal_False;
46 0 : const SwTableNode* pTblNd = 0;
47 :
48 0 : if( IsTableMode() || 0 != ( pTblNd = IsCrsrInTbl() ))
49 : {
50 0 : SwCursor* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
51 0 : SwCallLink aLk( *this ); // watch Crsr-Moves
52 0 : bRet = sal_True;
53 :
54 : // Check if we have to move the cursor to a covered cell before
55 : // proceeding:
56 0 : const SwNode* pTableBoxStartNode = pCrsr->GetNode()->FindTableBoxStartNode();
57 0 : const SwTableBox* pTableBox = 0;
58 :
59 0 : if ( pCrsr->GetCrsrRowSpanOffset() )
60 : {
61 0 : pTableBox = pTableBoxStartNode->GetTblBox();
62 0 : if ( pTableBox->getRowSpan() > 1 )
63 : {
64 0 : if ( !pTblNd )
65 0 : pTblNd = IsCrsrInTbl();
66 0 : pTableBox = & pTableBox->FindEndOfRowSpan( pTblNd->GetTable(),
67 0 : (sal_uInt16)(pTableBox->getRowSpan() + pCrsr->GetCrsrRowSpanOffset() ) );
68 0 : pTableBoxStartNode = pTableBox->GetSttNd();
69 : }
70 : }
71 :
72 0 : SwNodeIndex aCellStt( *pTableBoxStartNode->EndOfSectionNode(), 1 );
73 :
74 : // if there is another StartNode after the EndNode of a cell then
75 : // there is another cell
76 0 : if( !aCellStt.GetNode().IsStartNode() )
77 : {
78 0 : if( pCrsr->HasMark() || !bAppendLine )
79 0 : bRet = sal_False;
80 : else
81 : {
82 : // if there is no list anymore then create new one
83 0 : if ( !pTableBox )
84 0 : pTableBox = pTblNd->GetTable().GetTblBox(
85 0 : pCrsr->GetPoint()->nNode.GetNode().
86 0 : StartOfSectionIndex() );
87 :
88 : OSL_ENSURE( pTableBox, "Box is not in this table" );
89 0 : SwSelBoxes aBoxes;
90 :
91 : // the document might change; w/o Action views would not be notified
92 0 : ((SwEditShell*)this)->StartAllAction();
93 0 : bRet = pDoc->InsertRow( pTblNd->GetTable().
94 0 : SelLineFromBox( pTableBox, aBoxes, false ));
95 0 : ((SwEditShell*)this)->EndAllAction();
96 : }
97 : }
98 0 : if( bRet && 0 != ( bRet = pCrsr->GoNextCell() ))
99 0 : UpdateCrsr();
100 : }
101 0 : return bRet;
102 : }
103 :
104 :
105 0 : sal_Bool SwCrsrShell::GoPrevCell()
106 : {
107 0 : sal_Bool bRet = sal_False;
108 0 : if( IsTableMode() || IsCrsrInTbl() )
109 : {
110 0 : SwCursor* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
111 0 : SwCallLink aLk( *this ); // watch Crsr-Moves
112 0 : bRet = pCrsr->GoPrevCell();
113 0 : if( bRet )
114 0 : UpdateCrsr(); // update current cursor
115 : }
116 0 : return bRet;
117 : }
118 :
119 0 : static const SwFrm* lcl_FindMostUpperCellFrm( const SwFrm* pFrm )
120 : {
121 0 : while ( pFrm &&
122 0 : ( !pFrm->IsCellFrm() ||
123 0 : !pFrm->GetUpper()->GetUpper()->IsTabFrm() ||
124 0 : pFrm->GetUpper()->GetUpper()->GetUpper()->IsInTab() ) )
125 : {
126 0 : pFrm = pFrm->GetUpper();
127 : }
128 0 : return pFrm;
129 : }
130 :
131 0 : bool SwCrsrShell::_SelTblRowOrCol( bool bRow, bool bRowSimple )
132 : {
133 : // check if the current cursor's SPoint/Mark are in a table
134 0 : SwFrm *pFrm = GetCurrFrm();
135 0 : if( !pFrm->IsInTab() )
136 0 : return false;
137 :
138 0 : const SwTabFrm* pTabFrm = pFrm->FindTabFrm();
139 0 : const SwTabFrm* pMasterTabFrm = pTabFrm->IsFollow() ? pTabFrm->FindMaster( true ) : pTabFrm;
140 0 : const SwTable* pTable = pTabFrm->GetTable();
141 :
142 0 : SET_CURR_SHELL( this );
143 :
144 0 : const SwTableBox* pStt = 0;
145 0 : const SwTableBox* pEnd = 0;
146 :
147 : // search box based on layout
148 0 : SwSelBoxes aBoxes;
149 0 : SwTblSearchType eType = bRow ? nsSwTblSearchType::TBLSEARCH_ROW : nsSwTblSearchType::TBLSEARCH_COL;
150 0 : const bool bCheckProtected = !IsReadOnlyAvailable();
151 :
152 0 : if( bCheckProtected )
153 0 : eType = (SwTblSearchType)(eType | nsSwTblSearchType::TBLSEARCH_PROTECT);
154 :
155 0 : if ( !bRowSimple )
156 : {
157 0 : GetTblSel( *this, aBoxes, eType );
158 :
159 0 : if( aBoxes.empty() )
160 0 : return false;
161 :
162 0 : pStt = aBoxes[0];
163 0 : pEnd = aBoxes.back();
164 : }
165 : // #i32329# Enhanced table selection
166 0 : else if ( pTable->IsNewModel() )
167 : {
168 0 : const SwShellCrsr *pCrsr = _GetCrsr();
169 0 : SwTable::SearchType eSearchType = bRow ? SwTable::SEARCH_ROW : SwTable::SEARCH_COL;
170 0 : pTable->CreateSelection( *pCrsr, aBoxes, eSearchType, bCheckProtected );
171 0 : if( aBoxes.empty() )
172 0 : return false;
173 :
174 0 : pStt = aBoxes[0];
175 0 : pEnd = aBoxes.back();
176 : }
177 : else
178 : {
179 0 : const SwShellCrsr *pCrsr = _GetCrsr();
180 0 : const SwFrm* pStartFrm = pFrm;
181 0 : const SwCntntNode *pCNd = pCrsr->GetCntntNode( sal_False );
182 0 : const SwFrm* pEndFrm = pCNd ? pCNd->getLayoutFrm( GetLayout(), &pCrsr->GetMkPos() ) : 0;
183 :
184 0 : if ( bRow )
185 : {
186 0 : pStartFrm = lcl_FindMostUpperCellFrm( pStartFrm );
187 0 : pEndFrm = lcl_FindMostUpperCellFrm( pEndFrm );
188 : }
189 :
190 0 : if ( !pStartFrm || !pEndFrm )
191 0 : return false;
192 :
193 0 : const bool bVert = pFrm->ImplFindTabFrm()->IsVertical();
194 :
195 : // If we select upwards it is sufficient to set pStt and pEnd
196 : // to the first resp. last box of the selection obtained from
197 : // GetTblSel. However, selecting downwards requires the frames
198 : // located at the corners of the selection. This does not work
199 : // for column selections in vertical tables:
200 0 : const bool bSelectUp = ( bVert && !bRow ) ||
201 0 : *pCrsr->GetPoint() <= *pCrsr->GetMark();
202 0 : SwCellFrms aCells;
203 : GetTblSel( static_cast<const SwCellFrm*>(pStartFrm),
204 : static_cast<const SwCellFrm*>(pEndFrm),
205 0 : aBoxes, bSelectUp ? 0 : &aCells, eType );
206 :
207 0 : if( aBoxes.empty() || ( !bSelectUp && 4 != aCells.size() ) )
208 0 : return false;
209 :
210 0 : if ( bSelectUp )
211 : {
212 0 : pStt = aBoxes[0];
213 0 : pEnd = aBoxes.back();
214 : }
215 : else
216 : {
217 : // will become point of table cursor
218 0 : pStt = aCells[ bVert ? (bRow ? 0 : 3) : (bRow ? 2 : 1) ]->GetTabBox();
219 : // will become mark of table cursor
220 0 : pEnd = aCells[ bVert ? (bRow ? 3 : 0) : (bRow ? 1 : 2) ]->GetTabBox();
221 0 : }
222 : }
223 :
224 : // if no table cursor exists, create one
225 0 : if( !pTblCrsr )
226 : {
227 0 : pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() );
228 0 : pCurCrsr->DeleteMark();
229 0 : pCurCrsr->SwSelPaintRects::Hide();
230 : }
231 :
232 0 : pTblCrsr->DeleteMark();
233 :
234 : // set start and end of a column
235 0 : pTblCrsr->GetPoint()->nNode = *pEnd->GetSttNd();
236 0 : pTblCrsr->Move( fnMoveForward, fnGoCntnt );
237 0 : pTblCrsr->SetMark();
238 0 : pTblCrsr->GetPoint()->nNode = *pStt->GetSttNd()->EndOfSectionNode();
239 0 : pTblCrsr->Move( fnMoveBackward, fnGoCntnt );
240 :
241 : // set PtPos 'close' to the reference table, otherwise we might get problems
242 : // with the repeated headlines check in UpdateCrsr():
243 0 : if ( !bRow )
244 0 : pTblCrsr->GetPtPos() = pMasterTabFrm->IsVertical()
245 0 : ? pMasterTabFrm->Frm().TopRight()
246 0 : : pMasterTabFrm->Frm().TopLeft();
247 :
248 0 : UpdateCrsr();
249 0 : return true;
250 : }
251 :
252 0 : sal_Bool SwCrsrShell::SelTbl()
253 : {
254 : // check if the current cursor's SPoint/Mark are in a table
255 0 : SwFrm *pFrm = GetCurrFrm();
256 0 : if( !pFrm->IsInTab() )
257 0 : return sal_False;
258 :
259 0 : const SwTabFrm *pTblFrm = pFrm->ImplFindTabFrm();
260 0 : const SwTabFrm* pMasterTabFrm = pTblFrm->IsFollow() ? pTblFrm->FindMaster( true ) : pTblFrm;
261 0 : const SwTableNode* pTblNd = pTblFrm->GetTable()->GetTableNode();
262 :
263 0 : SET_CURR_SHELL( this );
264 :
265 0 : if( !pTblCrsr )
266 : {
267 0 : pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() );
268 0 : pCurCrsr->DeleteMark();
269 0 : pCurCrsr->SwSelPaintRects::Hide();
270 : }
271 :
272 0 : pTblCrsr->DeleteMark();
273 0 : pTblCrsr->GetPoint()->nNode = *pTblNd;
274 0 : pTblCrsr->Move( fnMoveForward, fnGoCntnt );
275 0 : pTblCrsr->SetMark();
276 : // set MkPos 'close' to the master table, otherwise we might get problems
277 : // with the repeated headlines check in UpdateCrsr():
278 0 : pTblCrsr->GetMkPos() = pMasterTabFrm->IsVertical() ? pMasterTabFrm->Frm().TopRight() : pMasterTabFrm->Frm().TopLeft();
279 0 : pTblCrsr->GetPoint()->nNode = *pTblNd->EndOfSectionNode();
280 0 : pTblCrsr->Move( fnMoveBackward, fnGoCntnt );
281 0 : UpdateCrsr();
282 0 : return sal_True;
283 : }
284 :
285 :
286 0 : sal_Bool SwCrsrShell::SelTblBox()
287 : {
288 : // if we're in a table, create a table cursor, and select the cell
289 : // that the current cursor's point resides in
290 :
291 : // search for start node of our table box. If not found, exit realy
292 : const SwStartNode* pStartNode =
293 0 : pCurCrsr->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
294 :
295 : #if OSL_DEBUG_LEVEL > 0
296 : // the old code checks whether we're in a table by asking the
297 : // frame. This should yield the same result as searching for the
298 : // table box start node, right?
299 : SwFrm *pFrm = GetCurrFrm();
300 : OSL_ENSURE( !pFrm->IsInTab() == !(pStartNode != NULL),
301 : "Schroedinger's table: We're in a box, and also we aren't." );
302 : #endif
303 :
304 0 : if( pStartNode == NULL )
305 0 : return sal_False;
306 :
307 :
308 0 : SET_CURR_SHELL( this );
309 :
310 : // create a table cursor, if there isn't one already
311 0 : if( !pTblCrsr )
312 : {
313 0 : pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() );
314 0 : pCurCrsr->DeleteMark();
315 0 : pCurCrsr->SwSelPaintRects::Hide();
316 : }
317 :
318 : // select the complete box with our shiny new pTblCrsr
319 : // 1. delete mark, and move point to first content node in box
320 :
321 0 : pTblCrsr->DeleteMark();
322 0 : *(pTblCrsr->GetPoint()) = SwPosition( *pStartNode );
323 0 : pTblCrsr->Move( fnMoveForward, fnGoNode );
324 :
325 : // 2. set mark, and move point to last content node in box
326 0 : pTblCrsr->SetMark();
327 0 : *(pTblCrsr->GetPoint()) = SwPosition( *(pStartNode->EndOfSectionNode()) );
328 0 : pTblCrsr->Move( fnMoveBackward, fnGoNode );
329 :
330 : // 3. exchange
331 0 : pTblCrsr->Exchange();
332 :
333 : // with some luck, UpdateCrsr() will now update everything that
334 : // needs updateing
335 0 : UpdateCrsr();
336 :
337 0 : return sal_True;
338 : }
339 :
340 : // TODO: provide documentation
341 : /** get the next non-protected cell inside a table
342 :
343 : @param[in,out] rIdx is on a table node
344 : @param bInReadOnly ???
345 :
346 : @return <false> if no suitable cell could be found, otherwise <rIdx> points
347 : to content in a suitable cell and <true> is returned.
348 : */
349 0 : static bool lcl_FindNextCell( SwNodeIndex& rIdx, sal_Bool bInReadOnly )
350 : {
351 : // check protected cells
352 0 : SwNodeIndex aTmp( rIdx, 2 ); // TableNode + StartNode
353 :
354 : // the resulting cell should be in that table:
355 0 : const SwTableNode* pTblNd = rIdx.GetNode().GetTableNode();
356 :
357 0 : if ( !pTblNd )
358 : {
359 : OSL_FAIL( "lcl_FindNextCell not celled with table start node!" );
360 0 : return false;
361 : }
362 :
363 0 : const SwNode* pTableEndNode = pTblNd->EndOfSectionNode();
364 :
365 0 : SwNodes& rNds = aTmp.GetNode().GetNodes();
366 0 : SwCntntNode* pCNd = aTmp.GetNode().GetCntntNode();
367 :
368 : // no content node => go to next content node
369 0 : if( !pCNd )
370 0 : pCNd = rNds.GoNext( &aTmp );
371 :
372 : // robust
373 0 : if ( !pCNd )
374 0 : return false;
375 :
376 0 : SwCntntFrm* pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() );
377 :
378 0 : if ( 0 == pFrm || pCNd->FindTableNode() != pTblNd ||
379 0 : (!bInReadOnly && pFrm->IsProtected() ) )
380 : {
381 : // we are not located inside a 'valid' cell. We have to continue searching...
382 :
383 : // skip behind current section. This might be the end of the table cell
384 : // or behind a inner section or or or...
385 0 : aTmp.Assign( *pCNd->EndOfSectionNode(), 1 );
386 :
387 : // loop to find a suitable cell...
388 0 : for( ;; )
389 : {
390 0 : SwNode* pNd = &aTmp.GetNode();
391 :
392 : // we break this loop if we reached the end of the table.
393 : // to make this code even more robust, we also break if we are
394 : // already behind the table end node:
395 0 : if( pNd == pTableEndNode || /*robust: */ pNd->GetIndex() > pTableEndNode->GetIndex() )
396 0 : return false;
397 :
398 : // ok, get the next content node:
399 0 : pCNd = aTmp.GetNode().GetCntntNode();
400 0 : if( 0 == pCNd )
401 0 : pCNd = rNds.GoNext( &aTmp );
402 :
403 : // robust:
404 0 : if ( !pCNd )
405 0 : return false;
406 :
407 : // check if we have found a suitable table cell:
408 0 : pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() );
409 :
410 0 : if ( 0 != pFrm && pCNd->FindTableNode() == pTblNd &&
411 0 : (bInReadOnly || !pFrm->IsProtected() ) )
412 : {
413 : // finally, we have found a suitable table cell => set index and return
414 0 : rIdx = *pCNd;
415 0 : return true;
416 : }
417 :
418 : // continue behind the current section:
419 0 : aTmp.Assign( *pCNd->EndOfSectionNode(), +1 );
420 : }
421 : }
422 :
423 0 : rIdx = *pCNd;
424 0 : return true;
425 : }
426 :
427 : /// see lcl_FindNextCell()
428 0 : static bool lcl_FindPrevCell( SwNodeIndex& rIdx, sal_Bool bInReadOnly )
429 : {
430 0 : SwNodeIndex aTmp( rIdx, -2 ); // TableNode + EndNode
431 :
432 0 : const SwNode* pTableEndNode = &rIdx.GetNode();
433 0 : const SwTableNode* pTblNd = pTableEndNode->StartOfSectionNode()->GetTableNode();
434 :
435 0 : if ( !pTblNd )
436 : {
437 : OSL_FAIL( "lcl_FindPrevCell not celled with table start node!" );
438 0 : return false;
439 : }
440 :
441 0 : SwNodes& rNds = aTmp.GetNode().GetNodes();
442 0 : SwCntntNode* pCNd = aTmp.GetNode().GetCntntNode();
443 :
444 0 : if( !pCNd )
445 0 : pCNd = rNds.GoPrevious( &aTmp );
446 :
447 0 : if ( !pCNd )
448 0 : return false;
449 :
450 0 : SwCntntFrm* pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() );
451 :
452 0 : if( 0 == pFrm || pCNd->FindTableNode() != pTblNd ||
453 0 : (!bInReadOnly && pFrm->IsProtected() ))
454 : {
455 : // skip before current section
456 0 : aTmp.Assign( *pCNd->StartOfSectionNode(), -1 );
457 0 : for( ;; )
458 : {
459 0 : SwNode* pNd = &aTmp.GetNode();
460 :
461 0 : if( pNd == pTblNd || pNd->GetIndex() < pTblNd->GetIndex() )
462 0 : return false;
463 :
464 0 : pCNd = aTmp.GetNode().GetCntntNode();
465 0 : if( 0 == pCNd )
466 0 : pCNd = rNds.GoPrevious( &aTmp );
467 :
468 0 : if ( !pCNd )
469 0 : return false;
470 :
471 0 : pFrm = pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() );
472 :
473 0 : if( 0 != pFrm && pCNd->FindTableNode() == pTblNd &&
474 0 : (bInReadOnly || !pFrm->IsProtected() ) )
475 : {
476 0 : rIdx = *pCNd;
477 0 : return true; // ok, not protected
478 : }
479 0 : aTmp.Assign( *pCNd->StartOfSectionNode(), - 1 );
480 : }
481 : }
482 :
483 0 : rIdx = *pCNd;
484 0 : return true;
485 : }
486 :
487 :
488 0 : sal_Bool GotoPrevTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl,
489 : sal_Bool bInReadOnly )
490 : {
491 0 : SwNodeIndex aIdx( rCurCrsr.GetPoint()->nNode );
492 :
493 0 : SwTableNode* pTblNd = aIdx.GetNode().FindTableNode();
494 0 : if( pTblNd )
495 : {
496 : // #i26532#: If we are inside a table, we may not go backward to the
497 : // table start node, because we would miss any tables inside this table.
498 0 : SwTableNode* pInnerTblNd = 0;
499 0 : SwNodeIndex aTmpIdx( aIdx );
500 0 : while( aTmpIdx.GetIndex() &&
501 0 : 0 == ( pInnerTblNd = aTmpIdx.GetNode().StartOfSectionNode()->GetTableNode()) )
502 0 : aTmpIdx--;
503 :
504 0 : if( pInnerTblNd == pTblNd )
505 0 : aIdx.Assign( *pTblNd, - 1 );
506 : }
507 :
508 0 : do {
509 0 : while( aIdx.GetIndex() &&
510 0 : 0 == ( pTblNd = aIdx.GetNode().StartOfSectionNode()->GetTableNode()) )
511 0 : aIdx--;
512 :
513 0 : if( pTblNd ) // any further table node?
514 : {
515 0 : if( fnPosTbl == fnMoveForward ) // at the beginning?
516 : {
517 0 : aIdx = *aIdx.GetNode().StartOfSectionNode();
518 0 : if( !lcl_FindNextCell( aIdx, bInReadOnly ))
519 : {
520 : // skip table
521 0 : aIdx.Assign( *pTblNd, -1 );
522 0 : continue;
523 : }
524 : }
525 : else
526 : {
527 : // check protected cells
528 0 : if( !lcl_FindNextCell( aIdx, bInReadOnly ))
529 : {
530 : // skip table
531 0 : aIdx.Assign( *pTblNd, -1 );
532 0 : continue;
533 : }
534 : }
535 :
536 0 : SwTxtNode* pTxtNode = aIdx.GetNode().GetTxtNode();
537 0 : if ( pTxtNode )
538 : {
539 0 : rCurCrsr.GetPoint()->nNode = *pTxtNode;
540 0 : rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ?
541 0 : pTxtNode->Len() :
542 0 : 0 );
543 : }
544 0 : return sal_True;
545 : }
546 : } while( pTblNd );
547 :
548 0 : return sal_False;
549 : }
550 :
551 :
552 0 : sal_Bool GotoNextTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl,
553 : sal_Bool bInReadOnly )
554 : {
555 0 : SwNodeIndex aIdx( rCurCrsr.GetPoint()->nNode );
556 0 : SwTableNode* pTblNd = aIdx.GetNode().FindTableNode();
557 :
558 0 : if( pTblNd )
559 0 : aIdx.Assign( *pTblNd->EndOfSectionNode(), 1 );
560 :
561 0 : sal_uLong nLastNd = rCurCrsr.GetDoc()->GetNodes().Count() - 1;
562 0 : do {
563 0 : while( aIdx.GetIndex() < nLastNd &&
564 0 : 0 == ( pTblNd = aIdx.GetNode().GetTableNode()) )
565 0 : ++aIdx;
566 0 : if( pTblNd ) // any further table node?
567 : {
568 0 : if( fnPosTbl == fnMoveForward ) // at the beginning?
569 : {
570 0 : if( !lcl_FindNextCell( aIdx, bInReadOnly ))
571 : {
572 : // skip table
573 0 : aIdx.Assign( *pTblNd->EndOfSectionNode(), + 1 );
574 0 : continue;
575 : }
576 : }
577 : else
578 : {
579 0 : aIdx = *aIdx.GetNode().EndOfSectionNode();
580 : // check protected cells
581 0 : if( !lcl_FindNextCell( aIdx, bInReadOnly ))
582 : {
583 : // skip table
584 0 : aIdx.Assign( *pTblNd->EndOfSectionNode(), + 1 );
585 0 : continue;
586 : }
587 : }
588 :
589 0 : SwTxtNode* pTxtNode = aIdx.GetNode().GetTxtNode();
590 0 : if ( pTxtNode )
591 : {
592 0 : rCurCrsr.GetPoint()->nNode = *pTxtNode;
593 0 : rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ?
594 0 : pTxtNode->Len() :
595 0 : 0 );
596 : }
597 0 : return sal_True;
598 : }
599 : } while( pTblNd );
600 :
601 0 : return sal_False;
602 : }
603 :
604 :
605 0 : sal_Bool GotoCurrTable( SwPaM& rCurCrsr, SwPosTable fnPosTbl,
606 : sal_Bool bInReadOnly )
607 : {
608 0 : SwTableNode* pTblNd = rCurCrsr.GetPoint()->nNode.GetNode().FindTableNode();
609 0 : if( !pTblNd )
610 0 : return sal_False;
611 :
612 0 : SwTxtNode* pTxtNode = 0;
613 0 : if( fnPosTbl == fnMoveBackward ) // to the end of the table
614 : {
615 0 : SwNodeIndex aIdx( *pTblNd->EndOfSectionNode() );
616 0 : if( !lcl_FindPrevCell( aIdx, bInReadOnly ))
617 0 : return sal_False;
618 0 : pTxtNode = aIdx.GetNode().GetTxtNode();
619 : }
620 : else
621 : {
622 0 : SwNodeIndex aIdx( *pTblNd );
623 0 : if( !lcl_FindNextCell( aIdx, bInReadOnly ))
624 0 : return sal_False;
625 0 : pTxtNode = aIdx.GetNode().GetTxtNode();
626 : }
627 :
628 0 : if ( pTxtNode )
629 : {
630 0 : rCurCrsr.GetPoint()->nNode = *pTxtNode;
631 0 : rCurCrsr.GetPoint()->nContent.Assign( pTxtNode, fnPosTbl == fnMoveBackward ?
632 0 : pTxtNode->Len() :
633 0 : 0 );
634 : }
635 :
636 0 : return sal_True;
637 : }
638 :
639 :
640 0 : sal_Bool SwCursor::MoveTable( SwWhichTable fnWhichTbl, SwPosTable fnPosTbl )
641 : {
642 0 : sal_Bool bRet = sal_False;
643 0 : SwTableCursor* pTblCrsr = dynamic_cast<SwTableCursor*>(this);
644 :
645 0 : if( pTblCrsr || !HasMark() )
646 : {
647 0 : SwCrsrSaveState aSaveState( *this );
648 0 : bRet = (*fnWhichTbl)( *this, fnPosTbl, IsReadOnlyAvailable() ) &&
649 : !IsSelOvr( nsSwCursorSelOverFlags::SELOVER_CHECKNODESSECTION |
650 0 : nsSwCursorSelOverFlags::SELOVER_TOGGLE );
651 : }
652 0 : return bRet;
653 : }
654 :
655 0 : sal_Bool SwCrsrShell::MoveTable( SwWhichTable fnWhichTbl, SwPosTable fnPosTbl )
656 : {
657 0 : SwCallLink aLk( *this ); // watch Crsr-Moves; call Link if needed
658 :
659 0 : SwShellCrsr* pCrsr = pTblCrsr ? pTblCrsr : pCurCrsr;
660 : bool bCheckPos;
661 : sal_Bool bRet;
662 0 : sal_uLong nPtNd = 0;
663 0 : xub_StrLen nPtCnt = 0;
664 :
665 0 : if ( !pTblCrsr && pCurCrsr->HasMark() )
666 : {
667 : // switch to table mode
668 0 : pTblCrsr = new SwShellTableCrsr( *this, *pCurCrsr->GetPoint() );
669 0 : pCurCrsr->DeleteMark();
670 0 : pCurCrsr->SwSelPaintRects::Hide();
671 0 : pTblCrsr->SetMark();
672 0 : pCrsr = pTblCrsr;
673 0 : bCheckPos = false;
674 : }
675 : else
676 : {
677 0 : bCheckPos = true;
678 0 : nPtNd = pCrsr->GetPoint()->nNode.GetIndex();
679 0 : nPtCnt = pCrsr->GetPoint()->nContent.GetIndex();
680 : }
681 :
682 0 : bRet = pCrsr->MoveTable( fnWhichTbl, fnPosTbl );
683 :
684 0 : if( bRet )
685 : {
686 : // #i45028# - set "top" position for repeated headline rows
687 0 : pCrsr->GetPtPos() = Point();
688 :
689 0 : UpdateCrsr(SwCrsrShell::SCROLLWIN|SwCrsrShell::CHKRANGE|SwCrsrShell::READONLY);
690 :
691 0 : if( bCheckPos &&
692 0 : pCrsr->GetPoint()->nNode.GetIndex() == nPtNd &&
693 0 : pCrsr->GetPoint()->nContent.GetIndex() == nPtCnt )
694 0 : bRet = sal_False;
695 : }
696 0 : return bRet;
697 : }
698 :
699 0 : bool SwCrsrShell::IsTblComplexForChart()
700 : {
701 0 : bool bRet = false;
702 :
703 : // Here we may trigger table formatting so we better do that inside an action
704 0 : StartAction();
705 0 : const SwTableNode* pTNd = pCurCrsr->GetPoint()->nNode.GetNode().FindTableNode();
706 0 : if( pTNd )
707 : {
708 : // in a table; check if table or section is balanced
709 0 : String sSel;
710 0 : if( pTblCrsr )
711 0 : sSel = GetBoxNms();
712 0 : bRet = pTNd->GetTable().IsTblComplexForChart( sSel );
713 : }
714 :
715 0 : EndAction();
716 :
717 0 : return bRet;
718 : }
719 :
720 0 : String SwCrsrShell::GetBoxNms() const
721 : {
722 0 : String sNm;
723 : const SwPosition* pPos;
724 : SwFrm* pFrm;
725 :
726 0 : if( IsTableMode() )
727 : {
728 0 : SwCntntNode *pCNd = pTblCrsr->Start()->nNode.GetNode().GetCntntNode();
729 0 : pFrm = pCNd ? pCNd->getLayoutFrm( GetLayout() ) : 0;
730 0 : if( !pFrm )
731 0 : return sNm;
732 :
733 0 : do {
734 0 : pFrm = pFrm->GetUpper();
735 0 : } while ( pFrm && !pFrm->IsCellFrm() );
736 :
737 : OSL_ENSURE( pFrm, "no frame for this box" );
738 :
739 0 : if( !pFrm )
740 0 : return sNm;
741 :
742 0 : sNm = ((SwCellFrm*)pFrm)->GetTabBox()->GetName();
743 0 : sNm += ':';
744 0 : pPos = pTblCrsr->End();
745 : }
746 : else
747 : {
748 0 : const SwTableNode* pTblNd = IsCrsrInTbl();
749 0 : if( !pTblNd )
750 0 : return sNm;
751 0 : pPos = GetCrsr()->GetPoint();
752 : }
753 :
754 0 : SwCntntNode* pCNd = pPos->nNode.GetNode().GetCntntNode();
755 0 : pFrm = pCNd ? pCNd->getLayoutFrm( GetLayout() ) : 0;
756 :
757 0 : if( pFrm )
758 : {
759 0 : do {
760 0 : pFrm = pFrm->GetUpper();
761 0 : } while ( pFrm && !pFrm->IsCellFrm() );
762 :
763 0 : if( pFrm )
764 0 : sNm += ((SwCellFrm*)pFrm)->GetTabBox()->GetName();
765 : }
766 0 : return sNm;
767 : }
768 :
769 :
770 8 : bool SwCrsrShell::GotoTable( const String& rName )
771 : {
772 8 : SwCallLink aLk( *this ); // watch Crsr-Moves
773 8 : bool bRet = !pTblCrsr && pCurCrsr->GotoTable( rName );
774 8 : if( bRet )
775 : {
776 8 : pCurCrsr->GetPtPos() = Point();
777 : UpdateCrsr( SwCrsrShell::SCROLLWIN | SwCrsrShell::CHKRANGE |
778 8 : SwCrsrShell::READONLY );
779 : }
780 8 : return bRet;
781 : }
782 :
783 :
784 1279 : sal_Bool SwCrsrShell::CheckTblBoxCntnt( const SwPosition* pPos )
785 : {
786 1279 : if( !pBoxIdx || !pBoxPtr || IsSelTblCells() || !IsAutoUpdateCells() )
787 1279 : return sal_False;
788 :
789 : // check if box content is consistent with given box format, reset if not
790 0 : SwTableBox* pChkBox = 0;
791 0 : SwStartNode* pSttNd = 0;
792 0 : if( !pPos )
793 : {
794 : // get stored position
795 0 : if( pBoxIdx && pBoxPtr &&
796 0 : 0 != ( pSttNd = pBoxIdx->GetNode().GetStartNode() ) &&
797 0 : SwTableBoxStartNode == pSttNd->GetStartNodeType() &&
798 0 : pBoxPtr == pSttNd->FindTableNode()->GetTable().
799 0 : GetTblBox( pBoxIdx->GetIndex() ) )
800 0 : pChkBox = pBoxPtr;
801 : }
802 0 : else if( 0 != ( pSttNd = pPos->nNode.GetNode().
803 : FindSttNodeByType( SwTableBoxStartNode )) )
804 : {
805 0 : pChkBox = pSttNd->FindTableNode()->GetTable().GetTblBox( pSttNd->GetIndex() );
806 : }
807 :
808 : // box has more than one paragraph
809 0 : if( pChkBox && pSttNd->GetIndex() + 2 != pSttNd->EndOfSectionIndex() )
810 0 : pChkBox = 0;
811 :
812 : // destroy pointer before next action starts
813 0 : if( !pPos && !pChkBox )
814 0 : ClearTblBoxCntnt();
815 :
816 : // cursor not anymore in this section?
817 0 : if( pChkBox && !pPos &&
818 0 : ( pCurCrsr->HasMark() || pCurCrsr->GetNext() != pCurCrsr ||
819 0 : pSttNd->GetIndex() + 1 == pCurCrsr->GetPoint()->nNode.GetIndex() ))
820 0 : pChkBox = 0;
821 :
822 : // Did the content of a box change at all? This is important if e.g. Undo
823 : // could not restore the content properly.
824 0 : if( pChkBox )
825 : {
826 0 : const SwTxtNode* pNd = GetDoc()->GetNodes()[
827 0 : pSttNd->GetIndex() + 1 ]->GetTxtNode();
828 0 : if( !pNd ||
829 0 : ( pNd->GetTxt() == ViewShell::GetShellRes()->aCalc_Error &&
830 0 : SFX_ITEM_SET == pChkBox->GetFrmFmt()->
831 0 : GetItemState( RES_BOXATR_FORMULA )) )
832 0 : pChkBox = 0;
833 : }
834 :
835 0 : if( pChkBox )
836 : {
837 : // destroy pointer before next action starts
838 0 : ClearTblBoxCntnt();
839 0 : StartAction();
840 0 : GetDoc()->ChkBoxNumFmt( *pChkBox, sal_True );
841 0 : EndAction();
842 : }
843 :
844 0 : return 0 != pChkBox;
845 : }
846 :
847 :
848 0 : void SwCrsrShell::SaveTblBoxCntnt( const SwPosition* pPos )
849 : {
850 0 : if( IsSelTblCells() || !IsAutoUpdateCells() )
851 0 : return ;
852 :
853 0 : if( !pPos )
854 0 : pPos = pCurCrsr->GetPoint();
855 :
856 0 : SwStartNode* pSttNd = pPos->nNode.GetNode().FindSttNodeByType( SwTableBoxStartNode );
857 :
858 0 : bool bCheckBox = false;
859 0 : if( pSttNd && pBoxIdx )
860 : {
861 0 : if( pSttNd == &pBoxIdx->GetNode() )
862 0 : pSttNd = 0;
863 : else
864 0 : bCheckBox = true;
865 : }
866 : else
867 0 : bCheckBox = 0 != pBoxIdx;
868 :
869 0 : if( bCheckBox )
870 : {
871 : // check pBoxIdx
872 0 : SwPosition aPos( *pBoxIdx );
873 0 : CheckTblBoxCntnt( &aPos );
874 : }
875 :
876 0 : if( pSttNd )
877 : {
878 0 : pBoxPtr = pSttNd->FindTableNode()->GetTable().GetTblBox( pSttNd->GetIndex() );
879 :
880 0 : if( pBoxIdx )
881 0 : *pBoxIdx = *pSttNd;
882 : else
883 0 : pBoxIdx = new SwNodeIndex( *pSttNd );
884 : }
885 : }
886 :
887 :
888 63 : void SwCrsrShell::ClearTblBoxCntnt()
889 : {
890 63 : delete pBoxIdx, pBoxIdx = 0;
891 63 : pBoxPtr = 0;
892 63 : }
893 :
894 23 : sal_Bool SwCrsrShell::EndAllTblBoxEdit()
895 : {
896 23 : sal_Bool bRet = sal_False;
897 23 : ViewShell *pSh = this;
898 46 : do {
899 23 : if( pSh->IsA( TYPE( SwCrsrShell ) ) )
900 : bRet |= ((SwCrsrShell*)pSh)->CheckTblBoxCntnt(
901 23 : ((SwCrsrShell*)pSh)->pCurCrsr->GetPoint() );
902 :
903 23 : } while( this != (pSh = (ViewShell *)pSh->GetNext()) );
904 23 : return bRet;
905 : }
906 :
907 :
908 :
909 :
910 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|