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 
31 #include <uielement/langselectionmenucontroller.hxx>
32 
33 //_________________________________________________________________________________________________________________
34 //	my own includes
35 //_________________________________________________________________________________________________________________
36 #include <threadhelp/resetableguard.hxx>
37 #include "services.h"
38 
39 //_________________________________________________________________________________________________________________
40 //	interface includes
41 //_________________________________________________________________________________________________________________
42 #include <com/sun/star/awt/XDevice.hpp>
43 #include <com/sun/star/beans/PropertyValue.hpp>
44 #include <com/sun/star/awt/MenuItemStyle.hpp>
45 #include <com/sun/star/frame/XDispatchProvider.hpp>
46 
47 //_________________________________________________________________________________________________________________
48 //	includes of other projects
49 //_________________________________________________________________________________________________________________
50 
51 #ifndef _VCL_MENU_HXX_
52 #include <vcl/menu.hxx>
53 #endif
54 #include <vcl/svapp.hxx>
55 #include <vcl/i18nhelp.hxx>
56 #include <tools/urlobj.hxx>
57 #include <rtl/ustrbuf.hxx>
58 #ifndef _VCL_MNEMONIC_HXX_
59 #include <vcl/mnemonic.hxx>
60 #endif
61 #include <com/sun/star/awt/XMenuExtended.hpp>
62 #include <comphelper/processfactory.hxx>
63 
64 #include <com/sun/star/document/XDocumentLanguages.hpp>
65 #include <com/sun/star/frame/XPopupMenuController.hpp>
66 #include <com/sun/star/linguistic2/XLanguageGuessing.hpp>
67 
68 #include <i18npool/mslangid.hxx>
69 #include <svl/languageoptions.hxx>
70 #include <com/sun/star/awt/MenuItemStyle.hpp>
71 #include <svtools/langtab.hxx>
72 #include <classes/fwlresid.hxx>
73 
74 #ifndef __FRAMEWORK_CLASSES_RESOURCE_HRC_
75 #include <classes/resource.hrc>
76 #endif
77 #include <dispatch/uieventloghelper.hxx>
78 
79 #include "helper/mischelper.hxx"
80 #include <vos/mutex.hxx>
81 
82 #include <map>
83 #include <set>
84 
85 //_________________________________________________________________________________________________________________
86 //	Defines
87 //_________________________________________________________________________________________________________________
88 //
89 using namespace ::com::sun::star;
90 using namespace com::sun::star::uno;
91 using namespace com::sun::star::lang;
92 using namespace com::sun::star::frame;
93 using namespace com::sun::star::beans;
94 using namespace com::sun::star::util;
95 
96 using ::rtl::OUString;
97 
98 namespace framework
99 {
100 
101 DEFINE_XSERVICEINFO_MULTISERVICE        (   LanguageSelectionMenuController			,
102                                             OWeakObject                             ,
103                                             SERVICENAME_POPUPMENUCONTROLLER			,
104 											IMPLEMENTATIONNAME_LANGUAGESELECTIONMENUCONTROLLER
105 										)
106 
107 DEFINE_INIT_SERVICE                     (   LanguageSelectionMenuController, {} )
108 
109 LanguageSelectionMenuController::LanguageSelectionMenuController( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xServiceManager ) :
110 	svt::PopupMenuControllerBase( xServiceManager ),
111 	m_bShowMenu( sal_True ),
112     m_aLangGuessHelper( xServiceManager )
113 {
114 }
115 
116 LanguageSelectionMenuController::~LanguageSelectionMenuController()
117 {
118 }
119 
120 // XEventListener
121 void SAL_CALL LanguageSelectionMenuController::disposing( const EventObject& ) throw ( RuntimeException )
122 {
123     Reference< css::awt::XMenuListener > xHolder(( OWeakObject *)this, UNO_QUERY );
124 
125     osl::MutexGuard aLock( m_aMutex );
126     m_xFrame.clear();
127     m_xDispatch.clear();
128     m_xLanguageDispatch.clear();
129     m_xServiceManager.clear();
130 
131     if ( m_xPopupMenu.is() )
132         m_xPopupMenu->removeMenuListener( Reference< css::awt::XMenuListener >(( OWeakObject *)this, UNO_QUERY ));
133     m_xPopupMenu.clear();
134 }
135 
136 // XStatusListener
137 void SAL_CALL LanguageSelectionMenuController::statusChanged( const FeatureStateEvent& Event ) throw ( RuntimeException )
138 {
139     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
140 
141     if (rBHelper.bDisposed || rBHelper.bInDispose)
142         return;
143 
144 	m_bShowMenu = sal_True;
145 	m_nScriptType = LS_SCRIPT_LATIN | LS_SCRIPT_ASIAN | LS_SCRIPT_COMPLEX;  //set the default value
146 
147     OUString               aStrValue;
148     Sequence< OUString > aSeq;
149 
150     if ( Event.State >>= aSeq )
151     {
152         if ( aSeq.getLength() == 4 )
153         {
154             // Retrieve all other values from the sequence and
155             // store it members!
156             m_aCurLang          = aSeq[0];
157             m_nScriptType       = static_cast< sal_Int16 >(aSeq[1].toInt32());
158             m_aKeyboardLang     = aSeq[2];
159             m_aGuessedTextLang  = aSeq[3];
160         }
161     }
162     else if ( !Event.State.hasValue() )
163 	{
164         m_bShowMenu = sal_False;	// no language -> no sub-menu entries -> disable menu
165 	}
166 }
167 
168 // XMenuListener
169 void LanguageSelectionMenuController::impl_select(const Reference< XDispatch >& _xDispatch,const ::com::sun::star::util::URL& aTargetURL)
170 {
171     Reference< XDispatch > xDispatch = _xDispatch;
172 
173 	if ( aTargetURL.Complete == m_aMenuCommandURL_Font )
174 	{	//open format/character dialog for current selection
175 		xDispatch = m_xMenuDispatch_Font;
176 	}
177 	else if ( aTargetURL.Complete == m_aMenuCommandURL_Lang )
178 	{	//open language tab-page in tools/options dialog
179 		xDispatch = m_xMenuDispatch_Lang;
180 	}
181 	else if ( aTargetURL.Complete == m_aMenuCommandURL_CharDlgForParagraph )
182 	{	//open format/character dialog for current selection
183 		xDispatch = m_xMenuDispatch_CharDlgForParagraph;
184 	}
185 
186 	if ( !xDispatch.is() )
187 	{
188 		Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
189 		if ( xDispatchProvider.is() )
190 			xDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
191 	}
192 
193 	if ( xDispatch.is() )
194 	{
195         Sequence<PropertyValue>	     aArgs;
196         if(::comphelper::UiEventsLogger::isEnabled()) //#i88653#
197             UiEventLogHelper( OUString::createFromAscii("LanguageSelectionMenuController")).log( m_xServiceManager, m_xFrame, aTargetURL, aArgs );
198         xDispatch->dispatch( aTargetURL, aArgs );
199 	}
200 }
201 
202 // XPopupMenuController
203 void LanguageSelectionMenuController::impl_setPopupMenu()
204 {
205     Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
206 
207     com::sun::star::util::URL aTargetURL;
208 
209     // Register for language updates
210     aTargetURL.Complete = m_aLangStatusCommandURL;
211     m_xURLTransformer->parseStrict( aTargetURL );
212     m_xLanguageDispatch = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
213 
214 	// Register for setting languages and opening language dialog
215     aTargetURL.Complete = m_aMenuCommandURL_Lang;
216     m_xURLTransformer->parseStrict( aTargetURL );
217     m_xMenuDispatch_Lang = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
218 
219 	// Register for opening character dialog
220     aTargetURL.Complete = m_aMenuCommandURL_Font;
221     m_xURLTransformer->parseStrict( aTargetURL );
222     m_xMenuDispatch_Font = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
223 
224 	// Register for opening character dialog with preselected paragraph
225     aTargetURL.Complete = m_aMenuCommandURL_CharDlgForParagraph;
226     m_xURLTransformer->parseStrict( aTargetURL );
227     m_xMenuDispatch_CharDlgForParagraph = xDispatchProvider->queryDispatch( aTargetURL, OUString(), 0 );
228 }
229 
230 void LanguageSelectionMenuController::fillPopupMenu( Reference< css::awt::XPopupMenu >& rPopupMenu , const Mode eMode )
231 {
232     VCLXPopupMenu* pVCLPopupMenu = (VCLXPopupMenu *)VCLXMenu::GetImplementation( rPopupMenu );
233     PopupMenu*     pPopupMenu    = 0;
234 
235     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
236 
237     resetPopupMenu( rPopupMenu );
238 	if (!m_bShowMenu)
239 		return;
240 
241     if ( pVCLPopupMenu )
242         pPopupMenu = (PopupMenu *)pVCLPopupMenu->GetMenu();
243 
244 	String aCmd;
245 	String aCmd_Dialog;
246 	String aCmd_Language;
247     if( eMode == MODE_SetLanguageSelectionMenu )
248 	{
249         aCmd_Dialog.AppendAscii(".uno:FontDialog?Language:string=*");
250 		aCmd_Language.AppendAscii(".uno:LanguageStatus?Language:string=Current_");
251 	}
252 	else if ( eMode == MODE_SetLanguageParagraphMenu )
253 	{
254 		aCmd_Dialog.AppendAscii(".uno:FontDialogForParagraph");
255 		aCmd_Language.AppendAscii(".uno:LanguageStatus?Language:string=Paragraph_");
256 	}
257     else if ( eMode == MODE_SetLanguageAllTextMenu )
258     {
259         aCmd_Dialog.AppendAscii(".uno:LanguageStatus?Language:string=*");
260         aCmd_Language.AppendAscii(".uno:LanguageStatus?Language:string=Default_");
261     }
262 
263     SvtLanguageTable    aLanguageTable;
264 
265     // get languages to be displayed in the menu
266     std::set< OUString > aLangItems;
267     FillLangItems( aLangItems, aLanguageTable, m_xFrame, m_aLangGuessHelper,
268             m_nScriptType, m_aCurLang, m_aKeyboardLang, m_aGuessedTextLang );
269 
270     //
271     // now add menu entries
272     // the different menues purpose will be handled by the different string
273     // for aCmd_Dialog and aCmd_Language
274     //
275 
276     sal_Int16 nItemId = 1;  // in this control the item id is not important for executing the command
277     const OUString sAsterix(RTL_CONSTASCII_USTRINGPARAM("*"));  // multiple languages in current selection
278     const OUString sEmpty;  // 'no language found' from language guessing
279     std::map< sal_Int16, OUString > aLangMap;
280     std::set< OUString >::const_iterator it;
281     for (it = aLangItems.begin(); it != aLangItems.end(); ++it)
282 	{
283         const OUString & rStr( *it );
284         if (rStr != OUString( aLanguageTable.GetString( LANGUAGE_NONE ) )&&
285             rStr != sAsterix &&
286             rStr != sEmpty)
287 		{
288 			pPopupMenu->InsertItem( nItemId, rStr );
289 			aCmd = aCmd_Language;
290 			aCmd += String( rStr );
291 			pPopupMenu->SetItemCommand( nItemId, aCmd );
292             if (rStr == m_aCurLang && eMode == MODE_SetLanguageSelectionMenu )
293 			{
294 				//make a sign for the current language
295 				pPopupMenu->CheckItem( nItemId, sal_True );
296 			}
297             aLangMap[ nItemId ] = rStr;
298             ++nItemId;
299 		}
300 	}
301 
302     // entry for LANGUAGE_NONE
303 	++nItemId;
304 	pPopupMenu->InsertItem( nItemId, String(FwlResId( STR_LANGSTATUS_NONE )) );
305 	aCmd=aCmd_Language;
306 	aCmd.AppendAscii("LANGUAGE_NONE");
307 	pPopupMenu->SetItemCommand( nItemId, aCmd );
308 
309     // entry for 'Reset to default language'
310 	++nItemId;
311 	pPopupMenu->InsertItem( nItemId, String(FwlResId( STR_RESET_TO_DEFAULT_LANGUAGE )) );
312 	aCmd=aCmd_Language;
313 	aCmd.AppendAscii("RESET_LANGUAGES");
314 	pPopupMenu->SetItemCommand( nItemId, aCmd );
315 
316     // entry for opening the Format/Character dialog
317 	++nItemId;
318 	pPopupMenu->InsertItem( nItemId, String(FwlResId( STR_LANGSTATUS_MORE )));
319     pPopupMenu->SetItemCommand( nItemId, aCmd_Dialog );
320 }
321 
322 
323 void SAL_CALL LanguageSelectionMenuController::updatePopupMenu() throw ( ::com::sun::star::uno::RuntimeException )
324 {
325 	svt::PopupMenuControllerBase::updatePopupMenu();
326 
327     // Force status update to get information about the current languages
328     osl::ClearableMutexGuard aLock( m_aMutex );
329     Reference< XDispatch > xDispatch( m_xLanguageDispatch );
330     com::sun::star::util::URL aTargetURL;
331     aTargetURL.Complete = m_aLangStatusCommandURL;
332     m_xURLTransformer->parseStrict( aTargetURL );
333     aLock.clear();
334 
335     if ( xDispatch.is() )
336     {
337         xDispatch->addStatusListener( SAL_STATIC_CAST( XStatusListener*, this ), aTargetURL );
338         xDispatch->removeStatusListener( SAL_STATIC_CAST( XStatusListener*, this ), aTargetURL );
339     }
340 
341     // TODO: Fill menu with the information retrieved by the status update
342 
343     if( m_aCommandURL.equalsAscii( ".uno:SetLanguageSelectionMenu" ))
344 	{
345         fillPopupMenu(m_xPopupMenu, MODE_SetLanguageSelectionMenu );
346 	}
347 	else if( m_aCommandURL.equalsAscii( ".uno:SetLanguageParagraphMenu" ))
348 	{
349 		fillPopupMenu(m_xPopupMenu, MODE_SetLanguageParagraphMenu );
350 	}
351     else if( m_aCommandURL.equalsAscii( ".uno:SetLanguageAllTextMenu" ))
352 	{
353         fillPopupMenu(m_xPopupMenu, MODE_SetLanguageAllTextMenu );
354 	}
355 }
356 
357 // XInitialization
358 void SAL_CALL LanguageSelectionMenuController::initialize( const Sequence< Any >& aArguments ) throw ( Exception, RuntimeException )
359 {
360     osl::MutexGuard aLock( m_aMutex );
361 
362     sal_Bool bInitalized( m_bInitialized );
363     if ( !bInitalized )
364     {
365 		svt::PopupMenuControllerBase::initialize(aArguments);
366 
367         if ( m_bInitialized )
368         {
369 			m_aLangStatusCommandURL				  = OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:LanguageStatus" ));
370 			m_aMenuCommandURL_Lang				  = m_aLangStatusCommandURL;
371 			m_aMenuCommandURL_Font			      = OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:FontDialog" ));
372 			m_aMenuCommandURL_CharDlgForParagraph = OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:FontDialogForParagraph" ));
373         }
374     }
375 }
376 
377 }
378 
379