tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / dbgui / csvgrid.cxx
blob1066a7deb28102f00157cd94833d5f963bf3f51d
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 <comphelper/lok.hxx>
21 #include <csvgrid.hxx>
22 #include <csvtablebox.hxx>
24 #include <algorithm>
25 #include <memory>
27 #include <svtools/colorcfg.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 <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 ***
55 namespace {
57 struct Func_SetType
59 sal_Int32 mnType;
60 explicit Func_SetType( sal_Int32 nType ) : mnType( nType ) {}
61 void operator()( ScCsvColState& rState ) const
62 { rState.mnType = mnType; }
65 struct Func_Select
67 bool mbSelect;
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)
76 : ScCsvControl(rData)
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 ) )
83 , maColStates( 1 )
84 , maTypeNames( 1 )
85 , mnFirstImpLine( 0 )
86 , mnRecentSelCol( CSV_COLUMN_INVALID )
87 , mnMTCurrCol( SAL_MAX_UINT32 )
88 , mbTracking( false )
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
120 InitFonts();
121 ImplClearSplits();
124 ScCsvGrid::~ScCsvGrid()
126 OSL_ENSURE(mpColorConfig, "the object hasn't been initialized properly");
127 if (mpColorConfig)
128 mpColorConfig->RemoveListener(this);
129 mpBackgrDev.disposeAndClear();
130 mpGridDev.disposeAndClear();
133 void
134 ScCsvGrid::Init()
136 OSL_PRECOND(!mpColorConfig, "the object has already been initialized");
137 mpColorConfig = &ScModule::get()->GetColorConfig();
138 InitColors();
139 mpColorConfig->AddListener(this);
142 // common grid handling -------------------------------------------------------
144 void ScCsvGrid::UpdateLayoutData()
146 DisableRepaint();
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);
153 UpdateOffsetX();
154 EnableRepaint();
157 void ScCsvGrid::UpdateOffsetX()
159 sal_Int32 nLastLine = GetLastVisLine() + 1;
160 sal_Int32 nDigits = 2;
161 for (;;)
163 nLastLine /= 10;
164 if (!nLastLine)
165 break;
166 ++nDigits;
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;
177 DisableRepaint();
179 if( nDiff & ScCsvDiff::RulerCursor )
181 ImplInvertCursor( rOldData.mnPosCursor );
182 ImplInvertCursor( GetRulerCursorPos() );
185 if( nDiff & ScCsvDiff::PosCount )
187 if( GetPosCount() < rOldData.mnPosCount )
189 SelectAll( false );
190 maSplits.RemoveRange( GetPosCount(), rOldData.mnPosCount );
192 else
193 maSplits.Remove( rOldData.mnPosCount );
194 maSplits.Insert( GetPosCount() );
195 maColStates.resize( maSplits.Count() - 1 );
198 if( nDiff & ScCsvDiff::LineOffset )
200 Execute( CSVCMD_UPDATECELLTEXTS );
201 UpdateOffsetX();
204 ScCsvDiff nHVDiff = nDiff & (ScCsvDiff::HorizontalMask | ScCsvDiff::VerticalMask);
205 if( nHVDiff == ScCsvDiff::PosOffset )
206 ImplDrawHorzScrolled( rOldData.mnPosOffset );
207 else if( nHVDiff != ScCsvDiff::Equal )
208 InvalidateGfx();
210 EnableRepaint();
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 );
221 ImplDrawGridDev();
222 Repaint();
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;
241 return nNewPos;
244 void ScCsvGrid::InitColors()
246 OSL_PRECOND(mpColorConfig, "the object hasn't been initialized properly");
247 if ( !mpColorConfig )
248 return;
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;
260 else
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();
270 InvalidateGfx();
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. */
281 // get default fonts
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));
319 InvalidateGfx();
322 void ScCsvGrid::InitSizeData()
324 maWinSize = GetOutputSizePixel();
325 mpBackgrDev->SetOutputSizePixel( maWinSize );
326 mpGridDev->SetOutputSizePixel( maWinSize );
327 InvalidateGfx();
330 // split handling -------------------------------------------------------------
332 void ScCsvGrid::InsertSplit( sal_Int32 nPos )
334 if( ImplInsertSplit( nPos ) )
336 DisableRepaint();
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
343 EnableRepaint();
347 void ScCsvGrid::RemoveSplit( sal_Int32 nPos )
349 if( ImplRemoveSplit( nPos ) )
351 DisableRepaint();
352 Execute( CSVCMD_EXPORTCOLUMNTYPE );
353 Execute( CSVCMD_UPDATECELLTEXTS );
354 ImplDrawColumn( GetColumnFromPos( nPos ) );
355 ValidateGfx(); // performance: do not redraw all columns
356 EnableRepaint();
360 void ScCsvGrid::MoveSplit( sal_Int32 nPos, sal_Int32 nNewPos )
362 sal_uInt32 nColIx = GetColumnFromPos( nPos );
363 if( nColIx == CSV_COLUMN_INVALID )
364 return;
366 DisableRepaint();
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 );
378 else
380 ImplRemoveSplit( nPos );
381 ImplInsertSplit( nNewPos );
382 Execute( CSVCMD_EXPORTCOLUMNTYPE );
383 Execute( CSVCMD_UPDATECELLTEXTS );
385 EnableRepaint();
388 void ScCsvGrid::RemoveAllSplits()
390 DisableRepaint();
391 ImplClearSplits();
392 Execute( CSVCMD_EXPORTCOLUMNTYPE );
393 Execute( CSVCMD_UPDATECELLTEXTS );
394 EnableRepaint();
397 void ScCsvGrid::SetSplits( const ScCsvSplits& rSplits )
399 DisableRepaint();
400 ImplClearSplits();
401 sal_uInt32 nCount = rSplits.Count();
402 for( sal_uInt32 nIx = 0; nIx < nCount; ++nIx )
403 maSplits.Insert( rSplits[ nIx ] );
404 maColStates.clear();
405 maColStates.resize( maSplits.Count() - 1 );
406 Execute( CSVCMD_EXPORTCOLUMNTYPE );
407 Execute( CSVCMD_UPDATECELLTEXTS );
408 EnableRepaint();
411 bool ScCsvGrid::ImplInsertSplit( sal_Int32 nPos )
413 sal_uInt32 nColIx = GetColumnFromPos( nPos );
414 bool bRet = (nColIx < GetColumnCount()) && maSplits.Insert( nPos );
415 if( bRet )
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 );
423 return bRet;
426 bool ScCsvGrid::ImplRemoveSplit( sal_Int32 nPos )
428 bool bRet = maSplits.Remove( nPos );
429 if( bRet )
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 );
438 return bRet;
441 void ScCsvGrid::ImplClearSplits()
443 sal_uInt32 nColumns = GetColumnCount();
444 maSplits.Clear();
445 maSplits.Insert( 0 );
446 maSplits.Insert( GetPosCount() );
447 maColStates.resize( 1 );
448 InvalidateGfx();
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 );
534 return nType;
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 );
543 Repaint( true );
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);
552 Repaint( true );
554 mxPopup->clear();
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();
611 switch( eDir )
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;
619 default:
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 ) )
651 return 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 );
661 Repaint();
662 Execute( CSVCMD_EXPORTCOLUMNTYPE );
663 if( bSelect )
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 );
683 if( 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 );
693 Repaint();
694 Execute( CSVCMD_EXPORTCOLUMNTYPE );
695 if( bSelect )
696 mnRecentSelCol = nColIndex1;
697 AccSendSelectionEvent();
701 void ScCsvGrid::SelectAll( bool bSelect )
703 SelectRange( 0, GetColumnCount() - 1, bSelect );
706 void ScCsvGrid::MoveCursor( sal_uInt32 nColIndex )
708 DisableRepaint();
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 ) );
721 EnableRepaint();
724 void ScCsvGrid::MoveCursorRel( ScMoveMode eDir )
726 if( GetFocusColumn() == CSV_COLUMN_INVALID )
727 return;
729 switch( eDir )
731 case MOVE_FIRST:
732 MoveCursor( 0 );
733 break;
734 case MOVE_LAST:
735 MoveCursor( GetColumnCount() - 1 );
736 break;
737 case MOVE_PREV:
738 if( GetFocusColumn() > 0 )
739 MoveCursor( GetFocusColumn() - 1 );
740 break;
741 case MOVE_NEXT:
742 if( GetFocusColumn() < GetColumnCount() - 1 )
743 MoveCursor( GetFocusColumn() + 1 );
744 break;
745 default:
747 // added to avoid warnings
752 void ScCsvGrid::ImplClearSelection()
754 ::std::for_each( maColStates.begin(), maColStates.end(), Func_Select( false ) );
755 ImplDrawGridDev();
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
765 Select( nColIndex );
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 ];
785 rStrVec.clear();
787 // scan for separators
788 OUString aCellText;
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 );
808 if( nDiff > 0 )
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 );
819 else
821 // append new column
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 );
829 else
830 rStrVec.push_back( aCellText.copy( 0, CSV_MAXSTRLEN ) );
831 ++nColIx;
833 InvalidateGfx();
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 ];
849 rStrVec.clear();
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;
862 InvalidateGfx();
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();
885 InitSizeData();
886 Execute( CSVCMD_UPDATECELLTEXTS );
889 void ScCsvGrid::GetFocus()
891 ScCsvControl::GetFocus();
892 Execute( CSVCMD_MOVEGRIDCURSOR, GetNoScrollCol( GetGridCursorPos() ) );
893 Repaint();
896 void ScCsvGrid::LoseFocus()
898 ScCsvControl::LoseFocus();
899 Repaint();
902 bool ScCsvGrid::MouseButtonDown( const MouseEvent& rMEvt )
904 DisableRepaint();
905 if( !HasFocus() )
906 GrabFocus();
908 Point aPos( rMEvt.GetPosPixel() );
909 sal_uInt32 nColIx = GetColumnFromX( aPos.X() );
911 if( rMEvt.IsLeft() )
913 if( (GetFirstX() > aPos.X()) || (aPos.X() > GetLastX()) ) // in header column
915 if( aPos.Y() <= GetHdrHeight() )
916 SelectAll();
918 else if( IsValidColumn( nColIx ) )
920 DoSelectAction( nColIx, rMEvt.GetModifier() );
921 mnMTCurrCol = nColIx;
922 mbMTSelecting = IsSelected( nColIx );
923 mbTracking = true;
926 EnableRepaint();
927 return true;
930 bool ScCsvGrid::MouseButtonUp( const MouseEvent& )
932 mbTracking = false;
933 return true;
936 bool ScCsvGrid::MouseMove( const MouseEvent& rMEvt )
938 if (!mbTracking)
939 return true;
941 DisableRepaint();
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;
954 EnableRepaint();
956 return true;
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 )
973 DisableRepaint();
974 MoveCursorRel( eHDir );
975 if( !bMod1 )
976 ImplClearSelection();
977 if( bShift )
978 SelectRange( mnRecentSelCol, GetFocusColumn() );
979 else if( !bMod1 )
980 Select( GetFocusColumn() );
981 EnableRepaint();
983 else if( eVDir != MOVE_NONE )
984 ScrollVertRel( eVDir );
985 else if( nCode == KEY_SPACE )
987 if( !bMod1 )
988 ImplClearSelection();
989 if( bShift )
990 SelectRange( mnRecentSelCol, GetFocusColumn() );
991 else if( bMod1 )
992 ToggleSelect( GetFocusColumn() );
993 else
994 Select( GetFocusColumn() );
996 else if( !bShift && bMod1 )
998 if( nCode == KEY_A )
999 SelectAll();
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 );
1030 else
1032 sal_uInt32 nColIx = GetFocusColumn();
1033 if( !IsSelected( nColIx ) )
1034 Select( 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 ) );
1039 break;
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() );
1050 break;
1052 default:
1053 bConsumed = false;
1054 break;
1056 return bConsumed;
1059 void ScCsvGrid::StyleUpdated()
1061 InitColors();
1062 InitFonts();
1063 UpdateLayoutData();
1064 Execute( CSVCMD_UPDATECELLTEXTS );
1066 ScCsvControl::StyleUpdated();
1069 void ScCsvGrid::ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints )
1071 InitColors();
1072 Repaint();
1075 // painting -------------------------------------------------------------------
1077 void ScCsvGrid::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
1079 ImplRedraw(rRenderContext);
1082 void ScCsvGrid::ImplRedraw(vcl::RenderContext& rRenderContext)
1084 if( IsVisible() )
1086 if( !IsValidGfx() )
1088 ValidateGfx();
1089 ImplDrawBackgrDev();
1090 ImplDrawGridDev();
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 ) );
1147 ++nCharIx;
1149 nCharIx = 0;
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 ) );
1161 ++nCharIx;
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 ) )
1179 return;
1181 ImplSetColumnClipRegion( *mpBackgrDev, nColIndex );
1183 // grid
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 );
1197 // cell texts
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 );
1217 // header
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 );
1235 // line numbers
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 );
1247 // grid
1248 mpBackgrDev->SetLineColor( maHeaderGridColor );
1249 if( IsRTL() )
1251 mpBackgrDev->DrawLine( Point( 0, 0 ), Point( 0, GetHeight() - 1 ) );
1252 mpBackgrDev->DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
1254 else
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)
1269 return;
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 );
1287 // header
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 );
1293 else
1295 // use transparent active color
1296 mpGridDev->SetFillColor( maSelectColor );
1297 mpGridDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aRect ) ), CSV_HDR_TRANSPARENCY );
1300 // column selection
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)
1314 return;
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) )
1329 return;
1330 if( std::abs( nPos - nOldPos ) > GetVisPosCount() / 2 )
1332 ImplDrawBackgrDev();
1333 ImplDrawGridDev();
1334 return;
1337 Point aSrc, aDest;
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 );
1346 else
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;
1413 return xRef;
1416 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */