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