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