/*
    SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
    SPDX-FileCopyrightText: 2011 Artur Duque de Souza <asouza@kde.org>
    SPDX-FileCopyrightText: 2013 Sebastian Kügler <sebas@kde.org>

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

#ifndef TOOLTIPOBJECT_H
#define TOOLTIPOBJECT_H

#include <Plasma/Plasma>

#include <QPointer>
#include <QQuickItem>
#include <QTimer>
#include <QVariant>

#include <KConfigWatcher>

class QQuickItem;
class ToolTipDialog;

/*!
 * \qmltype ToolTipArea
 * \inqmlmodule org.kde.plasma.core
 * \inherits Item
 *
 * \brief An Item managing a Plasma-themed tooltip.
 *
 * It is rendered in its own window.
 * You can either specify icon, mainText and subText, or a custom Component
 * that will be put inside the tooltip. By default the tooltip will be
 * rendered when hovering over the parent item.
 *
 * The item inside the ToolTipArea is loaded on demand and will be destroyed when the
 * tooltip is being hidden.
 *
 * Example usage:
 * \qml
 * import org.kde.plasma.core as PlasmaCore
 * import org.kde.kirigami 2.20 as Kirigami
 *
 * Kirigami.Icon {
 *     PlasmaCore.ToolTipArea {
 *         mainText: i18n("Tooltip Title")
 *         subText: i18n("Some explanation.")
 *         icon: "plasma"
 *         // alternatively, you can specify your own component
 *         // to be loaded when the tooltip shows
 *         mainItem: YourCustomItem { }
 *     }
 * }
 * \endqml
 */
class ToolTipArea : public QQuickItem
{
    Q_OBJECT
    QML_ELEMENT

    /*!
     * \qmlproperty Item ToolTipArea::mainItem
     * The item shown inside the tooltip.
     */
    Q_PROPERTY(QQuickItem *mainItem READ mainItem WRITE setMainItem NOTIFY mainItemChanged)

    /*!
     * \qmlproperty string ToolTipArea::mainText
     * The main text of this tooltip
     */
    Q_PROPERTY(QString mainText READ mainText WRITE setMainText NOTIFY mainTextChanged)

    /*!
     * \qmlproperty string ToolTipArea::subText
     * The description of this tooltip
     */
    Q_PROPERTY(QString subText READ subText WRITE setSubText NOTIFY subTextChanged)

    /*!
     * \qmlproperty enumeration ToolTipArea::textFormat
     * How to handle the text format of the tooltip subtext:
     * \list
     * \li Text.AutoText (default)
     * \li Text.PlainText
     * \li Text.StyledText
     * \li Text.RichText
     * \endlist
     * \note in the default implementation the main text is always plain text
     */
    Q_PROPERTY(int textFormat READ textFormat WRITE setTextFormat NOTIFY textFormatChanged)

    /*!
     * \qmlproperty var ToolTipArea::icon
     * An icon for this tooltip, accepted values are an icon name, a QIcon, QImage or QPixmap
     */
    Q_PROPERTY(QVariant icon READ icon WRITE setIcon NOTIFY iconChanged)

    /*!
     * \qmlproperty bool ToolTipArea::containsMouse
     * Returns whether the mouse is inside the item
     */
    Q_PROPERTY(bool containsMouse READ containsMouse NOTIFY containsMouseChanged)

    /*!
     * \qmlproperty Plasma::Types::Location ToolTipArea::location
     * Plasma Location of the dialog window. Useful if this dialog is a popup for a panel
     */
    Q_PROPERTY(Plasma::Types::Location location READ location WRITE setLocation NOTIFY locationChanged)

    /*!
     * \qmlproperty var ToolTipArea::image
     * TODO: single property for images?
     * An image for this tooltip, accepted values are an icon name, a QIcon, QImage or QPixmap
     */
    Q_PROPERTY(QVariant image READ image WRITE setImage NOTIFY imageChanged)

    /*!
     * \qmlproperty bool ToolTipArea::active
     * Property that controls if a tooltips will show on mouse over.
     * The default is true.
     */
    Q_PROPERTY(bool active MEMBER m_active WRITE setActive NOTIFY activeChanged)

