1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
23 #include <vcl/window.hxx>
28 #include <charfmt.hxx>
30 #include <sfx2/bindings.hxx>
31 #include <sfx2/dispatch.hxx>
32 #include <sfx2/request.hxx>
33 #include <editeng/eeitem.hxx>
34 #include <editeng/editeng.hxx>
35 #include <editeng/editdata.hxx>
36 #include <editeng/outliner.hxx>
37 #include <editeng/editview.hxx>
38 #include <editeng/scripttypeitem.hxx>
39 #include <editeng/langitem.hxx>
41 #include <svl/languageoptions.hxx>
42 #include <svtools/langtab.hxx>
43 #include <svl/slstitm.hxx>
44 #include <svl/stritem.hxx>
49 #include <viewopt.hxx>
51 #include "swabstdlg.hxx"
53 #include <vcl/msgbox.hxx>
55 #include <langhelper.hxx>
57 using namespace ::com::sun::star
;
59 namespace SwLangHelper
62 sal_uInt16
GetLanguageStatus( OutlinerView
* pOLV
, SfxItemSet
& rSet
)
64 ESelection aSelection
= pOLV
->GetSelection();
65 EditView
& rEditView
=pOLV
->GetEditView();
66 EditEngine
* pEditEngine
=rEditView
.GetEditEngine();
68 // the value of used script types
69 const sal_uInt16 nScriptType
=pOLV
->GetSelectedScriptType();
70 String
aScriptTypesInUse( OUString::number( nScriptType
) );//pEditEngine->GetScriptType(aSelection)
72 SvtLanguageTable aLangTable
;
74 // get keyboard language
76 LanguageType nLang
= LANGUAGE_DONTKNOW
;
78 Window
* pWin
= rEditView
.GetWindow();
80 nLang
= pWin
->GetInputLanguage();
81 if (nLang
!= LANGUAGE_DONTKNOW
&& nLang
!= LANGUAGE_SYSTEM
)
82 aKeyboardLang
= aLangTable
.GetString( nLang
);
84 // get the language that is in use
85 String aCurrentLang
= OUString("*");
86 SfxItemSet
aSet(pOLV
->GetAttribs());
87 nLang
= SwLangHelper::GetCurrentLanguage( aSet
,nScriptType
);
88 if (nLang
!= LANGUAGE_DONTKNOW
)
89 aCurrentLang
= aLangTable
.GetString( nLang
);
91 // build sequence for status value
92 uno::Sequence
< OUString
> aSeq( 4 );
93 aSeq
[0] = aCurrentLang
;
94 aSeq
[1] = aScriptTypesInUse
;
95 aSeq
[2] = aKeyboardLang
;
96 aSeq
[3] = SwLangHelper::GetTextForLanguageGuessing( pEditEngine
, aSelection
);
98 // set sequence as status value
99 SfxStringListItem
aItem( SID_LANGUAGE_STATUS
);
100 aItem
.SetStringList( aSeq
);
101 rSet
.Put( aItem
, SID_LANGUAGE_STATUS
);
105 bool SetLanguageStatus( OutlinerView
* pOLV
, SfxRequest
&rReq
, SwView
&rView
, SwWrtShell
&rSh
)
107 bool bRestoreSelection
= false;
108 SfxItemSet
aEditAttr(pOLV
->GetAttribs());
109 ESelection aSelection
= pOLV
->GetSelection();
110 EditView
& rEditView
= pOLV
->GetEditView();
111 EditEngine
* pEditEngine
= rEditView
.GetEditEngine();
116 SFX_REQUEST_ARG( rReq
, pItem
, SfxStringItem
, SID_LANGUAGE_STATUS
, sal_False
);
118 aNewLangTxt
= pItem
->GetValue();
120 //!! Remember the view frame right now...
121 //!! (call to GetView().GetViewFrame() will break if the
122 //!! SwTextShell got destroyed meanwhile.)
123 SfxViewFrame
*pViewFrame
= rView
.GetViewFrame();
125 if (aNewLangTxt
.EqualsAscii( "*" ))
127 // open the dialog "Tools/Options/Language Settings - Language"
128 SfxAbstractDialogFactory
* pFact
= SfxAbstractDialogFactory::Create();
131 VclAbstractDialog
* pDlg
= pFact
->CreateVclDialog( rView
.GetWindow(), SID_LANGUAGE_OPTIONS
);
138 // setting the new language...
139 if (aNewLangTxt
.Len() > 0)
141 const OUString
aSelectionLangPrefix("Current_");
142 const OUString
aParagraphLangPrefix("Paragraph_");
143 const OUString
aDocumentLangPrefix("Default_");
144 const String
aStrNone( OUString("LANGUAGE_NONE") );
145 const String
aStrResetLangs( OUString("RESET_LANGUAGES") );
148 bool bForSelection
= true;
149 bool bForParagraph
= false;
150 if (STRING_NOTFOUND
!= (nPos
= aNewLangTxt
.Search( aSelectionLangPrefix
, 0 )))
152 // ... for the current selection
153 aNewLangTxt
= aNewLangTxt
.Erase( nPos
, aSelectionLangPrefix
.getLength() );
154 bForSelection
= true;
156 else if (STRING_NOTFOUND
!= (nPos
= aNewLangTxt
.Search( aParagraphLangPrefix
, 0 )))
158 // ... for the current paragraph language
159 aNewLangTxt
= aNewLangTxt
.Erase( nPos
, aParagraphLangPrefix
.getLength() );
160 bForSelection
= true;
161 bForParagraph
= true;
163 else if (STRING_NOTFOUND
!= (nPos
= aNewLangTxt
.Search( aDocumentLangPrefix
, 0 )))
165 // ... as default document language
166 aNewLangTxt
= aNewLangTxt
.Erase( nPos
, aDocumentLangPrefix
.getLength() );
167 bForSelection
= false;
172 bRestoreSelection
= true;
173 SwLangHelper::SelectPara( rEditView
, aSelection
);
174 aSelection
= pOLV
->GetSelection();
176 if (!bForSelection
) // document language to be changed...
179 rSh
.LockView( sal_True
);
182 // prepare to apply new language to all text in document
184 rSh
.ExtendedSelectAll();
187 if (aNewLangTxt
== aStrNone
)
188 SwLangHelper::SetLanguage_None( rSh
, pOLV
, aSelection
, bForSelection
, aEditAttr
);
189 else if (aNewLangTxt
== aStrResetLangs
)
190 SwLangHelper::ResetLanguages( rSh
, pOLV
, aSelection
, bForSelection
);
192 SwLangHelper::SetLanguage( rSh
, pOLV
, aSelection
, aNewLangTxt
, bForSelection
, aEditAttr
);
194 // ugly hack, as it seems that EditView/EditEngine does not update their spellchecking marks
195 // when setting a new language attribute
198 const SwViewOption
* pVOpt
= rView
.GetWrtShellPtr()->GetViewOptions();
199 sal_uLong nCntrl
= pEditEngine
->GetControlWord();
201 nCntrl
&= ~EE_CNTRL_ONLINESPELLING
;
202 pEditEngine
->SetControlWord(nCntrl
);
205 if (pVOpt
->IsOnlineSpell())
206 nCntrl
|= EE_CNTRL_ONLINESPELLING
;
208 nCntrl
&= ~EE_CNTRL_ONLINESPELLING
;
209 pEditEngine
->SetControlWord(nCntrl
);
211 pEditEngine
->CompleteOnlineSpelling();
212 rEditView
.Invalidate();
217 // need to release view and restore selection...
218 rSh
.Pop( sal_False
);
219 rSh
.LockView( sal_False
);
225 // invalidate slot to get the new language displayed
226 pViewFrame
->GetBindings().Invalidate( rReq
.GetSlot() );
229 return bRestoreSelection
;
233 void SetLanguage( SwWrtShell
&rWrtSh
, const String
&rLangText
, bool bIsForSelection
, SfxItemSet
&rCoreSet
)
235 SetLanguage( rWrtSh
, 0 , ESelection(), rLangText
, bIsForSelection
, rCoreSet
);
238 void SetLanguage( SwWrtShell
&rWrtSh
, OutlinerView
* pOLV
, ESelection aSelection
, const String
&rLangText
, bool bIsForSelection
, SfxItemSet
&rCoreSet
)
240 const LanguageType nLang
= SvtLanguageTable().GetType( rLangText
);
241 if (nLang
!= LANGUAGE_DONTKNOW
)
243 sal_uInt16 nScriptType
= SvtLanguageOptions::GetScriptTypeOfLanguage( nLang
);
245 EditEngine
* pEditEngine
= pOLV
? pOLV
->GetEditView().GetEditEngine() : NULL
;
246 OSL_ENSURE( !pOLV
|| pEditEngine
, "OutlinerView without EditEngine???" );
249 sal_uInt16 nLangWhichId
= 0;
250 bool bIsSingleScriptType
= true;
253 case SCRIPTTYPE_LATIN
: nLangWhichId
= pEditEngine
? EE_CHAR_LANGUAGE
: RES_CHRATR_LANGUAGE
; break;
254 case SCRIPTTYPE_ASIAN
: nLangWhichId
= pEditEngine
? EE_CHAR_LANGUAGE_CJK
: RES_CHRATR_CJK_LANGUAGE
; break;
255 case SCRIPTTYPE_COMPLEX
: nLangWhichId
= pEditEngine
? EE_CHAR_LANGUAGE_CTL
: RES_CHRATR_CTL_LANGUAGE
; break;
257 bIsSingleScriptType
= false;
258 OSL_FAIL("unexpected case" );
260 if (bIsSingleScriptType
)
262 // change language for selection or paragraph
263 // (for paragraph is handled by previosuly having set the selection to the
267 // apply language to current selection
270 rCoreSet
.Put( SvxLanguageItem( nLang
, nLangWhichId
));
271 pEditEngine
->QuickSetAttribs( rCoreSet
, aSelection
);
275 rWrtSh
.GetCurAttr( rCoreSet
);
276 rCoreSet
.Put( SvxLanguageItem( nLang
, nLangWhichId
));
277 rWrtSh
.SetAttr( rCoreSet
);
280 else // change language for all text
282 // set document default language
283 switch (nLangWhichId
)
285 case EE_CHAR_LANGUAGE
: nLangWhichId
= RES_CHRATR_LANGUAGE
; break;
286 case EE_CHAR_LANGUAGE_CJK
: nLangWhichId
= RES_CHRATR_CJK_LANGUAGE
; break;
287 case EE_CHAR_LANGUAGE_CTL
: nLangWhichId
= RES_CHRATR_CTL_LANGUAGE
; break;
289 //Set the default document language
290 rWrtSh
.SetDefault( SvxLanguageItem( nLang
, nLangWhichId
) );
292 //Resolves: fdo#35282 Clear the language from all Text Styles, and
293 //fallback to default document language
294 const SwTxtFmtColls
*pColls
= rWrtSh
.GetDoc()->GetTxtFmtColls();
295 for(sal_uInt16 i
= 0, nCount
= pColls
->size(); i
< nCount
; ++i
)
297 SwTxtFmtColl
&rTxtColl
= *(*pColls
)[ i
];
298 rTxtColl
.ResetFmtAttr(nLangWhichId
);
300 //Resolves: fdo#35282 Clear the language from all Character Styles,
301 //and fallback to default document language
302 const SwCharFmts
*pCharFmts
= rWrtSh
.GetDoc()->GetCharFmts();
303 for(sal_uInt16 i
= 0, nCount
= pCharFmts
->size(); i
< nCount
; ++i
)
305 SwCharFmt
&rCharFmt
= *(*pCharFmts
)[ i
];
306 rCharFmt
.ResetFmtAttr(nLangWhichId
);
309 // #i102191: hard set respective language attribute in text document
310 // (for all text in the document - which should be selected by now...)
311 rWrtSh
.SetAttr( SvxLanguageItem( nLang
, nLangWhichId
) );
317 void SetLanguage_None( SwWrtShell
&rWrtSh
, bool bIsForSelection
, SfxItemSet
&rCoreSet
)
319 SetLanguage_None( rWrtSh
,0,ESelection(),bIsForSelection
,rCoreSet
);
322 void SetLanguage_None( SwWrtShell
&rWrtSh
, OutlinerView
* pOLV
, ESelection aSelection
, bool bIsForSelection
, SfxItemSet
&rCoreSet
)
325 const sal_uInt16 aLangWhichId_EE
[3] =
328 EE_CHAR_LANGUAGE_CJK
,
333 const sal_uInt16 aLangWhichId_Writer
[3] =
336 RES_CHRATR_CJK_LANGUAGE
,
337 RES_CHRATR_CTL_LANGUAGE
342 // change language for selection or paragraph
343 // (for paragraph is handled by previosuly having set the selection to the
346 EditEngine
* pEditEngine
= pOLV
? pOLV
->GetEditView().GetEditEngine() : NULL
;
347 OSL_ENSURE( !pOLV
|| pEditEngine
, "OutlinerView without EditEngine???" );
350 for (sal_uInt16 i
= 0; i
< 3; ++i
)
351 rCoreSet
.Put( SvxLanguageItem( LANGUAGE_NONE
, aLangWhichId_EE
[i
] ));
352 pEditEngine
->QuickSetAttribs( rCoreSet
, aSelection
);
356 rWrtSh
.GetCurAttr( rCoreSet
);
357 for (sal_uInt16 i
= 0; i
< 3; ++i
)
358 rCoreSet
.Put( SvxLanguageItem( LANGUAGE_NONE
, aLangWhichId_Writer
[i
] ));
359 rWrtSh
.SetAttr( rCoreSet
);
362 else // change language for all text
364 std::set
<sal_uInt16
> aAttribs
;
365 for (sal_uInt16 i
= 0; i
< 3; ++i
)
367 rWrtSh
.SetDefault( SvxLanguageItem( LANGUAGE_NONE
, aLangWhichId_Writer
[i
] ) );
368 aAttribs
.insert( aLangWhichId_Writer
[i
] );
371 // set all language attributes to default
372 // (for all text in the document - which should be selected by now...)
373 rWrtSh
.ResetAttr( aAttribs
);
377 void ResetLanguages( SwWrtShell
&rWrtSh
, bool bIsForSelection
)
379 ResetLanguages( rWrtSh
, 0 , ESelection(), bIsForSelection
);
382 void ResetLanguages( SwWrtShell
&rWrtSh
, OutlinerView
* pOLV
, ESelection aSelection
, bool bIsForSelection
)
384 (void) bIsForSelection
;
387 // reset language for current selection.
388 // The selection should already have been expanded to the whole paragraph or
389 // to all text in the document if those are the ranges where to reset
390 // the language attributes
394 EditView
&rEditView
= pOLV
->GetEditView();
395 rEditView
.RemoveAttribs( true, EE_CHAR_LANGUAGE
);
396 rEditView
.RemoveAttribs( true, EE_CHAR_LANGUAGE_CJK
);
397 rEditView
.RemoveAttribs( true, EE_CHAR_LANGUAGE_CTL
);
401 std::set
<sal_uInt16
> aAttribs
;
402 aAttribs
.insert( RES_CHRATR_LANGUAGE
);
403 aAttribs
.insert( RES_CHRATR_CJK_LANGUAGE
);
404 aAttribs
.insert( RES_CHRATR_CTL_LANGUAGE
);
405 rWrtSh
.ResetAttr( aAttribs
);
410 /// @returns : the language for the selected text that is set for the
411 /// specified attribute (script type).
412 /// If there are more than one languages used LANGUAGE_DONTKNOW will be returned.
413 /// @param nLangWhichId : one of
414 /// RES_CHRATR_LANGUAGE, RES_CHRATR_CJK_LANGUAGE, RES_CHRATR_CTL_LANGUAGE,
415 LanguageType
GetLanguage( SwWrtShell
&rSh
, sal_uInt16 nLangWhichId
)
417 SfxItemSet
aSet( rSh
.GetAttrPool(), nLangWhichId
, nLangWhichId
);
418 rSh
.GetCurAttr( aSet
);
420 return GetLanguage(aSet
,nLangWhichId
);
423 LanguageType
GetLanguage( SfxItemSet aSet
, sal_uInt16 nLangWhichId
)
426 LanguageType nLang
= LANGUAGE_SYSTEM
;
428 const SfxPoolItem
*pItem
= 0;
429 SfxItemState nState
= aSet
.GetItemState( nLangWhichId
, sal_True
, &pItem
);
430 if (nState
> SFX_ITEM_DEFAULT
&& pItem
)
432 // the item is set and can be used
433 nLang
= (dynamic_cast< const SvxLanguageItem
* >(pItem
))->GetLanguage();
435 else if (nState
== SFX_ITEM_DEFAULT
)
437 // since the attribute is not set: retrieve the default value
438 nLang
= (dynamic_cast< const SvxLanguageItem
& >(aSet
.GetPool()->GetDefaultItem( nLangWhichId
))).GetLanguage();
440 else if (nState
== SFX_ITEM_DONTCARE
)
442 // there is more than one language...
443 nLang
= LANGUAGE_DONTKNOW
;
445 OSL_ENSURE( nLang
!= LANGUAGE_SYSTEM
, "failed to get the language?" );
450 /// @returns: the language in use for the selected text.
451 /// 'In use' means the language(s) matching the script type(s) of the
452 /// selected text. Or in other words, the language a spell checker would use.
453 /// If there is more than one language LANGUAGE_DONTKNOW will be returned.
454 LanguageType
GetCurrentLanguage( SwWrtShell
&rSh
)
456 // get all script types used in current selection
457 const sal_uInt16 nScriptType
= rSh
.GetScriptType();
459 //set language attribute to use according to the script type
460 sal_uInt16 nLangWhichId
= 0;
461 bool bIsSingleScriptType
= true;
464 case SCRIPTTYPE_LATIN
: nLangWhichId
= RES_CHRATR_LANGUAGE
; break;
465 case SCRIPTTYPE_ASIAN
: nLangWhichId
= RES_CHRATR_CJK_LANGUAGE
; break;
466 case SCRIPTTYPE_COMPLEX
: nLangWhichId
= RES_CHRATR_CTL_LANGUAGE
; break;
467 default: bIsSingleScriptType
= false; break;
470 // get language according to the script type(s) in use
471 LanguageType nCurrentLang
= LANGUAGE_SYSTEM
;
472 if (bIsSingleScriptType
)
473 nCurrentLang
= GetLanguage( rSh
, nLangWhichId
);
476 // check if all script types are set to LANGUAGE_NONE and return
477 // that if this is the case. Otherwise, having multiple script types
478 // in use always means there are several languages in use...
479 const sal_uInt16 aScriptTypes
[3] =
482 RES_CHRATR_CJK_LANGUAGE
,
483 RES_CHRATR_CTL_LANGUAGE
485 nCurrentLang
= LANGUAGE_NONE
;
486 for (sal_uInt16 i
= 0; i
< 3; ++i
)
488 LanguageType nTmpLang
= GetLanguage( rSh
, aScriptTypes
[i
] );
489 if (nTmpLang
!= LANGUAGE_NONE
)
491 nCurrentLang
= LANGUAGE_DONTKNOW
;
496 OSL_ENSURE( nCurrentLang
!= LANGUAGE_SYSTEM
, "failed to get the language?" );
501 /// @returns: the language in use for the selected text.
502 /// 'In use' means the language(s) matching the script type(s) of the
503 /// selected text. Or in other words, the language a spell checker would use.
504 /// If there is more than one language LANGUAGE_DONTKNOW will be returned.
505 LanguageType
GetCurrentLanguage( SfxItemSet aSet
, sal_uInt16 nScriptType
)
507 //set language attribute to use according to the script type
508 sal_uInt16 nLangWhichId
= 0;
509 bool bIsSingleScriptType
= true;
512 case SCRIPTTYPE_LATIN
: nLangWhichId
= EE_CHAR_LANGUAGE
; break;
513 case SCRIPTTYPE_ASIAN
: nLangWhichId
= EE_CHAR_LANGUAGE_CJK
; break;
514 case SCRIPTTYPE_COMPLEX
: nLangWhichId
= EE_CHAR_LANGUAGE_CTL
; break;
515 default: bIsSingleScriptType
= false;
518 // get language according to the script type(s) in use
519 LanguageType nCurrentLang
= LANGUAGE_SYSTEM
;
520 if (bIsSingleScriptType
)
521 nCurrentLang
= GetLanguage( aSet
, nLangWhichId
);
524 // check if all script types are set to LANGUAGE_NONE and return
525 // that if this is the case. Otherwise, having multiple script types
526 // in use always means there are several languages in use...
527 const sal_uInt16 aScriptTypes
[3] =
530 EE_CHAR_LANGUAGE_CJK
,
533 nCurrentLang
= LANGUAGE_NONE
;
534 for (sal_uInt16 i
= 0; i
< 3; ++i
)
536 LanguageType nTmpLang
= GetLanguage( aSet
, aScriptTypes
[i
] );
537 if (nTmpLang
!= LANGUAGE_NONE
)
539 nCurrentLang
= LANGUAGE_DONTKNOW
;
544 OSL_ENSURE( nCurrentLang
!= LANGUAGE_SYSTEM
, "failed to get the language?" );
549 String
GetTextForLanguageGuessing( SwWrtShell
&rSh
)
551 // string for guessing language
553 SwPaM
*pCrsr
= rSh
.GetCrsr();
554 SwTxtNode
*pNode
= pCrsr
->GetNode()->GetTxtNode();
557 aText
= pNode
->GetTxt();
561 xub_StrLen nEnd
= pCrsr
->GetPoint()->nContent
.GetIndex();
562 // at most 100 chars to the left...
563 nStt
= nEnd
> 100 ? nEnd
- 100 : 0;
564 // ... and 100 to the right of the cursor position
565 nEnd
= aText
.Len() - nEnd
> 100 ? nEnd
+ 100 : aText
.Len();
566 aText
= aText
.Copy( nStt
, nEnd
- nStt
);
572 String
GetTextForLanguageGuessing( EditEngine
* rEditEngine
, ESelection aDocSelection
)
574 // string for guessing language
577 aText
= rEditEngine
->GetText(aDocSelection
);
581 xub_StrLen nEnd
= aDocSelection
.nEndPos
;
582 // at most 100 chars to the left...
583 nStt
= nEnd
> 100 ? nEnd
- 100 : 0;
584 // ... and 100 to the right of the cursor position
585 nEnd
= aText
.Len() - nEnd
> 100 ? nEnd
+ 100 : aText
.Len();
586 aText
= aText
.Copy( nStt
, nEnd
- nStt
);
593 void SelectPara( EditView
&rEditView
, const ESelection
&rCurSel
)
595 ESelection
aParaSel( rCurSel
.nStartPara
, 0, rCurSel
.nStartPara
, EE_TEXTPOS_ALL
);
596 rEditView
.SetSelection( aParaSel
);
599 void SelectCurrentPara( SwWrtShell
&rWrtSh
)
601 // select current para
602 if (!rWrtSh
.IsSttPara())
603 rWrtSh
.MovePara( fnParaCurr
, fnParaStart
);
604 if (!rWrtSh
.HasMark())
607 if (!rWrtSh
.IsEndPara())
608 rWrtSh
.MovePara( fnParaCurr
, fnParaEnd
);
609 #if OSL_DEBUG_LEVEL > 1
611 rWrtSh
.GetSelectedText( aSelTxt
);
617 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */