NCL Composer  0.1.5
 All Classes Functions Variables Pages
WelcomeWidget.cpp
1 /* Copyright (c) 2011 Telemidia/PUC-Rio.
2  * All rights reserved. This program and the accompanying materials
3  * are made available under the terms of the Eclipse Public License v1.0
4  * which accompanies this distribution, and is available at
5  * http://www.eclipse.org/legal/epl-v10.html
6  *
7  * Contributors:
8  * Telemidia/PUC-Rio - initial API and implementation
9  */
10 #include <WelcomeWidget.h>
11 #include <ui_WelcomeWidget.h>
12 #include <core/modules/ProjectControl.h>
13 #include <QtGlobal>
14 
15 namespace composer {
16 namespace gui {
17 
18 WelcomeWidget::WelcomeWidget(QWidget *parent): QWidget(parent),
19  ui(new Ui::WelcomeWidget)
20 {
21  ui->setupUi(this);
22  ui->tabWidget->installEventFilter(new ResizeFilter(ui->tabWidget));
23 
24  connect(ui->pushButton_OpenProject, SIGNAL(pressed()),
25  this, SIGNAL(userPressedOpenProject()));
26 
27  connect(ui->pushButton_NewProject, SIGNAL(pressed()),
28  this, SIGNAL(userPressedNewProject()));
29 
30  ui->pushButton_DownloadApp->setEnabled(false);
31 
32  connect(&httpNotifyMessages, SIGNAL(readyRead(const QHttpResponseHeader &)),
33  this, SLOT(notifyMessagesReadData(const QHttpResponseHeader &)));
34 
35 #ifdef WITH_CLUBENCL
36  //Connect the QHttp with
37  connect(&http, SIGNAL(readyRead(const QHttpResponseHeader &)),
38  this, SLOT(readData(const QHttpResponseHeader &)));
39 
40  connect(&http, SIGNAL(requestFinished(int,bool)),
41  this, SLOT(finishRSSLoad(int, bool)));
42 
43  connect(ui->pushButton_DownloadApp, SIGNAL(pressed()),
44  this, SLOT(downloadApplication()));
45 
46  connect(ui->listWidget_NCLClub, SIGNAL(currentRowChanged(int)),
47  this, SLOT(changeCurrentItem(int)));
48 
49  progressDialog = new QProgressDialog(this);
50  connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelDownload()));
51 
52  isDownloading = false;
53 
54  loadRSS();
55 #else
56  ui->tabWidget->removeTab(2);
57 #endif
58 
59 #ifdef WITH_TEST_VERSION_MESSAGE
60 #define LABEL_BUILD "This is an ALPHA version. Version: " \
61  NCLCOMPOSER_GUI_VERSION " Build Date and time:" BUILD_DATE
62 
63  ui->label_BuildMessage->setText(LABEL_BUILD);
64  ui->label_BuildMessage->setStyleSheet("color:white; font-size:13px; "
65  "text-align: right;");
66 #endif
67 
68  //TODO: By now, we have disable GUI to install new plugins
69  ui->tabWidget->removeTab(1);
70 
71  //TODO: Enable NCL Composer Tips
72  ui->frame_Tips->setVisible(false);
73 
74  //This will be visible only if there is messages to read
75  ui->labelNotifyMessage->setVisible(false);
76  updateNotifyMessages();
77 }
78 
80 {
81  delete ui;
82 }
83 
84 void WelcomeWidget::updateRecentProjects(QStringList recentProjects)
85 {
86  foreach (QCommandLinkButton *button,
87  ui->frame_RecentProjects->findChildren<QCommandLinkButton*>())
88  {
89  button->hide();
90  button->deleteLater();
91  }
92 
93  for(int i = 0; i < recentProjects.size() && i < MAX_RECENT_PROJECTS; i++)
94  {
95  QString file = recentProjects.at(i);
96  QCommandLinkButton *button = new QCommandLinkButton(
97  file.mid(file.lastIndexOf("/")+1), file, ui->frame_RecentProjects);
98  button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
99  button->setToolTip(file);
100  connect(button, SIGNAL(pressed()), this, SLOT(sendRecentProjectClicked()));
101 
102  ui->frame_RecentProjects->layout()->addWidget(button);
103  }
104 }
105 
106 void WelcomeWidget::updateNotifyMessages()
107 {
108  QUrl url = QUrl::fromUserInput(NCL_COMPOSER_NOTIFY_URL);
109  httpNotifyMessages.setHost(url.host());
110  connectionId = httpNotifyMessages.get(url.path());
111 }
112 
113 void WelcomeWidget::notifyMessagesReadData(const QHttpResponseHeader &resp)
114 {
115  if (resp.statusCode() != 200)
116  {
117  httpNotifyMessages.abort();
118  }
119  else
120  {
121  int min_message_id_to_show = DEFAULT_MIN_MESSAGE_ID_TO_SHOW;
122  int max_notify_messages = DEFAULT_MAX_NOTIFY_MESSAGES;
123 
124  // Get settings values
125  GlobalSettings settings;
126  settings.beginGroup("notify_system");
127  if(settings.contains("min_message_id_to_show"))
128  min_message_id_to_show =
129  qMax( settings.value("min_message_id_to_show").toInt(),
130  min_message_id_to_show);
131  else
132  settings.setValue("min_message_id_to_show", min_message_id_to_show);
133 
134  if(settings.contains("max_notify_messages"))
135  max_notify_messages = settings.value("max_notify_messages").toInt();
136  else
137  settings.setValue("max_notify_messages", max_notify_messages);
138 
139  QByteArray bytes = httpNotifyMessages.readAll();
140  if (bytes.size())
141  {
142  QStringList messages = QString(bytes).split("\n");
143  QString messageToShow = "";
144 
145  for(int i = 0; i < messages.size(); i++)
146  {
147  if( i > max_notify_messages - 1 ) break;
148  QStringList msgSplittedId = messages[i].split("\t");
149 
150  if(msgSplittedId.size() >= 2)
151  {
152  if( msgSplittedId[0].toInt() >= min_message_id_to_show )
153  messageToShow += msgSplittedId[1];
154  else
155  break;
156  }
157  }
158 
159  if(messageToShow.size())
160  {
161  ui->labelNotifyMessage->setText(messageToShow);
162  ui->labelNotifyMessage->setVisible(true);
163  }
164  }
165  }
166 }
167 
168 void WelcomeWidget::sendRecentProjectClicked()
169 {
170  QCommandLinkButton *button =
171  static_cast<QCommandLinkButton*> (QObject::sender());
172 
173  if(button != NULL)
174  {
175  emit userPressedRecentProject(button->description());
176  }
177 }
178 
179 #ifdef WITH_CLUBENCL
180 void WelcomeWidget::loadRSS()
181 {
182  xmlReader.clear();
183  n_items = 0;
184  isImageEnclosure = true;
185 
186  description.clear();
187  imgSrc.clear();
188  downloadUrl.clear();
189 
190  QUrl url = QUrl::fromUserInput(NCL_CLUB_URL);
191 
192  http.setHost(url.host());
193  connectionId = http.get(url.path());
194 }
195 
196 void WelcomeWidget::readData(const QHttpResponseHeader &resp)
197 {
198  if (resp.statusCode() != 200)
199  {
200  http.abort();
201  }
202  else
203  {
204  QByteArray bytes = http.readAll();
205  xmlReader.addData(bytes);
206  parseXml();
207  }
208 }
209 
210 void WelcomeWidget::parseXml()
211 {
212 // qDebug() << "WelcomeWidget::parseXml()";
213 
214  bool readingItem = false;
215 
216  while (!xmlReader.atEnd())
217  {
218  xmlReader.readNext();
219 
220  if (xmlReader.isStartElement())
221  {
222  if (xmlReader.name() == "item")
223  {
224  readingItem = true;
225 
226  currentLink.clear();
227  currentTitle.clear();
228  currentDate.clear();
229  currentDesc.clear();
230  }
231  else if(xmlReader.name() == "enclosure")
232  {
233  if(isImageEnclosure)
234  {
235  currentImg = xmlReader.attributes().value("url").toString();
236  imgSrc.push_back(currentImg);
237  isImageEnclosure = false;
238  }
239  else
240  {
241  isImageEnclosure = true;
242  currentDownloadUrl = xmlReader.attributes().value("url").toString();
243  downloadUrl.push_back(currentDownloadUrl);
244  }
245  }
246 
247  currentTag = xmlReader.name().toString();
248  }
249  else if (xmlReader.isEndElement())
250  {
251  if (xmlReader.name() == "item")
252  {
253 // qDebug() << "#########" << currentTitle
254 // << currentLink << currentDate << currentDesc << n_items;
255 
256  ui->listWidget_NCLClub->addItem(currentTitle);
257  description.push_back(currentDesc);
258 
259  n_items++;
260  readingItem = false;
261 
262  currentTitle.clear();
263  currentLink.clear();
264  currentDate.clear();
265  currentImg.clear();
266  currentDesc.clear();
267  }
268 
269  }
270  else if (xmlReader.isCharacters() && !xmlReader.isWhitespace())
271  {
272  if (currentTag == "title" && readingItem)
273  currentTitle += xmlReader.text().toString();
274  else if (currentTag == "link")
275  currentLink += xmlReader.text().toString();
276  else if (currentTag == "pubDate")
277  currentDate += xmlReader.text().toString();
278  else if(currentTag == "description")
279  currentDesc += xmlReader.text().toString();
280  }
281  }
282 
283  if (xmlReader.error() &&
284  xmlReader.error() != QXmlStreamReader::PrematureEndOfDocumentError)
285  {
286  qWarning() << "XML ERROR:"
287  << xmlReader.lineNumber() << ": " << xmlReader.errorString();
288 
289  http.abort();
290  }
291 }
292 
293 void WelcomeWidget::changeCurrentItem(int item)
294 {
295  currentNCLClubItem = item;
296 
297  if(!isDownloading)
298  ui->pushButton_DownloadApp->setEnabled(true);
299 
300  QString html = "<html><body><img src=\"";
301  html += imgSrc[item];
302  html += "\"/>\n";
303  html += description.at(item);
304  html += "</body></html>";
305  ui->webView->setHtml(html);
306 }
307 
308 void WelcomeWidget::finishRSSLoad(int connectionId, bool error)
309 {
310  qDebug() << "finishRSSLoad(" << connectionId << "," << error << ");";
311  if(error)
312  {
313  if(this->connectionId == connectionId)
314  {
315  QCommandLinkButton *button =
316  new QCommandLinkButton(this);
317  button->setIconSize(QSize(0,0));
318 
319  ui->listWidget_NCLClub->addItem(tr("Connection to NCL Club has failed."));
320  }
321  }
322 }
323 
324 void WelcomeWidget::downloadApplication()
325 {
326  QString urlStr = downloadUrl[currentNCLClubItem];
327  url = QUrl(urlStr);
328 
329  ui->pushButton_DownloadApp->setEnabled(false);
330  ui->pushButton_DownloadApp->setText(tr("Downloading application..."));
331  downloadFile();
332  progressDialog->show();
333 }
334 
335 void WelcomeWidget::downloadFile()
336 {
337  isDownloading = true;
338  QFileInfo fileInfo(url.path());
339  QString fileName = QDir::tempPath() + QDir::separator() + fileInfo.fileName();
340  if (fileName.isEmpty())
341  fileName = "index.html";
342 
343  if (QFile::exists(fileName)) {
344  if (QMessageBox::question(this, tr("Application from NCL Club"),
345  tr("There already exists a file called %1 in "
346  "the current directory. Overwrite?").arg(fileName),
347  QMessageBox::Yes|QMessageBox::No, QMessageBox::No)
348  == QMessageBox::No)
349  return;
350  QFile::remove(fileName);
351  }
352 
353  file = new QFile(fileName);
354  if (!file->open(QIODevice::WriteOnly)) {
355  QMessageBox::information(this, tr("HTTP"),
356  tr("Unable to save the file %1: %2.")
357  .arg(fileName).arg(file->errorString()));
358  delete file;
359  file = 0;
360  return;
361  }
362 
363  progressDialog->setWindowTitle(tr("Application from NCL Club"));
364  progressDialog->setLabelText(tr("Downloading %1.").arg(fileName));
365  // downloadButton->setEnabled(false);
366 
367  // schedule the request
368  httpRequestAborted = false;
369  startRequest(url);
370 }
371 
372 void WelcomeWidget::startRequest(const QUrl &url)
373 {
374  reply = qnam.get(QNetworkRequest(url));
375  connect(reply, SIGNAL(finished()),
376  this, SLOT(httpFinished()));
377  connect(reply, SIGNAL(readyRead()),
378  this, SLOT(httpReadyRead()));
379  connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
380  this, SLOT(updateDataReadProgress(qint64,qint64)));
381 }
382 
383 void WelcomeWidget::updateDataReadProgress(qint64 bytesRead, qint64 totalBytes)
384 {
385  if (httpRequestAborted)
386  return;
387 
388  progressDialog->setMaximum(totalBytes);
389  if(totalBytes > bytesRead)
390  progressDialog->setValue(bytesRead);
391 }
392 
393 void WelcomeWidget::cancelDownload()
394 {
395  // statusLabel->setText(tr("Download canceled."));
396  httpRequestAborted = true;
397  if(reply != NULL)
398  reply->abort();
399 
400  isDownloading = false;
401  ui->pushButton_DownloadApp->setEnabled(true);
402 }
403 
404 void WelcomeWidget::httpFinished()
405 {
406  if (httpRequestAborted) {
407  if (file) {
408  file->close();
409  file->remove();
410  delete file;
411  file = 0;
412  }
413  reply->deleteLater();
414  progressDialog->hide();
415  return;
416  }
417  file->flush();
418  file->close();
419 
420  isDownloading = false;
421  ui->pushButton_DownloadApp->setEnabled(true);
422  ui->pushButton_DownloadApp->setText(tr("Download and Import this application"));
423 
424  QFileInfo fileInfo(*file);
425 
426  QString filename = QFileDialog::getSaveFileName(
427  this,
428  tr("Choose the name of the new project to be created"),
429  QDir::currentPath(),
430  tr("NCL Composer Projects (*.cpr)") );
431 
432  if( !filename.isNull())
433  {
434  if(!filename.endsWith(".cpr"))
435  filename = filename + QString(".cpr");
436  }
437  else
438  {
439  qDebug() << "Filename is empty. A project will not be created!" << endl;
440  return;
441  }
442 
443  QFileInfo fileInfo2(filename);
444  projectName = filename;
445 
446  extract(fileInfo.absoluteFilePath(), fileInfo2.absoluteDir().absolutePath());
447 // file->remove(); //delete the file after unzipping it
448 // progressDialog->hide();
449  reply->deleteLater();
450  reply = 0;
451  delete file;
452  file = 0;
453 }
454 
455 void WelcomeWidget::httpReadyRead()
456 {
457  // this slot gets called every time the QNetworkReply has new data.
458  // We read all of its new data and write it into the file.
459  // That way we use less RAM than when reading it at the finished()
460  // signal of the QNetworkReply
461  if (file)
462  file->write(reply->readAll());
463 }
464 
465 bool WelcomeWidget::doExtractCurrentFile( QString extDirPath,
466  QString singleFileName,
467  bool stop)
468 {
469  if(stop) // this is the last call!
470  {
471  zip.close();
472  if (zip.getZipError() != UNZ_OK)
473  {
474  qWarning("testRead(): zip.close(): %d", zip.getZipError());
475  return false;
476  }
477 
478  qDebug() << fileNameToImport << projectName;
479  ProjectControl::getInstance()->importFromDocument( fileNameToImport,
480  projectName);
481  progressDialog->hide();
482 
483  return true;
484  }
485 
486  QuaZipFileInfo info;
487  QFile out;
488  QString name;
489  char c;
490 
491  zip.setCurrentFile(zipFile.getActualFileName());
492  if (!zip.getCurrentFileInfo(&info))
493  {
494  qWarning("testRead(): getCurrentFileInfo(): %d\n", zip.getZipError());
495  return false;
496  }
497 
498  if (!singleFileName.isEmpty())
499  if (!info.name.contains(singleFileName))
500  return true;
501 
502  if (!zipFile.open(QIODevice::ReadOnly))
503  {
504  qWarning("testRead(): file.open(): %d", zipFile.getZipError());
505  return false;
506  }
507 
508  name = QString("%1/%2").arg(extDirPath).arg(zipFile.getActualFileName());
509 
510  //progressDialog->setLabelText(tr("Unzipping file: %1").arg(name));
511  //progressDialog->setMaximum(zip.getEntriesCount());
512  //progressDialog->setValue(this->currentFile++);
513 
514  if(name.endsWith(QDir::separator()))
515  {
516  QDir dir(name);
517  dir.mkdir(name);
518  zipFile.close();
519  emit extractNextFile(extDirPath, singleFileName, !zip.goToNextFile());
520  return true;
521  }
522 
523  if (zipFile.getZipError() != UNZ_OK)
524  {
525  qWarning("testRead(): file.getFileName(): %d", zipFile.getZipError());
526  return false;
527  }
528 
529  out.setFileName(name);
530 
531  // this will fail if "name" contains subdirectories, but we don't mind that
532  out.open(QIODevice::WriteOnly);
533 
534  // Slow like hell (on GNU/Linux at least), but it is not my fault.
535  // Not ZIP/UNZIP package's fault either.
536  // The slowest thing here is out.putChar(c).
537  while (zipFile.getChar(&c)) out.putChar(c);
538 
539  out.close();
540 
541  //out.setFileName("out/" + name);
542  if(name.endsWith(".ncl")) //\fixme This is problematic. It can exists more than one .ncl file.
543  {
544  fileNameToImport = QFileInfo(out).absoluteFilePath();
545  }
546 
547  if (zipFile.getZipError() != UNZ_OK)
548  {
549  qWarning("testRead(): file.getFileName(): %d", zipFile.getZipError());
550  return false;
551  }
552 
553  if (!zipFile.atEnd())
554  {
555  qWarning("testRead(): read all but not EOF");
556  return false;
557  }
558 
559  zipFile.close();
560 
561  if (zipFile.getZipError() != UNZ_OK) {
562  qWarning("testRead(): file.close(): %d", zipFile.getZipError());
563  return false;
564  }
565 
566  emit extractNextFile(extDirPath, singleFileName, !zip.goToNextFile());
567 
568  return true;
569 }
570 
571 bool WelcomeWidget::extract( const QString &filePath,
572  const QString &extDirPath,
573  const QString &singleFileName)
574 {
575  zip.setZipName(filePath);
576  zipFile.setZip(&zip);
577 
578  connect(this, SIGNAL(extractNextFile(QString,QString,bool)),
579  this, SLOT(doExtractCurrentFile(QString,QString,bool)),
580  Qt::QueuedConnection);
581 
582  if (!zip.open(QuaZip::mdUnzip))
583  {
584  qWarning() << filePath;
585  qWarning("testRead(): zip.open(): %d", zip.getZipError());
586  return false;
587  }
588 
589  zip.setFileNameCodec("IBM866");
590 
591  qWarning("%d entries\n", zip.getEntriesCount());
592  qWarning("Global comment: %s\n", zip.getComment().toLocal8Bit().constData());
593 
594  this->currentFile = 0;
595 
596  emit extractNextFile(extDirPath, singleFileName, !zip.goToFirstFile());
597 
598  return true;
599 }
600 #endif
601 } }
602 
603 void composer::gui::WelcomeWidget::on_commandLinkButton_29_clicked()
604 {
605  QDesktopServices::openUrl(QUrl("http://www.telemidia.puc-rio.br/sites/telemidia.puc-rio.br/files/Introduction%20to%20DTV%20and%20to%20Ginga-NCL.pdf"));
606 }
607 
608 void composer::gui::WelcomeWidget::on_commandLinkButton_6_clicked()
609 {
610  QDesktopServices::openUrl(QUrl("http://www.telemidia.puc-rio.br/sites/telemidia.puc-rio.br/files/Curso%20Ginga%20Brasil.zip"));
611 }
612 
613 // void composer::gui::WelcomeWidget::on_commandLinkButton_9_clicked()
614 // {
615 // QDesktopServices::openUrl(QUrl("http://www.telemidia.puc-rio.br/sites/telemidia.puc-rio.br/files/MCAplDeclarativa.pdf"));
616 // }
617 
618 // void composer::gui::WelcomeWidget::on_commandLinkButton_30_clicked()
619 // {
620 // QDesktopServices::openUrl(QUrl("http://www.ncl.org.br/en/tutorials"));
621 // }
622 
623 void composer::gui::WelcomeWidget::on_commandLinkButton_10_clicked()
624 {
625  QDesktopServices::openUrl(QUrl("http://www.telemidia.puc-rio.br/sites/telemidia.puc-rio.br/files/Part%209%20-%20NCL3.0-EC.pdf"));
626 }
627 
628 void composer::gui::WelcomeWidget::on_commandLinkButton_11_clicked()
629 {
630  QDesktopServices::openUrl(QUrl("http://www.telemidia.puc-rio.br/sites/telemidia.puc-rio.br/files/Part%209%20-%20NCL3.0-EC.pdf"));
631 }
632 
633 void composer::gui::WelcomeWidget::on_commandLinkButton_31_clicked()
634 {
635  QDesktopServices::openUrl(QUrl("http://www.ncl.org.br/en/relatoriostecnicos"));
636 }
637 
638 void composer::gui::WelcomeWidget::on_commandLinkButton_7_clicked()
639 {
640  QDesktopServices::openUrl(QUrl("http://composer.telemidia.puc-rio.br"));
641 }
642 
643 void composer::gui::WelcomeWidget::on_commandLinkButton_8_clicked()
644 {
645  QDesktopServices::openUrl(QUrl("http://composer.telemidia.puc-rio.br/doku.php/how_to_create_a_plugin_to_ncl_composer"));
646 }
647 
648 void composer::gui::WelcomeWidget::on_commandLinkButton_pressed()
649 {
650  QDesktopServices::openUrl(QUrl("http://composer.telemidia.puc-rio.br/doku.php/plugins:index"));
651 }
652 
653 void composer::gui::WelcomeWidget::on_commandLinkButton_2_pressed()
654 {
655  emit userPressedSeeInstalledPlugins();
656 }
657 
658 void composer::gui::WelcomeWidget::on_commandLinkButton_3_pressed()
659 {
660  QDesktopServices::openUrl(QUrl("http://www.telemidia.puc-rio.br/sites/telemidia.puc-rio.br/files/Programando_em_NCL_30.pdf"));
661 }