#include <QResizeEvent>
#include <QStandardItemModel>
#include <QHeaderView>
#include <QScrollBar>

#include "QFitsWidgetTable.h"
#include "QFitsCubeSpectrum.h"
#include "qtdpuser.h"
#include "QFitsGlobal.h"
#include "QFitsViewingTools.h"
#include "QFitsSingleBuffer.h"
#include "QFitsMainView.h"
#include "QFitsMainWindow.h"
#include "QFitsWidget2D.h"
#include "fits.h"

// //////////////////////////////////////////////////////////////////////////
// class QFitsWidgetTable
// //////////////////////////////////////////////////////////////////////////
QFitsWidgetTable::QFitsWidgetTable(QFitsBaseBuffer *bb) : QFitsBaseWidget(bb)
{
    // needed for the bloody QFitsMultiTableModel/GRAVITY/FITS-recursion
    myBaseBuffer = bb;
    tableView    = new QFitsTableView(this);
    tableView->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    tableView->setMouseTracking(true);
    // disable multiple selection
    tableView->setSelectionMode(QAbstractItemView::ContiguousSelection);

//#ifndef Q_OS_MACX   how does Windows behave?
#ifdef Q_OS_LINUX
    // example:
    //    QString styleSheet = "::section {" // "QHeaderView::section {"
    //    "spacing: 10px;"
    //    "background-color: lightblue;"
    //    "color: white;"
    //    "border: 1px solid red;"
    //    "margin: 1px;"
    //    "text-align: right;"
    //    "font-family: arial;"
    //    "font-size: 12px; }";

    // example with gradient:
    //    background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,
    //                                      stop:0 #616161, stop: 0.5 #505050,
    //                                      stop: 0.6 #434343, stop:1 #656565);

    QString styleSheet = "::section:checked { background-color: lightblue; } ";
    tableView->horizontalHeader()->setStyleSheet(styleSheet);
    tableView->verticalHeader()->setStyleSheet(styleSheet);
#endif

    QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(myBaseBuffer);
    QFitsMultiBuffer *mb = dynamic_cast<QFitsMultiBuffer*>(myBaseBuffer);
    if (sb != NULL) {
        tableModel = new QFitsTableModel(this, this);
    } else if (mb != NULL) {
        QFitsTableModelMulti *tmm = new QFitsTableModelMulti(this, this);
        tableModel = tmm;
    } else {
        return;
    }

    tableView->setModel(tableModel);
    tableModel->setDpData(myBaseBuffer->getDpData());
    dummyView = new QFitsDummyMarkedView(this);

//    connect(tableView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
//            tableView, SLOT(unsetSpectrum(const QItemSelection &, const QItemSelection &)));
}

QFitsWidgetTable::~QFitsWidgetTable() {
    if (tableView != NULL) {
        delete tableView; tableView = NULL;
    }
    if (dummyView != NULL) {
        delete dummyView; dummyView = NULL;
    }
}

void QFitsWidgetTable::init(dpuserType *dpt) {
    tableModel->setDpData(dpt);
}

void QFitsWidgetTable::copyImage(int) {
    tableView->copySelectionToClipboard();
}

void QFitsWidgetTable::resizeColumns() {
    // these commands are very slow... implement manually should get faster.
    // (e.g. search max/min value, calculate string length, set column width accordingly)
    if ((tableView != NULL) && (tableView->isVisible())) {
        tableView->setVisible(false);
        tableView->resizeColumnsToContents();
        tableView->setVisible(true);
    }
}

QFitsSingleBuffer* QFitsWidgetTable::getSBunderMouse(int column) {
    QFitsSingleBuffer *sb = NULL;
    QFitsTableModelMulti *tmm = dynamic_cast<QFitsTableModelMulti*>(tableModel);
    if (tmm == NULL) {
        // dpuserType
        sb = getMyBuffer();
    } else {
        // dpuserTypeList
        int dpIndex = tmm->translateColumnNumber(&column);
        QFitsMultiBuffer *mb = dynamic_cast<QFitsMultiBuffer*>(myBaseBuffer);
        if (mb != NULL) {
            sb = mb->getSB(dpIndex);
        } else {
            sb = NULL;
        }
    }
    return sb;
}

void QFitsWidgetTable::activateSBunderMouse(int column) {
    fitsMainWindow->setActualSB(getSBunderMouse(column));
}

void QFitsWidgetTable::resizeEvent(QResizeEvent *e) {
    // make table using whole viewer area
    tableView->setGeometry(0, 0, e->size().width(), e->size().height());

    if (tableView->isVisible()) {
        tableView->calcScrollContinuum();
    }
}

void QFitsWidgetTable::setXRange(const double &min, const double &max)  {
    fitsMainWindow->spectrum->getPlotter()->setXRange(min, max);
}

QFitsBaseView* QFitsWidgetTable::getView() {
    return dummyView;
}

void QFitsWidgetTable::restoreState() {
    tableView->restoreState();
}

void QFitsWidgetTable::getVisibleRangeVertical(int *top, int *bottom) {
    *top    = tableView->indexAt(rect().topLeft()).row() + 1;
    *bottom = tableView->indexAt(rect().bottomLeft()).row();
    if (*bottom == -1) {
        *bottom = tableModel->rowCount(0);
    }
}

void QFitsWidgetTable::getVisibleRangeHorizontal(int *left, int *right) {
    *left  = tableView->indexAt(rect().topLeft()).column() + 1;
    *right = tableView->indexAt(rect().topRight()).column();
    if (*right == -1) {
        *right = tableModel->columnCount(0);
    }
}

void QFitsWidgetTable::setBruteRange(int min, int max) {
    tableView->setBruteRange(min, max);
}

// //////////////////////////////////////////////////////////////////////////
// class QFitsTableModel
// //////////////////////////////////////////////////////////////////////////
QFitsTableModel::QFitsTableModel(QObject *parent, QFitsWidgetTable *table)
    : QAbstractTableModel(parent)
{
    modelDpuserType = NULL;
    myParent = table;
}

// triggers updating of new contents in the table
void QFitsTableModel::setDpData(dpuserType *dpt) {
    fitsMainWindow->spectrum->hide();
    beginResetModel();
    modelDpuserType = dpt;
    endResetModel();
    myParent->resizeColumns();
}

Fits* QFitsTableModel::createPlotData(int section, QFV::Orientation orientation) {
    return extractPlotData(modelDpuserType, section, orientation);
}

