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 <tools/shl.hxx>
21 : #include <vcl/wrkwin.hxx>
22 : #include <vcl/menu.hxx>
23 : #include <vcl/msgbox.hxx>
24 : #include <vcl/scrbar.hxx>
25 : #include <SpellAttrib.hxx>
26 : #include <sfx2/dispatch.hxx>
27 : #include <sfx2/bindings.hxx>
28 : #include <svl/undo.hxx>
29 : #include <unotools/lingucfg.hxx>
30 : #include <vcl/textdata.hxx>
31 : #include <svtools/filter.hxx>
32 : #include <editeng/unolingu.hxx>
33 : #include <editeng/splwrap.hxx>
34 : #include <linguistic/lngprops.hxx>
35 : #include <linguistic/misc.hxx>
36 : #include <comphelper/processfactory.hxx>
37 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 : #include <com/sun/star/lang/XServiceInfo.hpp>
39 : #include <com/sun/star/lang/XServiceDisplayName.hpp>
40 : #include <com/sun/star/linguistic2/SpellFailure.hpp>
41 : #include <com/sun/star/frame/XStorable.hpp>
42 : #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
43 : #include <com/sun/star/system/SystemShellExecute.hpp>
44 : #include <sfx2/app.hxx>
45 : #include <vcl/help.hxx>
46 : #include <vcl/graph.hxx>
47 : #include <osl/file.hxx>
48 : #include <cuires.hrc>
49 : #include <helpid.hrc>
50 : #include "SpellDialog.hrc"
51 : #include <editeng/optitems.hxx>
52 : #include <editeng/svxenum.hxx>
53 : #include <svx/SpellDialogChildWindow.hxx>
54 : #include "SpellDialog.hxx"
55 : #include <svx/dlgutil.hxx>
56 : #include "optlingu.hxx"
57 : #include <dialmgr.hxx>
58 : #include <svx/svxerr.hxx>
59 : #include "treeopt.hxx"
60 : #include <svtools/langtab.hxx>
61 : #include <comphelper/anytostring.hxx>
62 : #include <cppuhelper/exc_hlp.hxx>
63 :
64 : using namespace ::com::sun::star;
65 : using namespace ::com::sun::star::uno;
66 : using namespace ::com::sun::star::beans;
67 : using namespace ::com::sun::star::linguistic2;
68 :
69 : using ::rtl::OUString;
70 :
71 : // struct SpellDialog_Impl ---------------------------------------------
72 :
73 0 : struct SpellDialog_Impl
74 : {
75 : Sequence< Reference< XDictionary > > aDics;
76 : };
77 : // -----------------------------------------------------------------------
78 :
79 : #define SPELLUNDO_START 200
80 :
81 : #define SPELLUNDO_CHANGE_LANGUAGE (SPELLUNDO_START + 1)
82 : #define SPELLUNDO_CHANGE_TEXTENGINE (SPELLUNDO_START + 2)
83 : #define SPELLUNDO_CHANGE_NEXTERROR (SPELLUNDO_START + 3)
84 : #define SPELLUNDO_CHANGE_ADD_TO_DICTIONARY (SPELLUNDO_START + 4)
85 : #define SPELLUNDO_CHANGE_GROUP (SPELLUNDO_START + 5) //undo list
86 : #define SPELLUNDO_MOVE_ERROREND (SPELLUNDO_START + 6)
87 : #define SPELLUNDO_UNDO_EDIT_MODE (SPELLUNDO_START + 7)
88 : #define SPELLUNDO_ADD_IGNORE_RULE (SPELLUNDO_START + 8)
89 :
90 : namespace svx{
91 : class SpellUndoAction_Impl : public SfxUndoAction
92 : {
93 : sal_uInt16 m_nId;
94 : const Link& m_rActionLink;
95 : //undo of button enabling
96 : bool m_bEnableChangePB;
97 : bool m_bEnableChangeAllPB;
98 : //undo of MarkNextError - used in change and change all, ignore and ignore all
99 : long m_nNewErrorStart;
100 : long m_nNewErrorEnd;
101 : long m_nOldErrorStart;
102 : long m_nOldErrorEnd;
103 : bool m_bIsErrorLanguageSelected;
104 : ::rtl::OUString m_sRuleId;
105 : //undo of AddToDictionary
106 : Reference<XDictionary> m_xDictionary;
107 : ::rtl::OUString m_sAddedWord;
108 : //move end of error - ::ChangeMarkedWord()
109 : long m_nOffset;
110 :
111 : public:
112 0 : SpellUndoAction_Impl(sal_uInt16 nId, const Link& rActionLink) :
113 : m_nId(nId),
114 : m_rActionLink( rActionLink),
115 : m_bEnableChangePB(false),
116 : m_bEnableChangeAllPB(false),
117 : m_nNewErrorStart(-1),
118 : m_nNewErrorEnd(-1),
119 : m_nOldErrorStart(-1),
120 : m_nOldErrorEnd(-1),
121 : m_bIsErrorLanguageSelected(false),
122 0 : m_nOffset(0)
123 0 : {}
124 :
125 : ~SpellUndoAction_Impl();
126 :
127 : virtual void Undo();
128 : virtual sal_uInt16 GetId() const;
129 :
130 0 : void SetEnableChangePB(){m_bEnableChangePB = true;}
131 0 : bool IsEnableChangePB(){return m_bEnableChangePB;}
132 :
133 0 : void SetEnableChangeAllPB(){m_bEnableChangeAllPB = true;}
134 0 : bool IsEnableChangeAllPB(){return m_bEnableChangeAllPB;}
135 :
136 0 : void SetErrorMove(long nNewStart, long nNewEnd, long nOldStart, long nOldEnd)
137 : {
138 0 : m_nNewErrorStart = nNewStart;
139 0 : m_nNewErrorEnd = nNewEnd;
140 0 : m_nOldErrorStart = nOldStart;
141 0 : m_nOldErrorEnd = nOldEnd;
142 0 : }
143 : long GetNewErrorStart() { return m_nNewErrorStart;}
144 : long GetNewErrorEnd() { return m_nNewErrorEnd;}
145 0 : long GetOldErrorStart() { return m_nOldErrorStart;}
146 0 : long GetOldErrorEnd() { return m_nOldErrorEnd;}
147 :
148 0 : void SetErrorLanguageSelected(bool bSet){ m_bIsErrorLanguageSelected = bSet;}
149 0 : bool IsErrorLanguageSelected() const {return m_bIsErrorLanguageSelected;}
150 :
151 0 : void SetDictionary(Reference<XDictionary> xDict) { m_xDictionary = xDict; }
152 0 : Reference<XDictionary> GetDictionary() const {return m_xDictionary;}
153 0 : void SetAddedWord(const ::rtl::OUString& rWord) {m_sAddedWord = rWord;}
154 0 : const ::rtl::OUString& GetAddedWord() const { return m_sAddedWord;}
155 :
156 0 : void SetOffset(long nSet) {m_nOffset = nSet;}
157 0 : long GetOffset() const {return m_nOffset;}
158 :
159 : void SetErrorType( const ::rtl::OUString& rId ) { m_sRuleId = rId; }
160 : const ::rtl::OUString& GetErrorType() const { return m_sRuleId; }
161 :
162 : };
163 : }//namespace svx
164 : using namespace ::svx;
165 :
166 : //-----------------------------------------------------------------------
167 0 : SpellUndoAction_Impl::~SpellUndoAction_Impl()
168 : {
169 0 : }
170 :
171 : //-----------------------------------------------------------------------
172 0 : void SpellUndoAction_Impl::Undo()
173 : {
174 0 : m_rActionLink.Call(this);
175 0 : }
176 :
177 : //-----------------------------------------------------------------------
178 0 : sal_uInt16 SpellUndoAction_Impl::GetId()const
179 : {
180 0 : return m_nId;
181 : }
182 :
183 0 : HelpFixedText::HelpFixedText( Window* pParent, const ResId& rResId ):
184 0 : FixedText( pParent, rResId )
185 : {
186 0 : }
187 :
188 0 : void HelpFixedText::Paint( const Rectangle& rRect )
189 : {
190 0 : Rectangle aTextRect( rRect.Left() + 6, rRect.Top(), rRect.Right() - 6, rRect.Bottom() );
191 0 : DrawText( aTextRect, GetText(), TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE );
192 0 : }
193 :
194 0 : long HelpFixedText::GetActualHeight( )
195 : {
196 0 : Rectangle rRect( GetPosPixel( ), GetSizePixel() );
197 0 : Rectangle aTextRect( rRect.Left() + 6, rRect.Top(), rRect.Right() - 6, rRect.Bottom() );
198 0 : Rectangle aBounds = GetTextRect( aTextRect, GetText(), TEXT_DRAW_WORDBREAK | TEXT_DRAW_MULTILINE );
199 :
200 0 : return aBounds.getHeight();
201 : }
202 :
203 : // class SvxSpellCheckDialog ---------------------------------------------
204 :
205 0 : SpellDialog::SpellDialog(
206 : SpellDialogChildWindow* pChildWindow,
207 : Window * pParent,
208 : SfxBindings* _pBindings)
209 : : SfxModelessDialog (_pBindings,
210 : pChildWindow,
211 : pParent,
212 0 : CUI_RES(RID_SVXDLG_SPELLCHECK)),
213 :
214 0 : aLanguageFT ( this, CUI_RES( FT_LANGUAGE ) ),
215 0 : aLanguageLB ( this, CUI_RES( LB_LANGUAGE ) ),
216 0 : aExplainFT ( this, CUI_RES( FT_EXPLAIN ) ),
217 0 : aExplainLink ( this, CUI_RES( LINK_EXPLAIN ) ),
218 0 : aNotInDictFT ( this, CUI_RES( FT_NOTINDICT ) ),
219 0 : aSentenceED ( this, CUI_RES( ED_NEWWORD ) ),
220 0 : aSuggestionFT ( this, CUI_RES( FT_SUGGESTION ) ),
221 0 : aSuggestionLB ( this, CUI_RES( LB_SUGGESTION ) ),
222 :
223 0 : aIgnorePB ( this, CUI_RES( PB_IGNORE ) ),
224 0 : aIgnoreAllPB ( this, CUI_RES( PB_IGNOREALL ) ),
225 0 : aIgnoreRulePB ( this, CUI_RES( PB_IGNORERULE ) ),
226 0 : aAddToDictMB ( this, CUI_RES( MB_ADDTODICT ) ),
227 0 : aAddToDictPB ( this, CUI_RES( PB_ADDTODICT ) ),
228 :
229 0 : aChangePB ( this, CUI_RES( PB_CHANGE ) ),
230 0 : aChangeAllPB ( this, CUI_RES( PB_CHANGEALL ) ),
231 0 : aAutoCorrPB ( this, CUI_RES( PB_AUTOCORR ) ),
232 :
233 0 : aCheckGrammarCB ( this, CUI_RES( CB_CHECK_GRAMMAR ) ),
234 :
235 0 : aHelpPB ( this, CUI_RES( PB_HELP ) ),
236 0 : aOptionsPB ( this, CUI_RES( PB_OPTIONS ) ),
237 0 : aUndoPB ( this, CUI_RES( PB_UNDO ) ),
238 0 : aClosePB ( this, CUI_RES( PB_CLOSE ) ),
239 0 : aBackgroundGB ( this, CUI_RES( GB_BACKGROUND ) ),
240 :
241 0 : aResumeST ( CUI_RES(ST_RESUME )),
242 : aIgnoreOnceST ( aIgnorePB.GetText()),
243 0 : aNoSuggestionsST( CUI_RES(ST_NOSUGGESTIONS)),
244 0 : m_sTitleSpelling ( CUI_RES( ST_SPELLING ) ),
245 0 : m_sTitleSpellingGrammar ( CUI_RES( ST_SPELLING_AND_GRAMMAR ) ),
246 0 : m_sTitleSpellingGrammarVendor ( CUI_RES( ST_SPELLING_AND_GRAMMAR_VENDORNAME ) ),
247 : aDialogUndoLink( LINK (this, SpellDialog, DialogUndoHdl)),
248 : bModified( false ),
249 : bFocusLocked( true ),
250 0 : rParent ( *pChildWindow )
251 : {
252 0 : FreeResource();
253 0 : xSpell = LinguMgr::GetSpellChecker();
254 0 : pImpl = new SpellDialog_Impl;
255 :
256 0 : const StyleSettings& rSettings = GetSettings().GetStyleSettings();
257 0 : Color aCol = rSettings.GetHelpColor();
258 0 : Wallpaper aWall( aCol );
259 0 : aExplainLink.SetBackground( aWall );
260 0 : aExplainFT.SetBackground( aWall );
261 :
262 : //HelpIds
263 0 : aClosePB. SetHelpId(HID_SPLDLG_BUTTON_CLOSE );
264 0 : aIgnorePB. SetHelpId(HID_SPLDLG_BUTTON_IGNORE );
265 0 : aIgnoreAllPB. SetHelpId(HID_SPLDLG_BUTTON_IGNOREALL);
266 0 : aIgnoreRulePB. SetHelpId(HID_SPLDLG_BUTTON_IGNORERULE);
267 0 : aChangePB. SetHelpId(HID_SPLDLG_BUTTON_CHANGE );
268 0 : aChangeAllPB. SetHelpId(HID_SPLDLG_BUTTON_CHANGEALL);
269 0 : aExplainLink. SetHelpId(HID_SPLDLG_BUTTON_EXPLAIN );
270 0 : Init_Impl();
271 :
272 : // disable controls if service is missing
273 0 : if (!xSpell.is())
274 0 : Enable( sal_False );
275 :
276 : Application::PostUserEvent( STATIC_LINK(
277 0 : this, SpellDialog, InitHdl ) );
278 0 : }
279 :
280 : // -----------------------------------------------------------------------
281 :
282 0 : SpellDialog::~SpellDialog()
283 : {
284 : // save possibly modified user-dictionaries
285 0 : Reference< XDictionaryList > xDicList( SvxGetDictionaryList() );
286 0 : if (xDicList.is())
287 : {
288 0 : linguistic::SaveDictionaries( xDicList );
289 : }
290 :
291 0 : delete aAddToDictMB.GetPopupMenu();
292 0 : delete pImpl;
293 0 : }
294 :
295 : // -----------------------------------------------------------------------
296 :
297 0 : void SpellDialog::Init_Impl()
298 : {
299 : // initialize handler
300 0 : aClosePB.SetClickHdl(LINK( this, SpellDialog, CancelHdl ) );
301 0 : aChangePB.SetClickHdl(LINK( this, SpellDialog, ChangeHdl ) );
302 0 : aChangeAllPB.SetClickHdl(LINK( this, SpellDialog, ChangeAllHdl ) );
303 0 : aIgnorePB.SetClickHdl(LINK( this, SpellDialog, IgnoreHdl ) );
304 0 : aIgnoreAllPB.SetClickHdl(LINK( this, SpellDialog, IgnoreAllHdl ) );
305 0 : aIgnoreRulePB.SetClickHdl(LINK( this, SpellDialog, IgnoreAllHdl ) );
306 0 : aUndoPB.SetClickHdl(LINK( this, SpellDialog, UndoHdl ) );
307 :
308 0 : aAutoCorrPB.SetClickHdl( LINK( this, SpellDialog, ExtClickHdl ) );
309 0 : aCheckGrammarCB.SetClickHdl( LINK( this, SpellDialog, CheckGrammarHdl ));
310 0 : aOptionsPB .SetClickHdl( LINK( this, SpellDialog, ExtClickHdl ) );
311 :
312 0 : aSuggestionLB.SetDoubleClickHdl( LINK( this, SpellDialog, ChangeHdl ) );
313 :
314 0 : aSentenceED.SetModifyHdl(LINK ( this, SpellDialog, ModifyHdl) );
315 :
316 0 : aAddToDictMB.SetSelectHdl(LINK ( this, SpellDialog, AddToDictSelectHdl ) );
317 0 : aAddToDictPB.SetClickHdl(LINK ( this, SpellDialog, AddToDictClickHdl ) );
318 :
319 0 : aLanguageLB.SetSelectHdl(LINK( this, SpellDialog, LanguageSelectHdl ) );
320 :
321 0 : aExplainLink.SetClickHdl( LINK( this, SpellDialog, HandleHyperlink ) );
322 :
323 : // initialize language ListBox
324 0 : aLanguageLB.SetLanguageList( LANG_LIST_SPELL_USED, sal_False, sal_False, sal_True );
325 :
326 0 : aSentenceED.ClearModifyFlag();
327 0 : SvxGetChangeAllList()->clear();
328 0 : }
329 :
330 : // -----------------------------------------------------------------------
331 :
332 0 : void SpellDialog::UpdateBoxes_Impl()
333 : {
334 : sal_Int32 i;
335 0 : aSuggestionLB.Clear();
336 :
337 0 : const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
338 :
339 0 : LanguageType nAltLanguage = LANGUAGE_NONE;
340 0 : Sequence< ::rtl::OUString > aNewWords;
341 0 : bool bIsGrammarError = false;
342 0 : if( pSpellErrorDescription )
343 : {
344 0 : nAltLanguage = LanguageTag( pSpellErrorDescription->aLocale ).getLanguageType();
345 0 : aNewWords = pSpellErrorDescription->aSuggestions;
346 0 : bIsGrammarError = pSpellErrorDescription->bIsGrammarError;
347 0 : aExplainLink.SetURL( pSpellErrorDescription->sExplanationURL );
348 0 : aExplainFT.SetText( pSpellErrorDescription->sExplanation );
349 : }
350 0 : if( pSpellErrorDescription && !pSpellErrorDescription->sDialogTitle.isEmpty() )
351 : {
352 : // use this function to apply the correct image to be used...
353 0 : SetTitle_Impl( nAltLanguage );
354 : // then change the title to the one to be actually used
355 0 : SetText( pSpellErrorDescription->sDialogTitle );
356 : }
357 : else
358 0 : SetTitle_Impl( nAltLanguage );
359 0 : SetSelectedLang_Impl( nAltLanguage );
360 0 : int nDicts = InitUserDicts();
361 :
362 : // enter alternatives
363 0 : const ::rtl::OUString *pNewWords = aNewWords.getConstArray();
364 0 : const sal_Int32 nSize = aNewWords.getLength();
365 0 : for ( i = 0; i < nSize; ++i )
366 : {
367 0 : String aTmp( pNewWords[i] );
368 0 : if ( LISTBOX_ENTRY_NOTFOUND == aSuggestionLB.GetEntryPos( aTmp ) )
369 : {
370 0 : aSuggestionLB.InsertEntry( aTmp );
371 0 : aSuggestionLB.SetEntryFlags(aSuggestionLB.GetEntryCount() - 1, LISTBOX_ENTRY_FLAG_MULTILINE);
372 : }
373 0 : }
374 0 : if(!nSize)
375 0 : aSuggestionLB.InsertEntry( aNoSuggestionsST );
376 0 : aAutoCorrPB.Enable( nSize > 0 );
377 :
378 0 : aSuggestionFT.Enable(nSize > 0);
379 0 : aSuggestionLB.Enable(nSize > 0);
380 0 : if( nSize )
381 : {
382 0 : aSuggestionLB.SelectEntryPos(0);
383 : }
384 0 : aChangePB.Enable( nSize > 0);
385 0 : aChangeAllPB.Enable(nSize > 0);
386 0 : bool bShowChangeAll = !bIsGrammarError;
387 0 : aChangeAllPB.Show( bShowChangeAll );
388 0 : aExplainFT.Show( !bShowChangeAll );
389 0 : aLanguageLB.Enable( bShowChangeAll );
390 0 : aIgnoreAllPB.Show( bShowChangeAll );
391 :
392 0 : aAddToDictMB.Show( bShowChangeAll && nDicts > 1);
393 0 : aAddToDictPB.Show( bShowChangeAll && nDicts <= 1);
394 0 : aIgnoreRulePB.Show( !bShowChangeAll );
395 0 : aIgnoreRulePB.Enable(pSpellErrorDescription && !pSpellErrorDescription->sRuleId.isEmpty());
396 0 : aAutoCorrPB.Show( bShowChangeAll && rParent.HasAutoCorrection() );
397 :
398 0 : bool bHasGrammarChecking = rParent.HasGrammarChecking();
399 0 : aCheckGrammarCB.Show( bHasGrammarChecking );
400 0 : if( !bHasGrammarChecking )
401 : {
402 : //resize the dialog to hide the hidden area of the CheckBox
403 0 : Size aBackSize = aBackgroundGB.GetSizePixel();
404 0 : sal_Int32 nDiff = aBackgroundGB.GetPosPixel().Y() + aBackSize.Height()
405 0 : - aCheckGrammarCB.GetPosPixel().Y();
406 0 : aBackSize.Height() -= nDiff;
407 0 : aBackgroundGB.SetSizePixel(aBackSize);
408 0 : Button* aButtons[] = { &aHelpPB, &aOptionsPB, &aUndoPB, &aClosePB, 0 };
409 0 : sal_Int32 nButton = 0;
410 0 : while( aButtons[nButton])
411 : {
412 0 : Point aPos = aButtons[nButton]->GetPosPixel();
413 0 : aPos.Y() -= nDiff;
414 0 : aButtons[nButton]->SetPosPixel(aPos);
415 0 : ++nButton;
416 : }
417 0 : Size aDlgSize = GetSizePixel();
418 0 : aDlgSize.Height() -= nDiff;
419 0 : SetSizePixel( aDlgSize );
420 : }
421 : else
422 : {
423 0 : bool bHasExplainLink = !aExplainLink.GetURL().isEmpty();
424 0 : aExplainLink.Show( bHasExplainLink );
425 :
426 0 : sal_Int32 nExplainWidth = aExplainLink.GetPosPixel().X() - aExplainFT.GetPosPixel().X();
427 0 : if ( !bHasExplainLink )
428 0 : nExplainWidth += aExplainLink.GetSizePixel().Width();
429 0 : sal_Int32 nExplainHeight = aExplainFT.GetActualHeight();
430 0 : sal_Int32 nCurrentHeight = aExplainFT.GetSizePixel().Height();
431 0 : if( aExplainFT.GetText().Len() == 0 )
432 : {
433 0 : nExplainHeight = 0;
434 0 : aExplainFT.Hide();
435 0 : aExplainLink.Hide();
436 : }
437 :
438 0 : Size aCtlSize = aExplainFT.GetSizePixel();
439 0 : aCtlSize.Height() = nExplainHeight;
440 0 : aCtlSize.Width() = nExplainWidth;
441 0 : aExplainFT.SetSizePixel( aCtlSize );
442 :
443 0 : aCtlSize = aExplainLink.GetSizePixel();
444 0 : aCtlSize.Height() = nExplainHeight;
445 0 : aExplainLink.SetSizePixel( aCtlSize );
446 :
447 0 : sal_Int32 nDiff = - ( nCurrentHeight - nExplainHeight );
448 0 : if ( nDiff != 0 )
449 : {
450 : Control* aControls[] = {
451 : &aNotInDictFT,
452 : &aSentenceED,
453 : &aSuggestionFT,
454 : &aSuggestionLB,
455 : &aIgnorePB,
456 : &aIgnoreAllPB,
457 : &aIgnoreRulePB,
458 : &aAddToDictMB,
459 : &aAddToDictPB,
460 : &aChangePB,
461 : &aChangeAllPB,
462 : &aAutoCorrPB,
463 : &aCheckGrammarCB,
464 : &aHelpPB,
465 : &aOptionsPB,
466 : &aUndoPB,
467 : &aClosePB,
468 : &aBackgroundGB,
469 : 0
470 0 : };
471 0 : sal_Int32 nControl = 0;
472 0 : while( aControls[nControl])
473 : {
474 0 : Point aPos = aControls[nControl]->GetPosPixel();
475 0 : aPos.Y() += nDiff;
476 0 : aControls[nControl]->SetPosPixel(aPos);
477 0 : ++nControl;
478 : }
479 0 : Size aDlgSize = GetSizePixel();
480 0 : aDlgSize.Height() += nDiff;
481 0 : SetSizePixel( aDlgSize );
482 0 : Invalidate();
483 : }
484 0 : }
485 0 : }
486 : // -----------------------------------------------------------------------
487 :
488 0 : void SpellDialog::SpellContinue_Impl(bool bUseSavedSentence, bool bIgnoreCurrentError )
489 : {
490 : //initially or after the last error of a sentence MarkNextError will fail
491 : //then GetNextSentence() has to be called followed again by MarkNextError()
492 : //MarkNextError is not initally called if the UndoEdit mode is active
493 0 : bool bNextSentence = false;
494 0 : if((!aSentenceED.IsUndoEditMode() && aSentenceED.MarkNextError( bIgnoreCurrentError )) ||
495 0 : true == ( bNextSentence = GetNextSentence_Impl(bUseSavedSentence, aSentenceED.IsUndoEditMode()) && aSentenceED.MarkNextError( false )))
496 : {
497 0 : const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
498 0 : if( pSpellErrorDescription )
499 : {
500 0 : UpdateBoxes_Impl();
501 : Control* aControls[] =
502 : {
503 : &aNotInDictFT,
504 : &aSentenceED,
505 : &aLanguageFT,
506 : 0
507 0 : };
508 0 : sal_Int32 nIdx = 0;
509 0 : do
510 : {
511 0 : aControls[nIdx]->Enable(sal_True);
512 : }
513 0 : while(aControls[++nIdx]);
514 :
515 : }
516 0 : if( bNextSentence )
517 : {
518 : //remove undo if a new sentence is active
519 0 : aSentenceED.ResetUndo();
520 0 : aUndoPB.Enable(sal_False);
521 : }
522 : }
523 0 : }
524 : /* Initialize, asynchronous to prevent virtial calls
525 : from a constructor
526 : */
527 0 : IMPL_STATIC_LINK( SpellDialog, InitHdl, SpellDialog *, EMPTYARG )
528 : {
529 0 : pThis->SetUpdateMode( sal_False );
530 : //show or hide AutoCorrect depending on the modules abilities
531 0 : pThis->aAutoCorrPB.Show(pThis->rParent.HasAutoCorrection());
532 0 : pThis->SpellContinue_Impl();
533 0 : pThis->aSentenceED.ResetUndo();
534 0 : pThis->aUndoPB.Enable(sal_False);
535 :
536 : // get current language
537 0 : pThis->UpdateBoxes_Impl();
538 :
539 : // fill dictionary PopupMenu
540 0 : pThis->InitUserDicts();
541 :
542 0 : pThis->LockFocusChanges(true);
543 0 : if( pThis->aChangePB.IsEnabled() )
544 0 : pThis->aChangePB.GrabFocus();
545 0 : else if( pThis->aIgnorePB.IsEnabled() )
546 0 : pThis->aIgnorePB.GrabFocus();
547 0 : else if( pThis->aClosePB.IsEnabled() )
548 0 : pThis->aClosePB.GrabFocus();
549 0 : pThis->LockFocusChanges(false);
550 : //show grammar CheckBox depending on the modules abilities
551 0 : pThis->aCheckGrammarCB.Check( pThis->rParent.IsGrammarChecking() );
552 0 : pThis->SetUpdateMode( sal_True );
553 0 : pThis->Show();
554 0 : return 0;
555 : };
556 :
557 : // -----------------------------------------------------------------------
558 :
559 0 : IMPL_LINK( SpellDialog, ExtClickHdl, Button *, pBtn )
560 : {
561 0 : if (&aOptionsPB == pBtn)
562 0 : StartSpellOptDlg_Impl();
563 0 : else if(&aAutoCorrPB == pBtn)
564 : {
565 : //get the currently selected wrong word
566 0 : String sCurrentErrorText = aSentenceED.GetErrorText();
567 : //get the wrong word from the XSpellAlternative
568 0 : const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
569 0 : if( pSpellErrorDescription )
570 : {
571 0 : String sWrong(pSpellErrorDescription->sErrorText);
572 : //if the word has not been edited in the MultiLineEdit then
573 : //the current suggestion should be used
574 : //if it's not the 'no suggestions' entry
575 0 : if(sWrong == sCurrentErrorText &&
576 0 : aSuggestionLB.IsEnabled() && aSuggestionLB.GetSelectEntryCount() > 0 &&
577 0 : aNoSuggestionsST != aSuggestionLB.GetSelectEntry())
578 : {
579 0 : sCurrentErrorText = aSuggestionLB.GetSelectEntry();
580 : }
581 0 : if(sWrong != sCurrentErrorText)
582 : {
583 0 : SvxPrepareAutoCorrect( sWrong, sCurrentErrorText );
584 0 : LanguageType eLang = GetSelectedLang_Impl();
585 0 : rParent.AddAutoCorrection( sWrong, sCurrentErrorText, eLang );
586 0 : }
587 0 : }
588 : }
589 0 : return 0;
590 : }
591 : // -----------------------------------------------------------------------
592 0 : IMPL_LINK( SpellDialog, CheckGrammarHdl, CheckBox*, pBox )
593 : {
594 0 : rParent.SetGrammarChecking( pBox->IsChecked() );
595 0 : Impl_Restore();
596 0 : return 0;
597 : }
598 :
599 0 : void SpellDialog::StartSpellOptDlg_Impl()
600 : {
601 : sal_uInt16 aSpellInfos[] =
602 : {
603 : SID_ATTR_SPELL,SID_ATTR_SPELL,
604 : SID_SPELL_MODIFIED, SID_SPELL_MODIFIED,
605 : SID_AUTOSPELL_CHECK, SID_AUTOSPELL_CHECK,
606 : 0
607 0 : };
608 0 : SfxItemSet aSet( SFX_APP()->GetPool(), aSpellInfos);
609 0 : aSet.Put(SfxSpellCheckItem( xSpell, SID_ATTR_SPELL ));
610 : SfxSingleTabDialog* pDlg =
611 0 : new SfxSingleTabDialog( this, aSet, RID_SFXPAGE_LINGU );
612 0 : SfxTabPage* pPage = SvxLinguTabPage::Create( pDlg, aSet );
613 0 : ( (SvxLinguTabPage*)pPage )->HideGroups( GROUP_MODULES );
614 0 : pDlg->SetTabPage( pPage );
615 0 : if(RET_OK == pDlg->Execute())
616 : {
617 0 : InitUserDicts();
618 0 : const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
619 0 : if(pOutSet)
620 0 : OfaTreeOptionsDialog::ApplyLanguageOptions(*pOutSet);
621 : }
622 0 : delete pDlg;
623 0 : }
624 :
625 : namespace
626 : {
627 0 : String getDotReplacementString(const String &rErrorText, const String &rSuggestedReplacement)
628 : {
629 0 : String aString = rErrorText;
630 :
631 : //dots are sometimes part of the spelled word but they are not necessarily part of the replacement
632 0 : bool bDot = aString.Len() && aString.GetChar(aString.Len() - 1 ) == '.';
633 :
634 0 : aString = rSuggestedReplacement;
635 :
636 0 : if(bDot && (!aString.Len() || aString.GetChar(aString.Len() - 1 ) != '.'))
637 0 : aString += '.';
638 :
639 0 : return aString;
640 : }
641 : }
642 :
643 :
644 0 : String SpellDialog::getReplacementString() const
645 : {
646 0 : String sOrigString = aSentenceED.GetErrorText();
647 :
648 0 : String sReplacement(sOrigString);
649 :
650 0 : if(aSuggestionLB.IsEnabled() &&
651 0 : aSuggestionLB.GetSelectEntryCount()>0 &&
652 0 : aNoSuggestionsST != aSuggestionLB.GetSelectEntry())
653 0 : sReplacement = aSuggestionLB.GetSelectEntry();
654 :
655 0 : return getDotReplacementString(sOrigString, sReplacement);
656 : }
657 :
658 : // -----------------------------------------------------------------------
659 :
660 0 : IMPL_LINK_NOARG(SpellDialog, ChangeHdl)
661 : {
662 0 : if(aSentenceED.IsUndoEditMode())
663 : {
664 0 : SpellContinue_Impl();
665 : }
666 : else
667 : {
668 0 : aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
669 0 : String aString = getReplacementString();
670 0 : aSentenceED.ChangeMarkedWord(aString, GetSelectedLang_Impl());
671 0 : SpellContinue_Impl();
672 0 : bModified = false;
673 0 : aSentenceED.UndoActionEnd();
674 : }
675 0 : if(!aChangePB.IsEnabled())
676 0 : aIgnorePB.GrabFocus();
677 0 : return 1;
678 : }
679 :
680 : // -----------------------------------------------------------------------
681 :
682 0 : IMPL_LINK_NOARG(SpellDialog, ChangeAllHdl)
683 : {
684 0 : aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
685 0 : String aString = getReplacementString();
686 0 : LanguageType eLang = GetSelectedLang_Impl();
687 :
688 : // add new word to ChangeAll list
689 0 : String aOldWord( aSentenceED.GetErrorText() );
690 0 : SvxPrepareAutoCorrect( aOldWord, aString );
691 0 : Reference<XDictionary> aXDictionary( SvxGetChangeAllList(), UNO_QUERY );
692 : sal_uInt8 nAdded = linguistic::AddEntryToDic( aXDictionary,
693 : aOldWord , sal_True,
694 0 : aString, eLang );
695 :
696 0 : if(nAdded == DIC_ERR_NONE)
697 : {
698 : SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
699 0 : SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
700 0 : pAction->SetDictionary(aXDictionary);
701 0 : pAction->SetAddedWord(aOldWord);
702 0 : aSentenceED.AddUndoAction(pAction);
703 : }
704 :
705 0 : aSentenceED.ChangeMarkedWord(aString, eLang);
706 0 : SpellContinue_Impl();
707 0 : bModified = false;
708 0 : aSentenceED.UndoActionEnd();
709 0 : return 1;
710 : }
711 : // -----------------------------------------------------------------------
712 :
713 0 : IMPL_LINK( SpellDialog, IgnoreAllHdl, Button *, pButton )
714 : {
715 0 : aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
716 : // add word to IgnoreAll list
717 0 : Reference< XDictionary > aXDictionary( SvxGetIgnoreAllList(), UNO_QUERY );
718 : //in case the error has been changed manually it has to be restored
719 0 : aSentenceED.RestoreCurrentError();
720 0 : if( pButton == &aIgnoreRulePB )
721 : {
722 0 : const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
723 : try
724 : {
725 0 : if( pSpellErrorDescription && pSpellErrorDescription->xGrammarChecker.is() )
726 : {
727 0 : pSpellErrorDescription->xGrammarChecker->ignoreRule( pSpellErrorDescription->sRuleId,
728 0 : pSpellErrorDescription->aLocale );
729 : }
730 : }
731 0 : catch( const uno::Exception& )
732 : {
733 : }
734 : }
735 : else
736 : {
737 0 : String sErrorText(aSentenceED.GetErrorText());
738 : sal_uInt8 nAdded = linguistic::AddEntryToDic( aXDictionary,
739 : sErrorText, sal_False,
740 0 : ::rtl::OUString(), LANGUAGE_NONE );
741 0 : if(nAdded == DIC_ERR_NONE)
742 : {
743 : SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
744 0 : SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
745 0 : pAction->SetDictionary(aXDictionary);
746 0 : pAction->SetAddedWord(sErrorText);
747 0 : aSentenceED.AddUndoAction(pAction);
748 0 : }
749 : }
750 :
751 0 : SpellContinue_Impl();
752 0 : bModified = false;
753 0 : aSentenceED.UndoActionEnd();
754 0 : return 1;
755 : }
756 :
757 : //-----------------------------------------------------------------------
758 0 : IMPL_LINK_NOARG(SpellDialog, UndoHdl)
759 : {
760 0 : aSentenceED.Undo();
761 0 : if(!aSentenceED.GetUndoActionCount())
762 0 : aUndoPB.Enable(sal_False);
763 0 : return 0;
764 : }
765 :
766 : //-----------------------------------------------------------------------
767 0 : IMPL_LINK( SpellDialog, DialogUndoHdl, SpellUndoAction_Impl*, pAction )
768 : {
769 0 : switch(pAction->GetId())
770 : {
771 : case SPELLUNDO_CHANGE_TEXTENGINE:
772 : {
773 0 : if(pAction->IsEnableChangePB())
774 0 : aChangePB.Enable(sal_False);
775 0 : if(pAction->IsEnableChangeAllPB())
776 0 : aChangeAllPB.Enable(sal_False);
777 : }
778 0 : break;
779 : case SPELLUNDO_CHANGE_NEXTERROR:
780 : {
781 0 : aSentenceED.MoveErrorMarkTo((sal_uInt16)pAction->GetOldErrorStart(), (sal_uInt16)pAction->GetOldErrorEnd(), false);
782 0 : if(pAction->IsErrorLanguageSelected())
783 : {
784 0 : UpdateBoxes_Impl();
785 : }
786 : }
787 0 : break;
788 : case SPELLUNDO_CHANGE_ADD_TO_DICTIONARY:
789 : {
790 0 : if(pAction->GetDictionary().is())
791 0 : pAction->GetDictionary()->remove(pAction->GetAddedWord());
792 : }
793 0 : break;
794 : case SPELLUNDO_MOVE_ERROREND :
795 : {
796 0 : if(pAction->GetOffset() != 0)
797 0 : aSentenceED.MoveErrorEnd(pAction->GetOffset());
798 : }
799 0 : break;
800 : case SPELLUNDO_UNDO_EDIT_MODE :
801 : {
802 : //refill the dialog with the currently spelled sentence - throw away all changes
803 0 : SpellContinue_Impl(true);
804 : }
805 0 : break;
806 : case SPELLUNDO_ADD_IGNORE_RULE:
807 : //undo of ignored rules is not supported
808 0 : break;
809 : }
810 :
811 0 : return 0;
812 : }
813 : // -----------------------------------------------------------------------
814 0 : void SpellDialog::Impl_Restore()
815 : {
816 : //clear the "ChangeAllList"
817 0 : SvxGetChangeAllList()->clear();
818 : //get a new sentence
819 0 : aSentenceED.SetText(rtl::OUString());
820 0 : aSentenceED.ResetModified();
821 : //Resolves: fdo#39348 refill the dialog with the currently spelled sentence
822 0 : SpellContinue_Impl(true);
823 0 : aIgnorePB.SetText(aIgnoreOnceST);
824 0 : }
825 :
826 0 : IMPL_LINK_NOARG(SpellDialog, IgnoreHdl)
827 : {
828 0 : if(aIgnorePB.GetText() == aResumeST)
829 : {
830 0 : Impl_Restore();
831 : }
832 : else
833 : {
834 : //in case the error has been changed manually it has to be restored,
835 : // since the users choice now was to ignore the error
836 0 : aSentenceED.RestoreCurrentError();
837 :
838 : // the word is being ignored
839 0 : SpellContinue_Impl( false, true );
840 : }
841 0 : return 1;
842 : }
843 :
844 : // -----------------------------------------------------------------------
845 :
846 0 : sal_Bool SpellDialog::Close()
847 : {
848 0 : GetBindings().GetDispatcher()->
849 0 : Execute(rParent.GetType(),
850 0 : SFX_CALLMODE_ASYNCHRON|SFX_CALLMODE_RECORD);
851 0 : return sal_True;
852 : }
853 : // -----------------------------------------------------------------------
854 :
855 0 : void SpellDialog::SetSelectedLang_Impl( LanguageType nLang )
856 : {
857 0 : aLanguageLB.SelectLanguage( nLang );
858 0 : }
859 :
860 : // -----------------------------------------------------------------------
861 :
862 0 : LanguageType SpellDialog::GetSelectedLang_Impl() const
863 : {
864 0 : sal_Int16 nLang = aLanguageLB.GetSelectLanguage();
865 0 : return nLang;
866 : }
867 :
868 : //-------------------------------------------------
869 0 : IMPL_LINK(SpellDialog, LanguageSelectHdl, SvxLanguageBox*, pBox)
870 : {
871 : //If selected language changes, then add->list should be regenerated to
872 : //match
873 0 : InitUserDicts();
874 :
875 : //if currently an error is selected then search for alternatives for
876 : //this word and fill the alternatives ListBox accordingly
877 0 : String sError = aSentenceED.GetErrorText();
878 0 : aSuggestionLB.Clear();
879 0 : if(sError.Len())
880 : {
881 0 : LanguageType eLanguage = pBox->GetSelectLanguage();
882 0 : Reference <XSpellAlternatives> xAlt = xSpell->spell( sError, eLanguage,
883 0 : Sequence< PropertyValue >() );
884 0 : if( xAlt.is() )
885 0 : aSentenceED.SetAlternatives( xAlt );
886 : else
887 : {
888 0 : aSentenceED.ChangeMarkedWord( sError, eLanguage );
889 0 : SpellContinue_Impl();
890 : }
891 :
892 0 : aSentenceED.AddUndoAction(new SpellUndoAction_Impl(SPELLUNDO_CHANGE_LANGUAGE, aDialogUndoLink));
893 : }
894 0 : SpellDialog::UpdateBoxes_Impl();
895 0 : return 0;
896 : }
897 : // -----------------------------------------------------------------------
898 :
899 0 : void SpellDialog::SetLanguage( sal_uInt16 nLang )
900 : /*
901 : Description:
902 : If the language has been changed in thesaurus,
903 : it must be changed here, too.
904 : */
905 : {
906 0 : SetTitle_Impl( nLang );
907 0 : aLanguageLB.SelectLanguage( nLang );
908 0 : }
909 :
910 0 : static Image lcl_GetImageFromPngUrl( const ::rtl::OUString &rFileUrl )
911 : {
912 0 : Image aRes;
913 0 : ::rtl::OUString aTmp;
914 0 : osl::FileBase::getSystemPathFromFileURL( rFileUrl, aTmp );
915 0 : Graphic aGraphic;
916 0 : const String aFilterName( RTL_CONSTASCII_USTRINGPARAM( IMP_PNG ) );
917 0 : if( GRFILTER_OK == GraphicFilter::LoadGraphic( aTmp, aFilterName, aGraphic ) )
918 : {
919 0 : aRes = Image( aGraphic.GetBitmapEx() );
920 : }
921 0 : return aRes;
922 : }
923 0 : void SpellDialog::SetTitle_Impl(LanguageType nLang)
924 : {
925 0 : String sTitle( m_sTitleSpelling );
926 0 : if( rParent.HasGrammarChecking() )
927 : {
928 0 : String sVendor;
929 0 : const SpellErrorDescription* pSpellErrorDescription = aSentenceED.GetAlternatives();
930 0 : if( pSpellErrorDescription && !pSpellErrorDescription->sServiceName.isEmpty() )
931 : {
932 0 : uno::Reference< lang::XServiceDisplayName > xDisplayName( pSpellErrorDescription->xGrammarChecker, uno::UNO_QUERY );
933 0 : if( xDisplayName.is() )
934 0 : sVendor = xDisplayName->getServiceDisplayName( pSpellErrorDescription->aLocale );
935 : }
936 :
937 0 : if( sVendor.Len() )
938 : {
939 0 : sTitle = m_sTitleSpellingGrammarVendor;
940 0 : sTitle.SearchAndReplaceAscii( "$VendorName", sVendor );
941 : }
942 : else
943 : {
944 0 : sTitle = m_sTitleSpellingGrammar;
945 0 : }
946 : }
947 0 : sTitle.SearchAndReplaceAscii( "$LANGUAGE ($LOCATION)", SvtLanguageTable::GetLanguageString(nLang) );
948 0 : SetText( sTitle );
949 0 : }
950 :
951 0 : int SpellDialog::InitUserDicts()
952 : {
953 0 : const LanguageType nLang = aLanguageLB.GetSelectLanguage();
954 :
955 0 : const Reference< XDictionary > *pDic = 0;
956 :
957 : // get list of dictionaries
958 0 : Reference< XDictionaryList > xDicList( SvxGetDictionaryList() );
959 0 : if (xDicList.is())
960 : {
961 : // add active, positive dictionary to dic-list (if not already done).
962 : // This is to ensure that there is at least on dictionary to which
963 : // words could be added.
964 0 : Reference< XDictionary > xDic( SvxGetOrCreatePosDic( xDicList ) );
965 0 : if (xDic.is())
966 0 : xDic->setActive( sal_True );
967 :
968 0 : pImpl->aDics = xDicList->getDictionaries();
969 : }
970 :
971 0 : SvtLinguConfig aCfg;
972 :
973 : // list suitable dictionaries
974 0 : bool bEnable = false;
975 0 : const sal_Int32 nSize = pImpl->aDics.getLength();
976 0 : pDic = pImpl->aDics.getConstArray();
977 0 : delete aAddToDictMB.GetPopupMenu();
978 0 : PopupMenu* pMenu = new PopupMenu;
979 0 : pMenu->SetMenuFlags(MENU_FLAG_NOAUTOMNEMONICS);
980 0 : sal_uInt16 nItemId = 1; // menu items should be enumerated from 1 and not 0
981 0 : for (sal_Int32 i = 0; i < nSize; ++i)
982 : {
983 0 : uno::Reference< linguistic2::XDictionary > xDicTmp( pDic[i], uno::UNO_QUERY );
984 0 : if (!xDicTmp.is() || SvxGetIgnoreAllList() == xDicTmp)
985 0 : continue;
986 :
987 0 : uno::Reference< frame::XStorable > xStor( xDicTmp, uno::UNO_QUERY );
988 0 : LanguageType nActLanguage = LanguageTag( xDicTmp->getLocale() ).getLanguageType();
989 0 : if( xDicTmp->isActive()
990 0 : && xDicTmp->getDictionaryType() != linguistic2::DictionaryType_NEGATIVE
991 : && (nLang == nActLanguage || LANGUAGE_NONE == nActLanguage )
992 0 : && (!xStor.is() || !xStor->isReadonly()) )
993 : {
994 0 : pMenu->InsertItem( nItemId, xDicTmp->getName() );
995 0 : bEnable = sal_True;
996 :
997 0 : uno::Reference< lang::XServiceInfo > xSvcInfo( xDicTmp, uno::UNO_QUERY );
998 0 : if (xSvcInfo.is())
999 : {
1000 : OUString aDictionaryImageUrl( aCfg.GetSpellAndGrammarContextDictionaryImage(
1001 0 : xSvcInfo->getImplementationName()) );
1002 0 : if (!aDictionaryImageUrl.isEmpty())
1003 : {
1004 0 : Image aImage( lcl_GetImageFromPngUrl( aDictionaryImageUrl ) );
1005 0 : pMenu->SetItemImage( nItemId, aImage );
1006 0 : }
1007 : }
1008 :
1009 0 : ++nItemId;
1010 : }
1011 0 : }
1012 0 : aAddToDictMB.SetPopupMenu(pMenu);
1013 0 : aAddToDictMB.Enable( bEnable );
1014 0 : aAddToDictPB.Enable( bEnable );
1015 :
1016 0 : int nDicts = nItemId-1;
1017 :
1018 0 : aAddToDictMB.Show( nDicts > 1 );
1019 0 : aAddToDictPB.Show( nDicts <= 1 );
1020 :
1021 0 : return nDicts;
1022 : }
1023 :
1024 : //-----------------------------------------------------------------------
1025 0 : IMPL_LINK(SpellDialog, AddToDictClickHdl, PushButton*, EMPTYARG )
1026 : {
1027 0 : return AddToDictionaryExecute(1, aAddToDictMB.GetPopupMenu());
1028 : }
1029 :
1030 : //-----------------------------------------------------------------------
1031 0 : IMPL_LINK(SpellDialog, AddToDictSelectHdl, MenuButton*, pButton )
1032 : {
1033 0 : return AddToDictionaryExecute(pButton->GetCurItemId(), pButton->GetPopupMenu());
1034 : }
1035 :
1036 : //-----------------------------------------------------------------------
1037 0 : int SpellDialog::AddToDictionaryExecute( sal_uInt16 nItemId, PopupMenu *pMenu )
1038 : {
1039 0 : aSentenceED.UndoActionStart( SPELLUNDO_CHANGE_GROUP );
1040 :
1041 : //GetErrorText() returns the current error even if the text is already
1042 : //manually changed
1043 0 : const String aNewWord= aSentenceED.GetErrorText();
1044 :
1045 0 : String aDicName ( pMenu->GetItemText( nItemId ) );
1046 :
1047 0 : uno::Reference< linguistic2::XDictionary > xDic;
1048 0 : uno::Reference< linguistic2::XDictionaryList > xDicList( SvxGetDictionaryList() );
1049 0 : if (xDicList.is())
1050 0 : xDic = xDicList->getDictionaryByName( aDicName );
1051 :
1052 0 : sal_Int16 nAddRes = DIC_ERR_UNKNOWN;
1053 0 : if (xDic.is())
1054 : {
1055 0 : nAddRes = linguistic::AddEntryToDic( xDic, aNewWord, sal_False, OUString(), LANGUAGE_NONE );
1056 : // save modified user-dictionary if it is persistent
1057 0 : uno::Reference< frame::XStorable > xSavDic( xDic, uno::UNO_QUERY );
1058 0 : if (xSavDic.is())
1059 0 : xSavDic->store();
1060 :
1061 0 : if (nAddRes == DIC_ERR_NONE)
1062 : {
1063 : SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
1064 0 : SPELLUNDO_CHANGE_ADD_TO_DICTIONARY, aDialogUndoLink);
1065 0 : pAction->SetDictionary( xDic );
1066 0 : pAction->SetAddedWord( aNewWord );
1067 0 : aSentenceED.AddUndoAction( pAction );
1068 : }
1069 : // failed because there is already an entry?
1070 0 : if (DIC_ERR_NONE != nAddRes && xDic->getEntry( aNewWord ).is())
1071 0 : nAddRes = DIC_ERR_NONE;
1072 : }
1073 0 : if (DIC_ERR_NONE != nAddRes)
1074 : {
1075 0 : SvxDicError( this, nAddRes );
1076 0 : return 0; // don't continue
1077 : }
1078 :
1079 : // go on
1080 0 : SpellContinue_Impl();
1081 0 : aSentenceED.UndoActionEnd();
1082 0 : return 0;
1083 : }
1084 :
1085 : //-----------------------------------------------------------------------
1086 0 : IMPL_LINK(SpellDialog, ModifyHdl, SentenceEditWindow_Impl*, pEd)
1087 : {
1088 0 : if (&aSentenceED == pEd)
1089 : {
1090 0 : bModified = true;
1091 0 : aSuggestionLB.SetNoSelection();
1092 0 : aSuggestionLB.Disable();
1093 0 : String sNewText( aSentenceED.GetText() );
1094 0 : aAutoCorrPB.Enable( sNewText != aSentenceED.GetText() );
1095 0 : SpellUndoAction_Impl* pSpellAction = new SpellUndoAction_Impl(SPELLUNDO_CHANGE_TEXTENGINE, aDialogUndoLink);
1096 0 : if(!aChangeAllPB.IsEnabled())
1097 : {
1098 0 : aChangeAllPB.Enable();
1099 0 : pSpellAction->SetEnableChangeAllPB();
1100 : }
1101 0 : if(!aChangePB.IsEnabled())
1102 : {
1103 0 : aChangePB.Enable();
1104 0 : pSpellAction->SetEnableChangePB();
1105 : }
1106 0 : aSentenceED.AddUndoAction(pSpellAction);
1107 : }
1108 0 : return 0;
1109 : };
1110 :
1111 : //-----------------------------------------------------------------------
1112 0 : IMPL_LINK_NOARG(SpellDialog, CancelHdl)
1113 : {
1114 : //apply changes and ignored text parts first - if there are any
1115 0 : rParent.ApplyChangedSentence(aSentenceED.CreateSpellPortions(true), false);
1116 0 : Close();
1117 0 : return 0;
1118 : }
1119 :
1120 : //-----------------------------------------------------------------------
1121 0 : void SpellDialog::Paint( const Rectangle& rRect )
1122 : {
1123 0 : ModelessDialog::Paint(rRect );
1124 0 : Rectangle aRect(aBackgroundGB.GetPosPixel(), aBackgroundGB.GetSizePixel());
1125 0 : DecorationView aDecoView( this );
1126 0 : aDecoView.DrawButton( aRect, BUTTON_DRAW_NOFILL);
1127 0 : }
1128 :
1129 : //-----------------------------------------------------------------------
1130 0 : long SpellDialog::Notify( NotifyEvent& rNEvt )
1131 : {
1132 : /* #i38338#
1133 : * FIXME: LoseFocus and GetFocus are signals from vcl that
1134 : * a window actually got/lost the focus, it never should be
1135 : * forwarded from another window, that is simply wrong.
1136 : * FIXME: overloading the virtual methods GetFocus and LoseFocus
1137 : * in SpellDialogChildWindow by making them pure is at least questionable.
1138 : * The only sensible thing would be to call the new Method differently,
1139 : * e.g. DialogGot/LostFocus or so.
1140 : */
1141 0 : if( IsVisible() && !bFocusLocked )
1142 : {
1143 0 : if( rNEvt.GetType() == EVENT_GETFOCUS )
1144 : {
1145 : //notify the child window of the focus change
1146 0 : rParent.GetFocus();
1147 : }
1148 0 : else if( rNEvt.GetType() == EVENT_LOSEFOCUS )
1149 : {
1150 : //notify the child window of the focus change
1151 0 : rParent.LoseFocus();
1152 : }
1153 : }
1154 0 : return SfxModelessDialog::Notify(rNEvt);
1155 : }
1156 :
1157 : //-------------------------------------------------
1158 0 : void SpellDialog::InvalidateDialog()
1159 : {
1160 0 : if( bFocusLocked )
1161 0 : return;
1162 0 : aIgnorePB.SetText(aResumeST);
1163 : Window* aDisableArr[] =
1164 : {
1165 : &aNotInDictFT,
1166 : &aSentenceED,
1167 : &aSuggestionFT,
1168 : &aSuggestionLB,
1169 : &aLanguageFT,
1170 : &aLanguageLB,
1171 : &aIgnoreAllPB,
1172 : &aIgnoreRulePB,
1173 : &aAddToDictMB,
1174 : &aAddToDictPB,
1175 : &aChangePB,
1176 : &aChangeAllPB,
1177 : &aAutoCorrPB,
1178 : &aUndoPB,
1179 : 0
1180 0 : };
1181 0 : sal_Int16 i = 0;
1182 0 : while(aDisableArr[i])
1183 : {
1184 0 : aDisableArr[i]->Enable(sal_False);
1185 0 : i++;
1186 : }
1187 0 : SfxModelessDialog::Deactivate();
1188 : }
1189 :
1190 : //-----------------------------------------------------------------------
1191 0 : bool SpellDialog::GetNextSentence_Impl(bool bUseSavedSentence, bool bRecheck)
1192 : {
1193 0 : bool bRet = false;
1194 0 : if(!bUseSavedSentence)
1195 : {
1196 : //apply changes and ignored text parts
1197 0 : rParent.ApplyChangedSentence(aSentenceED.CreateSpellPortions(true), bRecheck);
1198 : }
1199 0 : aSentenceED.ResetIgnoreErrorsAt();
1200 0 : aSentenceED.ResetModified();
1201 0 : SpellPortions aSentence = bUseSavedSentence ? m_aSavedSentence : rParent.GetNextWrongSentence( bRecheck );
1202 0 : if(!bUseSavedSentence)
1203 0 : m_aSavedSentence = aSentence;
1204 0 : bool bHasReplaced = false;
1205 0 : while(!aSentence.empty())
1206 : {
1207 : //apply all changes that are already part of the "ChangeAllList"
1208 : //returns true if the list still contains errors after the changes have been applied
1209 :
1210 0 : if(!ApplyChangeAllList_Impl(aSentence, bHasReplaced))
1211 : {
1212 0 : rParent.ApplyChangedSentence(aSentence, bRecheck);
1213 0 : aSentence = rParent.GetNextWrongSentence( bRecheck );
1214 : }
1215 : else
1216 0 : break;
1217 : }
1218 :
1219 0 : if(!aSentence.empty())
1220 : {
1221 0 : SpellPortions::iterator aStart = aSentence.begin();
1222 0 : rtl::OUString sText;
1223 0 : while(aStart != aSentence.end())
1224 : {
1225 : // hidden text has to be ignored
1226 0 : if(!aStart->bIsHidden)
1227 0 : sText += aStart->sText;
1228 0 : ++aStart;
1229 : }
1230 0 : aSentenceED.SetText(sText);
1231 0 : aStart = aSentence.begin();
1232 0 : sal_Int32 nStartPosition = 0;
1233 0 : sal_Int32 nEndPosition = 0;
1234 :
1235 0 : while(aStart != aSentence.end())
1236 : {
1237 : // hidden text has to be ignored
1238 0 : if(!aStart->bIsHidden)
1239 : {
1240 0 : nEndPosition += aStart->sText.getLength();
1241 0 : if(aStart->xAlternatives.is())
1242 : {
1243 0 : uno::Reference< container::XNamed > xNamed( aStart->xAlternatives, uno::UNO_QUERY );
1244 0 : ::rtl::OUString sServiceName;
1245 0 : if( xNamed.is() )
1246 0 : sServiceName = xNamed->getName();
1247 0 : SpellErrorDescription aDesc( false, aStart->xAlternatives->getWord(),
1248 0 : aStart->xAlternatives->getLocale(), aStart->xAlternatives->getAlternatives(), 0, sServiceName);
1249 0 : aSentenceED.SetAttrib( SpellErrorAttrib(aDesc), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
1250 : }
1251 0 : else if(aStart->bIsGrammarError )
1252 : {
1253 0 : beans::PropertyValues aProperties = aStart->aGrammarError.aProperties;
1254 0 : rtl::OUString sFullCommentURL;
1255 0 : sal_Int32 i = 0;
1256 0 : while ( sFullCommentURL.isEmpty() && i < aProperties.getLength() )
1257 : {
1258 0 : if ( aProperties[i].Name == "FullCommentURL" )
1259 : {
1260 0 : uno::Any aValue = aProperties[i].Value;
1261 0 : aValue >>= sFullCommentURL;
1262 : }
1263 0 : ++i;
1264 : }
1265 :
1266 0 : uno::Reference< lang::XServiceInfo > xInfo( aStart->xGrammarChecker, uno::UNO_QUERY );
1267 : SpellErrorDescription aDesc( true,
1268 0 : aStart->sText,
1269 0 : LanguageTag( aStart->eLanguage ).getLocale(),
1270 0 : aStart->aGrammarError.aSuggestions,
1271 0 : aStart->xGrammarChecker,
1272 0 : xInfo->getImplementationName(),
1273 0 : &aStart->sDialogTitle,
1274 0 : &aStart->aGrammarError.aFullComment,
1275 0 : &aStart->aGrammarError.aRuleIdentifier,
1276 0 : &sFullCommentURL );
1277 0 : aSentenceED.SetAttrib( SpellErrorAttrib(aDesc), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
1278 : }
1279 0 : if(aStart->bIsField)
1280 0 : aSentenceED.SetAttrib( SpellBackgroundAttrib(COL_LIGHTGRAY), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
1281 0 : aSentenceED.SetAttrib( SpellLanguageAttrib(aStart->eLanguage), 0, (sal_uInt16) nStartPosition, (sal_uInt16) nEndPosition );
1282 0 : nStartPosition = nEndPosition;
1283 : }
1284 0 : ++aStart;
1285 : }
1286 : //the edit field needs to be modified to apply the change from the ApplyChangeAllList
1287 0 : if(!bHasReplaced)
1288 0 : aSentenceED.ClearModifyFlag();
1289 0 : aSentenceED.ResetUndo();
1290 0 : aUndoPB.Enable(sal_False);
1291 0 : bRet = nStartPosition > 0;
1292 : }
1293 0 : return bRet;
1294 : }
1295 : /*-------------------------------------------------------------------------
1296 : replace errrors that have a replacement in the ChangeAllList
1297 : returns false if the result doesn't contain errors after the replacement
1298 : -----------------------------------------------------------------------*/
1299 0 : bool SpellDialog::ApplyChangeAllList_Impl(SpellPortions& rSentence, bool &bHasReplaced)
1300 : {
1301 0 : bHasReplaced = false;
1302 0 : bool bRet = true;
1303 0 : SpellPortions::iterator aStart = rSentence.begin();
1304 0 : Reference<XDictionary> xChangeAll( SvxGetChangeAllList(), UNO_QUERY );
1305 0 : if(!xChangeAll->getCount())
1306 0 : return bRet;
1307 0 : bRet = false;
1308 0 : while(aStart != rSentence.end())
1309 : {
1310 0 : if(aStart->xAlternatives.is())
1311 : {
1312 0 : const rtl::OUString &rString = aStart->sText;
1313 :
1314 0 : Reference<XDictionaryEntry> xEntry = xChangeAll->getEntry(rString);
1315 :
1316 0 : if(xEntry.is())
1317 : {
1318 0 : aStart->sText = getDotReplacementString(rString, xEntry->getReplacementText());
1319 0 : aStart->xAlternatives = 0;
1320 0 : bHasReplaced = true;
1321 : }
1322 : else
1323 0 : bRet = true;
1324 : }
1325 0 : else if( aStart->bIsGrammarError )
1326 0 : bRet = true;
1327 0 : ++aStart;
1328 : }
1329 0 : return bRet;
1330 : }
1331 :
1332 : //-----------------------------------------------------------------------
1333 0 : SentenceEditWindow_Impl::SentenceEditWindow_Impl( SpellDialog* pParent, const ResId& rResId ) :
1334 : MultiLineEdit( pParent, rResId ),
1335 : m_nErrorStart(0),
1336 : m_nErrorEnd(0),
1337 0 : m_bIsUndoEditMode(false)
1338 : {
1339 0 : DisableSelectionOnFocus();
1340 0 : }
1341 :
1342 : //-----------------------------------------------------------------------
1343 0 : SentenceEditWindow_Impl::~SentenceEditWindow_Impl()
1344 : {
1345 0 : }
1346 : /*-------------------------------------------------------------------------
1347 : The selection before inputting a key may have a range or not
1348 : and it may be inside or outside of field or error attributes.
1349 : A range may include the attribute partially, completely or together
1350 : with surrounding text. It may also contain more than one attribute
1351 : or no attribute at all.
1352 : Depending on this starting conditions some actions are necessary:
1353 : Attempts to delete a field are only allowed if the selection is the same
1354 : as the field's selection. Otherwise the field has to be selected and the key
1355 : input action has to be skipped.
1356 : Input of text at the start of the field requires the field attribute to be
1357 : corrected - it is not allowed to grow.
1358 :
1359 : In case of errors the appending of text should grow the error attribute because
1360 : that is what the user usually wants to do.
1361 :
1362 : Backspace at the start of the attribute requires to find out if a field ends
1363 : directly in front of the cursor position. In case of a field this attribute has to be
1364 : selected otherwise the key input method is allowed.
1365 :
1366 : All changes outside of the error attributes switch the dialog mode to a "Undo edit" state that
1367 : removes all visible attributes and switches off further attribute checks.
1368 : Undo in this restarts the dialog with a current sentence newly presented.
1369 : All changes to the sentence are undone including the ones before the "Undo edit state" has been reached
1370 :
1371 : We end up with 9 types of selection
1372 : 1 (LEFT_NO) - no range, start of attribute - can also be 3 at the same time
1373 : 2 (INSIDE_NO) - no range, inside of attribute
1374 : 3 (RIGHT_NO) - no range, end of attribute - can also be 1 at the same time
1375 : 4 (FULL) - range, same as attribute
1376 : 5 (INSIDE_YES) - range, inside of the attribute
1377 : 6 (BRACE)- range, from outside of the attribute to the inside or
1378 : including the complete attribute and something outside,
1379 : maybe more than one attribute
1380 : 7 (OUTSIDE_NO) - no range, not at an attribute
1381 : 8 (OUTSIDE_YES) - range, completely outside of all attributes
1382 :
1383 : What has to be done depending on the attribute type involved
1384 : possible actions: UE - Undo edit mode
1385 : CO - Continue, no additional action is required
1386 : FS - Field has to be completely selected
1387 : EX - The attribute has to be expanded to include the added text
1388 :
1389 : 1 - backspace delete any other
1390 : UE on field FS on error CO on field FS on error CO
1391 :
1392 : 2 - on field FS on error C
1393 : 3 - backspace delete any other
1394 : on field FS on error CO UE on field UE on error EX
1395 :
1396 : if 1 and 3 happen to apply both then backspace and other handling is 1 delete is 3
1397 :
1398 : 4 - on field UE and on error CO
1399 : 5 - on field FS and on error CO
1400 : 6 - on field FS and on error UE
1401 : 7 - UE
1402 : 8 - UE
1403 : -----------------------------------------------------------------------*/
1404 : #define INVALID 0
1405 : #define LEFT_NO 1
1406 : #define INSIDE_NO 2
1407 : #define RIGHT_NO 3
1408 : #define FULL 4
1409 : #define INSIDE_YES 5
1410 : #define BRACE 6
1411 : #define OUTSIDE_NO 7
1412 : #define OUTSIDE_YES 8
1413 :
1414 : #define ACTION_UNDOEDIT 0
1415 : #define ACTION_CONTINUE 1
1416 : #define ACTION_SELECTFIELD 2
1417 : #define ACTION_EXPAND 3
1418 :
1419 0 : long SentenceEditWindow_Impl::PreNotify( NotifyEvent& rNEvt )
1420 : {
1421 0 : bool bChange = false;
1422 0 : const TextCharAttrib* pErrorAttrib = 0;
1423 0 : if(rNEvt.GetType() == EVENT_KEYINPUT)
1424 : {
1425 0 : const KeyEvent& rKeyEvt = *rNEvt.GetKeyEvent();
1426 0 : bChange = TextEngine::DoesKeyChangeText( rKeyEvt );
1427 0 : if(bChange && !IsUndoEditMode() &&
1428 0 : rKeyEvt.GetKeyCode().GetCode() != KEY_TAB)
1429 : {
1430 0 : TextEngine* pTextEngine = GetTextEngine();
1431 0 : TextView* pTextView = pTextEngine->GetActiveView();
1432 0 : const TextSelection& rCurrentSelection = pTextView->GetSelection();
1433 : //determine if the selection contains a field
1434 0 : bool bHasField = false;
1435 0 : bool bHasError = false;
1436 0 : bool bHasFieldLeft = false;
1437 0 : bool bHasErrorLeft = false;
1438 :
1439 0 : bool bHasRange = rCurrentSelection.HasRange();
1440 0 : sal_uInt8 nSelectionType = 0; // invalid type!
1441 :
1442 0 : TextPaM aCursor(rCurrentSelection.GetStart());
1443 0 : const TextCharAttrib* pBackAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
1444 0 : const TextCharAttrib* pErrorAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
1445 0 : const TextCharAttrib* pBackAttrLeft = 0;
1446 0 : const TextCharAttrib* pErrorAttrLeft = 0;
1447 :
1448 0 : bHasField = pBackAttr != 0 && (bHasRange || pBackAttr->GetEnd() > aCursor.GetIndex());
1449 0 : bHasError = pErrorAttr != 0 && (bHasRange || pErrorAttr->GetEnd() > aCursor.GetIndex());
1450 0 : if(bHasRange)
1451 : {
1452 0 : if(pBackAttr &&
1453 0 : pBackAttr->GetStart() == rCurrentSelection.GetStart().GetIndex() &&
1454 0 : pBackAttr->GetEnd() == rCurrentSelection.GetEnd().GetIndex())
1455 : {
1456 0 : nSelectionType = FULL;
1457 : }
1458 0 : else if(pErrorAttr &&
1459 0 : pErrorAttr->GetStart() <= rCurrentSelection.GetStart().GetIndex() &&
1460 0 : pErrorAttr->GetEnd() >= rCurrentSelection.GetEnd().GetIndex())
1461 : {
1462 0 : nSelectionType = INSIDE_YES;
1463 : }
1464 : else
1465 : {
1466 0 : nSelectionType = bHasField||bHasError ? BRACE : OUTSIDE_NO;
1467 0 : while(aCursor.GetIndex() < rCurrentSelection.GetEnd().GetIndex())
1468 : {
1469 0 : ++aCursor.GetIndex();
1470 0 : const TextCharAttrib* pIntBackAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
1471 0 : const TextCharAttrib* pIntErrorAttr = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
1472 : //if any attr has been found then BRACE
1473 0 : if(pIntBackAttr || pIntErrorAttr)
1474 0 : nSelectionType = BRACE;
1475 : //the field has to be selected
1476 0 : if(pIntBackAttr && !pBackAttr)
1477 0 : pBackAttr = pIntBackAttr;
1478 0 : bHasField |= pIntBackAttr != 0;
1479 : }
1480 : }
1481 : }
1482 : else
1483 : {
1484 : //no range selection: then 1 2 3 and 8 are possible
1485 0 : const TextCharAttrib* pCurAttr = pBackAttr ? pBackAttr : pErrorAttr;
1486 0 : if(pCurAttr)
1487 : {
1488 0 : nSelectionType = pCurAttr->GetStart() == rCurrentSelection.GetStart().GetIndex() ?
1489 0 : LEFT_NO : pCurAttr->GetEnd() == rCurrentSelection.GetEnd().GetIndex() ? RIGHT_NO : INSIDE_NO;
1490 : }
1491 : else
1492 0 : nSelectionType = OUTSIDE_NO;
1493 :
1494 0 : bHasFieldLeft = pBackAttr && pBackAttr->GetEnd() == aCursor.GetIndex();
1495 0 : if(bHasFieldLeft)
1496 : {
1497 0 : pBackAttrLeft = pBackAttr;
1498 0 : pBackAttr = 0;
1499 : }
1500 0 : bHasErrorLeft = pErrorAttr && pErrorAttr->GetEnd() == aCursor.GetIndex();
1501 0 : if(bHasErrorLeft)
1502 : {
1503 0 : pErrorAttrLeft = pErrorAttr;
1504 0 : pErrorAttr = 0;
1505 : }
1506 :
1507 : //check previous position if this exists
1508 : //that is a redundant in the case the the attribute found above already is on the left cursor side
1509 : //but it's o.k. for two errors/fields side by side
1510 0 : if(aCursor.GetIndex())
1511 : {
1512 0 : --aCursor.GetIndex();
1513 0 : pBackAttrLeft = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_BACKGROUND );
1514 0 : pErrorAttrLeft = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR );
1515 0 : bHasFieldLeft = pBackAttrLeft !=0;
1516 0 : bHasErrorLeft = pErrorAttrLeft != 0;
1517 0 : ++aCursor.GetIndex();
1518 : }
1519 : }
1520 : //Here we have to determine if the error found is the one currently active
1521 0 : bool bIsErrorActive = (pErrorAttr && pErrorAttr->GetStart() == m_nErrorStart) ||
1522 0 : (pErrorAttrLeft && pErrorAttrLeft->GetStart() == m_nErrorStart);
1523 :
1524 : DBG_ASSERT(nSelectionType != INVALID, "selection type not set!");
1525 :
1526 0 : const KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
1527 0 : bool bDelete = rKeyCode.GetCode() == KEY_DELETE;
1528 0 : bool bBackspace = rKeyCode.GetCode() == KEY_BACKSPACE;
1529 :
1530 0 : sal_Int8 nAction = ACTION_CONTINUE;
1531 0 : switch(nSelectionType)
1532 : {
1533 : // 1 - backspace delete any other
1534 : // UE on field FS on error CO on field FS on error CO
1535 : case LEFT_NO :
1536 0 : if(bBackspace)
1537 : {
1538 0 : nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;
1539 : //to force the use of pBackAttrLeft
1540 0 : pBackAttr = 0;
1541 : }
1542 0 : else if(bDelete)
1543 0 : nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1544 : else
1545 0 : nAction = bHasError && !aCursor.GetIndex() ? ACTION_CONTINUE :
1546 0 : bHasError ? ACTION_EXPAND : bHasErrorLeft ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1547 0 : break;
1548 : // 2 - on field FS on error C
1549 : case INSIDE_NO :
1550 : nAction = bHasField ? ACTION_SELECTFIELD :
1551 0 : bIsErrorActive ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1552 0 : break;
1553 : // 3 - backspace delete any other
1554 : // on field FS on error CO UE on field UE on error EX
1555 : case RIGHT_NO :
1556 0 : if(bBackspace)
1557 0 : nAction = bHasFieldLeft ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1558 0 : else if(bDelete)
1559 0 : nAction = bHasFieldLeft && bHasError ? ACTION_CONTINUE : ACTION_UNDOEDIT;
1560 : else
1561 : nAction = bHasFieldLeft && bHasError ? ACTION_EXPAND :
1562 0 : bHasError ? ACTION_CONTINUE : bHasErrorLeft ? ACTION_EXPAND :ACTION_UNDOEDIT;
1563 0 : break;
1564 : // 4 - on field UE and on error CO
1565 : case FULL :
1566 0 : nAction = bHasField ? ACTION_UNDOEDIT : ACTION_CONTINUE;
1567 0 : break;
1568 : // 5 - on field FS and on error CO
1569 : case INSIDE_YES :
1570 0 : nAction = bHasField ? ACTION_SELECTFIELD : ACTION_CONTINUE;
1571 0 : break;
1572 : // 6 - on field FS and on error UE
1573 : case BRACE :
1574 0 : nAction = bHasField ? ACTION_SELECTFIELD : ACTION_UNDOEDIT;;
1575 0 : break;
1576 : // 7 - UE
1577 : // 8 - UE
1578 : case OUTSIDE_NO :
1579 : case OUTSIDE_YES:
1580 0 : nAction = ACTION_UNDOEDIT;
1581 0 : break;
1582 : }
1583 : //save the current paragraph
1584 0 : sal_uInt16 nCurrentLen = GetText().Len();
1585 0 : if(nAction != ACTION_SELECTFIELD)
1586 0 : pTextView->GetWindow()->KeyInput(rKeyEvt);
1587 : else
1588 : {
1589 0 : const TextCharAttrib* pCharAttr = pBackAttr ? pBackAttr : pBackAttrLeft;
1590 0 : if(pCharAttr)
1591 : {
1592 0 : TextPaM aStart(0, pCharAttr->GetStart());
1593 0 : TextPaM aEnd(0, pCharAttr->GetEnd());
1594 0 : TextSelection aNewSel(aStart, aEnd);
1595 0 : pTextView->SetSelection( aNewSel);
1596 : }
1597 : }
1598 0 : if(nAction == ACTION_EXPAND)
1599 : {
1600 : DBG_ASSERT(pErrorAttrLeft || pErrorAttr, "where is the error");
1601 : //text has been added on the right and only the 'error attribute has to be corrected
1602 0 : if(pErrorAttrLeft)
1603 : {
1604 0 : TextAttrib* pNewError = pErrorAttrLeft->GetAttr().Clone();
1605 0 : sal_uInt16 nStart = pErrorAttrLeft->GetStart();
1606 0 : sal_uInt16 nEnd = pErrorAttrLeft->GetEnd();
1607 0 : pTextEngine->RemoveAttrib( 0, *pErrorAttrLeft );
1608 0 : SetAttrib( *pNewError, 0, nStart, ++nEnd );
1609 : //only active errors move the mark
1610 0 : if(bIsErrorActive)
1611 : {
1612 0 : bool bGrammar = static_cast<const SpellErrorAttrib&>(*pNewError).GetErrorDescription().bIsGrammarError;
1613 0 : MoveErrorMarkTo(nStart, nEnd, bGrammar);
1614 : }
1615 0 : delete pNewError;
1616 : }
1617 : //text has been added on the left then the error attribute has to be expanded and the
1618 : //field attribute on the right - if any - has to be contracted
1619 0 : else if(pErrorAttr)
1620 : {
1621 : //determine the change
1622 0 : sal_uInt16 nAddedChars = GetText().Len() - nCurrentLen;
1623 :
1624 0 : TextAttrib* pNewError = pErrorAttr->GetAttr().Clone();
1625 0 : sal_uInt16 nStart = pErrorAttr->GetStart();
1626 0 : sal_uInt16 nEnd = pErrorAttr->GetEnd();
1627 0 : pTextEngine->RemoveAttrib( 0, *pErrorAttr );
1628 0 : nStart = nStart - (sal_uInt16)nAddedChars;
1629 0 : SetAttrib( *pNewError, 0, nStart - nAddedChars, nEnd );
1630 : //only if the error is active the mark is moved here
1631 0 : if(bIsErrorActive)
1632 : {
1633 0 : bool bGrammar = static_cast<const SpellErrorAttrib&>(*pNewError).GetErrorDescription().bIsGrammarError;
1634 0 : MoveErrorMarkTo(nStart, nEnd, bGrammar);
1635 : }
1636 0 : delete pNewError;
1637 :
1638 0 : if(pBackAttrLeft)
1639 : {
1640 0 : TextAttrib* pNewBack = pBackAttrLeft->GetAttr().Clone();
1641 0 : sal_uInt16 _nStart = pBackAttrLeft->GetStart();
1642 0 : sal_uInt16 _nEnd = pBackAttrLeft->GetEnd();
1643 0 : pTextEngine->RemoveAttrib( 0, *pBackAttrLeft );
1644 0 : SetAttrib( *pNewBack, 0, _nStart, _nEnd - nAddedChars);
1645 0 : delete pNewBack;
1646 : }
1647 : }
1648 : }
1649 0 : else if(nAction == ACTION_UNDOEDIT)
1650 : {
1651 0 : SetUndoEditMode(true);
1652 : }
1653 : //make sure the error positions are correct after text changes
1654 : //the old attribute may have been deleted
1655 : //all changes inside of the current error leave the error attribute at the current
1656 : //start position
1657 0 : if(!IsUndoEditMode() && bIsErrorActive)
1658 : {
1659 0 : const TextCharAttrib* pFontColor = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_FONTCOLOR );
1660 0 : pErrorAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_ERROR );
1661 0 : if(pFontColor && pErrorAttrib )
1662 : {
1663 0 : m_nErrorStart = pFontColor->GetStart();
1664 0 : m_nErrorEnd = pFontColor->GetEnd();
1665 0 : if(pErrorAttrib->GetStart() != m_nErrorStart || pErrorAttrib->GetEnd() != m_nErrorEnd)
1666 : {
1667 0 : TextAttrib* pNewError = pErrorAttrib->GetAttr().Clone();
1668 0 : pTextEngine->RemoveAttrib( 0, *pErrorAttr );
1669 0 : SetAttrib( *pNewError, 0, m_nErrorStart, m_nErrorEnd );
1670 0 : delete pNewError;
1671 : }
1672 : }
1673 : }
1674 : //this is not a modification anymore
1675 0 : if(nAction != ACTION_SELECTFIELD && !m_bIsUndoEditMode)
1676 0 : CallModifyLink();
1677 : }
1678 : else
1679 0 : bChange = false;
1680 : }
1681 0 : long nRet = bChange ? 1 : MultiLineEdit::PreNotify(rNEvt);
1682 0 : return nRet;
1683 : }
1684 :
1685 : //-----------------------------------------------------------------------
1686 0 : bool SentenceEditWindow_Impl::MarkNextError( bool bIgnoreCurrentError )
1687 : {
1688 0 : if (bIgnoreCurrentError)
1689 0 : m_aIgnoreErrorsAt.insert( m_nErrorStart );
1690 0 : ExtTextEngine* pTextEngine = GetTextEngine();
1691 0 : sal_uInt16 nTextLen = pTextEngine->GetTextLen(0);
1692 0 : if(m_nErrorEnd >= nTextLen - 1)
1693 0 : return false;
1694 : //if it's not already modified the modified flag has to be reset at the and of the marking
1695 0 : bool bModified = IsModified();
1696 0 : bool bRet = false;
1697 0 : const sal_uInt16 nOldErrorStart = m_nErrorStart;
1698 0 : const sal_uInt16 nOldErrorEnd = m_nErrorEnd;
1699 :
1700 : //create a cursor behind the end of the last error
1701 : //- or at 0 at the start of the sentence
1702 0 : TextPaM aCursor(0, m_nErrorEnd ? m_nErrorEnd + 1 : 0);
1703 : //search for SpellErrorAttrib
1704 :
1705 0 : const TextCharAttrib* pNextError = 0;
1706 : //iterate over the text and search for the next error that maybe has
1707 : //to be replace by a ChangeAllList replacement
1708 0 : bool bGrammarError = false;
1709 0 : while(aCursor.GetIndex() < nTextLen)
1710 : {
1711 0 : while(aCursor.GetIndex() < nTextLen &&
1712 0 : 0 == (pNextError = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR)))
1713 : {
1714 0 : ++aCursor.GetIndex();
1715 : }
1716 : // maybe the error found here is already in the ChangeAllList and has to be replaced
1717 :
1718 0 : Reference<XDictionary> xChangeAll( SvxGetChangeAllList(), UNO_QUERY );
1719 0 : Reference<XDictionaryEntry> xEntry;
1720 :
1721 0 : const SpellErrorDescription* pSpellErrorDescription = 0;
1722 0 : if(pNextError)
1723 : {
1724 0 : pSpellErrorDescription = &static_cast<const SpellErrorAttrib&>(pNextError->GetAttr()).GetErrorDescription();
1725 0 : bGrammarError = pSpellErrorDescription->bIsGrammarError;
1726 : }
1727 0 : if(xChangeAll->getCount() && pSpellErrorDescription &&
1728 0 : (xEntry = xChangeAll->getEntry( pSpellErrorDescription->sErrorText )).is())
1729 : {
1730 0 : m_nErrorStart = pNextError->GetStart();
1731 0 : m_nErrorEnd = pNextError->GetEnd();
1732 :
1733 0 : String sReplacement(getDotReplacementString(GetErrorText(), xEntry->getReplacementText()));
1734 :
1735 0 : ChangeMarkedWord(sReplacement, LanguageTag( pSpellErrorDescription->aLocale ).getLanguageType());
1736 :
1737 0 : aCursor.GetIndex() = aCursor.GetIndex() + (sal_uInt16)(xEntry->getReplacementText().getLength());
1738 : }
1739 : else
1740 : break;
1741 0 : }
1742 :
1743 : //if an attrib has been found search for the end of the error string
1744 0 : if(aCursor.GetIndex() < nTextLen)
1745 : {
1746 0 : m_nErrorStart = aCursor.GetIndex();
1747 0 : m_nErrorEnd = pNextError->GetEnd();
1748 0 : MoveErrorMarkTo(m_nErrorStart, m_nErrorEnd, bGrammarError);
1749 0 : bRet = true;
1750 : //add an undo action
1751 : SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
1752 0 : SPELLUNDO_CHANGE_NEXTERROR, GetSpellDialog()->aDialogUndoLink);
1753 0 : pAction->SetErrorMove(m_nErrorStart, m_nErrorEnd, nOldErrorStart, nOldErrorEnd);
1754 : const SpellErrorAttrib* pOldAttrib = static_cast<const SpellErrorAttrib*>(
1755 0 : pTextEngine->FindAttrib( TextPaM(0, nOldErrorStart), TEXTATTR_SPELL_ERROR ));
1756 0 : pAction->SetErrorLanguageSelected(pOldAttrib && pOldAttrib->GetErrorDescription().aSuggestions.getLength() &&
1757 0 : LanguageTag( pOldAttrib->GetErrorDescription().aLocale).getLanguageType() ==
1758 0 : GetSpellDialog()->aLanguageLB.GetSelectLanguage());
1759 0 : AddUndoAction(pAction);
1760 : }
1761 : else
1762 0 : m_nErrorStart = m_nErrorEnd = nTextLen;
1763 0 : if( !bModified )
1764 0 : ClearModifyFlag();
1765 0 : SpellDialog* pSpellDialog = GetSpellDialog();
1766 0 : pSpellDialog->aIgnorePB.Enable(bRet);
1767 0 : pSpellDialog->aIgnoreAllPB.Enable(bRet);
1768 0 : pSpellDialog->aAutoCorrPB.Enable(bRet);
1769 0 : pSpellDialog->aAddToDictMB.Enable(bRet);
1770 0 : pSpellDialog->aAddToDictPB.Enable(bRet);
1771 0 : return bRet;
1772 : }
1773 :
1774 : //-----------------------------------------------------------------------
1775 0 : void SentenceEditWindow_Impl::MoveErrorMarkTo(sal_uInt16 nStart, sal_uInt16 nEnd, bool bGrammarError)
1776 : {
1777 0 : TextEngine* pTextEngine = GetTextEngine();
1778 0 : pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTCOLOR, sal_True );
1779 0 : pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTWEIGHT, sal_True );
1780 0 : pTextEngine->SetAttrib( TextAttribFontWeight(WEIGHT_BOLD), 0, nStart, nEnd );
1781 0 : pTextEngine->SetAttrib( TextAttribFontColor(bGrammarError ? COL_LIGHTBLUE : COL_LIGHTRED), 0, nStart, nEnd );
1782 0 : m_nErrorStart = nStart;
1783 0 : m_nErrorEnd = nEnd;
1784 0 : }
1785 :
1786 : //-----------------------------------------------------------------------
1787 0 : void SentenceEditWindow_Impl::ChangeMarkedWord(const String& rNewWord, LanguageType eLanguage)
1788 : {
1789 : //calculate length changes
1790 0 : long nDiffLen = rNewWord.Len() - m_nErrorEnd + m_nErrorStart;
1791 0 : TextSelection aSel(TextPaM(0, m_nErrorStart), TextPaM(0, m_nErrorEnd));
1792 : //Remove spell errror attribute
1793 0 : ExtTextEngine* pTextEngine = GetTextEngine();
1794 0 : pTextEngine->UndoActionStart();
1795 0 : const TextCharAttrib* pErrorAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_ERROR );
1796 : DBG_ASSERT(pErrorAttrib, "no error attribute found");
1797 0 : const SpellErrorDescription* pSpellErrorDescription = 0;
1798 0 : if(pErrorAttrib)
1799 : {
1800 0 : pTextEngine->RemoveAttrib(0, *pErrorAttrib);
1801 0 : pSpellErrorDescription = &static_cast<const SpellErrorAttrib&>(pErrorAttrib->GetAttr()).GetErrorDescription();
1802 : }
1803 0 : const TextCharAttrib* pBackAttrib = pTextEngine->FindCharAttrib( TextPaM(0, m_nErrorStart), TEXTATTR_SPELL_BACKGROUND );
1804 0 : pTextEngine->ReplaceText( aSel, rNewWord );
1805 :
1806 0 : if(!m_nErrorStart)
1807 : {
1808 : //attributes following an error at the start of the text are not moved but expanded from the
1809 : //text engine - this is done to keep full-paragraph-attributes
1810 : //in the current case that handling is not desired
1811 : const TextCharAttrib* pLangAttrib =
1812 : pTextEngine->FindCharAttrib(
1813 0 : TextPaM(0, m_nErrorEnd), TEXTATTR_SPELL_LANGUAGE );
1814 0 : sal_uInt16 nTextLen = pTextEngine->GetTextLen( 0 );
1815 0 : if(pLangAttrib && !pLangAttrib->GetStart() && pLangAttrib->GetEnd() ==
1816 : nTextLen)
1817 : {
1818 0 : SpellLanguageAttrib aNewLangAttrib( static_cast<const SpellLanguageAttrib&>(pLangAttrib->GetAttr()).GetLanguage());
1819 0 : pTextEngine->RemoveAttrib(0, *pLangAttrib);
1820 0 : pTextEngine->SetAttrib( aNewLangAttrib, 0, (sal_uInt16)(m_nErrorEnd + nDiffLen) , nTextLen );
1821 : }
1822 : }
1823 : // undo expanded attributes!
1824 0 : if( pBackAttrib && pBackAttrib->GetStart() < m_nErrorStart && pBackAttrib->GetEnd() == m_nErrorEnd + nDiffLen)
1825 : {
1826 0 : TextAttrib* pNewBackground = pBackAttrib->GetAttr().Clone();
1827 0 : sal_uInt16 nStart = pBackAttrib->GetStart();
1828 0 : pTextEngine->RemoveAttrib(0, *pBackAttrib);
1829 0 : pTextEngine->SetAttrib(*pNewBackground, 0, nStart, m_nErrorStart);
1830 0 : delete pNewBackground;
1831 : }
1832 0 : pTextEngine->SetModified(sal_True);
1833 :
1834 : //adjust end position
1835 0 : long nEndTemp = m_nErrorEnd;
1836 0 : nEndTemp += nDiffLen;
1837 0 : m_nErrorEnd = (sal_uInt16)nEndTemp;
1838 :
1839 : SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
1840 0 : SPELLUNDO_MOVE_ERROREND, GetSpellDialog()->aDialogUndoLink);
1841 0 : pAction->SetOffset(nDiffLen);
1842 0 : AddUndoAction(pAction);
1843 0 : if(pSpellErrorDescription)
1844 0 : SetAttrib( SpellErrorAttrib(*pSpellErrorDescription), 0, m_nErrorStart, m_nErrorEnd );
1845 0 : SetAttrib( SpellLanguageAttrib(eLanguage), 0, m_nErrorStart, m_nErrorEnd );
1846 0 : pTextEngine->UndoActionEnd();
1847 0 : }
1848 :
1849 : //-------------------------------------------------
1850 0 : String SentenceEditWindow_Impl::GetErrorText() const
1851 : {
1852 0 : return GetTextEngine()->GetText(TextSelection(TextPaM(0, m_nErrorStart), TextPaM(0, m_nErrorEnd) ));
1853 : }
1854 :
1855 : //-----------------------------------------------------------------------
1856 0 : const SpellErrorDescription* SentenceEditWindow_Impl::GetAlternatives()
1857 : {
1858 0 : TextPaM aCursor(0, m_nErrorStart);
1859 : const SpellErrorAttrib* pAttrib = static_cast<const SpellErrorAttrib*>(
1860 0 : GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR));
1861 0 : return pAttrib ? &pAttrib->GetErrorDescription() : 0;
1862 : }
1863 :
1864 : //-----------------------------------------------------------------------
1865 0 : void SentenceEditWindow_Impl::RestoreCurrentError()
1866 : {
1867 0 : TextPaM aCursor(0, m_nErrorStart);
1868 : const SpellErrorAttrib* pAttrib = static_cast<const SpellErrorAttrib*>(
1869 0 : GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR));
1870 0 : if( pAttrib )
1871 : {
1872 0 : const SpellErrorDescription& rDesc = pAttrib->GetErrorDescription();
1873 0 : if( !rDesc.sErrorText.equals( GetErrorText() ) )
1874 0 : ChangeMarkedWord(rDesc.sErrorText, LanguageTag( rDesc.aLocale ).getLanguageType());
1875 : }
1876 0 : }
1877 :
1878 : //-----------------------------------------------------------------------
1879 0 : void SentenceEditWindow_Impl::SetAlternatives( Reference< XSpellAlternatives> xAlt )
1880 : {
1881 0 : TextPaM aCursor(0, m_nErrorStart);
1882 : DBG_ASSERT(static_cast<const SpellErrorAttrib*>(
1883 : GetTextEngine()->FindAttrib( aCursor, TEXTATTR_SPELL_ERROR)), "no error set?");
1884 :
1885 0 : ::rtl::OUString aWord;
1886 0 : lang::Locale aLocale;
1887 0 : uno::Sequence< ::rtl::OUString > aAlts;
1888 0 : ::rtl::OUString sServiceName;
1889 0 : if (xAlt.is())
1890 : {
1891 0 : aWord = xAlt->getWord();
1892 0 : aLocale = xAlt->getLocale();
1893 0 : aAlts = xAlt->getAlternatives();
1894 0 : uno::Reference< container::XNamed > xNamed( xAlt, uno::UNO_QUERY );
1895 0 : if (xNamed.is())
1896 0 : sServiceName = xNamed->getName();
1897 : }
1898 0 : SpellErrorDescription aDesc( false, aWord, aLocale, aAlts, 0, sServiceName);
1899 0 : GetTextEngine()->SetAttrib( SpellErrorAttrib(aDesc), 0, m_nErrorStart, m_nErrorEnd );
1900 0 : }
1901 :
1902 : //-----------------------------------------------------------------------
1903 0 : void SentenceEditWindow_Impl::SetAttrib( const TextAttrib& rAttr, sal_uLong nPara, sal_uInt16 nStart, sal_uInt16 nEnd )
1904 : {
1905 0 : GetTextEngine()->SetAttrib(rAttr, nPara, nStart, nEnd);
1906 0 : }
1907 :
1908 : //-----------------------------------------------------------------------
1909 0 : void SentenceEditWindow_Impl::SetText( const String& rStr )
1910 : {
1911 0 : m_nErrorStart = m_nErrorEnd = 0;
1912 0 : GetTextEngine()->SetText(rStr);
1913 0 : }
1914 :
1915 : //-----------------------------------------------------------------------
1916 : struct LanguagePosition_Impl
1917 : {
1918 : sal_uInt16 nPosition;
1919 : LanguageType eLanguage;
1920 :
1921 0 : LanguagePosition_Impl(sal_uInt16 nPos, LanguageType eLang) :
1922 : nPosition(nPos),
1923 0 : eLanguage(eLang)
1924 0 : {}
1925 : };
1926 : typedef std::vector<LanguagePosition_Impl> LanguagePositions_Impl;
1927 :
1928 0 : static void lcl_InsertBreakPosition_Impl(
1929 : LanguagePositions_Impl& rBreakPositions, sal_uInt16 nInsert, LanguageType eLanguage)
1930 : {
1931 0 : LanguagePositions_Impl::iterator aStart = rBreakPositions.begin();
1932 0 : while(aStart != rBreakPositions.end())
1933 : {
1934 0 : if(aStart->nPosition == nInsert)
1935 : {
1936 : //the language of following starts has to overwrite
1937 : //the one of previous ends
1938 0 : aStart->eLanguage = eLanguage;
1939 : return;
1940 : }
1941 0 : else if(aStart->nPosition > nInsert)
1942 : {
1943 :
1944 0 : rBreakPositions.insert(aStart, LanguagePosition_Impl(nInsert, eLanguage));
1945 : return;
1946 : }
1947 : else
1948 0 : ++aStart;
1949 : }
1950 0 : rBreakPositions.push_back(LanguagePosition_Impl(nInsert, eLanguage));
1951 : }
1952 : /*-------------------------------------------------------------------------
1953 : Returns the text in spell portions. Each portion contains text with an
1954 : equal language and attribute. The spell alternatives are empty.
1955 : -----------------------------------------------------------------------*/
1956 0 : svx::SpellPortions SentenceEditWindow_Impl::CreateSpellPortions( bool bSetIgnoreFlag ) const
1957 : {
1958 0 : svx::SpellPortions aRet;
1959 0 : ExtTextEngine* pTextEngine = GetTextEngine();
1960 0 : const sal_uInt16 nTextLen = pTextEngine->GetTextLen(0);
1961 0 : if(nTextLen)
1962 : {
1963 0 : TextPaM aCursor(0, 0);
1964 0 : LanguagePositions_Impl aBreakPositions;
1965 0 : const TextCharAttrib* pLastLang = 0;
1966 0 : const TextCharAttrib* pLastError = 0;
1967 0 : LanguageType eLang = LANGUAGE_DONTKNOW;
1968 0 : const TextCharAttrib* pError = 0;
1969 0 : while(aCursor.GetIndex() < nTextLen)
1970 : {
1971 0 : const TextCharAttrib* pLang = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_LANGUAGE);
1972 0 : if(pLang && pLang != pLastLang)
1973 : {
1974 0 : eLang = static_cast<const SpellLanguageAttrib&>(pLang->GetAttr()).GetLanguage();
1975 0 : lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->GetStart(), eLang);
1976 0 : lcl_InsertBreakPosition_Impl(aBreakPositions, pLang->GetEnd(), eLang);
1977 0 : pLastLang = pLang;
1978 : }
1979 0 : pError = pTextEngine->FindCharAttrib( aCursor, TEXTATTR_SPELL_ERROR);
1980 0 : if(pError && pLastError != pError)
1981 : {
1982 0 : lcl_InsertBreakPosition_Impl(aBreakPositions, pError->GetStart(), eLang);
1983 0 : lcl_InsertBreakPosition_Impl(aBreakPositions, pError->GetEnd(), eLang);
1984 0 : pLastError = pError;
1985 :
1986 : }
1987 0 : aCursor.GetIndex()++;
1988 : }
1989 :
1990 0 : if(nTextLen && aBreakPositions.empty())
1991 : {
1992 : //if all content has been overwritten the attributes may have been removed, too
1993 0 : svx::SpellPortion aPortion1;
1994 0 : aPortion1.eLanguage = GetSpellDialog()->GetSelectedLang_Impl();
1995 : aPortion1.sText = pTextEngine->GetText(
1996 0 : TextSelection(TextPaM(0, 0), TextPaM(0, nTextLen)));
1997 :
1998 0 : aRet.push_back(aPortion1);
1999 :
2000 : }
2001 0 : else if(!aBreakPositions.empty())
2002 : {
2003 0 : LanguagePositions_Impl::iterator aStart = aBreakPositions.begin();
2004 : //start should always be Null
2005 0 : eLang = aStart->eLanguage;
2006 0 : sal_uInt16 nStart = aStart->nPosition;
2007 : DBG_ASSERT(!nStart, "invalid start position - language attribute missing?");
2008 0 : ++aStart;
2009 :
2010 0 : while(aStart != aBreakPositions.end())
2011 : {
2012 0 : svx::SpellPortion aPortion1;
2013 0 : aPortion1.eLanguage = eLang;
2014 : aPortion1.sText = pTextEngine->GetText(
2015 0 : TextSelection(TextPaM(0, nStart), TextPaM(0, aStart->nPosition)));
2016 0 : bool bIsIgnoreError = m_aIgnoreErrorsAt.find( nStart ) != m_aIgnoreErrorsAt.end();
2017 0 : if( bSetIgnoreFlag && bIsIgnoreError )
2018 : {
2019 0 : aPortion1.bIgnoreThisError = true;
2020 : }
2021 0 : aRet.push_back(aPortion1);
2022 0 : nStart = aStart->nPosition;
2023 0 : eLang = aStart->eLanguage;
2024 0 : ++aStart;
2025 0 : }
2026 : }
2027 :
2028 : // quick partly fix of #i71318. Correct fix needs to patch the TextEngine itself...
2029 : // this one will only prevent text from disappearing. It may to not have the
2030 : // correct language and will probably not spell checked...
2031 0 : sal_uLong nPara = pTextEngine->GetParagraphCount();
2032 0 : if (nPara > 1)
2033 : {
2034 0 : String aLeftOverText;
2035 0 : for (sal_uLong i = 1; i < nPara; ++i)
2036 : {
2037 0 : aLeftOverText.AppendAscii( "\x0a" ); // the manual line break...
2038 0 : aLeftOverText += pTextEngine->GetText(i);
2039 : }
2040 0 : if (pError)
2041 : { // we need to add a new portion containing the left-over text
2042 0 : svx::SpellPortion aPortion2;
2043 0 : aPortion2.eLanguage = eLang;
2044 0 : aPortion2.sText = aLeftOverText;
2045 0 : aRet.push_back( aPortion2 );
2046 : }
2047 : else
2048 : { // we just need to append the left-over text to the last portion (which had no errors)
2049 0 : aRet[ aRet.size() - 1 ].sText += aLeftOverText;
2050 0 : }
2051 0 : }
2052 : }
2053 0 : return aRet;
2054 : }
2055 :
2056 : //-----------------------------------------------------------------------
2057 0 : void SentenceEditWindow_Impl::Undo()
2058 : {
2059 0 : ::svl::IUndoManager& rUndoMgr = GetTextEngine()->GetUndoManager();
2060 : DBG_ASSERT(GetUndoActionCount(), "no undo actions available" );
2061 0 : if(!GetUndoActionCount())
2062 0 : return;
2063 0 : bool bSaveUndoEdit = IsUndoEditMode();
2064 : sal_uInt16 nId;
2065 : //if the undo edit mode is active then undo all changes until the UNDO_EDIT_MODE action has been found
2066 0 : do
2067 : {
2068 0 : nId = rUndoMgr.GetUndoActionId();
2069 0 : rUndoMgr.Undo();
2070 0 : }while(bSaveUndoEdit && SPELLUNDO_UNDO_EDIT_MODE != nId && GetUndoActionCount());
2071 :
2072 0 : if(bSaveUndoEdit || SPELLUNDO_CHANGE_GROUP == nId)
2073 0 : GetSpellDialog()->UpdateBoxes_Impl();
2074 : }
2075 :
2076 : //-----------------------------------------------------------------------
2077 0 : void SentenceEditWindow_Impl::ResetUndo()
2078 : {
2079 0 : GetTextEngine()->ResetUndo();
2080 0 : }
2081 :
2082 : //-----------------------------------------------------------------------
2083 0 : void SentenceEditWindow_Impl::AddUndoAction( SfxUndoAction *pAction, sal_Bool bTryMerg )
2084 : {
2085 0 : ::svl::IUndoManager& rUndoMgr = GetTextEngine()->GetUndoManager();
2086 0 : rUndoMgr.AddUndoAction(pAction, bTryMerg);
2087 0 : GetSpellDialog()->aUndoPB.Enable();
2088 0 : }
2089 :
2090 : //-----------------------------------------------------------------------
2091 0 : sal_uInt16 SentenceEditWindow_Impl::GetUndoActionCount()
2092 : {
2093 0 : return GetTextEngine()->GetUndoManager().GetUndoActionCount();
2094 : }
2095 :
2096 : //-----------------------------------------------------------------------
2097 0 : void SentenceEditWindow_Impl::UndoActionStart( sal_uInt16 nId )
2098 : {
2099 0 : GetTextEngine()->UndoActionStart(nId);
2100 0 : }
2101 :
2102 : //-----------------------------------------------------------------------
2103 0 : void SentenceEditWindow_Impl::UndoActionEnd()
2104 : {
2105 0 : GetTextEngine()->UndoActionEnd();
2106 0 : }
2107 :
2108 : //-----------------------------------------------------------------------
2109 0 : void SentenceEditWindow_Impl::MoveErrorEnd(long nOffset)
2110 : {
2111 0 : if(nOffset > 0)
2112 0 : m_nErrorEnd = m_nErrorEnd - (sal_uInt16)nOffset;
2113 : else
2114 0 : m_nErrorEnd = m_nErrorEnd -(sal_uInt16)- nOffset;
2115 0 : }
2116 :
2117 : //-----------------------------------------------------------------------
2118 0 : void SentenceEditWindow_Impl::SetUndoEditMode(bool bSet)
2119 : {
2120 : DBG_ASSERT(!bSet || m_bIsUndoEditMode != bSet, "SetUndoEditMode with equal values?");
2121 0 : m_bIsUndoEditMode = bSet;
2122 : //disable all buttons except the Change
2123 0 : SpellDialog* pSpellDialog = GetSpellDialog();
2124 : Control* aControls[] =
2125 : {
2126 : &pSpellDialog->aChangeAllPB,
2127 : &pSpellDialog->aExplainFT,
2128 : &pSpellDialog->aIgnoreAllPB,
2129 : &pSpellDialog->aIgnoreRulePB,
2130 : &pSpellDialog->aIgnorePB,
2131 : &pSpellDialog->aSuggestionLB,
2132 : &pSpellDialog->aSuggestionFT,
2133 : &pSpellDialog->aLanguageFT,
2134 : &pSpellDialog->aLanguageLB,
2135 : &pSpellDialog->aAddToDictMB,
2136 : &pSpellDialog->aAddToDictPB,
2137 : &pSpellDialog->aAutoCorrPB,
2138 : 0
2139 0 : };
2140 0 : sal_Int32 nIdx = 0;
2141 0 : do
2142 : {
2143 0 : aControls[nIdx]->Enable(sal_False);
2144 : }
2145 0 : while(aControls[++nIdx]);
2146 :
2147 : //remove error marks
2148 0 : TextEngine* pTextEngine = GetTextEngine();
2149 0 : pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTCOLOR, sal_True );
2150 0 : pTextEngine->RemoveAttribs( 0, (sal_uInt16)TEXTATTR_FONTWEIGHT, sal_True );
2151 :
2152 : //put the appropriate action on the Undo-stack
2153 : SpellUndoAction_Impl* pAction = new SpellUndoAction_Impl(
2154 0 : SPELLUNDO_UNDO_EDIT_MODE, GetSpellDialog()->aDialogUndoLink);
2155 0 : AddUndoAction(pAction);
2156 0 : pSpellDialog->aChangePB.Enable();
2157 0 : }
2158 :
2159 0 : IMPL_LINK( SpellDialog, HandleHyperlink, FixedHyperlink*, pHyperlink )
2160 : {
2161 0 : rtl::OUString sURL=pHyperlink->GetURL();
2162 0 : rtl::OUString sTitle=GetText();
2163 :
2164 0 : if ( sURL.isEmpty() ) // Nothing to do, when the URL is empty
2165 0 : return 1;
2166 : try
2167 : {
2168 : uno::Reference< com::sun::star::system::XSystemShellExecute > xSystemShellExecute(
2169 0 : com::sun::star::system::SystemShellExecute::create(::comphelper::getProcessComponentContext()) );
2170 0 : xSystemShellExecute->execute( sURL, rtl::OUString(), com::sun::star::system::SystemShellExecuteFlags::URIS_ONLY );
2171 : }
2172 0 : catch ( uno::Exception& )
2173 : {
2174 0 : uno::Any exc( ::cppu::getCaughtException() );
2175 0 : rtl::OUString msg( ::comphelper::anyToString( exc ) );
2176 0 : const SolarMutexGuard guard;
2177 0 : ErrorBox aErrorBox( NULL, WB_OK, msg );
2178 0 : aErrorBox.SetText( sTitle );
2179 0 : aErrorBox.Execute();
2180 : }
2181 :
2182 0 : return 1;
2183 3 : }
2184 :
2185 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|