Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/control/roadmapwizard.cxx
Line
Count
Source
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
21
#include <tools/debug.hxx>
22
#include <tools/json_writer.hxx>
23
#include <tools/mapunit.hxx>
24
#include <osl/diagnose.h>
25
#include <vcl/event.hxx>
26
27
#include <strings.hrc>
28
#include <svdata.hxx>
29
#include <wizdlg.hxx>
30
31
#include <vector>
32
33
#include "wizimpldata.hxx"
34
#include <uiobject-internal.hxx>
35
36
0
#define WIZARDDIALOG_BUTTON_OFFSET_Y        6
37
0
#define WIZARDDIALOG_BUTTON_DLGOFFSET_X     6
38
0
#define WIZARDDIALOG_BUTTON_STDOFFSET_X     6
39
0
#define WIZARDDIALOG_BUTTON_SMALLSTDOFFSET_X 3
40
0
#define WIZARDDIALOG_VIEW_DLGOFFSET_X       6
41
0
#define WIZARDDIALOG_VIEW_DLGOFFSET_Y       6
42
43
namespace vcl
44
{
45
    sal_Int32 RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState, const WizardPath& _rPath )
46
0
    {
47
0
        sal_Int32 nStateIndexInPath = 0;
48
0
        for (auto const& path : _rPath)
49
0
        {
50
0
            if (path == _nState)
51
0
                return nStateIndexInPath;
52
0
            ++nStateIndexInPath;
53
0
        }
54
0
        return -1;
55
0
    }
56
57
    sal_Int32 RoadmapWizardImpl::getStateIndexInPath( WizardTypes::WizardState _nState, PathId _nPathId )
58
0
    {
59
0
        sal_Int32 nStateIndexInPath = -1;
60
0
        Paths::const_iterator aPathPos = aPaths.find( _nPathId );
61
0
        if ( aPathPos != aPaths.end( ) )
62
0
            nStateIndexInPath = getStateIndexInPath( _nState, aPathPos->second );
63
0
        return nStateIndexInPath;
64
0
    }
65
66
    sal_Int32 RoadmapWizardImpl::getFirstDifferentIndex( const WizardPath& _rLHS, const WizardPath& _rRHS )
67
0
    {
68
0
        sal_Int32 nMinLength = ::std::min( _rLHS.size(), _rRHS.size() );
69
0
        for ( sal_Int32 nCheck = 0; nCheck < nMinLength; ++nCheck )
70
0
        {
71
0
            if ( _rLHS[ nCheck ] != _rRHS[ nCheck ] )
72
0
                return nCheck;
73
0
        }
74
0
        return nMinLength;
75
0
    }
76
77
    //= RoadmapWizard
78
    RoadmapWizard::RoadmapWizard(vcl::Window* pParent, WinBits nStyle, InitFlag eFlag)
79
0
        : Dialog(pParent, nStyle, eFlag)
80
0
        , maWizardLayoutIdle("vcl RoadmapWizard maWizardLayoutIdle")
81
0
        , m_pFinish(nullptr)
82
0
        , m_pCancel(nullptr)
83
0
        , m_pNextPage(nullptr)
84
0
        , m_pPrevPage(nullptr)
85
0
        , m_pHelp(nullptr)
86
0
        , m_xWizardImpl(new WizardMachineImplData)
87
0
        , m_xRoadmapImpl(new RoadmapWizardImpl)
88
0
    {
89
0
        mpFirstPage     = nullptr;
90
0
        mpFirstBtn      = nullptr;
91
0
        mpCurTabPage    = nullptr;
92
0
        mpPrevBtn       = nullptr;
93
0
        mpNextBtn       = nullptr;
94
0
        mnCurLevel      = 0;
95
0
        mbEmptyViewMargin =  false;
96
0
        mnLeftAlignCount = 0;
97
98
0
        maWizardLayoutIdle.SetPriority(TaskPriority::RESIZE);
99
0
        maWizardLayoutIdle.SetInvokeHandler( LINK( this, RoadmapWizard, ImplHandleWizardLayoutTimerHdl ) );
100
101
0
        implConstruct();
102
103
0
        SetLeftAlignedButtonCount( 1 );
104
0
        mbEmptyViewMargin = true;
105
106
0
        mpRoadmap = VclPtr<ORoadmap>::Create(this, WB_TABSTOP);
107
0
        mpRoadmap->SetText( VclResId( STR_WIZDLG_ROADMAP_TITLE ) );
108
0
        mpRoadmap->SetPosPixel( Point( 0, 0 ) );
109
0
        mpRoadmap->SetItemSelectHdl( LINK( this, RoadmapWizard, OnRoadmapItemSelected ) );
110
111
0
        Size aRoadmapSize = LogicToPixel(Size(85, 0), MapMode(MapUnit::MapAppFont));
112
0
        aRoadmapSize.setHeight( GetSizePixel().Height() );
113
0
        mpRoadmap->SetSizePixel( aRoadmapSize );
114
115
0
        mpRoadmap->Show();
116
0
    }
Unexecuted instantiation: vcl::RoadmapWizard::RoadmapWizard(vcl::Window*, long, Dialog::InitFlag)
Unexecuted instantiation: vcl::RoadmapWizard::RoadmapWizard(vcl::Window*, long, Dialog::InitFlag)
117
118
    void RoadmapWizard::ShowRoadmap(bool bShow)
119
0
    {
120
0
        mpRoadmap->Show(bShow);
121
0
        CalcAndSetSize();
122
0
    }
123
124
    RoadmapWizard::~RoadmapWizard()
125
0
    {
126
0
        disposeOnce();
127
0
    }
128
129
    void RoadmapWizard::dispose()
130
0
    {
131
0
        m_xRoadmapImpl.reset();
132
133
0
        m_pFinish.disposeAndClear();
134
0
        m_pCancel.disposeAndClear();
135
0
        m_pNextPage.disposeAndClear();
136
0
        m_pPrevPage.disposeAndClear();
137
0
        m_pHelp.disposeAndClear();
138
139
0
        if (m_xWizardImpl)
140
0
        {
141
0
            for (WizardTypes::WizardState i = 0; i < m_xWizardImpl->nFirstUnknownPage; ++i)
142
0
            {
143
0
                TabPage *pPage = GetPage(i);
144
0
                if (pPage)
145
0
                    pPage->disposeOnce();
146
0
            }
147
0
            m_xWizardImpl.reset();
148
0
        }
149
150
0
        maWizardLayoutIdle.Stop();
151
152
        // Remove all buttons
153
0
        while ( mpFirstBtn )
154
0
            RemoveButton( mpFirstBtn->mpButton );
155
156
        // Remove all pages
157
0
        while ( mpFirstPage )
158
0
            RemovePage( mpFirstPage->mpPage );
159
160
0
        mpCurTabPage.reset();
161
0
        mpPrevBtn.reset();
162
0
        mpNextBtn.reset();
163
0
        mpRoadmap.disposeAndClear();
164
0
        Dialog::dispose();
165
0
    }
166
167
    void RoadmapWizard::SetRoadmapHelpId( const OUString& _rId )
168
0
    {
169
0
        mpRoadmap->SetHelpId( _rId );
170
0
    }
171
172
    void RoadmapWizard::SetRoadmapBitmap(const Bitmap& rBmp)
173
0
    {
174
0
        mpRoadmap->SetRoadmapBitmap(rBmp);
175
0
    }
176
177
    void RoadmapWizard::SetLeftAlignedButtonCount( sal_Int16 _nCount )
178
0
    {
179
0
        mnLeftAlignCount = _nCount;
180
0
    }
181
182
    void RoadmapWizard::ImplCalcSize( Size& rSize )
183
0
    {
184
        // calculate ButtonBar height and width
185
0
        tools::Long                nMaxHeight = 0;
186
0
        tools::Long                nBarWidth = WIZARDDIALOG_BUTTON_DLGOFFSET_X * 2 + LogicalCoordinateToPixel(6);
187
0
        ImplWizButtonData*  pBtnData = mpFirstBtn;
188
0
        while (pBtnData)
189
0
        {
190
0
            auto nBtnHeight = pBtnData->mpButton->GetSizePixel().Height();
191
0
            auto nBtnWidth = pBtnData->mpButton->GetSizePixel().Width();
192
0
            if (pBtnData->mpButton->IsVisible())
193
0
            {
194
0
                nBarWidth += nBtnWidth;
195
0
                nBarWidth += pBtnData->mnOffset;
196
0
            }
197
0
            if ( nBtnHeight > nMaxHeight )
198
0
                nMaxHeight = nBtnHeight;
199
0
            pBtnData = pBtnData->mpNext;
200
0
        }
201
0
        if ( nMaxHeight )
202
0
            nMaxHeight += WIZARDDIALOG_BUTTON_OFFSET_Y*2;
203
0
        rSize.AdjustHeight(nMaxHeight);
204
205
        // add in the view window size
206
0
        if ( mpRoadmap && mpRoadmap->IsVisible() )
207
0
        {
208
0
            Size aViewSize = mpRoadmap->GetSizePixel();
209
            // align left
210
0
            rSize.AdjustWidth(aViewSize.Width() );
211
0
        }
212
213
0
        if (nBarWidth > rSize.Width())
214
0
            rSize.setWidth(nBarWidth);
215
0
    }
216
217
    void RoadmapWizard::queue_resize(StateChangedType /*eReason*/)
218
0
    {
219
0
        if (maWizardLayoutIdle.IsActive())
220
0
            return;
221
0
        if (IsInClose())
222
0
            return;
223
0
        maWizardLayoutIdle.Start();
224
0
    }
225
226
    IMPL_LINK_NOARG(RoadmapWizard, ImplHandleWizardLayoutTimerHdl, Timer*, void)
227
0
    {
228
0
        ImplPosCtrls();
229
0
        ImplPosTabPage();
230
0
    }
231
232
    void RoadmapWizard::ImplPosCtrls()
