File indexing completed on 2024-04-14 14:09:17
0001 /* 0002 SPDX-FileCopyrightText: 2005 Jason Harris <kstars@30doradus.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "thumbnailpicker.h" 0008 0009 #include "kstarsdata.h" 0010 #include "ksutils.h" 0011 #include "ksnotification.h" 0012 #include "skyobjectuserdata.h" 0013 #include "thumbnaileditor.h" 0014 #include "dialogs/detaildialog.h" 0015 #include "skyobjects/skyobject.h" 0016 0017 #include <KIO/CopyJob> 0018 #include <KMessageBox> 0019 #include <KJobUiDelegate> 0020 0021 #include <QDebug> 0022 0023 #include <QLineEdit> 0024 #include <QPainter> 0025 #include <QPointer> 0026 #include <QScreen> 0027 #include <QUrlQuery> 0028 0029 ThumbnailPickerUI::ThumbnailPickerUI(QWidget *parent) : QFrame(parent) 0030 { 0031 setupUi(this); 0032 } 0033 0034 ThumbnailPicker::ThumbnailPicker(SkyObject *o, const QPixmap ¤t, QWidget *parent, double _w, double _h, 0035 QString cap) 0036 : QDialog(parent), SelectedImageIndex(-1), Object(o), bImageFound(false) 0037 { 0038 #ifdef Q_OS_OSX 0039 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); 0040 #endif 0041 thumbWidth = _w; 0042 thumbHeight = _h; 0043 Image = new QPixmap(current.scaled(_w, _h, Qt::KeepAspectRatio, Qt::FastTransformation)); 0044 ImageRect = new QRect(0, 0, 200, 200); 0045 0046 ui = new ThumbnailPickerUI(this); 0047 0048 setWindowTitle(cap); 0049 0050 QVBoxLayout *mainLayout = new QVBoxLayout; 0051 mainLayout->addWidget(ui); 0052 setLayout(mainLayout); 0053 0054 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 0055 mainLayout->addWidget(buttonBox); 0056 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); 0057 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); 0058 0059 ui->CurrentImage->setPixmap(*Image); 0060 0061 connect(ui->EditButton, SIGNAL(clicked()), this, SLOT(slotEditImage())); 0062 connect(ui->UnsetButton, SIGNAL(clicked()), this, SLOT(slotUnsetImage())); 0063 connect(ui->ImageList, SIGNAL(currentRowChanged(int)), this, SLOT(slotSetFromList(int))); 0064 connect(ui->ImageURLBox, SIGNAL(urlSelected(QUrl)), this, SLOT(slotSetFromURL())); 0065 connect(ui->ImageURLBox, SIGNAL(returnPressed()), this, SLOT(slotSetFromURL())); 0066 0067 //ui->ImageURLBox->lineEdit()->setTrapReturnKey( true ); 0068 ui->EditButton->setEnabled(false); 0069 0070 slotFillList(); 0071 } 0072 0073 ThumbnailPicker::~ThumbnailPicker() 0074 { 0075 while (!PixList.isEmpty()) 0076 delete PixList.takeFirst(); 0077 } 0078 0079 //Query online sources for images of the object 0080 void ThumbnailPicker::slotFillList() 0081 { 0082 //Query Google Image Search: 0083 0084 //Search for the primary name, or longname and primary name 0085 QString sName = QString("%1 ").arg(Object->name()); 0086 if (Object->longname() != Object->name()) 0087 { 0088 sName = QString("%1 ").arg(Object->longname()) + sName; 0089 } 0090 QString query = 0091 QString("http://www.google.com/search?q=%1&tbs=itp:photo,isz:ex,iszw:200,iszh:200&tbm=isch&source=lnt") 0092 .arg(sName); 0093 QUrlQuery gURL(query); 0094 0095 //gURL.addQueryItem( "q", sName ); //add the Google-image query string 0096 0097 parseGooglePage(gURL.query()); 0098 } 0099 0100 void ThumbnailPicker::slotProcessGoogleResult(KJob *result) 0101 { 0102 //Preload ImageList with the URLs in the object's ImageList: 0103 SkyObjectUserdata::LinkList ImageList{ 0104 KStarsData::Instance()->getUserData(Object->name()).images() 0105 }; 0106 0107 if (result->error()) 0108 { 0109 result->uiDelegate()->showErrorMessage(); 0110 result->kill(); 0111 return; 0112 } 0113 0114 QString PageHTML(static_cast<KIO::StoredTransferJob *>(result)->data()); 0115 0116 int index = PageHTML.indexOf("src=\"http:", 0); 0117 while (index >= 0) 0118 { 0119 index += 5; //move to end of "src=\"http:" marker 0120 0121 //Image URL is everything from index to next occurrence of "\"" 0122 ImageList.push_back(SkyObjectUserdata::LinkData{ 0123 "", QUrl{ PageHTML.mid(index, PageHTML.indexOf("\"", index) - index) }, 0124 SkyObjectUserdata::Type::website }); 0125 0126 index = PageHTML.indexOf("src=\"http:", index); 0127 } 0128 0129 //Total Number of images to be loaded: 0130 int nImages = ImageList.size(); 0131 if (nImages) 0132 { 0133 ui->SearchProgress->setMinimum(0); 0134 ui->SearchProgress->setMaximum(nImages - 1); 0135 ui->SearchLabel->setText(i18n("Loading images...")); 0136 } 0137 else 0138 { 0139 close(); 0140 return; 0141 } 0142 0143 //Add images from the ImageList 0144 for (const auto &image : ImageList) 0145 { 0146 const QUrl &u{ image.url }; 0147 0148 if (u.isValid()) 0149 { 0150 KIO::StoredTransferJob *j = 0151 KIO::storedGet(u, KIO::NoReload, KIO::HideProgressInfo); 0152 j->setUiDelegate(nullptr); 0153 connect(j, SIGNAL(result(KJob *)), SLOT(slotJobResult(KJob *))); 0154 } 0155 } 0156 } 0157 0158 void ThumbnailPicker::slotJobResult(KJob *job) 0159 { 0160 KIO::StoredTransferJob *stjob = (KIO::StoredTransferJob *)job; 0161 0162 //Update Progressbar 0163 if (!ui->SearchProgress->isHidden()) 0164 { 0165 ui->SearchProgress->setValue(ui->SearchProgress->value() + 1); 0166 if (ui->SearchProgress->value() == ui->SearchProgress->maximum()) 0167 { 0168 ui->SearchProgress->hide(); 0169 ui->SearchLabel->setText(i18n("Search results:")); 0170 } 0171 } 0172 0173 //If there was a problem, just return silently without adding image to list. 0174 if (job->error()) 0175 { 0176 qDebug() << Q_FUNC_INFO << " error=" << job->error(); 0177 job->kill(); 0178 return; 0179 } 0180 0181 QPixmap *pm = new QPixmap(); 0182 pm->loadFromData(stjob->data()); 0183 0184 uint w = pm->width(); 0185 uint h = pm->height(); 0186 uint pad = 0187 0; /*FIXME LATER 4* QDialogBase::marginHint() + 2*ui->SearchLabel->height() + QDialogBase::actionButton( QDialogBase::Ok )->height() + 25;*/ 0188 uint hDesk = QGuiApplication::primaryScreen()->geometry().height() - pad; 0189 0190 if (h > hDesk) 0191 *pm = pm->scaled(w * hDesk / h, hDesk, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 0192 0193 PixList.append(pm); 0194 0195 //Add 50x50 image and URL to listbox 0196 //ui->ImageList->insertItem( shrinkImage( PixList.last(), 50 ), 0197 // cjob->srcURLs().first().prettyUrl() ); 0198 ui->ImageList->addItem(new QListWidgetItem(QIcon(shrinkImage(PixList.last(), 200)), stjob->url().url())); 0199 } 0200 0201 //void ThumbnailPicker::parseGooglePage( QStringList &ImList, const QString &URL ) 0202 void ThumbnailPicker::parseGooglePage(const QString &URL) 0203 { 0204 QUrl googleURL(URL); 0205 KIO::StoredTransferJob *job = KIO::storedGet(googleURL); 0206 connect(job, SIGNAL(result(KJob*)), this, SLOT(slotProcessGoogleResult(KJob*))); 0207 0208 job->start(); 0209 } 0210 0211 QPixmap ThumbnailPicker::shrinkImage(QPixmap *pm, int size, bool setImage) 0212 { 0213 int w(pm->width()), h(pm->height()); 0214 int bigSize(w); 0215 int rx(0), ry(0), sx(0), sy(0), bx(0), by(0); 0216 if (size == 0) 0217 return QPixmap(); 0218 0219 //Prepare variables for rescaling image (if it is larger than 'size') 0220 if (w > size && w >= h) 0221 { 0222 h = size; 0223 w = size * pm->width() / pm->height(); 0224 } 0225 else if (h > size && h > w) 0226 { 0227 w = size; 0228 h = size * pm->height() / pm->width(); 0229 } 0230 sx = (w - size) / 2; 0231 sy = (h - size) / 2; 0232 if (sx < 0) 0233 { 0234 rx = -sx; 0235 sx = 0; 0236 } 0237 if (sy < 0) 0238 { 0239 ry = -sy; 0240 sy = 0; 0241 } 0242 0243 if (setImage) 0244 bigSize = int(200. * float(pm->width()) / float(w)); 0245 0246 QPixmap result(size, size); 0247 result.fill(Qt::black); //in case final image is smaller than 'size' 0248 0249 if (pm->width() > size || pm->height() > size) //image larger than 'size'? 0250 { 0251 //convert to QImage so we can smoothscale it 0252 QImage im(pm->toImage()); 0253 im = im.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 0254 0255 //bitBlt sizexsize square section of image 0256 QPainter p; 0257 p.begin(&result); 0258 p.drawImage(rx, ry, im, sx, sy, size, size); 0259 p.end(); 0260 0261 if (setImage) 0262 { 0263 bx = int(sx * float(pm->width()) / float(w)); 0264 by = int(sy * float(pm->width()) / float(w)); 0265 ImageRect->setRect(bx, by, bigSize, bigSize); 0266 } 0267 } 0268 else //image is smaller than size x size 0269 { 0270 QPainter p; 0271 p.begin(&result); 0272 p.drawImage(rx, ry, pm->toImage()); 0273 p.end(); 0274 0275 if (setImage) 0276 { 0277 bx = int(rx * float(pm->width()) / float(w)); 0278 by = int(ry * float(pm->width()) / float(w)); 0279 ImageRect->setRect(bx, by, bigSize, bigSize); 0280 } 0281 } 0282 0283 return result; 0284 } 0285 0286 void ThumbnailPicker::slotEditImage() 0287 { 0288 QPointer<ThumbnailEditor> te = new ThumbnailEditor(this, thumbWidth, thumbHeight); 0289 if (te->exec() == QDialog::Accepted) 0290 { 0291 QPixmap pm = te->thumbnail(); 0292 *Image = pm; 0293 ui->CurrentImage->setPixmap(pm); 0294 ui->CurrentImage->update(); 0295 } 0296 delete te; 0297 } 0298 0299 void ThumbnailPicker::slotUnsetImage() 0300 { 0301 // QFile file; 0302 //if ( KSUtils::openDataFile( file, "noimage.png" ) ) { 0303 // file.close(); 0304 // Image->load( file.fileName(), "PNG" ); 0305 // } else { 0306 // *Image = Image->scaled( dd->thumbnail()->width(), dd->thumbnail()->height() ); 0307 // Image->fill( dd->palette().color( QPalette::Window ) ); 0308 // } 0309 0310 QPixmap noImage; 0311 noImage.load(":/images/noimage.png"); 0312 Image = new QPixmap(noImage.scaled(thumbWidth, thumbHeight, Qt::KeepAspectRatio, Qt::FastTransformation)); 0313 0314 ui->EditButton->setEnabled(false); 0315 ui->CurrentImage->setPixmap(*Image); 0316 ui->CurrentImage->update(); 0317 0318 bImageFound = false; 0319 } 0320 0321 void ThumbnailPicker::slotSetFromList(int i) 0322 { 0323 //Display image in preview pane 0324 QPixmap pm; 0325 pm = shrinkImage(PixList[i], 200, true); //scale image 0326 SelectedImageIndex = i; 0327 0328 ui->CurrentImage->setPixmap(pm); 0329 ui->CurrentImage->update(); 0330 ui->EditButton->setEnabled(true); 0331 0332 *Image = PixList[i]->scaled(thumbWidth, thumbHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 0333 bImageFound = true; 0334 } 0335 0336 void ThumbnailPicker::slotSetFromURL() 0337 { 0338 //Attempt to load the specified URL 0339 QUrl u = ui->ImageURLBox->url(); 0340 0341 if (u.isValid()) 0342 { 0343 if (u.isLocalFile()) 0344 { 0345 QFile localFile(u.toLocalFile()); 0346 0347 //Add image to list 0348 //If image is taller than desktop, rescale it. 0349 QImage im(localFile.fileName()); 0350 0351 if (im.isNull()) 0352 { 0353 KSNotification::sorry(i18n("Failed to load image at %1", localFile.fileName()), i18n("Failed to load image")); 0354 return; 0355 } 0356 0357 uint w = im.width(); 0358 uint h = im.height(); 0359 uint pad = 0360 0; /* FIXME later 4*marginHint() + 2*ui->SearchLabel->height() + actionButton( Ok )->height() + 25; */ 0361 uint hDesk = QGuiApplication::primaryScreen()->geometry().height() - pad; 0362 0363 if (h > hDesk) 0364 im = im.scaled(w * hDesk / h, hDesk, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 0365 0366 //Add Image to top of list and 50x50 thumbnail image and URL to top of listbox 0367 PixList.insert(0, new QPixmap(QPixmap::fromImage(im))); 0368 ui->ImageList->insertItem(0, new QListWidgetItem(QIcon(shrinkImage(PixList.last(), 50)), u.url())); 0369 0370 //Select the new image 0371 ui->ImageList->setCurrentRow(0); 0372 slotSetFromList(0); 0373 } 0374 else 0375 { 0376 KIO::StoredTransferJob *j = KIO::storedGet(u, KIO::NoReload, KIO::HideProgressInfo); 0377 j->setUiDelegate(nullptr); 0378 connect(j, SIGNAL(result(KJob*)), SLOT(slotJobResult(KJob*))); 0379 } 0380 } 0381 }