summaryrefslogtreecommitdiff
path: root/include/svtools/dialogcontrolling.hxx
blob: ada35ea75581fda832a9bff7f6ae0aba36094fe3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#ifndef INCLUDED_SVTOOLS_DIALOGCONTROLLING_HXX
#define INCLUDED_SVTOOLS_DIALOGCONTROLLING_HXX

#include <svtools/svtdllapi.h>

#include <tools/link.hxx>
#include <vcl/button.hxx>
#include <vcl/vclevent.hxx>

#include <memory>
#include <vector>

namespace svt
{


    //= IWindowOperator

    /** an abstract interface for operating on a ->Window
    */
    class SVT_DLLPUBLIC SAL_NO_VTABLE IWindowOperator
    {
    public:
        /** called when an event happened which should be reacted to

            @param _rTrigger
                the event which triggered the call. If the Id of the event is 0, then this is the initial
                call which is made when ->_rOperateOn is added to the responsibility of the DialogController.
            @param _rOperateOn
                the window on which to operate
        */
        virtual void operateOn( const VclWindowEvent& _rTrigger, vcl::Window& _rOperateOn ) const = 0;

        virtual ~IWindowOperator();
    };
    typedef std::shared_ptr< IWindowOperator >  PWindowOperator;


    //= IWindowEventFilter

    /** an abstract interface for deciding whether a ->VclWindowEvent
        is worth paying attention to
    */
    class SVT_DLLPUBLIC SAL_NO_VTABLE IWindowEventFilter
    {
    public:
        virtual bool payAttentionTo( const VclWindowEvent& _rEvent ) const = 0;

        virtual ~IWindowEventFilter();
    };
    typedef std::shared_ptr< IWindowEventFilter >   PWindowEventFilter;


    //= DialogController

    struct DialogController_Data;
    /** a class controlling interactions between dialog controls

        An instance of this class listens to all events fired by a certain
        ->Control (more precise, a ->Window), the so-called instigator.

        Additionally, the ->DialogController maintains a list of windows which
        are affected by changes in the instigator window. Let's call those the
        dependent windows.

        Now, by help of an owner-provided ->IWindowEventFilter, the ->DialogController
        decides which events are worth attention. By help of an owner-provided
        ->IWindowOperator, it handles those events for all dependent windows.
    */
    class SVT_DLLPUBLIC DialogController
    {
    private:
        ::std::unique_ptr< DialogController_Data >    m_pImpl;

    public:
        DialogController( vcl::Window& _rInstigator, const PWindowEventFilter& _pEventFilter, const PWindowOperator& _pOperator );
        virtual ~DialogController();

        /** adds a window to the list of dependent windows

            @param _rWindow
                The window to add to the list of dependent windows.

                The caller is responsible for life-time control: The given window
                must live at least as long as the ->DialogController instance does.
        */
        void    addDependentWindow( vcl::Window& _rWindow );

        /** resets the controller so that no actions happened anymore.

            The instances is disfunctional after this method has been called.
        */
        void    reset();

    private:
        void    impl_update( const VclWindowEvent& _rTriggerEvent, vcl::Window& _rWindow );

        DECL_LINK( OnWindowEvent, VclWindowEvent&, void );

    private:
        DialogController( const DialogController& ) = delete;
        DialogController& operator=( const DialogController& ) = delete;
    };

    //= ControlDependencyManager

    struct ControlDependencyManager_Data;
    /** helper class for managing control dependencies

        Instances of this class are intended to be held as members of a dialog/tabpage/whatever
        class, with easy administration of inter-control dependencies (such as "Enable
        control X if and only if checkbox Y is checked).
    */
    class SVT_DLLPUBLIC ControlDependencyManager
    {
    private:
        ::std::unique_ptr< ControlDependencyManager_Data >    m_pImpl;

    public:
        ControlDependencyManager();
        ~ControlDependencyManager();

