CustomFilter Example

#include <QtGui>
#include <QMessageBox>
#include <QFileDialog>

#include "window.h"

/* Window */
Window::Window()
: DemoMainWindow(QStringLiteral("QtitanDataGrid"), QStringLiteral(QTN_VERSION_DATAGRID_STR), tr("Custom Filters"))
{
    Grid::loadTranslation();

    m_grid = new Qtitan::Grid();
    CustomFilterModel* model = new CustomFilterModel(m_grid);
    qRegisterMetaType<CustomFilterCondition>(CustomFilterCondition::xml_name.toLatin1());

    // Configure grid view
    m_grid->setViewType(Qtitan::Grid::TableView);
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();

    view->beginUpdate();

    view->options().setGridLineWidth(0);
    view->tableOptions().setColumnAutoWidth(true);
    view->options().setSelectionPolicy(GridViewOptions::MultiRowSelection);
    view->options().setFastScrollEffect(true);

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

    view->setModel(model);

    Qtitan::GridTableColumn* column = static_cast<Qtitan::GridTableColumn*>(view->getColumn(0));
    column->setEditorType(GridEditor::Numeric);
    static_cast<Qtitan::GridNumericEditorRepository *>(column->editorRepository())->setMinimum(-10000);
    static_cast<Qtitan::GridNumericEditorRepository *>(column->editorRepository())->setMaximum(10000);
    column->editorRepository()->setEditorActivationPolicy(
        GridEditor::ActivationPolicy(GridEditor::ActivateByDblClick | GridEditor::ActivateByEditPress));

    column = static_cast<Qtitan::GridTableColumn *>(view->getColumn(1));
    column->setEditorType(GridEditor::String);
    column->editorRepository()->setValidateOnEnter(false);
    column->editorRepository()->setEditorActivationPolicy(
        GridEditor::ActivationPolicy(GridEditor::ActivateByDblClick | GridEditor::ActivateByEditPress));

    column = static_cast<Qtitan::GridTableColumn *>(view->getColumn(2));
    column->setEditorType(GridEditor::Date);
    column->editorRepository()->setAutoSelect(true);
    column->editorRepository()->setEditorActivationPolicy(
        GridEditor::ActivationPolicy(GridEditor::ActivateByDblClick | GridEditor::ActivateByEditPress));

    column = (Qtitan::GridTableColumn *)view->getColumn(3);
    column->setEditorType(GridEditor::Time);
    column->editorRepository()->setAutoSelect(true);
    column->editorRepository()->setEditorActivationPolicy(
        GridEditor::ActivationPolicy(GridEditor::ActivateByDblClick | GridEditor::ActivateByEditPress));

    //Create settings widget
    QWidget* settings = new QWidget(this);
    QVBoxLayout* l = new QVBoxLayout(settings);

    QLabel* text = new QLabel(settings);
    text->setText(tr("Select several rows and press 'Set Filter' button to apply filter to these rows."));
    text->setWordWrap(true);
    l->addWidget(text);

    QPushButton* filterButton = new QPushButton(settings);
    filterButton->setText(tr("Set Filter"));
    connect(filterButton, SIGNAL(clicked()), this, SLOT(applyFilter()));
    l->addWidget(filterButton);

    QHBoxLayout* hblayout = new QHBoxLayout();
    QPushButton* saveButton = new QPushButton(settings);
    saveButton->setText(tr("Save Filter (new)"));
    connect(saveButton, SIGNAL(clicked()), this, SLOT(saveFilter()));
    hblayout->addWidget(saveButton);
    QPushButton* loadButton = new QPushButton(settings);
    loadButton->setText(tr("Load Filter (new)"));
    connect(loadButton, SIGNAL(clicked()), this, SLOT(loadFilter()));
    hblayout->addWidget(loadButton);
    l->addLayout(hblayout);

    view->endUpdate();

    setDemoWidget(m_grid, settings);

    setMinimumHeight(10);
}

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::focusRowChanged(int oldRowIndex, int rowIndex)
{
    Q_UNUSED(oldRowIndex);
    Q_UNUSED(rowIndex);
}

