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 * 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 ]; 53 } 54 55 static accessibility::XAccessibleAction* 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 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 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 * 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 * 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 * 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 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 * 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 255 action_wrapper_set_description (AtkAction *, gint, const gchar *) 256 { 257 return FALSE; 258 } 259 260 } // extern "C" 261 262 void 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