233
0
    {
234
0
        Size    aDlgSize = GetOutputSizePixel();
235
0
        tools::Long    nBtnWidth = 0;
236
0
        tools::Long    nMaxHeight = 0;
237
0
        tools::Long    nOffY = aDlgSize.Height();
238
239
0
        ImplWizButtonData* pBtnData = mpFirstBtn;
240
0
        int j = 0;
241
0
        while ( pBtnData )
242
0
        {
243
0
            if (j >= mnLeftAlignCount)
244
0
            {
245
0
                Size aBtnSize = pBtnData->mpButton->GetSizePixel();
246
0
                tools::Long nBtnHeight = aBtnSize.Height();
247
0
                if ( nBtnHeight > nMaxHeight )
248
0
                    nMaxHeight = nBtnHeight;
249
0
                nBtnWidth += aBtnSize.Width();
250
0
                nBtnWidth += pBtnData->mnOffset;
251
0
            }
252
0
            pBtnData = pBtnData->mpNext;
253
0
            j++;
254
0
        }
255
256
0
        if ( nMaxHeight )
257
0
        {
258
0
            tools::Long nOffX = aDlgSize.Width()-nBtnWidth-WIZARDDIALOG_BUTTON_DLGOFFSET_X;
259
0
            tools::Long nOffLeftAlignX = LogicalCoordinateToPixel(6);
260
0
            nOffY -= WIZARDDIALOG_BUTTON_OFFSET_Y+nMaxHeight;
261
262
0
            pBtnData = mpFirstBtn;
263
0
            int i = 0;
264
0
            while ( pBtnData )
265
0
            {
266
0
                Size aBtnSize = pBtnData->mpButton->GetSizePixel();
267
0
                if (i >= mnLeftAlignCount)
268
0
                {
269
0
                    Point aPos( nOffX, nOffY+((nMaxHeight-aBtnSize.Height())/2) );
270
0
                    pBtnData->mpButton->SetPosPixel( aPos );
271
0
                    nOffX += aBtnSize.Width();
272
0
                    nOffX += pBtnData->mnOffset;
273
0
                }
274
0
                else
275
0
                {
276
0
                    Point aPos( nOffLeftAlignX, nOffY+((nMaxHeight-aBtnSize.Height())/2) );
277
0
                    pBtnData->mpButton->SetPosPixel( aPos );
278
0
                    nOffLeftAlignX += aBtnSize.Width();
279
0
                    nOffLeftAlignX += pBtnData->mnOffset;
280
0
                }
281
282
0
                pBtnData = pBtnData->mpNext;
283
0
                i++;
284
0
            }
285
286
0
            nOffY -= WIZARDDIALOG_BUTTON_OFFSET_Y;
287
0
        }
288
289
0
        if ( !(mpRoadmap && mpRoadmap->IsVisible()) )
290
0
            return;
291
292
0
        tools::Long    nViewOffX = 0;
293
0
        tools::Long    nViewOffY = 0;
294
0
        tools::Long    nViewWidth = 0;
295
0
        tools::Long    nViewHeight = 0;
296
0
        tools::Long    nDlgHeight = nOffY;
297
0
        PosSizeFlags nViewPosFlags = PosSizeFlags::Pos;
298
        // align left
299
0
        {
300
0
            if ( mbEmptyViewMargin )
301
0
            {
302
0
                nViewOffX       = 0;
303
0
                nViewOffY       = 0;
304
0
                nViewHeight     = nDlgHeight;
305
0
            }
306
0
            else
307
0
            {
308
0
                nViewOffX       = WIZARDDIALOG_VIEW_DLGOFFSET_X;
309
0
                nViewOffY       = WIZARDDIALOG_VIEW_DLGOFFSET_Y;
310
0
                nViewHeight     = nDlgHeight-(WIZARDDIALOG_VIEW_DLGOFFSET_Y*2);
311
0
            }
312
0
            nViewPosFlags  |= PosSizeFlags::Height;
313
0
        }
314
0
        mpRoadmap->setPosSizePixel( nViewOffX, nViewOffY,
315
0
                                      nViewWidth, nViewHeight,
316
0
                                      nViewPosFlags );
317
0
    }
318
319
    tools::Long RoadmapWizard::LogicalCoordinateToPixel(int iCoordinate) const
320
0
    {
321
0
        Size aLocSize = LogicToPixel(Size(iCoordinate, 0), MapMode(MapUnit::MapAppFont));
322
0
        int iPixelCoordinate =  aLocSize.Width();
323
0
        return iPixelCoordinate;
324
0
    }
325
326
    void RoadmapWizard::ImplPosTabPage()
327
0
    {
328
0
        if ( !mpCurTabPage )
329
0
            return;
330
331
0
        if ( !IsInInitShow() )
332
0
        {
333
            // #100199# - On Unix initial size is equal to screen size, on Windows
334
            // it's 0,0. One cannot calculate the size unless dialog is visible.
335
0
            if ( !IsReallyVisible() )
336
0
                return;
337
0
        }
338
339
        // calculate height of ButtonBar
340
0
        tools::Long                nMaxHeight = 0;
341
0
        ImplWizButtonData*  pBtnData = mpFirstBtn;
342
0
        while ( pBtnData )
343
0
        {
344
0
            tools::Long nBtnHeight = pBtnData->mpButton->GetSizePixel().Height();
345
0
            if ( nBtnHeight > nMaxHeight )
346
0
                nMaxHeight = nBtnHeight;
347
0
            pBtnData = pBtnData->mpNext;
348
0
        }
349
0
        if ( nMaxHeight )
350
0
            nMaxHeight += WIZARDDIALOG_BUTTON_OFFSET_Y*2;
351
352
        // position TabPage
353
0
        Size aDlgSize = GetOutputSizePixel();
354
0
        aDlgSize.AdjustHeight( -nMaxHeight );
355
0
        tools::Long nOffX = 0;
356
0
        tools::Long nOffY = 0;
357
0
        if ( mpRoadmap && mpRoadmap->IsVisible() )
358
0
        {
359
0
            Size aViewSize = mpRoadmap->GetSizePixel();
360
            // align left
361
0
            tools::Long nViewOffset = mbEmptyViewMargin ? 0 : WIZARDDIALOG_VIEW_DLGOFFSET_X;
362
0
            nOffX += aViewSize.Width() + nViewOffset;
363
0
            aDlgSize.AdjustWidth( -nOffX );
364
0
        }
365
0
        Point aPos( nOffX, nOffY );
366
0
        mpCurTabPage->SetPosSizePixel( aPos, aDlgSize );
367
0
    }
368
369
    void RoadmapWizard::ImplShowTabPage( TabPage* pTabPage )
370
0
    {
371
0
        if ( mpCurTabPage == pTabPage )
372
0
            return;
373
374
0
        TabPage* pOldTabPage = mpCurTabPage;
375
376
0
        mpCurTabPage = pTabPage;
377
0
        if ( pTabPage )
378
0
        {
379
0
            ImplPosTabPage();
380
0
            pTabPage->Show();
381
0
        }
382
383
0
        if ( pOldTabPage )
384
0
            pOldTabPage->Hide();
385
0
    }
386
387
    TabPage* RoadmapWizard::ImplGetPage( sal_uInt16 nLevel ) const