int QFitsTableModel::rowCount(int) const {
    QModelIndex dummy;
    return rowCount(dummy);
}

int QFitsTableModel::columnCount(int) const {
    QModelIndex dummy;
    return columnCount(dummy);
}

Fits* QFitsTableModel::extractPlotData(dpuserType *dpt, int section, QFV::Orientation orientation) {
    Fits *ret = NULL;
    if (dpt->type == typeFits) {
        ret = new Fits;
        if (dpt->fvalue->Naxis(0) == 1) {
            if (orientation == QFV::Vertical) {
                ret->copy(*(dpt->fvalue));
            } else {
                ret->create(1, 1, R8);
                switch (dpt->fvalue->membits) {
                    case I1:
                    case I2:
                    case I4:
                    case I8:
                    case R4:
                    case R8:
                        ret->r8data[0] = dpt->fvalue->ValueAt(section);
                        break;
                    case C16:
                        ret->r8data[0] = (double)(dpt->fvalue->cdata[section].r);
                        break;
                    default: break;
                }
            }
        } else {
            if (orientation == QFV::Vertical) {
                dpt->fvalue->extractRange(*ret, section+1, section+1,
                                          1, rowCount(), -1, -1);
            } else {
                dpt->fvalue->extractRange(*ret, 1, dpt->fvalue->Naxis(1),
                                          section+1, section+1, -1, -1);
            }
        }
    }
    return ret;
}

QString QFitsTableModel::newBufferString(int xMin, int xMax, int yMin, int yMax) {
    std::string bufferIndex = fitsMainWindow->getCurrentBufferIndex();
    QString cmd = freeBufferName().c_str();
    cmd += " = ";
    cmd += bufferIndex.c_str();
    cmd += "[";

    xMin++;
    xMax++;
    yMin++;
    yMax++;
    if (modelDpuserType->type == typeFits) {
        QString indexStr;
        QFitsSingleBuffer *sb = myParent->getMyBuffer();
        switch (sb->Naxis(0)) {
        case 1:
            indexStr = QString::number(yMin) + ":" + QString::number(yMax);
            break;
        case 2:
            indexStr = QString::number(xMin) + ":" + QString::number(xMax) + "," +
                       QString::number(yMin) + ":" + QString::number(yMax);
            break;
        case 3:
            indexStr = QString::number(xMin) + ":" + QString::number(xMax) + "," +
                       QString::number(yMin) + ":" + QString::number(yMax) + "," +
                       QString::number((int)sb->getCubeCenter(QFV::Wavelength) + 0.5);
            break;
        default:
            break;
        }
        cmd += indexStr + "]";

        // not needed, since dpuser notifies widget of changes
        // emit dataChanged(index, index);
    } else if (modelDpuserType->type == typeStrarr) {
        // create command to change data value in fits
        cmd += QString::number(yMin) + ":" + QString::number(yMax) + "]";
    }
    return cmd;
}

// needed when subclassing QAbstractTableModel!
// calculates the number of needed columns to display the whole table
int QFitsTableModel::columnCount(const QModelIndex &) const {
    int cols = 0;
    if (modelDpuserType != NULL) {
        if (!modelDpuserType->showAsTable()) {
            // is a FITS and not a BINTABLE, but display anyway since we are nice guys...
            switch (modelDpuserType->fvalue->Naxis(0)) {
            case 1:
                cols = 1;
                break;
            case 2:
            case 3:
                cols = modelDpuserType->fvalue->Naxis(1);
                break;
            default:
                break;
            }
        } else {
            // is a BINTABLE kind of Fits or a strarr
            if (modelDpuserType->type == typeFits) {
                if ((modelDpuserType->fvalue->Naxis(0)) == 1) {
                    // 1D
                    cols = 1;
                } else {
                    // 2D
                    cols = modelDpuserType->fvalue->Naxis(1);
                }
            } else if (modelDpuserType->type == typeStrarr) {
                cols = 1;
            }
        }
    }
    return cols;
}

// needed when subclassing QAbstractTableModel!
// calculates the number of needed rows to display the whole table
int QFitsTableModel::rowCount(const QModelIndex &) const {
    int rows = 0;
    if (modelDpuserType != NULL) {
        if (!modelDpuserType->showAsTable()) {
            // is a FITS and not a BINTABLE, but display anyway since we are nice guys...
            switch (modelDpuserType->fvalue->Naxis(0)) {
            case 1:
                rows = modelDpuserType->fvalue->Naxis(1);
                break;
            case 2:
            case 3:
                rows = modelDpuserType->fvalue->Naxis(2);
                break;
            default:
                break;
            }
        } else {
            // is a BINTABLE kind of Fits or a strarr
            if (modelDpuserType->type == typeFits) {
                if ((modelDpuserType->fvalue->Naxis(0)) == 1) {
                    // 1D
                    rows = modelDpuserType->fvalue->Naxis(1);
                } else {
                    // 2D
                    rows = modelDpuserType->fvalue->Naxis(2);
                }
            } else if (modelDpuserType->type == typeStrarr) {
                rows = modelDpuserType->arrvalue->size();
            }
        }
    }
    return rows;
}

// get actual value from table (for displaying)
QVariant QFitsTableModel::data(const QModelIndex &index, int role) const {
    if (!index.isValid()) {
        return QVariant();
    }

    if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) {
        QVariant tmp = dataFromDpuserType(modelDpuserType, index.row(), index.column());
        if (role == Qt::EditRole) {
            // display selected text highlighted. Convert therefore to string, otherwise there are
            // scroll buttons in the edited cell...
            tmp = tmp.toString();
        }
        return tmp;
    }

    return QVariant();
}

