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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_framework.hxx"
24 
25 #include <uielement/popuptoolbarcontroller.hxx>
26 #include <framework/menuconfiguration.hxx>
27 #include <toolkit/awt/vclxmenu.hxx>
28 #include <comphelper/processfactory.hxx>
29 #include <svtools/imagemgr.hxx>
30 #include <svtools/miscopt.hxx>
31 #include <toolkit/helper/vclunohelper.hxx>
32 #include <tools/urlobj.hxx>
33 #include <unotools/moduleoptions.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/toolbox.hxx>
36 #include <vos/mutex.hxx>
37 
38 #include <com/sun/star/awt/PopupMenuDirection.hpp>
39 #include <com/sun/star/frame/PopupMenuControllerFactory.hpp>
40 #include <com/sun/star/frame/XDispatchProvider.hpp>
41 
42 #define UNO_COMMAND_RECENT_FILE_LIST    ".uno:RecentFileList"
43 #define SFX_REFERER_USER                "private:user"
44 
45 using rtl::OUString;
46 namespace css = ::com::sun::star;
47 
48 namespace framework
49 {
50 
PopupMenuToolbarController(const css::uno::Reference<css::uno::XComponentContext> & xContext,const OUString & rPopupCommand)51 PopupMenuToolbarController::PopupMenuToolbarController(
52     const css::uno::Reference< css::uno::XComponentContext >& xContext,
53     const OUString &rPopupCommand )
54     : svt::ToolboxController()
55     , m_xContext( xContext )
56     , m_bHasController( sal_False )
57     , m_aPopupCommand( rPopupCommand )
58 {
59 }
60 
~PopupMenuToolbarController()61 PopupMenuToolbarController::~PopupMenuToolbarController()
62 {
63 }
64 
dispose()65 void SAL_CALL PopupMenuToolbarController::dispose()
66 throw ( css::uno::RuntimeException )
67 {
68     svt::ToolboxController::dispose();
69 
70     osl::MutexGuard aGuard( m_aMutex );
71     if( m_xPopupMenuController.is() )
72     {
73         css::uno::Reference< css::lang::XComponent > xComponent(
74             m_xPopupMenuController, css::uno::UNO_QUERY );
75         if( xComponent.is() )
76         {
77             try
78             {
79                 xComponent->dispose();
80             }
81             catch (...)
82             {}
83         }
84         m_xPopupMenuController.clear();
85     }
86 
87     m_xContext.clear();
88     m_xPopupMenuFactory.clear();
89     m_xPopupMenu.clear();
90 }
91 
initialize(const css::uno::Sequence<css::uno::Any> & aArguments)92 void SAL_CALL PopupMenuToolbarController::initialize(
93     const css::uno::Sequence< css::uno::Any >& aArguments )
94 throw ( css::uno::Exception, css::uno::RuntimeException )
95 {
96     ToolboxController::initialize( aArguments );
97 
98     osl::MutexGuard aGuard( m_aMutex );
99     if ( !m_aPopupCommand.getLength() )
100         m_aPopupCommand = m_aCommandURL;
101 
102     try
103     {
104         m_xPopupMenuFactory.set(
105             css::frame::PopupMenuControllerFactory::create( m_xContext ) );
106         m_bHasController = m_xPopupMenuFactory->hasController(
107             m_aPopupCommand, getModuleName() );
108     }
109     catch (const css::uno::Exception& e)
110     {
111         OSL_TRACE( "PopupMenuToolbarController - caught an exception! %s",
112                    rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
113         (void) e;
114     }
115 
116     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
117     ToolBox* pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) );
118     if ( pToolBox )
119     {
120         ToolBoxItemBits nCurStyle( pToolBox->GetItemBits( m_nToolBoxId ) );
121         ToolBoxItemBits nSetStyle( getDropDownStyle() );
122         pToolBox->SetItemBits( m_nToolBoxId,
123                                m_bHasController ?
124                                     nCurStyle | nSetStyle :
125                                     nCurStyle & ~nSetStyle );
126     }
127 
128 }
129 
130 void SAL_CALL
statusChanged(const css::frame::FeatureStateEvent & rEvent)131 PopupMenuToolbarController::statusChanged(
132     const css::frame::FeatureStateEvent& rEvent )
133     throw ( css::uno::RuntimeException )
134 {
135     // TODO move to base class
136 
137     svt::ToolboxController::statusChanged( rEvent );
138     enable( rEvent.IsEnabled );
139 }
140 
141 css::uno::Reference< css::awt::XWindow > SAL_CALL
createPopupWindow()142 PopupMenuToolbarController::createPopupWindow()
143     throw ( css::uno::RuntimeException )
144 {
145     css::uno::Reference< css::awt::XWindow > xRet;
146 
147     osl::MutexGuard aGuard( m_aMutex );
148     if ( !m_bHasController )
149         return xRet;
150 
151     createPopupMenuController();
152 
153     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
154     ToolBox* pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) );
155     if ( !pToolBox )
156         return xRet;
157 
158     pToolBox->SetItemDown( m_nToolBoxId, sal_True );
159     sal_uInt16 nId = m_xPopupMenu->execute(
160         css::uno::Reference< css::awt::XWindowPeer >( getParent(), css::uno::UNO_QUERY ),
161         VCLUnoHelper::ConvertToAWTRect( pToolBox->GetItemRect( m_nToolBoxId ) ),
162         css::awt::PopupMenuDirection::EXECUTE_DEFAULT );
163     pToolBox->SetItemDown( m_nToolBoxId, sal_False );
164 
165     if ( nId )
166         functionExecuted( m_xPopupMenu->getCommand( nId ) );
167 
168     return xRet;
169 }
170 
functionExecuted(const OUString &)171 void PopupMenuToolbarController::functionExecuted( const OUString &/*rCommand*/)
172 {
173 }
174 
getDropDownStyle() const175 sal_uInt16 PopupMenuToolbarController::getDropDownStyle() const
176 {
177     return TIB_DROPDOWN;
178 }
179 
createPopupMenuController()180 void PopupMenuToolbarController::createPopupMenuController()
181 {
182     if( !m_bHasController )
183         return;
184 
185     if ( !m_xPopupMenuController.is() )
186     {
187         css::uno::Sequence< css::uno::Any > aArgs( 2 );
188         css::beans::PropertyValue aProp;
189 
190         aProp.Name = DECLARE_ASCII( "Frame" );
191         aProp.Value <<= m_xFrame;
192         aArgs[0] <<= aProp;
193 
194         aProp.Name = DECLARE_ASCII( "ModuleIdentifier" );
195         aProp.Value <<= getModuleName();
196         aArgs[1] <<= aProp;
197         try
198         {
199             m_xPopupMenu.set(
200                 m_xContext->getServiceManager()->createInstanceWithContext(
201                     DECLARE_ASCII( "com.sun.star.awt.PopupMenu" ), m_xContext ),
202                         css::uno::UNO_QUERY_THROW );
203             m_xPopupMenuController.set(
204                 m_xPopupMenuFactory->createInstanceWithArgumentsAndContext(
205                     m_aPopupCommand, aArgs, m_xContext), css::uno::UNO_QUERY_THROW );
206 
207             m_xPopupMenuController->setPopupMenu( m_xPopupMenu );
208         }
209         catch ( const css::uno::Exception &e )
210         {
211             m_xPopupMenu.clear();
212             OSL_TRACE( "PopupMenuToolbarController - caught an exception! %s",
213                        rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
214             (void) e;
215         }
216     }
217 }
218 
219 DEFINE_XSERVICEINFO_MULTISERVICE_2( WizardsToolbarController,
220                                     ::cppu::OWeakObject,
221                                     DECLARE_ASCII("com.sun.star.frame.ToolbarController"),
222                                     DECLARE_ASCII("org.apache.openoffice.comp.framework.WizardsToolbarController")
223                                    )
224 
225 DEFINE_INIT_SERVICE( WizardsToolbarController, {} )
226 
WizardsToolbarController(const css::uno::Reference<css::uno::XComponentContext> & xContext)227 WizardsToolbarController::WizardsToolbarController(
228     const css::uno::Reference< css::uno::XComponentContext >& xContext )
229     : PopupMenuToolbarController( xContext )
230 {
231 }
232 
getDropDownStyle() const233 sal_uInt16 WizardsToolbarController::getDropDownStyle() const
234 {
235     return TIB_DROPDOWNONLY;
236 }
237 
238 DEFINE_XSERVICEINFO_MULTISERVICE_2( OpenToolbarController,
239                                     ::cppu::OWeakObject,
240                                     DECLARE_ASCII("com.sun.star.frame.ToolbarController"),
241                                     DECLARE_ASCII("org.apache.openoffice.comp.framework.OpenToolbarController")
242                                    )
243 
244 DEFINE_INIT_SERVICE( OpenToolbarController, {} )
245 
OpenToolbarController(const css::uno::Reference<css::uno::XComponentContext> & xContext)246 OpenToolbarController::OpenToolbarController(
247     const css::uno::Reference< css::uno::XComponentContext >& xContext )
248     : PopupMenuToolbarController( xContext, DECLARE_ASCII( UNO_COMMAND_RECENT_FILE_LIST ) )
249 {
250 }
251 
252 
253 DEFINE_XSERVICEINFO_MULTISERVICE_2( NewToolbarController,
254                                     ::cppu::OWeakObject,
255                                     DECLARE_ASCII("com.sun.star.frame.ToolbarController"),
256                                     DECLARE_ASCII("org.apache.openoffice.comp.framework.NewToolbarController")
257                                    )
258 
259 DEFINE_INIT_SERVICE( NewToolbarController, {} )
260 
NewToolbarController(const css::uno::Reference<css::uno::XComponentContext> & xContext)261 NewToolbarController::NewToolbarController(
262     const css::uno::Reference< css::uno::XComponentContext >& xContext )
263     : PopupMenuToolbarController( xContext )
264 {
265 }
266 
267 void SAL_CALL
initialize(const css::uno::Sequence<css::uno::Any> & aArguments)268 NewToolbarController::initialize(
269     const css::uno::Sequence< css::uno::Any >& aArguments )
270 throw ( css::uno::Exception, css::uno::RuntimeException )
271 {
272     PopupMenuToolbarController::initialize( aArguments );
273 
274     osl::MutexGuard aGuard( m_aMutex );
275     createPopupMenuController();
276 }
277 
278 void SAL_CALL
statusChanged(const css::frame::FeatureStateEvent & rEvent)279 NewToolbarController::statusChanged(
280     const css::frame::FeatureStateEvent& rEvent )
281     throw ( css::uno::RuntimeException )
282 {
283     if ( rEvent.IsEnabled )
284     {
285         OUString aState;
286         rEvent.State >>= aState;
287         // set the image even if the state is not a string
288         // this will set the image of the default module
289         setItemImage( aState );
290     }
291 
292     enable( rEvent.IsEnabled );
293 }
294 
295 void SAL_CALL
execute(sal_Int16)296 NewToolbarController::execute( sal_Int16 /*KeyModifier*/ )
297     throw ( css::uno::RuntimeException )
298 {
299     osl::MutexGuard aGuard( m_aMutex );
300     if ( !m_aLastURL.getLength() )
301         return;
302 
303     OUString aTarget( RTL_CONSTASCII_USTRINGPARAM( "_default" ) );
304     if ( m_xPopupMenu.is() )
305     {
306         // TODO investigate how to wrap Get/SetUserValue in css::awt::XMenu
307         MenuConfiguration::Attributes* pMenuAttributes( 0 );
308         VCLXPopupMenu*  pTkPopupMenu =
309             ( VCLXPopupMenu * ) VCLXMenu::GetImplementation( m_xPopupMenu );
310 
311         vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
312         PopupMenu* pVCLPopupMenu = dynamic_cast< PopupMenu * >( pTkPopupMenu->GetMenu() );
313         if ( pVCLPopupMenu )
314             pMenuAttributes = reinterpret_cast< MenuConfiguration::Attributes* >(
315                 pVCLPopupMenu->GetUserValue( pVCLPopupMenu->GetCurItemId() ) );
316 
317         if ( pMenuAttributes )
318             aTarget = pMenuAttributes->aTargetFrame;
319     }
320 
321     css::uno::Sequence< css::beans::PropertyValue > aArgs( 1 );
322     aArgs[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "Referer"  ));
323     aArgs[0].Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( SFX_REFERER_USER ) );
324 
325     dispatchCommand( m_aLastURL, aArgs, aTarget );
326 }
327 
functionExecuted(const OUString & rCommand)328 void NewToolbarController::functionExecuted( const OUString &rCommand )
329 {
330     setItemImage( rCommand );
331 }
332 
333 /**
334     it return the existing state of the given URL in the popupmenu of this toolbox control.
335 
336     If the given URL can be located as an action command of one menu item of the
337     popup menu of this control, we return sal_True. Otherwhise we return sal_False.
338     Further we return a fallback URL, in case we have to return sal_False. Because
339     the outside code must select a valid item of the popup menu everytime ...
340     and we define it here. By the way this m ethod was written to handle
341     error situations gracefully. E.g. it can be called during creation time
342     but then we have no valid menu. For this case we know another fallback URL.
343     Then we return the private:factory/ URL of the default factory.
344 
345     @param  rPopupMenu
346                 pounts to the popup menu, on which item we try to locate the given URL
347                 Can be NULL! Search will be supressed then.
348 
349     @param  sURL
350                 the URL for searching
351 
352     @param  sFallback
353                 contains the fallback URL in case we return FALSE
354                 Must point to valid memory!
355 
356     @param  aImage
357                 contains the image of the menu for the URL.
358 
359     @return sal_True - if URL could be located as an item of the popup menu.
360             sal_False - otherwhise.
361 */
Impl_ExistURLInMenu(const css::uno::Reference<css::awt::XPopupMenu> & rPopupMenu,OUString & sURL,OUString & sFallback,Image & aImage)362 static sal_Bool Impl_ExistURLInMenu(
363     const css::uno::Reference< css::awt::XPopupMenu > &rPopupMenu,
364     OUString &sURL,
365     OUString &sFallback,
366     Image &aImage )
367 {
368     sal_Bool bValidFallback( sal_False );
369     sal_uInt16 nCount( 0 );
370     if ( rPopupMenu.is() && ( nCount = rPopupMenu->getItemCount() ) != 0 && sURL.getLength() )
371     {
372         for ( sal_uInt16 n = 0; n < nCount; ++n )
373         {
374             sal_uInt16 nId = rPopupMenu->getItemId( n );
375             OUString aCmd( rPopupMenu->getCommand( nId ) );
376 
377             if ( !bValidFallback && aCmd.getLength() )
378             {
379                 sFallback = aCmd;
380                 bValidFallback = sal_True;
381             }
382 
383             // match even if the menu command is more detailed
384             // (maybe an additional query) #i28667#
385             if ( aCmd.match( sURL ) )
386             {
387                 sURL = aCmd;
388                 const css::uno::Reference< css::graphic::XGraphic > xGraphic(
389                     rPopupMenu->getItemImage( nId ) );
390                 if ( xGraphic.is() )
391                     aImage = Image( xGraphic );
392                 return sal_True;
393             }
394         }
395     }
396 
397     if ( !bValidFallback )
398     {
399         rtl::OUStringBuffer aBuffer;
400         aBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "private:factory/" ) );
401         aBuffer.append( SvtModuleOptions().GetDefaultModuleName() );
402         sFallback = aBuffer.makeStringAndClear();
403     }
404 
405     return sal_False;
406 }
407 
408 /** We accept URL's here only, which exist as items of our internal popup menu.
409     All other ones will be ignored and a fallback is used.
410  */
setItemImage(const OUString & rCommand)411 void NewToolbarController::setItemImage( const OUString &rCommand )
412 {
413     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
414     ToolBox* pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) );
415     if ( !pToolBox )
416         return;
417 
418     OUString aURL = rCommand;
419     OUString sFallback;
420     Image aMenuImage;
421 
422     sal_Bool bValid( Impl_ExistURLInMenu( m_xPopupMenu, aURL, sFallback, aMenuImage ) );
423     if ( !bValid )
424         aURL = sFallback;
425 
426     sal_Bool bBig = SvtMiscOptions().AreCurrentSymbolsLarge();
427     sal_Bool bHC = pToolBox->GetSettings().GetStyleSettings().GetHighContrastMode();
428 
429     INetURLObject aURLObj( aURL );
430     Image aImage = SvFileInformationManager::GetImageNoDefault( aURLObj, bBig, bHC );
431     if ( !aImage )
432         aImage = !!aMenuImage ?
433             aMenuImage :
434             SvFileInformationManager::GetImage( aURLObj, bBig, bHC );
435 
436     // if everything failed, just use the image associated with the toolbar item command
437     if ( !aImage )
438         return;
439 
440     Size aBigSize( pToolBox->GetDefaultImageSize() );
441     if ( bBig && aImage.GetSizePixel() != aBigSize )
442     {
443         BitmapEx aScaleBmpEx( aImage.GetBitmapEx() );
444         aScaleBmpEx.Scale( aBigSize, BMP_SCALE_INTERPOLATE );
445         pToolBox->SetItemImage( m_nToolBoxId, Image( aScaleBmpEx ) );
446     }
447     else
448         pToolBox->SetItemImage( m_nToolBoxId, aImage );
449 
450     m_aLastURL = aURL;
451 }
452 
453 
454 }
455