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 : #include "clickableimage.hxx"
21 : #include "controlfeatureinterception.hxx"
22 : #include "urltransformer.hxx"
23 : #include "componenttools.hxx"
24 : #include <com/sun/star/form/XSubmit.hpp>
25 : #include <com/sun/star/awt/SystemPointer.hpp>
26 : #include <com/sun/star/form/FormComponentType.hpp>
27 : #include <com/sun/star/frame/XDispatch.hpp>
28 : #include <com/sun/star/frame/XDispatchProvider.hpp>
29 : #include <com/sun/star/frame/FrameSearchFlag.hpp>
30 : #include <com/sun/star/frame/XController.hpp>
31 : #include <com/sun/star/frame/XFrame.hpp>
32 : #include <com/sun/star/awt/ActionEvent.hpp>
33 : #include <com/sun/star/awt/XActionListener.hpp>
34 : #include <tools/urlobj.hxx>
35 : #include <tools/debug.hxx>
36 : #include <vcl/svapp.hxx>
37 : #include <sfx2/docfile.hxx>
38 : #include <sfx2/objsh.hxx>
39 : #include <osl/mutex.hxx>
40 : #include "services.hxx"
41 : #include <comphelper/container.hxx>
42 : #include <comphelper/listenernotification.hxx>
43 : #include <comphelper/processfactory.hxx>
44 : #include <svtools/imageresourceaccess.hxx>
45 : #define LOCAL_URL_PREFIX '#'
46 :
47 :
48 : namespace frm
49 : {
50 :
51 :
52 : using namespace ::com::sun::star::uno;
53 : using namespace ::com::sun::star::sdb;
54 : using namespace ::com::sun::star::sdbc;
55 : using namespace ::com::sun::star::sdbcx;
56 : using namespace ::com::sun::star::beans;
57 : using namespace ::com::sun::star::container;
58 : using namespace ::com::sun::star::form;
59 : using namespace ::com::sun::star::awt;
60 : using namespace ::com::sun::star::io;
61 : using namespace ::com::sun::star::lang;
62 : using namespace ::com::sun::star::util;
63 : using namespace ::com::sun::star::frame;
64 : using namespace ::com::sun::star::form::submission;
65 : using ::com::sun::star::awt::MouseEvent;
66 : using ::com::sun::star::task::XInteractionHandler;
67 :
68 :
69 : // OClickableImageBaseControl
70 :
71 :
72 62 : Sequence<Type> OClickableImageBaseControl::_getTypes()
73 : {
74 62 : static Sequence<Type> aTypes;
75 62 : if (!aTypes.getLength())
76 4 : aTypes = concatSequences(OControl::_getTypes(), OClickableImageBaseControl_BASE::getTypes());
77 62 : return aTypes;
78 : }
79 :
80 :
81 133 : OClickableImageBaseControl::OClickableImageBaseControl(const Reference<XComponentContext>& _rxFactory, const OUString& _aService)
82 : :OControl(_rxFactory, _aService)
83 : ,m_pThread(NULL)
84 : ,m_aSubmissionVetoListeners( m_aMutex )
85 : ,m_aApproveActionListeners( m_aMutex )
86 133 : ,m_aActionListeners( m_aMutex )
87 : {
88 133 : m_pFeatureInterception.reset( new ControlFeatureInterception( _rxFactory ) );
89 133 : }
90 :
91 :
92 250 : OClickableImageBaseControl::~OClickableImageBaseControl()
93 : {
94 125 : if (!OComponentHelper::rBHelper.bDisposed)
95 : {
96 0 : acquire();
97 0 : dispose();
98 : }
99 125 : }
100 :
101 : // UNO Binding
102 :
103 2610 : Any SAL_CALL OClickableImageBaseControl::queryAggregation(const Type& _rType) throw (RuntimeException, std::exception)
104 : {
105 2610 : Any aReturn = OControl::queryAggregation(_rType);
106 2610 : if (!aReturn.hasValue())
107 308 : aReturn = OClickableImageBaseControl_BASE::queryInterface(_rType);
108 2610 : return aReturn;
109 : }
110 :
111 : // XApproveActionBroadcaster
112 :
113 2 : void OClickableImageBaseControl::addApproveActionListener(
114 : const Reference<XApproveActionListener>& l) throw( RuntimeException, std::exception )
115 : {
116 2 : m_aApproveActionListeners.addInterface(l);
117 2 : }
118 :
119 :
120 2 : void OClickableImageBaseControl::removeApproveActionListener(
121 : const Reference<XApproveActionListener>& l) throw( RuntimeException, std::exception )
122 : {
123 2 : m_aApproveActionListeners.removeInterface(l);
124 2 : }
125 :
126 :
127 31 : void SAL_CALL OClickableImageBaseControl::registerDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) throw (RuntimeException, std::exception)
128 : {
129 31 : m_pFeatureInterception->registerDispatchProviderInterceptor( _rxInterceptor );
130 31 : }
131 :
132 :
133 31 : void SAL_CALL OClickableImageBaseControl::releaseDispatchProviderInterceptor( const Reference< XDispatchProviderInterceptor >& _rxInterceptor ) throw (RuntimeException, std::exception)
134 : {
135 31 : m_pFeatureInterception->releaseDispatchProviderInterceptor( _rxInterceptor );
136 31 : }
137 :
138 : // OComponentHelper
139 :
140 125 : void OClickableImageBaseControl::disposing()
141 : {
142 125 : EventObject aEvent( static_cast< XWeak* >( this ) );
143 125 : m_aApproveActionListeners.disposeAndClear( aEvent );
144 125 : m_aActionListeners.disposeAndClear( aEvent );
145 125 : m_aSubmissionVetoListeners.disposeAndClear( aEvent );
146 125 : m_pFeatureInterception->dispose();
147 :
148 : {
149 125 : ::osl::MutexGuard aGuard( m_aMutex );
150 125 : if( m_pThread )
151 : {
152 0 : m_pThread->release();
153 0 : m_pThread = NULL;
154 125 : }
155 : }
156 :
157 125 : OControl::disposing();
158 125 : }
159 :
160 :
161 0 : OImageProducerThread_Impl* OClickableImageBaseControl::getImageProducerThread()
162 : {
163 0 : if ( !m_pThread )
164 : {
165 0 : m_pThread = new OImageProducerThread_Impl( this );
166 0 : m_pThread->acquire();
167 0 : m_pThread->create();
168 : }
169 0 : return m_pThread;
170 : }
171 :
172 :
173 0 : bool OClickableImageBaseControl::approveAction( )
174 : {
175 0 : bool bCancelled = false;
176 0 : EventObject aEvent( static_cast< XWeak* >( this ) );
177 :
178 0 : ::cppu::OInterfaceIteratorHelper aIter( m_aApproveActionListeners );
179 0 : while( !bCancelled && aIter.hasMoreElements() )
180 : {
181 : // Every approveAction method must be thread-safe!
182 0 : if( !static_cast< XApproveActionListener* >( aIter.next() )->approveAction( aEvent ) )
183 0 : bCancelled = true;
184 : }
185 :
186 0 : return !bCancelled;
187 : }
188 :
189 :
190 : // This method is also called from a thread and thus must be thread-safe.
191 0 : void OClickableImageBaseControl::actionPerformed_Impl(bool bNotifyListener, const MouseEvent& rEvt)
192 : {
193 0 : if( bNotifyListener )
194 : {
195 0 : if ( !approveAction() )
196 0 : return;
197 : }
198 :
199 : // Whether the rest of the code is thread-safe, one can't tell. Therefore
200 : // we do most of the work on a locked solar mutex.
201 0 : Reference<XPropertySet> xSet;
202 0 : Reference< XInterface > xModelsParent;
203 0 : FormButtonType eButtonType = FormButtonType_PUSH;
204 : {
205 0 : SolarMutexGuard aGuard;
206 :
207 : // Get parent
208 0 : Reference<XFormComponent> xComp(getModel(), UNO_QUERY);
209 0 : if (!xComp.is())
210 0 : return;
211 :
212 0 : xModelsParent = xComp->getParent();
213 0 : if (!xModelsParent.is())
214 0 : return;
215 :
216 : // Which button type?
217 0 : xSet.set(xComp, css::uno::UNO_QUERY);
218 0 : if ( !xSet.is() )
219 0 : return;
220 0 : xSet->getPropertyValue(PROPERTY_BUTTONTYPE) >>= eButtonType;
221 : }
222 :
223 0 : switch (eButtonType)
224 : {
225 : case FormButtonType_RESET:
226 : {
227 : // Reset methods must be thread-safe!
228 0 : Reference<XReset> xReset(xModelsParent, UNO_QUERY);
229 0 : if (!xReset.is())
230 0 : return;
231 :
232 0 : xReset->reset();
233 : }
234 0 : break;
235 :
236 : case FormButtonType_SUBMIT:
237 : {
238 : // if some outer component can provide an interaction handler, use it
239 0 : Reference< XInteractionHandler > xHandler( m_pFeatureInterception->queryDispatch( "private:/InteractionHandler" ), UNO_QUERY );
240 : try
241 : {
242 0 : implSubmit( rEvt, xHandler );
243 : }
244 0 : catch( const Exception& )
245 : {
246 : // ignore
247 0 : }
248 : }
249 0 : break;
250 :
251 : case FormButtonType_URL:
252 : {
253 0 : SolarMutexGuard aGuard;
254 :
255 0 : Reference< XModel > xModel = getXModel(xModelsParent);
256 0 : if (!xModel.is())
257 0 : return;
258 :
259 :
260 : // Execute URL now
261 0 : Reference< XController > xController = xModel->getCurrentController();
262 0 : if (!xController.is())
263 0 : return;
264 :
265 0 : Reference< XFrame > xFrame = xController->getFrame();
266 0 : if( !xFrame.is() )
267 0 : return;
268 :
269 0 : URL aURL;
270 0 : aURL.Complete =
271 0 : getString(xSet->getPropertyValue(PROPERTY_TARGET_URL));
272 :
273 0 : if (!aURL.Complete.isEmpty() && (LOCAL_URL_PREFIX == aURL.Complete[0]))
274 : { // FIXME: The URL contains a local URL only. Since the URLTransformer does not handle this case correctly
275 : // (it can't: it does not know the document URL), we have to take care for this ourself.
276 : // The real solution would be to not allow such relative URLs (there is a rule that at runtime, all
277 : // URLs have to be absolute), but for compatibility reasons this is no option.
278 : // The more as the user does not want to see a local URL as "file://<path>/<document>#mark" if it
279 : // could be "#mark" as well.
280 : // If we someday say that this hack (yes, it's kind of a hack) is not sustainable anymore, the complete
281 : // solution would be:
282 : // * recognize URLs consisting of a mark only while _reading_ the document
283 : // * for this, allow the INetURLObject (which at the moment is invoked when reading URLs) to
284 : // transform such mark-only URLs into correct absolute URLs
285 : // * at the UI, show only the mark
286 : // * !!! recognize every SAVEAS on the document, so the absolute URL can be adjusted. This seems
287 : // rather impossible !!!
288 0 : aURL.Mark = aURL.Complete;
289 0 : aURL.Complete = xModel->getURL();
290 0 : aURL.Complete += aURL.Mark;
291 : }
292 :
293 0 : bool bDispatchUrlInternal = false;
294 0 : xSet->getPropertyValue(PROPERTY_DISPATCHURLINTERNAL) >>= bDispatchUrlInternal;
295 0 : if ( bDispatchUrlInternal )
296 : {
297 0 : m_pFeatureInterception->getTransformer().parseSmartWithAsciiProtocol( aURL, INET_FILE_SCHEME );
298 :
299 0 : OUString aTargetFrame;
300 0 : xSet->getPropertyValue(PROPERTY_TARGET_FRAME) >>= aTargetFrame;
301 :
302 0 : Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY)->queryDispatch( aURL, aTargetFrame,
303 : FrameSearchFlag::SELF | FrameSearchFlag::PARENT |
304 0 : FrameSearchFlag::SIBLINGS | FrameSearchFlag::CREATE );
305 :
306 0 : Sequence<PropertyValue> aArgs(1);
307 0 : PropertyValue& rProp = aArgs.getArray()[0];
308 0 : rProp.Name = "Referer";
309 0 : rProp.Value <<= xModel->getURL();
310 :
311 0 : if (xDisp.is())
312 0 : xDisp->dispatch( aURL, aArgs );
313 : }
314 : else
315 : {
316 0 : URL aHyperLink = m_pFeatureInterception->getTransformer().getStrictURLFromAscii( ".uno:OpenHyperlink" );
317 :
318 0 : Reference< XDispatch > xDisp = Reference< XDispatchProvider > (xFrame,UNO_QUERY)->queryDispatch(aHyperLink, OUString() , 0);
319 :
320 0 : if ( xDisp.is() )
321 : {
322 0 : Sequence<PropertyValue> aProps(3);
323 0 : aProps[0].Name = "URL";
324 0 : aProps[0].Value <<= aURL.Complete;
325 :
326 0 : aProps[1].Name = "FrameName";
327 0 : aProps[1].Value = xSet->getPropertyValue(PROPERTY_TARGET_FRAME);
328 :
329 0 : aProps[2].Name = "Referer";
330 0 : aProps[2].Value <<= xModel->getURL();
331 :
332 0 : xDisp->dispatch( aHyperLink, aProps );
333 0 : }
334 0 : }
335 0 : } break;
336 : default:
337 : {
338 : // notify the action listeners for a push button
339 0 : ActionEvent aEvt(static_cast<XWeak*>(this), m_aActionCommand);
340 0 : m_aActionListeners.notifyEach( &XActionListener::actionPerformed, aEvt );
341 : }
342 0 : }
343 : }
344 :
345 :
346 :
347 0 : void SAL_CALL OClickableImageBaseControl::addSubmissionVetoListener( const Reference< submission::XSubmissionVetoListener >& listener ) throw (NoSupportException, RuntimeException, std::exception)
348 : {
349 0 : m_aSubmissionVetoListeners.addInterface( listener );
350 0 : }
351 :
352 :
353 0 : void SAL_CALL OClickableImageBaseControl::removeSubmissionVetoListener( const Reference< submission::XSubmissionVetoListener >& listener ) throw (NoSupportException, RuntimeException, std::exception)
354 : {
355 0 : m_aSubmissionVetoListeners.removeInterface( listener );
356 0 : }
357 :
358 :
359 0 : void SAL_CALL OClickableImageBaseControl::submitWithInteraction( const Reference< XInteractionHandler >& _rxHandler ) throw (VetoException, WrappedTargetException, RuntimeException, std::exception)
360 : {
361 0 : implSubmit( MouseEvent(), _rxHandler );
362 0 : }
363 :
364 :
365 0 : void SAL_CALL OClickableImageBaseControl::submit( ) throw (VetoException, WrappedTargetException, RuntimeException, std::exception)
366 : {
367 0 : implSubmit( MouseEvent(), NULL );
368 0 : }
369 :
370 :
371 2 : Sequence< OUString > SAL_CALL OClickableImageBaseControl::getSupportedServiceNames( ) throw (RuntimeException, std::exception)
372 : {
373 2 : Sequence< OUString > aSupported = OControl::getSupportedServiceNames();
374 2 : aSupported.realloc( aSupported.getLength() + 1 );
375 :
376 2 : OUString* pArray = aSupported.getArray();
377 2 : pArray[ aSupported.getLength() - 1 ] = FRM_SUN_CONTROL_SUBMITBUTTON;
378 :
379 2 : return aSupported;
380 : }
381 :
382 :
383 0 : void OClickableImageBaseControl::implSubmit( const MouseEvent& _rEvent, const Reference< XInteractionHandler >& _rxHandler )
384 : {
385 : try
386 : {
387 : // allow the veto listeners to join the game
388 0 : m_aSubmissionVetoListeners.notifyEach( &XSubmissionVetoListener::submitting, EventObject( *this ) );
389 :
390 : // see whether there's an "submit interceptor" set at our model
391 0 : Reference< submission::XSubmissionSupplier > xSubmissionSupp( getModel(), UNO_QUERY );
392 0 : Reference< XSubmission > xSubmission;
393 0 : if ( xSubmissionSupp.is() )
394 0 : xSubmission = xSubmissionSupp->getSubmission();
395 :
396 0 : if ( xSubmission.is() )
397 : {
398 0 : if ( !_rxHandler.is() )
399 0 : xSubmission->submit();
400 : else
401 0 : xSubmission->submitWithInteraction( _rxHandler );
402 : }
403 : else
404 : {
405 : // no "interceptor" -> ordinary (old-way) submission
406 0 : Reference< XChild > xChild( getModel(), UNO_QUERY );
407 0 : Reference< XSubmit > xParentSubmission;
408 0 : if ( xChild.is() )
409 0 : xParentSubmission.set(xChild->getParent(), css::uno::UNO_QUERY);
410 0 : if ( xParentSubmission.is() )
411 0 : xParentSubmission->submit( this, _rEvent );
412 0 : }
413 : }
414 0 : catch( const VetoException& )
415 : {
416 : // allowed to leave
417 0 : throw;
418 : }
419 0 : catch( const RuntimeException& )
420 : {
421 : // allowed to leave
422 0 : throw;
423 : }
424 0 : catch( const WrappedTargetException& )
425 : {
426 : // allowed to leave
427 0 : throw;
428 : }
429 0 : catch( const Exception& e )
430 : {
431 : OSL_FAIL( "OClickableImageBaseControl::implSubmit: caught an unknown exception!" );
432 0 : throw WrappedTargetException( OUString(), *this, makeAny( e ) );
433 : }
434 0 : }
435 :
436 :
437 : // OClickableImageBaseModel
438 :
439 :
440 22 : Sequence<Type> OClickableImageBaseModel::_getTypes()
441 : {
442 : return concatSequences(
443 : OControlModel::_getTypes(),
444 : OClickableImageBaseModel_Base::getTypes()
445 22 : );
446 : }
447 :
448 :
449 :
450 66 : OClickableImageBaseModel::OClickableImageBaseModel( const Reference< XComponentContext >& _rxFactory, const OUString& _rUnoControlModelTypeName,
451 : const OUString& rDefault )
452 : :OControlModel( _rxFactory, _rUnoControlModelTypeName, rDefault )
453 : ,OPropertyChangeListener(m_aMutex)
454 : ,m_pMedium(NULL)
455 : ,m_pProducer( NULL )
456 : ,m_bDispatchUrlInternal(false)
457 : ,m_bDownloading(false)
458 66 : ,m_bProdStarted(false)
459 : {
460 66 : implConstruct();
461 66 : m_eButtonType = FormButtonType_PUSH;
462 66 : }
463 :
464 :
465 1 : OClickableImageBaseModel::OClickableImageBaseModel( const OClickableImageBaseModel* _pOriginal, const Reference<XComponentContext>& _rxFactory )
466 : :OControlModel( _pOriginal, _rxFactory )
467 : ,OPropertyChangeListener( m_aMutex )
468 : ,m_pMedium( NULL )
469 : ,m_pProducer( NULL )
470 : ,m_bDispatchUrlInternal(false)
471 : ,m_bDownloading( false )
472 1 : ,m_bProdStarted( false )
473 : {
474 1 : implConstruct();
475 :
476 : // copy properties
477 1 : m_eButtonType = _pOriginal->m_eButtonType;
478 1 : m_sTargetURL = _pOriginal->m_sTargetURL;
479 1 : m_sTargetFrame = _pOriginal->m_sTargetFrame;
480 1 : m_bDispatchUrlInternal = _pOriginal->m_bDispatchUrlInternal;
481 1 : }
482 :
483 :
484 1 : void OClickableImageBaseModel::implInitializeImageURL( )
485 : {
486 1 : osl_atomic_increment( &m_refCount );
487 : {
488 : // simulate a propertyChanged event for the ImageURL
489 1 : Any aImageURL;
490 1 : getFastPropertyValue( aImageURL, PROPERTY_ID_IMAGE_URL );
491 1 : _propertyChanged( PropertyChangeEvent( *this, PROPERTY_IMAGE_URL, sal_False, PROPERTY_ID_IMAGE_URL, Any( ), aImageURL ) );
492 : }
493 1 : osl_atomic_decrement( &m_refCount );
494 1 : }
495 :
496 :
497 67 : void OClickableImageBaseModel::implConstruct()
498 : {
499 67 : m_pProducer = new ImageProducer;
500 67 : osl_atomic_increment( &m_refCount );
501 : {
502 67 : m_xProducer = m_pProducer;
503 :
504 67 : if ( m_xAggregateSet.is() )
505 : {
506 67 : OPropertyChangeMultiplexer* pMultiplexer = new OPropertyChangeMultiplexer( this, m_xAggregateSet );
507 67 : pMultiplexer->addProperty( PROPERTY_IMAGE_URL );
508 : }
509 : }
510 67 : osl_atomic_decrement(&m_refCount);
511 67 : }
512 :
513 :
514 122 : OClickableImageBaseModel::~OClickableImageBaseModel()
515 : {
516 61 : if (!OComponentHelper::rBHelper.bDisposed)
517 : {
518 0 : acquire();
519 0 : dispose();
520 : }
521 : DBG_ASSERT(m_pMedium == NULL, "OClickableImageBaseModel::~OClickableImageBaseModel : leaving a memory leak ...");
522 : // This should be cleaned up at least in the dispose
523 :
524 61 : }
525 :
526 : // XImageProducer
527 :
528 0 : void SAL_CALL OClickableImageBaseModel::addConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException, std::exception)
529 : {
530 0 : ImageModelMethodGuard aGuard( *this );
531 0 : GetImageProducer()->addConsumer( _rxConsumer );
532 0 : }
533 :
534 :
535 0 : void SAL_CALL OClickableImageBaseModel::removeConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException, std::exception)
536 : {
537 0 : ImageModelMethodGuard aGuard( *this );
538 0 : GetImageProducer()->removeConsumer( _rxConsumer );
539 0 : }
540 :
541 :
542 0 : void SAL_CALL OClickableImageBaseModel::startProduction( ) throw (RuntimeException, std::exception)
543 : {
544 0 : ImageModelMethodGuard aGuard( *this );
545 0 : GetImageProducer()->startProduction();
546 0 : }
547 :
548 :
549 3 : Reference< submission::XSubmission > SAL_CALL OClickableImageBaseModel::getSubmission() throw (RuntimeException, std::exception)
550 : {
551 3 : return m_xSubmissionDelegate;
552 : }
553 :
554 :
555 1 : void SAL_CALL OClickableImageBaseModel::setSubmission( const Reference< submission::XSubmission >& _submission ) throw (RuntimeException, std::exception)
556 : {
557 1 : m_xSubmissionDelegate = _submission;
558 1 : }
559 :
560 :
561 7 : Sequence< OUString > SAL_CALL OClickableImageBaseModel::getSupportedServiceNames( ) throw (RuntimeException, std::exception)
562 : {
563 7 : Sequence< OUString > aSupported = OControlModel::getSupportedServiceNames();
564 7 : aSupported.realloc( aSupported.getLength() + 1 );
565 :
566 7 : OUString* pArray = aSupported.getArray();
567 7 : pArray[ aSupported.getLength() - 1 ] = FRM_SUN_COMPONENT_SUBMITBUTTON;
568 :
569 7 : return aSupported;
570 : }
571 :
572 : // OComponentHelper
573 :
574 61 : void OClickableImageBaseModel::disposing()
575 : {
576 61 : OControlModel::disposing();
577 61 : if (m_pMedium)
578 : {
579 0 : delete m_pMedium;
580 0 : m_pMedium = NULL;
581 : }
582 :
583 61 : m_xProducer = NULL;
584 61 : m_pProducer = NULL;
585 61 : }
586 :
587 :
588 12382 : Any SAL_CALL OClickableImageBaseModel::queryAggregation(const Type& _rType) throw (RuntimeException, std::exception)
589 : {
590 : // order matters:
591 : // we definitely want to "override" the XImageProducer interface of our aggregate,
592 : // thus check OClickableImageBaseModel_Base (which provides this) first
593 12382 : Any aReturn = OClickableImageBaseModel_Base::queryInterface( _rType );
594 :
595 : // BUT: _don't_ let it feel responsible for the XTypeProvider interface
596 : // (as this is implemented by our base class in the proper way)
597 24764 : if ( _rType.equals( cppu::UnoType<XTypeProvider>::get() )
598 12382 : || !aReturn.hasValue()
599 : )
600 9463 : aReturn = OControlModel::queryAggregation( _rType );
601 :
602 12382 : return aReturn;
603 : }
604 :
605 :
606 5028 : void OClickableImageBaseModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const
607 : {
608 5028 : switch (nHandle)
609 : {
610 220 : case PROPERTY_ID_BUTTONTYPE : rValue <<= m_eButtonType; break;
611 212 : case PROPERTY_ID_TARGET_URL : rValue <<= m_sTargetURL; break;
612 104 : case PROPERTY_ID_TARGET_FRAME : rValue <<= m_sTargetFrame; break;
613 102 : case PROPERTY_ID_DISPATCHURLINTERNAL : rValue <<= m_bDispatchUrlInternal; break;
614 : default:
615 4390 : OControlModel::getFastPropertyValue(rValue, nHandle);
616 : }
617 5028 : }
618 :
619 :
620 240 : void OClickableImageBaseModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) throw ( Exception, std::exception)
621 : {
622 240 : switch (nHandle)
623 : {
624 : case PROPERTY_ID_BUTTONTYPE :
625 : DBG_ASSERT(isA(rValue, static_cast<FormButtonType*>(NULL)), "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
626 10 : rValue >>= m_eButtonType;
627 10 : break;
628 :
629 : case PROPERTY_ID_TARGET_URL :
630 : DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_STRING, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
631 5 : rValue >>= m_sTargetURL;
632 5 : break;
633 :
634 : case PROPERTY_ID_TARGET_FRAME :
635 : DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_STRING, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
636 9 : rValue >>= m_sTargetFrame;
637 9 : break;
638 :
639 : case PROPERTY_ID_DISPATCHURLINTERNAL:
640 : DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, "OClickableImageBaseModel::setFastPropertyValue_NoBroadcast : invalid type !" );
641 8 : rValue >>= m_bDispatchUrlInternal;
642 8 : break;
643 :
644 : default:
645 208 : OControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue);
646 : }
647 240 : }
648 :
649 :
650 505 : sal_Bool OClickableImageBaseModel::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue)
651 : throw( IllegalArgumentException )
652 : {
653 505 : switch (nHandle)
654 : {
655 : case PROPERTY_ID_BUTTONTYPE :
656 31 : return tryPropertyValueEnum( rConvertedValue, rOldValue, rValue, m_eButtonType );
657 :
658 : case PROPERTY_ID_TARGET_URL :
659 42 : return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sTargetURL);
660 :
661 : case PROPERTY_ID_TARGET_FRAME :
662 46 : return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_sTargetFrame);
663 :
664 : case PROPERTY_ID_DISPATCHURLINTERNAL :
665 29 : return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bDispatchUrlInternal);
666 :
667 : default:
668 357 : return OControlModel::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue);
669 : }
670 : }
671 :
672 :
673 0 : void OClickableImageBaseModel::StartProduction()
674 : {
675 0 : ImageProducer *pImgProd = GetImageProducer();
676 : // grab the ImageURL
677 0 : OUString sURL;
678 0 : getPropertyValue("ImageURL") >>= sURL;
679 0 : if (!m_pMedium)
680 : {
681 0 : if ( ::svt::GraphicAccess::isSupportedURL( sURL ) )
682 0 : pImgProd->SetImage( sURL );
683 : else
684 : // caution: the medium may be NULL if somebody gave us an invalid URL to work with
685 0 : pImgProd->SetImage(OUString());
686 0 : m_bDownloading = false;
687 0 : return;
688 : }
689 0 : if (m_pMedium->GetErrorCode()==0)
690 : {
691 0 : SvStream* pStream = m_pMedium->GetInStream();
692 :
693 0 : pImgProd->SetImage(*pStream);
694 0 : pImgProd->startProduction();
695 0 : m_bProdStarted = true;
696 : }
697 : else
698 : {
699 0 : pImgProd->SetImage(OUString());
700 0 : delete m_pMedium;
701 0 : m_pMedium = 0;
702 0 : m_bDownloading = false;
703 0 : }
704 : }
705 :
706 :
707 5 : void OClickableImageBaseModel::SetURL( const OUString& rURL )
708 : {
709 5 : if (m_pMedium || rURL.isEmpty())
710 : {
711 : // Free the stream at the Producer, before the medium is deleted
712 1 : GetImageProducer()->SetImage(OUString());
713 1 : delete m_pMedium;
714 1 : m_pMedium = NULL;
715 : }
716 :
717 : // the SfxMedium is not allowed to be created with an invalid URL, so we have to check this first
718 5 : INetURLObject aUrl(rURL);
719 5 : if (INetProtocol::NotValid == aUrl.GetProtocol())
720 : // we treat an invalid URL like we would treat no URL
721 10 : return;
722 :
723 0 : if (!rURL.isEmpty() && !::svt::GraphicAccess::isSupportedURL( rURL ) )
724 : {
725 0 : if (m_pMedium)
726 0 : delete m_pMedium;
727 :
728 0 : m_pMedium = new SfxMedium(rURL, STREAM_STD_READ);
729 :
730 : // Find the XModel to get to the Object shell or at least the
731 : // Referer.
732 : // There's only a Model if we load HTML documents and the URL is
733 : // changed in a document that is already loaded. There's no way
734 : // we can get to the Model during loading.
735 0 : Reference< XModel > xModel;
736 0 : InterfaceRef xIfc( *this );
737 0 : while( !xModel.is() && xIfc.is() )
738 : {
739 0 : Reference<XChild> xChild( xIfc, UNO_QUERY );
740 0 : xIfc = xChild->getParent();
741 0 : xModel.set(xIfc, css::uno::UNO_QUERY);
742 0 : }
743 :
744 : // Search for the Object shell by iterating over all Object shells
745 : // and comparing their XModel to ourĀ“s.
746 : // As an optimization, we try the current Object shell first.
747 0 : SfxObjectShell *pObjSh = 0;
748 :
749 0 : if( xModel.is() )
750 : {
751 0 : SfxObjectShell *pTestObjSh = SfxObjectShell::Current();
752 0 : if( pTestObjSh )
753 : {
754 0 : Reference< XModel > xTestModel = pTestObjSh->GetModel();
755 0 : if( xTestModel == xModel )
756 0 : pObjSh = pTestObjSh;
757 : }
758 0 : if( !pObjSh )
759 : {
760 0 : pTestObjSh = SfxObjectShell::GetFirst();
761 0 : while( !pObjSh && pTestObjSh )
762 : {
763 0 : Reference< XModel > xTestModel = pTestObjSh->GetModel();
764 0 : if( xTestModel == xModel )
765 0 : pObjSh = pTestObjSh;
766 : else
767 0 : pTestObjSh = SfxObjectShell::GetNext( *pTestObjSh );
768 0 : }
769 : }
770 : }
771 :
772 : #ifdef USE_REGISTER_TRANSFER
773 : if( pObjSh )
774 : {
775 : // Transfer target frame, so that javascript: URLs
776 : // can also be "loaded"
777 : const SfxMedium *pShMedium = pObjSh->GetMedium();
778 : if( pShMedium )
779 : m_pMedium->SetLoadTargetFrame(pShMedium->GetLoadTargetFrame());
780 : }
781 : #else
782 0 : if( pObjSh )
783 : {
784 : // Transfer target frame, so that javascript: URLs
785 : // can also be "loaded"
786 0 : const SfxMedium *pShMedium = pObjSh->GetMedium();
787 0 : if( pShMedium )
788 0 : m_pMedium->SetLoadTargetFrame(pShMedium->GetLoadTargetFrame());
789 : }
790 : #endif
791 :
792 : // Set downloading flag to true. They will be Data Available Links,
793 : // if get to the pending staus.
794 0 : m_bDownloading = true;
795 0 : m_bProdStarted = false;
796 :
797 : // Kick off download (caution: can be synchronous).
798 0 : m_pMedium->Download(LINK(this, OClickableImageBaseModel, DownloadDoneLink));
799 : }
800 : else
801 : {
802 0 : if ( ::svt::GraphicAccess::isSupportedURL( rURL ) )
803 0 : GetImageProducer()->SetImage( rURL );
804 0 : GetImageProducer()->startProduction();
805 0 : }
806 : }
807 :
808 :
809 0 : void OClickableImageBaseModel::DataAvailable()
810 : {
811 0 : if (!m_bProdStarted)
812 0 : StartProduction();
813 :
814 0 : GetImageProducer()->NewDataAvailable();
815 0 : }
816 :
817 :
818 0 : void OClickableImageBaseModel::DownloadDone()
819 : {
820 0 : DataAvailable();
821 0 : m_bDownloading = false;
822 0 : }
823 :
824 :
825 0 : IMPL_LINK_NOARG( OClickableImageBaseModel, DownloadDoneLink )
826 : {
827 0 : ::osl::MutexGuard aGuard( m_aMutex );
828 0 : DownloadDone();
829 0 : return 0;
830 : }
831 :
832 :
833 5 : void OClickableImageBaseModel::_propertyChanged( const PropertyChangeEvent& rEvt )
834 : throw( RuntimeException )
835 : {
836 : // If a URL was set, it needs to be passed onto the ImageProducer.
837 5 : ::osl::MutexGuard aGuard(m_aMutex);
838 5 : SetURL( getString(rEvt.NewValue) );
839 5 : }
840 :
841 :
842 6 : Any OClickableImageBaseModel::getPropertyDefaultByHandle( sal_Int32 nHandle ) const
843 : {
844 6 : switch (nHandle)
845 : {
846 0 : case PROPERTY_ID_BUTTONTYPE : return makeAny( FormButtonType_PUSH );
847 : case PROPERTY_ID_TARGET_URL :
848 0 : case PROPERTY_ID_TARGET_FRAME : return makeAny( OUString() );
849 2 : case PROPERTY_ID_DISPATCHURLINTERNAL : return makeAny( sal_False );
850 : default:
851 4 : return OControlModel::getPropertyDefaultByHandle(nHandle);
852 : }
853 : }
854 :
855 :
856 : // OImageProducerThread_Impl
857 :
858 :
859 0 : EventObject* OImageProducerThread_Impl::cloneEvent( const EventObject* _pEvt ) const
860 : {
861 0 : return new EventObject( *_pEvt );
862 : }
863 :
864 :
865 0 : void OImageProducerThread_Impl::processEvent( ::cppu::OComponentHelper *pCompImpl,
866 : const EventObject* pEvt,
867 : const Reference<XControl>&,
868 : bool )
869 : {
870 0 : static_cast<OClickableImageBaseControl *>(pCompImpl)->actionPerformed_Impl( true, *static_cast<const MouseEvent *>(pEvt) );
871 0 : }
872 :
873 :
874 : } // namespace frm
875 :
876 :
877 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|