    /*!
     * \qmlproperty bool ToolTipArea::interactive
     * If interactive is false (default), the tooltip will automatically hide
     * itself as soon as the mouse leaves the tooltiparea, if is true, if the
     * mouse leaves tooltiparea and goes over the tooltip itself, the tooltip
     * won't hide, so it will be possible to interact with tooltip contents.
     */
    Q_PROPERTY(bool interactive MEMBER m_interactive WRITE setInteractive NOTIFY interactiveChanged)

    /*!
     * \qmlproperty int ToolTipArea::timeout
     * Timeout in milliseconds after which the tooltip will hide itself.
     * Set this value to -1 to never hide the tooltip automatically.
     */
    Q_PROPERTY(int timeout MEMBER m_timeout WRITE setTimeout)

public:
    explicit ToolTipArea(QQuickItem *parent = nullptr);
    ~ToolTipArea() override;

    QQuickItem *mainItem() const;
    void setMainItem(QQuickItem *mainItem);

    QString mainText() const;
    void setMainText(const QString &mainText);

    QString subText() const;
    void setSubText(const QString &subText);

    int textFormat() const;
    void setTextFormat(int format);

    QVariant icon() const;
    void setIcon(const QVariant &icon);

    QVariant image() const;
    void setImage(const QVariant &image);

    Plasma::Types::Location location() const;
    void setLocation(Plasma::Types::Location location);

    bool containsMouse() const;
    void setContainsMouse(bool contains);

    void setActive(bool active);

    void setInteractive(bool interactive);

    void setTimeout(int timeout);

public Q_SLOTS:

    /*!
     * \qmlmethod void ToolTipArea::showToolTip
     * Shows the tooltip.
     * \since 5.73
     */
    void showToolTip();

    /*!
     * \qmlmethod void ToolTipArea::hideToolTip
     *
     * Hides the tooltip after a grace period if shown. Does not affect whether the tooltip area is active.
     */
    void hideToolTip();

    /*!
     * \qmlmethod void ToolTipArea::hideImmediately
     *
     * Hides the tooltip immediately, in comparison to hideToolTip.
     * \since 5.84
     */
    void hideImmediately();

protected:
    bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
    void hoverEnterEvent(QHoverEvent *event) override;
    void hoverLeaveEvent(QHoverEvent *event) override;

    ToolTipDialog *tooltipDialogInstance();

Q_SIGNALS:
    void mainItemChanged();
    void mainTextChanged();
    void subTextChanged();
    void textFormatChanged();
    void iconChanged();
    void imageChanged();
    void containsMouseChanged();
    void locationChanged();
    void activeChanged();
    void interactiveChanged();
    /*!
     * \qmlsignal ToolTipArea::aboutToShow
     *
     * Emitted just before the tooltip dialog is shown.
     *
     * \since 5.45
     */
    void aboutToShow();
    /*!
     * \qmlsignal ToolTipArea::toolTipVisibleChanged(bool toolTipVisible)
     *
     * Emitted when the tooltip's visibility changes.
     *
     * \since 5.88
     */
    void toolTipVisibleChanged(bool toolTipVisible);

private Q_SLOTS:
    void settingsChanged(const KConfigGroup &group, const QByteArrayList &names);

private:
    bool isValid() const;

    void loadSettings(const KConfigGroup &cfg);
    bool m_tooltipsEnabledGlobally;
    bool m_containsMouse;
    Plasma::Types::Location m_location;
    QPointer<QQuickItem> m_mainItem;
    QTimer m_showTimer;
    QString m_mainText;
    QString m_subText;
    int m_textFormat;
    QVariant m_image;
    QVariant m_icon;
    bool m_active;
    bool m_interactive;
    int m_interval;
    int m_timeout;

    // ToolTipDialog is not a Q_GLOBAL_STATIC because QQuickwindows as global static
    // are deleted too late after some stuff in the qml runtime has already been deleted,
    // causing a crash on exit
    bool m_usingDialog : 1;
    static ToolTipDialog *s_dialog;
    static int s_dialogUsers;

    KConfigWatcher::Ptr m_plasmarcWatcher;
};

#endif
