Index: runtime/BrowserWindow.h IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- runtime/BrowserWindow.h (revision d79524ff60a4645af798ce1e926210320de26a99) +++ runtime/BrowserWindow.h (revision ) @@ -54,6 +54,11 @@ 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(); private: QString m_appServerUrl; @@ -79,6 +84,12 @@ bool m_initialLoad; int m_loadAttempt; + QString m_downloadFilename; + int m_downloadStarted; + int m_downloadCancelled; + QFile *m_file; + QProgressDialog *m_progressDialog; + QString m_defaultFilename; void createActions(); void pause(int seconds = 1); Index: runtime/BrowserWindow.cpp IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- runtime/BrowserWindow.cpp (revision d79524ff60a4645af798ce1e926210320de26a99) +++ runtime/BrowserWindow.cpp (revision ) @@ -23,7 +23,6 @@ #include #include #endif - // App headers #include "BrowserWindow.h" #include "ConfigWindow.h" @@ -42,6 +41,12 @@ 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_appServerUrl = url; @@ -83,6 +88,11 @@ // 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 +209,193 @@ return 0; } +// This slot will be called when user right click the download link and select "Save Link..." +void BrowserWindow::download(const QNetworkRequest &request) +{ + 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(); + QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), m_defaultFilename); + 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(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(); + QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), m_defaultFilename); + 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) { @@ -343,6 +540,40 @@ // Slot: Link is open from pgAdmin mainwindow void BrowserWindow::urlLinkClicked(const QUrl &name) { + QString csv_data = QString::fromUtf8(name.toEncoded()); + + // Find the "data:text/csv" tag, get the decoded data from QUrl class and write to csv file. + if (csv_data.contains(QRegExp("^data:text\\/csv"))) + { + // Ask user where to save the csv file in filesystem. + QString filename = QFileDialog::getSaveFileName(this, tr("Save csv file"), QDir::currentPath(), tr("Files (*.csv)") ); + if(!filename.isEmpty()) + { + // Decode the encoded uri data + QString csvData = QUrl::fromPercentEncoding(name.toEncoded()); + QStringList csvStrList = csvData.split(";"); + QString extractString = ""; + if (csvStrList.size() >= 3) + extractString = csvStrList.at(2); + 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; + } + // Write the csv data to file + qint64 data_return = csvfile.write(extractString.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; + } + csvfile.close(); + } + return; + } + // First check is there any tab opened with same URL then open it again. int tabFound = findURLTab(name); @@ -352,6 +583,11 @@ m_addNewGridLayout = new QGridLayout(m_addNewTab); 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); Index: web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js (revision d79524ff60a4645af798ce1e926210320de26a99) +++ web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js (revision ) @@ -2572,7 +2572,7 @@ 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, @@ -2585,7 +2585,7 @@ }).join('\n'); // Download the file. - var encodedUri = encodeURI('data:text/csv;charset=utf-8,' + csv), + var encodedUri = encodeURI('data:text/csv;charset=utf-8;' + csv), link = document.createElement('a'); link.setAttribute('href', encodedUri);