xref: /trunk/main/vcl/unx/gtk/a11y/atkaction.cxx (revision 24c56ab9)
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