fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / dbgui / csvgrid.cxx
blob7d6172496294ac99df072d70d0acf5e7b3a51f69
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "csvgrid.hxx"
22 #include <algorithm>
23 #include <memory>
25 #include <comphelper/string.hxx>
26 #include <svtools/colorcfg.hxx>
27 #include <svl/smplhint.hxx>
28 #include <sal/macros.h>
29 #include <tools/poly.hxx>
30 #include "scmod.hxx"
31 #include "asciiopt.hxx"
32 #include "impex.hxx"
33 #include "AccessibleCsvControl.hxx"
35 // *** edit engine ***
36 #include "scitems.hxx"
37 #include <editeng/eeitem.hxx>
38 #include <vcl/settings.hxx>
40 #include <editeng/colritem.hxx>
41 #include <editeng/fhgtitem.hxx>
42 #include <editeng/fontitem.hxx>
43 #include <svl/itemset.hxx>
44 #include "editutil.hxx"
45 // *** edit engine ***
47 struct Func_SetType
49 sal_Int32 mnType;
50 inline Func_SetType( sal_Int32 nType ) : mnType( nType ) {}
51 inline void operator()( ScCsvColState& rState ) const
52 { rState.mnType = mnType; }
55 struct Func_Select
57 bool mbSelect;
58 inline Func_Select( bool bSelect ) : mbSelect( bSelect ) {}
59 inline void operator()( ScCsvColState& rState ) const
60 { rState.Select( mbSelect ); }
63 ScCsvGrid::ScCsvGrid( ScCsvControl& rParent ) :
64 ScCsvControl( rParent ),
65 mpBackgrDev( VclPtr<VirtualDevice>::Create() ),
66 mpGridDev( VclPtr<VirtualDevice>::Create() ),
67 mpColorConfig( 0 ),
68 mpEditEngine( new ScEditEngineDefaulter( EditEngine::CreatePool(), true ) ),
69 maHeaderFont( GetFont() ),
70 maColStates( 1 ),
71 maTypeNames( 1 ),
72 mnFirstImpLine( 0 ),
73 mnRecentSelCol( CSV_COLUMN_INVALID ),
74 mnMTCurrCol( SAL_MAX_UINT32 ),
75 mbMTSelecting( false )
77 mpEditEngine->SetRefDevice( mpBackgrDev.get() );
78 mpEditEngine->SetRefMapMode( MapMode( MAP_PIXEL ) );
79 maEdEngSize = mpEditEngine->GetPaperSize();
81 maPopup.SetMenuFlags( maPopup.GetMenuFlags() | MenuFlags::NoAutoMnemonics );
83 EnableRTL( false ); // RTL
84 InitFonts();
85 ImplClearSplits();
88 ScCsvGrid::~ScCsvGrid()
90 disposeOnce();
93 void ScCsvGrid::dispose()
95 OSL_ENSURE(mpColorConfig, "the object hasn't been initialized properly");
96 if (mpColorConfig)
97 mpColorConfig->RemoveListener(this);
98 mpBackgrDev.disposeAndClear();
99 mpGridDev.disposeAndClear();
100 ScCsvControl::dispose();
103 void
104 ScCsvGrid::Init()
106 OSL_PRECOND(!mpColorConfig, "the object has already been initialized");
107 mpColorConfig = &SC_MOD()->GetColorConfig();
108 InitColors();
109 mpColorConfig->AddListener(this);
112 // common grid handling -------------------------------------------------------
114 void ScCsvGrid::UpdateLayoutData()
116 DisableRepaint();
117 SetFont( maMonoFont );
118 Execute( CSVCMD_SETCHARWIDTH, GetTextWidth( OUString( 'X' ) ) );
119 Execute( CSVCMD_SETLINEHEIGHT, GetTextHeight() + 1 );
120 SetFont( maHeaderFont );
121 Execute( CSVCMD_SETHDRHEIGHT, GetTextHeight() + 1 );
122 UpdateOffsetX();
123 EnableRepaint();
126 void ScCsvGrid::UpdateOffsetX()
128 sal_Int32 nLastLine = GetLastVisLine() + 1;
129 sal_Int32 nDigits = 2;
130 while( nLastLine /= 10 ) ++nDigits;
131 nDigits = std::max( nDigits, sal_Int32( 3 ) );
132 Execute( CSVCMD_SETHDRWIDTH, GetTextWidth( OUString( '0' ) ) * nDigits );
135 void ScCsvGrid::ApplyLayout( const ScCsvLayoutData& rOldData )
137 ScCsvDiff nDiff = GetLayoutData().GetDiff( rOldData );
138 if( nDiff == CSV_DIFF_EQUAL ) return;
140 DisableRepaint();
142 if( nDiff & CSV_DIFF_RULERCURSOR )
144 ImplInvertCursor( rOldData.mnPosCursor );
145 ImplInvertCursor( GetRulerCursorPos() );
148 if( nDiff & CSV_DIFF_POSCOUNT )
150 if( GetPosCount() < rOldData.mnPosCount )
152 SelectAll( false );
153 maSplits.RemoveRange( GetPosCount(), rOldData.mnPosCount );
155 else
156 maSplits.Remove( rOldData.mnPosCount );
157 maSplits.Insert( GetPosCount() );
158 maColStates.resize( maSplits.Count() - 1 );
161 if( nDiff & CSV_DIFF_LINEOFFSET )
163 Execute( CSVCMD_UPDATECELLTEXTS );
164 UpdateOffsetX();
167 ScCsvDiff nHVDiff = nDiff & (CSV_DIFF_HORIZONTAL | CSV_DIFF_VERTICAL);
168 if( nHVDiff == CSV_DIFF_POSOFFSET )
169 ImplDrawHorzScrolled( rOldData.mnPosOffset );
170 else if( nHVDiff != CSV_DIFF_EQUAL )
171 InvalidateGfx();
173 EnableRepaint();
175 if( nDiff & (CSV_DIFF_POSOFFSET | CSV_DIFF_LINEOFFSET) )
176 AccSendVisibleEvent();
179 void ScCsvGrid::SetFirstImportedLine( sal_Int32 nLine )
181 ImplDrawFirstLineSep( false );
182 mnFirstImpLine = nLine;
183 ImplDrawFirstLineSep( true );
184 ImplDrawGridDev();
185 Repaint();
188 sal_Int32 ScCsvGrid::GetNoScrollCol( sal_Int32 nPos ) const
190 sal_Int32 nNewPos = nPos;
191 if( nNewPos != CSV_POS_INVALID )
193 if( nNewPos < GetFirstVisPos() + CSV_SCROLL_DIST )
195 sal_Int32 nScroll = (GetFirstVisPos() > 0) ? CSV_SCROLL_DIST : 0;
196 nNewPos = GetFirstVisPos() + nScroll;
198 else if( nNewPos > GetLastVisPos() - CSV_SCROLL_DIST - 1L )
200 sal_Int32 nScroll = (GetFirstVisPos() < GetMaxPosOffset()) ? CSV_SCROLL_DIST : 0;
201 nNewPos = GetLastVisPos() - nScroll - 1;
204 return nNewPos;
207 void ScCsvGrid::InitColors()
209 OSL_PRECOND(mpColorConfig, "the object hasn't been initialized properly");
210 if ( !mpColorConfig )
211 return;
212 maBackColor.SetColor( static_cast< sal_uInt32 >( mpColorConfig->GetColorValue( ::svtools::DOCCOLOR ).nColor ) );
213 maGridColor.SetColor( static_cast< sal_uInt32 >( mpColorConfig->GetColorValue( ::svtools::CALCGRID ).nColor ) );
214 maGridPBColor.SetColor( static_cast< sal_uInt32 >( mpColorConfig->GetColorValue( ::svtools::CALCPAGEBREAK ).nColor ) );
215 maAppBackColor.SetColor( static_cast< sal_uInt32 >( mpColorConfig->GetColorValue( ::svtools::APPBACKGROUND ).nColor ) );
216 maTextColor.SetColor( static_cast< sal_uInt32 >( mpColorConfig->GetColorValue( ::svtools::FONTCOLOR ).nColor ) );
218 const StyleSettings& rSett = GetSettings().GetStyleSettings();
219 maHeaderBackColor = rSett.GetFaceColor();
220 maHeaderGridColor = rSett.GetDarkShadowColor();
221 maHeaderTextColor = rSett.GetButtonTextColor();
222 maSelectColor = rSett.GetActiveColor();
224 InvalidateGfx();
227 void ScCsvGrid::InitFonts()
229 maMonoFont = OutputDevice::GetDefaultFont( DefaultFontType::FIXED, LANGUAGE_ENGLISH_US, GetDefaultFontFlags::NONE );
230 maMonoFont.SetSize( Size( maMonoFont.GetSize().Width(), maHeaderFont.GetSize().Height() ) );
232 /* *** Set edit engine defaults ***
233 maMonoFont for Latin script, smaller default font for Asian and Complex script. */
235 // get default fonts
236 SvxFontItem aLatinItem( EE_CHAR_FONTINFO );
237 SvxFontItem aAsianItem( EE_CHAR_FONTINFO_CJK );
238 SvxFontItem aComplexItem( EE_CHAR_FONTINFO_CTL );
239 ::GetDefaultFonts( aLatinItem, aAsianItem, aComplexItem );
241 // create item set for defaults
242 SfxItemSet aDefSet( mpEditEngine->GetEmptyItemSet() );
243 EditEngine::SetFontInfoInItemSet( aDefSet, maMonoFont );
244 aDefSet.Put( aAsianItem );
245 aDefSet.Put( aComplexItem );
247 // set Asian/Complex font size to height of character in Latin font
248 sal_uLong nFontHt = static_cast< sal_uLong >( maMonoFont.GetSize().Height() );
249 aDefSet.Put( SvxFontHeightItem( nFontHt, 100, EE_CHAR_FONTHEIGHT_CJK ) );
250 aDefSet.Put( SvxFontHeightItem( nFontHt, 100, EE_CHAR_FONTHEIGHT_CTL ) );
252 // copy other items from default font
253 const SfxPoolItem& rWeightItem = aDefSet.Get( EE_CHAR_WEIGHT );
254 aDefSet.Put( rWeightItem, EE_CHAR_WEIGHT_CJK );
255 aDefSet.Put( rWeightItem, EE_CHAR_WEIGHT_CTL );
256 const SfxPoolItem& rItalicItem = aDefSet.Get( EE_CHAR_ITALIC );
257 aDefSet.Put( rItalicItem, EE_CHAR_ITALIC_CJK );
258 aDefSet.Put( rItalicItem, EE_CHAR_ITALIC_CTL );
259 const SfxPoolItem& rLangItem = aDefSet.Get( EE_CHAR_LANGUAGE );
260 aDefSet.Put( rLangItem, EE_CHAR_LANGUAGE_CJK );
261 aDefSet.Put( rLangItem, EE_CHAR_LANGUAGE_CTL );
263 mpEditEngine->SetDefaults( aDefSet );
264 InvalidateGfx();
267 void ScCsvGrid::InitSizeData()
269 maWinSize = GetSizePixel();
270 mpBackgrDev->SetOutputSizePixel( maWinSize );
271 mpGridDev->SetOutputSizePixel( maWinSize );
272 InvalidateGfx();
275 // split handling -------------------------------------------------------------
277 void ScCsvGrid::InsertSplit( sal_Int32 nPos )
279 if( ImplInsertSplit( nPos ) )
281 DisableRepaint();
282 Execute( CSVCMD_EXPORTCOLUMNTYPE );
283 Execute( CSVCMD_UPDATECELLTEXTS );
284 sal_uInt32 nColIx = GetColumnFromPos( nPos );
285 ImplDrawColumn( nColIx - 1 );
286 ImplDrawColumn( nColIx );
287 ValidateGfx(); // performance: do not redraw all columns
288 EnableRepaint();
292 void ScCsvGrid::RemoveSplit( sal_Int32 nPos )
294 if( ImplRemoveSplit( nPos ) )
296 DisableRepaint();
297 Execute( CSVCMD_EXPORTCOLUMNTYPE );
298 Execute( CSVCMD_UPDATECELLTEXTS );
299 ImplDrawColumn( GetColumnFromPos( nPos ) );
300 ValidateGfx(); // performance: do not redraw all columns
301 EnableRepaint();
305 void ScCsvGrid::MoveSplit( sal_Int32 nPos, sal_Int32 nNewPos )
307 sal_uInt32 nColIx = GetColumnFromPos( nPos );
308 if( nColIx != CSV_COLUMN_INVALID )
310 DisableRepaint();
311 if( (GetColumnPos( nColIx - 1 ) < nNewPos) && (nNewPos < GetColumnPos( nColIx + 1 )) )
313 // move a split in the range between 2 others -> keep selection state of both columns
314 maSplits.Remove( nPos );
315 maSplits.Insert( nNewPos );
316 Execute( CSVCMD_UPDATECELLTEXTS );
317 ImplDrawColumn( nColIx - 1 );
318 ImplDrawColumn( nColIx );
319 ValidateGfx(); // performance: do not redraw all columns
320 AccSendTableUpdateEvent( nColIx - 1, nColIx );
322 else
324 ImplRemoveSplit( nPos );
325 ImplInsertSplit( nNewPos );
326 Execute( CSVCMD_EXPORTCOLUMNTYPE );
327 Execute( CSVCMD_UPDATECELLTEXTS );
329 EnableRepaint();
333 void ScCsvGrid::RemoveAllSplits()
335 DisableRepaint();
336 ImplClearSplits();
337 Execute( CSVCMD_EXPORTCOLUMNTYPE );
338 Execute( CSVCMD_UPDATECELLTEXTS );
339 EnableRepaint();
342 void ScCsvGrid::SetSplits( const ScCsvSplits& rSplits )
344 DisableRepaint();
345 ImplClearSplits();
346 sal_uInt32 nCount = rSplits.Count();
347 for( sal_uInt32 nIx = 0; nIx < nCount; ++nIx )
348 maSplits.Insert( rSplits[ nIx ] );
349 maColStates.clear();
350 maColStates.resize( maSplits.Count() - 1 );
351 Execute( CSVCMD_EXPORTCOLUMNTYPE );
352 Execute( CSVCMD_UPDATECELLTEXTS );
353 EnableRepaint();
356 bool ScCsvGrid::ImplInsertSplit( sal_Int32 nPos )
358 sal_uInt32 nColIx = GetColumnFromPos( nPos );
359 bool bRet = (nColIx < GetColumnCount()) && maSplits.Insert( nPos );
360 if( bRet )
362 ScCsvColState aState( GetColumnType( nColIx ) );
363 aState.Select( IsSelected( nColIx ) && IsSelected( nColIx + 1 ) );
364 maColStates.insert( maColStates.begin() + nColIx + 1, aState );
365 AccSendInsertColumnEvent( nColIx + 1, nColIx + 1 );
366 AccSendTableUpdateEvent( nColIx, nColIx );
368 return bRet;
371 bool ScCsvGrid::ImplRemoveSplit( sal_Int32 nPos )
373 bool bRet = maSplits.Remove( nPos );
374 if( bRet )
376 sal_uInt32 nColIx = GetColumnFromPos( nPos );
377 bool bSel = IsSelected( nColIx ) || IsSelected( nColIx + 1 );
378 maColStates.erase( maColStates.begin() + nColIx + 1 );
379 maColStates[ nColIx ].Select( bSel );
380 AccSendRemoveColumnEvent( nColIx + 1, nColIx + 1 );
381 AccSendTableUpdateEvent( nColIx, nColIx );
383 return bRet;
386 void ScCsvGrid::ImplClearSplits()
388 sal_uInt32 nColumns = GetColumnCount();
389 maSplits.Clear();
390 maSplits.Insert( 0 );
391 maSplits.Insert( GetPosCount() );
392 maColStates.resize( 1 );
393 InvalidateGfx();
394 AccSendRemoveColumnEvent( 1, nColumns - 1 );
397 // columns/column types -------------------------------------------------------
399 sal_uInt32 ScCsvGrid::GetFirstVisColumn() const
401 return GetColumnFromPos( GetFirstVisPos() );
404 sal_uInt32 ScCsvGrid::GetLastVisColumn() const
406 return GetColumnFromPos( std::min( GetLastVisPos(), GetPosCount() ) - 1 );
409 bool ScCsvGrid::IsValidColumn( sal_uInt32 nColIndex ) const
411 return nColIndex < GetColumnCount();
414 bool ScCsvGrid::IsVisibleColumn( sal_uInt32 nColIndex ) const
416 return IsValidColumn( nColIndex ) &&
417 (GetColumnPos( nColIndex ) < GetLastVisPos()) &&
418 (GetFirstVisPos() < GetColumnPos( nColIndex + 1 ));
421 sal_Int32 ScCsvGrid::GetColumnX( sal_uInt32 nColIndex ) const
423 return GetX( GetColumnPos( nColIndex ) );
426 sal_uInt32 ScCsvGrid::GetColumnFromX( sal_Int32 nX ) const
428 sal_Int32 nPos = (nX - GetFirstX()) / GetCharWidth() + GetFirstVisPos();
429 return ((GetFirstVisPos() <= nPos) && (nPos <= GetLastVisPos())) ?
430 GetColumnFromPos( nPos ) : CSV_COLUMN_INVALID;
433 sal_uInt32 ScCsvGrid::GetColumnFromPos( sal_Int32 nPos ) const
435 return maSplits.UpperBound( nPos );
438 sal_Int32 ScCsvGrid::GetColumnWidth( sal_uInt32 nColIndex ) const
440 return IsValidColumn( nColIndex ) ? (GetColumnPos( nColIndex + 1 ) - GetColumnPos( nColIndex )) : 0;
443 void ScCsvGrid::SetColumnStates( const ScCsvColStateVec& rStates )
445 maColStates = rStates;
446 maColStates.resize( maSplits.Count() - 1 );
447 Execute( CSVCMD_EXPORTCOLUMNTYPE );
448 AccSendTableUpdateEvent( 0, GetColumnCount(), false );
449 AccSendSelectionEvent();
452 sal_Int32 ScCsvGrid::GetColumnType( sal_uInt32 nColIndex ) const
454 return IsValidColumn( nColIndex ) ? maColStates[ nColIndex ].mnType : CSV_TYPE_NOSELECTION;
457 void ScCsvGrid::SetColumnType( sal_uInt32 nColIndex, sal_Int32 nColType )
459 if( IsValidColumn( nColIndex ) )
461 maColStates[ nColIndex ].mnType = nColType;
462 AccSendTableUpdateEvent( nColIndex, nColIndex, false );
466 sal_Int32 ScCsvGrid::GetSelColumnType() const
468 sal_uInt32 nColIx = GetFirstSelected();
469 if( nColIx == CSV_COLUMN_INVALID )
470 return CSV_TYPE_NOSELECTION;
472 sal_Int32 nType = GetColumnType( nColIx );
473 while( (nColIx != CSV_COLUMN_INVALID) && (nType != CSV_TYPE_MULTI) )
475 if( nType != GetColumnType( nColIx ) )
476 nType = CSV_TYPE_MULTI;
477 nColIx = GetNextSelected( nColIx );
479 return nType;
482 void ScCsvGrid::SetSelColumnType( sal_Int32 nType )
484 if( (nType != CSV_TYPE_MULTI) && (nType != CSV_TYPE_NOSELECTION) )
486 for( sal_uInt32 nColIx = GetFirstSelected(); nColIx != CSV_COLUMN_INVALID; nColIx = GetNextSelected( nColIx ) )
487 SetColumnType( nColIx, nType );
488 Repaint( true );
489 Execute( CSVCMD_EXPORTCOLUMNTYPE );
493 void ScCsvGrid::SetTypeNames( const StringVec& rTypeNames )
495 OSL_ENSURE( !rTypeNames.empty(), "ScCsvGrid::SetTypeNames - vector is empty" );
496 maTypeNames = rTypeNames;
497 Repaint( true );
499 maPopup.Clear();
500 sal_uInt32 nCount = maTypeNames.size();
501 sal_uInt32 nIx;
502 sal_uInt16 nItemId;
503 for( nIx = 0, nItemId = 1; nIx < nCount; ++nIx, ++nItemId )
504 maPopup.InsertItem( nItemId, maTypeNames[ nIx ] );
506 ::std::for_each( maColStates.begin(), maColStates.end(), Func_SetType( CSV_TYPE_DEFAULT ) );
509 const OUString& ScCsvGrid::GetColumnTypeName( sal_uInt32 nColIndex ) const
511 sal_uInt32 nTypeIx = static_cast< sal_uInt32 >( GetColumnType( nColIndex ) );
512 return (nTypeIx < maTypeNames.size()) ? maTypeNames[ nTypeIx ] : EMPTY_OUSTRING;
515 static sal_uInt8 lcl_GetExtColumnType( sal_Int32 nIntType )
517 static const sal_uInt8 pExtTypes[] =
518 { SC_COL_STANDARD, SC_COL_TEXT, SC_COL_DMY, SC_COL_MDY, SC_COL_YMD, SC_COL_ENGLISH, SC_COL_SKIP };
519 static const sal_Int32 nExtTypeCount = SAL_N_ELEMENTS(pExtTypes);
520 return pExtTypes[ ((0 <= nIntType) && (nIntType < nExtTypeCount)) ? nIntType : 0 ];
523 void ScCsvGrid::FillColumnDataSep( ScAsciiOptions& rOptions ) const
525 sal_uInt32 nCount = GetColumnCount();
526 ScCsvExpDataVec aDataVec;
528 for( sal_uInt32 nColIx = 0; nColIx < nCount; ++nColIx )
530 if( GetColumnType( nColIx ) != CSV_TYPE_DEFAULT )
531 // 1-based column index
532 aDataVec.push_back( ScCsvExpData(
533 static_cast< sal_Int32 >( nColIx + 1 ),
534 lcl_GetExtColumnType( GetColumnType( nColIx ) ) ) );
536 rOptions.SetColumnInfo( aDataVec );
539 void ScCsvGrid::FillColumnDataFix( ScAsciiOptions& rOptions ) const
541 sal_uInt32 nCount = std::min( GetColumnCount(), static_cast<sal_uInt32>(MAXCOLCOUNT) );
542 ScCsvExpDataVec aDataVec( nCount + 1 );
544 for( sal_uInt32 nColIx = 0; nColIx < nCount; ++nColIx )
546 ScCsvExpData& rData = aDataVec[ nColIx ];
547 rData.mnIndex = static_cast< sal_Int32 >( GetColumnPos( nColIx ) );
548 rData.mnType = lcl_GetExtColumnType( GetColumnType( nColIx ) );
550 aDataVec[ nCount ].mnIndex = SAL_MAX_INT32;
551 aDataVec[ nCount ].mnType = SC_COL_SKIP;
552 rOptions.SetColumnInfo( aDataVec );
555 void ScCsvGrid::ScrollVertRel( ScMoveMode eDir )
557 sal_Int32 nLine = GetFirstVisLine();
558 switch( eDir )
560 case MOVE_PREV: --nLine; break;
561 case MOVE_NEXT: ++nLine; break;
562 case MOVE_FIRST: nLine = 0; break;
563 case MOVE_LAST: nLine = GetMaxLineOffset(); break;
564 case MOVE_PREVPAGE: nLine -= GetVisLineCount() - 2; break;
565 case MOVE_NEXTPAGE: nLine += GetVisLineCount() - 2; break;
566 default:
568 // added to avoid warnings
571 Execute( CSVCMD_SETLINEOFFSET, nLine );
574 void ScCsvGrid::ExecutePopup( const Point& rPos )
576 sal_uInt16 nItemId = maPopup.Execute( this, rPos );
577 if( nItemId ) // 0 = cancelled
578 Execute( CSVCMD_SETCOLUMNTYPE, maPopup.GetItemPos( nItemId ) );
581 // selection handling ---------------------------------------------------------
583 bool ScCsvGrid::IsSelected( sal_uInt32 nColIndex ) const
585 return IsValidColumn( nColIndex ) && maColStates[ nColIndex ].IsSelected();
588 sal_uInt32 ScCsvGrid::GetFirstSelected() const
590 return IsSelected( 0 ) ? 0 : GetNextSelected( 0 );
593 sal_uInt32 ScCsvGrid::GetNextSelected( sal_uInt32 nFromIndex ) const
595 sal_uInt32 nColCount = GetColumnCount();
596 for( sal_uInt32 nColIx = nFromIndex + 1; nColIx < nColCount; ++nColIx )
597 if( IsSelected( nColIx ) )
598 return nColIx;
599 return CSV_COLUMN_INVALID;
602 void ScCsvGrid::Select( sal_uInt32 nColIndex, bool bSelect )
604 if( IsValidColumn( nColIndex ) )
606 maColStates[ nColIndex ].Select( bSelect );
607 ImplDrawColumnSelection( nColIndex );
608 Repaint();
609 Execute( CSVCMD_EXPORTCOLUMNTYPE );
610 if( bSelect )
611 mnRecentSelCol = nColIndex;
612 AccSendSelectionEvent();
616 void ScCsvGrid::ToggleSelect( sal_uInt32 nColIndex )
618 Select( nColIndex, !IsSelected( nColIndex ) );
621 void ScCsvGrid::SelectRange( sal_uInt32 nColIndex1, sal_uInt32 nColIndex2, bool bSelect )
623 if( nColIndex1 == CSV_COLUMN_INVALID )
624 Select( nColIndex2 );
625 else if( nColIndex2 == CSV_COLUMN_INVALID )
626 Select( nColIndex1 );
627 else if( nColIndex1 > nColIndex2 )
629 SelectRange( nColIndex2, nColIndex1, bSelect );
630 if( bSelect )
631 mnRecentSelCol = nColIndex1;
633 else if( IsValidColumn( nColIndex1 ) && IsValidColumn( nColIndex2 ) )
635 for( sal_uInt32 nColIx = nColIndex1; nColIx <= nColIndex2; ++nColIx )
637 maColStates[ nColIx ].Select( bSelect );
638 ImplDrawColumnSelection( nColIx );
640 Repaint();
641 Execute( CSVCMD_EXPORTCOLUMNTYPE );
642 if( bSelect )
643 mnRecentSelCol = nColIndex1;
644 AccSendSelectionEvent();
648 void ScCsvGrid::SelectAll( bool bSelect )
650 SelectRange( 0, GetColumnCount() - 1, bSelect );
653 void ScCsvGrid::MoveCursor( sal_uInt32 nColIndex )
655 DisableRepaint();
656 if( IsValidColumn( nColIndex ) )
658 sal_Int32 nPosBeg = GetColumnPos( nColIndex );
659 sal_Int32 nPosEnd = GetColumnPos( nColIndex + 1 );
660 sal_Int32 nMinPos = std::max( nPosBeg - CSV_SCROLL_DIST, sal_Int32( 0 ) );
661 sal_Int32 nMaxPos = std::min( nPosEnd - GetVisPosCount() + CSV_SCROLL_DIST + sal_Int32( 1 ), nMinPos );
662 if( nPosBeg - CSV_SCROLL_DIST + 1 <= GetFirstVisPos() )
663 Execute( CSVCMD_SETPOSOFFSET, nMinPos );
664 else if( nPosEnd + CSV_SCROLL_DIST >= GetLastVisPos() )
665 Execute( CSVCMD_SETPOSOFFSET, nMaxPos );
667 Execute( CSVCMD_MOVEGRIDCURSOR, GetColumnPos( nColIndex ) );
668 EnableRepaint();
671 void ScCsvGrid::MoveCursorRel( ScMoveMode eDir )
673 if( GetFocusColumn() != CSV_COLUMN_INVALID )
675 switch( eDir )
677 case MOVE_FIRST:
678 MoveCursor( 0 );
679 break;
680 case MOVE_LAST:
681 MoveCursor( GetColumnCount() - 1 );
682 break;
683 case MOVE_PREV:
684 if( GetFocusColumn() > 0 )
685 MoveCursor( GetFocusColumn() - 1 );
686 break;
687 case MOVE_NEXT:
688 if( GetFocusColumn() < GetColumnCount() - 1 )
689 MoveCursor( GetFocusColumn() + 1 );
690 break;
691 default:
693 // added to avoid warnings
699 void ScCsvGrid::ImplClearSelection()
701 ::std::for_each( maColStates.begin(), maColStates.end(), Func_Select( false ) );
702 ImplDrawGridDev();
705 void ScCsvGrid::DoSelectAction( sal_uInt32 nColIndex, sal_uInt16 nModifier )
707 if( !(nModifier & KEY_MOD1) )
708 ImplClearSelection();
709 if( nModifier & KEY_SHIFT ) // SHIFT always expands
710 SelectRange( mnRecentSelCol, nColIndex );
711 else if( !(nModifier & KEY_MOD1) ) // no SHIFT/CTRL always selects 1 column
712 Select( nColIndex );
713 else if( IsTracking() ) // CTRL in tracking does not toggle
714 Select( nColIndex, mbMTSelecting );
715 else // CTRL only toggles
716 ToggleSelect( nColIndex );
717 Execute( CSVCMD_MOVEGRIDCURSOR, GetColumnPos( nColIndex ) );
720 // cell contents --------------------------------------------------------------
722 void ScCsvGrid::ImplSetTextLineSep(
723 sal_Int32 nLine, const OUString& rTextLine,
724 const OUString& rSepChars, sal_Unicode cTextSep, bool bMergeSep )
726 if( nLine < GetFirstVisLine() ) return;
728 sal_uInt32 nLineIx = nLine - GetFirstVisLine();
729 while( maTexts.size() <= nLineIx )
730 maTexts.push_back( StringVec() );
731 StringVec& rStrVec = maTexts[ nLineIx ];
732 rStrVec.clear();
734 // scan for separators
735 OUString aCellText;
736 const sal_Unicode* pSepChars = rSepChars.getStr();
737 const sal_Unicode* pChar = rTextLine.getStr();
738 sal_uInt32 nColIx = 0;
740 while( *pChar && (nColIx < sal::static_int_cast<sal_uInt32>(CSV_MAXCOLCOUNT)) )
742 // scan for next cell text
743 bool bIsQuoted = false;
744 bool bOverflowCell = false;
745 pChar = ScImportExport::ScanNextFieldFromString( pChar, aCellText,
746 cTextSep, pSepChars, bMergeSep, bIsQuoted, bOverflowCell );
747 /* TODO: signal overflow somewhere in UI */
749 // update column width
750 sal_Int32 nWidth = std::max( CSV_MINCOLWIDTH, aCellText.getLength() + 1 );
751 if( IsValidColumn( nColIx ) )
753 // expand existing column
754 sal_Int32 nDiff = nWidth - GetColumnWidth( nColIx );
755 if( nDiff > 0 )
757 Execute( CSVCMD_SETPOSCOUNT, GetPosCount() + nDiff );
758 for( sal_uInt32 nSplitIx = GetColumnCount() - 1; nSplitIx > nColIx; --nSplitIx )
760 sal_Int32 nPos = maSplits[ nSplitIx ];
761 maSplits.Remove( nPos );
762 maSplits.Insert( nPos + nDiff );
766 else
768 // append new column
769 sal_Int32 nLastPos = GetPosCount();
770 Execute( CSVCMD_SETPOSCOUNT, nLastPos + nWidth );
771 ImplInsertSplit( nLastPos );
774 if( aCellText.getLength() <= CSV_MAXSTRLEN )
775 rStrVec.push_back( aCellText );
776 else
777 rStrVec.push_back( aCellText.copy( 0, CSV_MAXSTRLEN ) );
778 ++nColIx;
780 InvalidateGfx();
783 void ScCsvGrid::ImplSetTextLineFix( sal_Int32 nLine, const OUString& rTextLine )
785 if( nLine < GetFirstVisLine() ) return;
787 sal_Int32 nChars = rTextLine.getLength();
788 if( nChars > GetPosCount() )
789 Execute( CSVCMD_SETPOSCOUNT, nChars );
791 sal_uInt32 nLineIx = nLine - GetFirstVisLine();
792 while( maTexts.size() <= nLineIx )
793 maTexts.push_back( StringVec() );
795 StringVec& rStrVec = maTexts[ nLineIx ];
796 rStrVec.clear();
797 sal_uInt32 nColCount = GetColumnCount();
798 sal_Int32 nStrLen = rTextLine.getLength();
799 sal_Int32 nStrIx = 0;
800 for( sal_uInt32 nColIx = 0; (nColIx < nColCount) && (nStrIx < nStrLen); ++nColIx )
802 sal_Int32 nColWidth = GetColumnWidth( nColIx );
803 sal_Int32 nLen = std::min( std::min( nColWidth, static_cast<sal_Int32>(CSV_MAXSTRLEN) ), nStrLen - nStrIx);
804 rStrVec.push_back( rTextLine.copy( nStrIx, nLen ) );
805 nStrIx = nStrIx + nColWidth;
807 InvalidateGfx();
810 const OUString& ScCsvGrid::GetCellText( sal_uInt32 nColIndex, sal_Int32 nLine ) const
812 if( nLine < GetFirstVisLine() ) return EMPTY_OUSTRING;
814 sal_uInt32 nLineIx = nLine - GetFirstVisLine();
815 if( nLineIx >= maTexts.size() ) return EMPTY_OUSTRING;
817 const StringVec& rStrVec = maTexts[ nLineIx ];
818 if( nColIndex >= rStrVec.size() ) return EMPTY_OUSTRING;
820 return rStrVec[ nColIndex ];
823 // event handling -------------------------------------------------------------
825 void ScCsvGrid::Resize()
827 ScCsvControl::Resize();
828 InitSizeData();
829 Execute( CSVCMD_UPDATECELLTEXTS );
832 void ScCsvGrid::GetFocus()
834 ScCsvControl::GetFocus();
835 Execute( CSVCMD_MOVEGRIDCURSOR, GetNoScrollCol( GetGridCursorPos() ) );
836 Repaint();
839 void ScCsvGrid::LoseFocus()
841 ScCsvControl::LoseFocus();
842 Repaint();
845 void ScCsvGrid::MouseButtonDown( const MouseEvent& rMEvt )
847 DisableRepaint();
848 if( !HasFocus() )
849 GrabFocus();
851 Point aPos( rMEvt.GetPosPixel() );
852 sal_uInt32 nColIx = GetColumnFromX( aPos.X() );
854 if( rMEvt.IsLeft() )
856 if( (GetFirstX() > aPos.X()) || (aPos.X() > GetLastX()) ) // in header column
858 if( aPos.Y() <= GetHdrHeight() )
859 SelectAll();
861 else if( IsValidColumn( nColIx ) )
863 DoSelectAction( nColIx, rMEvt.GetModifier() );
864 mnMTCurrCol = nColIx;
865 mbMTSelecting = IsSelected( nColIx );
866 StartTracking( STARTTRACK_BUTTONREPEAT );
869 EnableRepaint();
872 void ScCsvGrid::Tracking( const TrackingEvent& rTEvt )
874 if( rTEvt.IsTrackingEnded() || rTEvt.IsTrackingRepeat() )
876 DisableRepaint();
877 const MouseEvent& rMEvt = rTEvt.GetMouseEvent();
879 sal_Int32 nPos = (rMEvt.GetPosPixel().X() - GetFirstX()) / GetCharWidth() + GetFirstVisPos();
880 // on mouse tracking: keep position valid
881 nPos = std::max( std::min( nPos, GetPosCount() - sal_Int32( 1 ) ), sal_Int32( 0 ) );
882 Execute( CSVCMD_MAKEPOSVISIBLE, nPos );
884 sal_uInt32 nColIx = GetColumnFromPos( nPos );
885 if( mnMTCurrCol != nColIx )
887 DoSelectAction( nColIx, rMEvt.GetModifier() );
888 mnMTCurrCol = nColIx;
890 EnableRepaint();
894 void ScCsvGrid::KeyInput( const KeyEvent& rKEvt )
896 const vcl::KeyCode& rKCode = rKEvt.GetKeyCode();
897 sal_uInt16 nCode = rKCode.GetCode();
898 bool bShift = rKCode.IsShift();
899 bool bMod1 = rKCode.IsMod1();
901 if( !rKCode.IsMod2() )
903 ScMoveMode eHDir = GetHorzDirection( nCode, !bMod1 );
904 ScMoveMode eVDir = GetVertDirection( nCode, bMod1 );
906 if( eHDir != MOVE_NONE )
908 DisableRepaint();
909 MoveCursorRel( eHDir );
910 if( !bMod1 )
911 ImplClearSelection();
912 if( bShift )
913 SelectRange( mnRecentSelCol, GetFocusColumn() );
914 else if( !bMod1 )
915 Select( GetFocusColumn() );
916 EnableRepaint();
918 else if( eVDir != MOVE_NONE )
919 ScrollVertRel( eVDir );
920 else if( nCode == KEY_SPACE )
922 if( !bMod1 )
923 ImplClearSelection();
924 if( bShift )
925 SelectRange( mnRecentSelCol, GetFocusColumn() );
926 else if( bMod1 )
927 ToggleSelect( GetFocusColumn() );
928 else
929 Select( GetFocusColumn() );
931 else if( !bShift && bMod1 )
933 if( nCode == KEY_A )
934 SelectAll();
935 else if( (KEY_1 <= nCode) && (nCode <= KEY_9) )
937 sal_uInt32 nType = nCode - KEY_1;
938 if( nType < maTypeNames.size() )
939 Execute( CSVCMD_SETCOLUMNTYPE, nType );
944 if( rKCode.GetGroup() != KEYGROUP_CURSOR )
945 ScCsvControl::KeyInput( rKEvt );
948 void ScCsvGrid::Command( const CommandEvent& rCEvt )
950 switch( rCEvt.GetCommand() )
952 case CommandEventId::ContextMenu:
954 if( rCEvt.IsMouseEvent() )
956 Point aPos( rCEvt.GetMousePosPixel() );
957 sal_uInt32 nColIx = GetColumnFromX( aPos.X() );
958 if( IsValidColumn( nColIx ) && (GetFirstX() <= aPos.X()) && (aPos.X() <= GetLastX()) )
960 if( !IsSelected( nColIx ) )
961 DoSelectAction( nColIx, 0 ); // focus & select
962 ExecutePopup( aPos );
965 else
967 sal_uInt32 nColIx = GetFocusColumn();
968 if( !IsSelected( nColIx ) )
969 Select( nColIx );
970 sal_Int32 nX1 = std::max( GetColumnX( nColIx ), GetFirstX() );
971 sal_Int32 nX2 = std::min( GetColumnX( nColIx + 1 ), GetWidth() );
972 ExecutePopup( Point( (nX1 + nX2) / 2, GetHeight() / 2 ) );
975 break;
976 case CommandEventId::Wheel:
978 Point aPoint;
979 Rectangle aRect( aPoint, maWinSize );
980 if( aRect.IsInside( rCEvt.GetMousePosPixel() ) )
982 const CommandWheelData* pData = rCEvt.GetWheelData();
983 if( pData && (pData->GetMode() == CommandWheelMode::SCROLL) && !pData->IsHorz() )
984 Execute( CSVCMD_SETLINEOFFSET, GetFirstVisLine() - pData->GetNotchDelta() );
987 break;
988 default:
989 ScCsvControl::Command( rCEvt );
993 void ScCsvGrid::DataChanged( const DataChangedEvent& rDCEvt )
995 if( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
997 InitColors();
998 InitFonts();
999 UpdateLayoutData();
1000 Execute( CSVCMD_UPDATECELLTEXTS );
1002 ScCsvControl::DataChanged( rDCEvt );
1005 void ScCsvGrid::ConfigurationChanged( utl::ConfigurationBroadcaster*, sal_uInt32 )
1007 InitColors();
1008 Repaint();
1011 // painting -------------------------------------------------------------------
1013 void ScCsvGrid::Paint( vcl::RenderContext& /*rRenderContext*/, const Rectangle& )
1015 Repaint();
1018 void ScCsvGrid::ImplRedraw()
1020 if( IsVisible() )
1022 if( !IsValidGfx() )
1024 ValidateGfx();
1025 ImplDrawBackgrDev();
1026 ImplDrawGridDev();
1028 DrawOutDev( Point(), maWinSize, Point(), maWinSize, *mpGridDev.get() );
1029 ImplDrawTrackingRect( GetFocusColumn() );
1033 EditEngine* ScCsvGrid::GetEditEngine()
1035 return mpEditEngine.get();
1038 void ScCsvGrid::ImplSetColumnClipRegion( OutputDevice& rOutDev, sal_uInt32 nColIndex )
1040 rOutDev.SetClipRegion( vcl::Region( Rectangle(
1041 std::max( GetColumnX( nColIndex ), GetFirstX() ) + 1, 0,
1042 std::min( GetColumnX( nColIndex + 1 ), GetLastX() ), GetHeight() - 1 ) ) );
1045 void ScCsvGrid::ImplDrawColumnHeader( OutputDevice& rOutDev, sal_uInt32 nColIndex, Color aFillColor )
1047 sal_Int32 nX1 = GetColumnX( nColIndex ) + 1;
1048 sal_Int32 nX2 = GetColumnX( nColIndex + 1 );
1049 sal_Int32 nHdrHt = GetHdrHeight();
1051 rOutDev.SetLineColor();
1052 rOutDev.SetFillColor( aFillColor );
1053 rOutDev.DrawRect( Rectangle( nX1, 0, nX2, nHdrHt ) );
1055 rOutDev.SetFont( maHeaderFont );
1056 rOutDev.SetTextColor( maHeaderTextColor );
1057 rOutDev.SetTextFillColor();
1058 rOutDev.DrawText( Point( nX1 + 1, 0 ), GetColumnTypeName( nColIndex ) );
1060 rOutDev.SetLineColor( maHeaderGridColor );
1061 rOutDev.DrawLine( Point( nX1, nHdrHt ), Point( nX2, nHdrHt ) );
1062 rOutDev.DrawLine( Point( nX2, 0 ), Point( nX2, nHdrHt ) );
1065 void ScCsvGrid::ImplDrawCellText( const Point& rPos, const OUString& rText )
1067 OUString aPlainText( rText );
1068 aPlainText = aPlainText.replaceAll( "\t", " " );
1069 aPlainText = aPlainText.replaceAll( "\n", " " );
1070 mpEditEngine->SetPaperSize( maEdEngSize );
1072 /* #i60296# If string contains mixed script types, the space character
1073 U+0020 may be drawn with a wrong width (from non-fixed-width Asian or
1074 Complex font). Now we draw every non-space portion separately. */
1075 sal_Int32 nTokenCount = comphelper::string::getTokenCount(aPlainText, ' ');
1076 sal_Int32 nCharIxInt = 0;
1077 for( sal_Int32 nToken = 0; nToken < nTokenCount; ++nToken )
1079 sal_Int32 nBeginIx = nCharIxInt;
1080 OUString aToken = aPlainText.getToken( 0, ' ', nCharIxInt );
1081 if( !aToken.isEmpty() )
1083 sal_Int32 nX = rPos.X() + GetCharWidth() * nBeginIx;
1084 mpEditEngine->SetText( aToken );
1085 mpEditEngine->Draw( mpBackgrDev.get(), Point( nX, rPos.Y() ) );
1089 sal_Int32 nCharIx = 0;
1090 while( (nCharIx = rText.indexOf( '\t', nCharIx )) != -1 )
1092 sal_Int32 nX1 = rPos.X() + GetCharWidth() * nCharIx;
1093 sal_Int32 nX2 = nX1 + GetCharWidth() - 2;
1094 sal_Int32 nY = rPos.Y() + GetLineHeight() / 2;
1095 Color aColor( maTextColor );
1096 mpBackgrDev->SetLineColor( aColor );
1097 mpBackgrDev->DrawLine( Point( nX1, nY ), Point( nX2, nY ) );
1098 mpBackgrDev->DrawLine( Point( nX2 - 2, nY - 2 ), Point( nX2, nY ) );
1099 mpBackgrDev->DrawLine( Point( nX2 - 2, nY + 2 ), Point( nX2, nY ) );
1100 ++nCharIx;
1102 nCharIx = 0;
1103 while( (nCharIx = rText.indexOf( '\n', nCharIx )) != -1 )
1105 sal_Int32 nX1 = rPos.X() + GetCharWidth() * nCharIx;
1106 sal_Int32 nX2 = nX1 + GetCharWidth() - 2;
1107 sal_Int32 nY = rPos.Y() + GetLineHeight() / 2;
1108 Color aColor( maTextColor );
1109 mpBackgrDev->SetLineColor( aColor );
1110 mpBackgrDev->DrawLine( Point( nX1, nY ), Point( nX2, nY ) );
1111 mpBackgrDev->DrawLine( Point( nX1 + 2, nY - 2 ), Point( nX1, nY ) );
1112 mpBackgrDev->DrawLine( Point( nX1 + 2, nY + 2 ), Point( nX1, nY ) );
1113 mpBackgrDev->DrawLine( Point( nX2, nY - 2 ), Point( nX2, nY ) );
1114 ++nCharIx;
1118 void ScCsvGrid::ImplDrawFirstLineSep( bool bSet )
1120 if( IsVisibleLine( mnFirstImpLine ) && (mnFirstImpLine != GetFirstVisLine() ) )
1122 sal_Int32 nY = GetY( mnFirstImpLine );
1123 sal_Int32 nX = std::min( GetColumnX( GetLastVisColumn() + 1 ), GetLastX() );
1124 mpBackgrDev->SetLineColor( bSet ? maGridPBColor : maGridColor );
1125 mpBackgrDev->DrawLine( Point( GetFirstX() + 1, nY ), Point( nX, nY ) );
1129 void ScCsvGrid::ImplDrawColumnBackgr( sal_uInt32 nColIndex )
1131 if( !IsVisibleColumn( nColIndex ) )
1132 return;
1134 ImplSetColumnClipRegion( *mpBackgrDev.get(), nColIndex );
1136 // grid
1137 mpBackgrDev->SetLineColor();
1138 mpBackgrDev->SetFillColor( maBackColor );
1139 sal_Int32 nX1 = GetColumnX( nColIndex ) + 1;
1140 sal_Int32 nX2 = GetColumnX( nColIndex + 1 );
1141 sal_Int32 nY2 = GetY( GetLastVisLine() + 1 );
1142 sal_Int32 nHdrHt = GetHdrHeight();
1143 Rectangle aRect( nX1, nHdrHt, nX2, nY2 );
1144 mpBackgrDev->DrawRect( aRect );
1145 mpBackgrDev->SetLineColor( maGridColor );
1146 mpBackgrDev->DrawGrid( aRect, Size( 1, GetLineHeight() ), DrawGridFlags::HorzLines );
1147 mpBackgrDev->DrawLine( Point( nX2, nHdrHt ), Point( nX2, nY2 ) );
1148 ImplDrawFirstLineSep( true );
1150 // cell texts
1151 mpEditEngine->SetDefaultItem( SvxColorItem( maTextColor, EE_CHAR_COLOR ) );
1152 size_t nLineCount = ::std::min( static_cast< size_t >( GetLastVisLine() - GetFirstVisLine() + 1 ), maTexts.size() );
1153 // #i67432# cut string to avoid edit engine performance problems with very large strings
1154 sal_Int32 nFirstVisPos = ::std::max( GetColumnPos( nColIndex ), GetFirstVisPos() );
1155 sal_Int32 nLastVisPos = ::std::min( GetColumnPos( nColIndex + 1 ), GetLastVisPos() );
1156 sal_Int32 nStrPos = nFirstVisPos - GetColumnPos( nColIndex );
1157 sal_Int32 nStrLen = nLastVisPos - nFirstVisPos + 1;
1158 sal_Int32 nStrX = GetX( nFirstVisPos );
1159 for( size_t nLine = 0; nLine < nLineCount; ++nLine )
1161 StringVec& rStrVec = maTexts[ nLine ];
1162 if( (nColIndex < rStrVec.size()) && (rStrVec[ nColIndex ].getLength() > nStrPos) )
1164 const OUString& rStr = rStrVec[ nColIndex ];
1165 OUString aText = rStr.copy( nStrPos, ::std::min( nStrLen, rStr.getLength() - nStrPos) );
1166 ImplDrawCellText( Point( nStrX, GetY( GetFirstVisLine() + nLine ) ), aText );
1170 // header
1171 ImplDrawColumnHeader( *mpBackgrDev.get(), nColIndex, maHeaderBackColor );
1173 mpBackgrDev->SetClipRegion();
1176 void ScCsvGrid::ImplDrawRowHeaders()
1178 mpBackgrDev->SetLineColor();
1179 mpBackgrDev->SetFillColor( maAppBackColor );
1180 Point aPoint( GetHdrX(), 0 );
1181 Rectangle aRect( aPoint, Size( GetHdrWidth() + 1, GetHeight() ) );
1182 mpBackgrDev->DrawRect( aRect );
1184 mpBackgrDev->SetFillColor( maHeaderBackColor );
1185 aRect.Bottom() = GetY( GetLastVisLine() + 1 );
1186 mpBackgrDev->DrawRect( aRect );
1188 // line numbers
1189 mpBackgrDev->SetFont( maHeaderFont );
1190 mpBackgrDev->SetTextColor( maHeaderTextColor );
1191 mpBackgrDev->SetTextFillColor();
1192 sal_Int32 nLastLine = GetLastVisLine();
1193 for( sal_Int32 nLine = GetFirstVisLine(); nLine <= nLastLine; ++nLine )
1195 OUString aText( OUString::number( nLine + 1 ) );
1196 sal_Int32 nX = GetHdrX() + (GetHdrWidth() - mpBackgrDev->GetTextWidth( aText )) / 2;
1197 mpBackgrDev->DrawText( Point( nX, GetY( nLine ) ), aText );
1200 // grid
1201 mpBackgrDev->SetLineColor( maHeaderGridColor );
1202 if( IsRTL() )
1204 mpBackgrDev->DrawLine( Point( 0, 0 ), Point( 0, GetHeight() - 1 ) );
1205 mpBackgrDev->DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
1207 else
1208 mpBackgrDev->DrawLine( aRect.TopRight(), aRect.BottomRight() );
1209 aRect.Top() = GetHdrHeight();
1210 mpBackgrDev->DrawGrid( aRect, Size( 1, GetLineHeight() ), DrawGridFlags::HorzLines );
1213 void ScCsvGrid::ImplDrawBackgrDev()
1215 mpBackgrDev->SetLineColor();
1216 mpBackgrDev->SetFillColor( maAppBackColor );
1217 mpBackgrDev->DrawRect( Rectangle(
1218 Point( GetFirstX() + 1, 0 ), Size( GetWidth() - GetHdrWidth(), GetHeight() ) ) );
1220 sal_uInt32 nLastCol = GetLastVisColumn();
1221 if (nLastCol == CSV_COLUMN_INVALID)
1222 return;
1223 for( sal_uInt32 nColIx = GetFirstVisColumn(); nColIx <= nLastCol; ++nColIx )
1224 ImplDrawColumnBackgr( nColIx );
1226 ImplDrawRowHeaders();
1229 void ScCsvGrid::ImplDrawColumnSelection( sal_uInt32 nColIndex )
1231 ImplInvertCursor( GetRulerCursorPos() );
1232 ImplSetColumnClipRegion( *mpGridDev.get(), nColIndex );
1233 mpGridDev->DrawOutDev( Point(), maWinSize, Point(), maWinSize, *mpBackgrDev.get() );
1235 if( IsSelected( nColIndex ) )
1237 sal_Int32 nX1 = GetColumnX( nColIndex ) + 1;
1238 sal_Int32 nX2 = GetColumnX( nColIndex + 1 );
1240 // header
1241 Rectangle aRect( nX1, 0, nX2, GetHdrHeight() );
1242 mpGridDev->SetLineColor();
1243 if( maHeaderBackColor.IsDark() )
1244 // redraw with light gray background in dark mode
1245 ImplDrawColumnHeader( *mpGridDev.get(), nColIndex, COL_LIGHTGRAY );
1246 else
1248 // use transparent active color
1249 mpGridDev->SetFillColor( maSelectColor );
1250 mpGridDev->DrawTransparent( tools::PolyPolygon( Polygon( aRect ) ), CSV_HDR_TRANSPARENCY );
1253 // column selection
1254 aRect = Rectangle( nX1, GetHdrHeight() + 1, nX2, GetY( GetLastVisLine() + 1 ) - 1 );
1255 ImplInvertRect( *mpGridDev.get(), aRect );
1258 mpGridDev->SetClipRegion();
1259 ImplInvertCursor( GetRulerCursorPos() );
1262 void ScCsvGrid::ImplDrawGridDev()
1264 mpGridDev->DrawOutDev( Point(), maWinSize, Point(), maWinSize, *mpBackgrDev );
1265 sal_uInt32 nLastCol = GetLastVisColumn();
1266 if (nLastCol == CSV_COLUMN_INVALID)
1267 return;
1268 for( sal_uInt32 nColIx = GetFirstVisColumn(); nColIx <= nLastCol; ++nColIx )
1269 ImplDrawColumnSelection( nColIx );
1272 void ScCsvGrid::ImplDrawColumn( sal_uInt32 nColIndex )
1274 ImplDrawColumnBackgr( nColIndex );
1275 ImplDrawColumnSelection( nColIndex );
1278 void ScCsvGrid::ImplDrawHorzScrolled( sal_Int32 nOldPos )
1280 sal_Int32 nPos = GetFirstVisPos();
1281 if( !IsValidGfx() || (nPos == nOldPos) )
1282 return;
1283 if( std::abs( nPos - nOldPos ) > GetVisPosCount() / 2 )
1285 ImplDrawBackgrDev();
1286 ImplDrawGridDev();
1287 return;
1290 Point aSrc, aDest;
1291 sal_uInt32 nFirstColIx, nLastColIx;
1292 if( nPos < nOldPos )
1294 aSrc = Point( GetFirstX() + 1, 0 );
1295 aDest = Point( GetFirstX() + GetCharWidth() * (nOldPos - nPos) + 1, 0 );
1296 nFirstColIx = GetColumnFromPos( nPos );
1297 nLastColIx = GetColumnFromPos( nOldPos );
1299 else
1301 aSrc = Point( GetFirstX() + GetCharWidth() * (nPos - nOldPos) + 1, 0 );
1302 aDest = Point( GetFirstX() + 1, 0 );
1303 nFirstColIx = GetColumnFromPos( std::min( nOldPos + GetVisPosCount(), GetPosCount() ) - 1 );
1304 nLastColIx = GetColumnFromPos( std::min( nPos + GetVisPosCount(), GetPosCount() ) - 1 );
1307 ImplInvertCursor( GetRulerCursorPos() + (nPos - nOldPos) );
1308 Rectangle aRectangle( GetFirstX(), 0, GetLastX(), GetHeight() - 1 );
1309 vcl::Region aClipReg( aRectangle );
1310 mpBackgrDev->SetClipRegion( aClipReg );
1311 mpBackgrDev->CopyArea( aDest, aSrc, maWinSize );
1312 mpBackgrDev->SetClipRegion();
1313 mpGridDev->SetClipRegion( aClipReg );
1314 mpGridDev->CopyArea( aDest, aSrc, maWinSize );
1315 mpGridDev->SetClipRegion();
1316 ImplInvertCursor( GetRulerCursorPos() );
1318 for( sal_uInt32 nColIx = nFirstColIx; nColIx <= nLastColIx; ++nColIx )
1319 ImplDrawColumn( nColIx );
1321 sal_Int32 nLastX = GetX( GetPosCount() ) + 1;
1322 if( nLastX <= GetLastX() )
1324 Rectangle aRect( nLastX, 0, GetLastX(), GetHeight() - 1 );
1325 mpBackgrDev->SetLineColor();
1326 mpBackgrDev->SetFillColor( maAppBackColor );
1327 mpBackgrDev->DrawRect( aRect );
1328 mpGridDev->SetLineColor();
1329 mpGridDev->SetFillColor( maAppBackColor );
1330 mpGridDev->DrawRect( aRect );
1334 void ScCsvGrid::ImplInvertCursor( sal_Int32 nPos )
1336 if( IsVisibleSplitPos( nPos ) )
1338 sal_Int32 nX = GetX( nPos ) - 1;
1339 Rectangle aRect( Point( nX, 0 ), Size( 3, GetHdrHeight() ) );
1340 ImplInvertRect( *mpGridDev.get(), aRect );
1341 aRect.Top() = GetHdrHeight() + 1;
1342 aRect.Bottom() = GetY( GetLastVisLine() + 1 );
1343 ImplInvertRect( *mpGridDev.get(), aRect );
1347 void ScCsvGrid::ImplDrawTrackingRect( sal_uInt32 nColIndex )
1349 if( HasFocus() && IsVisibleColumn( nColIndex ) )
1351 sal_Int32 nX1 = std::max( GetColumnX( nColIndex ), GetFirstX() ) + 1;
1352 sal_Int32 nX2 = std::min( GetColumnX( nColIndex + 1 ) - sal_Int32( 1 ), GetLastX() );
1353 sal_Int32 nY2 = std::min( GetY( GetLastVisLine() + 1 ), GetHeight() ) - 1;
1354 InvertTracking( Rectangle( nX1, 0, nX2, nY2 ), SHOWTRACK_SMALL | SHOWTRACK_WINDOW );
1358 // accessibility ==============================================================
1360 ScAccessibleCsvControl* ScCsvGrid::ImplCreateAccessible()
1362 std::unique_ptr<ScAccessibleCsvControl> pControl(new ScAccessibleCsvGrid( *this ));
1363 pControl->Init();
1364 return pControl.release();
1367 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */