LibreOffice Module framework (master) 1
langselectionstatusbarcontroller.cxx
Go to the documentation of this file.
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/fwkresid.hxx>
21#include <services.h>
22#include <strings.hrc>
23#include <vcl/svapp.hxx>
24
26#include <com/sun/star/awt/PopupMenu.hpp>
27#include <com/sun/star/awt/PopupMenuDirection.hpp>
28#include <svtools/langtab.hxx>
30#include <sal/types.h>
31#include <sal/log.hxx>
32#include <com/sun/star/document/XDocumentLanguages.hpp>
33#include <com/sun/star/lang/XServiceInfo.hpp>
34#include <com/sun/star/i18n/ScriptType.hpp>
35#include <com/sun/star/ui/XStatusbarItem.hpp>
36
37#include <com/sun/star/frame/XFrame.hpp>
38
39#include <com/sun/star/awt/Command.hpp>
41
42#include <helper/mischelper.hxx>
43
44#include <rtl/ustrbuf.hxx>
45
46#include <map>
47#include <set>
48
49using namespace ::cppu;
50using namespace ::com::sun::star;
51using namespace css::uno;
52using namespace css::lang;
53using namespace css::frame;
54using namespace css::i18n;
55using namespace css::document;
56using namespace framework;
57
58namespace {
59
60class LangSelectionStatusbarController:
62{
63public:
64 explicit LangSelectionStatusbarController( const css::uno::Reference< css::uno::XComponentContext >& xContext );
65 LangSelectionStatusbarController(const LangSelectionStatusbarController&) = delete;
66 LangSelectionStatusbarController& operator=(const LangSelectionStatusbarController&) = delete;
67
68 // XInitialization
69 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
70
71 // XStatusListener
72 virtual void SAL_CALL statusChanged( const css::frame::FeatureStateEvent& Event ) override;
73
74 // XStatusbarController
75 virtual void SAL_CALL command( const css::awt::Point& aPos,
76 ::sal_Int32 nCommand,
77 sal_Bool bMouseEvent,
78 const css::uno::Any& aData ) override;
79 virtual void SAL_CALL click( const css::awt::Point& aPos ) override;
80
81private:
82 virtual ~LangSelectionStatusbarController() override {}
83
84 bool m_bShowMenu; // if the menu is to be displayed or not (depending on the selected object/text)
85 SvtScriptType m_nScriptType; // the flags for the different script types available in the selection, LATIN = 0x0001, ASIAN = 0x0002, COMPLEX = 0x0004
86 OUString m_aCurLang; // the language of the current selection, "*" if there are more than one languages
87 OUString m_aKeyboardLang; // the keyboard language
88 OUString m_aGuessedTextLang; // the 'guessed' language for the selection, "" if none could be guessed
89 LanguageGuessingHelper m_aLangGuessHelper;
90
92 void LangMenu( const css::awt::Point& aPos );
93};
94
95LangSelectionStatusbarController::LangSelectionStatusbarController( const uno::Reference< uno::XComponentContext >& xContext ) :
96 svt::StatusbarController( xContext, uno::Reference< frame::XFrame >(), OUString(), 0 ),
97 m_bShowMenu( true ),
99 m_aLangGuessHelper( xContext )
100{
101}
102
103void SAL_CALL LangSelectionStatusbarController::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
104{
105 SolarMutexGuard aSolarMutexGuard;
106
108
109 if ( m_xStatusbarItem.is() )
110 {
111 m_xStatusbarItem->setText( FwkResId(STR_LANGSTATUS_MULTIPLE_LANGUAGES) );
112 m_xStatusbarItem->setQuickHelpText(FwkResId(STR_LANGSTATUS_HINT));
113 }
114}
115
116void LangSelectionStatusbarController::LangMenu(
117 const css::awt::Point& aPos )
118{
119 if (!m_bShowMenu)
120 return;
121
122 const Reference<XServiceInfo> xService(m_xFrame->getController()->getModel(), UNO_QUERY);
123 bool bCalc = xService.is() && xService->supportsService("com.sun.star.sheet.SpreadsheetDocument");
124 bool bWriter = xService.is() && xService->supportsService("com.sun.star.text.GenericTextDocument");
125 //add context menu
126 Reference< awt::XPopupMenu > xPopupMenu( awt::PopupMenu::create( m_xContext ) );
127 //sub menu that contains all items except the last two items: Separator + Set Language for Paragraph
128 Reference< awt::XPopupMenu > subPopupMenu( awt::PopupMenu::create( m_xContext ) );
129
130 // get languages to be displayed in the menu
131 std::set< OUString > aLangItems;
132 FillLangItems( aLangItems, m_xFrame, m_aLangGuessHelper,
133 m_nScriptType, m_aCurLang, m_aKeyboardLang, m_aGuessedTextLang );
134
135 // add first few entries to main menu
136 sal_Int16 nItemId = static_cast< sal_Int16 >(MID_LANG_SEL_1);
137 static constexpr OUStringLiteral sAsterisk(u"*"); // multiple languages in current selection
138 const OUString sNone( SvtLanguageTable::GetLanguageString( LANGUAGE_NONE ));
139 std::map< sal_Int16, OUString > aLangMap;
140 for (auto const& langItem : aLangItems)
141 {
142 if ( langItem != sNone &&
143 langItem != sAsterisk &&
144 !langItem.isEmpty()) // 'no language found' from language guessing
145 {
146 SAL_WARN_IF( MID_LANG_SEL_1 > nItemId || nItemId > MID_LANG_SEL_9,
147 "fwk.uielement", "nItemId outside of expected range!" );
148 xPopupMenu->insertItem( nItemId, langItem, 0, nItemId );
149 if ( langItem == m_aCurLang )
150 {
151 //make a sign for the current language
152 xPopupMenu->checkItem( nItemId, true );
153 }
154 aLangMap[ nItemId ] = langItem;
155 ++nItemId;
156 }
157 }
158
159 if (bWriter)
160 {
161 xPopupMenu->insertItem( MID_LANG_SEL_NONE, FwkResId(STR_LANGSTATUS_NONE), 0, MID_LANG_SEL_NONE );
162 if ( sNone == m_aCurLang )
163 xPopupMenu->checkItem( MID_LANG_SEL_NONE, true );
164 xPopupMenu->insertItem( MID_LANG_SEL_RESET, FwkResId(STR_RESET_TO_DEFAULT_LANGUAGE), 0, MID_LANG_SEL_RESET );
165 xPopupMenu->insertItem( MID_LANG_SEL_MORE, FwkResId(STR_LANGSTATUS_MORE), 0, MID_LANG_SEL_MORE );
166
167 // add entries to submenu ('set language for paragraph')
168 nItemId = static_cast< sal_Int16 >(MID_LANG_PARA_1);
169 for (auto const& langItem : aLangItems)
170 {
171 if( langItem != sNone &&
172 langItem != sAsterisk &&
173 !langItem.isEmpty()) // 'no language found' from language guessing
174 {
175 SAL_WARN_IF( MID_LANG_PARA_1 > nItemId || nItemId > MID_LANG_PARA_9,
176 "fwk.uielement", "nItemId outside of expected range!" );
177 subPopupMenu->insertItem( nItemId, langItem, 0, nItemId );
178 aLangMap[nItemId] = langItem;
179 ++nItemId;
180 }
181 }
182 subPopupMenu->insertItem( MID_LANG_PARA_NONE, FwkResId(STR_LANGSTATUS_NONE), 0, MID_LANG_PARA_NONE );
183 subPopupMenu->insertItem( MID_LANG_PARA_RESET, FwkResId(STR_RESET_TO_DEFAULT_LANGUAGE), 0, MID_LANG_PARA_RESET );
184 subPopupMenu->insertItem( MID_LANG_PARA_MORE, FwkResId(STR_LANGSTATUS_MORE), 0, MID_LANG_PARA_MORE );
185
186 // add last two entries to main menu
187 xPopupMenu->insertSeparator( MID_LANG_PARA_SEPARATOR );
188 xPopupMenu->insertItem( MID_LANG_PARA_STRING, FwkResId(STR_SET_LANGUAGE_FOR_PARAGRAPH), 0, MID_LANG_PARA_STRING );
189 xPopupMenu->setPopupMenu( MID_LANG_PARA_STRING, subPopupMenu );
190 }
191 else
192 {
193 xPopupMenu->insertItem( MID_LANG_DEF_NONE, FwkResId(STR_LANGSTATUS_NONE), 0, MID_LANG_DEF_NONE );
194 if ( sNone == m_aCurLang )
195 xPopupMenu->checkItem( MID_LANG_DEF_NONE, true );
196 xPopupMenu->insertItem( MID_LANG_DEF_RESET, FwkResId(STR_RESET_TO_DEFAULT_LANGUAGE), 0, MID_LANG_DEF_RESET );
197 xPopupMenu->insertItem( MID_LANG_DEF_MORE, FwkResId(STR_LANGSTATUS_MORE), 0, MID_LANG_DEF_MORE );
198 }
199
200 // now display the popup menu and execute every command ...
201
202 Reference< awt::XWindowPeer > xParent( m_xParentWindow, UNO_QUERY );
203 css::awt::Rectangle aRect( aPos.X, aPos.Y, 0, 0 );
204 sal_Int16 nId = xPopupMenu->execute( xParent, aRect, css::awt::PopupMenuDirection::EXECUTE_UP+16 );
205 //click "More..."
206 if ( !(nId && m_xFrame.is()) )
207 return;
208
209 OUStringBuffer aBuff;
210 //set selected language as current language for selection
211 const OUString aSelectedLang = aLangMap[nId];
212
213 if (MID_LANG_SEL_1 <= nId && nId <= MID_LANG_SEL_9)
214 {
215 if (bWriter)
216 aBuff.append( ".uno:LanguageStatus?Language:string=Current_" );
217 else
218 aBuff.append( ".uno:LanguageStatus?Language:string=Default_" );
219
220 aBuff.append( aSelectedLang );
221 }
222 else if (nId == MID_LANG_SEL_NONE)
223 {
224 //set None as current language for selection
225 aBuff.append( ".uno:LanguageStatus?Language:string=Current_LANGUAGE_NONE" );
226 }
227 else if (nId == MID_LANG_SEL_RESET)
228 {
229 // reset language attributes for selection
230 aBuff.append( ".uno:LanguageStatus?Language:string=Current_RESET_LANGUAGES" );
231 }
232 else if (nId == MID_LANG_SEL_MORE)
233 {
234 //open the dialog "format/character" for current selection
235 aBuff.append( ".uno:FontDialog?Page:string=font" );
236 }
237 else if (nId == MID_LANG_DEF_NONE)
238 {
239 aBuff.append( ".uno:LanguageStatus?Language:string=Default_LANGUAGE_NONE" );
240 }
241 else if (nId == MID_LANG_DEF_RESET)
242 {
243 aBuff.append( ".uno:LanguageStatus?Language:string=Default_RESET_LANGUAGES" );
244 }
245 else if (nId == MID_LANG_DEF_MORE)
246 {
247 if (bCalc)
248 aBuff.append( ".uno:FormatCellDialog" );
249 else
250 aBuff.append( ".uno:LanguageStatus?Language:string=*" );
251 }
252 else if (MID_LANG_PARA_1 <= nId && nId <= MID_LANG_PARA_9)
253 {
254 aBuff.append( ".uno:LanguageStatus?Language:string=Paragraph_" + aSelectedLang );
255 }
256 else if (nId == MID_LANG_PARA_NONE)
257 {
258 //set None as language for current paragraph
259 aBuff.append( ".uno:LanguageStatus?Language:string=Paragraph_LANGUAGE_NONE" );
260 }
261 else if (nId == MID_LANG_PARA_RESET)
262 {
263 // reset language attributes for paragraph
264 aBuff.append( ".uno:LanguageStatus?Language:string=Paragraph_RESET_LANGUAGES" );
265 }
266 else if (nId == MID_LANG_PARA_MORE)
267 {
268 //open the dialog "format/character" for current paragraph
269 aBuff.append( ".uno:FontDialogForParagraph" );
270 }
271
272 const Sequence< beans::PropertyValue > aDummyArgs;
273 execute( aBuff.makeStringAndClear(), aDummyArgs );
274}
275
276void SAL_CALL LangSelectionStatusbarController::command(
277 const css::awt::Point& aPos,
278 ::sal_Int32 nCommand,
279 sal_Bool /*bMouseEvent*/,
280 const css::uno::Any& /*aData*/ )
281{
282 if ( nCommand & ::awt::Command::CONTEXTMENU )
283 {
284 LangMenu( aPos );
285 }
286}
287
288void SAL_CALL LangSelectionStatusbarController::click(
289 const css::awt::Point& aPos )
290{
291 LangMenu( aPos );
292}
293
294// XStatusListener
295void SAL_CALL LangSelectionStatusbarController::statusChanged( const FeatureStateEvent& Event )
296{
297 // This function will be called when observed data changes,
298 // for example the selection or keyboard language.
299 // - It displays the language in use in the status bar
300 // - and it stores the relevant data for creating the menu
301 // at some later point in the member variables
302 // m_nScriptType, m_aCurLang, m_aKeyboardLang, m_aGuessedText
303
304 SolarMutexGuard aSolarMutexGuard;
305
306 if ( m_bDisposed )
307 return;
308
309 m_bShowMenu = true;
310 m_nScriptType = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX; //set the default value
311
312 if ( !m_xStatusbarItem.is() )
313 return;
314
315 OUString aStrValue;
316 Sequence< OUString > aSeq;
317
318 if ( Event.State >>= aStrValue )
319 {
320 m_xStatusbarItem->setText( aStrValue );
321 m_xStatusbarItem->setQuickHelpText(FwkResId(STR_LANGSTATUS_HINT));
322 m_aCurLang = aStrValue;
323 }
324 else if ( Event.State >>= aSeq )
325 {
326 if ( aSeq.getLength() == 4 )
327 {
328 OUString aStatusText = aSeq[0];
329 if (aStatusText == "*")
330 {
331 aStatusText = FwkResId(STR_LANGSTATUS_MULTIPLE_LANGUAGES);
332 }
333 m_xStatusbarItem->setText( aStatusText );
334 m_xStatusbarItem->setQuickHelpText(FwkResId(STR_LANGSTATUS_HINT));
335
336 // Retrieve all other values from the sequence and
337 // store it members!
338 m_aCurLang = aSeq[0];
339 m_nScriptType = static_cast< SvtScriptType >( aSeq[1].toInt32() );
340 m_aKeyboardLang = aSeq[2];
341 m_aGuessedTextLang = aSeq[3];
342 }
343 }
344 else if ( !Event.State.hasValue() )
345 {
346 m_xStatusbarItem->setText( OUString() );
347 m_xStatusbarItem->setQuickHelpText(u"");
348 m_bShowMenu = false; // no language -> no menu
349 }
350}
351
352}
353
354extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
356 css::uno::XComponentContext *context,
357 css::uno::Sequence<css::uno::Any> const &)
358{
359 return cppu::acquire(new LangSelectionStatusbarController(context));
360}
361
362/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define COMPLEX
#define ASIAN
css::uno::Reference< css::lang::XComponent > m_xFrame
static OUString GetLanguageString(const LanguageType eType)
virtual void SAL_CALL command(const css::awt::Point &aPos, ::sal_Int32 nCommand, sal_Bool bMouseEvent, const css::uno::Any &aData) override
virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent &Event) override
virtual void SAL_CALL click(const css::awt::Point &aPos) override
virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > &aArguments) override
OUString FwkResId(TranslateId aId)
Definition: fwkresid.cxx:22
css::uno::Reference< css::uno::XComponentContext > m_xContext
bool m_bDisposed
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_framework_LangSelectionStatusbarController_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
SvtScriptType
Sequence< sal_Int8 > aSeq
#define SAL_WARN_IF(condition, area, stream)
Reference
@ MID_LANG_DEF_MORE
Definition: mischelper.hxx:62
@ MID_LANG_PARA_RESET
Definition: mischelper.hxx:77
@ MID_LANG_PARA_MORE
Definition: mischelper.hxx:78
@ MID_LANG_PARA_SEPARATOR
Definition: mischelper.hxx:64
@ MID_LANG_SEL_RESET
Definition: mischelper.hxx:58
@ MID_LANG_DEF_RESET
Definition: mischelper.hxx:61
@ MID_LANG_SEL_MORE
Definition: mischelper.hxx:59
@ MID_LANG_PARA_NONE
Definition: mischelper.hxx:76
@ MID_LANG_PARA_STRING
Definition: mischelper.hxx:65
@ MID_LANG_PARA_1
Definition: mischelper.hxx:67
@ MID_LANG_DEF_NONE
Definition: mischelper.hxx:60
@ MID_LANG_SEL_9
Definition: mischelper.hxx:56
@ MID_LANG_PARA_9
Definition: mischelper.hxx:75
@ MID_LANG_SEL_1
Definition: mischelper.hxx:48
@ MID_LANG_SEL_NONE
Definition: mischelper.hxx:57
void FillLangItems(std::set< OUString > &rLangItems, const uno::Reference< frame::XFrame > &rxFrame, const LanguageGuessingHelper &rLangGuessHelper, SvtScriptType nScriptType, const OUString &rCurLang, const OUString &rKeyboardLang, const OUString &rGuessedTextLang)
Definition: mischelper.cxx:57
sal_Int16 nId
unsigned char sal_Bool
constexpr OUStringLiteral sNone