Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,7 @@ void MainWindow::init()
ui->fileCloseAction->setShortcuts({QKeySequence(tr("Ctrl+F4")), QKeySequence(tr("Alt+Shift+W"))});
ui->actionCloseProject->setShortcuts({QKeySequence(tr("Ctrl+Shift+W")), QKeySequence(tr("Ctrl+Shift+F4"))});
addShortcutsTooltip(ui->fileCloseAction);
addShortcutsTooltip(ui->fileRevertAction);

// Load all settings
reloadSettings();
Expand Down
3 changes: 3 additions & 0 deletions src/MainWindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -1616,6 +1616,9 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed
<property name="whatsThis">
<string>This option is used to revert the current database file to its last saved state. All changes made since the last save operation are lost.</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+R</string>
</property>
<property name="menuRole">
<enum>QAction::NoRole</enum>
</property>
Expand Down
2 changes: 2 additions & 0 deletions src/PreferencesDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ void PreferencesDialog::loadSettings()
ui->spinCompleteThreshold->setValue(Settings::getValue("databrowser", "complete_threshold").toInt());
ui->checkShowImagesInline->setChecked(Settings::getValue("databrowser", "image_preview").toBool());
ui->checkCellWordWrap->setChecked(Settings::getValue("databrowser", "cell_word_wrap").toBool());
ui->checkSortCycleNone->setChecked(Settings::getValue("databrowser", "sort_cycle_none").toBool());
ui->txtNull->setText(Settings::getValue("databrowser", "null_text").toString());
ui->txtBlob->setText(Settings::getValue("databrowser", "blob_text").toString());
ui->editFilterEscape->setText(Settings::getValue("databrowser", "filter_escape").toString());
Expand Down Expand Up @@ -209,6 +210,7 @@ void PreferencesDialog::saveSettings(bool accept)
Settings::setValue("databrowser", "fontsize", ui->spinDataBrowserFontSize->value());
Settings::setValue("databrowser", "image_preview", ui->checkShowImagesInline->isChecked());
Settings::setValue("databrowser", "cell_word_wrap", ui->checkCellWordWrap->isChecked());
Settings::setValue("databrowser", "sort_cycle_none", ui->checkSortCycleNone->isChecked());
saveColorSetting(ui->fr_null_fg, "null_fg");
saveColorSetting(ui->fr_null_bg, "null_bg");
saveColorSetting(ui->fr_reg_fg, "reg_fg");
Expand Down
18 changes: 18 additions & 0 deletions src/PreferencesDialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -1293,6 +1293,16 @@ in new project file</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="labelSortCycleNone">
<property name="text">
<string>Clicking a sorted column header a third time removes sorting</string>
</property>
<property name="buddy">
<cstring>checkSortCycleNone</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinSymbolLimit">
<property name="correctionMode">
Expand Down Expand Up @@ -1343,6 +1353,13 @@ Can be set to 0 for disabling completion.</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="checkSortCycleNone">
<property name="toolTip">
<string>Enable this option to cycle through ascending, descending and no sorting when clicking a column header, instead of only switching between ascending and descending.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down Expand Up @@ -2071,6 +2088,7 @@ Can be set to 0 for disabling completion.</string>
<tabstop>spinCompleteThreshold</tabstop>
<tabstop>checkShowImagesInline</tabstop>
<tabstop>checkCellWordWrap</tabstop>
<tabstop>checkSortCycleNone</tabstop>
<tabstop>spinFilterDelay</tabstop>
<tabstop>editFilterEscape</tabstop>
<tabstop>treeSyntaxHighlighting</tabstop>
Expand Down
2 changes: 2 additions & 0 deletions src/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ QVariant Settings::getDefaultValue(const std::string& group, const std::string&
return false;
if(name == "cell_word_wrap")
return true;
if(name == "sort_cycle_none")
return false;
if(name == "indent_compact")
return false;
if (name == "sort_keys")
Expand Down
45 changes: 14 additions & 31 deletions src/TableBrowser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,14 @@ TableBrowser::TableBrowser(DBBrowserDB* _db, QWidget* parent) :
QStyledItemDelegate* styledItemDelegate = new QStyledItemDelegate(ui->comboBrowseTable);
ui->comboBrowseTable->setItemDelegate(styledItemDelegate);

// The shortcuts of these actions only apply while the focus is inside this browser. Without adding them to this widget they would only apply
// inside the toolbar or, without a context, be ambiguous when there are multiple browsers.
addAction(ui->actionNewRecord);
addAction(ui->actionDeleteRecord);

// Add the documentation of shortcuts, which aren't otherwise visible in the user interface, to some buttons.
addShortcutsTooltip(ui->actionNewRecord);
addShortcutsTooltip(ui->actionDeleteRecord);
addShortcutsTooltip(ui->actionRefresh, {QKeySequence(tr("Ctrl+R"))});
addShortcutsTooltip(ui->actionPrintTable);

Expand Down Expand Up @@ -1213,38 +1220,14 @@ void TableBrowser::headerClicked(int logicalindex)

// 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 column was control+clicked again, change its sort order.
// If not already in the sort order, add the column as a new sort column to the list.
bool present = false;
for(sqlb::OrderBy& sortedCol : columns) {
if(sortedCol.expr == column) {
sortedCol.direction = (sortedCol.direction == sqlb::OrderBy::Ascending ? sqlb::OrderBy::Descending : sqlb::OrderBy::Ascending);
present = true;
break;
}
}
if(!present)
columns.emplace_back(column, sqlb::OrderBy::Ascending);
} else {
// Single column sorting
const bool multiColumn = QApplication::keyboardModifiers().testFlag(Qt::ControlModifier);
sqlb::updateSortColumns(columns, column, multiColumn, Settings::getValue("databrowser", "sort_cycle_none").toBool());

// 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().expr == column)
{
columns.front().direction = (columns.front().direction == sqlb::OrderBy::Ascending ? sqlb::OrderBy::Descending : sqlb::OrderBy::Ascending);
} else {
columns.clear();
columns.emplace_back(column, sqlb::OrderBy::Ascending);
}
}

