/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the Qt3Support module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

/**
 * Copyright (C) 2023-2026 Linaro Limited (or its affiliates). All rights reserved.
 * Copyright (C) 2009-2023 Arm Limited (or its affiliates).
 * All rights reserved.
 */

#ifndef MDATABLE_H
#define MDATABLE_H

#include "lgpl_gui_export.h"

#include <QMap>
#include <QScrollArea>

class MDATableHeader;
class MDATable;
class QPaintEvent;
class QResizeEvent;
class QTimer;

struct MDATablePrivate;

class LGPL_GUI_EXPORT MDATableSelection
{
public:
    MDATableSelection();
    MDATableSelection(long long start_row, long long start_col, long long end_row, long long end_col);
    void init(long long row, long long col);
    void expandTo(long long row, long long col);
    bool operator==(const MDATableSelection &s) const;
    bool operator!=(const MDATableSelection &s) const { return !(operator==(s)); }

    long long topRow() const { return tRow; }
    long long bottomRow() const { return bRow; }
    long long leftCol() const { return lCol; }
    long long rightCol() const { return rCol; }
    long long anchorRow() const { return aRow; }
    long long anchorCol() const { return aCol; }
    long long numRows() const;
    long long numCols() const;

    bool isActive() const { return active; }
    bool isEmpty() const { return numRows() == 0; }
    bool isSingleElement() const { return numRows() == 1 && numCols() == 1; }

private:
    uint active : 1;
    uint inited : 1;
    long long tRow, lCol, bRow, rCol;
    long long aRow, aCol;
};

class LGPL_GUI_EXPORT MDATableItem
{
    friend class MDATable;

public:
    MDATableItem(MDATable *table);
    MDATableItem(MDATable *table, const QString &text);
    virtual ~MDATableItem() {};

    virtual QString text() const;
    virtual void setText(const QString &t);
    MDATable *table() const { return t; }

    virtual int alignment() const;

    virtual QString key() const;
    virtual QSize sizeHint() const;

    virtual void setRow(long long r);
    virtual void setCol(long long c);
    long long row() const;
    long long col() const;

    virtual void paint(QPainter *p, const QPalette &pal,
                        const QRect &cr, bool selected);

    virtual void setEnabled(bool b);
    bool isEnabled() const;

    virtual int rtti() const;
    static int RTTI;

private:
    QString txt;
    MDATable *t;
    uint enabled : 1;
    long long rw, cl;
};

class LGPL_GUI_EXPORT MDATable : public QScrollArea
{
    Q_OBJECT
    Q_ENUMS(FocusStyle)
    Q_PROPERTY(long long numRows READ numRows WRITE setNumRows)
    Q_PROPERTY(long long numCols READ numCols WRITE setNumCols)
    Q_PROPERTY(bool showGrid READ showGrid WRITE setShowGrid)
    Q_PROPERTY(FocusStyle focusStyle READ focusStyle WRITE setFocusStyle)
    Q_PROPERTY(int numSelections READ numSelections)

    friend class MDATableHeader;
    friend class MDATableItem;

public:
    MDATable(QWidget* parent=0, const char* name=0);
    MDATable(long long numRows, long long numCols,
            QWidget* parent=0, const char* name=0);
    ~MDATable();

    virtual void setItem(long long row, long long col, MDATableItem *item);
    virtual void setText(long long row, long long col, const QString &text);
    virtual MDATableItem *item(long long row, long long col) const;
    virtual QString text(long long row, long long col) const;
    virtual void clearCell(long long row, long long col);

    virtual QRect cellGeometry(long long row, long long col) const;
    virtual int columnWidth() const;
    virtual int rowHeight() const;
    virtual int columnPos(long long col) const;
    virtual int rowPos(long long row) const;
    virtual long long columnAt(int x) const;
    virtual long long rowAt(int y) const;

    virtual long long numRows() const;
    virtual long long numCols() const;

    void updateCell(long long row, long long col);

    bool eventFilter(QObject * o, QEvent *) override;

    long long currentRow() const { return curRow; }
    long long currentColumn() const { return curCol; }
    void ensureCellVisible(long long row, long long col);

    bool isSelected(long long row, long long col) const;
    bool isRowSelected(long long row, bool full = false) const;
    bool isColumnSelected(long long col, bool full = false) const;
    bool isSectionValid( long long row, long long col ) const;
    int numSelections() const;
    MDATableSelection selection(int num) const;
    virtual int addSelection(const MDATableSelection &s);
    virtual void removeSelection(const MDATableSelection &s);
    virtual void removeSelection(int num);
    virtual int currentSelection() const;
    MDATableSelection getCurrentSelection() const;

    void selectCells(long long start_row, long long start_col, long long end_row, long long end_col);
    void selectRow(long long row);
    void selectColumn(long long col);

    bool showGrid() const;

    QVariant inputMethodQuery(Qt::InputMethodQuery query) const override;

    virtual void takeItem(MDATableItem *i);

    virtual QRect cellRect(long long row, long long col) const;

    virtual void paintCell(QPainter *p, long long row, long long col,
                            const QRect &cr, bool selected);
    virtual void paintCell(QPainter *p, long long row, long long col,
                            const QRect &cr, bool selected, const QPalette::ColorGroup cg);
    virtual void paintFocus(QPainter *p, const QRect &r);
    QSize sizeHint() const override;

    bool isReadOnly() const;
    bool isRowReadOnly(long long row) const;
    bool isColumnReadOnly(long long col) const;

