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 <editsh.hxx>
21 : #include <doc.hxx>
22 : #include <IDocumentUndoRedo.hxx>
23 : #include <pam.hxx>
24 : #include <docary.hxx>
25 : #include <swundo.hxx>
26 : #include <section.hxx>
27 : #include <edimp.hxx>
28 : #include <sectfrm.hxx>
29 : #include <cntfrm.hxx>
30 : #include <tabfrm.hxx>
31 : #include <rootfrm.hxx>
32 :
33 : SwSection const*
34 0 : SwEditShell::InsertSection(
35 : SwSectionData & rNewData, SfxItemSet const*const pAttr)
36 : {
37 0 : const SwSection* pRet = 0;
38 0 : if( !IsTableMode() )
39 : {
40 0 : StartAllAction();
41 0 : GetDoc()->GetIDocumentUndoRedo().StartUndo( UNDO_INSSECTION, NULL );
42 :
43 0 : FOREACHPAM_START(GetCrsr())
44 : SwSection const*const pNew =
45 0 : GetDoc()->InsertSwSection( *PCURCRSR, rNewData, 0, pAttr );
46 0 : if( !pRet )
47 0 : pRet = pNew;
48 0 : FOREACHPAM_END()
49 :
50 0 : GetDoc()->GetIDocumentUndoRedo().EndUndo( UNDO_INSSECTION, NULL );
51 0 : EndAllAction();
52 : }
53 0 : return pRet;
54 : }
55 :
56 0 : sal_Bool SwEditShell::IsInsRegionAvailable() const
57 : {
58 0 : if( IsTableMode() )
59 0 : return sal_False;
60 0 : SwPaM* pCrsr = GetCrsr();
61 0 : if( pCrsr->GetNext() != pCrsr )
62 0 : return sal_False;
63 0 : if( pCrsr->HasMark() )
64 0 : return 0 != GetDoc()->IsInsRegionAvailable( *pCrsr );
65 :
66 0 : return sal_True;
67 : }
68 :
69 0 : const SwSection* SwEditShell::GetCurrSection() const
70 : {
71 0 : if( IsTableMode() )
72 0 : return 0;
73 :
74 0 : return GetDoc()->GetCurrSection( *GetCrsr()->GetPoint() );
75 : }
76 :
77 : /** Deliver the responsible area of the columns.
78 : *
79 : * In footnotes it may not be the area within the footnote.
80 : */
81 0 : const SwSection* SwEditShell::GetAnySection( sal_Bool bOutOfTab, const Point* pPt ) const
82 : {
83 : SwFrm *pFrm;
84 0 : if ( pPt )
85 : {
86 0 : SwPosition aPos( *GetCrsr()->GetPoint() );
87 0 : Point aPt( *pPt );
88 0 : GetLayout()->GetCrsrOfst( &aPos, aPt );
89 0 : SwCntntNode *pNd = aPos.nNode.GetNode().GetCntntNode();
90 0 : pFrm = pNd->getLayoutFrm( GetLayout(), pPt );
91 : }
92 : else
93 0 : pFrm = GetCurrFrm( sal_False );
94 :
95 0 : if( bOutOfTab && pFrm )
96 0 : pFrm = pFrm->FindTabFrm();
97 0 : if( pFrm && pFrm->IsInSct() )
98 : {
99 0 : SwSectionFrm* pSect = pFrm->FindSctFrm();
100 : OSL_ENSURE( pSect, "GetAnySection: Where's my Sect?" );
101 0 : if( pSect->IsInFtn() && pSect->GetUpper()->IsInSct() )
102 : {
103 0 : pSect = pSect->GetUpper()->FindSctFrm();
104 : OSL_ENSURE( pSect, "GetAnySection: Where's my SectFrm?" );
105 : }
106 0 : return pSect->GetSection();
107 : }
108 0 : return NULL;
109 : }
110 :
111 0 : sal_uInt16 SwEditShell::GetSectionFmtCount() const
112 : {
113 0 : return GetDoc()->GetSections().size();
114 : }
115 :
116 0 : sal_Bool SwEditShell::IsAnySectionInDoc( sal_Bool bChkReadOnly, sal_Bool bChkHidden, sal_Bool bChkTOX ) const
117 : {
118 0 : const SwSectionFmts& rFmts = GetDoc()->GetSections();
119 0 : sal_uInt16 nCnt = rFmts.size();
120 : sal_uInt16 n;
121 :
122 0 : for( n = 0; n < nCnt; ++n )
123 : {
124 : SectionType eTmpType;
125 0 : const SwSectionFmt* pFmt = rFmts[ n ];
126 0 : if( pFmt->IsInNodesArr() &&
127 0 : (bChkTOX ||
128 0 : ( (eTmpType = pFmt->GetSection()->GetType()) != TOX_CONTENT_SECTION
129 0 : && TOX_HEADER_SECTION != eTmpType ) ) )
130 : {
131 0 : const SwSection& rSect = *rFmts[ n ]->GetSection();
132 0 : if( (!bChkReadOnly && !bChkHidden ) ||
133 0 : (bChkReadOnly && rSect.IsProtectFlag() ) ||
134 0 : (bChkHidden && rSect.IsHiddenFlag() ) )
135 0 : break;
136 : }
137 : }
138 0 : return n != nCnt;
139 : }
140 :
141 0 : sal_uInt16 SwEditShell::GetSectionFmtPos( const SwSectionFmt& rFmt ) const
142 : {
143 0 : SwSectionFmt* pFmt = (SwSectionFmt*)&rFmt;
144 0 : return GetDoc()->GetSections().GetPos( pFmt );
145 : }
146 :
147 0 : const SwSectionFmt& SwEditShell::GetSectionFmt( sal_uInt16 nFmt ) const
148 : {
149 0 : return *GetDoc()->GetSections()[ nFmt ];
150 : }
151 :
152 0 : void SwEditShell::DelSectionFmt( sal_uInt16 nFmt )
153 : {
154 0 : StartAllAction();
155 0 : GetDoc()->DelSectionFmt( GetDoc()->GetSections()[ nFmt ] );
156 : // Call the AttrChangeNotify on the UI page.
157 0 : CallChgLnk();
158 0 : EndAllAction();
159 0 : }
160 :
161 0 : void SwEditShell::UpdateSection(sal_uInt16 const nSect,
162 : SwSectionData & rNewData, SfxItemSet const*const pAttr)
163 : {
164 0 : StartAllAction();
165 0 : GetDoc()->UpdateSection( nSect, rNewData, pAttr );
166 : // Call the AttrChangeNotify on the UI page.
167 0 : CallChgLnk();
168 0 : EndAllAction();
169 0 : }
170 :
171 0 : OUString SwEditShell::GetUniqueSectionName( const OUString* pChkStr ) const
172 : {
173 0 : return GetDoc()->GetUniqueSectionName( pChkStr );
174 : }
175 :
176 0 : void SwEditShell::SetSectionAttr( const SfxItemSet& rSet,
177 : SwSectionFmt* pSectFmt )
178 : {
179 0 : if( pSectFmt )
180 0 : _SetSectionAttr( *pSectFmt, rSet );
181 : else
182 : {
183 : // for all section in the selection
184 :
185 0 : FOREACHPAM_START(GetCrsr())
186 :
187 0 : const SwPosition* pStt = PCURCRSR->Start(),
188 0 : * pEnd = PCURCRSR->End();
189 :
190 0 : const SwSectionNode* pSttSectNd = pStt->nNode.GetNode().FindSectionNode(),
191 0 : * pEndSectNd = pEnd->nNode.GetNode().FindSectionNode();
192 :
193 0 : if( pSttSectNd || pEndSectNd )
194 : {
195 0 : if( pSttSectNd )
196 0 : _SetSectionAttr( *pSttSectNd->GetSection().GetFmt(),
197 0 : rSet );
198 0 : if( pEndSectNd && pSttSectNd != pEndSectNd )
199 0 : _SetSectionAttr( *pEndSectNd->GetSection().GetFmt(),
200 0 : rSet );
201 :
202 0 : if( pSttSectNd && pEndSectNd )
203 : {
204 0 : SwNodeIndex aSIdx( pStt->nNode );
205 0 : SwNodeIndex aEIdx( pEnd->nNode );
206 0 : if( pSttSectNd->EndOfSectionIndex() <
207 0 : pEndSectNd->GetIndex() )
208 : {
209 0 : aSIdx = pSttSectNd->EndOfSectionIndex() + 1;
210 0 : aEIdx = *pEndSectNd;
211 : }
212 :
213 0 : while( aSIdx < aEIdx )
214 : {
215 0 : if( 0 != (pSttSectNd = aSIdx.GetNode().GetSectionNode())
216 0 : || ( aSIdx.GetNode().IsEndNode() &&
217 0 : 0 != ( pSttSectNd = aSIdx.GetNode().
218 0 : StartOfSectionNode()->GetSectionNode())) )
219 0 : _SetSectionAttr( *pSttSectNd->GetSection().GetFmt(),
220 0 : rSet );
221 0 : ++aSIdx;
222 0 : }
223 : }
224 : }
225 :
226 0 : FOREACHPAM_END()
227 : }
228 0 : }
229 :
230 0 : void SwEditShell::_SetSectionAttr( SwSectionFmt& rSectFmt,
231 : const SfxItemSet& rSet )
232 : {
233 0 : StartAllAction();
234 0 : if(SFX_ITEM_SET == rSet.GetItemState(RES_CNTNT, false))
235 : {
236 0 : SfxItemSet aSet(rSet);
237 0 : aSet.ClearItem(RES_CNTNT);
238 0 : GetDoc()->SetAttr( aSet, rSectFmt );
239 : }
240 : else
241 0 : GetDoc()->SetAttr( rSet, rSectFmt );
242 :
243 : // Call the AttrChangeNotify on the UI page.
244 0 : CallChgLnk();
245 0 : EndAllAction();
246 0 : }
247 :
248 : /** Search inside the cursor selection for full selected sections.
249 : *
250 : * @return If any part of section in the selection return 0, if more than one return the count.
251 : */
252 0 : sal_uInt16 SwEditShell::GetFullSelectedSectionCount() const
253 : {
254 0 : sal_uInt16 nRet = 0;
255 0 : FOREACHPAM_START(GetCrsr())
256 :
257 0 : const SwPosition* pStt = PCURCRSR->Start(),
258 0 : * pEnd = PCURCRSR->End();
259 : const SwCntntNode* pCNd;
260 : // check the selection, if Start at Node begin and End at Node end
261 0 : if( pStt->nContent.GetIndex() ||
262 0 : ( 0 == ( pCNd = pEnd->nNode.GetNode().GetCntntNode() )) ||
263 0 : pCNd->Len() != pEnd->nContent.GetIndex() )
264 : {
265 0 : nRet = 0;
266 0 : break;
267 : }
268 :
269 : // !!!
270 : // what about table at start or end ?
271 : // There is no selection possible!
272 : // What about only a table inside the section ?
273 : // There is only a table selection possible!
274 :
275 0 : SwNodeIndex aSIdx( pStt->nNode, -1 ), aEIdx( pEnd->nNode, +1 );
276 0 : if( !aSIdx.GetNode().IsSectionNode() ||
277 0 : !aEIdx.GetNode().IsEndNode() ||
278 0 : !aEIdx.GetNode().StartOfSectionNode()->IsSectionNode() )
279 : {
280 0 : nRet = 0;
281 0 : break;
282 : }
283 :
284 0 : ++nRet;
285 0 : if( &aSIdx.GetNode() != aEIdx.GetNode().StartOfSectionNode() )
286 0 : ++nRet;
287 :
288 0 : FOREACHPAM_END()
289 0 : return nRet;
290 : }
291 :
292 : /** Find the suitable node for a special insert (alt-enter).
293 : *
294 : * This should enable inserting text before/after sections and tables.
295 : *
296 : * A node is found if:
297 : * 1) the innermost table/section is not in a write-protected area
298 : * 2) pCurrentPos is at or just before an end node
299 : * (or at or just after a start node)
300 : * 3) there are only start/end nodes between pCurrentPos and the innermost
301 : * table/section
302 : *
303 : * If a suitable node is found, an SwNode* is returned; else it is NULL.
304 : */
305 0 : static const SwNode* lcl_SpecialInsertNode(const SwPosition* pCurrentPos)
306 : {
307 0 : const SwNode* pReturn = NULL;
308 :
309 : // the current position
310 : OSL_ENSURE( pCurrentPos != NULL, "Strange, we have no position!" );
311 0 : const SwNode& rCurrentNode = pCurrentPos->nNode.GetNode();
312 :
313 : // find innermost section or table. At the end of this scope,
314 : // pInntermostNode contain the section/table before/after which we should
315 : // insert our empty paragraph, or it will be NULL if none is found.
316 0 : const SwNode* pInnermostNode = NULL;
317 : {
318 0 : const SwNode* pTableNode = rCurrentNode.FindTableNode();
319 0 : const SwNode* pSectionNode = rCurrentNode.FindSectionNode();
320 :
321 : // find the table/section which is close
322 0 : if( pTableNode == NULL )
323 0 : pInnermostNode = pSectionNode;
324 0 : else if ( pSectionNode == NULL )
325 0 : pInnermostNode = pTableNode;
326 : else
327 : {
328 : // compare and choose the larger one
329 : pInnermostNode =
330 0 : ( pSectionNode->GetIndex() > pTableNode->GetIndex() )
331 0 : ? pSectionNode : pTableNode;
332 : }
333 : }
334 :
335 : // The previous version had a check to skip empty read-only sections. Those
336 : // shouldn't occur, so we only need to check whether our pInnermostNode is
337 : // inside a protected area.
338 :
339 : // Now, pInnermostNode is NULL or the innermost section or table node.
340 0 : if( (pInnermostNode != NULL) && !pInnermostNode->IsProtect() )
341 : {
342 : OSL_ENSURE( pInnermostNode->IsTableNode() ||
343 : pInnermostNode->IsSectionNode(), "wrong node found" );
344 : OSL_ENSURE( ( pInnermostNode->GetIndex() <= rCurrentNode.GetIndex() )&&
345 : ( pInnermostNode->EndOfSectionNode()->GetIndex() >=
346 : rCurrentNode.GetIndex() ), "wrong node found" );
347 :
348 : // we now need to find the possible start/end positions
349 :
350 : // we found a start if
351 : // - we're at or just before a start node
352 : // - there are only start nodes between the current and pInnermostNode
353 0 : SwNodeIndex aBegin( pCurrentPos->nNode );
354 0 : if( rCurrentNode.IsCntntNode() &&
355 0 : (pCurrentPos->nContent.GetIndex() == 0))
356 0 : aBegin--;
357 0 : while( (aBegin != pInnermostNode->GetIndex()) &&
358 0 : aBegin.GetNode().IsStartNode() )
359 0 : aBegin--;
360 0 : bool bStart = ( aBegin == pInnermostNode->GetIndex() );
361 :
362 : // we found an end if
363 : // - we're at or just before an end node
364 : // - there are only end nodes between the current node and
365 : // pInnermostNode's end node
366 0 : SwNodeIndex aEnd( pCurrentPos->nNode );
367 0 : if( rCurrentNode.IsCntntNode() &&
368 0 : ( pCurrentPos->nContent.GetIndex() ==
369 0 : rCurrentNode.GetCntntNode()->Len() ) )
370 0 : ++aEnd;
371 0 : while( (aEnd != pInnermostNode->EndOfSectionNode()->GetIndex()) &&
372 0 : aEnd.GetNode().IsEndNode() )
373 0 : ++aEnd;
374 0 : bool bEnd = ( aEnd == pInnermostNode->EndOfSectionNode()->GetIndex() );
375 :
376 : // evalutate result: if both start + end, end is preferred
377 0 : if( bEnd )
378 0 : pReturn = pInnermostNode->EndOfSectionNode();
379 0 : else if ( bStart )
380 0 : pReturn = pInnermostNode;
381 : }
382 :
383 : OSL_ENSURE( ( pReturn == NULL ) || pReturn->IsStartNode() ||
384 : pReturn->IsEndNode(),
385 : "SpecialInsertNode failed" );
386 0 : return pReturn;
387 : }
388 :
389 : /** a node can be special-inserted (alt-Enter) whenever lcl_SpecialInsertNode
390 : finds a suitable position
391 : */
392 0 : bool SwEditShell::CanSpecialInsert() const
393 : {
394 0 : return NULL != lcl_SpecialInsertNode( GetCrsr()->GetPoint() );
395 : }
396 :
397 : /** check whether a node can be special-inserted (alt-Enter), and do so. Return
398 : whether insertion was possible.
399 : */
400 0 : bool SwEditShell::DoSpecialInsert()
401 : {
402 0 : bool bRet = false;
403 :
404 : // get current node
405 0 : SwPosition* pCursorPos = GetCrsr()->GetPoint();
406 0 : const SwNode* pInsertNode = lcl_SpecialInsertNode( pCursorPos );
407 0 : if( pInsertNode != NULL )
408 : {
409 0 : StartAllAction();
410 :
411 : // adjust insert position to insert before start nodes and after end
412 : // nodes
413 : SwNodeIndex aInsertIndex( *pInsertNode,
414 0 : pInsertNode->IsStartNode() ? -1 : 0 );
415 0 : SwPosition aInsertPos( aInsertIndex );
416 :
417 : // insert a new text node, and set the cursor
418 0 : bRet = GetDoc()->AppendTxtNode( aInsertPos );
419 0 : *pCursorPos = aInsertPos;
420 :
421 : // call AttrChangeNotify for the UI
422 0 : CallChgLnk();
423 :
424 0 : EndAllAction();
425 : }
426 :
427 0 : return bRet;
428 : }
429 :
430 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|