1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <bitmaps.hlst>
21
22 #include <cppuhelper/implbase.hxx>
23 #include <cppuhelper/supportsservice.hxx>
24 #include <comphelper/propertyvalue.hxx>
25 #include <menuconfiguration.hxx>
26 #include <svtools/imagemgr.hxx>
27 #include <svtools/toolboxcontroller.hxx>
28 #include <toolkit/awt/vclxmenu.hxx>
29 #include <toolkit/helper/vclunohelper.hxx>
30 #include <tools/diagnose_ex.h>
31 #include <tools/urlobj.hxx>
32 #include <vcl/commandinfoprovider.hxx>
33 #include <vcl/menu.hxx>
34 #include <vcl/svapp.hxx>
35 #include <vcl/toolbox.hxx>
36
37 #include <com/sun/star/awt/PopupMenuDirection.hpp>
38 #include <com/sun/star/awt/XPopupMenu.hpp>
39 #include <com/sun/star/frame/thePopupMenuControllerFactory.hpp>
40 #include <com/sun/star/frame/XPopupMenuController.hpp>
41 #include <com/sun/star/frame/XStorable.hpp>
42 #include <com/sun/star/frame/XSubToolbarController.hpp>
43 #include <com/sun/star/frame/XUIControllerFactory.hpp>
44 #include <com/sun/star/frame/XController.hpp>
45 #include <com/sun/star/lang/XServiceInfo.hpp>
46 #include <com/sun/star/ucb/CommandFailedException.hpp>
47 #include <com/sun/star/ucb/ContentCreationException.hpp>
48 #include <com/sun/star/util/XModifiable.hpp>
49
50 using namespace framework;
51
52 namespace
53 {
54
55 typedef cppu::ImplInheritanceHelper< svt::ToolboxController,
56 css::lang::XServiceInfo >
57 ToolBarBase;
58
59 class PopupMenuToolbarController : public ToolBarBase
60 {
61 public:
62 // XComponent
63 virtual void SAL_CALL dispose() override;
64 // XInitialization
65 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
66 // XToolbarController
67 virtual css::uno::Reference< css::awt::XWindow > SAL_CALL createPopupWindow() override;
68 // XStatusListener
69 virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
70
71 protected:
72 PopupMenuToolbarController( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
73 const OUString &rPopupCommand = OUString() );
74 virtual void functionExecuted( const OUString &rCommand );
75 virtual ToolBoxItemBits getDropDownStyle() const;
76 void createPopupMenuController();
77
78 bool m_bHasController;
79 bool m_bResourceURL;
80 OUString m_aPopupCommand;
81 css::uno::Reference< css::awt::XPopupMenu > m_xPopupMenu;
82
83 private:
84 css::uno::Reference< css::frame::XUIControllerFactory > m_xPopupMenuFactory;
85 css::uno::Reference< css::frame::XPopupMenuController > m_xPopupMenuController;
86 };
87
PopupMenuToolbarController(const css::uno::Reference<css::uno::XComponentContext> & xContext,const OUString & rPopupCommand)88 PopupMenuToolbarController::PopupMenuToolbarController(
89 const css::uno::Reference< css::uno::XComponentContext >& xContext,
90 const OUString &rPopupCommand )
91 : ToolBarBase( xContext, css::uno::Reference< css::frame::XFrame >(), /*aCommandURL*/OUString() )
92 , m_bHasController( false )
93 , m_bResourceURL( false )
94 , m_aPopupCommand( rPopupCommand )
95 {
96 }
97
dispose()98 void SAL_CALL PopupMenuToolbarController::dispose()
99 {
100 svt::ToolboxController::dispose();
101
102 osl::MutexGuard aGuard( m_aMutex );
103 if( m_xPopupMenuController.is() )
104 {
105 css::uno::Reference< css::lang::XComponent > xComponent(
106 m_xPopupMenuController, css::uno::UNO_QUERY );
107 if( xComponent.is() )
108 {
109 try
110 {
111 xComponent->dispose();
112 }
113 catch (...)
114 {}
115 }
116 m_xPopupMenuController.clear();
117 }
118
119 m_xContext.clear();
120 m_xPopupMenuFactory.clear();
121 m_xPopupMenu.clear();
122 }
123
initialize(const css::uno::Sequence<css::uno::Any> & aArguments)124 void SAL_CALL PopupMenuToolbarController::initialize(
125 const css::uno::Sequence< css::uno::Any >& aArguments )
126 {
127 ToolboxController::initialize( aArguments );
128
129 osl::MutexGuard aGuard( m_aMutex );
130 if ( !m_aPopupCommand.getLength() )
131 m_aPopupCommand = m_aCommandURL;
132
133 try
134 {
135 m_xPopupMenuFactory.set(
136 css::frame::thePopupMenuControllerFactory::get( m_xContext ) );
137 m_bHasController = m_xPopupMenuFactory->hasController(
138 m_aPopupCommand, getModuleName() );
139 }
140 catch (const css::uno::Exception&)
141 {
142 TOOLS_INFO_EXCEPTION( "fwk.uielement", "" );
143 }
144
145 if ( !m_bHasController && m_aPopupCommand.startsWith( "private:resource/" ) )
146 {
147 m_bResourceURL = true;
148 m_bHasController = true;
149 }
150
151 SolarMutexGuard aSolarLock;
152 ToolBox* pToolBox = nullptr;
153 ToolBoxItemId nItemId;
154 if ( getToolboxId( nItemId, &pToolBox ) )
155 {
156 ToolBoxItemBits nCurStyle( pToolBox->GetItemBits( nItemId ) );
157 ToolBoxItemBits nSetStyle( getDropDownStyle() );
158 pToolBox->SetItemBits( nItemId,
159 m_bHasController ?
160 nCurStyle | nSetStyle :
161 nCurStyle & ~nSetStyle );
162 }
163
164 }
165
statusChanged(const css::frame::FeatureStateEvent & rEvent)166 void SAL_CALL PopupMenuToolbarController::statusChanged( const css::frame::FeatureStateEvent& rEvent )
167 {
168 if ( m_bResourceURL )
169 return;
170
171 ToolBox* pToolBox = nullptr;
172 ToolBoxItemId nItemId;
173 if ( getToolboxId( nItemId, &pToolBox ) )
174 {
175 SolarMutexGuard aSolarLock;
176 pToolBox->EnableItem( nItemId, rEvent.IsEnabled );
177 bool bValue;
178 if ( rEvent.State >>= bValue )
179 pToolBox->CheckItem( nItemId, bValue );
180 }
181 }
182
183 css::uno::Reference< css::awt::XWindow > SAL_CALL
createPopupWindow()184 PopupMenuToolbarController::createPopupWindow()
185 {
186 css::uno::Reference< css::awt::XWindow > xRet;
187
188 osl::MutexGuard aGuard( m_aMutex );
189 if ( !m_bHasController )
190 return xRet;
191
192 createPopupMenuController();
193
194 SolarMutexGuard aSolarLock;
195 VclPtr< ToolBox > pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) );
196 if ( !pToolBox )
197 return xRet;
198
199 pToolBox->SetItemDown( m_nToolBoxId, true );
200 WindowAlign eAlign( pToolBox->GetAlign() );
201
202 // If the parent ToolBox is in popup mode (e.g. sub toolbar, overflow popup),
203 // its ToolBarManager can be disposed along with our controller, destroying
204 // m_xPopupMenu, while the latter still in execute. This should be fixed at a
205 // different level, for now just hold it here so it won't crash.
206 css::uno::Reference< css::awt::XPopupMenu > xPopupMenu ( m_xPopupMenu );
207 sal_uInt16 nId = xPopupMenu->execute(
208 css::uno::Reference< css::awt::XWindowPeer >( getParent(), css::uno::UNO_QUERY ),
209 VCLUnoHelper::ConvertToAWTRect( pToolBox->GetItemRect( m_nToolBoxId ) ),
210 ( eAlign == WindowAlign::Top || eAlign == WindowAlign::Bottom ) ?
211 css::awt::PopupMenuDirection::EXECUTE_DOWN :
212 css::awt::PopupMenuDirection::EXECUTE_RIGHT );
213 pToolBox->SetItemDown( m_nToolBoxId, false );
214
215 if ( nId )
216 functionExecuted( xPopupMenu->getCommand( nId ) );
217
218 return xRet;
219 }
220
functionExecuted(const OUString &)221 void PopupMenuToolbarController::functionExecuted( const OUString &/*rCommand*/)
222 {
223 }
224
getDropDownStyle() const225 ToolBoxItemBits PopupMenuToolbarController::getDropDownStyle() const
226 {
227 return ToolBoxItemBits::DROPDOWN;
228 }
229
createPopupMenuController()230 void PopupMenuToolbarController::createPopupMenuController()
231 {
232 if( !m_bHasController )
233 return;
234
235 if ( m_xPopupMenuController.is() )
236 {
237 m_xPopupMenuController->updatePopupMenu();
238 }
239 else
240 {
241 css::uno::Sequence<css::uno::Any> aArgs {
242 css::uno::makeAny(comphelper::makePropertyValue("Frame", m_xFrame)),
243 css::uno::makeAny(comphelper::makePropertyValue("ModuleIdentifier", m_sModuleName)),
244 css::uno::makeAny(comphelper::makePropertyValue("InToolbar", true))
245 };
246
247 try
248 {
249 m_xPopupMenu.set(
250 m_xContext->getServiceManager()->createInstanceWithContext(
251 "com.sun.star.awt.PopupMenu", m_xContext ),
252 css::uno::UNO_QUERY_THROW );
253
254 if (m_bResourceURL)
255 {
256 sal_Int32 nAppendIndex = aArgs.getLength();
257 aArgs.realloc(nAppendIndex + 1);
258 aArgs[nAppendIndex] <<= comphelper::makePropertyValue("ResourceURL", m_aPopupCommand);
259
260 m_xPopupMenuController.set( m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
261 "com.sun.star.comp.framework.ResourceMenuController", aArgs, m_xContext), css::uno::UNO_QUERY_THROW );
262 }
263 else
264 {
265 m_xPopupMenuController.set( m_xPopupMenuFactory->createInstanceWithArgumentsAndContext(
266 m_aPopupCommand, aArgs, m_xContext), css::uno::UNO_QUERY_THROW );
267 }
268
269 m_xPopupMenuController->setPopupMenu( m_xPopupMenu );
270 }
271 catch ( const css::uno::Exception & )
272 {
273 TOOLS_INFO_EXCEPTION( "fwk.uielement", "" );
274 m_xPopupMenu.clear();
275 }
276 }
277 }
278
279 class GenericPopupToolbarController : public PopupMenuToolbarController
280 {
281 public:
282 GenericPopupToolbarController( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
283 const css::uno::Sequence< css::uno::Any >& rxArgs );
284
285 // XInitialization
286 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& rxArgs ) override;
287
288 // XStatusListener
289 virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
290
291 // XServiceInfo
292 virtual OUString SAL_CALL getImplementationName() override;
293
294 virtual sal_Bool SAL_CALL supportsService(OUString const & rServiceName) override;
295
296 virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
297
298 private:
299 bool m_bSplitButton, m_bReplaceWithLast;
300 void functionExecuted(const OUString &rCommand) override;
301 ToolBoxItemBits getDropDownStyle() const override;
302 };
303
GenericPopupToolbarController(const css::uno::Reference<css::uno::XComponentContext> & xContext,const css::uno::Sequence<css::uno::Any> & rxArgs)304 GenericPopupToolbarController::GenericPopupToolbarController(
305 const css::uno::Reference< css::uno::XComponentContext >& xContext,
306 const css::uno::Sequence< css::uno::Any >& rxArgs )
307 : PopupMenuToolbarController( xContext )
308 , m_bReplaceWithLast( false )
309 {
310 css::beans::PropertyValue aPropValue;
311 for ( const auto& arg: rxArgs )
312 {
313 if ( ( arg >>= aPropValue ) && aPropValue.Name == "Value" )
314 {
315 sal_Int32 nIdx{ 0 };
316 OUString aValue;
317 aPropValue.Value >>= aValue;
318 m_aPopupCommand = aValue.getToken(0, ';', nIdx);
319 m_bReplaceWithLast = aValue.getToken(0, ';', nIdx).toBoolean();
320 break;
321 }
322 }
323 m_bSplitButton = m_bReplaceWithLast || !m_aPopupCommand.isEmpty();
324 }
325
getImplementationName()326 OUString GenericPopupToolbarController::getImplementationName()
327 {
328 return "com.sun.star.comp.framework.GenericPopupToolbarController";
329 }
330
supportsService(OUString const & rServiceName)331 sal_Bool GenericPopupToolbarController::supportsService(OUString const & rServiceName)
332 {
333 return cppu::supportsService( this, rServiceName );
334 }
335
getSupportedServiceNames()336 css::uno::Sequence<OUString> GenericPopupToolbarController::getSupportedServiceNames()
337 {
338 return {"com.sun.star.frame.ToolbarController"};
339 }
340
initialize(const css::uno::Sequence<css::uno::Any> & rxArgs)341 void GenericPopupToolbarController::initialize( const css::uno::Sequence< css::uno::Any >& rxArgs )
342 {
343 PopupMenuToolbarController::initialize( rxArgs );
344 if ( m_bReplaceWithLast )
345 // Create early, so we can use the menu is statusChanged method.
346 createPopupMenuController();
347 }
348
statusChanged(const css::frame::FeatureStateEvent & rEvent)349 void GenericPopupToolbarController::statusChanged( const css::frame::FeatureStateEvent& rEvent )
350 {
351 SolarMutexGuard aGuard;
352
353 if ( m_bReplaceWithLast && !rEvent.IsEnabled && m_xPopupMenu.is() )
354 {
355 Menu* pVclMenu = comphelper::getUnoTunnelImplementation<VCLXMenu>( m_xPopupMenu )->GetMenu();
356
357 ToolBox* pToolBox = nullptr;
358 ToolBoxItemId nId;
359 if ( getToolboxId( nId, &pToolBox ) && pToolBox->IsItemEnabled( nId ) )
360 {
361 pVclMenu->Activate();
362 pVclMenu->Deactivate();
363 }
364
365 for ( sal_uInt16 i = 0; i < pVclMenu->GetItemCount(); ++i )
366 {
367 sal_uInt16 nItemId = pVclMenu->GetItemId( i );
368 if ( nItemId && pVclMenu->IsItemEnabled( nItemId ) && !pVclMenu->GetPopupMenu( nItemId ) )
369 {
370 functionExecuted( pVclMenu->GetItemCommand( nItemId ) );
371 return;
372 }
373 }
374 }
375
376 PopupMenuToolbarController::statusChanged( rEvent );
377 }
378
functionExecuted(const OUString & rCommand)379 void GenericPopupToolbarController::functionExecuted( const OUString& rCommand )
380 {
381 if ( !m_bReplaceWithLast )
382 return;
383
384 removeStatusListener( m_aCommandURL );
385
386 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(rCommand, m_sModuleName);
387 OUString aRealCommand( vcl::CommandInfoProvider::GetRealCommandForCommand(aProperties) );
388 m_aCommandURL = aRealCommand.isEmpty() ? rCommand : aRealCommand;
389 addStatusListener( m_aCommandURL );
390
391 ToolBox* pToolBox = nullptr;
392 ToolBoxItemId nId;
393 if ( getToolboxId( nId, &pToolBox ) )
394 {
395 pToolBox->SetItemCommand( nId, rCommand );
396 pToolBox->SetHelpText( nId, OUString() ); // Will retrieve the new one from help.
397 pToolBox->SetItemText(nId, vcl::CommandInfoProvider::GetLabelForCommand(aProperties));
398 pToolBox->SetQuickHelpText(nId, vcl::CommandInfoProvider::GetTooltipForCommand(rCommand, aProperties, m_xFrame));
399
400 Image aImage = vcl::CommandInfoProvider::GetImageForCommand(rCommand, m_xFrame, pToolBox->GetImageSize());
401 if ( !!aImage )
402 pToolBox->SetItemImage( nId, aImage );
403 }
404 }
405
getDropDownStyle() const406 ToolBoxItemBits GenericPopupToolbarController::getDropDownStyle() const
407 {
408 return m_bSplitButton ? ToolBoxItemBits::DROPDOWN : ToolBoxItemBits::DROPDOWNONLY;
409 }
410
411 class SaveToolbarController : public cppu::ImplInheritanceHelper< PopupMenuToolbarController,
412 css::frame::XSubToolbarController,
413 css::util::XModifyListener >
414 {
415 public:
416 explicit SaveToolbarController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
417
418 // XInitialization
419 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
420
421 // XSubToolbarController
422 // Make ToolBarManager ask our controller for updated image, in case of icon theme change.
423 virtual sal_Bool SAL_CALL opensSubToolbar() override;
424 virtual OUString SAL_CALL getSubToolbarName() override;
425 virtual void SAL_CALL functionSelected( const OUString& aCommand ) override;
426 virtual void SAL_CALL updateImage() override;
427
428 // XStatusListener
429 virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
430
431 // XModifyListener
432 virtual void SAL_CALL modified( const css::lang::EventObject& rEvent ) override;
433
434 // XEventListener
435 virtual void SAL_CALL disposing( const css::lang::EventObject& rEvent ) override;
436
437 // XComponent
438 virtual void SAL_CALL dispose() override;
439
440 // XServiceInfo
441 virtual OUString SAL_CALL getImplementationName() override;
442 virtual sal_Bool SAL_CALL supportsService( OUString const & rServiceName ) override;
443 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
444
445 private:
446 bool m_bReadOnly;
447 bool m_bModified;
448 css::uno::Reference< css::frame::XStorable > m_xStorable;
449 css::uno::Reference< css::util::XModifiable > m_xModifiable;
450 };
451
SaveToolbarController(const css::uno::Reference<css::uno::XComponentContext> & rxContext)452 SaveToolbarController::SaveToolbarController( const css::uno::Reference< css::uno::XComponentContext >& rxContext )
453 : ImplInheritanceHelper( rxContext, ".uno:SaveAsMenu" )
454 , m_bReadOnly( false )
455 , m_bModified( false )
456 {
457 }
458
initialize(const css::uno::Sequence<css::uno::Any> & aArguments)459 void SaveToolbarController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
460 {
461 PopupMenuToolbarController::initialize( aArguments );
462
463 ToolBox* pToolBox = nullptr;
464 ToolBoxItemId nId;
465 if ( !getToolboxId( nId, &pToolBox ) )
466 return;
467
468 css::uno::Reference< css::frame::XController > xController = m_xFrame->getController();
469 if ( xController.is() )
470 m_xModifiable.set( xController->getModel(), css::uno::UNO_QUERY );
471
472 if ( m_xModifiable.is() && pToolBox->GetItemCommand( nId ) == m_aCommandURL )
473 // Will also enable the save as only mode.
474 m_xStorable.set( m_xModifiable, css::uno::UNO_QUERY );
475 else if ( !m_xModifiable.is() )
476 // Can be in table/query design.
477 m_xModifiable.set( xController, css::uno::UNO_QUERY );
478 else
479 // Simple save button, without the dropdown.
480 pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) & ~ ToolBoxItemBits::DROPDOWN );
481
482 if ( m_xModifiable.is() )
483 {
484 m_xModifiable->addModifyListener( this );
485 modified( css::lang::EventObject() );
486 }
487 }
488
opensSubToolbar()489 sal_Bool SaveToolbarController::opensSubToolbar()
490 {
491 return true;
492 }
493
getSubToolbarName()494 OUString SaveToolbarController::getSubToolbarName()
495 {
496 return OUString();
497 }
498
functionSelected(const OUString &)499 void SaveToolbarController::functionSelected( const OUString& /*aCommand*/ )
500 {
501 }
502
updateImage()503 void SaveToolbarController::updateImage()
504 {
505 SolarMutexGuard aGuard;
506 ToolBox* pToolBox = nullptr;
507 ToolBoxItemId nId;
508 if ( !getToolboxId( nId, &pToolBox ) )
509 return;
510
511 vcl::ImageType eImageType = pToolBox->GetImageSize();
512
513 Image aImage;
514
515 if ( m_bReadOnly )
516 {
517 aImage = vcl::CommandInfoProvider::GetImageForCommand(".uno:SaveAs", m_xFrame, eImageType);
518 }
519 else if ( m_bModified )
520 {
521 if (eImageType == vcl::ImageType::Size26)
522 aImage = Image(StockImage::Yes, BMP_SAVEMODIFIED_LARGE);
523 else if (eImageType == vcl::ImageType::Size32)
524 aImage = Image(StockImage::Yes, BMP_SAVEMODIFIED_EXTRALARGE);
525 else
526 aImage = Image(StockImage::Yes, BMP_SAVEMODIFIED_SMALL);
527 }
528
529 if ( !aImage )
530 aImage = vcl::CommandInfoProvider::GetImageForCommand(m_aCommandURL, m_xFrame, eImageType);
531
532 if ( !!aImage )
533 pToolBox->SetItemImage( nId, aImage );
534 }
535
statusChanged(const css::frame::FeatureStateEvent & rEvent)536 void SaveToolbarController::statusChanged( const css::frame::FeatureStateEvent& rEvent )
537 {
538 ToolBox* pToolBox = nullptr;
539 ToolBoxItemId nId;
540 if ( !getToolboxId( nId, &pToolBox ) )
541 return;
542
543 bool bLastReadOnly = m_bReadOnly;
544 m_bReadOnly = m_xStorable.is() && m_xStorable->isReadonly();
545 if ( bLastReadOnly != m_bReadOnly )
546 {
547 OUString sCommand = m_bReadOnly ? OUString( ".uno:SaveAs" ) : m_aCommandURL;
548 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(sCommand,
549 vcl::CommandInfoProvider::GetModuleIdentifier(m_xFrame));
550 pToolBox->SetQuickHelpText( nId,
551 vcl::CommandInfoProvider::GetTooltipForCommand(sCommand, aProperties, m_xFrame) );
552 pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) & ~( m_bReadOnly ? ToolBoxItemBits::DROPDOWN : ToolBoxItemBits::DROPDOWNONLY ) );
553 pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ( m_bReadOnly ? ToolBoxItemBits::DROPDOWNONLY : ToolBoxItemBits::DROPDOWN ) );
554 updateImage();
555 }
556
557 if ( !m_bReadOnly )
558 pToolBox->EnableItem( nId, rEvent.IsEnabled );
559 }
560
modified(const css::lang::EventObject &)561 void SaveToolbarController::modified( const css::lang::EventObject& /*rEvent*/ )
562 {
563 bool bLastModified = m_bModified;
564 m_bModified = m_xModifiable->isModified();
565 if ( bLastModified != m_bModified )
566 updateImage();
567 }
568
disposing(const css::lang::EventObject & rEvent)569 void SaveToolbarController::disposing( const css::lang::EventObject& rEvent )
570 {
571 if ( rEvent.Source == m_xModifiable )
572 {
573 m_xModifiable.clear();
574 m_xStorable.clear();
575 }
576 else
577 PopupMenuToolbarController::disposing( rEvent );
578 }
579
dispose()580 void SaveToolbarController::dispose()
581 {
582 PopupMenuToolbarController::dispose();
583 if ( m_xModifiable.is() )
584 {
585 m_xModifiable->removeModifyListener( this );
586 m_xModifiable.clear();
587 }
588 m_xStorable.clear();
589 }
590
getImplementationName()591 OUString SaveToolbarController::getImplementationName()
592 {
593 return "com.sun.star.comp.framework.SaveToolbarController";
594 }
595
supportsService(OUString const & rServiceName)596 sal_Bool SaveToolbarController::supportsService( OUString const & rServiceName )
597 {
598 return cppu::supportsService( this, rServiceName );
599 }
600
getSupportedServiceNames()601 css::uno::Sequence< OUString > SaveToolbarController::getSupportedServiceNames()
602 {
603 return {"com.sun.star.frame.ToolbarController"};
604 }
605
606 class NewToolbarController : public cppu::ImplInheritanceHelper<PopupMenuToolbarController, css::frame::XSubToolbarController>
607 {
608 public:
609 explicit NewToolbarController( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
610
611 // XServiceInfo
612 OUString SAL_CALL getImplementationName() override;
613
614 virtual sal_Bool SAL_CALL supportsService(OUString const & rServiceName) override;
615
616 css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
617
618 void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
619
620 // XSubToolbarController
621 // Make ToolBarManager ask our controller for updated image, in case of icon theme change.
opensSubToolbar()622 sal_Bool SAL_CALL opensSubToolbar() override { return true; }
getSubToolbarName()623 OUString SAL_CALL getSubToolbarName() override { return OUString(); }
functionSelected(const OUString &)624 void SAL_CALL functionSelected( const OUString& ) override {}
625 void SAL_CALL updateImage() override;
626
627 private:
628 void functionExecuted( const OUString &rCommand ) override;
629 void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& rEvent ) override;
630 void SAL_CALL execute( sal_Int16 KeyModifier ) override;
631 sal_uInt16 getMenuIdForCommand( std::u16string_view rCommand );
632
633 sal_uInt16 m_nMenuId;
634 };
635
NewToolbarController(const css::uno::Reference<css::uno::XComponentContext> & xContext)636 NewToolbarController::NewToolbarController(
637 const css::uno::Reference< css::uno::XComponentContext >& xContext )
638 : ImplInheritanceHelper( xContext )
639 , m_nMenuId( 0 )
640 {
641 }
642
getImplementationName()643 OUString NewToolbarController::getImplementationName()
644 {
645 return "org.apache.openoffice.comp.framework.NewToolbarController";
646 }
647
supportsService(OUString const & rServiceName)648 sal_Bool NewToolbarController::supportsService(OUString const & rServiceName)
649 {
650 return cppu::supportsService( this, rServiceName );
651 }
652
getSupportedServiceNames()653 css::uno::Sequence<OUString> NewToolbarController::getSupportedServiceNames()
654 {
655 return {"com.sun.star.frame.ToolbarController"};
656 }
657
initialize(const css::uno::Sequence<css::uno::Any> & aArguments)658 void SAL_CALL NewToolbarController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
659 {
660 PopupMenuToolbarController::initialize( aArguments );
661
662 osl::MutexGuard aGuard( m_aMutex );
663 createPopupMenuController();
664 }
665
statusChanged(const css::frame::FeatureStateEvent & rEvent)666 void SAL_CALL NewToolbarController::statusChanged( const css::frame::FeatureStateEvent& rEvent )
667 {
668 if ( rEvent.IsEnabled )
669 {
670 OUString aState;
671 rEvent.State >>= aState;
672 try
673 {
674 // set the image even if the state is not a string
675 // the toolbar item command will be used as a fallback
676 functionExecuted( aState );
677 }
678 catch (const css::ucb::CommandFailedException&)
679 {
680 }
681 catch (const css::ucb::ContentCreationException&)
682 {
683 }
684 }
685
686 enable( rEvent.IsEnabled );
687 }
688
execute(sal_Int16)689 void SAL_CALL NewToolbarController::execute( sal_Int16 /*KeyModifier*/ )
690 {
691 osl::MutexGuard aGuard( m_aMutex );
692
693 OUString aURL, aTarget;
694 if ( m_xPopupMenu.is() && m_nMenuId )
695 {
696 // TODO investigate how to wrap Get/SetUserValue in css::awt::XMenu
697 SolarMutexGuard aSolarMutexGuard;
698 Menu* pVclMenu = comphelper::getUnoTunnelImplementation<VCLXMenu>( m_xPopupMenu )->GetMenu();
699 aURL = pVclMenu->GetItemCommand( m_nMenuId );
700
701 MenuAttributes* pMenuAttributes( static_cast<MenuAttributes*>( pVclMenu->GetUserValue( m_nMenuId ) ) );
702 if ( pMenuAttributes )
703 aTarget = pMenuAttributes->aTargetFrame;
704 else
705 aTarget = "_default";
706 }
707 else
708 aURL = m_aCommandURL;
709
710 css::uno::Sequence< css::beans::PropertyValue > aArgs( 1 );
711 aArgs[0].Name = "Referer";
712 aArgs[0].Value <<= OUString( "private:user" );
713
714 dispatchCommand( aURL, aArgs, aTarget );
715 }
716
functionExecuted(const OUString & rCommand)717 void NewToolbarController::functionExecuted( const OUString &rCommand )
718 {
719 m_nMenuId = getMenuIdForCommand( rCommand );
720 updateImage();
721 }
722
getMenuIdForCommand(std::u16string_view rCommand)723 sal_uInt16 NewToolbarController::getMenuIdForCommand( std::u16string_view rCommand )
724 {
725 if ( m_xPopupMenu.is() && !rCommand.empty() )
726 {
727 Menu* pVclMenu( comphelper::getUnoTunnelImplementation<VCLXMenu>( m_xPopupMenu )->GetMenu() );
728 sal_uInt16 nCount = pVclMenu->GetItemCount();
729 for ( sal_uInt16 n = 0; n < nCount; ++n )
730 {
731 sal_uInt16 nId = pVclMenu->GetItemId( n );
732 OUString aCmd( pVclMenu->GetItemCommand( nId ) );
733
734 // match even if the menu command is more detailed
735 // (maybe an additional query) #i28667#
736 if ( aCmd.match( rCommand ) )
737 return nId;
738 }
739 }
740
741 return 0;
742 }
743
updateImage()744 void SAL_CALL NewToolbarController::updateImage()
745 {
746 SolarMutexGuard aSolarLock;
747 VclPtr< ToolBox> pToolBox = static_cast< ToolBox* >( VCLUnoHelper::GetWindow( getParent() ) );
748 if ( !pToolBox )
749 return;
750
751 OUString aURL, aImageId;
752 if ( m_xPopupMenu.is() && m_nMenuId )
753 {
754 Menu* pVclMenu = comphelper::getUnoTunnelImplementation<VCLXMenu>( m_xPopupMenu )->GetMenu();
755 aURL = pVclMenu->GetItemCommand( m_nMenuId );
756
757 MenuAttributes* pMenuAttributes( static_cast<MenuAttributes*>( pVclMenu->GetUserValue( m_nMenuId ) ) );
758 if ( pMenuAttributes )
759 aImageId = pMenuAttributes->aImageId;
760 }
761 else
762 aURL = m_aCommandURL;
763
764 INetURLObject aURLObj( aImageId.isEmpty() ? aURL : aImageId );
765 vcl::ImageType eImageType( pToolBox->GetImageSize() );
766 Image aImage = SvFileInformationManager::GetImageNoDefault( aURLObj, eImageType );
767 if ( !aImage )
768 aImage = vcl::CommandInfoProvider::GetImageForCommand( aURL, m_xFrame, eImageType );
769
770 if ( !aImage )
771 return;
772
773 pToolBox->SetItemImage( m_nToolBoxId, aImage );
774 }
775
776 }
777
778 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_framework_GenericPopupToolbarController_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const & args)779 com_sun_star_comp_framework_GenericPopupToolbarController_get_implementation(
780 css::uno::XComponentContext *context,
781 css::uno::Sequence<css::uno::Any> const &args)
782 {
783 return cppu::acquire(new GenericPopupToolbarController(context, args));
784 }
785
786 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
com_sun_star_comp_framework_SaveToolbarController_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)787 com_sun_star_comp_framework_SaveToolbarController_get_implementation(
788 css::uno::XComponentContext *context,
789 css::uno::Sequence<css::uno::Any> const &)
790 {
791 return cppu::acquire(new SaveToolbarController(context));
792 }
793
794 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
org_apache_openoffice_comp_framework_NewToolbarController_get_implementation(css::uno::XComponentContext * context,css::uno::Sequence<css::uno::Any> const &)795 org_apache_openoffice_comp_framework_NewToolbarController_get_implementation(
796 css::uno::XComponentContext *context,
797 css::uno::Sequence<css::uno::Any> const &)
798 {
799 return cppu::acquire(new NewToolbarController(context));
800 }
801
802 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
803