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