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