// Do the actual sorting
ui->dataTable->sortByColumns(columns);
// Do the actual sorting. Sorting by no column at all is what clearing the sort columns does.
if(columns.empty())
clearSorting();
else
ui->dataTable->sortByColumns(columns);

ui->actionClearSorting->setEnabled(columns.size() > 0);

Expand Down
12 changes: 12 additions & 0 deletions src/TableBrowser.ui
Original file line number Diff line number Diff line change
Expand Up @@ -733,6 +733,12 @@
<property name="whatsThis">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This button creates a new record in the database. Hold the mouse button to open a pop-up menu of different options:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;New Record&lt;/span&gt;: insert a new record with default values in the database.&lt;/li&gt;&lt;li&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Insert Values...&lt;/span&gt;: open a dialog for entering values before they are inserted in the database. This allows to enter values accomplishing the different constraints. This dialog is also open if the &lt;span style=&quot; font-weight:600;&quot;&gt;New Record&lt;/span&gt; option fails due to these constraints.&lt;/li&gt;&lt;/ul&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+N</string>
</property>
<property name="shortcutContext">
<enum>Qt::WidgetWithChildrenShortcut</enum>
</property>
</action>
<action name="actionDeleteRecord">
<property name="icon">
Expand All @@ -751,6 +757,12 @@
<property name="whatsThis">
<string>This button deletes the record or records currently selected in the table</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+D</string>
</property>
<property name="shortcutContext">
<enum>Qt::WidgetWithChildrenShortcut</enum>
</property>
</action>
<action name="newRecordAction">
<property name="icon">
Expand Down
37 changes: 37 additions & 0 deletions src/sql/Query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,41 @@ std::vector<SelectedColumn>::const_iterator Query::findSelectedColumnByName(cons
});
}

void updateSortColumns(std::vector<OrderBy>& columns, const std::string& column, bool multi_column, bool cycle_to_none)
{
auto toggle = [](OrderBy& sorted_column) {
sorted_column.direction = (sorted_column.direction == OrderBy::Ascending ? OrderBy::Descending : OrderBy::Ascending);
};

if(multi_column)
{
// If the column is in the sort order already, change its sort order. If not, add it as a new sort column to the list.
for(auto it = columns.begin(); it != columns.end(); ++it)
{
if(it->expr == column)
{
if(cycle_to_none && it->direction == OrderBy::Descending)
columns.erase(it);
else
toggle(*it);
return;
}
}
columns.emplace_back(column, OrderBy::Ascending);
} else {
// If we have exactly one sort column and it is the column which was just clicked, change its sort order.
// If not, replace the list of sort columns by a single new sort column.
if(columns.size() == 1 && columns.front().expr == column)
{
if(cycle_to_none && columns.front().direction == OrderBy::Descending)
columns.clear();
else
toggle(columns.front());
} else {
columns.clear();
columns.emplace_back(column, OrderBy::Ascending);
}
}
}

}
6 changes: 6 additions & 0 deletions src/sql/Query.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,12 @@ class Query
std::string buildWherePart() const;
};

// Update the list of sort columns after the header of the given column was clicked. With multi_column set (Ctrl+click) the column is added to
// the list or, if it already is in there, its direction is changed. Otherwise the list is replaced by that column or, if it already is the only
// sort column, its direction is changed. When cycle_to_none is set, changing the direction of a descending column removes it from the list
// instead, so repeated clicks cycle through ascending, descending and no sorting.
void updateSortColumns(std::vector<OrderBy>& columns, const std::string& column, bool multi_column, bool cycle_to_none);

}

#endif
35 changes: 35 additions & 0 deletions src/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,38 @@ set(TESTCACHE_HDR
add_executable(test-cache ${TESTCACHE_HDR} ${TESTCACHE_SRC})
target_link_libraries(test-cache ${QT_MAJOR}::Test)
add_test(NAME test-cache COMMAND $<TARGET_FILE:test-cache>)

# test sort cycle

set(TESTSORTCYCLE_SRC
TestSortCycle.cpp
../sql/Query.cpp
../sql/ObjectIdentifier.cpp
)

set(TESTSORTCYCLE_HDR
TestSortCycle.h
../sql/Query.h
../sql/ObjectIdentifier.h
)

add_executable(test-sort-cycle ${TESTSORTCYCLE_HDR} ${TESTSORTCYCLE_SRC})
target_link_libraries(test-sort-cycle ${QT_MAJOR}::Test)
add_test(NAME test-sort-cycle COMMAND $<TARGET_FILE:test-sort-cycle>)
set_tests_properties(test-sort-cycle PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen")

# test action shortcuts

set(TESTACTIONSHORTCUTS_SRC
TestActionShortcuts.cpp
)

set(TESTACTIONSHORTCUTS_HDR
TestActionShortcuts.h
)

add_executable(test-action-shortcuts ${TESTACTIONSHORTCUTS_HDR} ${TESTACTIONSHORTCUTS_SRC})
target_compile_definitions(test-action-shortcuts PRIVATE SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}/..")
target_link_libraries(test-action-shortcuts ${QT_MAJOR}::Test ${QT_MAJOR}::Widgets)
add_test(NAME test-action-shortcuts COMMAND $<TARGET_FILE:test-action-shortcuts>)
set_tests_properties(test-action-shortcuts PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen")
Loading
Loading