// set value into table when edited
bool QFitsTableModel::setData(const QModelIndex &index, const QVariant &value, int role) {
    if (index.isValid() && role == Qt::EditRole) {
        if (value.toString().isEmpty() ||
            (data(index).toString() == value.toString()))
        {
            // don't do anything when
            // 1) new string is empty
            // 2) old and new string are the same
            return false;
        }

        std::string bufferIndex = fitsMainWindow->getCurrentBufferIndex();
        if (modelDpuserType->type == typeFits) {
            int x = 0,
                y = 0,
                z = 0;
            QString indexStr;
            QFitsSingleBuffer *sb = myParent->getMyBuffer();

            switch (sb->Naxis(0)) {
            case 1:
                x = index.row() + 1;
                indexStr = QString::number(x);
                break;
            case 2:
                x = index.column() + 1,
                y = index.row() + 1;
                indexStr = QString::number(x) + "," + QString::number(y);
                break;
            case 3:
                x = index.column() + 1,
                y = index.row() + 1;
                z = (int)(sb->getCubeCenter(QFV::Wavelength) + 0.5);
                indexStr = QString::number(x) + "," + QString::number(y) + "," + QString::number(z);
                break;
            default:
                break;
            }

            // create command to change data value in fits
            QString cmd(bufferIndex.c_str());
            cmd += "[" + indexStr + "] = " + value.toString();
            dpuser_widget->executeCommand(cmd);

            // not needed, since dpuser notifies widget of changes
            // emit dataChanged(index, index);
            return true;
        } else if (modelDpuserType->type == typeStrarr) {
            // create command to change data value in fits
            QString cmd(bufferIndex.c_str());
            cmd += "[" + QString::number(index.row() + 1) + "] = \"" + value.toString() + "\"";
            dpuser_widget->executeCommand(cmd);
        }
    }
    return false;
}


// setup headers programmatically
QVariant QFitsTableModel::headerData(int section, Qt::Orientation orientation, int role) const {
    if (role == Qt::SizeHintRole) {
//            return QSize(1, 1);
    } else if (role == Qt::DisplayRole) {
        if (orientation == Qt::Horizontal) {
            // horizontal header
            if (section == 0) {
                const char* name = modelDpuserType->getColumnName();
                if (name != NULL) {
                    QString s(name);
                    s += "\n1";
                    return s;
                }
            } else {
                QString s("\n");
                s += QString::number(section + 1);
                return s;
            }
        } else {
            // vertical header
            return QString::number(section + 1);
        }
    }

    return QVariant();
}

Qt::ItemFlags QFitsTableModel::flags(const QModelIndex &index) const {
    Qt::ItemFlags flags = QAbstractItemModel::flags(index);

    // add in needed flags for table view
    flags |= (Qt::ItemIsEnabled |
              Qt::ItemIsSelectable |
              Qt::ItemIsEditable);

    return flags;
}

QVariant QFitsTableModel::dataFromDpuserType(dpuserType *dpt, int row, int col) const {
    if (dpt->type == typeFits) {
        Fits *fits = dpt->fvalue;
        int i = 0;
        switch(fits->Naxis(0)) {
        case 1:
            i = row;
            break;
        case 2:
            i = col + row*fits->Naxis(1);
            break;
        case 3:
            if (myParent->getMyBuffer() != NULL) {
                int z = (int)(myParent->getMyBuffer()->getCubeCenter(QFV::Wavelength) - 1 + 0.5);
                i = col + row*fits->Naxis(1) + z*fits->Naxis(1)*fits->Naxis(2);
            }
            break;
        default:
            break;
        }

        if (i >= fits->Nelements()) {
            // this should just be the case for QMutliBufferTable with columns of different size!
            return QVariant();
        }

        QString tmp;
        FitsBitpix bitpix = fits->getType();
        switch(bitpix) {
        case C16: //complex
            tmp = FormatComplexdpString(dpComplex(fits->cdata[i].r, fits->cdata[i].i)).c_str();
            break;
        case R8: //double
            tmp = QString::number(fits->r8data[i], 'g', 16);
            break;
        case R4: //float
            tmp = QString::number(fits->r4data[i]);
            break;
        case I1: //unsigned char
            tmp = QString::number(fits->i1data[i] * fits->getBSCALE() + fits->getBZERO());
            break;
        case I2: //short
            tmp = QString::number(fits->i2data[i] * fits->getBSCALE() + fits->getBZERO());
            break;
        case I4: //int
            tmp = QString::number(fits->i4data[i] * fits->getBSCALE() + fits->getBZERO());
            break;
        case I8: //long long
            tmp = QString::number(fits->i8data[i] * fits->getBSCALE() + fits->getBZERO(), 'g', 25);
            break;
        default:
            break;
        }
        return QVariant(' ' + tmp); // TODO: 12 Feb 2021: Prepending a space is a hack so numbers are shown sensibly when table cell is not wide enough to show full number (BUG in Qt as of at least 5.14?)
    } else if (dpt->type == typeStrarr) {
        if (row < dpt->arrvalue->size()) {
            QVariant tmp = dpt->arrvalue->at(row).to_c_str();
            return tmp;
        }
    }
    return QVariant();
}

// //////////////////////////////////////////////////////////////////////////
// class QFitsTableModelMulti
// //////////////////////////////////////////////////////////////////////////
QFitsTableModelMulti::QFitsTableModelMulti(QObject *parent, QFitsWidgetTable *p)
    : QFitsTableModel(parent, p)
{
}

QString QFitsTableModelMulti::newBufferString(int xMin, int xMax, int yMin, int yMax) {
    // we already asserted that xMin and xMax are in the same sub-SB
    std::string bufferIndex = fitsMainWindow->getCurrentBufferIndex();
    QFitsSingleBuffer *sb = myParent->getSBunderMouse(xMin);

    QString cmd = QString(freeBufferName().c_str()) +
                  " = " +
                  QString(bufferIndex.c_str()) +
                  sb->getExtensionIndicesString() +
                  "[";

    QVector<int> extVec = sb->getExtensionIndicesVec();
    dpuserType *dpt = modelDpuserType->dparrvalue->at(extVec.last());

    // reduce xMin/xMax because of any SBs left from actual SB
    // (indices are global in this specific MB)
    for (int i = 0; i < extVec.last(); i++) {
        dpuserType *tmpDpt = modelDpuserType->dparrvalue->at(i);
        int tmpInt = 0;
        if (tmpDpt->type == typeFits) {
            if (tmpDpt->fvalue->Naxis(0) == 1) {
                tmpInt = 1;
            } else {
                tmpInt = tmpDpt->fvalue->Naxis(1);
            }
        } else if (tmpDpt->type == typeStrarr) {
            tmpInt = 1;
        }
        xMin -= tmpInt;
        xMax -= tmpInt;
    }
    xMin++;
    xMax++;
    yMin++;
    yMax++;
    if (dpt->type == typeFits) {
        QString indexStr;
        switch (sb->Naxis(0)) {
        case 1:
            indexStr = QString::number(yMin) + ":" + QString::number(yMax);
            break;
        case 2:
            indexStr = QString::number(xMin) + ":" + QString::number(xMax) + "," +
                       QString::number(yMin) + ":" + QString::number(yMax);
            break;
        case 3:
            indexStr = QString::number(xMin) + ":" + QString::number(xMax) + "," +
                       QString::number(yMin) + ":" + QString::number(yMax) + "," +
                       QString::number((int)(sb->getCubeCenter(QFV::Wavelength) + 0.5));
            break;
        default:
            break;
        }
        cmd += indexStr;

        // not needed, since dpuser notifies widget of changes
        // emit dataChanged(index, index);
    } else if (dpt->type == typeStrarr) {
        // create command to change data value in fits
        cmd += QString::number(yMin) + ":" + QString::number(yMax);
    }
    cmd += "]";

    return cmd;
}

