Hello community,
here is the log from the commit of package sqlitebrowser for openSUSE:Factory checked in at 2018-06-29 22:37:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/sqlitebrowser (Old)
and /work/SRC/openSUSE:Factory/.sqlitebrowser.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "sqlitebrowser"
Fri Jun 29 22:37:01 2018 rev:10 rq:619772 version:3.10.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/sqlitebrowser/sqlitebrowser.changes 2017-09-04 12:30:36.955654839 +0200
+++ /work/SRC/openSUSE:Factory/.sqlitebrowser.new/sqlitebrowser.changes 2018-06-29 22:37:05.769965586 +0200
@@ -1,0 +2,29 @@
+Fri Jun 29 11:00:50 UTC 2018 - wbauer@tmo.at
+
+- update to version 3.10.1
+ * Bug fixes
+ - General
+ + cipher: Fix passphrases containing single quotes
+ + cipher: Change tab order in encryption dialog
+ + Fix typo in Russian translation
+ + Pass /norestart to vcredist installer
+ + Fix index updating when removing an indexed column from a table
+ + Don't automatically commit all changes when editing a table column
+ + Make text selectable in Edit dock even if db is opened as read only
+ + Add '<>NULL' filter
+ + Fix custom type saving when only focus changes for user-entered type
+ - DBHub.io related
+ + dbhub: Tweak certificate UI in the preferences dialog
+ + dbhub: Fix progress dialog for very large files
+ + dbhub: Remove closing "." from the progress dialog
+ + dbhub: Ask user what to do when trying to open an updated database
+ + dbhub: Enforce name and commit message length limits in push dialog
+ + dbhub: Add tooltip to cog tool button
+ + dbhub: Redownload database if local copy has been deleted
+ + dbhub: Fix wrong file size being shown for very large files
+ + dbhub: Support pushing to different branches than "master"
+ + dbhub: Improve file size format
+ + dbhub: Optimise code
+ + dbhub: Fix branch list in push dialog
+
+-------------------------------------------------------------------
Old:
----
sqlitebrowser-3.10.0.tar.gz
New:
----
sqlitebrowser-3.10.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ sqlitebrowser.spec ++++++
--- /var/tmp/diff_new_pack.RbAmbO/_old 2018-06-29 22:37:06.429965013 +0200
+++ /var/tmp/diff_new_pack.RbAmbO/_new 2018-06-29 22:37:06.433965010 +0200
@@ -1,7 +1,7 @@
#
# spec file for package sqlitebrowser
#
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
Name: sqlitebrowser
-Version: 3.10.0
+Version: 3.10.1
Release: 0
Summary: Create, design and edit SQLite Databases
License: GPL-3.0+ AND MPL-2.0
++++++ sqlitebrowser-3.10.0.tar.gz -> sqlitebrowser-3.10.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/CMakeLists.txt new/sqlitebrowser-3.10.1/CMakeLists.txt
--- old/sqlitebrowser-3.10.0/CMakeLists.txt 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/CMakeLists.txt 2017-09-20 15:59:51.000000000 +0200
@@ -413,7 +413,7 @@
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_VERSION_MAJOR "3")
set(CPACK_PACKAGE_VERSION_MINOR "10")
-set(CPACK_PACKAGE_VERSION_PATCH "0")
+set(CPACK_PACKAGE_VERSION_PATCH "1")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "DB Browser for SQLite")
if(WIN32 AND NOT UNIX)
# There is a bug in NSIS that does not handle full unix paths properly. Make
@@ -433,7 +433,7 @@
# VS redist
list(APPEND CPACK_NSIS_EXTRA_INSTALL_COMMANDS "
- ExecWait '\\\"$INSTDIR\\\\redist\\\\${VSREDIST}\\\" /install /passive /quiet'
+ ExecWait '\\\"$INSTDIR\\\\redist\\\\${VSREDIST}\\\" /install /passive /norestart /quiet'
Delete '\\\"$INSTDIR\\\\redist\\\\${VSREDIST}\\\"'
")
else(WIN32 AND NOT UNIX)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/CipherDialog.cpp new/sqlitebrowser-3.10.1/src/CipherDialog.cpp
--- old/sqlitebrowser-3.10.0/src/CipherDialog.cpp 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/CipherDialog.cpp 2017-09-20 15:59:51.000000000 +0200
@@ -40,7 +40,7 @@
QString CipherDialog::password() const
{
if(keyFormat() == KeyFormats::Passphrase)
- return QString("'%1'").arg(ui->editPassword->text());
+ return QString("'%1'").arg(ui->editPassword->text().replace("'", "''"));
else
return QString("\"x'%1'\"").arg(ui->editPassword->text().mid(2)); // Remove the '0x' part at the beginning
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/CipherDialog.ui new/sqlitebrowser-3.10.1/src/CipherDialog.ui
--- old/sqlitebrowser-3.10.0/src/CipherDialog.ui 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/CipherDialog.ui 2017-09-20 15:59:51.000000000 +0200
@@ -126,8 +126,8 @@
</layout>
</widget>
<tabstops>
- <tabstop>comboKeyFormat</tabstop>
<tabstop>editPassword</tabstop>
+ <tabstop>comboKeyFormat</tabstop>
<tabstop>editPassword2</tabstop>
<tabstop>spinPageSize</tabstop>
</tabstops>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/EditDialog.cpp new/sqlitebrowser-3.10.1/src/EditDialog.cpp
--- old/sqlitebrowser-3.10.0/src/EditDialog.cpp 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/EditDialog.cpp 2017-09-20 15:59:51.000000000 +0200
@@ -464,6 +464,8 @@
ui->buttonApply->setEnabled(!ro);
ui->buttonNull->setEnabled(!ro);
ui->buttonImport->setEnabled(!ro);
+ ui->editorText->setReadOnly(ro);
+ ui->editorBinary->setEnabled(!ro); // We disable the entire hex editor here instead of setting it to read only because it doesn't have a setReadOnly() method
}
// Update the information labels in the bottom left corner of the dialog
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/EditTableDialog.cpp new/sqlitebrowser-3.10.1/src/EditTableDialog.cpp
--- old/sqlitebrowser-3.10.0/src/EditTableDialog.cpp 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/EditTableDialog.cpp 2017-09-20 15:59:51.000000000 +0200
@@ -114,6 +114,7 @@
index = typeBox->count() - 1;
}
typeBox->setCurrentIndex(index);
+ typeBox->installEventFilter(this);
connect(typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypes()));
ui->treeWidget->setItemWidget(tbitem, kType, typeBox);
@@ -222,13 +223,13 @@
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
}
-void EditTableDialog::updateTypes()
+void EditTableDialog::updateTypes(QObject *object)
{
- QComboBox* typeBox = qobject_cast(sender());
+ QComboBox* typeBox = qobject_cast(object);
if(typeBox)
{
QString type = typeBox->currentText();
- QString column = sender()->property("column").toString();
+ QString column = typeBox->property("column").toString();
int index;
for(index=0; index < m_table.fields().size(); ++index)
@@ -244,6 +245,20 @@
}
}
+void EditTableDialog::updateTypes()
+{
+ updateTypes(sender());
+}
+
+bool EditTableDialog::eventFilter(QObject *object, QEvent *event)
+{
+ if(event->type() == QEvent::FocusOut)
+ {
+ updateTypes(object);
+ }
+ return false;
+}
+
void EditTableDialog::itemChanged(QTreeWidgetItem *item, int column)
{
int index = ui->treeWidget->indexOfTopLevelItem(item);
@@ -528,6 +543,7 @@
}
ui->treeWidget->setItemWidget(tbitem, kType, typeBox);
+ typeBox->installEventFilter(this);
connect(typeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypes()));
tbitem->setCheckState(kNotNull, Qt::Unchecked);
@@ -631,7 +647,8 @@
QComboBox* oldCombo = qobject_cast(ui->treeWidget->itemWidget(ui->treeWidget->topLevelItem(currentRow), kType));
QComboBox* newCombo = new QComboBox(ui->treeWidget);
newCombo->setProperty("column", oldCombo->property("column"));
- connect(newCombo, SIGNAL(activated(int)), this, SLOT(updateTypes()));
+ newCombo->installEventFilter(this);
+ connect(newCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateTypes()));
newCombo->setEditable(true);
for(int i=0; i < oldCombo->count(); ++i)
newCombo->addItem(oldCombo->itemText(i));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/EditTableDialog.h new/sqlitebrowser-3.10.1/src/EditTableDialog.h
--- old/sqlitebrowser-3.10.0/src/EditTableDialog.h 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/EditTableDialog.h 2017-09-20 15:59:51.000000000 +0200
@@ -51,6 +51,8 @@
virtual void reject();
void checkInput();
void itemChanged(QTreeWidgetItem* item, int column);
+ void updateTypes(QObject *object);
+ bool eventFilter(QObject *object, QEvent *event);
void updateTypes();
void moveUp();
void moveDown();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/MainWindow.cpp new/sqlitebrowser-3.10.1/src/MainWindow.cpp
--- old/sqlitebrowser-3.10.0/src/MainWindow.cpp 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/MainWindow.cpp 2017-09-20 15:59:51.000000000 +0200
@@ -111,6 +111,9 @@
ui->dockPlot->setWidget(plotDock);
ui->dockRemote->setWidget(remoteDock);
+ // Set up edit dock
+ editDock->setReadOnly(true);
+
// Restore window geometry
restoreGeometry(Settings::getValue("MainWindow", "geometry").toByteArray());
restoreState(Settings::getValue("MainWindow", "windowState").toByteArray());
@@ -851,7 +854,7 @@
}
// * Don't allow editing of other objects than tables (on the browse table) *
- bool isEditingAllowed = (m_currentTabTableModel == m_browseTableModel) &&
+ bool isEditingAllowed = !db.readOnly() && m_currentTabTableModel == m_browseTableModel &&
(db.getObjectByName(ui->comboBrowseTable->currentText())->type() == sqlb::Object::Types::Table);
// Enable or disable the Apply, Null, & Import buttons in the Edit Cell
@@ -875,7 +878,7 @@
return;
}
- bool editingAllowed = (m_currentTabTableModel == m_browseTableModel) &&
+ bool editingAllowed = !db.readOnly() && (m_currentTabTableModel == m_browseTableModel) &&
(db.getObjectByName(ui->comboBrowseTable->currentText())->type() == sqlb::Object::Types::Table);
// Don't allow editing of other objects than tables
@@ -1486,7 +1489,7 @@
ui->actionSaveProject->setEnabled(enable);
ui->actionEncryption->setEnabled(enable && write);
ui->buttonClearFilters->setEnabled(enable);
- ui->dockEdit->setEnabled(enable && write);
+ ui->dockEdit->setEnabled(enable);
ui->dockPlot->setEnabled(enable);
remoteDock->enableButtons();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/PreferencesDialog.ui new/sqlitebrowser-3.10.1/src/PreferencesDialog.ui
--- old/sqlitebrowser-3.10.0/src/PreferencesDialog.ui 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/PreferencesDialog.ui 2017-09-20 15:59:51.000000000 +0200
@@ -1035,6 +1035,9 @@
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
<column>
<property name="text">
<string>Subject CN</string>
@@ -1094,6 +1097,9 @@
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
<column>
<property name="text">
<string>File</string>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/RemoteDatabase.cpp new/sqlitebrowser-3.10.1/src/RemoteDatabase.cpp
--- old/sqlitebrowser-3.10.0/src/RemoteDatabase.cpp 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/RemoteDatabase.cpp 2017-09-20 15:59:51.000000000 +0200
@@ -181,6 +181,27 @@
emit gotLicenceList(licences);
break;
}
+ case RequestTypeBranchList:
+ {
+ // Read and check results
+ QJsonDocument json = QJsonDocument::fromJson(reply->readAll());
+ if(json.isNull() || !json.isObject())
+ break;
+ QJsonObject obj = json.object();
+ QJsonObject obj_branches = obj["branches"].toObject();
+
+ // Parse data and assemble branch list
+ QStringList branches;
+ for(auto it=obj_branches.constBegin();it!=obj_branches.constEnd();++it)
+ branches.append(it.key());
+
+ // Get default branch
+ QString default_branch = obj["default_branch"].toString("master");
+
+ // Send branch list to anyone who is interested
+ emit gotBranchList(branches, default_branch);
+ break;
+ }
case RequestTypePush:
emit uploadFinished(reply->url().toString());
break;
@@ -238,9 +259,14 @@
m_progress->reset();
} else {
// It's still downloading and we know the current progress
+
+ // Were using a range 0 to 10000 here, the progress dialog will calculate 0% to 100% values from that. The reason we're not using
+ // the byte counts as-is is that they're 64bit wide while the progress dialog takes only 32bit values, so for large files the values
+ // would lose precision. The reason why we're not using a range 0 to 100 is that our range increases the precision a bit and this way
+ // we're prepared if the progress dialog will show decimal numbers one day on one platform.
m_progress->setMinimum(0);
- m_progress->setMaximum(bytesTotal);
- m_progress->setValue(bytesTransmitted);
+ m_progress->setMaximum(10000);
+ m_progress->setValue(static_cast<int>((static_cast<float>(bytesTransmitted) / static_cast<float>(bytesTotal)) * 10000.0f));
}
// Check if the Cancel button has been pressed
@@ -320,9 +346,9 @@
// Set dialog text
if(upload)
- m_progress->setLabelText(tr("Uploading remote database to\n%1.").arg(url));
+ m_progress->setLabelText(tr("Uploading remote database to\n%1").arg(url));
else
- m_progress->setLabelText(tr("Downloading remote database from\n%1.").arg(url));
+ m_progress->setLabelText(tr("Downloading remote database from\n%1").arg(url));
// Show dialog
m_progress->show();
@@ -387,7 +413,7 @@
}
void RemoteDatabase::push(const QString& filename, const QString& url, const QString& clientCert, const QString& remotename,
- const QString& commitMessage, const QString& licence, bool isPublic)
+ const QString& commitMessage, const QString& licence, bool isPublic, const QString& branch)
{
// Check if network is accessible. If not, abort right here
if(m_manager->networkAccessible() == QNetworkAccessManager::NotAccessible)
@@ -416,6 +442,7 @@
addPart(multipart, "commitmsg", commitMessage);
addPart(multipart, "licence", licence);
addPart(multipart, "public", isPublic ? "true" : "false");
+ addPart(multipart, "branch", branch);
// Set SSL configuration when trying to access a file via the HTTPS protocol
bool https = QUrl(url).scheme().compare("https", Qt::CaseInsensitive) == 0;
@@ -574,8 +601,6 @@
// Extract commit id from url and remove query part afterwards
QString url_commit_id = QUrlQuery(url).queryItemValue("commit");
- QUrl url_without_query = url;
- url_without_query.setQuery(QString());
// Query commit id and filename for the given combination of url and identity
QString sql = QString("SELECT id, commit_id, file FROM local WHERE url=? AND identity=?");
@@ -583,7 +608,7 @@
if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, 0) != SQLITE_OK)
return QString();
- if(sqlite3_bind_text(stmt, 1, url_without_query.toString().toUtf8(), url_without_query.toString().toUtf8().length(), SQLITE_TRANSIENT))
+ if(sqlite3_bind_text(stmt, 1, url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8(), url.toString(QUrl::PrettyDecoded | QUrl::RemoveQuery).toUtf8().length(), SQLITE_TRANSIENT))
{
sqlite3_finalize(stmt);
return QString();
@@ -616,15 +641,79 @@
// is newer, or the local commit id is newer.
if(local_commit_id == url_commit_id)
{
- // Both commit ids are the same. That's the perfect match, so just return the path to the local file
- return Settings::getValue("remote", "clonedirectory").toString() + "/" + local_file;
+ // Both commit ids are the same. That's the perfect match, so we can download the local file if it still exists
+ return localCheckFile(local_file);
} else {
- // In all the other cases just treat the remote database as a completely new database for now.
+ // The commit ids differ. That means we have another version locally checked out than we're trying to download. Because the commit ids are
+ // only calculated on the server side and we're currently always checking out the latest version this can only mean that the remote version has
+ // been updated, i.e. is newer than the local version.
+
+ // TODO Support multiple checkouts of the same database at different versions at the same time. For this we need to be more intelligent with
+ // comparing the commit ids.
+
+ // Ask the user what to do: open the local version or updating to the new remote version
+ if(QMessageBox::question(nullptr, qApp->applicationName(),
+ tr("The remote database has been updated since the last checkout. Do you want to update the local database to the newest version? Note "
+ "that this discards any changes you have made locally! If you don't want to lose local changes, click No to open the local version."),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes)
+ {
+ // User wants to download the newest version. So delete the entry from the clones database and delete the local database copy and return an empty
+ // string to indicate a redownload request.
+
+ // Build full path to database file and delete it
+ QFile::remove(Settings::getValue("remote", "clonedirectory").toString() + "/" + local_file);
- // TODO Add some way to update the local clone here. Maybe ask the user what to do because I don't really know what the
- // most sensible way to go is in the two remaining cases. We can use the local_id variable (see above) to update the
- // record afterwards.
+ // Remove the old entry from the local clones database to enforce a redownload. The file column should be unique for the entire table because the
+ // files are all in the same directory and their names need to be unique because of this.
+ QString sql = QString("DELETE FROM local WHERE file=?");
+ sqlite3_stmt* stmt;
+ if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, 0) != SQLITE_OK)
+ return QString();
+ if(sqlite3_bind_text(stmt, 1, local_file.toUtf8(), local_file.toUtf8().length(), SQLITE_TRANSIENT))
+ {
+ sqlite3_finalize(stmt);
+ return QString();
+ }
+ sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+
+ // Return an empty string to indicate a redownload request
+ return QString();
+ } else {
+ // User wants to open the local version. So build the full path and return it if the file still exists.
+ return localCheckFile(local_file);
+ }
+ }
+}
+
+QString RemoteDatabase::localCheckFile(const QString& local_file)
+{
+ // This function takes the file name of a locally cloned database and checks if this file still exists. If it has been deleted in the meantime it returns
+ // an empty string and deletes the file from the clone database. If the file still exists, it returns the full path to the file.
+
+ // Build the full path to where the file should be
+ QString full_path = Settings::getValue("remote", "clonedirectory").toString() + "/" + local_file;
+
+ // Check if the database still exists. If so return its path, if not return an empty string to redownload it
+ if(QFile::exists(full_path))
+ {
+ return full_path;
+ } else {
+ // Remove the apparently invalid entry from the local clones database to avoid future lookups and confusions. The file column should
+ // be unique for the entire table because the files are all in the same directory and their names need to be unique because of this.
+ QString sql = QString("DELETE FROM local WHERE file=?");
+ sqlite3_stmt* stmt;
+ if(sqlite3_prepare_v2(m_dbLocal, sql.toUtf8(), -1, &stmt, 0) != SQLITE_OK)
+ return QString();
+ if(sqlite3_bind_text(stmt, 1, local_file.toUtf8(), local_file.toUtf8().length(), SQLITE_TRANSIENT))
+ {
+ sqlite3_finalize(stmt);
+ return QString();
+ }
+ sqlite3_step(stmt);
+ sqlite3_finalize(stmt);
+ // Return empty string to indicate a redownload request
return QString();
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/RemoteDatabase.h new/sqlitebrowser-3.10.1/src/RemoteDatabase.h
--- old/sqlitebrowser-3.10.0/src/RemoteDatabase.h 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/RemoteDatabase.h 2017-09-20 15:59:51.000000000 +0200
@@ -41,11 +41,12 @@
RequestTypeNewVersionCheck,
RequestTypePush,
RequestTypeLicenceList,
+ RequestTypeBranchList,
};
void fetch(const QString& url, RequestType type, const QString& clientCert = QString(), QVariant userdata = QVariant());
void push(const QString& filename, const QString& url, const QString& clientCert, const QString& remotename,
- const QString& commitMessage = QString(), const QString& licence = QString(), bool isPublic = false);
+ const QString& commitMessage = QString(), const QString& licence = QString(), bool isPublic = false, const QString& branch = QString("master"));
signals:
// The openFile signal is emitted whenever a remote database file shall be opened in the main window. This happens when the
@@ -57,6 +58,7 @@
void gotDirList(QString json, QVariant userdata);
void gotCurrentVersion(QString version, QString url);
void gotLicenceList(QMap licences);
+ void gotBranchList(QStringList branches, QString default_branch);
// The uploadFinished() signal is emitted when a push() call is finished, i.e. a database upload has completed.
void uploadFinished(QString url);
@@ -73,6 +75,7 @@
void localAssureOpened();
void localAdd(QString filename, QString identity, const QUrl& url);
QString localExists(const QUrl& url, QString identity);
+ QString localCheckFile(const QString& local_file);
// Helper functions for building multi-part HTTP requests
void addPart(QHttpMultiPart* multipart, const QString& name, const QString& value);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/RemoteDock.cpp new/sqlitebrowser-3.10.1/src/RemoteDock.cpp
--- old/sqlitebrowser-3.10.0/src/RemoteDock.cpp 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/RemoteDock.cpp 2017-09-20 15:59:51.000000000 +0200
@@ -111,7 +111,7 @@
// Push database
remoteDatabase.push(mainWindow->getDb().currentFile(), url, remoteModel->currentClientCertificate(), pushDialog.name(),
- pushDialog.commitMessage(), pushDialog.licence(), pushDialog.isPublic());
+ pushDialog.commitMessage(), pushDialog.licence(), pushDialog.isPublic(), pushDialog.branch());
}
void RemoteDock::newDirectoryNode(const QModelIndex& parent)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/RemoteDock.ui new/sqlitebrowser-3.10.1/src/RemoteDock.ui
--- old/sqlitebrowser-3.10.0/src/RemoteDock.ui 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/RemoteDock.ui 2017-09-20 15:59:51.000000000 +0200
@@ -35,6 +35,9 @@
</item>
<item>
<widget class="QToolButton" name="buttonLogin">
+ <property name="toolTip">
+ <string>Connect to the remote server using the currently selected identity. The correct server is taken from the identity as well.</string>
+ </property>
<property name="text">
<string>Go</string>
</property>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/RemoteModel.cpp new/sqlitebrowser-3.10.1/src/RemoteModel.cpp
--- old/sqlitebrowser-3.10.0/src/RemoteModel.cpp 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/RemoteModel.cpp 2017-09-20 15:59:51.000000000 +0200
@@ -233,7 +233,7 @@
return QVariant();
// Convert size to human readable format
- float size = item->value(RemoteModelColumnSize).toInt();
+ float size = item->value(RemoteModelColumnSize).toLongLong();
QStringList list;
list << "KiB" << "MiB" << "GiB" << "TiB";
QStringListIterator it(list);
@@ -243,7 +243,7 @@
unit = it.next();
size /= 1024.0;
}
- return QString().setNum(size, 'f', 2) + " " + unit;
+ return QString().setNum(size, 'f', 2).remove(".00") + " " + unit;
}
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/RemotePushDialog.cpp new/sqlitebrowser-3.10.1/src/RemotePushDialog.cpp
--- old/sqlitebrowser-3.10.0/src/RemotePushDialog.cpp 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/RemotePushDialog.cpp 2017-09-20 15:59:51.000000000 +0200
@@ -1,4 +1,5 @@
#include <QPushButton>
+#include <QUrlQuery>
#include "RemotePushDialog.h"
#include "ui_RemotePushDialog.h"
@@ -7,6 +8,8 @@
RemotePushDialog::RemotePushDialog(QWidget* parent, RemoteDatabase& remote, const QString& host, const QString& clientCert, const QString& name) :
QDialog(parent),
ui(new Ui::RemotePushDialog),
+ m_host(host),
+ m_clientCert(clientCert),
remoteDatabase(remote)
{
// Create UI
@@ -21,6 +24,10 @@
// Fetch list of available licences
connect(&remoteDatabase, &RemoteDatabase::gotLicenceList, this, &RemotePushDialog::fillInLicences);
remoteDatabase.fetch(host + "licence/list", RemoteDatabase::RequestTypeLicenceList, clientCert);
+
+ // Prepare fetching list of available branches
+ connect(&remoteDatabase, &RemoteDatabase::gotBranchList, this, &RemotePushDialog::fillInBranches);
+ reloadBranchList();
}
RemotePushDialog::~RemotePushDialog()
@@ -42,6 +49,12 @@
if(ui->editName->text().trimmed().isEmpty())
valid = false;
+ if(ui->editCommitMessage->toPlainText().size() > 1024)
+ valid = false;
+
+ if(ui->comboBranch->currentText().size() < 1 || ui->comboBranch->currentText().size() > 32)
+ valid = false;
+
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(valid);
}
@@ -67,7 +80,12 @@
bool RemotePushDialog::isPublic() const
{
- return ui->checkPublic->isChecked();
+ return ui->checkPublic->isChecked();
+}
+
+QString RemotePushDialog::branch() const
+{
+ return ui->comboBranch->currentText();
}
void RemotePushDialog::fillInLicences(const QMap& licences)
@@ -80,3 +98,31 @@
for(auto it=licences.constBegin();it!=licences.constEnd();++it)
ui->comboLicence->addItem(it.value(), it.key());
}
+
+void RemotePushDialog::fillInBranches(const QStringList& branches, const QString& default_branch)
+{
+ // Clear branch list and add the default branch
+ ui->comboBranch->clear();
+ ui->comboBranch->addItem(default_branch);
+
+ // Add rest of the branch list to the combo box
+ foreach(const QString& branch, branches)
+ {
+ if(branch != default_branch)
+ ui->comboBranch->addItem(branch);
+ }
+}
+
+void RemotePushDialog::reloadBranchList()
+{
+ // Assemble query URL
+ QUrl url(m_host + "branch/list");
+ QUrlQuery query;
+ query.addQueryItem("username", remoteDatabase.getInfoFromClientCert(m_clientCert, RemoteDatabase::CertInfoUser));
+ query.addQueryItem("folder", "/");
+ query.addQueryItem("dbname", ui->editName->text());
+ url.setQuery(query);
+
+ // Send request
+ remoteDatabase.fetch(url.toString(), RemoteDatabase::RequestTypeBranchList, m_clientCert);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/RemotePushDialog.h new/sqlitebrowser-3.10.1/src/RemotePushDialog.h
--- old/sqlitebrowser-3.10.0/src/RemotePushDialog.h 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/RemotePushDialog.h 2017-09-20 15:59:51.000000000 +0200
@@ -21,10 +21,15 @@
QString commitMessage() const;
QString licence() const;
bool isPublic() const;
+ QString branch() const;
private:
Ui::RemotePushDialog* ui;
+ // Connection details
+ QString m_host;
+ QString m_clientCert;
+
// Reference to the remote database object which is stored somewhere in the main window
RemoteDatabase& remoteDatabase;
@@ -32,7 +37,10 @@
void checkInput();
virtual void accept();
+ void reloadBranchList();
+
void fillInLicences(const QMap& licences);
+ void fillInBranches(const QStringList& branches, const QString& default_branch);
};
#endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/RemotePushDialog.ui new/sqlitebrowser-3.10.1/src/RemotePushDialog.ui
--- old/sqlitebrowser-3.10.0/src/RemotePushDialog.ui 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/RemotePushDialog.ui 2017-09-20 15:59:51.000000000 +0200
@@ -27,7 +27,11 @@
</widget>
</item>
<item row="0" column="1">
- <widget class="QLineEdit" name="editName"/>
+ <widget class="QLineEdit" name="editName">
+ <property name="maxLength">
+ <number>256</number>
+ </property>
+ </widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
@@ -53,7 +57,7 @@
</property>
</widget>
</item>
- <item row="3" column="0">
+ <item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Database licence</string>
@@ -63,7 +67,7 @@
</property>
</widget>
</item>
- <item row="3" column="1">
+ <item row="4" column="1">
<widget class="QComboBox" name="comboLicence">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -73,7 +77,7 @@
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Public</string>
@@ -83,9 +87,29 @@
</property>
</widget>
</item>
- <item row="2" column="1">
+ <item row="3" column="1">
<widget class="QCheckBox" name="checkPublic"/>
</item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Branch</string>
+ </property>
+ <property name="buddy">
+ <cstring>comboBranch</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="comboBranch">
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="duplicatesEnabled">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
@@ -103,6 +127,7 @@
<tabstops>
<tabstop>editName</tabstop>
<tabstop>editCommitMessage</tabstop>
+ <tabstop>comboBranch</tabstop>
<tabstop>checkPublic</tabstop>
<tabstop>comboLicence</tabstop>
</tabstops>
@@ -172,8 +197,57 @@
</hint>
</hints>
</connection>
+ <connection>
+ <sender>editCommitMessage</sender>
+ <signal>textChanged()</signal>
+ <receiver>RemotePushDialog</receiver>
+ <slot>checkInput()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>175</x>
+ <y>113</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>91</x>
+ <y>111</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>editName</sender>
+ <signal>editingFinished()</signal>
+ <receiver>RemotePushDialog</receiver>
+ <slot>reloadBranchList()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>176</x>
+ <y>25</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>77</x>
+ <y>3</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>comboBranch</sender>
+ <signal>currentTextChanged(QString)</signal>
+ <receiver>RemotePushDialog</receiver>
+ <slot>checkInput()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>172</x>
+ <y>138</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>33</x>
+ <y>151</y>
+ </hint>
+ </hints>
+ </connection>
</connections>
<slots>
<slot>checkInput()</slot>
+ <slot>reloadBranchList()</slot>
</slots>
</ui>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/app.plist new/sqlitebrowser-3.10.1/src/app.plist
--- old/sqlitebrowser-3.10.0/src/app.plist 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/app.plist 2017-09-20 15:59:51.000000000 +0200
@@ -52,7 +52,7 @@
<key>CFBundleExecutable</key>
<string>@EXECUTABLE@</string>
<key>CFBundleGetInfoString</key>
- <string>3.10.0</string>
+ <string>3.10.1</string>
<key>CFBundleIconFile</key>
<string>@ICON@</string>
<key>CFBundleIdentifier</key>
@@ -64,11 +64,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
- <string>3.10.0</string>
+ <string>3.10.1</string>
<key>CFBundleSignature</key>
<string>SqLB</string>
<key>CFBundleVersion</key>
- <string>3.10.0</string>
+ <string>3.10.1</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/sqlitedb.cpp new/sqlitebrowser-3.10.1/src/sqlitedb.cpp
--- old/sqlitebrowser-3.10.0/src/sqlitedb.cpp 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/sqlitedb.cpp 2017-09-20 15:59:51.000000000 +0200
@@ -1157,12 +1157,25 @@
if((*it)->type() == sqlb::Object::Types::Index)
{
sqlb::IndexPtr idx = (*it).dynamicCastsqlb::Index();
- for(int i=0;i<idx->columns().size();i++)
+
+ // Are we updating a field name or are we removing a field entirely?
+ if(to)
{
- if(idx->column(i)->name() == name)
- idx->column(i)->setName(to->name());
+ // We're updating a field name. So search for it in the index and replace it whereever it is found
+ for(int i=0;i<idx->columns().size();i++)
+ {
+ if(idx->column(i)->name() == name)
+ idx->column(i)->setName(to->name());
+ }
+ } else {
+ // We're removing a field. So remove it from any indices, too.
+ while(idx->removeColumn(name))
+ ;
}
- otherObjectsSql << idx->sql();
+
+ // Only try to add the index later if it has any columns remaining
+ if(idx->columns().size())
+ otherObjectsSql << idx->sql();
} else {
// If it's a view or a trigger we don't have any chance to corrections yet. Just store the statement as is and
// hope for the best.
@@ -1401,7 +1414,13 @@
// Set the pragma value
QString sql = QString("PRAGMA %1 = \"%2\";").arg(pragma).arg(value);
- releaseSavepoint();
+ // In general, we want to commit changes before running pragmas because most of them can't be rolled back and some of them
+ // even fail when run in a transaction. However, the defer_foreign_keys pragma has neither problem and we need it to be settable
+ // inside transactions (see the renameColumn() function where it is set and reset at some point and where we don't want the changes
+ // to be committed just because of this pragma).
+ if(pragma != "defer_foreign_keys")
+ releaseSavepoint();
+
bool res = executeSQL(sql, false, true); // PRAGMA statements are usually not transaction bound, so we can't revert
if( !res )
qWarning() << tr("Error setting pragma %1 to %2: %3").arg(pragma).arg(value).arg(lastErrorMessage);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/sqlitetablemodel.cpp new/sqlitebrowser-3.10.1/src/sqlitetablemodel.cpp
--- old/sqlitebrowser-3.10.0/src/sqlitetablemodel.cpp 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/sqlitetablemodel.cpp 2017-09-20 15:59:51.000000000 +0200
@@ -711,13 +711,23 @@
val2.clear();
if(value.left(2) == ">=" || value.left(2) == "<=" || value.left(2) == "<>")
{
- bool ok;
- value.mid(2).toFloat(&ok);
- if(ok)
+ // Check if we're filtering for '<> NULL'. In this case we need a special comparison operator.
+ if(value.left(2) == "<>" && value.mid(2) == "NULL")
{
- op = value.left(2);
- val = value.mid(2);
+ // We are filtering for '<> NULL'. Override the comparison operator to search for NULL values in this column. Also treat search value (NULL) as number,
+ // in order to avoid putting quotes around it.
+ op = "IS NOT";
numeric = true;
+ val = "NULL";
+ } else {
+ bool ok;
+ value.mid(2).toFloat(&ok);
+ if(ok)
+ {
+ op = value.left(2);
+ val = value.mid(2);
+ numeric = true;
+ }
}
} else if(value.left(1) == ">" || value.left(1) == "<") {
bool ok;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/translations/sqlb_ru.ts new/sqlitebrowser-3.10.1/src/translations/sqlb_ru.ts
--- old/sqlitebrowser-3.10.0/src/translations/sqlb_ru.ts 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/translations/sqlb_ru.ts 2017-09-20 15:59:51.000000000 +0200
@@ -3988,7 +3988,7 @@
<message>
<location filename="../SqlUiLexer.cpp" line="107"/>
<source>(X) The count(X) function returns a count of the number of times that X is not NULL in a group.</source>
- <translation>(X) Функция count(X) возвращает количесвто строк, в которых X не равно NULL в группе.</translation>
+ <translation>(X) Функция count(X) возвращает количество строк, в которых X не равно NULL в группе.</translation>
</message>
<message>
<location filename="../SqlUiLexer.cpp" line="108"/>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sqlitebrowser-3.10.0/src/version.h new/sqlitebrowser-3.10.1/src/version.h
--- old/sqlitebrowser-3.10.0/src/version.h 2017-08-18 20:15:39.000000000 +0200
+++ new/sqlitebrowser-3.10.1/src/version.h 2017-09-20 15:59:51.000000000 +0200
@@ -2,7 +2,7 @@
#define GEN_VERSION_H
#define MAJOR_VERSION 3
#define MINOR_VERSION 10
-#define PATCH_VERSION 0
+#define PATCH_VERSION 1
#define str(s) #s
#define xstr(s) str(s)