/* This file is part of the KDE project

   SPDX-FileCopyrightText: 2006 Boudewijn Rempt <boud@valdyas.org>
   SPDX-FileCopyrightText: 2006 Thorsten Zachmann <zachmann@kde.org>
   SPDX-FileCopyrightText: 2007, 2009 Thomas Zander <zander@kde.org>
   SPDX-FileCopyrightText: 2006, 2007 Jan Hambrecht <jaham@gmx.net>

   SPDX-License-Identifier: LGPL-2.0-or-later
*/

#ifndef KOSELECTION_H
#define KOSELECTION_H

#include <QObject>

#include "KoShape.h"
#include "KoFlake.h"

#include "kritaflake_export.h"

class KoShapeLayer;
class KoSelectionPrivate;

/**
 * A selection is a shape that contains a number of references
 * to shapes. That means that a selection can be manipulated in
 * the same way as a single shape.
 *
 * Note that a single shape can be selected in one view, and not in
 * another, and that in a single view, more than one selection can be
 * present. So selections should not be seen as singletons, or as
 * something completely transient.
 *
 * A selection, however, should not be selectable. We need to think
 * a little about the interaction here.
 */
class KRITAFLAKE_EXPORT KoSelection : public QObject, public KoShape, public KoShape::ShapeChangeListener
{
    Q_OBJECT

public:

    KoSelection(QObject *parent = 0);
    ~KoSelection() override;

    void paint(QPainter &painter, KoShapePaintingContext &paintcontext) const override;
    void setSize(const QSizeF &size) override;
    QSizeF size() const override;
    QRectF outlineRect() const override;
    QRectF boundingRect() const override;

    /**
     * Adds a shape to the selection.
     *
     * If the shape is a KoShapeGroup all of its child shapes are automatically added
     * to the selection.
     * If the shape has no parent or is not a KoShapeGroup, only the given shape is
     * added to the selection.
     * If the given shape is a child of a KoShapeGroup and recursive selection is enabled
     * the all parents and their child shapes up to the toplevel KoShapeGroup are added to
     * the selection.
     *
     * @param shape the shape to add to the selection
     */
    void select(KoShape *shape);

    /**
     * Removes a selected shape.
     *
     * If the shape is a KoShapeGroup all of its child shapes are automatically removed
     * from the selection.
     * If the shape has no parent or is not a KoShapeGroup, only the given shape is
     * removed from the selection.
     * If the given shape is a child of a KoShapeGroup and recursive selection is enabled
     * the all parents and their child shape up to the toplevel KoShapeGroup are removed
     * from the selection.
     *
     * @param shape the shape to remove from the selection
     */
    void deselect(KoShape *shape);

    /// clear the selections list
    void deselectAll();

    /**
     * Return the list of selected shapes
     * @return the list of selected shapes
     */
    const QList<KoShape*> selectedShapes() const;

    /**
     * Same as selectedShapes() but only for shapes in visible state. Used by
     * the algorithms that draw shapes on the image
     */
    const QList<KoShape*> selectedVisibleShapes() const;

    /**
     * Same as selectedShapes() but only for editable shapes. Used by
     * the algorithms that modify the image
     */
    const QList<KoShape*> selectedEditableShapes() const;

    /**
     * Same as selectedEditableShapes() but also includes shapes delegates.
     * Used for
     */
    const QList<KoShape*> selectedEditableShapesAndDelegates() const;

    /**
     * Return the first selected shape, or 0 if there is nothing selected.
     */
    KoShape *firstSelectedShape() const;

    /// return true if the shape is selected
    bool isSelected(const KoShape *shape) const;

    /// return the selection count, i.e. the number of all selected shapes
    int count() const;

    bool hitTest(const QPointF &position) const override;

    /**
     * Sets the currently active layer.
     * @param layer the new active layer
     */
    void setActiveLayer(KoShapeLayer *layer);

    /**
     * Returns a currently active layer.
     *
     * @return the currently active layer, or zero if there is none
     */
    KoShapeLayer *activeLayer() const;

    void notifyShapeChanged(ChangeType type, KoShape *shape) override;

Q_SIGNALS:
    /// emitted when the selection is changed
    void selectionChanged();

    /// emitted when the current layer is changed
    void currentLayerChanged(const KoShapeLayer *layer);

protected:
    KoSelection(const KoSelection &rhs);

private:
    class Private;
    QSharedDataPointer<Private> d;
};

#endif
