Line data Source code
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 <classes/menumanager.hxx>
21 : #include <framework/menuconfiguration.hxx>
22 : #include <framework/bmkmenu.hxx>
23 : #include <framework/addonmenu.hxx>
24 : #include <framework/imageproducer.hxx>
25 : #include <framework/addonsoptions.hxx>
26 : #include <classes/fwkresid.hxx>
27 : #include <services.h>
28 : #include "classes/resource.hrc"
29 :
30 : #include <com/sun/star/frame/XDispatchProvider.hpp>
31 : #include <com/sun/star/frame/XDispatch.hpp>
32 : #include <com/sun/star/util/URLTransformer.hpp>
33 : #include <com/sun/star/util/XURLTransformer.hpp>
34 : #include <com/sun/star/beans/XPropertySet.hpp>
35 : #include <com/sun/star/frame/XFramesSupplier.hpp>
36 : #include <com/sun/star/frame/Desktop.hpp>
37 : #include <com/sun/star/container/XEnumeration.hpp>
38 : #include <com/sun/star/util/XStringWidth.hpp>
39 :
40 : #include <comphelper/processfactory.hxx>
41 :
42 : #include <comphelper/extract.hxx>
43 : #include <svtools/menuoptions.hxx>
44 : #include <unotools/historyoptions.hxx>
45 : #include <unotools/pathoptions.hxx>
46 : #include <unotools/localfilehelper.hxx>
47 :
48 : #include <toolkit/helper/vclunohelper.hxx>
49 : #include <tools/urlobj.hxx>
50 :
51 : #include <vcl/svapp.hxx>
52 : #include <vcl/window.hxx>
53 : #include <vcl/settings.hxx>
54 :
55 : #include <osl/mutex.hxx>
56 : #include <osl/file.hxx>
57 : #include <cppuhelper/implbase1.hxx>
58 :
59 : using namespace ::cppu;
60 : using namespace ::com::sun::star::uno;
61 : using namespace ::com::sun::star::util;
62 : using namespace ::com::sun::star::beans;
63 : using namespace ::com::sun::star::frame;
64 : using namespace ::com::sun::star::lang;
65 : using namespace ::com::sun::star::container;
66 :
67 : class StringLength : public ::cppu::WeakImplHelper1< XStringWidth >
68 : {
69 : public:
70 0 : StringLength() {}
71 0 : virtual ~StringLength() {}
72 :
73 : // XStringWidth
74 0 : sal_Int32 SAL_CALL queryStringWidth( const OUString& aString )
75 : throw (RuntimeException, std::exception) SAL_OVERRIDE
76 : {
77 0 : return aString.getLength();
78 : }
79 : };
80 :
81 : namespace framework
82 : {
83 :
84 : // special menu ids/command ids for dynamic popup menus
85 : #define SID_SFX_START 5000
86 : #define SID_NEWDOCDIRECT (SID_SFX_START + 537)
87 : #define SID_AUTOPILOTMENU (SID_SFX_START + 1381)
88 : #define SID_ADDONLIST (SID_SFX_START + 1677)
89 :
90 : #define aSlotNewDocDirect "slot:5537"
91 : #define aSlotAutoPilot "slot:6381"
92 :
93 : #define aSpecialFileMenu "file"
94 : #define aSpecialWindowMenu "window"
95 : #define aSlotSpecialFileMenu "slot:5510"
96 : #define aSlotSpecialWindowMenu "slot:5610"
97 : #define aSlotSpecialToolsMenu "slot:6677"
98 :
99 : // special uno commands for picklist and window list
100 : #define aSpecialFileCommand "PickList"
101 : #define aSpecialWindowCommand "WindowList"
102 :
103 : const char UNO_COMMAND[] = ".uno:";
104 :
105 0 : MenuManager::MenuManager(
106 : const Reference< XComponentContext >& rxContext,
107 : Reference< XFrame >& rFrame, Menu* pMenu, bool bDelete, bool bDeleteChildren )
108 : :
109 0 : m_xContext(rxContext)
110 : {
111 0 : m_bActive = false;
112 0 : m_bDeleteMenu = bDelete;
113 0 : m_bDeleteChildren = bDeleteChildren;
114 0 : m_pVCLMenu = pMenu;
115 0 : m_xFrame = rFrame;
116 0 : m_bInitialized = false;
117 0 : m_bIsBookmarkMenu = false;
118 0 : acquire();
119 0 : const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
120 0 : m_bShowMenuImages = rSettings.GetUseImagesInMenus();
121 :
122 0 : sal_Int32 nAddonsURLPrefixLength = ADDONSPOPUPMENU_URL_PREFIX.getLength();
123 :
124 0 : sal_uInt16 nItemCount = pMenu->GetItemCount();
125 0 : m_aMenuItemHandlerVector.reserve(nItemCount);
126 0 : OUString aItemCommand;
127 0 : for ( sal_uInt16 i = 0; i < nItemCount; i++ )
128 : {
129 0 : sal_uInt16 nItemId = FillItemCommand(aItemCommand,pMenu, i );
130 0 : bool bShowMenuImages( m_bShowMenuImages );
131 :
132 : // overwrite the show icons on menu option?
133 0 : if (!bShowMenuImages)
134 : {
135 0 : MenuItemBits nBits = pMenu->GetItemBits( nItemId );
136 0 : bShowMenuImages = ( ( nBits & MenuItemBits::ICON ) == MenuItemBits::ICON );
137 : }
138 :
139 0 : PopupMenu* pPopupMenu = pMenu->GetPopupMenu( nItemId );
140 0 : if ( pPopupMenu )
141 : {
142 0 : AddMenu(pPopupMenu,aItemCommand,nItemId,bDeleteChildren,bDeleteChildren);
143 0 : if (! ( aItemCommand.getLength() > nAddonsURLPrefixLength &&
144 0 : aItemCommand.startsWith( ADDONSPOPUPMENU_URL_PREFIX ) ) )
145 : {
146 :
147 : // Create addon popup menu if there exist elements and this is the tools popup menu
148 0 : if ( ( nItemId == SID_ADDONLIST || aItemCommand == aSlotSpecialToolsMenu )
149 0 : && AddonMenuManager::HasAddonMenuElements() )
150 : {
151 0 : AddonMenu* pSubMenu = AddonMenuManager::CreateAddonMenu(rFrame, rxContext);
152 0 : if ( pSubMenu && ( pSubMenu->GetItemCount() > 0 ))
153 : {
154 0 : sal_uInt16 nCount = 0;
155 0 : if ( pPopupMenu->GetItemType( nCount-1 ) != MenuItemType::SEPARATOR )
156 0 : pPopupMenu->InsertSeparator();
157 :
158 : // Use resource to load popup menu title
159 0 : OUString aAddonsStrRes(FWK_RESSTR(STR_MENU_ADDONS));
160 0 : pPopupMenu->InsertItem( ITEMID_ADDONLIST, aAddonsStrRes );
161 0 : pPopupMenu->SetPopupMenu( ITEMID_ADDONLIST, pSubMenu );
162 :
163 : // Set item command for popup menu to enable it for GetImageFromURL
164 0 : aItemCommand = "slot:" + OUString::number( ITEMID_ADDONLIST );
165 0 : pPopupMenu->SetItemCommand( ITEMID_ADDONLIST, aItemCommand );
166 :
167 0 : AddMenu(pSubMenu,OUString(),nItemId,true,false);
168 : // Set image for the addon popup menu item
169 0 : if ( bShowMenuImages && !pPopupMenu->GetItemImage( ITEMID_ADDONLIST ))
170 : {
171 0 : Image aImage = GetImageFromURL( rFrame, aItemCommand, false );
172 0 : if ( !!aImage )
173 0 : pPopupMenu->SetItemImage( ITEMID_ADDONLIST, aImage );
174 0 : }
175 : }
176 : else
177 0 : delete pSubMenu;
178 : }
179 : }
180 : }
181 : else
182 : {
183 0 : if ( nItemId == SID_NEWDOCDIRECT || aItemCommand == aSlotNewDocDirect )
184 : {
185 0 : MenuConfiguration aMenuCfg( m_xContext );
186 0 : BmkMenu* pSubMenu = static_cast<BmkMenu*>(aMenuCfg.CreateBookmarkMenu( rFrame, BOOKMARK_NEWMENU ));
187 0 : pMenu->SetPopupMenu( nItemId, pSubMenu );
188 :
189 0 : AddMenu(pSubMenu,OUString(),nItemId,true,false);
190 0 : if ( bShowMenuImages && !pMenu->GetItemImage( nItemId ))
191 : {
192 0 : Image aImage = GetImageFromURL( rFrame, aItemCommand, false );
193 0 : if ( !!aImage )
194 0 : pMenu->SetItemImage( nItemId, aImage );
195 0 : }
196 : }
197 0 : else if ( nItemId == SID_AUTOPILOTMENU || aItemCommand == aSlotAutoPilot )
198 : {
199 0 : MenuConfiguration aMenuCfg( m_xContext );
200 0 : BmkMenu* pSubMenu = static_cast<BmkMenu*>(aMenuCfg.CreateBookmarkMenu( rFrame, BOOKMARK_WIZARDMENU ));
201 0 : pMenu->SetPopupMenu( nItemId, pSubMenu );
202 :
203 0 : AddMenu(pSubMenu,OUString(),nItemId,true,false);
204 :
205 0 : if ( bShowMenuImages && !pMenu->GetItemImage( nItemId ))
206 : {
207 0 : Image aImage = GetImageFromURL( rFrame, aItemCommand, false );
208 0 : if ( !!aImage )
209 0 : pMenu->SetItemImage( nItemId, aImage );
210 0 : }
211 : }
212 0 : else if ( pMenu->GetItemType( i ) != MenuItemType::SEPARATOR )
213 : {
214 0 : if ( bShowMenuImages )
215 : {
216 0 : if ( AddonMenuManager::IsAddonMenuId( nItemId ))
217 : {
218 : // Add-Ons uses a images from different places
219 0 : Image aImage;
220 0 : OUString aImageId;
221 :
222 : MenuConfiguration::Attributes* pMenuAttributes =
223 0 : reinterpret_cast<MenuConfiguration::Attributes*>(pMenu->GetUserValue( nItemId ));
224 :
225 0 : if ( pMenuAttributes && !pMenuAttributes->aImageId.isEmpty() )
226 : {
227 : // Retrieve image id from menu attributes
228 0 : aImage = GetImageFromURL( rFrame, aImageId, false );
229 : }
230 :
231 0 : if ( !aImage )
232 : {
233 0 : aImage = GetImageFromURL( rFrame, aItemCommand, false );
234 0 : if ( !aImage )
235 0 : aImage = AddonsOptions().GetImageFromURL( aItemCommand, false );
236 : }
237 :
238 0 : if ( !!aImage )
239 0 : pMenu->SetItemImage( nItemId, aImage );
240 : }
241 0 : else if ( !pMenu->GetItemImage( nItemId ))
242 : {
243 0 : Image aImage = GetImageFromURL( rFrame, aItemCommand, false );
244 0 : if ( !!aImage )
245 0 : pMenu->SetItemImage( nItemId, aImage );
246 : }
247 : }
248 :
249 0 : Reference< XDispatch > aXDispatchRef;
250 0 : m_aMenuItemHandlerVector.push_back( new MenuItemHandler( nItemId, NULL, aXDispatchRef ));
251 :
252 : }
253 : }
254 : }
255 :
256 : // retrieve label information for all menu items without item text
257 :
258 0 : SetHdl();
259 0 : }
260 :
261 0 : void MenuManager::SetHdl()
262 : {
263 0 : m_pVCLMenu->SetHighlightHdl( LINK( this, MenuManager, Highlight ));
264 0 : m_pVCLMenu->SetActivateHdl( LINK( this, MenuManager, Activate ));
265 0 : m_pVCLMenu->SetDeactivateHdl( LINK( this, MenuManager, Deactivate ));
266 0 : m_pVCLMenu->SetSelectHdl( LINK( this, MenuManager, Select ));
267 :
268 0 : if ( m_xContext.is() )
269 0 : m_xURLTransformer.set( URLTransformer::create( m_xContext ) );
270 0 : }
271 :
272 0 : MenuManager::~MenuManager()
273 : {
274 0 : std::vector< MenuItemHandler* >::iterator p;
275 0 : for ( p = m_aMenuItemHandlerVector.begin(); p != m_aMenuItemHandlerVector.end(); ++p )
276 : {
277 0 : MenuItemHandler* pItemHandler = *p;
278 0 : pItemHandler->xMenuItemDispatch.clear();
279 0 : if ( pItemHandler->pSubMenuManager )
280 0 : (static_cast< XInterface* >((OWeakObject*)pItemHandler->pSubMenuManager))->release();
281 0 : delete pItemHandler;
282 : }
283 :
284 0 : if ( m_bDeleteMenu )
285 0 : delete m_pVCLMenu;
286 0 : }
287 :
288 0 : MenuManager::MenuItemHandler* MenuManager::GetMenuItemHandler( sal_uInt16 nItemId )
289 : {
290 0 : SolarMutexGuard g;
291 :
292 0 : std::vector< MenuItemHandler* >::iterator p;
293 0 : for ( p = m_aMenuItemHandlerVector.begin(); p != m_aMenuItemHandlerVector.end(); ++p )
294 : {
295 0 : MenuItemHandler* pItemHandler = *p;
296 0 : if ( pItemHandler->nItemId == nItemId )
297 0 : return pItemHandler;
298 : }
299 :
300 0 : return 0;
301 : }
302 :
303 0 : void SAL_CALL MenuManager::statusChanged( const FeatureStateEvent& Event )
304 : throw ( RuntimeException, std::exception )
305 : {
306 0 : OUString aFeatureURL = Event.FeatureURL.Complete;
307 0 : MenuItemHandler* pStatusChangedMenu = NULL;
308 :
309 : {
310 0 : SolarMutexGuard g;
311 :
312 0 : std::vector< MenuItemHandler* >::iterator p;
313 0 : for ( p = m_aMenuItemHandlerVector.begin(); p != m_aMenuItemHandlerVector.end(); ++p )
314 : {
315 0 : MenuItemHandler* pMenuItemHandler = *p;
316 0 : if ( pMenuItemHandler->aMenuItemURL == aFeatureURL )
317 : {
318 0 : pStatusChangedMenu = pMenuItemHandler;
319 0 : break;
320 : }
321 0 : }
322 : }
323 :
324 0 : if ( pStatusChangedMenu )
325 : {
326 0 : SolarMutexGuard aSolarGuard;
327 : {
328 0 : bool bSetCheckmark = false;
329 0 : bool bCheckmark = false;
330 0 : bool bMenuItemEnabled = m_pVCLMenu->IsItemEnabled( pStatusChangedMenu->nItemId );
331 :
332 0 : if ( Event.IsEnabled != (bMenuItemEnabled ? 1 : 0) )
333 0 : m_pVCLMenu->EnableItem( pStatusChangedMenu->nItemId, Event.IsEnabled );
334 :
335 0 : if ( Event.State >>= bCheckmark )
336 0 : bSetCheckmark = true;
337 :
338 0 : if ( bSetCheckmark )
339 0 : m_pVCLMenu->CheckItem( pStatusChangedMenu->nItemId, bCheckmark );
340 : }
341 :
342 0 : if ( Event.Requery )
343 : {
344 0 : URL aTargetURL;
345 0 : aTargetURL.Complete = pStatusChangedMenu->aMenuItemURL;
346 :
347 0 : m_xURLTransformer->parseStrict( aTargetURL );
348 :
349 0 : Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
350 0 : Reference< XDispatch > xMenuItemDispatch = xDispatchProvider->queryDispatch(
351 0 : aTargetURL, OUString(), 0 );
352 :
353 0 : if ( xMenuItemDispatch.is() )
354 : {
355 0 : pStatusChangedMenu->xMenuItemDispatch = xMenuItemDispatch;
356 0 : pStatusChangedMenu->aMenuItemURL = aTargetURL.Complete;
357 0 : xMenuItemDispatch->addStatusListener( (static_cast< XStatusListener* >(this)), aTargetURL );
358 0 : }
359 0 : }
360 0 : }
361 0 : }
362 :
363 0 : void MenuManager::RemoveListener()
364 : {
365 0 : SolarMutexGuard g;
366 0 : ClearMenuDispatch();
367 0 : }
368 :
369 0 : void MenuManager::ClearMenuDispatch(const EventObject& Source,bool _bRemoveOnly)
370 : {
371 : // disposing called from parent dispatcher
372 : // remove all listener to prepare shutdown
373 :
374 0 : std::vector< MenuItemHandler* >::iterator p;
375 0 : for ( p = m_aMenuItemHandlerVector.begin(); p != m_aMenuItemHandlerVector.end(); ++p )
376 : {
377 0 : MenuItemHandler* pItemHandler = *p;
378 0 : if ( pItemHandler->xMenuItemDispatch.is() )
379 : {
380 0 : URL aTargetURL;
381 0 : aTargetURL.Complete = pItemHandler->aMenuItemURL;
382 0 : m_xURLTransformer->parseStrict( aTargetURL );
383 :
384 0 : pItemHandler->xMenuItemDispatch->removeStatusListener(
385 0 : (static_cast< XStatusListener* >(this)), aTargetURL );
386 : }
387 :
388 0 : pItemHandler->xMenuItemDispatch.clear();
389 0 : if ( pItemHandler->pSubMenuManager )
390 : {
391 0 : if ( _bRemoveOnly )
392 0 : pItemHandler->pSubMenuManager->RemoveListener();
393 : else
394 0 : pItemHandler->pSubMenuManager->disposing( Source );
395 : }
396 : }
397 0 : }
398 :
399 0 : void SAL_CALL MenuManager::disposing( const EventObject& Source ) throw ( RuntimeException, std::exception )
400 : {
401 0 : if ( Source.Source == m_xFrame )
402 : {
403 0 : SolarMutexGuard g;
404 0 : ClearMenuDispatch(Source,false);
405 : }
406 : else
407 : {
408 : // disposing called from menu item dispatcher, remove listener
409 0 : MenuItemHandler* pMenuItemDisposing = NULL;
410 :
411 : {
412 0 : SolarMutexGuard g;
413 :
414 0 : std::vector< MenuItemHandler* >::iterator p;
415 0 : for ( p = m_aMenuItemHandlerVector.begin(); p != m_aMenuItemHandlerVector.end(); ++p )
416 : {
417 0 : MenuItemHandler* pMenuItemHandler = *p;
418 0 : if ( pMenuItemHandler->xMenuItemDispatch == Source.Source )
419 : {
420 0 : pMenuItemDisposing = pMenuItemHandler;
421 0 : break;
422 : }
423 : }
424 :
425 0 : if ( pMenuItemDisposing )
426 : {
427 0 : URL aTargetURL;
428 0 : aTargetURL.Complete = pMenuItemDisposing->aMenuItemURL;
429 :
430 0 : m_xURLTransformer->parseStrict( aTargetURL );
431 :
432 0 : pMenuItemDisposing->xMenuItemDispatch->removeStatusListener((static_cast< XStatusListener* >(this)), aTargetURL );
433 0 : pMenuItemDisposing->xMenuItemDispatch.clear();
434 0 : }
435 : }
436 : }
437 0 : }
438 :
439 0 : void MenuManager::UpdateSpecialFileMenu( Menu* pMenu )
440 : {
441 : // update picklist
442 0 : Sequence< Sequence< PropertyValue > > aHistoryList = SvtHistoryOptions().GetList( ePICKLIST );
443 0 : ::std::vector< MenuItemHandler* > aNewPickVector;
444 0 : Reference< XStringWidth > xStringLength( new StringLength );
445 :
446 0 : sal_uInt16 nPickItemId = START_ITEMID_PICKLIST;
447 0 : int nPickListMenuItems = ( aHistoryList.getLength() > 99 ) ? 99 : aHistoryList.getLength();
448 :
449 0 : aNewPickVector.reserve(nPickListMenuItems);
450 0 : for ( int i = 0; i < nPickListMenuItems; i++ )
451 : {
452 0 : Sequence< PropertyValue > aPickListEntry = aHistoryList[i];
453 :
454 0 : Reference< XDispatch > aXDispatchRef;
455 : MenuItemHandler* pNewMenuItemHandler = new MenuItemHandler(
456 : nPickItemId++,
457 : NULL,
458 0 : aXDispatchRef );
459 :
460 0 : for ( int j = 0; j < aPickListEntry.getLength(); j++ )
461 : {
462 0 : Any a = aPickListEntry[j].Value;
463 :
464 0 : if ( aPickListEntry[j].Name == HISTORY_PROPERTYNAME_URL )
465 0 : a >>= pNewMenuItemHandler->aMenuItemURL;
466 0 : else if ( aPickListEntry[j].Name == HISTORY_PROPERTYNAME_FILTER )
467 0 : a >>= pNewMenuItemHandler->aFilter;
468 0 : else if ( aPickListEntry[j].Name == HISTORY_PROPERTYNAME_TITLE )
469 0 : a >>= pNewMenuItemHandler->aTitle;
470 0 : else if ( aPickListEntry[j].Name == HISTORY_PROPERTYNAME_PASSWORD )
471 0 : a >>= pNewMenuItemHandler->aPassword;
472 0 : }
473 :
474 0 : aNewPickVector.push_back( pNewMenuItemHandler );
475 0 : }
476 :
477 0 : if ( !aNewPickVector.empty() )
478 : {
479 0 : URL aTargetURL;
480 0 : Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
481 :
482 0 : Reference< XDispatch > xMenuItemDispatch;
483 :
484 0 : static const OUString s_sDefault("_default");
485 : // query for dispatcher
486 0 : std::vector< MenuItemHandler* >::iterator p;
487 0 : for ( p = aNewPickVector.begin(); p != aNewPickVector.end(); ++p )
488 : {
489 0 : MenuItemHandler* pMenuItemHandler = *p;
490 :
491 0 : aTargetURL.Complete = pMenuItemHandler->aMenuItemURL;
492 0 : m_xURLTransformer->parseStrict( aTargetURL );
493 :
494 0 : if ( !xMenuItemDispatch.is() )
495 : {
496 : // attention: this code assume that "_blank" can only be consumed by desktop service
497 0 : xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, s_sDefault, 0 );
498 : }
499 :
500 0 : if ( xMenuItemDispatch.is() )
501 : {
502 0 : pMenuItemHandler->xMenuItemDispatch = xMenuItemDispatch;
503 0 : pMenuItemHandler->aMenuItemURL = aTargetURL.Complete;
504 : }
505 : }
506 :
507 : {
508 0 : SolarMutexGuard g;
509 :
510 0 : int nRemoveItemCount = 0;
511 0 : int nItemCount = pMenu->GetItemCount();
512 :
513 0 : if ( nItemCount > 0 )
514 : {
515 : // remove all old picklist entries from menu
516 0 : sal_uInt16 nPos = pMenu->GetItemPos( START_ITEMID_PICKLIST );
517 0 : for ( sal_uInt16 n = nPos; n < pMenu->GetItemCount(); )
518 : {
519 0 : pMenu->RemoveItem( n );
520 0 : ++nRemoveItemCount;
521 : }
522 :
523 0 : if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MenuItemType::SEPARATOR )
524 0 : pMenu->RemoveItem( pMenu->GetItemCount()-1 );
525 :
526 : // remove all old picklist entries from menu handler
527 0 : if ( nRemoveItemCount > 0 )
528 : {
529 0 : for( sal_uInt32 nIndex = m_aMenuItemHandlerVector.size() - nRemoveItemCount;
530 0 : nIndex < m_aMenuItemHandlerVector.size(); )
531 : {
532 0 : delete m_aMenuItemHandlerVector.at( nIndex );
533 0 : m_aMenuItemHandlerVector.erase( m_aMenuItemHandlerVector.begin() + nIndex );
534 : }
535 : }
536 : }
537 :
538 : // append new picklist menu entries
539 0 : aNewPickVector.reserve(aNewPickVector.size());
540 0 : pMenu->InsertSeparator();
541 0 : const sal_uInt32 nCount = aNewPickVector.size();
542 0 : for ( sal_uInt32 i = 0; i < nCount; i++ )
543 : {
544 0 : char menuShortCut[5] = "~n: ";
545 :
546 0 : OUString aMenuShortCut;
547 0 : if ( i <= 9 )
548 : {
549 0 : if ( i == 9 )
550 0 : aMenuShortCut = "1~0: ";
551 : else
552 : {
553 0 : menuShortCut[1] = (char)( '1' + i );
554 0 : aMenuShortCut = OUString::createFromAscii( menuShortCut );
555 : }
556 : }
557 : else
558 : {
559 0 : aMenuShortCut = OUString::number(( i + 1 ));
560 0 : aMenuShortCut += ": ";
561 : }
562 :
563 : // Abbreviate URL
564 0 : OUString aURLString( aNewPickVector.at( i )->aMenuItemURL );
565 0 : OUString aTipHelpText;
566 0 : OUString aMenuTitle;
567 0 : INetURLObject aURL( aURLString );
568 :
569 0 : if ( aURL.GetProtocol() == INET_PROT_FILE )
570 : {
571 : // Do handle file URL differently => convert it to a system
572 : // path and abbreviate it with a special function:
573 0 : OUString aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
574 :
575 0 : OUString aSystemPath( aFileSystemPath );
576 0 : OUString aCompactedSystemPath;
577 :
578 0 : aTipHelpText = aSystemPath;
579 0 : oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
580 0 : if ( !nError )
581 0 : aMenuTitle = aCompactedSystemPath;
582 : else
583 0 : aMenuTitle = aSystemPath;
584 : }
585 : else
586 : {
587 : // Use INetURLObject to abbreviate all other URLs
588 0 : OUString aShortURL;
589 0 : aShortURL = aURL.getAbbreviated( xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
590 0 : aMenuTitle += aShortURL;
591 0 : aTipHelpText = aURLString;
592 : }
593 :
594 0 : OUString aTitle( aMenuShortCut + aMenuTitle );
595 :
596 0 : MenuItemHandler* pMenuItemHandler = aNewPickVector.at( i );
597 0 : pMenu->InsertItem( pMenuItemHandler->nItemId, aTitle );
598 0 : pMenu->SetTipHelpText( pMenuItemHandler->nItemId, aTipHelpText );
599 0 : m_aMenuItemHandlerVector.push_back( pMenuItemHandler );
600 0 : }
601 0 : }
602 0 : }
603 0 : }
604 :
605 0 : void MenuManager::UpdateSpecialWindowMenu( Menu* pMenu,const Reference< XComponentContext >& xContext )
606 : {
607 : // update window list
608 0 : ::std::vector< OUString > aNewWindowListVector;
609 :
610 0 : Reference< XDesktop2 > xDesktop = Desktop::create( xContext );
611 :
612 0 : sal_uInt16 nActiveItemId = 0;
613 0 : sal_uInt16 nItemId = START_ITEMID_WINDOWLIST;
614 :
615 0 : Reference< XFrame > xCurrentFrame = xDesktop->getCurrentFrame();
616 0 : Reference< XIndexAccess > xList( xDesktop->getFrames(), UNO_QUERY );
617 0 : sal_Int32 nFrameCount = xList->getCount();
618 0 : aNewWindowListVector.reserve(nFrameCount);
619 0 : for (sal_Int32 i=0; i<nFrameCount; ++i )
620 : {
621 0 : Reference< XFrame > xFrame;
622 0 : xList->getByIndex(i) >>= xFrame;
623 :
624 0 : if (xFrame.is())
625 : {
626 0 : if ( xFrame == xCurrentFrame )
627 0 : nActiveItemId = nItemId;
628 :
629 0 : vcl::Window* pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() );
630 0 : if ( pWin && pWin->IsVisible() )
631 : {
632 0 : aNewWindowListVector.push_back( pWin->GetText() );
633 0 : ++nItemId;
634 : }
635 : }
636 0 : }
637 :
638 : {
639 0 : SolarMutexGuard g;
640 :
641 0 : int nItemCount = pMenu->GetItemCount();
642 :
643 0 : if ( nItemCount > 0 )
644 : {
645 : // remove all old window list entries from menu
646 0 : sal_uInt16 nPos = pMenu->GetItemPos( START_ITEMID_WINDOWLIST );
647 0 : for ( sal_uInt16 n = nPos; n < pMenu->GetItemCount(); )
648 0 : pMenu->RemoveItem( n );
649 :
650 0 : if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MenuItemType::SEPARATOR )
651 0 : pMenu->RemoveItem( pMenu->GetItemCount()-1 );
652 : }
653 :
654 0 : if ( !aNewWindowListVector.empty() )
655 : {
656 : // append new window list entries to menu
657 0 : pMenu->InsertSeparator();
658 0 : nItemId = START_ITEMID_WINDOWLIST;
659 0 : const sal_uInt32 nCount = aNewWindowListVector.size();
660 0 : for ( sal_uInt32 i = 0; i < nCount; i++ )
661 : {
662 0 : pMenu->InsertItem( nItemId, aNewWindowListVector.at( i ), MenuItemBits::RADIOCHECK );
663 0 : if ( nItemId == nActiveItemId )
664 0 : pMenu->CheckItem( nItemId );
665 0 : ++nItemId;
666 : }
667 0 : }
668 0 : }
669 0 : }
670 :
671 0 : void MenuManager::CreatePicklistArguments( Sequence< PropertyValue >& aArgsList, const MenuItemHandler* pMenuItemHandler )
672 : {
673 0 : int NUM_OF_PICKLIST_ARGS = 3;
674 :
675 0 : Any a;
676 0 : aArgsList.realloc( NUM_OF_PICKLIST_ARGS );
677 :
678 0 : aArgsList[0].Name = "FileName";
679 0 : a <<= pMenuItemHandler->aMenuItemURL;
680 0 : aArgsList[0].Value = a;
681 :
682 0 : aArgsList[1].Name = "Referer";
683 0 : a <<= OUString( "private:user" );
684 0 : aArgsList[1].Value = a;
685 :
686 0 : OUString aFilter( pMenuItemHandler->aFilter );
687 :
688 0 : sal_Int32 nPos = aFilter.indexOf( '|' );
689 0 : if ( nPos >= 0 )
690 : {
691 0 : OUString aFilterOptions;
692 :
693 0 : if ( nPos < ( aFilter.getLength() - 1 ) )
694 0 : aFilterOptions = aFilter.copy( nPos+1 );
695 :
696 0 : aArgsList[2].Name = "FilterOptions";
697 0 : a <<= aFilterOptions;
698 0 : aArgsList[2].Value = a;
699 :
700 0 : aFilter = aFilter.copy( 0, nPos-1 );
701 0 : aArgsList.realloc( ++NUM_OF_PICKLIST_ARGS );
702 : }
703 :
704 0 : aArgsList[NUM_OF_PICKLIST_ARGS-1].Name = "FilterName";
705 0 : a <<= aFilter;
706 0 : aArgsList[NUM_OF_PICKLIST_ARGS-1].Value = a;
707 0 : }
708 :
709 : // vcl handler
710 :
711 0 : IMPL_LINK( MenuManager, Activate, Menu *, pMenu )
712 : {
713 0 : if ( pMenu == m_pVCLMenu )
714 : {
715 : // set/unset hiding disabled menu entries
716 0 : bool bDontHide = SvtMenuOptions().IsEntryHidingEnabled();
717 0 : const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
718 0 : bool bShowMenuImages = rSettings.GetUseImagesInMenus();
719 :
720 0 : sal_uInt16 nFlag = pMenu->GetMenuFlags();
721 0 : if ( bDontHide )
722 0 : nFlag &= ~MENU_FLAG_HIDEDISABLEDENTRIES;
723 : else
724 0 : nFlag |= MENU_FLAG_HIDEDISABLEDENTRIES;
725 0 : pMenu->SetMenuFlags( nFlag );
726 :
727 0 : if ( m_bActive )
728 0 : return 0;
729 :
730 0 : m_bActive = true;
731 :
732 0 : OUString aCommand( m_aMenuItemCommand );
733 0 : if (m_aMenuItemCommand.matchIgnoreAsciiCase(UNO_COMMAND))
734 : {
735 : // Remove protocol part from command so we can use an easier comparision method
736 0 : aCommand = aCommand.copy(RTL_CONSTASCII_LENGTH(UNO_COMMAND));
737 : }
738 :
739 0 : if ( m_aMenuItemCommand == aSpecialFileMenu || m_aMenuItemCommand == aSlotSpecialFileMenu || aCommand == aSpecialFileCommand )
740 0 : UpdateSpecialFileMenu( pMenu );
741 0 : else if ( m_aMenuItemCommand == aSpecialWindowMenu || m_aMenuItemCommand == aSlotSpecialWindowMenu || aCommand == aSpecialWindowCommand )
742 0 : UpdateSpecialWindowMenu( pMenu, m_xContext );
743 :
744 : // Check if some modes have changed so we have to update our menu images
745 0 : if ( bShowMenuImages != m_bShowMenuImages )
746 : {
747 : // The mode changed so we have to replace all images
748 0 : m_bShowMenuImages = bShowMenuImages;
749 0 : FillMenuImages( m_xFrame, pMenu, bShowMenuImages );
750 : }
751 :
752 0 : if ( m_bInitialized )
753 0 : return 0;
754 : else
755 : {
756 0 : URL aTargetURL;
757 :
758 0 : SolarMutexGuard g;
759 :
760 0 : Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
761 0 : if ( xDispatchProvider.is() )
762 : {
763 0 : std::vector< MenuItemHandler* >::iterator p;
764 0 : for ( p = m_aMenuItemHandlerVector.begin(); p != m_aMenuItemHandlerVector.end(); ++p )
765 : {
766 0 : MenuItemHandler* pMenuItemHandler = *p;
767 0 : if ( pMenuItemHandler &&
768 0 : pMenuItemHandler->pSubMenuManager == 0 &&
769 0 : !pMenuItemHandler->xMenuItemDispatch.is() )
770 : {
771 : // There is no dispatch mechanism for the special window list menu items,
772 : // because they are handled directly through XFrame->activate!!!
773 0 : if ( pMenuItemHandler->nItemId < START_ITEMID_WINDOWLIST ||
774 0 : pMenuItemHandler->nItemId > END_ITEMID_WINDOWLIST )
775 : {
776 0 : OUString aItemCommand = pMenu->GetItemCommand( pMenuItemHandler->nItemId );
777 0 : if ( aItemCommand.isEmpty() )
778 : {
779 0 : aItemCommand = "slot:" + OUString::number( pMenuItemHandler->nItemId );
780 0 : pMenu->SetItemCommand( pMenuItemHandler->nItemId, aItemCommand );
781 : }
782 :
783 0 : aTargetURL.Complete = aItemCommand;
784 :
785 0 : m_xURLTransformer->parseStrict( aTargetURL );
786 :
787 0 : Reference< XDispatch > xMenuItemDispatch;
788 0 : if ( m_bIsBookmarkMenu )
789 0 : xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, pMenuItemHandler->aTargetFrame, 0 );
790 : else
791 0 : xMenuItemDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
792 :
793 0 : if ( xMenuItemDispatch.is() )
794 : {
795 0 : pMenuItemHandler->xMenuItemDispatch = xMenuItemDispatch;
796 0 : pMenuItemHandler->aMenuItemURL = aTargetURL.Complete;
797 0 : xMenuItemDispatch->addStatusListener( (static_cast< XStatusListener* >(this)), aTargetURL );
798 : }
799 : else
800 0 : pMenu->EnableItem( pMenuItemHandler->nItemId, false );
801 : }
802 : }
803 : }
804 0 : }
805 0 : }
806 : }
807 :
808 0 : return 1;
809 : }
810 :
811 0 : IMPL_LINK( MenuManager, Deactivate, Menu *, pMenu )
812 : {
813 0 : if ( pMenu == m_pVCLMenu )
814 0 : m_bActive = false;
815 :
816 0 : return 1;
817 : }
818 :
819 0 : IMPL_LINK( MenuManager, Select, Menu *, pMenu )
820 : {
821 0 : URL aTargetURL;
822 0 : Sequence<PropertyValue> aArgs;
823 0 : Reference< XDispatch > xDispatch;
824 :
825 : {
826 0 : SolarMutexGuard g;
827 :
828 0 : sal_uInt16 nCurItemId = pMenu->GetCurItemId();
829 0 : if ( pMenu == m_pVCLMenu &&
830 0 : pMenu->GetItemType( nCurItemId ) != MenuItemType::SEPARATOR )
831 : {
832 0 : if ( nCurItemId >= START_ITEMID_WINDOWLIST &&
833 : nCurItemId <= END_ITEMID_WINDOWLIST )
834 : {
835 : // window list menu item selected
836 :
837 0 : Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext );
838 :
839 0 : sal_uInt16 nTaskId = START_ITEMID_WINDOWLIST;
840 0 : Reference< XIndexAccess > xList( xDesktop->getFrames(), UNO_QUERY );
841 0 : sal_Int32 nCount = xList->getCount();
842 0 : for ( sal_Int32 i=0; i<nCount; ++i )
843 : {
844 0 : Reference< XFrame > xFrame;
845 0 : xList->getByIndex(i) >>= xFrame;
846 :
847 0 : if ( xFrame.is() && nTaskId == nCurItemId )
848 : {
849 0 : vcl::Window* pWin = VCLUnoHelper::GetWindow( xFrame->getContainerWindow() );
850 0 : pWin->GrabFocus();
851 0 : pWin->ToTop( TOTOP_RESTOREWHENMIN );
852 0 : break;
853 : }
854 :
855 0 : nTaskId++;
856 0 : }
857 : }
858 : else
859 : {
860 0 : MenuItemHandler* pMenuItemHandler = GetMenuItemHandler( nCurItemId );
861 0 : if ( pMenuItemHandler && pMenuItemHandler->xMenuItemDispatch.is() )
862 : {
863 0 : aTargetURL.Complete = pMenuItemHandler->aMenuItemURL;
864 0 : m_xURLTransformer->parseStrict( aTargetURL );
865 :
866 0 : if ( nCurItemId >= START_ITEMID_PICKLIST &&
867 : nCurItemId < START_ITEMID_WINDOWLIST )
868 : {
869 : // picklist menu item selected
870 0 : CreatePicklistArguments( aArgs, pMenuItemHandler );
871 : }
872 0 : else if ( m_bIsBookmarkMenu )
873 : {
874 : // bookmark menu item selected
875 0 : aArgs.realloc( 1 );
876 0 : aArgs[0].Name = "Referer";
877 0 : aArgs[0].Value <<= OUString( "private:user" );
878 : }
879 :
880 0 : xDispatch = pMenuItemHandler->xMenuItemDispatch;
881 : }
882 : }
883 0 : }
884 : }
885 :
886 0 : if ( xDispatch.is() )
887 0 : xDispatch->dispatch( aTargetURL, aArgs );
888 :
889 0 : return 1;
890 : }
891 :
892 0 : IMPL_LINK_NOARG(MenuManager, Highlight)
893 : {
894 0 : return 0;
895 : }
896 :
897 0 : void MenuManager::AddMenu(PopupMenu* _pPopupMenu,const OUString& _sItemCommand,sal_uInt16 _nItemId,bool _bDelete,bool _bDeleteChildren)
898 : {
899 0 : MenuManager* pSubMenuManager = new MenuManager( m_xContext, m_xFrame, _pPopupMenu, _bDelete, _bDeleteChildren );
900 :
901 : // store menu item command as we later have to know which menu is active (see Activate handler)
902 0 : pSubMenuManager->m_aMenuItemCommand = _sItemCommand;
903 :
904 0 : Reference< XDispatch > aXDispatchRef;
905 : MenuItemHandler* pMenuItemHandler = new MenuItemHandler(
906 : _nItemId,
907 : pSubMenuManager,
908 0 : aXDispatchRef );
909 0 : m_aMenuItemHandlerVector.push_back( pMenuItemHandler );
910 0 : }
911 :
912 0 : sal_uInt16 MenuManager::FillItemCommand(OUString& _rItemCommand, Menu* _pMenu,sal_uInt16 _nIndex) const
913 : {
914 0 : sal_uInt16 nItemId = _pMenu->GetItemId( _nIndex );
915 :
916 0 : _rItemCommand = _pMenu->GetItemCommand( nItemId );
917 0 : if ( _rItemCommand.isEmpty() )
918 : {
919 0 : _rItemCommand = "slot:" + OUString::number( nItemId );
920 0 : _pMenu->SetItemCommand( nItemId, _rItemCommand );
921 : }
922 0 : return nItemId;
923 : }
924 6 : void MenuManager::FillMenuImages(Reference< XFrame >& _xFrame, Menu* _pMenu,bool bShowMenuImages)
925 : {
926 6 : AddonsOptions aAddonOptions;
927 :
928 180 : for ( sal_uInt16 nPos = 0; nPos < _pMenu->GetItemCount(); nPos++ )
929 : {
930 174 : sal_uInt16 nId = _pMenu->GetItemId( nPos );
931 174 : if ( _pMenu->GetItemType( nPos ) != MenuItemType::SEPARATOR )
932 : {
933 142 : bool bTmpShowMenuImages( bShowMenuImages );
934 : // overwrite the show icons on menu option?
935 142 : if (!bTmpShowMenuImages)
936 : {
937 0 : MenuItemBits nBits = _pMenu->GetItemBits( nId );
938 0 : bTmpShowMenuImages = ( ( nBits & MenuItemBits::ICON ) == MenuItemBits::ICON );
939 : }
940 :
941 142 : if ( bTmpShowMenuImages )
942 : {
943 142 : bool bImageSet = false;
944 142 : OUString aImageId;
945 :
946 : ::framework::MenuConfiguration::Attributes* pMenuAttributes =
947 142 : reinterpret_cast< ::framework::MenuConfiguration::Attributes*>(_pMenu->GetUserValue( nId ));
948 :
949 142 : if ( pMenuAttributes )
950 0 : aImageId = pMenuAttributes->aImageId; // Retrieve image id from menu attributes
951 :
952 142 : if ( !aImageId.isEmpty() )
953 : {
954 0 : Image aImage = GetImageFromURL( _xFrame, aImageId, false );
955 0 : if ( !!aImage )
956 : {
957 0 : bImageSet = true;
958 0 : _pMenu->SetItemImage( nId, aImage );
959 0 : }
960 : }
961 :
962 142 : if ( !bImageSet )
963 : {
964 142 : OUString aMenuItemCommand = _pMenu->GetItemCommand( nId );
965 284 : Image aImage = GetImageFromURL( _xFrame, aMenuItemCommand, false );
966 142 : if ( !aImage )
967 70 : aImage = aAddonOptions.GetImageFromURL( aMenuItemCommand, false );
968 :
969 284 : _pMenu->SetItemImage( nId, aImage );
970 142 : }
971 : }
972 : else
973 0 : _pMenu->SetItemImage( nId, Image() );
974 : }
975 6 : }
976 6 : }
977 951 : }
978 :
979 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|