Skip to content

Commit 8f5c17e

Browse files
committed
Edit Database Cell: fixed potential for data loss and better feedback
Remaining detected case for a potential data loss in the cell editor have been fixed: - Switching to another main tab. - Start a filter. In both cases a dialog for saving or discarding is open. Additionally, the cell editor shows the cell coordinates currently open. And the NULL text in margin is reset when the user types in the editor. See issue #2488
1 parent 974954f commit 8f5c17e

File tree

10 files changed

+79
-31
lines changed

10 files changed

+79
-31
lines changed

src/EditDialog.cpp

Lines changed: 54 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -110,20 +110,29 @@ EditDialog::~EditDialog()
110110
delete ui;
111111
}
112112

113-
void EditDialog::setCurrentIndex(const QModelIndex& idx)
113+
void EditDialog::promptSaveData()
114114
{
115-
if (m_currentIndex != QPersistentModelIndex(idx) && ui->buttonApply->isEnabled() &&
116-
(sciEdit->isModified() || ui->qtEdit->document()->isModified() || hexEdit->isModified())) {
115+
if (m_currentIndex.isValid() && isModified()) {
117116

118117
QMessageBox::StandardButton reply = QMessageBox::question(
119118
this,
120119
tr("Unsaved data in the cell editor"),
121120
tr("The cell editor contains data not yet applied to the database.\n"
122-
"Do you want to apply the edited data?"),
123-
QMessageBox::Apply | QMessageBox::Discard);
121+
"Do you want to apply the edited data to row=%1, column=%2?")
122+
.arg(m_currentIndex.row() + 1).arg(m_currentIndex.column()),
123+
QMessageBox::Apply | QMessageBox::Discard, QMessageBox::Apply);
124124

125125
if (reply == QMessageBox::Apply)
126126
accept();
127+
else
128+
reject();
129+
}
130+
}
131+
132+
void EditDialog::setCurrentIndex(const QModelIndex& idx)
133+
{
134+
if (m_currentIndex != QPersistentModelIndex(idx)) {
135+
promptSaveData();
127136
}
128137

129138
setDisabled(!idx.isValid());
@@ -132,11 +141,27 @@ void EditDialog::setCurrentIndex(const QModelIndex& idx)
132141

133142
QByteArray bArrData = idx.data(Qt::EditRole).toByteArray();
134143
loadData(bArrData);
144+
if (idx.isValid()) {
145+
ui->labelCell->setText(tr("Editing row=%1, column=%2")
146+
.arg(m_currentIndex.row() + 1).arg(m_currentIndex.column()));
147+
} else {
148+
ui->labelCell->setText(tr("No cell active."));
149+
}
135150
updateCellInfoAndMode(bArrData);
136151

137-
ui->buttonApply->setDisabled(true);
138-
sciEdit->setModified(false);
139-
ui->qtEdit->document()->setModified(false);
152+
setModified(false);
153+
}
154+
155+
bool EditDialog::isModified() const
156+
{
157+
return (sciEdit->isModified() || ui->qtEdit->document()->isModified());
158+
}
159+
160+
void EditDialog::setModified(bool modified)
161+
{
162+
ui->buttonApply->setEnabled(modified);
163+
sciEdit->setModified(modified);
164+
ui->qtEdit->document()->setModified(modified);
140165
}
141166

142167
void EditDialog::showEvent(QShowEvent*)
@@ -154,7 +179,7 @@ void EditDialog::reject()
154179
{
155180
// We override this, to ensure the Escape key doesn't make the Edit Cell
156181
// dock go away
157-
return;
182+
setCurrentIndex(m_currentIndex);
158183
}
159184

160185
// Loads data from a cell into the Edit Cell window
@@ -663,6 +688,7 @@ void EditDialog::accept()
663688
// The data is different, so commit it back to the database
664689
emit recordTextUpdated(m_currentIndex, removedBom + newTextData.toUtf8(), false);
665690
}
691+
setModified(false);
666692
}
667693

