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