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