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