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