Cut to clipboard operation in data browsers

"Cut" copies the cells to clipboard and then deletes the data taking into
account a possible NOT NULL constraint in the field to leave the cell empty
instead of setting it to NULL. Rowid column is ignored.

See issue #2355
This commit is contained in:
mgrojo
2020-08-06 22:22:21 +02:00
parent 4bf7adfa59
commit 09320c20e4
4 changed files with 34 additions and 0 deletions

View File

@@ -259,6 +259,7 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
QAction* condFormatAction = new QAction(QIcon(":/icons/edit_cond_formats"), tr("Edit Conditional Formats..."), m_contextMenu);
QAction* nullAction = new QAction(QIcon(":/icons/set_to_null"), tr("Set to NULL"), m_contextMenu);
QAction* cutAction = new QAction(QIcon(":/icons/cut"), tr("Cut"), m_contextMenu);
QAction* copyAction = new QAction(QIcon(":/icons/copy"), tr("Copy"), m_contextMenu);
QAction* copyWithHeadersAction = new QAction(QIcon(":/icons/special_copy"), tr("Copy with Headers"), m_contextMenu);
QAction* copyAsSQLAction = new QAction(QIcon(":/icons/sql_copy"), tr("Copy as SQL"), m_contextMenu);
@@ -281,6 +282,7 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
m_contextMenu->addSeparator();
m_contextMenu->addAction(nullAction);
m_contextMenu->addSeparator();
m_contextMenu->addAction(cutAction);
m_contextMenu->addAction(copyAction);
m_contextMenu->addAction(copyWithHeadersAction);
m_contextMenu->addAction(copyAsSQLAction);
@@ -296,6 +298,7 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
// This is only for displaying the shortcut in the context menu.
// An entry in keyPressEvent is still needed.
nullAction->setShortcut(QKeySequence(tr("Alt+Del")));
cutAction->setShortcut(QKeySequence::Cut);
copyAction->setShortcut(QKeySequence::Copy);
copyWithHeadersAction->setShortcut(QKeySequence(tr("Ctrl+Shift+C")));
copyAsSQLAction->setShortcut(QKeySequence(tr("Ctrl+Alt+C")));
@@ -325,6 +328,7 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
// Try to find out whether the current view is editable and (de)activate menu options according to that
bool editable = editTriggers() != QAbstractItemView::NoEditTriggers;
nullAction->setEnabled(enabled && editable);
cutAction->setEnabled(enabled && editable);
pasteAction->setEnabled(enabled && editable);
// Show menu
@@ -371,6 +375,7 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
connect(copyAction, &QAction::triggered, [&]() {
copy(false, false);
});
connect(cutAction, &QAction::triggered, this, &ExtendedTableWidget::cut);
connect(copyWithHeadersAction, &QAction::triggered, [&]() {
copy(true, false);
});
@@ -719,6 +724,30 @@ void ExtendedTableWidget::paste()
}
}
void ExtendedTableWidget::cut()
{
const QModelIndexList& indices = selectionModel()->selectedIndexes();
SqliteTableModel* m = qobject_cast<SqliteTableModel*>(model());
sqlb::TablePtr currentTable = m->db().getObjectByName<sqlb::Table>(m->currentTableName());
copy(false, false);
// Check if the column in the selection has a NOT NULL constraint, then update with an empty string, else with NULL
if(currentTable) {
for(const QModelIndex& index : indices) {
// Do not process rowid column
if(index.column() != 0) {
size_t indexField = static_cast<size_t>(index.column()-1);
const sqlb::Field& field = currentTable->fields.at(indexField);
const QVariant newValue = field.notnull() ? QVariant("") : QVariant();
// Update aborting in case of any error (to avoid repetitive errors like "Database is locked"
if(!model()->setData(index, newValue))
return;
}
}
}
}
void ExtendedTableWidget::useAsFilter(const QString& filterOperator, bool binary, const QString& operatorSuffix)
{
QModelIndex index = selectionModel()->currentIndex();
@@ -776,6 +805,9 @@ void ExtendedTableWidget::keyPressEvent(QKeyEvent* event)
{
copy(false, false);
return;
} else if(event->matches(QKeySequence::Cut)) {
// Call a custom cut method when Ctrl-X is pressed
cut();
} else if(event->matches(QKeySequence::Paste)) {
// Call a custom paste method when Ctrl-V is pressed
paste();

View File

@@ -81,6 +81,7 @@ private:
void copyMimeData(const QModelIndexList& fromIndices, QMimeData* mimeData, const bool withHeaders, const bool inSQL);
void copy(const bool withHeaders, const bool inSQL);
void paste();
void cut();
void useAsFilter(const QString& filterOperator, bool binary = false, const QString& operatorSuffix = QString());
void duplicateUpperCell();

BIN
src/icons/cut.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

View File

@@ -103,5 +103,6 @@
<file alias="open_data_in_app">application_go.png</file>
<file>monitor_link.png</file>
<file alias="clone_database">server_add.png</file>
<file alias="cut">cut.png</file>
</qresource>
</RCC>