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