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 <uielement/headermenucontroller.hxx>
21 
22 #include <services.h>
23 
24 #include <strings.hrc>
25 #include <classes/fwkresid.hxx>
26 
27 #include <com/sun/star/awt/XDevice.hpp>
28 #include <com/sun/star/beans/PropertyValue.hpp>
29 #include <com/sun/star/awt/MenuItemStyle.hpp>
30 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
31 #include <com/sun/star/container/XNameContainer.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 
34 #include <toolkit/awt/vclxmenu.hxx>
35 #include <vcl/menu.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/i18nhelp.hxx>
38 #include <rtl/ustrbuf.hxx>
39 #include <osl/mutex.hxx>
40 
41 //  Defines
42 
43 using namespace com::sun::star::uno;
44 using namespace com::sun::star::lang;
45 using namespace com::sun::star::frame;
46 using namespace com::sun::star::beans;
47 using namespace com::sun::star::util;
48 using namespace com::sun::star::style;
49 using namespace com::sun::star::container;
50 
51 const sal_uInt16 ALL_MENUITEM_ID = 1;
52 
53 namespace framework
54 {
55 
DEFINE_XSERVICEINFO_MULTISERVICE_2(HeaderMenuController,OWeakObject,SERVICENAME_POPUPMENUCONTROLLER,IMPLEMENTATIONNAME_HEADERMENUCONTROLLER)56 DEFINE_XSERVICEINFO_MULTISERVICE_2      (   HeaderMenuController                    ,
57                                             OWeakObject                             ,
58                                             SERVICENAME_POPUPMENUCONTROLLER         ,
59                                             IMPLEMENTATIONNAME_HEADERMENUCONTROLLER
60                                         )
61 
62 DEFINE_INIT_SERVICE                     (   HeaderMenuController, {} )
63 
64 HeaderMenuController::HeaderMenuController( const css::uno::Reference< css::uno::XComponentContext >& xContext, bool _bFooter ) :
65     svt::PopupMenuControllerBase( xContext )
66     ,m_bFooter(_bFooter)
67 {
68 }
69 
~HeaderMenuController()70 HeaderMenuController::~HeaderMenuController()
71 {
72 }
73 
74 // private function
fillPopupMenu(const Reference<css::frame::XModel> & rModel,Reference<css::awt::XPopupMenu> const & rPopupMenu)75 void HeaderMenuController::fillPopupMenu( const Reference< css::frame::XModel >& rModel, Reference< css::awt::XPopupMenu > const & rPopupMenu )
76 {
77     VCLXPopupMenu*       pPopupMenu        = static_cast<VCLXPopupMenu *>(comphelper::getUnoTunnelImplementation<VCLXMenu>( rPopupMenu ));
78     PopupMenu*           pVCLPopupMenu     = nullptr;
79 
80     SolarMutexGuard aSolarMutexGuard;
81 
82     resetPopupMenu( rPopupMenu );
83     if ( pPopupMenu )
84         pVCLPopupMenu = static_cast<PopupMenu *>(pPopupMenu->GetMenu());
85 
86     Reference< XStyleFamiliesSupplier > xStyleFamiliesSupplier( rModel, UNO_QUERY );
87     if ( pVCLPopupMenu && xStyleFamiliesSupplier.is())
88     {
89         Reference< XNameAccess > xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
90 
91         OUString aCmd( ".uno:InsertPageHeader" );
92         OUString aHeaderFooterIsOnStr( "HeaderIsOn" );
93         if ( m_bFooter )
94         {
95             aCmd = ".uno:InsertPageFooter";
96             aHeaderFooterIsOnStr = "FooterIsOn";
97         }
98         const OUString aIsPhysicalStr( "IsPhysical" );
99         const OUString aDisplayNameStr( "DisplayName" );
100 
101         try
102         {
103             Reference< XNameContainer > xNameContainer;
104             if ( xStyleFamilies->getByName("PageStyles") >>= xNameContainer )
105             {
106                 Sequence< OUString > aSeqNames = xNameContainer->getElementNames();
107 
108                 sal_uInt16   nId = 2;
109                 sal_uInt16  nCount = 0;
110                 bool bAllOneState( true );
111                 bool bLastCheck( true );
112                 bool bFirstChecked( false );
113                 bool bFirstItemInserted( false );
114                 for ( sal_Int32 n = 0; n < aSeqNames.getLength(); n++ )
115                 {
116                     OUString aName = aSeqNames[n];
117                     Reference< XPropertySet > xPropSet( xNameContainer->getByName( aName ), UNO_QUERY );
118                     if ( xPropSet.is() )
119                     {
120                         bool bIsPhysical( false );
121                         if (( xPropSet->getPropertyValue( aIsPhysicalStr ) >>= bIsPhysical ) && bIsPhysical )
122                         {
123                             OUString aDisplayName;
124                             bool      bHeaderIsOn( false );
125                             xPropSet->getPropertyValue( aDisplayNameStr ) >>= aDisplayName;
126                             xPropSet->getPropertyValue( aHeaderFooterIsOnStr ) >>= bHeaderIsOn;
127 
128                             OUStringBuffer aStrBuf( aCmd );
129                             aStrBuf.append( "?PageStyle:string=");
130                             aStrBuf.append( aDisplayName );
131                             aStrBuf.append( "&On:bool=" );
132                             if ( !bHeaderIsOn )
133                                 aStrBuf.append( "true" );
134                             else
135                                 aStrBuf.append( "false" );
136                             OUString aCommand( aStrBuf.makeStringAndClear() );
137                             pVCLPopupMenu->InsertItem( nId, aDisplayName, MenuItemBits::CHECKABLE );
138                             if ( !bFirstItemInserted )
139                             {
140                                 bFirstItemInserted = true;
141                                 bFirstChecked      = bHeaderIsOn;
142                             }
143 
144                             pVCLPopupMenu->SetItemCommand( nId, aCommand );
145 
146                             if ( bHeaderIsOn )
147                                 pVCLPopupMenu->CheckItem( nId );
148                             ++nId;
149 
150                             // Check if all entries have the same state
151                             if( bAllOneState && n && bHeaderIsOn != bLastCheck )
152                                 bAllOneState = false;
153                             bLastCheck = bHeaderIsOn;
154                             ++nCount;
155                         }
156                     }
157                 }
158 
159                 if ( bAllOneState && ( nCount > 1 ))
160                 {
161                     // Insert special item for all command
162                     pVCLPopupMenu->InsertItem( ALL_MENUITEM_ID, FwkResId(STR_MENU_HEADFOOTALL), MenuItemBits::NONE, OString(), 0 );
163 
164                     OUStringBuffer aStrBuf( aCmd );
165                     aStrBuf.append( "?On:bool=" );
166 
167                     // Command depends on check state of first menu item entry
168                     if ( !bFirstChecked )
169                         aStrBuf.append( "true" );
170                     else
171                         aStrBuf.append( "false" );
172 
173                     pVCLPopupMenu->SetItemCommand( 1, aStrBuf.makeStringAndClear() );
174                     pVCLPopupMenu->InsertSeparator(OString(), 1);
175                 }
176             }
177         }
178         catch ( const css::container::NoSuchElementException& )
179         {
180         }
181     }
182 }
183 
184 // XEventListener
disposing(const EventObject &)185 void SAL_CALL HeaderMenuController::disposing( const EventObject& )
186 {
187     Reference< css::awt::XMenuListener > xHolder(static_cast<OWeakObject *>(this), UNO_QUERY );
188 
189     osl::MutexGuard aLock( m_aMutex );
190     m_xFrame.clear();
191     m_xDispatch.clear();
192 
193     if ( m_xPopupMenu.is() )
194         m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(static_cast<OWeakObject *>(this), UNO_QUERY ));
195     m_xPopupMenu.clear();
196 }
197 
198 // XStatusListener
statusChanged(const FeatureStateEvent & Event)199 void SAL_CALL HeaderMenuController::statusChanged( const FeatureStateEvent& Event )
200 {
201     Reference< css::frame::XModel > xModel;
202 
203     if ( Event.State >>= xModel )
204     {
205         osl::MutexGuard aLock( m_aMutex );
206         m_xModel = xModel;
207         if ( m_xPopupMenu.is() )
208             fillPopupMenu( xModel, m_xPopupMenu );
209     }
210 }
211 
212 // XMenuListener
updatePopupMenu()213 void SAL_CALL HeaderMenuController::updatePopupMenu()
214 {
215     osl::ResettableMutexGuard aLock( m_aMutex );
216 
217     throwIfDisposed();
218 
219     Reference< css::frame::XModel > xModel( m_xModel );
220     aLock.clear();
221 
222     if ( !xModel.is() )
223         svt::PopupMenuControllerBase::updatePopupMenu();
224 
225     aLock.reset();
226     if ( m_xPopupMenu.is() && m_xModel.is() )
227         fillPopupMenu( m_xModel, m_xPopupMenu );
228 }
229 
230 }
231 
232 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
233