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_svx.hxx" 30 31 //------------------------------------------------------------------------ 32 // 33 // Global header 34 // 35 //------------------------------------------------------------------------ 36 #include <svl/itemset.hxx> 37 #include <editeng/editdata.hxx> 38 #include <editeng/outliner.hxx> 39 #include <svx/svdmodel.hxx> 40 #include <svx/svdobj.hxx> 41 #include <svx/svdpool.hxx> 42 43 //------------------------------------------------------------------------ 44 // 45 // Project-local header 46 // 47 //------------------------------------------------------------------------ 48 49 #include "AccessibleEmptyEditSource.hxx" 50 #include <svx/unoshtxt.hxx> 51 52 namespace accessibility 53 { 54 55 /** This class simply wraps a SvxTextEditSource, forwarding all 56 methods except the GetBroadcaster() call 57 */ 58 class AccessibleProxyEditSource_Impl : public SvxEditSource 59 { 60 public: 61 /** Construct AccessibleEmptyEditSource_Impl 62 63 @param rBrdCast 64 65 Proxy broadcaster to allow seamless flipping of edit source implementations. ProxyEditSource and EmptyEditSource 66 */ 67 AccessibleProxyEditSource_Impl( SdrObject& rObj, 68 SdrView& rView, 69 const Window& rViewWindow ); 70 ~AccessibleProxyEditSource_Impl(); 71 72 // from the SvxEditSource interface 73 SvxTextForwarder* GetTextForwarder(); 74 SvxViewForwarder* GetViewForwarder(); 75 SvxEditViewForwarder* GetEditViewForwarder( sal_Bool bCreate = sal_False ); 76 77 SvxEditSource* Clone() const; 78 79 void UpdateData(); 80 81 SfxBroadcaster& GetBroadcaster() const; 82 83 private: 84 SvxTextEditSource maEditSource; 85 86 }; 87 88 /** Dummy class, faking exactly one empty paragraph for EditEngine accessibility 89 */ 90 class AccessibleEmptyEditSource_Impl : public SvxEditSource, public SvxViewForwarder, public SvxTextForwarder, public SfxBroadcaster 91 { 92 public: 93 94 AccessibleEmptyEditSource_Impl() {} 95 ~AccessibleEmptyEditSource_Impl() {} 96 97 // from the SfxListener interface 98 void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); 99 100 // SvxEditSource 101 SvxTextForwarder* GetTextForwarder() { return this; } 102 SvxViewForwarder* GetViewForwarder() { return this; } 103 SvxEditSource* Clone() const { return NULL; } 104 void UpdateData() {} 105 SfxBroadcaster& GetBroadcaster() const { return *(const_cast<AccessibleEmptyEditSource_Impl*>(this)); } 106 107 // SvxTextForwarder 108 sal_uInt16 GetParagraphCount() const { return 1; } 109 sal_uInt16 GetTextLen( sal_uInt16 /*nParagraph*/ ) const { return 0; } 110 String GetText( const ESelection& /*rSel*/ ) const { return String(); } 111 SfxItemSet GetAttribs( const ESelection& /*rSel*/, sal_Bool /*bOnlyHardAttrib*/ = 0 ) const 112 { 113 // AW: Very dangerous: The former implementation used a SfxItemPool created on the 114 // fly which of course was deleted again ASAP. Thus, the returned SfxItemSet was using 115 // a deleted Pool by design. 116 return SfxItemSet(SdrObject::GetGlobalDrawObjectItemPool()); 117 } 118 SfxItemSet GetParaAttribs( sal_uInt16 /*nPara*/ ) const { return GetAttribs(ESelection()); } 119 void SetParaAttribs( sal_uInt16 /*nPara*/, const SfxItemSet& /*rSet*/ ) {} 120 void RemoveAttribs( const ESelection& /*rSelection*/, sal_Bool /*bRemoveParaAttribs*/, sal_uInt16 /*nWhich*/ ){} 121 void GetPortions( sal_uInt16 /*nPara*/, SvUShorts& /*rList*/ ) const {} 122 123 sal_uInt16 GetItemState( const ESelection& /*rSel*/, sal_uInt16 /*nWhich*/ ) const { return 0; } 124 sal_uInt16 GetItemState( sal_uInt16 /*nPara*/, sal_uInt16 /*nWhich*/ ) const { return 0; } 125 126 SfxItemPool* GetPool() const { return NULL; } 127 128 void QuickInsertText( const String& /*rText*/, const ESelection& /*rSel*/ ) {} 129 void QuickInsertField( const SvxFieldItem& /*rFld*/, const ESelection& /*rSel*/ ) {} 130 void QuickSetAttribs( const SfxItemSet& /*rSet*/, const ESelection& /*rSel*/ ) {} 131 void QuickInsertLineBreak( const ESelection& /*rSel*/ ) {} 132 133 const SfxItemSet * GetEmptyItemSetPtr() { return 0; } 134 135 void AppendParagraph() {} 136 xub_StrLen AppendTextPortion( sal_uInt16 /*nPara*/, const String & /*rText*/, const SfxItemSet & /*rSet*/ ) { return 0; } 137 138 //XTextCopy 139 void CopyText(const SvxTextForwarder& ){} 140 141 XubString CalcFieldValue( const SvxFieldItem& /*rField*/, sal_uInt16 /*nPara*/, sal_uInt16 /*nPos*/, Color*& /*rpTxtColor*/, Color*& /*rpFldColor*/ ) 142 { 143 return XubString(); 144 } 145 void FieldClicked( const SvxFieldItem&, sal_uInt16, xub_StrLen ) {;} 146 147 sal_Bool IsValid() const { return sal_True; } 148 149 void SetNotifyHdl( const Link& ) {} 150 LanguageType GetLanguage( sal_uInt16, sal_uInt16 ) const { return LANGUAGE_DONTKNOW; } 151 sal_uInt16 GetFieldCount( sal_uInt16 ) const { return 0; } 152 EFieldInfo GetFieldInfo( sal_uInt16, sal_uInt16 ) const { return EFieldInfo(); } 153 EBulletInfo GetBulletInfo( sal_uInt16 ) const { return EBulletInfo(); } 154 Rectangle GetCharBounds( sal_uInt16, sal_uInt16 ) const { return Rectangle(); } 155 Rectangle GetParaBounds( sal_uInt16 ) const { return Rectangle(); } 156 MapMode GetMapMode() const { return MapMode(); } 157 OutputDevice* GetRefDevice() const { return NULL; } 158 sal_Bool GetIndexAtPoint( const Point&, sal_uInt16&, sal_uInt16& ) const { return sal_False; } 159 sal_Bool GetWordIndices( sal_uInt16, sal_uInt16, sal_uInt16&, sal_uInt16& ) const { return sal_False; } 160 sal_Bool GetAttributeRun( sal_uInt16&, sal_uInt16&, sal_uInt16, sal_uInt16 ) const { return sal_False; } 161 sal_uInt16 GetLineCount( sal_uInt16 nPara ) const { return nPara == 0 ? 1 : 0; } 162 sal_uInt16 GetLineLen( sal_uInt16, sal_uInt16 ) const { return 0; } 163 void GetLineBoundaries( /*out*/sal_uInt16 & rStart, /*out*/sal_uInt16 & rEnd, sal_uInt16 /*nParagraph*/, sal_uInt16 /*nLine*/ ) const { rStart = rEnd = 0; } 164 sal_uInt16 GetLineNumberAtIndex( sal_uInt16 /*nPara*/, sal_uInt16 /*nIndex*/ ) const { return 0; } 165 166 // the following two methods would, strictly speaking, require 167 // a switch to a real EditSource, too. Fortunately, the 168 // AccessibleEditableTextPara implementation currently always 169 // calls GetEditViewForwarder(true) before doing 170 // changes. Thus, we rely on this behabviour here (problem 171 // when that changes: via accessibility API, it would no 172 // longer be possible to enter text in previously empty 173 // shapes). 174 sal_Bool Delete( const ESelection& ) { return sal_False; } 175 sal_Bool InsertText( const String&, const ESelection& ) { return sal_False; } 176 sal_Bool QuickFormatDoc( sal_Bool ) { return sal_True; } 177 sal_Int16 GetDepth( sal_uInt16 ) const { return -1; } 178 sal_Bool SetDepth( sal_uInt16, sal_Int16 ) { return sal_True; } 179 180 Rectangle GetVisArea() const { return Rectangle(); } 181 Point LogicToPixel( const Point& rPoint, const MapMode& /*rMapMode*/ ) const { return rPoint; } 182 Point PixelToLogic( const Point& rPoint, const MapMode& /*rMapMode*/ ) const { return rPoint; } 183 184 }; 185 186 // ------------------------------------------------------------------------- 187 // Implementing AccessibleProxyEditSource_Impl 188 // ------------------------------------------------------------------------- 189 190 AccessibleProxyEditSource_Impl::AccessibleProxyEditSource_Impl( SdrObject& rObj, 191 SdrView& rView, 192 const Window& rViewWindow ) : 193 maEditSource( rObj, 0, rView, rViewWindow ) 194 { 195 } 196 197 AccessibleProxyEditSource_Impl::~AccessibleProxyEditSource_Impl() 198 { 199 } 200 201 SvxTextForwarder* AccessibleProxyEditSource_Impl::GetTextForwarder() 202 { 203 return maEditSource.GetTextForwarder(); 204 } 205 206 SvxViewForwarder* AccessibleProxyEditSource_Impl::GetViewForwarder() 207 { 208 return maEditSource.GetViewForwarder(); 209 } 210 211 SvxEditViewForwarder* AccessibleProxyEditSource_Impl::GetEditViewForwarder( sal_Bool bCreate ) 212 { 213 return maEditSource.GetEditViewForwarder( bCreate ); 214 } 215 216 SvxEditSource* AccessibleProxyEditSource_Impl::Clone() const 217 { 218 return maEditSource.Clone(); 219 } 220 221 void AccessibleProxyEditSource_Impl::UpdateData() 222 { 223 maEditSource.UpdateData(); 224 } 225 226 SfxBroadcaster& AccessibleProxyEditSource_Impl::GetBroadcaster() const 227 { 228 return maEditSource.GetBroadcaster(); 229 } 230 231 232 // ------------------------------------------------------------------------- 233 // Implementing AccessibleEmptyEditSource 234 // ------------------------------------------------------------------------- 235 236 AccessibleEmptyEditSource::AccessibleEmptyEditSource( SdrObject& rObj, 237 SdrView& rView, 238 const Window& rViewWindow ) : 239 mpEditSource( new AccessibleEmptyEditSource_Impl() ), 240 mrObj(rObj), 241 mrView(rView), 242 mrViewWindow(rViewWindow), 243 mbEditSourceEmpty( true ) 244 { 245 if( mrObj.GetModel() ) 246 StartListening( *mrObj.GetModel() ); 247 } 248 249 AccessibleEmptyEditSource::~AccessibleEmptyEditSource() 250 { 251 if( !mbEditSourceEmpty ) 252 { 253 // deregister as listener 254 if( mpEditSource.get() ) 255 EndListening( mpEditSource->GetBroadcaster() ); 256 } 257 else 258 { 259 if( mrObj.GetModel() ) 260 EndListening( *mrObj.GetModel() ); 261 } 262 } 263 264 SvxTextForwarder* AccessibleEmptyEditSource::GetTextForwarder() 265 { 266 if( !mpEditSource.get() ) 267 return NULL; 268 269 return mpEditSource->GetTextForwarder(); 270 } 271 272 SvxViewForwarder* AccessibleEmptyEditSource::GetViewForwarder() 273 { 274 if( !mpEditSource.get() ) 275 return NULL; 276 277 return mpEditSource->GetViewForwarder(); 278 } 279 280 void AccessibleEmptyEditSource::Switch2ProxyEditSource() 281 { 282 // deregister EmptyEditSource model listener 283 if( mrObj.GetModel() ) 284 EndListening( *mrObj.GetModel() ); 285 286 ::std::auto_ptr< SvxEditSource > pProxySource( new AccessibleProxyEditSource_Impl(mrObj, mrView, mrViewWindow) ); 287 ::std::auto_ptr< SvxEditSource > tmp = mpEditSource; 288 mpEditSource = pProxySource; 289 pProxySource = tmp; 290 291 // register as listener 292 StartListening( mpEditSource->GetBroadcaster() ); 293 294 // we've irrevocably a full EditSource now. 295 mbEditSourceEmpty = false; 296 } 297 298 SvxEditViewForwarder* AccessibleEmptyEditSource::GetEditViewForwarder( sal_Bool bCreate ) 299 { 300 if( !mpEditSource.get() ) 301 return NULL; 302 303 // switch edit source, if not yet done 304 if( mbEditSourceEmpty && bCreate ) 305 Switch2ProxyEditSource(); 306 307 return mpEditSource->GetEditViewForwarder( bCreate ); 308 } 309 310 SvxEditSource* AccessibleEmptyEditSource::Clone() const 311 { 312 if( !mpEditSource.get() ) 313 return NULL; 314 315 return mpEditSource->Clone(); 316 } 317 318 void AccessibleEmptyEditSource::UpdateData() 319 { 320 if( mpEditSource.get() ) 321 mpEditSource->UpdateData(); 322 } 323 324 SfxBroadcaster& AccessibleEmptyEditSource::GetBroadcaster() const 325 { 326 return *(const_cast<AccessibleEmptyEditSource*>(this)); 327 } 328 329 void AccessibleEmptyEditSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) 330 { 331 const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint ); 332 333 if( pSdrHint && pSdrHint->GetKind() == HINT_BEGEDIT && 334 &mrObj == pSdrHint->GetObject() && mpEditSource.get() ) 335 { 336 // switch edit source, if not yet done. This is necessary 337 // to become a full-fledged EditSource the first time a 338 // user start entering text in a previously empty object. 339 if( mbEditSourceEmpty ) 340 Switch2ProxyEditSource(); 341 } 342 else if (pSdrHint && pSdrHint->GetObject()!=NULL) 343 { 344 // When the SdrObject just got a para outliner object then 345 // switch the edit source. 346 if (pSdrHint->GetObject()->GetOutlinerParaObject() != NULL) 347 Switch2ProxyEditSource(); 348 } 349 350 // forward messages 351 Broadcast( rHint ); 352 } 353 354 } // end of namespace accessibility 355 356 //------------------------------------------------------------------------ 357