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