1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: olinewin.cxx,v $
10 * $Revision: 1.15.32.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
35 #include <vcl/svapp.hxx>
36 #include <vcl/taskpanelist.hxx>
38 #include "olinewin.hxx"
39 #include "olinetab.hxx"
40 #include "document.hxx"
44 // ============================================================================
46 const long SC_OL_BITMAPSIZE
= 12;
47 const long SC_OL_POSOFFSET
= 2;
49 const size_t SC_OL_NOLEVEL
= static_cast< size_t >( -1 );
50 const size_t SC_OL_HEADERENTRY
= static_cast< size_t >( -1 );
52 const USHORT SC_OL_IMAGE_PLUS
= 9;
53 const USHORT SC_OL_IMAGE_MINUS
= SC_OL_IMAGE_PLUS
+ 1;
54 const USHORT SC_OL_IMAGE_NOTPRESSED
= SC_OL_IMAGE_MINUS
+ 1;
55 const USHORT SC_OL_IMAGE_PRESSED
= SC_OL_IMAGE_NOTPRESSED
+ 1;
57 // ============================================================================
59 ScOutlineWindow::ScOutlineWindow( Window
* pParent
, ScOutlineMode eMode
, ScViewData
* pViewData
, ScSplitPos eWhich
) :
61 mrViewData( *pViewData
),
63 mbHoriz( eMode
== SC_OUTLINE_HOR
),
64 mbMirrorEntries( false ), // updated in SetHeaderSize
65 mbMirrorLevels( false ), // updated in SetHeaderSize
67 maLineColor( COL_BLACK
),
75 mnFocusEntry( SC_OL_HEADERENTRY
),
76 mbDontDrawFocus( false )
78 EnableRTL( FALSE
); // mirroring is done manually
81 maFocusRect
.SetEmpty();
84 // insert the window into task pane list for "F6 cycling"
85 if( SystemWindow
* pSysWin
= GetSystemWindow() )
86 if( TaskPaneList
* pTaskPaneList
= pSysWin
->GetTaskPaneList() )
87 pTaskPaneList
->AddWindow( this );
90 ScOutlineWindow::~ScOutlineWindow()
92 // remove the window from task pane list
93 if( SystemWindow
* pSysWin
= GetSystemWindow() )
94 if( TaskPaneList
* pTaskPaneList
= pSysWin
->GetTaskPaneList() )
95 pTaskPaneList
->RemoveWindow( this );
98 void ScOutlineWindow::SetHeaderSize( long nNewSize
)
100 BOOL bLayoutRTL
= GetDoc().IsLayoutRTL( GetTab() );
101 mbMirrorEntries
= bLayoutRTL
&& mbHoriz
;
102 mbMirrorLevels
= bLayoutRTL
&& !mbHoriz
;
104 bool bNew
= (nNewSize
!= mnHeaderSize
);
105 mnHeaderSize
= nNewSize
;
106 mnHeaderPos
= mbMirrorEntries
? (GetOutputSizeEntry() - mnHeaderSize
) : 0;
107 mnMainFirstPos
= mbMirrorEntries
? 0 : mnHeaderSize
;
108 mnMainLastPos
= GetOutputSizeEntry() - (mbMirrorEntries
? mnHeaderSize
: 0) - 1;
113 long ScOutlineWindow::GetDepthSize() const
115 long nSize
= GetLevelCount() * SC_OL_BITMAPSIZE
;
117 nSize
+= 2 * SC_OL_POSOFFSET
+ 1;
121 void ScOutlineWindow::ScrollPixel( long nDiff
)
124 mbDontDrawFocus
= true;
126 long nStart
= mnMainFirstPos
;
127 long nEnd
= mnMainLastPos
;
129 long nInvStart
, nInvEnd
;
133 nInvStart
= nEnd
+ nDiff
;
140 nInvEnd
= nStart
+ nDiff
;
143 ScrollRel( nDiff
, nStart
, nEnd
);
144 Invalidate( GetRectangle( 0, nInvStart
, GetOutputSizeLevel() - 1, nInvEnd
) );
147 // if focus becomes invisible, move it to next visible button
148 ImplMoveFocusToVisible( nDiff
< 0 );
150 mbDontDrawFocus
= false;
154 void ScOutlineWindow::ScrollRel( long nEntryDiff
, long nEntryStart
, long nEntryEnd
)
156 Rectangle
aRect( GetRectangle( 0, nEntryStart
, GetOutputSizeLevel() - 1, nEntryEnd
) );
158 Scroll( nEntryDiff
, 0, aRect
);
160 Scroll( 0, nEntryDiff
, aRect
);
163 // internal -------------------------------------------------------------------
165 void ScOutlineWindow::InitSettings()
167 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
168 SetBackground( rStyleSettings
.GetFaceColor() );
169 maLineColor
= rStyleSettings
.GetButtonTextColor();
170 mpSymbols
= ScGlobal::GetOutlineSymbols( !!GetBackground().GetColor().IsDark() );
174 const ScOutlineArray
* ScOutlineWindow::GetOutlineArray() const
176 const ScOutlineTable
* pTable
= GetDoc().GetOutlineTable( GetTab() );
177 if ( !pTable
) return NULL
;
178 return mbHoriz
? pTable
->GetColArray() : pTable
->GetRowArray();
181 const ScOutlineEntry
* ScOutlineWindow::GetOutlineEntry( size_t nLevel
, size_t nEntry
) const
183 const ScOutlineArray
* pArray
= GetOutlineArray();
184 return pArray
? pArray
->GetEntry( sal::static_int_cast
<USHORT
>(nLevel
), sal::static_int_cast
<USHORT
>(nEntry
) ) : NULL
;
187 bool ScOutlineWindow::IsHidden( SCCOLROW nColRowIndex
) const
190 GetDoc().ColHidden(static_cast<SCCOL
>(nColRowIndex
), GetTab()) :
191 GetDoc().RowHidden(static_cast<SCROW
>(nColRowIndex
), GetTab());
194 bool ScOutlineWindow::IsFiltered( SCCOLROW nColRowIndex
) const
196 // columns cannot be filtered
197 return !mbHoriz
&& GetDoc().RowFiltered( static_cast<SCROW
>(nColRowIndex
), GetTab() );
200 bool ScOutlineWindow::IsFirstVisible( SCCOLROW nColRowIndex
) const
202 bool bAllHidden
= true;
203 for ( SCCOLROW nPos
= 0; (nPos
< nColRowIndex
) && bAllHidden
; ++nPos
)
204 bAllHidden
= IsHidden( nPos
);
208 void ScOutlineWindow::GetVisibleRange( SCCOLROW
& rnColRowStart
, SCCOLROW
& rnColRowEnd
) const
212 rnColRowStart
= mrViewData
.GetPosX( WhichH( meWhich
) );
213 rnColRowEnd
= rnColRowStart
+ mrViewData
.VisibleCellsX( WhichH( meWhich
) );
217 rnColRowStart
= mrViewData
.GetPosY( WhichV( meWhich
) );
218 rnColRowEnd
= rnColRowStart
+ mrViewData
.VisibleCellsY( WhichV( meWhich
) );
221 // include collapsed columns/rows in front of visible range
222 while ( (rnColRowStart
> 0) && IsHidden( rnColRowStart
- 1 ) )
226 Point
ScOutlineWindow::GetPoint( long nLevelPos
, long nEntryPos
) const
228 return mbHoriz
? Point( nEntryPos
, nLevelPos
) : Point( nLevelPos
, nEntryPos
);
231 Rectangle
ScOutlineWindow::GetRectangle(
232 long nLevelStart
, long nEntryStart
, long nLevelEnd
, long nEntryEnd
) const
234 return Rectangle( GetPoint( nLevelStart
, nEntryStart
), GetPoint( nLevelEnd
, nEntryEnd
) );
237 long ScOutlineWindow::GetOutputSizeLevel() const
239 Size
aSize( GetOutputSizePixel() );
240 return mbHoriz
? aSize
.Height() : aSize
.Width();
243 long ScOutlineWindow::GetOutputSizeEntry() const
245 Size
aSize( GetOutputSizePixel() );
246 return mbHoriz
? aSize
.Width() : aSize
.Height();
249 size_t ScOutlineWindow::GetLevelCount() const
251 const ScOutlineArray
* pArray
= GetOutlineArray();
252 size_t nLevelCount
= pArray
? pArray
->GetDepth() : 0;
253 return nLevelCount
? (nLevelCount
+ 1) : 0;
256 long ScOutlineWindow::GetLevelPos( size_t nLevel
) const
258 // #i51970# must always return the *left* edge of the area used by a level
259 long nPos
= static_cast< long >( SC_OL_POSOFFSET
+ nLevel
* SC_OL_BITMAPSIZE
);
260 return mbMirrorLevels
? (GetOutputSizeLevel() - nPos
- SC_OL_BITMAPSIZE
) : nPos
;
263 size_t ScOutlineWindow::GetLevelFromPos( long nLevelPos
) const
265 if( mbMirrorLevels
) nLevelPos
= GetOutputSizeLevel() - nLevelPos
- 1;
266 long nStart
= SC_OL_POSOFFSET
;
267 if ( nLevelPos
< nStart
) return SC_OL_NOLEVEL
;
268 size_t nLevel
= static_cast< size_t >( (nLevelPos
- nStart
) / SC_OL_BITMAPSIZE
);
269 return (nLevel
< GetLevelCount()) ? nLevel
: SC_OL_NOLEVEL
;
272 long ScOutlineWindow::GetColRowPos( SCCOLROW nColRowIndex
) const
274 long nDocPos
= mbHoriz
?
275 mrViewData
.GetScrPos( static_cast<SCCOL
>(nColRowIndex
), 0, meWhich
, TRUE
).X() :
276 mrViewData
.GetScrPos( 0, static_cast<SCROW
>(nColRowIndex
), meWhich
, TRUE
).Y();
277 return mnMainFirstPos
+ nDocPos
;
280 long ScOutlineWindow::GetHeaderEntryPos() const
282 return mnHeaderPos
+ (mnHeaderSize
- SC_OL_BITMAPSIZE
) / 2;
285 bool ScOutlineWindow::GetEntryPos(
286 size_t nLevel
, size_t nEntry
,
287 long& rnStartPos
, long& rnEndPos
, long& rnImagePos
) const
289 const ScOutlineEntry
* pEntry
= GetOutlineEntry( nLevel
, nEntry
);
290 if ( !pEntry
|| !pEntry
->IsVisible() )
293 SCCOLROW nStart
= pEntry
->GetStart();
294 SCCOLROW nEnd
= pEntry
->GetEnd();
296 long nEntriesSign
= mbMirrorEntries
? -1 : 1;
298 // --- common calculation ---
300 rnStartPos
= GetColRowPos( nStart
);
301 rnEndPos
= GetColRowPos( nEnd
+ 1 );
303 bool bHidden
= IsHidden( nStart
);
304 rnImagePos
= bHidden
?
305 (rnStartPos
- ( SC_OL_BITMAPSIZE
/ 2 ) * nEntriesSign
) :
306 rnStartPos
+ nEntriesSign
;
307 long nCenter
= (rnStartPos
+ rnEndPos
- SC_OL_BITMAPSIZE
* nEntriesSign
+
308 ( mbMirrorEntries
? 1 : 0 )) / 2L;
309 rnImagePos
= mbMirrorEntries
? Max( rnImagePos
, nCenter
) : Min( rnImagePos
, nCenter
);
311 // --- refinements ---
313 // do not cut leftmost/topmost image
314 if ( bHidden
&& IsFirstVisible( nStart
) )
315 rnImagePos
= rnStartPos
;
317 // do not cover previous collapsed image
318 if ( !bHidden
&& nEntry
)
320 const ScOutlineEntry
* pPrevEntry
= GetOutlineEntry( nLevel
, nEntry
- 1 );
321 SCCOLROW nPrevEnd
= pPrevEntry
->GetEnd();
322 if ( (nPrevEnd
+ 1 == nStart
) && IsHidden( nPrevEnd
) )
324 if ( IsFirstVisible( pPrevEntry
->GetStart() ) )
325 rnStartPos
+= SC_OL_BITMAPSIZE
* nEntriesSign
;
327 rnStartPos
+= ( SC_OL_BITMAPSIZE
/ 2 ) * nEntriesSign
;
328 rnImagePos
= rnStartPos
;
332 // restrict rnStartPos...rnEndPos to valid area
333 rnStartPos
= std::max( rnStartPos
, mnMainFirstPos
);
334 rnEndPos
= std::max( rnEndPos
, mnMainFirstPos
);
336 if ( mbMirrorEntries
)
337 rnImagePos
-= SC_OL_BITMAPSIZE
- 1; // start pos aligns with right edge of bitmap
339 // --- all rows filtered? ---
341 bool bVisible
= true;
345 for ( SCCOLROW nRow
= nStart
; (nRow
<= nEnd
) && !bVisible
; ++nRow
)
346 bVisible
= !IsFiltered( nRow
);
351 bool ScOutlineWindow::GetImagePos( size_t nLevel
, size_t nEntry
, Point
& rPos
) const
353 bool bRet
= nLevel
< GetLevelCount();
356 long nLevelPos
= GetLevelPos( nLevel
);
357 if ( nEntry
== SC_OL_HEADERENTRY
)
358 rPos
= GetPoint( nLevelPos
, GetHeaderEntryPos() );
361 long nStartPos
, nEndPos
, nImagePos
;
362 bRet
= GetEntryPos( nLevel
, nEntry
, nStartPos
, nEndPos
, nImagePos
);
363 rPos
= GetPoint( nLevelPos
, nImagePos
);
369 bool ScOutlineWindow::IsButtonVisible( size_t nLevel
, size_t nEntry
) const
372 if ( nEntry
== SC_OL_HEADERENTRY
)
373 bRet
= (mnHeaderSize
> 0) && (nLevel
< GetLevelCount());
376 const ScOutlineEntry
* pEntry
= GetOutlineEntry( nLevel
, nEntry
);
377 if ( pEntry
&& pEntry
->IsVisible() )
379 SCCOLROW nStart
, nEnd
;
380 GetVisibleRange( nStart
, nEnd
);
381 bRet
= (nStart
<= pEntry
->GetStart()) && (pEntry
->GetStart() <= nEnd
);
387 bool ScOutlineWindow::ItemHit( const Point
& rPos
, size_t& rnLevel
, size_t& rnEntry
, bool& rbButton
) const
389 const ScOutlineArray
* pArray
= GetOutlineArray();
390 if ( !pArray
) return false;
392 SCCOLROW nStartIndex
, nEndIndex
;
393 GetVisibleRange( nStartIndex
, nEndIndex
);
395 size_t nLevel
= GetLevelFromPos( mbHoriz
? rPos
.Y() : rPos
.X() );
396 if ( nLevel
== SC_OL_NOLEVEL
)
399 // long nLevelPos = GetLevelPos( nLevel );
400 long nEntryMousePos
= mbHoriz
? rPos
.X() : rPos
.Y();
402 // --- level buttons ---
404 if ( mnHeaderSize
> 0 )
406 long nImagePos
= GetHeaderEntryPos();
407 if ( (nImagePos
<= nEntryMousePos
) && (nEntryMousePos
< nImagePos
+ SC_OL_BITMAPSIZE
) )
410 rnEntry
= SC_OL_HEADERENTRY
;
416 // --- expand/collapse buttons and expanded lines ---
418 // search outline entries backwards
419 size_t nEntry
= pArray
->GetCount( sal::static_int_cast
<USHORT
>(nLevel
) );
424 const ScOutlineEntry
* pEntry
= pArray
->GetEntry( sal::static_int_cast
<USHORT
>(nLevel
),
425 sal::static_int_cast
<USHORT
>(nEntry
) );
426 SCCOLROW nStart
= pEntry
->GetStart();
427 SCCOLROW nEnd
= pEntry
->GetEnd();
429 if ( (nEnd
>= nStartIndex
) && (nStart
<= nEndIndex
) )
431 long nStartPos
, nEndPos
, nImagePos
;
432 if ( GetEntryPos( nLevel
, nEntry
, nStartPos
, nEndPos
, nImagePos
) )
438 if ( (nStart
>= nStartIndex
) && (nImagePos
<= nEntryMousePos
) && (nEntryMousePos
< nImagePos
+ SC_OL_BITMAPSIZE
) )
445 if ( mbMirrorEntries
)
446 ::std::swap( nStartPos
, nEndPos
); // in RTL mode, nStartPos is the larger value
447 if ( (nStartPos
<= nEntryMousePos
) && (nEntryMousePos
<= nEndPos
) )
459 bool ScOutlineWindow::ButtonHit( const Point
& rPos
, size_t& rnLevel
, size_t& rnEntry
) const
462 bool bRet
= ItemHit( rPos
, rnLevel
, rnEntry
, bButton
);
463 return bRet
&& bButton
;
466 bool ScOutlineWindow::LineHit( const Point
& rPos
, size_t& rnLevel
, size_t& rnEntry
) const
469 bool bRet
= ItemHit( rPos
, rnLevel
, rnEntry
, bButton
);
470 return bRet
&& !bButton
;
473 void ScOutlineWindow::DoFunction( size_t nLevel
, size_t nEntry
) const
475 ScDBFunc
& rFunc
= *mrViewData
.GetView();
476 if ( nEntry
== SC_OL_HEADERENTRY
)
477 rFunc
.SelectLevel( mbHoriz
, sal::static_int_cast
<USHORT
>(nLevel
) );
480 const ScOutlineEntry
* pEntry
= GetOutlineEntry( nLevel
, nEntry
);
483 if ( pEntry
->IsHidden() )
484 rFunc
.ShowOutline( mbHoriz
, sal::static_int_cast
<USHORT
>(nLevel
), sal::static_int_cast
<USHORT
>(nEntry
) );
486 rFunc
.HideOutline( mbHoriz
, sal::static_int_cast
<USHORT
>(nLevel
), sal::static_int_cast
<USHORT
>(nEntry
) );
491 void ScOutlineWindow::DoExpand( size_t nLevel
, size_t nEntry
) const
493 const ScOutlineEntry
* pEntry
= GetOutlineEntry( nLevel
, nEntry
);
494 if ( pEntry
&& pEntry
->IsHidden() )
495 DoFunction( nLevel
, nEntry
);
498 void ScOutlineWindow::DoCollapse( size_t nLevel
, size_t nEntry
) const
500 const ScOutlineEntry
* pEntry
= GetOutlineEntry( nLevel
, nEntry
);
501 if ( pEntry
&& !pEntry
->IsHidden() )
502 DoFunction( nLevel
, nEntry
);
505 void ScOutlineWindow::Resize()
508 SetHeaderSize( mnHeaderSize
); // recalculates header/group positions
509 if ( !IsFocusButtonVisible() )
512 ShowFocus(); // calculates valid position
516 void ScOutlineWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
518 if ( (rDCEvt
.GetType() == DATACHANGED_SETTINGS
) &&
519 (rDCEvt
.GetFlags() & SETTINGS_STYLE
) )
524 Window::DataChanged( rDCEvt
);
527 // drawing --------------------------------------------------------------------
529 void ScOutlineWindow::SetEntryAreaClipRegion()
531 SetClipRegion( Rectangle(
532 GetPoint( 0, mnMainFirstPos
),
533 GetPoint( GetOutputSizeLevel() - 1, mnMainLastPos
) ) );
536 void ScOutlineWindow::DrawLineRel(
537 long nLevelStart
, long nEntryStart
, long nLevelEnd
, long nEntryEnd
)
539 DrawLine( GetPoint( nLevelStart
, nEntryStart
), GetPoint( nLevelEnd
, nEntryEnd
) );
542 void ScOutlineWindow::DrawRectRel(
543 long nLevelStart
, long nEntryStart
, long nLevelEnd
, long nEntryEnd
)
545 DrawRect( GetRectangle( nLevelStart
, nEntryStart
, nLevelEnd
, nEntryEnd
) );
548 void ScOutlineWindow::DrawImageRel( long nLevelPos
, long nEntryPos
, USHORT nId
)
550 DBG_ASSERT( mpSymbols
, "ScOutlineWindow::DrawImageRel - no images" );
551 const Image
& rImage
= mpSymbols
->GetImage( nId
);
553 SetFillColor( GetBackground().GetColor() );
554 Point
aPos( GetPoint( nLevelPos
, nEntryPos
) );
555 DrawRect( Rectangle( aPos
, rImage
.GetSizePixel() ) );
556 DrawImage( aPos
, rImage
);
559 void ScOutlineWindow::DrawBorderRel( size_t nLevel
, size_t nEntry
, bool bPressed
)
562 if ( GetImagePos( nLevel
, nEntry
, aPos
) )
564 DBG_ASSERT( mpSymbols
, "ScOutlineWindow::DrawBorderRel - no images" );
565 USHORT nId
= bPressed
? SC_OL_IMAGE_PRESSED
: SC_OL_IMAGE_NOTPRESSED
;
566 bool bClip
= (nEntry
!= SC_OL_HEADERENTRY
);
568 SetEntryAreaClipRegion();
569 DrawImage( aPos
, mpSymbols
->GetImage( nId
) );
573 mbMTPressed
= bPressed
;
576 void ScOutlineWindow::ShowFocus()
580 // first move to a visible position
581 ImplMoveFocusToVisible( true );
583 if ( IsFocusButtonVisible() )
586 if ( GetImagePos( mnFocusLevel
, mnFocusEntry
, aPos
) )
588 aPos
+= Point( 1, 1 );
589 maFocusRect
= Rectangle( aPos
, Size( SC_OL_BITMAPSIZE
- 2, SC_OL_BITMAPSIZE
- 2 ) );
590 bool bClip
= (mnFocusEntry
!= SC_OL_HEADERENTRY
);
592 SetEntryAreaClipRegion();
593 InvertTracking( maFocusRect
, SHOWTRACK_SMALL
| SHOWTRACK_WINDOW
);
601 void ScOutlineWindow::HideFocus()
603 if ( !maFocusRect
.IsEmpty() )
605 bool bClip
= (mnFocusEntry
!= SC_OL_HEADERENTRY
);
607 SetEntryAreaClipRegion();
608 InvertTracking( maFocusRect
, SHOWTRACK_SMALL
| SHOWTRACK_WINDOW
);
611 maFocusRect
.SetEmpty();
615 void ScOutlineWindow::Paint( const Rectangle
& /* rRect */ )
617 long nEntriesSign
= mbMirrorEntries
? -1 : 1;
618 long nLevelsSign
= mbMirrorLevels
? -1 : 1;
620 Size aSize
= GetOutputSizePixel();
621 long nLevelEnd
= (mbHoriz
? aSize
.Height() : aSize
.Width()) - 1;
622 long nEntryEnd
= (mbHoriz
? aSize
.Width() : aSize
.Height()) - 1;
624 SetLineColor( maLineColor
);
625 long nBorderPos
= mbMirrorLevels
? 0 : nLevelEnd
;
626 DrawLineRel( nBorderPos
, 0, nBorderPos
, nEntryEnd
);
628 const ScOutlineArray
* pArray
= GetOutlineArray();
629 if ( !pArray
) return;
631 size_t nLevelCount
= GetLevelCount();
633 // --- draw header images ---
635 if ( mnHeaderSize
> 0 )
637 long nEntryPos
= GetHeaderEntryPos();
638 for ( size_t nLevel
= 0; nLevel
< nLevelCount
; ++nLevel
)
639 DrawImageRel( GetLevelPos( nLevel
), nEntryPos
, static_cast< USHORT
>( nLevel
+ 1 ) );
641 SetLineColor( maLineColor
);
642 long nLinePos
= mnHeaderPos
+ (mbMirrorEntries
? 0 : (mnHeaderSize
- 1));
643 DrawLineRel( 0, nLinePos
, nLevelEnd
, nLinePos
);
646 // --- draw lines & collapse/expand images ---
648 SetEntryAreaClipRegion();
650 SCCOLROW nStartIndex
, nEndIndex
;
651 GetVisibleRange( nStartIndex
, nEndIndex
);
653 for ( size_t nLevel
= 0; nLevel
+ 1 < nLevelCount
; ++nLevel
)
655 long nLevelPos
= GetLevelPos( nLevel
);
656 long nEntryPos1
= 0, nEntryPos2
= 0, nImagePos
= 0;
658 size_t nEntryCount
= pArray
->GetCount( sal::static_int_cast
<USHORT
>(nLevel
) );
661 // first draw all lines in the current level
663 SetFillColor( maLineColor
);
664 for ( nEntry
= 0; nEntry
< nEntryCount
; ++nEntry
)
666 const ScOutlineEntry
* pEntry
= pArray
->GetEntry( sal::static_int_cast
<USHORT
>(nLevel
),
667 sal::static_int_cast
<USHORT
>(nEntry
) );
668 SCCOLROW nStart
= pEntry
->GetStart();
669 SCCOLROW nEnd
= pEntry
->GetEnd();
672 bool bDraw
= (nEnd
>= nStartIndex
) && (nStart
<= nEndIndex
);
673 // find output coordinates
675 bDraw
= GetEntryPos( nLevel
, nEntry
, nEntryPos1
, nEntryPos2
, nImagePos
);
676 // draw, if not collapsed
677 if ( bDraw
&& !pEntry
->IsHidden() )
679 if ( nStart
>= nStartIndex
)
680 nEntryPos1
+= nEntriesSign
;
681 nEntryPos2
-= 2 * nEntriesSign
;
682 long nLinePos
= nLevelPos
;
683 if ( mbMirrorLevels
)
684 nLinePos
+= SC_OL_BITMAPSIZE
- 1; // align with right edge of bitmap
685 DrawRectRel( nLinePos
, nEntryPos1
, nLinePos
+ nLevelsSign
, nEntryPos2
);
687 if ( nEnd
<= nEndIndex
)
688 DrawRectRel( nLinePos
, nEntryPos2
- nEntriesSign
,
689 nLinePos
+ ( SC_OL_BITMAPSIZE
/ 3 ) * nLevelsSign
, nEntryPos2
);
693 // draw all images in the level from last to first
694 nEntry
= nEntryCount
;
699 const ScOutlineEntry
* pEntry
= pArray
->GetEntry( sal::static_int_cast
<USHORT
>(nLevel
),
700 sal::static_int_cast
<USHORT
>(nEntry
) );
701 SCCOLROW nStart
= pEntry
->GetStart();
702 // SCCOLROW nEnd = pEntry->GetEnd();
705 bool bDraw
= (nStartIndex
<= nStart
) && (nStart
<= nEndIndex
+ 1);
706 // find output coordinates
708 bDraw
= GetEntryPos( nLevel
, nEntry
, nEntryPos1
, nEntryPos2
, nImagePos
);
709 // draw, if not hidden by higher levels
712 USHORT nImageId
= pEntry
->IsHidden() ? SC_OL_IMAGE_PLUS
: SC_OL_IMAGE_MINUS
;
713 DrawImageRel( nLevelPos
, nImagePos
, nImageId
);
720 if ( !mbDontDrawFocus
)
724 // focus ----------------------------------------------------------------------
726 /** Increments or decrements a value and wraps at the specified limits.
727 @return true = value wrapped. */
728 bool lcl_RotateValue( size_t& rnValue
, size_t nMin
, size_t nMax
, bool bForward
)
730 DBG_ASSERT( nMin
<= nMax
, "lcl_RotateValue - invalid range" );
731 DBG_ASSERT( nMax
< static_cast< size_t >( -1 ), "lcl_RotateValue - range overflow" );
735 if ( rnValue
< nMax
)
745 if ( rnValue
> nMin
)
756 bool ScOutlineWindow::IsFocusButtonVisible() const
758 return IsButtonVisible( mnFocusLevel
, mnFocusEntry
);
761 bool ScOutlineWindow::ImplMoveFocusByEntry( bool bForward
, bool bFindVisible
)
763 const ScOutlineArray
* pArray
= GetOutlineArray();
767 bool bWrapped
= false;
768 size_t nEntryCount
= pArray
->GetCount( sal::static_int_cast
<USHORT
>(mnFocusLevel
) );
769 // #i29530# entry count may be decreased after changing active sheet
770 if( mnFocusEntry
>= nEntryCount
)
771 mnFocusEntry
= SC_OL_HEADERENTRY
;
772 size_t nOldEntry
= mnFocusEntry
;
776 if ( mnFocusEntry
== SC_OL_HEADERENTRY
)
778 // move from header to first or last entry
779 if ( nEntryCount
> 0 )
780 mnFocusEntry
= bForward
? 0 : (nEntryCount
- 1);
781 /* wrapped, if forward from right header to first entry,
782 or if backward from left header to last entry */
783 // Header and entries are now always in consistent order,
784 // so there's no need to check for mirroring here.
785 if ( !nEntryCount
|| !bForward
)
788 else if ( lcl_RotateValue( mnFocusEntry
, 0, nEntryCount
- 1, bForward
) )
790 // lcl_RotateValue returns true -> wrapped the entry range -> move to header
791 mnFocusEntry
= SC_OL_HEADERENTRY
;
792 /* wrapped, if forward from last entry to left header,
793 or if backward from first entry to right header */
798 while ( bFindVisible
&& !IsFocusButtonVisible() && (nOldEntry
!= mnFocusEntry
) );
803 bool ScOutlineWindow::ImplMoveFocusByLevel( bool bForward
)
805 const ScOutlineArray
* pArray
= GetOutlineArray();
809 bool bWrapped
= false;
810 size_t nLevelCount
= GetLevelCount();
812 if ( mnFocusEntry
== SC_OL_HEADERENTRY
)
814 if ( nLevelCount
> 0 )
815 bWrapped
= lcl_RotateValue( mnFocusLevel
, 0, nLevelCount
- 1, bForward
);
819 const ScOutlineEntry
* pEntry
= pArray
->GetEntry( sal::static_int_cast
<USHORT
>(mnFocusLevel
),
820 sal::static_int_cast
<USHORT
>(mnFocusEntry
) );
823 SCCOLROW nStart
= pEntry
->GetStart();
824 SCCOLROW nEnd
= pEntry
->GetEnd();
825 size_t nNewLevel
= mnFocusLevel
;
826 size_t nNewEntry
= 0;
829 if ( bForward
&& (mnFocusLevel
+ 2 < nLevelCount
) )
831 // next level -> find first child entry
832 nNewLevel
= mnFocusLevel
+ 1;
833 // TODO - change ScOutlineArray interface to size_t usage
834 USHORT nTmpEntry
= 0;
835 bFound
= pArray
->GetEntryIndexInRange( sal::static_int_cast
<USHORT
>(nNewLevel
), nStart
, nEnd
, nTmpEntry
);
836 nNewEntry
= nTmpEntry
;
838 else if ( !bForward
&& (mnFocusLevel
> 0) )
840 // previous level -> find parent entry
841 nNewLevel
= mnFocusLevel
- 1;
842 // TODO - change ScOutlineArray interface to size_t usage
843 USHORT nTmpEntry
= 0;
844 bFound
= pArray
->GetEntryIndex( sal::static_int_cast
<USHORT
>(nNewLevel
), nStart
, nTmpEntry
);
845 nNewEntry
= nTmpEntry
;
848 if ( bFound
&& IsButtonVisible( nNewLevel
, nNewEntry
) )
850 mnFocusLevel
= nNewLevel
;
851 mnFocusEntry
= nNewEntry
;
859 bool ScOutlineWindow::ImplMoveFocusByTabOrder( bool bForward
, bool bFindVisible
)
862 size_t nOldLevel
= mnFocusLevel
;
863 size_t nOldEntry
= mnFocusEntry
;
867 /* one level up, if backward from left header,
868 or one level down, if forward from right header */
869 if ( (!bForward
) && (mnFocusEntry
== SC_OL_HEADERENTRY
) )
870 bRet
|= ImplMoveFocusByLevel( bForward
);
871 // move to next/previous entry
872 bool bWrapInLevel
= ImplMoveFocusByEntry( bForward
, false );
873 bRet
|= bWrapInLevel
;
874 /* one level up, if wrapped backward to right header,
875 or one level down, if wrapped forward to right header */
876 if ( bForward
&& bWrapInLevel
)
877 bRet
|= ImplMoveFocusByLevel( bForward
);
879 while ( bFindVisible
&& !IsFocusButtonVisible() && ((nOldLevel
!= mnFocusLevel
) || (nOldEntry
!= mnFocusEntry
)) );
884 void ScOutlineWindow::ImplMoveFocusToVisible( bool bForward
)
886 // first try to find an entry in the same level
887 if ( !IsFocusButtonVisible() )
888 ImplMoveFocusByEntry( bForward
, true );
889 // then try to find any other entry
890 if ( !IsFocusButtonVisible() )
891 ImplMoveFocusByTabOrder( bForward
, true );
894 void ScOutlineWindow::MoveFocusByEntry( bool bForward
)
897 ImplMoveFocusByEntry( bForward
, true );
901 void ScOutlineWindow::MoveFocusByLevel( bool bForward
)
904 ImplMoveFocusByLevel( bForward
);
908 void ScOutlineWindow::MoveFocusByTabOrder( bool bForward
)
911 ImplMoveFocusByTabOrder( bForward
, true );
915 void ScOutlineWindow::GetFocus()
921 void ScOutlineWindow::LoseFocus()
928 // mouse ----------------------------------------------------------------------
930 void ScOutlineWindow::StartMouseTracking( size_t nLevel
, size_t nEntry
)
935 DrawBorderRel( nLevel
, nEntry
, true );
938 void ScOutlineWindow::EndMouseTracking()
941 DrawBorderRel( mnMTLevel
, mnMTEntry
, false );
945 void ScOutlineWindow::MouseMove( const MouseEvent
& rMEvt
)
947 if ( IsMouseTracking() )
949 size_t nLevel
, nEntry
;
952 if ( ButtonHit( rMEvt
.GetPosPixel(), nLevel
, nEntry
) )
953 bHit
= (nLevel
== mnMTLevel
) && (nEntry
== mnMTEntry
);
955 if ( bHit
!= mbMTPressed
)
956 DrawBorderRel( mnMTLevel
, mnMTEntry
, bHit
);
960 void ScOutlineWindow::MouseButtonUp( const MouseEvent
& rMEvt
)
962 if ( IsMouseTracking() )
966 size_t nLevel
, nEntry
;
967 if ( ButtonHit( rMEvt
.GetPosPixel(), nLevel
, nEntry
) )
968 if ( (nLevel
== mnMTLevel
) && (nEntry
== mnMTEntry
) )
969 DoFunction( nLevel
, nEntry
);
973 void ScOutlineWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
975 size_t nLevel
, nEntry
;
976 bool bHit
= ButtonHit( rMEvt
.GetPosPixel(), nLevel
, nEntry
);
978 StartMouseTracking( nLevel
, nEntry
);
979 else if ( rMEvt
.GetClicks() == 2 )
981 bHit
= LineHit( rMEvt
.GetPosPixel(), nLevel
, nEntry
);
983 DoFunction( nLevel
, nEntry
);
986 // if an item has been hit and window is focused, move focus to this item
987 if ( bHit
&& HasFocus() )
990 mnFocusLevel
= nLevel
;
991 mnFocusEntry
= nEntry
;
997 // keyboard -------------------------------------------------------------------
999 void ScOutlineWindow::KeyInput( const KeyEvent
& rKEvt
)
1001 const KeyCode
& rKCode
= rKEvt
.GetKeyCode();
1002 bool bNoMod
= !rKCode
.GetModifier();
1003 bool bShift
= (rKCode
.GetModifier() == KEY_SHIFT
);
1004 bool bCtrl
= (rKCode
.GetModifier() == KEY_MOD1
);
1006 USHORT nCode
= rKCode
.GetCode();
1007 bool bUpDownKey
= (nCode
== KEY_UP
) || (nCode
== KEY_DOWN
);
1008 bool bLeftRightKey
= (nCode
== KEY_LEFT
) || (nCode
== KEY_RIGHT
);
1011 if ( (nCode
== KEY_TAB
) && (bNoMod
|| bShift
) )
1012 // move forward without SHIFT key
1013 MoveFocusByTabOrder( bNoMod
); // TAB uses logical order, regardless of mirroring
1015 // LEFT/RIGHT/UP/DOWN keys
1016 else if ( bNoMod
&& (bUpDownKey
|| bLeftRightKey
) )
1018 bool bForward
= (nCode
== KEY_DOWN
) || (nCode
== KEY_RIGHT
);
1019 if ( mbHoriz
== bLeftRightKey
)
1020 // move inside level with LEFT/RIGHT in horizontal and with UP/DOWN in vertical
1021 MoveFocusByEntry( bForward
!= mbMirrorEntries
);
1023 // move to next/prev level with LEFT/RIGHT in vertical and with UP/DOWN in horizontal
1024 MoveFocusByLevel( bForward
!= mbMirrorLevels
);
1028 else if ( bCtrl
&& (nCode
>= KEY_1
) && (nCode
<= KEY_9
) )
1030 size_t nLevel
= static_cast< size_t >( nCode
- KEY_1
);
1031 if ( nLevel
< GetLevelCount() )
1032 DoFunction( nLevel
, SC_OL_HEADERENTRY
);
1036 else switch ( rKCode
.GetFullCode() )
1038 case KEY_ADD
: DoExpand( mnFocusLevel
, mnFocusEntry
); break;
1039 case KEY_SUBTRACT
: DoCollapse( mnFocusLevel
, mnFocusEntry
); break;
1041 case KEY_RETURN
: DoFunction( mnFocusLevel
, mnFocusEntry
); break;
1042 default: Window::KeyInput( rKEvt
);
1047 // ============================================================================