668694
void EditDialog::setDataInBuffer(const QByteArray& bArrdata, DataSources source)
@@ -888,12 +914,14 @@ void EditDialog::editTextChanged()
888914

889915
// If data has been entered in the text editor, it can't be a NULL
890916
// any more. It hasn't been validated yet, so it cannot be JSON nor XML.
891-
if (dataType == Null && isModified && dataLength != 0)
917+
if (dataType == Null && isModified && dataLength != 0) {
892918
dataType = Text;
893-
894-
if (dataType != Null)
895-
ui->labelType->setText(tr("Type of data currently in cell: Text / Numeric"));
896-
ui->labelSize->setText(tr("%n character(s)", "", dataLength));
919+
sciEdit->clearTextInMargin();
920+
}
921+
if (dataType == Null)
922+
ui->labelInfo->setText(tr("Type: NULL; Size: 0 bytes"));
923+
else
924+
ui->labelInfo->setText(tr("Type: Text / Numeric; Size: %n character(s)", "", dataLength));
897925
}
898926
}
899927

@@ -989,6 +1017,9 @@ void EditDialog::setFocus()
9891017
// Sets or unsets read-only properties for the editors.
9901018
void EditDialog::setReadOnly(bool ro)
9911019
{
1020+
if (ro && !isReadOnly) {
1021+
promptSaveData();
1022+
}
9921023
isReadOnly = ro;
9931024

9941025
ui->buttonApply->setEnabled(!ro);
@@ -1050,15 +1081,16 @@ void EditDialog::updateCellInfoAndMode(const QByteArray& bArrdata)
10501081
// Display the image format
10511082
QString imageFormat = imageReader.format();
10521083

1053-
ui->labelType->setText(tr("Type of data currently in cell: %1 Image").arg(imageFormat.toUpper()));
1054-
10551084
// Display the image dimensions and size
10561085
QSize imageDimensions = imageReader.size();
10571086
unsigned int imageSize = static_cast<unsigned int>(cellData.size());
10581087

1059-
QString labelSizeText = tr("%1x%2 pixel(s)").arg(imageDimensions.width()).arg(imageDimensions.height()) + ", " + humanReadableSize(imageSize);
1088+
QString labelInfoText = tr("Type: %1 Image; Size: %2x%3 pixel(s)")
1089+
.arg(imageFormat.toUpper())
1090+
.arg(imageDimensions.width()).arg(imageDimensions.height())
1091+
+ ", " + humanReadableSize(imageSize);
10601092

1061-
ui->labelSize->setText(labelSizeText);
1093+
ui->labelInfo->setText(labelInfoText);
10621094

10631095
return;
10641096
}
@@ -1067,8 +1099,7 @@ void EditDialog::updateCellInfoAndMode(const QByteArray& bArrdata)
10671099
switch (dataType) {
10681100
case Null: {
10691101
// NULL data type
1070-
ui->labelType->setText(tr("Type of data currently in cell: NULL"));
1071-
ui->labelSize->setText(tr("%n byte(s)", "", 0));
1102+
ui->labelInfo->setText(tr("Type: NULL; Size: 0 bytes"));
10721103

10731104
// Use margin to set the NULL text.
10741105
sciEdit->setTextInMargin(Settings::getValue("databrowser", "null_text").toString());
@@ -1080,25 +1111,22 @@ void EditDialog::updateCellInfoAndMode(const QByteArray& bArrdata)
10801111
// Text only
10811112
// Determine the length of the cell text in characters (possibly different to number of bytes).
10821113
int textLength = QString(cellData).length();
1083-
ui->labelType->setText(tr("Type of data currently in cell: Text / Numeric"));
1084-
ui->labelSize->setText(tr("%n character(s)", "", textLength));
1114+
ui->labelInfo->setText(tr("Type: Text / Numeric; Size: %n character(s)", "", textLength));
10851115
break;
10861116
}
10871117
case JSON: {
10881118
// Valid JSON
10891119
// Determine the length of the cell text in characters (possibly different to number of bytes).
10901120
int jsonLength = QString(cellData).length();
1091-
ui->labelType->setText(tr("Type of data currently in cell: Valid JSON"));
1092-
ui->labelSize->setText(tr("%n character(s)", "", jsonLength));
1121+
ui->labelInfo->setText(tr("Type: Valid JSON; Size: %n character(s)", "", jsonLength));
10931122
break;
10941123
}
10951124
default:
10961125

10971126
// Determine the length of the cell data
10981127
int dataLength = cellData.length();
10991128
// If none of the above data types, consider it general binary data
1100-
ui->labelType->setText(tr("Type of data currently in cell: Binary"));
1101-
ui->labelSize->setText(tr("%n byte(s)", "", dataLength));
1129+
ui->labelInfo->setText(tr("Type: Binary; Size: %n byte(s)", "", dataLength));
11021130
break;
11031131
}
11041132
}

