qgseditorwidgetwrapper.h 13.2 KB
Newer Older
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 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
/***************************************************************************
    qgseditorwidgetwrapper.h
     --------------------------------------
    Date                 : 20.4.2013
    Copyright            : (C) 2013 Matthias Kuhn
    Email                : matthias at opengis dot ch
 ***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef QGSEDITORWIDGETWRAPPER_H
#define QGSEDITORWIDGETWRAPPER_H

#include <QObject>
#include "qgis_sip.h"
#include <QMap>
#include <QVariant>

class QgsVectorLayer;
class QgsField;

#include "qgswidgetwrapper.h"
#include "qgis_gui.h"
#include "qgis_sip.h"

/**
 * \ingroup gui
 * Manages an editor widget
 * Widget and wrapper share the same parent
 *
 * A wrapper controls one attribute editor widget and is able to create a default
 * widget or use a pre-existent widget. It is able to set the widget to the value implied
 * by a field of a vector layer, or return the value it currently holds. Every time it is changed
 * it has to emit a valueChanged signal. If it fails to do so, there is no guarantee that the
 * changed status of the widget will be saved.
 *
 * It can also handle additional fields of a vector layer and would set the widget
 * for their corresponding values and emit valuesChanged signal.
 *
 */
class GUI_EXPORT QgsEditorWidgetWrapper : public QgsWidgetWrapper
{
    Q_OBJECT

    Q_PROPERTY( bool constraintResultVisible READ constraintResultVisible WRITE setConstraintResultVisible NOTIFY constraintResultVisibleChanged )
    Q_PROPERTY( ConstraintResult constraintResult READ constraintResult NOTIFY constraintStatusChanged )

  public:

    /**
     * Result of constraint checks.
     * \since QGIS 3.0
     */
    enum ConstraintResult
    {
      ConstraintResultPass = 0, //!< Widget passed constraints successfully
      ConstraintResultFailHard, //!< Widget failed at least one hard (enforced) constraint
      ConstraintResultFailSoft, //!< Widget failed at least one soft (non-enforced) constraint
    };

    /**
     * Create a new widget wrapper
     *
     * \param vl        The layer on which the field is
     * \param fieldIdx  The field which will be controlled
     * \param editor    An editor widget. Can be NULLPTR if one should be autogenerated.
     * \param parent    A parent widget for this widget wrapper and the created widget.
     */
    explicit QgsEditorWidgetWrapper( QgsVectorLayer *vl, int fieldIdx, QWidget *editor = nullptr, QWidget *parent SIP_TRANSFERTHIS = nullptr );

    /**
     * Will be used to access the widget's value. Read the value from the widget and
     * return it properly formatted to be saved in the attribute.
     *
     * If an invalid variant is returned this will be interpreted as no change.
     * Be sure to return a NULL QVariant if it should be set to NULL.
     *
     * \returns The current value the widget represents
     */
    virtual QVariant value() const = 0;

    /**
     * Returns the list of additional fields which the editor handles
     * \since QGIS 3.10
     */
    virtual QStringList additionalFields() const {return QStringList();}

    /**
     * Will be used to access the widget's values for potential additional fields handled by the widget
     * \returns A map of additional field names with their corresponding values
     * \see additionalFields
     * \since QGIS 3.10
     */
    virtual QVariantList additionalFieldValues() const {return QVariantList();}

    /**
     * Access the field index.
     *
     * \returns The index of the field you are working on
     *
     * \see layer()
     */
    int fieldIdx() const;

    /**
     * Access the field.
     *
     * \returns The field you are working on
     *
     * \see layer()
     */
    QgsField field() const;

    /**
     * Access the default value of the field.
     *
     * \returns the default value of the field
     *
     * \see layer()
     */
    QVariant defaultValue() const;

    /**
     * Will return a wrapper for a given widget
     * \param widget The widget which was created by a wrapper
     * \returns The wrapper for the widget or NULLPTR
     */
    static QgsEditorWidgetWrapper *fromWidget( QWidget *widget );

    /**
     * Check if the given widget or one of its parent is a QTableView.
     * \param parent the widget to check
     * \returns TRUE if yes
     */
    static bool isInTable( const QWidget *parent );

    /**
     * Is used to enable or disable the edit functionality of the managed widget.
     * By default this will enable or disable the whole widget
     *
     * \param enabled  Enable or Disable?
     */
    void setEnabled( bool enabled ) override;

    /**
     * Sets the widget to display in an indeterminate "mixed value" state.
     * \since QGIS 2.16
     */
    virtual void showIndeterminateState() {}

    /**
     * Update constraint.
     * \param featureContext the feature to use to evaluate the constraint
     * \param constraintOrigin optional origin for constraints to check. This can be used to limit the constraints tested
     * to only provider or layer based constraints.
     * \since QGIS 2.16
     */
    void updateConstraint( const QgsFeature &featureContext, QgsFieldConstraints::ConstraintOrigin constraintOrigin = QgsFieldConstraints::ConstraintOriginNotSet );

    /**
     * Update constraint on a feature coming from a specific layer.
     * \param layer The vector layer where the feature is defined
     * \param index The index of the field to check
     * \param feature The feature to use to evaluate the constraint
     * \param constraintOrigin Optional origin for constraints to check. This
     * can be used to limit the constraints tested to only provider or layer
     * based constraints.
     * \since QGIS 3.0
     */
    void updateConstraint( const QgsVectorLayer *layer, int index, const QgsFeature &feature, QgsFieldConstraints::ConstraintOrigin constraintOrigin = QgsFieldConstraints::ConstraintOriginNotSet );

    /**
     * Gets the current constraint status.
     * \returns TRUE if the constraint is valid or if there's no constraint,
     * FALSE otherwise
     * \see constraintFailureReason()
     * \see isBlockingCommit()
     * \since QGIS 2.16
     */
    bool isValidConstraint() const;

    /**
     * Returns true if the widget is preventing the feature from being committed. This may be TRUE as a result
     * of attribute values failing enforced field constraints.
     * \see isValidConstraint()
     * \since QGIS 3.0
     */
    bool isBlockingCommit() const;

    /**
     * Returns the reason why a constraint check has failed (or an empty string
     * if constraint check was successful).
     * \see isValidConstraint()
     * \since QGIS 3.0
     */
    QString constraintFailureReason() const;

    /**
     * Add a hint text on the widget
     * \param hintText The hint text to display
     * \since QGIS 3.0
     */
    virtual void setHint( const QString &hintText );

    /**
     * Returns the constraint result, which is the current result of the constraint
     * on the widget influencing its visualization.
     *
     * \since QGIS 3.0
     */
    ConstraintResult constraintResult() const;

    /**
     * Returns whether the constraint result is visible.
     *
     * Returns TRUE if the constraint result will be visualized on the widget (with color).
     * This will be disabled when the form is not editable.
     *
     * \since QGIS 3.0
     */
    bool constraintResultVisible() const;

    /**
     * Sets whether the constraint result is visible.
     *
     * Controls if the constraint result should be visualized on the widget (with color).
     * This will be disabled when the form is not editable.
     *
     * \param constraintResultVisible if constraintResult should be displayed (mostly editable status)
     * \since QGIS 3.0
     */
    void setConstraintResultVisible( bool constraintResultVisible );

  signals:

    /**
     * Emit this signal, whenever the value changed.
     *
     * \param value The new value
     * \deprecated since QGIS 3.10 use valuesChanged signal instead
     */
    Q_DECL_DEPRECATED void valueChanged( const QVariant &value );

    /**
     * Emit this signal, whenever the value changed.
     * It will also return the values for the additional fields handled by the widget
     *
     * \param value The new value
     * \param additionalFieldValues A map of additional field names with their corresponding values
     * \since QGIS 3.10
     */
    void valuesChanged( const QVariant &value, const QVariantList &additionalFieldValues = QVariantList() );

