1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <comphelper/lok.hxx>
21 #include <csvgrid.hxx>
22 #include <csvtablebox.hxx>
27 #include <svtools/colorcfg.hxx>
28 #include <sal/macros.h>
29 #include <tools/poly.hxx>
31 #include <asciiopt.hxx>
33 #include <AccessibleCsvControl.hxx>
35 // *** edit engine ***
36 #include <editeng/eeitem.hxx>
37 #include <vcl/commandevent.hxx>
38 #include <vcl/event.hxx>
39 #include <vcl/settings.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/virdev.hxx>
42 #include <vcl/weldutils.hxx>
44 #include <editeng/colritem.hxx>
45 #include <editeng/fhgtitem.hxx>
46 #include <editeng/fontitem.hxx>
47 #include <editeng/wghtitem.hxx>
48 #include <editeng/postitem.hxx>
49 #include <editeng/langitem.hxx>
50 #include <svl/itempool.hxx>
51 #include <svl/itemset.hxx>
52 #include <editutil.hxx>
53 // *** edit engine ***
60 explicit Func_SetType( sal_Int32 nType
) : mnType( nType
) {}
61 void operator()( ScCsvColState
& rState
) const
62 { rState
.mnType
= mnType
; }
68 explicit Func_Select( bool bSelect
) : mbSelect( bSelect
) {}
69 void operator()( ScCsvColState
& rState
) const
70 { rState
.Select( mbSelect
); }
75 ScCsvGrid::ScCsvGrid(const ScCsvLayoutData
& rData
, std::unique_ptr
<weld::Menu
> xPopup
, ScCsvTableBox
* pTableBox
)
77 , mpTableBox(pTableBox
)
78 , mpBackgrDev( VclPtr
<VirtualDevice
>::Create() )
79 , mpGridDev( VclPtr
<VirtualDevice
>::Create() )
80 , mxPopup(std::move(xPopup
))
81 , mpColorConfig( nullptr )
82 , mpEditEngine( new ScEditEngineDefaulter( EditEngine::CreatePool().get(), true ) )
86 , mnRecentSelCol( CSV_COLUMN_INVALID
)
87 , mnMTCurrCol( SAL_MAX_UINT32
)
89 , mbMTSelecting( false )
91 mpEditEngine
->SetRefDevice( mpBackgrDev
.get() );
92 mpEditEngine
->SetRefMapMode( MapMode( MapUnit::MapPixel
) );
93 maEdEngSize
= mpEditEngine
->GetPaperSize();
96 void ScCsvGrid::SetDrawingArea(weld::DrawingArea
* pDrawingArea
)
98 OutputDevice
& rRefDevice
= pDrawingArea
->get_ref_device();
99 maHeaderFont
= Application::GetSettings().GetStyleSettings().GetAppFont();
101 // expand the point size of the desired font to the equivalent pixel size
102 weld::SetPointFont(rRefDevice
, maHeaderFont
);
103 maHeaderFont
= rRefDevice
.GetFont();
105 // Because this is an always LeftToRight layout widget the initial size of
106 // this widget needs to be smaller than the size of the parent scrolling
107 // window (ScCsvTableBox ctor) because in RTL mode the alignment is against
108 // the right edge of the parent, and if larger than the scrolling window
109 // the left edge will be lost. If this widget is smaller than the scrolling
110 // window it is stretched to fit the parent and the problem doesn't arise.
111 Size
aInitialSize(10, 10);
112 if (comphelper::LibreOfficeKit::isActive())
113 aInitialSize
= Size(-1, 150);
114 ScCsvControl::SetDrawingArea(pDrawingArea
);
115 pDrawingArea
->set_size_request(aInitialSize
.Width(), aInitialSize
.Height());
116 SetOutputSizePixel(aInitialSize
);
118 EnableRTL( false ); // RTL
124 ScCsvGrid::~ScCsvGrid()
126 OSL_ENSURE(mpColorConfig
, "the object hasn't been initialized properly");
128 mpColorConfig
->RemoveListener(this);
129 mpBackgrDev
.disposeAndClear();
130 mpGridDev
.disposeAndClear();
136 OSL_PRECOND(!mpColorConfig
, "the object has already been initialized");
137 mpColorConfig
= &ScModule::get()->GetColorConfig();
139 mpColorConfig
->AddListener(this);
142 // common grid handling -------------------------------------------------------
144 void ScCsvGrid::UpdateLayoutData()
147 OutputDevice
& rRefDevice
= GetDrawingArea()->get_ref_device();
148 rRefDevice
.SetFont(maMonoFont
);
149 Execute(CSVCMD_SETCHARWIDTH
, rRefDevice
.GetTextWidth(OUString('X')));
150 Execute(CSVCMD_SETLINEHEIGHT
, rRefDevice
.GetTextHeight() + 1);
151 rRefDevice
.SetFont(maHeaderFont
);
152 Execute(CSVCMD_SETHDRHEIGHT
, rRefDevice
.GetTextHeight() + 1);
157 void ScCsvGrid::UpdateOffsetX()
159 sal_Int32 nLastLine
= GetLastVisLine() + 1;
160 sal_Int32 nDigits
= 2;
168 nDigits
= std::max( nDigits
, sal_Int32( 3 ) );
169 Execute(CSVCMD_SETHDRWIDTH
, GetDrawingArea()->get_approximate_digit_width() * nDigits
);
172 void ScCsvGrid::ApplyLayout( const ScCsvLayoutData
& rOldData
)
174 ScCsvDiff nDiff
= GetLayoutData().GetDiff( rOldData
);
175 if( nDiff
== ScCsvDiff::Equal
) return;
179 if( nDiff
& ScCsvDiff::RulerCursor
)
181 ImplInvertCursor( rOldData
.mnPosCursor
);
182 ImplInvertCursor( GetRulerCursorPos() );
185 if( nDiff
& ScCsvDiff::PosCount
)
187 if( GetPosCount() < rOldData
.mnPosCount
)
190 maSplits
.RemoveRange( GetPosCount(), rOldData
.mnPosCount
);
193 maSplits
.Remove( rOldData
.mnPosCount
);
194 maSplits
.Insert( GetPosCount() );
195 maColStates
.resize( maSplits
.Count() - 1 );
198 if( nDiff
& ScCsvDiff::LineOffset
)
200 Execute( CSVCMD_UPDATECELLTEXTS
);
204 ScCsvDiff nHVDiff
= nDiff
& (ScCsvDiff::HorizontalMask
| ScCsvDiff::VerticalMask
);
205 if( nHVDiff
== ScCsvDiff::PosOffset
)
206 ImplDrawHorzScrolled( rOldData
.mnPosOffset
);
207 else if( nHVDiff
!= ScCsvDiff::Equal
)
212 if( nDiff
& (ScCsvDiff::PosOffset
| ScCsvDiff::LineOffset
) )
213 AccSendVisibleEvent();
216 void ScCsvGrid::SetFirstImportedLine( sal_Int32 nLine
)
218 ImplDrawFirstLineSep( false );
219 mnFirstImpLine
= nLine
;
220 ImplDrawFirstLineSep( true );
225 sal_Int32
ScCsvGrid::GetNoScrollCol( sal_Int32 nPos
) const
227 sal_Int32 nNewPos
= nPos
;
228 if( nNewPos
!= CSV_POS_INVALID
)
230 if( nNewPos
< GetFirstVisPos() + CSV_SCROLL_DIST
)
232 sal_Int32 nScroll
= (GetFirstVisPos() > 0) ? CSV_SCROLL_DIST
: 0;
233 nNewPos
= GetFirstVisPos() + nScroll
;
235 else if( nNewPos
> GetLastVisPos() - CSV_SCROLL_DIST
- 1 )
237 sal_Int32 nScroll
= (GetFirstVisPos() < GetMaxPosOffset()) ? CSV_SCROLL_DIST
: 0;
238 nNewPos
= GetLastVisPos() - nScroll
- 1;
244 void ScCsvGrid::InitColors()
246 OSL_PRECOND(mpColorConfig
, "the object hasn't been initialized properly");
247 if ( !mpColorConfig
)
249 maBackColor
= mpColorConfig
->GetColorValue( ::svtools::DOCCOLOR
).nColor
;
250 maGridColor
= mpColorConfig
->GetColorValue( ::svtools::CALCGRID
).nColor
;
251 maGridPBColor
= mpColorConfig
->GetColorValue( ::svtools::CALCPAGEBREAK
).nColor
;
252 maAppBackColor
= mpColorConfig
->GetColorValue( ::svtools::APPBACKGROUND
).nColor
;
253 maTextColor
= mpColorConfig
->GetColorValue( ::svtools::FONTCOLOR
, false ).nColor
;
255 // tdf#147386 If Automatic font color is used, then check background color and use Black/White as font color
256 if ( maTextColor
== COL_AUTO
)
258 if ( maBackColor
.IsDark() )
259 maTextColor
= COL_WHITE
;
261 maTextColor
= COL_BLACK
;
264 const StyleSettings
& rSett
= Application::GetSettings().GetStyleSettings();
265 maHeaderBackColor
= rSett
.GetFaceColor();
266 maHeaderGridColor
= rSett
.GetDarkShadowColor();
267 maHeaderTextColor
= rSett
.GetButtonTextColor();
268 maSelectColor
= rSett
.GetActiveColor();
273 void ScCsvGrid::InitFonts()
275 maMonoFont
= OutputDevice::GetDefaultFont( DefaultFontType::FIXED
, LANGUAGE_ENGLISH_US
, GetDefaultFontFlags::NONE
);
276 maMonoFont
.SetFontSize( Size( maMonoFont
.GetFontSize().Width(), maHeaderFont
.GetFontSize().Height() ) );
278 /* *** Set edit engine defaults ***
279 maMonoFont for Latin script, smaller default font for Asian and Complex script. */
282 SvxFontItem
aLatinItem( EE_CHAR_FONTINFO
);
283 SvxFontItem
aAsianItem( EE_CHAR_FONTINFO_CJK
);
284 SvxFontItem
aComplexItem( EE_CHAR_FONTINFO_CTL
);
285 ::GetDefaultFonts( aLatinItem
, aAsianItem
, aComplexItem
);
287 // create item set for defaults
288 auto pDefSet
= std::make_unique
<SfxItemSet
>(mpEditEngine
->GetEmptyItemSet());
289 EditEngine::SetFontInfoInItemSet(*pDefSet
, maMonoFont
);
290 pDefSet
->Put(aAsianItem
);
291 pDefSet
->Put(aComplexItem
);
293 // set Asian/Complex font size to height of character in Latin font
294 sal_uLong nFontHt
= static_cast< sal_uLong
>( maMonoFont
.GetFontSize().Height() );
295 pDefSet
->Put(SvxFontHeightItem(nFontHt
, 100, EE_CHAR_FONTHEIGHT_CJK
));
296 pDefSet
->Put(SvxFontHeightItem(nFontHt
, 100, EE_CHAR_FONTHEIGHT_CTL
));
298 // copy other items from default font
299 const SfxPoolItem
& rWeightItem
= pDefSet
->Get(EE_CHAR_WEIGHT
);
300 std::unique_ptr
<SfxPoolItem
> pNewItem(rWeightItem
.Clone());
301 pNewItem
->SetWhich(EE_CHAR_WEIGHT_CJK
);
302 pDefSet
->Put(*pNewItem
);
303 pNewItem
->SetWhich(EE_CHAR_WEIGHT_CTL
);
304 pDefSet
->Put(*pNewItem
);
305 const SfxPoolItem
& rItalicItem
= pDefSet
->Get(EE_CHAR_ITALIC
);
306 pNewItem
.reset(rItalicItem
.Clone());
307 pNewItem
->SetWhich(EE_CHAR_ITALIC_CJK
);
308 pDefSet
->Put(*pNewItem
);
309 pNewItem
->SetWhich(EE_CHAR_ITALIC_CTL
);
310 pDefSet
->Put(*pNewItem
);
311 const SfxPoolItem
& rLangItem
= pDefSet
->Get(EE_CHAR_LANGUAGE
);
312 pNewItem
.reset(rLangItem
.Clone());
313 pNewItem
->SetWhich(EE_CHAR_LANGUAGE_CJK
);
314 pDefSet
->Put(*pNewItem
);
315 pNewItem
->SetWhich(EE_CHAR_LANGUAGE_CTL
);
316 pDefSet
->Put(*pNewItem
);
318 mpEditEngine
->SetDefaults(std::move(pDefSet
));
322 void ScCsvGrid::InitSizeData()
324 maWinSize
= GetOutputSizePixel();
325 mpBackgrDev
->SetOutputSizePixel( maWinSize
);
326 mpGridDev
->SetOutputSizePixel( maWinSize
);
330 // split handling -------------------------------------------------------------
332 void ScCsvGrid::InsertSplit( sal_Int32 nPos
)
334 if( ImplInsertSplit( nPos
) )
337 Execute( CSVCMD_EXPORTCOLUMNTYPE
);
338 Execute( CSVCMD_UPDATECELLTEXTS
);
339 sal_uInt32 nColIx
= GetColumnFromPos( nPos
);
340 ImplDrawColumn( nColIx
- 1 );
341 ImplDrawColumn( nColIx
);
342 ValidateGfx(); // performance: do not redraw all columns
347 void ScCsvGrid::RemoveSplit( sal_Int32 nPos
)
349 if( ImplRemoveSplit( nPos
) )
352 Execute( CSVCMD_EXPORTCOLUMNTYPE
);
353 Execute( CSVCMD_UPDATECELLTEXTS
);
354 ImplDrawColumn( GetColumnFromPos( nPos
) );
355 ValidateGfx(); // performance: do not redraw all columns
360 void ScCsvGrid::MoveSplit( sal_Int32 nPos
, sal_Int32 nNewPos
)
362 sal_uInt32 nColIx
= GetColumnFromPos( nPos
);
363 if( nColIx
== CSV_COLUMN_INVALID
)
367 if( (GetColumnPos( nColIx
- 1 ) < nNewPos
) && (nNewPos
< GetColumnPos( nColIx
+ 1 )) )
369 // move a split in the range between 2 others -> keep selection state of both columns
370 maSplits
.Remove( nPos
);
371 maSplits
.Insert( nNewPos
);
372 Execute( CSVCMD_UPDATECELLTEXTS
);
373 ImplDrawColumn( nColIx
- 1 );
374 ImplDrawColumn( nColIx
);
375 ValidateGfx(); // performance: do not redraw all columns
376 AccSendTableUpdateEvent( nColIx
- 1, nColIx
);
380 ImplRemoveSplit( nPos
);
381 ImplInsertSplit( nNewPos
);
382 Execute( CSVCMD_EXPORTCOLUMNTYPE
);
383 Execute( CSVCMD_UPDATECELLTEXTS
);
388 void ScCsvGrid::RemoveAllSplits()
392 Execute( CSVCMD_EXPORTCOLUMNTYPE
);
393 Execute( CSVCMD_UPDATECELLTEXTS
);
397 void ScCsvGrid::SetSplits( const ScCsvSplits
& rSplits
)
401 sal_uInt32 nCount
= rSplits
.Count();
402 for( sal_uInt32 nIx
= 0; nIx
< nCount
; ++nIx
)
403 maSplits
.Insert( rSplits
[ nIx
] );
405 maColStates
.resize( maSplits
.Count() - 1 );
406 Execute( CSVCMD_EXPORTCOLUMNTYPE
);
407 Execute( CSVCMD_UPDATECELLTEXTS
);
411 bool ScCsvGrid::ImplInsertSplit( sal_Int32 nPos
)
413 sal_uInt32 nColIx
= GetColumnFromPos( nPos
);
414 bool bRet
= (nColIx
< GetColumnCount()) && maSplits
.Insert( nPos
);
417 ScCsvColState
aState( GetColumnType( nColIx
) );
418 aState
.Select( IsSelected( nColIx
) && IsSelected( nColIx
+ 1 ) );
419 maColStates
.insert( maColStates
.begin() + nColIx
+ 1, aState
);
420 AccSendInsertColumnEvent( nColIx
+ 1, nColIx
+ 1 );
421 AccSendTableUpdateEvent( nColIx
, nColIx
);
426 bool ScCsvGrid::ImplRemoveSplit( sal_Int32 nPos
)
428 bool bRet
= maSplits
.Remove( nPos
);
431 sal_uInt32 nColIx
= GetColumnFromPos( nPos
);
432 bool bSel
= IsSelected( nColIx
) || IsSelected( nColIx
+ 1 );
433 maColStates
.erase( maColStates
.begin() + nColIx
+ 1 );
434 maColStates
[ nColIx
].Select( bSel
);
435 AccSendRemoveColumnEvent( nColIx
+ 1, nColIx
+ 1 );
436 AccSendTableUpdateEvent( nColIx
, nColIx
);
441 void ScCsvGrid::ImplClearSplits()
443 sal_uInt32 nColumns
= GetColumnCount();
445 maSplits
.Insert( 0 );
446 maSplits
.Insert( GetPosCount() );
447 maColStates
.resize( 1 );
449 AccSendRemoveColumnEvent( 1, nColumns
- 1 );
452 // columns/column types -------------------------------------------------------
454 sal_uInt32
ScCsvGrid::GetFirstVisColumn() const
456 return GetColumnFromPos( GetFirstVisPos() );
459 sal_uInt32
ScCsvGrid::GetLastVisColumn() const
461 return GetColumnFromPos( std::min( GetLastVisPos(), GetPosCount() ) - 1 );
464 bool ScCsvGrid::IsValidColumn( sal_uInt32 nColIndex
) const
466 return nColIndex
< GetColumnCount();
469 bool ScCsvGrid::IsVisibleColumn( sal_uInt32 nColIndex
) const
471 return IsValidColumn( nColIndex
) &&
472 (GetColumnPos( nColIndex
) < GetLastVisPos()) &&
473 (GetFirstVisPos() < GetColumnPos( nColIndex
+ 1 ));
476 sal_Int32
ScCsvGrid::GetColumnX( sal_uInt32 nColIndex
) const
478 return GetX( GetColumnPos( nColIndex
) );
481 sal_uInt32
ScCsvGrid::GetColumnFromX( sal_Int32 nX
) const
483 sal_Int32 nPos
= (nX
- GetFirstX()) / GetCharWidth() + GetFirstVisPos();
484 return ((GetFirstVisPos() <= nPos
) && (nPos
<= GetLastVisPos())) ?
485 GetColumnFromPos( nPos
) : CSV_COLUMN_INVALID
;
488 sal_uInt32
ScCsvGrid::GetColumnFromPos( sal_Int32 nPos
) const
490 return maSplits
.UpperBound( nPos
);
493 sal_Int32
ScCsvGrid::GetColumnWidth( sal_uInt32 nColIndex
) const
495 return IsValidColumn( nColIndex
) ? (GetColumnPos( nColIndex
+ 1 ) - GetColumnPos( nColIndex
)) : 0;
498 void ScCsvGrid::SetColumnStates( ScCsvColStateVec
&& rStates
)
500 maColStates
= std::move(rStates
);
501 maColStates
.resize( maSplits
.Count() - 1 );
502 Execute( CSVCMD_EXPORTCOLUMNTYPE
);
503 AccSendTableUpdateEvent( 0, GetColumnCount(), false );
504 AccSendSelectionEvent();
507 sal_Int32
ScCsvGrid::GetColumnType( sal_uInt32 nColIndex
) const
509 return IsValidColumn( nColIndex
) ? maColStates
[ nColIndex
].mnType
: CSV_TYPE_NOSELECTION
;
512 void ScCsvGrid::SetColumnType( sal_uInt32 nColIndex
, sal_Int32 nColType
)
514 if( IsValidColumn( nColIndex
) )
516 maColStates
[ nColIndex
].mnType
= nColType
;
517 AccSendTableUpdateEvent( nColIndex
, nColIndex
, false );
521 sal_Int32
ScCsvGrid::GetSelColumnType() const
523 sal_uInt32 nColIx
= GetFirstSelected();
524 if( nColIx
== CSV_COLUMN_INVALID
)
525 return CSV_TYPE_NOSELECTION
;
527 sal_Int32 nType
= GetColumnType( nColIx
);
528 while( (nColIx
!= CSV_COLUMN_INVALID
) && (nType
!= CSV_TYPE_MULTI
) )
530 if( nType
!= GetColumnType( nColIx
) )
531 nType
= CSV_TYPE_MULTI
;
532 nColIx
= GetNextSelected( nColIx
);
537 void ScCsvGrid::SetSelColumnType( sal_Int32 nType
)
539 if( (nType
!= CSV_TYPE_MULTI
) && (nType
!= CSV_TYPE_NOSELECTION
) )
541 for( sal_uInt32 nColIx
= GetFirstSelected(); nColIx
!= CSV_COLUMN_INVALID
; nColIx
= GetNextSelected( nColIx
) )
542 SetColumnType( nColIx
, nType
);
544 Execute( CSVCMD_EXPORTCOLUMNTYPE
);
548 void ScCsvGrid::SetTypeNames( std::vector
<OUString
>&& rTypeNames
)
550 OSL_ENSURE( !rTypeNames
.empty(), "ScCsvGrid::SetTypeNames - vector is empty" );
551 maTypeNames
= std::move(rTypeNames
);
555 sal_uInt32 nCount
= maTypeNames
.size();
556 for (sal_uInt32 nIx
= 0; nIx
< nCount
; ++nIx
)
557 mxPopup
->append(OUString::number(nIx
), maTypeNames
[nIx
]);
559 ::std::for_each( maColStates
.begin(), maColStates
.end(), Func_SetType( CSV_TYPE_DEFAULT
) );
562 OUString
ScCsvGrid::GetColumnTypeName( sal_uInt32 nColIndex
) const
564 sal_uInt32 nTypeIx
= static_cast< sal_uInt32
>( GetColumnType( nColIndex
) );
565 return (nTypeIx
< maTypeNames
.size()) ? maTypeNames
[ nTypeIx
] : OUString();
568 static sal_uInt8
lcl_GetExtColumnType( sal_Int32 nIntType
)
570 static const sal_uInt8 pExtTypes
[] =
571 { SC_COL_STANDARD
, SC_COL_TEXT
, SC_COL_DMY
, SC_COL_MDY
, SC_COL_YMD
, SC_COL_ENGLISH
, SC_COL_SKIP
};
572 static const sal_Int32 nExtTypeCount
= SAL_N_ELEMENTS(pExtTypes
);
573 return pExtTypes
[ ((0 <= nIntType
) && (nIntType
< nExtTypeCount
)) ? nIntType
: 0 ];
576 void ScCsvGrid::FillColumnDataSep( ScAsciiOptions
& rOptions
) const
578 sal_uInt32 nCount
= GetColumnCount();
579 ScCsvExpDataVec aDataVec
;
581 for( sal_uInt32 nColIx
= 0; nColIx
< nCount
; ++nColIx
)
583 if( GetColumnType( nColIx
) != CSV_TYPE_DEFAULT
)
584 // 1-based column index
585 aDataVec
.emplace_back(
586 static_cast< sal_Int32
>( nColIx
+ 1 ),
587 lcl_GetExtColumnType( GetColumnType( nColIx
) ) );
589 rOptions
.SetColumnInfo( aDataVec
);
592 void ScCsvGrid::FillColumnDataFix( ScAsciiOptions
& rOptions
) const
594 sal_uInt32 nCount
= std::min( GetColumnCount(), static_cast<sal_uInt32
>(MAXCOLCOUNT
) );
595 ScCsvExpDataVec
aDataVec( nCount
+ 1 );
597 for( sal_uInt32 nColIx
= 0; nColIx
< nCount
; ++nColIx
)
599 ScCsvExpData
& rData
= aDataVec
[ nColIx
];
600 rData
.mnIndex
= GetColumnPos( nColIx
);
601 rData
.mnType
= lcl_GetExtColumnType( GetColumnType( nColIx
) );
603 aDataVec
[ nCount
].mnIndex
= SAL_MAX_INT32
;
604 aDataVec
[ nCount
].mnType
= SC_COL_SKIP
;
605 rOptions
.SetColumnInfo( aDataVec
);
608 void ScCsvGrid::ScrollVertRel( ScMoveMode eDir
)
610 sal_Int32 nLine
= GetFirstVisLine();
613 case MOVE_PREV
: --nLine
; break;
614 case MOVE_NEXT
: ++nLine
; break;
615 case MOVE_FIRST
: nLine
= 0; break;
616 case MOVE_LAST
: nLine
= GetMaxLineOffset(); break;
617 case MOVE_PREVPAGE
: nLine
-= GetVisLineCount() - 2; break;
618 case MOVE_NEXTPAGE
: nLine
+= GetVisLineCount() - 2; break;
621 // added to avoid warnings
624 Execute( CSVCMD_SETLINEOFFSET
, nLine
);
627 void ScCsvGrid::ExecutePopup( const Point
& rPos
)
629 OUString sItemId
= mxPopup
->popup_at_rect(GetDrawingArea(), tools::Rectangle(rPos
, Size(1, 1)));
630 if (!sItemId
.isEmpty()) // empty = cancelled
631 Execute(CSVCMD_SETCOLUMNTYPE
, sItemId
.toInt32());
634 // selection handling ---------------------------------------------------------
636 bool ScCsvGrid::IsSelected( sal_uInt32 nColIndex
) const
638 return IsValidColumn( nColIndex
) && maColStates
[ nColIndex
].IsSelected();
641 sal_uInt32
ScCsvGrid::GetFirstSelected() const
643 return IsSelected( 0 ) ? 0 : GetNextSelected( 0 );
646 sal_uInt32
ScCsvGrid::GetNextSelected( sal_uInt32 nFromIndex
) const
648 sal_uInt32 nColCount
= GetColumnCount();
649 for( sal_uInt32 nColIx
= nFromIndex
+ 1; nColIx
< nColCount
; ++nColIx
)
650 if( IsSelected( nColIx
) )
652 return CSV_COLUMN_INVALID
;
655 void ScCsvGrid::Select( sal_uInt32 nColIndex
, bool bSelect
)
657 if( IsValidColumn( nColIndex
) )
659 maColStates
[ nColIndex
].Select( bSelect
);
660 ImplDrawColumnSelection( nColIndex
);
662 Execute( CSVCMD_EXPORTCOLUMNTYPE
);
664 mnRecentSelCol
= nColIndex
;
665 AccSendSelectionEvent();
669 void ScCsvGrid::ToggleSelect( sal_uInt32 nColIndex
)
671 Select( nColIndex
, !IsSelected( nColIndex
) );
674 void ScCsvGrid::SelectRange( sal_uInt32 nColIndex1
, sal_uInt32 nColIndex2
, bool bSelect
)
676 if( nColIndex1
== CSV_COLUMN_INVALID
)
677 Select( nColIndex2
);
678 else if( nColIndex2
== CSV_COLUMN_INVALID
)
679 Select( nColIndex1
);
680 else if( nColIndex1
> nColIndex2
)
682 SelectRange( nColIndex2
, nColIndex1
, bSelect
);
684 mnRecentSelCol
= nColIndex1
;
686 else if( IsValidColumn( nColIndex1
) && IsValidColumn( nColIndex2
) )
688 for( sal_uInt32 nColIx
= nColIndex1
; nColIx
<= nColIndex2
; ++nColIx
)
690 maColStates
[ nColIx
].Select( bSelect
);
691 ImplDrawColumnSelection( nColIx
);
694 Execute( CSVCMD_EXPORTCOLUMNTYPE
);
696 mnRecentSelCol
= nColIndex1
;
697 AccSendSelectionEvent();
701 void ScCsvGrid::SelectAll( bool bSelect
)
703 SelectRange( 0, GetColumnCount() - 1, bSelect
);
706 void ScCsvGrid::MoveCursor( sal_uInt32 nColIndex
)
709 if( IsValidColumn( nColIndex
) )
711 sal_Int32 nPosBeg
= GetColumnPos( nColIndex
);
712 sal_Int32 nPosEnd
= GetColumnPos( nColIndex
+ 1 );
713 sal_Int32 nMinPos
= std::max( nPosBeg
- CSV_SCROLL_DIST
, sal_Int32( 0 ) );
714 sal_Int32 nMaxPos
= std::min( nPosEnd
- GetVisPosCount() + CSV_SCROLL_DIST
+ sal_Int32( 1 ), nMinPos
);
715 if( nPosBeg
- CSV_SCROLL_DIST
+ 1 <= GetFirstVisPos() )
716 Execute( CSVCMD_SETPOSOFFSET
, nMinPos
);
717 else if( nPosEnd
+ CSV_SCROLL_DIST
>= GetLastVisPos() )
718 Execute( CSVCMD_SETPOSOFFSET
, nMaxPos
);
720 Execute( CSVCMD_MOVEGRIDCURSOR
, GetColumnPos( nColIndex
) );
724 void ScCsvGrid::MoveCursorRel( ScMoveMode eDir
)
726 if( GetFocusColumn() == CSV_COLUMN_INVALID
)
735 MoveCursor( GetColumnCount() - 1 );
738 if( GetFocusColumn() > 0 )
739 MoveCursor( GetFocusColumn() - 1 );
742 if( GetFocusColumn() < GetColumnCount() - 1 )
743 MoveCursor( GetFocusColumn() + 1 );
747 // added to avoid warnings
752 void ScCsvGrid::ImplClearSelection()
754 ::std::for_each( maColStates
.begin(), maColStates
.end(), Func_Select( false ) );
758 void ScCsvGrid::DoSelectAction( sal_uInt32 nColIndex
, sal_uInt16 nModifier
)
760 if( !(nModifier
& KEY_MOD1
) )
761 ImplClearSelection();
762 if( nModifier
& KEY_SHIFT
) // SHIFT always expands
763 SelectRange( mnRecentSelCol
, nColIndex
);
764 else if( !(nModifier
& KEY_MOD1
) ) // no SHIFT/CTRL always selects 1 column
766 else if( mbTracking
) // CTRL in tracking does not toggle
767 Select( nColIndex
, mbMTSelecting
);
768 else // CTRL only toggles
769 ToggleSelect( nColIndex
);
770 Execute( CSVCMD_MOVEGRIDCURSOR
, GetColumnPos( nColIndex
) );
773 // cell contents --------------------------------------------------------------
775 void ScCsvGrid::ImplSetTextLineSep(
776 sal_Int32 nLine
, const OUString
& rTextLine
,
777 const OUString
& rSepChars
, sal_Unicode cTextSep
, bool bMergeSep
, bool bRemoveSpace
)
779 if( nLine
< GetFirstVisLine() ) return;
781 sal_uInt32 nLineIx
= nLine
- GetFirstVisLine();
782 while( maTexts
.size() <= nLineIx
)
783 maTexts
.emplace_back( );
784 std::vector
<OUString
>& rStrVec
= maTexts
[ nLineIx
];
787 // scan for separators
789 const sal_Unicode
* pSepChars
= rSepChars
.getStr();
790 const sal_Unicode
* pChar
= rTextLine
.getStr();
791 sal_uInt32 nColIx
= 0;
793 while( *pChar
&& (nColIx
< sal::static_int_cast
<sal_uInt32
>(CSV_MAXCOLCOUNT
)) )
795 // scan for next cell text
796 bool bIsQuoted
= false;
797 bool bOverflowCell
= false;
798 pChar
= ScImportExport::ScanNextFieldFromString( pChar
, aCellText
,
799 cTextSep
, pSepChars
, bMergeSep
, bIsQuoted
, bOverflowCell
, bRemoveSpace
);
800 /* TODO: signal overflow somewhere in UI */
802 // update column width
803 sal_Int32 nWidth
= std::max( CSV_MINCOLWIDTH
, ScImportExport::CountVisualWidth( aCellText
) + 1 );
804 if( IsValidColumn( nColIx
) )
806 // expand existing column
807 sal_Int32 nDiff
= nWidth
- GetColumnWidth( nColIx
);
810 Execute( CSVCMD_SETPOSCOUNT
, GetPosCount() + nDiff
);
811 for( sal_uInt32 nSplitIx
= GetColumnCount() - 1; nSplitIx
> nColIx
; --nSplitIx
)
813 sal_Int32 nPos
= maSplits
[ nSplitIx
];
814 maSplits
.Remove( nPos
);
815 maSplits
.Insert( nPos
+ nDiff
);
822 sal_Int32 nLastPos
= GetPosCount();
823 Execute( CSVCMD_SETPOSCOUNT
, nLastPos
+ nWidth
);
824 ImplInsertSplit( nLastPos
);
827 if( aCellText
.getLength() <= CSV_MAXSTRLEN
)
828 rStrVec
.push_back( aCellText
);
830 rStrVec
.push_back( aCellText
.copy( 0, CSV_MAXSTRLEN
) );
836 void ScCsvGrid::ImplSetTextLineFix( sal_Int32 nLine
, std::u16string_view rTextLine
)
838 if( nLine
< GetFirstVisLine() ) return;
840 sal_Int32 nWidth
= ScImportExport::CountVisualWidth( rTextLine
);
841 if( nWidth
> GetPosCount() )
842 Execute( CSVCMD_SETPOSCOUNT
, nWidth
);
844 sal_uInt32 nLineIx
= nLine
- GetFirstVisLine();
845 while( maTexts
.size() <= nLineIx
)
846 maTexts
.emplace_back( );
848 std::vector
<OUString
>& rStrVec
= maTexts
[ nLineIx
];
850 sal_uInt32 nColCount
= GetColumnCount();
851 sal_Int32 nStrLen
= rTextLine
.size();
852 sal_Int32 nStrIx
= 0;
853 for( sal_uInt32 nColIx
= 0; (nColIx
< nColCount
) && (nStrIx
< nStrLen
); ++nColIx
)
855 sal_Int32 nColWidth
= GetColumnWidth( nColIx
);
856 sal_Int32 nLastIx
= nStrIx
;
857 ScImportExport::CountVisualWidth( rTextLine
, nLastIx
, nColWidth
);
858 sal_Int32 nLen
= std::min( CSV_MAXSTRLEN
, nLastIx
- nStrIx
);
859 rStrVec
.push_back( OUString(rTextLine
.substr( nStrIx
, nLen
)) );
860 nStrIx
= nStrIx
+ nLen
;
865 OUString
ScCsvGrid::GetCellText( sal_uInt32 nColIndex
, sal_Int32 nLine
) const
867 if( nLine
< GetFirstVisLine() ) return OUString();
869 sal_uInt32 nLineIx
= nLine
- GetFirstVisLine();
870 if( nLineIx
>= maTexts
.size() ) return OUString();
872 const std::vector
<OUString
>& rStrVec
= maTexts
[ nLineIx
];
873 if( nColIndex
>= rStrVec
.size() ) return OUString();
875 return rStrVec
[ nColIndex
];
878 // event handling -------------------------------------------------------------
880 void ScCsvGrid::Resize()
882 mpTableBox
->InitControls();
884 ScCsvControl::Resize();
886 Execute( CSVCMD_UPDATECELLTEXTS
);
889 void ScCsvGrid::GetFocus()
891 ScCsvControl::GetFocus();
892 Execute( CSVCMD_MOVEGRIDCURSOR
, GetNoScrollCol( GetGridCursorPos() ) );
896 void ScCsvGrid::LoseFocus()
898 ScCsvControl::LoseFocus();
902 bool ScCsvGrid::MouseButtonDown( const MouseEvent
& rMEvt
)
908 Point
aPos( rMEvt
.GetPosPixel() );
909 sal_uInt32 nColIx
= GetColumnFromX( aPos
.X() );
913 if( (GetFirstX() > aPos
.X()) || (aPos
.X() > GetLastX()) ) // in header column
915 if( aPos
.Y() <= GetHdrHeight() )
918 else if( IsValidColumn( nColIx
) )
920 DoSelectAction( nColIx
, rMEvt
.GetModifier() );
921 mnMTCurrCol
= nColIx
;
922 mbMTSelecting
= IsSelected( nColIx
);
930 bool ScCsvGrid::MouseButtonUp( const MouseEvent
& )
936 bool ScCsvGrid::MouseMove( const MouseEvent
& rMEvt
)
943 sal_Int32 nPos
= (rMEvt
.GetPosPixel().X() - GetFirstX()) / GetCharWidth() + GetFirstVisPos();
944 // on mouse tracking: keep position valid
945 nPos
= std::clamp( nPos
, sal_Int32(0), GetPosCount() - 1 );
946 Execute( CSVCMD_MAKEPOSVISIBLE
, nPos
);
948 sal_uInt32 nColIx
= GetColumnFromPos( nPos
);
949 if( mnMTCurrCol
!= nColIx
)
951 DoSelectAction( nColIx
, rMEvt
.GetModifier() );
952 mnMTCurrCol
= nColIx
;
959 bool ScCsvGrid::KeyInput( const KeyEvent
& rKEvt
)
961 const vcl::KeyCode
& rKCode
= rKEvt
.GetKeyCode();
962 sal_uInt16 nCode
= rKCode
.GetCode();
963 bool bShift
= rKCode
.IsShift();
964 bool bMod1
= rKCode
.IsMod1();
966 if( !rKCode
.IsMod2() )
968 ScMoveMode eHDir
= GetHorzDirection( nCode
, !bMod1
);
969 ScMoveMode eVDir
= GetVertDirection( nCode
, bMod1
);
971 if( eHDir
!= MOVE_NONE
)
974 MoveCursorRel( eHDir
);
976 ImplClearSelection();
978 SelectRange( mnRecentSelCol
, GetFocusColumn() );
980 Select( GetFocusColumn() );
983 else if( eVDir
!= MOVE_NONE
)
984 ScrollVertRel( eVDir
);
985 else if( nCode
== KEY_SPACE
)
988 ImplClearSelection();
990 SelectRange( mnRecentSelCol
, GetFocusColumn() );
992 ToggleSelect( GetFocusColumn() );
994 Select( GetFocusColumn() );
996 else if( !bShift
&& bMod1
)
1000 else if( (KEY_1
<= nCode
) && (nCode
<= KEY_9
) )
1002 sal_uInt32 nType
= nCode
- KEY_1
;
1003 if( nType
< maTypeNames
.size() )
1004 Execute( CSVCMD_SETCOLUMNTYPE
, nType
);
1009 return rKCode
.GetGroup() == KEYGROUP_CURSOR
;
1012 bool ScCsvGrid::Command( const CommandEvent
& rCEvt
)
1014 bool bConsumed
= true;
1015 switch( rCEvt
.GetCommand() )
1017 case CommandEventId::ContextMenu
:
1019 if( rCEvt
.IsMouseEvent() )
1021 Point
aPos( rCEvt
.GetMousePosPixel() );
1022 sal_uInt32 nColIx
= GetColumnFromX( aPos
.X() );
1023 if( IsValidColumn( nColIx
) && (GetFirstX() <= aPos
.X()) && (aPos
.X() <= GetLastX()) )
1025 if( !IsSelected( nColIx
) )
1026 DoSelectAction( nColIx
, 0 ); // focus & select
1027 ExecutePopup( aPos
);
1032 sal_uInt32 nColIx
= GetFocusColumn();
1033 if( !IsSelected( nColIx
) )
1035 sal_Int32 nX1
= std::max( GetColumnX( nColIx
), GetFirstX() );
1036 sal_Int32 nX2
= std::min( GetColumnX( nColIx
+ 1 ), GetWidth() );
1037 ExecutePopup( Point( (nX1
+ nX2
) / 2, GetHeight() / 2 ) );
1041 case CommandEventId::Wheel
:
1043 tools::Rectangle
aRect( Point(), maWinSize
);
1044 if( aRect
.Contains( rCEvt
.GetMousePosPixel() ) )
1046 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
1047 if( pData
&& (pData
->GetMode() == CommandWheelMode::SCROLL
) && !pData
->IsHorz() )
1048 Execute( CSVCMD_SETLINEOFFSET
, GetFirstVisLine() - pData
->GetNotchDelta() );
1059 void ScCsvGrid::StyleUpdated()
1064 Execute( CSVCMD_UPDATECELLTEXTS
);
1066 ScCsvControl::StyleUpdated();
1069 void ScCsvGrid::ConfigurationChanged( utl::ConfigurationBroadcaster
*, ConfigurationHints
)
1075 // painting -------------------------------------------------------------------
1077 void ScCsvGrid::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1079 ImplRedraw(rRenderContext
);
1082 void ScCsvGrid::ImplRedraw(vcl::RenderContext
& rRenderContext
)
1089 ImplDrawBackgrDev();
1092 rRenderContext
.DrawOutDev( Point(), maWinSize
, Point(), maWinSize
, *mpGridDev
);
1096 EditEngine
* ScCsvGrid::GetEditEngine()
1098 return mpEditEngine
.get();
1101 void ScCsvGrid::ImplSetColumnClipRegion( OutputDevice
& rOutDev
, sal_uInt32 nColIndex
)
1103 rOutDev
.SetClipRegion( vcl::Region( tools::Rectangle(
1104 std::max( GetColumnX( nColIndex
), GetFirstX() ) + 1, 0,
1105 std::min( GetColumnX( nColIndex
+ 1 ), GetLastX() ), GetHeight() - 1 ) ) );
1108 void ScCsvGrid::ImplDrawColumnHeader( OutputDevice
& rOutDev
, sal_uInt32 nColIndex
, Color aFillColor
)
1110 sal_Int32 nX1
= GetColumnX( nColIndex
) + 1;
1111 sal_Int32 nX2
= GetColumnX( nColIndex
+ 1 );
1112 sal_Int32 nHdrHt
= GetHdrHeight();
1114 rOutDev
.SetLineColor();
1115 rOutDev
.SetFillColor( aFillColor
);
1116 rOutDev
.DrawRect( tools::Rectangle( nX1
, 0, nX2
, nHdrHt
) );
1118 rOutDev
.SetFont( maHeaderFont
);
1119 rOutDev
.SetTextColor( maHeaderTextColor
);
1120 rOutDev
.SetTextFillColor();
1121 rOutDev
.DrawText( Point( nX1
+ 1, 0 ), GetColumnTypeName( nColIndex
) );
1123 rOutDev
.SetLineColor( maHeaderGridColor
);
1124 rOutDev
.DrawLine( Point( nX1
, nHdrHt
), Point( nX2
, nHdrHt
) );
1125 rOutDev
.DrawLine( Point( nX2
, 0 ), Point( nX2
, nHdrHt
) );
1128 void ScCsvGrid::ImplDrawCellText( const Point
& rPos
, const OUString
& rText
)
1130 OUString aPlainText
= rText
.replaceAll( "\t", " " );
1131 aPlainText
= aPlainText
.replaceAll( "\n", " " );
1132 mpEditEngine
->SetPaperSize( maEdEngSize
);
1133 mpEditEngine
->SetTextCurrentDefaults(aPlainText
);
1134 mpEditEngine
->Draw(*mpBackgrDev
, rPos
);
1136 sal_Int32 nCharIx
= 0;
1137 while( (nCharIx
= rText
.indexOf( '\t', nCharIx
)) != -1 )
1139 sal_Int32 nX1
= rPos
.X() + GetCharWidth() * nCharIx
;
1140 sal_Int32 nX2
= nX1
+ GetCharWidth() - 2;
1141 sal_Int32 nY
= rPos
.Y() + GetLineHeight() / 2;
1142 Color
aColor( maTextColor
);
1143 mpBackgrDev
->SetLineColor( aColor
);
1144 mpBackgrDev
->DrawLine( Point( nX1
, nY
), Point( nX2
, nY
) );
1145 mpBackgrDev
->DrawLine( Point( nX2
- 2, nY
- 2 ), Point( nX2
, nY
) );
1146 mpBackgrDev
->DrawLine( Point( nX2
- 2, nY
+ 2 ), Point( nX2
, nY
) );
1150 while( (nCharIx
= rText
.indexOf( '\n', nCharIx
)) != -1 )
1152 sal_Int32 nX1
= rPos
.X() + GetCharWidth() * nCharIx
;
1153 sal_Int32 nX2
= nX1
+ GetCharWidth() - 2;
1154 sal_Int32 nY
= rPos
.Y() + GetLineHeight() / 2;
1155 Color
aColor( maTextColor
);
1156 mpBackgrDev
->SetLineColor( aColor
);
1157 mpBackgrDev
->DrawLine( Point( nX1
, nY
), Point( nX2
, nY
) );
1158 mpBackgrDev
->DrawLine( Point( nX1
+ 2, nY
- 2 ), Point( nX1
, nY
) );
1159 mpBackgrDev
->DrawLine( Point( nX1
+ 2, nY
+ 2 ), Point( nX1
, nY
) );
1160 mpBackgrDev
->DrawLine( Point( nX2
, nY
- 2 ), Point( nX2
, nY
) );
1165 void ScCsvGrid::ImplDrawFirstLineSep( bool bSet
)
1167 if( IsVisibleLine( mnFirstImpLine
) && (mnFirstImpLine
!= GetFirstVisLine() ) )
1169 sal_Int32 nY
= GetY( mnFirstImpLine
);
1170 sal_Int32 nX
= std::min( GetColumnX( GetLastVisColumn() + 1 ), GetLastX() );
1171 mpBackgrDev
->SetLineColor( bSet
? maGridPBColor
: maGridColor
);
1172 mpBackgrDev
->DrawLine( Point( GetFirstX() + 1, nY
), Point( nX
, nY
) );
1176 void ScCsvGrid::ImplDrawColumnBackgr( sal_uInt32 nColIndex
)
1178 if( !IsVisibleColumn( nColIndex
) )
1181 ImplSetColumnClipRegion( *mpBackgrDev
, nColIndex
);
1184 mpBackgrDev
->SetLineColor();
1185 mpBackgrDev
->SetFillColor( maBackColor
);
1186 sal_Int32 nX1
= GetColumnX( nColIndex
) + 1;
1187 sal_Int32 nX2
= GetColumnX( nColIndex
+ 1 );
1188 sal_Int32 nY2
= GetY( GetLastVisLine() + 1 );
1189 sal_Int32 nHdrHt
= GetHdrHeight();
1190 tools::Rectangle
aRect( nX1
, nHdrHt
, nX2
, nY2
);
1191 mpBackgrDev
->DrawRect( aRect
);
1192 mpBackgrDev
->SetLineColor( maGridColor
);
1193 mpBackgrDev
->DrawGrid( aRect
, Size( 1, GetLineHeight() ), DrawGridFlags::HorzLines
);
1194 mpBackgrDev
->DrawLine( Point( nX2
, nHdrHt
), Point( nX2
, nY2
) );
1195 ImplDrawFirstLineSep( true );
1198 mpEditEngine
->SetDefaultItem( SvxColorItem( maTextColor
, EE_CHAR_COLOR
) );
1199 size_t nLineCount
= ::std::min( static_cast< size_t >( GetLastVisLine() - GetFirstVisLine() + 1 ), maTexts
.size() );
1200 // #i67432# cut string to avoid edit engine performance problems with very large strings
1201 sal_Int32 nFirstVisPos
= ::std::max( GetColumnPos( nColIndex
), GetFirstVisPos() );
1202 sal_Int32 nLastVisPos
= ::std::min( GetColumnPos( nColIndex
+ 1 ), GetLastVisPos() );
1203 sal_Int32 nStrPos
= nFirstVisPos
- GetColumnPos( nColIndex
);
1204 sal_Int32 nStrLen
= nLastVisPos
- nFirstVisPos
+ 1;
1205 sal_Int32 nStrX
= GetX( nFirstVisPos
);
1206 for( size_t nLine
= 0; nLine
< nLineCount
; ++nLine
)
1208 std::vector
<OUString
>& rStrVec
= maTexts
[ nLine
];
1209 if( (nColIndex
< rStrVec
.size()) && (rStrVec
[ nColIndex
].getLength() > nStrPos
) )
1211 const OUString
& rStr
= rStrVec
[ nColIndex
];
1212 OUString aText
= rStr
.copy( nStrPos
, ::std::min( nStrLen
, rStr
.getLength() - nStrPos
) );
1213 ImplDrawCellText( Point( nStrX
, GetY( GetFirstVisLine() + nLine
) ), aText
);
1218 ImplDrawColumnHeader( *mpBackgrDev
, nColIndex
, maHeaderBackColor
);
1220 mpBackgrDev
->SetClipRegion();
1223 void ScCsvGrid::ImplDrawRowHeaders()
1225 mpBackgrDev
->SetLineColor();
1226 mpBackgrDev
->SetFillColor( maAppBackColor
);
1227 Point
aPoint( GetHdrX(), 0 );
1228 tools::Rectangle
aRect( aPoint
, Size( GetHdrWidth() + 1, GetHeight() ) );
1229 mpBackgrDev
->DrawRect( aRect
);
1231 mpBackgrDev
->SetFillColor( maHeaderBackColor
);
1232 aRect
.SetBottom( GetY( GetLastVisLine() + 1 ) );
1233 mpBackgrDev
->DrawRect( aRect
);
1236 mpBackgrDev
->SetFont( maHeaderFont
);
1237 mpBackgrDev
->SetTextColor( maHeaderTextColor
);
1238 mpBackgrDev
->SetTextFillColor();
1239 sal_Int32 nLastLine
= GetLastVisLine();
1240 for( sal_Int32 nLine
= GetFirstVisLine(); nLine
<= nLastLine
; ++nLine
)
1242 OUString
aText( OUString::number( nLine
+ 1 ) );
1243 sal_Int32 nX
= GetHdrX() + (GetHdrWidth() - mpBackgrDev
->GetTextWidth( aText
)) / 2;
1244 mpBackgrDev
->DrawText( Point( nX
, GetY( nLine
) ), aText
);
1248 mpBackgrDev
->SetLineColor( maHeaderGridColor
);
1251 mpBackgrDev
->DrawLine( Point( 0, 0 ), Point( 0, GetHeight() - 1 ) );
1252 mpBackgrDev
->DrawLine( aRect
.TopLeft(), aRect
.BottomLeft() );
1255 mpBackgrDev
->DrawLine( aRect
.TopRight(), aRect
.BottomRight() );
1256 aRect
.SetTop( GetHdrHeight() );
1257 mpBackgrDev
->DrawGrid( aRect
, Size( 1, GetLineHeight() ), DrawGridFlags::HorzLines
);
1260 void ScCsvGrid::ImplDrawBackgrDev()
1262 mpBackgrDev
->SetLineColor();
1263 mpBackgrDev
->SetFillColor( maAppBackColor
);
1264 mpBackgrDev
->DrawRect( tools::Rectangle(
1265 Point( GetFirstX() + 1, 0 ), Size( GetWidth() - GetHdrWidth(), GetHeight() ) ) );
1267 sal_uInt32 nLastCol
= GetLastVisColumn();
1268 if (nLastCol
== CSV_COLUMN_INVALID
)
1270 for( sal_uInt32 nColIx
= GetFirstVisColumn(); nColIx
<= nLastCol
; ++nColIx
)
1271 ImplDrawColumnBackgr( nColIx
);
1273 ImplDrawRowHeaders();
1276 void ScCsvGrid::ImplDrawColumnSelection( sal_uInt32 nColIndex
)
1278 ImplInvertCursor( GetRulerCursorPos() );
1279 ImplSetColumnClipRegion( *mpGridDev
, nColIndex
);
1280 mpGridDev
->DrawOutDev( Point(), maWinSize
, Point(), maWinSize
, *mpBackgrDev
);
1282 if( IsSelected( nColIndex
) )
1284 sal_Int32 nX1
= GetColumnX( nColIndex
) + 1;
1285 sal_Int32 nX2
= GetColumnX( nColIndex
+ 1 );
1288 tools::Rectangle
aRect( nX1
, 0, nX2
, GetHdrHeight() );
1289 mpGridDev
->SetLineColor();
1290 if( maHeaderBackColor
.IsDark() )
1291 // redraw with light gray background in dark mode
1292 ImplDrawColumnHeader( *mpGridDev
, nColIndex
, COL_LIGHTGRAY
);
1295 // use transparent active color
1296 mpGridDev
->SetFillColor( maSelectColor
);
1297 mpGridDev
->DrawTransparent( tools::PolyPolygon( tools::Polygon( aRect
) ), CSV_HDR_TRANSPARENCY
);
1301 aRect
= tools::Rectangle( nX1
, GetHdrHeight() + 1, nX2
, GetY( GetLastVisLine() + 1 ) - 1 );
1302 ImplInvertRect( *mpGridDev
, aRect
);
1305 mpGridDev
->SetClipRegion();
1306 ImplInvertCursor( GetRulerCursorPos() );
1309 void ScCsvGrid::ImplDrawGridDev()
1311 mpGridDev
->DrawOutDev( Point(), maWinSize
, Point(), maWinSize
, *mpBackgrDev
);
1312 sal_uInt32 nLastCol
= GetLastVisColumn();
1313 if (nLastCol
== CSV_COLUMN_INVALID
)
1315 for( sal_uInt32 nColIx
= GetFirstVisColumn(); nColIx
<= nLastCol
; ++nColIx
)
1316 ImplDrawColumnSelection( nColIx
);
1319 void ScCsvGrid::ImplDrawColumn( sal_uInt32 nColIndex
)
1321 ImplDrawColumnBackgr( nColIndex
);
1322 ImplDrawColumnSelection( nColIndex
);
1325 void ScCsvGrid::ImplDrawHorzScrolled( sal_Int32 nOldPos
)
1327 sal_Int32 nPos
= GetFirstVisPos();
1328 if( !IsValidGfx() || (nPos
== nOldPos
) )
1330 if( std::abs( nPos
- nOldPos
) > GetVisPosCount() / 2 )
1332 ImplDrawBackgrDev();
1338 sal_uInt32 nFirstColIx
, nLastColIx
;
1339 if( nPos
< nOldPos
)
1341 aSrc
= Point( GetFirstX() + 1, 0 );
1342 aDest
= Point( GetFirstX() + GetCharWidth() * (nOldPos
- nPos
) + 1, 0 );
1343 nFirstColIx
= GetColumnFromPos( nPos
);
1344 nLastColIx
= GetColumnFromPos( nOldPos
);
1348 aSrc
= Point( GetFirstX() + GetCharWidth() * (nPos
- nOldPos
) + 1, 0 );
1349 aDest
= Point( GetFirstX() + 1, 0 );
1350 nFirstColIx
= GetColumnFromPos( std::min( nOldPos
+ GetVisPosCount(), GetPosCount() ) - 1 );
1351 nLastColIx
= GetColumnFromPos( std::min( nPos
+ GetVisPosCount(), GetPosCount() ) - 1 );
1354 ImplInvertCursor( GetRulerCursorPos() + (nPos
- nOldPos
) );
1355 tools::Rectangle
aRectangle( GetFirstX(), 0, GetLastX(), GetHeight() - 1 );
1356 vcl::Region
aClipReg( aRectangle
);
1357 mpBackgrDev
->SetClipRegion( aClipReg
);
1358 mpBackgrDev
->CopyArea( aDest
, aSrc
, maWinSize
);
1359 mpBackgrDev
->SetClipRegion();
1360 mpGridDev
->SetClipRegion( aClipReg
);
1361 mpGridDev
->CopyArea( aDest
, aSrc
, maWinSize
);
1362 mpGridDev
->SetClipRegion();
1363 ImplInvertCursor( GetRulerCursorPos() );
1365 for( sal_uInt32 nColIx
= nFirstColIx
; nColIx
<= nLastColIx
; ++nColIx
)
1366 ImplDrawColumn( nColIx
);
1368 sal_Int32 nLastX
= GetX( GetPosCount() ) + 1;
1369 if( nLastX
<= GetLastX() )
1371 tools::Rectangle
aRect( nLastX
, 0, GetLastX(), GetHeight() - 1 );
1372 mpBackgrDev
->SetLineColor();
1373 mpBackgrDev
->SetFillColor( maAppBackColor
);
1374 mpBackgrDev
->DrawRect( aRect
);
1375 mpGridDev
->SetLineColor();
1376 mpGridDev
->SetFillColor( maAppBackColor
);
1377 mpGridDev
->DrawRect( aRect
);
1381 void ScCsvGrid::ImplInvertCursor( sal_Int32 nPos
)
1383 if( IsVisibleSplitPos( nPos
) )
1385 sal_Int32 nX
= GetX( nPos
) - 1;
1386 tools::Rectangle
aRect( Point( nX
, 0 ), Size( 3, GetHdrHeight() ) );
1387 ImplInvertRect( *mpGridDev
, aRect
);
1388 aRect
.SetTop( GetHdrHeight() + 1 );
1389 aRect
.SetBottom( GetY( GetLastVisLine() + 1 ) );
1390 ImplInvertRect( *mpGridDev
, aRect
);
1394 tools::Rectangle
ScCsvGrid::GetFocusRect()
1396 auto nColIndex
= GetFocusColumn();
1397 if( HasFocus() && IsVisibleColumn( nColIndex
) )
1399 sal_Int32 nX1
= std::max( GetColumnX( nColIndex
), GetFirstX() ) + 1;
1400 sal_Int32 nX2
= std::min( GetColumnX( nColIndex
+ 1 ) - sal_Int32( 1 ), GetLastX() );
1401 sal_Int32 nY2
= std::min( GetY( GetLastVisLine() + 1 ), GetHeight() ) - 1;
1402 return tools::Rectangle( nX1
, 0, nX2
, nY2
);
1404 return weld::CustomWidgetController::GetFocusRect();
1407 // accessibility ==============================================================
1409 css::uno::Reference
<css::accessibility::XAccessible
> ScCsvGrid::CreateAccessible()
1411 rtl::Reference
<ScAccessibleCsvGrid
> xRef(new ScAccessibleCsvGrid(*this));
1412 mxAccessible
= xRef
;
1416 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */