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