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