1 /*
2  * newsbutton.cpp
3  * Copyright 2018, Thorbjørn Lindeijer <bjorn@lindeijer.nl>
4  *
5  * This file is part of Tiled.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along with
18  * this program. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "newsbutton.h"
22 
23 #include "newsfeed.h"
24 #include "preferences.h"
25 #include "utils.h"
26 
27 #include <QDesktopServices>
28 #include <QEvent>
29 #include <QMenu>
30 #include <QPainter>
31 
32 #ifdef TILED_SNAPSHOT
33 static const char newsArchiveUrl[] = "https://thorbjorn.itch.io/tiled/devlog";
34 #else
35 static const char newsArchiveUrl[] = "https://www.mapeditor.org/news";
36 #endif
37 
38 namespace Tiled {
39 
NewsButton(QWidget * parent)40 NewsButton::NewsButton(QWidget *parent)
41     : QToolButton(parent)
42     , mReadIcon(QLatin1String("://images/16/mail-read-symbolic.png"))
43     , mUnreadIcon(QLatin1String("://images/16/mail-unread-symbolic.png"))
44 {
45     const auto preferences = Preferences::instance();
46     setVisible(preferences->displayNews());
47     connect(preferences, &Preferences::displayNewsChanged, this, &NewsButton::setVisible);
48 
49     auto &feed = NewsFeed::instance();
50 
51     setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
52     setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
53     setAutoRaise(true);
54     setToolTip(feed.errorString());
55 
56     connect(&feed, &NewsFeed::refreshed,
57             this, &NewsButton::refreshButton);
58     connect(&feed, &NewsFeed::errorStringChanged,
59             this, &NewsButton::setToolTip);
60 
61     connect(this, &QToolButton::pressed,
62             this, &NewsButton::showNewsMenu);
63 
64     refreshButton();
65     retranslateUi();
66 }
67 
changeEvent(QEvent * event)68 void NewsButton::changeEvent(QEvent *event)
69 {
70     QToolButton::changeEvent(event);
71     switch (event->type()) {
72     case QEvent::LanguageChange:
73         retranslateUi();
74         break;
75     default:
76         break;
77     }
78 }
79 
refreshButton()80 void NewsButton::refreshButton()
81 {
82     auto &feed = NewsFeed::instance();
83     auto unreadCount = feed.unreadCount();
84 
85     if (unreadCount > 0) {
86         QPixmap numberPixmap(Utils::smallIconSize());
87         numberPixmap.fill(Qt::transparent);
88 
89         QPainter painter(&numberPixmap);
90         painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
91 
92         painter.setBrush(QColor(250, 92, 92));
93         painter.setPen(Qt::NoPen);
94         painter.drawEllipse(numberPixmap.rect().adjusted(1, 1, -1, -1));
95 
96         auto font = painter.font();
97         font.setBold(true);
98         painter.setFont(font);
99         painter.setBrush(Qt::white);
100         painter.setPen(Qt::white);
101         painter.drawText(numberPixmap.rect(), Qt::AlignCenter, unreadCount < 5 ? QString::number(unreadCount) :
102                                                                                  QStringLiteral("!"));
103 
104         setIcon(QIcon(numberPixmap));
105     } else {
106         setIcon(QIcon());
107     }
108 
109     setEnabled(!feed.isEmpty());
110 }
111 
showNewsMenu()112 void NewsButton::showNewsMenu()
113 {
114     auto newsFeedMenu = new QMenu;
115     auto &feed = NewsFeed::instance();
116 
117     for (const NewsItem &newsItem : feed.newsItems()) {
118         QAction *action = newsFeedMenu->addAction(newsItem.title, [=] {
119             QDesktopServices::openUrl(newsItem.link);
120             NewsFeed::instance().markRead(newsItem);
121         });
122 
123         if (feed.isUnread(newsItem)) {
124             QFont f = action->font();
125             f.setBold(true);
126             action->setFont(f);
127             action->setIcon(mUnreadIcon);
128         } else {
129             action->setIcon(mReadIcon);
130         }
131     }
132 
133     newsFeedMenu->addSeparator();
134 #ifdef TILED_SNAPSHOT
135     QAction *action = newsFeedMenu->addAction(tr("View All Posts"));
136 #else
137     QAction *action = newsFeedMenu->addAction(tr("News Archive"));
138 #endif
139     connect(action, &QAction::triggered, [] {
140         QDesktopServices::openUrl(QUrl(QLatin1String(newsArchiveUrl)));
141         NewsFeed::instance().markAllRead();
142     });
143 
144     auto size = newsFeedMenu->sizeHint();
145     auto rect = QRect(mapToGlobal(QPoint(width() - size.width(), -size.height())), size);
146     newsFeedMenu->setGeometry(rect);
147     newsFeedMenu->exec();
148 
149     setDown(false);
150 }
151 
retranslateUi()152 void NewsButton::retranslateUi()
153 {
154 #ifdef TILED_SNAPSHOT
155     setText(tr("Devlog"));
156 #else
157     setText(tr("News"));
158 #endif
159 }
160 
161 } // namespace Tiled
162 
163 #include "moc_newsbutton.cpp"
164