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