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