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/langselectionstatusbarcontroller.hxx>
32 #include <classes/fwkresid.hxx>
33 #include <services.h>
34 #include <classes/resource.hrc>
35 #include <vos/mutex.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/window.hxx>
38 #include <vcl/status.hxx>
39 #ifndef _TOOLKIT_HELPER_VCLUNOHELPER_HXX_
40 #include <toolkit/unohlp.hxx>
41 #endif
42 #include <toolkit/helper/convert.hxx>
43 
44 #include <com/sun/star/frame/XPopupMenuController.hpp>
45 #include <toolkit/helper/vclunohelper.hxx>
46 #include <com/sun/star/awt/PopupMenuDirection.hpp>
47 #include <svtools/langtab.hxx>
48 #include "sal/types.h"
49 #include <vcl/svapp.hxx>
50 #include <com/sun/star/awt/MenuItemStyle.hpp>
51 #include <com/sun/star/document/XDocumentLanguages.hpp>
52 #include <i18npool/mslangid.hxx>
53 #include <com/sun/star/i18n/ScriptType.hpp>
54 #include <com/sun/star/frame/XModule.hpp>
55 #include <com/sun/star/frame/XModel.hpp>
56 
57 #include <classes/fwkresid.hxx>
58 #ifndef __FRAMEWORK_CLASSES_RESOURCE_HRC_
59 #include <classes/resource.hrc>
60 #endif
61 #include <com/sun/star/frame/XFrame.hpp>
62 #include <com/sun/star/frame/XDispatch.hpp>
63 #include <com/sun/star/frame/XDispatchProvider.hpp>
64 #include <com/sun/star/util/XURLTransformer.hpp>
65 #include <comphelper/processfactory.hxx>
66 
67 #include <toolkit/unohlp.hxx>
68 #include <tools/gen.hxx>
69 #include <com/sun/star/awt/Command.hpp>
70 #include <svl/languageoptions.hxx>
71 #include <com/sun/star/linguistic2/XLanguageGuessing.hpp>
72 #include <dispatch/uieventloghelper.hxx>
73 
74 #include "helper/mischelper.hxx"
75 
76 #include <map>
77 #include <set>
78 
79 using namespace ::cppu;
80 using namespace ::com::sun::star;
81 using namespace ::com::sun::star::uno;
82 using namespace ::com::sun::star::lang;
83 using namespace ::com::sun::star::frame;
84 using namespace ::com::sun::star::i18n;
85 using namespace ::com::sun::star::document;
86 
87 using ::rtl::OUString;
88 
89 
90 namespace framework
91 {
92 
93 ////////////////////////////////////////////////////////////
94 
95 DEFINE_XSERVICEINFO_MULTISERVICE        (   LangSelectionStatusbarController     	    ,
96                                             OWeakObject                             ,
97                                             SERVICENAME_STATUSBARCONTROLLER		    ,
98 											IMPLEMENTATIONNAME_LANGSELECTIONSTATUSBARCONTROLLER
99 										)
100 
101 DEFINE_INIT_SERVICE                     (   LangSelectionStatusbarController, {} )
102 
103 LangSelectionStatusbarController::LangSelectionStatusbarController( const uno::Reference< lang::XMultiServiceFactory >& xServiceManager ) :
104     svt::StatusbarController( xServiceManager, uno::Reference< frame::XFrame >(), OUString(), 0 ),
105 	m_bShowMenu( sal_True ),
106     m_nScriptType( LS_SCRIPT_LATIN | LS_SCRIPT_ASIAN | LS_SCRIPT_COMPLEX ),
107     m_aLangGuessHelper( xServiceManager )
108 {
109 }
110 
111 // XInterface
112 Any SAL_CALL LangSelectionStatusbarController::queryInterface( const Type& rType )
113 throw ( RuntimeException )
114 {
115     return svt::StatusbarController::queryInterface( rType );
116 }
117 
118 void SAL_CALL LangSelectionStatusbarController::acquire() throw ()
119 {
120     svt::StatusbarController::acquire();
121 }
122 
123 void SAL_CALL LangSelectionStatusbarController::release() throw ()
124 {
125     svt::StatusbarController::release();
126 }
127 
128 void SAL_CALL LangSelectionStatusbarController::initialize( const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aArguments )
129 throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException)
130 {
131     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::initialize" );
132     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
133 
134     svt::StatusbarController::initialize( aArguments );
135 
136     if ( m_xParentWindow.is() && m_nID > 0 )
137     {
138         Window* pWindow = VCLUnoHelper::GetWindow( m_xParentWindow );
139         if ( pWindow && ( pWindow->GetType() == WINDOW_STATUSBAR ))
140         {
141             StatusBar* pStatusBar = (StatusBar *)pWindow;
142             pStatusBar->SetItemText( m_nID, FwkResId( STR_LANGSTATUS_MULTIPLE_LANGUAGES ) );
143         }
144     }
145 }
146 
147 // XComponent
148 void SAL_CALL LangSelectionStatusbarController::dispose()
149 throw (::com::sun::star::uno::RuntimeException)
150 {
151     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::dispose" );
152     svt::StatusbarController::dispose();
153 }
154 
155 // XEventListener
156 void SAL_CALL LangSelectionStatusbarController::disposing( const com::sun::star::lang::EventObject& Source )
157 throw ( RuntimeException )
158 {
159     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::disposing" );
160     svt::StatusbarController::disposing( Source );
161 }
162 
163 // XStatusbarController
164 ::sal_Bool SAL_CALL LangSelectionStatusbarController::mouseButtonDown(
165     const ::com::sun::star::awt::MouseEvent& )
166 throw (::com::sun::star::uno::RuntimeException)
167 {
168     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::mouseButtonDown" );
169     return sal_False;
170 }
171 
172 ::sal_Bool SAL_CALL LangSelectionStatusbarController::mouseMove(
173     const ::com::sun::star::awt::MouseEvent& )
174 throw (::com::sun::star::uno::RuntimeException)
175 {
176     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::mouseMove" );
177     return sal_False;
178 }
179 
180 ::sal_Bool SAL_CALL LangSelectionStatusbarController::mouseButtonUp(
181     const ::com::sun::star::awt::MouseEvent& )
182 throw (::com::sun::star::uno::RuntimeException)
183 {
184     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::mouseButtonUp" );
185     return sal_False;
186 }
187 
188 void LangSelectionStatusbarController::LangMenu()
189 throw (::com::sun::star::uno::RuntimeException)
190 {
191     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::LangMenu" );
192 	if (!m_bShowMenu)
193 		return;
194 
195 	//add context menu
196     const static OUString s_sPopupMenu(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.PopupMenu"));
197 	Reference< awt::XPopupMenu > xPopupMenu( m_xServiceManager->createInstance( s_sPopupMenu ), UNO_QUERY );
198     //sub menu that contains all items except the last two items: Separator + Set Language for Paragraph
199 	Reference< awt::XPopupMenu > subPopupMenu(m_xServiceManager->createInstance( s_sPopupMenu ), UNO_QUERY );
200 
201     SvtLanguageTable    aLanguageTable;
202 
203     // get languages to be displayed in the menu
204     std::set< OUString > aLangItems;
205     FillLangItems( aLangItems, aLanguageTable, m_xFrame, m_aLangGuessHelper,
206             m_nScriptType, m_aCurLang, m_aKeyboardLang, m_aGuessedTextLang );
207 
208     //
209     // add first few entries to main menu
210     //
211 	sal_Int16 nItemId = static_cast< sal_Int16 >(MID_LANG_SEL_1);
212     const OUString sAsterix(RTL_CONSTASCII_USTRINGPARAM("*"));  // multiple languages in current selection
213     const OUString sEmpty;  // 'no language found' from language guessing
214     std::map< sal_Int16, OUString > aLangMap;
215     std::set< OUString >::const_iterator it;
216     for (it = aLangItems.begin(); it != aLangItems.end(); ++it)
217     {
218         const OUString & rStr( *it );
219         if ( rStr != OUString( aLanguageTable.GetString( LANGUAGE_NONE ) ) &&
220              rStr != sAsterix &&
221              rStr != sEmpty)
222 		{
223             DBG_ASSERT( MID_LANG_SEL_1 <= nItemId && nItemId <= MID_LANG_SEL_9,
224                     "nItemId outside of expected range!" );
225 	        xPopupMenu->insertItem( nItemId, rStr, css::awt::MenuItemStyle::RADIOCHECK, nItemId );
226 		    if ( rStr == m_aCurLang )
227 	        {
228 				//make a sign for the current language
229                 xPopupMenu->checkItem( nItemId, sal_True );
230 		    }
231             aLangMap[ nItemId ] = rStr;
232 			++nItemId;
233 		}
234     }
235     xPopupMenu->insertItem( MID_LANG_SEL_NONE,  String( FwkResId( STR_LANGSTATUS_NONE )), css::awt::MenuItemStyle::RADIOCHECK, MID_LANG_SEL_NONE );
236     xPopupMenu->insertItem( MID_LANG_SEL_RESET, String( FwkResId( STR_RESET_TO_DEFAULT_LANGUAGE )), css::awt::MenuItemStyle::RADIOCHECK, MID_LANG_SEL_RESET );
237     xPopupMenu->insertItem( MID_LANG_SEL_MORE,  String( FwkResId( STR_LANGSTATUS_MORE )), css::awt::MenuItemStyle::RADIOCHECK, MID_LANG_SEL_MORE );
238 
239     //
240     // add entries to submenu ('set language for paragraph')
241     //
242 	nItemId = static_cast< sal_Int16 >(MID_LANG_PARA_1);
243     for (it = aLangItems.begin(); it != aLangItems.end(); ++it)
244     {
245         const OUString & rStr( *it );
246         if( rStr != OUString( aLanguageTable.GetString( LANGUAGE_NONE ) )&&
247             rStr != sAsterix &&
248             rStr != sEmpty)
249 		{
250             DBG_ASSERT( MID_LANG_PARA_1 <= nItemId && nItemId <= MID_LANG_PARA_9,
251                     "nItemId outside of expected range!" );
252             subPopupMenu->insertItem( nItemId, rStr, css::awt::MenuItemStyle::RADIOCHECK, nItemId );
253 			aLangMap[nItemId] = rStr;
254             ++nItemId;
255 		}
256     }
257     subPopupMenu->insertItem( MID_LANG_PARA_NONE,  String( FwkResId( STR_LANGSTATUS_NONE )), css::awt::MenuItemStyle::RADIOCHECK, MID_LANG_PARA_NONE );
258     subPopupMenu->insertItem( MID_LANG_PARA_RESET, String( FwkResId( STR_RESET_TO_DEFAULT_LANGUAGE )), css::awt::MenuItemStyle::RADIOCHECK, MID_LANG_PARA_RESET );
259     subPopupMenu->insertItem( MID_LANG_PARA_MORE,  String( FwkResId( STR_LANGSTATUS_MORE )), css::awt::MenuItemStyle::RADIOCHECK, MID_LANG_PARA_MORE );
260 
261     //
262     // add last two entries to main menu
263     //
264 	xPopupMenu->insertSeparator( MID_LANG_PARA_SEPERATOR );
265     xPopupMenu->insertItem( MID_LANG_PARA_STRING, String( FwkResId( STR_SET_LANGUAGE_FOR_PARAGRAPH )), css::awt::MenuItemStyle::RADIOCHECK, MID_LANG_PARA_STRING );
266 	xPopupMenu->setPopupMenu( MID_LANG_PARA_STRING, subPopupMenu );
267 
268 
269     //
270     // now display the popup menu and execute every command ...
271     //
272 
273 	Reference< awt::XWindowPeer > xParent( m_xParentWindow, UNO_QUERY );
274 
275 	com::sun::star::awt::Rectangle aRectangle;
276 	Window* pWindow = VCLUnoHelper::GetWindow( m_xParentWindow );
277 	const Point mMousePos = pWindow->GetPointerPosPixel();
278     aRectangle.X = mMousePos.X();
279 	aRectangle.Y = mMousePos.Y();
280 	sal_Int16 nId = xPopupMenu->execute( xParent, aRectangle, com::sun::star::awt::PopupMenuDirection::EXECUTE_UP+16 );
281     //click "More..."
282     if ( nId && m_xFrame.is() )
283     {
284         uno::Reference< XDispatchProvider > xDispatchProvider( m_xFrame, UNO_QUERY );
285         util::URL aURL;
286 
287 		if (MID_LANG_SEL_1 <= nId && nId <= MID_LANG_SEL_9)
288 		{
289             //set selected language as current language for selection
290 			String aSelectedLang = aLangMap[nId];
291             aURL.Complete += OUString::createFromAscii(".uno:LanguageStatus?Language:string=Current_");
292 			aURL.Complete += aSelectedLang;
293 		}
294 		else if (nId == MID_LANG_SEL_NONE)
295 		{
296             //set None as current language for selection
297             aURL.Complete += OUString::createFromAscii(".uno:LanguageStatus?Language:string=Current_LANGUAGE_NONE");
298 		}
299 		else if (nId == MID_LANG_SEL_RESET)
300 		{
301             // reset language attributes for selection
302             aURL.Complete += OUString::createFromAscii(".uno:LanguageStatus?Language:string=Current_RESET_LANGUAGES");
303         }
304 		else if (nId == MID_LANG_SEL_MORE)
305 		{
306 			//open the dialog "format/character" for current selection
307             aURL.Complete += OUString::createFromAscii(".uno:FontDialog?Language:string=*");
308 		}
309         else if (MID_LANG_PARA_1 <= nId && nId <= MID_LANG_PARA_9)
310 		{
311             //set selected language for current paragraph
312             String aSelectedLang = aLangMap[nId];
313             aURL.Complete += OUString::createFromAscii(".uno:LanguageStatus?Language:string=Paragraph_");
314             aURL.Complete += aSelectedLang;
315 		}
316         else if (nId == MID_LANG_PARA_NONE)
317         {
318             //set None as language for current paragraph
319             aURL.Complete += OUString::createFromAscii(".uno:LanguageStatus?Language:string=Paragraph_LANGUAGE_NONE");
320         }
321         else if (nId == MID_LANG_PARA_RESET)
322         {
323             // reset language attributes for paragraph
324             aURL.Complete += OUString::createFromAscii(".uno:LanguageStatus?Language:string=Paragraph_RESET_LANGUAGES");
325         }
326         else if (nId == MID_LANG_PARA_MORE)
327 		{
328 			//open the dialog "format/character" for current paragraph
329             aURL.Complete += OUString::createFromAscii(".uno:FontDialogForParagraph");
330 		}
331 
332 		uno::Reference< util::XURLTransformer > xURLTransformer( m_xServiceManager->createInstance( OUString::createFromAscii("com.sun.star.util.URLTransformer" )), uno::UNO_QUERY );
333         xURLTransformer->parseStrict( aURL );
334         uno::Reference< XDispatch > xDispatch = xDispatchProvider->queryDispatch(aURL, OUString(), 0);
335         if( xDispatch.is() )
336         {
337 		    uno::Sequence< beans::PropertyValue > aPV;
338             if(::comphelper::UiEventsLogger::isEnabled()) //#i88653#
339                 UiEventLogHelper( OUString::createFromAscii("ButtonToolbarController")).log(m_xServiceManager, m_xFrame, aURL, aPV);
340             xDispatch->dispatch( aURL, aPV);
341 		}
342     }
343 }
344 
345 void SAL_CALL LangSelectionStatusbarController::command(
346     const ::com::sun::star::awt::Point& /*aPos*/,
347     ::sal_Int32 nCommand,
348     ::sal_Bool /*bMouseEvent*/,
349     const ::com::sun::star::uno::Any& /*aData*/ )
350 throw (::com::sun::star::uno::RuntimeException)
351 {
352     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::command" );
353 	if ( nCommand & ::awt::Command::CONTEXTMENU )
354 	{
355         LangMenu();
356 	}
357 }
358 
359 void SAL_CALL LangSelectionStatusbarController::paint(
360     const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XGraphics >& xGraphics,
361     const ::com::sun::star::awt::Rectangle& rOutputRectangle,
362     ::sal_Int32 nItemId,
363     ::sal_Int32 nStyle )
364 throw (::com::sun::star::uno::RuntimeException)
365 {
366     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::paint" );
367     svt::StatusbarController::paint( xGraphics, rOutputRectangle, nItemId, nStyle );
368 }
369 
370 void SAL_CALL LangSelectionStatusbarController::click()
371 throw (::com::sun::star::uno::RuntimeException)
372 {
373     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::click" );
374     LangMenu();
375 }
376 
377 void SAL_CALL LangSelectionStatusbarController::doubleClick()
378 throw (::com::sun::star::uno::RuntimeException)
379 {
380     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::doubleClick" );
381     svt::StatusbarController::doubleClick();
382 }
383 
384 // XStatusListener
385 void SAL_CALL LangSelectionStatusbarController::statusChanged( const FeatureStateEvent& Event )
386 throw ( RuntimeException )
387 {
388     // This function will be called when observed data changes,
389     // for example the selection or keyboard language.
390     // - It displays the language in use in the status bar
391     // - and it stores the relevant data for creating the menu
392     //   at some later point in the member variables
393     //      m_nScriptType, m_aCurLang, m_aKeyboardLang, m_aGuessedText
394 
395     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "framework", "Ocke.Janssen@sun.com", "LangSelectionStatusbarController::statusChanged" );
396     vos::OGuard aSolarMutexGuard( Application::GetSolarMutex() );
397 
398     if ( m_bDisposed )
399         return;
400 
401 	m_bShowMenu = sal_True;
402 
403 	m_nScriptType = LS_SCRIPT_LATIN | LS_SCRIPT_ASIAN | LS_SCRIPT_COMPLEX;  //set the default value
404     Window* pWindow = VCLUnoHelper::GetWindow( m_xParentWindow );
405     if ( pWindow && pWindow->GetType() == WINDOW_STATUSBAR && m_nID != 0 )
406     {
407         OUString               aStrValue;
408         Sequence< OUString > aSeq;
409 
410         StatusBar*    pStatusBar = (StatusBar *)pWindow;
411         if ( Event.State >>= aStrValue )
412             pStatusBar->SetItemText( m_nID, aStrValue );
413         else if ( Event.State >>= aSeq )
414         {
415             if ( aSeq.getLength() == 4 )
416             {
417 				const String aMultipleLangText( FwkResId( STR_LANGSTATUS_MULTIPLE_LANGUAGES ) );
418 				OUString aStatusText = aSeq[0];
419 				if ( 0 == aStatusText.compareToAscii( "*" ))
420 					aStatusText = aMultipleLangText;
421 				pStatusBar->SetItemText( m_nID, aStatusText );
422 
423                 // Retrieve all other values from the sequence and
424                 // store it members!
425 				m_aCurLang      = aSeq[0];
426                 m_nScriptType   = static_cast< sal_Int16 >( aSeq[1].toInt32() );
427 	            m_aKeyboardLang = aSeq[2];
428                 m_aGuessedTextLang  = aSeq[3];
429             }
430         }
431         else if ( !Event.State.hasValue() )
432 		{
433             pStatusBar->SetItemText( m_nID, String() );
434 			m_bShowMenu = sal_False;	// no language -> no menu
435 		}
436     }
437 }
438 
439 }
440 
441