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