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 <com/sun/star/accessibility/AccessibleStateType.hpp>
29 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
30 #include <unotools/accessiblestatesethelper.hxx>
31 #include <vos/mutex.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/window.hxx>
34 #include <frmfmt.hxx>
35 #include <ndnotxt.hxx>
36 #include <flyfrm.hxx>
37 #include <cntfrm.hxx>
38 #include <fmtcntnt.hxx>
39 #include <ndindex.hxx>
40 #include "fesh.hxx"
41 #include <hints.hxx>
42 #include "accmap.hxx"
43 #include "accframebase.hxx"
44 
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::accessibility;
47 using ::rtl::OUString;
48 
49 sal_Bool SwAccessibleFrameBase::IsSelected()
50 {
51 	sal_Bool bRet = sal_False;
52 
53     DBG_ASSERT( GetMap(), "no map?" );
54 	const ViewShell *pVSh = GetMap()->GetShell();
55     DBG_ASSERT( pVSh, "no shell?" );
56 	if( pVSh->ISA( SwFEShell ) )
57 	{
58 		const SwFEShell *pFESh = static_cast< const SwFEShell * >( pVSh );
59 		const SwFrm *pFlyFrm = pFESh->GetCurrFlyFrm();
60 		if( pFlyFrm == GetFrm() )
61 			bRet = sal_True;
62 	}
63 
64 	return bRet;
65 }
66 
67 void SwAccessibleFrameBase::GetStates(
68 		::utl::AccessibleStateSetHelper& rStateSet )
69 {
70 	SwAccessibleContext::GetStates( rStateSet );
71 
72 	const ViewShell *pVSh = GetMap()->GetShell();
73     DBG_ASSERT( pVSh, "no shell?" );
74 	sal_Bool bSelectable =  pVSh->ISA( SwFEShell );
75 
76 	// SELECTABLE
77 	if( bSelectable )
78 		rStateSet.AddState( AccessibleStateType::SELECTABLE );
79 
80 	// FOCUSABLE
81 	if( bSelectable )
82 		rStateSet.AddState( AccessibleStateType::FOCUSABLE );
83 
84 	// SELECTED and FOCUSED
85 	if( IsSelected() )
86 	{
87 		rStateSet.AddState( AccessibleStateType::SELECTED );
88 		ASSERT( bIsSelected, "bSelected out of sync" );
89 		::vos::ORef < SwAccessibleContext > xThis( this );
90 		GetMap()->SetCursorContext( xThis );
91 
92 		Window *pWin = GetWindow();
93 		if( pWin && pWin->HasFocus() )
94 			rStateSet.AddState( AccessibleStateType::FOCUSED );
95 	}
96 }
97 
98 
99 sal_uInt8 SwAccessibleFrameBase::GetNodeType( const SwFlyFrm *pFlyFrm )
100 {
101 	sal_uInt8 nType = ND_TEXTNODE;
102 	if( pFlyFrm->Lower() )
103 	{
104  		if( pFlyFrm->Lower()->IsNoTxtFrm() )
105 		{
106 			const SwCntntFrm *pCntFrm =
107 				static_cast<const SwCntntFrm *>( pFlyFrm->Lower() );
108 			nType = pCntFrm->GetNode()->GetNodeType();
109 		}
110 	}
111 	else
112 	{
113 		const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt();
114 		const SwFmtCntnt& rCntnt = pFrmFmt->GetCntnt();
115 		const SwNodeIndex *pNdIdx = rCntnt.GetCntntIdx();
116 		if( pNdIdx )
117 		{
118 			const SwCntntNode *pCNd =
119 				(pNdIdx->GetNodes())[pNdIdx->GetIndex()+1]->GetCntntNode();
120 			if( pCNd )
121 				nType = pCNd->GetNodeType();
122 		}
123 	}
124 
125 	return nType;
126 }
127 
128 SwAccessibleFrameBase::SwAccessibleFrameBase(
129         SwAccessibleMap* pInitMap,
130         sal_Int16 nInitRole,
131         const SwFlyFrm* pFlyFrm  ) :
132     SwAccessibleContext( pInitMap, nInitRole, pFlyFrm ),
133 	bIsSelected( sal_False )
134 {
135 	vos::OGuard aGuard(Application::GetSolarMutex());
136 
137 	const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt();
138 	const_cast< SwFrmFmt * >( pFrmFmt )->Add( this );
139 
140 	SetName( pFrmFmt->GetName() );
141 
142 	bIsSelected = IsSelected();
143 }
144 
145 void SwAccessibleFrameBase::_InvalidateCursorPos()
146 {
147 	sal_Bool bNewSelected = IsSelected();
148 	sal_Bool bOldSelected;
149 
150 	{
151 		vos::OGuard aGuard( aMutex );
152 		bOldSelected = bIsSelected;
153 		bIsSelected = bNewSelected;
154 	}
155 
156 	if( bNewSelected )
157 	{
158 		// remember that object as the one that has the caret. This is
159 		// neccessary to notify that object if the cursor leaves it.
160 		::vos::ORef < SwAccessibleContext > xThis( this );
161 		GetMap()->SetCursorContext( xThis );
162 	}
163 
164 	if( bOldSelected != bNewSelected )
165 	{
166 		Window *pWin = GetWindow();
167 		if( pWin && pWin->HasFocus() && bNewSelected )
168 			FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected );
169 		FireStateChangedEvent( AccessibleStateType::SELECTED, bNewSelected );
170 		if( pWin && pWin->HasFocus() && !bNewSelected )
171 			FireStateChangedEvent( AccessibleStateType::FOCUSED, bNewSelected );
172 
173 		uno::Reference< XAccessible > xParent( GetWeakParent() );
174 		if( xParent.is() )
175 		{
176 			SwAccessibleContext *pAcc =
177 				static_cast <SwAccessibleContext *>( xParent.get() );
178 
179 			AccessibleEventObject aEvent;
180 			aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
181 			pAcc->FireAccessibleEvent( aEvent );
182 		}
183 	}
184 }
185 
186 void SwAccessibleFrameBase::_InvalidateFocus()
187 {
188 	Window *pWin = GetWindow();
189 	if( pWin )
190 	{
191 		sal_Bool bSelected;
192 
193 		{
194 			vos::OGuard aGuard( aMutex );
195 			bSelected = bIsSelected;
196 		}
197 		ASSERT( bSelected, "focus object should be selected" );
198 
199 		FireStateChangedEvent( AccessibleStateType::FOCUSED,
200 							   pWin->HasFocus() && bSelected );
201 	}
202 }
203 
204 sal_Bool SwAccessibleFrameBase::HasCursor()
205 {
206 	vos::OGuard aGuard( aMutex );
207 	return bIsSelected;
208 }
209 
210 
211 SwAccessibleFrameBase::~SwAccessibleFrameBase()
212 {
213 }
214 
215 void SwAccessibleFrameBase::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew)
216 {
217 	sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ;
218 	const SwFlyFrm *pFlyFrm = static_cast< const SwFlyFrm * >( GetFrm() );
219 	switch( nWhich )
220 	{
221 	case RES_NAME_CHANGED:
222 		if(  pFlyFrm )
223 		{
224 			const SwFrmFmt *pFrmFmt = pFlyFrm->GetFmt();
225 			ASSERT( pFrmFmt == GetRegisteredIn(), "invalid frame" );
226 
227 			OUString sOldName( GetName() );
228 			ASSERT( !pOld ||
229 					static_cast < const SwStringMsgPoolItem * >( pOld )->GetString() == String( sOldName ),
230 					"invalid old name" );
231 
232 			const String& rNewName = pFrmFmt->GetName();
233 			SetName( rNewName );
234 			ASSERT( !pNew ||
235 					static_cast < const SwStringMsgPoolItem * >( pNew )->GetString() == rNewName,
236 					"invalid new name" );
237 
238 			if( sOldName != GetName() )
239 			{
240 				AccessibleEventObject aEvent;
241 				aEvent.EventId = AccessibleEventId::NAME_CHANGED;
242 				aEvent.OldValue <<= sOldName;
243 				aEvent.NewValue <<= GetName();
244 				FireAccessibleEvent( aEvent );
245 			}
246 		}
247 		break;
248 	case RES_OBJECTDYING:
249         // mba: it seems that this class intentionally does not call code in base class SwClient
250 		if( GetRegisteredIn() ==
251 				static_cast< SwModify *>( static_cast< const SwPtrMsgPoolItem * >( pOld )->pObject ) )
252 			GetRegisteredInNonConst()->Remove( this );
253 		break;
254 
255 	case RES_FMT_CHG:
256 		if( static_cast< const SwFmtChg * >(pNew)->pChangedFmt == GetRegisteredIn() &&
257 			static_cast< const SwFmtChg * >(pOld)->pChangedFmt->IsFmtInDTOR() )
258 			GetRegisteredInNonConst()->Remove( this );
259 		break;
260 
261 	default:
262         // mba: former call to base class method removed as it is meant to handle only RES_OBJECTDYING
263 		break;
264 	}
265 }
266 
267 void SwAccessibleFrameBase::Dispose( sal_Bool bRecursive )
268 {
269 	vos::OGuard aGuard(Application::GetSolarMutex());
270 
271 	if( GetRegisteredIn() )
272 		GetRegisteredInNonConst()->Remove( this );
273 
274 	SwAccessibleContext::Dispose( bRecursive );
275 }
276