xref: /trunk/main/sc/source/ui/dbgui/csvruler.cxx (revision b3f79822)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 
28 // ============================================================================
29 #include "csvruler.hxx"
30 #include "AccessibleCsvControl.hxx"
31 
32 
33 #include <optutil.hxx>
34 #include <com/sun/star/uno/Any.hxx>
35 #include <com/sun/star/uno/Sequence.hxx>
36 #include "miscuno.hxx"
37 
38 using namespace rtl;
39 using namespace com::sun::star::uno;
40 
41 
42 
43 // ============================================================================
44 #define SEP_PATH            "Office.Calc/Dialogs/CSVImport"
45 #define FIXED_WIDTH_LIST    "FixedWidthList"
46 
47 
48 // ============================================================================
49 
load_FixedWidthList(ScCsvSplits & aSplits)50 static void load_FixedWidthList(ScCsvSplits &aSplits)
51 {
52     String sSplits;
53     OUString sFixedWidthLists;
54 
55     Sequence<Any>aValues;
56     const Any *pProperties;
57     Sequence<OUString> aNames(1);
58     OUString* pNames = aNames.getArray();
59     ScLinkConfigItem aItem( OUString::createFromAscii( SEP_PATH ) );
60 
61     pNames[0] = OUString::createFromAscii( FIXED_WIDTH_LIST );
62     aValues = aItem.GetProperties( aNames );
63     pProperties = aValues.getConstArray();
64 
65     if( pProperties[0].hasValue() )
66     {
67         aSplits.Clear();
68         pProperties[0] >>= sFixedWidthLists;
69 
70         sSplits = String( sFixedWidthLists );
71 
72         // String ends with a semi-colon so there is no 'int' after the last one.
73         xub_StrLen n = sSplits.GetTokenCount() - 1;
74         for (xub_StrLen i = 0; i < n; ++i)
75             aSplits.Insert( sSplits.GetToken(i).ToInt32() );
76     }
77 }
save_FixedWidthList(ScCsvSplits aSplits)78 static void save_FixedWidthList(ScCsvSplits aSplits)
79 {
80     String sSplits;
81     // Create a semi-colon separated string to save the splits
82     sal_uInt32 n = aSplits.Count();
83     for (sal_uInt32 i = 0; i < n; ++i)
84     {
85         sSplits.Append( String::CreateFromInt32( aSplits[i] ) );
86         sSplits.Append((char)';');
87     }
88 
89     OUString sFixedWidthLists = OUString( sSplits );
90     Sequence<Any> aValues;
91     Any *pProperties;
92     Sequence<OUString> aNames(1);
93     OUString* pNames = aNames.getArray();
94     ScLinkConfigItem aItem( OUString::createFromAscii( SEP_PATH ) );
95 
96     pNames[0] = OUString::createFromAscii( FIXED_WIDTH_LIST );
97     aValues = aItem.GetProperties( aNames );
98     pProperties = aValues.getArray();
99     pProperties[0] <<= sFixedWidthLists;
100 
101     aItem.PutProperties(aNames, aValues);
102 }
103 
ScCsvRuler(ScCsvControl & rParent)104 ScCsvRuler::ScCsvRuler( ScCsvControl& rParent ) :
105     ScCsvControl( rParent ),
106     mnPosCursorLast( 1 )
107 {
108     EnableRTL( false ); // #107812# RTL
109     InitColors();
110     InitSizeData();
111     maBackgrDev.SetFont( GetFont() );
112     maRulerDev.SetFont( GetFont() );
113 
114     load_FixedWidthList( maSplits );
115 }
116 
~ScCsvRuler()117 ScCsvRuler::~ScCsvRuler()
118 {
119     save_FixedWidthList( maSplits );
120 }
121 
122 
123 // common ruler handling ------------------------------------------------------
124 
SetPosSizePixel(long nX,long nY,long nWidth,long nHeight,sal_uInt16 nFlags)125 void ScCsvRuler::SetPosSizePixel(
126         long nX, long nY, long nWidth, long nHeight, sal_uInt16 nFlags )
127 {
128     if( nFlags & WINDOW_POSSIZE_HEIGHT )
129         nHeight = GetTextHeight() + mnSplitSize + 2;
130     ScCsvControl::SetPosSizePixel( nX, nY, nWidth, nHeight, nFlags );
131 }
132 
ApplyLayout(const ScCsvLayoutData & rOldData)133 void ScCsvRuler::ApplyLayout( const ScCsvLayoutData& rOldData )
134 {
135     ScCsvDiff nDiff = GetLayoutData().GetDiff( rOldData ) & (CSV_DIFF_HORIZONTAL | CSV_DIFF_RULERCURSOR);
136     if( nDiff == CSV_DIFF_EQUAL ) return;
137 
138     DisableRepaint();
139     if( nDiff & CSV_DIFF_HORIZONTAL )
140     {
141         InitSizeData();
142         if( GetRulerCursorPos() >= GetPosCount() )
143             MoveCursor( GetPosCount() - 1 );
144     }
145     if( nDiff & CSV_DIFF_RULERCURSOR )
146     {
147         ImplInvertCursor( rOldData.mnPosCursor );
148         ImplInvertCursor( GetRulerCursorPos() );
149     }
150     EnableRepaint();
151 
152     if( nDiff & CSV_DIFF_POSOFFSET )
153         AccSendVisibleEvent();
154 }
155 
InitColors()156 void ScCsvRuler::InitColors()
157 {
158     const StyleSettings& rSett = GetSettings().GetStyleSettings();
159     maBackColor = rSett.GetFaceColor();
160     maActiveColor = rSett.GetWindowColor();
161     maTextColor = rSett.GetLabelTextColor();
162     maSplitColor = maBackColor.IsDark() ? maTextColor : Color( COL_LIGHTRED );
163     InvalidateGfx();
164 }
165 
InitSizeData()166 void ScCsvRuler::InitSizeData()
167 {
168     maWinSize = GetSizePixel();
169 
170     mnSplitSize = (GetCharWidth() * 3 / 5) | 1; // make an odd number
171 
172     sal_Int32 nActiveWidth = Min( GetWidth() - GetHdrWidth(), GetPosCount() * GetCharWidth() );
173     sal_Int32 nActiveHeight = GetTextHeight();
174 
175     maActiveRect.SetPos( Point( GetFirstX(), (GetHeight() - nActiveHeight - 1) / 2 ) );
176     maActiveRect.SetSize( Size( nActiveWidth, nActiveHeight ) );
177 
178     maBackgrDev.SetOutputSizePixel( maWinSize );
179     maRulerDev.SetOutputSizePixel( maWinSize );
180 
181     InvalidateGfx();
182 }
183 
MoveCursor(sal_Int32 nPos,bool bScroll)184 void ScCsvRuler::MoveCursor( sal_Int32 nPos, bool bScroll )
185 {
186     DisableRepaint();
187     if( bScroll )
188         Execute( CSVCMD_MAKEPOSVISIBLE, nPos );
189     Execute( CSVCMD_MOVERULERCURSOR, IsVisibleSplitPos( nPos ) ? nPos : CSV_POS_INVALID );
190     EnableRepaint();
191     AccSendCaretEvent();
192 }
193 
MoveCursorRel(ScMoveMode eDir)194 void ScCsvRuler::MoveCursorRel( ScMoveMode eDir )
195 {
196     if( GetRulerCursorPos() != CSV_POS_INVALID )
197     {
198         switch( eDir )
199         {
200             case MOVE_FIRST:
201                 MoveCursor( 1 );
202             break;
203             case MOVE_LAST:
204                 MoveCursor( GetPosCount() - 1 );
205             break;
206             case MOVE_PREV:
207                 if( GetRulerCursorPos() > 1 )
208                     MoveCursor( GetRulerCursorPos() - 1 );
209             break;
210             case MOVE_NEXT:
211                 if( GetRulerCursorPos() < GetPosCount() - 1 )
212                     MoveCursor( GetRulerCursorPos() + 1 );
213             break;
214             default:
215             {
216                 // added to avoid warnings
217             }
218         }
219     }
220 }
221 
MoveCursorToSplit(ScMoveMode eDir)222 void ScCsvRuler::MoveCursorToSplit( ScMoveMode eDir )
223 {
224     if( GetRulerCursorPos() != CSV_POS_INVALID )
225     {
226         sal_uInt32 nIndex = CSV_VEC_NOTFOUND;
227         switch( eDir )
228         {
229             case MOVE_FIRST:    nIndex = maSplits.LowerBound( 0 );                          break;
230             case MOVE_LAST:     nIndex = maSplits.UpperBound( GetPosCount() );              break;
231             case MOVE_PREV:     nIndex = maSplits.UpperBound( GetRulerCursorPos() - 1 );    break;
232             case MOVE_NEXT:     nIndex = maSplits.LowerBound( GetRulerCursorPos() + 1 );    break;
233             default:
234             {
235                 // added to avoid warnings
236             }
237         }
238         sal_Int32 nPos = maSplits[ nIndex ];
239         if( nPos != CSV_POS_INVALID )
240             MoveCursor( nPos );
241     }
242 }
243 
ScrollVertRel(ScMoveMode eDir)244 void ScCsvRuler::ScrollVertRel( ScMoveMode eDir )
245 {
246     sal_Int32 nLine = GetFirstVisLine();
247     switch( eDir )
248     {
249         case MOVE_PREV:     --nLine;                        break;
250         case MOVE_NEXT:     ++nLine;                        break;
251         case MOVE_PREVPAGE: nLine -= GetVisLineCount() - 1; break;
252         case MOVE_NEXTPAGE: nLine += GetVisLineCount() - 1; break;
253         default:
254         {
255             // added to avoid warnings
256         }
257     }
258     Execute( CSVCMD_SETLINEOFFSET, nLine );
259 }
260 
261 
262 // split handling -------------------------------------------------------------
263 
GetNoScrollPos(sal_Int32 nPos) const264 sal_Int32 ScCsvRuler::GetNoScrollPos( sal_Int32 nPos ) const
265 {
266     sal_Int32 nNewPos = nPos;
267     if( nNewPos != CSV_POS_INVALID )
268     {
269         if( nNewPos < GetFirstVisPos() + CSV_SCROLL_DIST )
270         {
271             sal_Int32 nScroll = (GetFirstVisPos() > 0) ? CSV_SCROLL_DIST : 0;
272             nNewPos = Max( nPos, GetFirstVisPos() + nScroll );
273         }
274         else if( nNewPos > GetLastVisPos() - CSV_SCROLL_DIST - 1L )
275         {
276             sal_Int32 nScroll = (GetFirstVisPos() < GetMaxPosOffset()) ? CSV_SCROLL_DIST : 0;
277             nNewPos = Min( nNewPos, GetLastVisPos() - nScroll - sal_Int32( 1 ) );
278         }
279     }
280     return nNewPos;
281 }
282 
InsertSplit(sal_Int32 nPos)283 void ScCsvRuler::InsertSplit( sal_Int32 nPos )
284 {
285     if( maSplits.Insert( nPos ) )
286     {
287         ImplDrawSplit( nPos );
288         Repaint();
289     }
290 }
291 
RemoveSplit(sal_Int32 nPos)292 void ScCsvRuler::RemoveSplit( sal_Int32 nPos )
293 {
294     if( maSplits.Remove( nPos ) )
295     {
296         ImplEraseSplit( nPos );
297         Repaint();
298     }
299 }
300 
MoveSplit(sal_Int32 nPos,sal_Int32 nNewPos)301 void ScCsvRuler::MoveSplit( sal_Int32 nPos, sal_Int32 nNewPos )
302 {
303     bool bRemove = maSplits.Remove( nPos );
304     bool bInsert = maSplits.Insert( nNewPos );
305     if( bRemove || bInsert )
306     {
307         ImplEraseSplit( nPos );
308         ImplDrawSplit( nNewPos );
309         Repaint();
310     }
311 }
312 
RemoveAllSplits()313 void ScCsvRuler::RemoveAllSplits()
314 {
315     maSplits.Clear();
316     Repaint( true );
317 }
318 
FindEmptyPos(sal_Int32 nPos,ScMoveMode eDir) const319 sal_Int32 ScCsvRuler::FindEmptyPos( sal_Int32 nPos, ScMoveMode eDir ) const
320 {
321     sal_Int32 nNewPos = nPos;
322     if( nNewPos != CSV_POS_INVALID )
323     {
324         switch( eDir )
325         {
326             case MOVE_FIRST:
327                 nNewPos = Min( nPos, FindEmptyPos( 0, MOVE_NEXT ) );
328             break;
329             case MOVE_LAST:
330                 nNewPos = Max( nPos, FindEmptyPos( GetPosCount(), MOVE_PREV ) );
331             break;
332             case MOVE_PREV:
333                 while( HasSplit( --nNewPos ) ) ;
334             break;
335             case MOVE_NEXT:
336                 while( HasSplit( ++nNewPos ) ) ;
337             break;
338             default:
339             {
340                 // added to avoid warnings
341             }
342         }
343     }
344     return IsValidSplitPos( nNewPos ) ? nNewPos : CSV_POS_INVALID;
345 }
346 
MoveCurrSplit(sal_Int32 nNewPos)347 void ScCsvRuler::MoveCurrSplit( sal_Int32 nNewPos )
348 {
349     DisableRepaint();
350     Execute( CSVCMD_MOVESPLIT, GetRulerCursorPos(), nNewPos );
351     MoveCursor( nNewPos );
352     EnableRepaint();
353 }
354 
MoveCurrSplitRel(ScMoveMode eDir)355 void ScCsvRuler::MoveCurrSplitRel( ScMoveMode eDir )
356 {
357     if( HasSplit( GetRulerCursorPos() ) )
358     {
359         sal_Int32 nNewPos = FindEmptyPos( GetRulerCursorPos(), eDir );
360         if( nNewPos != CSV_POS_INVALID )
361             MoveCurrSplit( nNewPos );
362     }
363 }
364 
365 
366 // event handling -------------------------------------------------------------
367 
Resize()368 void ScCsvRuler::Resize()
369 {
370     ScCsvControl::Resize();
371     InitSizeData();
372     Repaint();
373 }
374 
GetFocus()375 void ScCsvRuler::GetFocus()
376 {
377     ScCsvControl::GetFocus();
378     DisableRepaint();
379     if( GetRulerCursorPos() == CSV_POS_INVALID )
380         MoveCursor( GetNoScrollPos( mnPosCursorLast ) );
381     EnableRepaint();
382 }
383 
LoseFocus()384 void ScCsvRuler::LoseFocus()
385 {
386     ScCsvControl::LoseFocus();
387     mnPosCursorLast = GetRulerCursorPos();
388     MoveCursor( CSV_POS_INVALID );
389 }
390 
DataChanged(const DataChangedEvent & rDCEvt)391 void ScCsvRuler::DataChanged( const DataChangedEvent& rDCEvt )
392 {
393     if( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) )
394     {
395         InitColors();
396         Repaint();
397     }
398     ScCsvControl::DataChanged( rDCEvt );
399 }
400 
MouseButtonDown(const MouseEvent & rMEvt)401 void ScCsvRuler::MouseButtonDown( const MouseEvent& rMEvt )
402 {
403     DisableRepaint();
404     if( !HasFocus() )
405         GrabFocus();
406     if( rMEvt.IsLeft() )
407     {
408         sal_Int32 nPos = GetPosFromX( rMEvt.GetPosPixel().X() );
409         if( IsVisibleSplitPos( nPos ) )
410             StartMouseTracking( nPos );
411         ImplSetMousePointer( nPos );
412     }
413     EnableRepaint();
414 }
415 
MouseMove(const MouseEvent & rMEvt)416 void ScCsvRuler::MouseMove( const MouseEvent& rMEvt )
417 {
418     if( !rMEvt.IsModifierChanged() )
419     {
420         sal_Int32 nPos = GetPosFromX( rMEvt.GetPosPixel().X() );
421         if( IsTracking() )
422         {
423             // on mouse tracking: keep position valid
424             nPos = Max( Min( nPos, GetPosCount() - sal_Int32( 1 ) ), sal_Int32( 1 ) );
425             MoveMouseTracking( nPos );
426         }
427         else
428         {
429             Point aPoint;
430             Rectangle aRect( aPoint, maWinSize );
431             if( !IsVisibleSplitPos( nPos ) || !aRect.IsInside( rMEvt.GetPosPixel() ) )
432                 // if focused, keep old cursor position for key input
433                 nPos = HasFocus() ? GetRulerCursorPos() : CSV_POS_INVALID;
434             MoveCursor( nPos, false );
435         }
436         ImplSetMousePointer( nPos );
437     }
438 }
439 
Tracking(const TrackingEvent & rTEvt)440 void ScCsvRuler::Tracking( const TrackingEvent& rTEvt )
441 {
442     if( rTEvt.IsTrackingEnded() || rTEvt.IsTrackingRepeat() )
443         MouseMove( rTEvt.GetMouseEvent() );
444     if( rTEvt.IsTrackingEnded() )
445         EndMouseTracking( !rTEvt.IsTrackingCanceled() );
446 }
447 
KeyInput(const KeyEvent & rKEvt)448 void ScCsvRuler::KeyInput( const KeyEvent& rKEvt )
449 {
450     const KeyCode& rKCode = rKEvt.GetKeyCode();
451     sal_uInt16 nCode = rKCode.GetCode();
452     bool bNoMod = !rKCode.GetModifier();
453     bool bShift = (rKCode.GetModifier() == KEY_SHIFT);
454     bool bJump = (rKCode.GetModifier() == KEY_MOD1);
455     bool bMove = (rKCode.GetModifier() == (KEY_MOD1 | KEY_SHIFT));
456 
457     ScMoveMode eHDir = GetHorzDirection( nCode, true );
458     ScMoveMode eVDir = GetVertDirection( nCode, false );
459 
460     if( bNoMod )
461     {
462         if( eHDir != MOVE_NONE )
463             MoveCursorRel( eHDir );
464         else if( eVDir != MOVE_NONE )
465             ScrollVertRel( eVDir );
466         else switch( nCode )
467         {
468             case KEY_SPACE:     Execute( CSVCMD_TOGGLESPLIT, GetRulerCursorPos() ); break;
469             case KEY_INSERT:    Execute( CSVCMD_INSERTSPLIT, GetRulerCursorPos() ); break;
470             case KEY_DELETE:    Execute( CSVCMD_REMOVESPLIT, GetRulerCursorPos() ); break;
471         }
472     }
473     else if( bJump && (eHDir != MOVE_NONE) )
474         MoveCursorToSplit( eHDir );
475     else if( bMove && (eHDir != MOVE_NONE) )
476         MoveCurrSplitRel( eHDir );
477     else if( bShift && (nCode == KEY_DELETE) )
478         Execute( CSVCMD_REMOVEALLSPLITS );
479 
480     if( rKCode.GetGroup() != KEYGROUP_CURSOR )
481         ScCsvControl::KeyInput( rKEvt );
482 }
483 
StartMouseTracking(sal_Int32 nPos)484 void ScCsvRuler::StartMouseTracking( sal_Int32 nPos )
485 {
486     mnPosMTStart = mnPosMTCurr = nPos;
487     mbPosMTMoved = false;
488     maOldSplits = maSplits;
489     Execute( CSVCMD_INSERTSPLIT, nPos );
490     if( HasSplit( nPos ) )
491         StartTracking( STARTTRACK_BUTTONREPEAT );
492 }
493 
MoveMouseTracking(sal_Int32 nPos)494 void ScCsvRuler::MoveMouseTracking( sal_Int32 nPos )
495 {
496     if( mnPosMTCurr != nPos )
497     {
498         DisableRepaint();
499         MoveCursor( nPos );
500         if( (mnPosMTCurr != mnPosMTStart) && maOldSplits.HasSplit( mnPosMTCurr ) )
501             Execute( CSVCMD_INSERTSPLIT, nPos );
502         else
503             Execute( CSVCMD_MOVESPLIT, mnPosMTCurr, nPos );
504         mnPosMTCurr = nPos;
505         mbPosMTMoved = true;
506         EnableRepaint();
507     }
508 }
509 
EndMouseTracking(bool bApply)510 void ScCsvRuler::EndMouseTracking( bool bApply )
511 {
512     if( bApply )    // tracking finished successfully
513     {
514         // remove on simple click on an existing split
515         if( (mnPosMTCurr == mnPosMTStart) && maOldSplits.HasSplit( mnPosMTCurr ) && !mbPosMTMoved )
516             Execute( CSVCMD_REMOVESPLIT, mnPosMTCurr );
517     }
518     else            // tracking cancelled
519     {
520         MoveCursor( mnPosMTStart );
521         // move split to origin
522         if( maOldSplits.HasSplit( mnPosMTStart ) )
523             MoveMouseTracking( mnPosMTStart );
524         // remove temporarily inserted split
525         else if( !maOldSplits.HasSplit( mnPosMTCurr ) )
526             Execute( CSVCMD_REMOVESPLIT, mnPosMTCurr );
527     }
528     mnPosMTStart = CSV_POS_INVALID;
529 }
530 
531 
532 // painting -------------------------------------------------------------------
533 
Paint(const Rectangle &)534 void ScCsvRuler::Paint( const Rectangle& )
535 {
536     Repaint();
537 }
538 
ImplRedraw()539 void ScCsvRuler::ImplRedraw()
540 {
541     if( IsVisible() )
542     {
543         if( !IsValidGfx() )
544         {
545             ValidateGfx();
546             ImplDrawBackgrDev();
547             ImplDrawRulerDev();
548         }
549         DrawOutDev( Point(), maWinSize, Point(), maWinSize, maRulerDev );
550         ImplDrawTrackingRect();
551     }
552 }
553 
ImplDrawArea(sal_Int32 nPosX,sal_Int32 nWidth)554 void ScCsvRuler::ImplDrawArea( sal_Int32 nPosX, sal_Int32 nWidth )
555 {
556     maBackgrDev.SetLineColor();
557     Rectangle aRect( Point( nPosX, 0 ), Size( nWidth, GetHeight() ) );
558     maBackgrDev.SetFillColor( maBackColor );
559     maBackgrDev.DrawRect( aRect );
560 
561     aRect = maActiveRect;
562     aRect.Left() = Max( GetFirstX(), nPosX );
563     aRect.Right() = Min( Min( GetX( GetPosCount() ), GetLastX() ), nPosX + nWidth - sal_Int32( 1 ) );
564     if( aRect.Left() <= aRect.Right() )
565     {
566         maBackgrDev.SetFillColor( maActiveColor );
567         maBackgrDev.DrawRect( aRect );
568     }
569 
570     maBackgrDev.SetLineColor( maTextColor );
571     sal_Int32 nY = GetHeight() - 1;
572     maBackgrDev.DrawLine( Point( nPosX, nY ), Point( nPosX + nWidth - 1, nY ) );
573 }
574 
ImplDrawBackgrDev()575 void ScCsvRuler::ImplDrawBackgrDev()
576 {
577     ImplDrawArea( 0, GetWidth() );
578 
579     // scale
580     maBackgrDev.SetLineColor( maTextColor );
581     maBackgrDev.SetFillColor();
582     sal_Int32 nPos;
583 
584     sal_Int32 nFirstPos = Max( GetPosFromX( 0 ) - (sal_Int32)(1L), (sal_Int32)(0L) );
585     sal_Int32 nLastPos = GetPosFromX( GetWidth() );
586     sal_Int32 nY = (maActiveRect.Top() + maActiveRect.Bottom()) / 2;
587     for( nPos = nFirstPos; nPos <= nLastPos; ++nPos )
588     {
589         sal_Int32 nX = GetX( nPos );
590         if( nPos % 5 )
591             maBackgrDev.DrawPixel( Point( nX, nY ) );
592         else
593             maBackgrDev.DrawLine( Point( nX, nY - 1 ), Point( nX, nY + 1 ) );
594     }
595 
596     // texts
597     maBackgrDev.SetTextColor( maTextColor );
598     maBackgrDev.SetTextFillColor();
599     for( nPos = ((nFirstPos + 9) / 10) * 10; nPos <= nLastPos; nPos += 10 )
600     {
601         String aText( String::CreateFromInt32( nPos ) );
602         sal_Int32 nTextWidth = maBackgrDev.GetTextWidth( aText );
603         sal_Int32 nTextX = GetX( nPos ) - nTextWidth / 2;
604         ImplDrawArea( nTextX - 1, nTextWidth + 2 );
605         maBackgrDev.DrawText( Point( nTextX, maActiveRect.Top() ), aText );
606     }
607 }
608 
ImplDrawSplit(sal_Int32 nPos)609 void ScCsvRuler::ImplDrawSplit( sal_Int32 nPos )
610 {
611     if( IsVisibleSplitPos( nPos ) )
612     {
613         Point aPos( GetX( nPos ) - mnSplitSize / 2, GetHeight() - mnSplitSize - 2 );
614         Size aSize( mnSplitSize, mnSplitSize );
615         maRulerDev.SetLineColor( maTextColor );
616         maRulerDev.SetFillColor( maSplitColor );
617         maRulerDev.DrawEllipse( Rectangle( aPos, aSize ) );
618         maRulerDev.DrawPixel( Point( GetX( nPos ), GetHeight() - 2 ) );
619     }
620 }
621 
ImplEraseSplit(sal_Int32 nPos)622 void ScCsvRuler::ImplEraseSplit( sal_Int32 nPos )
623 {
624     if( IsVisibleSplitPos( nPos ) )
625     {
626         ImplInvertCursor( GetRulerCursorPos() );
627         Point aPos( GetX( nPos ) - mnSplitSize / 2, 0 );
628         Size aSize( mnSplitSize, GetHeight() );
629         maRulerDev.DrawOutDev( aPos, aSize, aPos, aSize, maBackgrDev );
630         ImplInvertCursor( GetRulerCursorPos() );
631     }
632 }
633 
ImplDrawRulerDev()634 void ScCsvRuler::ImplDrawRulerDev()
635 {
636     maRulerDev.DrawOutDev( Point(), maWinSize, Point(), maWinSize, maBackgrDev );
637     ImplInvertCursor( GetRulerCursorPos() );
638 
639     sal_uInt32 nFirst = maSplits.LowerBound( GetFirstVisPos() );
640     sal_uInt32 nLast = maSplits.UpperBound( GetLastVisPos() );
641     if( (nFirst != CSV_VEC_NOTFOUND) && (nLast != CSV_VEC_NOTFOUND) )
642         for( sal_uInt32 nIndex = nFirst; nIndex <= nLast; ++nIndex )
643             ImplDrawSplit( GetSplitPos( nIndex ) );
644 }
645 
ImplInvertCursor(sal_Int32 nPos)646 void ScCsvRuler::ImplInvertCursor( sal_Int32 nPos )
647 {
648     if( IsVisibleSplitPos( nPos ) )
649     {
650         ImplInvertRect( maRulerDev, Rectangle( Point( GetX( nPos ) - 1, 0 ), Size( 3, GetHeight() - 1 ) ) );
651         if( HasSplit( nPos ) )
652             ImplDrawSplit( nPos );
653     }
654 }
655 
ImplDrawTrackingRect()656 void ScCsvRuler::ImplDrawTrackingRect()
657 {
658     if( HasFocus() )
659         InvertTracking( Rectangle( 0, 0, GetWidth() - 1, GetHeight() - 2 ),
660             SHOWTRACK_SMALL | SHOWTRACK_WINDOW );
661 }
662 
ImplSetMousePointer(sal_Int32 nPos)663 void ScCsvRuler::ImplSetMousePointer( sal_Int32 nPos )
664 {
665     SetPointer( Pointer( HasSplit( nPos ) ? POINTER_HSPLIT : POINTER_ARROW ) );
666 }
667 
668 
669 // accessibility ==============================================================
670 
ImplCreateAccessible()671 ScAccessibleCsvControl* ScCsvRuler::ImplCreateAccessible()
672 {
673     return new ScAccessibleCsvRuler( *this );
674 }
675 
676 
677 // ============================================================================
678 
679