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