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 #ifndef INCLUDED_VCL_WIZDLG_HXX
21 #define INCLUDED_VCL_WIZDLG_HXX
22 
23 #include <memory>
24 #include <vcl/toolkit/button.hxx>
25 #include <vcl/toolkit/dialog.hxx>
26 #include <vcl/roadmapwizard.hxx>
27 #include <vcl/tabpage.hxx>
28 
29 struct ImplWizPageData
30 {
31     ImplWizPageData*    mpNext;
32     VclPtr<TabPage>     mpPage;
33 };
34 
35 namespace vcl
36 {
37     struct RoadmapWizardImpl;
38     class RoadmapWizard;
39 
40     namespace RoadmapWizardTypes
41     {
42         typedef VclPtr<TabPage> (* RoadmapPageFactory)( RoadmapWizard& );
43     };
44 
45     //= RoadmapWizard
46 
47     /** wizard for a roadmap
48 
49         The basic new concept introduced is a <em>path</em>:<br/>
50         A <em>path</em> is a sequence of states, which are to be executed in a linear order.
51         Elements in the path can be skipped, depending on choices the user makes.
52 
53         In the most simple wizards, you will have only one path consisting of <code>n</code> elements,
54         which are to be visited successively.
55 
56         In a slightly more complex wizard, you will have one linear path, were certain
57         steps might be skipped due to user input. For instance, the user may decide to not specify
58         certain aspects of the to-be-created object (e.g. by unchecking a check box),
59         and the wizard then will simply disable the step which corresponds to this step.
60 
61         In a yet more advanced wizards, you will have several paths of length <code>n1</code> and
62         <code>n2</code>, which share at least the first <code>k</code> states (where <code>k</code>
63         is at least 1), and an arbitrary number of other states.
64     */
65     class RoadmapWizard : public Dialog
66     {
67     private:
68         Idle                    maWizardLayoutIdle;
69         Size                    maPageSize;
70         ImplWizPageData*        mpFirstPage;
71         ImplWizButtonData*      mpFirstBtn;
72         VclPtr<TabPage>         mpCurTabPage;
73         VclPtr<PushButton>      mpPrevBtn;
74         VclPtr<PushButton>      mpNextBtn;
75         VclPtr<vcl::Window>     mpViewWindow;
76         sal_uInt16              mnCurLevel;
77         sal_Int16               mnLeftAlignCount;
78         bool                    mbEmptyViewMargin;
79 
80         DECL_LINK( ImplHandleWizardLayoutTimerHdl, Timer*, void );
81 
82         // IMPORTANT:
83         // traveling pages should not be done by calling these base class member, some mechanisms of this class
84         // here (e.g. committing page data) depend on having full control over page traveling.
85         // So use the travelXXX methods if you need to travel
86 
87     protected:
88         tools::Long                LogicalCoordinateToPixel(int iCoordinate);
89         /**sets the number of buttons which should be left-aligned. Normally, buttons are right-aligned.
90 
91             only to be used during construction, before any layouting happened
92         */
93         void                SetLeftAlignedButtonCount( sal_Int16 _nCount );
94 
95         void                CalcAndSetSize();
96 
97     public:
98         VclPtr<OKButton>       m_pFinish;
99         VclPtr<CancelButton>   m_pCancel;
100         VclPtr<PushButton>     m_pNextPage;
101         VclPtr<PushButton>     m_pPrevPage;
102         VclPtr<HelpButton>     m_pHelp;
103 
104     private:
105         std::unique_ptr<WizardMachineImplData> m_xWizardImpl;
106         // hold members in this structure to allow keeping compatible when members are added
107         std::unique_ptr<RoadmapWizardImpl> m_xRoadmapImpl;
108 
109     public:
110         RoadmapWizard(vcl::Window* pParent, WinBits nStyle = WB_STDDIALOG, InitFlag eFlag = InitFlag::Default);
111         virtual ~RoadmapWizard( ) override;
112         virtual void dispose() override;
113 
114         virtual void        Resize() override;
115         virtual void        StateChanged( StateChangedType nStateChange ) override;
116         virtual bool        EventNotify( NotifyEvent& rNEvt ) override;
117 
118         void                ActivatePage();
119 
120         virtual void        queue_resize(StateChangedType eReason = StateChangedType::Layout) override;
121 
122         bool                ShowPage( sal_uInt16 nLevel );
123         void                Finish( tools::Long nResult = 0 );
GetCurLevel() const124         sal_uInt16          GetCurLevel() const { return mnCurLevel; }
125 
126         void                AddPage( TabPage* pPage );
127         void                RemovePage( TabPage* pPage );
128         void                SetPage( sal_uInt16 nLevel, TabPage* pPage );
129         TabPage*            GetPage( sal_uInt16 nLevel ) const;
130 
131         void                AddButton( Button* pButton, tools::Long nOffset = 0 );
132         void                RemoveButton( Button* pButton );
133 
SetPageSizePixel(const Size & rSize)134         void                SetPageSizePixel( const Size& rSize ) { maPageSize = rSize; }
GetPageSizePixel() const135         const Size&         GetPageSizePixel() const { return maPageSize; }
136 
137         /// enable (or disable) buttons
138         void                enableButtons(WizardButtonFlags _nWizardButtonFlags, bool _bEnable);
139 
140         /// determines whether there is a next state to which we can advance
141         bool            canAdvance() const;
142 
143         void            SetRoadmapHelpId( const OString& _rId );
144 
145         void            InsertRoadmapItem(int nIndex, const OUString& rLabel, int nId, bool bEnabled);
146         void            DeleteRoadmapItems();
147         int             GetCurrentRoadmapItemID() const;
148         void            SelectRoadmapItemByID(int nId, bool bGrabFocus = true);
149         void            SetItemSelectHdl( const Link<LinkParamNone*,void>& _rHdl );
150         void            ShowRoadmap(bool bShow);
151 
152         FactoryFunction GetUITestFactory() const override;
153 
154     protected:
155 
156         /// to override to create new pages
157         VclPtr<TabPage>     createPage(WizardTypes::WizardState nState);
158 
159         /// will be called when a new page is about to be displayed
160         void                enterState(WizardTypes::WizardState _nState);
161 
162         /** will be called when the current state is about to be left for the given reason
163 
164             The base implementation in this class will simply call <member>OWizardPage::commitPage</member>
165             for the current page, and return whatever this call returns.
166 
167             @param _eReason
168                 The reason why the state is to be left.
169             @return
170                 <TRUE/> if and only if the page is allowed to be left
171         */
172         bool                prepareLeaveCurrentState( WizardTypes::CommitPageReason eReason );
173 
174         /** determine the next state to travel from the given one
175 
176             This method ensures that traveling happens along the active path.
177 
178             Return WZS_INVALID_STATE to prevent traveling.
179 
180             @see activatePath
181         */
182         WizardTypes::WizardState determineNextState(WizardTypes::WizardState nCurrentState) const;
183 
184         /// travel to the next state
185         void                travelNext();
186 
187         /// travel to the previous state
188         void                travelPrevious();
189 
190         /** enables the automatic enabled/disabled state of the "Next" button
191 
192             If this is <TRUE/>, then upon entering a new state, the "Next" button will automatically be
193             enabled if and only if determineNextState does not return WZS_INVALID_STATE.
194         */
195         bool                isAutomaticNextButtonStateEnabled() const;
196 
197         /** removes a page from the history. Should be called when the page is being disabled
198         */
199         void                removePageFromHistory(WizardTypes::WizardState nToRemove);
200 
201         /** skips one or more states, until a given state is reached
202 
203             The method behaves as if from the current state, <method>travelNext</method>s were called
204             successively, until <arg>_nTargetState</arg> is reached, but without actually creating or
205             displaying the \EDntermediate pages.
206 
207             The skipped states appear in the state history, so <method>travelPrevious</method> will make use of them.
208 
209             @return
210                 <TRUE/> if and only if traveling was successful
211 
212             @see skip
213             @see skipBackwardUntil
214         */
215         bool                    skipUntil(WizardTypes::WizardState nTargetState);
216 
217         /** moves back one or more states, until a given state is reached
218 
219             This method allows traveling backwards more than one state without actually showing the intermediate
220             states.
221 
222             For instance, if you want to travel two steps backward at a time, you could used
223             two travelPrevious calls, but this would <em>show</em> both pages, which is not necessary,
224             since you're interested in the target page only. Using <member>skipBackwardUntil</member> relieves
225             you of this.
226 
227             @return
228                 <TRUE/> if and only if traveling was successful
229 
230             @see skipUntil
231             @see skip
232         */
233         bool                    skipBackwardUntil(WizardTypes::WizardState nTargetState);
234 
235         /** returns the current state of the machine
236 
237             Vulgo, this is the identifier of the current tab page :)
238         */
getCurrentState() const239         WizardTypes::WizardState getCurrentState() const { return GetCurLevel(); }
240 
241         static IWizardPageController*  getPageController( TabPage* _pCurrentPage );
242 
243         /** returns a human readable name for a given state
244 
245             There is a default implementation for this method, which returns the display name
246             as given in a call to describeState. If there is no description for the given state,
247             this is worth an assertion in a non-product build, and then an empty string is
248             returned.
249         */
250         OUString  getStateDisplayName(WizardTypes::WizardState nState) const;
251 
252     private:
253         DECL_LINK( OnRoadmapItemSelected, LinkParamNone*, void );
254 
255         /** updates the roadmap control to show the given path, as far as possible
256             (modulo conflicts with other paths)
257         */
258         void implUpdateRoadmap( );
259 
260     public:
261         class AccessGuard
262         {
263             friend class RoadmapWizardTravelSuspension;
264         private:
AccessGuard()265             AccessGuard() { }
266         };
267 
268         void                   suspendTraveling( AccessGuard );
269         void                   resumeTraveling( AccessGuard );
270         bool                   isTravelingSuspended() const;
271 
272     protected:
273         void GetOrCreatePage(const WizardTypes::WizardState i_nState);
274 
275     private:
276         void             ImplCalcSize( Size& rSize );
277         void             ImplPosCtrls();
278         void             ImplPosTabPage();
279         void             ImplShowTabPage( TabPage* pPage );
280         TabPage*         ImplGetPage( sal_uInt16 nLevel ) const;
281 
282 
283         DECL_LINK(OnNextPage, Button*, void);
284         DECL_LINK(OnPrevPage, Button*, void);
285         DECL_LINK(OnFinish, Button*, void);
286 
287         void     implUpdateTitle();
288         void     implConstruct( const WizardButtonFlags _nButtonFlags );
289     };
290 
291     /// helper class to temporarily suspend any traveling in the wizard
292     class RoadmapWizardTravelSuspension
293     {
294     public:
RoadmapWizardTravelSuspension(RoadmapWizard & rWizard)295         RoadmapWizardTravelSuspension(RoadmapWizard& rWizard)
296             : m_pOWizard(&rWizard)
297         {
298             m_pOWizard->suspendTraveling(RoadmapWizard::AccessGuard());
299         }
300 
~RoadmapWizardTravelSuspension()301         ~RoadmapWizardTravelSuspension()
302         {
303             if (m_pOWizard)
304                 m_pOWizard->resumeTraveling(RoadmapWizard::AccessGuard());
305         }
306 
307     private:
308         VclPtr<RoadmapWizard> m_pOWizard;
309     };
310 
311 } // namespace vcl
312 
313 #endif
314 
315 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
316