    /**
     * Emit this signal when the constraint status changed.
     * \brief constraintStatusChanged
     * \param constraint represented as a string
     * \param desc is the constraint description
     * \param err the error represented as a string. Empty if none.
     * \param status
     */
    void constraintStatusChanged( const QString &constraint, const QString &desc, const QString &err, QgsEditorWidgetWrapper::ConstraintResult status );

    /**
     * Emit this signal when the constraint result visibility changed.
     */
    void constraintResultVisibleChanged( bool visible );

  public slots:

    /**
     * Will be called when the feature changes
     *
     * Is forwarded to the slot setValues()
     *
     * \param feature The new feature
     */
    void setFeature( const QgsFeature &feature ) override;

    /**
     * Is called, when the value of the widget needs to be changed. Update the widget representation
     * to reflect the new value.
     *
     * \param value The new value of the attribute
     * \deprecated since QGIS 3.10
     */
    // TODO Q_DECL_DEPRECATED
    virtual void setValue( const QVariant &value ) SIP_DEPRECATED;

    /**
     * Is called, when the value of the widget or additional field values
     * needs to be changed. Update the widget representation
     * to reflect the new values.
     * \since QGIS 3.10
     */
    void setValues( const QVariant &value, const QVariantList &additionalValues );

    /**
     * Will call the value() method to determine the emitted value
     */
    void emitValueChanged();

  protected:

    /**
     * This should update the widget with a visual cue if a constraint status
     * changed.
     *
     * By default a stylesheet will be applied on the widget that changes the
     * background color to red.
     *
     * This can be overwritten in subclasses to allow individual widgets to
     * change the visual cue.
     *
     * \since QGIS 2.16
     */
    virtual void updateConstraintWidgetStatus();


    /**
     * The feature currently being edited, in its current state
     *
     * \return the feature currently being edited, in its current state
     * \since QGIS 3.2
     */
    QgsFeature formFeature() const { return mFormFeature; }

    /**
     * Set the feature currently being edited to \a feature
     *
     * \since QGIS 3.2
     */
    void setFormFeature( const QgsFeature &feature ) { mFormFeature = feature; }

    /**
     * Update the feature currently being edited by changing its
     * attribute \a attributeName to \a attributeValue
     *
     * \return bool TRUE on success
     * \since QGIS 3.2
     */
    bool setFormFeatureAttribute( const QString &attributeName, const QVariant &attributeValue );


  private:

    /**
    * Is called, when the value of the widget needs to be changed. Update the widget representation
    * to reflect the new value.
    *
    * \param value The new value of the attribute
    * \param additionalValues The values of potential additional fields
    * \note Will be pure virtual in QGIS 4.x
    * \since QGIS 3.10
    */
    virtual void updateValues( const QVariant &value, const QVariantList &additionalValues = QVariantList() ); //TODO QGIS 4: make it pure virtual

    // TODO QGIS 4: remove
    bool isRunningDeprecatedSetValue = false;

    /**
     * mFieldIdx the widget feature field id
     */
    int mFieldIdx = -1;

    QList<int> mAdditionalFieldIndexes;

    /**
     * The feature currently being edited, in its current state
     */
    QgsFeature mFormFeature;

    /**
     * Boolean storing the current validity of the constraint for this widget.
     */
    bool mValidConstraint;

    //! True if widget is blocking feature commits
    bool mIsBlockingCommit;

    //! Contains the string explanation of why a constraint check failed
    QString mConstraintFailureReason;

    //! The current constraint result
    ConstraintResult mConstraintResult = ConstraintResultPass;

    //! The current constraint result
    bool mConstraintResultVisible = false;

    mutable QVariant mDefaultValue; // Cache default value, we don't want to retrieve different serial numbers if called repeatedly

};

// We'll use this class inside a QVariant in the widgets properties
Q_DECLARE_METATYPE( QgsEditorWidgetWrapper * )

#endif // QGSEDITORWIDGETWRAPPER_H