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 #include "fmprop.hrc"
32 #include "svx/fmresids.hrc"
33 #include "fmtextcontroldialogs.hxx"
34 #include "fmtextcontrolfeature.hxx"
35 #include "fmtextcontrolshell.hxx"
36 #include "editeng/crsditem.hxx"
37 #include "svx/dialmgr.hxx"
38 #include "editeng/editeng.hxx"
39 #include "editeng/eeitem.hxx"
40 #include "svx/fmglob.hxx"
41 #include "editeng/scriptspaceitem.hxx"
42 #include "svx/svxids.hrc"
43 #include "editeng/udlnitem.hxx"
44 
45 /** === begin UNO includes === **/
46 #include <com/sun/star/beans/XPropertySet.hpp>
47 #include <com/sun/star/awt/FontDescriptor.hpp>
48 #include <com/sun/star/frame/XDispatchProvider.hpp>
49 #include <com/sun/star/form/XForm.hpp>
50 #include <com/sun/star/container/XChild.hpp>
51 #include <com/sun/star/awt/XFocusListener.hpp>
52 #include <com/sun/star/awt/XMouseListener.hpp>
53 /** === end UNO includes === **/
54 
55 #include <comphelper/componentcontext.hxx>
56 #include <comphelper/processfactory.hxx>
57 #include <cppuhelper/implbase1.hxx>
58 #include <sfx2/app.hxx>
59 #include <sfx2/bindings.hxx>
60 #include <sfx2/dispatch.hxx>
61 #include <sfx2/msgpool.hxx>
62 #include <sfx2/objsh.hxx>
63 #include <sfx2/request.hxx>
64 #include <sfx2/sfxuno.hxx>
65 #include <sfx2/viewfrm.hxx>
66 #include <svl/eitem.hxx>
67 #include <svl/intitem.hxx>
68 #include <svl/itempool.hxx>
69 #include <svl/languageoptions.hxx>
70 #include <svtools/stringtransfer.hxx>
71 #include <svl/whiter.hxx>
72 #include <toolkit/helper/vclunohelper.hxx>
73 #include <tools/diagnose_ex.h>
74 #include <vcl/msgbox.hxx>
75 #include <vcl/outdev.hxx>
76 #include <vos/mutex.hxx>
77 
78 #include <memory>
79 
80 //........................................................................
81 namespace svx
82 {
83 //........................................................................
84 
85     using namespace ::com::sun::star;
86     using namespace ::com::sun::star::uno;
87     using namespace ::com::sun::star::awt;
88     using namespace ::com::sun::star::form;
89     using namespace ::com::sun::star::form::runtime;
90     using namespace ::com::sun::star::lang;
91     using namespace ::com::sun::star::frame;
92     using namespace ::com::sun::star::util;
93     using namespace ::com::sun::star::beans;
94     using namespace ::com::sun::star::container;
95 
96 	//====================================================================
97     typedef sal_uInt16 WhichId;
98 
99 	//====================================================================
100     static SfxSlotId pTextControlSlots[] =
101     {
102         SID_CLIPBOARD_FORMAT_ITEMS,
103         SID_CUT,
104         SID_COPY,
105         SID_PASTE,
106         SID_SELECTALL,
107 //        SID_ATTR_TABSTOP,           /* 2 */
108         SID_ATTR_CHAR_FONT,
109         SID_ATTR_CHAR_POSTURE,
110         SID_ATTR_CHAR_WEIGHT,
111         SID_ATTR_CHAR_SHADOWED,
112         SID_ATTR_CHAR_WORDLINEMODE,
113         SID_ATTR_CHAR_CONTOUR,
114         SID_ATTR_CHAR_STRIKEOUT,
115         SID_ATTR_CHAR_UNDERLINE,
116         SID_ATTR_CHAR_FONTHEIGHT,
117         SID_ATTR_CHAR_COLOR,
118         SID_ATTR_CHAR_KERNING,
119         SID_ATTR_CHAR_LANGUAGE,     /* 20 */
120         SID_ATTR_CHAR_ESCAPEMENT,
121         SID_ATTR_PARA_ADJUST,       /* 28 */
122         SID_ATTR_PARA_ADJUST_LEFT,
123         SID_ATTR_PARA_ADJUST_RIGHT,
124         SID_ATTR_PARA_ADJUST_CENTER,
125         SID_ATTR_PARA_ADJUST_BLOCK,
126         SID_ATTR_PARA_LINESPACE,    /* 33 */
127         SID_ATTR_PARA_LINESPACE_10,
128         SID_ATTR_PARA_LINESPACE_15,
129         SID_ATTR_PARA_LINESPACE_20,
130         SID_ATTR_LRSPACE,           /* 48 */
131         SID_ATTR_ULSPACE,           /* 49 */
132         SID_ATTR_CHAR_AUTOKERN,
133         SID_SET_SUPER_SCRIPT,
134         SID_SET_SUB_SCRIPT,
135         SID_CHAR_DLG,
136         SID_PARA_DLG,
137 //        SID_TEXTDIRECTION_LEFT_TO_RIGHT, /* 907 */
138 //        SID_TEXTDIRECTION_TOP_TO_BOTTOM,
139         SID_ATTR_CHAR_SCALEWIDTH,       /* 911 */
140         SID_ATTR_CHAR_RELIEF,
141         SID_ATTR_PARA_LEFT_TO_RIGHT,    /* 950 */
142         SID_ATTR_PARA_RIGHT_TO_LEFT,
143         SID_ATTR_CHAR_OVERLINE,
144         0
145     };
146 
147     // slots which we are not responsible for on the SfxShell level, but
148     // need to handle during the "paragraph attributes" and/or "character
149     // attributes" dialogs
150     static SfxSlotId pDialogSlots[] =
151     {
152         SID_ATTR_TABSTOP,
153         SID_ATTR_PARA_HANGPUNCTUATION,
154         SID_ATTR_PARA_FORBIDDEN_RULES,
155         SID_ATTR_PARA_SCRIPTSPACE,
156         SID_ATTR_CHAR_LATIN_LANGUAGE,
157         SID_ATTR_CHAR_CJK_LANGUAGE,
158         SID_ATTR_CHAR_CTL_LANGUAGE,
159         SID_ATTR_CHAR_LATIN_FONT,
160         SID_ATTR_CHAR_CJK_FONT,
161         SID_ATTR_CHAR_CTL_FONT,
162 		SID_ATTR_CHAR_LATIN_FONTHEIGHT,
163 		SID_ATTR_CHAR_CJK_FONTHEIGHT,
164 		SID_ATTR_CHAR_CTL_FONTHEIGHT,
165 		SID_ATTR_CHAR_LATIN_WEIGHT,
166 		SID_ATTR_CHAR_CJK_WEIGHT,
167 		SID_ATTR_CHAR_CTL_WEIGHT,
168 		SID_ATTR_CHAR_LATIN_POSTURE,
169 		SID_ATTR_CHAR_CJK_POSTURE,
170         SID_ATTR_CHAR_CTL_POSTURE,
171         SID_ATTR_CHAR_EMPHASISMARK,
172         0
173     };
174 
175 	//====================================================================
176 	//= FmFocusListenerAdapter
177 	//====================================================================
178     typedef ::cppu::WeakImplHelper1 <   XFocusListener
179                                     >   FmFocusListenerAdapter_Base;
180     class FmFocusListenerAdapter : public FmFocusListenerAdapter_Base
181     {
182     private:
183         IFocusObserver*         m_pObserver;
184         Reference< XWindow >    m_xWindow;
185 
186     public:
187         FmFocusListenerAdapter( const Reference< XControl >& _rxControl, IFocusObserver* _pObserver );
188 
189         // clean up the instance
190         void    dispose();
191 
192     protected:
193         ~FmFocusListenerAdapter();
194 
195     protected:
196         virtual void SAL_CALL focusGained( const FocusEvent& e ) throw (RuntimeException);
197         virtual void SAL_CALL focusLost( const FocusEvent& e ) throw (RuntimeException);
198         virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException);
199     };
200 
201     //--------------------------------------------------------------------
202     DBG_NAME( FmFocusListenerAdapter )
203     //--------------------------------------------------------------------
204     FmFocusListenerAdapter::FmFocusListenerAdapter( const Reference< XControl >& _rxControl, IFocusObserver* _pObserver )
205         :m_pObserver( _pObserver )
206         ,m_xWindow( _rxControl, UNO_QUERY )
207     {
208         DBG_CTOR( FmFocusListenerAdapter, NULL );
209 
210         DBG_ASSERT( m_xWindow.is(), "FmFocusListenerAdapter::FmFocusListenerAdapter: invalid control!" );
211         osl_incrementInterlockedCount( &m_refCount );
212         {
213             try
214             {
215                 if ( m_xWindow.is() )
216                     m_xWindow->addFocusListener( this );
217             }
218             catch( const Exception& )
219             {
220                 DBG_UNHANDLED_EXCEPTION();
221             }
222         }
223         osl_decrementInterlockedCount( &m_refCount );
224     }
225 
226     //--------------------------------------------------------------------
227     FmFocusListenerAdapter::~FmFocusListenerAdapter()
228     {
229         acquire();
230         dispose();
231 
232         DBG_DTOR( FmFocusListenerAdapter, NULL );
233     }
234 
235     //--------------------------------------------------------------------
236     void FmFocusListenerAdapter::dispose()
237     {
238         if ( m_xWindow.is() )
239         {
240             m_xWindow->removeFocusListener( this );
241             m_xWindow.clear();
242         }
243     }
244 
245     //--------------------------------------------------------------------
246     void SAL_CALL FmFocusListenerAdapter::focusGained( const FocusEvent& e ) throw (RuntimeException)
247     {
248         if ( m_pObserver )
249             m_pObserver->focusGained( e );
250     }
251 
252     //--------------------------------------------------------------------
253     void SAL_CALL FmFocusListenerAdapter::focusLost( const FocusEvent& e ) throw (RuntimeException)
254     {
255         if ( m_pObserver )
256             m_pObserver->focusLost( e );
257     }
258 
259     //--------------------------------------------------------------------
260     void SAL_CALL FmFocusListenerAdapter::disposing( const EventObject& Source ) throw (RuntimeException)
261     {
262         (void)Source;
263         DBG_ASSERT( Source.Source == m_xWindow, "FmFocusListenerAdapter::disposing: where did this come from?" );
264         m_xWindow.clear();
265     }
266 
267 	//====================================================================
268 	//= FmMouseListenerAdapter
269 	//====================================================================
270     typedef ::cppu::WeakImplHelper1 <   XMouseListener
271                                     >   FmMouseListenerAdapter_Base;
272     class FmMouseListenerAdapter : public FmMouseListenerAdapter_Base
273     {
274     private:
275         IContextRequestObserver*  m_pObserver;
276         Reference< XWindow >    m_xWindow;
277 
278     public:
279         FmMouseListenerAdapter( const Reference< XControl >& _rxControl, IContextRequestObserver* _pObserver );
280 
281         // clean up the instance
282         void    dispose();
283 
284     protected:
285         ~FmMouseListenerAdapter();
286 
287     protected:
288         virtual void SAL_CALL mousePressed( const awt::MouseEvent& e ) throw (RuntimeException);
289         virtual void SAL_CALL mouseReleased( const awt::MouseEvent& e ) throw (RuntimeException);
290         virtual void SAL_CALL mouseEntered( const awt::MouseEvent& e ) throw (RuntimeException);
291         virtual void SAL_CALL mouseExited( const awt::MouseEvent& e ) throw (RuntimeException);
292         virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException);
293     };
294 
295 	//====================================================================
296 	//= FmMouseListenerAdapter
297 	//====================================================================
298     //--------------------------------------------------------------------
299     DBG_NAME( FmMouseListenerAdapter )
300     //--------------------------------------------------------------------
301     FmMouseListenerAdapter::FmMouseListenerAdapter( const Reference< XControl >& _rxControl, IContextRequestObserver* _pObserver )
302         :m_pObserver( _pObserver )
303         ,m_xWindow( _rxControl, UNO_QUERY )
304     {
305         DBG_CTOR( FmMouseListenerAdapter, NULL );
306 
307         DBG_ASSERT( m_xWindow.is(), "FmMouseListenerAdapter::FmMouseListenerAdapter: invalid control!" );
308         osl_incrementInterlockedCount( &m_refCount );
309         {
310             try
311             {
312                 if ( m_xWindow.is() )
313                     m_xWindow->addMouseListener( this );
314             }
315             catch( const Exception& )
316             {
317                 DBG_UNHANDLED_EXCEPTION();
318             }
319         }
320         osl_decrementInterlockedCount( &m_refCount );
321     }
322 
323     //--------------------------------------------------------------------
324     FmMouseListenerAdapter::~FmMouseListenerAdapter()
325     {
326         acquire();
327         dispose();
328 
329         DBG_DTOR( FmMouseListenerAdapter, NULL );
330     }
331 
332     //--------------------------------------------------------------------
333     void FmMouseListenerAdapter::dispose()
334     {
335         if ( m_xWindow.is() )
336         {
337             m_xWindow->removeMouseListener( this );
338             m_xWindow.clear();
339         }
340     }
341 
342     //--------------------------------------------------------------------
343     void SAL_CALL FmMouseListenerAdapter::mousePressed( const awt::MouseEvent& _rEvent ) throw (::com::sun::star::uno::RuntimeException)
344     {
345         ::vos::OGuard aGuard( Application::GetSolarMutex() );
346 	    // is this a request for a context menu?
347 	    if ( _rEvent.PopupTrigger )
348         {
349             if ( m_pObserver )
350                 m_pObserver->contextMenuRequested( _rEvent );
351         }
352     }
353 
354     //--------------------------------------------------------------------
355     void SAL_CALL FmMouseListenerAdapter::mouseReleased( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException)
356     {
357         // not interested in
358     }
359 
360     //--------------------------------------------------------------------
361     void SAL_CALL FmMouseListenerAdapter::mouseEntered( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException)
362     {
363         // not interested in
364     }
365 
366     //--------------------------------------------------------------------
367     void SAL_CALL FmMouseListenerAdapter::mouseExited( const awt::MouseEvent& /*e*/ ) throw (::com::sun::star::uno::RuntimeException)
368     {
369         // not interested in
370     }
371 
372     //--------------------------------------------------------------------
373     void SAL_CALL FmMouseListenerAdapter::disposing( const EventObject& Source ) throw (RuntimeException)
374     {
375         (void)Source;
376         DBG_ASSERT( Source.Source == m_xWindow, "FmMouseListenerAdapter::disposing: where did this come from?" );
377         m_xWindow.clear();
378     }
379 
380     //====================================================================
381     //= FmTextControlShell
382 	//====================================================================
383     //------------------------------------------------------------------------
384     namespace
385     {
386         //....................................................................
387         void lcl_translateUnoStateToItem( SfxSlotId _nSlot, const Any& _rUnoState, SfxItemSet& _rSet )
388         {
389             WhichId nWhich = _rSet.GetPool()->GetWhich( _nSlot );
390             if ( !_rUnoState.hasValue() )
391             {
392                 if  ( ( _nSlot != SID_CUT )
393                    && ( _nSlot != SID_COPY )
394                    && ( _nSlot != SID_PASTE )
395                     )
396                 {
397                     _rSet.InvalidateItem( nWhich );
398                 }
399             }
400             else
401             {
402                 switch ( _rUnoState.getValueType().getTypeClass() )
403                 {
404                 case TypeClass_BOOLEAN:
405                 {
406                     sal_Bool bState = sal_False;
407                     _rUnoState >>= bState;
408                     if ( _nSlot == SID_ATTR_PARA_SCRIPTSPACE )
409                         _rSet.Put( SvxScriptSpaceItem( bState, nWhich ) );
410                     else
411     				    _rSet.Put( SfxBoolItem( nWhich, bState ) );
412                 }
413                 break;
414 
415                 default:
416                 {
417                     Sequence< PropertyValue > aComplexState;
418                     if ( _rUnoState >>= aComplexState )
419                     {
420                         if ( !aComplexState.getLength() )
421                             _rSet.InvalidateItem( nWhich );
422                         else
423                         {
424                             SfxAllItemSet aAllItems( _rSet );
425                             TransformParameters( _nSlot, aComplexState, aAllItems );
426                             const SfxPoolItem* pTransformed = aAllItems.GetItem( nWhich );
427                             OSL_ENSURE( pTransformed, "lcl_translateUnoStateToItem: non-empty parameter sequence leading to empty item?" );
428                             if ( pTransformed )
429                                 _rSet.Put( *pTransformed );
430                             else
431                                 _rSet.InvalidateItem( nWhich );
432                         }
433                     }
434                     else
435                     {
436                         DBG_ERROR( "lcl_translateUnoStateToItem: invalid state!" );
437                     }
438                 }
439                 }
440             }
441         }
442 
443         //....................................................................
444         ::rtl::OUString lcl_getUnoSlotName( SfxApplication&, SfxSlotId _nSlotId )
445         {
446             ::rtl::OUString sSlotUnoName;
447 
448             SfxSlotPool& rSlotPool = SfxSlotPool::GetSlotPool( NULL );
449             const SfxSlot* pSlot = rSlotPool.GetSlot( _nSlotId );
450 
451             const sal_Char* pAsciiUnoName = NULL;
452             if ( pSlot )
453             {
454                 pAsciiUnoName = pSlot->GetUnoName();
455             }
456             else
457             {
458                 // some hard-coded slots, which do not have a UNO name at SFX level, but which
459                 // we nevertheless need to transport via UNO mechanisms, so we need a name
460                 switch ( _nSlotId )
461                 {
462                 case SID_ATTR_PARA_HANGPUNCTUATION: pAsciiUnoName = "AllowHangingPunctuation"; break;
463                 case SID_ATTR_PARA_FORBIDDEN_RULES: pAsciiUnoName = "ApplyForbiddenCharacterRules"; break;
464                 case SID_ATTR_PARA_SCRIPTSPACE: pAsciiUnoName = "UseScriptSpacing"; break;
465                 }
466             }
467 
468             if ( pAsciiUnoName )
469             {
470                 sSlotUnoName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:" ) );
471                 sSlotUnoName += ::rtl::OUString::createFromAscii( pAsciiUnoName );
472             }
473 #if OSL_DEBUG_LEVEL > 0
474             else
475             {
476                 ::rtl::OString sMessage( "lcl_getUnoSlotName: invalid slot id, or invalid slot, or no UNO name!\n" );
477                 sMessage += "(slot id: ";
478                 sMessage += ::rtl::OString::valueOf( (sal_Int32)_nSlotId );
479                 sMessage += ")";
480                 DBG_ERROR( sMessage );
481             }
482 #endif
483             return sSlotUnoName;
484         }
485 
486         //....................................................................
487         bool lcl_determineReadOnly( const Reference< XControl >& _rxControl )
488         {
489             bool bIsReadOnlyModel = true;
490             try
491             {
492                 Reference< XPropertySet > xModelProps;
493                 if ( _rxControl.is() )
494                     xModelProps = xModelProps.query( _rxControl->getModel() );
495                 Reference< XPropertySetInfo > xModelPropInfo;
496                 if ( xModelProps.is() )
497                     xModelPropInfo = xModelProps->getPropertySetInfo();
498 
499                 if ( !xModelPropInfo.is() || !xModelPropInfo->hasPropertyByName( FM_PROP_READONLY ) )
500                     bIsReadOnlyModel = true;
501                 else
502                 {
503                     sal_Bool bReadOnly = sal_True;
504                     xModelProps->getPropertyValue( FM_PROP_READONLY ) >>= bReadOnly;
505                     bIsReadOnlyModel = bReadOnly;
506                 }
507             }
508             catch( const Exception& )
509             {
510                 DBG_UNHANDLED_EXCEPTION();
511             }
512             return bIsReadOnlyModel;
513         }
514 
515         //....................................................................
516         static Window* lcl_getWindow( const Reference< XControl >& _rxControl )
517         {
518             Window* pWindow = NULL;
519             try
520             {
521                 Reference< XWindowPeer > xControlPeer;
522                 if ( _rxControl.is() )
523                     xControlPeer = _rxControl->getPeer();
524                 if ( xControlPeer.is() )
525                     pWindow = VCLUnoHelper::GetWindow( xControlPeer );
526             }
527             catch( const Exception& )
528             {
529                 DBG_UNHANDLED_EXCEPTION();
530             }
531 
532             return pWindow;
533         }
534 
535         //....................................................................
536         bool lcl_isRichText( const Reference< XControl >& _rxControl )
537         {
538             if ( !_rxControl.is() )
539                 return false;
540 
541             bool bIsRichText = false;
542             try
543             {
544                 Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
545                 Reference< XPropertySetInfo > xPSI;
546                 if ( xModelProps.is() )
547                     xPSI = xModelProps->getPropertySetInfo();
548                 ::rtl::OUString sRichTextPropertyName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RichText" ) );
549                 if ( xPSI.is() && xPSI->hasPropertyByName( sRichTextPropertyName ) )
550                 {
551                     OSL_VERIFY( xModelProps->getPropertyValue( sRichTextPropertyName ) >>= bIsRichText );
552                 }
553             }
554             catch( const Exception& )
555             {
556                 DBG_UNHANDLED_EXCEPTION();
557             }
558             return bIsRichText;
559         }
560     }
561 
562     //------------------------------------------------------------------------
563     FmTextControlShell::FmTextControlShell( SfxViewFrame* _pFrame )
564         :m_bActiveControl( false )
565         ,m_bActiveControlIsReadOnly( true )
566         ,m_bActiveControlIsRichText( false )
567         ,m_pViewFrame( _pFrame )
568         ,m_rBindings( _pFrame->GetBindings() )
569         ,m_bNeedClipboardInvalidation( true )
570     {
571         m_aClipboardInvalidation.SetTimeoutHdl( LINK( this, FmTextControlShell, OnInvalidateClipboard ) );
572         m_aClipboardInvalidation.SetTimeout( 200 );
573     }
574 
575     //------------------------------------------------------------------------
576     FmTextControlShell::~FmTextControlShell()
577     {
578         dispose();
579     }
580 
581     //------------------------------------------------------------------------
582     IMPL_LINK( FmTextControlShell, OnInvalidateClipboard, void*, /*_pNotInterestedIn*/ )
583     {
584         if ( m_bNeedClipboardInvalidation )
585         {
586             DBG_TRACE( "FmTextControlShell::ClipBoard: invalidating clipboard slots" );
587             m_rBindings.Invalidate( SID_CUT );
588             m_rBindings.Invalidate( SID_COPY );
589             m_rBindings.Invalidate( SID_PASTE );
590             m_bNeedClipboardInvalidation = false;
591         }
592         return 0L;
593     }
594 
595     //------------------------------------------------------------------------
596     void FmTextControlShell::transferFeatureStatesToItemSet( ControlFeatures& _rDispatchers, SfxAllItemSet& _rSet, bool _bTranslateLatin )
597     {
598         SfxItemPool& rPool = *_rSet.GetPool();
599 
600         for (   ControlFeatures::const_iterator aFeature = _rDispatchers.begin();
601                 aFeature != _rDispatchers.end();
602                 ++aFeature
603             )
604         {
605             SfxSlotId nSlotId( aFeature->first );
606             #if OSL_DEBUG_LEVEL > 0
607                 ::rtl::OUString sUnoSlotName;
608                 if ( SFX_APP() )
609                     sUnoSlotName = lcl_getUnoSlotName( *SFX_APP(), nSlotId );
610                 else
611                     sUnoSlotName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "<unknown>" ) );
612                 ::rtl::OString sUnoSlotNameAscii( "\"" );
613                 sUnoSlotNameAscii += ::rtl::OString( sUnoSlotName.getStr(), sUnoSlotName.getLength(), RTL_TEXTENCODING_ASCII_US );
614                 sUnoSlotNameAscii += "\"";
615             #endif
616 
617             if ( _bTranslateLatin )
618             {
619                 // A rich text control offers a dispatcher for the "Font" slot/feature.
620                 // Sadly, the semantics of the dispatches is that the feature "Font" depends
621                 // on the current cursor position: If it's on latin text, it's the "latin font"
622                 // which is set up at the control. If it's on CJK text, it's the "CJK font", and
623                 // aequivalent for "CTL font".
624                 // The same holds for some other font related features/slots.
625                 // Thus, we have separate dispatches for "Latin Font", "Latin Font Size", etc,
626                 // which are only "virtual", in a sense that there exist no item with this id.
627                 // So when we encounter such a dispatcher for, say, "Latin Font", we need to
628                 // put an item into the set which has the "Font" id.
629 
630                 switch ( nSlotId )
631                 {
632                 case SID_ATTR_CHAR_LATIN_FONT:      nSlotId = SID_ATTR_CHAR_FONT; break;
633                 case SID_ATTR_CHAR_LATIN_FONTHEIGHT:nSlotId = SID_ATTR_CHAR_FONTHEIGHT; break;
634                 case SID_ATTR_CHAR_LATIN_LANGUAGE:  nSlotId = SID_ATTR_CHAR_LANGUAGE; break;
635                 case SID_ATTR_CHAR_LATIN_POSTURE:   nSlotId = SID_ATTR_CHAR_POSTURE; break;
636                 case SID_ATTR_CHAR_LATIN_WEIGHT:    nSlotId = SID_ATTR_CHAR_WEIGHT; break;
637                 }
638             }
639 
640             WhichId nWhich = rPool.GetWhich( nSlotId );
641             bool bIsInPool = rPool.IsInRange( nWhich );
642             if ( bIsInPool )
643             {
644                 #if OSL_DEBUG_LEVEL > 0
645                     bool bFeatureIsEnabled = aFeature->second->isFeatureEnabled();
646                     ::rtl::OString sMessage( "FmTextControlShell::transferFeatureStatesToItemSet: found a feature state for " );
647                     sMessage += sUnoSlotNameAscii;
648                     if ( !bFeatureIsEnabled )
649                         sMessage += " (disabled)";
650                     DBG_TRACE( sMessage );
651                 #endif
652 
653                 lcl_translateUnoStateToItem( nSlotId, aFeature->second->getFeatureState(), _rSet );
654             }
655             #if OSL_DEBUG_LEVEL > 0
656             else
657             {
658                 ::rtl::OString sMessage( "FmTextControlShell::transferFeatureStatesToItemSet: found a feature state for " );
659                 sMessage += sUnoSlotNameAscii;
660                 sMessage += ", but could not translate it into an item!";
661                 DBG_TRACE( sMessage );
662             }
663             #endif
664         }
665     }
666 
667     //------------------------------------------------------------------------
668     void FmTextControlShell::executeAttributeDialog( AttributeSet _eSet, SfxRequest& _rReq )
669     {
670         const SvxFontListItem* pFontList = PTR_CAST( SvxFontListItem, m_pViewFrame->GetObjectShell()->GetItem( SID_ATTR_CHAR_FONTLIST ) );
671         DBG_ASSERT( pFontList, "FmTextControlShell::executeAttributeDialog: no font list item!" );
672         if ( !pFontList )
673             return;
674 
675         SfxItemPool* pPool = EditEngine::CreatePool();
676         pPool->FreezeIdRanges();
677         ::std::auto_ptr< SfxItemSet > pPureItems( new SfxItemSet( *pPool ) );
678 
679         // put the current states of the items into the set
680         ::std::auto_ptr< SfxAllItemSet > pCurrentItems( new SfxAllItemSet( *pPureItems ) );
681         transferFeatureStatesToItemSet( m_aControlFeatures, *pCurrentItems );
682 
683         // additional items, which we are not responsible for at the SfxShell level,
684         // but which need to be forwarded to the dialog, anyway
685         ControlFeatures aAdditionalFestures;
686         fillFeatureDispatchers( m_xActiveControl, pDialogSlots, aAdditionalFestures );
687         transferFeatureStatesToItemSet( aAdditionalFestures, *pCurrentItems, true );
688 
689         ::std::auto_ptr< SfxTabDialog > pDialog ( _eSet == eCharAttribs
690                                                 ? static_cast< SfxTabDialog* >( new TextControlCharAttribDialog( NULL, *pCurrentItems, *pFontList ) )
691                                                 : static_cast< SfxTabDialog* >( new TextControlParaAttribDialog( NULL, *pCurrentItems ) ) );
692         if ( RET_OK == pDialog->Execute() )
693         {
694             const SfxItemSet& rModifiedItems = *pDialog->GetOutputItemSet();
695             for ( WhichId nWhich = pPool->GetFirstWhich(); nWhich <= pPool->GetLastWhich(); ++nWhich )
696             {
697                 if ( rModifiedItems.GetItemState( nWhich ) == SFX_ITEM_SET )
698                 {
699                     SfxSlotId nSlotForItemSet = pPool->GetSlotId( nWhich );
700                     const SfxPoolItem* pModifiedItem = rModifiedItems.GetItem( nWhich );
701 
702 
703                     SfxSlotId nSlotForDispatcher = nSlotForItemSet;
704                     switch ( nSlotForDispatcher )
705                     {
706                         case SID_ATTR_CHAR_FONT:      nSlotForDispatcher = SID_ATTR_CHAR_LATIN_FONT; break;
707                         case SID_ATTR_CHAR_FONTHEIGHT:nSlotForDispatcher = SID_ATTR_CHAR_LATIN_FONTHEIGHT; break;
708                         case SID_ATTR_CHAR_LANGUAGE:  nSlotForDispatcher = SID_ATTR_CHAR_LATIN_LANGUAGE; break;
709                         case SID_ATTR_CHAR_POSTURE:   nSlotForDispatcher = SID_ATTR_CHAR_LATIN_POSTURE; break;
710                         case SID_ATTR_CHAR_WEIGHT:    nSlotForDispatcher = SID_ATTR_CHAR_LATIN_WEIGHT; break;
711                     }
712 
713                     // do we already have a dispatcher for this slot/feature?
714                     ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlotForDispatcher );
715                     bool bFound = aFeaturePos != m_aControlFeatures.end( );
716 
717                     if ( !bFound )
718                     {
719                         aFeaturePos = aAdditionalFestures.find( nSlotForDispatcher );
720                         bFound = aFeaturePos != aAdditionalFestures.end( );
721                     }
722 
723                     if ( bFound )
724                     {
725                         Sequence< PropertyValue > aArgs;
726                         // temporarily put the modified item into a "clean" set,
727                         // and let TransformItems calc the respective UNO parameters
728                         pPureItems->Put( *pModifiedItem );
729                         TransformItems( nSlotForItemSet, *pPureItems, aArgs );
730                         pPureItems->ClearItem( nWhich );
731 
732                         if  (   ( nSlotForItemSet == SID_ATTR_PARA_HANGPUNCTUATION )
733                             ||  ( nSlotForItemSet == SID_ATTR_PARA_FORBIDDEN_RULES )
734                             ||  ( nSlotForItemSet == SID_ATTR_PARA_SCRIPTSPACE )
735                             )
736                         {
737                             // these are no UNO slots, they need special handling since TransformItems cannot
738                             // handle them
739                             DBG_ASSERT( aArgs.getLength() == 0, "FmTextControlShell::executeAttributeDialog: these are no UNO slots - are they?" );
740 
741                             const SfxBoolItem* pBoolItem = PTR_CAST( SfxBoolItem, pModifiedItem );
742                             DBG_ASSERT( pBoolItem, "FmTextControlShell::executeAttributeDialog: no bool item?!" );
743                             if ( pBoolItem )
744                             {
745                                 aArgs.realloc( 1 );
746                                 aArgs[ 0 ].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enable" ) );
747                                 aArgs[ 0 ].Value <<= (sal_Bool)pBoolItem->GetValue();
748                             }
749                         }
750 
751                         // dispatch this
752                         aFeaturePos->second->dispatch( aArgs );
753                     }
754                 #if OSL_DEBUG_LEVEL > 0
755                     else
756                     {
757                         ::rtl::OString sError( "FmTextControShell::executeAttributeDialog: Could not handle the following item:" );
758                         sError += "\n  SlotID: "; sError += ::rtl::OString::valueOf( (sal_Int32)nSlotForItemSet );
759                         sError += "\n  WhichID: "; sError += ::rtl::OString::valueOf( (sal_Int32)nWhich );
760                         sError += "\n  UNO name: ";
761 
762                         ::rtl::OUString sUnoSlotName = lcl_getUnoSlotName( *SFX_APP(), nSlotForItemSet );
763                         if ( sUnoSlotName.getLength() )
764                             sError += ::rtl::OString( sUnoSlotName.getStr(), sUnoSlotName.getLength(), RTL_TEXTENCODING_ASCII_US );
765                         else
766                             sError += "unknown (no SfxSlot)";
767                         DBG_ERROR( sError.getStr() );
768                     }
769                 #endif
770                 }
771             }
772             _rReq.Done( rModifiedItems );
773         }
774 
775         pDialog.reset();
776         pCurrentItems.reset();
777         pPureItems.reset();
778         SfxItemPool::Free(pPool);
779     }
780 
781     //------------------------------------------------------------------------
782     bool FmTextControlShell::executeSelectAll( )
783     {
784         try
785         {
786             if ( m_xActiveTextComponent.is() )
787             {
788                 sal_Int32 nTextLen = m_xActiveTextComponent->getText().getLength();
789                 m_xActiveTextComponent->setSelection( awt::Selection( 0, nTextLen ) );
790                 return true;
791             }
792         }
793         catch( const Exception& )
794         {
795             DBG_UNHANDLED_EXCEPTION();
796         }
797         return false;   // not handled
798     }
799 
800     //------------------------------------------------------------------------
801     bool FmTextControlShell::executeClipboardSlot( SfxSlotId _nSlot )
802     {
803         try
804         {
805             if ( m_xActiveTextComponent.is() )
806             {
807                 switch ( _nSlot )
808                 {
809                 case SID_COPY:
810                 case SID_CUT:
811                 {
812                     ::rtl::OUString sSelectedText( m_xActiveTextComponent->getSelectedText() );
813                     ::svt::OStringTransfer::CopyString( sSelectedText, lcl_getWindow( m_xActiveControl ) );
814                     if ( SID_CUT == _nSlot )
815                     {
816                         awt::Selection aSelection( m_xActiveTextComponent->getSelection() );
817                         m_xActiveTextComponent->insertText( aSelection, ::rtl::OUString() );
818                     }
819                 }
820                 break;
821                 case SID_PASTE:
822                 {
823                     ::rtl::OUString sClipboardContent;
824                     OSL_VERIFY( ::svt::OStringTransfer::PasteString( sClipboardContent, lcl_getWindow( m_xActiveControl ) ) );
825                     awt::Selection aSelection( m_xActiveTextComponent->getSelection() );
826                     m_xActiveTextComponent->insertText( aSelection, sClipboardContent );
827                 }
828                 break;
829                 default:
830                     OSL_ENSURE( sal_False, "FmTextControlShell::executeClipboardSlot: invalid slot!" );
831                 }
832                 return true;
833             }
834         }
835         catch( const Exception& )
836         {
837             DBG_UNHANDLED_EXCEPTION();
838         }
839         return false;   // not handled
840     }
841 
842     //------------------------------------------------------------------------
843     void FmTextControlShell::ExecuteTextAttribute( SfxRequest& _rReq )
844     {
845 	    SfxSlotId nSlot = _rReq.GetSlot();
846 
847         ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlot );
848         if ( aFeaturePos == m_aControlFeatures.end() )
849         {
850             // special slots
851             switch ( nSlot )
852             {
853             case SID_CHAR_DLG:
854                 executeAttributeDialog( eCharAttribs, _rReq );
855                 break;
856 
857             case SID_PARA_DLG:
858                 executeAttributeDialog( eParaAttribs, _rReq );
859                 break;
860 
861             case SID_SELECTALL:
862                 executeSelectAll();
863                 break;
864 
865             case SID_CUT:
866             case SID_COPY:
867             case SID_PASTE:
868                 executeClipboardSlot( nSlot );
869                 break;
870 
871             default:
872                 DBG_ASSERT( aFeaturePos != m_aControlFeatures.end(), "FmTextControShell::ExecuteTextAttribute: I have no such dispatcher, and cannot handle it at all!" );
873                 return;
874             }
875         }
876         else
877         {
878             // slots which are dispatched to the control
879 
880             switch ( nSlot )
881             {
882             case SID_ATTR_CHAR_STRIKEOUT:
883             case SID_ATTR_CHAR_UNDERLINE:
884             case SID_ATTR_CHAR_OVERLINE:
885             {
886                 SfxItemSet aToggled( *_rReq.GetArgs() );
887 
888                 lcl_translateUnoStateToItem( nSlot, aFeaturePos->second->getFeatureState(), aToggled );
889                 WhichId nWhich = aToggled.GetPool()->GetWhich( nSlot );
890                 const SfxPoolItem* pItem = aToggled.GetItem( nWhich );
891                 if ( ( SID_ATTR_CHAR_UNDERLINE == nSlot ) || ( SID_ATTR_CHAR_OVERLINE == nSlot ) )
892                 {
893                     const SvxOverlineItem* pTextLine = PTR_CAST( SvxOverlineItem, pItem );
894                     DBG_ASSERT( pTextLine, "FmTextControlShell::ExecuteTextAttribute: ooops - no underline/overline item!" );
895                     if ( pTextLine )
896                     {
897             		    FontUnderline eTL = pTextLine->GetLineStyle();
898 						if ( SID_ATTR_CHAR_UNDERLINE == nSlot ) {
899 	            		    aToggled.Put( SvxUnderlineItem( eTL == UNDERLINE_SINGLE ? UNDERLINE_NONE : UNDERLINE_SINGLE, nWhich ) );
900 						} else {
901 	            		    aToggled.Put( SvxOverlineItem( eTL == UNDERLINE_SINGLE ? UNDERLINE_NONE : UNDERLINE_SINGLE, nWhich ) );
902 						}
903                     }
904                 }
905                 else
906                 {
907                     const SvxCrossedOutItem* pCrossedOut = PTR_CAST( SvxCrossedOutItem, pItem );
908                     DBG_ASSERT( pCrossedOut, "FmTextControlShell::ExecuteTextAttribute: ooops - no CrossedOut item!" );
909                     if ( pCrossedOut )
910                     {
911             		    FontStrikeout eFS = pCrossedOut->GetStrikeout();
912             		    aToggled.Put( SvxCrossedOutItem( eFS == STRIKEOUT_SINGLE ? STRIKEOUT_NONE : STRIKEOUT_SINGLE, nWhich ) );
913                     }
914                 }
915 
916                 Sequence< PropertyValue > aArguments;
917                 TransformItems( nSlot, aToggled, aArguments );
918                 aFeaturePos->second->dispatch( aArguments );
919             }
920             break;
921 
922             case SID_ATTR_CHAR_FONTHEIGHT:
923             case SID_ATTR_CHAR_FONT:
924             case SID_ATTR_CHAR_POSTURE:
925             case SID_ATTR_CHAR_WEIGHT:
926             case SID_ATTR_CHAR_SHADOWED:
927             case SID_ATTR_CHAR_CONTOUR:
928             case SID_SET_SUPER_SCRIPT:
929             case SID_SET_SUB_SCRIPT:
930             {
931                 const SfxItemSet* pArgs = _rReq.GetArgs();
932                 Sequence< PropertyValue > aArgs;
933                 if ( pArgs )
934                     TransformItems( nSlot, *pArgs, aArgs );
935                 aFeaturePos->second->dispatch( aArgs );
936             }
937             break;
938 
939             default:
940                 if ( aFeaturePos->second->isFeatureEnabled() )
941                     aFeaturePos->second->dispatch();
942                 break;
943             }
944         }
945         _rReq.Done();
946     }
947 
948     //------------------------------------------------------------------------
949     void FmTextControlShell::GetTextAttributeState( SfxItemSet& _rSet )
950     {
951 	    SfxWhichIter aIter( _rSet );
952 	    sal_uInt16 nSlot = aIter.FirstWhich();
953 	    while ( nSlot )
954 	    {
955             if  (   ( nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT )
956                 ||  ( nSlot == SID_ATTR_PARA_RIGHT_TO_LEFT )
957                 )
958             {
959                 if ( !SvtLanguageOptions().IsCTLFontEnabled() )
960                 {
961                     _rSet.DisableItem( nSlot );
962                     nSlot = aIter.NextWhich();
963                     continue;
964                 }
965             }
966 
967             ControlFeatures::const_iterator aFeaturePos = m_aControlFeatures.find( nSlot );
968             if ( aFeaturePos != m_aControlFeatures.end() )
969             {
970                 if ( aFeaturePos->second->isFeatureEnabled() )
971                     lcl_translateUnoStateToItem( nSlot, aFeaturePos->second->getFeatureState(), _rSet );
972                 else
973                     _rSet.DisableItem( nSlot );
974             }
975             else
976             {
977                 bool bDisable = false;
978 
979                 bool bNeedWriteableControl = false;
980                 bool bNeedTextComponent = false;
981                 bool bNeedSelection = false;
982 
983                 switch ( nSlot )
984                 {
985                 case SID_CHAR_DLG:
986                 case SID_PARA_DLG:
987                     bDisable |= m_aControlFeatures.empty();
988                     bNeedWriteableControl = true;
989                     break;
990 
991                 case SID_CUT:
992                     bNeedSelection = true;
993                     bNeedTextComponent = true;
994                     bNeedWriteableControl = true;
995                     DBG_TRACE( "FmTextControlShell::ClipBoard: need to invalidate again" );
996                     m_bNeedClipboardInvalidation = true;
997                     break;
998 
999                 case SID_PASTE:
1000                 {
1001                     Window* pActiveControlVCLWindow = lcl_getWindow( m_xActiveControl );
1002                     if ( pActiveControlVCLWindow )
1003                     {
1004 		                TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pActiveControlVCLWindow) );
1005                         bDisable |= !aDataHelper.HasFormat( SOT_FORMAT_STRING );
1006                     }
1007                     else
1008                         bDisable |= true;
1009 
1010                     bNeedTextComponent = true;
1011                     bNeedWriteableControl = true;
1012                 }
1013                 break;
1014 
1015                 case SID_COPY:
1016                     bNeedTextComponent = true;
1017                     bNeedSelection = true;
1018                     break;
1019 
1020                 case SID_SELECTALL:
1021                     bNeedTextComponent = true;
1022                     break;
1023 
1024                 default:
1025                     // slot is unknown at all
1026                     bDisable |= true;
1027                     break;
1028                 }
1029                 OSL_POSTCOND( !bNeedSelection || bNeedTextComponent, "FmTextControlShell::GetTextAttributeState: bNeedSelection should imply bNeedTextComponent!" );
1030 
1031                 if ( !bDisable && bNeedWriteableControl )
1032                     bDisable |= !IsActiveControl( ) || m_bActiveControlIsReadOnly;
1033 
1034                 if ( !bDisable && bNeedTextComponent )
1035                     bDisable |= !m_xActiveTextComponent.is();
1036 
1037                 if ( !bDisable && bNeedSelection )
1038                 {
1039                     awt::Selection aSelection = m_xActiveTextComponent->getSelection();
1040                     bDisable |= aSelection.Min == aSelection.Max;
1041                 }
1042 
1043                 if ( bDisable )
1044                     _rSet.DisableItem( nSlot );
1045             }
1046 
1047             nSlot = aIter.NextWhich();
1048 	    }
1049     }
1050 
1051     //------------------------------------------------------------------------
1052     bool FmTextControlShell::IsActiveControl( bool _bCountRichTextOnly ) const
1053     {
1054         if ( _bCountRichTextOnly && !m_bActiveControlIsRichText )
1055             return false;
1056 
1057         return m_bActiveControl;
1058     }
1059 
1060     //------------------------------------------------------------------------
1061     void FmTextControlShell::dispose()
1062     {
1063         if ( IsActiveControl() )
1064             controlDeactivated();
1065         if ( isControllerListening() )
1066             stopControllerListening();
1067     }
1068 
1069     //------------------------------------------------------------------------
1070     void FmTextControlShell::designModeChanged( bool /*_bNewDesignMode*/ )
1071     {
1072         m_rBindings.Invalidate( pTextControlSlots );
1073     }
1074 
1075     //------------------------------------------------------------------------
1076     void FmTextControlShell::formActivated( const Reference< XFormController >& _rxController )
1077     {
1078 #if OSL_DEBUG_LEVEL > 0
1079         ::rtl::OString sTrace( "FmTextControlShell::formActivated: 0x" );
1080         sTrace += ::rtl::OString::valueOf( (sal_IntPtr)_rxController.get(), 16 );
1081         DBG_TRACE( sTrace );
1082 #endif
1083 
1084         DBG_ASSERT( _rxController.is(), "FmTextControlShell::formActivated: invalid controller!" );
1085         if ( !_rxController.is() )
1086             return;
1087 
1088         // sometimes, a form controller notifies activations, even if it's already activated
1089         if ( m_xActiveController == _rxController )
1090             return;
1091 
1092         try
1093         {
1094             startControllerListening( _rxController );
1095             controlActivated( _rxController->getCurrentControl() );
1096         }
1097         catch( const Exception& )
1098         {
1099             DBG_UNHANDLED_EXCEPTION();
1100         }
1101     }
1102 
1103     //------------------------------------------------------------------------
1104     void FmTextControlShell::formDeactivated( const Reference< XFormController >& _rxController )
1105     {
1106 #if OSL_DEBUG_LEVEL > 0
1107         ::rtl::OString sTrace( "FmTextControlShell::formDeactivated: 0x" );
1108         sTrace += ::rtl::OString::valueOf( (sal_IntPtr)_rxController.get(), 16 );
1109         DBG_TRACE( sTrace );
1110 #endif
1111         (void)_rxController;
1112 
1113         if ( IsActiveControl() )
1114             controlDeactivated();
1115         if ( isControllerListening() )
1116             stopControllerListening();
1117     }
1118 
1119     //------------------------------------------------------------------------
1120     void FmTextControlShell::startControllerListening( const Reference< XFormController >& _rxController )
1121     {
1122         OSL_PRECOND( _rxController.is(), "FmTextControlShell::startControllerListening: invalid controller!" );
1123         if ( !_rxController.is() )
1124             return;
1125 
1126         OSL_PRECOND( !isControllerListening(), "FmTextControlShell::startControllerListening: already listening!" );
1127         if ( isControllerListening() )
1128             stopControllerListening( );
1129         DBG_ASSERT( !isControllerListening(), "FmTextControlShell::startControllerListening: inconsistence!" );
1130 
1131         try
1132         {
1133             Sequence< Reference< XControl > > aControls( _rxController->getControls() );
1134             m_aControlObservers.resize( 0 );
1135             m_aControlObservers.reserve( aControls.getLength() );
1136 
1137             const Reference< XControl >* pControls = aControls.getConstArray();
1138             const Reference< XControl >* pControlsEnd = pControls + aControls.getLength();
1139             for ( ; pControls != pControlsEnd; ++pControls )
1140             {
1141                 m_aControlObservers.push_back( FocusListenerAdapter( new FmFocusListenerAdapter( *pControls, this ) ) );
1142             }
1143         }
1144         catch( const Exception& )
1145         {
1146             DBG_UNHANDLED_EXCEPTION();
1147         }
1148 
1149         m_xActiveController = _rxController;
1150     }
1151 
1152     //------------------------------------------------------------------------
1153     void FmTextControlShell::stopControllerListening( )
1154     {
1155         OSL_PRECOND( isControllerListening(), "FmTextControlShell::stopControllerListening: inconsistence!" );
1156 
1157         // dispose all listeners associated with the controls of the active controller
1158         for (   FocusListenerAdapters::iterator aLoop = m_aControlObservers.begin();
1159                 aLoop != m_aControlObservers.end();
1160                 ++aLoop
1161             )
1162         {
1163             (*aLoop)->dispose();
1164         }
1165 
1166         FocusListenerAdapters aEmpty;
1167         m_aControlObservers.swap( aEmpty );
1168 
1169         m_xActiveController.clear();
1170     }
1171 
1172     //------------------------------------------------------------------------
1173     void FmTextControlShell::implClearActiveControlRef()
1174     {
1175         // no more features for this control
1176         for (   ControlFeatures::iterator aLoop = m_aControlFeatures.begin();
1177                 aLoop != m_aControlFeatures.end();
1178                 ++aLoop
1179             )
1180         {
1181             aLoop->second->dispose();
1182         }
1183 
1184         ControlFeatures aEmpty;
1185         m_aControlFeatures.swap( aEmpty );
1186 
1187         if ( m_aContextMenuObserver.get() )
1188         {
1189             m_aContextMenuObserver->dispose();
1190             m_aContextMenuObserver = MouseListenerAdapter();
1191         }
1192 
1193         if ( m_xActiveTextComponent.is() )
1194         {
1195             DBG_TRACE( "FmTextControlShell::ClipBoard: stopping timer for clipboard invalidation" );
1196             m_aClipboardInvalidation.Stop();
1197         }
1198         // no more active control
1199         m_xActiveControl.clear();
1200         m_xActiveTextComponent.clear();
1201         m_bActiveControlIsReadOnly = true;
1202         m_bActiveControlIsRichText = false;
1203         m_bActiveControl = false;
1204     }
1205 
1206     //------------------------------------------------------------------------
1207     void FmTextControlShell::controlDeactivated( )
1208     {
1209         DBG_ASSERT( IsActiveControl(), "FmTextControlShell::controlDeactivated: no active control!" );
1210 
1211         m_bActiveControl = false;
1212 
1213         m_rBindings.Invalidate( pTextControlSlots );
1214     }
1215 
1216     //------------------------------------------------------------------------
1217     void FmTextControlShell::controlActivated( const Reference< XControl >& _rxControl )
1218     {
1219         // ensure that all knittings with the previously active control are lost
1220         if ( m_xActiveControl.is() )
1221             implClearActiveControlRef();
1222         DBG_ASSERT( m_aControlFeatures.empty(), "FmTextControlShell::controlActivated: should have no dispatchers when I'm here!" );
1223 
1224 #if OSL_DEBUG_LEVEL > 0
1225         {
1226             Sequence< Reference< XControl > > aActiveControls;
1227             if ( m_xActiveController.is() )
1228                 aActiveControls = m_xActiveController->getControls();
1229 
1230             bool bFoundThisControl = false;
1231 
1232             const Reference< XControl >* pControls = aActiveControls.getConstArray();
1233             const Reference< XControl >* pControlsEnd = pControls + aActiveControls.getLength();
1234             for ( ; ( pControls != pControlsEnd ) && !bFoundThisControl; ++pControls )
1235             {
1236                 if ( *pControls == _rxControl )
1237                     bFoundThisControl = true;
1238             }
1239             DBG_ASSERT( bFoundThisControl, "FmTextControlShell::controlActivated: only controls which belong to the active controller can be activated!" );
1240         }
1241 #endif
1242         // ask the control for dispatchers for our text-related slots
1243         fillFeatureDispatchers( _rxControl, pTextControlSlots, m_aControlFeatures );
1244 
1245         // remember this control
1246         m_xActiveControl = _rxControl;
1247         m_xActiveTextComponent = m_xActiveTextComponent.query( _rxControl );
1248         m_bActiveControlIsReadOnly = lcl_determineReadOnly( m_xActiveControl );
1249         m_bActiveControlIsRichText = lcl_isRichText( m_xActiveControl );
1250 
1251         // if we found a rich text control, we need context menu support
1252         if ( m_bActiveControlIsRichText )
1253         {
1254             DBG_ASSERT( NULL == m_aContextMenuObserver.get(), "FmTextControlShell::controlActivated: already have an observer!" );
1255             m_aContextMenuObserver = MouseListenerAdapter( new FmMouseListenerAdapter( _rxControl, this ) );
1256         }
1257 
1258         if ( m_xActiveTextComponent.is() )
1259         {
1260             DBG_TRACE( "FmTextControlShell::ClipBoard: starting timer for clipboard invalidation" );
1261             m_aClipboardInvalidation.Start();
1262         }
1263 
1264         m_bActiveControl = true;
1265 
1266     	m_rBindings.Invalidate( pTextControlSlots );
1267 
1268         if ( m_pViewFrame )
1269             m_pViewFrame->UIFeatureChanged();
1270 
1271         // don't call the activation handler if we don't have any slots we can serve
1272         // The activation handler is used to put the shell on the top of the dispatcher stack,
1273         // so it's preferred when slots are distributed.
1274         // Note that this is a slight hack, to prevent that we grab slots from the SfxDispatcher
1275         // which should be served by other shells (e.g. Cut/Copy/Paste).
1276         // A real solution would be a forwarding-mechanism for slots: We should be on the top
1277         // if we're active, but if we cannot handle the slot, then we need to tell the dispatcher
1278         // to skip our shell, and pass the slot to the next one. However, this mechanism is not
1279         // not in place in SFX.
1280         // Another possibility would be to have dedicated shells for the slots which we might
1281         // or might not be able to serve. However, this could probably increase the number of
1282         // shells too much (In theory, nearly every slot could have an own shell then).
1283         //
1284         // #i51621# / 2005-08-19 / frank.schoenheit@sun.com
1285         bool bHaveAnyServeableSlots = m_xActiveTextComponent.is() || !m_aControlFeatures.empty();
1286         if ( m_aControlActivationHandler.IsSet() && bHaveAnyServeableSlots )
1287             m_aControlActivationHandler.Call( NULL );
1288 
1289         m_bNeedClipboardInvalidation = true;
1290     }
1291 
1292     //------------------------------------------------------------------------
1293     void FmTextControlShell::fillFeatureDispatchers(  const Reference< XControl > _rxControl, SfxSlotId* _pZeroTerminatedSlots,
1294             ControlFeatures& _rDispatchers )
1295     {
1296         Reference< XDispatchProvider > xProvider( _rxControl, UNO_QUERY );
1297         SfxApplication* pApplication = SFX_APP();
1298         DBG_ASSERT( pApplication, "FmTextControlShell::fillFeatureDispatchers: no SfxApplication!" );
1299         if ( xProvider.is() && pApplication )
1300         {
1301             SfxSlotId* pSlots = _pZeroTerminatedSlots;
1302             while ( *pSlots )
1303             {
1304                 FmTextControlFeature* pDispatcher = implGetFeatureDispatcher( xProvider, pApplication, *pSlots );
1305                 if ( pDispatcher )
1306                     _rDispatchers.insert( ControlFeatures::value_type( *pSlots, ControlFeature( pDispatcher ) ) );
1307 
1308                 ++pSlots;
1309             }
1310         }
1311     }
1312 
1313     //------------------------------------------------------------------------
1314     void FmTextControlShell::impl_parseURL_nothrow( URL& _rURL )
1315     {
1316         try
1317         {
1318             if ( !m_xURLTransformer.is() )
1319             {
1320                 ::comphelper::ComponentContext aContext( ::comphelper::getProcessServiceFactory() );
1321                 aContext.createComponent( "com.sun.star.util.URLTransformer", m_xURLTransformer );
1322             }
1323             if ( m_xURLTransformer.is() )
1324                 m_xURLTransformer->parseStrict( _rURL );
1325         }
1326         catch( const Exception& )
1327         {
1328         	DBG_UNHANDLED_EXCEPTION();
1329         }
1330     }
1331 
1332     //------------------------------------------------------------------------
1333     FmTextControlFeature* FmTextControlShell::implGetFeatureDispatcher( const Reference< XDispatchProvider >& _rxProvider, SfxApplication* _pApplication, SfxSlotId _nSlot )
1334     {
1335         OSL_PRECOND( _rxProvider.is() && _pApplication, "FmTextControlShell::implGetFeatureDispatcher: invalid arg(s)!" );
1336         URL aFeatureURL;
1337         aFeatureURL.Complete = lcl_getUnoSlotName( *_pApplication, _nSlot );
1338         impl_parseURL_nothrow( aFeatureURL );
1339         Reference< XDispatch > xDispatcher = _rxProvider->queryDispatch( aFeatureURL, ::rtl::OUString(), 0xFF );
1340         if ( xDispatcher.is() )
1341             return new FmTextControlFeature( xDispatcher, aFeatureURL, _nSlot, this );
1342         return NULL;
1343     }
1344 
1345     //------------------------------------------------------------------------
1346     void FmTextControlShell::Invalidate( SfxSlotId _nSlot )
1347     {
1348     	m_rBindings.Invalidate( _nSlot );
1349         // despite this method being called "Invalidate", we also update here - this gives more immediate
1350         // feedback in the UI
1351     	m_rBindings.Update( _nSlot );
1352     }
1353 
1354     //------------------------------------------------------------------------
1355     void FmTextControlShell::focusGained( const ::com::sun::star::awt::FocusEvent& _rEvent )
1356     {
1357         Reference< XControl > xControl( _rEvent.Source, UNO_QUERY );
1358 
1359 #if OSL_DEBUG_LEVEL > 0
1360         ::rtl::OString sTrace( "FmTextControlShell::focusGained: 0x" );
1361         sTrace += ::rtl::OString::valueOf( (sal_IntPtr)xControl.get(), 16 );
1362         DBG_TRACE( sTrace );
1363 #endif
1364 
1365         DBG_ASSERT( xControl.is(), "FmTextControlShell::focusGained: suspicious focus event!" );
1366         if ( xControl.is() )
1367             controlActivated( xControl );
1368     }
1369 
1370     //------------------------------------------------------------------------
1371     void FmTextControlShell::focusLost( const ::com::sun::star::awt::FocusEvent& _rEvent )
1372     {
1373         Reference< XControl > xControl( _rEvent.Source, UNO_QUERY );
1374 
1375 #if OSL_DEBUG_LEVEL > 0
1376         ::rtl::OString sTrace( "FmTextControlShell::focusLost: 0x" );
1377         sTrace += ::rtl::OString::valueOf( (sal_IntPtr)xControl.get(), 16 );
1378         DBG_TRACE( sTrace );
1379 #endif
1380 
1381         m_bActiveControl = false;
1382     }
1383 
1384     //------------------------------------------------------------------------
1385     void FmTextControlShell::ForgetActiveControl()
1386     {
1387         implClearActiveControlRef();
1388     }
1389 
1390     //------------------------------------------------------------------------
1391     void FmTextControlShell::contextMenuRequested( const awt::MouseEvent& /*_rEvent*/ )
1392     {
1393         m_rBindings.GetDispatcher()->ExecutePopup( SVX_RES( RID_FM_TEXTATTRIBUTE_MENU ) );
1394     }
1395 
1396 //........................................................................
1397 } // namespace svx
1398 //........................................................................
1399