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