diff --git a/src/plugins/coreplugin/coreplugin.pro b/src/plugins/coreplugin/coreplugin.pro index cf8eead807c..d5c54c3908d 100644 --- a/src/plugins/coreplugin/coreplugin.pro +++ b/src/plugins/coreplugin/coreplugin.pro @@ -107,7 +107,8 @@ SOURCES += mainwindow.cpp \ ssh/sftpchannel.cpp \ outputpanemanager.cpp \ navigationsubwidget.cpp \ - sidebarwidget.cpp + sidebarwidget.cpp \ + rssfetcher.cpp HEADERS += mainwindow.h \ editmode.h \ @@ -218,7 +219,8 @@ HEADERS += mainwindow.h \ ssh/sftpchannel_p.h \ outputpanemanager.h \ navigationsubwidget.h \ - sidebarwidget.h + sidebarwidget.h \ + rssfetcher.h FORMS += dialogs/newdialog.ui \ actionmanager/commandmappings.ui \ diff --git a/src/plugins/welcome/rssfetcher.cpp b/src/plugins/coreplugin/rssfetcher.cpp similarity index 77% rename from src/plugins/welcome/rssfetcher.cpp rename to src/plugins/coreplugin/rssfetcher.cpp index e37a9cf2fda..ed657ba991a 100644 --- a/src/plugins/welcome/rssfetcher.cpp +++ b/src/plugins/coreplugin/rssfetcher.cpp @@ -28,7 +28,7 @@ **************************************************************************/ #include "rssfetcher.h" -#include +#include "coreconstants.h" #include #include @@ -47,7 +47,7 @@ #include #endif -using namespace Welcome::Internal; +using namespace Core::Internal; static const QString getOsString() { @@ -114,23 +114,25 @@ static const QString getOsString() return osString; } -RSSFetcher::RSSFetcher(int maxItems) - : QThread(0), m_maxItems(maxItems), m_items(0), m_networkAccessManager(0) +RssFetcher::RssFetcher(int maxItems) + : QThread(0), m_maxItems(maxItems), m_items(0), + m_requestCount(0), m_networkAccessManager(0) { + qRegisterMetaType("RssItem"); moveToThread(this); } -RSSFetcher::~RSSFetcher() +RssFetcher::~RssFetcher() { } -void RSSFetcher::run() +void RssFetcher::run() { exec(); delete m_networkAccessManager; } -void RSSFetcher::fetch(const QUrl &url) +void RssFetcher::fetch(const QUrl &url) { QString agentStr = QString::fromLatin1("Qt-Creator/%1 (QHttp %2; %3; %4; %5 bit)") .arg(Core::Constants::IDE_VERSION_LONG).arg(qVersion()) @@ -143,71 +145,83 @@ void RSSFetcher::fetch(const QUrl &url) connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), SLOT(fetchingFinished(QNetworkReply*))); } + m_requestCount++; m_networkAccessManager->get(req); } -void RSSFetcher::fetchingFinished(QNetworkReply *reply) +void RssFetcher::fetchingFinished(QNetworkReply *reply) { const bool error = (reply->error() != QNetworkReply::NoError); if (!error) { parseXml(reply); m_items = 0; } - emit finished(error); + if (--m_requestCount == 0) + emit finished(error); reply->deleteLater(); } -RSSFetcher::TagElement RSSFetcher::tagElement(const QStringRef &r) +RssFetcher::TagElement RssFetcher::tagElement(const QStringRef &r, TagElement prev) { if (r == QLatin1String("item")) return itemElement; if (r == QLatin1String("title")) return titleElement; + if (r == QLatin1String("category")) + return categoryElement; if (r == QLatin1String("description")) return descriptionElement; - if (r == QLatin1String("link")) - return linkElement; + if (r == QLatin1String("image")) + return imageElement; + if (r == QLatin1String("link")) { + if (prev == imageElement) + return imageLinkElement; + else + return linkElement; + } return otherElement; } -void RSSFetcher::parseXml(QIODevice *device) +void RssFetcher::parseXml(QIODevice *device) { QXmlStreamReader xmlReader(device); TagElement currentTag = otherElement; - QString linkString; - QString descriptionString; - QString titleString; - + RssItem item; while (!xmlReader.atEnd()) { switch (xmlReader.readNext()) { case QXmlStreamReader::StartElement: - currentTag = tagElement(xmlReader.name()); + currentTag = tagElement(xmlReader.name(), currentTag); if (currentTag == itemElement) { - titleString.clear(); - descriptionString.clear(); - linkString.clear(); + item = RssItem(); } break; case QXmlStreamReader::EndElement: if (xmlReader.name() == QLatin1String("item")) { m_items++; - if (m_items > m_maxItems) + if ((uint)m_items > (uint)m_maxItems) return; - emit newsItemReady(titleString, descriptionString, linkString); + emit newsItemReady(item.title, item.description, item.url); + emit rssItemReady(item); } break; case QXmlStreamReader::Characters: if (!xmlReader.isWhitespace()) { switch (currentTag) { case titleElement: - titleString += xmlReader.text().toString(); + item.title += xmlReader.text().toString(); break; case descriptionElement: - descriptionString += xmlReader.text().toString(); + item.description += xmlReader.text().toString(); + break; + case categoryElement: + item.category += xmlReader.text().toString(); break; case linkElement: - linkString += xmlReader.text().toString(); + item.url += xmlReader.text().toString(); + break; + case imageLinkElement: + item.imagePath += xmlReader.text().toString(); break; default: break; @@ -222,6 +236,6 @@ void RSSFetcher::parseXml(QIODevice *device) qWarning("Welcome::Internal::RSSFetcher: XML ERROR: %d: %s (%s)", int(xmlReader.lineNumber()), qPrintable(xmlReader.errorString()), - qPrintable(titleString)); + qPrintable(item.title)); } } diff --git a/src/plugins/welcome/rssfetcher.h b/src/plugins/coreplugin/rssfetcher.h similarity index 76% rename from src/plugins/welcome/rssfetcher.h rename to src/plugins/coreplugin/rssfetcher.h index 09c9db848e8..87d0936c990 100644 --- a/src/plugins/welcome/rssfetcher.h +++ b/src/plugins/coreplugin/rssfetcher.h @@ -30,28 +30,41 @@ #ifndef RSSFETCHER_H #define RSSFETCHER_H +#include "core_global.h" + #include +#include QT_BEGIN_NAMESPACE class QNetworkReply; class QNetworkAccessManager; -class QUrl; class QIODevice; QT_END_NAMESPACE -namespace Welcome { +namespace Core { namespace Internal { -class RSSFetcher : public QThread +class CORE_EXPORT RssItem +{ +public: + QString title; + QString description; + QString category; + QString url; + QString imagePath; +}; + +class CORE_EXPORT RssFetcher : public QThread { Q_OBJECT public: - explicit RSSFetcher(int maxItems); + explicit RssFetcher(int maxItems = -1); virtual void run(); - virtual ~RSSFetcher(); + virtual ~RssFetcher(); signals: void newsItemReady(const QString& title, const QString& desciption, const QString& url); + void rssItemReady(const RssItem& item); void finished(bool error); public slots: @@ -59,17 +72,19 @@ public slots: void fetch(const QUrl &url); private: - enum TagElement { itemElement, titleElement, descriptionElement, linkElement, otherElement }; - static TagElement tagElement(const QStringRef &); + enum TagElement { itemElement, titleElement, descriptionElement, linkElement, + imageElement, imageLinkElement, categoryElement, otherElement }; + static TagElement tagElement(const QStringRef &, TagElement prev); void parseXml(QIODevice *); const int m_maxItems; int m_items; + int m_requestCount; QNetworkAccessManager* m_networkAccessManager; }; -} // namespace Welcome +} // namespace Core } // namespace Internal #endif // RSSFETCHER_H diff --git a/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.cpp b/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.cpp index 7742aa51061..637d7cce686 100644 --- a/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.cpp +++ b/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,9 @@ #include #include #include +#include + +using namespace Core::Internal; namespace Qt4ProjectManager { namespace Internal { @@ -61,13 +65,21 @@ namespace Internal { const char ExamplePathPropertyName[] = "__qt_ExamplePath"; const char HelpPathPropertyName[] = "__qt_HelpPath"; +void PixmapDownloader::populatePixmap(QNetworkReply *reply) { + QImage image; + image.loadFromData(reply->readAll()); + m_label->setScaledContents(false); + m_label->setPixmap(QPixmap::fromImage(image)); + deleteLater(); +} + GettingStartedWelcomePageWidget::GettingStartedWelcomePageWidget(QWidget *parent) : - QWidget(parent), - ui(new Ui::GettingStartedWelcomePageWidget) + QWidget(parent), ui(new Ui::GettingStartedWelcomePageWidget), m_rssFetcher(0) { ui->setupUi(this); ui->didYouKnowTextBrowser->viewport()->setAutoFillBackground(false); + ui->detailsLabel->hide(); connect(ui->tutorialTreeWidget, SIGNAL(activated(QString)), SLOT(slotOpenHelpPage(const QString&))); @@ -102,11 +114,27 @@ GettingStartedWelcomePageWidget::GettingStartedWelcomePageWidget(QWidget *parent QIcon::fromTheme(QLatin1String("document-new"), ui->createNewProjectButton->icon())); ui->openProjectButton->setIcon( QIcon::fromTheme(QLatin1String("document-open"), ui->openProjectButton->icon())); + + m_rssFetcher = new RssFetcher; + connect (m_rssFetcher, SIGNAL(rssItemReady(const RssItem&)), SLOT(addToFeatures(const RssItem&))); + connect (m_rssFetcher, SIGNAL(finished(bool)), SLOT(showFeature()), Qt::QueuedConnection); + connect(this, SIGNAL(startRssFetching(QUrl)), m_rssFetcher, SLOT(fetch(QUrl)), Qt::QueuedConnection); + m_rssFetcher->start(QThread::LowestPriority); + const QString featureRssFile = Core::ICore::instance()->resourcePath()+QLatin1String("/rss/featured.rss"); + emit startRssFetching(QUrl::fromLocalFile(featureRssFile)); + + connect(ui->nextFeatureBtn, SIGNAL(clicked()), this, SLOT(slotNextFeature())); + connect(ui->prevFeatureBtn, SIGNAL(clicked()), this, SLOT(slotPrevFeature())); + + QTimer::singleShot(0, this, SLOT(slotSetPrivateQmlExamples())); } GettingStartedWelcomePageWidget::~GettingStartedWelcomePageWidget() { + m_rssFetcher->exit(); + m_rssFetcher->wait(); + delete m_rssFetcher; delete ui; } @@ -422,6 +450,56 @@ QStringList GettingStartedWelcomePageWidget::tipsOfTheDay() return tips; } +void GettingStartedWelcomePageWidget::addToFeatures(const RssItem &feature) +{ + m_featuredItems.append(feature); +} + +void GettingStartedWelcomePageWidget::showFeature(int feature) +{ + if (feature == -1) { + srand(QDateTime::currentDateTime().toTime_t()); + m_currentTip = rand()%m_featuredItems.count(); + } + + RssItem item = m_featuredItems.at(m_currentFeature); + ui->featuredTextLabel->setTextFormat(Qt::RichText); + QString text = QString::fromLatin1("%1
%2