Fits* QFitsTableModelMulti::createPlotData(int section, QFV::Orientation orientation) {
    QFitsMultiBuffer *mb = dynamic_cast<QFitsMultiBuffer*>(myParent->getBaseBuffer());
    if (mb != NULL) {
        if (orientation == QFV::Vertical) {
            int   col       = section,
                  dpIndex   = translateColumnNumber(&col);
            return extractPlotData(modelDpuserType->dparrvalue->at(dpIndex), col, orientation);
        } else {
            int listSize = modelDpuserType->dparrvalue->size();

            // extract all rows from MB
            Fits *fList[modelDpuserType->dparrvalue->size()];
            for (int i = 0; i < listSize; i++) {
                fList[i] = extractPlotData(modelDpuserType->dparrvalue->at(i), section, orientation);
                if (fList[i] != NULL) {
                    fList[i]->setType(R8);
                }
            }

            // check sizes and generate 1D
            int size = 0;
            for (int i = 0; i < listSize; i++) {
                if (fList[i] != NULL) {
                    size += fList[i]->Nelements();
                } else {
                    size++;
                }
            }
            Fits *ret = new Fits();
            ret->create(size, 1, R8);

            // copy data from temporary fits to
            int pos = 0;
            for (int i = 0; i < listSize; i++) {
                if (fList[i] != NULL) {
                    for (int j = 0; j < fList[i]->Nelements(); j++) {
                        ret->r8data[pos++] = fList[i]->r8data[j];
                    }
                } else {
                    ret->r8data[pos++] = 0. / 0.;
                }
            }

            // delete temporary fits
            for (int i = 0; i < listSize; i++) {
                delete fList[i]; fList[i] = NULL;
            }
            return ret;
        }
    }
    return NULL;
}

int QFitsTableModelMulti::rowCount(int section) const {
    int   col       = section,
          dpIndex   = translateColumnNumber(&col);
    QFitsMultiBuffer *mb = dynamic_cast<QFitsMultiBuffer*>(myParent->getBaseBuffer());
    if (mb != NULL) {
        return rCount(modelDpuserType->dparrvalue->at(dpIndex));
    }
    return -1;
}

// needed when subclassing QAbstractTableModel!
// calculates the number of needed columns to display the whole table
int QFitsTableModelMulti::columnCount(const QModelIndex &) const {
    int cols = 0;
    if ((modelDpuserType != NULL) && (modelDpuserType->dparrvalue != NULL)) {
        for (int i = 0; i < modelDpuserType->dparrvalue->size(); i++) {
            dpuserType *dpt = modelDpuserType->dparrvalue->at(i);
            if (dpt->type == typeFits) {
                if ((dpt->fvalue->Naxis(0)) == 1) {
                    // 1D
                    cols += 1;
                } else {
                    // 2D
                    cols += dpt->fvalue->Naxis(1);
                }
            } else if (dpt->type == typeStrarr) {
                cols += 1;
            }
        }
    }
    return cols;
}

// needed when subclassing QAbstractTableModel!
// calculates the number of needed rows to display the whole table
int QFitsTableModelMulti::rowCount(const QModelIndex &) const {
    int rows = 0;
    if ((modelDpuserType != NULL) && (modelDpuserType->dparrvalue != NULL)) {
        for (int i = 0; i < modelDpuserType->dparrvalue->size(); i++) {
            int tmp = rCount(modelDpuserType->dparrvalue->at(i));
            if (rows < tmp) {
                rows = tmp;
            }
        }
    }
    return rows;
}

int QFitsTableModelMulti::rCount(const dpuserType *dpt) const {
    if (dpt->type == typeFits) {
        if ((dpt->fvalue->Naxis(0)) == 1) {
            // 1D
            return dpt->fvalue->Naxis(1);
        } else {
            // 2D
            return dpt->fvalue->Naxis(2);
        }
    } else if (dpt->type == typeStrarr) {
        return dpt->arrvalue->size();
    }
}

// get actual value from table (for displaying)
QVariant QFitsTableModelMulti::data(const QModelIndex &index, int role) const {
    if (!index.isValid()) {
        return QVariant();
    }

    int col = index.column();
    int dpIndex = translateColumnNumber(&col);

    if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) {
        QVariant tmp = dataFromDpuserType(modelDpuserType->dparrvalue->at(dpIndex), index.row(), col);
        if (role == Qt::EditRole) {
            // display selected text highlighted. Convert therefore to string, otherwise there are
            // scroll buttons in the edited cell...
            tmp = tmp.toString();
        }
        return tmp;
    }

    if (role == Qt::BackgroundRole) {
        if (dpIndex % 2 != 0) {
            // give odd numbered columns a light shade of gray
            return QBrush(QColor(245, 245, 245));
        }
    }

    return QVariant();
}

// set value into multi table when edited
bool QFitsTableModelMulti::setData(const QModelIndex &index, const QVariant &value, int role) {
    return false;
}

// input:   section: global index into table
// returns: index into applicable dpuserType in modelDpuserType->dparrvalue, section is modified to be correct index into dpuserType
int QFitsTableModelMulti::translateColumnNumber(int *section) const {
    int i = 0;
    for (i = 0; i < modelDpuserType->dparrvalue->size(); i++) {
        int sub = 0;
        if (modelDpuserType->dparrvalue->at(i)->type == typeFits) {
            if (modelDpuserType->dparrvalue->at(i)->fvalue->Naxis(0) == 1) {
                sub = 1;
            } else {
                sub = modelDpuserType->dparrvalue->at(i)->fvalue->Naxis(1);
            }
        } else if (modelDpuserType->dparrvalue->at(i)->type == typeStrarr) {
            sub = 1;
        }
        *section -= sub;
        if (*section < 0) {
            *section += sub;
            break;
        }
        if (*section == 0) {
            i++;
            break;
        }
    }
    return i;
}

