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