File indexing completed on 2024-05-12 04:58:13
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 * ============================================================ */ 0018 #include "siteinfo.h" 0019 #include "ui_siteinfo.h" 0020 #include "listitemdelegate.h" 0021 #include "webview.h" 0022 #include "webpage.h" 0023 #include "mainapplication.h" 0024 #include "downloaditem.h" 0025 #include "certificateinfowidget.h" 0026 #include "qztools.h" 0027 #include "iconprovider.h" 0028 #include "scripts.h" 0029 #include "networkmanager.h" 0030 #include "locationbar.h" 0031 0032 #include <QMenu> 0033 #include <QMessageBox> 0034 #include <QFileDialog> 0035 #include <QNetworkDiskCache> 0036 #include <QClipboard> 0037 #include <QTimer> 0038 #include <QGraphicsPixmapItem> 0039 #include <QShortcut> 0040 0041 SiteInfo::SiteInfo(WebView *view) 0042 : QDialog(view) 0043 , ui(new Ui::SiteInfo) 0044 , m_certWidget(nullptr) 0045 , m_view(view) 0046 , m_imageReply(nullptr) 0047 , m_baseUrl(view->url()) 0048 { 0049 setAttribute(Qt::WA_DeleteOnClose); 0050 ui->setupUi(this); 0051 ui->treeTags->setLayoutDirection(Qt::LeftToRight); 0052 QzTools::centerWidgetOnScreen(this); 0053 0054 auto* delegate = new ListItemDelegate(24, ui->listWidget); 0055 delegate->setUpdateParentHeight(true); 0056 delegate->setUniformItemSizes(true); 0057 ui->listWidget->setItemDelegate(delegate); 0058 0059 ui->listWidget->item(0)->setIcon(QIcon::fromTheme(QSL("document-properties"), QIcon(QSL(":/icons/preferences/document-properties.png")))); 0060 ui->listWidget->item(1)->setIcon(QIcon::fromTheme(QSL("applications-graphics"), QIcon(QSL(":/icons/preferences/applications-graphics.png")))); 0061 ui->listWidget->item(0)->setSelected(true); 0062 0063 // General 0064 ui->heading->setText(QSL("<b>%1</b>:").arg(m_view->title())); 0065 ui->siteAddress->setText(m_view->url().toString()); 0066 0067 if (m_view->url().scheme() == QL1S("https")) 0068 ui->securityLabel->setText(tr("<b>Connection is Encrypted.</b>")); 0069 else 0070 ui->securityLabel->setText(tr("<b>Connection Not Encrypted.</b>")); 0071 0072 m_view->page()->runJavaScript(QSL("document.charset"), WebPage::SafeJsWorld, [this](const QVariant &res) { 0073 ui->encodingLabel->setText(res.toString()); 0074 }); 0075 0076 // Meta 0077 m_view->page()->runJavaScript(Scripts::getAllMetaAttributes(), WebPage::SafeJsWorld, [this](const QVariant &res) { 0078 const QVariantList &list = res.toList(); 0079 for (const QVariant &val : list) { 0080 const QVariantMap &meta = val.toMap(); 0081 QString content = meta.value(QSL("content")).toString(); 0082 QString name = meta.value(QSL("name")).toString(); 0083 0084 if (name.isEmpty()) 0085 name = meta.value(QSL("httpequiv")).toString(); 0086 0087 if (content.isEmpty() || name.isEmpty()) 0088 continue; 0089 0090 auto* item = new QTreeWidgetItem(ui->treeTags); 0091 item->setText(0, name); 0092 item->setText(1, content); 0093 ui->treeTags->addTopLevelItem(item); 0094 } 0095 }); 0096 0097 // Images 0098 m_view->page()->runJavaScript(Scripts::getAllImages(), WebPage::SafeJsWorld, [this](const QVariant &res) { 0099 const QVariantList &list = res.toList(); 0100 for (const QVariant &val : list) { 0101 const QVariantMap &img = val.toMap(); 0102 QString src = img.value(QSL("src")).toString(); 0103 QString alt = img.value(QSL("alt")).toString(); 0104 if (alt.isEmpty()) { 0105 if (src.indexOf(QLatin1Char('/')) == -1) { 0106 alt = src; 0107 } 0108 else { 0109 int pos = src.lastIndexOf(QLatin1Char('/')); 0110 alt = src.mid(pos); 0111 alt.remove(QLatin1Char('/')); 0112 } 0113 } 0114 0115 if (src.isEmpty() || alt.isEmpty()) 0116 continue; 0117 0118 auto* item = new QTreeWidgetItem(ui->treeImages); 0119 item->setText(0, alt); 0120 item->setText(1, src); 0121 ui->treeImages->addTopLevelItem(item); 0122 } 0123 }); 0124 0125 connect(ui->saveButton, SIGNAL(clicked(QAbstractButton*)), this, SLOT(saveImage())); 0126 connect(ui->listWidget, SIGNAL(currentRowChanged(int)), ui->stackedWidget, SLOT(setCurrentIndex(int))); 0127 connect(ui->treeImages, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(showImagePreview(QTreeWidgetItem*))); 0128 connect(ui->treeImages, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(imagesCustomContextMenuRequested(QPoint))); 0129 connect(ui->treeTags, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tagsCustomContextMenuRequested(QPoint))); 0130 0131 auto *shortcutTagsCopyAll = new QShortcut(QKeySequence(QSL("Ctrl+C")), ui->treeTags); 0132 shortcutTagsCopyAll->setContext(Qt::WidgetShortcut); 0133 connect(shortcutTagsCopyAll, &QShortcut::activated, [=]{copySelectedItems(ui->treeTags, false);}); 0134 0135 auto *shortcutTagsCopyValues = new QShortcut(QKeySequence(QSL("Ctrl+Shift+C")), ui->treeTags); 0136 shortcutTagsCopyValues->setContext(Qt::WidgetShortcut); 0137 connect(shortcutTagsCopyValues, &QShortcut::activated, [=]{copySelectedItems(ui->treeTags, true);}); 0138 0139 auto *shortcutImagesCopyAll = new QShortcut(QKeySequence(QSL("Ctrl+C")), ui->treeImages); 0140 shortcutImagesCopyAll->setContext(Qt::WidgetShortcut); 0141 connect(shortcutImagesCopyAll, &QShortcut::activated, [=]{copySelectedItems(ui->treeImages, false);}); 0142 0143 auto *shortcutImagesCopyValues = new QShortcut(QKeySequence(QSL("Ctrl+Shift+C")), ui->treeImages); 0144 shortcutImagesCopyValues->setContext(Qt::WidgetShortcut); 0145 connect(shortcutImagesCopyValues, &QShortcut::activated, [=]{copySelectedItems(ui->treeImages, true);}); 0146 0147 ui->treeImages->setContextMenuPolicy(Qt::CustomContextMenu); 0148 ui->treeImages->sortByColumn(-1, Qt::AscendingOrder); 0149 0150 ui->treeTags->setContextMenuPolicy(Qt::CustomContextMenu); 0151 ui->treeTags->sortByColumn(-1, Qt::AscendingOrder); 0152 0153 QzTools::setWmClass(QSL("Site Info"), this); 0154 } 0155 0156 bool SiteInfo::canShowSiteInfo(const QUrl &url) 0157 { 0158 if (LocationBar::convertUrlToText(url).isEmpty()) 0159 return false; 0160 0161 if (url.scheme() == QL1S("falkon") || url.scheme() == QL1S("view-source") || url.scheme() == QL1S("extension")) 0162 return false; 0163 0164 return true; 0165 } 0166 0167 void SiteInfo::imagesCustomContextMenuRequested(const QPoint &p) 0168 { 0169 QTreeWidgetItem* item = ui->treeImages->itemAt(p); 0170 if (!item) { 0171 return; 0172 } 0173 0174 QMenu menu; 0175 menu.addAction(QIcon::fromTheme(QSL("edit-copy")), tr("Copy Image Location"), QKeySequence(QSL("Ctrl+C")), this, [=]{copySelectedItems(ui->treeImages, false);}); 0176 menu.addAction(tr("Copy Image Name"), QKeySequence(QSL("Ctrl+Shift+C")), this, [=]{copySelectedItems(ui->treeImages, true);}); 0177 menu.addSeparator(); 0178 menu.addAction(QIcon::fromTheme(QSL("document-save")), tr("Save Image to Disk"), this, SLOT(saveImage())); 0179 menu.exec(ui->treeImages->viewport()->mapToGlobal(p)); 0180 } 0181 0182 void SiteInfo::tagsCustomContextMenuRequested(const QPoint &p) 0183 { 0184 QTreeWidgetItem* item = ui->treeTags->itemAt(p); 0185 if (!item) { 0186 return; 0187 } 0188 0189 QMenu menu; 0190 menu.addAction(tr("Copy Values"), QKeySequence(QSL("Ctrl+C")), this, [=]{copySelectedItems(ui->treeTags, false);}); 0191 menu.addAction(tr("Copy Tags and Values"), QKeySequence(QSL("Ctrl+Shift+C")), this, [=]{copySelectedItems(ui->treeTags, true);}); 0192 menu.exec(ui->treeTags->viewport()->mapToGlobal(p)); 0193 } 0194 0195 void SiteInfo::copySelectedItems(const QTreeWidget* treeWidget, const bool both) 0196 { 0197 QList<QTreeWidgetItem*> itemList = treeWidget->selectedItems(); 0198 QString tmpText = QSL(""); 0199 0200 for (int i = 0; i < itemList.size(); ++i) { 0201 if (i != 0) { 0202 tmpText.append(QSL("\n")); 0203 } 0204 if (both) { 0205 tmpText.append((itemList[i])->text(0)); 0206 tmpText.append(QSL("\t")); 0207 } 0208 tmpText.append((itemList[i])->text(1)); 0209 } 0210 qApp->clipboard()->setText(tmpText); 0211 } 0212 0213 void SiteInfo::saveImage() 0214 { 0215 QTreeWidgetItem* item = ui->treeImages->currentItem(); 0216 if (!item) { 0217 return; 0218 } 0219 0220 if (!ui->mediaPreview->scene() || ui->mediaPreview->scene()->items().isEmpty()) 0221 return; 0222 0223 QGraphicsItem *graphicsItem = ui->mediaPreview->scene()->items().at(0); 0224 auto *pixmapItem = static_cast<QGraphicsPixmapItem*>(graphicsItem); 0225 if (graphicsItem->type() != QGraphicsPixmapItem::Type || !pixmapItem) 0226 return; 0227 0228 if (!pixmapItem || pixmapItem->pixmap().isNull()) { 0229 QMessageBox::warning(this, tr("Error!"), tr("This preview is not available!")); 0230 return; 0231 } 0232 0233 QString imageFileName = QzTools::getFileNameFromUrl(QUrl(item->text(1))); 0234 int index = imageFileName.lastIndexOf(QLatin1Char('.')); 0235 if (index != -1) { 0236 imageFileName.truncate(index); 0237 imageFileName.append(QL1S(".png")); 0238 } 0239 0240 QString filePath = QzTools::getSaveFileName(QSL("SiteInfo-DownloadImage"), this, tr("Save image..."), 0241 QDir::homePath() + QDir::separator() + imageFileName, 0242 QSL("*.png")); 0243 if (filePath.isEmpty()) { 0244 return; 0245 } 0246 0247 if (!pixmapItem->pixmap().save(filePath, "PNG")) { 0248 QMessageBox::critical(this, tr("Error!"), tr("Cannot write to file!")); 0249 return; 0250 } 0251 } 0252 0253 void SiteInfo::showLoadingText() 0254 { 0255 delete ui->mediaPreview->scene(); 0256 auto* scene = new QGraphicsScene(ui->mediaPreview); 0257 0258 scene->addText(tr("Loading...")); 0259 0260 ui->mediaPreview->setScene(scene); 0261 } 0262 0263 void SiteInfo::showPixmap(QPixmap pixmap) 0264 { 0265 pixmap.setDevicePixelRatio(devicePixelRatioF()); 0266 0267 delete ui->mediaPreview->scene(); 0268 auto* scene = new QGraphicsScene(ui->mediaPreview); 0269 0270 if (pixmap.isNull()) 0271 scene->addText(tr("Preview not available")); 0272 else 0273 scene->addPixmap(pixmap); 0274 0275 ui->mediaPreview->setScene(scene); 0276 } 0277 0278 void SiteInfo::showImagePreview(QTreeWidgetItem *item) 0279 { 0280 if ((!item) || (item->treeWidget()->selectedItems().length() > 1)) { 0281 return; 0282 } 0283 QUrl imageUrl = QUrl::fromEncoded(item->text(1).toUtf8()); 0284 if (imageUrl.isRelative()) { 0285 imageUrl = m_baseUrl.resolved(imageUrl); 0286 } 0287 0288 QPixmap pixmap; 0289 bool loading = false; 0290 0291 if (imageUrl.scheme() == QLatin1String("data")) { 0292 QByteArray encodedUrl = item->text(1).toUtf8(); 0293 QByteArray imageData = encodedUrl.mid(encodedUrl.indexOf(',') + 1); 0294 pixmap = QzTools::pixmapFromByteArray(imageData); 0295 } 0296 else if (imageUrl.scheme() == QLatin1String("file")) { 0297 pixmap = QPixmap(imageUrl.toLocalFile()); 0298 } 0299 else if (imageUrl.scheme() == QLatin1String("qrc")) { 0300 pixmap = QPixmap(imageUrl.toString().mid(3)); // Remove qrc from url 0301 } 0302 else { 0303 delete m_imageReply; 0304 m_imageReply = mApp->networkManager()->get(QNetworkRequest(imageUrl)); 0305 connect(m_imageReply, &QNetworkReply::finished, this, [this]() { 0306 if (m_imageReply->error() != QNetworkReply::NoError) 0307 return; 0308 0309 const QByteArray &data = m_imageReply->readAll(); 0310 showPixmap(QPixmap::fromImage(QImage::fromData(data))); 0311 }); 0312 0313 loading = true; 0314 showLoadingText(); 0315 } 0316 0317 if (!loading) 0318 showPixmap(pixmap); 0319 } 0320 0321 SiteInfo::~SiteInfo() 0322 { 0323 delete ui; 0324 delete m_certWidget; 0325 }