// setup headers programmatically
QVariant QFitsTableModelMulti::headerData(int section, Qt::Orientation orientation, int role) const {
    if (role == Qt::SizeHintRole) {
//        return QSize(1, 1);
    } else if (role == Qt::DisplayRole) {
        if (orientation == Qt::Horizontal) {
            int dpIndex = translateColumnNumber(&section);
            // horizontal header
            if (section == 0) {
                QString s(modelDpuserType->dparrvalue->at(dpIndex)->getColumnName());
                if (s.size() == 0) {
                    s += "(none)";
                }
                s += "\n1";
                return s;
            } else {
                QString s("\n");
                s += QString::number(section + 1);
                return s;
            }
        } else {
            // vertical header
            return QString::number(section + 1);
        }
    }

    return QVariant();
}

Qt::ItemFlags QFitsTableModelMulti::flags(const QModelIndex &index) const {
    Qt::ItemFlags flags = QAbstractItemModel::flags(index);

    // add in needed flags for table view
    flags |= (Qt::ItemIsEnabled |
              Qt::ItemIsSelectable/* |
              Qt::ItemIsEditable*/);

    return flags;
}

// //////////////////////////////////////////////////////////////////////////
// class QFitsTableView
// //////////////////////////////////////////////////////////////////////////

QFitsTableView::QFitsTableView(QFitsWidgetTable *p) : QTableView(p) {
    myParent                                = p;
    columnState                             = -1;
    rowState                                = -1;
    actualCellX                             = 0;
    actualCellY                             = 0;
    rightPopupMenu                          = NULL;
    plotSpectrum                            = NULL;
    markedTable                             = false;
    brute_rangeHorizontal.first              = -1;
    brute_rangeHorizontal.second             = -1;
    brute_rangeVertical.first                = -1;
    brute_rangeVertical.second               = -1;

    connect(horizontalHeader(), SIGNAL(sectionPressed(int)),
            this, SLOT(setSpectrumVertical(int)));
    connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
            this, SLOT(scrollMoved(int)));

    connect(verticalHeader(), SIGNAL(sectionPressed(int)),
            this, SLOT(setSpectrumHorizontal(int)));
    connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
            this, SLOT(scrollMoved(int)));

    setStyleSheet("QTableView QTableCornerButton::section { border: 1px solid darkgray; }");

    connect(this, SIGNAL(clicked(const QModelIndex&)),
            this, SLOT(unsetSpectrum(const QModelIndex&)));
}

QFitsTableView::~QFitsTableView() {
    if (rightPopupMenu) {
        delete rightPopupMenu; rightPopupMenu = NULL;
    }
    if (plotSpectrum) {
        delete plotSpectrum; plotSpectrum = NULL;
    }
}

bool QFitsTableView::doPlotData() {
    if (plotSpectrum != NULL) {
        return true;
    }
    return false;
}

void QFitsTableView::restoreState() {
    // restore state of headers (if sections have been highlighted or not)
    if (columnState > -1) {
        selectColumn(columnState);
    } else if (rowState > -1) {
        selectRow(rowState);
    }

    // set CubeSpectrum accordingly
    if (plotSpectrum) {
        setupCubeSpectrum();
    }
}

void QFitsTableView::mousePressEvent(QMouseEvent *m) {
    if (m->button() == Qt::RightButton) {
        // show dynamic popup menu
        QFitsSingleBuffer* sb = myParent->getSBunderMouse(actualCellX);
        if (sb != NULL) {
            rightPopupMenu = new QMenu;
            QModelIndexList selected = selectionModel()->selectedIndexes();
            if (selected.size() == 0) {
                // no selection
                if (sb->isMultiBufferChild()) {
                    QFitsMultiBuffer *mb = sb->getMyMultiBuffer();
                    rightPopupMenu->addAction("Copy sub-table to new buffer",
                                              this, SLOT(copySubTableToNewBuffer()));
                    if (mb->isMultiBufferChild()) {
                        rightPopupMenu->addAction("Copy whole table to new buffer",
                                                  this, SLOT(copyWholeTableToNewBuffer()));
                    }
                    rightPopupMenu->exec(m->globalPos());
                } else {
                    // SB, no selection --> do nothing
                }
            } else {
                bool ok = false;
                if (!sb->isMultiBufferChild()) {
                    ok = true;
                }
                if (sb->isMultiBufferChild()) {
                    int colMax = INT_MIN, colMin = INT_MAX;
                    for (int i = 0; i < selected.size(); i++) {
                        if (selected[i].column() < colMin) {
                            colMin = selected[i].column();
                        }
                        if (selected[i].column() > colMax) {
                            colMax = selected[i].column();
                        }
                    }
                    if (myParent->getSBunderMouse(colMin) == myParent->getSBunderMouse(colMax)) {
                        ok = true;
                    }
                }

                if (ok) {
                    rightPopupMenu->addAction("Copy selection to new buffer",
                                              this, SLOT(copySelectionToNewBuffer()));
                    rightPopupMenu->exec(m->globalPos());
                }
            }
            delete rightPopupMenu; rightPopupMenu = NULL;
        }
    } else if (m->button() == Qt::LeftButton) {
        QFitsBaseBuffer *bb = myParent->getBaseBuffer();
        bool locked = (bb->getLockedSingleBuffer() != NULL);
        if (!locked) {
            QModelIndexList selected = selectionModel()->selectedIndexes();
            QTableView::mousePressEvent(m);
            if (selected.size() != 0) {
                clearSelection();
            } else {
                unsetSpectrum();
            }
            clearFocus();
        }
    } else {
        QTableView::mousePressEvent(m);
        unsetSpectrum();
    }
}

