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 31 32 // ============================================================================ 33 #include "csvgrid.hxx" 34 35 #include <algorithm> 36 #include <svtools/colorcfg.hxx> 37 #include <svl/smplhint.hxx> 38 #include <tools/poly.hxx> 39 #include "scmod.hxx" 40 #include "asciiopt.hxx" 41 #include "impex.hxx" 42 #include "AccessibleCsvControl.hxx" 43 44 // *** edit engine *** 45 #include "scitems.hxx" 46 #include <editeng/eeitem.hxx> 47 48 49 #include <editeng/colritem.hxx> 50 #include <editeng/fhgtitem.hxx> 51 #include <editeng/fontitem.hxx> 52 #include <svl/itemset.hxx> 53 #include "editutil.hxx" 54 // *** edit engine *** 55 56 57 // ============================================================================ 58 59 struct Func_SetType 60 { 61 sal_Int32 mnType; 62 inline Func_SetType( sal_Int32 nType ) : mnType( nType ) {} 63 inline void operator()( ScCsvColState& rState ) { rState.mnType = mnType; } 64 }; 65 66 struct Func_Select 67 { 68 bool mbSelect; 69 inline Func_Select( bool bSelect ) : mbSelect( bSelect ) {} 70 inline void operator()( ScCsvColState& rState ) { rState.Select( mbSelect ); } 71 }; 72 73 74 // ============================================================================ 75 76 ScCsvGrid::ScCsvGrid( ScCsvControl& rParent ) : 77 ScCsvControl( rParent ), 78 mrColorConfig( SC_MOD()->GetColorConfig() ), 79 mpEditEngine( new ScEditEngineDefaulter( EditEngine::CreatePool(), sal_True ) ), 80 maHeaderFont( GetFont() ), 81 maColStates( 1 ), 82 maTypeNames( 1 ), 83 mnFirstImpLine( 0 ), 84 mnRecentSelCol( CSV_COLUMN_INVALID ) 85 { 86 mpEditEngine->SetRefDevice( &maBackgrDev ); 87 mpEditEngine->SetRefMapMode( MapMode( MAP_PIXEL ) ); 88 maEdEngSize = mpEditEngine->GetPaperSize(); 89 90 maPopup.SetMenuFlags( maPopup.GetMenuFlags() | MENU_FLAG_NOAUTOMNEMONICS ); 91 92 EnableRTL( false ); // #107812# RTL 93 InitColors(); 94 InitFonts(); 95 ImplClearSplits(); 96 mrColorConfig.AddListener(this); 97 } 98 99 ScCsvGrid::~ScCsvGrid() 100 { 101 mrColorConfig.RemoveListener(this); 102 } 103 104 105 // common grid handling ------------------------------------------------------- 106 107 void ScCsvGrid::UpdateLayoutData() 108 { 109 DisableRepaint(); 110 SetFont( maMonoFont ); 111 Execute( CSVCMD_SETCHARWIDTH, GetTextWidth( String( 'X' ) ) ); 112 Execute( CSVCMD_SETLINEHEIGHT, GetTextHeight() + 1 ); 113 SetFont( maHeaderFont ); 114 Execute( CSVCMD_SETHDRHEIGHT, GetTextHeight() + 1 ); 115 UpdateOffsetX(); 116 EnableRepaint(); 117 } 118 119 void ScCsvGrid::UpdateOffsetX() 120 { 121 sal_Int32 nLastLine = GetLastVisLine() + 1; 122 sal_Int32 nDigits = 2; 123 while( nLastLine /= 10 ) ++nDigits; 124 nDigits = Max( nDigits, sal_Int32( 3 ) ); 125 Execute( CSVCMD_SETHDRWIDTH, GetTextWidth( String( '0' ) ) * nDigits ); 126 } 127 128 void ScCsvGrid::ApplyLayout( const ScCsvLayoutData& rOldData ) 129 { 130 ScCsvDiff nDiff = GetLayoutData().GetDiff( rOldData ); 131 if( nDiff == CSV_DIFF_EQUAL ) return; 132 133 DisableRepaint(); 134 135 if( nDiff & CSV_DIFF_RULERCURSOR ) 136 { 137 ImplInvertCursor( rOldData.mnPosCursor ); 138 ImplInvertCursor( GetRulerCursorPos() ); 139 } 140 141 if( nDiff & CSV_DIFF_POSCOUNT ) 142 { 143 if( GetPosCount() < rOldData.mnPosCount ) 144 { 145 SelectAll( false ); 146 maSplits.RemoveRange( GetPosCount(), rOldData.mnPosCount ); 147 } 148 else 149 maSplits.Remove( rOldData.mnPosCount ); 150 maSplits.Insert( GetPosCount() ); 151 maColStates.resize( maSplits.Count() - 1 ); 152 } 153 154 if( nDiff & CSV_DIFF_LINEOFFSET ) 155 { 156 Execute( CSVCMD_UPDATECELLTEXTS ); 157 UpdateOffsetX(); 158 } 159 160 ScCsvDiff nHVDiff = nDiff & (CSV_DIFF_HORIZONTAL | CSV_DIFF_VERTICAL); 161 if( nHVDiff == CSV_DIFF_POSOFFSET ) 162 ImplDrawHorzScrolled( rOldData.mnPosOffset ); 163 else if( nHVDiff != CSV_DIFF_EQUAL ) 164 InvalidateGfx(); 165 166 EnableRepaint(); 167 168 if( nDiff & (CSV_DIFF_POSOFFSET | CSV_DIFF_LINEOFFSET) ) 169 AccSendVisibleEvent(); 170 } 171 172 void ScCsvGrid::SetFirstImportedLine( sal_Int32 nLine ) 173 { 174 ImplDrawFirstLineSep( false ); 175 mnFirstImpLine = nLine; 176 ImplDrawFirstLineSep( true ); 177 ImplDrawGridDev(); 178 Repaint(); 179 } 180 181 sal_Int32 ScCsvGrid::GetNoScrollCol( sal_Int32 nPos ) const 182 { 183 sal_Int32 nNewPos = nPos; 184 if( nNewPos != CSV_POS_INVALID ) 185 { 186 if( nNewPos < GetFirstVisPos() + CSV_SCROLL_DIST ) 187 { 188 sal_Int32 nScroll = (GetFirstVisPos() > 0) ? CSV_SCROLL_DIST : 0; 189 nNewPos = GetFirstVisPos() + nScroll; 190 } 191 else if( nNewPos > GetLastVisPos() - CSV_SCROLL_DIST - 1L ) 192 { 193 sal_Int32 nScroll = (GetFirstVisPos() < GetMaxPosOffset()) ? CSV_SCROLL_DIST : 0; 194 nNewPos = GetLastVisPos() - nScroll - 1; 195 } 196 } 197 return nNewPos; 198 } 199 200 void ScCsvGrid::InitColors() 201 { 202 maBackColor.SetColor( static_cast< sal_uInt32 >( mrColorConfig.GetColorValue( ::svtools::DOCCOLOR ).nColor ) ); 203 maGridColor.SetColor( static_cast< sal_uInt32 >( mrColorConfig.GetColorValue( ::svtools::CALCGRID ).nColor ) ); 204 maGridPBColor.SetColor( static_cast< sal_uInt32 >( mrColorConfig.GetColorValue( ::svtools::CALCPAGEBREAK ).nColor ) ); 205 maAppBackColor.SetColor( static_cast< sal_uInt32 >( mrColorConfig.GetColorValue( ::svtools::APPBACKGROUND ).nColor ) ); 206 maTextColor.SetColor( static_cast< sal_uInt32 >( mrColorConfig.GetColorValue( ::svtools::FONTCOLOR ).nColor ) ); 207 208 const StyleSettings& rSett = GetSettings().GetStyleSettings(); 209 maHeaderBackColor = rSett.GetFaceColor(); 210 maHeaderGridColor = rSett.GetDarkShadowColor(); 211 maHeaderTextColor = rSett.GetButtonTextColor(); 212 maSelectColor = rSett.GetActiveColor(); 213 214 InvalidateGfx(); 215 } 216 217 void ScCsvGrid::InitFonts() 218 { 219 maMonoFont = OutputDevice::GetDefaultFont( DEFAULTFONT_FIXED, LANGUAGE_ENGLISH_US, 0 ); 220 maMonoFont.SetSize( Size( maMonoFont.GetSize().Width(), maHeaderFont.GetSize().Height() ) ); 221 222 /* *** Set edit engine defaults *** 223 maMonoFont for Latin script, smaller default font for Asian and Complex script. */ 224 225 // get default fonts 226 SvxFontItem aLatinItem( EE_CHAR_FONTINFO ); 227 SvxFontItem aAsianItem( EE_CHAR_FONTINFO_CJK ); 228 SvxFontItem aComplexItem( EE_CHAR_FONTINFO_CTL ); 229 ::GetDefaultFonts( aLatinItem, aAsianItem, aComplexItem ); 230 231 // create item set for defaults 232 SfxItemSet aDefSet( mpEditEngine->GetEmptyItemSet() ); 233 EditEngine::SetFontInfoInItemSet( aDefSet, maMonoFont ); 234 aDefSet.Put( aAsianItem ); 235 aDefSet.Put( aComplexItem ); 236 237 // set Asian/Complex font size to height of character in Latin font 238 sal_uLong nFontHt = static_cast< sal_uLong >( maMonoFont.GetSize().Height() ); 239 aDefSet.Put( SvxFontHeightItem( nFontHt, 100, EE_CHAR_FONTHEIGHT_CJK ) ); 240 aDefSet.Put( SvxFontHeightItem( nFontHt, 100, EE_CHAR_FONTHEIGHT_CTL ) ); 241 242 // copy other items from default font 243 const SfxPoolItem& rWeightItem = aDefSet.Get( EE_CHAR_WEIGHT ); 244 aDefSet.Put( rWeightItem, EE_CHAR_WEIGHT_CJK ); 245 aDefSet.Put( rWeightItem, EE_CHAR_WEIGHT_CTL ); 246 const SfxPoolItem& rItalicItem = aDefSet.Get( EE_CHAR_ITALIC ); 247 aDefSet.Put( rItalicItem, EE_CHAR_ITALIC_CJK ); 248 aDefSet.Put( rItalicItem, EE_CHAR_ITALIC_CTL ); 249 const SfxPoolItem& rLangItem = aDefSet.Get( EE_CHAR_LANGUAGE ); 250 aDefSet.Put( rLangItem, EE_CHAR_LANGUAGE_CJK ); 251 aDefSet.Put( rLangItem, EE_CHAR_LANGUAGE_CTL ); 252 253 mpEditEngine->SetDefaults( aDefSet ); 254 InvalidateGfx(); 255 } 256 257 void ScCsvGrid::InitSizeData() 258 { 259 maWinSize = GetSizePixel(); 260 maBackgrDev.SetOutputSizePixel( maWinSize ); 261 maGridDev.SetOutputSizePixel( maWinSize ); 262 InvalidateGfx(); 263 } 264 265 266 // split handling ------------------------------------------------------------- 267 268 void ScCsvGrid::InsertSplit( sal_Int32 nPos ) 269 { 270 if( ImplInsertSplit( nPos ) ) 271 { 272 DisableRepaint(); 273 Execute( CSVCMD_EXPORTCOLUMNTYPE ); 274 Execute( CSVCMD_UPDATECELLTEXTS ); 275 sal_uInt32 nColIx = GetColumnFromPos( nPos ); 276 ImplDrawColumn( nColIx - 1 ); 277 ImplDrawColumn( nColIx ); 278 ValidateGfx(); // performance: do not redraw all columns 279 EnableRepaint(); 280 } 281 } 282 283 void ScCsvGrid::RemoveSplit( sal_Int32 nPos ) 284 { 285 if( ImplRemoveSplit( nPos ) ) 286 { 287 DisableRepaint(); 288 Execute( CSVCMD_EXPORTCOLUMNTYPE ); 289 Execute( CSVCMD_UPDATECELLTEXTS ); 290 ImplDrawColumn( GetColumnFromPos( nPos ) ); 291 ValidateGfx(); // performance: do not redraw all columns 292 EnableRepaint(); 293 } 294 } 295 296 void ScCsvGrid::MoveSplit( sal_Int32 nPos, sal_Int32 nNewPos ) 297 { 298 sal_uInt32 nColIx = GetColumnFromPos( nPos ); 299 if( nColIx != CSV_COLUMN_INVALID ) 300 { 301 DisableRepaint(); 302 if( (GetColumnPos( nColIx - 1 ) < nNewPos) && (nNewPos < GetColumnPos( nColIx + 1 )) ) 303 { 304 // move a split in the range between 2 others -> keep selection state of both columns 305 maSplits.Remove( nPos ); 306 maSplits.Insert( nNewPos ); 307 Execute( CSVCMD_UPDATECELLTEXTS ); 308 ImplDrawColumn( nColIx - 1 ); 309 ImplDrawColumn( nColIx ); 310 ValidateGfx(); // performance: do not redraw all columns 311 AccSendTableUpdateEvent( nColIx - 1, nColIx ); 312 } 313 else 314 { 315 ImplRemoveSplit( nPos ); 316 ImplInsertSplit( nNewPos ); 317 Execute( CSVCMD_EXPORTCOLUMNTYPE ); 318 Execute( CSVCMD_UPDATECELLTEXTS ); 319 } 320 EnableRepaint(); 321 } 322 } 323 324 void ScCsvGrid::RemoveAllSplits() 325 { 326 DisableRepaint(); 327 ImplClearSplits(); 328 Execute( CSVCMD_EXPORTCOLUMNTYPE ); 329 Execute( CSVCMD_UPDATECELLTEXTS ); 330 EnableRepaint(); 331 } 332 333 void ScCsvGrid::SetSplits( const ScCsvSplits& rSplits ) 334 { 335 DisableRepaint(); 336 ImplClearSplits(); 337 sal_uInt32 nCount = rSplits.Count(); 338 for( sal_uInt32 nIx = 0; nIx < nCount; ++nIx ) 339 maSplits.Insert( rSplits[ nIx ] ); 340 maColStates.clear(); 341 maColStates.resize( maSplits.Count() - 1 ); 342 Execute( CSVCMD_EXPORTCOLUMNTYPE ); 343 Execute( CSVCMD_UPDATECELLTEXTS ); 344 EnableRepaint(); 345 } 346 347 bool ScCsvGrid::ImplInsertSplit( sal_Int32 nPos ) 348 { 349 sal_uInt32 nColIx = GetColumnFromPos( nPos ); 350 bool bRet = (nColIx < GetColumnCount()) && maSplits.Insert( nPos ); 351 if( bRet ) 352 { 353 ScCsvColState aState( GetColumnType( nColIx ) ); 354 aState.Select( IsSelected( nColIx ) && IsSelected( nColIx + 1 ) ); 355 maColStates.insert( maColStates.begin() + nColIx + 1, aState ); 356 AccSendInsertColumnEvent( nColIx + 1, nColIx + 1 ); 357 AccSendTableUpdateEvent( nColIx, nColIx ); 358 } 359 return bRet; 360 } 361 362 bool ScCsvGrid::ImplRemoveSplit( sal_Int32 nPos ) 363 { 364 bool bRet = maSplits.Remove( nPos ); 365 if( bRet ) 366 { 367 sal_uInt32 nColIx = GetColumnFromPos( nPos ); 368 bool bSel = IsSelected( nColIx ) || IsSelected( nColIx + 1 ); 369 maColStates.erase( maColStates.begin() + nColIx + 1 ); 370 maColStates[ nColIx ].Select( bSel ); 371 AccSendRemoveColumnEvent( nColIx + 1, nColIx + 1 ); 372 AccSendTableUpdateEvent( nColIx, nColIx ); 373 } 374 return bRet; 375 } 376 377 void ScCsvGrid::ImplClearSplits() 378 { 379 sal_uInt32 nColumns = GetColumnCount(); 380 maSplits.Clear(); 381 maSplits.Insert( 0 ); 382 maSplits.Insert( GetPosCount() ); 383 maColStates.resize( 1 ); 384 InvalidateGfx(); 385 AccSendRemoveColumnEvent( 1, nColumns - 1 ); 386 } 387 388 // columns/column types ------------------------------------------------------- 389 390 sal_uInt32 ScCsvGrid::GetFirstVisColumn() const 391 { 392 return GetColumnFromPos( GetFirstVisPos() ); 393 } 394 395 sal_uInt32 ScCsvGrid::GetLastVisColumn() const 396 { 397 return GetColumnFromPos( Min( GetLastVisPos(), GetPosCount() ) - 1 ); 398 } 399 400 bool ScCsvGrid::IsValidColumn( sal_uInt32 nColIndex ) const 401 { 402 return nColIndex < GetColumnCount(); 403 } 404 405 bool ScCsvGrid::IsVisibleColumn( sal_uInt32 nColIndex ) const 406 { 407 return IsValidColumn( nColIndex ) && 408 (GetColumnPos( nColIndex ) < GetLastVisPos()) && 409 (GetFirstVisPos() < GetColumnPos( nColIndex + 1 )); 410 } 411 412 sal_Int32 ScCsvGrid::GetColumnX( sal_uInt32 nColIndex ) const 413 { 414 return GetX( GetColumnPos( nColIndex ) ); 415 } 416 417 sal_uInt32 ScCsvGrid::GetColumnFromX( sal_Int32 nX ) const 418 { 419 sal_Int32 nPos = (nX - GetFirstX()) / GetCharWidth() + GetFirstVisPos(); 420 return ((GetFirstVisPos() <= nPos) && (nPos <= GetLastVisPos())) ? 421 GetColumnFromPos( nPos ) : CSV_COLUMN_INVALID; 422 } 423 424 sal_uInt32 ScCsvGrid::GetColumnFromPos( sal_Int32 nPos ) const 425 { 426 return maSplits.UpperBound( nPos ); 427 } 428 429 sal_Int32 ScCsvGrid::GetColumnWidth( sal_uInt32 nColIndex ) const 430 { 431 return IsValidColumn( nColIndex ) ? (GetColumnPos( nColIndex + 1 ) - GetColumnPos( nColIndex )) : 0; 432 } 433 434 void ScCsvGrid::SetColumnStates( const ScCsvColStateVec& rStates ) 435 { 436 maColStates = rStates; 437 maColStates.resize( maSplits.Count() - 1 ); 438 Execute( CSVCMD_EXPORTCOLUMNTYPE ); 439 AccSendTableUpdateEvent( 0, GetColumnCount(), false ); 440 AccSendSelectionEvent(); 441 } 442 443 sal_Int32 ScCsvGrid::GetColumnType( sal_uInt32 nColIndex ) const 444 { 445 return IsValidColumn( nColIndex ) ? maColStates[ nColIndex ].mnType : CSV_TYPE_NOSELECTION; 446 } 447 448 void ScCsvGrid::SetColumnType( sal_uInt32 nColIndex, sal_Int32 nColType ) 449 { 450 if( IsValidColumn( nColIndex ) ) 451 { 452 maColStates[ nColIndex ].mnType = nColType; 453 AccSendTableUpdateEvent( nColIndex, nColIndex, false ); 454 } 455 } 456 457 sal_Int32 ScCsvGrid::GetSelColumnType() const 458 { 459 sal_uInt32 nColIx = GetFirstSelected(); 460 if( nColIx == CSV_COLUMN_INVALID ) 461 return CSV_TYPE_NOSELECTION; 462 463 sal_Int32 nType = GetColumnType( nColIx ); 464 while( (nColIx != CSV_COLUMN_INVALID) && (nType != CSV_TYPE_MULTI) ) 465 { 466 if( nType != GetColumnType( nColIx ) ) 467 nType = CSV_TYPE_MULTI; 468 nColIx = GetNextSelected( nColIx ); 469 } 470 return nType; 471 } 472 473 void ScCsvGrid::SetSelColumnType( sal_Int32 nType ) 474 { 475 if( (nType != CSV_TYPE_MULTI) && (nType != CSV_TYPE_NOSELECTION) ) 476 { 477 for( sal_uInt32 nColIx = GetFirstSelected(); nColIx != CSV_COLUMN_INVALID; nColIx = GetNextSelected( nColIx ) ) 478 SetColumnType( nColIx, nType ); 479 Repaint( true ); 480 Execute( CSVCMD_EXPORTCOLUMNTYPE ); 481 } 482 } 483 484 void ScCsvGrid::SetTypeNames( const StringVec& rTypeNames ) 485 { 486 DBG_ASSERT( !rTypeNames.empty(), "ScCsvGrid::SetTypeNames - vector is empty" ); 487 maTypeNames = rTypeNames; 488 Repaint( true ); 489 490 maPopup.Clear(); 491 sal_uInt32 nCount = maTypeNames.size(); 492 sal_uInt32 nIx; 493 sal_uInt16 nItemId; 494 for( nIx = 0, nItemId = 1; nIx < nCount; ++nIx, ++nItemId ) 495 maPopup.InsertItem( nItemId, maTypeNames[ nIx ] ); 496 497 ::std::for_each( maColStates.begin(), maColStates.end(), Func_SetType( CSV_TYPE_DEFAULT ) ); 498 } 499 500 const String& ScCsvGrid::GetColumnTypeName( sal_uInt32 nColIndex ) const 501 { 502 sal_uInt32 nTypeIx = static_cast< sal_uInt32 >( GetColumnType( nColIndex ) ); 503 return (nTypeIx < maTypeNames.size()) ? maTypeNames[ nTypeIx ] : EMPTY_STRING; 504 } 505 506 sal_uInt8 lcl_GetExtColumnType( sal_Int32 nIntType ) 507 { 508 static sal_uInt8 pExtTypes[] = 509 { SC_COL_STANDARD, SC_COL_TEXT, SC_COL_DMY, SC_COL_MDY, SC_COL_YMD, SC_COL_ENGLISH, SC_COL_SKIP }; 510 static sal_Int32 nExtTypeCount = sizeof( pExtTypes ) / sizeof( *pExtTypes ); 511 return pExtTypes[ ((0 <= nIntType) && (nIntType < nExtTypeCount)) ? nIntType : 0 ]; 512 } 513 514 void ScCsvGrid::FillColumnDataSep( ScAsciiOptions& rOptions ) const 515 { 516 sal_uInt32 nCount = GetColumnCount(); 517 ScCsvExpDataVec aDataVec; 518 519 for( sal_uInt32 nColIx = 0; nColIx < nCount; ++nColIx ) 520 { 521 if( GetColumnType( nColIx ) != CSV_TYPE_DEFAULT ) 522 // 1-based column index 523 aDataVec.push_back( ScCsvExpData( 524 static_cast< xub_StrLen >( nColIx + 1 ), 525 lcl_GetExtColumnType( GetColumnType( nColIx ) ) ) ); 526 } 527 rOptions.SetColumnInfo( aDataVec ); 528 } 529 530 void ScCsvGrid::FillColumnDataFix( ScAsciiOptions& rOptions ) const 531 { 532 sal_uInt32 nCount = Min( GetColumnCount(), static_cast<sal_uInt32>(MAXCOLCOUNT) ); 533 ScCsvExpDataVec aDataVec( nCount + 1 ); 534 535 for( sal_uInt32 nColIx = 0; nColIx < nCount; ++nColIx ) 536 { 537 ScCsvExpData& rData = aDataVec[ nColIx ]; 538 rData.mnIndex = static_cast< xub_StrLen >( 539 Min( static_cast< sal_Int32 >( STRING_MAXLEN ), GetColumnPos( nColIx ) ) ); 540 rData.mnType = lcl_GetExtColumnType( GetColumnType( nColIx ) ); 541 } 542 aDataVec[ nCount ].mnIndex = STRING_MAXLEN; 543 aDataVec[ nCount ].mnType = SC_COL_SKIP; 544 rOptions.SetColumnInfo( aDataVec ); 545 } 546 547 void ScCsvGrid::ScrollVertRel( ScMoveMode eDir ) 548 { 549 sal_Int32 nLine = GetFirstVisLine(); 550 switch( eDir ) 551 { 552 case MOVE_PREV: --nLine; break; 553 case MOVE_NEXT: ++nLine; break; 554 case MOVE_FIRST: nLine = 0; break; 555 case MOVE_LAST: nLine = GetMaxLineOffset(); break; 556 case MOVE_PREVPAGE: nLine -= GetVisLineCount() - 2; break; 557 case MOVE_NEXTPAGE: nLine += GetVisLineCount() - 2; break; 558 default: 559 { 560 // added to avoid warnings 561 } 562 } 563 Execute( CSVCMD_SETLINEOFFSET, nLine ); 564 } 565 566 void ScCsvGrid::ExecutePopup( const Point& rPos ) 567 { 568 sal_uInt16 nItemId = maPopup.Execute( this, rPos ); 569 if( nItemId ) // 0 = cancelled 570 Execute( CSVCMD_SETCOLUMNTYPE, maPopup.GetItemPos( nItemId ) ); 571 } 572 573 574 // selection handling --------------------------------------------------------- 575 576 bool ScCsvGrid::IsSelected( sal_uInt32 nColIndex ) const 577 { 578 return IsValidColumn( nColIndex ) && maColStates[ nColIndex ].IsSelected(); 579 } 580 581 sal_uInt32 ScCsvGrid::GetFirstSelected() const 582 { 583 return IsSelected( 0 ) ? 0 : GetNextSelected( 0 ); 584 } 585 586 sal_uInt32 ScCsvGrid::GetNextSelected( sal_uInt32 nFromIndex ) const 587 { 588 sal_uInt32 nColCount = GetColumnCount(); 589 for( sal_uInt32 nColIx = nFromIndex + 1; nColIx < nColCount; ++nColIx ) 590 if( IsSelected( nColIx ) ) 591 return nColIx; 592 return CSV_COLUMN_INVALID; 593 } 594 595 void ScCsvGrid::Select( sal_uInt32 nColIndex, bool bSelect ) 596 { 597 if( IsValidColumn( nColIndex ) ) 598 { 599 maColStates[ nColIndex ].Select( bSelect ); 600 ImplDrawColumnSelection( nColIndex ); 601 Repaint(); 602 Execute( CSVCMD_EXPORTCOLUMNTYPE ); 603 if( bSelect ) 604 mnRecentSelCol = nColIndex; 605 AccSendSelectionEvent(); 606 } 607 } 608 609 void ScCsvGrid::ToggleSelect( sal_uInt32 nColIndex ) 610 { 611 Select( nColIndex, !IsSelected( nColIndex ) ); 612 } 613 614 void ScCsvGrid::SelectRange( sal_uInt32 nColIndex1, sal_uInt32 nColIndex2, bool bSelect ) 615 { 616 if( nColIndex1 == CSV_COLUMN_INVALID ) 617 Select( nColIndex2 ); 618 else if( nColIndex2 == CSV_COLUMN_INVALID ) 619 Select( nColIndex1 ); 620 else if( nColIndex1 > nColIndex2 ) 621 { 622 SelectRange( nColIndex2, nColIndex1, bSelect ); 623 if( bSelect ) 624 mnRecentSelCol = nColIndex1; 625 } 626 else if( IsValidColumn( nColIndex1 ) && IsValidColumn( nColIndex2 ) ) 627 { 628 for( sal_uInt32 nColIx = nColIndex1; nColIx <= nColIndex2; ++nColIx ) 629 { 630 maColStates[ nColIx ].Select( bSelect ); 631 ImplDrawColumnSelection( nColIx ); 632 } 633 Repaint(); 634 Execute( CSVCMD_EXPORTCOLUMNTYPE ); 635 if( bSelect ) 636 mnRecentSelCol = nColIndex1; 637 AccSendSelectionEvent(); 638 } 639 } 640 641 void ScCsvGrid::SelectAll( bool bSelect ) 642 { 643 SelectRange( 0, GetColumnCount() - 1, bSelect ); 644 } 645 646 void ScCsvGrid::MoveCursor( sal_uInt32 nColIndex ) 647 { 648 DisableRepaint(); 649 if( IsValidColumn( nColIndex ) ) 650 { 651 sal_Int32 nPosBeg = GetColumnPos( nColIndex ); 652 sal_Int32 nPosEnd = GetColumnPos( nColIndex + 1 ); 653 sal_Int32 nMinPos = Max( nPosBeg - CSV_SCROLL_DIST, sal_Int32( 0 ) ); 654 sal_Int32 nMaxPos = Min( nPosEnd - GetVisPosCount() + CSV_SCROLL_DIST + sal_Int32( 1 ), nMinPos ); 655 if( nPosBeg - CSV_SCROLL_DIST + 1 <= GetFirstVisPos() ) 656 Execute( CSVCMD_SETPOSOFFSET, nMinPos ); 657 else if( nPosEnd + CSV_SCROLL_DIST >= GetLastVisPos() ) 658 Execute( CSVCMD_SETPOSOFFSET, nMaxPos ); 659 } 660 Execute( CSVCMD_MOVEGRIDCURSOR, GetColumnPos( nColIndex ) ); 661 EnableRepaint(); 662 } 663 664 void ScCsvGrid::MoveCursorRel( ScMoveMode eDir ) 665 { 666 if( GetFocusColumn() != CSV_COLUMN_INVALID ) 667 { 668 switch( eDir ) 669 { 670 case MOVE_FIRST: 671 MoveCursor( 0 ); 672 break; 673 case MOVE_LAST: 674 MoveCursor( GetColumnCount() - 1 ); 675 break; 676 case MOVE_PREV: 677 if( GetFocusColumn() > 0 ) 678 MoveCursor( GetFocusColumn() - 1 ); 679 break; 680 case MOVE_NEXT: 681 if( GetFocusColumn() < GetColumnCount() - 1 ) 682 MoveCursor( GetFocusColumn() + 1 ); 683 break; 684 default: 685 { 686 // added to avoid warnings 687 } 688 } 689 } 690 } 691 692 void ScCsvGrid::ImplClearSelection() 693 { 694 ::std::for_each( maColStates.begin(), maColStates.end(), Func_Select( false ) ); 695 ImplDrawGridDev(); 696 } 697 698 void ScCsvGrid::DoSelectAction( sal_uInt32 nColIndex, sal_uInt16 nModifier ) 699 { 700 if( !(nModifier & KEY_MOD1) ) 701 ImplClearSelection(); 702 if( nModifier & KEY_SHIFT ) // SHIFT always expands 703 SelectRange( mnRecentSelCol, nColIndex ); 704 else if( !(nModifier & KEY_MOD1) ) // no SHIFT/CTRL always selects 1 column 705 Select( nColIndex ); 706 else if( IsTracking() ) // CTRL in tracking does not toggle 707 Select( nColIndex, mbMTSelecting ); 708 else // CTRL only toggles 709 ToggleSelect( nColIndex ); 710 Execute( CSVCMD_MOVEGRIDCURSOR, GetColumnPos( nColIndex ) ); 711 } 712 713 714 // cell contents -------------------------------------------------------------- 715 716 void ScCsvGrid::ImplSetTextLineSep( 717 sal_Int32 nLine, const String& rTextLine, 718 const String& rSepChars, sal_Unicode cTextSep, bool bMergeSep ) 719 { 720 if( nLine < GetFirstVisLine() ) return; 721 722 sal_uInt32 nLineIx = nLine - GetFirstVisLine(); 723 while( maTexts.size() <= nLineIx ) 724 maTexts.push_back( StringVec() ); 725 StringVec& rStrVec = maTexts[ nLineIx ]; 726 rStrVec.clear(); 727 728 // scan for separators 729 String aCellText; 730 const sal_Unicode* pSepChars = rSepChars.GetBuffer(); 731 const sal_Unicode* pChar = rTextLine.GetBuffer(); 732 sal_uInt32 nColIx = 0; 733 734 while( *pChar && (nColIx < sal::static_int_cast<sal_uInt32>(CSV_MAXCOLCOUNT)) ) 735 { 736 // scan for next cell text 737 bool bIsQuoted = false; 738 pChar = ScImportExport::ScanNextFieldFromString( pChar, aCellText, cTextSep, pSepChars, bMergeSep, bIsQuoted ); 739 740 // update column width 741 sal_Int32 nWidth = Max( CSV_MINCOLWIDTH, aCellText.Len() + sal_Int32( 1 ) ); 742 if( IsValidColumn( nColIx ) ) 743 { 744 // expand existing column 745 sal_Int32 nDiff = nWidth - GetColumnWidth( nColIx ); 746 if( nDiff > 0 ) 747 { 748 Execute( CSVCMD_SETPOSCOUNT, GetPosCount() + nDiff ); 749 for( sal_uInt32 nSplitIx = GetColumnCount() - 1; nSplitIx > nColIx; --nSplitIx ) 750 { 751 sal_Int32 nPos = maSplits[ nSplitIx ]; 752 maSplits.Remove( nPos ); 753 maSplits.Insert( nPos + nDiff ); 754 } 755 } 756 } 757 else 758 { 759 // append new column 760 sal_Int32 nLastPos = GetPosCount(); 761 Execute( CSVCMD_SETPOSCOUNT, nLastPos + nWidth ); 762 ImplInsertSplit( nLastPos ); 763 } 764 765 if( aCellText.Len() <= CSV_MAXSTRLEN ) 766 rStrVec.push_back( aCellText ); 767 else 768 rStrVec.push_back( aCellText.Copy( 0, CSV_MAXSTRLEN ) ); 769 ++nColIx; 770 } 771 InvalidateGfx(); 772 } 773 774 void ScCsvGrid::ImplSetTextLineFix( sal_Int32 nLine, const String& rTextLine ) 775 { 776 if( nLine < GetFirstVisLine() ) return; 777 778 sal_Int32 nChars = rTextLine.Len(); 779 if( nChars > GetPosCount() ) 780 Execute( CSVCMD_SETPOSCOUNT, nChars ); 781 782 sal_uInt32 nLineIx = nLine - GetFirstVisLine(); 783 while( maTexts.size() <= nLineIx ) 784 maTexts.push_back( StringVec() ); 785 786 StringVec& rStrVec = maTexts[ nLineIx ]; 787 rStrVec.clear(); 788 sal_uInt32 nColCount = GetColumnCount(); 789 xub_StrLen nStrLen = rTextLine.Len(); 790 xub_StrLen nStrIx = 0; 791 for( sal_uInt32 nColIx = 0; (nColIx < nColCount) && (nStrIx < nStrLen); ++nColIx ) 792 { 793 xub_StrLen nColWidth = static_cast< xub_StrLen >( GetColumnWidth( nColIx ) ); 794 rStrVec.push_back( rTextLine.Copy( nStrIx, Max( nColWidth, CSV_MAXSTRLEN ) ) ); 795 nStrIx = sal::static_int_cast<xub_StrLen>( nStrIx + nColWidth ); 796 } 797 InvalidateGfx(); 798 } 799 800 const String& ScCsvGrid::GetCellText( sal_uInt32 nColIndex, sal_Int32 nLine ) const 801 { 802 if( nLine < GetFirstVisLine() ) return EMPTY_STRING; 803 804 sal_uInt32 nLineIx = nLine - GetFirstVisLine(); 805 if( nLineIx >= maTexts.size() ) return EMPTY_STRING; 806 807 const StringVec& rStrVec = maTexts[ nLineIx ]; 808 if( nColIndex >= rStrVec.size() ) return EMPTY_STRING; 809 810 return rStrVec[ nColIndex ]; 811 } 812 813 814 // event handling ------------------------------------------------------------- 815 816 void ScCsvGrid::Resize() 817 { 818 ScCsvControl::Resize(); 819 InitSizeData(); 820 Execute( CSVCMD_UPDATECELLTEXTS ); 821 } 822 823 void ScCsvGrid::GetFocus() 824 { 825 ScCsvControl::GetFocus(); 826 Execute( CSVCMD_MOVEGRIDCURSOR, GetNoScrollCol( GetGridCursorPos() ) ); 827 Repaint(); 828 } 829 830 void ScCsvGrid::LoseFocus() 831 { 832 ScCsvControl::LoseFocus(); 833 Repaint(); 834 } 835 836 void ScCsvGrid::MouseButtonDown( const MouseEvent& rMEvt ) 837 { 838 DisableRepaint(); 839 if( !HasFocus() ) 840 GrabFocus(); 841 842 Point aPos( rMEvt.GetPosPixel() ); 843 sal_uInt32 nColIx = GetColumnFromX( aPos.X() ); 844 845 if( rMEvt.IsLeft() ) 846 { 847 if( (GetFirstX() > aPos.X()) || (aPos.X() > GetLastX()) ) // in header column 848 { 849 if( aPos.Y() <= GetHdrHeight() ) 850 SelectAll(); 851 } 852 else if( IsValidColumn( nColIx ) ) 853 { 854 DoSelectAction( nColIx, rMEvt.GetModifier() ); 855 mnMTCurrCol = nColIx; 856 mbMTSelecting = IsSelected( nColIx ); 857 StartTracking( STARTTRACK_BUTTONREPEAT ); 858 } 859 } 860 EnableRepaint(); 861 } 862 863 void ScCsvGrid::Tracking( const TrackingEvent& rTEvt ) 864 { 865 if( rTEvt.IsTrackingEnded() || rTEvt.IsTrackingRepeat() ) 866 { 867 DisableRepaint(); 868 const MouseEvent& rMEvt = rTEvt.GetMouseEvent(); 869 870 sal_Int32 nPos = (rMEvt.GetPosPixel().X() - GetFirstX()) / GetCharWidth() + GetFirstVisPos(); 871 // on mouse tracking: keep position valid 872 nPos = Max( Min( nPos, GetPosCount() - sal_Int32( 1 ) ), sal_Int32( 0 ) ); 873 Execute( CSVCMD_MAKEPOSVISIBLE, nPos ); 874 875 sal_uInt32 nColIx = GetColumnFromPos( nPos ); 876 if( mnMTCurrCol != nColIx ) 877 { 878 DoSelectAction( nColIx, rMEvt.GetModifier() ); 879 mnMTCurrCol = nColIx; 880 } 881 EnableRepaint(); 882 } 883 } 884 885 void ScCsvGrid::KeyInput( const KeyEvent& rKEvt ) 886 { 887 const KeyCode& rKCode = rKEvt.GetKeyCode(); 888 sal_uInt16 nCode = rKCode.GetCode(); 889 bool bShift = rKCode.IsShift() == sal_True; 890 bool bMod1 = rKCode.IsMod1() == sal_True; 891 892 if( !rKCode.IsMod2() ) 893 { 894 ScMoveMode eHDir = GetHorzDirection( nCode, !bMod1 ); 895 ScMoveMode eVDir = GetVertDirection( nCode, bMod1 ); 896 897 if( eHDir != MOVE_NONE ) 898 { 899 DisableRepaint(); 900 MoveCursorRel( eHDir ); 901 if( !bMod1 ) 902 ImplClearSelection(); 903 if( bShift ) 904 SelectRange( mnRecentSelCol, GetFocusColumn() ); 905 else if( !bMod1 ) 906 Select( GetFocusColumn() ); 907 EnableRepaint(); 908 } 909 else if( eVDir != MOVE_NONE ) 910 ScrollVertRel( eVDir ); 911 else if( nCode == KEY_SPACE ) 912 { 913 if( !bMod1 ) 914 ImplClearSelection(); 915 if( bShift ) 916 SelectRange( mnRecentSelCol, GetFocusColumn() ); 917 else if( bMod1 ) 918 ToggleSelect( GetFocusColumn() ); 919 else 920 Select( GetFocusColumn() ); 921 } 922 else if( !bShift && bMod1 ) 923 { 924 if( nCode == KEY_A ) 925 SelectAll(); 926 else if( (KEY_1 <= nCode) && (nCode <= KEY_9) ) 927 { 928 sal_uInt32 nType = nCode - KEY_1; 929 if( nType < maTypeNames.size() ) 930 Execute( CSVCMD_SETCOLUMNTYPE, nType ); 931 } 932 } 933 } 934 935 if( rKCode.GetGroup() != KEYGROUP_CURSOR ) 936 ScCsvControl::KeyInput( rKEvt ); 937 } 938 939 void ScCsvGrid::Command( const CommandEvent& rCEvt ) 940 { 941 switch( rCEvt.GetCommand() ) 942 { 943 case COMMAND_CONTEXTMENU: 944 { 945 if( rCEvt.IsMouseEvent() ) 946 { 947 Point aPos( rCEvt.GetMousePosPixel() ); 948 sal_uInt32 nColIx = GetColumnFromX( aPos.X() ); 949 if( IsValidColumn( nColIx ) && (GetFirstX() <= aPos.X()) && (aPos.X() <= GetLastX()) ) 950 { 951 if( !IsSelected( nColIx ) ) 952 DoSelectAction( nColIx, 0 ); // focus & select 953 ExecutePopup( aPos ); 954 } 955 } 956 else 957 { 958 sal_uInt32 nColIx = GetFocusColumn(); 959 if( !IsSelected( nColIx ) ) 960 Select( nColIx ); 961 sal_Int32 nX1 = Max( GetColumnX( nColIx ), GetFirstX() ); 962 sal_Int32 nX2 = Min( GetColumnX( nColIx + 1 ), GetWidth() ); 963 ExecutePopup( Point( (nX1 + nX2) / 2, GetHeight() / 2 ) ); 964 } 965 } 966 break; 967 case COMMAND_WHEEL: 968 { 969 Point aPoint; 970 Rectangle aRect( aPoint, maWinSize ); 971 if( aRect.IsInside( rCEvt.GetMousePosPixel() ) ) 972 { 973 const CommandWheelData* pData = rCEvt.GetWheelData(); 974 if( pData && (pData->GetMode() == COMMAND_WHEEL_SCROLL) && !pData->IsHorz() ) 975 Execute( CSVCMD_SETLINEOFFSET, GetFirstVisLine() - pData->GetNotchDelta() ); 976 } 977 } 978 break; 979 default: 980 ScCsvControl::Command( rCEvt ); 981 } 982 } 983 984 void ScCsvGrid::DataChanged( const DataChangedEvent& rDCEvt ) 985 { 986 if( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) ) 987 { 988 InitColors(); 989 InitFonts(); 990 UpdateLayoutData(); 991 Execute( CSVCMD_UPDATECELLTEXTS ); 992 } 993 ScCsvControl::DataChanged( rDCEvt ); 994 } 995 996 void ScCsvGrid::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 ) 997 { 998 InitColors(); 999 Repaint(); 1000 } 1001 1002 1003 // painting ------------------------------------------------------------------- 1004 1005 void ScCsvGrid::Paint( const Rectangle& ) 1006 { 1007 Repaint(); 1008 } 1009 1010 void ScCsvGrid::ImplRedraw() 1011 { 1012 if( IsVisible() ) 1013 { 1014 if( !IsValidGfx() ) 1015 { 1016 ValidateGfx(); 1017 ImplDrawBackgrDev(); 1018 ImplDrawGridDev(); 1019 } 1020 DrawOutDev( Point(), maWinSize, Point(), maWinSize, maGridDev ); 1021 ImplDrawTrackingRect( GetFocusColumn() ); 1022 } 1023 } 1024 1025 EditEngine* ScCsvGrid::GetEditEngine() 1026 { 1027 return mpEditEngine.get(); 1028 } 1029 1030 void ScCsvGrid::ImplSetColumnClipRegion( OutputDevice& rOutDev, sal_uInt32 nColIndex ) 1031 { 1032 rOutDev.SetClipRegion( Region( Rectangle( 1033 Max( GetColumnX( nColIndex ), GetFirstX() ) + 1, 0, 1034 Min( GetColumnX( nColIndex + 1 ), GetLastX() ), GetHeight() - 1 ) ) ); 1035 } 1036 1037 void ScCsvGrid::ImplDrawColumnHeader( OutputDevice& rOutDev, sal_uInt32 nColIndex, Color aFillColor ) 1038 { 1039 sal_Int32 nX1 = GetColumnX( nColIndex ) + 1; 1040 sal_Int32 nX2 = GetColumnX( nColIndex + 1 ); 1041 sal_Int32 nHdrHt = GetHdrHeight(); 1042 1043 rOutDev.SetLineColor(); 1044 rOutDev.SetFillColor( aFillColor ); 1045 rOutDev.DrawRect( Rectangle( nX1, 0, nX2, nHdrHt ) ); 1046 1047 rOutDev.SetFont( maHeaderFont ); 1048 rOutDev.SetTextColor( maHeaderTextColor ); 1049 rOutDev.SetTextFillColor(); 1050 rOutDev.DrawText( Point( nX1 + 1, 0 ), GetColumnTypeName( nColIndex ) ); 1051 1052 rOutDev.SetLineColor( maHeaderGridColor ); 1053 rOutDev.DrawLine( Point( nX1, nHdrHt ), Point( nX2, nHdrHt ) ); 1054 rOutDev.DrawLine( Point( nX2, 0 ), Point( nX2, nHdrHt ) ); 1055 } 1056 1057 void ScCsvGrid::ImplDrawCellText( const Point& rPos, const String& rText ) 1058 { 1059 String aPlainText( rText ); 1060 aPlainText.SearchAndReplaceAll( '\t', ' ' ); 1061 aPlainText.SearchAndReplaceAll( '\n', ' ' ); 1062 mpEditEngine->SetPaperSize( maEdEngSize ); 1063 1064 /* #i60296# If string contains mixed script types, the space character 1065 U+0020 may be drawn with a wrong width (from non-fixed-width Asian or 1066 Complex font). Now we draw every non-space portion separately. */ 1067 xub_StrLen nTokenCount = aPlainText.GetTokenCount( ' ' ); 1068 xub_StrLen nCharIx = 0; 1069 for( xub_StrLen nToken = 0; nToken < nTokenCount; ++nToken ) 1070 { 1071 xub_StrLen nBeginIx = nCharIx; 1072 String aToken = aPlainText.GetToken( 0, ' ', nCharIx ); 1073 if( aToken.Len() > 0 ) 1074 { 1075 sal_Int32 nX = rPos.X() + GetCharWidth() * nBeginIx; 1076 mpEditEngine->SetText( aToken ); 1077 mpEditEngine->Draw( &maBackgrDev, Point( nX, rPos.Y() ) ); 1078 } 1079 } 1080 1081 nCharIx = 0; 1082 while( (nCharIx = rText.Search( '\t', nCharIx )) != STRING_NOTFOUND ) 1083 { 1084 sal_Int32 nX1 = rPos.X() + GetCharWidth() * nCharIx; 1085 sal_Int32 nX2 = nX1 + GetCharWidth() - 2; 1086 sal_Int32 nY = rPos.Y() + GetLineHeight() / 2; 1087 Color aColor( maTextColor ); 1088 maBackgrDev.SetLineColor( aColor ); 1089 maBackgrDev.DrawLine( Point( nX1, nY ), Point( nX2, nY ) ); 1090 maBackgrDev.DrawLine( Point( nX2 - 2, nY - 2 ), Point( nX2, nY ) ); 1091 maBackgrDev.DrawLine( Point( nX2 - 2, nY + 2 ), Point( nX2, nY ) ); 1092 ++nCharIx; 1093 } 1094 nCharIx = 0; 1095 while( (nCharIx = rText.Search( '\n', nCharIx )) != STRING_NOTFOUND ) 1096 { 1097 sal_Int32 nX1 = rPos.X() + GetCharWidth() * nCharIx; 1098 sal_Int32 nX2 = nX1 + GetCharWidth() - 2; 1099 sal_Int32 nY = rPos.Y() + GetLineHeight() / 2; 1100 Color aColor( maTextColor ); 1101 maBackgrDev.SetLineColor( aColor ); 1102 maBackgrDev.DrawLine( Point( nX1, nY ), Point( nX2, nY ) ); 1103 maBackgrDev.DrawLine( Point( nX1 + 2, nY - 2 ), Point( nX1, nY ) ); 1104 maBackgrDev.DrawLine( Point( nX1 + 2, nY + 2 ), Point( nX1, nY ) ); 1105 maBackgrDev.DrawLine( Point( nX2, nY - 2 ), Point( nX2, nY ) ); 1106 ++nCharIx; 1107 } 1108 } 1109 1110 void ScCsvGrid::ImplDrawFirstLineSep( bool bSet ) 1111 { 1112 if( IsVisibleLine( mnFirstImpLine ) && (mnFirstImpLine != GetFirstVisLine() ) ) 1113 { 1114 sal_Int32 nY = GetY( mnFirstImpLine ); 1115 sal_Int32 nX = Min( GetColumnX( GetLastVisColumn() + 1 ), GetLastX() ); 1116 maBackgrDev.SetLineColor( bSet ? maGridPBColor : maGridColor ); 1117 maBackgrDev.DrawLine( Point( GetFirstX() + 1, nY ), Point( nX, nY ) ); 1118 } 1119 } 1120 1121 void ScCsvGrid::ImplDrawColumnBackgr( sal_uInt32 nColIndex ) 1122 { 1123 if( !IsVisibleColumn( nColIndex ) ) 1124 return; 1125 1126 ImplSetColumnClipRegion( maBackgrDev, nColIndex ); 1127 1128 // grid 1129 maBackgrDev.SetLineColor(); 1130 maBackgrDev.SetFillColor( maBackColor ); 1131 sal_Int32 nX1 = GetColumnX( nColIndex ) + 1; 1132 sal_Int32 nX2 = GetColumnX( nColIndex + 1 ); 1133 sal_Int32 nY2 = GetY( GetLastVisLine() + 1 ); 1134 sal_Int32 nHdrHt = GetHdrHeight(); 1135 Rectangle aRect( nX1, nHdrHt, nX2, nY2 ); 1136 maBackgrDev.DrawRect( aRect ); 1137 maBackgrDev.SetLineColor( maGridColor ); 1138 maBackgrDev.DrawGrid( aRect, Size( 1, GetLineHeight() ), GRID_HORZLINES ); 1139 maBackgrDev.DrawLine( Point( nX2, nHdrHt ), Point( nX2, nY2 ) ); 1140 ImplDrawFirstLineSep( true ); 1141 1142 // cell texts 1143 mpEditEngine->SetDefaultItem( SvxColorItem( maTextColor, EE_CHAR_COLOR ) ); 1144 size_t nLineCount = ::std::min( static_cast< size_t >( GetLastVisLine() - GetFirstVisLine() + 1 ), maTexts.size() ); 1145 // #i67432# cut string to avoid edit engine performance problems with very large strings 1146 sal_Int32 nFirstVisPos = ::std::max( GetColumnPos( nColIndex ), GetFirstVisPos() ); 1147 sal_Int32 nLastVisPos = ::std::min( GetColumnPos( nColIndex + 1 ), GetLastVisPos() ); 1148 xub_StrLen nStrPos = static_cast< xub_StrLen >( nFirstVisPos - GetColumnPos( nColIndex ) ); 1149 xub_StrLen nStrLen = static_cast< xub_StrLen >( nLastVisPos - nFirstVisPos + 1 ); 1150 sal_Int32 nStrX = GetX( nFirstVisPos ); 1151 for( size_t nLine = 0; nLine < nLineCount; ++nLine ) 1152 { 1153 StringVec& rStrVec = maTexts[ nLine ]; 1154 if( (nColIndex < rStrVec.size()) && (rStrVec[ nColIndex ].Len() > nStrPos) ) 1155 { 1156 String aText( rStrVec[ nColIndex ], nStrPos, nStrLen ); 1157 ImplDrawCellText( Point( nStrX, GetY( GetFirstVisLine() + nLine ) ), aText ); 1158 } 1159 } 1160 1161 // header 1162 ImplDrawColumnHeader( maBackgrDev, nColIndex, maHeaderBackColor ); 1163 1164 maBackgrDev.SetClipRegion(); 1165 } 1166 1167 void ScCsvGrid::ImplDrawRowHeaders() 1168 { 1169 maBackgrDev.SetLineColor(); 1170 maBackgrDev.SetFillColor( maAppBackColor ); 1171 Point aPoint( GetHdrX(), 0 ); 1172 Rectangle aRect( aPoint, Size( GetHdrWidth() + 1, GetHeight() ) ); 1173 maBackgrDev.DrawRect( aRect ); 1174 1175 maBackgrDev.SetFillColor( maHeaderBackColor ); 1176 aRect.Bottom() = GetY( GetLastVisLine() + 1 ); 1177 maBackgrDev.DrawRect( aRect ); 1178 1179 // line numbers 1180 maBackgrDev.SetFont( maHeaderFont ); 1181 maBackgrDev.SetTextColor( maHeaderTextColor ); 1182 maBackgrDev.SetTextFillColor(); 1183 sal_Int32 nLastLine = GetLastVisLine(); 1184 for( sal_Int32 nLine = GetFirstVisLine(); nLine <= nLastLine; ++nLine ) 1185 { 1186 String aText( String::CreateFromInt32( nLine + 1 ) ); 1187 sal_Int32 nX = GetHdrX() + (GetHdrWidth() - maBackgrDev.GetTextWidth( aText )) / 2; 1188 maBackgrDev.DrawText( Point( nX, GetY( nLine ) ), aText ); 1189 } 1190 1191 // grid 1192 maBackgrDev.SetLineColor( maHeaderGridColor ); 1193 if( IsRTL() ) 1194 { 1195 maBackgrDev.DrawLine( Point( 0, 0 ), Point( 0, GetHeight() - 1 ) ); 1196 maBackgrDev.DrawLine( aRect.TopLeft(), aRect.BottomLeft() ); 1197 } 1198 else 1199 maBackgrDev.DrawLine( aRect.TopRight(), aRect.BottomRight() ); 1200 aRect.Top() = GetHdrHeight(); 1201 maBackgrDev.DrawGrid( aRect, Size( 1, GetLineHeight() ), GRID_HORZLINES ); 1202 } 1203 1204 void ScCsvGrid::ImplDrawBackgrDev() 1205 { 1206 maBackgrDev.SetLineColor(); 1207 maBackgrDev.SetFillColor( maAppBackColor ); 1208 maBackgrDev.DrawRect( Rectangle( 1209 Point( GetFirstX() + 1, 0 ), Size( GetWidth() - GetHdrWidth(), GetHeight() ) ) ); 1210 1211 sal_uInt32 nLastCol = GetLastVisColumn(); 1212 for( sal_uInt32 nColIx = GetFirstVisColumn(); nColIx <= nLastCol; ++nColIx ) 1213 ImplDrawColumnBackgr( nColIx ); 1214 1215 ImplDrawRowHeaders(); 1216 } 1217 1218 void ScCsvGrid::ImplDrawColumnSelection( sal_uInt32 nColIndex ) 1219 { 1220 ImplInvertCursor( GetRulerCursorPos() ); 1221 ImplSetColumnClipRegion( maGridDev, nColIndex ); 1222 maGridDev.DrawOutDev( Point(), maWinSize, Point(), maWinSize, maBackgrDev ); 1223 1224 if( IsSelected( nColIndex ) ) 1225 { 1226 sal_Int32 nX1 = GetColumnX( nColIndex ) + 1; 1227 sal_Int32 nX2 = GetColumnX( nColIndex + 1 ); 1228 1229 // header 1230 Rectangle aRect( nX1, 0, nX2, GetHdrHeight() ); 1231 maGridDev.SetLineColor(); 1232 if( maHeaderBackColor.IsDark() ) 1233 // redraw with light gray background in dark mode 1234 ImplDrawColumnHeader( maGridDev, nColIndex, COL_LIGHTGRAY ); 1235 else 1236 { 1237 // use transparent active color 1238 maGridDev.SetFillColor( maSelectColor ); 1239 maGridDev.DrawTransparent( PolyPolygon( Polygon( aRect ) ), CSV_HDR_TRANSPARENCY ); 1240 } 1241 1242 // column selection 1243 aRect = Rectangle( nX1, GetHdrHeight() + 1, nX2, GetY( GetLastVisLine() + 1 ) - 1 ); 1244 ImplInvertRect( maGridDev, aRect ); 1245 } 1246 1247 maGridDev.SetClipRegion(); 1248 ImplInvertCursor( GetRulerCursorPos() ); 1249 } 1250 1251 void ScCsvGrid::ImplDrawGridDev() 1252 { 1253 maGridDev.DrawOutDev( Point(), maWinSize, Point(), maWinSize, maBackgrDev ); 1254 sal_uInt32 nLastCol = GetLastVisColumn(); 1255 for( sal_uInt32 nColIx = GetFirstVisColumn(); nColIx <= nLastCol; ++nColIx ) 1256 ImplDrawColumnSelection( nColIx ); 1257 } 1258 1259 void ScCsvGrid::ImplDrawColumn( sal_uInt32 nColIndex ) 1260 { 1261 ImplDrawColumnBackgr( nColIndex ); 1262 ImplDrawColumnSelection( nColIndex ); 1263 } 1264 1265 void ScCsvGrid::ImplDrawHorzScrolled( sal_Int32 nOldPos ) 1266 { 1267 sal_Int32 nPos = GetFirstVisPos(); 1268 if( !IsValidGfx() || (nPos == nOldPos) ) 1269 return; 1270 if( Abs( nPos - nOldPos ) > GetVisPosCount() / 2 ) 1271 { 1272 ImplDrawBackgrDev(); 1273 ImplDrawGridDev(); 1274 return; 1275 } 1276 1277 Point aSrc, aDest; 1278 sal_uInt32 nFirstColIx, nLastColIx; 1279 if( nPos < nOldPos ) 1280 { 1281 aSrc = Point( GetFirstX() + 1, 0 ); 1282 aDest = Point( GetFirstX() + GetCharWidth() * (nOldPos - nPos) + 1, 0 ); 1283 nFirstColIx = GetColumnFromPos( nPos ); 1284 nLastColIx = GetColumnFromPos( nOldPos ); 1285 } 1286 else 1287 { 1288 aSrc = Point( GetFirstX() + GetCharWidth() * (nPos - nOldPos) + 1, 0 ); 1289 aDest = Point( GetFirstX() + 1, 0 ); 1290 nFirstColIx = GetColumnFromPos( Min( nOldPos + GetVisPosCount(), GetPosCount() ) - 1 ); 1291 nLastColIx = GetColumnFromPos( Min( nPos + GetVisPosCount(), GetPosCount() ) - 1 ); 1292 } 1293 1294 ImplInvertCursor( GetRulerCursorPos() + (nPos - nOldPos) ); 1295 Rectangle aRectangle( GetFirstX(), 0, GetLastX(), GetHeight() - 1 ); 1296 Region aClipReg( aRectangle ); 1297 maBackgrDev.SetClipRegion( aClipReg ); 1298 maBackgrDev.CopyArea( aDest, aSrc, maWinSize ); 1299 maBackgrDev.SetClipRegion(); 1300 maGridDev.SetClipRegion( aClipReg ); 1301 maGridDev.CopyArea( aDest, aSrc, maWinSize ); 1302 maGridDev.SetClipRegion(); 1303 ImplInvertCursor( GetRulerCursorPos() ); 1304 1305 for( sal_uInt32 nColIx = nFirstColIx; nColIx <= nLastColIx; ++nColIx ) 1306 ImplDrawColumn( nColIx ); 1307 1308 sal_Int32 nLastX = GetX( GetPosCount() ) + 1; 1309 if( nLastX <= GetLastX() ) 1310 { 1311 Rectangle aRect( nLastX, 0, GetLastX(), GetHeight() - 1 ); 1312 maBackgrDev.SetLineColor(); 1313 maBackgrDev.SetFillColor( maAppBackColor ); 1314 maBackgrDev.DrawRect( aRect ); 1315 maGridDev.SetLineColor(); 1316 maGridDev.SetFillColor( maAppBackColor ); 1317 maGridDev.DrawRect( aRect ); 1318 } 1319 } 1320 1321 void ScCsvGrid::ImplInvertCursor( sal_Int32 nPos ) 1322 { 1323 if( IsVisibleSplitPos( nPos ) ) 1324 { 1325 sal_Int32 nX = GetX( nPos ) - 1; 1326 Rectangle aRect( Point( nX, 0 ), Size( 3, GetHdrHeight() ) ); 1327 ImplInvertRect( maGridDev, aRect ); 1328 aRect.Top() = GetHdrHeight() + 1; 1329 aRect.Bottom() = GetY( GetLastVisLine() + 1 ); 1330 ImplInvertRect( maGridDev, aRect ); 1331 } 1332 } 1333 1334 void ScCsvGrid::ImplDrawTrackingRect( sal_uInt32 nColIndex ) 1335 { 1336 if( HasFocus() && IsVisibleColumn( nColIndex ) ) 1337 { 1338 sal_Int32 nX1 = Max( GetColumnX( nColIndex ), GetFirstX() ) + 1; 1339 sal_Int32 nX2 = Min( GetColumnX( nColIndex + 1 ) - sal_Int32( 1 ), GetLastX() ); 1340 sal_Int32 nY2 = Min( GetY( GetLastVisLine() + 1 ), GetHeight() ) - 1; 1341 InvertTracking( Rectangle( nX1, 0, nX2, nY2 ), SHOWTRACK_SMALL | SHOWTRACK_WINDOW ); 1342 } 1343 } 1344 1345 1346 // accessibility ============================================================== 1347 1348 ScAccessibleCsvControl* ScCsvGrid::ImplCreateAccessible() 1349 { 1350 return new ScAccessibleCsvGrid( *this ); 1351 } 1352 1353 1354 // ============================================================================ 1355 1356