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
5 changes: 5 additions & 0 deletions distri/sqlitebrowser.desktop.appdata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
</screenshots>
<url type="homepage">https://sqlitebrowser.org/</url>
<url type="bugtracker">https://github.com/sqlitebrowser/sqlitebrowser/issues</url>
<url type="donation">https://www.patreon.com/db4s</url>
<url type="faq">https://github.com/sqlitebrowser/sqlitebrowser/wiki/Frequently-Asked-Questions</url>
<url type="translate">https://github.com/sqlitebrowser/sqlitebrowser/wiki/Translations</url>
<url type="contribute">https://github.com/sqlitebrowser/sqlitebrowser/wiki#for-developers</url>
<url type="vcs-browser">https://github.com/sqlitebrowser/sqlitebrowser</url>
<releases>
<release version="3.13.1" date="2024-10-16" />
<release version="3.13.0" date="2024-07-23" />
Expand Down
4 changes: 4 additions & 0 deletions src/ExtendedTableWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) :
m_frozen_column_count(0),
m_item_border_delegate(new ItemBorderDelegate(this))
{
setWordWrap(Settings::getValue("databrowser", "cell_word_wrap").toBool());

setHorizontalScrollMode(ExtendedTableWidget::ScrollPerPixel);
// Force ScrollPerItem, so scrolling shows all table rows
setVerticalScrollMode(ExtendedTableWidget::ScrollPerItem);
Expand Down Expand Up @@ -511,6 +513,8 @@ void ExtendedTableWidget::reloadSettings()
verticalHeader()->setDefaultSectionSize(fontMetrics.height()+10);
if(m_frozen_table_view)
m_frozen_table_view->reloadSettings();

setWordWrap(Settings::getValue("databrowser", "cell_word_wrap").toBool());
}

bool ExtendedTableWidget::copyMimeData(const QModelIndexList& fromIndices, QMimeData* mimeData, const bool withHeaders, const bool inSQL)
Expand Down
14 changes: 14 additions & 0 deletions src/ImportCsvDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <QTextStream>
#include <QFileInfo>
#include <memory>
#include <regex>

// Enable this line to show basic performance stats after each imported CSV file. Please keep in mind that while these
// numbers might help to estimate the performance of the algorithm, this is not a proper benchmark.
Expand Down Expand Up @@ -71,11 +72,13 @@ ImportCsvDialog::ImportCsvDialog(const std::vector<QString>& filenames, DBBrowse
ui->comboSeparator->blockSignals(true);
ui->comboQuote->blockSignals(true);
ui->comboEncoding->blockSignals(true);
ui->checkReplaceNonAlnum->blockSignals(true);

ui->checkboxHeader->setChecked(Settings::getValue("importcsv", "firstrowheader").toBool());
ui->checkBoxTrimFields->setChecked(Settings::getValue("importcsv", "trimfields").toBool());
ui->checkBoxSeparateTables->setChecked(Settings::getValue("importcsv", "separatetables").toBool());
ui->checkLocalConventions->setChecked(Settings::getValue("importcsv", "localconventions").toBool());
ui->checkReplaceNonAlnum->setChecked(Settings::getValue("importcsv", "replacenonalnum").toBool());
setSeparatorChar(getSettingsChar("importcsv", "separator"));
setQuoteChar(getSettingsChar("importcsv", "quotecharacter"));
setEncoding(Settings::getValue("importcsv", "encoding").toString());
Expand All @@ -87,6 +90,7 @@ ImportCsvDialog::ImportCsvDialog(const std::vector<QString>& filenames, DBBrowse
ui->comboSeparator->blockSignals(false);
ui->comboQuote->blockSignals(false);
ui->comboEncoding->blockSignals(false);
ui->checkReplaceNonAlnum->blockSignals(false);

// Prepare and show interface depending on how many files are selected
if (csvFilenames.size() > 1)
Expand Down Expand Up @@ -193,6 +197,7 @@ void ImportCsvDialog::accept()
Settings::setValue("importcsv", "separatetables", ui->checkBoxSeparateTables->isChecked());
Settings::setValue("importcsv", "localconventions", ui->checkLocalConventions->isChecked());
Settings::setValue("importcsv", "encoding", currentEncoding());
Settings::setValue("importcsv", "replacenonalnum", ui->checkReplaceNonAlnum->isChecked());

// Get all the selected files and start the import
if (ui->filePickerBlock->isVisible())
Expand Down Expand Up @@ -425,6 +430,13 @@ sqlb::FieldVector ImportCsvDialog::generateFieldList(const QString& filename) co
{
// Take field name from CSV
fieldname = std::string(rowData.fields[i].data, rowData.fields[i].data_length);

// Replace any non-nlphanumeric characters with an underscore
if(ui->checkReplaceNonAlnum->isChecked())
{
std::regex pattern("[^a-zA-Z0-9_]");
fieldname = std::regex_replace(fieldname, pattern, "_");
}
}

// If we don't have a field name by now, generate one
Expand Down Expand Up @@ -879,6 +891,8 @@ void ImportCsvDialog::toggleAdvancedSection(bool show)
ui->checkIgnoreDefaults->setVisible(show);
ui->labelOnConflictStrategy->setVisible(show);
ui->comboOnConflictStrategy->setVisible(show);
ui->labelReplaceNonAlnum->setVisible(show);
ui->checkReplaceNonAlnum->setVisible(show);
}

char32_t ImportCsvDialog::toUtf8(const QString& s) const
Expand Down
23 changes: 23 additions & 0 deletions src/ImportCsvDialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,23 @@
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QCheckBox" name="checkReplaceNonAlnum">
<property name="toolTip">
<string>Replace non-alphanumeric characters in column name with an underscore.</string>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QLabel" name="labelReplaceNonAlnum">
<property name="text">
<string>Replace non-alphanumeric in column name</string>
</property>
<property name="buddy">
<cstring>checkReplaceNonAlnum</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
Expand Down Expand Up @@ -793,6 +810,12 @@
</hint>
</hints>
</connection>
<connection>
<sender>checkReplaceNonAlnum</sender>
<signal>toggled(bool)</signal>
<receiver>ImportCsvDialog</receiver>
<slot>updatePreview()</slot>
</connection>
</connections>
<slots>
<slot>updatePreview()</slot>
Expand Down
60 changes: 52 additions & 8 deletions src/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,11 @@ bool MainWindow::fileOpen(const QString& fileName, bool openFromProject, bool re
loadPragmas();

refreshTableBrowsers();

if (db.readOnly()) {
if (!fileSystemWatch.files().isEmpty())
fileSystemWatch.removePaths(fileSystemWatch.files());
fileSystemWatch.addPath(wFile);
}
retval = true;
} else {
QMessageBox::warning(this, qApp->applicationName(), tr("Could not open database file.\nReason: %1").arg(db.lastError()));
Expand Down Expand Up @@ -700,6 +704,10 @@ void MainWindow::refreshTableBrowsers(bool all)
QApplication::restoreOverrideCursor();
}

void MainWindow::refreshDb() {
refreshTableBrowsers();
}

bool MainWindow::fileSaveAs() {

QString fileName = FileDialog::getSaveFileName(
Expand Down Expand Up @@ -743,6 +751,8 @@ bool MainWindow::fileClose()
if(!db.close())
return false;

if (!fileSystemWatch.files().isEmpty())
fileSystemWatch.removePaths(fileSystemWatch.files());
TableBrowser::resetSharedSettings();
setCurrentFile(QString());
loadPragmas();
Expand Down Expand Up @@ -1235,34 +1245,60 @@ void MainWindow::executeQuery()
// Prepare a lambda function for logging the results of a query
auto logged_queries = std::make_shared<QString>();
auto query_logger = [sqlWidget, editor, logged_queries](bool ok, const QString& status_message, int from_position, int to_position) {
int editor_length = editor->length();
int lines = editor->lines();
if(editor_length == 0 || lines == 0)
{
sqlWidget->finishExecution(status_message, ok);
return;
}

from_position = qBound(0, from_position, editor_length);
to_position = qBound(0, to_position, editor_length);

// Clamp a (line, index) pair from lineIndexFromPosition to valid editor bounds.
auto clampToEditor = [&](int& line, int& index) {
line = qMin(line, lines - 1);
index = qMin(index, editor->text(line).size());
};

int execute_from_line, execute_from_index;
editor->lineIndexFromPosition(from_position, &execute_from_line, &execute_from_index);
clampToEditor(execute_from_line, execute_from_index);

// Special case: if the start position is at the end of a line, then move to the beginning of next line.
// Otherwise for the typical case, the line reference is one less than expected.
// Note that execute_from_index uses character positions and not byte positions, so at() can be used.
QChar char_at_index = editor->text(execute_from_line).at(execute_from_index);
if (char_at_index == '\r' || char_at_index == '\n') {
execute_from_line++;
// The next lines could be empty, so skip all of them too.
while(editor->text(execute_from_line).trimmed().isEmpty())
QString line_text = editor->text(execute_from_line);
if(execute_from_index < line_text.size())
{
QChar char_at_index = line_text.at(execute_from_index);
if (char_at_index == '\r' || char_at_index == '\n') {
execute_from_line++;
execute_from_index = 0;
// The next lines could be empty, so skip all of them too.
while(execute_from_line < lines && editor->text(execute_from_line).trimmed().isEmpty())
execute_from_line++;
execute_from_index = 0;
}
}
clampToEditor(execute_from_line, execute_from_index);

// If there was an error highlight the erroneous SQL statement
if(!ok)
{
int end_of_current_statement_line, end_of_current_statement_index;
editor->lineIndexFromPosition(to_position, &end_of_current_statement_line, &end_of_current_statement_index);
clampToEditor(end_of_current_statement_line, end_of_current_statement_index);
editor->setErrorIndicator(execute_from_line, execute_from_index, end_of_current_statement_line, end_of_current_statement_index);

editor->setCursorPosition(execute_from_line, execute_from_index);
}

// Log the query and the result message.
// The query takes the last placeholder as it may itself contain the sequence '%' + number.
QString query = editor->text(from_position, to_position);
QString query;
if(from_position < to_position)
query = editor->text(from_position, to_position);
QString log_message = "-- " + tr("At line %1:").arg(execute_from_line+1) + "\n" + query.trimmed() + "\n-- " + tr("Result: %1").arg(status_message);
logged_queries->append(log_message + "\n");

Expand Down Expand Up @@ -2462,6 +2498,14 @@ void MainWindow::reloadSettings()

ui->actionDropQualifiedCheck->setChecked(Settings::getValue("SchemaDock", "dropQualifiedNames").toBool());
ui->actionEnquoteNamesCheck->setChecked(Settings::getValue("SchemaDock", "dropEnquotedNames").toBool());

if (Settings::getValue("db", "watcher").toBool())
connect(&fileSystemWatch, &QFileSystemWatcher::fileChanged, this, &MainWindow::refreshDb, Qt::UniqueConnection);
else {
disconnect(&fileSystemWatch, &QFileSystemWatcher::fileChanged, nullptr, nullptr);
if (!fileSystemWatch.files().isEmpty())
fileSystemWatch.removePaths(fileSystemWatch.files());
}
}

void MainWindow::checkNewVersion(const bool automatic)
Expand Down
5 changes: 5 additions & 0 deletions src/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

#include <memory>
#include <vector>

#include <QMainWindow>
#include <QFileSystemWatcher>

struct BrowseDataTableSettings;
class DbStructureModel;
Expand Down Expand Up @@ -121,6 +123,8 @@ friend TableBrowserDock;
QString currentProjectFilename;
bool isProjectModified;

QFileSystemWatcher fileSystemWatch;

void init();
void clearCompleterModelsFields();

Expand Down Expand Up @@ -176,6 +180,7 @@ private slots:
void fileNewInMemoryDatabase(bool open_create_dialog = true);
// Refresh visible table browsers. When all is true, refresh all browsers.
void refreshTableBrowsers(bool all = false);
void refreshDb();
bool fileClose();
bool fileSaveAs();
void createTable();
Expand Down
4 changes: 4 additions & 0 deletions src/PreferencesDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ void PreferencesDialog::loadSettings()
}

ui->spinStructureFontSize->setValue(Settings::getValue("db", "fontsize").toInt());
ui->watcherCheckBox->setChecked(Settings::getValue("db", "watcher").toBool());

// Gracefully handle the preferred Data Browser font not being available
int matchingFont = ui->comboDataBrowserFont->findText(Settings::getValue("databrowser", "font").toString(), Qt::MatchExactly);
Expand All @@ -119,6 +120,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->checkCellWordWrap->setChecked(Settings::getValue("databrowser", "cell_word_wrap").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 @@ -196,12 +198,14 @@ void PreferencesDialog::saveSettings(bool accept)
Settings::setValue("db", "defaultsqltext", ui->editDatabaseDefaultSqlText->text());
Settings::setValue("db", "defaultfieldtype", ui->defaultFieldTypeComboBox->currentIndex());
Settings::setValue("db", "fontsize", ui->spinStructureFontSize->value());
Settings::setValue("db", "watcher", ui->watcherCheckBox->isChecked());

Settings::setValue("checkversion", "enabled", ui->checkUpdates->isChecked());

Settings::setValue("databrowser", "font", ui->comboDataBrowserFont->currentText());
Settings::setValue("databrowser", "fontsize", ui->spinDataBrowserFontSize->value());
Settings::setValue("databrowser", "image_preview", ui->checkShowImagesInline->isChecked());
Settings::setValue("databrowser", "cell_word_wrap", ui->checkCellWordWrap->isChecked());
saveColorSetting(ui->fr_null_fg, "null_fg");
saveColorSetting(ui->fr_null_bg, "null_bg");
saveColorSetting(ui->fr_reg_fg, "reg_fg");
Expand Down
41 changes: 41 additions & 0 deletions src/PreferencesDialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,29 @@ in new project file</string>
<item row="5" column="1">
<widget class="QSpinBox" name="spinStructureFontSize"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_5">
<property name="toolTip">
<string>When the database is open in readonly mode, watch the database file and refresh when it is updated.</string>
</property>
<property name="text">
<string>&amp;When readonly, refresh on changed file</string>
</property>
<property name="buddy">
<cstring>watcherCheckBox</cstring>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="watcherCheckBox">
<property name="text">
<string>enabled</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
Expand Down Expand Up @@ -1212,6 +1235,16 @@ in new project file</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelCellWordWrap">
<property name="text">
<string>Enable word wrap in cell</string>
</property>
<property name="buddy">
<cstring>checkCellWordWrap</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinSymbolLimit">
<property name="correctionMode">
Expand Down Expand Up @@ -1255,6 +1288,13 @@ Can be set to 0 for disabling completion.</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="checkCellWordWrap">
<property name="toolTip">
<string>Enable this option to turn on word wrap in the cells.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down Expand Up @@ -1981,6 +2021,7 @@ Can be set to 0 for disabling completion.</string>
<tabstop>spinSymbolLimit</tabstop>
<tabstop>spinCompleteThreshold</tabstop>
<tabstop>checkShowImagesInline</tabstop>
<tabstop>checkCellWordWrap</tabstop>
<tabstop>spinFilterDelay</tabstop>
<tabstop>editFilterEscape</tabstop>
<tabstop>treeSyntaxHighlighting</tabstop>
Expand Down
6 changes: 6 additions & 0 deletions src/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ QVariant Settings::getDefaultValue(const std::string& group, const std::string&
if(group == "db" && name == "fontsize")
return 10;

// db/watcher?
if(group == "db" && name == "watcher")
return false;

// exportcsv/firstrowheader?
if(group == "exportcsv" && name == "firstrowheader")
return true;
Expand Down Expand Up @@ -303,6 +307,8 @@ QVariant Settings::getDefaultValue(const std::string& group, const std::string&
return 1000;
if(name == "image_preview")
return false;
if(name == "cell_word_wrap")
return true;
if(name == "indent_compact")
return false;
if (name == "sort_keys")
Expand Down
Loading
Loading