void QFitsTableView::mouseMoveEvent(QMouseEvent *m) {
    QFitsBaseBuffer *bb = myParent->getBaseBuffer();
    if (bb->getLockedSingleBuffer() == NULL) {
        actualCellX = columnAt(m->x());
        actualCellY = rowAt(m->y());

        QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(bb);
        if ((sb != NULL) &&
            (sb->Naxis(0) == 1) &&
            (sb->getImage()->width() > sb->getImage()->height()))
        {
            // for 1D-data:
            // if user has switched from ViewImage to ViewTable, image has to be rotated
            sb->rotImage(true);
        }

        handleMouseEventData();
        QTableView::mouseMoveEvent(m);
    }
    handleMouseEventCaption(columnAt(m->x()));
}

void QFitsTableView::wheelEvent(QWheelEvent *w) {
    QFitsBaseBuffer *bb = myParent->getBaseBuffer();
    if (bb->getLockedSingleBuffer() == NULL) {
        int inc     = w->angleDelta().y() / 120 * 3,
            top     = indexAt(rect().topLeft()).row(),
            bottom  = indexAt(rect().bottomLeft()).row(),
            nrRows  = myParent->getTableModel()->rowCount(0);
        if (bottom == -1) {
            bottom = myParent->getTableModel()->rowCount(0);
        }

        if (top - inc < 0) {
            inc = top;
        } else if (bottom - inc > nrRows-1) {
            inc = bottom - nrRows;
        }

        if (inc != 0) {
            actualCellY -= inc;

            handleMouseEventData();

            if ((actualCellX != -1 ) && (actualCellY != -1)) {
                QAbstractScrollArea::wheelEvent(w);
            }
        }
    }
}

void QFitsTableView::handleMouseEventCaption(int cellX) {
    if (cellX != -1 ) {
        QFitsBaseBuffer *bb = myParent->getBaseBuffer();
        QString fname = bb->getAppearance().windowTitle;
        int pos = fname.indexOf(", table #");
        if (pos != -1) {
            fname.chop(fname.size() - pos);
        }

        if ((dynamic_cast<QFitsMultiBuffer*>(bb) != NULL) &&
            (bb->getExtensionIndicesVec().size() > 0))
        {
            fname += ", ext #";
            if (bb->getExtensionIndicesVec().size() == 1) {
                fname += QString::number(bb->getExtensionIndicesVec().at(0));
            } else {
                fname += bb->getExtensionIndicesString();
            }
        }
        QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(bb);
        if ((sb != NULL) && sb->isMultiBufferChild()) {
            fname += ", ext #";
            fname += QString::number(bb->getExtensionIndicesVec().at(0));
        }

        QFitsTableModelMulti *tmm = dynamic_cast<QFitsTableModelMulti*>(myParent->getTableModel());
        if (tmm != NULL) {
            // for TableModelMulti first translate column index before sending it to ViewingTools
            int myCol = cellX;

            if (fname.size() > 0) {
                fname += ", table # " + QString::number(tmm->translateColumnNumber(&myCol) + 1);
            }
        }
        fitsMainWindow->setWindowTitle(fname);
    }
}

void QFitsTableView::handleMouseEventData() {
    if ((actualCellX == -1 ) || (actualCellY == -1)) {
        leaveCells();
    } else {
        QFitsSingleBuffer *sb = myParent->getSBunderMouse(actualCellX);
        if ((sb != NULL) && (sb->getDpData()->type == typeFits)) {
            // only set SB under curser as actual if it is a Fits
            myParent->activateSBunderMouse(actualCellX);
        }

        QFitsTableModelMulti *tmm = dynamic_cast<QFitsTableModelMulti*>(myParent->getTableModel());
        if (tmm != NULL) {
            // for TableModelMulti first translate column index before sending it to ViewingTools
            int myCol = actualCellX;
            tmm->translateColumnNumber(&myCol);
            fitsMainWindow->updateTools(myCol+1, actualCellY+1,
                                        myCol+1, actualCellY+1);
        } else {
            fitsMainWindow->updateTools(actualCellX+1, actualCellY+1,
                                        actualCellX+1, actualCellY+1);
        }
    }
}

void QFitsTableView::keyPressEvent(QKeyEvent *e) {
    fitsMainWindow->main_view->keyPressEvent(e);
}

void QFitsTableView::enterEvent(QEvent *e) {
    //
    // set appropriate caption for MultiTable
    //
    QFitsBaseBuffer *bb = myParent->getBaseBuffer();
    QString fname = bb->getAppearance().windowTitle;
    int pos = fname.indexOf(", table #");
    if (pos != -1) {
        fname.chop(fname.size() - pos);
    }
    if ((dynamic_cast<QFitsMultiBuffer*>(bb) != NULL) &&
        (bb->getExtensionIndicesVec().size() > 0))
    {
        fname += ", ext #";
        if (bb->getExtensionIndicesVec().size() == 1) {
            fname += QString::number(bb->getExtensionIndicesVec().at(0));
        } else {
            fname += bb->getExtensionIndicesString();
        }
    }
    QFitsSingleBuffer *sb = dynamic_cast<QFitsSingleBuffer*>(bb);
    if ((sb != NULL) && sb->isMultiBufferChild()) {
        fname += ", ext #";
        fname += QString::number(bb->getExtensionIndicesVec().at(0));
    }

    QFitsTableModelMulti *tmm = dynamic_cast<QFitsTableModelMulti*>(myParent->getTableModel());
    if ((tmm != NULL) && (fname.size() > 0)) {
        int myCol = actualCellX,
            ext   = tmm->translateColumnNumber(&myCol);
        fname += ", table # " + QString::number(ext+1);
        fitsMainWindow->setWindowTitle(fname);
    }

    //
    // check if row or column had previously been selected,
    // if yes then update spectrum
    //
    if (myParent->getBaseBuffer()->getLockedSingleBuffer() == NULL) {
        if (columnState >= 0) {
            plotSpectrumVertical();
        } else if (rowState >= 0) {
            plotSpectrumHorizontal();
        } else {
            fitsMainWindow->setActualSB(NULL);
            setupCubeSpectrum();
        }
    }
}

void QFitsTableView::leaveEvent(QEvent*) {
    if (myParent->getBaseBuffer()->getLockedSingleBuffer() == NULL) {
        leaveCells();
    }
}

void QFitsTableView::leaveCells() {
    fitsMainWindow->viewingtools->clear();
    fitsMainWindow->mytoolbar->updateImageMinMax(NULL);
    fitsMainWindow->mytoolbar->updateSpecMinMaxY(NULL);
}

void QFitsTableView::copyWholeTableToNewBuffer() {
    std::string bufferIndex = fitsMainWindow->getCurrentBufferIndex();
    QFitsSingleBuffer* sb = myParent->getSBunderMouse(actualCellX);

    QString extStr = sb->getExtensionIndicesString();
    extStr.remove(extStr.lastIndexOf("["), extStr.size()-extStr.lastIndexOf("["));


    QString cmd = QString(freeBufferName().c_str()) + " = " +
                  QString(bufferIndex.c_str()) +
                  extStr;

    dpuser_widget->executeCommand(cmd);
}

void QFitsTableView::copySubTableToNewBuffer() {
    std::string bufferIndex         = fitsMainWindow->getCurrentBufferIndex();
    QFitsSingleBuffer* sb   = myParent->getSBunderMouse(actualCellX);

    QString cmd = QString(freeBufferName().c_str()) +
                  " = " +
                  QString(bufferIndex.c_str()) +
                  sb->getExtensionIndicesString();

    dpuser_widget->executeCommand(cmd);
}

void QFitsTableView::copySelectionToNewBuffer() {
    QModelIndexList selected = selectionModel()->selectedIndexes();
    int colMax = INT_MIN, colMin = INT_MAX,
        rowMax = INT_MIN, rowMin = INT_MAX;
    for (int i = 0; i < selected.size(); i++) {
        if (selected[i].column() < colMin) {
            colMin = selected[i].column();
        }
        if (selected[i].column() > colMax) {
            colMax = selected[i].column();
        }
        if (selected[i].row() < rowMin) {
            rowMin = selected[i].row();
        }
        if (selected[i].row() > rowMax) {
            rowMax = selected[i].row();
        }
    }

    QFitsTableModel *tm = myParent->getTableModel();
    if (dynamic_cast<QFitsTableModelMulti*>(tm) == NULL) {
        // dpuserType
        QString s = tm->newBufferString(colMin, colMax, rowMin, rowMax);
        dpuser_widget->executeCommand(s);
    } else {
        // dpuserTypeList
        QFitsTableModelMulti *tmm = dynamic_cast<QFitsTableModelMulti*>(myParent->getTableModel());
        if (tmm != NULL) {
            if (myParent->getSBunderMouse(colMin) == myParent->getSBunderMouse(colMax)) {
                QString s = tmm->newBufferString(colMin, colMax, rowMin, rowMax);
                dpuser_widget->executeCommand(s);
            }
        }
    }
}

void QFitsTableView::copySelectionToClipboard() {
    QModelIndexList selected = selectionModel()->selectedIndexes();
    if (selected.isEmpty()) return;
    int n = selected.size();
    if (selected.size() > 256*256) {
        QMessageBox::warning(this, "QFitsView", "Too many data points to be copied");
        return;
    }

    QMimeData *copyData = new QMimeData();
    QStringList entries;
    QString line;

    QFitsTableModel *tm = myParent->getTableModel();
    if (dynamic_cast<QFitsTableModelMulti*>(tm) == NULL) {
        // dpuserType
        int row = selected[0].row();
        for (int i = 0; i < selected.size(); i++) {
            QVariant tmp = tm->data(selected[i]);
            if (selected[i].row() != row) {
                line.remove(line.length()-1, 1);
                entries << line;
                line.clear();
                row = selected[i].row();
            }
            line += tmp.toString();
            line += ",";
        }
        line.remove(line.length()-1, 1);
        entries << line;
        line.clear();
    } else {
        // dpuserTypeList
        QFitsTableModelMulti *tmm = dynamic_cast<QFitsTableModelMulti*>(myParent->getTableModel());
        if (tmm != NULL) {
            int row = selected[0].row();
            for (int i = 0; i < selected.size(); i++) {
                QVariant tmp = tmm->data(selected[i]);
                if (selected[i].row() != row) {
                    line.remove(line.length()-1, 1);
                    entries << line;
                    line.clear();
                    row = selected[i].row();
                }
                line += tmp.toString();
                line += ",";
            }
            line.remove(line.length()-1, 1);
            entries << line;
            line.clear();
        }
    }
    entries << "";
    copyData->setText(entries.join("\n"));
    QApplication::clipboard()->setMimeData(copyData);
}


void QFitsTableView::setSpectrumVertical(int) {
    bool locked = (myParent->getBaseBuffer()->getLockedSingleBuffer() != NULL);
    if (locked) {
        clearSelection();
        clearFocus();
    } else {
        unsetSpectrum();
        columnState = selectionModel()->currentIndex().column();
        rowState = -1;

        plotSpectrumVertical();
    }
}

void QFitsTableView::plotSpectrumVertical() {
    myParent->activateSBunderMouse(columnState);

    QFitsSingleBuffer *sb = fitsMainWindow->getActualSB();
    sb->setCubeSpecOrientation(QFV::Vertical, true);

    if (sb != NULL) {
        sb->mtv_setLastActiveSection(columnState, QFV::Vertical);

        if (plotSpectrum) {
            delete plotSpectrum; plotSpectrum = NULL;
        }

        if (sb->getDpData()->type == typeFits) {
            QFitsTableModel *tm = myParent->getTableModel();
            plotSpectrum = tm->createPlotData(columnState, QFV::Vertical);
            if (plotSpectrum == NULL) {
                if (!fitsMainWindow->getCurrentBuffer()->getHasMixedView()) {
                    fitsMainWindow->spectrum->hide();
                }
            } else {
                if ((brute_rangeVertical.first < 0) || (brute_rangeVertical.second < 0)) {
                    brute_rangeVertical.first  = 1;
                    brute_rangeVertical.second = plotSpectrum->Naxis(1);
                }
                myParent->getBaseBuffer()->setSpecChannelMinX(brute_rangeVertical.first);
                myParent->getBaseBuffer()->setSpecChannelMaxX(brute_rangeVertical.second);
//                myParent->getBaseBuffer()->mtv_setMinMaxXbrute(brute_rangeVertical.first,
//                                                               brute_rangeVertical.second);
                setupCubeSpectrum();
                calcScrollContinuum();
            }
        } else {
            sb->setSpecChannelMinX(0);
            sb->setSpecChannelMaxX(0);
            fitsMainWindow->spectrum->changeWorkArrayTable();
        }
        if ((sb != NULL) && (sb != sb->getMarkedSingleBuffer())){
            sb->setMarkedSingleBuffer(sb, false);
        }
    }
}

