MasterDetail Example

#include <QtGui>
#include <QMessageBox>

#include "window.h"

#if (QT_VERSION > QT_VERSION_CHECK(5, 15, 0))
#define Qt_SkipEmptyParts Qt::SkipEmptyParts
#else
#define Qt_SkipEmptyParts QString::SkipEmptyParts
#endif

Window::Window()
: DemoMainWindow(QStringLiteral("QtitanDataGrid"), QStringLiteral(QTN_VERSION_DATAGRID_STR), tr("Master Detail Example"))
{
    Grid::loadTranslation();

    m_grid = new Qtitan::Grid();
    QAbstractItemModel* model = createMasterModel();

    // Configure grid view
    m_grid->setViewType(Qtitan::Grid::BandedTableView);
    Qtitan::GridBandedTableView* view = m_grid->view<Qtitan::GridBandedTableView>();
    view->beginUpdate();

    view->options().setModelDecoration(false);
    view->options().setPreviewRowText(tr("Country Statistics"));
    view->options().setRowAutoHeight(true);
    view->options().setPreviewRowEnabled(true);
    view->options().setPreviewRowHeight(200);
    view->options().setModelItemsDragEnabled(true);
    view->bandedOptions().setBandsQuickCustomization(false);

    Qtitan::GridTableBand* band = view->addBand(tr("Aggregate and per capita GDP in Europe, 1870-2000"));
    band->setTextAlignment(Qt::AlignCenter);

    //Connect Grid's context menu handler.
    connect(view, SIGNAL(contextMenu(ContextMenuEventArgs*)), this, SLOT(contextMenu(ContextMenuEventArgs* )));
    connect(view, SIGNAL(previewRowChanged(PreviewRowArgs*)), this, SLOT(previewRowChanged(PreviewRowArgs*)));

    view->setModel(model);
    Qtitan::GridTableColumn* column = (Qtitan::GridTableColumn *)view->getColumnByModelColumnName(tr("Flag"));
    column->setEditorType(GridEditor::Picture);
    column->editorRepository()->setEditable(false);
    column->setMaxWidth(40);
    column->setMaxWidth(50);
    column->setFilterButtonVisible(false);
    column->setSortEnabled(false);

    column = (Qtitan::GridTableColumn *)view->getColumnByModelColumnName(tr("Photo"));
    column->setEditorType(GridEditor::Picture);
    column->editorRepository()->setEditable(false);
    column->setFilterButtonVisible(false);
    column->setSortEnabled(false);
    view->endUpdate();

    setDemoWidget(m_grid, createSettingsWidget());

    view->bestFit();
}

QWidget* Window::createSettingsWidget()
{
    //Create settings widget
    QWidget* settings = new QWidget(this);
    QVBoxLayout* l = new QVBoxLayout(settings);

    l->addLayout(createStyleSetting());

    QCheckBox* autoWidthCheck = new QCheckBox(settings);
    autoWidthCheck->setText(tr("Column auto width"));
    connect(autoWidthCheck, SIGNAL(stateChanged(int)), this, SLOT(autoWidthStateChanged(int)));
    l->addWidget(autoWidthCheck);
    autoWidthCheck->setChecked(true);

    QCheckBox* fastScrollCheck = new QCheckBox(settings);
    fastScrollCheck->setText(tr("Fast scroll effect"));
    connect(fastScrollCheck, SIGNAL(stateChanged(int)), this, SLOT(fastScrollChanged(int)));
    l->addWidget(fastScrollCheck);
    fastScrollCheck->setChecked(true);

    QCheckBox* dottedLineCheck = new QCheckBox(settings);
    dottedLineCheck->setText(tr("Dotted grid line"));
    connect(dottedLineCheck, SIGNAL(stateChanged(int)), this, SLOT(dottedLineChanged(int)));
    l->addWidget(dottedLineCheck);
    dottedLineCheck->setChecked(false);

    QLabel* label = new QLabel(this);
    QHBoxLayout* hl = new QHBoxLayout(0);
    label->setText(tr("Grid line style:"));
    QComboBox* lineStylesSelect = new QComboBox(settings);

    lineStylesSelect->addItem(tr("None"));
    lineStylesSelect->addItem(tr("Both"));
    lineStylesSelect->addItem(tr("Both2D"));
    lineStylesSelect->addItem(tr("Horizontal"));
    lineStylesSelect->addItem(tr("Horizontal2D"));
    lineStylesSelect->addItem(tr("Vertical"));
    lineStylesSelect->addItem(tr("Vertical2D"));
    connect(lineStylesSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(selectGridLineStyles(int)));
    hl->addWidget(label);
    hl->addWidget(lineStylesSelect);
    l->addLayout(hl);
    lineStylesSelect->setCurrentIndex(3);

    QCheckBox* zoomEnable = new QCheckBox(settings);
    zoomEnable->setText(tr("Zoom enabled"));
    zoomEnable->setChecked(true);
    connect(zoomEnable, SIGNAL(stateChanged(int)), this, SLOT(zoomEnabledChanged(int)));
    l->addWidget(zoomEnable);

    QCheckBox* zoomIndicator = new QCheckBox(settings);
    zoomIndicator->setText(tr("Show zoom indicator"));
    zoomIndicator->setChecked(true);
    connect(zoomIndicator, SIGNAL(stateChanged(int)), this, SLOT(zoomIndicatorChanged(int)));
    l->addWidget(zoomIndicator);

    QSlider* zoomSlider = new QSlider(settings);
    zoomSlider->setOrientation(Qt::Horizontal);
    zoomSlider->setTickPosition(QSlider::TicksBothSides);
    zoomSlider->setMinimum(25);
    zoomSlider->setMaximum(300);
    zoomSlider->setTickInterval(25);
    zoomSlider->setSingleStep(25);
    zoomSlider->setValue(100);
    connect(zoomSlider, SIGNAL(sliderMoved(int)), this, SLOT(zoomValueChanged(int)));
    connect(m_grid->view<Qtitan::GridTableView>(), SIGNAL(zoomChanged(int)), zoomSlider, SLOT(setValue(int)));
    l->addWidget(zoomSlider);

    QCheckBox* cellAutoRaise = new QCheckBox(settings);
    cellAutoRaise->setText(tr("Auto raise cell button"));
    connect(cellAutoRaise, SIGNAL(stateChanged(int)), this, SLOT(cellButtonAutoRaiseEnabled(int)));
    cellAutoRaise->setChecked(true);
    l->addWidget(cellAutoRaise);

    QLabel* previewExpandButtonLabel = new QLabel(this);
    hl = new QHBoxLayout(0);
    previewExpandButtonLabel->setText(tr("Preview Expand Style (new):"));
    QComboBox* previewExpandButtonComboBox = new QComboBox(settings);
    connect(previewExpandButtonComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectPreviewRowExpandStyle(int)));
    previewExpandButtonComboBox->addItem(tr("Keep Expanded"));
    previewExpandButtonComboBox->addItem(tr("Text Button"));
    previewExpandButtonComboBox->addItem(tr("Button"));
    hl->addWidget(previewExpandButtonLabel);
    hl->addWidget(previewExpandButtonComboBox);
    l->addLayout(hl);
    previewExpandButtonComboBox->setCurrentIndex(2);

    QCheckBox* transparentBox = new QCheckBox(settings);
    transparentBox->setText(tr("Transparent Background"));
    connect(transparentBox, SIGNAL(stateChanged(int)), this, SLOT(transparentBackgroundEnabled(int)));
    transparentBox->setChecked(false);
    l->addWidget(transparentBox);

    QCheckBox* rowSizingBox = new QCheckBox(settings);
    rowSizingBox->setText(tr("Resizing row (new)"));
    connect(rowSizingBox, SIGNAL(stateChanged(int)), this, SLOT(rowSizingEnabled(int)));
    rowSizingBox->setChecked(true);
    l->addWidget(rowSizingBox);

    QPushButton* printButton = new QPushButton(settings);
    printButton->setText(tr("Print Preview"));
    connect(printButton, SIGNAL(clicked()), this, SLOT(printPreview()));
    l->addWidget(printButton);
    return settings;
}

void Window::autoWidthStateChanged(int state)
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    view->tableOptions().setColumnAutoWidth(state == Qt::Checked);
}

void Window::fastScrollChanged(int state)
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    view->options().setFastScrollEffect(state == Qt::Checked);
}

void Window::dottedLineChanged(int state)
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    QPen pen = view->options().gridLinePen();
    pen.setStyle(state == Qt::Checked ? Qt::DotLine : Qt::SolidLine);
    view->options().setGridLinePen(pen);
}

