1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_toolkit.hxx"
26 
27 #include <vcl/svapp.hxx>
28 #include <vcl/window.hxx>
29 #include <vcl/wall.hxx>
30 #include <vos/mutex.hxx>
31 #include <toolkit/controls/dialogcontrol.hxx>
32 #include <toolkit/helper/property.hxx>
33 #include <toolkit/helper/unopropertyarrayhelper.hxx>
34 #include <toolkit/controls/stdtabcontroller.hxx>
35 #include <com/sun/star/awt/PosSize.hpp>
36 #include <com/sun/star/awt/WindowAttribute.hpp>
37 #include <com/sun/star/resource/XStringResourceResolver.hpp>
38 #include <com/sun/star/graphic/XGraphicProvider.hpp>
39 #include <tools/list.hxx>
40 #include <cppuhelper/typeprovider.hxx>
41 #include <tools/debug.hxx>
42 #include <tools/diagnose_ex.h>
43 #include <comphelper/sequence.hxx>
44 #include <vcl/svapp.hxx>
45 #include <vcl/outdev.hxx>
46 
47 #include <toolkit/helper/vclunohelper.hxx>
48 #include <unotools/ucbstreamhelper.hxx>
49 #include <vcl/graph.hxx>
50 #include <vcl/image.hxx>
51 #include <map>
52 #include <algorithm>
53 #include <functional>
54 #include "tools/urlobj.hxx"
55 #include "osl/file.hxx"
56 
57 using namespace ::com::sun::star;
58 using namespace ::com::sun::star::uno;
59 using namespace ::com::sun::star::awt;
60 using namespace ::com::sun::star::lang;
61 using namespace ::com::sun::star::container;
62 using namespace ::com::sun::star::beans;
63 using namespace ::com::sun::star::util;
64 
65 #define PROPERTY_DIALOGSOURCEURL ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DialogSourceURL" ))
66 #define PROPERTY_IMAGEURL ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ImageURL" ))
67 #define PROPERTY_GRAPHIC ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Graphic" ))
68 //
69 ////HELPER
70 ::rtl::OUString getPhysicalLocation( const ::com::sun::star::uno::Any& rbase, const ::com::sun::star::uno::Any& rUrl );
71 
72 //	----------------------------------------------------
73 //	class UnoControlDialogModel
74 //	----------------------------------------------------
75 UnoControlDialogModel::UnoControlDialogModel( const Reference< XMultiServiceFactory >& i_factory )
76 	:ControlModelContainerBase( i_factory )
77 {
78 	ImplRegisterProperty( BASEPROPERTY_BACKGROUNDCOLOR );
79 //	ImplRegisterProperty( BASEPROPERTY_BORDER );
80 	ImplRegisterProperty( BASEPROPERTY_DEFAULTCONTROL );
81 	ImplRegisterProperty( BASEPROPERTY_ENABLED );
82 	ImplRegisterProperty( BASEPROPERTY_FONTDESCRIPTOR );
83 //	ImplRegisterProperty( BASEPROPERTY_PRINTABLE );
84 	ImplRegisterProperty( BASEPROPERTY_HELPTEXT );
85 	ImplRegisterProperty( BASEPROPERTY_HELPURL );
86 	ImplRegisterProperty( BASEPROPERTY_TITLE );
87 	ImplRegisterProperty( BASEPROPERTY_SIZEABLE );
88 	ImplRegisterProperty( BASEPROPERTY_DESKTOP_AS_PARENT );
89     ImplRegisterProperty( BASEPROPERTY_DECORATION );
90 	ImplRegisterProperty( BASEPROPERTY_DIALOGSOURCEURL );
91     ImplRegisterProperty( BASEPROPERTY_GRAPHIC );
92     ImplRegisterProperty( BASEPROPERTY_IMAGEURL );
93 
94 	Any aBool;
95 	aBool <<= (sal_Bool) sal_True;
96 	ImplRegisterProperty( BASEPROPERTY_MOVEABLE, aBool );
97 	ImplRegisterProperty( BASEPROPERTY_CLOSEABLE, aBool );
98 }
99 
100 UnoControlDialogModel::UnoControlDialogModel( const UnoControlDialogModel& rModel )
101 	: ControlModelContainerBase( rModel )
102 {
103 }
104 
105 UnoControlDialogModel::~UnoControlDialogModel()
106 {
107 }
108 
109 UnoControlModel* UnoControlDialogModel::Clone() const
110 {
111 	// clone the container itself
112 	UnoControlDialogModel* pClone = new UnoControlDialogModel( *this );
113 
114 	Clone_Impl(*pClone);
115 
116 	return pClone;
117 }
118 
119 
120 ::rtl::OUString UnoControlDialogModel::getServiceName( ) throw(RuntimeException)
121 {
122 	return ::rtl::OUString::createFromAscii( szServiceName_UnoControlDialogModel );
123 }
124 
125 Any UnoControlDialogModel::ImplGetDefaultValue( sal_uInt16 nPropId ) const
126 {
127     Any aAny;
128 
129     switch ( nPropId )
130     {
131         case BASEPROPERTY_DEFAULTCONTROL:
132 		    aAny <<= ::rtl::OUString::createFromAscii( szServiceName_UnoControlDialog );
133             break;
134         default:
135             aAny = UnoControlModel::ImplGetDefaultValue( nPropId );
136     }
137 
138     return aAny;
139 }
140 
141 ::cppu::IPropertyArrayHelper& UnoControlDialogModel::getInfoHelper()
142 {
143 	static UnoPropertyArrayHelper* pHelper = NULL;
144 	if ( !pHelper )
145 	{
146 		Sequence<sal_Int32> aIDs = ImplGetPropertyIds();
147 		pHelper = new UnoPropertyArrayHelper( aIDs );
148 	}
149 	return *pHelper;
150 }
151 
152 // XMultiPropertySet
153 Reference< XPropertySetInfo > UnoControlDialogModel::getPropertySetInfo(  ) throw(RuntimeException)
154 {
155 	static Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
156 	return xInfo;
157 }
158 
159 // ============================================================================
160 // = class UnoDialogControl
161 // ============================================================================
162 
163 UnoDialogControl::UnoDialogControl( const uno::Reference< lang::XMultiServiceFactory >& i_factory )
164     :UnoDialogControl_Base( i_factory )
165     ,maTopWindowListeners( *this )
166     ,mbWindowListener(false)
167 {
168 	maComponentInfos.nWidth = 300;
169 	maComponentInfos.nHeight = 450;
170  }
171 
172 UnoDialogControl::~UnoDialogControl()
173 {
174 }
175 
176 ::rtl::OUString UnoDialogControl::GetComponentServiceName()
177 {
178 
179     sal_Bool bDecoration( sal_True );
180     ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_DECORATION )) >>= bDecoration;
181     if ( bDecoration )
182         return ::rtl::OUString::createFromAscii( "Dialog" );
183     else
184         return ::rtl::OUString::createFromAscii( "TabPage" );
185 }
186 
187 void UnoDialogControl::dispose() throw(RuntimeException)
188 {
189 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
190 
191 	EventObject aEvt;
192 	aEvt.Source = static_cast< ::cppu::OWeakObject* >( this );
193 	maTopWindowListeners.disposeAndClear( aEvt );
194     ControlContainerBase::dispose();
195 }
196 
197 void SAL_CALL UnoDialogControl::disposing(
198     const EventObject& Source )
199 throw(RuntimeException)
200 {
201 	ControlContainerBase::disposing( Source );
202 }
203 
204 sal_Bool UnoDialogControl::setModel( const Reference< XControlModel >& rxModel ) throw(RuntimeException)
205 {
206         // #Can we move all the Resource stuff to the ControlContainerBase ?
207 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
208         sal_Bool bRet = ControlContainerBase::setModel( rxModel );
209 	ImplStartListingForResourceEvents();
210 	return bRet;
211 }
212 
213 void UnoDialogControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer >  & rParentPeer ) throw(RuntimeException)
214 {
215 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
216 
217 	UnoControlContainer::createPeer( rxToolkit, rParentPeer );
218 
219 	Reference < XTopWindow > xTW( getPeer(), UNO_QUERY );
220     if ( xTW.is() )
221     {
222         xTW->setMenuBar( mxMenuBar );
223 
224         if ( !mbWindowListener )
225         {
226             Reference< XWindowListener > xWL( static_cast< cppu::OWeakObject*>( this ), UNO_QUERY );
227             addWindowListener( xWL );
228             mbWindowListener = true;
229         }
230 
231         if ( maTopWindowListeners.getLength() )
232 		    xTW->addTopWindowListener( &maTopWindowListeners );
233     }
234 }
235 
236 void UnoDialogControl::PrepareWindowDescriptor( ::com::sun::star::awt::WindowDescriptor& rDesc )
237 {
238     sal_Bool bDecoration( sal_True );
239     ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_DECORATION )) >>= bDecoration;
240     if ( !bDecoration )
241     {
242         // Now we have to manipulate the WindowDescriptor
243         rDesc.WindowAttributes = rDesc.WindowAttributes | ::com::sun::star::awt::WindowAttribute::NODECORATION;
244     }
245 
246     // We have to set the graphic property before the peer
247     // will be created. Otherwise the properties will be copied
248     // into the peer via propertiesChangeEvents. As the order of
249     // can lead to overwrites we have to set the graphic property
250     // before the propertiesChangeEvents are sent!
251     ::rtl::OUString aImageURL;
252     Reference< graphic::XGraphic > xGraphic;
253     if (( ImplGetPropertyValue( PROPERTY_IMAGEURL ) >>= aImageURL ) &&
254         ( aImageURL.getLength() > 0 ))
255     {
256         ::rtl::OUString absoluteUrl =
257             getPhysicalLocation( ImplGetPropertyValue( PROPERTY_DIALOGSOURCEURL ),
258                                  ImplGetPropertyValue( PROPERTY_IMAGEURL ));
259 
260 		xGraphic = ControlContainerBase::Impl_getGraphicFromURL_nothrow( absoluteUrl );
261         ImplSetPropertyValue( PROPERTY_GRAPHIC, uno::makeAny( xGraphic ), sal_True );
262     }
263 }
264 
265 void UnoDialogControl::addTopWindowListener( const Reference< XTopWindowListener >& rxListener ) throw (RuntimeException)
266 {
267 	maTopWindowListeners.addInterface( rxListener );
268 	if( getPeer().is() && maTopWindowListeners.getLength() == 1 )
269 	{
270 		Reference < XTopWindow >  xTW( getPeer(), UNO_QUERY );
271 		xTW->addTopWindowListener( &maTopWindowListeners );
272 	}
273 }
274 
275 void UnoDialogControl::removeTopWindowListener( const Reference< XTopWindowListener >& rxListener ) throw (RuntimeException)
276 {
277 	if( getPeer().is() && maTopWindowListeners.getLength() == 1 )
278 	{
279 		Reference < XTopWindow >  xTW( getPeer(), UNO_QUERY );
280 		xTW->removeTopWindowListener( &maTopWindowListeners );
281 	}
282 	maTopWindowListeners.removeInterface( rxListener );
283 }
284 
285 void UnoDialogControl::toFront(  ) throw (RuntimeException)
286 {
287 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
288 	if ( getPeer().is() )
289 	{
290 		Reference< XTopWindow > xTW( getPeer(), UNO_QUERY );
291 		if( xTW.is() )
292 			xTW->toFront();
293 	}
294 }
295 
296 void UnoDialogControl::toBack(  ) throw (RuntimeException)
297 {
298 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
299 	if ( getPeer().is() )
300 	{
301 		Reference< XTopWindow > xTW( getPeer(), UNO_QUERY );
302 		if( xTW.is() )
303 			xTW->toBack();
304 	}
305 }
306 
307 void UnoDialogControl::setMenuBar( const Reference< XMenuBar >& rxMenuBar ) throw (RuntimeException)
308 {
309 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
310 	mxMenuBar = rxMenuBar;
311 	if ( getPeer().is() )
312 	{
313 		Reference< XTopWindow > xTW( getPeer(), UNO_QUERY );
314 		if( xTW.is() )
315 			xTW->setMenuBar( mxMenuBar );
316 	}
317 }
318 static ::Size ImplMapPixelToAppFont( OutputDevice* pOutDev, const ::Size& aSize )
319 {
320     ::Size aTmp = pOutDev->PixelToLogic( aSize, MAP_APPFONT );
321     return aTmp;
322 }
323 // ::com::sun::star::awt::XWindowListener
324 void SAL_CALL UnoDialogControl::windowResized( const ::com::sun::star::awt::WindowEvent& e )
325 throw (::com::sun::star::uno::RuntimeException)
326 {
327     OutputDevice*pOutDev = Application::GetDefaultDevice();
328 	DBG_ASSERT( pOutDev, "Missing Default Device!" );
329 	if ( pOutDev && !mbSizeModified )
330 	{
331         // Currentley we are simply using MAP_APPFONT
332 		::Size aAppFontSize( e.Width, e.Height );
333 
334         Reference< XControl > xDialogControl( *this, UNO_QUERY_THROW );
335         Reference< XDevice > xDialogDevice( xDialogControl->getPeer(), UNO_QUERY );
336         OSL_ENSURE( xDialogDevice.is(), "UnoDialogControl::windowResized: no peer, but a windowResized event?" );
337 
338         // #i87592 In design mode the drawing layer works with sizes with decoration.
339         // Therefore we have to substract them before writing back to the properties (model).
340 		if ( xDialogDevice.is() && mbDesignMode )
341         {
342             DeviceInfo aDeviceInfo( xDialogDevice->getInfo() );
343             aAppFontSize.Width() -= aDeviceInfo.LeftInset + aDeviceInfo.RightInset;
344             aAppFontSize.Height() -= aDeviceInfo.TopInset + aDeviceInfo.BottomInset;
345         }
346 
347         aAppFontSize = ImplMapPixelToAppFont( pOutDev, aAppFontSize );
348 
349         // Remember that changes have been done by listener. No need to
350         // update the position because of property change event.
351         mbSizeModified = true;
352         Sequence< rtl::OUString > aProps( 2 );
353         Sequence< Any > aValues( 2 );
354         // Properties in a sequence must be sorted!
355         aProps[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Height" ));
356         aProps[1] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Width"  ));
357         aValues[0] <<= aAppFontSize.Height();
358         aValues[1] <<= aAppFontSize.Width();
359 
360 	    ImplSetPropertyValues( aProps, aValues, true );
361         mbSizeModified = false;
362 	}
363 }
364 
365 void SAL_CALL UnoDialogControl::windowMoved( const ::com::sun::star::awt::WindowEvent& e )
366 throw (::com::sun::star::uno::RuntimeException)
367 {
368 	OutputDevice*pOutDev = Application::GetDefaultDevice();
369 	DBG_ASSERT( pOutDev, "Missing Default Device!" );
370 	if ( pOutDev && !mbPosModified )
371 	{
372         // Currentley we are simply using MAP_APPFONT
373         Any    aAny;
374 		::Size aTmp( e.X, e.Y );
375         aTmp = ImplMapPixelToAppFont( pOutDev, aTmp );
376 
377         // Remember that changes have been done by listener. No need to
378         // update the position because of property change event.
379         mbPosModified = true;
380         Sequence< rtl::OUString > aProps( 2 );
381         Sequence< Any > aValues( 2 );
382         aProps[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PositionX"  ));
383         aProps[1] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PositionY" ));
384         aValues[0] <<= aTmp.Width();
385         aValues[1] <<= aTmp.Height();
386 
387 	    ImplSetPropertyValues( aProps, aValues, true );
388         mbPosModified = false;
389 	}
390 }
391 
392 void SAL_CALL UnoDialogControl::windowShown( const EventObject& e ) throw (RuntimeException)
393 {
394     (void)e;
395 }
396 
397 void SAL_CALL UnoDialogControl::windowHidden( const EventObject& e ) throw (RuntimeException)
398 {
399     (void)e;
400 }
401 
402 void SAL_CALL UnoDialogControl::endDialog( ::sal_Int32 i_result ) throw (RuntimeException)
403 {
404     Reference< XDialog2 > xPeerDialog( getPeer(), UNO_QUERY );
405     if ( xPeerDialog.is() )
406         xPeerDialog->endDialog( i_result );
407 }
408 
409 void SAL_CALL UnoDialogControl::setHelpId( const rtl::OUString& i_id ) throw (RuntimeException)
410 {
411     Reference< XDialog2 > xPeerDialog( getPeer(), UNO_QUERY );
412     if ( xPeerDialog.is() )
413         xPeerDialog->setHelpId( i_id );
414 }
415 
416 void UnoDialogControl::setTitle( const ::rtl::OUString& Title ) throw(RuntimeException)
417 {
418 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
419 	Any aAny;
420 	aAny <<= Title;
421 	ImplSetPropertyValue( GetPropertyName( BASEPROPERTY_TITLE ), aAny, sal_True );
422 }
423 
424 ::rtl::OUString UnoDialogControl::getTitle() throw(RuntimeException)
425 {
426 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
427 	return ImplGetPropertyValue_UString( BASEPROPERTY_TITLE );
428 }
429 
430 sal_Int16 UnoDialogControl::execute() throw(RuntimeException)
431 {
432 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
433 	sal_Int16 nDone = -1;
434 	if ( getPeer().is() )
435 	{
436 		Reference< XDialog > xDlg( getPeer(), UNO_QUERY );
437 		if( xDlg.is() )
438 		{
439 			GetComponentInfos().bVisible = sal_True;
440 			nDone = xDlg->execute();
441 			GetComponentInfos().bVisible = sal_False;
442 		}
443 	}
444 	return nDone;
445 }
446 
447 void UnoDialogControl::endExecute() throw(RuntimeException)
448 {
449 	vos::OGuard aSolarGuard( Application::GetSolarMutex() );
450 	if ( getPeer().is() )
451 	{
452 		Reference< XDialog > xDlg( getPeer(), UNO_QUERY );
453 		if( xDlg.is() )
454 		{
455 			xDlg->endExecute();
456 			GetComponentInfos().bVisible = sal_False;
457 		}
458 	}
459 }
460 
461 // XModifyListener
462 void SAL_CALL UnoDialogControl::modified(
463     const lang::EventObject& /*rEvent*/ )
464 throw (RuntimeException)
465 {
466     ImplUpdateResourceResolver();
467 }
468 
469 void UnoDialogControl::ImplModelPropertiesChanged( const Sequence< PropertyChangeEvent >& rEvents ) throw(RuntimeException)
470 {
471     sal_Int32 nLen = rEvents.getLength();
472 	for( sal_Int32 i = 0; i < nLen; i++ )
473 	{
474 		const PropertyChangeEvent& rEvt = rEvents.getConstArray()[i];
475 		Reference< XControlModel > xModel( rEvt.Source, UNO_QUERY );
476 		sal_Bool bOwnModel = (XControlModel*)xModel.get() == (XControlModel*)getModel().get();
477         if ( bOwnModel && rEvt.PropertyName.equalsAsciiL( "ImageURL", 8 ))
478         {
479             ::rtl::OUString aImageURL;
480             Reference< graphic::XGraphic > xGraphic;
481             if (( ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_IMAGEURL ) ) >>= aImageURL ) &&
482                 ( aImageURL.getLength() > 0 ))
483             {
484                 ::rtl::OUString absoluteUrl =
485                     getPhysicalLocation( ImplGetPropertyValue( GetPropertyName( BASEPROPERTY_DIALOGSOURCEURL )),
486                                          uno::makeAny(aImageURL));
487 
488                 xGraphic = Impl_getGraphicFromURL_nothrow( absoluteUrl );
489             }
490             ImplSetPropertyValue(  GetPropertyName( BASEPROPERTY_GRAPHIC), uno::makeAny( xGraphic ), sal_True );
491             break;
492         }
493     }
494     ControlContainerBase::ImplModelPropertiesChanged(rEvents);
495 }
496