1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
30 
31 #ifndef __FRAMEWORK_HELPER_TITLEBARUPDATE_HXX_
32 #include <helper/titlebarupdate.hxx>
33 #endif
34 
35 //_________________________________________________________________________________________________________________
36 //	my own includes
37 //_________________________________________________________________________________________________________________
38 
39 #ifndef __FRAMEWORK_PATTERN_WINDOW_HXX_
40 #include <pattern/window.hxx>
41 #endif
42 
43 #ifndef __FRAMEWORK_THREADHELP_WRITEGUARD_HXX_
44 #include <threadhelp/writeguard.hxx>
45 #endif
46 
47 #ifndef __FRAMEWORK_THREADHELP_READGUARD_HXX_
48 #include <threadhelp/readguard.hxx>
49 #endif
50 
51 #ifndef __FRAMEWORK_MACROS_GENERIC_HXX_
52 #include <macros/generic.hxx>
53 #endif
54 
55 #ifndef __FRAMEWORK_SERVICES_H_
56 #include <services.h>
57 #endif
58 
59 #ifndef __FRAMEWORK_PROPETIES_H_
60 #include <properties.h>
61 #endif
62 
63 //_________________________________________________________________________________________________________________
64 //	interface includes
65 //_________________________________________________________________________________________________________________
66 
67 #ifndef _COM_SUN_STAR_AWT_XWINDOW_HPP_
68 #include <com/sun/star/awt/XWindow.hpp>
69 #endif
70 
71 #ifndef _COM_SUN_STAR_LANG_XSERVICXEINFO_HPP_
72 #include <com/sun/star/lang/XServiceInfo.hpp>
73 #endif
74 
75 #ifndef _COM_SUN_STAR_LANG_ILLEGALARGUMENTEXCEPTION_HPP_
76 #include <com/sun/star/lang/IllegalArgumentException.hpp>
77 #endif
78 
79 #ifndef _COM_SUN_STAR_FRAME_XMODULEMANAGER_HPP_
80 #include <com/sun/star/frame/XModuleManager.hpp>
81 #endif
82 
83 #ifndef _COM_SUN_STAR_CONTAINER_XNAMEACCESS_HPP_
84 #include <com/sun/star/container/XNameAccess.hpp>
85 #endif
86 
87 #ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
88 #include <com/sun/star/beans/XPropertySet.hpp>
89 #endif
90 
91 #ifndef _COM_SUN_STAR_BEANS_XMATERIALHOLDER_HPP_
92 #include <com/sun/star/beans/XMaterialHolder.hpp>
93 #endif
94 
95 #ifndef _COM_SUN_STAR_FRAME_XTITLECHANGEBROADCASTER_HPP_
96 #include <com/sun/star/frame/XTitleChangeBroadcaster.hpp>
97 #endif
98 
99 #ifndef _COM_SUN_STAR_BEANS_NAMEDVALUE_HPP_
100 #include <com/sun/star/beans/NamedValue.hpp>
101 #endif
102 
103 //_________________________________________________________________________________________________________________
104 //	other includes
105 //_________________________________________________________________________________________________________________
106 
107 #include <comphelper/sequenceashashmap.hxx>
108 #include <unotools/configmgr.hxx>
109 #include <unotools/bootstrap.hxx>
110 #include <vcl/window.hxx>
111 #include <vcl/syswin.hxx>
112 #include <toolkit/unohlp.hxx>
113 #include <vcl/svapp.hxx>
114 #include <vcl/wrkwin.hxx>
115 #include <tools/diagnose_ex.h>
116 
117 //_________________________________________________________________________________________________________________
118 //	namespace
119 
120 namespace framework{
121 
122 //_________________________________________________________________________________________________________________
123 //	const
124 
125 static const ::sal_Int32 INVALID_ICON_ID = -1;
126 static const ::sal_Int32 DEFAULT_ICON_ID =  0;
127 
128 //_________________________________________________________________________________________________________________
129 //	definitions
130 
131 //*****************************************************************************************************************
132 //  XInterface, XTypeProvider
133 
134 DEFINE_XINTERFACE_5(TitleBarUpdate                                                              ,
135                     OWeakObject                                                                 ,
136                     DIRECT_INTERFACE (css::lang::XTypeProvider                                  ),
137                     DIRECT_INTERFACE (css::lang::XInitialization                                ),
138                     DIRECT_INTERFACE (css::frame::XFrameActionListener                          ),
139                     DIRECT_INTERFACE (css::frame::XTitleChangeListener                          ),
140                     DERIVED_INTERFACE(css::lang::XEventListener,css::frame::XFrameActionListener))
141 
142 DEFINE_XTYPEPROVIDER_5(TitleBarUpdate                  ,
143                        css::lang::XTypeProvider        ,
144                        css::lang::XInitialization      ,
145                        css::frame::XFrameActionListener,
146                        css::frame::XTitleChangeListener,
147                        css::lang::XEventListener       )
148 
149 //*****************************************************************************************************************
150 TitleBarUpdate::TitleBarUpdate(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
151     : ThreadHelpBase          (&Application::GetSolarMutex())
152     , m_xSMGR                 (xSMGR                        )
153     , m_xFrame                (                             )
154 {
155 }
156 
157 //*****************************************************************************************************************
158 TitleBarUpdate::~TitleBarUpdate()
159 {
160 }
161 
162 //*****************************************************************************************************************
163 void SAL_CALL TitleBarUpdate::initialize(const css::uno::Sequence< css::uno::Any >& lArguments)
164     throw(css::uno::Exception       ,
165           css::uno::RuntimeException)
166 {
167     // check arguments
168     css::uno::Reference< css::frame::XFrame > xFrame;
169     if (lArguments.getLength() < 1)
170         throw css::lang::IllegalArgumentException(
171                 DECLARE_ASCII("Empty argument list!"),
172                 static_cast< ::cppu::OWeakObject* >(this),
173                 1);
174 
175     lArguments[0] >>= xFrame;
176     if (!xFrame.is())
177         throw css::lang::IllegalArgumentException(
178                 DECLARE_ASCII("No valid frame specified!"),
179                 static_cast< ::cppu::OWeakObject* >(this),
180                 1);
181 
182     // SYNCHRONIZED ->
183     WriteGuard aWriteLock(m_aLock);
184     // hold the frame as weak reference(!) so it can die everytimes :-)
185     m_xFrame = xFrame;
186     aWriteLock.unlock();
187     // <- SYNCHRONIZED
188 
189     // start listening
190     xFrame->addFrameActionListener(this);
191 
192     css::uno::Reference< css::frame::XTitleChangeBroadcaster > xBroadcaster(xFrame, css::uno::UNO_QUERY);
193     if (xBroadcaster.is ())
194         xBroadcaster->addTitleChangeListener (this);
195 }
196 
197 //*****************************************************************************************************************
198 void SAL_CALL TitleBarUpdate::frameAction(const css::frame::FrameActionEvent& aEvent)
199     throw(css::uno::RuntimeException)
200 {
201     // we are interested on events only, which must trigger a title bar update
202     // because component was changed.
203     if (
204         (aEvent.Action == css::frame::FrameAction_COMPONENT_ATTACHED  ) ||
205         (aEvent.Action == css::frame::FrameAction_COMPONENT_REATTACHED) ||
206         (aEvent.Action == css::frame::FrameAction_COMPONENT_DETACHING )
207        )
208     {
209         impl_forceUpdate ();
210     }
211 }
212 
213 //*****************************************************************************************************************
214 void SAL_CALL TitleBarUpdate::titleChanged(const css::frame::TitleChangedEvent& /* aEvent */)
215     throw (css::uno::RuntimeException)
216 {
217     impl_forceUpdate ();
218 }
219 
220 //*****************************************************************************************************************
221 void SAL_CALL TitleBarUpdate::disposing(const css::lang::EventObject&)
222     throw(css::uno::RuntimeException)
223 {
224     // nothing todo here - because we hold the frame as weak reference only
225 }
226 
227 //*****************************************************************************************************************
228 ::sal_Bool TitleBarUpdate::implst_getModuleInfo(const css::uno::Reference< css::frame::XFrame >& xFrame,
229                                                       TModuleInfo&                               rInfo )
230 {
231     if ( ! xFrame.is ())
232         return sal_False;
233 
234     // SYNCHRONIZED ->
235     ReadGuard aReadLock(m_aLock);
236     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
237     aReadLock.unlock();
238     // <- SYNCHRONIZED
239 
240     try
241     {
242         css::uno::Reference< css::frame::XModuleManager > xModuleManager(
243             xSMGR->createInstance(SERVICENAME_MODULEMANAGER),
244             css::uno::UNO_QUERY_THROW);
245 
246         css::uno::Reference< css::container::XNameAccess > xConfig(
247             xModuleManager,
248             css::uno::UNO_QUERY_THROW);
249 
250                                         rInfo.sID = xModuleManager->identify(xFrame);
251         ::comphelper::SequenceAsHashMap lProps    = xConfig->getByName (rInfo.sID);
252 
253         rInfo.sUIName = lProps.getUnpackedValueOrDefault (OFFICEFACTORY_PROPNAME_UINAME, ::rtl::OUString());
254         rInfo.nIcon   = lProps.getUnpackedValueOrDefault (OFFICEFACTORY_PROPNAME_ICON  , INVALID_ICON_ID  );
255 
256 		// Note: If we could retrieve a module id ... everything is OK.
257 		// UIName and Icon ID are optional values !
258         ::sal_Bool bSuccess = (rInfo.sID.getLength () > 0);
259         return bSuccess;
260     }
261     catch(const css::uno::Exception&)
262         {}
263 
264     return sal_False;
265 }
266 
267 //*****************************************************************************************************************
268 void TitleBarUpdate::impl_forceUpdate()
269 {
270     // SYNCHRONIZED ->
271     ReadGuard aReadLock(m_aLock);
272     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR ;
273     css::uno::Reference< css::frame::XFrame >              xFrame(m_xFrame.get(), css::uno::UNO_QUERY);
274     aReadLock.unlock();
275     // <- SYNCHRONIZED
276 
277     // frame already gone ? We hold it weak only ...
278     if ( ! xFrame.is())
279         return;
280 
281     // no window -> no chance to set/update title and icon
282     css::uno::Reference< css::awt::XWindow > xWindow = xFrame->getContainerWindow();
283     if ( ! xWindow.is())
284         return;
285 
286     impl_updateIcon  (xFrame);
287     impl_updateTitle (xFrame);
288 }
289 
290 //*****************************************************************************************************************
291 void TitleBarUpdate::impl_updateIcon(const css::uno::Reference< css::frame::XFrame >& xFrame)
292 {
293     css::uno::Reference< css::frame::XController > xController = xFrame->getController      ();
294     css::uno::Reference< css::awt::XWindow >       xWindow     = xFrame->getContainerWindow ();
295 
296     if (
297         ( ! xController.is() ) ||
298         ( ! xWindow.is()     )
299        )
300         return;
301 
302     // a) set default value to an invalid one. So we can start further searches for right icon id, if
303     //    first steps failed!
304     sal_Int32 nIcon = INVALID_ICON_ID;
305 
306     // b) try to find information on controller property set directly
307     //    Don't forget to catch possible exceptions - because these property is an optional one!
308     css::uno::Reference< css::beans::XPropertySet > xSet( xController, css::uno::UNO_QUERY );
309     if ( xSet.is() )
310     {
311         try
312         {
313             css::uno::Reference< css::beans::XPropertySetInfo > const xPSI( xSet->getPropertySetInfo(), css::uno::UNO_SET_THROW );
314             if ( xPSI->hasPropertyByName( CONTROLLER_PROPNAME_ICONID ) )
315                 xSet->getPropertyValue( CONTROLLER_PROPNAME_ICONID ) >>= nIcon;
316         }
317         catch(const css::uno::Exception&)
318         {
319             DBG_UNHANDLED_EXCEPTION();
320         }
321     }
322 
323     // c) if b) failed ... identify the used module and retrieve set icon from module config.
324     //    Tirck :-) Module was already specified outside and aInfo contains all needed informations.
325     if ( nIcon == INVALID_ICON_ID )
326 	{
327 		TModuleInfo aInfo;
328 		if (implst_getModuleInfo(xFrame, aInfo))
329 			nIcon = aInfo.nIcon;
330 	}
331 
332     // d) if all steps failed - use fallback :-)
333     //    ... means using the global staroffice icon
334     if( nIcon == INVALID_ICON_ID )
335         nIcon = DEFAULT_ICON_ID;
336 
337     // e) set icon on container window now
338     //    Don't forget SolarMutex! We use vcl directly :-(
339     //    Check window pointer for right WorkWindow class too!!!
340 
341     // VCL SYNCHRONIZED ->
342     ::vos::OClearableGuard aSolarLock( Application::GetSolarMutex() );
343 
344     Window* pWindow = (VCLUnoHelper::GetWindow( xWindow ));
345     if (
346         ( pWindow                                 ) &&
347         ( pWindow->GetType() == WINDOW_WORKWINDOW )
348        )
349     {
350         WorkWindow* pWorkWindow = (WorkWindow*)pWindow;
351         pWorkWindow->SetIcon( (sal_uInt16)nIcon );
352 
353         css::uno::Reference< css::frame::XModel > xModel = xController->getModel();
354         rtl::OUString aURL;
355         if( xModel.is() )
356             aURL = xModel->getURL();
357         pWorkWindow->SetRepresentedURL( aURL );
358     }
359 
360     aSolarLock.clear();
361     // <- VCL SYNCHRONIZED
362 }
363 
364 //*****************************************************************************************************************
365 void TitleBarUpdate::impl_updateTitle(const css::uno::Reference< css::frame::XFrame >& xFrame)
366 {
367 	// no window ... no chance to set any title -> return
368     css::uno::Reference< css::awt::XWindow > xWindow = xFrame->getContainerWindow ();
369     if ( ! xWindow.is() )
370         return;
371 
372 	css::uno::Reference< css::frame::XTitle > xTitle(xFrame, css::uno::UNO_QUERY);
373 	if ( ! xTitle.is() )
374 		return;
375 
376 	const ::rtl::OUString sTitle = xTitle->getTitle ();
377 
378     // VCL SYNCHRONIZED ->
379     ::vos::OClearableGuard aSolarLock( Application::GetSolarMutex() );
380 
381     Window* pWindow = (VCLUnoHelper::GetWindow( xWindow ));
382     if (
383         ( pWindow                                 ) &&
384         ( pWindow->GetType() == WINDOW_WORKWINDOW )
385        )
386     {
387         WorkWindow* pWorkWindow = (WorkWindow*)pWindow;
388         pWorkWindow->SetText( sTitle );
389     }
390 
391     aSolarLock.clear();
392     // <- VCL SYNCHRONIZED
393 }
394 
395 } // namespace framework
396