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