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