now actually downloads parts

Fri, 02 Aug 2013 22:02:40 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Fri, 02 Aug 2013 22:02:40 +0300
changeset 427
d308149fbc90
parent 426
be5746bf0f12
child 428
53e577061dc8

now actually downloads parts

src/download.cpp file | annotate | diff | comparison | revisions
src/download.h file | annotate | diff | comparison | revisions
src/ui/downloadfrom.ui file | annotate | diff | comparison | revisions
--- a/src/download.cpp	Fri Aug 02 18:42:06 2013 +0300
+++ b/src/download.cpp	Fri Aug 02 22:02:40 2013 +0300
@@ -16,11 +16,17 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QDir>
+#include <QProgressBar>
 #include "download.h"
 #include "ui_downloadfrom.h"
 #include "types.h"
 #include "gui.h"
 #include "build/moc_download.cpp"
+#include "file.h"
 
 PartDownloader g_PartDownloader;
 
@@ -39,6 +45,8 @@
 PartDownloadPrompt::PartDownloadPrompt (QWidget* parent) : QDialog (parent) {
 	ui = new Ui_DownloadFrom;
 	ui->setupUi (this);
+	ui->fname->setFocus();
+	
 	connect (ui->source, SIGNAL (currentIndexChanged (int)), this, SLOT (sourceChanged (int)));
 	connect (ui->buttonBox, SIGNAL (accepted()), this, SLOT (startDownload()));
 }
