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_vcl.hxx"
26
27 #include "atkwrapper.hxx"
28
29 #include <com/sun/star/accessibility/XAccessibleAction.hpp>
30 #include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp>
31
32 #include <com/sun/star/awt/Key.hpp>
33 #include <com/sun/star/awt/KeyModifier.hpp>
34
35 #include <rtl/strbuf.hxx>
36 #include <algorithm>
37 #include <map>
38
39 #include <stdio.h>
40
41 using namespace ::com::sun::star;
42
43 // FIXME
44 static G_CONST_RETURN gchar *
getAsConst(const rtl::OString & rString)45 getAsConst( const rtl::OString& rString )
46 {
47 static const int nMax = 10;
48 static rtl::OString aUgly[nMax];
49 static int nIdx = 0;
50 nIdx = (nIdx + 1) % nMax;
51 aUgly[nIdx] = rString;
52 return aUgly[ nIdx ].getStr();
53 }
54
55 static accessibility::XAccessibleAction*
getAction(AtkAction * action)56 getAction( AtkAction *action ) throw (uno::RuntimeException)
57 {
58 AtkObjectWrapper *pWrap = ATK_OBJECT_WRAPPER( action );
59
60 if( pWrap )
61 {
62 if( !pWrap->mpAction && pWrap->mpContext )
63 {
64 uno::Any any = pWrap->mpContext->queryInterface( accessibility::XAccessibleAction::static_type(NULL) );
65 pWrap->mpAction = reinterpret_cast< accessibility::XAccessibleAction * > (any.pReserved);
66 pWrap->mpAction->acquire();
67 }
68
69 return pWrap->mpAction;
70 }
71
72 return NULL;
73 }
74
75 extern "C" {
76
77 static gboolean
action_wrapper_do_action(AtkAction * action,gint i)78 action_wrapper_do_action (AtkAction *action,
79 gint i)
80 {
81 try {
82 accessibility::XAccessibleAction* pAction = getAction( action );
83 if( pAction )
84 return pAction->doAccessibleAction( i );
85 }
86 catch(const uno::Exception& e) {
87 g_warning( "Exception in doAccessibleAction()" );
88 }
89
90 return FALSE;
91 }
92
93 static gint
action_wrapper_get_n_actions(AtkAction * action)94 action_wrapper_get_n_actions (AtkAction *action)
95 {
96 try {
97 accessibility::XAccessibleAction* pAction = getAction( action );
98 if( pAction )
99 return pAction->getAccessibleActionCount();
100 }
101 catch(const uno::Exception& e) {
102 g_warning( "Exception in getAccessibleActionCount()" );
103 }
104
105 return 0;
106 }
107
108 static G_CONST_RETURN gchar *
action_wrapper_get_description(AtkAction *,gint)109 action_wrapper_get_description (AtkAction *, gint)
110 {
111 // GAIL implement this only for cells
112 g_warning( "Not implemented: get_description()" );
113 return "";
114 }
115
116 static G_CONST_RETURN gchar *
action_wrapper_get_localized_name(AtkAction *,gint)117 action_wrapper_get_localized_name (AtkAction *, gint)
118 {
119 // GAIL doesn't implement this as well
120 g_warning( "Not implemented: get_localized_name()" );
121 return "";
122 }
123
124 #define ACTION_NAME_PAIR( OOoName, AtkName ) \
125 std::pair< const rtl::OUString, const gchar * > ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OOoName ) ), AtkName )
126
127 static G_CONST_RETURN gchar *
action_wrapper_get_name(AtkAction * action,gint i)128 action_wrapper_get_name (AtkAction *action,
129 gint i)
130 {
131 static std::map< rtl::OUString, const gchar * > aNameMap;
132
133 if( aNameMap.empty() )
134 {
135 aNameMap.insert( ACTION_NAME_PAIR( "click", "click" ) );
136 aNameMap.insert( ACTION_NAME_PAIR( "select", "click" ) );
137 aNameMap.insert( ACTION_NAME_PAIR( "togglePopup", "push" ) );
138 }
139
140 try {
141 accessibility::XAccessibleAction* pAction = getAction( action );
142 if( pAction )
143 {
144 std::map< rtl::OUString, const gchar * >::iterator iter;
145
146 rtl::OUString aDesc( pAction->getAccessibleActionDescription( i ) );
147
148 iter = aNameMap.find( aDesc );
149 if( iter != aNameMap.end() )
150 return iter->second;
151
152 std::pair< const rtl::OUString, const gchar * > aNewVal( aDesc,
153 g_strdup( OUStringToConstGChar(aDesc) ) );
154
155 if( aNameMap.insert( aNewVal ).second )
156 return aNewVal.second;
157 }
158 }
159 catch(const uno::Exception& e) {
160 g_warning( "Exception in getAccessibleActionDescription()" );
161 }
162
163 return "";
164 }
165
166 /*
167 * GNOME Expects a string in the format:
168 *
169 * <nmemonic>;<full-path>;<accelerator>
170 *
171 * The keybindings in <full-path> should be separated by ":"
172 */
173
174 static inline void
appendKeyStrokes(rtl::OStringBuffer & rBuffer,const uno::Sequence<awt::KeyStroke> & rKeyStrokes)175 appendKeyStrokes(rtl::OStringBuffer& rBuffer, const uno::Sequence< awt::KeyStroke >& rKeyStrokes)
176 {
177 for( sal_Int32 i = 0; i < rKeyStrokes.getLength(); i++ )
178 {
179 if( rKeyStrokes[i].Modifiers & awt::KeyModifier::SHIFT )
180 rBuffer.append("<Shift>");
181 if( rKeyStrokes[i].Modifiers & awt::KeyModifier::MOD1 )
182 rBuffer.append("<Control>");
183 if( rKeyStrokes[i].Modifiers & awt::KeyModifier::MOD2 )
184 rBuffer.append("<Alt>");
185
186 if( ( rKeyStrokes[i].KeyCode >= awt::Key::A ) && ( rKeyStrokes[i].KeyCode <= awt::Key::Z ) )
187 rBuffer.append( (sal_Char) ( 'a' + ( rKeyStrokes[i].KeyCode - awt::Key::A ) ) );
188 else
189 {
190 sal_Char c = '\0';
191
192 switch( rKeyStrokes[i].KeyCode )
193 {
194 case awt::Key::TAB: c = '\t'; break;
195 case awt::Key::SPACE: c = ' '; break;
196 case awt::Key::ADD: c = '+'; break;
197 case awt::Key::SUBTRACT: c = '-'; break;
198 case awt::Key::MULTIPLY: c = '*'; break;
199 case awt::Key::DIVIDE: c = '/'; break;
200 case awt::Key::POINT: c = '.'; break;
201 case awt::Key::COMMA: c = ','; break;
202 case awt::Key::LESS: c = '<'; break;
203 case awt::Key::GREATER: c = '>'; break;
204 case awt::Key::EQUAL: c = '='; break;
205 case 0:
206 break;
207 default:
208 g_warning( "Unmapped KeyCode: %d", rKeyStrokes[i].KeyCode );
209 break;
210 }
211
212 if( c != '\0' )
213 rBuffer.append( c );
214 }
215 }
216 }
217
218
219 static G_CONST_RETURN gchar *
action_wrapper_get_keybinding(AtkAction * action,gint i)220 action_wrapper_get_keybinding (AtkAction *action,
221 gint i)
222 {
223 try {
224 accessibility::XAccessibleAction* pAction = getAction( action );
225 if( pAction )
226 {
227 uno::Reference< accessibility::XAccessibleKeyBinding > xBinding( pAction->getAccessibleActionKeyBinding( i ));
228
229 if( xBinding.is() )
230 {
231 rtl::OStringBuffer aRet;
232
233 sal_Int32 nmax = std::min( xBinding->getAccessibleKeyBindingCount(), (sal_Int32) 3 );
234 for( sal_Int32 n = 0; n < nmax; n++ )
235 {
236 appendKeyStrokes( aRet, xBinding->getAccessibleKeyBinding( n ) );
237
238 if( n < 2 )
239 aRet.append( (sal_Char) ';' );
240 }
241
242 // !! FIXME !! remember keystroke in wrapper object ?
243 return getAsConst( aRet.makeStringAndClear() );
244 }
245 }
246 }
247 catch(const uno::Exception& e) {
248 g_warning( "Exception in get_keybinding()" );
249 }
250
251 return "";
252 }
253
254 static gboolean
action_wrapper_set_description(AtkAction *,gint,const gchar *)255 action_wrapper_set_description (AtkAction *, gint, const gchar *)
256 {
257 return FALSE;
258 }
259
260 } // extern "C"
261
262 void
actionIfaceInit(AtkActionIface * iface)263 actionIfaceInit (AtkActionIface *iface)
264 {
265 g_return_if_fail (iface != NULL);
266
267 iface->do_action = action_wrapper_do_action;
268 iface->get_n_actions = action_wrapper_get_n_actions;
269 iface->get_description = action_wrapper_get_description;
270 iface->get_keybinding = action_wrapper_get_keybinding;
271 iface->get_name = action_wrapper_get_name;
272 iface->get_localized_name = action_wrapper_get_localized_name;
273 iface->set_description = action_wrapper_set_description;
274 }
275