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