File indexing completed on 2023-05-30 09:09:56
0001 /* This file is part of the KDE project 0002 Copyright (C) 2000 Simon Hausmann <hausmann@kde.org> 0003 0004 This library is free software; you can redistribute it and/or 0005 modify it under the terms of the GNU Library General Public 0006 License as published by the Free Software Foundation; either 0007 version 2 of the License, or (at your option) any later version. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "khtmlimage.h" 0021 #include "khtmlview.h" 0022 #include "khtml_ext.h" 0023 #include "xml/dom_docimpl.h" 0024 #include "html/html_documentimpl.h" 0025 #include "html/html_elementimpl.h" 0026 #include "rendering/render_image.h" 0027 #include "misc/loader.h" 0028 0029 #include <QTimer> 0030 #include <QVBoxLayout> 0031 0032 #include <kparts/guiactivateevent.h> 0033 #include <kjobuidelegate.h> 0034 #include <kio/job.h> 0035 #include <qmimedatabase.h> 0036 #include <klocalizedstring.h> 0037 #include <kactioncollection.h> 0038 #include <kaboutdata.h> 0039 0040 #include "../khtml_version.h" 0041 0042 0043 KHTMLImage::KHTMLImage(QWidget *parentWidget, 0044 QObject *parent, const QVariantList &args) 0045 : KParts::ReadOnlyPart(parent), m_image(nullptr) 0046 { 0047 KHTMLPart *parentPart = qobject_cast<KHTMLPart *>(parent); 0048 0049 KAboutData about("khtmlimage", i18n("KHTML Image"), QStringLiteral(KHTML_VERSION_STRING)); 0050 KHTMLPart::GUIProfile prof = KHTMLPart::DefaultGUI; 0051 if (args.contains("Browser/View")) { 0052 prof = KHTMLPart::BrowserViewGUI; 0053 } 0054 setComponentData(about, prof == KHTMLPart::BrowserViewGUI && !parentPart); 0055 0056 QWidget *box = new QWidget(parentWidget); 0057 box->setLayout(new QVBoxLayout(box)); 0058 box->setAcceptDrops(true); 0059 0060 m_khtml = new KHTMLPart(box, this, prof); 0061 box->layout()->addWidget(m_khtml->widget()); 0062 m_khtml->setAutoloadImages(true); 0063 0064 // We do not want our subpart to be destroyed when its widget is, 0065 // since that may cause all KHTMLParts to die when we're dealing 0066 // with 0067 m_khtml->setAutoDeletePart(false); 0068 0069 connect(m_khtml->view(), SIGNAL(finishedLayout()), this, SLOT(restoreScrollPosition())); 0070 0071 setWidget(box); 0072 0073 // VBox can't take focus, so pass it on to sub-widget 0074 box->setFocusProxy(m_khtml->widget()); 0075 0076 m_ext = new KHTMLImageBrowserExtension(this); 0077 m_ext->setObjectName("be"); 0078 0079 m_sbExt = new KParts::StatusBarExtension(this); 0080 m_sbExt->setObjectName("sbe"); 0081 0082 // Remove unnecessary actions. 0083 delete actionCollection()->action("setEncoding"); 0084 delete actionCollection()->action("viewDocumentSource"); 0085 delete actionCollection()->action("selectAll"); 0086 0087 // forward important signals from the khtml part 0088 0089 // forward opening requests to parent frame (if existing) 0090 KHTMLPart *p = qobject_cast<KHTMLPart *>(parent); 0091 KParts::BrowserExtension *be = p ? p->browserExtension() : m_ext; 0092 connect(m_khtml->browserExtension(), SIGNAL(openUrlRequestDelayed(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)), 0093 be, SIGNAL(openUrlRequestDelayed(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments))); 0094 0095 connect(m_khtml->browserExtension(), SIGNAL(popupMenu(QPoint,QUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), 0096 this, SLOT(slotPopupMenu(QPoint,QUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap))); 0097 0098 connect(m_khtml->browserExtension(), SIGNAL(enableAction(const char*,bool)), 0099 m_ext, SIGNAL(enableAction(const char*,bool))); 0100 0101 m_ext->setURLDropHandlingEnabled(true); 0102 } 0103 0104 KHTMLImage::~KHTMLImage() 0105 { 0106 disposeImage(); 0107 0108 // important: delete the html part before the part or qobject destructor runs. 0109 // we now delete the htmlpart which deletes the part's widget which makes 0110 // _OUR_ m_widget 0 which in turn avoids our part destructor to delete the 0111 // widget ;-) 0112 // ### additional note: it _can_ be that the part has been deleted before: 0113 // when we're in a html frameset and the view dies first, then it will also 0114 // kill the htmlpart 0115 if (m_khtml) { 0116 delete static_cast<KHTMLPart *>(m_khtml); 0117 } 0118 } 0119 0120 bool KHTMLImage::openUrl(const QUrl &url) 0121 { 0122 static const QString &html = QString::fromLatin1("<html><body><img src=\"%1\"></body></html>"); 0123 0124 // Propagate statusbar to our kid part. 0125 KParts::StatusBarExtension::childObject(m_khtml)->setStatusBar(m_sbExt->statusBar()); 0126 0127 disposeImage(); 0128 0129 setUrl(url); 0130 0131 emit started(nullptr); 0132 0133 KParts::OpenUrlArguments args = arguments(); 0134 m_mimeType = args.mimeType(); 0135 0136 QUrl kurl(url); 0137 emit setWindowCaption(kurl.toDisplayString()); 0138 0139 // Need to keep a copy of the offsets since they are cleared when emitting completed 0140 m_xOffset = args.xOffset(); 0141 m_yOffset = args.yOffset(); 0142 0143 m_khtml->begin(this->url()); 0144 m_khtml->setAutoloadImages(true); 0145 0146 DOM::DocumentImpl *impl = dynamic_cast<DOM::DocumentImpl *>(m_khtml->document().handle()); // ### hack ;-) 0147 if (!impl) { 0148 return false; 0149 } 0150 0151 if (arguments().reload()) { 0152 impl->docLoader()->setCachePolicy(KIO::CC_Reload); 0153 } 0154 0155 khtml::DocLoader *dl = impl->docLoader(); 0156 m_image = dl->requestImage(this->url().toString()); 0157 if (m_image) { 0158 m_image->ref(this); 0159 } 0160 0161 m_khtml->write(html.arg(this->url().toString())); 0162 m_khtml->end(); 0163 0164 /* 0165 connect( khtml::Cache::loader(), SIGNAL(requestDone(khtml::DocLoader*,khtml::CachedObject*)), 0166 this, SLOT(updateWindowCaption()) ); 0167 */ 0168 return true; 0169 } 0170 0171 bool KHTMLImage::closeUrl() 0172 { 0173 disposeImage(); 0174 return m_khtml->closeUrl(); 0175 } 0176 0177 // This can happen after openUrl returns, or directly from m_image->ref() 0178 void KHTMLImage::notifyFinished(khtml::CachedObject *o) 0179 { 0180 if (!m_image || o != m_image) { 0181 return; 0182 } 0183 0184 //const QPixmap &pix = m_image->pixmap(); 0185 QString caption; 0186 0187 QMimeDatabase db; 0188 QMimeType mimeType; 0189 if (!m_mimeType.isEmpty()) { 0190 mimeType = db.mimeTypeForName(m_mimeType); 0191 } 0192 0193 if (mimeType.isValid()) { 0194 if (!m_image->suggestedTitle().isEmpty()) { 0195 caption = i18n("%1 (%2 - %3x%4 Pixels)", m_image->suggestedTitle(), mimeType.comment(), m_image->pixmap_size().width(), m_image->pixmap_size().height()); 0196 } else { 0197 caption = i18n("%1 - %2x%3 Pixels", mimeType.comment(), 0198 m_image->pixmap_size().width(), m_image->pixmap_size().height()); 0199 } 0200 } else { 0201 if (!m_image->suggestedTitle().isEmpty()) { 0202 caption = i18n("%1 (%2x%3 Pixels)", m_image->suggestedTitle(), m_image->pixmap_size().width(), m_image->pixmap_size().height()); 0203 } else { 0204 caption = i18n("Image - %1x%2 Pixels", m_image->pixmap_size().width(), m_image->pixmap_size().height()); 0205 } 0206 } 0207 0208 emit setWindowCaption(caption); 0209 emit completed(); 0210 emit setStatusBarText(i18n("Done.")); 0211 } 0212 0213 void KHTMLImage::restoreScrollPosition() 0214 { 0215 if (m_khtml->view()->contentsY() == 0) { 0216 m_khtml->view()->setContentsPos(m_xOffset, m_yOffset); 0217 } 0218 } 0219 0220 void KHTMLImage::guiActivateEvent(KParts::GUIActivateEvent *e) 0221 { 0222 // prevent the base implementation from emitting setWindowCaption with 0223 // our url. It destroys our pretty, previously caption. Konq saves/restores 0224 // the caption for us anyway. 0225 if (e->activated()) { 0226 return; 0227 } 0228 KParts::ReadOnlyPart::guiActivateEvent(e); 0229 } 0230 0231 /* 0232 void KHTMLImage::slotImageJobFinished( KIO::Job *job ) 0233 { 0234 if ( job->error() ) 0235 { 0236 job->uiDelegate()->showErrorMessage(); 0237 emit canceled( job->errorString() ); 0238 } 0239 else 0240 { 0241 emit completed(); 0242 QTimer::singleShot( 0, this, SLOT(updateWindowCaption()) ); 0243 } 0244 } 0245 0246 void KHTMLImage::updateWindowCaption() 0247 { 0248 if ( !m_khtml ) 0249 return; 0250 0251 DOM::HTMLDocumentImpl *impl = dynamic_cast<DOM::HTMLDocumentImpl *>( m_khtml->document().handle() ); 0252 if ( !impl ) 0253 return; 0254 0255 DOM::HTMLElementImpl *body = impl->body(); 0256 if ( !body ) 0257 return; 0258 0259 DOM::NodeImpl *image = body->firstChild(); 0260 if ( !image ) 0261 return; 0262 0263 khtml::RenderImage *renderImage = dynamic_cast<khtml::RenderImage *>( image->renderer() ); 0264 if ( !renderImage ) 0265 return; 0266 0267 QPixmap pix = renderImage->pixmap(); 0268 0269 QString caption; 0270 0271 KMimeType::Ptr mimeType; 0272 if ( !m_mimeType.isEmpty() ) 0273 mimeType = KMimeType::mimeType( m_mimeType, KMimeType::ResolveAliases ); 0274 0275 if ( mimeType ) 0276 caption = i18n( "%1 - %2x%3 Pixels" ).arg( mimeType.comment() ) 0277 .arg( pix.width() ).arg( pix.height() ); 0278 else 0279 caption = i18n( "Image - %1x%2 Pixels" ).arg( pix.width() ).arg( pix.height() ); 0280 0281 emit setWindowCaption( caption ); 0282 emit completed(); 0283 emit setStatusBarText(i18n("Done.")); 0284 } 0285 */ 0286 0287 void KHTMLImage::disposeImage() 0288 { 0289 if (!m_image) { 0290 return; 0291 } 0292 0293 m_image->deref(this); 0294 m_image = nullptr; 0295 } 0296 0297 KHTMLImageBrowserExtension::KHTMLImageBrowserExtension(KHTMLImage *parent) 0298 : KParts::BrowserExtension(parent) 0299 { 0300 m_imgPart = parent; 0301 } 0302 0303 int KHTMLImageBrowserExtension::xOffset() 0304 { 0305 return m_imgPart->doc()->view()->contentsX(); 0306 } 0307 0308 int KHTMLImageBrowserExtension::yOffset() 0309 { 0310 return m_imgPart->doc()->view()->contentsY(); 0311 } 0312 0313 void KHTMLImageBrowserExtension::print() 0314 { 0315 static_cast<KHTMLPartBrowserExtension *>(m_imgPart->doc()->browserExtension())->print(); 0316 } 0317 0318 void KHTMLImageBrowserExtension::reparseConfiguration() 0319 { 0320 static_cast<KHTMLPartBrowserExtension *>(m_imgPart->doc()->browserExtension())->reparseConfiguration(); 0321 m_imgPart->doc()->setAutoloadImages(true); 0322 } 0323 0324 void KHTMLImageBrowserExtension::disableScrolling() 0325 { 0326 static_cast<KHTMLPartBrowserExtension *>(m_imgPart->doc()->browserExtension())->disableScrolling(); 0327 } 0328 0329 void KHTMLImage::slotPopupMenu(const QPoint &global, const QUrl &url, mode_t mode, 0330 const KParts::OpenUrlArguments &origArgs, 0331 const KParts::BrowserArguments &browserArgs, 0332 KParts::BrowserExtension::PopupFlags flags, 0333 const KParts::BrowserExtension::ActionGroupMap &actionGroups) 0334 { 0335 KParts::OpenUrlArguments args = origArgs; 0336 args.setMimeType(m_mimeType); 0337 m_ext->popupMenu(global, url, mode, args, browserArgs, flags, actionGroups); 0338 } 0339