void Window::selectGridLineStyles(int index)
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    switch (index)
    {
    case 0:
        view->options().setGridLines(Qtitan::LinesNone);
        break;
    case 1:
        view->options().setGridLines(Qtitan::LinesBoth);
        break;
    case 2:
        view->options().setGridLines(Qtitan::LinesBoth2D);
        break;
    case 3:
        view->options().setGridLines(Qtitan::LinesHorizontal);
        break;
    case 4:
        view->options().setGridLines(Qtitan::LinesHorizontal2D);
        break;
    case 5:
        view->options().setGridLines(Qtitan::LinesVertical);
        break;
    case 6:
        view->options().setGridLines(Qtitan::LinesVertical2D);
        break;
    default:
        view->options().setGridLines(Qtitan::LinesBoth);
    }
}

void Window::zoomEnabledChanged(int state)
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    view->options().setZoomEnabled(state == Qt::Checked);
}

void Window::zoomIndicatorChanged(int state)
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    view->options().setZoomIndicatorActive(state == Qt::Checked);
}

void Window::zoomValueChanged(int value)
{
    double factor = qCeil((double)value / 25) * 25;
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    view->options().setZoomFactor(factor / 100);
}

void Window::cellButtonAutoRaiseEnabled(int state)
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    view->options().setCellButtonAutoRaise(state == Qt::Checked);
}

void Window::transparentBackgroundEnabled(int state)
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    view->options().setTransparentBackground(state == Qt::Checked);

    view->options().setAlternatingRowColors(!view->options().alternatingRowColors());
}

void Window::rowSizingEnabled(int state)
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    view->tableOptions().setRowSizingEnabled(state == Qt::Checked);
}

void Window::selectPreviewRowExpandStyle(int index)
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    if (index == 0)
        view->options().setPreviewRowExpandStyle(GridViewOptions::PreviewKeepExpanded);
    else if (index == 1)
        view->options().setPreviewRowExpandStyle(GridViewOptions::PreviewExpandTextButton);
    else
        view->options().setPreviewRowExpandStyle(GridViewOptions::PreviewExpandButton);
}

void Window::contextMenu(ContextMenuEventArgs* args)
{
    args->contextMenu()->addAction(tr("Print Preview"), this, SLOT(printPreview()));
    args->contextMenu()->addSeparator();
    args->contextMenu()->addAction(tr("Developer Machines on the Web"), this, SLOT(showCompanyWebSite()));
}

void Window::cellButtonClicked(CellButtonClickEventArgs* args)
{
    QMessageBox::information(this, tr("Cell button clicked"),
        tr("Clicked: Button - %1, Column Title - %2, RowIndex - %3").arg(args->buttonIndex()).arg(args->column()->caption()).arg(args->row().rowIndex()));
}

void Window::printPreview()
{
    m_grid->view<Qtitan::GridTableView>()->printPreview();
}

void Window::setShadeColor(const QColor& color)
{
    m_grid->themeManager()->setShadeColor(color);
}

void Window::previewRowChanged(PreviewRowArgs* args)
{
    QString country = args->index().data().toString();
    if (!m_detailModelMap.contains(country))
        return;
    QAbstractItemModel* model = m_detailModelMap[country];

    Grid* detailGrid = qobject_cast<Grid *>(args->widget());
    if (detailGrid == Q_NULL)
    {
        detailGrid = new Grid();
        detailGrid->setAttribute(Qt::WA_NoSystemBackground, true);
        detailGrid->setViewType(Qtitan::Grid::TableView);
    }
    Qtitan::GridTableView* view = detailGrid->view<Qtitan::GridTableView>();
    view->setModel(model);

    args->setWidget(detailGrid);
    args->setHandled(true);
}

static void simplified_strings(QStringList& list)
{
    for (QStringList::iterator it = list.begin(); it != list.end(); ++it)
        *it = (*it).simplified();
}

void Window::addDetailModel(const QString& country, const QString& gdp, const QString& population, const QString& gdpPerCapita)
{
    QAbstractItemModel* model = new QStandardItemModel(0, 4, this);
    m_detailModelMap.insert(country, model);

    model->setHeaderData(0, Qt::Horizontal, tr("Year"));
    model->setHeaderData(1, Qt::Horizontal, tr("GDP ($ international prices)"));
    model->setHeaderData(2, Qt::Horizontal, tr("Population (Millions)"));
    model->setHeaderData(3, Qt::Horizontal, tr("GDP Per Capita ($ international prices)"));

    QStringList gdp_data = gdp.split(QStringLiteral(","), Qt_SkipEmptyParts);
    simplified_strings(gdp_data);
    QStringList population_data = population.split(QStringLiteral(","), Qt_SkipEmptyParts);
    simplified_strings(population_data);
    QStringList gdpPerCapita_data = gdpPerCapita.split(QStringLiteral(","), Qt_SkipEmptyParts);
    simplified_strings(gdpPerCapita_data);
    Q_ASSERT(gdp_data[0] == country && population_data[0] == country && gdpPerCapita_data[0] == country);
    QStringList years;
    years << QStringLiteral("1870") << QStringLiteral("1890") << QStringLiteral("1913") << QStringLiteral("1929")
          << QStringLiteral("1937") << QStringLiteral("1950") << QStringLiteral("1973") << QStringLiteral("1990") << QStringLiteral("2000");
    for (int row = 0; row < years.size(); ++row)
    {
        model->insertRows(row, 1);
        QModelIndex index = model->index(row, 0);
        model->setData(index, years[row]);
        index = model->index(row, 1);
        model->setData(index, gdp_data[row + 1]);
        index = model->index(row, 2);
        model->setData(index, population_data[row + 1]);
        index = model->index(row, 3);
        model->setData(index, gdpPerCapita_data[row + 1]);
    }
}

