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_forms.hxx"
30 #include "richtextcontrol.hxx"
31 #include "frm_module.hxx"
32 #ifndef _FRM_PROPERTY_HRC_
33 #include "property.hrc"
34 #endif
35 #include "services.hxx"
36 
37 #include "richtextmodel.hxx"
38 #include "richtextvclcontrol.hxx"
39 #include "clipboarddispatcher.hxx"
40 #include "parametrizedattributedispatcher.hxx"
41 #include "specialdispatchers.hxx"
42 
43 /** === begin UNO includes === **/
44 #include <com/sun/star/awt/PosSize.hpp>
45 /** === end UNO includes === **/
46 
47 #include <toolkit/helper/vclunohelper.hxx>
48 #include <tools/diagnose_ex.h>
49 #include <vcl/svapp.hxx>
50 
51 #include <svx/svxids.hrc>
52 #include <editeng/editview.hxx>
53 #include <svl/itemset.hxx>
54 #include <svl/itempool.hxx>
55 #include <sfx2/msgpool.hxx>
56 
57 //--------------------------------------------------------------------------
58 extern "C" void SAL_CALL createRegistryInfo_ORichTextControl()
59 {
60     static ::frm::OMultiInstanceAutoRegistration< ::frm::ORichTextControl > aAutoRegistration;
61 }
62 
63 //.........................................................................
64 namespace frm
65 {
66 //.........................................................................
67 
68     using namespace ::com::sun::star::uno;
69     using namespace ::com::sun::star::beans;
70     using namespace ::com::sun::star::awt;
71     using namespace ::com::sun::star::lang;
72     using namespace ::com::sun::star::frame;
73 
74 #define FORWARD_TO_PEER_1( unoInterface, method, param1 )   \
75     Reference< unoInterface > xTypedPeer( getPeer(), UNO_QUERY );   \
76     if ( xTypedPeer.is() )  \
77     {   \
78         xTypedPeer->method( param1 );  \
79     }
80 
81 #define FORWARD_TO_PEER_1_RET( returnType, unoInterface, method, param1 )   \
82     returnType aReturn; \
83     Reference< unoInterface > xTypedPeer( getPeer(), UNO_QUERY );   \
84     if ( xTypedPeer.is() )  \
85     {   \
86         aReturn = xTypedPeer->method( param1 );  \
87     }   \
88     return aReturn;
89 
90 #define FORWARD_TO_PEER_3( unoInterface, method, param1, param2, param3 )   \
91     Reference< unoInterface > xTypedPeer( getPeer(), UNO_QUERY );   \
92     if ( xTypedPeer.is() )  \
93     {   \
94         xTypedPeer->method( param1, param2, param3 );  \
95     }
96 
97 #define FORWARD_TO_PEER_3_RET( returnType, unoInterface, method, param1, param2, param3 )   \
98     returnType aReturn; \
99     Reference< unoInterface > xTypedPeer( getPeer(), UNO_QUERY );   \
100     if ( xTypedPeer.is() )  \
101     {   \
102         aReturn = xTypedPeer->method( param1, param2, param3 );  \
103     }   \
104     return aReturn;
105 
106     //==================================================================
107     // ORichTextControl
108     //==================================================================
109     DBG_NAME( ORichTextControl )
110     //------------------------------------------------------------------
111     ORichTextControl::ORichTextControl( const Reference< XMultiServiceFactory >& _rxORB )
112         :UnoEditControl( _rxORB )
113     {
114         DBG_CTOR( ORichTextControl, NULL );
115     }
116 
117     //------------------------------------------------------------------
118     ORichTextControl::~ORichTextControl()
119     {
120         DBG_DTOR( ORichTextControl, NULL );
121     }
122 
123     //------------------------------------------------------------------
124     IMPLEMENT_FORWARD_XTYPEPROVIDER2( ORichTextControl, UnoEditControl, ORichTextControl_Base )
125 
126     //------------------------------------------------------------------
127     Any SAL_CALL ORichTextControl::queryAggregation( const Type& _rType ) throw ( RuntimeException )
128     {
129         Any aReturn = UnoEditControl::queryAggregation( _rType );
130 
131         if ( !aReturn.hasValue() )
132             aReturn = ORichTextControl_Base::queryInterface( _rType );
133 
134         return aReturn;
135     }
136 
137     //------------------------------------------------------------------
138     namespace
139     {
140         //..............................................................
141         static void implAdjustTriStateFlag( const Reference< XPropertySet >& _rxProps, const ::rtl::OUString& _rPropertyName,
142             WinBits& _rAllBits, WinBits _nPositiveFlag, WinBits nNegativeFlag )
143         {
144             sal_Bool bFlagValue = sal_False;
145             if ( _rxProps->getPropertyValue( _rPropertyName ) >>= bFlagValue )
146                 _rAllBits |= ( bFlagValue ? _nPositiveFlag : nNegativeFlag );
147         }
148 
149         //..............................................................
150         static void implAdjustTwoStateFlag( const Any& _rValue, WinBits& _rAllBits, WinBits _nFlag, bool _bInvert = false )
151         {
152             sal_Bool bFlagValue = sal_False;
153             if ( _rValue >>= bFlagValue )
154             {
155                 if ( _bInvert )
156                     bFlagValue = !bFlagValue;
157                 if ( bFlagValue )
158                     _rAllBits |= _nFlag;
159                 else
160                     _rAllBits &= ~_nFlag;
161             }
162         }
163 
164         //..............................................................
165         static void implAdjustTwoStateFlag( const Reference< XPropertySet >& _rxProps, const ::rtl::OUString& _rPropertyName,
166             WinBits& _rAllBits, WinBits _nFlag, bool _bInvert = false )
167         {
168             implAdjustTwoStateFlag( _rxProps->getPropertyValue( _rPropertyName ), _rAllBits, _nFlag, _bInvert );
169         }
170 
171         //..............................................................
172         static void adjustTwoStateWinBit( Window* _pWindow, const Any& _rValue, WinBits _nFlag, bool _bInvert = false )
173         {
174             WinBits nBits = _pWindow->GetStyle();
175             implAdjustTwoStateFlag( _rValue, nBits, _nFlag, _bInvert );
176             _pWindow->SetStyle( nBits );
177         }
178 
179         //..............................................................
180         static WinBits getWinBits( const Reference< XControlModel >& _rxModel, WinBits nBaseBits = 0 )
181         {
182             WinBits nBits = nBaseBits;
183             try
184             {
185                 Reference< XPropertySet > xProps( _rxModel, UNO_QUERY );
186                 if ( xProps.is() )
187                 {
188                     sal_Int16 nBorder = 0;
189                     xProps->getPropertyValue( PROPERTY_BORDER ) >>= nBorder;
190                     if ( nBorder )
191                         nBits |= WB_BORDER;
192 
193                     implAdjustTriStateFlag( xProps, PROPERTY_TABSTOP,        nBits, WB_TABSTOP, WB_NOTABSTOP );
194                     implAdjustTwoStateFlag( xProps, PROPERTY_HSCROLL,        nBits, WB_HSCROLL );
195                     implAdjustTwoStateFlag( xProps, PROPERTY_VSCROLL,        nBits, WB_VSCROLL );
196                     implAdjustTwoStateFlag( xProps, PROPERTY_HARDLINEBREAKS, nBits, WB_WORDBREAK, true );
197                 }
198             }
199             catch( const Exception& )
200             {
201                 DBG_UNHANDLED_EXCEPTION();
202             }
203             return nBits;
204         }
205     }
206 
207     //------------------------------------------------------------------
208     void SAL_CALL ORichTextControl::createPeer( const Reference< XToolkit >& _rToolkit, const Reference< XWindowPeer >& _rParentPeer ) throw( RuntimeException )
209     {
210         sal_Bool bReallyActAsRichText = sal_False;
211         try
212         {
213             Reference< XPropertySet > xModelProps( getModel(), UNO_QUERY_THROW );
214             xModelProps->getPropertyValue( PROPERTY_RICH_TEXT ) >>= bReallyActAsRichText;
215         }
216         catch( const Exception& )
217         {
218             DBG_UNHANDLED_EXCEPTION();
219         }
220 
221         if ( !bReallyActAsRichText )
222         {
223             UnoEditControl::createPeer( _rToolkit, _rParentPeer );
224             OControl::initFormControlPeer( getPeer() );
225             return;
226         }
227 
228     	::vos::OGuard aGuard( Application::GetSolarMutex() );
229 
230 	    if (!getPeer().is())
231 	    {
232 		    mbCreatingPeer = sal_True;
233 
234             // determine the VLC window for the parent
235 		    Window* pParentWin = NULL;
236 		    if ( _rParentPeer.is() )
237 		    {
238 			    VCLXWindow* pParentXWin = VCLXWindow::GetImplementation( _rParentPeer );
239 			    if ( pParentXWin )
240 				    pParentWin = pParentXWin->GetWindow();
241                 DBG_ASSERT( pParentWin, "ORichTextControl::createPeer: could not obtain the VCL-level parent window!" );
242 		    }
243 
244             // create the peer
245             Reference< XControlModel > xModel( getModel() );
246             ORichTextPeer* pPeer = ORichTextPeer::Create( xModel, pParentWin, getWinBits( xModel ) );
247             DBG_ASSERT( pPeer, "ORichTextControl::createPeer: invalid peer returned!" );
248             if ( pPeer )
249             {
250                 // by definition, the returned component is aquired once
251                 pPeer->release();
252 
253                 // announce the peer to the base class
254                 setPeer( pPeer );
255 
256                 // initialize ourself (and thus the peer) with the model properties
257     		    updateFromModel();
258 
259                 Reference< XView >  xPeerView( getPeer(), UNO_QUERY );
260                 if ( xPeerView.is() )
261                 {
262 			        xPeerView->setZoom( maComponentInfos.nZoomX, maComponentInfos.nZoomY );
263 			        xPeerView->setGraphics( mxGraphics );
264                 }
265 
266                 // a lot of initial settings from our component infos
267 	            setPosSize( maComponentInfos.nX, maComponentInfos.nY, maComponentInfos.nWidth, maComponentInfos.nHeight, PosSize::POSSIZE );
268 
269                 pPeer->setVisible   ( maComponentInfos.bVisible && !mbDesignMode );
270                 pPeer->setEnable    ( maComponentInfos.bEnable                   );
271                 pPeer->setDesignMode( mbDesignMode                               );
272 
273                 peerCreated();
274             }
275 
276 		    mbCreatingPeer = sal_False;
277 
278             OControl::initFormControlPeer( getPeer() );
279         }
280     }
281 
282     //------------------------------------------------------------------
283     ::rtl::OUString	SAL_CALL ORichTextControl::getImplementationName()  throw( RuntimeException )
284     {
285         return getImplementationName_Static();
286     }
287 
288     //------------------------------------------------------------------
289     Sequence< ::rtl::OUString > SAL_CALL ORichTextControl::getSupportedServiceNames()  throw( RuntimeException )
290     {
291         return getSupportedServiceNames_Static();
292     }
293 
294     //------------------------------------------------------------------
295     ::rtl::OUString	SAL_CALL ORichTextControl::getImplementationName_Static()
296     {
297         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.form.ORichTextControl" ) );
298     }
299 
300     //------------------------------------------------------------------
301     Sequence< ::rtl::OUString > SAL_CALL ORichTextControl::getSupportedServiceNames_Static()
302     {
303         Sequence< ::rtl::OUString > aServices( 3 );
304         aServices[ 0 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.UnoControl" ) );
305         aServices[ 1 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.UnoControlEdit" ) );
306         aServices[ 2 ] = FRM_SUN_CONTROL_RICHTEXTCONTROL;
307         return aServices;
308     }
309 
310     //------------------------------------------------------------------
311     Reference< XInterface > SAL_CALL ORichTextControl::Create( const Reference< XMultiServiceFactory >& _rxFactory )
312     {
313         return *( new ORichTextControl( _rxFactory ) );
314     }
315 
316     //--------------------------------------------------------------------
317     Reference< XDispatch > SAL_CALL ORichTextControl::queryDispatch( const ::com::sun::star::util::URL& _rURL, const ::rtl::OUString& _rTargetFrameName, sal_Int32 _nSearchFlags ) throw (RuntimeException)
318     {
319         FORWARD_TO_PEER_3_RET( Reference< XDispatch >, XDispatchProvider, queryDispatch, _rURL, _rTargetFrameName, _nSearchFlags );
320     }
321 
322     //--------------------------------------------------------------------
323     Sequence< Reference< XDispatch > > SAL_CALL ORichTextControl::queryDispatches( const Sequence< DispatchDescriptor >& _rRequests ) throw (RuntimeException)
324     {
325         FORWARD_TO_PEER_1_RET( Sequence< Reference< XDispatch > >, XDispatchProvider, queryDispatches, _rRequests );
326     }
327 
328     //--------------------------------------------------------------------
329     sal_Bool ORichTextControl::requiresNewPeer( const ::rtl::OUString& _rPropertyName ) const
330     {
331         return UnoControl::requiresNewPeer( _rPropertyName ) || _rPropertyName.equals( PROPERTY_RICH_TEXT );
332     }
333 
334     //==================================================================
335     // ORichTextPeer
336     //==================================================================
337     DBG_NAME( ORichTextPeer )
338     //------------------------------------------------------------------
339     ORichTextPeer* ORichTextPeer::Create( const Reference< XControlModel >& _rxModel, Window* _pParentWindow, WinBits _nStyle )
340     {
341         DBG_TESTSOLARMUTEX();
342 
343         // the EditEngine of the model
344         RichTextEngine* pEngine = ORichTextModel::getEditEngine( _rxModel );
345         OSL_ENSURE( pEngine, "ORichTextPeer::Create: could not obtaine the edit engine from the model!" );
346         if ( !pEngine )
347             return NULL;
348 
349         // the peer itself
350         ORichTextPeer* pPeer = new ORichTextPeer;
351         pPeer->acquire();   // by definition, the returned object is aquired once
352 
353         // the VCL control for the peer
354         RichTextControl* pRichTextControl = new RichTextControl( pEngine, _pParentWindow, _nStyle, NULL, pPeer );
355 
356         // some knittings
357         pRichTextControl->SetComponentInterface( pPeer );
358 
359         // outta here
360         return pPeer;
361     }
362 
363     //------------------------------------------------------------------
364     ORichTextPeer::ORichTextPeer()
365     {
366         DBG_CTOR( ORichTextPeer, NULL );
367     }
368 
369     //------------------------------------------------------------------
370     ORichTextPeer::~ORichTextPeer()
371     {
372         DBG_DTOR( ORichTextPeer, NULL );
373     }
374 
375     //------------------------------------------------------------------
376     void ORichTextPeer::dispose( ) throw(RuntimeException)
377     {
378         {
379         	::vos::OGuard aGuard( GetMutex() );
380             RichTextControl* pRichTextControl = static_cast< RichTextControl* >( GetWindow() );
381 
382             if ( pRichTextControl )
383             {
384                 for (   AttributeDispatchers::iterator aDisposeLoop = m_aDispatchers.begin();
385                         aDisposeLoop != m_aDispatchers.end();
386                         ++aDisposeLoop
387                     )
388                 {
389                     pRichTextControl->disableAttributeNotification( aDisposeLoop->first );
390                     aDisposeLoop->second->dispose();
391                 }
392             }
393 
394             AttributeDispatchers aEmpty;
395             m_aDispatchers.swap( aEmpty );
396         }
397 
398         VCLXWindow::dispose();
399     }
400 
401     //--------------------------------------------------------------------
402     void SAL_CALL ORichTextPeer::draw( sal_Int32 _nX, sal_Int32 _nY ) throw(::com::sun::star::uno::RuntimeException)
403     {
404     	::vos::OGuard aGuard( Application::GetSolarMutex() );
405 
406         RichTextControl* pControl = static_cast< RichTextControl* >( GetWindow() );
407         if ( !pControl )
408             return;
409 
410         OutputDevice* pTargetDevice = VCLUnoHelper::GetOutputDevice( getGraphics() );
411         OSL_ENSURE( pTargetDevice != NULL, "ORichTextPeer::draw: no graphics -> no drawing!" );
412         if ( !pTargetDevice )
413             return;
414 
415         ::Size aSize = pControl->GetSizePixel();
416         const MapUnit eTargetUnit = pTargetDevice->GetMapMode().GetMapUnit();
417         if ( eTargetUnit != MAP_PIXEL )
418 		    aSize = pControl->PixelToLogic( aSize, eTargetUnit );
419 
420         ::Point aPos( _nX, _nY );
421         // the XView::draw API talks about pixels, always ...
422         if ( eTargetUnit != MAP_PIXEL )
423             aPos = pTargetDevice->PixelToLogic( aPos );
424 
425         pControl->Draw( pTargetDevice, aPos, aSize, WINDOW_DRAW_NOCONTROLS );
426     }
427 
428     //--------------------------------------------------------------------
429     void SAL_CALL ORichTextPeer::setProperty( const ::rtl::OUString& _rPropertyName, const Any& _rValue ) throw (RuntimeException)
430     {
431         if ( !GetWindow() )
432         {
433             VCLXWindow::setProperty( _rPropertyName, _rValue );
434             return;
435         }
436 
437         if ( _rPropertyName.equals( PROPERTY_BACKGROUNDCOLOR ) )
438         {
439             RichTextControl* pControl = static_cast< RichTextControl* >( GetWindow() );
440             if ( !_rValue.hasValue() )
441             {
442                 pControl->SetBackgroundColor( );
443             }
444             else
445             {
446                 sal_Int32 nColor = COL_TRANSPARENT;
447                 _rValue >>= nColor;
448                 pControl->SetBackgroundColor( Color( nColor ) );
449             }
450         }
451         else if (  _rPropertyName.equals( PROPERTY_HSCROLL ) )
452         {
453             adjustTwoStateWinBit( GetWindow(), _rValue, WB_HSCROLL );
454         }
455         else if ( _rPropertyName.equals( PROPERTY_VSCROLL ) )
456         {
457             adjustTwoStateWinBit( GetWindow(), _rValue, WB_VSCROLL );
458         }
459         else if ( _rPropertyName.equals( PROPERTY_HARDLINEBREAKS ) )
460         {
461             adjustTwoStateWinBit( GetWindow(), _rValue, WB_WORDBREAK, true );
462         }
463         else if ( _rPropertyName.equals( PROPERTY_READONLY ) )
464         {
465             RichTextControl* pControl = static_cast< RichTextControl* >( GetWindow() );
466             sal_Bool bReadOnly( pControl->IsReadOnly() );
467             OSL_VERIFY( _rValue >>= bReadOnly );
468             pControl->SetReadOnly( bReadOnly );
469 
470             // update the dispatchers
471             for (   AttributeDispatchers::iterator aDispatcherLoop = m_aDispatchers.begin();
472                     aDispatcherLoop != m_aDispatchers.end();
473                     ++aDispatcherLoop
474                 )
475             {
476                 aDispatcherLoop->second->invalidate();
477             }
478         }
479         else if ( _rPropertyName.equals( PROPERTY_HIDEINACTIVESELECTION ) )
480         {
481             RichTextControl* pRichTextControl = static_cast< RichTextControl* >( GetWindow() );
482             sal_Bool bHide = pRichTextControl->GetHideInactiveSelection();
483             OSL_VERIFY( _rValue >>= bHide );
484             pRichTextControl->SetHideInactiveSelection( bHide );
485         }
486         else
487             VCLXWindow::setProperty( _rPropertyName, _rValue );
488     }
489 
490     //------------------------------------------------------------------
491     IMPLEMENT_FORWARD_XINTERFACE2( ORichTextPeer, VCLXWindow, ORichTextPeer_Base )
492 
493     //------------------------------------------------------------------
494     IMPLEMENT_FORWARD_XTYPEPROVIDER2( ORichTextPeer, VCLXWindow, ORichTextPeer_Base )
495 
496     //--------------------------------------------------------------------
497     namespace
498     {
499         static SfxSlotId lcl_translateConflictingSlot( SfxSlotId _nIDFromPool )
500         {
501             // HACK HACK HACK
502             // unfortunately, some of our applications have some conflicting slots,
503             // i.e. slots which have the same UNO name as an existing other (common)
504             // slot.
505             // For instance, both the slots SID_SET_SUPER_SCRIPT (from SVX) and FN_SET_SUPER_SCRIPT
506             // (from SW) have the UNO name "SuperScript".
507             // Now, if the controls lives in a text document, and asks the SfxSlotPool for
508             // the id belonging to "SuperScript", it gets the FN_SET_SUPER_SCRIPT - which
509             // is completely unknown to the EditEngine.
510             // So, we need to translate such conflicting ids.
511             //
512             // Note that the real solution would be to fix the applications to
513             // *not* define conflicting slots. Alternatively, if SFX would provide a slot pool
514             // which is *static* (i.e. independent on the active application), then we
515             // would also never encounter such a conflict.
516             SfxSlotId nReturn( _nIDFromPool );
517             switch ( _nIDFromPool )
518             {
519             case 20411: /* FM_SET_SUPER_SCRIPT, originating in SW */
520                 nReturn = SID_SET_SUPER_SCRIPT;
521                 break;
522             case 20412: /* FN_SET_SUB_SCRIPT, originating in SW */
523                 nReturn = SID_SET_SUB_SCRIPT;
524                 break;
525             }
526             return nReturn;
527         }
528     }
529 
530     //--------------------------------------------------------------------
531     ORichTextPeer::SingleAttributeDispatcher ORichTextPeer::implCreateDispatcher( SfxSlotId _nSlotId, const ::com::sun::star::util::URL& _rURL )
532     {
533         RichTextControl* pRichTextControl = static_cast< RichTextControl* >( GetWindow() );
534         OSL_PRECOND( pRichTextControl, "ORichTextPeer::implCreateDispatcher: invalid window!" );
535         if ( !pRichTextControl )
536             return SingleAttributeDispatcher( NULL );
537 
538         ORichTextFeatureDispatcher* pDispatcher = NULL;
539         OAttributeDispatcher* pAttributeDispatcher = NULL;
540         switch ( _nSlotId )
541         {
542         case SID_CUT:
543             pDispatcher = new OClipboardDispatcher( pRichTextControl->getView(), OClipboardDispatcher::eCut );
544             break;
545 
546         case SID_COPY:
547             pDispatcher = new OClipboardDispatcher( pRichTextControl->getView(), OClipboardDispatcher::eCopy );
548             break;
549 
550         case SID_PASTE:
551             pDispatcher = new OPasteClipboardDispatcher( pRichTextControl->getView() );
552             break;
553 
554         case SID_SELECTALL:
555             pDispatcher = new OSelectAllDispatcher( pRichTextControl->getView(), _rURL );
556             break;
557 
558         case SID_ATTR_PARA_LEFT_TO_RIGHT:
559         case SID_ATTR_PARA_RIGHT_TO_LEFT:
560             pAttributeDispatcher = new OParagraphDirectionDispatcher( pRichTextControl->getView(), _nSlotId, _rURL, pRichTextControl );
561             break;
562 
563         case SID_TEXTDIRECTION_TOP_TO_BOTTOM:
564         case SID_TEXTDIRECTION_LEFT_TO_RIGHT:
565             pDispatcher = new OTextDirectionDispatcher( pRichTextControl->getView(), _rURL );
566             break;
567 
568         case SID_ATTR_PARA_HANGPUNCTUATION:
569         case SID_ATTR_PARA_FORBIDDEN_RULES:
570         case SID_ATTR_PARA_SCRIPTSPACE:
571             pAttributeDispatcher = new OAsianFontLayoutDispatcher( pRichTextControl->getView(), _nSlotId, _rURL, pRichTextControl );
572             break;
573 
574         default:
575         {
576             // is it a supported slot?
577             bool bSupportedSlot = false;
578             if ( !bSupportedSlot )
579             {
580                 const SfxItemPool& rPool = *pRichTextControl->getView().GetEmptyItemSet().GetPool();
581                 bSupportedSlot = rPool.IsInRange( rPool.GetWhich( _nSlotId ) );
582             }
583             if ( !bSupportedSlot )
584                 bSupportedSlot = RichTextControl::isMappableSlot( _nSlotId );
585 
586             if ( bSupportedSlot )
587             {   // it's really a slot which is supported by the EditEngine
588 
589                 bool bNeedParametrizedDispatcher = true;
590                 if  (  ( _nSlotId == SID_ATTR_CHAR_POSTURE )
591                     || ( _nSlotId == SID_ATTR_CHAR_CJK_POSTURE )
592                     || ( _nSlotId == SID_ATTR_CHAR_CTL_POSTURE )
593                     || ( _nSlotId == SID_ATTR_CHAR_LATIN_POSTURE )
594                     || ( _nSlotId == SID_ATTR_CHAR_WEIGHT )
595                     || ( _nSlotId == SID_ATTR_CHAR_CJK_WEIGHT )
596                     || ( _nSlotId == SID_ATTR_CHAR_CTL_WEIGHT )
597                     || ( _nSlotId == SID_ATTR_CHAR_LATIN_WEIGHT )
598                     || ( _nSlotId == SID_ATTR_CHAR_LANGUAGE )
599                     || ( _nSlotId == SID_ATTR_CHAR_CJK_LANGUAGE )
600                     || ( _nSlotId == SID_ATTR_CHAR_CTL_LANGUAGE )
601                     || ( _nSlotId == SID_ATTR_CHAR_LATIN_LANGUAGE )
602                     || ( _nSlotId == SID_ATTR_CHAR_CONTOUR )
603                     || ( _nSlotId == SID_ATTR_CHAR_SHADOWED )
604                     || ( _nSlotId == SID_ATTR_CHAR_WORDLINEMODE )
605                     || ( _nSlotId == SID_ATTR_CHAR_COLOR )
606                     || ( _nSlotId == SID_ATTR_CHAR_RELIEF )
607                     || ( _nSlotId == SID_ATTR_CHAR_KERNING )
608                     || ( _nSlotId == SID_ATTR_CHAR_AUTOKERN )
609                     || ( _nSlotId == SID_ATTR_CHAR_SCALEWIDTH )
610                     )
611                 {
612                     bNeedParametrizedDispatcher = true;
613                 }
614                 else if (  ( _nSlotId == SID_ATTR_PARA_HANGPUNCTUATION )
615                         || ( _nSlotId == SID_ATTR_PARA_FORBIDDEN_RULES )
616                         || ( _nSlotId == SID_ATTR_PARA_SCRIPTSPACE )
617                         )
618                 {
619                     bNeedParametrizedDispatcher = false;
620                 }
621                 else
622                 {
623                     SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool( NULL );
624                     const SfxSlot* pSlot = rSlotPool.GetSlot( _nSlotId );
625                     const SfxType* pType = pSlot ? pSlot->GetType() : NULL;
626                     if ( pType )
627                     {
628                         bNeedParametrizedDispatcher = ( pType->nAttribs > 0 );
629                     }
630                 }
631 
632                 if ( bNeedParametrizedDispatcher )
633                 {
634                 #if OSL_DEBUG_LEVEL > 0
635                     ::rtl::OString sTrace( "ORichTextPeer::implCreateDispatcher: creating *parametrized* dispatcher for " );
636                     sTrace += ::rtl::OString( _rURL.Complete.getStr(), _rURL.Complete.getLength(), RTL_TEXTENCODING_ASCII_US );
637                     DBG_TRACE( sTrace.getStr() );
638                 #endif
639                     pAttributeDispatcher = new OParametrizedAttributeDispatcher( pRichTextControl->getView(), _nSlotId, _rURL, pRichTextControl );
640                 }
641                 else
642                 {
643                 #if OSL_DEBUG_LEVEL > 0
644                     ::rtl::OString sTrace( "ORichTextPeer::implCreateDispatcher: creating *normal* dispatcher for " );
645                     sTrace += ::rtl::OString( _rURL.Complete.getStr(), _rURL.Complete.getLength(), RTL_TEXTENCODING_ASCII_US );
646                     DBG_TRACE( sTrace.getStr() );
647                 #endif
648                     pAttributeDispatcher = new OAttributeDispatcher( pRichTextControl->getView(), _nSlotId, _rURL, pRichTextControl );
649                 }
650             }
651         #if OSL_DEBUG_LEVEL > 0
652             else
653             {
654                 ::rtl::OString sTrace( "ORichTextPeer::implCreateDispatcher: not creating dispatcher (unsupported slot) for " );
655                 sTrace += ::rtl::OString( _rURL.Complete.getStr(), _rURL.Complete.getLength(), RTL_TEXTENCODING_ASCII_US );
656                 DBG_TRACE( sTrace.getStr() );
657             }
658         #endif
659         }
660         break;
661         }
662 
663         SingleAttributeDispatcher xDispatcher( pDispatcher );
664         if ( pAttributeDispatcher )
665         {
666             xDispatcher = SingleAttributeDispatcher( pAttributeDispatcher );
667             pRichTextControl->enableAttributeNotification( _nSlotId, pAttributeDispatcher );
668         }
669 
670         return xDispatcher;
671     }
672 
673     //--------------------------------------------------------------------
674     namespace
675     {
676         SfxSlotId lcl_getSlotFromUnoName( SfxSlotPool& _rSlotPool, const ::rtl::OUString& _rUnoSlotName )
677         {
678             const SfxSlot* pSlot = _rSlotPool.GetUnoSlot( _rUnoSlotName );
679             if ( pSlot )
680             {
681                 // okay, there's a slot with the given UNO name
682                 return lcl_translateConflictingSlot( pSlot->GetSlotId() );
683             }
684 
685             // some hard-coded slots, which do not have a UNO name at SFX level, but which
686             // we nevertheless need to transport via UNO mechanisms, so we need a name
687             if ( _rUnoSlotName.equalsAscii( "AllowHangingPunctuation" ) )
688                 return SID_ATTR_PARA_HANGPUNCTUATION;
689             if ( _rUnoSlotName.equalsAscii( "ApplyForbiddenCharacterRules" ) )
690                 return SID_ATTR_PARA_FORBIDDEN_RULES;
691             if ( _rUnoSlotName.equalsAscii( "UseScriptSpacing" ) )
692                 return SID_ATTR_PARA_SCRIPTSPACE;
693 
694             OSL_ENSURE( pSlot, "lcl_getSlotFromUnoName: unknown UNO slot name!" );
695             return 0;
696         }
697     }
698 
699     //--------------------------------------------------------------------
700     Reference< XDispatch > SAL_CALL ORichTextPeer::queryDispatch( const ::com::sun::star::util::URL& _rURL, const ::rtl::OUString& /*_rTargetFrameName*/, sal_Int32 /*_nSearchFlags*/ ) throw (RuntimeException)
701     {
702         Reference< XDispatch > xReturn;
703         if ( !GetWindow() )
704         {
705             OSL_ENSURE( sal_False, "ORichTextPeer::queryDispatch: already disposed?" );
706             return xReturn;
707         }
708 
709         // is it an UNO slot?
710         ::rtl::OUString sUnoProtocolPrefix( RTL_CONSTASCII_USTRINGPARAM( ".uno:" ) );
711         if ( 0 == _rURL.Complete.compareTo( sUnoProtocolPrefix, sUnoProtocolPrefix.getLength() ) )
712         {
713             ::rtl::OUString sUnoSlotName = _rURL.Complete.copy( sUnoProtocolPrefix.getLength() );
714             SfxSlotId nSlotId = lcl_getSlotFromUnoName( SfxSlotPool::GetSlotPool( NULL ), sUnoSlotName );
715             if ( nSlotId > 0 )
716             {
717                 // do we already have a dispatcher for this?
718                 AttributeDispatchers::const_iterator aDispatcherPos = m_aDispatchers.find( nSlotId );
719                 if ( aDispatcherPos == m_aDispatchers.end() )
720                 {
721                     SingleAttributeDispatcher pDispatcher = implCreateDispatcher( nSlotId, _rURL );
722                     if ( pDispatcher.is() )
723                     {
724                         aDispatcherPos = m_aDispatchers.insert( AttributeDispatchers::value_type( nSlotId, pDispatcher ) ).first;
725                     }
726                 }
727 
728                 if ( aDispatcherPos != m_aDispatchers.end() )
729                     xReturn = aDispatcherPos->second.getRef();
730             }
731         }
732 
733         return xReturn;
734     }
735 
736     //--------------------------------------------------------------------
737     Sequence< Reference< XDispatch > > SAL_CALL ORichTextPeer::queryDispatches( const Sequence< DispatchDescriptor >& _rRequests ) throw (RuntimeException)
738     {
739         Sequence< Reference< XDispatch > >  aReturn( _rRequests.getLength() );
740         Reference< XDispatch >*             pReturn = aReturn.getArray();
741 
742         const DispatchDescriptor* pRequest = _rRequests.getConstArray();
743         const DispatchDescriptor* pRequestEnd = pRequest + _rRequests.getLength();
744         for ( ; pRequest != pRequestEnd; ++pRequest, ++pReturn )
745         {
746             *pReturn = queryDispatch( pRequest->FeatureURL, pRequest->FrameName, pRequest->SearchFlags );
747         }
748         return aReturn;
749     }
750 
751     //--------------------------------------------------------------------
752     void ORichTextPeer::onSelectionChanged( const ESelection& /*_rSelection*/ )
753     {
754         AttributeDispatchers::iterator aDispatcherPos = m_aDispatchers.find( SID_COPY );
755         if ( aDispatcherPos != m_aDispatchers.end() )
756             aDispatcherPos->second.get()->invalidate();
757 
758         aDispatcherPos = m_aDispatchers.find( SID_CUT );
759         if ( aDispatcherPos != m_aDispatchers.end() )
760             aDispatcherPos->second.get()->invalidate();
761     }
762 
763 //........................................................................
764 }   // namespace frm
765 //........................................................................
766 
767