388
0
    {
389
0
        sal_uInt16              nTempLevel = 0;
390
0
        ImplWizPageData*    pPageData = mpFirstPage;
391
0
        while ( pPageData )
392
0
        {
393
0
            if ( (nTempLevel == nLevel) || !pPageData->mpNext )
394
0
                break;
395
396
0
            nTempLevel++;
397
0
            pPageData = pPageData->mpNext;
398
0
        }
399
400
0
        if ( pPageData )
401
0
            return pPageData->mpPage;
402
0
        return nullptr;
403
0
    }
404
405
    void RoadmapWizard::implConstruct()
406
0
    {
407
0
        m_xWizardImpl->sTitleBase = GetText();
408
409
        // create buttons
410
        // the help button
411
0
        m_pHelp= VclPtr<HelpButton>::Create(this, WB_TABSTOP);
412
0
        m_pHelp->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont)));
413
0
        m_pHelp->Show();
414
0
        m_pHelp->set_id(u"help"_ustr);
415
0
        AddButton( m_pHelp, WIZARDDIALOG_BUTTON_STDOFFSET_X);
416
417
        // the previous button
418
0
        m_pPrevPage = VclPtr<PushButton>::Create(this, WB_TABSTOP);
419
0
        m_pPrevPage->SetHelpId( HID_WIZARD_PREVIOUS );
420
0
        m_pPrevPage->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont)));
421
0
        m_pPrevPage->SetText(VclResId(STR_WIZDLG_PREVIOUS));
422
0
        m_pPrevPage->Show();
423
0
        m_pPrevPage->set_id(u"previous"_ustr);
424
0
        AddButton( m_pPrevPage, ( WIZARDDIALOG_BUTTON_SMALLSTDOFFSET_X) );      // half x-offset to the next button
425
0
        mpPrevBtn = m_pPrevPage;
426
0
        m_pPrevPage->SetClickHdl( LINK( this, RoadmapWizard, OnPrevPage ) );
427
428
        // the next button
429
0
        m_pNextPage = VclPtr<PushButton>::Create(this, WB_TABSTOP);
430
0
        m_pNextPage->SetHelpId( HID_WIZARD_NEXT );
431
0
        m_pNextPage->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont)));
432
0
        m_pNextPage->SetText(VclResId(STR_WIZDLG_NEXT));
433
0
        m_pNextPage->Show();
434
0
        m_pNextPage->set_id(u"next"_ustr);
435
0
        AddButton( m_pNextPage, WIZARDDIALOG_BUTTON_STDOFFSET_X );
436
0
        mpNextBtn = m_pNextPage;
437
0
        m_pNextPage->SetClickHdl( LINK( this, RoadmapWizard, OnNextPage ) );
438
439
        // the finish button
440
0
        m_pFinish = VclPtr<OKButton>::Create(this, WB_TABSTOP);
441
0
        m_pFinish->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont)));
442
0
        m_pFinish->SetText(VclResId(STR_WIZDLG_FINISH));
443
0
        m_pFinish->Show();
444
0
        m_pFinish->set_id(u"finish"_ustr);
445
0
        AddButton( m_pFinish, WIZARDDIALOG_BUTTON_STDOFFSET_X );
446
0
        m_pFinish->SetClickHdl( LINK( this, RoadmapWizard, OnFinish ) );
447
448
        // the cancel button
449
0
        m_pCancel = VclPtr<CancelButton>::Create(this, WB_TABSTOP);
450
0
        m_pCancel->SetSizePixel(LogicToPixel(Size(50, 14), MapMode(MapUnit::MapAppFont)));
451
0
        m_pCancel->Show();
452
0
        AddButton( m_pCancel, WIZARDDIALOG_BUTTON_STDOFFSET_X );
453
0
    }
454
455
    void RoadmapWizard::Resize()
456
0
    {
457
0
        if ( IsReallyShown() && !IsInInitShow() )
458
0
        {
459
0
            ImplPosCtrls();
460
0
            ImplPosTabPage();
461
0
        }
462
463
0
        Dialog::Resize();
464
0
    }
465
466
    void RoadmapWizard::CalcAndSetSize()
467
0
    {
468
0
        Size aDlgSize = GetPageSizePixel();
469
0
        if ( !aDlgSize.Width() || !aDlgSize.Height() )
470
0
        {
471
0
            ImplWizPageData*  pPageData = mpFirstPage;
472
0
            while ( pPageData )
473
0
            {
474
0
                if ( pPageData->mpPage )
475
0
                {
476
0
                    Size aPageSize = pPageData->mpPage->GetSizePixel();
477
0
                    if ( aPageSize.Width() > aDlgSize.Width() )
478
0
                        aDlgSize.setWidth( aPageSize.Width() );
479
0
                    if ( aPageSize.Height() > aDlgSize.Height() )
480
0
                        aDlgSize.setHeight( aPageSize.Height() );
481
0
                }
482
483
0
                pPageData = pPageData->mpNext;
484
0
            }
485
0
        }
486
0
        ImplCalcSize( aDlgSize );
487
0
        SetMinOutputSizePixel( aDlgSize );
488
0
        SetOutputSizePixel( aDlgSize );
489
0
    }
490
491
    void RoadmapWizard::StateChanged( StateChangedType nType )
492
0
    {
493
0
        if ( nType == StateChangedType::InitShow )
494
0
        {
495
0
            if ( IsDefaultSize() )
496
0
            {
497
0
                CalcAndSetSize();
498
0
            }
499
500
0
            ImplPosCtrls();
501
0
            ImplPosTabPage();
502
0
            ImplShowTabPage( ImplGetPage( mnCurLevel ) );
503
0
        }
504
505
0
        Dialog::StateChanged( nType );
506
0
    }
507
508
    bool RoadmapWizard::EventNotify( NotifyEvent& rNEvt )