src/EditDialog.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ class EditDialog : public QDialog
2121
~EditDialog() override;
2222

2323
void setCurrentIndex(const QModelIndex& idx);
24+
bool isModified() const;
25+
void setModified(bool modified);
2426
QPersistentModelIndex currentIndex() const { return m_currentIndex; }
27+
void promptSaveData();
2528

2629
public slots:
2730
void setFocus();

src/EditDialog.ui

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ In the Evaluation mode, entered SQLite expressions are evaluated and the result
214214
<item>
215215
<layout class="QVBoxLayout" name="verticalLayout">
216216
<item>
217-
<widget class="QLabel" name="labelType">
217+
<widget class="QLabel" name="labelCell">
218218
<property name="sizePolicy">
219219
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
220220
<horstretch>0</horstretch>
@@ -228,15 +228,15 @@ In the Evaluation mode, entered SQLite expressions are evaluated and the result
228228
</size>
229229
</property>
230230
<property name="text">
231-
<string>Type of data currently in cell</string>
231+
<string>Identification of the cell currently in the editor</string>
232232
</property>
233233
<property name="wordWrap">
234234
<bool>true</bool>
235235
</property>
236236
</widget>
237237
</item>
238238
<item>
239-
<widget class="QLabel" name="labelSize">
239+
<widget class="QLabel" name="labelInfo">
240240
<property name="sizePolicy">
241241
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
242242
<horstretch>0</horstretch>
@@ -250,7 +250,7 @@ In the Evaluation mode, entered SQLite expressions are evaluated and the result
250250
</size>
251251
</property>
252252
<property name="text">
253-
<string>Size of data currently in table</string>
253+
<string>Type and size of data currently in table</string>
254254
</property>
255255
<property name="textFormat">
256256
<enum>Qt::PlainText</enum>

src/FilterLineEdit.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ void FilterLineEdit::keyReleaseEvent(QKeyEvent* event)
8383
}
8484
}
8585

86+
void FilterLineEdit::focusInEvent(QFocusEvent* event)
87+
{
88+
QLineEdit::focusInEvent(event);
89+
emit filterFocused();
90+
}
91+
8692
void FilterLineEdit::clear()
8793
{
8894
// When programmatically clearing the line edit's value make sure the effects are applied immediately, i.e.

src/FilterLineEdit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@ private slots:
2828
void addFilterAsCondFormat(QString text);
2929
void clearAllCondFormats();
3030
void editCondFormats();
31+
void filterFocused();
3132

3233
protected:
3334
void keyReleaseEvent(QKeyEvent* event) override;
35+
void focusInEvent(QFocusEvent* event) override;
3436
void setFilterHelper(const QString& filterOperator, const QString& operatorSuffix = QString());
3537

3638
private:

src/FilterTableHeader.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ void FilterTableHeader::generateFilters(size_t number, size_t number_of_hidden_f
4242
FilterLineEdit* l = new FilterLineEdit(this, &filterWidgets, i);
4343
l->setVisible(i >= number_of_hidden_filters);
4444
connect(l, &FilterLineEdit::delayedTextChanged, this, &FilterTableHeader::inputChanged);
45+
connect(l, &FilterLineEdit::filterFocused, this, [this](){emit filterFocused();});
4546
connect(l, &FilterLineEdit::addFilterAsCondFormat, this, &FilterTableHeader::addFilterAsCondFormat);
4647
connect(l, &FilterLineEdit::clearAllCondFormats, this, &FilterTableHeader::clearAllCondFormats);
4748
connect(l, &FilterLineEdit::editCondFormats, this, &FilterTableHeader::editCondFormats);

src/FilterTableHeader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public slots:
2525

2626
signals:
2727
void filterChanged(size_t column, QString value);
28+
void filterFocused();
2829
void addCondFormat(size_t column, QString filter);
2930
void allCondFormatsCleared(size_t column);
3031
void condFormatsEdited(size_t column);

src/MainWindow.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include "ExportSqlDialog.h"
2121
#include "SqlUiLexer.h"
2222
#include "FileDialog.h"
23-
#include "FilterTableHeader.h"
2423
#include "RemoteDock.h"
2524
#include "FindReplaceDialog.h"
2625
#include "RunSql.h"
@@ -3837,6 +3836,7 @@ TableBrowserDock* MainWindow::newTableBrowserTab(const sqlb::ObjectIdentifier& t
38373836
auto& settings = d->tableBrowser()->settings(d->tableBrowser()->currentlyBrowsedTableName());
38383837
plotDock->updatePlot(d->tableBrowser()->model(), &settings, true, false);
38393838
});
3839+
connect(d->tableBrowser(), &TableBrowser::prepareForFilter, editDock, &EditDialog::promptSaveData);
38403840

38413841
// Set up dock and add it to the tab
38423842
ui->tabBrowsers->addDockWidget(Qt::TopDockWidgetArea, d);

src/TableBrowser.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,19 @@ TableBrowser::TableBrowser(DBBrowserDB* _db, QWidget* parent) :
112112

113113
// Set up filters
114114
connect(ui->dataTable->filterHeader(), &FilterTableHeader::filterChanged, this, &TableBrowser::updateFilter);
115+
connect(ui->dataTable->filterHeader(), &FilterTableHeader::filterFocused, this, [this]() {
116+
emit prepareForFilter();
117+
});
115118
connect(ui->dataTable->filterHeader(), &FilterTableHeader::addCondFormat, this, &TableBrowser::addCondFormatFromFilter);
116119
connect(ui->dataTable->filterHeader(), &FilterTableHeader::allCondFormatsCleared, this, &TableBrowser::clearAllCondFormats);
117120
connect(ui->dataTable->filterHeader(), &FilterTableHeader::condFormatsEdited, this, &TableBrowser::editCondFormats);
118121
connect(ui->dataTable, &ExtendedTableWidget::editCondFormats, this, &TableBrowser::editCondFormats);
119122
connect(ui->dataTable, &ExtendedTableWidget::dataAboutToBeEdited, this, &TableBrowser::dataAboutToBeEdited);
120123

121124
// Set up global filter
125+
connect(ui->editGlobalFilter, &FilterLineEdit::filterFocused, this, [this]() {
126+
emit prepareForFilter();
127+
});
122128
connect(ui->editGlobalFilter, &FilterLineEdit::delayedTextChanged, this, [this](const QString& value) {
123129
// Split up filter values
124130
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)

src/TableBrowser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ public slots:
9797
void currentTableChanged(sqlb::ObjectIdentifier table);
9898
void foreignKeyClicked(sqlb::ObjectIdentifier table, std::string column, QByteArray value);
9999
void dataAboutToBeEdited(const QModelIndex& index);
100+
void prepareForFilter();
100101

101102
private slots:
102103
void clear();

0 commit comments

Comments
 (0)