Files
sqlitebrowser/src/FilterTableHeader.cpp
Manuel abb6f686a3 Initial implementation of "conditional formatting" (#1503)
After setting a filter, the user can select from the context menu in the
filter line a new option "Use for Conditional Format", that assigns
automatically a colour to the background of cells fulfilling that
condition.

The formatting is preserved after the user has removed the filter. Several
conditional formats can be successively added to a column using different
filters.

The conditional formats of a column can be cleared when the filter is empty
selecting "Clear All Conditional Formats" from the filter line context
menu.

The conditional formats are saved and loaded in project files as other
browse table settings.

A new class Palette has been added for reusing the automatic colour
assignment of the Plot Dock. It takes into account the theme kind of the
application (dark, light) for the colour selection.

A new class CondFormat for using the conditional formatting settings from
several classes. The conversion of a filter string from our format to an
SQL condition has been moved here for reuse in filters and conditional
formatting.

Whether the conditional format applies is resolved by SQLite, so filters
and conditional formats give the same exact results.

Code for getting a pragma value has been reused for getting the condition
result, and consequently renamed to selectSingleCell.

Possible future improvement:
- New dialog for editing the conditional formatting (at least colour and
application order of conditions, but maybe too: adding new conditions and
editing the condition itself).
2018-10-30 21:22:14 +01:00

114 lines
4.3 KiB
C++

#include "FilterTableHeader.h"
#include "FilterLineEdit.h"
#include <QApplication>
#include <QTableView>
#include <QScrollBar>
FilterTableHeader::FilterTableHeader(QTableView* parent) :
QHeaderView(Qt::Horizontal, parent)
{
// Activate the click signals to allow sorting
setSectionsClickable(true);
setSortIndicatorShown(true);
// Do some connects: Basically just resize and reposition the input widgets whenever anything changes
connect(this, SIGNAL(sectionResized(int,int,int)), this, SLOT(adjustPositions()));
connect(parent->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjustPositions()));
connect(parent->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjustPositions()));
// Set custom context menu handling
setContextMenuPolicy(Qt::CustomContextMenu);
}
void FilterTableHeader::generateFilters(int number, bool showFirst)
{
// Delete all the current filter widgets
qDeleteAll(filterWidgets);
filterWidgets.clear();
// And generate a bunch of new ones
for(int i=0;i < number; ++i)
{
FilterLineEdit* l = new FilterLineEdit(this, &filterWidgets, i);
if(!showFirst && i == 0) // This hides the first input widget which belongs to the hidden rowid column
l->setVisible(false);
else
l->setVisible(true);
connect(l, SIGNAL(delayedTextChanged(QString)), this, SLOT(inputChanged(QString)));
connect(l, SIGNAL(addFilterAsCondFormat(QString)), this, SLOT(addFilterAsCondFormat(QString)));
connect(l, SIGNAL(clearAllCondFormats()), this, SLOT(clearAllCondFormats()));
filterWidgets.push_back(l);
}
// Position them correctly
adjustPositions();
}
QSize FilterTableHeader::sizeHint() const
{
// For the size hint just take the value of the standard implementation and add the height of a input widget to it if necessary
QSize s = QHeaderView::sizeHint();
if(filterWidgets.size())
s.setHeight(s.height() + filterWidgets.at(0)->sizeHint().height() + 5); // The 5 adds just adds some extra space
return s;
}
void FilterTableHeader::updateGeometries()
{
// If there are any input widgets add a viewport margin to the header to generate some empty space for them which is not affected by scrolling
if(filterWidgets.size())
setViewportMargins(0, 0, 0, filterWidgets.at(0)->sizeHint().height());
else
setViewportMargins(0, 0, 0, 0);
// Now just call the parent implementation and reposition the input widgets
QHeaderView::updateGeometries();
adjustPositions();
}
void FilterTableHeader::adjustPositions()
{
// Loop through all widgets
for(int i=0;i < filterWidgets.size(); ++i)
{
// Get the current widget, move it and resize it
QWidget* w = filterWidgets.at(i);
if (QApplication::layoutDirection() == Qt::RightToLeft)
w->move(width() - (sectionPosition(i) + sectionSize(i) - offset()), w->sizeHint().height() + 2); // The two adds some extra space between the header label and the input widget
else
w->move(sectionPosition(i) - offset(), w->sizeHint().height() + 2); // The two adds some extra space between the header label and the input widget
w->resize(sectionSize(i), w->sizeHint().height());
}
}
void FilterTableHeader::inputChanged(const QString& new_value)
{
// Just get the column number and the new value and send them to anybody interested in filter changes
emit filterChanged(sender()->property("column").toInt(), new_value);
}
void FilterTableHeader::addFilterAsCondFormat(const QString& filter)
{
// Just get the column number and the new value and send them to anybody interested in new conditional formatting
emit addCondFormat(sender()->property("column").toInt(), filter);
}
void FilterTableHeader::clearAllCondFormats()
{
// Just get the column number and send it to anybody responsible or interested in clearing conditional formatting
emit clearAllCondFormats(sender()->property("column").toInt());
}
void FilterTableHeader::clearFilters()
{
for(FilterLineEdit* filterLineEdit : filterWidgets)
filterLineEdit->clear();
}
void FilterTableHeader::setFilter(int column, const QString& value)
{
if(column < filterWidgets.size())
filterWidgets.at(column)->setText(value);
}