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