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