Support inline preview of image data in cells

This adds a new option in the Preferences dialog to enable a preview of
images in BLOB cells directly in the grid view of the Browse Data tab.

See issue #2000.
This commit is contained in:
Martin Kleusberg
2019-09-22 20:43:07 +02:00
parent 4081debd71
commit 2d4c5ce0ba
7 changed files with 90 additions and 33 deletions

View File

@@ -1,6 +1,9 @@
#include "Data.h"
#include <QBuffer>
#include <QImageReader>
#include <QTextCodec>
#include <algorithm>
// Note that these aren't all possible BOMs. But they are probably the most common ones.
@@ -88,6 +91,19 @@ QByteArray removeBom(QByteArray& data)
}
}
QString isImageData(const QByteArray& data)
{
// Check if it's an image. First do a quick test by calling canRead() which only checks the first couple of bytes or so. Only if
// that returned true, do a more sophisticated test of the data. This way we get both, good performance and proper data checking.
QBuffer imageBuffer(const_cast<QByteArray*>(&data));
QImageReader readerBuffer(&imageBuffer);
QString imageFormat = readerBuffer.format();
if(readerBuffer.canRead() && !readerBuffer.read().isNull())
return imageFormat;
else
return QString();
}
QStringList toStringList(const QList<QByteArray>& list) {
QStringList strings;
for (const QByteArray &item : list) {

View File

@@ -21,6 +21,9 @@ bool startsWithBom(const QByteArray& data);
// with a BOM an empty byte array is returned and the original data is not modified.
QByteArray removeBom(QByteArray& data);
// Check if a byte array contains an image. Returns the name of the image format for images or a null string for non-image data.
QString isImageData(const QByteArray& data);
QStringList toStringList(const QList<QByteArray>& list);
QByteArray encodeString(const QByteArray& str, const QString& encoding);

View File

@@ -11,7 +11,6 @@
#include <QKeySequence>
#include <QShortcut>
#include <QImageReader>
#include <QBuffer>
#include <QModelIndex>
#include <QtXml/QDomDocument>
#include <QMessageBox>
@@ -856,12 +855,9 @@ int EditDialog::checkDataType(const QByteArray& bArrdata)
return Null;
}
// Check if it's an image. First do a quick test by calling canRead() which only checks the first couple of bytes or so. Only if
// that returned true, do a more sophisticated test of the data. This way we get both, good performance and proper data checking.
QBuffer imageBuffer(&cellData);
QImageReader readerBuffer(&imageBuffer);
QString imageFormat = readerBuffer.format();
if(readerBuffer.canRead() && !readerBuffer.read().isNull())
// Check if it's an image
QString imageFormat = isImageData(cellData);
if(!imageFormat.isNull())
return imageFormat == "svg" ? SVG : Image;
// Check if it's text only

View File

@@ -109,6 +109,7 @@ void PreferencesDialog::loadSettings()
ui->spinSymbolLimit->setValue(Settings::getValue("databrowser", "symbol_limit").toInt());
ui->spinCompleteThreshold->setValue(Settings::getValue("databrowser", "complete_threshold").toInt());
ui->checkShowImagesInline->setChecked(Settings::getValue("databrowser", "image_preview").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());
@@ -217,6 +218,7 @@ void PreferencesDialog::saveSettings()
Settings::setValue("databrowser", "font", ui->comboDataBrowserFont->currentText());
Settings::setValue("databrowser", "fontsize", ui->spinDataBrowserFontSize->value());
Settings::setValue("databrowser", "image_preview", ui->checkShowImagesInline->isChecked());
saveColorSetting(ui->fr_null_fg, "null_fg");
saveColorSetting(ui->fr_null_bg, "null_bg");
saveColorSetting(ui->fr_reg_fg, "reg_fg");

View File

@@ -821,6 +821,23 @@ Can be set to 0 for disabling completion.</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Show images in cell</string>
</property>
<property name="buddy">
<cstring>checkShowImagesInline</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="checkShowImagesInline">
<property name="toolTip">
<string>Enable this option to show a preview of BLOBs containing image data in the cells. This can affect the performance of the data browser, however.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -1866,10 +1883,12 @@ Can be set to 0 for disabling completion.</string>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>comboDefaultLocation</tabstop>
<tabstop>locationEdit</tabstop>
<tabstop>setLocationButton</tabstop>
<tabstop>languageComboBox</tabstop>
<tabstop>appStyleCombo</tabstop>
<tabstop>toolbarStyleComboMain</tabstop>
<tabstop>toolbarStyleComboStructure</tabstop>
<tabstop>toolbarStyleComboBrowse</tabstop>
@@ -1877,6 +1896,7 @@ Can be set to 0 for disabling completion.</string>
<tabstop>toolbarStyleComboEditCell</tabstop>
<tabstop>checkUseRemotes</tabstop>
<tabstop>checkUpdates</tabstop>
<tabstop>buttonManageFileExtension</tabstop>
<tabstop>encodingComboBox</tabstop>
<tabstop>foreignKeysCheckBox</tabstop>
<tabstop>checkHideSchemaLinebreaks</tabstop>
@@ -1886,6 +1906,9 @@ Can be set to 0 for disabling completion.</string>
<tabstop>editDatabaseDefaultSqlText</tabstop>
<tabstop>comboDataBrowserFont</tabstop>
<tabstop>spinDataBrowserFontSize</tabstop>
<tabstop>spinSymbolLimit</tabstop>
<tabstop>spinCompleteThreshold</tabstop>
<tabstop>checkShowImagesInline</tabstop>
<tabstop>fr_null_fg</tabstop>
<tabstop>fr_null_bg</tabstop>
<tabstop>txtNull</tabstop>
@@ -1902,20 +1925,25 @@ Can be set to 0 for disabling completion.</string>
<tabstop>spinEditorFontSize</tabstop>
<tabstop>spinLogFontSize</tabstop>
<tabstop>spinTabSize</tabstop>
<tabstop>wrapComboBox</tabstop>
<tabstop>quoteComboBox</tabstop>
<tabstop>checkAutoCompletion</tabstop>
<tabstop>checkCompleteUpper</tabstop>
<tabstop>checkErrorIndicators</tabstop>
<tabstop>checkHorizontalTiling</tabstop>
<tabstop>listExtensions</tabstop>
<tabstop>buttonAddExtension</tabstop>
<tabstop>buttonRemoveExtension</tabstop>
<tabstop>checkRegexDisabled</tabstop>
<tabstop>editRemoteCloneDirectory</tabstop>
<tabstop>buttonRemoteBrowseCloneDirectory</tabstop>
<tabstop>tableCaCerts</tabstop>
<tabstop>checkAllowLoadExtension</tabstop>
<tabstop>tabCertificates</tabstop>
<tabstop>tableClientCerts</tabstop>
<tabstop>buttonClientCertAdd</tabstop>
<tabstop>buttonClientCertRemove</tabstop>
<tabstop>tabWidget</tabstop>
<tabstop>buttonProxy</tabstop>
<tabstop>editRemoteCloneDirectory</tabstop>
<tabstop>buttonRemoteBrowseCloneDirectory</tabstop>
<tabstop>tableCaCerts</tabstop>
</tabstops>
<resources>
<include location="icons/icons.qrc"/>
@@ -1992,12 +2020,12 @@ Can be set to 0 for disabling completion.</string>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>365</x>
<y>207</y>
<x>344</x>
<y>230</y>
</hint>
<hint type="destinationlabel">
<x>108</x>
<y>280</y>
<x>119</x>
<y>273</y>
</hint>
</hints>
</connection>
@@ -2008,8 +2036,8 @@ Can be set to 0 for disabling completion.</string>
<slot>setVisible(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>365</x>
<y>207</y>
<x>344</x>
<y>230</y>
</hint>
<hint type="destinationlabel">
<x>365</x>
@@ -2024,8 +2052,8 @@ Can be set to 0 for disabling completion.</string>
<slot>activateRemoteTab(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>161</x>
<y>172</y>
<x>231</x>
<y>393</y>
</hint>
<hint type="destinationlabel">
<x>382</x>
@@ -2040,8 +2068,8 @@ Can be set to 0 for disabling completion.</string>
<slot>addClientCertificate()</slot>
<hints>
<hint type="sourcelabel">
<x>578</x>
<y>315</y>
<x>722</x>
<y>110</y>
</hint>
<hint type="destinationlabel">
<x>596</x>
@@ -2056,8 +2084,8 @@ Can be set to 0 for disabling completion.</string>
<slot>removeClientCertificate()</slot>
<hints>
<hint type="sourcelabel">
<x>578</x>
<y>353</y>
<x>722</x>
<y>139</y>
</hint>
<hint type="destinationlabel">
<x>597</x>
@@ -2072,8 +2100,8 @@ Can be set to 0 for disabling completion.</string>
<slot>chooseRemoteCloneDirectory()</slot>
<hints>
<hint type="sourcelabel">
<x>567</x>
<y>54</y>
<x>732</x>
<y>538</y>
</hint>
<hint type="destinationlabel">
<x>595</x>
@@ -2088,12 +2116,12 @@ Can be set to 0 for disabling completion.</string>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>474</x>
<y>464</y>
<x>642</x>
<y>450</y>
</hint>
<hint type="destinationlabel">
<x>474</x>
<y>492</y>
<x>642</x>
<y>480</y>
</hint>
</hints>
</connection>
@@ -2104,8 +2132,8 @@ Can be set to 0 for disabling completion.</string>
<slot>on_buttonBox_clicked(QAbstractButton*)</slot>
<hints>
<hint type="sourcelabel">
<x>385</x>
<y>591</y>
<x>394</x>
<y>584</y>
</hint>
<hint type="destinationlabel">
<x>385</x>
@@ -2120,8 +2148,8 @@ Can be set to 0 for disabling completion.</string>
<slot>configureProxy()</slot>
<hints>
<hint type="sourcelabel">
<x>385</x>
<y>591</y>
<x>225</x>
<y>506</y>
</hint>
<hint type="destinationlabel">
<x>385</x>

View File

@@ -208,6 +208,8 @@ QVariant Settings::getDefaultValue(const std::string& group, const std::string&
return 5000;
if(name == "complete_threshold")
return 1000;
if(name == "image_preview")
return false;
if(name == "indent_compact")
return false;
if(name == "auto_switch_mode")

View File

@@ -390,6 +390,16 @@ QVariant SqliteTableModel::data(const QModelIndex &index, int role) const
.arg(QKeySequence(Qt::CTRL).toString(QKeySequence::NativeText));
else
return QString();
} else if(role == Qt::DecorationRole) {
if(!row_available)
return QVariant();
if(Settings::getValue("databrowser", "image_preview").toBool() && !isImageData(cached_row->at(column)).isNull())
{
QImage img;
img.loadFromData(cached_row->at(column));
return QPixmap::fromImage(img);
}
}
return QVariant();