public inbox for [email protected]
help / color / mirror / Atom feedFrom: Neel Patel <[email protected]>
To: Dave Page <[email protected]>
Cc: pgadmin-hackers <[email protected]>
Subject: Re: [pgAdmin4][runtime]: Download feature in runtime
Date: Wed, 6 Jul 2016 13:42:43 +0530
Message-ID: <CACCA4P3JOe40WYMGjhpSWYGR=WuvRbbp2gfDKLnU+1rXuW9Www@mail.gmail.com> (raw)
In-Reply-To: <CA+OCxoxE-Le_yovC177qHS+27pZJLbgmJ4=n+TCWakFW5Fe8eA@mail.gmail.com>
References: <CACCA4P2eP9URRcHXXiPftxodmV_da57pjSw9PKLgpjEHjrb6MQ@mail.gmail.com>
<CA+OCxozY73dR+0OrOrO-urNHaUOJBXjUJB1q31-oMRyM4jXoyg@mail.gmail.com>
<CACCA4P2bEpUNZhkGQLY1JnMiBChFhauLpqiuAgJQiYcTV6YZ7g@mail.gmail.com>
<CA+OCxoxE-Le_yovC177qHS+27pZJLbgmJ4=n+TCWakFW5Fe8eA@mail.gmail.com>
List-Unsubscribe: <mailto:[email protected]?body=unsub%20pgadmin-hackers>
Hi Dave,
I have tried to fix most of the review comments. I have modified the patch
on top of your changes. Please find attached updated patch file.
Find my comments inline. Can you please review and let us know your
feedback ?
Thanks,
Neel Patel
On Fri, Jul 1, 2016 at 2:39 PM, Dave Page <[email protected]> wrote:
> On Fri, Jul 1, 2016 at 5:43 AM, Neel Patel <[email protected]>
> wrote:
> > Hi Dave,
> >
> > On Thu, Jun 30, 2016 at 7:31 PM, Dave Page <[email protected]> wrote:
> >>
> >> Hi
> >>
> >> On Thu, Jun 30, 2016 at 10:42 AM, Neel Patel
> >> <[email protected]> wrote:
> >> > Hi,
> >> >
> >> > Please find attached patch file for initial version of download file
> in
> >> > runtime application.
> >>
> >> I've attached an update with some improved messages, and setting the
> >> progress dialogue to be modal (seeing as we cannot have multiple
> >> downloads, and it's easy to lose the dialogue).
> >>
> >> > With this patch, we have implemented two features.
> >> >
> >> > Feature 1 :- Normal "Download file" from runtime application
> >> >
> >> > Previously "Download file" was not implemented in runtime application.
> >> > With this patch file, we have handled Qt signal for download file
> >> > properly.
> >>
> >> This seems to work fine. I did get one crash (after I cancelled a
> >> download, then tried it again), but I couldn't reproduce that.
> >
> >
> > Okay. I will try to reproduce the issue and also i will try to review the
> > code again if i can find something regrading crash.
>
I have tried to reproduce the crash but no luck. I have tried on Linux and
Mac.
>
> Thanks.
>
> >
> >>
> >> > Feature 2 :- "download" attribute support for 'a' tag for client
> side
> >> > download
> >> >
> >> > As per our knowledge, webkit has not implemented the download
> attribute
> >> > at
> >> > 'a' tag.
> >> > Currently it shows under development from below link.
> >> >
> >> > https://bugreports.qt.io/browse/QTBUG-47732
> >> >
> >> > We did not found any signal in Qt for download attribute feature but
> to
> >> > implement this feature in runtime application, we added one workaround
> >> > to
> >> > make it work with download CSV file.
> >> >
> >> > When we click on download buttons, we are getting Qt signal
> >> > "urlLinkClicked"
> >> > and in that url we are finding "data:text/csv" from encoded URL
> >> > generated
> >> > from sqleditor. Once we found that tag then we are decoding the csv
> data
> >> > and
> >> > writing to file.
> >> >
> >> > Is that right approach ? Should we add our own custom mime-type to
> >> > header ?
> >> > Let us know your thoughts on this feature.
> >>
> >> This doesn't work so well, for a number of reasons:
> >>
> >> 1) QT Creator is complaining that your regexp contains an invalid
> >> escape sequence (line 546).
> >
> >
> > I will fix.
> >>
> >>
> >> 2) The default file name seems to be the entire data blob. I would
> >> suggest making the file name "download.csv" if we don't know anything
> >> better. The "csv" part should be taken from the mime type (see below)
> >>
> >> 3) Should we handle all "data:" downloads in this way? Taking the file
> >> type and default extension from the mimetype offered.
> >
> >
> > We can handle all "data:" download. We will extract the filename and
> > extension from mime type.
> > As i know, Qt provides QUrlQuery class which will be useful to find the
> key
> > value pair. I will test and let you know.
> >
> > e.g. If we have header as below
> >
> >
> "data:text/csv;charset=utf-8;Content-disposition:attachment;filename=download.csv;"
> >
> > From the QurlQuery class we can query "filename" and "data:" and
> accordingly
> > save the data to filename provided.
> >
> > Please suggest.
>
> Sounds good.
>
> >> 4) When I change the filename the data is properly saved, but then I
> >> get a confirmation message that still has the full data blob as the
> >> filename.
>
I found that it is due to different Qt version. You might be using Qt 5.5.
In Qt 5.5, we are getting "download" signal and for Qt < 5.5 we are getting
"urlLinkClicked" signal for client side data download.
We have fixed the issue for all Qt version. Let me know if you can still
able to reproduce the issue.
> >>
> >> 5) It somehow seems to have let me save files with forward slashes in
> >> the name. See attachment.
>
Fixed.
>
> >
> > I think we should not ask for "Save as" dialog. If there is no key found
> of
> > "filename" in encodedURI then we should create the file "download.csv" in
> > user's download directory and save the csv data.
>
> Well we can get the extension from the mimetype in that instance, but
> otherwise I agree with the naming. I do think we need a Save As
> dialogue, as the user should be able to choose the location for the
> file (and rename it). We should also remember the last save location
> for convenience.
>
Fixed.
>
> >> 6) I get all sorts of weird redrawing on the screen when downloading a
> >> data blob. I suspect it's because the filename (which is still the
> >> entire data blob) is shown on the progress dialogue.
> >>
>
Fixed.
> >
> > I will try to fix as per above comments and submit the patch again.
> > Let us know for any misunderstanding.
>
> Cool, thanks.
>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EnterpriseDB UK: http://www.enterprisedb.com
> The Enterprise PostgreSQL Company
>
--
Sent via pgadmin-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgadmin-hackers
Attachments:
[application/octet-stream] download_runtime_v3.patch (19.1K, 3-download_runtime_v3.patch)
download | inline diff:
diff --git a/runtime/BrowserWindow.cpp b/runtime/BrowserWindow.cpp
index e875b28..a73ab00 100644
--- a/runtime/BrowserWindow.cpp
+++ b/runtime/BrowserWindow.cpp
@@ -23,7 +23,6 @@
#include <QInputDialog>
#include <QLineEdit>
#endif
-
// App headers
#include "BrowserWindow.h"
#include "ConfigWindow.h"
@@ -42,6 +41,14 @@ BrowserWindow::BrowserWindow(QString url)
m_widget = NULL;
m_toolBtnBack = NULL;
m_toolBtnForward = NULL;
+ m_downloadStarted = 0;
+ m_downloadCancelled = 0;
+ m_file = NULL;
+ m_downloadFilename = "";
+ m_defaultFilename = "";
+ m_progressDialog = NULL;
+ m_last_open_folder_path = QDir::currentPath();
+ m_dir = "";
m_appServerUrl = url;
@@ -83,6 +90,11 @@ BrowserWindow::BrowserWindow(QString url)
// Register the slot on tab index change
connect(m_tabWidget,SIGNAL(currentChanged(int )),this,SLOT(tabIndexChanged(int )));
+ // Listen for the download file request from the web page
+ m_mainWebView->page()->setForwardUnsupportedContent(true);
+ connect(m_mainWebView->page(), SIGNAL(downloadRequested(const QNetworkRequest &)), this, SLOT(download(const QNetworkRequest &)));
+ connect(m_mainWebView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
+
m_mainWebView->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
// Restore the geometry
@@ -199,6 +211,281 @@ int BrowserWindow::findURLTab(const QUrl &name)
return 0;
}
+// This slot will be called when user right click the download link and select "Save Link..."
+void BrowserWindow::download(const QNetworkRequest &request)
+{
+ // Check that request contains the data download at client side
+ QUrl name;
+ if (checkClientDownload(name, request))
+ return;
+
+ if (m_downloadStarted)
+ {
+ // Inform the user that a download is already started
+ QMessageBox::information(this, tr("Download warning"), tr("File download already in progress: %1").arg(m_defaultFilename));
+ return;
+ }
+
+ m_defaultFilename = QFileInfo(request.url().toString()).fileName();
+
+ QFileDialog save_dialog(this);
+ save_dialog.setAcceptMode(QFileDialog::AcceptSave);
+ save_dialog.setWindowTitle(tr("Save file"));
+ save_dialog.setDirectory(m_last_open_folder_path);
+ save_dialog.selectFile(m_defaultFilename);
+
+ QObject::connect(&save_dialog, SIGNAL(directoryEntered(const QString &)), this, SLOT(current_dir_path(const QString &)));
+ m_dir = m_last_open_folder_path;
+ QString fileName = "";
+ QString f_name = "";
+
+ if (save_dialog.exec() == QDialog::Accepted) {
+ fileName = save_dialog.selectedFiles().first();
+ f_name = fileName.replace(m_dir, "");
+ // remove the first character from fiename
+ f_name.remove(0,1);
+ m_defaultFilename = f_name;
+ }
+ else
+ return;
+
+ fileName = m_dir + fileName;
+ // clear the last folder open path
+ m_dir.clear();
+
+#ifdef __APPLE__
+ // Check that user has given valid file name or not - forward slash not allowed in file name
+ // In Mac OSX, forward slash is converted to colon(:) by Qt so we need to check for colon.
+ if (f_name.indexOf(":") != -1)
+ {
+ QMessageBox::information(this, tr("File name error"), tr("Invalid file name"));
+ return;
+ }
+#else
+ // Check that user has given valid file name or not - forward slash not allowed in file name
+ if (f_name.indexOf("/") != -1)
+ {
+ QMessageBox::information(this, tr("File name error"), tr("Invalid file name"));
+ return;
+ }
+#endif
+
+ if (fileName.isEmpty())
+ return;
+ else
+ {
+ m_downloadFilename = fileName;
+
+ QNetworkRequest newRequest = request;
+ newRequest.setAttribute(QNetworkRequest::User, fileName);
+
+ QObject *obj_web_page = QObject::sender();
+ if (obj_web_page != NULL)
+ {
+ QWebPage *sender_web_page = dynamic_cast<QWebPage*>(obj_web_page);
+ if (sender_web_page != NULL)
+ {
+ QNetworkAccessManager *networkManager = sender_web_page->networkAccessManager();
+ QNetworkReply *reply = networkManager->get(newRequest);
+ if (reply != NULL)
+ {
+ m_downloadStarted = 1;
+ m_downloadCancelled = 0;
+ // Connect the signal for downloadProgress and downloadFinished for file download
+ connect( reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadFileProgress(qint64, qint64)) );
+ connect( reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
+ }
+ }
+ }
+ }
+}
+
+//This slot will called in chunk and give the progress for the file download
+void BrowserWindow::downloadFileProgress(qint64 readData, qint64 totalData)
+{
+ QNetworkReply *reply = ((QNetworkReply*)sender());
+ QNetworkRequest request = reply->request();
+ QVariant v = request.attribute(QNetworkRequest::User);
+
+ // Is download is canceled by the user then no action is taken, just return
+ if (m_downloadCancelled)
+ return;
+
+ if(reply != NULL && reply->error() != QNetworkReply::NoError)
+ {
+ qDebug() << "Network error occurred whilst downloading: " << m_defaultFilename;
+ return;
+ }
+
+ // Download is not yet started so open the file first time.
+ if (!m_file)
+ {
+ m_file = new QFile(m_downloadFilename);
+ if (!m_file->open(QIODevice::WriteOnly))
+ {
+ qDebug() << "Error opening file: " << m_downloadFilename;
+ m_downloadFilename.clear();
+ m_defaultFilename.clear();
+ m_downloadStarted = 0;
+ return;
+ }
+
+ // Start downloading progress bar
+ m_progressDialog = new QProgressDialog (tr("Downloading file: %1 ").arg(m_defaultFilename), "Cancel", readData, totalData, this);
+ m_progressDialog->setWindowModality(Qt::WindowModal);
+ m_progressDialog->setWindowTitle("Download progress");
+ m_progressDialog->setMinimumWidth(450);
+ m_progressDialog->setMinimumHeight(80);
+ m_progressDialog->setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint);
+ QObject::connect(m_progressDialog, SIGNAL(canceled()), this, SLOT(progressCanceled()));
+ m_progressDialog->show();
+ }
+
+ if (m_file)
+ {
+ // Write the data to file
+ m_file->write(reply->read(readData));
+ m_progressDialog->setValue(readData);
+
+ // As read data and totalData difference is zero means downloading is finished
+ if ((totalData - readData) == 0)
+ {
+ if (m_progressDialog)
+ {
+ delete m_progressDialog;
+ m_progressDialog = NULL;
+ }
+
+ // Downloading complted so we need to display the message
+ // Inform user that downloading is completed
+ QMessageBox::information(this, tr("Download completed"), tr("Successfully downloaded %1").arg(m_defaultFilename));
+ m_downloadFilename.clear();
+ m_defaultFilename.clear();
+ m_downloadStarted = 0;
+ m_downloadCancelled = 0;
+ if (m_file)
+ {
+ delete m_file;
+ m_file = NULL;
+ }
+ }
+ }
+}
+
+//This slot will called when user cancel the downloading file which is in progress.
+void BrowserWindow::progressCanceled()
+{
+ m_downloadCancelled = 1;
+
+ if (m_progressDialog)
+ {
+ delete m_progressDialog;
+ m_progressDialog = NULL;
+ }
+
+ if (m_file)
+ {
+ delete m_file;
+ m_file = NULL;
+ }
+
+ m_downloadFilename.clear();
+ m_defaultFilename.clear();
+ m_downloadStarted = 0;
+}
+
+// This slot will called when file downloading is finished
+void BrowserWindow::downloadFinished()
+{
+ if (m_progressDialog)
+ {
+ delete m_progressDialog;
+ m_progressDialog = NULL;
+ }
+
+ // Inform user that downloading is completed
+ if (m_downloadStarted)
+ QMessageBox::information(this, tr("Download completed"), tr("Successfully downloaded %1").arg(m_defaultFilename));
+
+ m_downloadFilename.clear();
+ m_defaultFilename.clear();
+ m_downloadStarted = 0;
+ m_downloadCancelled = 0;
+ if (m_file)
+ {
+ delete m_file;
+ m_file = NULL;
+ }
+}
+
+// This slot will be called when user directly click on any download file
+void BrowserWindow::unsupportedContent(QNetworkReply * reply)
+{
+ if (m_downloadStarted)
+ {
+ //Inform the user that one download already started
+ QMessageBox::information(this, tr("Download warning"), tr("File download already in progress: %1").arg(m_defaultFilename));
+ return;
+ }
+
+ m_defaultFilename = QFileInfo(reply->url().toString()).fileName();
+ QFileDialog save_dialog(this);
+ save_dialog.setAcceptMode(QFileDialog::AcceptSave);
+ save_dialog.setWindowTitle(tr("Save file"));
+ save_dialog.setDirectory(m_last_open_folder_path);
+ save_dialog.selectFile(m_defaultFilename);
+
+ QObject::connect(&save_dialog, SIGNAL(directoryEntered(const QString &)), this, SLOT(current_dir_path(const QString &)));
+ m_dir = m_last_open_folder_path;
+ QString fileName = "";
+ QString f_name = "";
+
+ if (save_dialog.exec() == QDialog::Accepted) {
+ fileName = save_dialog.selectedFiles().first();
+ f_name = fileName.replace(m_dir, "");
+ // remove the first character from fiename
+ f_name.remove(0,1);
+ m_defaultFilename = f_name;
+ }
+ else
+ return;
+
+ fileName = m_dir + fileName;
+ // clear the last folder open path
+ m_dir.clear();
+
+#ifdef __APPLE__
+ // Check that user has given valid file name or not - forward slash not allowed in file name
+ // In Mac OSX, forward slash is converted to colon(:) by Qt so we need to check for colon.
+ if (f_name.indexOf(":") != -1)
+ {
+ QMessageBox::information(this, tr("File name error"), tr("Invalid file name"));
+ return;
+ }
+#else
+ // Check that user has given valid file name or not - forward slash not allowed in file name
+ if (f_name.indexOf("/") != -1)
+ {
+ QMessageBox::information(this, tr("File name error"), tr("Invalid file name"));
+ return;
+ }
+#endif
+
+ if (fileName.isEmpty())
+ return;
+ else
+ {
+ m_downloadFilename = fileName;
+ if (reply != NULL)
+ {
+ m_downloadStarted = 1;
+ m_downloadCancelled = 0;
+ connect( reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadFileProgress(qint64, qint64)));
+ connect( reply, SIGNAL(finished()), this, SLOT(downloadFinished()));
+ }
+ }
+}
+
// Slot: When the tab index change, hide/show the toolbutton displayed on tab
void BrowserWindow::tabIndexChanged(int index)
{
@@ -340,9 +627,142 @@ void BrowserWindow::tabTitleChanged(const QString &str)
}
}
+// This function will used to download the data set in encoded URL so data will be downloaded at client side.
+bool BrowserWindow::checkClientDownload(const QUrl &name, const QNetworkRequest &request)
+{
+ QString mime_type = "";
+ QString file_name = "";
+ QString write_data = "";
+ QString csv_data = "";
+ bool return_val = false;
+
+ /*
+ In Qt version 5.5, "download" signal is emitted when 'download' attribute is set on 'a' tag.
+ In "download" signal emission, name will be empty and data will be in request object.
+ Earlier version ( < 5.5 ), "urlLinkClicked" signal is emitted so name will contain the object data.
+ */
+ if (name.isEmpty())
+ csv_data = QFileInfo(request.url().toString()).fileName();
+ else
+ csv_data = QString::fromUtf8(name.toEncoded());
+
+ QUrlQuery downloadData(csv_data);
+ QStringList keyValueData = csv_data.split("&");
+ file_name = downloadData.queryItemValue("filename");
+ write_data = downloadData.queryItemValue("value");
+
+ int key_value_length = keyValueData.size();
+ int i_count = 0;
+
+ // we have key value data so we need to tokeniza it and find the values
+ while (i_count < key_value_length)
+ {
+ //Extract the extension after "data:" word found from encoded url.
+ QString start_match_string = "data:";
+ int s_offset = keyValueData.at(i_count).indexOf(start_match_string);
+ if (s_offset != -1)
+ {
+ int format_offset = keyValueData.at(i_count).indexOf("/");
+ mime_type = keyValueData.at(i_count).mid((format_offset+1));
+ break;
+ }
+
+ int split_offset = keyValueData.at(i_count).indexOf("=");
+ if (split_offset == -1)
+ {
+ mime_type = keyValueData.at(i_count);
+ break;
+ }
+
+ i_count += 1;
+ }
+
+ // write data to file
+ if (!write_data.isEmpty())
+ {
+ QString filename = "";
+ QString f_name = "";
+ QFileDialog saveAsdialog(this);
+ saveAsdialog.setAcceptMode(QFileDialog::AcceptSave);
+ saveAsdialog.selectNameFilter(tr("Files (*.%1)").arg(mime_type));
+ saveAsdialog.setWindowTitle(tr("Save %1 file").arg(mime_type));
+ saveAsdialog.setDirectory(m_last_open_folder_path);
+ saveAsdialog.selectFile(file_name);
+ saveAsdialog.setDefaultSuffix(mime_type);
+
+ QObject::connect(&saveAsdialog, SIGNAL(directoryEntered(const QString &)), this, SLOT(current_dir_path(const QString &)));
+ m_dir = m_last_open_folder_path;
+
+ if (saveAsdialog.exec() == QDialog::Accepted) {
+ filename = saveAsdialog.selectedFiles().at(0);
+ QString filename = saveAsdialog.selectedFiles().first();
+ f_name = filename.replace(m_dir, "");
+ // remove the first character from fiename
+ f_name.remove(0,1);
+ }
+
+ // clear the last folder open path
+ m_dir.clear();
+
+ return_val = true;
+
+#ifdef __APPLE__
+ // Check that user has given valid file name or not - forward slash not allowed in file name
+ // In Mac OSX, forward slash is converted to colon(:) by Qt so we need to check for colon.
+ if (f_name.indexOf(":") != -1)
+ {
+ QMessageBox::information(this, tr("File name error"), tr("Invalid file name"));
+ return return_val;
+ }
+#else
+ // Check that user has given valid file name or not - forward slash not allowed in file name
+ if (f_name.indexOf("/") != -1)
+ {
+ QMessageBox::information(this, tr("File name error"), tr("Invalid file name"));
+ return return_val;
+ }
+#endif
+ if(!filename.isEmpty())
+ {
+ // save the last open folder path
+ m_last_open_folder_path = QFileInfo(filename).path();
+ // Decode the encoded uri data
+ QString csvData = QUrl::fromPercentEncoding(write_data.toUtf8());
+
+ QFile csvfile(filename);
+ if (!csvfile.open(QIODevice::WriteOnly | QIODevice::Text))
+ {
+ QMessageBox::information(this, tr("Save csv file"), tr("Error while opening file %1").arg(filename));
+ return return_val;
+ }
+ // Write the csv data to file
+ qint64 data_return = csvfile.write(csvData.toUtf8().constData());
+ if (data_return == -1)
+ {
+ QMessageBox::information(this, tr("Save csv file"), tr("Error while writing data to file %1").arg(filename));
+ csvfile.close();
+ return return_val;
+ }
+ csvfile.close();
+ }
+ }
+
+ return return_val;
+}
+
+void BrowserWindow::current_dir_path(const QString &dir)
+{
+ m_dir = dir;
+}
+
// Slot: Link is open from pgAdmin mainwindow
void BrowserWindow::urlLinkClicked(const QUrl &name)
{
+ // Check that request contains the data download at client side
+ QNetworkRequest request;
+ if (checkClientDownload(name, request))
+ return;
+
// First check is there any tab opened with same URL then open it again.
int tabFound = findURLTab(name);
@@ -353,6 +773,11 @@ void BrowserWindow::urlLinkClicked(const QUrl &name)
m_addNewGridLayout->setContentsMargins(0, 0, 0, 0);
m_addNewWebView = new WebViewWindow(m_addNewTab);
+ // Listen for the download request from the web page
+ m_addNewWebView->page()->setForwardUnsupportedContent(true);
+ connect(m_addNewWebView->page(), SIGNAL(downloadRequested(const QNetworkRequest &)), this, SLOT(download(const QNetworkRequest &)));
+ connect(m_addNewWebView->page(), SIGNAL(unsupportedContent(QNetworkReply*)), this, SLOT(unsupportedContent(QNetworkReply*)));
+
m_widget = new QWidget(m_addNewTab);
m_toolBtnBack = new QToolButton(m_widget);
m_toolBtnBack->setFixedHeight(PGA_BTN_SIZE);
diff --git a/runtime/BrowserWindow.h b/runtime/BrowserWindow.h
index 43f90fe..7635549 100644
--- a/runtime/BrowserWindow.h
+++ b/runtime/BrowserWindow.h
@@ -54,6 +54,12 @@ public slots:
void tabIndexChanged(int index);
void goBackPage();
void goForwardPage();
+ void download(const QNetworkRequest &request);
+ void unsupportedContent(QNetworkReply * reply);
+ void downloadFinished();
+ void downloadFileProgress(qint64 , qint64 );
+ void progressCanceled();
+ void current_dir_path(const QString &dir);
private:
QString m_appServerUrl;
@@ -79,10 +85,19 @@ private:
bool m_initialLoad;
int m_loadAttempt;
+ QString m_downloadFilename;
+ int m_downloadStarted;
+ int m_downloadCancelled;
+ QFile *m_file;
+ QProgressDialog *m_progressDialog;
+ QString m_defaultFilename;
+ QString m_last_open_folder_path;
+ QString m_dir;
void createActions();
void pause(int seconds = 1);
int findURLTab(const QUrl &name);
+ bool checkClientDownload(const QUrl &name, const QNetworkRequest &request);
};
#endif // BROWSERWINDOW_H
diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
index 295caf4..2df2b5f 100644
--- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
+++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js
@@ -2587,7 +2587,7 @@ define(
keys = _.pluck(self.columns, 'name');
// Fetch the items from fullCollection and convert it as csv format
- var csv = labels.join(',') + '\n';
+ var csv = keys.join(',') + '\n';
csv += coll.map(function(item) {
return _.map(keys, function(key) {
var cell = csv_col [key].cell,
@@ -2600,7 +2600,7 @@ define(
}).join('\n');
// Download the file.
- var encodedUri = encodeURI('data:text/csv;charset=utf-8,' + csv),
+ var encodedUri = encodeURI('data:text/csv&charset=utf-8&filename=download.csv&value=' + csv),
link = document.createElement('a');
link.setAttribute('href', encodedUri);
view thread (8+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected]
Subject: Re: [pgAdmin4][runtime]: Download feature in runtime
In-Reply-To: <CACCA4P3JOe40WYMGjhpSWYGR=WuvRbbp2gfDKLnU+1rXuW9Www@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox