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 <vcl/svapp.hxx>
21 : #include <vcl/taskpanelist.hxx>
22 :
23 : #include "olinewin.hxx"
24 : #include "olinetab.hxx"
25 : #include "document.hxx"
26 : #include "dbfunc.hxx"
27 : #include "sc.hrc"
28 :
29 : // ============================================================================
30 :
31 : const long SC_OL_BITMAPSIZE = 12;
32 : const long SC_OL_POSOFFSET = 2;
33 :
34 : const size_t SC_OL_NOLEVEL = static_cast< size_t >( -1 );
35 : const size_t SC_OL_HEADERENTRY = static_cast< size_t >( -1 );
36 :
37 : const sal_uInt16 SC_OL_IMAGE_PLUS = 9;
38 : const sal_uInt16 SC_OL_IMAGE_MINUS = SC_OL_IMAGE_PLUS + 1;
39 : const sal_uInt16 SC_OL_IMAGE_NOTPRESSED = SC_OL_IMAGE_MINUS + 1;
40 : const sal_uInt16 SC_OL_IMAGE_PRESSED = SC_OL_IMAGE_NOTPRESSED + 1;
41 :
42 : // ============================================================================
43 :
44 0 : ScOutlineWindow::ScOutlineWindow( Window* pParent, ScOutlineMode eMode, ScViewData* pViewData, ScSplitPos eWhich ) :
45 : Window( pParent ),
46 : mrViewData( *pViewData ),
47 : meWhich( eWhich ),
48 : mbHoriz( eMode == SC_OUTLINE_HOR ),
49 : mbMirrorEntries( false ), // updated in SetHeaderSize
50 : mbMirrorLevels( false ), // updated in SetHeaderSize
51 : mpSymbols( NULL ),
52 : maLineColor( COL_BLACK ),
53 : mnHeaderSize( 0 ),
54 : mnHeaderPos( 0 ),
55 : mnMainFirstPos( 0 ),
56 : mnMainLastPos( 0 ),
57 : mbMTActive( false ),
58 : mbMTPressed( false ),
59 : mnFocusLevel( 0 ),
60 : mnFocusEntry( SC_OL_HEADERENTRY ),
61 0 : mbDontDrawFocus( false )
62 : {
63 0 : EnableRTL( false ); // mirroring is done manually
64 :
65 0 : InitSettings();
66 0 : maFocusRect.SetEmpty();
67 0 : SetHeaderSize( 0 );
68 :
69 : // insert the window into task pane list for "F6 cycling"
70 0 : if( SystemWindow* pSysWin = GetSystemWindow() )
71 0 : if( TaskPaneList* pTaskPaneList = pSysWin->GetTaskPaneList() )
72 0 : pTaskPaneList->AddWindow( this );
73 0 : }
74 :
75 0 : ScOutlineWindow::~ScOutlineWindow()
76 : {
77 : // remove the window from task pane list
78 0 : if( SystemWindow* pSysWin = GetSystemWindow() )
79 0 : if( TaskPaneList* pTaskPaneList = pSysWin->GetTaskPaneList() )
80 0 : pTaskPaneList->RemoveWindow( this );
81 0 : }
82 :
83 0 : void ScOutlineWindow::SetHeaderSize( long nNewSize )
84 : {
85 0 : sal_Bool bLayoutRTL = GetDoc().IsLayoutRTL( GetTab() );
86 0 : mbMirrorEntries = bLayoutRTL && mbHoriz;
87 0 : mbMirrorLevels = bLayoutRTL && !mbHoriz;
88 :
89 0 : bool bNew = (nNewSize != mnHeaderSize);
90 0 : mnHeaderSize = nNewSize;
91 0 : mnHeaderPos = mbMirrorEntries ? (GetOutputSizeEntry() - mnHeaderSize) : 0;
92 0 : mnMainFirstPos = mbMirrorEntries ? 0 : mnHeaderSize;
93 0 : mnMainLastPos = GetOutputSizeEntry() - (mbMirrorEntries ? mnHeaderSize : 0) - 1;
94 0 : if ( bNew )
95 0 : Invalidate();
96 0 : }
97 :
98 0 : long ScOutlineWindow::GetDepthSize() const
99 : {
100 0 : long nSize = GetLevelCount() * SC_OL_BITMAPSIZE;
101 0 : if ( nSize > 0 )
102 0 : nSize += 2 * SC_OL_POSOFFSET + 1;
103 0 : return nSize;
104 : }
105 :
106 0 : void ScOutlineWindow::ScrollPixel( long nDiff )
107 : {
108 0 : HideFocus();
109 0 : mbDontDrawFocus = true;
110 :
111 0 : long nStart = mnMainFirstPos;
112 0 : long nEnd = mnMainLastPos;
113 :
114 : long nInvStart, nInvEnd;
115 0 : if (nDiff < 0)
116 : {
117 0 : nStart -= nDiff;
118 0 : nInvStart = nEnd + nDiff;
119 0 : nInvEnd = nEnd;
120 : }
121 : else
122 : {
123 0 : nEnd -= nDiff;
124 0 : nInvStart = nStart;
125 0 : nInvEnd = nStart + nDiff;
126 : }
127 :
128 0 : ScrollRel( nDiff, nStart, nEnd );
129 0 : Invalidate( GetRectangle( 0, nInvStart, GetOutputSizeLevel() - 1, nInvEnd ) );
130 0 : Update();
131 :
132 : // if focus becomes invisible, move it to next visible button
133 0 : ImplMoveFocusToVisible( nDiff < 0 );
134 :
135 0 : mbDontDrawFocus = false;
136 0 : ShowFocus();
137 0 : }
138 :
139 0 : void ScOutlineWindow::ScrollRel( long nEntryDiff, long nEntryStart, long nEntryEnd )
140 : {
141 0 : Rectangle aRect( GetRectangle( 0, nEntryStart, GetOutputSizeLevel() - 1, nEntryEnd ) );
142 0 : if ( mbHoriz )
143 0 : Scroll( nEntryDiff, 0, aRect );
144 : else
145 0 : Scroll( 0, nEntryDiff, aRect );
146 0 : }
147 :
148 : // internal -------------------------------------------------------------------
149 :
150 0 : void ScOutlineWindow::InitSettings()
151 : {
152 0 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
153 0 : SetBackground( rStyleSettings.GetFaceColor() );
154 0 : maLineColor = rStyleSettings.GetButtonTextColor();
155 0 : mpSymbols = ScGlobal::GetOutlineSymbols();
156 0 : Invalidate();
157 0 : }
158 :
159 0 : const ScOutlineArray* ScOutlineWindow::GetOutlineArray() const
160 : {
161 0 : const ScOutlineTable* pTable = GetDoc().GetOutlineTable( GetTab() );
162 0 : if ( !pTable ) return NULL;
163 0 : return mbHoriz ? pTable->GetColArray() : pTable->GetRowArray();
164 : }
165 :
166 0 : const ScOutlineEntry* ScOutlineWindow::GetOutlineEntry( size_t nLevel, size_t nEntry ) const
167 : {
168 0 : const ScOutlineArray* pArray = GetOutlineArray();
169 0 : return pArray ? pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) ) : NULL;
170 : }
171 :
172 0 : bool ScOutlineWindow::IsHidden( SCCOLROW nColRowIndex ) const
173 : {
174 : return mbHoriz ?
175 0 : GetDoc().ColHidden(static_cast<SCCOL>(nColRowIndex), GetTab()) :
176 0 : GetDoc().RowHidden(static_cast<SCROW>(nColRowIndex), GetTab());
177 : }
178 :
179 0 : bool ScOutlineWindow::IsFiltered( SCCOLROW nColRowIndex ) const
180 : {
181 : // columns cannot be filtered
182 0 : return !mbHoriz && GetDoc().RowFiltered( static_cast<SCROW>(nColRowIndex), GetTab() );
183 : }
184 :
185 0 : bool ScOutlineWindow::IsFirstVisible( SCCOLROW nColRowIndex ) const
186 : {
187 0 : bool bAllHidden = true;
188 0 : for ( SCCOLROW nPos = 0; (nPos < nColRowIndex) && bAllHidden; ++nPos )
189 0 : bAllHidden = IsHidden( nPos );
190 0 : return bAllHidden;
191 : }
192 :
193 0 : void ScOutlineWindow::GetVisibleRange( SCCOLROW& rnColRowStart, SCCOLROW& rnColRowEnd ) const
194 : {
195 0 : if ( mbHoriz )
196 : {
197 0 : rnColRowStart = mrViewData.GetPosX( WhichH( meWhich ) );
198 0 : rnColRowEnd = rnColRowStart + mrViewData.VisibleCellsX( WhichH( meWhich ) );
199 : }
200 : else
201 : {
202 0 : rnColRowStart = mrViewData.GetPosY( WhichV( meWhich ) );
203 0 : rnColRowEnd = rnColRowStart + mrViewData.VisibleCellsY( WhichV( meWhich ) );
204 : }
205 :
206 : // include collapsed columns/rows in front of visible range
207 0 : while ( (rnColRowStart > 0) && IsHidden( rnColRowStart - 1 ) )
208 0 : --rnColRowStart;
209 0 : }
210 :
211 0 : Point ScOutlineWindow::GetPoint( long nLevelPos, long nEntryPos ) const
212 : {
213 0 : return mbHoriz ? Point( nEntryPos, nLevelPos ) : Point( nLevelPos, nEntryPos );
214 : }
215 :
216 0 : Rectangle ScOutlineWindow::GetRectangle(
217 : long nLevelStart, long nEntryStart, long nLevelEnd, long nEntryEnd ) const
218 : {
219 0 : return Rectangle( GetPoint( nLevelStart, nEntryStart ), GetPoint( nLevelEnd, nEntryEnd ) );
220 : }
221 :
222 0 : long ScOutlineWindow::GetOutputSizeLevel() const
223 : {
224 0 : Size aSize( GetOutputSizePixel() );
225 0 : return mbHoriz ? aSize.Height() : aSize.Width();
226 : }
227 :
228 0 : long ScOutlineWindow::GetOutputSizeEntry() const
229 : {
230 0 : Size aSize( GetOutputSizePixel() );
231 0 : return mbHoriz ? aSize.Width() : aSize.Height();
232 : }
233 :
234 0 : size_t ScOutlineWindow::GetLevelCount() const
235 : {
236 0 : const ScOutlineArray* pArray = GetOutlineArray();
237 0 : size_t nLevelCount = pArray ? pArray->GetDepth() : 0;
238 0 : return nLevelCount ? (nLevelCount + 1) : 0;
239 : }
240 :
241 0 : long ScOutlineWindow::GetLevelPos( size_t nLevel ) const
242 : {
243 : // #i51970# must always return the *left* edge of the area used by a level
244 0 : long nPos = static_cast< long >( SC_OL_POSOFFSET + nLevel * SC_OL_BITMAPSIZE );
245 0 : return mbMirrorLevels ? (GetOutputSizeLevel() - nPos - SC_OL_BITMAPSIZE) : nPos;
246 : }
247 :
248 0 : size_t ScOutlineWindow::GetLevelFromPos( long nLevelPos ) const
249 : {
250 0 : if( mbMirrorLevels ) nLevelPos = GetOutputSizeLevel() - nLevelPos - 1;
251 0 : long nStart = SC_OL_POSOFFSET;
252 0 : if ( nLevelPos < nStart ) return SC_OL_NOLEVEL;
253 0 : size_t nLevel = static_cast< size_t >( (nLevelPos - nStart) / SC_OL_BITMAPSIZE );
254 0 : return (nLevel < GetLevelCount()) ? nLevel : SC_OL_NOLEVEL;
255 : }
256 :
257 0 : long ScOutlineWindow::GetColRowPos( SCCOLROW nColRowIndex ) const
258 : {
259 : long nDocPos = mbHoriz ?
260 0 : mrViewData.GetScrPos( static_cast<SCCOL>(nColRowIndex), 0, meWhich, sal_True ).X() :
261 0 : mrViewData.GetScrPos( 0, static_cast<SCROW>(nColRowIndex), meWhich, sal_True ).Y();
262 0 : return mnMainFirstPos + nDocPos;
263 : }
264 :
265 0 : long ScOutlineWindow::GetHeaderEntryPos() const
266 : {
267 0 : return mnHeaderPos + (mnHeaderSize - SC_OL_BITMAPSIZE) / 2;
268 : }
269 :
270 0 : bool ScOutlineWindow::GetEntryPos(
271 : size_t nLevel, size_t nEntry,
272 : long& rnStartPos, long& rnEndPos, long& rnImagePos ) const
273 : {
274 0 : const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
275 0 : if ( !pEntry || !pEntry->IsVisible() )
276 0 : return false;
277 :
278 0 : SCCOLROW nStart = pEntry->GetStart();
279 0 : SCCOLROW nEnd = pEntry->GetEnd();
280 :
281 0 : long nEntriesSign = mbMirrorEntries ? -1 : 1;
282 :
283 : // --- common calculation ---
284 :
285 0 : rnStartPos = GetColRowPos( nStart );
286 0 : rnEndPos = GetColRowPos( nEnd + 1 );
287 :
288 0 : bool bHidden = IsHidden( nStart );
289 : rnImagePos = bHidden ?
290 : (rnStartPos - ( SC_OL_BITMAPSIZE / 2 ) * nEntriesSign) :
291 0 : rnStartPos + nEntriesSign;
292 : long nCenter = (rnStartPos + rnEndPos - SC_OL_BITMAPSIZE * nEntriesSign +
293 0 : ( mbMirrorEntries ? 1 : 0 )) / 2L;
294 0 : rnImagePos = mbMirrorEntries ? Max( rnImagePos, nCenter ) : Min( rnImagePos, nCenter );
295 :
296 : // --- refinements ---
297 :
298 : // do not cut leftmost/topmost image
299 0 : if ( bHidden && IsFirstVisible( nStart ) )
300 0 : rnImagePos = rnStartPos;
301 :
302 : // do not cover previous collapsed image
303 0 : if ( !bHidden && nEntry )
304 : {
305 0 : const ScOutlineEntry* pPrevEntry = GetOutlineEntry( nLevel, nEntry - 1 );
306 0 : SCCOLROW nPrevEnd = pPrevEntry->GetEnd();
307 0 : if ( (nPrevEnd + 1 == nStart) && IsHidden( nPrevEnd ) )
308 : {
309 0 : if ( IsFirstVisible( pPrevEntry->GetStart() ) )
310 0 : rnStartPos += SC_OL_BITMAPSIZE * nEntriesSign;
311 : else
312 0 : rnStartPos += ( SC_OL_BITMAPSIZE / 2 ) * nEntriesSign;
313 0 : rnImagePos = rnStartPos;
314 : }
315 : }
316 :
317 : // restrict rnStartPos...rnEndPos to valid area
318 0 : rnStartPos = std::max( rnStartPos, mnMainFirstPos );
319 0 : rnEndPos = std::max( rnEndPos, mnMainFirstPos );
320 :
321 0 : if ( mbMirrorEntries )
322 0 : rnImagePos -= SC_OL_BITMAPSIZE - 1; // start pos aligns with right edge of bitmap
323 :
324 : // --- all rows filtered? ---
325 :
326 0 : bool bVisible = true;
327 0 : if ( !mbHoriz )
328 : {
329 0 : bVisible = false;
330 0 : for ( SCCOLROW nRow = nStart; (nRow <= nEnd) && !bVisible; ++nRow )
331 0 : bVisible = !IsFiltered( nRow );
332 : }
333 0 : return bVisible;
334 : }
335 :
336 0 : bool ScOutlineWindow::GetImagePos( size_t nLevel, size_t nEntry, Point& rPos ) const
337 : {
338 0 : bool bRet = nLevel < GetLevelCount();
339 0 : if ( bRet )
340 : {
341 0 : long nLevelPos = GetLevelPos( nLevel );
342 0 : if ( nEntry == SC_OL_HEADERENTRY )
343 0 : rPos = GetPoint( nLevelPos, GetHeaderEntryPos() );
344 : else
345 : {
346 : long nStartPos, nEndPos, nImagePos;
347 0 : bRet = GetEntryPos( nLevel, nEntry, nStartPos, nEndPos, nImagePos );
348 0 : rPos = GetPoint( nLevelPos, nImagePos );
349 : }
350 : }
351 0 : return bRet;
352 : }
353 :
354 0 : bool ScOutlineWindow::IsButtonVisible( size_t nLevel, size_t nEntry ) const
355 : {
356 0 : bool bRet = false;
357 0 : if ( nEntry == SC_OL_HEADERENTRY )
358 0 : bRet = (mnHeaderSize > 0) && (nLevel < GetLevelCount());
359 : else
360 : {
361 0 : const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
362 0 : if ( pEntry && pEntry->IsVisible() )
363 : {
364 : SCCOLROW nStart, nEnd;
365 0 : GetVisibleRange( nStart, nEnd );
366 0 : bRet = (nStart <= pEntry->GetStart()) && (pEntry->GetStart() <= nEnd);
367 : }
368 : }
369 0 : return bRet;
370 : }
371 :
372 0 : bool ScOutlineWindow::ItemHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry, bool& rbButton ) const
373 : {
374 0 : const ScOutlineArray* pArray = GetOutlineArray();
375 0 : if ( !pArray ) return false;
376 :
377 : SCCOLROW nStartIndex, nEndIndex;
378 0 : GetVisibleRange( nStartIndex, nEndIndex );
379 :
380 0 : size_t nLevel = GetLevelFromPos( mbHoriz ? rPos.Y() : rPos.X() );
381 0 : if ( nLevel == SC_OL_NOLEVEL )
382 0 : return false;
383 :
384 0 : long nEntryMousePos = mbHoriz ? rPos.X() : rPos.Y();
385 :
386 : // --- level buttons ---
387 :
388 0 : if ( mnHeaderSize > 0 )
389 : {
390 0 : long nImagePos = GetHeaderEntryPos();
391 0 : if ( (nImagePos <= nEntryMousePos) && (nEntryMousePos < nImagePos + SC_OL_BITMAPSIZE) )
392 : {
393 0 : rnLevel = nLevel;
394 0 : rnEntry = SC_OL_HEADERENTRY;
395 0 : rbButton = true;
396 0 : return true;
397 : }
398 : }
399 :
400 : // --- expand/collapse buttons and expanded lines ---
401 :
402 : // search outline entries backwards
403 0 : size_t nEntry = pArray->GetCount( sal::static_int_cast<sal_uInt16>(nLevel) );
404 0 : while ( nEntry )
405 : {
406 0 : --nEntry;
407 :
408 0 : const ScOutlineEntry* pEntry = pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel),
409 0 : sal::static_int_cast<sal_uInt16>(nEntry) );
410 0 : SCCOLROW nStart = pEntry->GetStart();
411 0 : SCCOLROW nEnd = pEntry->GetEnd();
412 :
413 0 : if ( (nEnd >= nStartIndex) && (nStart <= nEndIndex) )
414 : {
415 : long nStartPos, nEndPos, nImagePos;
416 0 : if ( GetEntryPos( nLevel, nEntry, nStartPos, nEndPos, nImagePos ) )
417 : {
418 0 : rnLevel = nLevel;
419 0 : rnEntry = nEntry;
420 :
421 : // button?
422 0 : if ( (nStart >= nStartIndex) && (nImagePos <= nEntryMousePos) && (nEntryMousePos < nImagePos + SC_OL_BITMAPSIZE) )
423 : {
424 0 : rbButton = true;
425 0 : return true;
426 : }
427 :
428 : // line?
429 0 : if ( mbMirrorEntries )
430 0 : ::std::swap( nStartPos, nEndPos ); // in RTL mode, nStartPos is the larger value
431 0 : if ( (nStartPos <= nEntryMousePos) && (nEntryMousePos <= nEndPos) )
432 : {
433 0 : rbButton = false;
434 0 : return true;
435 : }
436 : }
437 : }
438 : }
439 :
440 0 : return false;
441 : }
442 :
443 0 : bool ScOutlineWindow::ButtonHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry ) const
444 : {
445 : bool bButton;
446 0 : bool bRet = ItemHit( rPos, rnLevel, rnEntry, bButton );
447 0 : return bRet && bButton;
448 : }
449 :
450 0 : bool ScOutlineWindow::LineHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry ) const
451 : {
452 : bool bButton;
453 0 : bool bRet = ItemHit( rPos, rnLevel, rnEntry, bButton );
454 0 : return bRet && !bButton;
455 : }
456 :
457 0 : void ScOutlineWindow::DoFunction( size_t nLevel, size_t nEntry ) const
458 : {
459 0 : ScDBFunc& rFunc = *mrViewData.GetView();
460 0 : if ( nEntry == SC_OL_HEADERENTRY )
461 0 : rFunc.SelectLevel( mbHoriz, sal::static_int_cast<sal_uInt16>(nLevel) );
462 : else
463 : {
464 0 : const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
465 0 : if ( pEntry )
466 : {
467 0 : if ( pEntry->IsHidden() )
468 0 : rFunc.ShowOutline( mbHoriz, sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) );
469 : else
470 0 : rFunc.HideOutline( mbHoriz, sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) );
471 : }
472 : }
473 0 : }
474 :
475 0 : void ScOutlineWindow::DoExpand( size_t nLevel, size_t nEntry ) const
476 : {
477 0 : const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
478 0 : if ( pEntry && pEntry->IsHidden() )
479 0 : DoFunction( nLevel, nEntry );
480 0 : }
481 :
482 0 : void ScOutlineWindow::DoCollapse( size_t nLevel, size_t nEntry ) const
483 : {
484 0 : const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
485 0 : if ( pEntry && !pEntry->IsHidden() )
486 0 : DoFunction( nLevel, nEntry );
487 0 : }
488 :
489 0 : void ScOutlineWindow::Resize()
490 : {
491 0 : Window::Resize();
492 0 : SetHeaderSize( mnHeaderSize ); // recalculates header/group positions
493 0 : if ( !IsFocusButtonVisible() )
494 : {
495 0 : HideFocus();
496 0 : ShowFocus(); // calculates valid position
497 : }
498 0 : }
499 :
500 0 : void ScOutlineWindow::DataChanged( const DataChangedEvent& rDCEvt )
501 : {
502 0 : if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
503 0 : (rDCEvt.GetFlags() & SETTINGS_STYLE) )
504 : {
505 0 : InitSettings();
506 0 : Invalidate();
507 : }
508 0 : Window::DataChanged( rDCEvt );
509 0 : }
510 :
511 : // drawing --------------------------------------------------------------------
512 :
513 0 : void ScOutlineWindow::SetEntryAreaClipRegion()
514 : {
515 : SetClipRegion( Rectangle(
516 0 : GetPoint( 0, mnMainFirstPos ),
517 0 : GetPoint( GetOutputSizeLevel() - 1, mnMainLastPos ) ) );
518 0 : }
519 :
520 0 : void ScOutlineWindow::DrawLineRel(
521 : long nLevelStart, long nEntryStart, long nLevelEnd, long nEntryEnd )
522 : {
523 0 : DrawLine( GetPoint( nLevelStart, nEntryStart ), GetPoint( nLevelEnd, nEntryEnd ) );
524 0 : }
525 :
526 0 : void ScOutlineWindow::DrawRectRel(
527 : long nLevelStart, long nEntryStart, long nLevelEnd, long nEntryEnd )
528 : {
529 0 : DrawRect( GetRectangle( nLevelStart, nEntryStart, nLevelEnd, nEntryEnd ) );
530 0 : }
531 :
532 0 : void ScOutlineWindow::DrawImageRel( long nLevelPos, long nEntryPos, sal_uInt16 nId )
533 : {
534 : OSL_ENSURE( mpSymbols, "ScOutlineWindow::DrawImageRel - no images" );
535 0 : const Image& rImage = mpSymbols->GetImage( nId );
536 0 : SetLineColor();
537 0 : SetFillColor( GetBackground().GetColor() );
538 0 : Point aPos( GetPoint( nLevelPos, nEntryPos ) );
539 0 : DrawRect( Rectangle( aPos, rImage.GetSizePixel() ) );
540 0 : DrawImage( aPos, rImage );
541 0 : }
542 :
543 0 : void ScOutlineWindow::DrawBorderRel( size_t nLevel, size_t nEntry, bool bPressed )
544 : {
545 0 : Point aPos;
546 0 : if ( GetImagePos( nLevel, nEntry, aPos ) )
547 : {
548 : OSL_ENSURE( mpSymbols, "ScOutlineWindow::DrawBorderRel - no images" );
549 0 : sal_uInt16 nId = bPressed ? SC_OL_IMAGE_PRESSED : SC_OL_IMAGE_NOTPRESSED;
550 0 : bool bClip = (nEntry != SC_OL_HEADERENTRY);
551 0 : if ( bClip )
552 0 : SetEntryAreaClipRegion();
553 0 : DrawImage( aPos, mpSymbols->GetImage( nId ) );
554 0 : if ( bClip )
555 0 : SetClipRegion();
556 : }
557 0 : mbMTPressed = bPressed;
558 0 : }
559 :
560 0 : void ScOutlineWindow::ShowFocus()
561 : {
562 0 : if ( HasFocus() )
563 : {
564 : // first move to a visible position
565 0 : ImplMoveFocusToVisible( true );
566 :
567 0 : if ( IsFocusButtonVisible() )
568 : {
569 0 : Point aPos;
570 0 : if ( GetImagePos( mnFocusLevel, mnFocusEntry, aPos ) )
571 : {
572 0 : aPos += Point( 1, 1 );
573 0 : maFocusRect = Rectangle( aPos, Size( SC_OL_BITMAPSIZE - 2, SC_OL_BITMAPSIZE - 2 ) );
574 0 : bool bClip = (mnFocusEntry != SC_OL_HEADERENTRY);
575 0 : if ( bClip )
576 0 : SetEntryAreaClipRegion();
577 0 : InvertTracking( maFocusRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW );
578 0 : if ( bClip )
579 0 : SetClipRegion();
580 : }
581 : }
582 : }
583 0 : }
584 :
585 0 : void ScOutlineWindow::HideFocus()
586 : {
587 0 : if ( !maFocusRect.IsEmpty() )
588 : {
589 0 : bool bClip = (mnFocusEntry != SC_OL_HEADERENTRY);
590 0 : if ( bClip )
591 0 : SetEntryAreaClipRegion();
592 0 : InvertTracking( maFocusRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW );
593 0 : if ( bClip )
594 0 : SetClipRegion();
595 0 : maFocusRect.SetEmpty();
596 : }
597 0 : }
598 :
599 0 : void ScOutlineWindow::Paint( const Rectangle& /* rRect */ )
600 : {
601 0 : long nEntriesSign = mbMirrorEntries ? -1 : 1;
602 0 : long nLevelsSign = mbMirrorLevels ? -1 : 1;
603 :
604 0 : Size aSize = GetOutputSizePixel();
605 0 : long nLevelEnd = (mbHoriz ? aSize.Height() : aSize.Width()) - 1;
606 0 : long nEntryEnd = (mbHoriz ? aSize.Width() : aSize.Height()) - 1;
607 :
608 0 : SetLineColor( maLineColor );
609 0 : long nBorderPos = mbMirrorLevels ? 0 : nLevelEnd;
610 0 : DrawLineRel( nBorderPos, 0, nBorderPos, nEntryEnd );
611 :
612 0 : const ScOutlineArray* pArray = GetOutlineArray();
613 0 : if ( !pArray ) return;
614 :
615 0 : size_t nLevelCount = GetLevelCount();
616 :
617 : // --- draw header images ---
618 :
619 0 : if ( mnHeaderSize > 0 )
620 : {
621 0 : long nEntryPos = GetHeaderEntryPos();
622 0 : for ( size_t nLevel = 0; nLevel < nLevelCount; ++nLevel )
623 0 : DrawImageRel( GetLevelPos( nLevel ), nEntryPos, static_cast< sal_uInt16 >( nLevel + 1 ) );
624 :
625 0 : SetLineColor( maLineColor );
626 0 : long nLinePos = mnHeaderPos + (mbMirrorEntries ? 0 : (mnHeaderSize - 1));
627 0 : DrawLineRel( 0, nLinePos, nLevelEnd, nLinePos );
628 : }
629 :
630 : // --- draw lines & collapse/expand images ---
631 :
632 0 : SetEntryAreaClipRegion();
633 :
634 : SCCOLROW nStartIndex, nEndIndex;
635 0 : GetVisibleRange( nStartIndex, nEndIndex );
636 :
637 0 : for ( size_t nLevel = 0; nLevel + 1 < nLevelCount; ++nLevel )
638 : {
639 0 : long nLevelPos = GetLevelPos( nLevel );
640 0 : long nEntryPos1 = 0, nEntryPos2 = 0, nImagePos = 0;
641 :
642 0 : size_t nEntryCount = pArray->GetCount( sal::static_int_cast<sal_uInt16>(nLevel) );
643 : size_t nEntry;
644 :
645 : // first draw all lines in the current level
646 0 : SetLineColor();
647 0 : SetFillColor( maLineColor );
648 0 : for ( nEntry = 0; nEntry < nEntryCount; ++nEntry )
649 : {
650 0 : const ScOutlineEntry* pEntry = pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel),
651 0 : sal::static_int_cast<sal_uInt16>(nEntry) );
652 0 : SCCOLROW nStart = pEntry->GetStart();
653 0 : SCCOLROW nEnd = pEntry->GetEnd();
654 :
655 : // visible range?
656 0 : bool bDraw = (nEnd >= nStartIndex) && (nStart <= nEndIndex);
657 : // find output coordinates
658 0 : if ( bDraw )
659 0 : bDraw = GetEntryPos( nLevel, nEntry, nEntryPos1, nEntryPos2, nImagePos );
660 : // draw, if not collapsed
661 0 : if ( bDraw && !pEntry->IsHidden() )
662 : {
663 0 : if ( nStart >= nStartIndex )
664 0 : nEntryPos1 += nEntriesSign;
665 0 : nEntryPos2 -= 2 * nEntriesSign;
666 0 : long nLinePos = nLevelPos;
667 0 : if ( mbMirrorLevels )
668 0 : nLinePos += SC_OL_BITMAPSIZE - 1; // align with right edge of bitmap
669 0 : DrawRectRel( nLinePos, nEntryPos1, nLinePos + nLevelsSign, nEntryPos2 );
670 :
671 0 : if ( nEnd <= nEndIndex )
672 : DrawRectRel( nLinePos, nEntryPos2 - nEntriesSign,
673 0 : nLinePos + ( SC_OL_BITMAPSIZE / 3 ) * nLevelsSign, nEntryPos2 );
674 : }
675 : }
676 :
677 : // draw all images in the level from last to first
678 0 : nEntry = nEntryCount;
679 0 : while ( nEntry )
680 : {
681 0 : --nEntry;
682 :
683 0 : const ScOutlineEntry* pEntry = pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel),
684 0 : sal::static_int_cast<sal_uInt16>(nEntry) );
685 0 : SCCOLROW nStart = pEntry->GetStart();
686 :
687 : // visible range?
688 0 : bool bDraw = (nStartIndex <= nStart) && (nStart <= nEndIndex + 1);
689 : // find output coordinates
690 0 : if ( bDraw )
691 0 : bDraw = GetEntryPos( nLevel, nEntry, nEntryPos1, nEntryPos2, nImagePos );
692 : // draw, if not hidden by higher levels
693 0 : if ( bDraw )
694 : {
695 0 : sal_uInt16 nImageId = pEntry->IsHidden() ? SC_OL_IMAGE_PLUS : SC_OL_IMAGE_MINUS;
696 0 : DrawImageRel( nLevelPos, nImagePos, nImageId );
697 : }
698 : }
699 : }
700 :
701 0 : SetClipRegion();
702 :
703 0 : if ( !mbDontDrawFocus )
704 0 : ShowFocus();
705 : }
706 :
707 : // focus ----------------------------------------------------------------------
708 :
709 : /** Increments or decrements a value and wraps at the specified limits.
710 : @return true = value wrapped. */
711 0 : static bool lcl_RotateValue( size_t& rnValue, size_t nMin, size_t nMax, bool bForward )
712 : {
713 : OSL_ENSURE( nMin <= nMax, "lcl_RotateValue - invalid range" );
714 : OSL_ENSURE( nMax < static_cast< size_t >( -1 ), "lcl_RotateValue - range overflow" );
715 0 : bool bWrap = false;
716 0 : if ( bForward )
717 : {
718 0 : if ( rnValue < nMax )
719 0 : ++rnValue;
720 : else
721 : {
722 0 : rnValue = nMin;
723 0 : bWrap = true;
724 : }
725 : }
726 : else
727 : {
728 0 : if ( rnValue > nMin )
729 0 : --rnValue;
730 : else
731 : {
732 0 : rnValue = nMax;
733 0 : bWrap = true;
734 : }
735 : }
736 0 : return bWrap;
737 : }
738 :
739 0 : bool ScOutlineWindow::IsFocusButtonVisible() const
740 : {
741 0 : return IsButtonVisible( mnFocusLevel, mnFocusEntry );
742 : }
743 :
744 0 : bool ScOutlineWindow::ImplMoveFocusByEntry( bool bForward, bool bFindVisible )
745 : {
746 0 : const ScOutlineArray* pArray = GetOutlineArray();
747 0 : if ( !pArray )
748 0 : return false;
749 :
750 0 : bool bWrapped = false;
751 0 : size_t nEntryCount = pArray->GetCount( sal::static_int_cast<sal_uInt16>(mnFocusLevel) );
752 : // #i29530# entry count may be decreased after changing active sheet
753 0 : if( mnFocusEntry >= nEntryCount )
754 0 : mnFocusEntry = SC_OL_HEADERENTRY;
755 0 : size_t nOldEntry = mnFocusEntry;
756 :
757 0 : do
758 : {
759 0 : if ( mnFocusEntry == SC_OL_HEADERENTRY )
760 : {
761 : // move from header to first or last entry
762 0 : if ( nEntryCount > 0 )
763 0 : mnFocusEntry = bForward ? 0 : (nEntryCount - 1);
764 : /* wrapped, if forward from right header to first entry,
765 : or if backward from left header to last entry */
766 : // Header and entries are now always in consistent order,
767 : // so there's no need to check for mirroring here.
768 0 : if ( !nEntryCount || !bForward )
769 0 : bWrapped = true;
770 : }
771 0 : else if ( lcl_RotateValue( mnFocusEntry, 0, nEntryCount - 1, bForward ) )
772 : {
773 : // lcl_RotateValue returns true -> wrapped the entry range -> move to header
774 0 : mnFocusEntry = SC_OL_HEADERENTRY;
775 : /* wrapped, if forward from last entry to left header,
776 : or if backward from first entry to right header */
777 0 : if ( bForward )
778 0 : bWrapped = true;
779 : }
780 : }
781 0 : while ( bFindVisible && !IsFocusButtonVisible() && (nOldEntry != mnFocusEntry) );
782 :
783 0 : return bWrapped;
784 : }
785 :
786 0 : bool ScOutlineWindow::ImplMoveFocusByLevel( bool bForward )
787 : {
788 0 : const ScOutlineArray* pArray = GetOutlineArray();
789 0 : if ( !pArray )
790 0 : return false;
791 :
792 0 : bool bWrapped = false;
793 0 : size_t nLevelCount = GetLevelCount();
794 :
795 0 : if ( mnFocusEntry == SC_OL_HEADERENTRY )
796 : {
797 0 : if ( nLevelCount > 0 )
798 0 : bWrapped = lcl_RotateValue( mnFocusLevel, 0, nLevelCount - 1, bForward );
799 : }
800 : else
801 : {
802 : const ScOutlineEntry* pEntry = pArray->GetEntry(
803 0 : mnFocusLevel, mnFocusEntry);
804 :
805 0 : if ( pEntry )
806 : {
807 0 : SCCOLROW nStart = pEntry->GetStart();
808 0 : SCCOLROW nEnd = pEntry->GetEnd();
809 0 : size_t nNewLevel = mnFocusLevel;
810 0 : size_t nNewEntry = 0;
811 :
812 0 : bool bFound = false;
813 0 : if ( bForward && (mnFocusLevel + 2 < nLevelCount) )
814 : {
815 : // next level -> find first child entry
816 0 : nNewLevel = mnFocusLevel + 1;
817 0 : bFound = pArray->GetEntryIndexInRange(nNewLevel, nStart, nEnd, nNewEntry);
818 : }
819 0 : else if ( !bForward && (mnFocusLevel > 0) )
820 : {
821 : // previous level -> find parent entry
822 0 : nNewLevel = mnFocusLevel - 1;
823 0 : bFound = pArray->GetEntryIndex(nNewLevel, nStart, nNewEntry);
824 : }
825 :
826 0 : if ( bFound && IsButtonVisible( nNewLevel, nNewEntry ) )
827 : {
828 0 : mnFocusLevel = nNewLevel;
829 0 : mnFocusEntry = nNewEntry;
830 : }
831 : }
832 : }
833 :
834 0 : return bWrapped;
835 : }
836 :
837 0 : bool ScOutlineWindow::ImplMoveFocusByTabOrder( bool bForward, bool bFindVisible )
838 : {
839 0 : bool bRet = false;
840 0 : size_t nOldLevel = mnFocusLevel;
841 0 : size_t nOldEntry = mnFocusEntry;
842 :
843 0 : do
844 : {
845 : /* one level up, if backward from left header,
846 : or one level down, if forward from right header */
847 0 : if ( (!bForward) && (mnFocusEntry == SC_OL_HEADERENTRY) )
848 0 : bRet |= ImplMoveFocusByLevel( bForward );
849 : // move to next/previous entry
850 0 : bool bWrapInLevel = ImplMoveFocusByEntry( bForward, false );
851 0 : bRet |= bWrapInLevel;
852 : /* one level up, if wrapped backward to right header,
853 : or one level down, if wrapped forward to right header */
854 0 : if ( bForward && bWrapInLevel )
855 0 : bRet |= ImplMoveFocusByLevel( bForward );
856 : }
857 0 : while ( bFindVisible && !IsFocusButtonVisible() && ((nOldLevel != mnFocusLevel) || (nOldEntry != mnFocusEntry)) );
858 :
859 0 : return bRet;
860 : }
861 :
862 0 : void ScOutlineWindow::ImplMoveFocusToVisible( bool bForward )
863 : {
864 : // first try to find an entry in the same level
865 0 : if ( !IsFocusButtonVisible() )
866 0 : ImplMoveFocusByEntry( bForward, true );
867 : // then try to find any other entry
868 0 : if ( !IsFocusButtonVisible() )
869 0 : ImplMoveFocusByTabOrder( bForward, true );
870 0 : }
871 :
872 0 : void ScOutlineWindow::MoveFocusByEntry( bool bForward )
873 : {
874 0 : HideFocus();
875 0 : ImplMoveFocusByEntry( bForward, true );
876 0 : ShowFocus();
877 0 : }
878 :
879 0 : void ScOutlineWindow::MoveFocusByLevel( bool bForward )
880 : {
881 0 : HideFocus();
882 0 : ImplMoveFocusByLevel( bForward );
883 0 : ShowFocus();
884 0 : }
885 :
886 0 : void ScOutlineWindow::MoveFocusByTabOrder( bool bForward )
887 : {
888 0 : HideFocus();
889 0 : ImplMoveFocusByTabOrder( bForward, true );
890 0 : ShowFocus();
891 0 : }
892 :
893 0 : void ScOutlineWindow::GetFocus()
894 : {
895 0 : Window::GetFocus();
896 0 : ShowFocus();
897 0 : }
898 :
899 0 : void ScOutlineWindow::LoseFocus()
900 : {
901 0 : HideFocus();
902 0 : Window::LoseFocus();
903 0 : }
904 :
905 :
906 : // mouse ----------------------------------------------------------------------
907 :
908 0 : void ScOutlineWindow::StartMouseTracking( size_t nLevel, size_t nEntry )
909 : {
910 0 : mbMTActive = true;
911 0 : mnMTLevel = nLevel;
912 0 : mnMTEntry = nEntry;
913 0 : DrawBorderRel( nLevel, nEntry, true );
914 0 : }
915 :
916 0 : void ScOutlineWindow::EndMouseTracking()
917 : {
918 0 : if ( mbMTPressed )
919 0 : DrawBorderRel( mnMTLevel, mnMTEntry, false );
920 0 : mbMTActive = false;
921 0 : }
922 :
923 0 : void ScOutlineWindow::MouseMove( const MouseEvent& rMEvt )
924 : {
925 0 : if ( IsMouseTracking() )
926 : {
927 : size_t nLevel, nEntry;
928 0 : bool bHit = false;
929 :
930 0 : if ( ButtonHit( rMEvt.GetPosPixel(), nLevel, nEntry ) )
931 0 : bHit = (nLevel == mnMTLevel) && (nEntry == mnMTEntry);
932 :
933 0 : if ( bHit != mbMTPressed )
934 0 : DrawBorderRel( mnMTLevel, mnMTEntry, bHit );
935 : }
936 0 : }
937 :
938 0 : void ScOutlineWindow::MouseButtonUp( const MouseEvent& rMEvt )
939 : {
940 0 : if ( IsMouseTracking() )
941 : {
942 0 : EndMouseTracking();
943 :
944 : size_t nLevel, nEntry;
945 0 : if ( ButtonHit( rMEvt.GetPosPixel(), nLevel, nEntry ) )
946 0 : if ( (nLevel == mnMTLevel) && (nEntry == mnMTEntry) )
947 0 : DoFunction( nLevel, nEntry );
948 : }
949 0 : }
950 :
951 0 : void ScOutlineWindow::MouseButtonDown( const MouseEvent& rMEvt )
952 : {
953 : size_t nLevel, nEntry;
954 0 : bool bHit = ButtonHit( rMEvt.GetPosPixel(), nLevel, nEntry );
955 0 : if ( bHit )
956 0 : StartMouseTracking( nLevel, nEntry );
957 0 : else if ( rMEvt.GetClicks() == 2 )
958 : {
959 0 : bHit = LineHit( rMEvt.GetPosPixel(), nLevel, nEntry );
960 0 : if ( bHit )
961 0 : DoFunction( nLevel, nEntry );
962 : }
963 :
964 : // if an item has been hit and window is focused, move focus to this item
965 0 : if ( bHit && HasFocus() )
966 : {
967 0 : HideFocus();
968 0 : mnFocusLevel = nLevel;
969 0 : mnFocusEntry = nEntry;
970 0 : ShowFocus();
971 : }
972 0 : }
973 :
974 :
975 : // keyboard -------------------------------------------------------------------
976 :
977 0 : void ScOutlineWindow::KeyInput( const KeyEvent& rKEvt )
978 : {
979 0 : const KeyCode& rKCode = rKEvt.GetKeyCode();
980 0 : bool bNoMod = !rKCode.GetModifier();
981 0 : bool bShift = (rKCode.GetModifier() == KEY_SHIFT);
982 0 : bool bCtrl = (rKCode.GetModifier() == KEY_MOD1);
983 :
984 0 : sal_uInt16 nCode = rKCode.GetCode();
985 0 : bool bUpDownKey = (nCode == KEY_UP) || (nCode == KEY_DOWN);
986 0 : bool bLeftRightKey = (nCode == KEY_LEFT) || (nCode == KEY_RIGHT);
987 :
988 : // TAB key
989 0 : if ( (nCode == KEY_TAB) && (bNoMod || bShift) )
990 : // move forward without SHIFT key
991 0 : MoveFocusByTabOrder( bNoMod ); // TAB uses logical order, regardless of mirroring
992 :
993 : // LEFT/RIGHT/UP/DOWN keys
994 0 : else if ( bNoMod && (bUpDownKey || bLeftRightKey) )
995 : {
996 0 : bool bForward = (nCode == KEY_DOWN) || (nCode == KEY_RIGHT);
997 0 : if ( mbHoriz == bLeftRightKey )
998 : // move inside level with LEFT/RIGHT in horizontal and with UP/DOWN in vertical
999 0 : MoveFocusByEntry( bForward != mbMirrorEntries );
1000 : else
1001 : // move to next/prev level with LEFT/RIGHT in vertical and with UP/DOWN in horizontal
1002 0 : MoveFocusByLevel( bForward != mbMirrorLevels );
1003 : }
1004 :
1005 : // CTRL + number
1006 0 : else if ( bCtrl && (nCode >= KEY_1) && (nCode <= KEY_9) )
1007 : {
1008 0 : size_t nLevel = static_cast< size_t >( nCode - KEY_1 );
1009 0 : if ( nLevel < GetLevelCount() )
1010 0 : DoFunction( nLevel, SC_OL_HEADERENTRY );
1011 : }
1012 :
1013 : // other key codes
1014 0 : else switch ( rKCode.GetFullCode() )
1015 : {
1016 0 : case KEY_ADD: DoExpand( mnFocusLevel, mnFocusEntry ); break;
1017 0 : case KEY_SUBTRACT: DoCollapse( mnFocusLevel, mnFocusEntry ); break;
1018 : case KEY_SPACE:
1019 0 : case KEY_RETURN: DoFunction( mnFocusLevel, mnFocusEntry ); break;
1020 0 : default: Window::KeyInput( rKEvt );
1021 : }
1022 15 : }
1023 :
1024 :
1025 : // ============================================================================
1026 :
1027 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|