@@ -51,55 +59,16 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-str PartDownloadPrompt::getURL() {
-	str fname;
-	Source src = (Source) ui->source->currentIndex();
+str PartDownloadPrompt::getURL() const {
+	const Source src = getSource();
 	
 	switch (src) {
 	case OfficialLibrary:
 	case PartsTracker:
-		{
-			fname = ui->fname->text();
+		if (src == OfficialLibrary)
+			return str (PartDownloader::k_OfficialURL) + getDest();
 		
-			// Ensure .dat extension
-			if (fname.right (4) != ".dat") {
-				// Remove the existing extension, if any. It may be we're here over a
-				// typo in the .dat extension.
-				if (fname.lastIndexOf (".") >= fname.length() - 4)
-					fname.chop (fname.length() - fname.lastIndexOf ("."));
-				
-				fname += ".dat";
-			}
-			
-			/* These sources have stuff only in parts/, parts/s/, p/, and p/48/. If
-			* we haven't already specified either parts/ or p/, we need to add it
-			* automatically. Part files are numbers which can be followed by:
-			* - c** (composites)
-			* - d** (formed stickers)
-			* - a lowercase alphabetic letter for variants
-			*
-			* Subfiles have an s** prefix, in which case we use parts/s/. Note that
-			* the regex starts with a '^' so it won't catch already fully given part
-			* file names.
-			*/
-			str partRegex = "^[0-9]+(c[0-9][0-9]+)*(d[0-9][0-9]+)*[a-z]?";
-			str subpartRegex = partRegex + "s[0-9][0-9]+";
-			
-			partRegex += "\\.dat$";
-			subpartRegex += "\\.dat$";
-			
-			if (QRegExp (subpartRegex).exactMatch (fname))
-				fname.prepend ("parts/s/");
-			elif (QRegExp (partRegex).exactMatch (fname))
-				fname.prepend ("parts/");
-			elif (fname.left (6) != "parts/" && fname.left (2) != "p/")
-				fname.prepend ("p/");
-		}
-		
-		if (src == OfficialLibrary)
-			return str (PartDownloader::k_OfficialURL) + fname;
-		
-		return str (PartDownloader::k_UnofficialURL) + fname;
+		return str (PartDownloader::k_UnofficialURL) + getDest();
 	
 	case CustomURL:
 		return ui->fname->text();
@@ -111,6 +80,66 @@
 
 // =============================================================================
 // -----------------------------------------------------------------------------
+str PartDownloadPrompt::getDest() const {
+	str fname = ui->fname->text();
+	
+	if (getSource() == CustomURL)
+		fname = basename (fname);
+	
+	// Ensure .dat extension
+	if (fname.right (4) != ".dat") {
+		// Remove the existing extension, if any. It may be we're here over a
+		// typo in the .dat extension.
+		if (fname.lastIndexOf (".") >= fname.length() - 4)
+			fname.chop (fname.length() - fname.lastIndexOf ("."));
+		
+		fname += ".dat";
+	}
+	
+	/* Try determine where to put this part. We have four directories:
+	 * parts/, parts/s/, p/, and p/48/. If we haven't already specified
+	 * either parts/ or p/, we need to add it automatically. Part files
+	 * are numbers which can be followed by:
+	 * - c** (composites)
+	 * - d** (formed stickers)
+	 * - a lowercase alphabetic letter for variants
+	 *
+	 * Subfiles have an s** prefix, in which case we use parts/s/. Note that
+	 * the regex starts with a '^' so it won't catch already fully given part
+	 * file names.
+	 */
+	{
+		str partRegex = "^[0-9]+(c[0-9][0-9]+)*(d[0-9][0-9]+)*[a-z]?";
+		str subpartRegex = partRegex + "s[0-9][0-9]+";
+		
+		partRegex += "\\.dat$";
+		subpartRegex += "\\.dat$";
+		
+		if (QRegExp (subpartRegex).exactMatch (fname))
+			fname.prepend ("parts/s/");
+		elif (QRegExp (partRegex).exactMatch (fname))
+			fname.prepend ("parts/");
+		elif (fname.left (6) != "parts/" && fname.left (2) != "p/")
+			fname.prepend ("p/");
+	}
+	
+	return fname;
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+str PartDownloadPrompt::fullFilePath() const {
+	return "/home/arezey/ldraw/downloads/" + getDest(); // FIXME: hehe
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+PartDownloadPrompt::Source PartDownloadPrompt::getSource() const {
+	return (Source) ui->source->currentIndex();
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
 void PartDownloadPrompt::sourceChanged (int i) {
 	if (i == CustomURL)
 		ui->fileNameLabel->setText (tr ("URL:"));
@@ -118,41 +147,102 @@
 		ui->fileNameLabel->setText (tr ("File name:"));
 }
 
+// =============================================================================
+// -----------------------------------------------------------------------------
 void PartDownloadPrompt::startDownload() {
 	int row = ui->progress->rowCount();
 	ui->progress->setEnabled (true);
 	ui->buttonBox->setEnabled (false);
 	ui->progress->insertRow (row);
+	ui->fname->setEnabled (false);
+	ui->source->setEnabled (false);
 	
-	PartDownloadRequest* req = new PartDownloadRequest (getURL(), this);
+	PartDownloadRequest* req = new PartDownloadRequest (getURL(), getDest(), this);
 	req->setTableRow (row);
 	req->updateToTable();
 }
 
 // =============================================================================
 // -----------------------------------------------------------------------------
-PartDownloadRequest::PartDownloadRequest (str url, PartDownloadPrompt* parent) :
+PartDownloadRequest::PartDownloadRequest (str url, str dest, PartDownloadPrompt* parent) :
 	QObject (parent),
 	m_prompt (parent),
-	m_url (url) {}
+	m_url (url),
+	m_dest (dest),
+	m_fpath (m_prompt->fullFilePath()),
+	m_nam (new QNetworkAccessManager),
+	m_firstUpdate (true),
+	m_state (Requesting)
+{
+	// Make sure that we have a valid destination.
+	str dirpath = dirname (m_fpath);
+	
+	QDir dir (dirpath);
+	if (!dir.exists()) {
+		print ("Creating %1...\n", dirpath);
+		if (!dir.mkpath (dirpath))
+			critical (fmt (tr ("Couldn't create the directory %1!"), dirpath));
+	}
+	
+	m_reply = m_nam->get (QNetworkRequest (QUrl (url)));
+	connect (m_reply, SIGNAL (finished()), this, SLOT (downloadFinished()));
+	connect (m_reply, SIGNAL (readyRead()), this, SLOT (readyRead()));
+	connect (m_reply, SIGNAL (downloadProgress (qint64, qint64)), this, SLOT (downloadProgress (qint64, qint64)));
+}
+
+// =============================================================================
+// -----------------------------------------------------------------------------
+PartDownloadRequest::~PartDownloadRequest() {
+
+}
 
 // =============================================================================
 // -----------------------------------------------------------------------------
 void PartDownloadRequest::updateToTable() {
 	QTableWidget* table = m_prompt->ui->progress;
-	QTableWidgetItem* urlItem = table->item (tableRow(), 0),
-		*progressItem = table->item (tableRow(), 1);
+	QProgressBar* progressBar = qobject_cast<QProgressBar*> (table->cellWidget (tableRow(), ProgressColumn));
 	
-	if (!urlItem || !progressItem) {
-		urlItem = new QTableWidgetItem;
-		progressItem = new QTableWidgetItem;
-		
-		table->setItem (tableRow(), 0, urlItem);
-		table->setItem (tableRow(), 1, progressItem);
+	if (!progressBar) {
+		progressBar = new QProgressBar;
+		table->setCellWidget (tableRow(), ProgressColumn, progressBar);
 	}
 	
-	urlItem->setText (m_url);
-	progressItem->setText ("---");
+	progressBar->setRange (0, m_bytesTotal);
+	progressBar->setValue (m_bytesRead);
+	
+	if (m_firstUpdate) {
+		QLabel* lb = new QLabel (fmt ("<b>%1</b><br>%2", m_dest, m_url), table);
+		table->setCellWidget (tableRow(), PartLabelColumn, lb);
+		
+		// Make sure that the cell is big enough to contain the label
+		if (table->columnWidth (PartLabelColumn) < lb->width())
+			table->setColumnWidth (PartLabelColumn, lb->width());
+		
+		table->setRowHeight (tableRow(), lb->height());
+		m_firstUpdate = false;
+	}
+}
+
+void PartDownloadRequest::downloadFinished() {
+	m_state = Finished;
+	m_bytesRead = m_bytesTotal;
+	updateToTable();
+}
+
+void PartDownloadRequest::downloadProgress (int64 recv, int64 total) {
+	m_bytesRead = recv;
+	m_bytesTotal = total;
+	m_state = Downloading;
+	updateToTable();
+}
+
+void PartDownloadRequest::readyRead() {
+	QFile f (m_fpath);
+	if (!f.open (QIODevice::Append))
+		return;
+	
+	f.write (m_reply->readAll());
+	f.close();
 }
 
 // =============================================================================
--- a/src/download.h	Fri Aug 02 18:42:06 2013 +0300
+++ b/src/download.h	Fri Aug 02 22:02:40 2013 +0300
@@ -21,6 +21,7 @@
 
 #include <QDialog>
 #include "common.h"
+#include "types.h"
 
 class Ui_DownloadFrom;
 class QNetworkAccessManager;
@@ -53,7 +54,10 @@
 	
 	explicit PartDownloadPrompt (QWidget* parent = null);
 	virtual ~PartDownloadPrompt();
-	str getURL();
+	str getURL() const;
+	str fullFilePath() const;
+	str getDest() const;
+	Source getSource() const;
 	
 public slots:
 	void sourceChanged (int i);
@@ -67,17 +71,42 @@
 // =============================================================================
 // -----------------------------------------------------------------------------
 class PartDownloadRequest : public QObject {
+	Q_OBJECT
 	PROPERTY (int, tableRow, setTableRow)
 	
 public:
-	explicit PartDownloadRequest (str url, PartDownloadPrompt* parent);
+	enum TableColumn {
+		PartLabelColumn,
+		ProgressColumn,
+	};
+	
+	enum State {
+		Requesting,
+		Downloading,
+		Finished,
+		Aborted,
+	};
+	
+	explicit PartDownloadRequest (str url, str dest, PartDownloadPrompt* parent);
+	         PartDownloadRequest (const PartDownloadRequest&) = delete;
+	virtual ~PartDownloadRequest();
 	void updateToTable();
 	
+	void operator= (const PartDownloadRequest&) = delete;
+	
+public slots:
+	void downloadFinished();
+	void readyRead();
+	void downloadProgress (qint64 recv, qint64 total);
+	
 private:
 	PartDownloadPrompt* m_prompt;
-	str m_url;
+	str m_url, m_dest, m_fpath;
 	QNetworkAccessManager* m_nam;
 	QNetworkReply* m_reply;
+	bool m_firstUpdate;
+	State m_state;
+	int64 m_bytesRead, m_bytesTotal;
 };
 
 #endif // LDFORGE_DOWNLOAD_H
\ No newline at end of file
--- a/src/ui/downloadfrom.ui	Fri Aug 02 18:42:06 2013 +0300
+++ b/src/ui/downloadfrom.ui	Fri Aug 02 22:02:40 2013 +0300
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>406</width>
-    <height>319</height>
+    <width>546</width>
+    <height>405</height>
    </rect>
   </property>
   <property name="windowTitle">

mercurial