    void repaintSelections();

    enum FocusStyle { FollowStyle, SpreadSheet };
    virtual void setFocusStyle(FocusStyle fs);
    FocusStyle focusStyle() const;

    void setSparse(bool);
    bool isSparse() const;

    void clear();
    void clearData();
    
    void addValidRegion(const QRegion& r);

public slots:
    virtual void setNumRows(long long r);
    virtual void setNumCols(long long r);
    virtual void setShowGrid(bool b);
    virtual void hideRow(long long row);
    virtual void hideColumn(long long col);
    virtual void showRow(long long row);
    virtual void showColumn(long long col);
    virtual void hideRows(long long from, long long to);
    virtual void hideColumns(long long from, long long to);
    virtual void showRows(long long from, long long to);
    virtual void showColumns(long long from, long long to);
    bool isRowHidden(long long row) const;
    bool isColumnHidden(long long col) const;

    virtual void setColumnWidth(int w);
    virtual void setRowHeight(int h);

    virtual void adjustColumnWidth();

    virtual void setLeftMargin(int m);
    virtual void setTopMargin(int m);
    virtual void setCurrentCell(long long row, long long col);
    void clearSelection(bool repaint = true);

    virtual void setLeftHeaderLines(int numLines);
    virtual void setTopHeaderLines(int numLines);
    virtual void setLeftHeaderLineNameAndBounds(int line, const QString& name, long long min, long long max);
    virtual void setTopHeaderLineNameAndBounds(int line, const QString& name, long long min, long long max);

    void copy();

protected:
    void drawContents(QPainter *p, const QRect &rect);
    void mousePressEvent(QMouseEvent*) override;
    void mouseMoveEvent(QMouseEvent*) override;
    void mouseDoubleClickEvent(QMouseEvent*) override;
    void mouseReleaseEvent(QMouseEvent*) override;
    void contextMenuEvent(QContextMenuEvent * e) override;
    void keyPressEvent(QKeyEvent*) override;
    void focusInEvent(QFocusEvent*) override;
    void focusOutEvent(QFocusEvent*) override;
    void resizeEvent(QResizeEvent *) override;
    void showEvent(QShowEvent *e) override;
    void changeEvent(QEvent *event) override;
    void paintEvent(QPaintEvent *e) override;

    virtual void paintEmptyArea(QPainter *p, int cx, int cy, int cw, int ch);
    virtual void activateNextCell();

    virtual void resizeData(long long len);
    long long indexOf(long long row, long long col) const;

    virtual void updateGeometries();

protected slots:
    virtual void columnWidthChanged();
    virtual void rowHeightChanged();
    void leftHeaderFixedExtentChanged(int s);
    void topHeaderFixedExtentChanged(int s);

signals:
    void currentChanged(long long row, long long col);
    void clicked(long long row, long long col, int button, const QPoint &mousePos);
    void doubleClicked(long long row, long long col, int button, const QPoint &mousePos);
    void pressed(long long row, long long col, int button, const QPoint &mousePos);
    void selectionChanged();
    void valueChanged(long long row, long long col);
    void contextMenuRequested(long long row, long long col, const QPoint &pos);

private slots:
    void doAutoScroll();
    void updateGeometriesSlot();

private:
    void mousePressEventEx(QMouseEvent*);
    void repaintSelections(MDATableSelection *oldSelection,
                            MDATableSelection *newSelection,
                            bool updateVertical = true,
                            bool updateHorizontal = true);
    QRect rangeGeometry(long long topRow,long long leftCol,
                         long long bottomRow, long long rightCol, bool &optimize);
    void fixRow(long long &row, int y);
    void fixCol(long long &col, int x);

    void init(long long numRows, long long numCols);
    QSize tableSize() const;
    void repaintCell(long long row, long long col);
    void updateScrollBars();

    bool isSelected(long long row, long long col, bool includeCurrent) const;
    void setCurrentCell(long long row, long long col, bool updateSelections, bool ensureVisible = false);
    void fixCell(long long &row, long long &col, int key);
    void delayedUpdateGeometries();
    void saveContents(QVector<MDATableItem*> &tmp);
    void updateHeaderAndResizeContents(MDATableHeader *header,
					long long num, long long colRow,
					int width, bool &updateBefore);
    void restoreContents(QVector<MDATableItem*> &tmp);
    void finishContentsResze(bool updateBefore);

private:
    QVector<MDATableItem*> contents;
    long long curRow;
    long long curCol;
    MDATableHeader *leftHeader, *topHeader;
    QList<MDATableSelection*> selections;
    MDATableSelection *currentSel;
    QTimer *autoScrollTimer;
    long long lastSortCol;
    bool sGrid : 1;
    bool mRows : 1;
    bool mCols : 1;
    bool asc : 1;
    bool doSort : 1;
    bool shouldClearSelection : 1;
    bool dEnabled : 1;
    bool context_menu : 1;
    bool drawActiveSelection : 1;
    bool was_visible : 1;
    long long pressedRow, pressedCol;
    MDATablePrivate *d;
    long long oldCurrentRow, oldCurrentCol;
    FocusStyle focusStl;
    int maxColWidth;
    QMap<long long, MDATableItem *> sparseContents;
    bool sparse;
    QRegion validRegion;
    QMargins viewportMargins;

#if defined(Q_DISABLE_COPY)
    MDATable(const MDATable &);
    MDATable &operator=(const MDATable &);
#endif
};

#endif // MDATABLE_H

