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