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