Kstars

thumbnailpicker.cpp
1/*
2 SPDX-FileCopyrightText: 2005 Jason Harris <kstars@30doradus.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "thumbnailpicker.h"
8
9#include "kstarsdata.h"
10#include "ksutils.h"
11#include "ksnotification.h"
12#include "skyobjectuserdata.h"
13#include "thumbnaileditor.h"
14#include "dialogs/detaildialog.h"
15#include "skyobjects/skyobject.h"
16
17#include <KIO/CopyJob>
18#include <KMessageBox>
19#include <KJobUiDelegate>
20
21#include <QDebug>
22
23#include <QLineEdit>
24#include <QPainter>
25#include <QPointer>
26#include <QScreen>
27#include <QUrlQuery>
28
29ThumbnailPickerUI::ThumbnailPickerUI(QWidget *parent) : QFrame(parent)
30{
31 setupUi(this);
32}
33
34ThumbnailPicker::ThumbnailPicker(SkyObject *o, const QPixmap &current, QWidget *parent, double _w, double _h,
35 QString cap)
36 : QDialog(parent), SelectedImageIndex(-1), Object(o), bImageFound(false)
37{
38#ifdef Q_OS_OSX
39 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
40#endif
41 thumbWidth = _w;
42 thumbHeight = _h;
43 Image = new QPixmap(current.scaled(_w, _h, Qt::KeepAspectRatio, Qt::FastTransformation));
44 ImageRect = new QRect(0, 0, 200, 200);
45
46 ui = new ThumbnailPickerUI(this);
47
48 setWindowTitle(cap);
49
50 QVBoxLayout *mainLayout = new QVBoxLayout;
51 mainLayout->addWidget(ui);
52 setLayout(mainLayout);
53
55 mainLayout->addWidget(buttonBox);
56 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
57 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
58
59 ui->CurrentImage->setPixmap(*Image);
60
61 connect(ui->EditButton, SIGNAL(clicked()), this, SLOT(slotEditImage()));
62 connect(ui->UnsetButton, SIGNAL(clicked()), this, SLOT(slotUnsetImage()));
63 connect(ui->ImageList, SIGNAL(currentRowChanged(int)), this, SLOT(slotSetFromList(int)));
64 connect(ui->ImageURLBox, SIGNAL(urlSelected(QUrl)), this, SLOT(slotSetFromURL()));
65 connect(ui->ImageURLBox, SIGNAL(returnPressed()), this, SLOT(slotSetFromURL()));
66
67 //ui->ImageURLBox->lineEdit()->setTrapReturnKey( true );
68 ui->EditButton->setEnabled(false);
69
70 slotFillList();
71}
72
73ThumbnailPicker::~ThumbnailPicker()
74{
75 while (!PixList.isEmpty())
76 delete PixList.takeFirst();
77}
78
79//Query online sources for images of the object
80void ThumbnailPicker::slotFillList()
81{
82 //Query Google Image Search:
83
84 //Search for the primary name, or longname and primary name
85 QString sName = QString("%1 ").arg(Object->name());
86 if (Object->longname() != Object->name())
87 {
88 sName = QString("%1 ").arg(Object->longname()) + sName;
89 }
91 QString("http://www.google.com/search?q=%1&tbs=itp:photo,isz:ex,iszw:200,iszh:200&tbm=isch&source=lnt")
92 .arg(sName);
93 QUrlQuery gURL(query);
94
95 //gURL.addQueryItem( "q", sName ); //add the Google-image query string
96
97 parseGooglePage(gURL.query());
98}
99
100void ThumbnailPicker::slotProcessGoogleResult(KJob *result)
101{
102 //Preload ImageList with the URLs in the object's ImageList:
103 SkyObjectUserdata::LinkList ImageList{
104 KStarsData::Instance()->getUserData(Object->name()).images()
105 };
106
107 if (result->error())
108 {
109 result->uiDelegate()->showErrorMessage();
110 result->kill();
111 return;
112 }
113
114 QString PageHTML(static_cast<KIO::StoredTransferJob *>(result)->data());
115
116 int index = PageHTML.indexOf("src=\"http:", 0);
117 while (index >= 0)
118 {
119 index += 5; //move to end of "src=\"http:" marker
120
121 //Image URL is everything from index to next occurrence of "\""
122 ImageList.push_back(SkyObjectUserdata::LinkData{
123 "", QUrl{ PageHTML.mid(index, PageHTML.indexOf("\"", index) - index) },
124 SkyObjectUserdata::Type::website });
125
126 index = PageHTML.indexOf("src=\"http:", index);
127 }
128
129 //Total Number of images to be loaded:
130 int nImages = ImageList.size();
131 if (nImages)
132 {
133 ui->SearchProgress->setMinimum(0);
134 ui->SearchProgress->setMaximum(nImages - 1);
135 ui->SearchLabel->setText(i18n("Loading images..."));
136 }
137 else
138 {
139 close();
140 return;
141 }
142
143 //Add images from the ImageList
144 for (const auto &image : ImageList)
145 {
146 const QUrl &u{ image.url };
147
148 if (u.isValid())
149 {
151 KIO::storedGet(u, KIO::NoReload, KIO::HideProgressInfo);
152 j->setUiDelegate(nullptr);
153 connect(j, SIGNAL(result(KJob *)), SLOT(slotJobResult(KJob *)));
154 }
155 }
156}
157
158void ThumbnailPicker::slotJobResult(KJob *job)
159{
161
162 //Update Progressbar
163 if (!ui->SearchProgress->isHidden())
164 {
165 ui->SearchProgress->setValue(ui->SearchProgress->value() + 1);
166 if (ui->SearchProgress->value() == ui->SearchProgress->maximum())
167 {
168 ui->SearchProgress->hide();
169 ui->SearchLabel->setText(i18n("Search results:"));
170 }
171 }
172
173 //If there was a problem, just return silently without adding image to list.
174 if (job->error())
175 {
176 qDebug() << Q_FUNC_INFO << " error=" << job->error();
177 job->kill();
178 return;
179 }
180
181 QPixmap *pm = new QPixmap();
182 pm->loadFromData(stjob->data());
183
184 uint w = pm->width();
185 uint h = pm->height();
186 uint pad =
187 0; /*FIXME LATER 4* QDialogBase::marginHint() + 2*ui->SearchLabel->height() + QDialogBase::actionButton( QDialogBase::Ok )->height() + 25;*/
188 uint hDesk = QGuiApplication::primaryScreen()->geometry().height() - pad;
189
190 if (h > hDesk)
191 *pm = pm->scaled(w * hDesk / h, hDesk, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
192
193 PixList.append(pm);
194
195 //Add 50x50 image and URL to listbox
196 //ui->ImageList->insertItem( shrinkImage( PixList.last(), 50 ),
197 // cjob->srcURLs().first().prettyUrl() );
198 ui->ImageList->addItem(new QListWidgetItem(QIcon(shrinkImage(PixList.last(), 200)), stjob->url().url()));
199}
200
201//void ThumbnailPicker::parseGooglePage( QStringList &ImList, const QString &URL )
202void ThumbnailPicker::parseGooglePage(const QString &URL)
203{
204 QUrl googleURL(URL);
205 KIO::StoredTransferJob *job = KIO::storedGet(googleURL);
206 connect(job, SIGNAL(result(KJob*)), this, SLOT(slotProcessGoogleResult(KJob*)));
207
208 job->start();
209}
210
211QPixmap ThumbnailPicker::shrinkImage(QPixmap *pm, int size, bool setImage)
212{
213 int w(pm->width()), h(pm->height());
214 int bigSize(w);
215 int rx(0), ry(0), sx(0), sy(0), bx(0), by(0);
216 if (size == 0)
217 return QPixmap();
218
219 //Prepare variables for rescaling image (if it is larger than 'size')
220 if (w > size && w >= h)
221 {
222 h = size;
223 w = size * pm->width() / pm->height();
224 }
225 else if (h > size && h > w)
226 {
227 w = size;
228 h = size * pm->height() / pm->width();
229 }
230 sx = (w - size) / 2;
231 sy = (h - size) / 2;
232 if (sx < 0)
233 {
234 rx = -sx;
235 sx = 0;
236 }
237 if (sy < 0)
238 {
239 ry = -sy;
240 sy = 0;
241 }
242
243 if (setImage)
244 bigSize = int(200. * float(pm->width()) / float(w));
245
247 result.fill(Qt::black); //in case final image is smaller than 'size'
248
249 if (pm->width() > size || pm->height() > size) //image larger than 'size'?
250 {
251 //convert to QImage so we can smoothscale it
252 QImage im(pm->toImage());
253 im = im.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
254
255 //bitBlt sizexsize square section of image
256 QPainter p;
257 p.begin(&result);
258 p.drawImage(rx, ry, im, sx, sy, size, size);
259 p.end();
260
261 if (setImage)
262 {
263 bx = int(sx * float(pm->width()) / float(w));
264 by = int(sy * float(pm->width()) / float(w));
265 ImageRect->setRect(bx, by, bigSize, bigSize);
266 }
267 }
268 else //image is smaller than size x size
269 {
270 QPainter p;
271 p.begin(&result);
272 p.drawImage(rx, ry, pm->toImage());
273 p.end();
274
275 if (setImage)
276 {
277 bx = int(rx * float(pm->width()) / float(w));
278 by = int(ry * float(pm->width()) / float(w));
279 ImageRect->setRect(bx, by, bigSize, bigSize);
280 }
281 }
282
283 return result;
284}
285
286void ThumbnailPicker::slotEditImage()
287{
288 QPointer<ThumbnailEditor> te = new ThumbnailEditor(this, thumbWidth, thumbHeight);
289 if (te->exec() == QDialog::Accepted)
290 {
291 QPixmap pm = te->thumbnail();
292 *Image = pm;
293 ui->CurrentImage->setPixmap(pm);
294 ui->CurrentImage->update();
295 }
296 delete te;
297}
298
299void ThumbnailPicker::slotUnsetImage()
300{
301 // QFile file;
302 //if ( KSUtils::openDataFile( file, "noimage.png" ) ) {
303 // file.close();
304 // Image->load( file.fileName(), "PNG" );
305 // } else {
306 // *Image = Image->scaled( dd->thumbnail()->width(), dd->thumbnail()->height() );
307 // Image->fill( dd->palette().color( QPalette::Window ) );
308 // }
309
310 QPixmap noImage;
311 noImage.load(":/images/noimage.png");
312 Image = new QPixmap(noImage.scaled(thumbWidth, thumbHeight, Qt::KeepAspectRatio, Qt::FastTransformation));
313
314 ui->EditButton->setEnabled(false);
315 ui->CurrentImage->setPixmap(*Image);
316 ui->CurrentImage->update();
317
318 bImageFound = false;
319}
320
321void ThumbnailPicker::slotSetFromList(int i)
322{
323 //Display image in preview pane
324 QPixmap pm;
325 pm = shrinkImage(PixList[i], 200, true); //scale image
326 SelectedImageIndex = i;
327
328 ui->CurrentImage->setPixmap(pm);
329 ui->CurrentImage->update();
330 ui->EditButton->setEnabled(true);
331
332 *Image = PixList[i]->scaled(thumbWidth, thumbHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
333 bImageFound = true;
334}
335
336void ThumbnailPicker::slotSetFromURL()
337{
338 //Attempt to load the specified URL
339 QUrl u = ui->ImageURLBox->url();
340
341 if (u.isValid())
342 {
343 if (u.isLocalFile())
344 {
345 QFile localFile(u.toLocalFile());
346
347 //Add image to list
348 //If image is taller than desktop, rescale it.
349 QImage im(localFile.fileName());
350
351 if (im.isNull())
352 {
353 KSNotification::sorry(i18n("Failed to load image at %1", localFile.fileName()), i18n("Failed to load image"));
354 return;
355 }
356
357 uint w = im.width();
358 uint h = im.height();
359 uint pad =
360 0; /* FIXME later 4*marginHint() + 2*ui->SearchLabel->height() + actionButton( Ok )->height() + 25; */
361 uint hDesk = QGuiApplication::primaryScreen()->geometry().height() - pad;
362
363 if (h > hDesk)
364 im = im.scaled(w * hDesk / h, hDesk, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
365
366 //Add Image to top of list and 50x50 thumbnail image and URL to top of listbox
367 PixList.insert(0, new QPixmap(QPixmap::fromImage(im)));
368 ui->ImageList->insertItem(0, new QListWidgetItem(QIcon(shrinkImage(PixList.last(), 50)), u.url()));
369
370 //Select the new image
371 ui->ImageList->setCurrentRow(0);
372 slotSetFromList(0);
373 }
374 else
375 {
377 j->setUiDelegate(nullptr);
378 connect(j, SIGNAL(result(KJob*)), SLOT(slotJobResult(KJob*)));
379 }
380 }
381}
const QUrl & url() const
QByteArray data() const
int error() const
virtual Q_SCRIPTABLE void start()=0
bool kill(KJob::KillVerbosity verbosity=KJob::Quietly)
void setUiDelegate(KJobUiDelegate *delegate)
const SkyObjectUserdata::Data & getUserData(const QString &name)
Get a reference to the user data of an object with the name name.
Provides all necessary information about an object in the sky: its coordinates, name(s),...
Definition skyobject.h:42
virtual QString name(void) const
Definition skyobject.h:145
virtual QString longname(void) const
Definition skyobject.h:164
QString i18n(const char *text, const TYPE &arg...)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
KIOCORE_EXPORT StoredTransferJob * storedGet(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
HideProgressInfo
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
int result() const const
void append(QList< T > &&value)
iterator insert(const_iterator before, parameter_type value)
bool isEmpty() const const
T & last()
value_type takeFirst()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool begin(QPaintDevice *device)
void drawImage(const QPoint &point, const QImage &image)
bool end()
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
int height() const const
bool load(const QString &fileName, const char *format, Qt::ImageConversionFlags flags)
bool loadFromData(const QByteArray &data, const char *format, Qt::ImageConversionFlags flags)
QPixmap scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
QImage toImage() const const
int width() const const
void setRect(int x, int y, int width, int height)
QString arg(Args &&... args) const const
KeepAspectRatio
FastTransformation
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isLocalFile() const const
bool isValid() const const
QString toLocalFile() const const
QString url(FormattingOptions options) const const
bool close()
void setEnabled(bool)
void hide()
bool isHidden() const const
void update()
Stores the tite and URL of a webpage.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:59:51 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.