BuildmLearn Toolkit  2.0.4
BuildmLearn Toolkit is an easy-to-use program that helps users make mobile apps without any knowledge of application development.
 All Classes Functions Enumerations Groups Pages
formuploadbundle.cpp
1 /*
2  Copyright (c) 2012, BuildmLearn Contributors listed at http://buildmlearn.org/people/
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7 
8  * Redistributions of source code must retain the above copyright notice, this
9  list of conditions and the following disclaimer.
10 
11  * Redistributions in binary form must reproduce the above copyright notice,
12  this list of conditions and the following disclaimer in the documentation
13  and/or other materials provided with the distribution.
14 
15  * Neither the name of the BuildmLearn nor the names of its
16  contributors may be used to endorse or promote products derived from
17  this software without specific prior written permission.
18 
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 
31 #include "gui/formuploadbundle.h"
32 
33 #include "gui/lineeditwithstatus.h"
34 #include "miscellaneous/application.h"
35 #include "miscellaneous/iconfactory.h"
36 #include "network-web/downloader.h"
37 #include "network-web/networkfactory.h"
38 #include "core/templatefactory.h"
39 #include "core/templatecore.h"
40 #include "core/templateeditor.h"
41 #include "definitions/definitions.h"
42 
43 #include <QPushButton>
44 #include "QFileDialog"
45 
46 
47 FormUploadBundle::FormUploadBundle(QWidget *parent)
48  : QDialog(parent), m_ui(new Ui::FormUploadBundle), m_uploader(NULL), m_uploadStatus(StoreFactory::OtherError) {
49  m_ui->setupUi(this);
50 
51  setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog | Qt::WindowSystemMenuHint | Qt::WindowTitleHint);
52  setWindowIcon(IconFactory::instance()->fromTheme("project-upload"));
53 
54  // Obtain buttons.
55  m_btnClose = m_ui->m_buttonBox->button(QDialogButtonBox::Close);
56  m_btnUpload = m_ui->m_buttonBox->addButton(tr("&Upload application"),
57  QDialogButtonBox::ActionRole);
58 
59  m_ui->m_txtApplicationName->lineEdit()->setPlaceholderText(tr("Name of your application"));
60  m_ui->m_txtAuthorEmail->lineEdit()->setPlaceholderText(tr("Your e-mail"));
61  m_ui->m_txtAuthorName->lineEdit()->setPlaceholderText(tr("Your name"));
62 
63  // Add categories.
64  m_ui->m_cmbCategory->addItem(tr("Science"), "Science");
65  m_ui->m_cmbCategory->addItem(tr("Math"), "Math");
66  m_ui->m_cmbCategory->addItem(tr("Physics"), "Physics");
67  m_ui->m_cmbCategory->addItem(tr("Literature"), "Literature");
68  m_ui->m_cmbCategory->addItem(tr("English"), "English");
69  m_ui->m_cmbCategory->addItem(tr("Geography"), "Geography");
70  m_ui->m_cmbCategory->addItem(tr("Social Studies"), "Social Studies");
71  m_ui->m_cmbCategory->addItem(tr("Language"), "Language");
72  m_ui->m_cmbCategory->addItem(tr("History"), "History");
73  m_ui->m_cmbCategory->addItem(tr("Chemistry"), "Chemistry");
74 
75  connect(m_ui->m_txtApplicationName->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(checkApplicationName(QString)));
76  connect(m_ui->m_txtAuthorEmail->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(checkAuthorEmail(QString)));
77  connect(m_ui->m_txtAuthorName->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(checkAuthorName(QString)));
78  connect(this, SIGNAL(metadataChanged()), this, SLOT(checkMetadata()));
79  connect(m_btnUpload, SIGNAL(clicked()), this, SLOT(startUpload()));
80  connect(m_ui->m_btnSelectIcon, SIGNAL(clicked()), this, SLOT(selectApplicationIcon()));
81 
82  setTabOrder(m_ui->m_txtApplicationName->lineEdit(), m_ui->m_txtApplicationDescription);
83  setTabOrder(m_ui->m_txtApplicationDescription, m_ui->m_txtAuthorName->lineEdit());
84  setTabOrder(m_ui->m_txtAuthorName->lineEdit(), m_ui->m_txtAuthorEmail->lineEdit());
85  setTabOrder(m_ui->m_txtAuthorEmail->lineEdit(), m_ui->m_cmbCategory);
86  /*setTabOrder(m_ui->m_cmbCategory, m_btnUpload);
87  setTabOrder(m_btnUpload, m_ui->m_buttonBox->);
88  */
89  checkApplicationName(QString());
90  checkAuthorName(QString());
91  checkAuthorEmail(QString());
92  checkApplicationIcon(QString());
93 }
94 
95 FormUploadBundle::~FormUploadBundle() {
96  delete m_ui;
97 }
98 
99 void FormUploadBundle::checkAuthorName(const QString &author_name) {
100  bool input_ok = !author_name.simplified().isEmpty();
101  m_ui->m_txtAuthorName->setStatus(input_ok ?
102  WidgetWithStatus::Ok :
103  WidgetWithStatus::Error,
104  input_ok ?
105  tr("Your name is okay.") :
106  tr("Enter valid name."));
107 
108  emit metadataChanged();
109 }
110 
111 void FormUploadBundle::checkAuthorEmail(const QString &author_email) {
112  bool input_ok = QRegExp("^\\S+@\\S+\\.\\S{2,3}$").exactMatch(author_email);
113  m_ui->m_txtAuthorEmail->setStatus(input_ok ?
114  WidgetWithStatus::Ok :
115  WidgetWithStatus::Error,
116  input_ok ?
117  tr("Your e-mail is okay.") :
118  tr("Enter valid e-mail in the form \"john@doe.com\"."));
119 
120  emit metadataChanged();
121 }
122 
123 void FormUploadBundle::checkApplicationName(const QString &application_name) {
124  bool input_ok = !application_name.simplified().isEmpty();
125  m_ui->m_txtApplicationName->setStatus(input_ok ?
126  WidgetWithStatus::Ok :
127  WidgetWithStatus::Error,
128  input_ok ?
129  tr("Your application name is okay.") :
130  tr("Enter valid application name."));
131 
132  emit metadataChanged();
133 }
134 
135 void FormUploadBundle::checkMetadata() {
136  m_btnUpload->setEnabled(m_ui->m_txtApplicationName->status() == WidgetWithStatus::Ok &&
137  m_ui->m_txtAuthorEmail->status() == WidgetWithStatus::Ok &&
138  m_ui->m_txtAuthorName->status() == WidgetWithStatus::Ok &&
139  m_ui->m_lblIcon->status() == WidgetWithStatus::Ok);
140 
141  if (m_btnUpload->isEnabled()) {
142  m_ui->m_lblProgress->setStatus(WidgetWithStatus::Ok,
143  tr("Ready to upload."),
144  tr("Ready to upload."));
145  }
146  else {
147  m_ui->m_lblProgress->setStatus(WidgetWithStatus::Error,
148  tr("Fill-in missing metadata."),
149  tr("In order to continue, fill-in missing metadata."));
150  }
151 }
152 
153 void FormUploadBundle::selectApplicationIcon() {
154  QString selected_picture = QFileDialog::getOpenFileName(this, tr("Select icon for application"),
155  m_ui->m_lblIcon->label()->toolTip().isEmpty() ?
156  APP_APK_ICON_PATH :
157  m_ui->m_lblIcon->label()->toolTip(),
158  tr("Icons (*.jpg *.png)"));
159 
160  checkApplicationIcon(selected_picture);
161 }
162 
163 void FormUploadBundle::checkApplicationIcon(const QString &icon_path) {
164  if (!icon_path.isEmpty()) {
165  m_ui->m_lblIcon->setStatus(WidgetWithStatus::Ok,
166  tr("Correct icon is selected."),
167  QDir::toNativeSeparators(icon_path));
168  }
169  else {
170  m_ui->m_lblIcon->setStatus(WidgetWithStatus::Error,
171  tr("No valid icon is selected."),
172  QDir::toNativeSeparators(icon_path));
173  }
174 
175  emit metadataChanged();
176 }
177 
178 void FormUploadBundle::startUpload() {
179  // Prepare parameters and data.
180  QString xml_bundle_data = qApp->templateManager()->activeCore()->editor()->generateBundleData();
181 
182  if (xml_bundle_data.isEmpty()) {
183  m_ui->m_lblProgress->setStatus(WidgetWithStatus::Error,
184  tr("Cannot upload application."),
185  tr("Application cannot be uploaded because template return error.\nContact application developers to fix this issue."));
186  return;
187  }
188 
189  if (m_uploader == NULL) {
190  m_uploader = new Downloader(this);
191 
192  connect(m_uploader, SIGNAL(progress(qint64,qint64)), this, SLOT(uploadProgress(qint64,qint64)));
193  connect(m_uploader, SIGNAL(completed(QNetworkReply::NetworkError,QByteArray)), this,
194  SLOT(uploadCompleted(QNetworkReply::NetworkError,QByteArray)));
195  }
196 
197  // Finally, start file upload.
198  m_btnClose->setEnabled(false);
199  m_btnUpload->setEnabled(false);
200 
201  // Obtain real endpoint.
202 
203  QByteArray endpoint;
204  QNetworkReply::NetworkError endpoint_status = NetworkFactory::downloadFile(STORE_ENDPOINT, 5000,
205  endpoint);
206 
207  if (endpoint_status != QNetworkReply::NoError) {
208  // Endpoint was not obtained.
209  m_btnClose->setEnabled(true);
210  m_btnUpload->setEnabled(true);
211  m_ui->m_lblProgress->setStatus(WidgetWithStatus::Error,
212  tr("Endpoint was not obtained."),
213  tr("Endpoint was not obtained."));
214 
215  return;
216  }
217 
218  m_uploader->uploadBundleFile(QString(endpoint), xml_bundle_data, STORE_API_KEY,
219  m_ui->m_txtAuthorName->lineEdit()->text(),
220  m_ui->m_txtAuthorEmail->lineEdit()->text(),
221  m_ui->m_txtApplicationName->lineEdit()->text(),
222  m_ui->m_lblIcon->label()->toolTip());
223  m_ui->m_lblProgress->setStatus(WidgetWithStatus::Information,
224  tr("Uploading application..."),
225  tr("Uploading application..."));
226 }
227 
228 void FormUploadBundle::uploadProgress(qint64 bytes_sent, qint64 bytes_total) {
229  m_ui->m_progressUpload->setValue(bytes_sent * 100.0 / bytes_total);
230  qApp->processEvents();
231 }
232 
233 void FormUploadBundle::uploadCompleted(QNetworkReply::NetworkError error, QByteArray output) {
234  qDebug(qPrintable(QString(output)));
235 
236  m_uploadStatus = StoreFactory::parseResponseXml(error, output);
237  QString string_status = StoreFactory::uploadStatusToString(m_uploadStatus);
238 
239  if (m_uploadStatus == StoreFactory::Success) {
240  close();
241  }
242  else {
243  m_ui->m_lblProgress->setStatus(WidgetWithStatus::Error,
244  string_status,
245  string_status);
246  }
247 
248  m_btnClose->setEnabled(true);
249  m_btnUpload->setEnabled(true);
250 }
251 
252 StoreFactory::UploadStatus FormUploadBundle::uploadStatus() const {
253  return m_uploadStatus;
254 }
Simple file downloader with progress reporting.
Definition: downloader.h:47
UploadStatus
Possible states of application upload process.
Definition: storefactory.h:45
Form for uploading applications to BuildmLearn Store.
Main BuildmLearn Store functionality.
Definition: storefactory.h:40
static QNetworkReply::NetworkError downloadFile(const QString &url, int timeout, QByteArray &output, bool protected_contents=false, const QString &username=QString(), const QString &password=QString())
Performs SYNCHRONOUS download of file with given URL and given timeout.
static UploadStatus parseResponseXml(QNetworkReply::NetworkError error_status, const QByteArray &response)
Parses received XML from BuildmLearn Store server.
void uploadBundleFile(QString url, const QString &bundle_data, const QString &key, const QString &author_name, const QString &author_email, const QString &application_name, const QString &application_icon)
Uploads given bundle_data to store server via HTTP POST.
Definition: downloader.cpp:73
static QString uploadStatusToString(UploadStatus status)
Converts UploadStatus enumeration to textual representation.
static IconFactory * instance()
Singleton getter.
Definition: iconfactory.cpp:48