1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_framework.hxx"
30 #include <uielement/fontsizemenucontroller.hxx>
31 
32 //_________________________________________________________________________________________________________________
33 //	my own includes
34 //_________________________________________________________________________________________________________________
35 #include <threadhelp/resetableguard.hxx>
36 #include "services.h"
37 
38 //_________________________________________________________________________________________________________________
39 //	interface includes
40 //_________________________________________________________________________________________________________________
41 #include <com/sun/star/awt/XDevice.hpp>
42 #include <com/sun/star/beans/PropertyValue.hpp>
43 #include <com/sun/star/awt/MenuItemStyle.hpp>
44 #include <com/sun/star/frame/XDispatchProvider.hpp>
45 #include <com/sun/star/view/XPrintable.hpp>
46 
47 //_________________________________________________________________________________________________________________
48 //	includes of other projects
49 //_________________________________________________________________________________________________________________
50 
51 #ifndef _VCL_MENU_HXX_
52 #include <vcl/menu.hxx>
53 #endif
54 #include <tools/mapunit.hxx>
55 #ifndef _VCL_SVAPP_HXX_
56 #include <vcl/svapp.hxx>
57 #endif
58 #include <vcl/i18nhelp.hxx>
59 #ifndef _VCL_OUTPUTDEVICE_HXX_
60 #include <vcl/outdev.hxx>
61 #endif
62 #include <vcl/print.hxx>
63 #ifndef _SVTOOLS_CTRLTOOL_HXX_
64 #include <svtools/ctrltool.hxx>
65 #endif
66 #include <dispatch/uieventloghelper.hxx>
67 #include <vos/mutex.hxx>
68 
69 //_________________________________________________________________________________________________________________
70 //	Defines
71 //_________________________________________________________________________________________________________________
72 //
73 
74 using namespace com::sun::star::uno;
75 using namespace com::sun::star::lang;
76 using namespace com::sun::star::frame;
77 using namespace com::sun::star::beans;
78 using namespace com::sun::star::util;
79 using namespace com::sun::star::view;
80 using namespace com::sun::star::beans;
81 
82 namespace framework
83 {
84 
85 DEFINE_XSERVICEINFO_MULTISERVICE        (   FontSizeMenuController			            ,
86                                             OWeakObject                                 ,
87                                             SERVICENAME_POPUPMENUCONTROLLER			    ,
88 											IMPLEMENTATIONNAME_FONTSIZEMENUCONTROLLER
89 										)
90 
91 DEFINE_INIT_SERVICE                     (   FontSizeMenuController, {} )
92 
93 FontSizeMenuController::FontSizeMenuController( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ) :
94 	svt::PopupMenuControllerBase( xServiceManager ),
95     m_pHeightArray( 0 ),
96     m_bRebuildMenu( sal_True )
97 {
98 }
99 
100 FontSizeMenuController::~FontSizeMenuController()
101 {
102     delete []m_pHeightArray;
103 }
104 
105 // private function
106 rtl::OUString FontSizeMenuController::retrievePrinterName( com::sun::star::uno::Reference< com::sun::star::frame::XFrame >& rFrame )
107 {
108     rtl::OUString aPrinterName;
109 
110     if ( rFrame.is() )
111     {
112         Reference< XController > xController = m_xFrame->getController();
113         if ( xController.is() )
114         {
115             Reference< XPrintable > xPrintable( xController->getModel(), UNO_QUERY );
116             if ( xPrintable.is() )
117             {
118                 Sequence< PropertyValue > aPrinterSeq = xPrintable->getPrinter();
119                 for ( int i = 0; i < aPrinterSeq.getLength(); i++ )
120                 {
121                     if ( aPrinterSeq[i].Name.equalsAscii( "Name" ))
122                     {
123                         aPrinterSeq[i].Value >>= aPrinterName;
124                         break;
125                     }
126                 }
127             }
128         }
129     }
130 
131     return aPrinterName;
132 }
133 
134 // private function
135 void FontSizeMenuController::setCurHeight( long nHeight, Reference< css::awt::XPopupMenu >& rPopupMenu )
136 {
137 	// check menu item
138 	rtl::OUString	aHeight     = Application::GetSettings().GetUILocaleI18nHelper().GetNum( nHeight, 1, sal_True, sal_False  );
139 	sal_uInt16		    nChecked    = 0;
140 	sal_uInt16		    nItemCount  = rPopupMenu->getItemCount();
141 	for( sal_uInt16 i = 0; i < nItemCount; i++ )
142 	{
143 		sal_uInt16 nItemId = rPopupMenu->getItemId( i );
144 
145 		if ( m_pHeightArray[i] == nHeight )
146 		{
147 			rPopupMenu->checkItem( nItemId, sal_True );
148 			return;
149 		}
150 
151 		if ( rPopupMenu->isItemChecked( nItemId ) )
152 			nChecked = nItemId;
153 	}
154 
155 	if ( nChecked )
156 		rPopupMenu->checkItem( nChecked, sal_False );
157 }
158 
159 // private function
160 void FontSizeMenuController::fillPopupMenu( Reference< css::awt::XPopupMenu >& rPopupMenu )
161 {
162     const rtl::OUString     aFontNameCommand( RTL_CONSTASCII_USTRINGPARAM( ".uno:FontHeight?FontHeight=" ));
163     VCLXPopupMenu*          pPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu );
164     PopupMenu*              pVCLPopupMenu = 0;
165 
166     resetPopupMenu( rPopupMenu );
167     if ( pPopupMenu )
168         pVCLPopupMenu = (PopupMenu *)pPopupMenu->GetMenu();
169 
170     if ( pVCLPopupMenu )
171     {
172         FontList*       pFontList = 0;
173         Printer*        pInfoPrinter = 0;
174         rtl::OUString   aPrinterName;
175 
176         vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
177 
178         // try to retrieve printer name of document
179         aPrinterName = retrievePrinterName( m_xFrame );
180         if ( aPrinterName.getLength() > 0 )
181         {
182             pInfoPrinter = new Printer( aPrinterName );
183             if ( pInfoPrinter && pInfoPrinter->GetDevFontCount() > 0 )
184                 pFontList = new FontList( pInfoPrinter );
185         }
186 
187         if ( pFontList == 0 )
188             pFontList   = new FontList( Application::GetDefaultDevice() );
189 
190         FontInfo aFntInfo = pFontList->Get( m_aFontDescriptor.Name, m_aFontDescriptor.StyleName );
191 
192 	    // setup font size array
193 	    if ( m_pHeightArray )
194 		    delete m_pHeightArray;
195 
196 	    const long* pTempAry;
197 	    const long* pAry = pFontList->GetSizeAry( aFntInfo );
198 	    sal_uInt16 nSizeCount = 0;
199 	    while ( pAry[nSizeCount] )
200 		    nSizeCount++;
201 
202 	    sal_uInt16 nPos = 0;
203         const rtl::OUString aFontHeightCommand( RTL_CONSTASCII_USTRINGPARAM( ".uno:FontHeight?FontHeight.Height:float=" ));
204 
205         // first insert font size names (for simplified/traditional chinese)
206 	    float           fPoint;
207         rtl::OUString   aHeightString;
208         FontSizeNames   aFontSizeNames( Application::GetSettings().GetUILanguage() );
209 	    m_pHeightArray = new long[nSizeCount+aFontSizeNames.Count()];
210         rtl::OUString   aCommand;
211 
212         if ( !aFontSizeNames.IsEmpty() )
213 	    {
214 		    if ( pAry == pFontList->GetStdSizeAry() )
215 		    {
216 			    // for scalable fonts all font size names
217 			    sal_uLong nCount = aFontSizeNames.Count();
218 			    for( sal_uLong i = 0; i < nCount; i++ )
219 			    {
220 				    String	aSizeName = aFontSizeNames.GetIndexName( i );
221 				    long	nSize = aFontSizeNames.GetIndexSize( i );
222 				    m_pHeightArray[nPos] = nSize;
223 				    nPos++; // Id is nPos+1
224 				    pVCLPopupMenu->InsertItem( nPos, aSizeName, MIB_RADIOCHECK | MIB_AUTOCHECK );
225 				    fPoint = float( m_pHeightArray[nPos-1] ) / 10;
226 
227                     // Create dispatchable .uno command and set it
228                     aCommand = aFontHeightCommand + rtl::OUString::valueOf( fPoint );
229                     pVCLPopupMenu->SetItemCommand( nPos, aCommand );
230 			    }
231 		    }
232 		    else
233 		    {
234 			    // for fixed size fonts only selectable font size names
235 			    pTempAry = pAry;
236 			    while ( *pTempAry )
237 			    {
238 				    String aSizeName = aFontSizeNames.Size2Name( *pTempAry );
239 				    if ( aSizeName.Len() )
240 				    {
241 					    m_pHeightArray[nPos] = *pTempAry;
242 					    nPos++; // Id is nPos+1
243 					    pVCLPopupMenu->InsertItem( nPos, aSizeName, MIB_RADIOCHECK | MIB_AUTOCHECK );
244 				        fPoint = float( m_pHeightArray[nPos-1] ) / 10;
245 
246                         // Create dispatchable .uno command and set it
247                         aCommand = aFontHeightCommand + rtl::OUString::valueOf( fPoint );
248                         pVCLPopupMenu->SetItemCommand( nPos, aCommand );
249                     }
250 				    pTempAry++;
251 			    }
252 		    }
253 	    }
254 
255 	    // then insert numerical font size values
256         const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
257 	    pTempAry = pAry;
258 	    while ( *pTempAry )
259 	    {
260 		    m_pHeightArray[nPos] = *pTempAry;
261 		    nPos++; // Id is nPos+1
262 		    pVCLPopupMenu->InsertItem( nPos, rI18nHelper.GetNum( *pTempAry, 1, sal_True, sal_False ), MIB_RADIOCHECK | MIB_AUTOCHECK );
263             fPoint = float( m_pHeightArray[nPos-1] ) / 10;
264 
265             // Create dispatchable .uno command and set it
266             aCommand = aFontHeightCommand + rtl::OUString::valueOf( fPoint );
267             pVCLPopupMenu->SetItemCommand( nPos, aCommand );
268 
269             pTempAry++;
270 	    }
271 
272 	    setCurHeight( long( m_aFontHeight.Height * 10), rPopupMenu );
273 
274 	    delete pFontList;
275 	    delete pInfoPrinter;
276     }
277 }
278 
279 // XEventListener
280 void SAL_CALL FontSizeMenuController::disposing( const EventObject& ) throw ( RuntimeException )
281 {
282     Reference< css::awt::XMenuListener > xHolder(( OWeakObject *)this, UNO_QUERY );
283 
284     osl::MutexGuard aLock( m_aMutex );
285     m_xFrame.clear();
286     m_xDispatch.clear();
287     m_xCurrentFontDispatch.clear();
288     if ( m_xPopupMenu.is() )
289         m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(( OWeakObject *)this, UNO_QUERY ));
290     m_xPopupMenu.clear();
291 }
292 
293 // XStatusListener
294 void SAL_CALL FontSizeMenuController::statusChanged( const FeatureStateEvent& Event ) throw ( RuntimeException )
295 {
296     com::sun::star::awt::FontDescriptor                 aFontDescriptor;
297     ::com::sun::star::frame::status::FontHeight   aFontHeight;
298 
299     if ( Event.State >>= aFontDescriptor )
300     {
301         osl::MutexGuard aLock( m_aMutex );
302         m_aFontDescriptor = aFontDescriptor;
303 
304         if ( m_xPopupMenu.is() )
305             fillPopupMenu( m_xPopupMenu );
306 
307     }
308     else if ( Event.State >>= aFontHeight )
309     {
310         osl::MutexGuard aLock( m_aMutex );
311         m_aFontHeight = aFontHeight;
312 
313 	    if ( m_xPopupMenu.is() )
314         {
315             vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
316 	        setCurHeight( long( m_aFontHeight.Height * 10), m_xPopupMenu );
317         }
318     }
319 }
320 
321 // XMenuListener
322 void FontSizeMenuController::impl_select(const Reference< XDispatch >& _xDispatch,const ::com::sun::star::util::URL& aTargetURL)
323 {
324     Sequence<PropertyValue>	     aArgs;
325     if(::comphelper::UiEventsLogger::isEnabled()) //#i88653#
326         UiEventLogHelper(::rtl::OUString::createFromAscii("FontSizeMenuController")).log(m_xServiceManager, m_xFrame, aTargetURL, aArgs);
327 	OSL_ENSURE(_xDispatch.is(),"FontSizeMenuController::impl_select: No dispatch");
328 	if ( _xDispatch.is() )
329 		_xDispatch->dispatch( aTargetURL, aArgs );
330 }
331 
332 // XPopupMenuController
333 void FontSizeMenuController::impl_setPopupMenu()
334 {
335     Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
336     com::sun::star::util::URL aTargetURL;
337     // Register for font name updates which gives us info about the current font!
338     aTargetURL.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:CharFontName" ));
339     m_xURLTransformer->parseStrict( aTargetURL );
340     m_xCurrentFontDispatch = xDispatchProvider->queryDispatch( aTargetURL, ::rtl::OUString(), 0 );
341 }
342 
343 void SAL_CALL FontSizeMenuController::updatePopupMenu() throw ( ::com::sun::star::uno::RuntimeException )
344 {
345     osl::ClearableMutexGuard aLock( m_aMutex );
346 
347 	throwIfDisposed();
348 
349     Reference< XDispatch > xDispatch( m_xCurrentFontDispatch );
350     com::sun::star::util::URL aTargetURL;
351     aTargetURL.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:CharFontName" ));
352     m_xURLTransformer->parseStrict( aTargetURL );
353     aLock.clear();
354 
355     if ( xDispatch.is() )
356     {
357         xDispatch->addStatusListener( SAL_STATIC_CAST( XStatusListener*, this ), aTargetURL );
358         xDispatch->removeStatusListener( SAL_STATIC_CAST( XStatusListener*, this ), aTargetURL );
359     }
360 
361 	svt::PopupMenuControllerBase::updatePopupMenu();
362 }
363 }
364