void QFitsTableView::setSpectrumHorizontal(int) {
    bool locked = (myParent->getBaseBuffer()->getLockedSingleBuffer() != NULL);
    if (locked) {
        clearSelection();
        clearFocus();
    } else {
        unsetSpectrum();
        rowState = selectionModel()->currentIndex().row();
        columnState = -1;

        plotSpectrumHorizontal();
    }
}

void QFitsTableView::plotSpectrumHorizontal() {
    myParent->activateSBunderMouse(0);

    QFitsSingleBuffer *sb = fitsMainWindow->getActualSB();
    sb->setCubeSpecOrientation(QFV::Horizontal, true);

    if (sb != NULL) {
        sb->mtv_setLastActiveSection(rowState, QFV::Horizontal);

        if (plotSpectrum) {
            delete plotSpectrum; plotSpectrum = NULL;
        }

        QFitsTableModel *tm = myParent->getTableModel();
        plotSpectrum = tm->createPlotData(rowState, QFV::Horizontal);
        if (plotSpectrum == NULL) {
            if (!fitsMainWindow->getCurrentBuffer()->getHasMixedView()) {
                fitsMainWindow->spectrum->hide();
            }
        } else {
            if ((brute_rangeHorizontal.first < 0) || (brute_rangeHorizontal.second < 0)) {
                brute_rangeHorizontal.first  = 1;
                brute_rangeHorizontal.second = plotSpectrum->Naxis(1);
            }
            // TODO: Check if this is really what we want or if, as for the Vertical case, we just want to set the Channel Min/Max
            myParent->getBaseBuffer()->mtv_setMinMaxXbrute(brute_rangeHorizontal.first,
                                    brute_rangeHorizontal.second);
            setupCubeSpectrum();
            calcScrollContinuum();
        }

        if ((sb != NULL) && (sb != sb->getMarkedSingleBuffer())){
            sb->setMarkedSingleBuffer(sb, false);
        }
    }
}

void QFitsTableView::setBruteRange(int min, int max) {
    if (min < 1) {
        min = 1;
    }
    if ((plotSpectrum != NULL) &&
        (max > plotSpectrum->Nelements()))
    {
        max = plotSpectrum->Nelements();
    }

    if (columnState > -1) {   
        brute_rangeVertical.first  = min;
        brute_rangeVertical.second  = max;
    } else if (rowState > -1) {
        brute_rangeHorizontal.first  = min;
        brute_rangeHorizontal.second  = max;
    }
}

void QFitsTableView::unsetSpectrum(const QModelIndex&) {
    unsetSpectrum();
}

void QFitsTableView::unsetSpectrum(const QItemSelection &s, const QItemSelection &e) {
    unsetSpectrum();
}

void QFitsTableView::unsetSpectrum() {
    QFitsBaseBuffer *bb = myParent->getBaseBuffer();
    bool locked = (bb->getLockedSingleBuffer() != NULL);
    if (locked) {
        clearSelection();
        clearFocus();
    }

    if (plotSpectrum) {
        columnState = -1;
        rowState = -1;
        fitsMainWindow->spectrum->enableControls(true);
        if (!fitsMainWindow->getCurrentBuffer()->getHasMixedView()) {
            fitsMainWindow->spectrum->hide();
        }
        QFitsBaseBuffer *bb = myParent->getBaseBuffer();
        if (bb != NULL) {
            bb->setCubeDisplay1D(NULL);
        }
        delete plotSpectrum; plotSpectrum = NULL;
        fitsMainWindow->setActualSB(NULL);
        setupCubeSpectrum();
    }
}

void QFitsTableView::setupCubeSpectrum() {
    if (plotSpectrum) {
        QFitsBaseBuffer *bb = myParent->getBaseBuffer();
        if (bb != NULL) {
            Fits *copy = new Fits();
            copy->copy(*plotSpectrum);
            bb->setCubeDisplay1D(copy);
        }
    }

    fitsMainWindow->spectrum->getPlotter()->setData();
    fitsMainWindow->spectrum->changeWorkArrayTable();
    fitsMainWindow->spectrum->enableControls(false);
}

void QFitsTableView::calcScrollContinuum() {
    if (fitsMainWindow->spectrum->isVisible()) {
        double  tmpHalfWidth = 0,
                center       = 0;
        QFitsBaseBuffer *bb = myParent->getBaseBuffer();
        if (columnState != -1) {
            int top          = 0,
                bottom       = 0;

            myParent->getVisibleRangeVertical(&top, &bottom);

            if ((top != 1) ||
                (myParent->getTableModel()->rowCount(0) != bottom))
            {
                tmpHalfWidth = (bottom - top) / 2.;
                center = tmpHalfWidth + top;
            }

            bb->setCubeMode(DisplayCubeLinemap, true);
            bb->setCubeCenter(center, bb->getCubeSpecOrientation(), true);
            bb->setLineWidth(tmpHalfWidth, bb->getCubeSpecOrientation(), true);
            fitsMainWindow->spectrum->update();
        }
        if (rowState != -1) {
            int left         = 0,
                right        = 0;

            myParent->getVisibleRangeHorizontal(&left, &right);

            if ((left != 1) ||
                (myParent->getTableModel()->columnCount(0) != right))
            {
                tmpHalfWidth = (right - left) / 2.;
                center = tmpHalfWidth + left;
            }

            bb->setCubeMode(DisplayCubeLinemap, true);
            bb->setCubeCenter(center, bb->getCubeSpecOrientation(), true);
            bb->setLineWidth(tmpHalfWidth, bb->getCubeSpecOrientation(), true);
            fitsMainWindow->spectrum->update();
        }
    }
}

void QFitsTableView::scrollMoved(int) {
    calcScrollContinuum();
}

// //////////////////////////////////////////////////////////////////////////
// class QFitsDummyMarkedView
// //////////////////////////////////////////////////////////////////////////
QFitsDummyMarkedView::QFitsDummyMarkedView(QFitsWidgetTable *parent, QWidget *w) : QFitsBaseView(w) {
    myWidget = parent;
}

void QFitsDummyMarkedView::switchBackgroundColor() {
    QFitsTableView* tv = myWidget->getTableView();

    if (tv->getMarkedTable()) {
        // deselect
        tv->setMarkedTable(false);
        tv->clearSelection();
    } else {
        // select
        tv->setMarkedTable(true);
        tv->restoreState();
    }
}
