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