QAbstractItemModel* Window::createMasterModel()
{
    QAbstractItemModel* model = new QStandardItemModel(0, 7, this);
    model->setHeaderData(0, Qt::Horizontal, tr("Country"));
    model->setHeaderData(1, Qt::Horizontal, tr("Capital"));
    model->setHeaderData(2, Qt::Horizontal, tr("Language"));
    model->setHeaderData(3, Qt::Horizontal, tr("Flag"));
    model->setHeaderData(4, Qt::Horizontal, tr("Part"));
    model->setHeaderData(5, Qt::Horizontal, tr("Photo"));
    model->setHeaderData(6, Qt::Horizontal, tr("Info"));
    QFile countriesFile(QStringLiteral(":/Countries_in_Europe.data"));
    QFile gdpFile(QStringLiteral(":/GDP_in_Europe.data"));
    QFile populationFile(QStringLiteral(":/Population_in_Europe.data"));
    QFile gdpPerCapitaFile(QStringLiteral(":/Per_capita_GDP_in_Europe.data"));

    if (!countriesFile.open(QFile::ReadOnly | QFile::Text))
        return Q_NULL;
    if (!gdpFile.open(QFile::ReadOnly | QFile::Text))
        return Q_NULL;
    if (!populationFile.open(QFile::ReadOnly | QFile::Text))
        return Q_NULL;
    if (!gdpPerCapitaFile.open(QFile::ReadOnly | QFile::Text))
        return Q_NULL;

    QTextStream countriesStream(&countriesFile);
    QTextStream gdpStream(&gdpFile);
    QTextStream populationStream(&populationFile);
    QTextStream gdpPerCapitaStream(&gdpPerCapitaFile);

    int row = 0;
    QString countriesLine = countriesStream.readLine();
    QString gdpLine = gdpStream.readLine();
    QString populationLine = populationStream.readLine();
    QString gdpPerCapitaLine = gdpPerCapitaStream.readLine();

    while (!countriesLine.isEmpty())
    {
        if (countriesLine[0] != QLatin1Char('#'))
        {
            model->insertRows(row, 1, QModelIndex());

            QStringList columns = countriesLine.split(QStringLiteral(","), Qt_SkipEmptyParts);
            simplified_strings(columns);

            QString country = columns[0];
            QString resname = country;
            resname.replace(QStringLiteral(" "), QString());

            addDetailModel(country, gdpLine, populationLine, gdpPerCapitaLine);

            QModelIndex index = model->index(row, 0, QModelIndex());
            model->setData(index, country);

            index = model->index(row, 1, QModelIndex());
            model->setData(index, columns[1]);

            index = model->index(row, 2, QModelIndex());
            model->setData(index, columns[2]);

            index = model->index(row, 3, QModelIndex());

            QPixmap flag(QStringLiteral(":/res/Flag_of_%1.png").arg(resname));
            if (flag.isNull())
            {
                Q_ASSERT(false);
            }
            model->setData(index, flag);

            index = model->index(row, 4, QModelIndex());
            model->setData(index, columns[3]);

            index = model->index(row, 5, QModelIndex());
            QPixmap photo(QStringLiteral(":/res/%1.jpg").arg(resname));
            if (photo.isNull())
            {
                Q_ASSERT(false);
            }
            model->setData(index, photo);

            index = model->index(row, 6, QModelIndex());
            model->setData(index, QStringLiteral("-"));
            row++;
        }
        countriesLine = countriesStream.readLine();
        gdpLine = gdpStream.readLine();
        gdpPerCapitaLine = gdpPerCapitaStream.readLine();
        populationLine = populationStream.readLine();
    }

    return model;
}