509
0
    {
510
0
        if ( (rNEvt.GetType() == NotifyEventType::KEYINPUT) && mpPrevBtn && mpNextBtn )
511
0
        {
512
0
            const KeyEvent* pKEvt = rNEvt.GetKeyEvent();
513
0
            vcl::KeyCode aKeyCode = pKEvt->GetKeyCode();
514
0
            sal_uInt16 nKeyCode = aKeyCode.GetCode();
515
516
0
            if ( aKeyCode.IsMod1() )
517
0
            {
518
0
                if ( aKeyCode.IsShift() || (nKeyCode == KEY_PAGEUP) )
519
0
                {
520
0
                    if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEUP) )
521
0
                    {
522
0
                        if ( mpPrevBtn->IsVisible() &&
523
0
                            mpPrevBtn->IsEnabled() && mpPrevBtn->IsInputEnabled() )
524
0
                        {
525
0
                            mpPrevBtn->SetPressed( true );
526
0
                            mpPrevBtn->SetPressed( false );
527
0
                            mpPrevBtn->Click();
528
0
                        }
529
0
                        return true;
530
0
                    }
531
0
                }
532
0
                else
533
0
                {
534
0
                    if ( (nKeyCode == KEY_TAB) || (nKeyCode == KEY_PAGEDOWN) )
535
0
                    {
536
0
                        if ( mpNextBtn->IsVisible() &&
537
0
                            mpNextBtn->IsEnabled() && mpNextBtn->IsInputEnabled() )
538
0
                        {
539
0
                            mpNextBtn->SetPressed( true );
540
0
                            mpNextBtn->SetPressed( false );
541
0
                            mpNextBtn->Click();
542
0
                        }
543
0
                        return true;
544
0
                    }
545
0
                }
546
0
            }
547
0
        }
548
549
0
        return Dialog::EventNotify( rNEvt );
550
0
    }
551
552
    void RoadmapWizard::ShowPage(sal_uInt16 nLevel)
553
0
    {
554
0
        mnCurLevel = nLevel;
555
556
        // synchronize the roadmap
557
0
        implUpdateRoadmap();
558
0
        mpRoadmap->SelectRoadmapItemByID(getCurrentState());
559
560
0
        ImplShowTabPage( ImplGetPage( mnCurLevel ) );
561
0
    }
562
563
    void RoadmapWizard::Finish( tools::Long nResult )
564
0
    {
565
0
        if ( IsInExecute() )
566
0
            EndDialog( nResult );
567
0
        else if ( GetStyle() & WB_CLOSEABLE )
568
0
            Close();
569
0
    }
570
571
    void RoadmapWizard::AddPage( TabPage* pPage )
572
0
    {
573
0
        ImplWizPageData* pNewPageData = new ImplWizPageData;
574
0
        pNewPageData->mpNext    = nullptr;
575
0
        pNewPageData->mpPage    = pPage;
576
577
0
        if ( !mpFirstPage )
578
0
            mpFirstPage = pNewPageData;
579
0
        else
580
0
        {
581
0
            pPage->Hide();
582
0
            ImplWizPageData* pPageData = mpFirstPage;
583
0
            while ( pPageData->mpNext )
584
0
                pPageData = pPageData->mpNext;
585
0
            pPageData->mpNext = pNewPageData;
586
0
        }
587
0
    }
588
589
    void RoadmapWizard::RemovePage( TabPage* pPage )
590
0
    {
591
0
        ImplWizPageData*  pPrevPageData = nullptr;
592
0
        ImplWizPageData*  pPageData = mpFirstPage;
593
0
        while ( pPageData )
594
0
        {
595
0
            if ( pPageData->mpPage == pPage )
596
0
            {
597
0
                if ( pPrevPageData )
598
0
                    pPrevPageData->mpNext = pPageData->mpNext;
599
0
                else
600
0
                    mpFirstPage = pPageData->mpNext;
601
0
                if ( pPage == mpCurTabPage )
602
0
                    mpCurTabPage = nullptr;
603
0
                delete pPageData;
604
0
                return;
605
0
            }
606
607
0
            pPrevPageData = pPageData;
608
0
            pPageData = pPageData->mpNext;
609
0
        }
610
611
0
        OSL_FAIL( "RoadmapWizard::RemovePage() - Page not in list" );
612
0
    }
613
614
    void RoadmapWizard::SetPage( sal_uInt16 nLevel, TabPage* pPage )
615
0
    {
616
0
        sal_uInt16              nTempLevel = 0;
617
0
        ImplWizPageData*    pPageData = mpFirstPage;
618
0
        while ( pPageData )
619
0
        {
620
0
            if ( (nTempLevel == nLevel) || !pPageData->mpNext )
621
0
                break;
622
623
0
            nTempLevel++;
624
0
            pPageData = pPageData->mpNext;
625
0
        }
626
627
0
        if ( pPageData )
628
0
        {
629
0
            if ( pPageData->mpPage == mpCurTabPage )
630
0
                mpCurTabPage = nullptr;
631
0
            pPageData->mpPage = pPage;
632
0
        }
633
0
    }
634
635
    TabPage* RoadmapWizard::GetPage( sal_uInt16 nLevel ) const
636
0
    {
637
0
        sal_uInt16 nTempLevel = 0;
638
639
0
        for (ImplWizPageData* pPageData = mpFirstPage; pPageData;
640
0
             pPageData = pPageData->mpNext)
641
0
        {
642
0
            if ( nTempLevel == nLevel )
643
0
                return pPageData->mpPage;
644
0
            nTempLevel++;
645
0
        }
646
647
0
        return nullptr;
648
0
    }
649
650
    void RoadmapWizard::AddButton( Button* pButton, tools::Long nOffset )
