@@ -45,6 +45,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
 | 
			
		||||
 | 
			
		||||
##################################### Set Application options #####################################
 | 
			
		||||
 | 
			
		||||
######## Set URLs ########
 | 
			
		||||
set(Launcher_NEWS_RSS_URL "https://multimc.org/rss.xml" CACHE STRING "URL to fetch Launcher's news RSS feed from.")
 | 
			
		||||
 | 
			
		||||
######## Set version numbers ########
 | 
			
		||||
set(Launcher_VERSION_MAJOR    1)
 | 
			
		||||
set(Launcher_VERSION_MINOR    0)
 | 
			
		||||
 
 | 
			
		||||
@@ -181,6 +181,15 @@ set(NOTIFICATIONS_SOURCES
 | 
			
		||||
    notifications/NotificationChecker.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# Backend for the news bar... there's usually no news.
 | 
			
		||||
set(NEWS_SOURCES
 | 
			
		||||
    # News System
 | 
			
		||||
    news/NewsChecker.h
 | 
			
		||||
    news/NewsChecker.cpp
 | 
			
		||||
    news/NewsEntry.h
 | 
			
		||||
    news/NewsEntry.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# Icon interface
 | 
			
		||||
set(ICONS_SOURCES
 | 
			
		||||
    # Icons System and related code
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										132
									
								
								launcher/news/NewsChecker.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								launcher/news/NewsChecker.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,132 @@
 | 
			
		||||
/* Copyright 2013-2021 MultiMC Contributors
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "NewsChecker.h"
 | 
			
		||||
 | 
			
		||||
#include <QByteArray>
 | 
			
		||||
#include <QDomDocument>
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
NewsChecker::NewsChecker(shared_qobject_ptr<QNetworkAccessManager> network, const QString& feedUrl)
 | 
			
		||||
{
 | 
			
		||||
    m_network = network;
 | 
			
		||||
    m_feedUrl = feedUrl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewsChecker::reloadNews()
 | 
			
		||||
{
 | 
			
		||||
    // Start a netjob to download the RSS feed and call rssDownloadFinished() when it's done.
 | 
			
		||||
    if (isLoadingNews())
 | 
			
		||||
    {
 | 
			
		||||
        qDebug() << "Ignored request to reload news. Currently reloading already.";
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qDebug() << "Reloading news.";
 | 
			
		||||
 | 
			
		||||
    NetJob* job = new NetJob("News RSS Feed", m_network);
 | 
			
		||||
    job->addNetAction(Net::Download::makeByteArray(m_feedUrl, &newsData));
 | 
			
		||||
    QObject::connect(job, &NetJob::succeeded, this, &NewsChecker::rssDownloadFinished);
 | 
			
		||||
    QObject::connect(job, &NetJob::failed, this, &NewsChecker::rssDownloadFailed);
 | 
			
		||||
    m_newsNetJob.reset(job);
 | 
			
		||||
    job->start();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewsChecker::rssDownloadFinished()
 | 
			
		||||
{
 | 
			
		||||
    // Parse the XML file and process the RSS feed entries.
 | 
			
		||||
    qDebug() << "Finished loading RSS feed.";
 | 
			
		||||
 | 
			
		||||
    m_newsNetJob.reset();
 | 
			
		||||
    QDomDocument doc;
 | 
			
		||||
    {
 | 
			
		||||
        // Stuff to store error info in.
 | 
			
		||||
        QString errorMsg = "Unknown error.";
 | 
			
		||||
        int errorLine = -1;
 | 
			
		||||
        int errorCol = -1;
 | 
			
		||||
 | 
			
		||||
        // Parse the XML.
 | 
			
		||||
        if (!doc.setContent(newsData, false, &errorMsg, &errorLine, &errorCol))
 | 
			
		||||
        {
 | 
			
		||||
            QString fullErrorMsg = QString("Error parsing RSS feed XML. %s at %d:%d.").arg(errorMsg, errorLine, errorCol);
 | 
			
		||||
            fail(fullErrorMsg);
 | 
			
		||||
            newsData.clear();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        newsData.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If the parsing succeeded, read it.
 | 
			
		||||
    QDomNodeList items = doc.elementsByTagName("item");
 | 
			
		||||
    m_newsEntries.clear();
 | 
			
		||||
    for (int i = 0; i < items.length(); i++)
 | 
			
		||||
    {
 | 
			
		||||
        QDomElement element = items.at(i).toElement();
 | 
			
		||||
        NewsEntryPtr entry;
 | 
			
		||||
        entry.reset(new NewsEntry());
 | 
			
		||||
        QString errorMsg = "An unknown error occurred.";
 | 
			
		||||
        if (NewsEntry::fromXmlElement(element, entry.get(), &errorMsg))
 | 
			
		||||
        {
 | 
			
		||||
            qDebug() << "Loaded news entry" << entry->title;
 | 
			
		||||
            m_newsEntries.append(entry);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            qWarning() << "Failed to load news entry at index" << i << ":" << errorMsg;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    succeed();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewsChecker::rssDownloadFailed(QString reason)
 | 
			
		||||
{
 | 
			
		||||
    // Set an error message and fail.
 | 
			
		||||
    fail(tr("Failed to load news RSS feed:\n%1").arg(reason));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QList<NewsEntryPtr> NewsChecker::getNewsEntries() const
 | 
			
		||||
{
 | 
			
		||||
    return m_newsEntries;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool NewsChecker::isLoadingNews() const
 | 
			
		||||
{
 | 
			
		||||
    return m_newsNetJob.get() != nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString NewsChecker::getLastLoadErrorMsg() const
 | 
			
		||||
{
 | 
			
		||||
    return m_lastLoadError;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewsChecker::succeed()
 | 
			
		||||
{
 | 
			
		||||
    m_lastLoadError = "";
 | 
			
		||||
    qDebug() << "News loading succeeded.";
 | 
			
		||||
    m_newsNetJob.reset();
 | 
			
		||||
    emit newsLoaded();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NewsChecker::fail(const QString& errorMsg)
 | 
			
		||||
{
 | 
			
		||||
    m_lastLoadError = errorMsg;
 | 
			
		||||
    qDebug() << "Failed to load news:" << errorMsg;
 | 
			
		||||
    m_newsNetJob.reset();
 | 
			
		||||
    emit newsLoadingFailed(errorMsg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										105
									
								
								launcher/news/NewsChecker.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								launcher/news/NewsChecker.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
/* Copyright 2013-2021 MultiMC Contributors
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <QObject>
 | 
			
		||||
#include <QString>
 | 
			
		||||
#include <QList>
 | 
			
		||||
 | 
			
		||||
#include <net/NetJob.h>
 | 
			
		||||
 | 
			
		||||
#include "NewsEntry.h"
 | 
			
		||||
 | 
			
		||||
class NewsChecker : public QObject
 | 
			
		||||
{
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
public:
 | 
			
		||||
    /*!
 | 
			
		||||
     * Constructs a news reader to read from the given RSS feed URL.
 | 
			
		||||
     */
 | 
			
		||||
    NewsChecker(shared_qobject_ptr<QNetworkAccessManager> network, const QString& feedUrl);
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
     * Returns the error message for the last time the news was loaded.
 | 
			
		||||
     * Empty string if the last load was successful.
 | 
			
		||||
     */
 | 
			
		||||
    QString getLastLoadErrorMsg() const;
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
     * Returns true if the news has been loaded successfully.
 | 
			
		||||
     */
 | 
			
		||||
    bool isNewsLoaded() const;
 | 
			
		||||
 | 
			
		||||
    //! True if the news is currently loading. If true, reloadNews() will do nothing.
 | 
			
		||||
    bool isLoadingNews() const;
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
     * Returns a list of news entries.
 | 
			
		||||
     */
 | 
			
		||||
    QList<NewsEntryPtr> getNewsEntries() const;
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
     * Reloads the news from the website's RSS feed.
 | 
			
		||||
     * If the news is already loading, this does nothing.
 | 
			
		||||
     */
 | 
			
		||||
    void Q_SLOT reloadNews();
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    /*!
 | 
			
		||||
     * Signal fired after the news has finished loading.
 | 
			
		||||
     */
 | 
			
		||||
    void newsLoaded();
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
     * Signal fired after the news fails to load.
 | 
			
		||||
     */
 | 
			
		||||
    void newsLoadingFailed(QString errorMsg);
 | 
			
		||||
 | 
			
		||||
protected slots:
 | 
			
		||||
    void rssDownloadFinished();
 | 
			
		||||
    void rssDownloadFailed(QString reason);
 | 
			
		||||
 | 
			
		||||
protected: /* data */
 | 
			
		||||
    //! The URL for the RSS feed to fetch.
 | 
			
		||||
    QString m_feedUrl;
 | 
			
		||||
 | 
			
		||||
    //! List of news entries.
 | 
			
		||||
    QList<NewsEntryPtr> m_newsEntries;
 | 
			
		||||
 | 
			
		||||
    //! The network job to use to load the news.
 | 
			
		||||
    NetJob::Ptr m_newsNetJob;
 | 
			
		||||
 | 
			
		||||
    //! True if news has been loaded.
 | 
			
		||||
    bool m_loadedNews;
 | 
			
		||||
 | 
			
		||||
    QByteArray newsData;
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
     * Gets the error message that was given last time the news was loaded.
 | 
			
		||||
     * If the last news load succeeded, this will be an empty string.
 | 
			
		||||
     */
 | 
			
		||||
    QString m_lastLoadError;
 | 
			
		||||
 | 
			
		||||
    shared_qobject_ptr<QNetworkAccessManager> m_network;
 | 
			
		||||
 | 
			
		||||
protected slots:
 | 
			
		||||
    /// Emits newsLoaded() and sets m_lastLoadError to empty string.
 | 
			
		||||
    void succeed();
 | 
			
		||||
 | 
			
		||||
    /// Emits newsLoadingFailed() and sets m_lastLoadError to the given message.
 | 
			
		||||
    void fail(const QString& errorMsg);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										77
									
								
								launcher/news/NewsEntry.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								launcher/news/NewsEntry.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
/* Copyright 2013-2021 MultiMC Contributors
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "NewsEntry.h"
 | 
			
		||||
 | 
			
		||||
#include <QDomNodeList>
 | 
			
		||||
#include <QVariant>
 | 
			
		||||
 | 
			
		||||
NewsEntry::NewsEntry(QObject* parent) :
 | 
			
		||||
    QObject(parent)
 | 
			
		||||
{
 | 
			
		||||
    this->title = tr("Untitled");
 | 
			
		||||
    this->content = tr("No content.");
 | 
			
		||||
    this->link = "";
 | 
			
		||||
    this->author = tr("Unknown Author");
 | 
			
		||||
    this->pubDate = QDateTime::currentDateTime();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NewsEntry::NewsEntry(const QString& title, const QString& content, const QString& link, const QString& author, const QDateTime& pubDate, QObject* parent) :
 | 
			
		||||
    QObject(parent)
 | 
			
		||||
{
 | 
			
		||||
    this->title = title;
 | 
			
		||||
    this->content = content;
 | 
			
		||||
    this->link = link;
 | 
			
		||||
    this->author = author;
 | 
			
		||||
    this->pubDate = pubDate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * Gets the text content of the given child element as a QVariant.
 | 
			
		||||
 */
 | 
			
		||||
inline QString childValue(const QDomElement& element, const QString& childName, QString defaultVal="")
 | 
			
		||||
{
 | 
			
		||||
    QDomNodeList nodes = element.elementsByTagName(childName);
 | 
			
		||||
    if (nodes.count() > 0)
 | 
			
		||||
    {
 | 
			
		||||
        QDomElement element = nodes.at(0).toElement();
 | 
			
		||||
        return element.text();
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return defaultVal;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool NewsEntry::fromXmlElement(const QDomElement& element, NewsEntry* entry, QString* errorMsg)
 | 
			
		||||
{
 | 
			
		||||
    QString title = childValue(element, "title", tr("Untitled"));
 | 
			
		||||
    QString content = childValue(element, "description", tr("No content."));
 | 
			
		||||
    QString link = childValue(element, "link");
 | 
			
		||||
    QString author = childValue(element, "dc:creator", tr("Unknown Author"));
 | 
			
		||||
    QString pubDateStr = childValue(element, "pubDate");
 | 
			
		||||
 | 
			
		||||
    // FIXME: For now, we're just ignoring timezones. We assume that all time zones in the RSS feed are the same.
 | 
			
		||||
    QString dateFormat("ddd, dd MMM yyyy hh:mm:ss");
 | 
			
		||||
    QDateTime pubDate = QDateTime::fromString(pubDateStr, dateFormat);
 | 
			
		||||
 | 
			
		||||
    entry->title = title;
 | 
			
		||||
    entry->content = content;
 | 
			
		||||
    entry->link = link;
 | 
			
		||||
    entry->author = author;
 | 
			
		||||
    entry->pubDate = pubDate;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										65
									
								
								launcher/news/NewsEntry.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								launcher/news/NewsEntry.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
			
		||||
/* Copyright 2013-2021 MultiMC Contributors
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <QObject>
 | 
			
		||||
#include <QString>
 | 
			
		||||
#include <QDomElement>
 | 
			
		||||
#include <QDateTime>
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
class NewsEntry : public QObject
 | 
			
		||||
{
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    /*!
 | 
			
		||||
     * Constructs an empty news entry.
 | 
			
		||||
     */
 | 
			
		||||
    explicit NewsEntry(QObject* parent=0);
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
     * Constructs a new news entry.
 | 
			
		||||
     * Note that content may contain HTML.
 | 
			
		||||
     */
 | 
			
		||||
    NewsEntry(const QString& title, const QString& content, const QString& link, const QString& author, const QDateTime& pubDate, QObject* parent=0);
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
     * Attempts to load information from the given XML element into the given news entry pointer.
 | 
			
		||||
     * If this fails, the function will return false and store an error message in the errorMsg pointer.
 | 
			
		||||
     */
 | 
			
		||||
    static bool fromXmlElement(const QDomElement& element, NewsEntry* entry, QString* errorMsg=0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //! The post title.
 | 
			
		||||
    QString title;
 | 
			
		||||
 | 
			
		||||
    //! The post's content. May contain HTML.
 | 
			
		||||
    QString content;
 | 
			
		||||
 | 
			
		||||
    //! URL to the post.
 | 
			
		||||
    QString link;
 | 
			
		||||
 | 
			
		||||
    //! The post's author.
 | 
			
		||||
    QString author;
 | 
			
		||||
    
 | 
			
		||||
    //! The date and time that this post was published.
 | 
			
		||||
    QDateTime pubDate;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef std::shared_ptr<NewsEntry> NewsEntryPtr;
 | 
			
		||||
 | 
			
		||||
@@ -58,6 +58,7 @@
 | 
			
		||||
#include <BuildConfig.h>
 | 
			
		||||
#include <net/NetJob.h>
 | 
			
		||||
#include <net/Download.h>
 | 
			
		||||
#include <news/NewsChecker.h>
 | 
			
		||||
#include <notifications/NotificationChecker.h>
 | 
			
		||||
#include <tools/BaseProfiler.h>
 | 
			
		||||
#include <updater/DownloadTask.h>
 | 
			
		||||
@@ -200,6 +201,7 @@ public:
 | 
			
		||||
    //TranslatedAction actionRefresh;
 | 
			
		||||
    TranslatedAction actionCheckUpdate;
 | 
			
		||||
    TranslatedAction actionSettings;
 | 
			
		||||
    TranslatedAction actionMoreNews;
 | 
			
		||||
    TranslatedAction actionManageAccounts;
 | 
			
		||||
    TranslatedAction actionLaunchInstance;
 | 
			
		||||
    TranslatedAction actionRenameInstance;
 | 
			
		||||
@@ -244,6 +246,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    TranslatedToolbar mainToolBar;
 | 
			
		||||
    TranslatedToolbar instanceToolBar;
 | 
			
		||||
    TranslatedToolbar newsToolBar;
 | 
			
		||||
    QVector<TranslatedToolbar *> all_toolbars;
 | 
			
		||||
    bool m_kill = false;
 | 
			
		||||
 | 
			
		||||
@@ -426,6 +429,29 @@ public:
 | 
			
		||||
        MainWindow->setStatusBar(statusBar);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void createNewsToolbar(QMainWindow *MainWindow)
 | 
			
		||||
    {
 | 
			
		||||
        newsToolBar = TranslatedToolbar(MainWindow);
 | 
			
		||||
        newsToolBar->setObjectName(QStringLiteral("newsToolBar"));
 | 
			
		||||
        newsToolBar->setMovable(false);
 | 
			
		||||
        newsToolBar->setAllowedAreas(Qt::BottomToolBarArea);
 | 
			
		||||
        newsToolBar->setIconSize(QSize(16, 16));
 | 
			
		||||
        newsToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
 | 
			
		||||
        newsToolBar->setFloatable(false);
 | 
			
		||||
        newsToolBar->setWindowTitle(QT_TRANSLATE_NOOP("MainWindow", "News Toolbar"));
 | 
			
		||||
 | 
			
		||||
        actionMoreNews = TranslatedAction(MainWindow);
 | 
			
		||||
        actionMoreNews->setObjectName(QStringLiteral("actionMoreNews"));
 | 
			
		||||
        actionMoreNews->setIcon(APPLICATION->getThemedIcon("news"));
 | 
			
		||||
        actionMoreNews.setTextId(QT_TRANSLATE_NOOP("MainWindow", "More news..."));
 | 
			
		||||
        actionMoreNews.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the development blog to read more news about %1."));
 | 
			
		||||
        all_actions.append(&actionMoreNews);
 | 
			
		||||
        newsToolBar->addAction(actionMoreNews);
 | 
			
		||||
 | 
			
		||||
        all_toolbars.append(&newsToolBar);
 | 
			
		||||
        MainWindow->addToolBar(Qt::BottomToolBarArea, newsToolBar);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void createInstanceToolbar(QMainWindow *MainWindow)
 | 
			
		||||
    {
 | 
			
		||||
        instanceToolBar = TranslatedToolbar(MainWindow);
 | 
			
		||||
@@ -610,6 +636,7 @@ public:
 | 
			
		||||
        MainWindow->setCentralWidget(centralWidget);
 | 
			
		||||
 | 
			
		||||
        createStatusBar(MainWindow);
 | 
			
		||||
        createNewsToolbar(MainWindow);
 | 
			
		||||
        createInstanceToolbar(MainWindow);
 | 
			
		||||
 | 
			
		||||
        retranslateUi(MainWindow);
 | 
			
		||||
@@ -664,6 +691,20 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
 | 
			
		||||
        connect(secretEventFilter, &KonamiCode::triggered, this, &MainWindow::konamiTriggered);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add the news label to the news toolbar.
 | 
			
		||||
    {
 | 
			
		||||
        m_newsChecker.reset(new NewsChecker(APPLICATION->network(), BuildConfig.NEWS_RSS_URL));
 | 
			
		||||
        newsLabel = new QToolButton();
 | 
			
		||||
        newsLabel->setIcon(APPLICATION->getThemedIcon("news"));
 | 
			
		||||
        newsLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
 | 
			
		||||
        newsLabel->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
 | 
			
		||||
        newsLabel->setFocusPolicy(Qt::NoFocus);
 | 
			
		||||
        ui->newsToolBar->insertWidget(ui->actionMoreNews, newsLabel);
 | 
			
		||||
        QObject::connect(newsLabel, &QAbstractButton::clicked, this, &MainWindow::newsButtonClicked);
 | 
			
		||||
        QObject::connect(m_newsChecker.get(), &NewsChecker::newsLoaded, this, &MainWindow::updateNewsLabel);
 | 
			
		||||
        updateNewsLabel();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Create the instance list widget
 | 
			
		||||
    {
 | 
			
		||||
        view = new InstanceView(ui->centralWidget);
 | 
			
		||||
@@ -768,6 +809,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
 | 
			
		||||
    // TODO: refresh accounts here?
 | 
			
		||||
    // auto accounts = APPLICATION->accounts();
 | 
			
		||||
 | 
			
		||||
    // load the news
 | 
			
		||||
    {
 | 
			
		||||
        m_newsChecker->reloadNews();
 | 
			
		||||
        updateNewsLabel();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if(BuildConfig.UPDATER_ENABLED)
 | 
			
		||||
    {
 | 
			
		||||
        bool updatesAllowed = APPLICATION->updatesAreAllowed();
 | 
			
		||||
@@ -1141,6 +1189,29 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
 | 
			
		||||
    return QMainWindow::eventFilter(obj, ev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWindow::updateNewsLabel()
 | 
			
		||||
{
 | 
			
		||||
    if (m_newsChecker->isLoadingNews())
 | 
			
		||||
    {
 | 
			
		||||
        newsLabel->setText(tr("Loading news..."));
 | 
			
		||||
        newsLabel->setEnabled(false);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        QList<NewsEntryPtr> entries = m_newsChecker->getNewsEntries();
 | 
			
		||||
        if (entries.length() > 0)
 | 
			
		||||
        {
 | 
			
		||||
            newsLabel->setText(entries[0]->title);
 | 
			
		||||
            newsLabel->setEnabled(true);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            newsLabel->setText(tr("No news available."));
 | 
			
		||||
            newsLabel->setEnabled(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWindow::updateAvailable(GoUpdate::Status status)
 | 
			
		||||
{
 | 
			
		||||
    if(!APPLICATION->updatesAreAllowed())
 | 
			
		||||
@@ -1614,6 +1685,24 @@ void MainWindow::on_actionReportBug_triggered()
 | 
			
		||||
    DesktopServices::openUrl(QUrl(BuildConfig.BUG_TRACKER_URL));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWindow::on_actionMoreNews_triggered()
 | 
			
		||||
{
 | 
			
		||||
    DesktopServices::openUrl(QUrl("https://multimc.org/posts.html"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWindow::newsButtonClicked()
 | 
			
		||||
{
 | 
			
		||||
    QList<NewsEntryPtr> entries = m_newsChecker->getNewsEntries();
 | 
			
		||||
    if (entries.count() > 0)
 | 
			
		||||
    {
 | 
			
		||||
        DesktopServices::openUrl(QUrl(entries[0]->link));
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        DesktopServices::openUrl(QUrl("https://multimc.org/posts.html"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MainWindow::on_actionAbout_triggered()
 | 
			
		||||
{
 | 
			
		||||
    AboutDialog dialog(this);
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@
 | 
			
		||||
#include "updater/GoUpdate.h"
 | 
			
		||||
 | 
			
		||||
class LaunchController;
 | 
			
		||||
class NewsChecker;
 | 
			
		||||
class NotificationChecker;
 | 
			
		||||
class QToolButton;
 | 
			
		||||
class InstanceProxyModel;
 | 
			
		||||
@@ -108,6 +109,10 @@ private slots:
 | 
			
		||||
 | 
			
		||||
    void on_actionReportBug_triggered();
 | 
			
		||||
 | 
			
		||||
    void on_actionMoreNews_triggered();
 | 
			
		||||
 | 
			
		||||
    void newsButtonClicked();
 | 
			
		||||
 | 
			
		||||
    void on_actionLaunchInstance_triggered();
 | 
			
		||||
 | 
			
		||||
    void on_actionLaunchInstanceOffline_triggered();
 | 
			
		||||
@@ -169,6 +174,8 @@ private slots:
 | 
			
		||||
 | 
			
		||||
    void repopulateAccountsMenu();
 | 
			
		||||
 | 
			
		||||
    void updateNewsLabel();
 | 
			
		||||
 | 
			
		||||
    /*!
 | 
			
		||||
     * Runs the DownloadTask and installs updates.
 | 
			
		||||
     */
 | 
			
		||||
@@ -198,12 +205,14 @@ private:
 | 
			
		||||
    // these are managed by Qt's memory management model!
 | 
			
		||||
    InstanceView *view = nullptr;
 | 
			
		||||
    InstanceProxyModel *proxymodel = nullptr;
 | 
			
		||||
    QToolButton *newsLabel = nullptr;
 | 
			
		||||
    QLabel *m_statusLeft = nullptr;
 | 
			
		||||
    QLabel *m_statusCenter = nullptr;
 | 
			
		||||
    QMenu *accountMenu = nullptr;
 | 
			
		||||
    QToolButton *accountMenuButton = nullptr;
 | 
			
		||||
    KonamiCode * secretEventFilter = nullptr;
 | 
			
		||||
 | 
			
		||||
    unique_qobject_ptr<NewsChecker> m_newsChecker;
 | 
			
		||||
    unique_qobject_ptr<NotificationChecker> m_notificationChecker;
 | 
			
		||||
 | 
			
		||||
    InstancePtr m_selectedInstance;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user