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 "ImageControl.hxx"
21 :
22 : #include "property.hrc"
23 : #include "frm_resource.hrc"
24 : #include "frm_resource.hxx"
25 : #include "services.hxx"
26 : #include "componenttools.hxx"
27 :
28 : #include <svtools/imageresourceaccess.hxx>
29 : #include <unotools/ucblockbytes.hxx>
30 : #include <sfx2/filedlghelper.hxx>
31 : #include <com/sun/star/awt/PopupMenu.hpp>
32 : #include <com/sun/star/awt/XPopupMenu.hpp>
33 : #include <com/sun/star/awt/PopupMenuDirection.hpp>
34 : #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
35 : #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
36 : #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
37 : #include <com/sun/star/ui/dialogs/XFilePicker.hpp>
38 : #include <com/sun/star/sdbc/DataType.hpp>
39 : #include <com/sun/star/awt/MouseButton.hpp>
40 : #include <com/sun/star/awt/XWindow.hpp>
41 : #include <com/sun/star/awt/XDialog.hpp>
42 : #include <com/sun/star/io/XActiveDataSink.hpp>
43 : #include <com/sun/star/io/NotConnectedException.hpp>
44 : #include <com/sun/star/beans/PropertyValue.hpp>
45 : #include <com/sun/star/graphic/XGraphic.hpp>
46 : #include <com/sun/star/graphic/GraphicObject.hpp>
47 : #include <tools/urlobj.hxx>
48 : #include <tools/stream.hxx>
49 : #include <tools/debug.hxx>
50 : #include <tools/diagnose_ex.h>
51 : #include <vcl/svapp.hxx>
52 : #include <unotools/streamhelper.hxx>
53 : #include <comphelper/extract.hxx>
54 : #include <comphelper/guarding.hxx>
55 : #include <unotools/ucbstreamhelper.hxx>
56 : #include <svl/urihelper.hxx>
57 :
58 : #include <memory>
59 :
60 : #define ID_OPEN_GRAPHICS 1
61 : #define ID_CLEAR_GRAPHICS 2
62 :
63 : //.........................................................................
64 : namespace frm
65 : {
66 : //.........................................................................
67 : using namespace ::com::sun::star;
68 : using namespace ::com::sun::star::uno;
69 : using namespace ::com::sun::star::sdb;
70 : using namespace ::com::sun::star::sdbc;
71 : using namespace ::com::sun::star::sdbcx;
72 : using namespace ::com::sun::star::beans;
73 : using namespace ::com::sun::star::container;
74 : using namespace ::com::sun::star::form;
75 : using namespace ::com::sun::star::awt;
76 : using namespace ::com::sun::star::io;
77 : using namespace ::com::sun::star::ui::dialogs;
78 : using namespace ::com::sun::star::lang;
79 : using namespace ::com::sun::star::util;
80 : using namespace ::com::sun::star::graphic;
81 : using namespace ::com::sun::star::frame;
82 :
83 : //==============================================================================
84 : //= OImageControlModel
85 : //==============================================================================
86 : namespace
87 : {
88 : enum ImageStoreType
89 : {
90 : ImageStoreBinary,
91 : ImageStoreLink,
92 :
93 : ImageStoreInvalid
94 : };
95 :
96 0 : ImageStoreType lcl_getImageStoreType( const sal_Int32 _nFieldType )
97 : {
98 : // binary/longvarchar types could be used to store images in binary representation
99 0 : if ( ( _nFieldType == DataType::BINARY )
100 : || ( _nFieldType == DataType::VARBINARY )
101 : || ( _nFieldType == DataType::LONGVARBINARY )
102 : || ( _nFieldType == DataType::OTHER )
103 : || ( _nFieldType == DataType::OBJECT )
104 : || ( _nFieldType == DataType::BLOB )
105 : || ( _nFieldType == DataType::LONGVARCHAR )
106 : || ( _nFieldType == DataType::CLOB )
107 : )
108 0 : return ImageStoreBinary;
109 :
110 : // char types could be used to store links to images
111 0 : if ( ( _nFieldType == DataType::CHAR )
112 : || ( _nFieldType == DataType::VARCHAR )
113 : )
114 0 : return ImageStoreLink;
115 :
116 0 : return ImageStoreInvalid;
117 : }
118 : }
119 :
120 : //==============================================================================
121 : // OImageControlModel
122 : //==============================================================================
123 :
124 : //------------------------------------------------------------------------------
125 0 : InterfaceRef SAL_CALL OImageControlModel_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
126 : {
127 0 : return *(new OImageControlModel(_rxFactory));
128 : }
129 :
130 : //------------------------------------------------------------------------------
131 0 : Sequence<Type> OImageControlModel::_getTypes()
132 : {
133 : return concatSequences(
134 : OBoundControlModel::_getTypes(),
135 : OImageControlModel_Base::getTypes()
136 0 : );
137 : }
138 :
139 : DBG_NAME(OImageControlModel)
140 : //------------------------------------------------------------------
141 0 : OImageControlModel::OImageControlModel(const Reference<XMultiServiceFactory>& _rxFactory)
142 : :OBoundControlModel( _rxFactory, VCL_CONTROLMODEL_IMAGECONTROL, FRM_SUN_CONTROL_IMAGECONTROL, sal_False, sal_False, sal_False )
143 : // use the old control name for compytibility reasons
144 : ,m_pImageProducer( NULL )
145 : ,m_bExternalGraphic( true )
146 : ,m_bReadOnly( sal_False )
147 : ,m_sImageURL()
148 0 : ,m_xGraphicObject()
149 : {
150 : DBG_CTOR( OImageControlModel, NULL );
151 0 : m_nClassId = FormComponentType::IMAGECONTROL;
152 0 : initOwnValueProperty( PROPERTY_IMAGE_URL );
153 :
154 0 : implConstruct();
155 0 : }
156 :
157 : //------------------------------------------------------------------
158 0 : OImageControlModel::OImageControlModel( const OImageControlModel* _pOriginal, const Reference< XMultiServiceFactory >& _rxFactory )
159 : :OBoundControlModel( _pOriginal, _rxFactory )
160 : // use the old control name for compytibility reasons
161 : ,m_pImageProducer( NULL )
162 : ,m_bExternalGraphic( true )
163 : ,m_bReadOnly( _pOriginal->m_bReadOnly )
164 : ,m_sImageURL( _pOriginal->m_sImageURL )
165 0 : ,m_xGraphicObject( _pOriginal->m_xGraphicObject )
166 : {
167 : DBG_CTOR( OImageControlModel, NULL );
168 0 : implConstruct();
169 :
170 0 : osl_atomic_increment( &m_refCount );
171 : {
172 : // simulate a propertyChanged event for the ImageURL
173 0 : ::osl::MutexGuard aGuard( m_aMutex );
174 0 : impl_handleNewImageURL_lck( eOther );
175 : }
176 0 : osl_atomic_decrement( &m_refCount );
177 0 : }
178 :
179 : //------------------------------------------------------------------
180 0 : void OImageControlModel::implConstruct()
181 : {
182 0 : m_pImageProducer = new ImageProducer;
183 0 : m_xImageProducer = m_pImageProducer;
184 0 : m_pImageProducer->SetDoneHdl( LINK( this, OImageControlModel, OnImageImportDone ) );
185 0 : }
186 :
187 : //------------------------------------------------------------------
188 0 : OImageControlModel::~OImageControlModel()
189 : {
190 0 : if (!OComponentHelper::rBHelper.bDisposed)
191 : {
192 0 : acquire();
193 0 : dispose();
194 : }
195 :
196 : DBG_DTOR(OImageControlModel,NULL);
197 0 : }
198 :
199 : // XCloneable
200 : //------------------------------------------------------------------------------
201 0 : IMPLEMENT_DEFAULT_CLONING( OImageControlModel )
202 :
203 : // XServiceInfo
204 : //------------------------------------------------------------------------------
205 0 : StringSequence OImageControlModel::getSupportedServiceNames() throw()
206 : {
207 0 : StringSequence aSupported = OBoundControlModel::getSupportedServiceNames();
208 0 : aSupported.realloc(aSupported.getLength() + 1);
209 :
210 0 : ::rtl::OUString*pArray = aSupported.getArray();
211 0 : pArray[aSupported.getLength()-1] = FRM_SUN_COMPONENT_IMAGECONTROL;
212 0 : return aSupported;
213 : }
214 :
215 : //------------------------------------------------------------------------------
216 0 : Any SAL_CALL OImageControlModel::queryAggregation(const Type& _rType) throw (RuntimeException)
217 : {
218 : // Order matters: we want to "override" the XImageProducer interface of the aggreate with out
219 : // own XImageProducer interface, thus we need to query OImageControlModel_Base first
220 0 : Any aReturn = OImageControlModel_Base::queryInterface( _rType );
221 :
222 : // BUT: _don't_ let it feel responsible for the XTypeProvider interface
223 : // (as this is implemented by our base class in the proper way)
224 0 : if ( _rType.equals( ::getCppuType( static_cast< Reference< XTypeProvider >* >( NULL ) ) )
225 0 : || !aReturn.hasValue()
226 : )
227 0 : aReturn = OBoundControlModel::queryAggregation( _rType );
228 :
229 0 : return aReturn;
230 : }
231 :
232 : //------------------------------------------------------------------------------
233 0 : sal_Bool OImageControlModel::approveDbColumnType( sal_Int32 _nColumnType )
234 : {
235 0 : return ImageStoreInvalid != lcl_getImageStoreType( _nColumnType );
236 : }
237 :
238 : //------------------------------------------------------------------------------
239 0 : void OImageControlModel::getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const
240 : {
241 0 : switch (nHandle)
242 : {
243 : case PROPERTY_ID_READONLY:
244 0 : rValue <<= (sal_Bool)m_bReadOnly;
245 0 : break;
246 : case PROPERTY_ID_IMAGE_URL:
247 0 : rValue <<= m_sImageURL;
248 0 : break;
249 : case PROPERTY_ID_GRAPHIC:
250 0 : rValue <<= m_xGraphicObject.is() ? m_xGraphicObject->getGraphic() : Reference< XGraphic >();
251 0 : break;
252 : default:
253 0 : OBoundControlModel::getFastPropertyValue(rValue, nHandle);
254 : }
255 0 : }
256 :
257 : //------------------------------------------------------------------------------
258 0 : void OImageControlModel::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle, const Any& rValue) throw ( ::com::sun::star::uno::Exception)
259 : {
260 0 : switch (nHandle)
261 : {
262 : case PROPERTY_ID_READONLY :
263 : DBG_ASSERT(rValue.getValueType().getTypeClass() == TypeClass_BOOLEAN, "OImageControlModel::setFastPropertyValue_NoBroadcast : invalid type !" );
264 0 : m_bReadOnly = getBOOL(rValue);
265 0 : break;
266 :
267 : case PROPERTY_ID_IMAGE_URL:
268 0 : OSL_VERIFY( rValue >>= m_sImageURL );
269 0 : impl_handleNewImageURL_lck( eOther );
270 : {
271 0 : ControlModelLock aLock( *this );
272 : // that's a fake ... onValuePropertyChange expects to receive the only lock to our instance,
273 : // but we're already called with our mutex locked ...
274 0 : onValuePropertyChange( aLock );
275 : }
276 0 : break;
277 :
278 : case PROPERTY_ID_GRAPHIC:
279 : {
280 0 : Reference< XGraphic > xGraphic;
281 0 : OSL_VERIFY( rValue >>= xGraphic );
282 0 : if ( !xGraphic.is() )
283 0 : m_xGraphicObject.clear();
284 : else
285 : {
286 0 : m_xGraphicObject = GraphicObject::create( m_aContext.getUNOContext() );
287 0 : m_xGraphicObject->setGraphic( xGraphic );
288 : }
289 :
290 0 : if ( m_bExternalGraphic )
291 : {
292 : // if that's an external graphic, i.e. one which has not been loaded by ourselves in response to a
293 : // new image URL, then also adjust our ImageURL.
294 0 : ::rtl::OUString sNewImageURL;
295 0 : if ( m_xGraphicObject.is() )
296 : {
297 0 : sNewImageURL = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.GraphicObject:" ) );
298 0 : sNewImageURL = sNewImageURL + m_xGraphicObject->getUniqueID();
299 : }
300 0 : m_sImageURL = sNewImageURL;
301 : // TODO: speaking strictly, this would need to be notified, since ImageURL is a bound property. However,
302 : // this method here is called with a locked mutex, so we cannot simply call listeners ...
303 : // I think the missing notification (and thus clients which potentially cannot observe the change)
304 : // is less severe than the potential deadlock ...
305 0 : }
306 : }
307 0 : break;
308 :
309 : default:
310 0 : OBoundControlModel::setFastPropertyValue_NoBroadcast(nHandle, rValue);
311 0 : break;
312 : }
313 0 : }
314 :
315 : //------------------------------------------------------------------------------
316 0 : sal_Bool OImageControlModel::convertFastPropertyValue(Any& rConvertedValue, Any& rOldValue, sal_Int32 nHandle, const Any& rValue)
317 : throw( IllegalArgumentException )
318 : {
319 0 : switch (nHandle)
320 : {
321 : case PROPERTY_ID_READONLY :
322 0 : return tryPropertyValue(rConvertedValue, rOldValue, rValue, m_bReadOnly);
323 :
324 : case PROPERTY_ID_IMAGE_URL:
325 0 : return tryPropertyValue( rConvertedValue, rOldValue, rValue, m_sImageURL );
326 :
327 : case PROPERTY_ID_GRAPHIC:
328 : {
329 0 : const Reference< XGraphic > xGraphic( getFastPropertyValue( PROPERTY_ID_GRAPHIC ), UNO_QUERY );
330 0 : return tryPropertyValue( rConvertedValue, rOldValue, rValue, xGraphic );
331 : }
332 :
333 : default:
334 0 : return OBoundControlModel::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue);
335 : }
336 : }
337 :
338 : //------------------------------------------------------------------------------
339 0 : void OImageControlModel::describeFixedProperties( Sequence< Property >& _rProps ) const
340 : {
341 0 : BEGIN_DESCRIBE_PROPERTIES( 4, OBoundControlModel )
342 0 : DECL_IFACE_PROP2( GRAPHIC, XGraphic, BOUND, TRANSIENT );
343 0 : DECL_PROP1 ( IMAGE_URL, ::rtl::OUString, BOUND );
344 0 : DECL_BOOL_PROP1 ( READONLY, BOUND );
345 0 : DECL_PROP1 ( TABINDEX, sal_Int16, BOUND );
346 : END_DESCRIBE_PROPERTIES();
347 0 : }
348 :
349 : //------------------------------------------------------------------------------
350 0 : void OImageControlModel::describeAggregateProperties( Sequence< Property >& /* [out] */ o_rAggregateProperties ) const
351 : {
352 0 : OBoundControlModel::describeAggregateProperties( o_rAggregateProperties );
353 : // remove ImageULR and Graphic properties, we "overload" them. This is because our aggregate synchronizes those
354 : // two, but we have an own sychronization mechanism.
355 0 : RemoveProperty( o_rAggregateProperties, PROPERTY_IMAGE_URL );
356 0 : RemoveProperty( o_rAggregateProperties, PROPERTY_GRAPHIC );
357 0 : }
358 :
359 : //------------------------------------------------------------------------------
360 0 : ::rtl::OUString OImageControlModel::getServiceName() throw ( ::com::sun::star::uno::RuntimeException)
361 : {
362 0 : return FRM_COMPONENT_IMAGECONTROL; // old (non-sun) name for compatibility !
363 : }
364 :
365 : //------------------------------------------------------------------------------
366 0 : void OImageControlModel::write(const Reference<XObjectOutputStream>& _rxOutStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
367 : {
368 : // Base class
369 0 : OBoundControlModel::write(_rxOutStream);
370 : // Version
371 0 : _rxOutStream->writeShort(0x0003);
372 : // Name
373 0 : _rxOutStream->writeBoolean(m_bReadOnly);
374 0 : writeHelpTextCompatibly(_rxOutStream);
375 : // from version 0x0003 : common properties
376 0 : writeCommonProperties(_rxOutStream);
377 0 : }
378 :
379 : //------------------------------------------------------------------------------
380 0 : void OImageControlModel::read(const Reference<XObjectInputStream>& _rxInStream) throw ( ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
381 : {
382 0 : OBoundControlModel::read(_rxInStream);
383 :
384 : // Version
385 0 : sal_uInt16 nVersion = _rxInStream->readShort();
386 0 : switch (nVersion)
387 : {
388 : case 0x0001:
389 0 : m_bReadOnly = _rxInStream->readBoolean();
390 0 : break;
391 : case 0x0002:
392 0 : m_bReadOnly = _rxInStream->readBoolean();
393 0 : readHelpTextCompatibly(_rxInStream);
394 0 : break;
395 : case 0x0003:
396 0 : m_bReadOnly = _rxInStream->readBoolean();
397 0 : readHelpTextCompatibly(_rxInStream);
398 0 : readCommonProperties(_rxInStream);
399 0 : break;
400 : default :
401 : OSL_FAIL("OImageControlModel::read : unknown version !");
402 0 : m_bReadOnly = sal_False;
403 0 : defaultCommonProperties();
404 0 : break;
405 : }
406 : // Display default values after read
407 0 : if ( !getControlSource().isEmpty() )
408 : { // (not if we don't have a control source - the "State" property acts like it is persistent, then
409 0 : ::osl::MutexGuard aGuard(m_aMutex); // resetNoBroadcast expects this mutex guarding
410 0 : resetNoBroadcast();
411 : }
412 0 : }
413 :
414 : //------------------------------------------------------------------------------
415 0 : sal_Bool OImageControlModel::impl_updateStreamForURL_lck( const ::rtl::OUString& _rURL, ValueChangeInstigator _eInstigator )
416 : {
417 : // create a stream for the image specified by the URL
418 0 : ::std::auto_ptr< SvStream > pImageStream;
419 0 : Reference< XInputStream > xImageStream;
420 :
421 0 : if ( ::svt::GraphicAccess::isSupportedURL( _rURL ) )
422 : {
423 0 : xImageStream = ::svt::GraphicAccess::getImageXStream( getContext().getLegacyServiceFactory(), _rURL );
424 : }
425 : else
426 : {
427 0 : pImageStream.reset( ::utl::UcbStreamHelper::CreateStream( _rURL, STREAM_READ ) );
428 0 : sal_Bool bSetNull = ( pImageStream.get() == NULL ) || ( ERRCODE_NONE != pImageStream->GetErrorCode() );
429 :
430 0 : if ( !bSetNull )
431 : {
432 : // get the size of the stream
433 0 : pImageStream->Seek(STREAM_SEEK_TO_END);
434 0 : sal_Int32 nSize = (sal_Int32)pImageStream->Tell();
435 0 : if (pImageStream->GetBufferSize() < 8192)
436 0 : pImageStream->SetBufferSize(8192);
437 0 : pImageStream->Seek(STREAM_SEEK_TO_BEGIN);
438 :
439 0 : xImageStream = new ::utl::OInputStreamHelper( new SvLockBytes( pImageStream.get(), sal_False ), nSize );
440 : }
441 : }
442 :
443 0 : if ( xImageStream.is() )
444 : {
445 0 : if ( m_xColumnUpdate.is() )
446 0 : m_xColumnUpdate->updateBinaryStream( xImageStream, xImageStream->available() );
447 : else
448 0 : setControlValue( makeAny( xImageStream ), _eInstigator );
449 0 : xImageStream->closeInput();
450 0 : return sal_True;
451 : }
452 :
453 0 : return sal_False;
454 : }
455 :
456 : //------------------------------------------------------------------------------
457 0 : sal_Bool OImageControlModel::impl_handleNewImageURL_lck( ValueChangeInstigator _eInstigator )
458 : {
459 0 : switch ( lcl_getImageStoreType( getFieldType() ) )
460 : {
461 : case ImageStoreBinary:
462 0 : if ( impl_updateStreamForURL_lck( m_sImageURL, _eInstigator ) )
463 0 : return sal_True;
464 0 : break;
465 :
466 : case ImageStoreLink:
467 : {
468 0 : ::rtl::OUString sCommitURL( m_sImageURL );
469 0 : if ( !m_sDocumentURL.isEmpty() )
470 0 : sCommitURL = URIHelper::simpleNormalizedMakeRelative( m_sDocumentURL, sCommitURL );
471 : OSL_ENSURE( m_xColumnUpdate.is(), "OImageControlModel::impl_handleNewImageURL_lck: no bound field, but ImageStoreLink?!" );
472 0 : if ( m_xColumnUpdate.is() )
473 : {
474 0 : m_xColumnUpdate->updateString( sCommitURL );
475 0 : return sal_True;
476 0 : }
477 : }
478 0 : break;
479 :
480 : case ImageStoreInvalid:
481 : OSL_FAIL( "OImageControlModel::impl_handleNewImageURL_lck: image storage type type!" );
482 0 : break;
483 : }
484 :
485 : // if we're here, then the above code was unable to update our field/control from the given URL
486 : // => fall back to NULL/VOID
487 0 : if ( m_xColumnUpdate.is() )
488 0 : m_xColumnUpdate->updateNull();
489 : else
490 0 : setControlValue( Any(), _eInstigator );
491 :
492 0 : return sal_True;
493 : }
494 :
495 : //------------------------------------------------------------------------------
496 0 : sal_Bool OImageControlModel::commitControlValueToDbColumn( bool _bPostReset )
497 : {
498 0 : if ( _bPostReset )
499 : {
500 : // since this is a "commit after reset", we can simply update the column
501 : // with null - this is our "default" which we were just reset to
502 0 : if ( m_xColumnUpdate.is() )
503 0 : m_xColumnUpdate->updateNull();
504 : }
505 : else
506 : {
507 0 : ::osl::MutexGuard aGuard(m_aMutex);
508 0 : return impl_handleNewImageURL_lck( eDbColumnBinding );
509 : }
510 :
511 0 : return sal_True;
512 : }
513 :
514 : //------------------------------------------------------------------------------
515 : namespace
516 : {
517 0 : bool lcl_isValidDocumentURL( const ::rtl::OUString& _rDocURL )
518 : {
519 0 : return ( !_rDocURL.isEmpty() && _rDocURL != "private:object" );
520 : }
521 : }
522 :
523 : //------------------------------------------------------------------------------
524 0 : void OImageControlModel::onConnectedDbColumn( const Reference< XInterface >& _rxForm )
525 : {
526 0 : OBoundControlModel::onConnectedDbColumn( _rxForm );
527 :
528 : try
529 : {
530 0 : Reference< XModel > xDocument( getXModel( *this ) );
531 0 : if ( xDocument.is() )
532 : {
533 0 : m_sDocumentURL = xDocument->getURL();
534 0 : if ( !lcl_isValidDocumentURL( m_sDocumentURL ) )
535 : {
536 0 : Reference< XChild > xAsChild( xDocument, UNO_QUERY );
537 0 : while ( xAsChild.is() && !lcl_isValidDocumentURL( m_sDocumentURL ) )
538 : {
539 0 : xDocument.set( xAsChild->getParent(), UNO_QUERY );
540 0 : if ( xDocument.is() )
541 0 : m_sDocumentURL = xDocument->getURL();
542 0 : xAsChild.set( xDocument, UNO_QUERY );
543 0 : }
544 : }
545 0 : }
546 : }
547 0 : catch( const Exception& )
548 : {
549 : DBG_UNHANDLED_EXCEPTION();
550 : }
551 0 : }
552 :
553 : //------------------------------------------------------------------------------
554 0 : void OImageControlModel::onDisconnectedDbColumn()
555 : {
556 0 : OBoundControlModel::onDisconnectedDbColumn();
557 :
558 0 : m_sDocumentURL = ::rtl::OUString();
559 0 : }
560 :
561 : //------------------------------------------------------------------------------
562 0 : Any OImageControlModel::translateDbColumnToControlValue()
563 : {
564 0 : switch ( lcl_getImageStoreType( getFieldType() ) )
565 : {
566 : case ImageStoreBinary:
567 : {
568 0 : Reference< XInputStream > xImageStream( m_xColumn->getBinaryStream() );
569 0 : if ( m_xColumn->wasNull() )
570 0 : xImageStream.clear();
571 0 : return makeAny( xImageStream );
572 : }
573 : case ImageStoreLink:
574 : {
575 0 : ::rtl::OUString sImageLink( m_xColumn->getString() );
576 0 : if ( !m_sDocumentURL.isEmpty() )
577 0 : sImageLink = INetURLObject::GetAbsURL( m_sDocumentURL, sImageLink );
578 0 : return makeAny( sImageLink );
579 : }
580 : case ImageStoreInvalid:
581 : OSL_FAIL( "OImageControlModel::translateDbColumnToControlValue: invalid field type!" );
582 0 : break;
583 : }
584 0 : return Any();
585 : }
586 :
587 : //------------------------------------------------------------------------------
588 0 : Any OImageControlModel::getControlValue( ) const
589 : {
590 0 : return makeAny( m_sImageURL );
591 : }
592 :
593 : //------------------------------------------------------------------------------
594 0 : void OImageControlModel::doSetControlValue( const Any& _rValue )
595 : {
596 : DBG_ASSERT( GetImageProducer() && m_xImageProducer.is(), "OImageControlModel::doSetControlValue: no image producer!" );
597 0 : if ( !GetImageProducer() || !m_xImageProducer.is() )
598 0 : return;
599 :
600 0 : bool bStartProduction = false;
601 0 : switch ( lcl_getImageStoreType( getFieldType() ) )
602 : {
603 : case ImageStoreBinary:
604 : {
605 : // give the image producer the stream
606 0 : Reference< XInputStream > xInStream;
607 0 : _rValue >>= xInStream;
608 0 : GetImageProducer()->setImage( xInStream );
609 0 : bStartProduction = true;
610 : }
611 0 : break;
612 :
613 : case ImageStoreLink:
614 : {
615 0 : ::rtl::OUString sImageURL;
616 0 : _rValue >>= sImageURL;
617 0 : GetImageProducer()->SetImage( sImageURL );
618 0 : bStartProduction = true;
619 : }
620 0 : break;
621 :
622 : case ImageStoreInvalid:
623 : OSL_FAIL( "OImageControlModel::doSetControlValue: invalid field type!" );
624 0 : break;
625 :
626 : } // switch ( lcl_getImageStoreType( getFieldType() ) )
627 :
628 0 : if ( bStartProduction )
629 : {
630 : // start production
631 0 : Reference< XImageProducer > xProducer = m_xImageProducer;
632 : {
633 : // release our mutex once (it's acquired in the calling method!), as starting the image production may
634 : // result in the locking of the solar mutex (unfortunally the default implementation of our aggregate,
635 : // VCLXImageControl, does this locking)
636 0 : MutexRelease aRelease(m_aMutex);
637 0 : xProducer->startProduction();
638 0 : }
639 : }
640 : }
641 :
642 : // OComponentHelper
643 : //------------------------------------------------------------------
644 0 : void SAL_CALL OImageControlModel::disposing()
645 : {
646 0 : OBoundControlModel::disposing();
647 0 : }
648 :
649 : //------------------------------------------------------------------------------
650 0 : void OImageControlModel::resetNoBroadcast()
651 : {
652 0 : if ( hasField() ) // only reset when we are connected to a column
653 0 : OBoundControlModel::resetNoBroadcast( );
654 0 : }
655 :
656 : //--------------------------------------------------------------------
657 0 : Reference< XImageProducer > SAL_CALL OImageControlModel::getImageProducer() throw ( RuntimeException)
658 : {
659 0 : return this;
660 : }
661 :
662 : //--------------------------------------------------------------------
663 0 : void SAL_CALL OImageControlModel::addConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException)
664 : {
665 0 : GetImageProducer()->addConsumer( _rxConsumer );
666 0 : }
667 :
668 : //--------------------------------------------------------------------
669 0 : void SAL_CALL OImageControlModel::removeConsumer( const Reference< XImageConsumer >& _rxConsumer ) throw (RuntimeException)
670 : {
671 0 : GetImageProducer()->removeConsumer( _rxConsumer );
672 0 : }
673 :
674 : //--------------------------------------------------------------------
675 0 : void SAL_CALL OImageControlModel::startProduction( ) throw (RuntimeException)
676 : {
677 0 : GetImageProducer()->startProduction();
678 0 : }
679 :
680 : //------------------------------------------------------------------------------
681 0 : IMPL_LINK( OImageControlModel, OnImageImportDone, ::Graphic*, i_pGraphic )
682 : {
683 0 : const Reference< XGraphic > xGraphic( i_pGraphic != NULL ? Image( i_pGraphic->GetBitmapEx() ).GetXGraphic() : NULL );
684 0 : m_bExternalGraphic = false;
685 : try
686 : {
687 0 : setPropertyValue( PROPERTY_GRAPHIC, makeAny( xGraphic ) );
688 : }
689 0 : catch ( const Exception& )
690 : {
691 : DBG_UNHANDLED_EXCEPTION();
692 : }
693 0 : m_bExternalGraphic = true;
694 0 : return 1L;
695 : }
696 :
697 : //==================================================================
698 : // OImageControlControl
699 : //==================================================================
700 :
701 : //------------------------------------------------------------------
702 0 : InterfaceRef SAL_CALL OImageControlControl_CreateInstance(const Reference<XMultiServiceFactory>& _rxFactory)
703 : {
704 0 : return *(new OImageControlControl(_rxFactory));
705 : }
706 :
707 : //------------------------------------------------------------------------------
708 0 : Sequence<Type> OImageControlControl::_getTypes()
709 : {
710 : return concatSequences(
711 : OBoundControl::_getTypes(),
712 : OImageControlControl_Base::getTypes()
713 0 : );
714 : }
715 :
716 : //------------------------------------------------------------------------------
717 0 : OImageControlControl::OImageControlControl(const Reference<XMultiServiceFactory>& _rxFactory)
718 : :OBoundControl(_rxFactory, VCL_CONTROL_IMAGECONTROL)
719 0 : ,m_aModifyListeners( m_aMutex )
720 : {
721 0 : increment(m_refCount);
722 : {
723 : // Add as Focus- and MouseListener
724 0 : Reference< XWindow > xComp;
725 0 : query_aggregation( m_xAggregate, xComp );
726 0 : if ( xComp.is() )
727 0 : xComp->addMouseListener( this );
728 : }
729 0 : decrement(m_refCount);
730 0 : }
731 :
732 : //------------------------------------------------------------------------------
733 0 : Any SAL_CALL OImageControlControl::queryAggregation(const Type& _rType) throw (RuntimeException)
734 : {
735 0 : Any aReturn = OBoundControl::queryAggregation( _rType );
736 0 : if ( !aReturn.hasValue() )
737 : aReturn = ::cppu::queryInterface(
738 : _rType,
739 : static_cast< XMouseListener* >( this ),
740 : static_cast< XModifyBroadcaster* >( this )
741 0 : );
742 :
743 0 : return aReturn;
744 : }
745 :
746 : //------------------------------------------------------------------------------
747 0 : StringSequence OImageControlControl::getSupportedServiceNames() throw()
748 : {
749 0 : StringSequence aSupported = OBoundControl::getSupportedServiceNames();
750 0 : aSupported.realloc(aSupported.getLength() + 1);
751 :
752 0 : ::rtl::OUString*pArray = aSupported.getArray();
753 0 : pArray[aSupported.getLength()-1] = FRM_SUN_CONTROL_IMAGECONTROL;
754 0 : return aSupported;
755 : }
756 :
757 : //------------------------------------------------------------------------------
758 0 : void SAL_CALL OImageControlControl::addModifyListener( const Reference< XModifyListener >& _Listener ) throw (RuntimeException)
759 : {
760 0 : m_aModifyListeners.addInterface( _Listener );
761 0 : }
762 :
763 : //------------------------------------------------------------------------------
764 0 : void SAL_CALL OImageControlControl::removeModifyListener( const Reference< XModifyListener >& _Listener ) throw (RuntimeException)
765 : {
766 0 : m_aModifyListeners.removeInterface( _Listener );
767 0 : }
768 :
769 : //------------------------------------------------------------------------------
770 0 : void SAL_CALL OImageControlControl::disposing()
771 : {
772 0 : EventObject aEvent( *this );
773 0 : m_aModifyListeners.disposeAndClear( aEvent );
774 :
775 0 : OBoundControl::disposing();
776 0 : }
777 :
778 : //------------------------------------------------------------------------------
779 0 : void SAL_CALL OImageControlControl::disposing( const EventObject& _Event ) throw(RuntimeException)
780 : {
781 0 : OBoundControl::disposing( _Event );
782 0 : }
783 :
784 : //------------------------------------------------------------------------------
785 0 : void OImageControlControl::implClearGraphics( sal_Bool _bForce )
786 : {
787 0 : Reference< XPropertySet > xSet( getModel(), UNO_QUERY );
788 0 : if ( xSet.is() )
789 : {
790 0 : if ( _bForce )
791 : {
792 0 : ::rtl::OUString sOldImageURL;
793 0 : xSet->getPropertyValue( PROPERTY_IMAGE_URL ) >>= sOldImageURL;
794 :
795 0 : if ( sOldImageURL.isEmpty() )
796 : // the ImageURL is already empty, so simply setting a new empty one would not suffice
797 : // (since it would be ignored)
798 0 : xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "private:emptyImage" ) ) ) );
799 : // (the concrete URL we're passing here doens't matter. It's important that
800 : // the model cannot resolve it to a a valid resource describing an image stream
801 : }
802 :
803 0 : xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( ::rtl::OUString() ) );
804 0 : }
805 0 : }
806 :
807 : //------------------------------------------------------------------------------
808 0 : bool OImageControlControl::implInsertGraphics()
809 : {
810 0 : Reference< XPropertySet > xSet( getModel(), UNO_QUERY );
811 0 : if ( !xSet.is() )
812 0 : return false;
813 :
814 0 : ::rtl::OUString sTitle = FRM_RES_STRING(RID_STR_IMPORT_GRAPHIC);
815 : // build some arguments for the upcoming dialog
816 : try
817 : {
818 0 : ::sfx2::FileDialogHelper aDialog( TemplateDescription::FILEOPEN_LINK_PREVIEW, SFXWB_GRAPHIC );
819 0 : aDialog.SetTitle( sTitle );
820 :
821 0 : Reference< XFilePickerControlAccess > xController( aDialog.GetFilePicker(), UNO_QUERY_THROW );
822 0 : xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0, ::cppu::bool2any(sal_True));
823 :
824 0 : Reference<XPropertySet> xBoundField;
825 0 : if ( hasProperty( PROPERTY_BOUNDFIELD, xSet ) )
826 0 : xSet->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xBoundField;
827 0 : sal_Bool bHasField = xBoundField.is();
828 :
829 : // if the control is bound to a DB field, then it's not possible to decide whether or not to link
830 0 : xController->enableControl(ExtendedFilePickerElementIds::CHECKBOX_LINK, !bHasField );
831 :
832 : // if the control is bound to a DB field, then linking of the image depends on the type of the field
833 0 : sal_Bool bImageIsLinked = sal_True;
834 0 : if ( bHasField )
835 : {
836 0 : sal_Int32 nFieldType = DataType::OTHER;
837 0 : OSL_VERIFY( xBoundField->getPropertyValue( PROPERTY_FIELDTYPE ) >>= nFieldType );
838 0 : bImageIsLinked = ( lcl_getImageStoreType( nFieldType ) == ImageStoreLink );
839 : }
840 0 : xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, makeAny( bImageIsLinked ) );
841 :
842 0 : if ( ERRCODE_NONE == aDialog.Execute() )
843 : {
844 : // reset the url property in case it already has the value we're about to set - in this case
845 : // our propertyChanged would not get called without this.
846 0 : implClearGraphics( sal_False );
847 0 : sal_Bool bIsLink = sal_False;
848 0 : xController->getValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0) >>= bIsLink;
849 : // Force bIsLink to be sal_True if we're bound to a field. Though we initialized the file picker with IsLink=TRUE
850 : // in this case, and disabled the respective control, there might be picker implementations which do not
851 : // respect this, and return IsLink=FALSE here. In this case, "normalize" the flag.
852 : // #i112659#
853 0 : bIsLink |= bHasField;
854 0 : if ( !bIsLink )
855 : {
856 0 : Graphic aGraphic;
857 0 : aDialog.GetGraphic( aGraphic );
858 0 : xSet->setPropertyValue( PROPERTY_GRAPHIC, makeAny( aGraphic.GetXGraphic() ) );
859 : }
860 : else
861 0 : xSet->setPropertyValue( PROPERTY_IMAGE_URL, makeAny( ::rtl::OUString( aDialog.GetPath() ) ) );
862 :
863 0 : return true;
864 0 : }
865 : }
866 0 : catch(const Exception&)
867 : {
868 : OSL_FAIL("OImageControlControl::implInsertGraphics: caught an exception while attempting to execute the FilePicker!");
869 : }
870 0 : return false;
871 : }
872 :
873 : //------------------------------------------------------------------------------
874 0 : bool OImageControlControl::impl_isEmptyGraphics_nothrow() const
875 : {
876 0 : bool bIsEmpty = true;
877 :
878 : try
879 : {
880 0 : Reference< XPropertySet > xModelProps( const_cast< OImageControlControl* >( this )->getModel(), UNO_QUERY_THROW );
881 0 : Reference< XGraphic > xGraphic;
882 0 : OSL_VERIFY( xModelProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Graphic" ) ) ) >>= xGraphic );
883 0 : bIsEmpty = !xGraphic.is();
884 : }
885 0 : catch( const Exception& )
886 : {
887 : DBG_UNHANDLED_EXCEPTION();
888 : }
889 :
890 0 : return bIsEmpty;
891 : }
892 :
893 : // MouseListener
894 : //------------------------------------------------------------------------------
895 0 : void OImageControlControl::mousePressed(const ::com::sun::star::awt::MouseEvent& e) throw ( ::com::sun::star::uno::RuntimeException)
896 : {
897 0 : SolarMutexGuard aGuard;
898 :
899 0 : if (e.Buttons != MouseButton::LEFT)
900 : return;
901 :
902 0 : bool bModified = false;
903 : // is this a request for a context menu?
904 0 : if ( e.PopupTrigger )
905 : {
906 0 : Reference< XPopupMenu > xMenu( awt::PopupMenu::create( m_aContext.getUNOContext() ) );
907 : DBG_ASSERT( xMenu.is(), "OImageControlControl::mousePressed: could not create a popup menu!" );
908 :
909 0 : Reference< XWindowPeer > xWindowPeer = getPeer();
910 : DBG_ASSERT( xWindowPeer.is(), "OImageControlControl::mousePressed: no window!" );
911 :
912 0 : if ( xMenu.is() && xWindowPeer.is() )
913 : {
914 0 : xMenu->insertItem( ID_OPEN_GRAPHICS, FRM_RES_STRING( RID_STR_OPEN_GRAPHICS ), 0, 0 );
915 0 : xMenu->insertItem( ID_CLEAR_GRAPHICS, FRM_RES_STRING( RID_STR_CLEAR_GRAPHICS ), 0, 1 );
916 :
917 : // check if the ImageURL is empty
918 0 : if ( impl_isEmptyGraphics_nothrow() )
919 0 : xMenu->enableItem( ID_CLEAR_GRAPHICS, sal_False );
920 :
921 0 : awt::Rectangle aRect( e.X, e.Y, 0, 0 );
922 0 : if ( ( e.X < 0 ) || ( e.Y < 0 ) )
923 : { // context menu triggered by keyboard
924 : // position it in the center of the control
925 0 : Reference< XWindow > xWindow( static_cast< ::cppu::OWeakObject* >( this ), UNO_QUERY );
926 : OSL_ENSURE( xWindow.is(), "OImageControlControl::mousePressed: me not a window? How this?" );
927 0 : if ( xWindow.is() )
928 : {
929 0 : awt::Rectangle aPosSize = xWindow->getPosSize();
930 0 : aRect.X = aPosSize.Width / 2;
931 0 : aRect.Y = aPosSize.Height / 2;
932 0 : }
933 : }
934 :
935 0 : const sal_Int16 nResult = xMenu->execute( xWindowPeer, aRect, PopupMenuDirection::EXECUTE_DEFAULT );
936 :
937 0 : switch ( nResult )
938 : {
939 : case ID_OPEN_GRAPHICS:
940 0 : implInsertGraphics();
941 0 : bModified = true;
942 0 : break;
943 :
944 : case ID_CLEAR_GRAPHICS:
945 0 : implClearGraphics( sal_True );
946 0 : bModified = true;
947 0 : break;
948 : }
949 0 : }
950 : }
951 : else
952 : {
953 : //////////////////////////////////////////////////////////////////////
954 : // Double click
955 0 : if (e.ClickCount == 2)
956 : {
957 :
958 0 : Reference<XPropertySet> xSet(getModel(), UNO_QUERY);
959 0 : if (!xSet.is())
960 : return;
961 :
962 : // If the Control is not bound, do not display a dialog (because the to-be-sent URL would be invalid anyway)
963 0 : Reference<XPropertySet> xBoundField;
964 0 : if (hasProperty(PROPERTY_BOUNDFIELD, xSet))
965 0 : ::cppu::extractInterface(xBoundField, xSet->getPropertyValue(PROPERTY_BOUNDFIELD));
966 0 : if (!xBoundField.is())
967 : {
968 : // but only if our IMAGE_URL property is handled as if it is transient, which is equivalent to
969 : // an empty control source
970 0 : if ( !hasProperty(PROPERTY_CONTROLSOURCE, xSet) || !::comphelper::getString(xSet->getPropertyValue(PROPERTY_CONTROLSOURCE)).isEmpty() )
971 : return;
972 : }
973 :
974 0 : sal_Bool bReadOnly = false;
975 0 : xSet->getPropertyValue(PROPERTY_READONLY) >>= bReadOnly;
976 0 : if (bReadOnly)
977 : return;
978 :
979 0 : if ( implInsertGraphics() )
980 0 : bModified = true;
981 : }
982 : }
983 :
984 0 : if ( bModified )
985 : {
986 0 : EventObject aEvent( *this );
987 0 : m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent );
988 0 : }
989 : }
990 :
991 : //------------------------------------------------------------------------------
992 0 : void SAL_CALL OImageControlControl::mouseReleased(const awt::MouseEvent& /*e*/) throw ( RuntimeException )
993 : {
994 0 : }
995 :
996 : //------------------------------------------------------------------------------
997 0 : void SAL_CALL OImageControlControl::mouseEntered(const awt::MouseEvent& /*e*/) throw ( RuntimeException )
998 : {
999 0 : }
1000 :
1001 : //------------------------------------------------------------------------------
1002 0 : void SAL_CALL OImageControlControl::mouseExited(const awt::MouseEvent& /*e*/) throw ( RuntimeException )
1003 : {
1004 0 : }
1005 :
1006 : //.........................................................................
1007 : } // namespace frm
1008 : //.........................................................................
1009 :
1010 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|