%3").arg(item.category).arg(item.title).arg(item.description); + ui->featuredTextLabel->setText(text); + QString imagePath = item.imagePath; + if (!imagePath.startsWith("http")) { + imagePath = Core::ICore::instance()->resourcePath() + "/rss/" + item.imagePath; + ui->featuredImage->setPixmap(QPixmap(imagePath)); + } else { + new PixmapDownloader(QUrl(imagePath), ui->featuredImage); + } + + if (item.category == QLatin1String("Event")) { + ui->detailsLabel->setText(QString::fromLatin1("Details...").arg(item.url)); + ui->detailsLabel->show(); + ui->detailsLabel->setOpenExternalLinks(true); + } + else if (item.category == QLatin1String("Tutorial")) { + ui->detailsLabel->setText(QString::fromLatin1("Take Tutorial").arg(item.url+"?view=split")); + ui->detailsLabel->show(); + ui->detailsLabel->setOpenExternalLinks(true); + } + ui->featuredImage->setScaledContents(true); +} + +void GettingStartedWelcomePageWidget::slotNextFeature() +{ + m_currentFeature = ((m_currentFeature+1)%m_featuredItems.count()); + showFeature(m_currentFeature); +} + +void GettingStartedWelcomePageWidget::slotPrevFeature() +{ + m_currentFeature = ((m_currentFeature-1)+m_featuredItems.count())%m_featuredItems.count(); + showFeature(m_currentFeature); +} + + } // namespace Internal } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.h b/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.h index e0903d3eed6..8a575e79507 100644 --- a/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.h +++ b/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.h @@ -31,6 +31,22 @@ #define GETTINGSTARTEDWELCOMEPAGEWIDGET_H #include +#include +#include + +QT_BEGIN_NAMESPACE +class QUrl; +class QLabel; +QT_END_NAMESPACE + +namespace Core { + namespace Internal { + class RssFetcher; + class RssItem; + } +} + +using namespace Core::Internal; namespace Qt4ProjectManager { namespace Internal { @@ -39,6 +55,24 @@ namespace Ui { class GettingStartedWelcomePageWidget; } +class PixmapDownloader : public QNetworkAccessManager { + Q_OBJECT +public: + PixmapDownloader(const QUrl& url, QLabel* label, QObject *parent = 0) + : QNetworkAccessManager(parent), m_url(url), m_label(label) + { + connect(this, SIGNAL(finished(QNetworkReply*)), SLOT(populatePixmap(QNetworkReply*))); + get(QNetworkRequest(url)); + } +public slots: + void populatePixmap(QNetworkReply* reply); + +private: + QUrl m_url; + QLabel *m_label; + +}; + class GettingStartedWelcomePageWidget : public QWidget { Q_OBJECT @@ -57,8 +91,15 @@ private slots: void slotOpenExample(); void slotNextTip(); void slotPrevTip(); + void slotNextFeature(); + void slotPrevFeature(); void slotCreateNewProject(); void slotSetPrivateQmlExamples(); + void addToFeatures(const RssItem&); + void showFeature(int feature = -1); + +signals: + void startRssFetching(const QUrl&); private: QStringList tipsOfTheDay(); @@ -69,6 +110,9 @@ private: const QString &sourcePath); Ui::GettingStartedWelcomePageWidget *ui; int m_currentTip; + int m_currentFeature; + QList m_featuredItems; + Core::Internal::RssFetcher *m_rssFetcher; }; } // namespace Internal diff --git a/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.ui b/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.ui index 616c897e0f7..226479a345f 100644 --- a/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.ui +++ b/src/plugins/qt4projectmanager/gettingstartedwelcomepagewidget.ui @@ -6,27 +6,21 @@ 0 0 - 646 - 367 + 672 + 366 Form - - + + 0 - + 0 - - 0 - - - 2 - - + @@ -37,8 +31,8 @@ QFrame::Raised - - + + @@ -46,6 +40,12 @@ 0 + + + 250 + 0 + + @@ -61,113 +61,12 @@ - - + - - - - 0 - 0 - - - - - 400 - 16777215 - - - - - - - - - - Explore Qt C++ Examples - - - - - - - false - - - - 0 - 0 - - - - - 0 - 30 - - - - Examples not installed... - - - - - - - - - - - 0 - 0 - - - - - 400 - 16777215 - - - - - - - - - - Explore Qt Quick Examples - - - - - - - false - - - - 0 - 0 - - - - - 0 - 30 - - - - Examples not installed... - - - - - - - @@ -175,10 +74,10 @@ 0 - + - 400 - 16777215 + 250 + 0 @@ -336,7 +235,128 @@ - + + + + + 0 + 0 + + + + + 500 + 0 + + + + + 500 + 16777215 + + + + + + + + + + Examples + + + + + + + Explore Qt C++ Examples + + + + + + + false + + + + 0 + 0 + + + + + 0 + 30 + + + + Examples not installed... + + + + + + + Explore Qt Quick Examples + + + + + + + false + + + + 0 + 0 + + + + + 0 + 30 + + + + Examples not installed... + + + + + + + Explore Qt C++ Mobile Examples + + + + + + + false + + + + 0 + 0 + + + + + 0 + 30 + + + + Examples not installed... + + + + + + + 6 @@ -391,6 +411,212 @@ + + + + + 150 + 16777215 + + + + QFrame#featureFrame { + +background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 rgba(245, 245, 245, 255), stop:1 rgba(225,225,225, 255)); + +border-left: 1px solid "#C9C9C9"; +border-bottom: 1px solid "#C9C9C9"; +} + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + Featured + + + + + + + + 128 + 0 + + + + + 16777215 + 128 + + + + Image + + + + + + + Text + + + true + + + + + + + + + Qt::Horizontal + + + + 24 + 38 + + + + + + + + Link + + + + + + + + + Qt::Vertical + + + + 20 + 239 + + + + + + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 13 + + + + + + + + QToolButton{ + border-left:solid 0 px; + height:16px; + width:12px; +} + + + + + + + + :/welcome/images/arrow-right.png:/welcome/images/arrow-right.png + + + Qt::NoArrow + + + + + + + QToolButton{ + border-right:solid 0 px; + height:16px; + width:12px; +} + + + + + + + + :/welcome/images/arrow-left.png:/welcome/images/arrow-left.png + + + Qt::NoArrow + + + + + + + Qt::Vertical + + + + 20 + 13 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + diff --git a/src/plugins/welcome/communitywelcomepagewidget.cpp b/src/plugins/welcome/communitywelcomepagewidget.cpp index 77a05b64cd9..ac80277d91d 100644 --- a/src/plugins/welcome/communitywelcomepagewidget.cpp +++ b/src/plugins/welcome/communitywelcomepagewidget.cpp @@ -30,13 +30,15 @@ #include "communitywelcomepagewidget.h" #include "ui_communitywelcomepagewidget.h" -#include "rssfetcher.h" +#include #include #include #include #include +using namespace Core::Internal; + struct Site { const char *description; const char *url; @@ -80,7 +82,7 @@ static inline void populateWelcomeTreeWidget(const Site *sites, int count, Utils CommunityWelcomePageWidget::CommunityWelcomePageWidget(QWidget *parent) : QWidget(parent), - m_rssFetcher(new RSSFetcher(7)), + m_rssFetcher(new RssFetcher(7)), ui(new Ui::CommunityWelcomePageWidget) { ui->setupUi(this); diff --git a/src/plugins/welcome/communitywelcomepagewidget.h b/src/plugins/welcome/communitywelcomepagewidget.h index 3bfb9d72bea..ff088e692c3 100644 --- a/src/plugins/welcome/communitywelcomepagewidget.h +++ b/src/plugins/welcome/communitywelcomepagewidget.h @@ -36,11 +36,15 @@ QT_BEGIN_NAMESPACE class QUrl; QT_END_NAMESPACE +namespace Core{ +namespace Internal { + class RssFetcher; +} +} + namespace Welcome { namespace Internal { -class RSSFetcher; - namespace Ui { class CommunityWelcomePageWidget; } @@ -61,7 +65,7 @@ private slots: private: - RSSFetcher *m_rssFetcher; + Core::Internal::RssFetcher *m_rssFetcher; Ui::CommunityWelcomePageWidget *ui; }; diff --git a/src/plugins/welcome/welcome.pro b/src/plugins/welcome/welcome.pro index d2e6e7c33ea..f5ad9bbe9f3 100644 --- a/src/plugins/welcome/welcome.pro +++ b/src/plugins/welcome/welcome.pro @@ -5,13 +5,11 @@ include(../../qtcreatorplugin.pri) include(welcome_dependencies.pri) HEADERS += welcomeplugin.h \ welcomemode.h \ - rssfetcher.h \ communitywelcomepagewidget.h \ communitywelcomepage.h \ welcome_global.h SOURCES += welcomeplugin.cpp \ welcomemode.cpp \ - rssfetcher.cpp \ communitywelcomepagewidget.cpp \ communitywelcomepage.cpp