1 /**********************************************************************************************
2 Copyright (C) 2014 Oliver Eichler <oliver.eichler@gmx.de>
3 Copyright (C) 2019 Henri Hornburg <hrnbg@t-online.de>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 **********************************************************************************************/
19
20 #include "gis/wpt/CDetailsGeoCache.h"
21 #include "gis/wpt/CGisItemWpt.h"
22 #include "helpers/CWebPage.h"
23
24 #include <QtNetwork>
25 #include <QtWidgets>
26
27 #define HTTP_ATTR_WHAT QNetworkRequest::Attribute(QNetworkRequest::User + 1)
28 #define HTTP_ATTR_INFO QNetworkRequest::Attribute(QNetworkRequest::User + 2)
29
30
CDetailsGeoCache(CGisItemWpt & wpt,QWidget * parent)31 CDetailsGeoCache::CDetailsGeoCache(CGisItemWpt& wpt, QWidget* parent)
32 : QDialog(parent)
33 , wpt(wpt)
34 {
35 setupUi(this);
36 setWindowTitle(wpt.getName());
37
38 QString strPos;
39 QPointF pos = wpt.getPosition();
40 IUnit::degToStr(pos.x(), pos.y(), strPos);
41
42 const CGisItemWpt::geocache_t& geocache = wpt.getGeoCache();
43
44 QString status;
45 if(geocache.archived)
46 {
47 status = tr("Archived");
48 }
49 else if(geocache.available)
50 {
51 status = tr("Available");
52 }
53 else
54 {
55 status = tr("Not Available");
56 }
57
58 if(geocache.needsMaintenance)
59 {
60 status += ", " + tr("Needs Maintenance");
61 }
62
63 labelName->setText(geocache.name + " - " + status);
64 labelPositon->setText(strPos);
65 labelOwner->setText(geocache.owner);
66 labelSize->setText(geocache.container);
67 labelHiddenDate->setText(wpt.getTime().date().toString(Qt::SystemLocaleShortDate));
68 //Last found is set below to only loop logs once
69
70 qreal d = geocache.difficulty;
71 labelD1->setPixmap(QPixmap(d < 0.5 ? "://icons/cache/32x32/star_empty.png" : d < 1.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation));
72 labelD2->setPixmap(QPixmap(d < 1.5 ? "://icons/cache/32x32/star_empty.png" : d < 2.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation));
73 labelD3->setPixmap(QPixmap(d < 2.5 ? "://icons/cache/32x32/star_empty.png" : d < 3.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation));
74 labelD4->setPixmap(QPixmap(d < 3.5 ? "://icons/cache/32x32/star_empty.png" : d < 4.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation));
75 labelD5->setPixmap(QPixmap(d < 4.5 ? "://icons/cache/32x32/star_empty.png" : d < 5.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation));
76 qreal t = geocache.terrain;
77 labelT1->setPixmap(QPixmap(t < 0.5 ? "://icons/cache/32x32/star_empty.png" : t < 1.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation));
78 labelT2->setPixmap(QPixmap(t < 1.5 ? "://icons/cache/32x32/star_empty.png" : t < 2.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation));
79 labelT3->setPixmap(QPixmap(t < 2.5 ? "://icons/cache/32x32/star_empty.png" : t < 3.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation));
80 labelT4->setPixmap(QPixmap(t < 3.5 ? "://icons/cache/32x32/star_empty.png" : t < 4.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation));
81 labelT5->setPixmap(QPixmap(t < 4.5 ? "://icons/cache/32x32/star_empty.png" : t < 5.0 ? "://icons/cache/32x32/halfstar.png" : "://icons/cache/32x32/star.png").scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation));
82
83 checkHint->setEnabled(!geocache.hint.isEmpty());
84 labelHint->setText(geocache.hint.isEmpty() ? tr("none") : tr("???"));
85 toolIcon->setIcon(wpt.getIcon());
86 labelStatus->hide();
87
88 if(!geocache.attributes.isEmpty())
89 {
90 const QList<quint8>& keys = geocache.attributes.keys();
91 for(quint8 attribute : keys)
92 {
93 QString filepath = "://icons/geocaching/attributes/";
94 if(!geocache.attributes[attribute])
95 {
96 filepath.append('_');
97 }
98 filepath += QString::number(attribute) + ".png";
99
100 QLabel* attrLabel = new QLabel(this);//To avoid memory leak
101 attrLabel->setAlignment(Qt::AlignLeft);
102 attrLabel->setPixmap(QPixmap(filepath));
103 attributeHorLayout->insertWidget(0, attrLabel);
104 }
105
106 labelNoAttr->setHidden(true);
107 }
108
109 QString desc;
110 if(geocache.shortDescIsHtml)
111 {
112 desc += geocache.shortDesc;
113 }
114 else
115 {
116 QString str = geocache.shortDesc;
117 desc += "<p>" + str.replace("\n", "<br/>") + "</p>";
118 }
119
120 if(geocache.longDescIsHtml)
121 {
122 desc += geocache.longDesc;
123 }
124 else
125 {
126 QString str = geocache.longDesc;
127 desc += "<p>" + str.replace("\n", "<br/>") + "</p>";
128 }
129
130 CWebPage* webDescPage = new CWebPage(webDesc);
131 webDesc->setPage(webDescPage);
132 webDesc->setHtml(desc);
133
134 const QDateTime& lastFound = geocache.getLastFound();
135 labelLastFound->setText(lastFound.date().toString(Qt::SystemLocaleShortDate));
136
137 CWebPage* webLogPage = new CWebPage(webLogs);
138 webLogs->setPage(webLogPage);
139 webLogs->setHtml(geocache.getLogs());
140
141 timerDownload = new QTimer(this);
142 timerDownload->setSingleShot(true);
143 connect(timerDownload, &QTimer::timeout, this, &CDetailsGeoCache::slotDownloadDone);
144 connect(buttonVisitWebsite, &QPushButton::clicked, this, &CDetailsGeoCache::slotVisitWebsite);
145 connect(checkHint, &QCheckBox::toggled, this, &CDetailsGeoCache::slotHintChanged);
146 connect(webDescPage, &CWebPage::linkClicked, this, &CDetailsGeoCache::slotLinkClicked);
147 connect(toolUpdateSpoiler, &QToolButton::clicked, this, &CDetailsGeoCache::slotCollectSpoiler);
148
149 networkManager = new QNetworkAccessManager(this);
150 connect(networkManager, &QNetworkAccessManager::finished, this, &CDetailsGeoCache::slotRequestFinished);
151
152 const QList<CGisItemWpt::image_t>& images = wpt.getImages();
153 photoAlbum->reload(images);
154 if(images.isEmpty())
155 {
156 slotCollectSpoiler();
157 toolUpdateSpoiler->setEnabled(false);
158 }
159 else
160 {
161 toolUpdateSpoiler->setEnabled(true);
162 }
163 if(wpt.isOnDevice())
164 {
165 toolUpdateSpoiler->setEnabled(false);
166 }
167
168 listHistory->setEnabled(false);
169 listHistory->setupHistory(wpt);
170 }
171
~CDetailsGeoCache()172 CDetailsGeoCache::~CDetailsGeoCache()
173 {
174 }
175
slotVisitWebsite()176 void CDetailsGeoCache::slotVisitWebsite()
177 {
178 QDesktopServices::openUrl("https://www.coord.info/" + wpt.getName());
179 }
180
slotHintChanged(bool on)181 void CDetailsGeoCache::slotHintChanged(bool on)
182 {
183 if(on)
184 {
185 labelHint->setText(wpt.getGeoCache().hint);
186 }
187 else
188 {
189 labelHint->setText(tr("???"));
190 }
191 }
192
slotLinkClicked(const QUrl & url)193 void CDetailsGeoCache::slotLinkClicked(const QUrl& url)
194 {
195 QDesktopServices::openUrl(url);
196 }
197
slotCollectSpoiler()198 void CDetailsGeoCache::slotCollectSpoiler()
199 {
200 const QList<IGisItem::link_t>& links = wpt.getLinks();
201 if(links.isEmpty())
202 {
203 return;
204 }
205
206 wpt.loadHistory(0);
207 photoAlbum->reload(wpt.getImages());
208 listHistory->setupHistory(wpt);
209
210 QNetworkRequest request;
211 request.setUrl(links.first().uri);
212 networkManager->get(request);
213
214 timerDownload->start(10000);
215 labelStatus->show();
216 labelStatus->setText(tr("Searching for images..."));
217 }
218
slotRequestFinished(QNetworkReply * reply)219 void CDetailsGeoCache::slotRequestFinished(QNetworkReply* reply)
220 {
221 if(reply->error() != QNetworkReply::NoError)
222 {
223 qDebug() << reply->errorString();
224 reply->deleteLater();
225 return;
226 }
227
228 qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
229 qDebug() << reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute);
230 qDebug() << reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
231
232 qint32 httpStatusCodeAttribute = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
233 if(reply->property("whatfor") == "image")
234 {
235 QString info = reply->property("info").toString();
236
237 if((httpStatusCodeAttribute == 301) || (httpStatusCodeAttribute == 302))
238 {
239 QNetworkRequest request;
240 request.setUrl(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl());
241 QNetworkReply* reply = networkManager->get(request);
242 reply->setProperty("whatfor", "image");
243 reply->setProperty("info", info);
244 }
245 else if(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200)
246 {
247 CGisItemWpt::image_t image;
248 image.info = info;
249 image.pixmap.loadFromData(reply->readAll());
250 wpt.addImage(image);
251
252 photoAlbum->reload(wpt.getImages());
253 listHistory->setupHistory(wpt);
254
255 cntSpoiler--;
256 if(cntSpoiler == 0)
257 {
258 slotDownloadDone();
259 }
260 }
261 }
262 else
263 {
264 if((httpStatusCodeAttribute == 301) || (httpStatusCodeAttribute == 302))
265 {
266 QNetworkRequest request;
267 request.setUrl(reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl());
268 networkManager->get(request);
269 }
270 }
271
272
273 QString asw = reply->readAll();
274 reply->deleteLater();
275
276 if(asw.isEmpty())
277 {
278 return;
279 }
280
281 QRegExp re1(".*CachePageImages.*");
282 QRegExp re2("(https://.*\\.jpg).*>(.*)</a>");
283 re2.setMinimal(true);
284
285 bool watchOut = false;
286 QStringList lines = asw.split("\n");
287 for(const QString& line : qAsConst(lines))
288 {
289 if(!watchOut && re1.exactMatch(line))
290 {
291 watchOut = true;
292 }
293 else if(watchOut)
294 {
295 int pos = 0;
296 while ((pos = re2.indexIn(line, pos)) != NOIDX)
297 {
298 QString url = re2.cap(1);
299 QString info = re2.cap(2);
300
301 QNetworkRequest request;
302 request.setUrl(url);
303 QNetworkReply* reply = networkManager->get(request);
304 reply->setProperty("whatfor", "image");
305 reply->setProperty("info", info);
306 cntSpoiler++;
307
308 pos += re2.matchedLength();
309 }
310
311 watchOut = false;
312 }
313 }
314 }
315
slotDownloadDone()316 void CDetailsGeoCache::slotDownloadDone()
317 {
318 timerDownload->stop();
319 cntSpoiler = 0;
320 if(wpt.getImages().isEmpty())
321 {
322 labelStatus->setText(tr("No images found"));
323 }
324 else
325 {
326 labelStatus->hide();
327 }
328 }
329