Bug Summary

File:home/maarten/src/libreoffice/core/sc/source/ui/view/olinewin.cxx
Warning:line 347, column 20
2nd function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

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