        /** ensures that a given window is enabled or disabled, according to the check state
            of a given radio button
            @param _rRadio
                denotes the radio button whose check state is to observe
            @param _rDependentWindow
                denotes the window which should be enabled when ->_rRadio is checked, and
                disabled when it's unchecked
        */
        void    enableOnRadioCheck( RadioButton& _rRadio, vcl::Window& _rDependentWindow );
        void    enableOnRadioCheck( RadioButton& _rRadio, vcl::Window& _rDependentWindow1, vcl::Window& _rDependentWindow2 );
        void    enableOnRadioCheck( RadioButton& _rRadio, vcl::Window& _rDependentWindow1, vcl::Window& _rDependentWindow2, vcl::Window& _rDependentWindow3 );
        void    enableOnRadioCheck( RadioButton& _rRadio, vcl::Window& _rDependentWindow1, vcl::Window& _rDependentWindow2, vcl::Window& _rDependentWindow3, vcl::Window& _rDependentWindow4, vcl::Window& _rDependentWindow5 );

        /** adds a non-standard controller whose functionality is not covered by the other methods

            @param _pController
                the controller to add to the manager. Must not be <NULL/>.
        */
        void    addController( const std::shared_ptr<DialogController>& _pController );

    private:
        ControlDependencyManager( const ControlDependencyManager& ) = delete;
        ControlDependencyManager& operator=( const ControlDependencyManager& ) = delete;
    };


    //= EnableOnCheck

    /** a helper class implementing the ->IWindowOperator interface,
        which enables a dependent window depending on the check state of
        an instigator window.

        @see DialogController
    */
    template< class CHECKABLE >
    class SVT_DLLPUBLIC EnableOnCheck : public IWindowOperator
    {
    public:
        typedef CHECKABLE   SourceType;

    private:
        SourceType& m_rCheckable;

    public:
        /** constructs the instance

            @param _rCheckable
                a ->Window instance which supports a boolean method IsChecked. Usually
                a ->RadioButton or ->CheckBox
        */
        EnableOnCheck( SourceType& _rCheckable )
            :m_rCheckable( _rCheckable )
        {
        }

        virtual void operateOn( const VclWindowEvent& /*_rTrigger*/, vcl::Window& _rOperateOn ) const override
        {
            _rOperateOn.Enable( m_rCheckable.IsChecked() );
        }
    };


    //= FilterForRadioOrCheckToggle

    /** a helper class implementing the ->IWindowEventFilter interface,
        which filters for radio buttons or check boxes being toggled.

        Technically, the class simply filters for the ->VclEventId::RadiobuttonToggle
        and the ->VclEventId::CheckboxToggle event.
    */
    class SVT_DLLPUBLIC FilterForRadioOrCheckToggle : public IWindowEventFilter
    {
        const vcl::Window&   m_rWindow;
    public:
        FilterForRadioOrCheckToggle( const vcl::Window& _rWindow )
            :m_rWindow( _rWindow )
        {
        }

        bool payAttentionTo( const VclWindowEvent& _rEvent ) const override
        {
            if  (   ( _rEvent.GetWindow() == &m_rWindow )
                &&  (   ( _rEvent.GetId() == VclEventId::RadiobuttonToggle )
                    ||  ( _rEvent.GetId() == VclEventId::CheckboxToggle )
                    )
                )
                return true;
            return false;
        }
    };


    //= RadioDependentEnabler

    /** a ->DialogController derivee which enables or disables its dependent windows,
        depending on the check state of a radio button.

        The usage of this class is as simple as
        <code>
        pController = new RadioDependentEnabler( m_aOptionSelectSomething );
        pController->addDependentWindow( m_aLabelSelection );
        pController->addDependentWindow( m_aListSelection );
        </code>

        With this, both <code>m_aLabelSelection</code> and <code>m_aListSelection</code> will
        be disabled if and only <code>m_aOptionSelectSomething</code> is checked.
    */
    class SVT_DLLPUBLIC RadioDependentEnabler : public DialogController
    {
    public:
        RadioDependentEnabler( RadioButton& _rButton )
            :DialogController( _rButton,
                PWindowEventFilter( new FilterForRadioOrCheckToggle( _rButton ) ),
                PWindowOperator( new EnableOnCheck< RadioButton >( _rButton ) ) )
        {
        }
    };


} // namespace svt


#endif // INCLUDED_SVTOOLS_DIALOGCONTROLLING_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */