xref: /AOO41X/main/sw/source/core/edit/edsect.cxx (revision efeef26f81c84063fb0a91bde3856d4a51172d90)
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