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