docthemes: Save themes def. to a file when added to ColorSets
[LibreOffice.git] / sw / source / uibase / shells / langhelper.cxx
blobbb7d4d969668709bd66e46d96491010a4530f47a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <string.h>
22 #include <wrtsh.hxx>
23 #include <doc.hxx>
24 #include <docary.hxx>
25 #include <charfmt.hxx>
27 #include <sfx2/bindings.hxx>
28 #include <sfx2/request.hxx>
29 #include <sfx2/sfxdlg.hxx>
30 #include <sfx2/viewfrm.hxx>
31 #include <editeng/eeitem.hxx>
32 #include <editeng/editeng.hxx>
33 #include <editeng/editdata.hxx>
34 #include <editeng/outliner.hxx>
35 #include <editeng/editview.hxx>
36 #include <editeng/langitem.hxx>
38 #include <svl/languageoptions.hxx>
39 #include <svtools/langtab.hxx>
40 #include <svl/slstitm.hxx>
41 #include <svl/stritem.hxx>
42 #include <svx/svxids.hrc>
43 #include <osl/diagnose.h>
45 #include <ndtxt.hxx>
46 #include <pam.hxx>
47 #include <view.hxx>
48 #include <viewopt.hxx>
50 #include <langhelper.hxx>
52 using namespace ::com::sun::star;
54 namespace SwLangHelper
57 void GetLanguageStatus( OutlinerView* pOLV, SfxItemSet& rSet )
59 ESelection aSelection = pOLV->GetSelection();
60 EditView& rEditView=pOLV->GetEditView();
61 EditEngine& rEditEngine = rEditView.getEditEngine();
63 // the value of used script types
64 const SvtScriptType nScriptType =pOLV->GetSelectedScriptType();
65 OUString aScriptTypesInUse( OUString::number( static_cast<int>(nScriptType) ) );//rEditEngine.GetScriptType(aSelection)
67 // get keyboard language
68 OUString aKeyboardLang;
69 LanguageType nLang = rEditView.GetInputLanguage();
70 if (nLang != LANGUAGE_DONTKNOW && nLang != LANGUAGE_SYSTEM)
71 aKeyboardLang = SvtLanguageTable::GetLanguageString( nLang );
73 // get the language that is in use
74 OUString aCurrentLang(u"*"_ustr);
75 SfxItemSet aSet(pOLV->GetAttribs());
76 nLang = SwLangHelper::GetCurrentLanguage( aSet,nScriptType );
77 if (nLang != LANGUAGE_DONTKNOW)
78 aCurrentLang = SvtLanguageTable::GetLanguageString( nLang );
80 // build sequence for status value
81 uno::Sequence<OUString> aSeq{ aCurrentLang,
82 aScriptTypesInUse,
83 aKeyboardLang,
84 SwLangHelper::GetTextForLanguageGuessing(&rEditEngine, aSelection)
87 // set sequence as status value
88 SfxStringListItem aItem( SID_LANGUAGE_STATUS );
89 aItem.SetStringList( aSeq );
90 rSet.Put( aItem );
93 bool SetLanguageStatus( OutlinerView* pOLV, SfxRequest &rReq, SwView const &rView, SwWrtShell &rSh )
95 bool bRestoreSelection = false;
96 ESelection aSelection = pOLV->GetSelection();
97 EditView & rEditView = pOLV->GetEditView();
98 SfxItemSet aEditAttr(rEditView.GetEmptyItemSet());
100 // get the language
101 OUString aNewLangText;
103 const SfxStringItem* pItem = rReq.GetArg<SfxStringItem>(SID_LANGUAGE_STATUS);
104 if (pItem)
105 aNewLangText = pItem->GetValue();
107 //!! Remember the view frame right now...
108 //!! (call to GetView().GetViewFrame() will break if the
109 //!! SwTextShell got destroyed meanwhile.)
110 SfxViewFrame& rViewFrame = rView.GetViewFrame();
112 if (aNewLangText == "*" )
114 // open the dialog "Tools/Options/Languages and Locales - General"
115 SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
116 ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateVclDialog( rView.GetFrameWeld(), SID_LANGUAGE_OPTIONS ));
117 pDlg->Execute();
119 else
121 // setting the new language...
122 if (!aNewLangText.isEmpty())
124 static constexpr OUString aSelectionLangPrefix(u"Current_"_ustr);
125 static constexpr OUString aParagraphLangPrefix(u"Paragraph_"_ustr);
126 static constexpr OUString aDocumentLangPrefix(u"Default_"_ustr);
128 sal_Int32 nPos = 0;
129 bool bForSelection = true;
130 bool bForParagraph = false;
131 if (-1 != (nPos = aNewLangText.indexOf( aSelectionLangPrefix )))
133 // ... for the current selection
134 aNewLangText = aNewLangText.replaceAt(nPos, aSelectionLangPrefix.getLength(), u"");
135 bForSelection = true;
137 else if (-1 != (nPos = aNewLangText.indexOf( aParagraphLangPrefix )))
139 // ... for the current paragraph language
140 aNewLangText = aNewLangText.replaceAt(nPos, aParagraphLangPrefix.getLength(), u"");
141 bForSelection = true;
142 bForParagraph = true;
144 else if (-1 != (nPos = aNewLangText.indexOf( aDocumentLangPrefix )))
146 // ... as default document language
147 aNewLangText = aNewLangText.replaceAt(nPos, aDocumentLangPrefix.getLength(), u"");
148 bForSelection = false;
151 if (bForParagraph)
153 bRestoreSelection = true;
154 SwLangHelper::SelectPara( rEditView, aSelection );
155 aSelection = pOLV->GetSelection();
157 if (!bForSelection) // document language to be changed...
159 rSh.StartAction();
160 rSh.LockView( true );
161 rSh.Push();
163 // prepare to apply new language to all text in document
164 rSh.SelAll();
165 rSh.ExtendedSelectAll();
168 if (aNewLangText == "LANGUAGE_NONE")
169 SwLangHelper::SetLanguage_None( rSh, pOLV, aSelection, bForSelection, aEditAttr );
170 else if (aNewLangText == "RESET_LANGUAGES")
171 SwLangHelper::ResetLanguages( rSh, pOLV );
172 else
173 SwLangHelper::SetLanguage( rSh, pOLV, aSelection, aNewLangText, bForSelection, aEditAttr );
175 if (!bForSelection)
177 // need to release view and restore selection...
178 rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
179 rSh.LockView( false );
180 rSh.EndAction();
185 // invalidate slot to get the new language displayed
186 rViewFrame.GetBindings().Invalidate( rReq.GetSlot() );
188 rReq.Done();
189 return bRestoreSelection;
192 void SetLanguage( SwWrtShell &rWrtSh, std::u16string_view rLangText, bool bIsForSelection, SfxItemSet &rCoreSet )
194 SetLanguage( rWrtSh, nullptr , ESelection(), rLangText, bIsForSelection, rCoreSet );
197 void SetLanguage( SwWrtShell &rWrtSh, OutlinerView const * pOLV, const ESelection& rSelection, std::u16string_view rLangText, bool bIsForSelection, SfxItemSet &rCoreSet )
199 const LanguageType nLang = SvtLanguageTable::GetLanguageType( rLangText );
200 if (nLang == LANGUAGE_DONTKNOW)
201 return;
203 EditEngine* pEditEngine = pOLV ? &pOLV->GetEditView().getEditEngine() : nullptr;
204 OSL_ENSURE( !pOLV || pEditEngine, "OutlinerView without EditEngine???" );
206 //get ScriptType
207 TypedWhichId<SvxLanguageItem> nLangWhichId(0);
208 bool bIsSingleScriptType = true;
209 switch (SvtLanguageOptions::GetScriptTypeOfLanguage( nLang ))
211 case SvtScriptType::LATIN : nLangWhichId = pEditEngine ? EE_CHAR_LANGUAGE : RES_CHRATR_LANGUAGE; break;
212 case SvtScriptType::ASIAN : nLangWhichId = pEditEngine ? EE_CHAR_LANGUAGE_CJK : RES_CHRATR_CJK_LANGUAGE; break;
213 case SvtScriptType::COMPLEX : nLangWhichId = pEditEngine ? EE_CHAR_LANGUAGE_CTL : RES_CHRATR_CTL_LANGUAGE; break;
214 default:
215 bIsSingleScriptType = false;
216 OSL_FAIL("unexpected case" );
218 if (!bIsSingleScriptType)
219 return;
221 // change language for selection or paragraph
222 // (for paragraph is handled by previously having set the selection to the
223 // whole paragraph)
224 if (bIsForSelection)
226 // apply language to current selection
227 if (pEditEngine)
229 rCoreSet.Put( SvxLanguageItem( nLang, nLangWhichId ));
230 pEditEngine->QuickSetAttribs(rCoreSet, rSelection);
232 else
234 rWrtSh.GetCurAttr( rCoreSet );
235 rCoreSet.Put( SvxLanguageItem( nLang, nLangWhichId ));
236 rWrtSh.SetAttrSet( rCoreSet );
239 else // change language for all text
241 // set document default language
242 switch (nLangWhichId)
244 case EE_CHAR_LANGUAGE : nLangWhichId = RES_CHRATR_LANGUAGE; break;
245 case EE_CHAR_LANGUAGE_CJK : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
246 case EE_CHAR_LANGUAGE_CTL : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
248 //Set the default document language
249 rWrtSh.SetDefault( SvxLanguageItem( nLang, nLangWhichId ) );
250 rWrtSh.GetDoc()->GetDocShell()->Broadcast(SfxHint(SfxHintId::LanguageChanged));
252 // #i102191: hard set respective language attribute in text document
253 // (for all text in the document - which should be selected by now...)
254 rWrtSh.SetAttrItem( SvxLanguageItem( nLang, nLangWhichId ) );
258 void SetLanguage_None( SwWrtShell &rWrtSh, bool bIsForSelection, SfxItemSet &rCoreSet )
260 SetLanguage_None( rWrtSh,nullptr,ESelection(),bIsForSelection,rCoreSet );
263 void SetLanguage_None( SwWrtShell &rWrtSh, OutlinerView const * pOLV, const ESelection& rSelection, bool bIsForSelection, SfxItemSet &rCoreSet )
265 // EditEngine IDs
266 const sal_uInt16 aLangWhichId_EE[3] =
268 EE_CHAR_LANGUAGE,
269 EE_CHAR_LANGUAGE_CJK,
270 EE_CHAR_LANGUAGE_CTL
273 // Writer IDs
274 const sal_uInt16 aLangWhichId_Writer[3] =
276 RES_CHRATR_LANGUAGE,
277 RES_CHRATR_CJK_LANGUAGE,
278 RES_CHRATR_CTL_LANGUAGE
281 if (bIsForSelection)
283 // change language for selection or paragraph
284 // (for paragraph is handled by previously having set the selection to the
285 // whole paragraph)
287 EditEngine* pEditEngine = pOLV ? &pOLV->GetEditView().getEditEngine() : nullptr;
288 OSL_ENSURE( !pOLV || pEditEngine, "OutlinerView without EditEngine???" );
289 if (pEditEngine)
291 for (sal_uInt16 i : aLangWhichId_EE)
292 rCoreSet.Put( SvxLanguageItem( LANGUAGE_NONE, i ));
293 pEditEngine->QuickSetAttribs(rCoreSet, rSelection);
295 else
297 rWrtSh.GetCurAttr( rCoreSet );
298 for (sal_uInt16 i : aLangWhichId_Writer)
299 rCoreSet.Put( SvxLanguageItem( LANGUAGE_NONE, i ));
300 rWrtSh.SetAttrSet( rCoreSet );
303 else // change language for all text
305 o3tl::sorted_vector<sal_uInt16> aAttribs;
306 for (sal_uInt16 i : aLangWhichId_Writer)
308 rWrtSh.SetDefault( SvxLanguageItem( LANGUAGE_NONE, i ) );
309 aAttribs.insert( i );
311 rWrtSh.GetDoc()->GetDocShell()->Broadcast(SfxHint(SfxHintId::LanguageChanged));
313 // set all language attributes to default
314 // (for all text in the document - which should be selected by now...)
315 rWrtSh.ResetAttr( aAttribs );
319 void ResetLanguages( SwWrtShell &rWrtSh, OutlinerView const * pOLV )
321 // reset language for current selection.
322 // The selection should already have been expanded to the whole paragraph or
323 // to all text in the document if those are the ranges where to reset
324 // the language attributes
326 if (pOLV)
328 EditView &rEditView = pOLV->GetEditView();
329 rEditView.RemoveAttribs( true, EE_CHAR_LANGUAGE );
330 rEditView.RemoveAttribs( true, EE_CHAR_LANGUAGE_CJK );
331 rEditView.RemoveAttribs( true, EE_CHAR_LANGUAGE_CTL );
333 // ugly hack, as it seems that EditView/EditEngine does not update their spellchecking marks
334 // when setting a new language attribute
335 EditEngine& rEditEngine = rEditView.getEditEngine();
336 EEControlBits nCntrl = rEditEngine.GetControlWord();
337 // turn off
338 rEditEngine.SetControlWord(nCntrl & ~EEControlBits::ONLINESPELLING);
339 //turn back on
340 rEditEngine.SetControlWord(nCntrl);
341 rEditEngine.CompleteOnlineSpelling();
343 rEditView.Invalidate();
345 else
347 rWrtSh.ResetAttr(
348 { RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE });
352 /// @returns : the language for the selected text that is set for the
353 /// specified attribute (script type).
354 /// If there are more than one languages used LANGUAGE_DONTKNOW will be returned.
355 /// @param nLangWhichId : one of
356 /// RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
357 LanguageType GetLanguage( SwWrtShell &rSh, TypedWhichId<SvxLanguageItem> nLangWhichId )
359 SfxItemSet aSet( rSh.GetAttrPool(), nLangWhichId, nLangWhichId );
360 rSh.GetCurAttr( aSet );
362 return GetLanguage(aSet,nLangWhichId);
365 LanguageType GetLanguage( SfxItemSet const & aSet, TypedWhichId<SvxLanguageItem> nLangWhichId )
368 LanguageType nLang = LANGUAGE_SYSTEM;
370 const SvxLanguageItem *pItem = nullptr;
371 SfxItemState nState = aSet.GetItemState( nLangWhichId, true, &pItem );
372 if (nState > SfxItemState::DEFAULT && pItem)
374 // the item is set and can be used
375 nLang = pItem->GetLanguage();
377 else if (nState == SfxItemState::DEFAULT)
379 // since the attribute is not set: retrieve the default value
380 nLang = aSet.GetPool()->GetUserOrPoolDefaultItem( nLangWhichId ).GetLanguage();
382 else if (nState == SfxItemState::INVALID)
384 // there is more than one language...
385 nLang = LANGUAGE_DONTKNOW;
387 OSL_ENSURE( nLang != LANGUAGE_SYSTEM, "failed to get the language?" );
389 return nLang;
392 /// @returns: the language in use for the selected text.
393 /// 'In use' means the language(s) matching the script type(s) of the
394 /// selected text. Or in other words, the language a spell checker would use.
395 /// If there is more than one language LANGUAGE_DONTKNOW will be returned.
396 LanguageType GetCurrentLanguage( SwWrtShell &rSh )
398 //set language attribute to use according to the script type
399 TypedWhichId<SvxLanguageItem> nLangWhichId(0);
400 bool bIsSingleScriptType = true;
401 switch (rSh.GetScriptType())
403 case SvtScriptType::LATIN : nLangWhichId = RES_CHRATR_LANGUAGE; break;
404 case SvtScriptType::ASIAN : nLangWhichId = RES_CHRATR_CJK_LANGUAGE; break;
405 case SvtScriptType::COMPLEX : nLangWhichId = RES_CHRATR_CTL_LANGUAGE; break;
406 default: bIsSingleScriptType = false; break;
409 // get language according to the script type(s) in use
410 LanguageType nCurrentLang = LANGUAGE_SYSTEM;
411 if (bIsSingleScriptType)
412 nCurrentLang = GetLanguage( rSh, nLangWhichId );
413 else
415 // check if all script types are set to LANGUAGE_NONE and return
416 // that if this is the case. Otherwise, having multiple script types
417 // in use always means there are several languages in use...
418 const TypedWhichId<SvxLanguageItem> aScriptTypes[3] =
420 RES_CHRATR_LANGUAGE,
421 RES_CHRATR_CJK_LANGUAGE,
422 RES_CHRATR_CTL_LANGUAGE
424 nCurrentLang = LANGUAGE_NONE;
425 for (const TypedWhichId<SvxLanguageItem>& aScriptType : aScriptTypes)
427 LanguageType nTmpLang = GetLanguage( rSh, aScriptType );
428 if (nTmpLang != LANGUAGE_NONE)
430 nCurrentLang = LANGUAGE_DONTKNOW;
431 break;
435 OSL_ENSURE( nCurrentLang != LANGUAGE_SYSTEM, "failed to get the language?" );
437 return nCurrentLang;
440 /// @returns: the language in use for the selected text.
441 /// 'In use' means the language(s) matching the script type(s) of the
442 /// selected text. Or in other words, the language a spell checker would use.
443 /// If there is more than one language LANGUAGE_DONTKNOW will be returned.
444 LanguageType GetCurrentLanguage( SfxItemSet const & aSet, SvtScriptType nScriptType )
446 //set language attribute to use according to the script type
447 TypedWhichId<SvxLanguageItem> nLangWhichId(0);
448 bool bIsSingleScriptType = true;
449 switch (nScriptType)
451 case SvtScriptType::LATIN : nLangWhichId = EE_CHAR_LANGUAGE; break;
452 case SvtScriptType::ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break;
453 case SvtScriptType::COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break;
454 default: bIsSingleScriptType = false;
457 // get language according to the script type(s) in use
458 LanguageType nCurrentLang = LANGUAGE_SYSTEM;
459 if (bIsSingleScriptType)
460 nCurrentLang = GetLanguage( aSet, nLangWhichId );
461 else
463 // check if all script types are set to LANGUAGE_NONE and return
464 // that if this is the case. Otherwise, having multiple script types
465 // in use always means there are several languages in use...
466 const TypedWhichId<SvxLanguageItem> aScriptTypes[3] =
468 EE_CHAR_LANGUAGE,
469 EE_CHAR_LANGUAGE_CJK,
470 EE_CHAR_LANGUAGE_CTL
472 nCurrentLang = LANGUAGE_NONE;
473 for (const TypedWhichId<SvxLanguageItem>& aScriptType : aScriptTypes)
475 LanguageType nTmpLang = GetLanguage( aSet, aScriptType );
476 if (nTmpLang != LANGUAGE_NONE)
478 nCurrentLang = LANGUAGE_DONTKNOW;
479 break;
483 OSL_ENSURE( nCurrentLang != LANGUAGE_SYSTEM, "failed to get the language?" );
485 return nCurrentLang;
488 OUString GetTextForLanguageGuessing( SwWrtShell const &rSh )
490 // string for guessing language
491 OUString aText;
492 SwPaM *pCursor = rSh.GetCursor();
493 SwTextNode *pNode = pCursor->GetPointNode().GetTextNode();
494 if (pNode)
496 aText = pNode->GetText();
497 if (!aText.isEmpty())
499 sal_Int32 nEnd = pCursor->GetPoint()->GetContentIndex();
500 // at most 100 chars to the left...
501 const sal_Int32 nStt = nEnd > 100 ? nEnd - 100 : 0;
502 // ... and 100 to the right of the cursor position
503 nEnd = aText.getLength() - nEnd > 100 ? nEnd + 100 : aText.getLength();
504 aText = aText.copy( nStt, nEnd - nStt );
507 return aText;
510 OUString GetTextForLanguageGuessing(EditEngine const * rEditEngine, const ESelection& rDocSelection)
512 // string for guessing language
514 // get the full text of the paragraph that the end of selection is in
515 OUString aText = rEditEngine->GetText(rDocSelection.end.nIndex);
516 if (!aText.isEmpty())
518 sal_Int32 nStt = 0;
519 sal_Int32 nEnd = rDocSelection.end.nIndex;
520 // at most 100 chars to the left...
521 nStt = nEnd > 100 ? nEnd - 100 : 0;
522 // ... and 100 to the right of the cursor position
523 nEnd = aText.getLength() - nEnd > 100 ? nEnd + 100 : aText.getLength();
524 aText = aText.copy( nStt, nEnd - nStt );
527 return aText;
530 void SelectPara( EditView &rEditView, const ESelection &rCurSel )
532 ESelection aParaSel(rCurSel.start.nPara, 0, rCurSel.start.nPara, EE_TEXTPOS_MAX);
533 rEditView.SetSelection( aParaSel );
536 void SelectCurrentPara( SwWrtShell &rWrtSh )
538 // select current para
539 if (!rWrtSh.IsSttPara())
540 rWrtSh.MovePara( GoCurrPara, fnParaStart );
541 if (!rWrtSh.HasMark())
542 rWrtSh.SetMark();
543 rWrtSh.SwapPam();
544 if (!rWrtSh.IsEndPara())
545 rWrtSh.MovePara( GoCurrPara, fnParaEnd );
549 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */