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 - wba...@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<QComboBox*>(sender());
+    QComboBox* typeBox = qobject_cast<QComboBox*>(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<QComboBox*>(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<QString, QString> 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<QString, QString>& 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<QString, QString>& 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).dynamicCast<sqlb::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)


Reply via email to