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