void Window::applyFilter()
{
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    GridFilterGroupCondition* groupCondition = new GridFilterGroupCondition(view->filter());
    CustomFilterCondition* condition = new CustomFilterCondition(view->filter());
    groupCondition->addCondition(condition);

    GridSelection* selection = view->selection();
    while (!selection->end())
    {
        GridRow row = selection->row();
        condition->addRow(row.modelIndex().row());
        selection->next();
    }

    view->filter()->setCondition(groupCondition, true /* add to history */);
    view->filter()->setActive(true);

    view->showFilterPanel();
}

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

void Window::saveFilter()
{
    QString fileName = QFileDialog::getSaveFileName(this,
        tr("Save QtitanDataGrid Filter to File"), QStringLiteral("qtitan-filter.xml"), tr("Filter-XML (*.xml)"));
    if (fileName.isEmpty())
        return;
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    view->filter()->saveToFile(fileName);
}

void Window::loadFilter()
{
    QStringList files = QFileDialog::getOpenFileNames(this,
        tr("Open QtitanDataGrid Filter File"), QString(), tr("Filter-XML (*.xml)"));
    if (files.size() != 1 || files[0].isEmpty())
        return;
    Qtitan::GridTableView* view = m_grid->view<Qtitan::GridTableView>();
    view->filter()->loadFromFile(files[0]);
}

/* CustomFilterCondition */
CustomFilterCondition::CustomFilterCondition(GridFilter* filter)
    : GridFilterCondition(filter) { }

bool CustomFilterCondition::isTrue(const QModelIndex& index)
{
    return m_modelRows.contains(index.row());
}

GridFilterCondition* CustomFilterCondition::clone() const
{
    CustomFilterCondition* retval = new CustomFilterCondition(m_filter);
    retval->m_modelRows = m_modelRows;
    return retval;
}

QString CustomFilterCondition::createPresentation() const
{
    QString retval = QObject::tr("custom filter: row in (");
    QList<int> list = m_modelRows.values();
    std::sort(list.begin(), list.end());
    for (QList<int>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it)
    {
        if (it != list.constBegin())
            retval += QStringLiteral(", ");
        retval += QString::number(*it);
    }
    retval += QStringLiteral(")");
    return retval;
}

int CustomFilterCondition::conditionCount() const
{
    return m_modelRows.size();
}

QString CustomFilterCondition::xml_name = QStringLiteral("CustomCondition");

#ifndef QTN_NOUSE_XML_MODULE
bool CustomFilterCondition::saveToXML(IXmlStreamWriter* xmlwriter)
{
    xmlwriter->writeStartElement(QStringLiteral("Qtitan:%1").arg(xml_name));
    for (QSet<int>::const_iterator it = m_modelRows.constBegin(); it != m_modelRows.constEnd(); ++it)
    {
        xmlwriter->writeStartElement(QStringLiteral("Qtitan:Row"));
        xmlwriter->writeAttribute(QStringLiteral("index"), QStringLiteral("%1").arg(*it));
        xmlwriter->writeEndElement();
    }
    xmlwriter->writeEndElement();
    return true;
}

bool CustomFilterCondition::loadFromXML(IXmlStreamReader* xmlreader)
{
    m_modelRows.clear();
    if (xmlreader->tokenType() != QXmlStreamReader::StartElement ||
        xmlreader->qualifiedName() != QStringLiteral("Qtitan:%1").arg(xml_name))
        return false;
    while (xmlreader->readNextStartElement())
    {
        if (xmlreader->qualifiedName() != QStringLiteral("Qtitan:Row"))
            return false;
        QXmlStreamAttributes attrs = xmlreader->attributes();
        if (attrs.hasAttribute(QStringLiteral("index")))
            m_modelRows.insert(attrs.value(QStringLiteral("index")).toInt());
        xmlreader->skipCurrentElement();
    }
    return true;
}
#endif

void CustomFilterCondition::addRow(int modelRowIndex)
{
    m_modelRows.insert(modelRowIndex);
}

void CustomFilterCondition::removeRow(int modelRowIndex)
{
    m_modelRows.remove(modelRowIndex);
}

/* CustomFilterModel */
CustomFilterModel::CustomFilterModel(QObject *parent)
: QAbstractItemModel(parent)
{
    m_values.resize(100);
    int y = 2012;
    int m = 1;
    int d = 1;
    for (int i = 0; i < m_values.size(); ++i)
    {
        m_values[i].v0 = i;
        m_values[i].v1 = QStringLiteral("String = %1").arg(i);
        m_values[i].v3 = QTime(12, 0, 0);
        if (d > 28)
        {
            d = 1;
            m++;
            if (m > 12)
            {
                m = 1;
                y++;
            }
        }
        m_values[i].v2 = QDate(y, m, d);
        if (!((i + 1) % 10))
            d++;
    }
}

QVariant CustomFilterModel::headerData(int section, Qt::Orientation orientation,
                                      int role) const
{
    Q_UNUSED(orientation);
    Q_UNUSED(role);
    switch (section)
    {
    case 0:
        return QStringLiteral("Integer");
    case 1:
        return QStringLiteral("String");
    case 2:
        return QStringLiteral("Date");
    case 3:
        return QStringLiteral("Time");
    default:
        break;
    }
    return QVariant();
}

QModelIndex CustomFilterModel::parent(const QModelIndex & /*child*/) const
{
    return QModelIndex();
}

bool CustomFilterModel::hasChildren(const QModelIndex &parent) const
{
    if (parent.model() == this || !parent.isValid())
    {
        return rowCount(parent) > 0 && columnCount(parent) > 0;
    }
    return false;
}

int CustomFilterModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    return m_values.size();
}

int CustomFilterModel::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    return 4;
}

QModelIndex CustomFilterModel::index(int row, int column, const QModelIndex &parent) const
{
    if (parent.isValid())
        return QModelIndex();

    if (row < 0 || row >= rowCount(parent))
        return QModelIndex();

    if (column < 0 || column >= columnCount(parent))
        return QModelIndex();

    return createIndex(row, column, Q_NULL);
}

QVariant CustomFilterModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (index.row() < 0 || index.row() >= rowCount(index.parent()))
        return QVariant();

    if (index.column() < 0 || index.column() >= columnCount(index.parent()))
        return QVariant();

    if (role == Qt::DisplayRole || role == Qt::EditRole)
    {
        switch (index.column())
        {
        case 0:
            return m_values[index.row()].v0;
        case 1:
            return m_values[index.row()].v1;
        case 2:
            return m_values[index.row()].v2;
        case 3:
            return m_values[index.row()].v3;
        }
    }
    else if (role == Qt::CheckStateRole)
    {
        switch (index.column())
        {
        case 0:
            return m_values[index.row()].v0;
        }
    }
    return QVariant();
}

bool CustomFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (!index.isValid())
        return false;

    if (index.row() < 0 || index.row() >= rowCount(index.parent()))
        return false;

    if (index.column() < 0 || index.column() >= columnCount(index.parent()))
        return false;

    if (role != Qt::EditRole)
        return false;

    switch (index.column())
    {
    case 0:
        {
            m_values[index.row()].v0 = value.toInt();
        }
        break;
    case 1:
        {
            m_values[index.row()].v1 = value.toString();
        }
        break;
    case 2:
        {
            m_values[index.row()].v2 = value.toDate();
        }
        break;
    case 3:
        {
            m_values[index.row()].v3 = value.toTime();
        }
        break;
    default:
        break;
    }

    emit dataChanged(index, index);
    return true;
}

Qt::ItemFlags CustomFilterModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return Qt::ItemFlags();
    return Qt::ItemIsEnabled | Qt::ItemIsEditable;
}