File indexing completed on 2024-03-24 15:32:32

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 
0340 #include "moc_khtmlimage.cpp"