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