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