Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "propcontroller.hxx"
30 : : #include "pcrstrings.hxx"
31 : : #include "standardcontrol.hxx"
32 : : #include "linedescriptor.hxx"
33 : : #include "propresid.hrc"
34 : : #include "formresid.hrc"
35 : : #include "propertyeditor.hxx"
36 : : #include "modulepcr.hxx"
37 : : #include "formstrings.hxx"
38 : : #include "formmetadata.hxx"
39 : : #include "formbrowsertools.hxx"
40 : : #include "propertycomposer.hxx"
41 : :
42 : : #include <com/sun/star/awt/XWindow.hpp>
43 : : #include <com/sun/star/util/XCloseable.hpp>
44 : : #include <com/sun/star/inspection/PropertyControlType.hpp>
45 : : #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
46 : : #include <tools/debug.hxx>
47 : : #include <tools/diagnose_ex.h>
48 : : #include <comphelper/types.hxx>
49 : : #include <comphelper/extract.hxx>
50 : : #include <toolkit/awt/vclxwindow.hxx>
51 : : #include <toolkit/unohlp.hxx>
52 : : #include <comphelper/property.hxx>
53 : : #include <vcl/msgbox.hxx>
54 : : #include <vcl/svapp.hxx>
55 : : #include <osl/mutex.hxx>
56 : : #include <cppuhelper/component_context.hxx>
57 : : #include <cppuhelper/exc_hlp.hxx>
58 : :
59 : : #include <algorithm>
60 : : #include <functional>
61 : : #include <sal/macros.h>
62 : :
63 : : //------------------------------------------------------------------------
64 : : // !!! outside the namespace !!!
65 : 0 : extern "C" void SAL_CALL createRegistryInfo_OPropertyBrowserController()
66 : : {
67 : 0 : ::pcr::OAutoRegistration< ::pcr::OPropertyBrowserController > aAutoRegistration;
68 : 0 : }
69 : :
70 : : //............................................................................
71 : : namespace pcr
72 : : {
73 : : //............................................................................
74 : :
75 : : using namespace ::com::sun::star;
76 : : using namespace ::com::sun::star::uno;
77 : : using namespace ::com::sun::star::awt;
78 : : using namespace ::com::sun::star::form;
79 : : using namespace ::com::sun::star::beans;
80 : : using namespace ::com::sun::star::script;
81 : : using namespace ::com::sun::star::lang;
82 : : using namespace ::com::sun::star::container;
83 : : using namespace ::com::sun::star::frame;
84 : : using namespace ::com::sun::star::util;
85 : : using namespace ::com::sun::star::inspection;
86 : : using namespace ::com::sun::star::ucb;
87 : : using namespace ::comphelper;
88 : :
89 : : #define THISREF() static_cast< XController* >(this)
90 : :
91 : : //========================================================================
92 : : //= OPropertyBrowserController
93 : : //========================================================================
94 : : DBG_NAME(OPropertyBrowserController)
95 : : //------------------------------------------------------------------------
96 : 0 : OPropertyBrowserController::OPropertyBrowserController( const Reference< XComponentContext >& _rxContext )
97 : : :m_aContext(_rxContext)
98 : : ,m_aDisposeListeners( m_aMutex )
99 : : ,m_aControlObservers( m_aMutex )
100 : : ,m_pView(NULL)
101 : : ,m_bContainerFocusListening( false )
102 : : ,m_bSuspendingPropertyHandlers( false )
103 : : ,m_bConstructed( false )
104 : 0 : ,m_bBindingIntrospectee( false )
105 : : {
106 : : DBG_CTOR(OPropertyBrowserController,NULL);
107 : 0 : }
108 : :
109 : : //------------------------------------------------------------------------
110 : 0 : OPropertyBrowserController::~OPropertyBrowserController()
111 : : {
112 : : // stop listening for property changes
113 : 0 : acquire();
114 : 0 : stopInspection( true );
115 : : DBG_DTOR(OPropertyBrowserController,NULL);
116 : 0 : }
117 : :
118 : : //------------------------------------------------------------------------
119 : 0 : IMPLEMENT_FORWARD_REFCOUNT( OPropertyBrowserController, OPropertyBrowserController_Base )
120 : :
121 : : //------------------------------------------------------------------------
122 : 0 : Any SAL_CALL OPropertyBrowserController::queryInterface( const Type& _rType ) throw (RuntimeException)
123 : : {
124 : 0 : Any aReturn = OPropertyBrowserController_Base::queryInterface( _rType );
125 : 0 : if ( !aReturn.hasValue() )
126 : : aReturn = ::cppu::queryInterface(
127 : : _rType,
128 : : static_cast< XObjectInspectorUI* >( this )
129 : 0 : );
130 : 0 : return aReturn;
131 : : }
132 : :
133 : : //------------------------------------------------------------------------
134 : 0 : void OPropertyBrowserController::startContainerWindowListening()
135 : : {
136 : 0 : if (m_bContainerFocusListening)
137 : 0 : return;
138 : :
139 : 0 : if (m_xFrame.is())
140 : : {
141 : 0 : Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow();
142 : 0 : if (xContainerWindow.is())
143 : : {
144 : 0 : xContainerWindow->addFocusListener(this);
145 : 0 : m_bContainerFocusListening = sal_True;
146 : 0 : }
147 : : }
148 : :
149 : : DBG_ASSERT(m_bContainerFocusListening, "OPropertyBrowserController::startContainerWindowListening: unable to start listening (inconsistence)!");
150 : : }
151 : :
152 : : //------------------------------------------------------------------------
153 : 0 : void OPropertyBrowserController::stopContainerWindowListening()
154 : : {
155 : 0 : if (!m_bContainerFocusListening)
156 : 0 : return;
157 : :
158 : 0 : if (m_xFrame.is())
159 : : {
160 : 0 : Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow();
161 : 0 : if (xContainerWindow.is())
162 : : {
163 : 0 : xContainerWindow->removeFocusListener(this);
164 : 0 : m_bContainerFocusListening = sal_False;
165 : 0 : }
166 : : }
167 : :
168 : : DBG_ASSERT(!m_bContainerFocusListening, "OPropertyBrowserController::stopContainerWindowListening: unable to stop listening (inconsistence)!");
169 : : }
170 : :
171 : : //--------------------------------------------------------------------
172 : 0 : Reference< XObjectInspectorModel > SAL_CALL OPropertyBrowserController::getInspectorModel() throw (RuntimeException)
173 : : {
174 : 0 : return m_xModel;
175 : : }
176 : :
177 : : //--------------------------------------------------------------------
178 : 0 : void OPropertyBrowserController::impl_initializeView_nothrow()
179 : : {
180 : : OSL_PRECOND( haveView(), "OPropertyBrowserController::impl_initializeView_nothrow: not to be called when we have no view!" );
181 : 0 : if ( !haveView() )
182 : 0 : return;
183 : :
184 : 0 : if ( !m_xModel.is() )
185 : : // allowed
186 : 0 : return;
187 : :
188 : : try
189 : : {
190 : 0 : getPropertyBox().EnableHelpSection( m_xModel->getHasHelpSection() );
191 : 0 : getPropertyBox().SetHelpLineLimites( m_xModel->getMinHelpTextLines(), m_xModel->getMaxHelpTextLines() );
192 : : }
193 : 0 : catch( const Exception& )
194 : : {
195 : : DBG_UNHANDLED_EXCEPTION();
196 : : }
197 : : }
198 : :
199 : : //--------------------------------------------------------------------
200 : 0 : void OPropertyBrowserController::impl_updateReadOnlyView_nothrow()
201 : : {
202 : : // this is a huge cudgel, admitted.
203 : : // The problem is that in case we were previously read-only, all our controls
204 : : // were created read-only, too. We cannot simply switch them to not-read-only.
205 : : // Even if they had an API for this, we do not know whether they were
206 : : // originally created read-only, or if they are read-only just because
207 : : // the model was.
208 : 0 : impl_rebindToInspectee_nothrow( m_aInspectedObjects );
209 : 0 : }
210 : :
211 : : //--------------------------------------------------------------------
212 : 0 : bool OPropertyBrowserController::impl_isReadOnlyModel_throw() const
213 : : {
214 : 0 : if ( !m_xModel.is() )
215 : 0 : return false;
216 : :
217 : 0 : return m_xModel->getIsReadOnly();
218 : : }
219 : :
220 : : //--------------------------------------------------------------------
221 : 0 : void OPropertyBrowserController::impl_startOrStopModelListening_nothrow( bool _bDoListen ) const
222 : : {
223 : : try
224 : : {
225 : 0 : Reference< XPropertySet > xModelProperties( m_xModel, UNO_QUERY );
226 : 0 : if ( !xModelProperties.is() )
227 : : // okay, so the model doesn't want to change its properties
228 : : // dynamically - fine with us
229 : 0 : return;
230 : :
231 : : void (SAL_CALL XPropertySet::*pListenerOperation)( const ::rtl::OUString&, const Reference< XPropertyChangeListener >& )
232 : 0 : = _bDoListen ? &XPropertySet::addPropertyChangeListener : &XPropertySet::removePropertyChangeListener;
233 : :
234 : 0 : (xModelProperties.get()->*pListenerOperation)(
235 : : ::rtl::OUString( "IsReadOnly" ),
236 : : const_cast< OPropertyBrowserController* >( this )
237 : 0 : );
238 : : }
239 : 0 : catch( const Exception& )
240 : : {
241 : : DBG_UNHANDLED_EXCEPTION();
242 : : }
243 : : }
244 : :
245 : : //--------------------------------------------------------------------
246 : 0 : void OPropertyBrowserController::impl_bindToNewModel_nothrow( const Reference< XObjectInspectorModel >& _rxInspectorModel )
247 : : {
248 : 0 : impl_startOrStopModelListening_nothrow( false );
249 : 0 : m_xModel = _rxInspectorModel;
250 : 0 : impl_startOrStopModelListening_nothrow( true );
251 : :
252 : : // initialize the view, if we already have one
253 : 0 : if ( haveView() )
254 : 0 : impl_initializeView_nothrow();
255 : :
256 : : // inspect again, if we already have inspectees
257 : 0 : if ( !m_aInspectedObjects.empty() )
258 : 0 : impl_rebindToInspectee_nothrow( m_aInspectedObjects );
259 : 0 : }
260 : :
261 : : //--------------------------------------------------------------------
262 : 0 : void SAL_CALL OPropertyBrowserController::setInspectorModel( const Reference< XObjectInspectorModel >& _inspectorModel ) throw (RuntimeException)
263 : : {
264 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
265 : :
266 : 0 : if ( m_xModel == _inspectorModel )
267 : 0 : return;
268 : :
269 : 0 : impl_bindToNewModel_nothrow( _inspectorModel );
270 : : }
271 : :
272 : : //--------------------------------------------------------------------
273 : 0 : Reference< XObjectInspectorUI > SAL_CALL OPropertyBrowserController::getInspectorUI() throw (RuntimeException)
274 : : {
275 : : // we're derived from this interface, though we do not expose it in queryInterface and getTypes.
276 : 0 : return this;
277 : : }
278 : :
279 : : //--------------------------------------------------------------------
280 : 0 : void SAL_CALL OPropertyBrowserController::inspect( const Sequence< Reference< XInterface > >& _rObjects ) throw (com::sun::star::util::VetoException, RuntimeException)
281 : : {
282 : 0 : SolarMutexGuard aSolarGuard;
283 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
284 : :
285 : 0 : if ( m_bSuspendingPropertyHandlers || !suspendAll_nothrow() )
286 : : { // we already are trying to suspend the component (this is somewhere up the stack)
287 : : // OR one of our property handlers raised a veto against closing. Well, we *need* to close
288 : : // it in order to inspect another object.
289 : 0 : throw VetoException();
290 : : }
291 : 0 : if ( m_bBindingIntrospectee )
292 : 0 : throw VetoException();
293 : :
294 : 0 : m_bBindingIntrospectee = true;
295 : 0 : impl_rebindToInspectee_nothrow( InterfaceArray( _rObjects.getConstArray(), _rObjects.getConstArray() + _rObjects.getLength() ) );
296 : 0 : m_bBindingIntrospectee = false;
297 : :
298 : 0 : }
299 : :
300 : : //--------------------------------------------------------------------
301 : 0 : Reference< XDispatch > SAL_CALL OPropertyBrowserController::queryDispatch( const URL& /*URL*/, const ::rtl::OUString& /*TargetFrameName*/, ::sal_Int32 /*SearchFlags*/ ) throw (RuntimeException)
302 : : {
303 : : // we don't have any dispatches at all, right now
304 : 0 : return Reference< XDispatch >();
305 : : }
306 : :
307 : : //--------------------------------------------------------------------
308 : 0 : Sequence< Reference< XDispatch > > SAL_CALL OPropertyBrowserController::queryDispatches( const Sequence< DispatchDescriptor >& Requests ) throw (RuntimeException)
309 : : {
310 : 0 : Sequence< Reference< XDispatch > > aReturn;
311 : 0 : sal_Int32 nLen = Requests.getLength();
312 : 0 : aReturn.realloc( nLen );
313 : :
314 : 0 : Reference< XDispatch >* pReturn = aReturn.getArray();
315 : 0 : const Reference< XDispatch >* pReturnEnd = aReturn.getArray() + nLen;
316 : 0 : const DispatchDescriptor* pDescripts = Requests.getConstArray();
317 : :
318 : 0 : for ( ; pReturn != pReturnEnd; ++ pReturn, ++pDescripts )
319 : 0 : *pReturn = queryDispatch( pDescripts->FeatureURL, pDescripts->FrameName, pDescripts->SearchFlags );
320 : :
321 : 0 : return aReturn;
322 : : }
323 : :
324 : : //------------------------------------------------------------------------
325 : 0 : void SAL_CALL OPropertyBrowserController::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException)
326 : : {
327 : 0 : if ( m_bConstructed )
328 : 0 : throw AlreadyInitializedException();
329 : :
330 : 0 : StlSyntaxSequence< Any > arguments( _arguments );
331 : 0 : if ( arguments.empty() )
332 : : { // constructor: "createDefault()"
333 : 0 : createDefault();
334 : : return;
335 : : }
336 : :
337 : 0 : Reference< XObjectInspectorModel > xModel;
338 : 0 : if ( arguments.size() == 1 )
339 : : { // constructor: "createWithModel( XObjectInspectorModel )"
340 : 0 : if ( !( arguments[0] >>= xModel ) )
341 : 0 : throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
342 : 0 : createWithModel( xModel );
343 : : return;
344 : : }
345 : :
346 : 0 : throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
347 : : }
348 : :
349 : : //------------------------------------------------------------------------
350 : 0 : void OPropertyBrowserController::createDefault()
351 : : {
352 : 0 : m_bConstructed = true;
353 : 0 : }
354 : :
355 : : //------------------------------------------------------------------------
356 : 0 : void OPropertyBrowserController::createWithModel( const Reference< XObjectInspectorModel >& _rxModel )
357 : : {
358 : 0 : osl_incrementInterlockedCount( &m_refCount );
359 : : {
360 : 0 : setInspectorModel( _rxModel );
361 : : }
362 : 0 : osl_decrementInterlockedCount( &m_refCount );
363 : :
364 : 0 : m_bConstructed = true;
365 : 0 : }
366 : :
367 : : //------------------------------------------------------------------------
368 : 0 : void SAL_CALL OPropertyBrowserController::attachFrame( const Reference< XFrame >& _rxFrame ) throw(RuntimeException)
369 : : {
370 : 0 : SolarMutexGuard aSolarGuard;
371 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
372 : :
373 : 0 : if (_rxFrame.is() && haveView())
374 : 0 : throw RuntimeException(::rtl::OUString("Unable to attach to a second frame."),*this);
375 : :
376 : : // revoke as focus listener from the old container window
377 : 0 : stopContainerWindowListening();
378 : :
379 : 0 : m_xFrame = _rxFrame;
380 : 0 : if (!m_xFrame.is())
381 : 0 : return;
382 : :
383 : : // TODO: this construction perhaps should be done outside. Don't know the exact meaning of attachFrame.
384 : : // Maybe it is intended to only announce the frame to the controller, and the instance doing this
385 : : // announcement is responsible for calling setComponent, too.
386 : 0 : Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow();
387 : 0 : VCLXWindow* pContainerWindow = VCLXWindow::GetImplementation(xContainerWindow);
388 : 0 : Window* pParentWin = pContainerWindow ? pContainerWindow->GetWindow() : NULL;
389 : 0 : if (!pParentWin)
390 : 0 : throw RuntimeException(::rtl::OUString("The frame is invalid. Unable to extract the container window."),*this);
391 : :
392 : 0 : if ( Construct( pParentWin ) )
393 : : {
394 : : try
395 : : {
396 : 0 : m_xFrame->setComponent( VCLUnoHelper::GetInterface( m_pView ), this );
397 : : }
398 : 0 : catch( const Exception& )
399 : : {
400 : : OSL_FAIL( "OPropertyBrowserController::attachFrame: caught an exception!" );
401 : : }
402 : : }
403 : :
404 : 0 : startContainerWindowListening();
405 : :
406 : 0 : UpdateUI();
407 : : }
408 : :
409 : : //------------------------------------------------------------------------
410 : 0 : sal_Bool SAL_CALL OPropertyBrowserController::attachModel( const Reference< XModel >& _rxModel ) throw(RuntimeException)
411 : : {
412 : 0 : Reference< XObjectInspectorModel > xModel( _rxModel, UNO_QUERY );
413 : 0 : if ( !xModel.is() )
414 : 0 : return false;
415 : :
416 : 0 : setInspectorModel( xModel );
417 : 0 : return getInspectorModel() == _rxModel;
418 : : }
419 : :
420 : : //------------------------------------------------------------------------
421 : 0 : sal_Bool OPropertyBrowserController::suspendAll_nothrow()
422 : : {
423 : : // if there is a handle inside its "onInteractivePropertySelection" method,
424 : : // then veto
425 : : // Normally, we could expect every handler to do this itself, but being
426 : : // realistic, it's safer to handle this here in general.
427 : 0 : if ( m_xInteractiveHandler.is() )
428 : 0 : return sal_False;
429 : :
430 : 0 : m_bSuspendingPropertyHandlers = true;
431 : 0 : sal_Bool bHandlerVeto = !suspendPropertyHandlers_nothrow( sal_True );
432 : 0 : m_bSuspendingPropertyHandlers = false;
433 : 0 : if ( bHandlerVeto )
434 : 0 : return sal_False;
435 : :
436 : 0 : return sal_True;
437 : : }
438 : :
439 : : //------------------------------------------------------------------------
440 : 0 : sal_Bool OPropertyBrowserController::suspendPropertyHandlers_nothrow( sal_Bool _bSuspend )
441 : : {
442 : 0 : PropertyHandlerArray aAllHandlers; // will contain every handler exactly once
443 : 0 : for ( PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.begin();
444 : 0 : handler != m_aPropertyHandlers.end();
445 : : ++handler
446 : : )
447 : : {
448 : 0 : if ( ::std::find( aAllHandlers.begin(), aAllHandlers.end(), handler->second ) != aAllHandlers.end() )
449 : : // already visited this particular handler (m_aPropertyHandlers usually contains
450 : : // the same handler more than once)
451 : 0 : continue;
452 : 0 : aAllHandlers.push_back( handler->second );
453 : : }
454 : :
455 : 0 : for ( PropertyHandlerArray::iterator loop = aAllHandlers.begin();
456 : 0 : loop != aAllHandlers.end();
457 : : ++loop
458 : : )
459 : : {
460 : : try
461 : : {
462 : 0 : if ( !(*loop)->suspend( _bSuspend ) )
463 : 0 : if ( _bSuspend )
464 : : // if we're not suspending, but reactivating, ignore the error
465 : 0 : return sal_False;
466 : : }
467 : 0 : catch( const Exception& )
468 : : {
469 : : OSL_FAIL( "OPropertyBrowserController::suspendPropertyHandlers_nothrow: caught an exception!" );
470 : : }
471 : : }
472 : 0 : return sal_True;
473 : : }
474 : :
475 : : //------------------------------------------------------------------------
476 : 0 : sal_Bool SAL_CALL OPropertyBrowserController::suspend( sal_Bool _bSuspend ) throw(RuntimeException)
477 : : {
478 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
479 : : OSL_ENSURE( haveView(), "OPropertyBrowserController::suspend: don't have a view anymore!" );
480 : :
481 : 0 : if ( !_bSuspend )
482 : : { // this means a "suspend" is to be "revoked"
483 : 0 : suspendPropertyHandlers_nothrow( sal_False );
484 : : // we ourself cannot revoke our suspend
485 : 0 : return sal_False;
486 : : }
487 : :
488 : 0 : if ( !suspendAll_nothrow() )
489 : 0 : return sal_False;
490 : :
491 : : // commit the editor's content
492 : 0 : if ( haveView() )
493 : 0 : getPropertyBox().CommitModified();
494 : :
495 : : // stop listening
496 : 0 : stopContainerWindowListening();
497 : :
498 : : // outtahere
499 : 0 : return sal_True;
500 : : }
501 : :
502 : : //------------------------------------------------------------------------
503 : 0 : Any SAL_CALL OPropertyBrowserController::getViewData( ) throw(RuntimeException)
504 : : {
505 : 0 : return makeAny( m_sPageSelection );
506 : : }
507 : :
508 : : //------------------------------------------------------------------------
509 : 0 : void SAL_CALL OPropertyBrowserController::restoreViewData( const Any& Data ) throw(RuntimeException)
510 : : {
511 : 0 : ::rtl::OUString sPageSelection;
512 : 0 : if ( ( Data >>= sPageSelection ) && !sPageSelection.isEmpty() )
513 : : {
514 : 0 : m_sPageSelection = sPageSelection;
515 : 0 : selectPageFromViewData();
516 : 0 : }
517 : 0 : }
518 : :
519 : : //------------------------------------------------------------------------
520 : 0 : Reference< XModel > SAL_CALL OPropertyBrowserController::getModel( ) throw(RuntimeException)
521 : : {
522 : : // have no model
523 : 0 : return Reference< XModel >();
524 : : }
525 : :
526 : : //------------------------------------------------------------------------
527 : 0 : Reference< XFrame > SAL_CALL OPropertyBrowserController::getFrame( ) throw(RuntimeException)
528 : : {
529 : 0 : return m_xFrame;
530 : : }
531 : :
532 : : //------------------------------------------------------------------------
533 : 0 : void SAL_CALL OPropertyBrowserController::dispose( ) throw(RuntimeException)
534 : : {
535 : 0 : SolarMutexGuard aSolarGuard;
536 : :
537 : : // stop inspecting the current object
538 : 0 : stopInspection( false );
539 : :
540 : : // say our dispose listeners goodbye
541 : 0 : ::com::sun::star::lang::EventObject aEvt;
542 : 0 : aEvt.Source = static_cast< ::cppu::OWeakObject* >(this);
543 : 0 : m_aDisposeListeners.disposeAndClear(aEvt);
544 : 0 : m_aControlObservers.disposeAndClear(aEvt);
545 : :
546 : : // don't delete explicitly (this is done by the frame we reside in)
547 : 0 : m_pView = NULL;
548 : :
549 : 0 : Reference< XComponent > xViewAsComp( m_xView, UNO_QUERY );
550 : 0 : if ( xViewAsComp.is() )
551 : 0 : xViewAsComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
552 : 0 : m_xView.clear( );
553 : :
554 : 0 : m_aInspectedObjects.clear();
555 : 0 : impl_bindToNewModel_nothrow( NULL );
556 : 0 : }
557 : :
558 : : //------------------------------------------------------------------------
559 : 0 : void SAL_CALL OPropertyBrowserController::addEventListener( const Reference< XEventListener >& _rxListener ) throw(RuntimeException)
560 : : {
561 : 0 : m_aDisposeListeners.addInterface(_rxListener);
562 : 0 : }
563 : :
564 : : //------------------------------------------------------------------------
565 : 0 : void SAL_CALL OPropertyBrowserController::removeEventListener( const Reference< XEventListener >& _rxListener ) throw(RuntimeException)
566 : : {
567 : 0 : m_aDisposeListeners.removeInterface(_rxListener);
568 : 0 : }
569 : :
570 : : //------------------------------------------------------------------------
571 : 0 : ::rtl::OUString SAL_CALL OPropertyBrowserController::getImplementationName( ) throw(RuntimeException)
572 : : {
573 : 0 : return getImplementationName_static();
574 : : }
575 : :
576 : : //------------------------------------------------------------------------
577 : 0 : sal_Bool SAL_CALL OPropertyBrowserController::supportsService( const ::rtl::OUString& ServiceName ) throw(RuntimeException)
578 : : {
579 : 0 : Sequence< ::rtl::OUString > aSupported(getSupportedServiceNames());
580 : 0 : const ::rtl::OUString* pArray = aSupported.getConstArray();
581 : 0 : for (sal_Int32 i = 0; i < aSupported.getLength(); ++i, ++pArray)
582 : 0 : if (pArray->equals(ServiceName))
583 : 0 : return sal_True;
584 : 0 : return sal_False;
585 : : }
586 : :
587 : : //------------------------------------------------------------------------
588 : 0 : Sequence< ::rtl::OUString > SAL_CALL OPropertyBrowserController::getSupportedServiceNames( ) throw(RuntimeException)
589 : : {
590 : 0 : return getSupportedServiceNames_static();
591 : : }
592 : :
593 : : //------------------------------------------------------------------------
594 : 0 : ::rtl::OUString OPropertyBrowserController::getImplementationName_static( ) throw(RuntimeException)
595 : : {
596 : 0 : return ::rtl::OUString("org.openoffice.comp.extensions.ObjectInspector");
597 : : }
598 : :
599 : : //------------------------------------------------------------------------
600 : 0 : Sequence< ::rtl::OUString > OPropertyBrowserController::getSupportedServiceNames_static( ) throw(RuntimeException)
601 : : {
602 : 0 : Sequence< ::rtl::OUString > aSupported(1);
603 : 0 : aSupported[0] = ::rtl::OUString("com.sun.star.inspection.ObjectInspector");
604 : 0 : return aSupported;
605 : : }
606 : :
607 : : //------------------------------------------------------------------------
608 : 0 : Reference< XInterface > SAL_CALL OPropertyBrowserController::Create(const Reference< XComponentContext >& _rxContext)
609 : : {
610 : 0 : return *(new OPropertyBrowserController( _rxContext ) );
611 : : }
612 : :
613 : : //------------------------------------------------------------------------
614 : 0 : void SAL_CALL OPropertyBrowserController::focusGained( const FocusEvent& _rSource ) throw (RuntimeException)
615 : : {
616 : 0 : Reference< XWindow > xSourceWindow(_rSource.Source, UNO_QUERY);
617 : 0 : Reference< XWindow > xContainerWindow;
618 : 0 : if (m_xFrame.is())
619 : 0 : xContainerWindow = m_xFrame->getContainerWindow();
620 : :
621 : 0 : if ( xContainerWindow.get() == xSourceWindow.get() )
622 : : { // our container window got the focus
623 : 0 : if ( haveView() )
624 : 0 : getPropertyBox().GrabFocus();
625 : 0 : }
626 : 0 : }
627 : :
628 : : //------------------------------------------------------------------------
629 : 0 : void SAL_CALL OPropertyBrowserController::focusLost( const FocusEvent& /*_rSource*/ ) throw (RuntimeException)
630 : : {
631 : : // not interested in
632 : 0 : }
633 : :
634 : : //------------------------------------------------------------------------
635 : 0 : void SAL_CALL OPropertyBrowserController::disposing( const EventObject& _rSource ) throw(RuntimeException)
636 : : {
637 : 0 : if ( m_xView.is() && ( m_xView == _rSource.Source ) )
638 : : {
639 : 0 : m_xView = NULL;
640 : 0 : m_pView = NULL;
641 : : }
642 : :
643 : 0 : for ( InterfaceArray::iterator loop = m_aInspectedObjects.begin();
644 : 0 : loop != m_aInspectedObjects.end();
645 : : ++loop
646 : : )
647 : : {
648 : 0 : if ( *loop == _rSource.Source )
649 : : {
650 : 0 : m_aInspectedObjects.erase( loop );
651 : 0 : break;
652 : : }
653 : : }
654 : 0 : }
655 : :
656 : : //------------------------------------------------------------------------
657 : 0 : IMPL_LINK_NOARG(OPropertyBrowserController, OnPageActivation)
658 : : {
659 : 0 : updateViewDataFromActivePage();
660 : 0 : return 0L;
661 : : }
662 : :
663 : : //------------------------------------------------------------------------
664 : 0 : void OPropertyBrowserController::updateViewDataFromActivePage()
665 : : {
666 : 0 : if (!haveView())
667 : 0 : return;
668 : :
669 : 0 : ::rtl::OUString sOldSelection = m_sPageSelection;
670 : 0 : m_sPageSelection = ::rtl::OUString();
671 : :
672 : 0 : const sal_uInt16 nCurrentPage = m_pView->getActivaPage();
673 : 0 : if ( (sal_uInt16)-1 != nCurrentPage )
674 : : {
675 : 0 : for ( HashString2Int16::const_iterator pageId = m_aPageIds.begin();
676 : 0 : pageId != m_aPageIds.end();
677 : : ++pageId
678 : : )
679 : : {
680 : 0 : if ( nCurrentPage == pageId->second )
681 : : {
682 : 0 : m_sPageSelection = pageId->first;
683 : 0 : break;
684 : : }
685 : : }
686 : : }
687 : :
688 : 0 : if ( !m_sPageSelection.isEmpty() )
689 : 0 : m_sLastValidPageSelection = m_sPageSelection;
690 : 0 : else if ( !sOldSelection.isEmpty() )
691 : 0 : m_sLastValidPageSelection = sOldSelection;
692 : : }
693 : :
694 : : //------------------------------------------------------------------------
695 : 0 : sal_uInt16 OPropertyBrowserController::impl_getPageIdForCategory_nothrow( const ::rtl::OUString& _rCategoryName ) const
696 : : {
697 : 0 : sal_uInt16 nPageId = (sal_uInt16)-1;
698 : 0 : HashString2Int16::const_iterator pagePos = m_aPageIds.find( _rCategoryName );
699 : 0 : if ( pagePos != m_aPageIds.end() )
700 : 0 : nPageId = pagePos->second;
701 : 0 : return nPageId;
702 : : }
703 : :
704 : : //------------------------------------------------------------------------
705 : 0 : void OPropertyBrowserController::selectPageFromViewData()
706 : : {
707 : 0 : sal_uInt16 nNewPage = impl_getPageIdForCategory_nothrow( m_sPageSelection );
708 : :
709 : 0 : if ( haveView() && ( nNewPage != (sal_uInt16)-1 ) )
710 : 0 : m_pView->activatePage( nNewPage );
711 : :
712 : : // just in case ...
713 : 0 : updateViewDataFromActivePage();
714 : 0 : }
715 : :
716 : : //------------------------------------------------------------------------
717 : 0 : sal_Bool OPropertyBrowserController::Construct(Window* _pParentWin)
718 : : {
719 : : DBG_ASSERT(!haveView(), "OPropertyBrowserController::Construct: already have a view!");
720 : : DBG_ASSERT(_pParentWin, "OPropertyBrowserController::Construct: invalid parent window!");
721 : :
722 : 0 : m_pView = new OPropertyBrowserView(m_aContext.getLegacyServiceFactory(), _pParentWin);
723 : 0 : m_pView->setPageActivationHandler(LINK(this, OPropertyBrowserController, OnPageActivation));
724 : :
725 : : // add as dispose listener for our view. The view is disposed by the frame we're plugged into,
726 : : // and this disposal _deletes_ the view, so it would be deadly if we use our m_pView member
727 : : // after that
728 : 0 : m_xView = VCLUnoHelper::GetInterface(m_pView);
729 : 0 : Reference< XComponent > xViewAsComp(m_xView, UNO_QUERY);
730 : 0 : if (xViewAsComp.is())
731 : 0 : xViewAsComp->addEventListener( static_cast< XPropertyChangeListener* >( this ) );
732 : :
733 : 0 : getPropertyBox().SetLineListener(this);
734 : 0 : getPropertyBox().SetControlObserver(this);
735 : 0 : impl_initializeView_nothrow();
736 : :
737 : 0 : m_pView->Show();
738 : :
739 : 0 : return sal_True;
740 : : }
741 : :
742 : : //------------------------------------------------------------------------
743 : 0 : void SAL_CALL OPropertyBrowserController::propertyChange( const PropertyChangeEvent& _rEvent ) throw (RuntimeException)
744 : : {
745 : 0 : if ( _rEvent.Source == m_xModel )
746 : : {
747 : 0 : if ( _rEvent.PropertyName == "IsReadOnly" )
748 : 0 : impl_updateReadOnlyView_nothrow();
749 : : return;
750 : : }
751 : :
752 : 0 : if ( m_sCommittingProperty == _rEvent.PropertyName )
753 : : return;
754 : :
755 : 0 : if ( !haveView() )
756 : : return;
757 : :
758 : 0 : Any aNewValue( _rEvent.NewValue );
759 : 0 : if ( impl_hasPropertyHandlerFor_nothrow( _rEvent.PropertyName ) )
760 : : {
761 : : // forward the new value to the property box, to reflect the change in the UI
762 : 0 : aNewValue = impl_getPropertyValue_throw( _rEvent.PropertyName );
763 : :
764 : : // check whether the state is ambiguous. This is interesting in case we display the properties
765 : : // for multiple objects at once: In this case, we'll get a notification from one of the objects,
766 : : // but need to care for the "composed" value, which can be "ambiguous".
767 : 0 : PropertyHandlerRef xHandler( impl_getHandlerForProperty_throw( _rEvent.PropertyName ), UNO_SET_THROW );
768 : 0 : PropertyState ePropertyState( xHandler->getPropertyState( _rEvent.PropertyName ) );
769 : 0 : bool bAmbiguousValue = ( PropertyState_AMBIGUOUS_VALUE == ePropertyState );
770 : :
771 : 0 : getPropertyBox().SetPropertyValue( _rEvent.PropertyName, aNewValue, bAmbiguousValue );
772 : : }
773 : :
774 : : // if it's a actuating property, then update the UI for any dependent
775 : : // properties
776 : 0 : if ( impl_isActuatingProperty_nothrow( _rEvent.PropertyName ) )
777 : 0 : impl_broadcastPropertyChange_nothrow( _rEvent.PropertyName, aNewValue, _rEvent.OldValue, false );
778 : : }
779 : :
780 : : //------------------------------------------------------------------------
781 : 0 : Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::createPropertyControl( ::sal_Int16 ControlType, ::sal_Bool _CreateReadOnly ) throw (IllegalArgumentException, RuntimeException)
782 : : {
783 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
784 : :
785 : 0 : Reference< XPropertyControl > xControl;
786 : :
787 : : // default winbits: a border only
788 : 0 : WinBits nWinBits = WB_BORDER;
789 : :
790 : : // read-only-ness
791 : 0 : _CreateReadOnly |= (sal_Bool)impl_isReadOnlyModel_throw();
792 : 0 : if ( _CreateReadOnly )
793 : 0 : nWinBits |= WB_READONLY;
794 : :
795 : 0 : switch ( ControlType )
796 : : {
797 : : case PropertyControlType::StringListField:
798 : 0 : xControl = new OMultilineEditControl( &getPropertyBox(), eStringList, nWinBits | WB_DROPDOWN | WB_TABSTOP );
799 : 0 : break;
800 : :
801 : : case PropertyControlType::MultiLineTextField:
802 : 0 : xControl = new OMultilineEditControl( &getPropertyBox(), eMultiLineText, nWinBits | WB_DROPDOWN | WB_TABSTOP );
803 : 0 : break;
804 : :
805 : : case PropertyControlType::ListBox:
806 : 0 : xControl = new OListboxControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN);
807 : 0 : break;
808 : :
809 : : case PropertyControlType::ComboBox:
810 : 0 : xControl = new OComboboxControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN);
811 : 0 : break;
812 : :
813 : : case PropertyControlType::TextField:
814 : 0 : xControl = new OEditControl( &getPropertyBox(), sal_False, nWinBits | WB_TABSTOP );
815 : 0 : break;
816 : :
817 : : case PropertyControlType::CharacterField:
818 : 0 : xControl = new OEditControl( &getPropertyBox(), sal_True, nWinBits | WB_TABSTOP );
819 : 0 : break;
820 : :
821 : : case PropertyControlType::NumericField:
822 : 0 : xControl = new ONumericControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_SPIN | WB_REPEAT );
823 : 0 : break;
824 : :
825 : : case PropertyControlType::DateTimeField:
826 : 0 : xControl = new ODateTimeControl( &getPropertyBox(), nWinBits | WB_TABSTOP );
827 : 0 : break;
828 : :
829 : : case PropertyControlType::DateField:
830 : 0 : xControl = new ODateControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_SPIN | WB_REPEAT );
831 : 0 : break;
832 : :
833 : : case PropertyControlType::TimeField:
834 : 0 : xControl = new OTimeControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_SPIN | WB_REPEAT );
835 : 0 : break;
836 : :
837 : : case PropertyControlType::ColorListBox:
838 : 0 : xControl = new OColorControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN );
839 : 0 : break;
840 : :
841 : : case PropertyControlType::HyperlinkField:
842 : 0 : xControl = new OHyperlinkControl( &getPropertyBox(), nWinBits | WB_TABSTOP | WB_DROPDOWN );
843 : 0 : break;
844 : :
845 : : default:
846 : 0 : throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
847 : : }
848 : :
849 : 0 : return xControl;
850 : : }
851 : :
852 : : //------------------------------------------------------------------------
853 : 0 : void OPropertyBrowserController::impl_toggleInspecteeListening_nothrow( bool _bOn )
854 : : {
855 : 0 : for ( InterfaceArray::const_iterator loop = m_aInspectedObjects.begin();
856 : 0 : loop != m_aInspectedObjects.end();
857 : : ++loop
858 : : )
859 : : {
860 : : try
861 : : {
862 : 0 : Reference< XComponent > xComp( *loop, UNO_QUERY );
863 : 0 : if ( xComp.is() )
864 : : {
865 : 0 : if ( _bOn )
866 : 0 : xComp->addEventListener( static_cast< XPropertyChangeListener* >( this ) );
867 : : else
868 : 0 : xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) );
869 : 0 : }
870 : : }
871 : 0 : catch( const Exception& )
872 : : {
873 : : DBG_UNHANDLED_EXCEPTION();
874 : : }
875 : : }
876 : 0 : }
877 : :
878 : : //------------------------------------------------------------------------
879 : 0 : void OPropertyBrowserController::stopInspection( bool _bCommitModified )
880 : : {
881 : 0 : if ( haveView() )
882 : : {
883 : 0 : if ( _bCommitModified )
884 : : // commit the editor's content
885 : 0 : getPropertyBox().CommitModified();
886 : :
887 : : // hide the property box so that it does not flicker
888 : 0 : getPropertyBox().Hide();
889 : :
890 : : // clear the property box
891 : 0 : getPropertyBox().ClearAll();
892 : : }
893 : :
894 : : // destroy the view first
895 : 0 : if ( haveView() )
896 : : {
897 : : // remove the pages
898 : 0 : for ( HashString2Int16::const_iterator erase = m_aPageIds.begin();
899 : 0 : erase != m_aPageIds.end();
900 : : ++erase
901 : : )
902 : 0 : getPropertyBox().RemovePage( erase->second );
903 : 0 : clearContainer( m_aPageIds );
904 : : }
905 : :
906 : 0 : clearContainer( m_aProperties );
907 : :
908 : : // de-register as dispose-listener from our inspected objects
909 : 0 : impl_toggleInspecteeListening_nothrow( false );
910 : :
911 : : // handlers are obsolete, so is our "composer" for their UI requests
912 : 0 : if ( m_pUIRequestComposer.get() )
913 : 0 : m_pUIRequestComposer->dispose();
914 : 0 : m_pUIRequestComposer.reset( NULL );
915 : :
916 : : // clean up the property handlers
917 : 0 : PropertyHandlerArray aAllHandlers; // will contain every handler exactly once
918 : 0 : for ( PropertyHandlerRepository::const_iterator aHandler = m_aPropertyHandlers.begin();
919 : 0 : aHandler != m_aPropertyHandlers.end();
920 : : ++aHandler
921 : : )
922 : 0 : if ( ::std::find( aAllHandlers.begin(), aAllHandlers.end(), aHandler->second ) == aAllHandlers.end() )
923 : 0 : aAllHandlers.push_back( aHandler->second );
924 : :
925 : 0 : for ( PropertyHandlerArray::iterator loop = aAllHandlers.begin();
926 : 0 : loop != aAllHandlers.end();
927 : : ++loop
928 : : )
929 : : {
930 : : try
931 : : {
932 : 0 : (*loop)->removePropertyChangeListener( this );
933 : 0 : (*loop)->dispose();
934 : : }
935 : 0 : catch( const DisposedException& )
936 : : {
937 : : }
938 : 0 : catch( const Exception& )
939 : : {
940 : : DBG_UNHANDLED_EXCEPTION();
941 : : }
942 : : }
943 : :
944 : 0 : clearContainer( m_aPropertyHandlers );
945 : 0 : clearContainer( m_aDependencyHandlers );
946 : 0 : }
947 : :
948 : : //------------------------------------------------------------------------
949 : 0 : bool OPropertyBrowserController::impl_hasPropertyHandlerFor_nothrow( const ::rtl::OUString& _rPropertyName ) const
950 : : {
951 : 0 : PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName );
952 : 0 : return ( handlerPos != m_aPropertyHandlers.end() );
953 : : }
954 : :
955 : : //------------------------------------------------------------------------
956 : 0 : OPropertyBrowserController::PropertyHandlerRef OPropertyBrowserController::impl_getHandlerForProperty_throw( const ::rtl::OUString& _rPropertyName ) const
957 : : {
958 : 0 : PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName );
959 : 0 : if ( handlerPos == m_aPropertyHandlers.end() )
960 : 0 : throw RuntimeException();
961 : 0 : return handlerPos->second;
962 : : }
963 : :
964 : : //------------------------------------------------------------------------
965 : 0 : Any OPropertyBrowserController::impl_getPropertyValue_throw( const ::rtl::OUString& _rPropertyName )
966 : : {
967 : 0 : PropertyHandlerRef handler = impl_getHandlerForProperty_throw( _rPropertyName );
968 : 0 : return handler->getPropertyValue( _rPropertyName );
969 : : }
970 : :
971 : : //------------------------------------------------------------------------
972 : 0 : void OPropertyBrowserController::impl_rebindToInspectee_nothrow( const InterfaceArray& _rObjects )
973 : : {
974 : : try
975 : : {
976 : : // stop inspecting the old object(s)
977 : 0 : stopInspection( true );
978 : :
979 : : // inspect the new object(s)
980 : 0 : m_aInspectedObjects = _rObjects;
981 : 0 : doInspection();
982 : :
983 : : // update the user interface
984 : 0 : UpdateUI();
985 : : }
986 : :
987 : 0 : catch(const Exception&)
988 : : {
989 : : OSL_FAIL("OPropertyBrowserController::impl_rebindToInspectee_nothrow: caught an exception !");
990 : : }
991 : 0 : }
992 : :
993 : : //------------------------------------------------------------------------
994 : 0 : void OPropertyBrowserController::doInspection()
995 : : {
996 : : try
997 : : {
998 : : //////////////////////////////////////////////////////////////////////
999 : : // obtain the properties of the object
1000 : 0 : ::std::vector< Property > aProperties;
1001 : :
1002 : 0 : PropertyHandlerArray aPropertyHandlers;
1003 : 0 : getPropertyHandlers( m_aInspectedObjects, aPropertyHandlers );
1004 : :
1005 : 0 : PropertyHandlerArray::iterator aHandler( aPropertyHandlers.begin() );
1006 : 0 : while ( aHandler != aPropertyHandlers.end() )
1007 : : {
1008 : : DBG_ASSERT( aHandler->get(), "OPropertyBrowserController::doInspection: invalid handler!" );
1009 : :
1010 : 0 : StlSyntaxSequence< Property > aThisHandlersProperties = (*aHandler)->getSupportedProperties();
1011 : :
1012 : 0 : if ( aThisHandlersProperties.empty() )
1013 : : {
1014 : : // this handler doesn't know anything about the current inspectee -> ignore it
1015 : 0 : (*aHandler)->dispose();
1016 : 0 : aHandler = aPropertyHandlers.erase( aHandler );
1017 : 0 : continue;
1018 : : }
1019 : :
1020 : : // append these properties to our "all properties" array
1021 : 0 : aProperties.reserve( aProperties.size() + aThisHandlersProperties.size() );
1022 : 0 : for ( StlSyntaxSequence< Property >::const_iterator copyProperty = aThisHandlersProperties.begin();
1023 : 0 : copyProperty != aThisHandlersProperties.end();
1024 : : ++copyProperty
1025 : : )
1026 : : {
1027 : : ::std::vector< Property >::const_iterator previous = ::std::find_if(
1028 : : aProperties.begin(),
1029 : : aProperties.end(),
1030 : : FindPropertyByName( copyProperty->Name )
1031 : 0 : );
1032 : 0 : if ( previous == aProperties.end() )
1033 : : {
1034 : 0 : aProperties.push_back( *copyProperty );
1035 : 0 : continue;
1036 : : }
1037 : :
1038 : : // there already was another (previous) handler which supported this property.
1039 : : // Don't add it to aProperties, again.
1040 : :
1041 : : // Also, ensure that handlers which previously expressed interest in *changes*
1042 : : // of this property are not notified.
1043 : : // This is 'cause we have a new handler which is responsible for this property,
1044 : : // which means it can give it a completely different meaning than the previous
1045 : : // handler for this property is prepared for.
1046 : : ::std::pair< PropertyHandlerMultiRepository::iterator, PropertyHandlerMultiRepository::iterator >
1047 : 0 : aDepHandlers = m_aDependencyHandlers.equal_range( copyProperty->Name );
1048 : 0 : m_aDependencyHandlers.erase( aDepHandlers.first, aDepHandlers.second );
1049 : : }
1050 : :
1051 : : // determine the superseded properties
1052 : 0 : StlSyntaxSequence< ::rtl::OUString > aSupersededByThisHandler = (*aHandler)->getSupersededProperties();
1053 : 0 : for ( StlSyntaxSequence< ::rtl::OUString >::const_iterator superseded = aSupersededByThisHandler.begin();
1054 : 0 : superseded != aSupersededByThisHandler.end();
1055 : : ++superseded
1056 : : )
1057 : : {
1058 : : ::std::vector< Property >::iterator existent = ::std::find_if(
1059 : : aProperties.begin(),
1060 : : aProperties.end(),
1061 : : FindPropertyByName( *superseded )
1062 : 0 : );
1063 : 0 : if ( existent != aProperties.end() )
1064 : : // one of the properties superseded by this handler was supported by a previous
1065 : : // one -> erase
1066 : 0 : aProperties.erase( existent );
1067 : : }
1068 : :
1069 : : // be notified of changes which this handler is responsible for
1070 : 0 : (*aHandler)->addPropertyChangeListener( this );
1071 : :
1072 : : // remember this handler for every of the properties which it is responsible
1073 : : // for
1074 : 0 : for ( StlSyntaxSequence< Property >::const_iterator remember = aThisHandlersProperties.begin();
1075 : 0 : remember != aThisHandlersProperties.end();
1076 : : ++remember
1077 : : )
1078 : : {
1079 : 0 : m_aPropertyHandlers[ remember->Name ] = *aHandler;
1080 : : // note that this implies that if two handlers support the same property,
1081 : : // the latter wins
1082 : : }
1083 : :
1084 : : // see if the handler expresses interest in any actuating properties
1085 : 0 : StlSyntaxSequence< ::rtl::OUString > aInterestingActuations = (*aHandler)->getActuatingProperties();
1086 : 0 : for ( StlSyntaxSequence< ::rtl::OUString >::const_iterator aLoop = aInterestingActuations.begin();
1087 : 0 : aLoop != aInterestingActuations.end();
1088 : : ++aLoop
1089 : : )
1090 : : {
1091 : : m_aDependencyHandlers.insert( PropertyHandlerMultiRepository::value_type(
1092 : 0 : *aLoop, *aHandler ) );
1093 : : }
1094 : :
1095 : 0 : ++aHandler;
1096 : 0 : }
1097 : :
1098 : : // create a new composer for UI requests coming from the handlers
1099 : 0 : m_pUIRequestComposer.reset( new ComposedPropertyUIUpdate( getInspectorUI(), this ) );
1100 : :
1101 : : // sort the properties by relative position, as indicated by the model
1102 : 0 : for ( ::std::vector< Property >::const_iterator sourceProps = aProperties.begin();
1103 : 0 : sourceProps != aProperties.end();
1104 : : ++sourceProps
1105 : : )
1106 : : {
1107 : 0 : sal_Int32 nRelativePropertyOrder = sourceProps - aProperties.begin();
1108 : 0 : if ( m_xModel.is() )
1109 : 0 : nRelativePropertyOrder = m_xModel->getPropertyOrderIndex( sourceProps->Name );
1110 : 0 : while ( m_aProperties.find( nRelativePropertyOrder ) != m_aProperties.end() )
1111 : 0 : ++nRelativePropertyOrder;
1112 : 0 : m_aProperties[ nRelativePropertyOrder ] = *sourceProps;
1113 : : }
1114 : :
1115 : : // be notified when one of our inspectees dies
1116 : 0 : impl_toggleInspecteeListening_nothrow( true );
1117 : : }
1118 : 0 : catch(const Exception&)
1119 : : {
1120 : : OSL_FAIL("OPropertyBrowserController::doInspection : caught an exception !");
1121 : : }
1122 : 0 : }
1123 : :
1124 : : //------------------------------------------------------------------------
1125 : 0 : ::com::sun::star::awt::Size SAL_CALL OPropertyBrowserController::getMinimumSize() throw (::com::sun::star::uno::RuntimeException)
1126 : : {
1127 : 0 : ::com::sun::star::awt::Size aSize;
1128 : 0 : if( m_pView )
1129 : 0 : return m_pView->getMinimumSize();
1130 : : else
1131 : 0 : return aSize;
1132 : : }
1133 : :
1134 : : //------------------------------------------------------------------------
1135 : 0 : ::com::sun::star::awt::Size SAL_CALL OPropertyBrowserController::getPreferredSize() throw (::com::sun::star::uno::RuntimeException)
1136 : : {
1137 : 0 : return getMinimumSize();
1138 : : }
1139 : :
1140 : : //------------------------------------------------------------------------
1141 : 0 : ::com::sun::star::awt::Size SAL_CALL OPropertyBrowserController::calcAdjustedSize( const ::com::sun::star::awt::Size& _rNewSize ) throw (::com::sun::star::uno::RuntimeException)
1142 : : {
1143 : 0 : awt::Size aMinSize = getMinimumSize( );
1144 : 0 : awt::Size aAdjustedSize( _rNewSize );
1145 : 0 : if ( aAdjustedSize.Width < aMinSize.Width )
1146 : 0 : aAdjustedSize.Width = aMinSize.Width;
1147 : 0 : if ( aAdjustedSize.Height < aMinSize.Height )
1148 : 0 : aAdjustedSize.Height = aMinSize.Height;
1149 : 0 : return aAdjustedSize;
1150 : : }
1151 : :
1152 : : //------------------------------------------------------------------------
1153 : 0 : void OPropertyBrowserController::describePropertyLine( const Property& _rProperty, OLineDescriptor& _rDescriptor ) SAL_THROW((Exception))
1154 : : {
1155 : : try
1156 : : {
1157 : 0 : PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.find( _rProperty.Name );
1158 : 0 : if ( handler == m_aPropertyHandlers.end() )
1159 : 0 : throw RuntimeException(); // caught below
1160 : :
1161 : 0 : _rDescriptor.assignFrom( handler->second->describePropertyLine( _rProperty.Name, this ) );
1162 : :
1163 : : //////////////////////////////////////////////////////////////////////
1164 : :
1165 : 0 : _rDescriptor.xPropertyHandler = handler->second;
1166 : 0 : _rDescriptor.sName = _rProperty.Name;
1167 : 0 : _rDescriptor.aValue = _rDescriptor.xPropertyHandler->getPropertyValue( _rProperty.Name );
1168 : :
1169 : 0 : if ( _rDescriptor.DisplayName.isEmpty() )
1170 : : {
1171 : : #ifdef DBG_UTIL
1172 : : ::rtl::OString sMessage( "OPropertyBrowserController::describePropertyLine: handler did not provide a display name for '" );
1173 : : sMessage += ::rtl::OString( _rProperty.Name.getStr(), _rProperty.Name.getLength(), RTL_TEXTENCODING_ASCII_US );
1174 : : sMessage += ::rtl::OString( "'!" );
1175 : : DBG_ASSERT( !_rDescriptor.DisplayName.isEmpty(), sMessage.getStr() );
1176 : : #endif
1177 : 0 : _rDescriptor.DisplayName = _rProperty.Name;
1178 : : }
1179 : :
1180 : 0 : PropertyState ePropertyState( _rDescriptor.xPropertyHandler->getPropertyState( _rProperty.Name ) );
1181 : 0 : if ( PropertyState_AMBIGUOUS_VALUE == ePropertyState )
1182 : : {
1183 : 0 : _rDescriptor.bUnknownValue = true;
1184 : 0 : _rDescriptor.aValue.clear();
1185 : : }
1186 : :
1187 : 0 : _rDescriptor.bReadOnly = impl_isReadOnlyModel_throw();
1188 : : }
1189 : 0 : catch( const Exception& )
1190 : : {
1191 : : OSL_FAIL( "OPropertyBrowserController::describePropertyLine: caught an exception!" );
1192 : : }
1193 : 0 : }
1194 : :
1195 : : //------------------------------------------------------------------------
1196 : 0 : void OPropertyBrowserController::impl_buildCategories_throw()
1197 : : {
1198 : : OSL_PRECOND( m_aPageIds.empty(), "OPropertyBrowserController::impl_buildCategories_throw: duplicate call!" );
1199 : :
1200 : 0 : StlSyntaxSequence< PropertyCategoryDescriptor > aCategories;
1201 : 0 : if ( m_xModel.is() )
1202 : 0 : aCategories = m_xModel->describeCategories();
1203 : :
1204 : 0 : for ( StlSyntaxSequence< PropertyCategoryDescriptor >::const_iterator category = aCategories.begin();
1205 : 0 : category != aCategories.end();
1206 : : ++category
1207 : : )
1208 : : {
1209 : : OSL_ENSURE( m_aPageIds.find( category->ProgrammaticName ) == m_aPageIds.end(),
1210 : : "OPropertyBrowserController::impl_buildCategories_throw: duplicate programmatic name!" );
1211 : :
1212 : 0 : m_aPageIds[ category->ProgrammaticName ] =
1213 : 0 : getPropertyBox().AppendPage( category->UIName, HelpIdUrl::getHelpId( category->HelpURL ) );
1214 : 0 : }
1215 : 0 : }
1216 : :
1217 : : //------------------------------------------------------------------------
1218 : 0 : void OPropertyBrowserController::UpdateUI()
1219 : : {
1220 : : try
1221 : : {
1222 : 0 : if ( !haveView() )
1223 : : // too early, will return later
1224 : 0 : return;
1225 : :
1226 : 0 : getPropertyBox().DisableUpdate();
1227 : :
1228 : 0 : sal_Bool bHaveFocus = getPropertyBox().HasChildPathFocus();
1229 : :
1230 : : // create our tab pages
1231 : 0 : impl_buildCategories_throw();
1232 : : // (and allow for pages to be actually unused)
1233 : 0 : ::std::set< sal_uInt16 > aUsedPages;
1234 : :
1235 : : // when building the UI below, remember which properties are actuating,
1236 : : // to allow for a initial actuatinPropertyChanged call
1237 : 0 : ::std::vector< ::rtl::OUString > aActuatingProperties;
1238 : 0 : ::std::vector< Any > aActuatingPropertyValues;
1239 : :
1240 : : // ask the handlers to describe the property UI, and insert the resulting
1241 : : // entries into our list boxes
1242 : 0 : OrderedPropertyMap::const_iterator property( m_aProperties.begin() );
1243 : 0 : for ( ; property != m_aProperties.end(); ++property )
1244 : : {
1245 : 0 : OLineDescriptor aDescriptor;
1246 : 0 : describePropertyLine( property->second, aDescriptor );
1247 : :
1248 : 0 : bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( property->second.Name );
1249 : :
1250 : : #if OSL_DEBUG_LEVEL > 0
1251 : : if ( aDescriptor.Category.isEmpty() )
1252 : : {
1253 : : ::rtl::OString sMessage( "OPropertyBrowserController::UpdateUI: empty category provided for property '" );
1254 : : sMessage += ::rtl::OString( property->second.Name.getStr(), property->second.Name.getLength(), osl_getThreadTextEncoding() );
1255 : : sMessage += "'!";
1256 : : OSL_FAIL( sMessage.getStr() );
1257 : : }
1258 : : #endif
1259 : : // finally insert this property control
1260 : 0 : sal_uInt16 nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category );
1261 : 0 : if ( nTargetPageId == (sal_uInt16)-1 )
1262 : : {
1263 : : // this category does not yet exist. This is allowed, as an inspector model might be lazy, and not provide
1264 : : // any category information of its own. In this case, we have a fallback ...
1265 : 0 : m_aPageIds[ aDescriptor.Category ] =
1266 : 0 : getPropertyBox().AppendPage( aDescriptor.Category, rtl::OString() );
1267 : 0 : nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category );
1268 : : }
1269 : :
1270 : 0 : getPropertyBox().InsertEntry( aDescriptor, nTargetPageId );
1271 : 0 : aUsedPages.insert( nTargetPageId );
1272 : :
1273 : : // if it's an actuating property, remember it
1274 : 0 : if ( bIsActuatingProperty )
1275 : : {
1276 : 0 : aActuatingProperties.push_back( property->second.Name );
1277 : 0 : aActuatingPropertyValues.push_back( impl_getPropertyValue_throw( property->second.Name ) );
1278 : : }
1279 : 0 : }
1280 : :
1281 : : // update any dependencies for the actuating properties which we encountered
1282 : : {
1283 : 0 : ::std::vector< ::rtl::OUString >::const_iterator aProperty = aActuatingProperties.begin();
1284 : 0 : ::std::vector< Any >::const_iterator aPropertyValue = aActuatingPropertyValues.begin();
1285 : 0 : for ( ; aProperty != aActuatingProperties.end(); ++aProperty, ++aPropertyValue )
1286 : 0 : impl_broadcastPropertyChange_nothrow( *aProperty, *aPropertyValue, *aPropertyValue, true );
1287 : : }
1288 : :
1289 : : // remove any unused pages (which we did not encounter properties for)
1290 : 0 : HashString2Int16 aSurvivingPageIds;
1291 : 0 : for ( HashString2Int16::iterator pageId = m_aPageIds.begin();
1292 : 0 : pageId != m_aPageIds.end();
1293 : : ++pageId
1294 : : )
1295 : : {
1296 : 0 : if ( aUsedPages.find( pageId->second ) == aUsedPages.end() )
1297 : 0 : getPropertyBox().RemovePage( pageId->second );
1298 : : else
1299 : 0 : aSurvivingPageIds.insert( *pageId );
1300 : : }
1301 : 0 : m_aPageIds.swap( aSurvivingPageIds );
1302 : :
1303 : :
1304 : 0 : getPropertyBox().Show();
1305 : 0 : getPropertyBox().EnableUpdate();
1306 : 0 : if ( bHaveFocus )
1307 : 0 : getPropertyBox().GrabFocus();
1308 : :
1309 : : // activate the first page
1310 : 0 : if ( !m_aPageIds.empty() )
1311 : : {
1312 : 0 : Sequence< PropertyCategoryDescriptor > aCategories( m_xModel->describeCategories() );
1313 : 0 : if ( aCategories.getLength() )
1314 : 0 : m_pView->activatePage( m_aPageIds[ aCategories[0].ProgrammaticName ] );
1315 : : else
1316 : : // allowed: if we default-created the pages ...
1317 : 0 : m_pView->activatePage( m_aPageIds.begin()->second );
1318 : : }
1319 : :
1320 : : // activate the previously active page (if possible)
1321 : 0 : if ( !m_sLastValidPageSelection.isEmpty() )
1322 : 0 : m_sPageSelection = m_sLastValidPageSelection;
1323 : 0 : selectPageFromViewData();
1324 : : }
1325 : 0 : catch( const Exception& )
1326 : : {
1327 : : DBG_UNHANDLED_EXCEPTION();
1328 : : }
1329 : : }
1330 : :
1331 : : //------------------------------------------------------------------------
1332 : 0 : void OPropertyBrowserController::Clicked( const ::rtl::OUString& _rName, sal_Bool _bPrimary )
1333 : : {
1334 : : try
1335 : : {
1336 : : // since the browse buttons do not get the focus when clicked with the mouse,
1337 : : // we need to commit the changes in the current property field
1338 : 0 : getPropertyBox().CommitModified();
1339 : :
1340 : 0 : PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.find( _rName );
1341 : : DBG_ASSERT( handler != m_aPropertyHandlers.end(), "OPropertyBrowserController::Clicked: a property without handler? This will crash!" );
1342 : :
1343 : 0 : ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer );
1344 : :
1345 : 0 : Any aData;
1346 : 0 : m_xInteractiveHandler = handler->second;
1347 : : InteractiveSelectionResult eResult =
1348 : 0 : handler->second->onInteractivePropertySelection( _rName, _bPrimary, aData,
1349 : 0 : m_pUIRequestComposer->getUIForPropertyHandler( handler->second ) );
1350 : :
1351 : 0 : switch ( eResult )
1352 : : {
1353 : : case InteractiveSelectionResult_Cancelled:
1354 : : case InteractiveSelectionResult_Success:
1355 : : // okay, nothing to do
1356 : 0 : break;
1357 : : case InteractiveSelectionResult_ObtainedValue:
1358 : 0 : handler->second->setPropertyValue( _rName, aData );
1359 : 0 : break;
1360 : : case InteractiveSelectionResult_Pending:
1361 : : // also okay, we expect that the handler has disabled the UI as necessary
1362 : 0 : break;
1363 : : default:
1364 : : OSL_FAIL( "OPropertyBrowserController::Clicked: unknown result value!" );
1365 : 0 : break;
1366 : 0 : }
1367 : : }
1368 : 0 : catch (const Exception&)
1369 : : {
1370 : : DBG_UNHANDLED_EXCEPTION();
1371 : : }
1372 : 0 : m_xInteractiveHandler = NULL;
1373 : 0 : }
1374 : :
1375 : : //------------------------------------------------------------------------
1376 : 0 : sal_Bool SAL_CALL OPropertyBrowserController::hasPropertyByName( const ::rtl::OUString& _rName ) throw (RuntimeException)
1377 : : {
1378 : 0 : for ( OrderedPropertyMap::const_iterator search = m_aProperties.begin();
1379 : 0 : search != m_aProperties.end();
1380 : : ++search
1381 : : )
1382 : 0 : if ( search->second.Name == _rName )
1383 : 0 : return true;
1384 : 0 : return false;
1385 : : }
1386 : :
1387 : : //------------------------------------------------------------------------
1388 : 0 : void OPropertyBrowserController::Commit( const ::rtl::OUString& rName, const Any& _rValue )
1389 : : {
1390 : : try
1391 : : {
1392 : 0 : rtl::OUString sPlcHolder = String( PcrRes( RID_EMBED_IMAGE_PLACEHOLDER ) );
1393 : 0 : bool bIsPlaceHolderValue = false;
1394 : :
1395 : 0 : if ( rName.equals( PROPERTY_IMAGE_URL ) )
1396 : : {
1397 : : // if the prop value is the PlaceHolder
1398 : : // can ignore it
1399 : 0 : rtl::OUString sVal;
1400 : 0 : _rValue >>= sVal;
1401 : 0 : if ( sVal.equals( sPlcHolder ) )
1402 : 0 : bIsPlaceHolderValue = true;
1403 : : }
1404 : 0 : m_sCommittingProperty = rName;
1405 : :
1406 : 0 : bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( rName );
1407 : :
1408 : 0 : Any aOldValue;
1409 : 0 : if ( bIsActuatingProperty )
1410 : 0 : aOldValue = impl_getPropertyValue_throw( rName );
1411 : :
1412 : : // do we have a dedicated handler for this property, which we can delegate some tasks to?
1413 : 0 : PropertyHandlerRef handler = impl_getHandlerForProperty_throw( rName );
1414 : :
1415 : : //////////////////////////////////////////////////////////////////////
1416 : : // set the value ( only if it's not a placeholder )
1417 : 0 : if ( !bIsPlaceHolderValue )
1418 : 0 : handler->setPropertyValue( rName, _rValue );
1419 : :
1420 : : //////////////////////////////////////////////////////////////////////
1421 : : // re-retrieve the value
1422 : 0 : Any aNormalizedValue = handler->getPropertyValue( rName );
1423 : :
1424 : : // care for any inter-property dependencies
1425 : 0 : if ( bIsActuatingProperty )
1426 : 0 : impl_broadcastPropertyChange_nothrow( rName, aNormalizedValue, aOldValue, false );
1427 : :
1428 : : // and display it again. This ensures proper formatting
1429 : 0 : getPropertyBox().SetPropertyValue( rName, aNormalizedValue, false );
1430 : : }
1431 : 0 : catch(const PropertyVetoException& eVetoException)
1432 : : {
1433 : 0 : InfoBox(m_pView, eVetoException.Message).Execute();
1434 : 0 : PropertyHandlerRef handler = impl_getHandlerForProperty_throw( rName );
1435 : 0 : Any aNormalizedValue = handler->getPropertyValue( rName );
1436 : 0 : getPropertyBox().SetPropertyValue( rName, aNormalizedValue, false );
1437 : : }
1438 : 0 : catch(const Exception&)
1439 : : {
1440 : : OSL_FAIL("OPropertyBrowserController::Commit : caught an exception !");
1441 : : }
1442 : :
1443 : 0 : m_sCommittingProperty = ::rtl::OUString();
1444 : 0 : }
1445 : :
1446 : : //--------------------------------------------------------------------
1447 : : namespace
1448 : : {
1449 : : }
1450 : :
1451 : : //--------------------------------------------------------------------
1452 : 0 : void OPropertyBrowserController::focusGained( const Reference< XPropertyControl >& _Control )
1453 : : {
1454 : 0 : m_aControlObservers.notifyEach( &XPropertyControlObserver::focusGained, _Control );
1455 : 0 : }
1456 : :
1457 : : //--------------------------------------------------------------------
1458 : 0 : void OPropertyBrowserController::valueChanged( const Reference< XPropertyControl >& _Control )
1459 : : {
1460 : 0 : m_aControlObservers.notifyEach( &XPropertyControlObserver::valueChanged, _Control );
1461 : 0 : }
1462 : :
1463 : : //------------------------------------------------------------------------
1464 : : namespace
1465 : : {
1466 : 0 : Reference< XPropertyHandler > lcl_createHandler( const ComponentContext& _rContext, const Any& _rFactoryDescriptor )
1467 : : {
1468 : 0 : Reference< XPropertyHandler > xHandler;
1469 : :
1470 : 0 : ::rtl::OUString sServiceName;
1471 : 0 : Reference< XSingleServiceFactory > xServiceFac;
1472 : 0 : Reference< XSingleComponentFactory > xComponentFac;
1473 : :
1474 : 0 : if ( _rFactoryDescriptor >>= sServiceName )
1475 : 0 : _rContext.createComponent( sServiceName, xHandler );
1476 : 0 : else if ( _rFactoryDescriptor >>= xServiceFac )
1477 : 0 : xHandler = xHandler.query( xServiceFac->createInstance() );
1478 : 0 : else if ( _rFactoryDescriptor >>= xComponentFac )
1479 : 0 : xHandler = xHandler.query( xComponentFac->createInstanceWithContext( _rContext.getUNOContext() ) );
1480 : : OSL_ENSURE(xHandler.is(),"lcl_createHandler: Can not create handler");
1481 : 0 : return xHandler;
1482 : : }
1483 : : }
1484 : :
1485 : : //------------------------------------------------------------------------
1486 : 0 : void OPropertyBrowserController::getPropertyHandlers( const InterfaceArray& _rObjects, PropertyHandlerArray& _rHandlers )
1487 : : {
1488 : 0 : _rHandlers.resize( 0 );
1489 : 0 : if ( _rObjects.empty() )
1490 : 0 : return;
1491 : :
1492 : : // create a component context for the handlers, containing some information about where
1493 : : // they live
1494 : 0 : Reference< XComponentContext > xHandlerContext( m_aContext.getUNOContext() );
1495 : :
1496 : : // if our own creator did not pass a dialog parent window, use our own view for this
1497 : 0 : Reference< XWindow > xParentWindow( m_aContext.getContextValueByAsciiName( "DialogParentWindow" ), UNO_QUERY );
1498 : 0 : if ( !xParentWindow.is() )
1499 : : {
1500 : : ::cppu::ContextEntry_Init aHandlerContextInfo[] =
1501 : : {
1502 : : ::cppu::ContextEntry_Init( ::rtl::OUString( "DialogParentWindow" ), makeAny( VCLUnoHelper::GetInterface( m_pView ) ) )
1503 : 0 : };
1504 : : xHandlerContext = ::cppu::createComponentContext(
1505 : : aHandlerContextInfo, SAL_N_ELEMENTS( aHandlerContextInfo ),
1506 : 0 : m_aContext.getUNOContext() );
1507 : : }
1508 : :
1509 : 0 : Sequence< Any > aHandlerFactories;
1510 : 0 : if ( m_xModel.is() )
1511 : 0 : aHandlerFactories = m_xModel->getHandlerFactories();
1512 : :
1513 : 0 : const Any* pHandlerFactory = aHandlerFactories.getConstArray();
1514 : 0 : const Any* pHandlerFactoryEnd = aHandlerFactories.getConstArray() + aHandlerFactories.getLength();
1515 : :
1516 : 0 : while ( pHandlerFactory != pHandlerFactoryEnd )
1517 : : {
1518 : 0 : if ( _rObjects.size() == 1 )
1519 : : { // we're inspecting only one object -> one handler
1520 : 0 : Reference< XPropertyHandler > xHandler( lcl_createHandler( m_aContext, *pHandlerFactory ) );
1521 : 0 : if ( xHandler.is() )
1522 : : {
1523 : 0 : xHandler->inspect( _rObjects[0] );
1524 : 0 : _rHandlers.push_back( xHandler );
1525 : 0 : }
1526 : : }
1527 : : else
1528 : : {
1529 : : // create a single handler for every single object
1530 : 0 : ::std::vector< Reference< XPropertyHandler > > aSingleHandlers( _rObjects.size() );
1531 : 0 : ::std::vector< Reference< XPropertyHandler > >::iterator pHandler = aSingleHandlers.begin();
1532 : :
1533 : 0 : InterfaceArray::const_iterator pObject = _rObjects.begin();
1534 : 0 : InterfaceArray::const_iterator pObjectEnd = _rObjects.end();
1535 : :
1536 : 0 : for ( ; pObject != pObjectEnd; ++pObject )
1537 : : {
1538 : 0 : *pHandler = lcl_createHandler( m_aContext, *pHandlerFactory );
1539 : 0 : if ( pHandler->is() )
1540 : : {
1541 : 0 : (*pHandler)->inspect( *pObject );
1542 : 0 : ++pHandler;
1543 : : }
1544 : : }
1545 : 0 : aSingleHandlers.resize( pHandler - aSingleHandlers.begin() );
1546 : :
1547 : : // then create a handler which composes information out of those single handlers
1548 : 0 : if ( !aSingleHandlers.empty() )
1549 : 0 : _rHandlers.push_back( new PropertyComposer( aSingleHandlers ) );
1550 : : }
1551 : :
1552 : 0 : ++pHandlerFactory;
1553 : 0 : }
1554 : :
1555 : : // note that the handlers will not be used by our caller, if they indicate that there are no
1556 : : // properties they feel responsible for
1557 : : }
1558 : :
1559 : : //------------------------------------------------------------------------
1560 : 0 : bool OPropertyBrowserController::impl_findObjectProperty_nothrow( const ::rtl::OUString& _rName, OrderedPropertyMap::const_iterator* _pProperty )
1561 : : {
1562 : 0 : OrderedPropertyMap::const_iterator search = m_aProperties.begin();
1563 : 0 : for ( ; search != m_aProperties.end(); ++search )
1564 : 0 : if ( search->second.Name == _rName )
1565 : 0 : break;
1566 : 0 : if ( _pProperty )
1567 : 0 : *_pProperty = search;
1568 : 0 : return ( search != m_aProperties.end() );
1569 : : }
1570 : :
1571 : : //------------------------------------------------------------------------
1572 : 0 : void OPropertyBrowserController::rebuildPropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
1573 : : {
1574 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
1575 : 0 : if ( !haveView() )
1576 : 0 : throw RuntimeException();
1577 : :
1578 : 0 : OrderedPropertyMap::const_iterator propertyPos;
1579 : 0 : if ( !impl_findObjectProperty_nothrow( _rPropertyName, &propertyPos ) )
1580 : 0 : return;
1581 : :
1582 : 0 : OLineDescriptor aDescriptor;
1583 : : try
1584 : : {
1585 : 0 : describePropertyLine( propertyPos->second, aDescriptor );
1586 : : }
1587 : 0 : catch( const Exception& )
1588 : : {
1589 : : OSL_FAIL( "OPropertyBrowserController::rebuildPropertyUI: caught an exception!" );
1590 : : }
1591 : :
1592 : 0 : getPropertyBox().ChangeEntry( aDescriptor );
1593 : : }
1594 : :
1595 : : //------------------------------------------------------------------------
1596 : 0 : void OPropertyBrowserController::enablePropertyUI( const ::rtl::OUString& _rPropertyName, sal_Bool _bEnable ) throw (RuntimeException)
1597 : : {
1598 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
1599 : 0 : if ( !haveView() )
1600 : 0 : throw RuntimeException();
1601 : :
1602 : 0 : if ( !impl_findObjectProperty_nothrow( _rPropertyName ) )
1603 : 0 : return;
1604 : :
1605 : 0 : getPropertyBox().EnablePropertyLine( _rPropertyName, _bEnable );
1606 : : }
1607 : :
1608 : : //------------------------------------------------------------------------
1609 : 0 : void OPropertyBrowserController::enablePropertyUIElements( const ::rtl::OUString& _rPropertyName, sal_Int16 _nElements, sal_Bool _bEnable ) throw (RuntimeException)
1610 : : {
1611 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
1612 : 0 : if ( !haveView() )
1613 : 0 : throw RuntimeException();
1614 : :
1615 : 0 : if ( !impl_findObjectProperty_nothrow( _rPropertyName ) )
1616 : 0 : return;
1617 : :
1618 : 0 : getPropertyBox().EnablePropertyControls( _rPropertyName, _nElements, _bEnable );
1619 : : }
1620 : :
1621 : : //------------------------------------------------------------------------
1622 : 0 : void OPropertyBrowserController::showPropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
1623 : : {
1624 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
1625 : 0 : if ( !haveView() )
1626 : 0 : throw RuntimeException();
1627 : :
1628 : : // look up the property in our object properties
1629 : 0 : OrderedPropertyMap::const_iterator propertyPos;
1630 : 0 : if ( !impl_findObjectProperty_nothrow( _rPropertyName, &propertyPos ) )
1631 : : return;
1632 : :
1633 : 0 : if ( getPropertyBox().GetPropertyPos( _rPropertyName ) != LISTBOX_ENTRY_NOTFOUND )
1634 : : {
1635 : 0 : rebuildPropertyUI( _rPropertyName );
1636 : : return;
1637 : : }
1638 : :
1639 : 0 : OLineDescriptor aDescriptor;
1640 : 0 : describePropertyLine( propertyPos->second, aDescriptor );
1641 : :
1642 : : // look for the position to insert the property
1643 : :
1644 : : // side note: The methods GetPropertyPos and InsertEntry of the OPropertyEditor work
1645 : : // only on the current page. This implies that it's impossible to use this method here
1646 : : // to show property lines which are *not* on the current page.
1647 : : // This is sufficient for now, but should be changed in the future.
1648 : :
1649 : : // by definition, the properties in m_aProperties are in the order in which they appear in the UI
1650 : : // So all we need is a predecessor of pProperty in m_aProperties
1651 : 0 : sal_uInt16 nUIPos = LISTBOX_ENTRY_NOTFOUND;
1652 : 0 : do
1653 : : {
1654 : 0 : if ( propertyPos != m_aProperties.begin() )
1655 : 0 : --propertyPos;
1656 : 0 : nUIPos = getPropertyBox().GetPropertyPos( propertyPos->second.Name );
1657 : : }
1658 : 0 : while ( ( nUIPos == LISTBOX_ENTRY_NOTFOUND ) && ( propertyPos != m_aProperties.begin() ) );
1659 : :
1660 : 0 : if ( nUIPos == LISTBOX_ENTRY_NOTFOUND )
1661 : : // insert at the very top
1662 : 0 : nUIPos = 0;
1663 : : else
1664 : : // insert right after the predecessor we found
1665 : 0 : ++nUIPos;
1666 : :
1667 : 0 : getPropertyBox().InsertEntry(
1668 : 0 : aDescriptor, impl_getPageIdForCategory_nothrow( aDescriptor.Category ), nUIPos );
1669 : : }
1670 : :
1671 : : //------------------------------------------------------------------------
1672 : 0 : void OPropertyBrowserController::hidePropertyUI( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
1673 : : {
1674 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
1675 : 0 : if ( !haveView() )
1676 : 0 : throw RuntimeException();
1677 : :
1678 : 0 : if ( !impl_findObjectProperty_nothrow( _rPropertyName ) )
1679 : 0 : return;
1680 : :
1681 : 0 : getPropertyBox().RemoveEntry( _rPropertyName );
1682 : : }
1683 : :
1684 : : //------------------------------------------------------------------------
1685 : 0 : void OPropertyBrowserController::showCategory( const ::rtl::OUString& _rCategory, sal_Bool _bShow ) throw (RuntimeException)
1686 : : {
1687 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
1688 : 0 : if ( !haveView() )
1689 : 0 : throw RuntimeException();
1690 : :
1691 : 0 : sal_uInt16 nPageId = impl_getPageIdForCategory_nothrow( _rCategory );
1692 : : OSL_ENSURE( nPageId != (sal_uInt16)-1, "OPropertyBrowserController::showCategory: invalid category!" );
1693 : :
1694 : 0 : getPropertyBox().ShowPropertyPage( nPageId, _bShow );
1695 : 0 : }
1696 : :
1697 : : //------------------------------------------------------------------------
1698 : 0 : Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::getPropertyControl( const ::rtl::OUString& _rPropertyName ) throw (RuntimeException)
1699 : : {
1700 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
1701 : 0 : if ( !haveView() )
1702 : 0 : throw RuntimeException();
1703 : :
1704 : 0 : Reference< XPropertyControl > xControl( getPropertyBox().GetPropertyControl( _rPropertyName ) );
1705 : 0 : return xControl;
1706 : : }
1707 : :
1708 : : //--------------------------------------------------------------------
1709 : 0 : void SAL_CALL OPropertyBrowserController::registerControlObserver( const Reference< XPropertyControlObserver >& _Observer ) throw (RuntimeException)
1710 : : {
1711 : 0 : m_aControlObservers.addInterface( _Observer );
1712 : 0 : }
1713 : :
1714 : : //--------------------------------------------------------------------
1715 : 0 : void SAL_CALL OPropertyBrowserController::revokeControlObserver( const Reference< XPropertyControlObserver >& _Observer ) throw (RuntimeException)
1716 : : {
1717 : 0 : m_aControlObservers.removeInterface( _Observer );
1718 : 0 : }
1719 : :
1720 : : //------------------------------------------------------------------------
1721 : 0 : void SAL_CALL OPropertyBrowserController::setHelpSectionText( const ::rtl::OUString& _rHelpText ) throw (NoSupportException, RuntimeException)
1722 : : {
1723 : 0 : SolarMutexGuard aSolarGuard;
1724 : 0 : ::osl::MutexGuard aGuard( m_aMutex );
1725 : :
1726 : 0 : if ( !haveView() )
1727 : 0 : throw DisposedException();
1728 : :
1729 : 0 : if ( !getPropertyBox().HasHelpSection() )
1730 : 0 : throw NoSupportException();
1731 : :
1732 : 0 : getPropertyBox().SetHelpText( _rHelpText );
1733 : 0 : }
1734 : :
1735 : : //------------------------------------------------------------------------
1736 : 0 : void OPropertyBrowserController::impl_broadcastPropertyChange_nothrow( const ::rtl::OUString& _rPropertyName, const Any& _rNewValue, const Any& _rOldValue, bool _bFirstTimeInit ) const
1737 : : {
1738 : : // are there one or more handlers which are interested in the actuation?
1739 : : ::std::pair< PropertyHandlerMultiRepository::const_iterator, PropertyHandlerMultiRepository::const_iterator > aInterestedHandlers =
1740 : 0 : m_aDependencyHandlers.equal_range( _rPropertyName );
1741 : 0 : if ( aInterestedHandlers.first == aInterestedHandlers.second )
1742 : : // none of our handlers is interested in this
1743 : 0 : return;
1744 : :
1745 : 0 : ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer );
1746 : : try
1747 : : {
1748 : : // collect the responses from all interested handlers
1749 : 0 : PropertyHandlerMultiRepository::const_iterator handler = aInterestedHandlers.first;
1750 : 0 : while ( handler != aInterestedHandlers.second )
1751 : : {
1752 : 0 : handler->second->actuatingPropertyChanged( _rPropertyName, _rNewValue, _rOldValue,
1753 : 0 : m_pUIRequestComposer->getUIForPropertyHandler( handler->second ),
1754 : 0 : _bFirstTimeInit );
1755 : 0 : ++handler;
1756 : : }
1757 : : }
1758 : 0 : catch( const Exception& )
1759 : : {
1760 : : DBG_UNHANDLED_EXCEPTION();
1761 : 0 : }
1762 : : }
1763 : :
1764 : : //............................................................................
1765 : : } // namespace pcr
1766 : : //............................................................................
1767 : :
1768 : :
1769 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|