Line data Source code
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 "SwRewriter.hxx"
21 : #include "chrdlg.hrc"
22 : #include "cmdid.h"
23 : #include "comcore.hrc"
24 : #include "crsskip.hxx"
25 : #include "doc.hxx"
26 : #include "docsh.hxx"
27 : #include "edtwin.hxx"
28 : #include "helpid.h"
29 : #include "hintids.hxx"
30 : #include "langhelper.hxx"
31 : #include "ndtxt.hxx"
32 : #include "olmenu.hrc"
33 : #include "olmenu.hxx"
34 : #include "swabstdlg.hxx"
35 : #include "swmodule.hxx"
36 : #include "swtypes.hxx"
37 : #include "swundo.hxx"
38 : #include "uitool.hxx"
39 : #include "unomid.h"
40 : #include "view.hxx"
41 : #include "viewopt.hxx"
42 : #include "wrtsh.hxx"
43 : #include "wview.hxx"
44 : #include "textsh.hxx"
45 :
46 : #include <comphelper/anytostring.hxx>
47 : #include <comphelper/processfactory.hxx>
48 : #include <cppuhelper/exc_hlp.hxx>
49 : #include <editeng/acorrcfg.hxx>
50 : #include <editeng/svxacorr.hxx>
51 : #include <editeng/langitem.hxx>
52 : #include <editeng/splwrap.hxx>
53 : #include <editeng/brushitem.hxx>
54 : #include <editeng/unolingu.hxx>
55 : #include <editeng/editview.hxx>
56 : #include <i18nlangtag/mslangid.hxx>
57 : #include <i18nlangtag/languagetag.hxx>
58 : #include <linguistic/lngprops.hxx>
59 : #include <linguistic/misc.hxx>
60 : #include <osl/file.hxx>
61 : #include <rtl/string.hxx>
62 : #include <vcl/graphicfilter.hxx>
63 : #include <sfx2/dispatch.hxx>
64 : #include <sfx2/imagemgr.hxx>
65 : #include <sfx2/request.hxx>
66 : #include <sfx2/sfxdlg.hxx>
67 : #include <svl/itemset.hxx>
68 : #include <svl/languageoptions.hxx>
69 : #include <svl/stritem.hxx>
70 : #include <svtools/langtab.hxx>
71 : #include <svx/dlgutil.hxx>
72 : #include <unotools/lingucfg.hxx>
73 : #include <unotools/linguprops.hxx>
74 : #include <vcl/layout.hxx>
75 : #include <vcl/settings.hxx>
76 : #include <vcl/svapp.hxx>
77 : #include <sal/macros.h>
78 :
79 : #include <map>
80 :
81 : #include <com/sun/star/container/XIndexAccess.hpp>
82 : #include <com/sun/star/container/XNameAccess.hpp>
83 : #include <com/sun/star/document/XDocumentLanguages.hpp>
84 : #include <com/sun/star/frame/XModuleManager.hpp>
85 : #include <com/sun/star/frame/XStorable.hpp>
86 : #include <com/sun/star/i18n/ScriptType.hpp>
87 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
88 : #include <com/sun/star/lang/XServiceInfo.hpp>
89 : #include <com/sun/star/linguistic2/SingleProofreadingError.hpp>
90 : #include <com/sun/star/linguistic2/XLanguageGuessing.hpp>
91 : #include <com/sun/star/linguistic2/XSpellChecker1.hpp>
92 : #include <com/sun/star/uno/Any.hxx>
93 : #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
94 : #include <com/sun/star/system/SystemShellExecute.hpp>
95 : #include <com/sun/star/frame/theUICommandDescription.hpp>
96 :
97 : using namespace ::com::sun::star;
98 :
99 : /// @returns : the language for the selected text that is set for the
100 : /// specified attribute (script type).
101 : /// If there are more than one languages used LANGUAGE_DONTKNOW will be returned.
102 : /// @param nLangWhichId : one of
103 : /// RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
104 : /// @returns: the language in use for the selected text.
105 : /// 'In use' means the language(s) matching the script type(s) of the
106 : /// selected text. Or in other words, the language a spell checker would use.
107 : /// If there is more than one language LANGUAGE_DONTKNOW will be returned.
108 : // check if nScriptType includes the script type associated to nLang
109 10 : static inline bool lcl_checkScriptType( SvtScriptType nScriptType, LanguageType nLang )
110 : {
111 10 : return bool(nScriptType & SvtLanguageOptions::GetScriptTypeOfLanguage( nLang ));
112 : }
113 :
114 2 : void SwSpellPopup::fillLangPopupMenu(
115 : PopupMenu *pPopupMenu,
116 : sal_uInt16 nLangItemIdStart,
117 : const uno::Sequence< OUString >& aSeq,
118 : SwWrtShell* pWrtSh,
119 : std::map< sal_Int16, OUString > &rLangTable )
120 : {
121 2 : if (!pPopupMenu)
122 2 : return;
123 :
124 : // set of languages to be displayed in the sub menus
125 2 : std::set< OUString > aLangItems;
126 :
127 4 : OUString aCurLang( aSeq[0] );
128 2 : SvtScriptType nScriptType = static_cast<SvtScriptType>(aSeq[1].toInt32());
129 4 : OUString aKeyboardLang( aSeq[2] );
130 4 : OUString aGuessedTextLang( aSeq[3] );
131 :
132 4 : if (!aCurLang.isEmpty() &&
133 2 : LANGUAGE_DONTKNOW != SvtLanguageTable::GetLanguageType( aCurLang ))
134 2 : aLangItems.insert( aCurLang );
135 :
136 : //2--System
137 2 : const AllSettings& rAllSettings = Application::GetSettings();
138 2 : LanguageType rSystemLanguage = rAllSettings.GetLanguageTag().getLanguageType();
139 2 : if (rSystemLanguage != LANGUAGE_DONTKNOW)
140 : {
141 2 : if (lcl_checkScriptType( nScriptType, rSystemLanguage ))
142 2 : aLangItems.insert( SvtLanguageTable::GetLanguageString(rSystemLanguage) );
143 : }
144 :
145 : //3--UI
146 2 : LanguageType rUILanguage = rAllSettings.GetUILanguageTag().getLanguageType();
147 2 : if (rUILanguage != LANGUAGE_DONTKNOW)
148 : {
149 2 : if (lcl_checkScriptType(nScriptType, rUILanguage ))
150 2 : aLangItems.insert( SvtLanguageTable::GetLanguageString(rUILanguage) );
151 : }
152 :
153 : //4--guessed language
154 2 : if (!aGuessedTextLang.isEmpty())
155 : {
156 2 : if (lcl_checkScriptType(nScriptType, SvtLanguageTable::GetLanguageType(aGuessedTextLang)))
157 2 : aLangItems.insert( aGuessedTextLang );
158 : }
159 :
160 : //5--keyboard language
161 2 : if (!aKeyboardLang.isEmpty())
162 : {
163 0 : if (lcl_checkScriptType(nScriptType, SvtLanguageTable::GetLanguageType(aKeyboardLang)))
164 0 : aLangItems.insert( aKeyboardLang );
165 : }
166 :
167 : //6--all languages used in current document
168 4 : uno::Reference< com::sun::star::frame::XModel > xModel;
169 4 : uno::Reference< com::sun::star::frame::XController > xController( pWrtSh->GetView().GetViewFrame()->GetFrame().GetFrameInterface()->getController(), uno::UNO_QUERY );
170 2 : if ( xController.is() )
171 2 : xModel = xController->getModel();
172 4 : uno::Reference< document::XDocumentLanguages > xDocumentLanguages( xModel, uno::UNO_QUERY );
173 : /*the description of nScriptType flags
174 : LATIN : 0x0001
175 : ASIAN : 0x0002
176 : COMPLEX: 0x0004
177 : */
178 2 : const sal_Int16 nMaxCount = 7;
179 2 : if (xDocumentLanguages.is())
180 : {
181 2 : uno::Sequence< lang::Locale > rLocales( xDocumentLanguages->getDocumentLanguages( static_cast<sal_Int16>(nScriptType), nMaxCount ) );
182 2 : if (rLocales.getLength() > 0)
183 : {
184 6 : for (sal_Int32 i = 0; i < rLocales.getLength(); ++i)
185 : {
186 4 : if (aLangItems.size() == (size_t)nMaxCount)
187 0 : break;
188 4 : const lang::Locale& rLocale = rLocales[i];
189 4 : if (lcl_checkScriptType( nScriptType, SvtLanguageTable::GetLanguageType( rLocale.Language )))
190 4 : aLangItems.insert( rLocale.Language );
191 : }
192 2 : }
193 : }
194 :
195 2 : sal_uInt16 nItemId = nLangItemIdStart;
196 2 : std::set< OUString >::const_iterator it;
197 8 : for (it = aLangItems.begin(); it != aLangItems.end(); ++it)
198 : {
199 6 : OUString aEntryText( *it );
200 22 : if (aEntryText != OUString( SvtLanguageTable::GetLanguageString( LANGUAGE_NONE ) )&&
201 22 : aEntryText != "*" && // multiple languages in current selection
202 4 : !aEntryText.isEmpty()) // 'no language found' from language guessing
203 : {
204 : OSL_ENSURE( nLangItemIdStart <= nItemId && nItemId <= nLangItemIdStart + MN_MAX_NUM_LANG,
205 : "nItemId outside of expected range!" );
206 4 : pPopupMenu->InsertItem( nItemId, aEntryText, MenuItemBits::RADIOCHECK );
207 4 : if (aEntryText == aCurLang)
208 : {
209 : //make a check mark for the current language
210 2 : pPopupMenu->CheckItem( nItemId, true );
211 : }
212 4 : rLangTable[ nItemId ] = aEntryText;
213 4 : ++nItemId;
214 : }
215 6 : }
216 :
217 2 : pPopupMenu->InsertItem( nLangItemIdStart + MN_NONE_OFFSET, OUString(SW_RES( STR_LANGSTATUS_NONE )), MenuItemBits::RADIOCHECK );
218 2 : if ( SvtLanguageTable::GetLanguageString( LANGUAGE_NONE ) == aCurLang )
219 0 : pPopupMenu->CheckItem( nLangItemIdStart + MN_NONE_OFFSET, true );
220 :
221 2 : pPopupMenu->InsertItem( nLangItemIdStart + MN_RESET_OFFSET, OUString(SW_RES( STR_RESET_TO_DEFAULT_LANGUAGE )), MenuItemBits::NONE );
222 4 : pPopupMenu->InsertItem( nLangItemIdStart + MN_MORE_OFFSET, OUString(SW_RES( STR_LANGSTATUS_MORE )), MenuItemBits::NONE );
223 : }
224 :
225 1 : OUString RetrieveLabelFromCommand( const OUString& aCmdURL )
226 : {
227 1 : OUString aLabel;
228 1 : if ( !aCmdURL.isEmpty() )
229 : {
230 : try
231 : {
232 : uno::Reference< container::XNameAccess > const xNameAccess(
233 : frame::theUICommandDescription::get(
234 : ::comphelper::getProcessComponentContext() ),
235 1 : uno::UNO_QUERY_THROW );
236 2 : uno::Reference< container::XNameAccess > xUICommandLabels;
237 2 : uno::Any a = xNameAccess->getByName( "com.sun.star.text.TextDocument" );
238 2 : uno::Reference< container::XNameAccess > xUICommands;
239 1 : a >>= xUICommandLabels;
240 2 : OUString aStr;
241 2 : uno::Sequence< beans::PropertyValue > aPropSeq;
242 1 : a = xUICommandLabels->getByName( aCmdURL );
243 1 : if ( a >>= aPropSeq )
244 : {
245 2 : for ( sal_Int32 i = 0; i < aPropSeq.getLength(); i++ )
246 : {
247 2 : if ( aPropSeq[i].Name == "Name" )
248 : {
249 1 : aPropSeq[i].Value >>= aStr;
250 1 : break;
251 : }
252 : }
253 : }
254 2 : aLabel = aStr;
255 : }
256 0 : catch (const uno::Exception&)
257 : {
258 : }
259 : }
260 :
261 1 : return aLabel;
262 : }
263 :
264 1 : SwSpellPopup::SwSpellPopup(
265 : SwWrtShell* pWrtSh,
266 : const uno::Reference< linguistic2::XSpellAlternatives > &xAlt,
267 : const OUString &rParaText
268 : ) : PopupMenu( SW_RES(MN_SPELL_POPUP) )
269 : , m_pSh( pWrtSh )
270 : , m_xSpellAlt(xAlt)
271 1 : , m_bGrammarResults(false)
272 : {
273 : OSL_ENSURE(m_xSpellAlt.is(), "no spelling alternatives available");
274 :
275 1 : SetMenuFlags(MenuFlags::NoAutoMnemonics);
276 1 : bool bUseImagesInMenus = Application::GetSettings().GetStyleSettings().GetUseImagesInMenus();
277 :
278 1 : m_nCheckedLanguage = LANGUAGE_NONE;
279 1 : if (m_xSpellAlt.is())
280 : {
281 0 : m_nCheckedLanguage = LanguageTag( m_xSpellAlt->getLocale() ).getLanguageType();
282 0 : m_aSuggestions = m_xSpellAlt->getAlternatives();
283 : }
284 1 : sal_Int16 nStringCount = static_cast< sal_Int16 >( m_aSuggestions.getLength() );
285 :
286 1 : SvtLinguConfig aCfg;
287 :
288 1 : PopupMenu *pMenu = GetPopupMenu(MN_AUTOCORR);
289 1 : pMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics);
290 1 : bool bEnable = false;
291 1 : if( nStringCount )
292 : {
293 0 : Image aImage;
294 0 : OUString aSuggestionImageUrl;
295 :
296 0 : if (bUseImagesInMenus)
297 : {
298 0 : uno::Reference< container::XNamed > xNamed( m_xSpellAlt, uno::UNO_QUERY );
299 0 : if (xNamed.is())
300 : {
301 0 : aSuggestionImageUrl = aCfg.GetSpellAndGrammarContextSuggestionImage( xNamed->getName() );
302 0 : aImage = Image( aSuggestionImageUrl );
303 0 : }
304 : }
305 :
306 0 : InsertSeparator(OString(), 0);
307 0 : bEnable = true;
308 0 : sal_uInt16 nAutoCorrItemId = MN_AUTOCORR_START;
309 0 : sal_uInt16 nItemId = MN_SUGGESTION_START;
310 0 : for (sal_uInt16 i = 0; i < nStringCount; ++i)
311 : {
312 0 : const OUString aEntry = m_aSuggestions[ i ];
313 0 : InsertItem(nItemId, aEntry, MenuItemBits::NONE, OString(), i);
314 0 : SetHelpId( nItemId, HID_LINGU_REPLACE);
315 0 : if (!aSuggestionImageUrl.isEmpty())
316 0 : SetItemImage( nItemId, aImage );
317 :
318 0 : pMenu->InsertItem( nAutoCorrItemId, aEntry );
319 0 : pMenu->SetHelpId( nAutoCorrItemId, HID_LINGU_AUTOCORR);
320 :
321 0 : ++nAutoCorrItemId;
322 0 : ++nItemId;
323 0 : }
324 : }
325 :
326 2 : OUString aIgnoreSelection( SW_RES( STR_IGNORE_SELECTION ) );
327 2 : OUString aSpellingAndGrammar = RetrieveLabelFromCommand( ".uno:SpellingAndGrammarDialog" );
328 1 : SetItemText( MN_SPELLING_DLG, aSpellingAndGrammar );
329 1 : sal_uInt16 nItemPos = GetItemPos( MN_IGNORE_WORD );
330 1 : InsertItem(MN_IGNORE_SELECTION, aIgnoreSelection, MenuItemBits::NONE, OString(), nItemPos);
331 1 : SetHelpId( MN_IGNORE_SELECTION, HID_LINGU_IGNORE_SELECTION);
332 :
333 1 : EnableItem( MN_AUTOCORR, bEnable );
334 :
335 2 : uno::Reference< linguistic2::XLanguageGuessing > xLG = SW_MOD()->GetLanguageGuesser();
336 1 : m_nGuessLangWord = LANGUAGE_NONE;
337 1 : m_nGuessLangPara = LANGUAGE_NONE;
338 1 : if (m_xSpellAlt.is() && xLG.is())
339 : {
340 0 : m_nGuessLangWord = EditView::CheckLanguage( m_xSpellAlt->getWord(), ::GetSpellChecker(), xLG, false );
341 0 : m_nGuessLangPara = EditView::CheckLanguage( rParaText, ::GetSpellChecker(), xLG, true );
342 : }
343 1 : if (m_nGuessLangWord != LANGUAGE_NONE || m_nGuessLangPara != LANGUAGE_NONE)
344 : {
345 : // make sure LANGUAGE_NONE gets not used as menu entry
346 0 : if (m_nGuessLangWord == LANGUAGE_NONE)
347 0 : m_nGuessLangWord = m_nGuessLangPara;
348 0 : if (m_nGuessLangPara == LANGUAGE_NONE)
349 0 : m_nGuessLangPara = m_nGuessLangWord;
350 : }
351 :
352 1 : pMenu = GetPopupMenu(MN_ADD_TO_DIC);
353 1 : pMenu->SetMenuFlags(MenuFlags::NoAutoMnemonics); //! necessary to retrieve the correct dictionary name in 'Execute' below
354 2 : uno::Reference< linguistic2::XSearchableDictionaryList > xDicList( SvxGetDictionaryList() );
355 1 : sal_uInt16 nItemId = MN_DICTIONARIES_START;
356 1 : if (xDicList.is())
357 : {
358 : // add the default positive dictionary to dic-list (if not already done).
359 : // This is to ensure that there is at least one dictionary to which
360 : // words could be added.
361 1 : uno::Reference< linguistic2::XDictionary > xDic( SvxGetOrCreatePosDic( xDicList ) );
362 1 : if (xDic.is())
363 1 : xDic->setActive( sal_True );
364 :
365 1 : m_aDics = xDicList->getDictionaries();
366 1 : const uno::Reference< linguistic2::XDictionary > *pDic = m_aDics.getConstArray();
367 1 : sal_uInt16 nDicCount = static_cast< sal_uInt16 >(m_aDics.getLength());
368 :
369 7 : for( sal_uInt16 i = 0; i < nDicCount; i++ )
370 : {
371 6 : uno::Reference< linguistic2::XDictionary > xDicTmp( pDic[i], uno::UNO_QUERY );
372 6 : if (!xDicTmp.is() || SvxGetIgnoreAllList() == xDicTmp)
373 1 : continue;
374 :
375 10 : uno::Reference< frame::XStorable > xStor( xDicTmp, uno::UNO_QUERY );
376 5 : LanguageType nActLanguage = LanguageTag( xDicTmp->getLocale() ).getLanguageType();
377 10 : if( xDicTmp->isActive()
378 5 : && xDicTmp->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
379 5 : && (m_nCheckedLanguage == nActLanguage || LANGUAGE_NONE == nActLanguage )
380 7 : && (!xStor.is() || !xStor->isReadonly()) )
381 : {
382 : // the extra 1 is because of the (possible) external
383 : // linguistic entry above
384 2 : pMenu->InsertItem( nItemId, xDicTmp->getName() );
385 2 : m_aDicNameSingle = xDicTmp->getName();
386 :
387 2 : if (bUseImagesInMenus)
388 : {
389 2 : uno::Reference< lang::XServiceInfo > xSvcInfo( xDicTmp, uno::UNO_QUERY );
390 2 : if (xSvcInfo.is())
391 : {
392 : OUString aDictionaryImageUrl( aCfg.GetSpellAndGrammarContextDictionaryImage(
393 0 : xSvcInfo->getImplementationName() ) );
394 0 : if (!aDictionaryImageUrl.isEmpty())
395 : {
396 0 : Image aImage( aDictionaryImageUrl );
397 0 : pMenu->SetItemImage( nItemId, aImage );
398 0 : }
399 2 : }
400 : }
401 :
402 2 : ++nItemId;
403 : }
404 6 : }
405 : }
406 1 : EnableItem( MN_ADD_TO_DIC, (nItemId - MN_DICTIONARIES_START) > 1 );
407 1 : EnableItem( MN_ADD_TO_DIC_SINGLE, (nItemId - MN_DICTIONARIES_START) == 1 );
408 :
409 : //ADD NEW LANGUAGE MENU ITEM
410 :
411 2 : OUString aScriptTypesInUse( OUString::number( static_cast<int>(pWrtSh->GetScriptType()) ) );
412 :
413 : // get keyboard language
414 2 : OUString aKeyboardLang;
415 1 : SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
416 1 : LanguageType nLang = rEditWin.GetInputLanguage();
417 1 : if (nLang != LANGUAGE_DONTKNOW && nLang != LANGUAGE_SYSTEM)
418 0 : aKeyboardLang = SvtLanguageTable::GetLanguageString( nLang );
419 :
420 : // get the language that is in use
421 2 : OUString aCurrentLang("*");
422 1 : nLang = SwLangHelper::GetCurrentLanguage( *pWrtSh );
423 1 : if (nLang != LANGUAGE_DONTKNOW)
424 1 : aCurrentLang = SvtLanguageTable::GetLanguageString( nLang );
425 :
426 : // build sequence for status value
427 2 : uno::Sequence< OUString > aSeq( 4 );
428 1 : aSeq[0] = aCurrentLang;
429 1 : aSeq[1] = aScriptTypesInUse;
430 1 : aSeq[2] = aKeyboardLang;
431 1 : aSeq[3] = SvtLanguageTable::GetLanguageString(m_nGuessLangWord);
432 :
433 1 : pMenu = GetPopupMenu(MN_SET_LANGUAGE_SELECTION);
434 1 : fillLangPopupMenu( pMenu, MN_SET_LANGUAGE_SELECTION_START, aSeq, pWrtSh, m_aLangTable_Text );
435 1 : EnableItem( MN_SET_LANGUAGE_SELECTION, true );
436 :
437 1 : pMenu = GetPopupMenu(MN_SET_LANGUAGE_PARAGRAPH);
438 1 : fillLangPopupMenu( pMenu, MN_SET_LANGUAGE_PARAGRAPH_START, aSeq, pWrtSh, m_aLangTable_Paragraph );
439 1 : EnableItem( MN_SET_LANGUAGE_PARAGRAPH, true );
440 :
441 1 : if (bUseImagesInMenus)
442 : {
443 1 : uno::Reference< frame::XFrame > xFrame = pWrtSh->GetView().GetViewFrame()->GetFrame().GetFrameInterface();
444 2 : Image rImg = ::GetImage( xFrame, ".uno:SpellingAndGrammarDialog", false );
445 2 : SetItemImage( MN_SPELLING_DLG, rImg );
446 : }
447 :
448 1 : checkRedline();
449 2 : RemoveDisabledEntries( true, true );
450 1 : }
451 :
452 0 : SwSpellPopup::SwSpellPopup(
453 : SwWrtShell *pWrtSh,
454 : const linguistic2::ProofreadingResult &rResult,
455 : sal_Int32 nErrorInResult,
456 : const uno::Sequence< OUString > &rSuggestions,
457 : const OUString &rParaText ) :
458 : PopupMenu( SW_RES(MN_SPELL_POPUP) ),
459 : m_pSh( pWrtSh ),
460 : m_xGrammarResult( rResult ),
461 : m_aSuggestions( rSuggestions ),
462 : m_sExplanationLink( ),
463 : m_bGrammarResults( true ),
464 0 : m_aInfo16( SW_RES(IMG_INFO_16) )
465 : {
466 0 : m_nCheckedLanguage = LanguageTag::convertToLanguageType( rResult.aLocale );
467 0 : m_nGrammarError = nErrorInResult;
468 0 : bool bUseImagesInMenus = Application::GetSettings().GetStyleSettings().GetUseImagesInMenus();
469 :
470 0 : sal_uInt16 nPos = 0;
471 0 : OUString aMessageText( rResult.aErrors[ nErrorInResult ].aShortComment );
472 0 : InsertSeparator(OString(), nPos++);
473 0 : InsertItem(MN_SHORT_COMMENT, aMessageText, MenuItemBits::NOSELECT, OString(), nPos++);
474 0 : if (bUseImagesInMenus)
475 0 : SetItemImage( MN_SHORT_COMMENT, m_aInfo16 );
476 :
477 : // Add an item to show detailed infos if the FullCommentURL property is defined
478 0 : beans::PropertyValues aProperties = rResult.aErrors[ nErrorInResult ].aProperties;
479 : {
480 0 : sal_Int32 i = 0;
481 0 : while ( m_sExplanationLink.isEmpty() && i < aProperties.getLength() )
482 : {
483 0 : if ( aProperties[i].Name == "FullCommentURL" )
484 : {
485 0 : uno::Any aValue = aProperties[i].Value;
486 0 : aValue >>= m_sExplanationLink;
487 : }
488 0 : ++i;
489 : }
490 : }
491 :
492 0 : if ( !m_sExplanationLink.isEmpty( ) )
493 : {
494 0 : InsertItem(MN_EXPLANATION_LINK, SW_RESSTR(STR_EXPLANATION_LINK), MenuItemBits::TEXT | MenuItemBits::HELP, OString(), nPos++);
495 : }
496 :
497 0 : SetMenuFlags(MenuFlags::NoAutoMnemonics);
498 :
499 0 : InsertSeparator(OString(), nPos++);
500 0 : sal_Int32 nStringCount = m_aSuggestions.getLength();
501 0 : if ( nStringCount ) // suggestions available...
502 : {
503 0 : Image aImage;
504 0 : OUString aSuggestionImageUrl;
505 :
506 0 : if (bUseImagesInMenus)
507 : {
508 0 : uno::Reference< lang::XServiceInfo > xInfo( rResult.xProofreader, uno::UNO_QUERY );
509 0 : if (xInfo.is())
510 : {
511 0 : aSuggestionImageUrl = SvtLinguConfig().GetSpellAndGrammarContextSuggestionImage( xInfo->getImplementationName() );
512 0 : aImage = Image( aSuggestionImageUrl );
513 0 : }
514 : }
515 :
516 0 : sal_uInt16 nItemId = MN_SUGGESTION_START;
517 0 : for (sal_Int32 i = 0; i < nStringCount; ++i)
518 : {
519 0 : const OUString aEntry = m_aSuggestions[ i ];
520 0 : InsertItem(nItemId, aEntry, MenuItemBits::NONE, OString(), nPos++);
521 0 : SetHelpId( nItemId, HID_LINGU_REPLACE );
522 0 : if (!aSuggestionImageUrl.isEmpty())
523 0 : SetItemImage( nItemId, aImage );
524 :
525 0 : ++nItemId;
526 0 : }
527 0 : InsertSeparator(OString(), nPos++);
528 : }
529 :
530 0 : OUString aIgnoreSelection( SW_RES( STR_IGNORE_SELECTION ) );
531 0 : OUString aSpellingAndGrammar = RetrieveLabelFromCommand( ".uno:SpellingAndGrammarDialog" );
532 0 : SetItemText( MN_SPELLING_DLG, aSpellingAndGrammar );
533 0 : sal_uInt16 nItemPos = GetItemPos( MN_IGNORE_WORD );
534 0 : InsertItem( MN_IGNORE_SELECTION, aIgnoreSelection, MenuItemBits::NONE, OString(), nItemPos );
535 0 : SetHelpId( MN_IGNORE_SELECTION, HID_LINGU_IGNORE_SELECTION);
536 :
537 0 : EnableItem( MN_AUTOCORR, false );
538 :
539 0 : uno::Reference< linguistic2::XLanguageGuessing > xLG = SW_MOD()->GetLanguageGuesser();
540 0 : m_nGuessLangWord = LANGUAGE_NONE;
541 0 : m_nGuessLangPara = LANGUAGE_NONE;
542 0 : if (xLG.is())
543 : {
544 0 : m_nGuessLangPara = EditView::CheckLanguage( rParaText, ::GetSpellChecker(), xLG, true );
545 : }
546 0 : if (m_nGuessLangWord != LANGUAGE_NONE || m_nGuessLangPara != LANGUAGE_NONE)
547 : {
548 : // make sure LANGUAGE_NONE gets not used as menu entry
549 0 : if (m_nGuessLangWord == LANGUAGE_NONE)
550 0 : m_nGuessLangWord = m_nGuessLangPara;
551 0 : if (m_nGuessLangPara == LANGUAGE_NONE)
552 0 : m_nGuessLangPara = m_nGuessLangWord;
553 : }
554 :
555 0 : EnableItem( MN_ADD_TO_DIC, false );
556 0 : EnableItem( MN_ADD_TO_DIC_SINGLE, false );
557 :
558 : //ADD NEW LANGUAGE MENU ITEM
559 :
560 0 : OUString aScriptTypesInUse( OUString::number( static_cast<int>(pWrtSh->GetScriptType()) ) );
561 :
562 : // get keyboard language
563 0 : OUString aKeyboardLang;
564 0 : SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
565 0 : LanguageType nLang = rEditWin.GetInputLanguage();
566 0 : if (nLang != LANGUAGE_DONTKNOW && nLang != LANGUAGE_SYSTEM)
567 0 : aKeyboardLang = SvtLanguageTable::GetLanguageString( nLang );
568 :
569 : // get the language that is in use
570 0 : OUString aCurrentLang("*");
571 0 : nLang = SwLangHelper::GetCurrentLanguage( *pWrtSh );
572 0 : if (nLang != LANGUAGE_DONTKNOW)
573 0 : aCurrentLang = SvtLanguageTable::GetLanguageString( nLang );
574 :
575 : // build sequence for status value
576 0 : uno::Sequence< OUString > aSeq( 4 );
577 0 : aSeq[0] = aCurrentLang;
578 0 : aSeq[1] = aScriptTypesInUse;
579 0 : aSeq[2] = aKeyboardLang;
580 0 : aSeq[3] = SvtLanguageTable::GetLanguageString(m_nGuessLangWord);
581 :
582 0 : PopupMenu *pMenu = GetPopupMenu(MN_SET_LANGUAGE_SELECTION);
583 0 : fillLangPopupMenu( pMenu, MN_SET_LANGUAGE_SELECTION_START, aSeq, pWrtSh, m_aLangTable_Text );
584 0 : EnableItem( MN_SET_LANGUAGE_SELECTION, true );
585 :
586 0 : pMenu = GetPopupMenu(MN_SET_LANGUAGE_PARAGRAPH);
587 0 : fillLangPopupMenu( pMenu, MN_SET_LANGUAGE_PARAGRAPH_START, aSeq, pWrtSh, m_aLangTable_Paragraph );
588 0 : EnableItem( MN_SET_LANGUAGE_PARAGRAPH, true );
589 :
590 0 : if (bUseImagesInMenus)
591 : {
592 0 : uno::Reference< frame::XFrame > xFrame = pWrtSh->GetView().GetViewFrame()->GetFrame().GetFrameInterface();
593 0 : Image rImg = ::GetImage( xFrame, ".uno:SpellingAndGrammarDialog", false );
594 0 : SetItemImage( MN_SPELLING_DLG, rImg );
595 : }
596 :
597 0 : checkRedline();
598 0 : RemoveDisabledEntries( true, true );
599 0 : }
600 :
601 1 : void SwSpellPopup::checkRedline()
602 : {
603 : // Let SwView::GetState() already has the logic on when to disable the
604 : // accept/reject and the next/prev change items, let it do the decision.
605 :
606 : // Build an item set that contains a void item for each menu entry. The
607 : // WhichId of each item is set, so SwView may clear it.
608 : static const sal_uInt16 pRedlineIds[] = {
609 : FN_REDLINE_ACCEPT_DIRECT,
610 : FN_REDLINE_REJECT_DIRECT,
611 : FN_REDLINE_NEXT_CHANGE,
612 : FN_REDLINE_PREV_CHANGE
613 : };
614 1 : SwDoc *pDoc = m_pSh->GetDoc();
615 1 : SfxItemSet aSet(pDoc->GetAttrPool(), FN_REDLINE_ACCEPT_DIRECT, FN_REDLINE_PREV_CHANGE);
616 5 : for (size_t i = 0; i < SAL_N_ELEMENTS(pRedlineIds); ++i)
617 : {
618 4 : const sal_uInt16 nWhich = pRedlineIds[i];
619 4 : aSet.Put(SfxVoidItem(nWhich), nWhich);
620 : }
621 1 : m_pSh->GetView().GetState(aSet);
622 :
623 : // Enable/disable items based on if the which id of the void items are
624 : // cleared or not.
625 5 : for (size_t i = 0; i < SAL_N_ELEMENTS(pRedlineIds); ++i)
626 : {
627 4 : const sal_uInt16 nWhich = pRedlineIds[i];
628 4 : EnableItem(nWhich, aSet.Get(nWhich).Which());
629 1 : }
630 1 : }
631 :
632 0 : sal_uInt16 SwSpellPopup::Execute( const Rectangle& rWordPos, vcl::Window* pWin )
633 : {
634 0 : sal_uInt16 nRet = PopupMenu::Execute(pWin, pWin->LogicToPixel(rWordPos));
635 0 : Execute( nRet );
636 0 : return nRet;
637 : }
638 :
639 0 : void SwSpellPopup::Execute( sal_uInt16 nId )
640 : {
641 0 : if (nId == USHRT_MAX)
642 0 : return;
643 :
644 0 : if (/*m_bGrammarResults && */nId == MN_SHORT_COMMENT)
645 0 : return; // nothing to do since it is the error message (short comment)
646 :
647 0 : if ((MN_SUGGESTION_START <= nId && nId <= MN_SUGGESTION_END) ||
648 0 : (MN_AUTOCORR_START <= nId && nId <= MN_AUTOCORR_END))
649 : {
650 0 : sal_Int32 nAltIdx = (MN_SUGGESTION_START <= nId && nId <= MN_SUGGESTION_END) ?
651 0 : nId - MN_SUGGESTION_START : nId - MN_AUTOCORR_START;
652 : OSL_ENSURE( 0 <= nAltIdx && nAltIdx < m_aSuggestions.getLength(), "index out of range" );
653 0 : if (0 <= nAltIdx && nAltIdx < m_aSuggestions.getLength() && (m_bGrammarResults || m_xSpellAlt.is()))
654 : {
655 0 : bool bOldIns = m_pSh->IsInsMode();
656 0 : m_pSh->SetInsMode( true );
657 :
658 0 : OUString aTmp( m_aSuggestions[ nAltIdx ] );
659 0 : OUString aOrig( m_bGrammarResults ? OUString() : m_xSpellAlt->getWord() );
660 :
661 : // if original word has a trailing . (likely the end of a sentence)
662 : // and the replacement text hasn't, then add it to the replacement
663 0 : if (!aTmp.isEmpty() && !aOrig.isEmpty() &&
664 0 : aOrig.endsWith(".") && /* !IsAlphaNumeric ??*/
665 0 : !aTmp.endsWith("."))
666 : {
667 0 : aTmp += ".";
668 : }
669 :
670 : // #111827#
671 0 : SwRewriter aRewriter;
672 :
673 0 : aRewriter.AddRule(UndoArg1, m_pSh->GetCrsrDescr());
674 0 : aRewriter.AddRule(UndoArg2, OUString(SW_RES(STR_YIELDS)));
675 :
676 0 : OUString aTmpStr( SW_RES(STR_START_QUOTE) );
677 0 : aTmpStr += aTmp;
678 0 : aTmpStr += OUString(SW_RES(STR_END_QUOTE));
679 0 : aRewriter.AddRule(UndoArg3, aTmpStr);
680 :
681 0 : m_pSh->StartUndo(UNDO_UI_REPLACE, &aRewriter);
682 0 : m_pSh->StartAction();
683 0 : m_pSh->DelLeft();
684 :
685 0 : m_pSh->Insert( aTmp );
686 :
687 : /* #102505# EndAction/EndUndo moved down since insertion
688 : of temporary auto correction is now undoable two and
689 : must reside in the same undo group.*/
690 :
691 : // record only if it's NOT already present in autocorrection
692 0 : SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect();
693 :
694 0 : OUString aOrigWord( m_bGrammarResults ? OUString() : m_xSpellAlt->getWord() ) ;
695 0 : OUString aNewWord( m_aSuggestions[ nAltIdx ] );
696 0 : SvxPrepareAutoCorrect( aOrigWord, aNewWord );
697 :
698 0 : if (MN_AUTOCORR_START <= nId && nId <= MN_AUTOCORR_END)
699 0 : pACorr->PutText( aOrigWord, aNewWord, m_nCheckedLanguage );
700 :
701 : /* #102505# EndAction/EndUndo moved down since insertion
702 : of temporary auto correction is now undoable two and
703 : must reside in the same undo group.*/
704 0 : m_pSh->EndAction();
705 0 : m_pSh->EndUndo();
706 :
707 0 : m_pSh->SetInsMode( bOldIns );
708 0 : }
709 : }
710 0 : else if (nId == MN_SPELLING_DLG)
711 : {
712 0 : if (m_bGrammarResults)
713 : {
714 0 : SvtLinguConfig().SetProperty( UPN_IS_GRAMMAR_INTERACTIVE, uno::makeAny( true ));
715 : }
716 0 : m_pSh->Left(CRSR_SKIP_CHARS, false, 1, false );
717 : {
718 0 : uno::Reference<linguistic2::XSearchableDictionaryList> xDictionaryList( SvxGetDictionaryList() );
719 0 : SvxDicListChgClamp aClamp( xDictionaryList );
720 0 : m_pSh->GetView().GetViewFrame()->GetDispatcher()->
721 0 : Execute( FN_SPELL_GRAMMAR_DIALOG, SfxCallMode::ASYNCHRON );
722 : }
723 : }
724 0 : else if (nId == MN_IGNORE_SELECTION)
725 : {
726 0 : SwPaM *pPaM = m_pSh->GetCrsr();
727 0 : if (pPaM)
728 0 : SwEditShell::IgnoreGrammarErrorAt( *pPaM );
729 : }
730 0 : else if (nId == MN_IGNORE_WORD)
731 : {
732 0 : uno::Reference< linguistic2::XDictionary > xDictionary( SvxGetIgnoreAllList(), uno::UNO_QUERY );
733 0 : if (m_bGrammarResults) {
734 : try
735 : {
736 0 : m_xGrammarResult.xProofreader->ignoreRule(
737 0 : m_xGrammarResult.aErrors[ m_nGrammarError ].aRuleIdentifier,
738 0 : m_xGrammarResult.aLocale );
739 : // refresh the layout of the actual paragraph (faster)
740 0 : SwPaM *pPaM = m_pSh->GetCrsr();
741 0 : if (pPaM)
742 0 : SwEditShell::IgnoreGrammarErrorAt( *pPaM );
743 : // refresh the layout of all paragraphs (workaround to launch a dictionary event)
744 0 : xDictionary->setActive(sal_False);
745 0 : xDictionary->setActive(sal_True);
746 : }
747 0 : catch( const uno::Exception& )
748 : {
749 : }
750 : } else {
751 0 : OUString sWord(m_xSpellAlt->getWord());
752 : linguistic::DictionaryError nAddRes = linguistic::AddEntryToDic( xDictionary,
753 0 : sWord, false, OUString(), LANGUAGE_NONE );
754 0 : if (linguistic::DictionaryError::NONE != nAddRes && !xDictionary->getEntry(sWord).is())
755 : {
756 0 : SvxDicError(&m_pSh->GetView().GetViewFrame()->GetWindow(), nAddRes);
757 0 : }
758 0 : }
759 : }
760 0 : else if ((MN_DICTIONARIES_START <= nId && nId <= MN_DICTIONARIES_END) || nId == MN_ADD_TO_DIC_SINGLE)
761 : {
762 0 : OUString sWord( m_xSpellAlt->getWord() );
763 0 : OUString aDicName;
764 :
765 0 : if (MN_DICTIONARIES_START <= nId && nId <= MN_DICTIONARIES_END)
766 : {
767 0 : PopupMenu *pMenu = GetPopupMenu(MN_ADD_TO_DIC);
768 0 : aDicName = pMenu->GetItemText(nId);
769 : }
770 : else
771 0 : aDicName = m_aDicNameSingle;
772 :
773 0 : uno::Reference< linguistic2::XDictionary > xDic;
774 0 : uno::Reference< linguistic2::XSearchableDictionaryList > xDicList( SvxGetDictionaryList() );
775 0 : if (xDicList.is())
776 0 : xDic = xDicList->getDictionaryByName( aDicName );
777 :
778 0 : if (xDic.is())
779 : {
780 0 : linguistic::DictionaryError nAddRes = linguistic::AddEntryToDic(xDic, sWord, false, OUString(), LANGUAGE_NONE);
781 : // save modified user-dictionary if it is persistent
782 0 : uno::Reference< frame::XStorable > xSavDic( xDic, uno::UNO_QUERY );
783 0 : if (xSavDic.is())
784 0 : xSavDic->store();
785 :
786 0 : if (linguistic::DictionaryError::NONE != nAddRes && !xDic->getEntry(sWord).is())
787 : {
788 0 : SvxDicError(&m_pSh->GetView().GetViewFrame()->GetWindow(), nAddRes);
789 0 : }
790 0 : }
791 : }
792 0 : else if ( nId == MN_EXPLANATION_LINK && !m_sExplanationLink.isEmpty() )
793 : {
794 : try
795 : {
796 : uno::Reference< com::sun::star::system::XSystemShellExecute > xSystemShellExecute(
797 0 : com::sun::star::system::SystemShellExecute::create( ::comphelper::getProcessComponentContext() ) );
798 0 : xSystemShellExecute->execute( m_sExplanationLink, OUString(),
799 0 : com::sun::star::system::SystemShellExecuteFlags::URIS_ONLY );
800 : }
801 0 : catch (const uno::Exception&)
802 : {
803 0 : uno::Any exc( ::cppu::getCaughtException() );
804 0 : OUString msg( ::comphelper::anyToString( exc ) );
805 0 : const SolarMutexGuard guard;
806 0 : ScopedVclPtrInstance< MessageDialog > aErrorBox(nullptr, msg);
807 0 : aErrorBox->SetText( "Explanations" );
808 0 : aErrorBox->Execute();
809 : }
810 : }
811 0 : else if (nId == FN_REDLINE_ACCEPT_DIRECT || nId == FN_REDLINE_REJECT_DIRECT
812 0 : || nId == FN_REDLINE_NEXT_CHANGE || nId == FN_REDLINE_PREV_CHANGE)
813 : {
814 : // Let SwView::Execute() handle the redline actions.
815 0 : SfxRequest aReq(m_pSh->GetView().GetViewFrame(), nId);
816 0 : m_pSh->GetView().Execute(aReq);
817 : }
818 : else
819 : {
820 : // Set language for selection or for paragraph...
821 :
822 0 : SfxItemSet aCoreSet( m_pSh->GetView().GetPool(),
823 : RES_CHRATR_LANGUAGE, RES_CHRATR_LANGUAGE,
824 : RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CJK_LANGUAGE,
825 : RES_CHRATR_CTL_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
826 0 : 0 );
827 0 : OUString aNewLangText;
828 :
829 0 : if (MN_SET_LANGUAGE_SELECTION_START <= nId && nId <= MN_SET_LANGUAGE_SELECTION_END)
830 : {
831 : //Set language for current selection
832 0 : aNewLangText = m_aLangTable_Text[nId];
833 0 : SwLangHelper::SetLanguage( *m_pSh, aNewLangText, true, aCoreSet );
834 : }
835 0 : else if (nId == MN_SET_SELECTION_NONE)
836 : {
837 : //Set Language_None for current selection
838 0 : SwLangHelper::SetLanguage_None( *m_pSh, true, aCoreSet );
839 : }
840 0 : else if (nId == MN_SET_SELECTION_RESET)
841 : {
842 : //reset languages for current selection
843 0 : SwLangHelper::ResetLanguages( *m_pSh, true );
844 : }
845 0 : else if (nId == MN_SET_SELECTION_MORE)
846 : {
847 : //Open Format/Character Dialog
848 0 : sw_CharDialog( *m_pSh, true, SID_ATTR_CHAR_FONT, 0, 0 );
849 : }
850 0 : else if (MN_SET_LANGUAGE_PARAGRAPH_START <= nId && nId <= MN_SET_LANGUAGE_PARAGRAPH_END)
851 : {
852 : //Set language for current paragraph
853 0 : aNewLangText = m_aLangTable_Paragraph[nId];
854 0 : m_pSh->Push(); // save cursor
855 0 : SwLangHelper::SelectCurrentPara( *m_pSh );
856 0 : SwLangHelper::SetLanguage( *m_pSh, aNewLangText, true, aCoreSet );
857 0 : m_pSh->Pop( false ); // restore cursor
858 : }
859 0 : else if (nId == MN_SET_PARA_NONE)
860 : {
861 : //Set Language_None for current paragraph
862 0 : m_pSh->Push(); // save cursor
863 0 : SwLangHelper::SelectCurrentPara( *m_pSh );
864 0 : SwLangHelper::SetLanguage_None( *m_pSh, true, aCoreSet );
865 0 : m_pSh->Pop( false ); // restore cursor
866 : }
867 0 : else if (nId == MN_SET_PARA_RESET)
868 : {
869 : //reset languages for current paragraph
870 0 : m_pSh->Push(); // save cursor
871 0 : SwLangHelper::SelectCurrentPara( *m_pSh );
872 0 : SwLangHelper::ResetLanguages( *m_pSh, true );
873 0 : m_pSh->Pop( false ); // restore cursor
874 : }
875 0 : else if (nId == MN_SET_PARA_MORE)
876 : {
877 0 : m_pSh->Push(); // save cursor
878 0 : SwLangHelper::SelectCurrentPara( *m_pSh );
879 : //Open Format/Character Dialog
880 0 : sw_CharDialog( *m_pSh, true, SID_ATTR_CHAR_FONT, 0, 0 );
881 0 : m_pSh->Pop( false ); // restore cursor
882 0 : }
883 : }
884 :
885 0 : m_pSh->EnterStdMode();
886 177 : }
887 :
888 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|