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 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
|
/************************************************************************
*
* Copyright (C) 2016-2025 IRCAD France
* Copyright (C) 2016-2021 IHU Strasbourg
*
* This file is part of Sight.
*
* Sight is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Sight is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Sight. If not, see <https://www.gnu.org/licenses/>.
*
***********************************************************************/
#pragma once
#include <activity/sequencer.hpp>
#include <data/activity_set.hpp>
#include <data/boolean.hpp>
#include <ui/__/editor.hpp>
#include <QButtonGroup>
#include <QPointer>
namespace sight::module::ui::qt::activity
{
/**
* @brief This editor displays an activity stepper that allows to select the activity to launch, and display the
* current selection
*
* The order of the activities is given in the configuration.
*
* Activity are created for each activity using the data produced by the previous activities. This activities are
* stored in the current ActivitySet. By default all the data are stored, you can to backward and forward as you want in
* the existing activities. Using the tag 'clearActivities', you can remove the last activities when going backward to
* force the user to re-generate the data.
*
* @warning If an activity can not be launched with the existing parameters, the signal 'dataRequired' is emitted. It
* can be connected to an activity wizard to add the missing data, or you can supplied 'requirementOverrides' map.
*
* @note If the inout ActivitySet already contains activities, their are parsed and the sequencer open on the last
* activities. Be careful to store them in the right order.
*
* @section Signal Signal
* - \b activity_created(data::activity::sptr) : This signal is emitted when an activity is created (using
* next() or previous().
* - \b data_required() : This signal is emitted when the activity can not be launch because it requires data.
* - \b hasNext(bool): This signal is emitted on sendInfo() slot, with the information if an activity is present after
* the current one.
* - \b hasPrevious(bool): This signal is emitted on sendInfo() slot, with the information if an activity is present
* before the current one.
* - \b nextEnabled(bool): This signal is emitted when the next button is enabled and can be launched.
*
* @section Slots Slots
* - \b next() : Create the next activity
* - \b previous() : Create the next activity
* - \b go_to(std::string) : If enabled, switch to the given activity
* - \b send_info() : Send the 'hasNext' and 'hasPrevious' signals for the current activity
* - \b reset_requirements() : Reset requirements that have been created by the activity
*
* @section XML XML Configuration
* @code{.xml}
<service type="sight::module::ui::qt::activity::sequencer">
<inout key="activitySet" uid="" auto_connect="true" />
<activity id="..." name="..." />
<activity id="..." name="..." />
<activity id="..." name="..." />
<clearActivities>false</clearActivities>
<buttonWidth>200</buttonWidth>
<fontSize>12</fontSize>
</service>
@endcode
* @subsection In In
* - \b requirementOverrides [sight::data::map] (optional): provide some data that will be passed as activity
* requirements. Can be used to supply required data that cannot be created by the activity, or to override
* data that would normally be passed from an activity to the next.
*
* @subsection In-Out In-Out
* - \b activity_set [sight::data::activity_set]: used to store the Activity of the managed activities
*
* @subsection Configuration Configuration
* - \b activity :
* - \b id: id of the activities to launch. The first activity in the list is the first that will be launched.
* - \b name(optional): name of the activity to display in the editor. If it is empty, the the activity's will be
* used
* - \b clearActivities (optional, default: false): defines if the activities and their requirements should be removed
* when going backward.
* - \b buttonWidth (optional): the width of the buttons of the sequencer.
* - \b fontSize (optional): the size of the font used in the buttons of the sequencer.
*
* @todo listen the current activity data to notify when the next activity can be created
*/
class sequencer : public QObject,
public sight::ui::editor,
public sight::activity::sequencer
{
Q_OBJECT
public:
SIGHT_DECLARE_SERVICE(sequencer, sight::ui::editor);
/// Initialize signals and slots
sequencer() noexcept;
/// Destructor. Do nothing.
~sequencer() noexcept override = default;
struct slots final
{
using key_t = sight::core::com::slots::key_t;
inline static const key_t GO_TO = "go_to";
inline static const key_t CHECK_NEXT = "check_next";
inline static const key_t VALIDATE_NEXT = "validate_next";
inline static const key_t NEXT = "next";
inline static const key_t PREVIOUS = "previous";
inline static const key_t SEND_INFO = "send_info";
inline static const key_t RESET_REQUIREMENTS = "reset_requirements";
inline static const key_t ENABLE_USER_WARNING = "enable_user_warning";
inline static const key_t DISABLE_USER_WARNING = "disable_user_warning";
inline static const key_t SET_USER_WARNING = "set_user_warning";
};
struct signals final
{
using key_t = sight::core::com::signals::key_t;
inline static const key_t ACTIVITY_CREATED = "activity_created";
inline static const key_t DATA_REQUIRED = "data_required";
inline static const key_t HAS_PREVIOUS = "hasPrevious";
inline static const key_t HAS_NEXT = "hasNext";
inline static const key_t NEXT_ENABLED = "nextEnabled";
inline static const key_t NEXT_VALIDATED = "next_validated";
inline static const key_t NEXT_VALID = "next_valid";
inline static const key_t NEXT_INVALID = "next_invalid";
using void_signal_t = core::com::signal<void ()>;
using bool_signal_t = core::com::signal<void (bool)>;
using activity_signal_t = core::com::signal<void (data::activity::sptr)>;
};
/// Slot: Check if the next activities can be enabled
void check_next();
/// Slot: Validate the next activities without enabling it. Emits nextValidated(true/false), next(In)Valid signals
void validate_next();
/// Slot: Create the next activity, emit 'dataRequired' signal if the activity require additional data
void next();
/// Slot: Create the previous activity, emit 'dataRequired' signal if the activity require additional data
void previous();
/// Slot: Send the 'hasNext' and 'enablePrevious' signals for the current activity
void send_info() const;
// Slot: Reset requirements of activities
using sight::activity::sequencer::reset_requirements;
/// Slot: Enables the user warning dialog about possible loss of un-validated data
/// Does nothing if "warning_message" wasn't configured.
void enable_user_warning();
/// Slot: Disables the user warning dialog about possible loss of un-validated data
/// Does nothing if "warning_message" wasn't configured.
void disable_user_warning();
/// Slot: Configures the user warning according to _state value.
/// Does nothing if "warning_message" wasn't configured.
void set_user_warning(bool _state);
public Q_SLOTS:
/// Create the activity at the given index, emit 'dataRequired' signal if the activity require additional data
void go_to_index(int _index);
protected:
/// Parses the configuration
void configuring() override;
/// Create the sequencer widgets: launch Qml file
void starting() override;
/// Destroy the container
void stopping() override;
/**
* @brief Analyse the contained in the current activity_set.
*
* - if the is an unknown activity, it is removed
* - else, the activity data is stored in m_requirements
* - the last activity is launched
*/
void updating() override;
/// Slot: create the activity, emit 'dataRequired' signal if the activity require additional data
void go_to(std::string _activity_id);
/// Connect the service to the ActivitySet signals
connections_t auto_connections() const override;
private:
/// Invoke 'enableActivity' method in Qml file
void enable_activity(int _index);
/// Invokes 'disableActivity' method in Qml file
void disable_activity(int _index);
/// List of the activities
std::vector<std::string> m_activity_names;
QPointer<QWidget> m_widget;
QPointer<QButtonGroup> m_button_group;
/// Defines if the activities should be cleared when going backward
bool m_clear_activities {false};
/// Display a warning message if changing activities without validating it.
bool m_warn_user {false};
/// Configured warning message, if empty no warnings are displayed.
std::string m_warning_message;
std::string m_button_width {"200"};
double m_font_size {12.0};
const signals::activity_signal_t::sptr m_activity_created {
new_signal<signals::activity_signal_t>(signals::ACTIVITY_CREATED)
};
const signals::activity_signal_t::sptr m_data_required {
new_signal<signals::activity_signal_t>(signals::DATA_REQUIRED)
};
const signals::bool_signal_t::sptr m_has_previous {
new_signal<signals::bool_signal_t>(signals::HAS_PREVIOUS)
};
const signals::bool_signal_t::sptr m_has_next {
new_signal<signals::bool_signal_t>(signals::HAS_NEXT)
};
const signals::bool_signal_t::sptr m_next_enabled {
new_signal<signals::bool_signal_t>(signals::NEXT_ENABLED)
};
const signals::bool_signal_t::sptr m_next_validated {
new_signal<signals::bool_signal_t>(signals::NEXT_VALIDATED)
};
const signals::void_signal_t::sptr m_next_valid {
new_signal<signals::void_signal_t>(signals::NEXT_VALID)
};
const signals::void_signal_t::sptr m_next_invalid {
new_signal<signals::void_signal_t>(signals::NEXT_INVALID)
};
static constexpr std::string_view ACTIVITY_SET_INOUT = "activitySet";
data::ptr<data::activity_set, data::access::inout> m_activity_set {this, ACTIVITY_SET_INOUT};
data::property<data::boolean> m_linear {this, "linear", true};
};
} // namespace sight::module::ui::qt::activity
|