xref: /trunk/main/sw/source/core/crsr/callnk.cxx (revision 69a74367)
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 
28 #include <hintids.hxx>
29 
30 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
31 #include <com/sun/star/i18n/ScriptType.hdl>
32 #endif
33 #include <fmtcntnt.hxx>
34 #include <txatbase.hxx>
35 #include <frmatr.hxx>
36 #include <viscrs.hxx>
37 #include <callnk.hxx>
38 #include <crsrsh.hxx>
39 #include <doc.hxx>
40 #include <frmfmt.hxx>
41 #include <txtfrm.hxx>
42 #include <ndtxt.hxx>
43 #include <flyfrm.hxx>
44 #include <breakit.hxx>
45 
46 
SwCallLink(SwCrsrShell & rSh,sal_uLong nAktNode,xub_StrLen nAktCntnt,sal_uInt8 nAktNdTyp,long nLRPos,bool bAktSelection)47 SwCallLink::SwCallLink( SwCrsrShell & rSh, sal_uLong nAktNode, xub_StrLen nAktCntnt,
48 						sal_uInt8 nAktNdTyp, long nLRPos, bool bAktSelection )
49 	: rShell( rSh ), nNode( nAktNode ), nCntnt( nAktCntnt ),
50       nNdTyp( nAktNdTyp ), nLeftFrmPos( nLRPos ),
51       bHasSelection( bAktSelection )
52 {
53 }
54 
55 
SwCallLink(SwCrsrShell & rSh)56 SwCallLink::SwCallLink( SwCrsrShell & rSh )
57 	: rShell( rSh )
58 {
59 	// SPoint-Werte vom aktuellen Cursor merken
60 	SwPaM* pCrsr = rShell.IsTableMode() ? rShell.GetTblCrs() : rShell.GetCrsr();
61 	SwNode& rNd = pCrsr->GetPoint()->nNode.GetNode();
62 	nNode = rNd.GetIndex();
63 	nCntnt = pCrsr->GetPoint()->nContent.GetIndex();
64 	nNdTyp = rNd.GetNodeType();
65     bHasSelection = ( *pCrsr->GetPoint() != *pCrsr->GetMark() );
66 
67 	if( ND_TEXTNODE & nNdTyp )
68 		nLeftFrmPos = SwCallLink::getLayoutFrm( rShell.GetLayout(), (SwTxtNode&)rNd, nCntnt,
69 											!rShell.ActionPend() );
70 	else
71 	{
72 		nLeftFrmPos = 0;
73 
74 		// eine Sonderbehandlung fuer die SwFeShell: diese setzt beim Loeschen
75 		// der Kopf-/Fusszeile, Fussnoten den Cursor auf NULL (Node + Content)
76 		// steht der Cursor auf keinem CntntNode, wird sich das im NdType
77 		// gespeichert.
78 		if( ND_CONTENTNODE & nNdTyp )
79 			nNdTyp = 0;
80 	}
81 }
82 
83 
~SwCallLink()84 SwCallLink::~SwCallLink()
85 {
86 	if( !nNdTyp || !rShell.bCallChgLnk )		// siehe ctor
87 		return ;
88 
89 	// wird ueber Nodes getravellt, Formate ueberpruefen und im neuen
90 	// Node wieder anmelden
91 	SwPaM* pCurCrsr = rShell.IsTableMode() ? rShell.GetTblCrs() : rShell.GetCrsr();
92 	SwCntntNode * pCNd = pCurCrsr->GetCntntNode();
93 	if( !pCNd )
94 		return;
95 
96 	xub_StrLen nCmp, nAktCntnt = pCurCrsr->GetPoint()->nContent.GetIndex();
97 	sal_uInt16 nNdWhich = pCNd->GetNodeType();
98 	sal_uLong nAktNode = pCurCrsr->GetPoint()->nNode.GetIndex();
99 
100 	// melde die Shell beim akt. Node als abhaengig an, dadurch koennen
101 	// alle Attribut-Aenderungen ueber den Link weiter gemeldet werden.
102 	pCNd->Add( &rShell );
103 
104 	if( nNdTyp != nNdWhich || nNode != nAktNode )
105 	{
106 		/* immer, wenn zwischen Nodes gesprungen wird, kann es
107 		 * vorkommen, das neue Attribute gelten; die Text-Attribute.
108 		 * Es muesste also festgestellt werden, welche Attribute
109 		 * jetzt gelten; das kann auch gleich der Handler machen
110 		 */
111 		rShell.CallChgLnk();
112 	}
113     else if( !bHasSelection != !(*pCurCrsr->GetPoint() != *pCurCrsr->GetMark()) )
114     {
115         // always call change link when selection changes
116 		rShell.CallChgLnk();
117     }
118 	else if( rShell.aChgLnk.IsSet() && ND_TEXTNODE == nNdWhich &&
119 			 nCntnt != nAktCntnt )
120 	{
121 		// nur wenn mit Left/right getravellt, dann Text-Hints pruefen
122 		// und sich nicht der Frame geaendert hat (Spalten!)
123 		if( nLeftFrmPos == SwCallLink::getLayoutFrm( rShell.GetLayout(), (SwTxtNode&)*pCNd, nAktCntnt,
124 													!rShell.ActionPend() ) &&
125 			(( nCmp = nCntnt ) + 1 == nAktCntnt ||			// Right
126 			nCntnt -1 == ( nCmp = nAktCntnt )) )			// Left
127 		{
128 			if( nCmp == nAktCntnt && pCurCrsr->HasMark() ) // left & Sele
129 				++nCmp;
130 			if ( ((SwTxtNode*)pCNd)->HasHints() )
131 			{
132 
133 				const SwpHints &rHts = ((SwTxtNode*)pCNd)->GetSwpHints();
134 				sal_uInt16 n;
135 				xub_StrLen nStart;
136 				const xub_StrLen *pEnd;
137 
138 				for( n = 0; n < rHts.Count(); n++ )
139 				{
140 					const SwTxtAttr* pHt = rHts[ n ];
141 					pEnd = pHt->End();
142 					nStart = *pHt->GetStart();
143 
144 					// nur Start oder Start und Ende gleich, dann immer
145 					// beim Ueberlaufen von Start callen
146 					if( ( !pEnd || ( nStart == *pEnd ) ) &&
147 						( nStart == nCntnt || nStart == nAktCntnt) )
148 					{
149 						rShell.CallChgLnk();
150 						return;
151 					}
152 
153 					// hat das Attribut einen Bereich und dieser nicht leer
154 					else if( pEnd && nStart < *pEnd &&
155 						// dann teste, ob ueber Start/Ende getravellt wurde
156 						( nStart == nCmp ||
157 							( pHt->DontExpand() ? nCmp == *pEnd-1
158 												: nCmp == *pEnd ) ))
159 					{
160 						rShell.CallChgLnk();
161 						return;
162 					}
163 					nStart = 0;
164 				}
165 			}
166 
167 			if( pBreakIt->GetBreakIter().is() )
168 			{
169 				const String& rTxt = ((SwTxtNode*)pCNd)->GetTxt();
170 				if( !nCmp ||
171 					pBreakIt->GetBreakIter()->getScriptType( rTxt, nCmp )
172 					 != pBreakIt->GetBreakIter()->getScriptType( rTxt, nCmp - 1 ))
173 				{
174 					rShell.CallChgLnk();
175 					return;
176 				}
177 			}
178 		}
179 		else
180 			/* wenn mit Home/End/.. mehr als 1 Zeichen getravellt, dann
181 			 * immer den ChgLnk rufen, denn es kann hier nicht
182 			 * festgestellt werden, was sich geaendert; etwas kann
183 			 * veraendert sein.
184 			 */
185 			rShell.CallChgLnk();
186 	}
187 
188 	const SwFrm* pFrm;
189 	const SwFlyFrm *pFlyFrm;
190 	if( !rShell.ActionPend() && 0 != ( pFrm = pCNd->getLayoutFrm(rShell.GetLayout(),0,0,sal_False) ) &&
191 		0 != ( pFlyFrm = pFrm->FindFlyFrm() ) && !rShell.IsTableMode() )
192 	{
193 		const SwNodeIndex* pIndex = pFlyFrm->GetFmt()->GetCntnt().GetCntntIdx();
194 		ASSERT( pIndex, "Fly ohne Cntnt" );
195 
196 		if (!pIndex)
197 		    return;
198 
199 		const SwNode& rStNd = pIndex->GetNode();
200 
201 		if( rStNd.EndOfSectionNode()->StartOfSectionIndex() > nNode ||
202 			nNode > rStNd.EndOfSectionIndex() )
203 			rShell.GetFlyMacroLnk().Call( (void*)pFlyFrm->GetFmt() );
204 	}
205 }
206 
getLayoutFrm(const SwRootFrm * pRoot,SwTxtNode & rNd,xub_StrLen nCntPos,sal_Bool bCalcFrm)207 long SwCallLink::getLayoutFrm( const SwRootFrm* pRoot, SwTxtNode& rNd, xub_StrLen nCntPos, sal_Bool bCalcFrm )
208 {
209 	SwTxtFrm* pFrm = (SwTxtFrm*)rNd.getLayoutFrm(pRoot,0,0,bCalcFrm), *pNext = pFrm;
210 	if ( pFrm && !pFrm->IsHiddenNow() )
211 	{
212 		if( pFrm->HasFollow() )
213 			while( 0 != ( pNext = (SwTxtFrm*)pFrm->GetFollow() ) &&
214 					nCntPos >= pNext->GetOfst() )
215 				pFrm = pNext;
216 
217 		return pFrm->Frm().Left();
218 	}
219 	return 0;
220 }
221 
222