Add support for sorting by multiple columns in the Browse Data tab

This allows sorting by multiple columns (as in ORDER BY Field1, Field2)
by holding the Control key while clicking on another column header in
the Browse Data tab.

See issue #1761.
This commit is contained in:
Martin Kleusberg
2019-03-01 11:32:38 +01:00
parent 00bc7db5c0
commit f3a54e4c71
6 changed files with 76 additions and 42 deletions

View File

@@ -80,20 +80,7 @@ QDataStream& operator>>(QDataStream& ds, sqlb::ObjectIdentifier& objid)
return ds;
}
// These are temporary helper functions to turn a vector of sorted columns into a single column to sort and vice verse. This is done by just taking the
// first sort column there is and ignoring all the others or creating a single item vector respectively. These functions can be removed once all parts
// of the application have been converted to deal with vectors of sorted columns.
static void fromSortOrderVector(const std::vector<sqlb::SortedColumn>& vector, int& index, Qt::SortOrder& mode)
{
if(vector.size())
{
index = vector.at(0).column;
mode = vector.at(0).direction == sqlb::Ascending ? Qt::AscendingOrder : Qt::DescendingOrder;
} else {
index = 0;
mode = Qt::AscendingOrder;
}
}
// This is a temporary helper function. Delete it once we clean up the project file loading.
static std::vector<sqlb::SortedColumn> toSortOrderVector(int index, Qt::SortOrder mode)
{
std::vector<sqlb::SortedColumn> vector;
@@ -777,10 +764,7 @@ void MainWindow::populateTable()
sqlb::Query query(tablename);
// Sorting
int sortOrderIndex;
Qt::SortOrder sortOrderMode;
fromSortOrderVector(storedData.query.orderBy(), sortOrderIndex, sortOrderMode);
query.orderBy().emplace_back(sortOrderIndex, sortOrderMode == Qt::AscendingOrder ? sqlb::Ascending : sqlb::Descending);
query.orderBy() = storedData.query.orderBy();
// Filters
for(auto it=storedData.filterValues.constBegin();it!=storedData.filterValues.constEnd();++it)
@@ -863,10 +847,10 @@ void MainWindow::applyBrowseTableSettings(BrowseDataTableSettings storedData, bo
ui->dataTable->setColumnWidth(widthIt.key(), widthIt.value());
// Sorting
int sortOrderIndex;
Qt::SortOrder sortOrderMode;
fromSortOrderVector(storedData.query.orderBy(), sortOrderIndex, sortOrderMode);
ui->dataTable->filterHeader()->setSortIndicator(sortOrderIndex, sortOrderMode);
// For now just use the first sort column for the sort indicator
ui->dataTable->filterHeader()->setSortIndicator(
storedData.query.orderBy().front().column,
storedData.query.orderBy().front().direction == sqlb::Ascending ? Qt::AscendingOrder : Qt::DescendingOrder);
// Filters
if(!skipFilters)
@@ -2010,19 +1994,44 @@ void MainWindow::browseTableHeaderClicked(int logicalindex)
// Abort if there is more than one column selected because this tells us that the user pretty sure wants to do a range selection
// instead of sorting data. But restore before the sort indicator automatically changed by Qt so it still indicates the last
// use sort action.
if(ui->dataTable->selectionModel()->selectedColumns().count() > 1) {
// This check is disabled when the Control key is pressed. This is done because we use the Control key for sorting by multiple columns and
// Qt seems to pretty much always select multiple columns when the Control key is pressed.
if(!QApplication::keyboardModifiers().testFlag(Qt::ControlModifier) && ui->dataTable->selectionModel()->selectedColumns().count() > 1) {
applyBrowseTableSettings(settings);
return;
}
int column;
Qt::SortOrder order;
fromSortOrderVector(settings.query.orderBy(), column, order);
if(column == logicalindex)
order = order == Qt::AscendingOrder ? Qt::DescendingOrder : Qt::AscendingOrder;
else
order = Qt::AscendingOrder;
settings.query.orderBy() = toSortOrderVector(logicalindex, order);
ui->dataTable->sortByColumn(logicalindex, order);
// Get the current list of sort columns
auto& columns = settings.query.orderBy();
// Before sorting, first check if the Control key is pressed. If it is, we want to append this column to the list of sort columns. If it is not,
// we want to sort only by the new column.
if(QApplication::keyboardModifiers().testFlag(Qt::ControlModifier))
{
// Multi column sorting
// If the last sort column was just clicked again, change its sort order.
// If not, add the column as a new sort column to the list.
if(columns.size() && columns.back().column == logicalindex)
columns.back().direction = (columns.back().direction == sqlb::Ascending ? sqlb::Descending : sqlb::Ascending);
else
columns.emplace_back(logicalindex, sqlb::Ascending);
} else {
// Single column sorting
// If we have exactly one sort column and it is the column which was just clicked, change its sort order.
// If not, clear the list of sorting columns and replace it by a single new sort column.
if(columns.size() == 1 && columns.front().column == logicalindex)
{
columns.front().direction = (columns.front().direction == sqlb::Ascending ? sqlb::Descending : sqlb::Ascending);
} else {
columns.clear();
columns.emplace_back(logicalindex, sqlb::Ascending);
}
}
// Do the actual sorting
ui->dataTable->sortByColumns(columns);
// select the first item in the column so the header is bold
// we might try to select the last selected item
@@ -2821,10 +2830,7 @@ bool MainWindow::loadProject(QString filename, bool readOnly)
populateTable(); // Refresh view
sqlb::ObjectIdentifier current_table = currentlyBrowsedTableName();
int sortIndex;
Qt::SortOrder sortMode;
fromSortOrderVector(browseTableSettings[current_table].query.orderBy(), sortIndex, sortMode);
ui->dataTable->sortByColumn(sortIndex, sortMode);
ui->dataTable->sortByColumns(browseTableSettings[current_table].query.orderBy());
showRowidColumn(browseTableSettings[current_table].showRowid);
unlockViewEditing(!browseTableSettings[current_table].unlockViewPk.isEmpty(), browseTableSettings[current_table].unlockViewPk);
}