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 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 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 95 ScConversionEngineBase::~ScConversionEngineBase() 96 { 97 } 98 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 262 void ScConversionEngineBase::RestoreCursorPos() 263 { 264 const ScAddress& rPos = maSelState.GetCellCursor(); 265 mrViewData.GetViewShell()->SetCursor( rPos.Col(), rPos.Row() ); 266 } 267 268 bool ScConversionEngineBase::ShowTableWrapDialog() 269 { 270 // default: no dialog, always restart at top 271 return true; 272 } 273 274 void ScConversionEngineBase::ShowFinishDialog() 275 { 276 // default: no dialog 277 } 278 279 // private -------------------------------------------------------------------- 280 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 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 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 339 sal_Bool ScSpellingEngine::SpellNextDocument() 340 { 341 return FindNextConversionCell(); 342 } 343 344 bool ScSpellingEngine::NeedsConversion() 345 { 346 return HasSpellErrors() != EE_SPELL_OK; 347 } 348 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 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 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 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 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 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 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 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 443 sal_Bool ScTextConversionEngine::ConvertNextDocument() 444 { 445 return FindNextConversionCell(); 446 } 447 448 bool ScTextConversionEngine::NeedsConversion() 449 { 450 return HasConvertibleTextPortion( maConvParam.GetSourceLang() ); 451 } 452 453 // ============================================================================ 454 455