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