651
0
    {
652
0
        ImplWizButtonData* pNewBtnData = new ImplWizButtonData;
653
0
        pNewBtnData->mpNext     = nullptr;
654
0
        pNewBtnData->mpButton   = pButton;
655
0
        pNewBtnData->mnOffset   = nOffset;
656
657
0
        if ( !mpFirstBtn )
658
0
            mpFirstBtn = pNewBtnData;
659
0
        else
660
0
        {
661
0
            ImplWizButtonData* pBtnData = mpFirstBtn;
662
0
            while ( pBtnData->mpNext )
663
0
                pBtnData = pBtnData->mpNext;
664
0
            pBtnData->mpNext = pNewBtnData;
665
0
        }
666
0
    }
667
668
    void RoadmapWizard::RemoveButton( Button* pButton )
669
0
    {
670
0
        ImplWizButtonData*  pPrevBtnData = nullptr;
671
0
        ImplWizButtonData*  pBtnData = mpFirstBtn;
672
0
        while ( pBtnData )
673
0
        {
674
0
            if ( pBtnData->mpButton == pButton )
675
0
            {
676
0
                if ( pPrevBtnData )
677
0
                    pPrevBtnData->mpNext = pBtnData->mpNext;
678
0
                else
679
0
                    mpFirstBtn = pBtnData->mpNext;
680
0
                delete pBtnData;
681
0
                return;
682
0
            }
683
684
0
            pPrevBtnData = pBtnData;
685
0
            pBtnData = pBtnData->mpNext;
686
0
        }
687
688
0
        OSL_FAIL( "RoadmapWizard::RemoveButton() - Button not in list" );
689
0
    }
690
691
    IMPL_LINK_NOARG(RoadmapWizard, OnFinish, Button*, void)
692
0
    {
693
0
        if ( isTravelingSuspended() )
694
0
            return;
695
0
        RoadmapWizardTravelSuspension aTravelGuard( *this );
696
0
        Finish( RET_OK );
697
0
    }
698
699
    void RoadmapWizard::skipBackwardUntil(WizardTypes::WizardState _nTargetState)
700
0
    {
701
        // don't travel directly on m_xWizardImpl->aStateHistory, in case something goes wrong
702
0
        std::stack< WizardTypes::WizardState > aTravelVirtually = m_xWizardImpl->aStateHistory;
703
704
0
        WizardTypes::WizardState nCurrentRollbackState = getCurrentState();
705
0
        while ( nCurrentRollbackState != _nTargetState )
706
0
        {
707
0
            assert(!aTravelVirtually.empty() && "RoadmapWizard::skipBackwardUntil: this target state does not exist in the history!");
708
0
            nCurrentRollbackState = aTravelVirtually.top();
709
0
            aTravelVirtually.pop();
710
0
        }
711
0
        m_xWizardImpl->aStateHistory = std::move(aTravelVirtually);
712
0
        ShowPage(_nTargetState);
713
0
    }
714
715
    void RoadmapWizard::skipUntil(WizardTypes::WizardState _nTargetState)
716
0
    {
717
0
        WizardTypes::WizardState nCurrentState = getCurrentState();
718
719
        // don't travel directly on m_xWizardImpl->aStateHistory, in case something goes wrong
720
0
        std::stack< WizardTypes::WizardState > aTravelVirtually = m_xWizardImpl->aStateHistory;
721
0
        while ( nCurrentState != _nTargetState )
722
0
        {
723
0
            WizardTypes::WizardState nNextState = determineNextState( nCurrentState );
724
0
            assert(nNextState != WZS_INVALID_STATE && "RoadmapWizard::skipUntil: the given target state does not exist!");
725
726
            // remember the skipped state in the history
727
0
            aTravelVirtually.push( nCurrentState );
728
729
            // get the next state
730
0
            nCurrentState = nNextState;
731
0
        }
732
0
        m_xWizardImpl->aStateHistory = std::move(aTravelVirtually);
733
        // show the target page
734
0
        ShowPage(nCurrentState);
735
0
    }
736
737
    void RoadmapWizard::travelNext()
738
0
    {
739
        // determine the next state to travel to
740
0
        WizardTypes::WizardState nCurrentState = getCurrentState();
741
0
        WizardTypes::WizardState nNextState = determineNextState(nCurrentState);
742
0
        if (WZS_INVALID_STATE == nNextState)
743
0
            return;
744
745
        // the state history is used by the enterState method
746
        // all fine
747
0
        m_xWizardImpl->aStateHistory.push(nCurrentState);
748
0
        ShowPage(nNextState);
749
0
    }
750
751
    void RoadmapWizard::travelPrevious()
752
0
    {
753
0
        DBG_ASSERT(!m_xWizardImpl->aStateHistory.empty(), "RoadmapWizard::travelPrevious: have no previous page!");
754
755
        // the next state to switch to
756
0
        WizardTypes::WizardState nPreviousState = m_xWizardImpl->aStateHistory.top();
757
758
        // the state history is used by the enterState method
759
0
        m_xWizardImpl->aStateHistory.pop();
760
        // show this page
761
0
        ShowPage(nPreviousState);
762
0
    }
763
764
    void  RoadmapWizard::removePageFromHistory( WizardTypes::WizardState nToRemove )
765
0
    {
766
767
0
        std::stack< WizardTypes::WizardState > aTemp;
768
0
        while(!m_xWizardImpl->aStateHistory.empty())
769
0
        {
770
0
            WizardTypes::WizardState nPreviousState = m_xWizardImpl->aStateHistory.top();
771
0
            m_xWizardImpl->aStateHistory.pop();
772
0
            if(nPreviousState != nToRemove)
773
0
                aTemp.push( nPreviousState );
774
0
            else
775
0
                break;
776
0
        }
777
0
        while(!aTemp.empty())
778
0
        {
779
0
            m_xWizardImpl->aStateHistory.push( aTemp.top() );
780
0
            aTemp.pop();
781
0
        }
782
0
    }
783
784
    IMPL_LINK_NOARG(RoadmapWizard, OnPrevPage, Button*, void)
