xref: /trunk/main/sc/source/ui/view/spelleng.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 #include "spelleng.hxx"
31 #include <com/sun/star/i18n/TextConversionOption.hpp>
32 
33 #include <memory>
34 
35 #include "scitems.hxx"
36 #include <editeng/eeitem.hxx>
37 
38 
39 #include <editeng/langitem.hxx>
40 #include <editeng/editobj.hxx>
41 #include <editeng/editview.hxx>
42 #include <sfx2/viewfrm.hxx>
43 #include <vcl/msgbox.hxx>
44 #include <vcl/svapp.hxx>
45 
46 #include "spelldialog.hxx"
47 #include "tabvwsh.hxx"
48 #include "docsh.hxx"
49 #include "cell.hxx"
50 #include "patattr.hxx"
51 #include "waitoff.hxx"
52 #include "globstr.hrc"
53 
54 
55 using namespace ::com::sun::star;
56 
57 // ============================================================================
58 
59 namespace {
60 
61 bool lclHasString( ScDocument& rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString )
62 {
63 	String aCompStr;
64     rDoc.GetString( nCol, nRow, nTab, aCompStr );
65     return aCompStr == rString;      //! case-insensitive?
66 }
67 
68 } // namespace
69 
70 // ----------------------------------------------------------------------------
71 
72 ScConversionEngineBase::ScConversionEngineBase(
73         SfxItemPool* pEnginePoolP, ScViewData& rViewData,
74         ScDocument* pUndoDoc, ScDocument* pRedoDoc ) :
75     ScEditEngineDefaulter( pEnginePoolP ),
76     mrViewData( rViewData ),
77     mrDocShell( *rViewData.GetDocShell() ),
78     mrDoc( *rViewData.GetDocShell()->GetDocument() ),
79     maSelState( rViewData ),
80     mpUndoDoc( pUndoDoc ),
81     mpRedoDoc( pRedoDoc ),
82     meCurrLang( LANGUAGE_ENGLISH_US ),
83     mbIsAnyModified( false ),
84     mbInitialState( true ),
85     mbWrappedInTable( false ),
86     mbFinished( false )
87 {
88     maSelState.GetCellCursor().GetVars( mnStartCol, mnStartRow, mnStartTab );
89     // start with cell A1 in cell/range/multi-selection, will seek to first selected
90     if( maSelState.GetSelectionType() == SC_SELECTTYPE_SHEET )
91     {
92         mnStartCol = 0;
93         mnStartRow = 0;
94     }
95     mnCurrCol = mnStartCol;
96     mnCurrRow = mnStartRow;
97 }
98 
99 ScConversionEngineBase::~ScConversionEngineBase()
100 {
101 }
102 
103 bool ScConversionEngineBase::FindNextConversionCell()
104 {
105     ScMarkData& rMark = mrViewData.GetMarkData();
106     ScTabViewShell* pViewShell = mrViewData.GetViewShell();
107     ScBaseCell* pCell = NULL;
108     const ScPatternAttr* pPattern = NULL;
109     const ScPatternAttr* pLastPattern = NULL;
110     ::std::auto_ptr< SfxItemSet > pEditDefaults( new SfxItemSet( GetEmptyItemSet() ) );
111 
112     if( IsModified() )
113     {
114         mbIsAnyModified = true;
115 
116         String aNewStr = GetText();
117 
118         sal_Bool bMultiTab = (rMark.GetSelectCount() > 1);
119         String aVisibleStr;
120         if( bMultiTab )
121             mrDoc.GetString( mnCurrCol, mnCurrRow, mnStartTab, aVisibleStr );
122 
123         for( SCTAB nTab = 0, nTabCount = mrDoc.GetTableCount(); nTab < nTabCount; ++nTab )
124         {
125             //  #69965# always change the cell on the visible tab,
126             //  on the other selected tabs only if they contain the same text
127 
128             if( (nTab == mnStartTab) ||
129                 (bMultiTab && rMark.GetTableSelect( nTab ) &&
130                  lclHasString( mrDoc, mnCurrCol, mnCurrRow, nTab, aVisibleStr )) )
131             {
132                 ScAddress aPos( mnCurrCol, mnCurrRow, nTab );
133                 CellType eCellType = mrDoc.GetCellType( aPos );
134                 pCell = mrDoc.GetCell( aPos );
135 
136                 if( mpUndoDoc && pCell )
137                 {
138                     ScBaseCell* pUndoCell = pCell->CloneWithoutNote( *mpUndoDoc );
139                     mpUndoDoc->PutCell( aPos, pUndoCell );
140                 }
141 
142                 if( eCellType == CELLTYPE_EDIT )
143                 {
144                     if( pCell )
145                     {
146                         ScEditCell* pEditCell = static_cast< ScEditCell* >( pCell );
147                         ::std::auto_ptr< EditTextObject > pEditObj( CreateTextObject() );
148                         pEditCell->SetData( pEditObj.get(), GetEditTextObjectPool() );
149                     }
150                 }
151                 else
152                 {
153                     mrDoc.SetString( mnCurrCol, mnCurrRow, nTab, aNewStr );
154                     pCell = mrDoc.GetCell( aPos );
155                 }
156 
157                 if( mpRedoDoc && pCell )
158                 {
159                     ScBaseCell* pRedoCell = pCell->CloneWithoutNote( *mpRedoDoc );
160                     mpRedoDoc->PutCell( aPos, pRedoCell );
161                 }
162 
163                 mrDocShell.PostPaintCell( mnCurrCol, mnCurrRow, nTab );
164             }
165         }
166     }
167     pCell = NULL;
168     SCCOL nNewCol = mnCurrCol;
169     SCROW nNewRow = mnCurrRow;
170 
171     if( mbInitialState )
172     {
173         /*  On very first call, decrement row to let GetNextSpellingCell() find
174             the first cell of current range. */
175         mbInitialState = false;
176         --nNewRow;
177     }
178 
179     bool bSheetSel = maSelState.GetSelectionType() == SC_SELECTTYPE_SHEET;
180     bool bLoop = true;
181     bool bFound = false;
182     while( bLoop && !bFound )
183     {
184         bLoop = mrDoc.GetNextSpellingCell( nNewCol, nNewRow, mnStartTab, bSheetSel, rMark );
185         if( bLoop )
186         {
187             FillFromCell( mnCurrCol, mnCurrRow, mnStartTab );
188 
189             if( mbWrappedInTable && ((nNewCol > mnStartCol) || ((nNewCol == mnStartCol) && (nNewRow >= mnStartRow))) )
190             {
191                 ShowFinishDialog();
192                 bLoop = false;
193                 mbFinished = true;
194             }
195             else if( nNewCol > MAXCOL )
196             {
197                 // no more cells in the sheet - try to restart at top of sheet
198 
199                 if( bSheetSel || ((mnStartCol == 0) && (mnStartRow == 0)) )
200                 {
201                     // conversion started at cell A1 or in selection, do not query to restart at top
202                     ShowFinishDialog();
203                     bLoop = false;
204                     mbFinished = true;
205                 }
206                 else if( ShowTableWrapDialog() )
207                 {
208                     // conversion started anywhere but in cell A1, user wants to restart
209                     nNewRow = MAXROW + 2;
210                     mbWrappedInTable = true;
211                 }
212                 else
213                 {
214                     bLoop = false;
215                     mbFinished = true;
216                 }
217             }
218             else
219             {
220                 pPattern = mrDoc.GetPattern( nNewCol, nNewRow, mnStartTab );
221                 if( pPattern && (pPattern != pLastPattern) )
222                 {
223                     pPattern->FillEditItemSet( pEditDefaults.get() );
224                     SetDefaults( *pEditDefaults );
225                     pLastPattern = pPattern;
226                 }
227 
228                 // language changed?
229                 const SfxPoolItem* pItem = mrDoc.GetAttr( nNewCol, nNewRow, mnStartTab, ATTR_FONT_LANGUAGE );
230                 if( const SvxLanguageItem* pLangItem = PTR_CAST( SvxLanguageItem, pItem ) )
231                 {
232                     LanguageType eLang = static_cast< LanguageType >( pLangItem->GetValue() );
233                     if( eLang == LANGUAGE_SYSTEM )
234                         eLang = Application::GetSettings().GetLanguage();   // never use SYSTEM for spelling
235                     if( eLang != meCurrLang )
236                     {
237                         meCurrLang = eLang;
238                         SetDefaultLanguage( eLang );
239                     }
240                 }
241 
242                 FillFromCell( nNewCol, nNewRow, mnStartTab );
243 
244                 bFound = bLoop && NeedsConversion();
245             }
246         }
247     }
248 
249     if( bFound )
250     {
251         pViewShell->AlignToCursor( nNewCol, nNewRow, SC_FOLLOW_JUMP );
252         pViewShell->SetCursor( nNewCol, nNewRow, sal_True );
253         mrViewData.GetView()->MakeEditView( this, nNewCol, nNewRow );
254         EditView* pEditView = mrViewData.GetSpellingView();
255         // maSelState.GetEditSelection() returns (0,0) if not in edit mode -> ok
256         pEditView->SetSelection( maSelState.GetEditSelection() );
257 
258         ClearModifyFlag();
259         mnCurrCol = nNewCol;
260         mnCurrRow = nNewRow;
261     }
262 
263     return bFound;
264 }
265 
266 void ScConversionEngineBase::RestoreCursorPos()
267 {
268     const ScAddress& rPos = maSelState.GetCellCursor();
269     mrViewData.GetViewShell()->SetCursor( rPos.Col(), rPos.Row() );
270 }
271 
272 bool ScConversionEngineBase::ShowTableWrapDialog()
273 {
274     // default: no dialog, always restart at top
275     return true;
276 }
277 
278 void ScConversionEngineBase::ShowFinishDialog()
279 {
280     // default: no dialog
281 }
282 
283 // private --------------------------------------------------------------------
284 
285 void ScConversionEngineBase::FillFromCell( SCCOL nCol, SCROW nRow, SCTAB nTab )
286 {
287     CellType eCellType;
288     mrDoc.GetCellType( nCol, nRow, nTab, eCellType );
289 
290     switch( eCellType )
291     {
292         case CELLTYPE_STRING:
293         {
294             String aText;
295             mrDoc.GetString( nCol, nRow, nTab, aText );
296             SetText( aText );
297         }
298         break;
299         case CELLTYPE_EDIT:
300         {
301             ScBaseCell* pCell = NULL;
302             mrDoc.GetCell( nCol, nRow, nTab, pCell );
303             if( pCell )
304             {
305                 const EditTextObject* pNewEditObj = NULL;
306                 static_cast< ScEditCell* >( pCell )->GetData( pNewEditObj );
307                 if( pNewEditObj )
308                     SetText( *pNewEditObj );
309             }
310         }
311         break;
312         default:
313             SetText( EMPTY_STRING );
314     }
315 }
316 
317 // ============================================================================
318 
319 ScSpellingEngine::ScSpellingEngine(
320         SfxItemPool* pEnginePoolP, ScViewData& rViewData,
321         ScDocument* pUndoDoc, ScDocument* pRedoDoc,
322         XSpellCheckerRef xSpeller ) :
323     ScConversionEngineBase( pEnginePoolP, rViewData, pUndoDoc, pRedoDoc )
324 {
325     SetSpeller( xSpeller );
326 }
327 
328 void ScSpellingEngine::ConvertAll( EditView& rEditView )
329 {
330     EESpellState eState = EE_SPELL_OK;
331     if( FindNextConversionCell() )
332         eState = rEditView.StartSpeller( static_cast< sal_Bool >( sal_True ) );
333 
334     DBG_ASSERT( eState != EE_SPELL_NOSPELLER, "ScSpellingEngine::Convert - no spell checker" );
335     if( eState == EE_SPELL_NOLANGUAGE )
336     {
337         Window* pParent = GetDialogParent();
338         ScWaitCursorOff aWaitOff( pParent );
339         InfoBox( pParent, ScGlobal::GetRscString( STR_NOLANGERR ) ).Execute();
340     }
341 }
342 
343 sal_Bool ScSpellingEngine::SpellNextDocument()
344 {
345     return FindNextConversionCell();
346 }
347 
348 bool ScSpellingEngine::NeedsConversion()
349 {
350     return HasSpellErrors() != EE_SPELL_OK;
351 }
352 
353 bool ScSpellingEngine::ShowTableWrapDialog()
354 {
355     Window* pParent = GetDialogParent();
356     ScWaitCursorOff aWaitOff( pParent );
357     MessBox aMsgBox( pParent, WinBits( WB_YES_NO | WB_DEF_YES ),
358         ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ),
359         ScGlobal::GetRscString( STR_SPELLING_BEGIN_TAB) );
360     return aMsgBox.Execute() == RET_YES;
361 }
362 
363 void ScSpellingEngine::ShowFinishDialog()
364 {
365     Window* pParent = GetDialogParent();
366     ScWaitCursorOff aWaitOff( pParent );
367     InfoBox( pParent, ScGlobal::GetRscString( STR_SPELLING_STOP_OK ) ).Execute();
368 }
369 
370 Window* ScSpellingEngine::GetDialogParent()
371 {
372     sal_uInt16 nWinId = ScSpellDialogChildWindow::GetChildWindowId();
373     SfxViewFrame* pViewFrm = mrViewData.GetViewShell()->GetViewFrame();
374     if( pViewFrm->HasChildWindow( nWinId ) )
375         if( SfxChildWindow* pChild = pViewFrm->GetChildWindow( nWinId ) )
376             if( Window* pWin = pChild->GetWindow() )
377                 if( pWin->IsVisible() )
378                     return pWin;
379 
380     // fall back to standard dialog parent
381     return mrDocShell.GetActiveDialogParent();
382 }
383 
384 // ============================================================================
385 
386 ScConversionParam::ScConversionParam( ScConversionType eConvType ) :
387     meConvType( eConvType ),
388     meSourceLang( LANGUAGE_NONE ),
389     meTargetLang( LANGUAGE_NONE ),
390     mnOptions( 0 ),
391     mbUseTargetFont( false ),
392     mbIsInteractive( false )
393 {
394 }
395 
396 ScConversionParam::ScConversionParam( ScConversionType eConvType,
397         LanguageType eLang, sal_Int32 nOptions, bool bIsInteractive ) :
398     meConvType( eConvType ),
399     meSourceLang( eLang ),
400     meTargetLang( eLang ),
401     mnOptions( nOptions ),
402     mbUseTargetFont( false ),
403     mbIsInteractive( bIsInteractive )
404 {
405     if (LANGUAGE_KOREAN == eLang)
406         mnOptions = i18n::TextConversionOption::CHARACTER_BY_CHARACTER;
407 }
408 
409 ScConversionParam::ScConversionParam( ScConversionType eConvType,
410         LanguageType eSourceLang, LanguageType eTargetLang, const Font& rTargetFont,
411         sal_Int32 nOptions, bool bIsInteractive ) :
412     meConvType( eConvType ),
413     meSourceLang( eSourceLang ),
414     meTargetLang( eTargetLang ),
415     maTargetFont( rTargetFont ),
416     mnOptions( nOptions ),
417     mbUseTargetFont( true ),
418     mbIsInteractive( bIsInteractive )
419 {
420     if (LANGUAGE_KOREAN == meSourceLang && LANGUAGE_KOREAN == meTargetLang)
421         mnOptions = i18n::TextConversionOption::CHARACTER_BY_CHARACTER;
422 }
423 
424 // ----------------------------------------------------------------------------
425 
426 ScTextConversionEngine::ScTextConversionEngine(
427         SfxItemPool* pEnginePoolP, ScViewData& rViewData,
428         const ScConversionParam& rConvParam,
429         ScDocument* pUndoDoc, ScDocument* pRedoDoc ) :
430     ScConversionEngineBase( pEnginePoolP, rViewData, pUndoDoc, pRedoDoc ),
431     maConvParam( rConvParam )
432 {
433 }
434 
435 void ScTextConversionEngine::ConvertAll( EditView& rEditView )
436 {
437     if( FindNextConversionCell() )
438     {
439         rEditView.StartTextConversion(
440             maConvParam.GetSourceLang(), maConvParam.GetTargetLang(), maConvParam.GetTargetFont(),
441             maConvParam.GetOptions(), maConvParam.IsInteractive(), sal_True );
442         // #i34769# restore initial cursor position
443         RestoreCursorPos();
444     }
445 }
446 
447 sal_Bool ScTextConversionEngine::ConvertNextDocument()
448 {
449     return FindNextConversionCell();
450 }
451 
452 bool ScTextConversionEngine::NeedsConversion()
453 {
454     return HasConvertibleTextPortion( maConvParam.GetSourceLang() );
455 }
456 
457 // ============================================================================
458 
459