785
0
    {
786
0
        if ( isTravelingSuspended() )
787
0
            return;
788
0
        RoadmapWizardTravelSuspension aTravelGuard( *this );
789
0
        travelPrevious();
790
0
    }
791
792
    IMPL_LINK_NOARG(RoadmapWizard, OnNextPage, Button*, void)
793
0
    {
794
0
        if ( isTravelingSuspended() )
795
0
            return;
796
0
        RoadmapWizardTravelSuspension aTravelGuard( *this );
797
0
        travelNext();
798
0
    }
799
800
    bool RoadmapWizard::isTravelingSuspended() const
801
0
    {
802
0
        return m_xWizardImpl->m_bTravelingSuspended;
803
0
    }
804
805
    void RoadmapWizard::suspendTraveling( AccessGuard )
806
0
    {
807
0
        DBG_ASSERT( !m_xWizardImpl->m_bTravelingSuspended, "RoadmapWizard::suspendTraveling: already suspended!" );
808
0
        m_xWizardImpl->m_bTravelingSuspended = true;
809
0
    }
810
811
    void RoadmapWizard::resumeTraveling( AccessGuard )
812
0
    {
813
0
        DBG_ASSERT( m_xWizardImpl->m_bTravelingSuspended, "RoadmapWizard::resumeTraveling: nothing to resume!" );
814
0
        m_xWizardImpl->m_bTravelingSuspended = false;
815
0
    }
816
817
    void RoadmapWizard::implUpdateRoadmap( )
818
0
    {
819
0
        DBG_ASSERT( m_xRoadmapImpl->aPaths.find( m_xRoadmapImpl->nActivePath ) != m_xRoadmapImpl->aPaths.end(),
820
0
            "RoadmapWizard::implUpdateRoadmap: there is no such path!" );
821
0
        const WizardPath& rActivePath( m_xRoadmapImpl->aPaths[ m_xRoadmapImpl->nActivePath ] );
822
823
0
        sal_Int32 nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( getCurrentState(), rActivePath );
824
0
        if (nCurrentStatePathIndex < 0)
825
0
            return;
826
0
        assert(nCurrentStatePathIndex >= 0 && o3tl::make_unsigned(nCurrentStatePathIndex) < rActivePath.size());
827
828
        // determine up to which index (in the new path) we have to display the items
829
0
        RoadmapTypes::ItemIndex nUpperStepBoundary = static_cast<RoadmapTypes::ItemIndex>(rActivePath.size());
830
0
        bool bIncompletePath = false;
831
0
        if ( !m_xRoadmapImpl->bActivePathIsDefinite )
832
0
        {
833
0
            for (auto const& path : m_xRoadmapImpl->aPaths)
834
0
            {
835
0
                if ( path.first == m_xRoadmapImpl->nActivePath )
836
                    // it's the path we are just activating -> no need to check anything
837
0
                    continue;
838
                // the index from which on both paths differ
839
0
                sal_Int32 nDivergenceIndex = RoadmapWizardImpl::getFirstDifferentIndex( rActivePath, path.second );
840
0
                if ( nDivergenceIndex <= nCurrentStatePathIndex )
841
                    // they differ in an index which we have already left behind us
842
                    // -> this is no conflict anymore
843
0
                    continue;
844
845
                // the path conflicts with our new path -> don't activate the
846
                // *complete* new path, but only up to the step which is unambiguous
847
0
                nUpperStepBoundary = nDivergenceIndex;
848
0
                bIncompletePath = true;
849
0
            }
850
0
        }
851
852
        // now, we have to remove all items after nCurrentStatePathIndex, and insert the items from the active
853
        // path, up to (excluding) nUpperStepBoundary
854
0
        RoadmapTypes::ItemIndex nLoopUntil = ::std::max( nUpperStepBoundary, mpRoadmap->GetItemCount() );
855
0
        for ( RoadmapTypes::ItemIndex nItemIndex = nCurrentStatePathIndex; nItemIndex < nLoopUntil; ++nItemIndex )
856
0
        {
857
0
            bool bExistentItem = ( nItemIndex < mpRoadmap->GetItemCount() );
858
0
            bool bNeedItem = ( nItemIndex < nUpperStepBoundary );
859
860
0
            bool bInsertItem = false;
861
0
            if ( bExistentItem )
862
0
            {
863
0
                if ( !bNeedItem )
864
0
                {
865
0
                    while ( nItemIndex < mpRoadmap->GetItemCount() )
866
0
                        mpRoadmap->DeleteRoadmapItem( nItemIndex );
867
0
                    break;
868
0
                }
869
0
                else
870
0
                {
871
                    // there is an item with this index in the roadmap - does it match what is requested by
872
                    // the respective state in the active path?
873
0
                    RoadmapTypes::ItemId nPresentItemId = mpRoadmap->GetItemID( nItemIndex );
874
0
                    WizardTypes::WizardState nRequiredState = rActivePath[ nItemIndex ];
875
0
                    if ( nPresentItemId != nRequiredState )
876
0
                    {
877
0
                        mpRoadmap->DeleteRoadmapItem( nItemIndex );
878
0
                        bInsertItem = true;
879
0
                    }
880
0
                }
881
0
            }
882
0
            else
883
0
            {
884
0
                DBG_ASSERT( bNeedItem, "RoadmapWizard::implUpdateRoadmap: ehm - none needed, none present - why did the loop not terminate?" );
885
0
                bInsertItem = bNeedItem;
886
0
            }
887
888
0
            WizardTypes::WizardState nState( rActivePath[ nItemIndex ] );
889
0
            if ( bInsertItem )
890
0
            {
891
0
                mpRoadmap->InsertRoadmapItem(
892
0
                    nItemIndex,
893
0
                    getStateDisplayName( nState ),
894
0
                    nState,
895
0
                    true
896
0
                );
897
0
            }
898
899
0
            const bool bEnable = m_xRoadmapImpl->aDisabledStates.find( nState ) == m_xRoadmapImpl->aDisabledStates.end();
900
0
            mpRoadmap->EnableRoadmapItem( mpRoadmap->GetItemID( nItemIndex ), bEnable );
901
0
        }
902
903
0
        mpRoadmap->SetRoadmapComplete( !bIncompletePath );
904
0
    }
905
906
    WizardTypes::WizardState RoadmapWizard::determineNextState( WizardTypes::WizardState _nCurrentState ) const
907
0
    {
908
0
        sal_Int32 nCurrentStatePathIndex = -1;
909
910
0
        Paths::const_iterator aActivePathPos = m_xRoadmapImpl->aPaths.find( m_xRoadmapImpl->nActivePath );
911
0
        if ( aActivePathPos != m_xRoadmapImpl->aPaths.end() )
912
0
            nCurrentStatePathIndex = RoadmapWizardImpl::getStateIndexInPath( _nCurrentState, aActivePathPos->second );
913
914
0
        DBG_ASSERT( nCurrentStatePathIndex != -1, "RoadmapWizard::determineNextState: ehm - how can we travel if there is no (valid) active path?" );
915
0
        if (nCurrentStatePathIndex < 0)
916
0
            return WZS_INVALID_STATE;
917
0
        assert(nCurrentStatePathIndex >= 0 && o3tl::make_unsigned(nCurrentStatePathIndex) < aActivePathPos->second.size());
918
919
0
        sal_Int32 nNextStateIndex = nCurrentStatePathIndex + 1;
920
921
0
        while   (   ( nNextStateIndex < static_cast<sal_Int32>(aActivePathPos->second.size()) )
922
0
                &&  ( m_xRoadmapImpl->aDisabledStates.find( aActivePathPos->second[ nNextStateIndex ] ) != m_xRoadmapImpl->aDisabledStates.end() )
923
0
                )
924
0
        {
925
0
            ++nNextStateIndex;
926
0
        }
927
928
0
        if ( nNextStateIndex >= static_cast<sal_Int32>(aActivePathPos->second.size()) )
929
            // there is no next state in the current path (at least none which is enabled)
930
0
            return WZS_INVALID_STATE;
931
932
0
        return aActivePathPos->second[ nNextStateIndex ];
933
0
    }
934
935
936
    IMPL_LINK_NOARG(RoadmapWizard, OnRoadmapItemSelected, LinkParamNone*, void)
937
0
    {
938
0
        RoadmapTypes::ItemId nCurItemId = mpRoadmap->GetCurrentRoadmapItemID();
939
0
        if ( nCurItemId == getCurrentState() )
940
            // nothing to do
941
0
            return;
942
943
0
        if ( isTravelingSuspended() )
944
0
            return;
945
946
0
        RoadmapWizardTravelSuspension aTravelGuard( *this );
947
948
0
        sal_Int32 nCurrentIndex = m_xRoadmapImpl->getStateIndexInPath( getCurrentState(), m_xRoadmapImpl->nActivePath );
949
0
        sal_Int32 nNewIndex     = m_xRoadmapImpl->getStateIndexInPath( nCurItemId, m_xRoadmapImpl->nActivePath );
950
951
0
        DBG_ASSERT( ( nCurrentIndex != -1 ) && ( nNewIndex != -1 ),
952
0
            "RoadmapWizard::OnRoadmapItemSelected: something's wrong here!" );
953
0
        if ( ( nCurrentIndex == -1 ) || ( nNewIndex == -1 ) )
954
0
        {
955
0
            return;
956
0
        }
957
958
0
        if ( nNewIndex > nCurrentIndex )
959
0
        {
960
0
            skipUntil(static_cast<WizardTypes::WizardState>(nCurItemId));
961
0
            WizardTypes::WizardState nTemp = static_cast<WizardTypes::WizardState>(nCurItemId);
962
0
            while( nTemp )
963
0
            {
964
0
                if( m_xRoadmapImpl->aDisabledStates.find( --nTemp ) != m_xRoadmapImpl->aDisabledStates.end() )
965
0
                    removePageFromHistory( nTemp );
966
0
            }
967
0
        }
968
0
        else
969
0
            skipBackwardUntil(static_cast<WizardTypes::WizardState>(nCurItemId));
970
0
    }
971
972
    OUString RoadmapWizard::getStateDisplayName( WizardTypes::WizardState nState )
973
0
    {
974
0
        return OUString::number(nState);
975
0
    }
976
977
    void RoadmapWizard::InsertRoadmapItem(int nItemIndex, const OUString& rText, int nItemId, bool bEnable)
978
0
    {
979
0
        mpRoadmap->InsertRoadmapItem(nItemIndex, rText, nItemId, bEnable);
980
0
    }
981
982
    void RoadmapWizard::SelectRoadmapItemByID(int nItemId, bool bGrabFocus)
983
0
    {
984
0
        mpRoadmap->SelectRoadmapItemByID(nItemId, bGrabFocus);
985
0
    }
986
987
    void RoadmapWizard::DeleteRoadmapItems()
988
0
    {
989
0
        while (mpRoadmap->GetItemCount())
990
0
            mpRoadmap->DeleteRoadmapItem(0);
991
0
    }
992
993
    void RoadmapWizard::SetItemSelectHdl( const Link<LinkParamNone*,void>& _rHdl )
994
0
    {
995
0
        mpRoadmap->SetItemSelectHdl(_rHdl);
996
0
    }
997
998
    int RoadmapWizard::GetCurrentRoadmapItemID() const
999
0
    {
1000
0
        return mpRoadmap->GetCurrentRoadmapItemID();
1001
0
    }
1002
1003
    FactoryFunction RoadmapWizard::GetUITestFactory() const
1004
0
    {
1005
0
        return RoadmapWizardUIObject::create;
1006
0
    }
1007
1008
}   // namespace vcl
1009
1010
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */