Warning, file /frameworks/khtml/src/kmultipart/kmultipart.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 Copyright (C) 2002 David Faure <david@mandrakesoft.com> 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 "kmultipart.h" 0021 0022 #include "httpfiltergzip_p.h" 0023 #include <klocalizedstring.h> 0024 #include <kjobuidelegate.h> 0025 #include <kio/job.h> 0026 #include <QFile> 0027 #include <qtemporaryfile.h> 0028 #include <kmessagebox.h> 0029 #include <kmimetypetrader.h> 0030 #include <kpluginfactory.h> 0031 #include <khtml_part.h> 0032 #include <kxmlguifactory.h> 0033 #include <QTimer> 0034 #include <QVBoxLayout> 0035 #include <kaboutdata.h> 0036 0037 static KAboutData kmultipartAboutData() 0038 { 0039 KAboutData aboutData("kmultipart", i18n("KMultiPart"), 0040 "0.1", 0041 i18n("Embeddable component for multipart/mixed"), 0042 KAboutLicense::GPL, 0043 i18n("Copyright 2001-2011, David Faure <faure@kde.org>")); 0044 return aboutData; 0045 } 0046 0047 K_PLUGIN_FACTORY(KMultiPartFactory, registerPlugin<KMultiPart>();) 0048 0049 //#define DEBUG_PARSING 0050 0051 class KLineParser 0052 { 0053 public: 0054 KLineParser() 0055 { 0056 m_lineComplete = false; 0057 } 0058 void addChar(char c, bool storeNewline) 0059 { 0060 if (!storeNewline && c == '\r') { 0061 return; 0062 } 0063 Q_ASSERT(!m_lineComplete); 0064 if (storeNewline || c != '\n') { 0065 int sz = m_currentLine.size(); 0066 m_currentLine.resize(sz + 1); 0067 m_currentLine[sz] = c; 0068 } 0069 if (c == '\n') { 0070 m_lineComplete = true; 0071 } 0072 } 0073 bool isLineComplete() const 0074 { 0075 return m_lineComplete; 0076 } 0077 QByteArray currentLine() const 0078 { 0079 return m_currentLine; 0080 } 0081 void clearLine() 0082 { 0083 Q_ASSERT(m_lineComplete); 0084 reset(); 0085 } 0086 void reset() 0087 { 0088 m_currentLine.resize(0); 0089 m_lineComplete = false; 0090 } 0091 private: 0092 QByteArray m_currentLine; 0093 bool m_lineComplete; // true when ending with '\n' 0094 }; 0095 0096 /* testcase: 0097 Content-type: multipart/mixed;boundary=ThisRandomString 0098 0099 --ThisRandomString 0100 Content-type: text/plain 0101 0102 Data for the first object. 0103 0104 --ThisRandomString 0105 Content-type: text/plain 0106 0107 Data for the second and last object. 0108 0109 --ThisRandomString-- 0110 */ 0111 0112 KMultiPart::KMultiPart(QWidget *parentWidget, 0113 QObject *parent, const QVariantList &) 0114 : KParts::ReadOnlyPart(parent) 0115 { 0116 m_filter = nullptr; 0117 0118 setComponentData(kmultipartAboutData()); 0119 0120 QWidget *box = new QWidget(parentWidget); 0121 box->setLayout(new QVBoxLayout(box)); 0122 setWidget(box); 0123 0124 m_extension = new KParts::BrowserExtension(this); 0125 0126 m_part = nullptr; 0127 m_isHTMLPart = false; 0128 m_job = nullptr; 0129 m_lineParser = new KLineParser; 0130 m_tempFile = nullptr; 0131 0132 m_timer = new QTimer(this); 0133 connect(m_timer, SIGNAL(timeout()), this, SLOT(slotProgressInfo())); 0134 } 0135 0136 KMultiPart::~KMultiPart() 0137 { 0138 // important: delete the nested part before the part or qobject destructor runs. 0139 // we now delete the nested part which deletes the part's widget which makes 0140 // _OUR_ m_widget 0 which in turn avoids our part destructor to delete the 0141 // widget ;-) 0142 // ### additional note: it _can_ be that the part has been deleted before: 0143 // when we're in a html frameset and the view dies first, then it will also 0144 // kill the htmlpart 0145 if (m_part) { 0146 delete static_cast<KParts::ReadOnlyPart *>(m_part); 0147 } 0148 delete m_job; 0149 delete m_lineParser; 0150 if (m_tempFile) { 0151 m_tempFile->setAutoRemove(true); 0152 delete m_tempFile; 0153 } 0154 delete m_filter; 0155 m_filter = nullptr; 0156 } 0157 0158 void KMultiPart::startHeader() 0159 { 0160 m_bParsingHeader = true; // we expect a header to come first 0161 m_bGotAnyHeader = false; 0162 m_gzip = false; 0163 // just to be sure for now 0164 delete m_filter; 0165 m_filter = nullptr; 0166 } 0167 0168 bool KMultiPart::openUrl(const QUrl &url) 0169 { 0170 setUrl(url); 0171 m_lineParser->reset(); 0172 startHeader(); 0173 0174 //m_mimeType = arguments().mimeType(); 0175 0176 // Hmm, args.reload is set to true when reloading, but this doesn't seem to be enough... 0177 // I get "HOLD: Reusing held worker for <url>", and the old data 0178 0179 m_job = KIO::get(url, 0180 arguments().reload() ? KIO::Reload : KIO::NoReload, 0181 KIO::HideProgressInfo); 0182 0183 emit started(nullptr /*m_job*/); // don't pass the job, it would interfere with our own infoMessage 0184 0185 connect(m_job, SIGNAL(result(KJob*)), 0186 this, SLOT(slotJobFinished(KJob*))); 0187 connect(m_job, SIGNAL(data(KIO::Job*,QByteArray)), 0188 this, SLOT(slotData(KIO::Job*,QByteArray))); 0189 0190 m_numberOfFrames = 0; 0191 m_numberOfFramesSkipped = 0; 0192 m_totalNumberOfFrames = 0; 0193 m_qtime.start(); 0194 m_timer->start(1000); //1s 0195 0196 return true; 0197 } 0198 0199 // Yes, libkdenetwork's has such a parser already (MultiPart), 0200 // but it works on the complete string, expecting the whole data to be available.... 0201 // The version here is asynchronous. 0202 void KMultiPart::slotData(KIO::Job *job, const QByteArray &data) 0203 { 0204 if (m_boundary.isNull()) { 0205 QString tmp = job->queryMetaData("media-boundary"); 0206 // qCDebug(KHTML_LOG) << "Got Boundary from kio-http '" << tmp << "'"; 0207 if (!tmp.isEmpty()) { 0208 // as per r437578, sometimes we se something like this: 0209 // Content-Type: multipart/x-mixed-replace; boundary=--myboundary 0210 // .. 0211 // --myboundary 0212 // e.g. the hashes specified in the header are extra. However, 0213 // we also see the following on the w3c bugzilla: 0214 // boundary="------- =_aaaaaaaaaa0" 0215 // .. 0216 //--------- =_aaaaaaaaaa0 0217 // e.g. the hashes are accurate. For now, we consider the quoted 0218 // case to be quirk-free, and only apply the -- stripping quirk 0219 // when we're unquoted. 0220 if (tmp.startsWith(QLatin1String("--")) && 0221 job->queryMetaData("media-boundary-kio-quoted") != "true") { 0222 m_boundary = tmp.toLatin1(); 0223 } else { 0224 m_boundary = QByteArray("--") + tmp.toLatin1(); 0225 } 0226 m_boundaryLength = m_boundary.length(); 0227 } 0228 } 0229 // Append to m_currentLine until eol 0230 for (int i = 0; i < data.size(); ++i) { 0231 // Store char. Skip if '\n' and currently parsing a header. 0232 m_lineParser->addChar(data[i], !m_bParsingHeader); 0233 if (m_lineParser->isLineComplete()) { 0234 QByteArray line = m_lineParser->currentLine(); 0235 #ifdef DEBUG_PARSING 0236 // qCDebug(KHTML_LOG) << "line.size()=" << line.size(); 0237 #endif 0238 #ifdef DEBUG_PARSING 0239 // qCDebug(KHTML_LOG) << "[" << m_bParsingHeader << "] line='" << line << "'"; 0240 #endif 0241 if (m_bParsingHeader) { 0242 if (!line.isEmpty()) { 0243 m_bGotAnyHeader = true; 0244 } 0245 if (m_boundary.isNull()) { 0246 if (!line.isEmpty()) { 0247 #ifdef DEBUG_PARSING 0248 // qCDebug(KHTML_LOG) << "Boundary is " << line; 0249 #endif 0250 m_boundary = line; 0251 m_boundaryLength = m_boundary.length(); 0252 } 0253 } else if (!qstrnicmp(line.data(), "Content-Encoding:", 17)) { 0254 QString encoding = QString::fromLatin1(line.data() + 17).trimmed().toLower(); 0255 if (encoding == "gzip" || encoding == "x-gzip") { 0256 m_gzip = true; 0257 } else { 0258 // qCDebug(KHTML_LOG) << "FIXME: unhandled encoding type in KMultiPart: " << encoding; 0259 } 0260 } 0261 // parse Content-Type 0262 else if (!qstrnicmp(line.data(), "Content-Type:", 13)) { 0263 Q_ASSERT(m_nextMimeType.isNull()); 0264 m_nextMimeType = QString::fromLatin1(line.data() + 14).trimmed(); 0265 int semicolon = m_nextMimeType.indexOf(';'); 0266 if (semicolon != -1) { 0267 m_nextMimeType = m_nextMimeType.left(semicolon); 0268 } 0269 // qCDebug(KHTML_LOG) << "m_nextMimeType=" << m_nextMimeType; 0270 } 0271 // Empty line, end of headers (if we had any header line before) 0272 else if (line.isEmpty() && m_bGotAnyHeader) { 0273 m_bParsingHeader = false; 0274 #ifdef DEBUG_PARSING 0275 // qCDebug(KHTML_LOG) << "end of headers"; 0276 #endif 0277 startOfData(); 0278 } 0279 // First header (when we know it from kio_http) 0280 else if (line == m_boundary) 0281 ; // nothing to do 0282 else if (!line.isEmpty()) { // this happens with e.g. Set-Cookie: 0283 // qCDebug(KHTML_LOG) << "Ignoring header " << line; 0284 } 0285 } else { 0286 if (!qstrncmp(line, m_boundary, m_boundaryLength)) { 0287 #ifdef DEBUG_PARSING 0288 // qCDebug(KHTML_LOG) << "boundary found!"; 0289 // qCDebug(KHTML_LOG) << "after it is " << line.data() + m_boundaryLength; 0290 #endif 0291 // Was it the very last boundary ? 0292 if (!qstrncmp(line.data() + m_boundaryLength, "--", 2)) { 0293 #ifdef DEBUG_PARSING 0294 // qCDebug(KHTML_LOG) << "Completed!"; 0295 #endif 0296 endOfData(); 0297 emit completed(); 0298 } else { 0299 char nextChar = *(line.data() + m_boundaryLength); 0300 #ifdef DEBUG_PARSING 0301 // qCDebug(KHTML_LOG) << "KMultiPart::slotData nextChar='" << nextChar << "'"; 0302 #endif 0303 if (nextChar == '\n' || nextChar == '\r') { 0304 endOfData(); 0305 startHeader(); 0306 } else { 0307 // otherwise, false hit, it has trailing stuff 0308 sendData(line); 0309 } 0310 } 0311 } else { 0312 // send to part 0313 sendData(line); 0314 } 0315 } 0316 m_lineParser->clearLine(); 0317 } 0318 } 0319 } 0320 0321 void KMultiPart::setPart(const QString &mimeType) 0322 { 0323 KXMLGUIFactory *guiFactory = factory(); 0324 if (guiFactory) { // seems to be 0 when restoring from SM 0325 guiFactory->removeClient(this); 0326 } 0327 // qCDebug(KHTML_LOG) << "KMultiPart::setPart " << mimeType; 0328 delete m_part; 0329 // Try to find an appropriate viewer component 0330 m_part = KMimeTypeTrader::createPartInstanceFromQuery<KParts::ReadOnlyPart> 0331 (m_mimeType, widget(), this); 0332 widget()->layout()->addWidget(m_part->widget()); 0333 if (!m_part) { 0334 // TODO launch external app 0335 KMessageBox::error(widget(), i18n("No handler found for %1.", m_mimeType)); 0336 return; 0337 } 0338 // By making the part a child XMLGUIClient of ours, we get its GUI merged in. 0339 insertChildClient(m_part); 0340 m_part->widget()->show(); 0341 0342 connect(m_part, SIGNAL(completed()), 0343 this, SLOT(slotPartCompleted())); 0344 connect(m_part, SIGNAL(completed(bool)), 0345 this, SLOT(slotPartCompleted())); 0346 0347 m_isHTMLPart = (mimeType == "text/html"); 0348 KParts::BrowserExtension *childExtension = KParts::BrowserExtension::childObject(m_part); 0349 0350 if (childExtension) { 0351 0352 // Forward signals from the part's browser extension 0353 // this is very related (but not exactly like) KHTMLPart::processObjectRequest 0354 0355 connect(childExtension, SIGNAL(openUrlNotify()), 0356 m_extension, SIGNAL(openUrlNotify())); 0357 0358 connect(childExtension, SIGNAL(openUrlRequestDelayed(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments)), 0359 m_extension, SIGNAL(openUrlRequest(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments))); 0360 0361 connect(childExtension, SIGNAL(createNewWindow(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::WindowArgs,KParts::ReadOnlyPart**)), 0362 m_extension, SIGNAL(createNewWindow(QUrl,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::WindowArgs,KParts::ReadOnlyPart**))); 0363 0364 // Keep in sync with khtml_part.cpp 0365 connect(childExtension, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), 0366 m_extension, SIGNAL(popupMenu(QPoint,KFileItemList,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap))); 0367 connect(childExtension, SIGNAL(popupMenu(QPoint,QUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap)), 0368 m_extension, SIGNAL(popupMenu(QPoint,QUrl,mode_t,KParts::OpenUrlArguments,KParts::BrowserArguments,KParts::BrowserExtension::PopupFlags,KParts::BrowserExtension::ActionGroupMap))); 0369 0370 if (m_isHTMLPart) 0371 connect(childExtension, SIGNAL(infoMessage(QString)), 0372 m_extension, SIGNAL(infoMessage(QString))); 0373 // For non-HTML we prefer to show our infoMessage ourselves. 0374 0375 childExtension->setBrowserInterface(m_extension->browserInterface()); 0376 0377 connect(childExtension, SIGNAL(enableAction(const char*,bool)), 0378 m_extension, SIGNAL(enableAction(const char*,bool))); 0379 connect(childExtension, SIGNAL(setLocationBarUrl(QString)), 0380 m_extension, SIGNAL(setLocationBarUrl(QString))); 0381 connect(childExtension, SIGNAL(setIconUrl(QUrl)), 0382 m_extension, SIGNAL(setIconUrl(QUrl))); 0383 connect(childExtension, SIGNAL(loadingProgress(int)), 0384 m_extension, SIGNAL(loadingProgress(int))); 0385 if (m_isHTMLPart) // for non-HTML we have our own 0386 connect(childExtension, SIGNAL(speedProgress(int)), 0387 m_extension, SIGNAL(speedProgress(int))); 0388 connect(childExtension, SIGNAL(selectionInfo(KFileItemList)), 0389 m_extension, SIGNAL(selectionInfo(KFileItemList))); 0390 connect(childExtension, SIGNAL(selectionInfo(QString)), 0391 m_extension, SIGNAL(selectionInfo(QString))); 0392 connect(childExtension, SIGNAL(selectionInfo(QList<QUrl>)), 0393 m_extension, SIGNAL(selectionInfo(QList<QUrl>))); 0394 connect(childExtension, SIGNAL(mouseOverInfo(KFileItem)), 0395 m_extension, SIGNAL(mouseOverInfo(KFileItem))); 0396 connect(childExtension, SIGNAL(moveTopLevelWidget(int,int)), 0397 m_extension, SIGNAL(moveTopLevelWidget(int,int))); 0398 connect(childExtension, SIGNAL(resizeTopLevelWidget(int,int)), 0399 m_extension, SIGNAL(resizeTopLevelWidget(int,int))); 0400 } 0401 0402 m_partIsLoading = false; 0403 // Load the part's plugins too. 0404 // ###### This is a hack. The bug is that KHTMLPart doesn't load its plugins 0405 // if className != "Browser/View". 0406 loadPlugins(this, m_part, m_part->componentData()); 0407 // Get the part's GUI to appear 0408 if (guiFactory) { 0409 guiFactory->addClient(this); 0410 } 0411 } 0412 0413 void KMultiPart::startOfData() 0414 { 0415 // qCDebug(KHTML_LOG) << "KMultiPart::startOfData"; 0416 Q_ASSERT(!m_nextMimeType.isNull()); 0417 if (m_nextMimeType.isNull()) { 0418 return; 0419 } 0420 0421 if (m_gzip) { 0422 // We can't use KFilterDev because it assumes it can read as much data as necessary 0423 // from the underlying device. It's a pull strategy, while KMultiPart has to do 0424 // a push strategy. 0425 m_filter = new HTTPFilterGZip; 0426 connect(m_filter, SIGNAL(output(QByteArray)), this, SLOT(reallySendData(QByteArray))); 0427 } 0428 0429 if (m_mimeType != m_nextMimeType) { 0430 // Need to switch parts (or create the initial one) 0431 m_mimeType = m_nextMimeType; 0432 setPart(m_mimeType); 0433 } 0434 Q_ASSERT(m_part); 0435 // Pass args (e.g. reload) 0436 m_part->setArguments(arguments()); 0437 KParts::BrowserExtension *childExtension = KParts::BrowserExtension::childObject(m_part); 0438 if (childExtension) { 0439 childExtension->setBrowserArguments(m_extension->browserArguments()); 0440 } 0441 0442 m_nextMimeType.clear(); 0443 if (m_tempFile) { 0444 m_tempFile->setAutoRemove(true); 0445 delete m_tempFile; 0446 m_tempFile = nullptr; 0447 } 0448 if (m_isHTMLPart) { 0449 KHTMLPart *htmlPart = static_cast<KHTMLPart *>(static_cast<KParts::ReadOnlyPart *>(m_part)); 0450 htmlPart->begin(url()); 0451 } else { 0452 // ###### TODO use a QByteArray and a data: URL instead 0453 m_tempFile = new QTemporaryFile; 0454 m_tempFile->open(); 0455 } 0456 } 0457 0458 void KMultiPart::sendData(const QByteArray &line) 0459 { 0460 if (m_filter) { 0461 m_filter->slotInput(line); 0462 } else { 0463 reallySendData(line); 0464 } 0465 } 0466 0467 void KMultiPart::reallySendData(const QByteArray &line) 0468 { 0469 if (m_isHTMLPart) { 0470 KHTMLPart *htmlPart = static_cast<KHTMLPart *>(static_cast<KParts::ReadOnlyPart *>(m_part)); 0471 htmlPart->write(line.data(), line.size()); 0472 } else if (m_tempFile) { 0473 m_tempFile->write(line.data(), line.size()); 0474 } 0475 } 0476 0477 void KMultiPart::endOfData() 0478 { 0479 Q_ASSERT(m_part); 0480 if (m_isHTMLPart) { 0481 KHTMLPart *htmlPart = static_cast<KHTMLPart *>(static_cast<KParts::ReadOnlyPart *>(m_part)); 0482 htmlPart->end(); 0483 } else if (m_tempFile) { 0484 const QString tempFileName = m_tempFile->fileName(); 0485 m_tempFile->close(); 0486 if (m_partIsLoading) { 0487 // The part is still loading the last data! Let it proceed then 0488 // Otherwise we'd keep canceling it, and nothing would ever show up... 0489 // qCDebug(KHTML_LOG) << "KMultiPart::endOfData part isn't ready, skipping frame"; 0490 ++m_numberOfFramesSkipped; 0491 m_tempFile->setAutoRemove(true); 0492 } else { 0493 // qCDebug(KHTML_LOG) << "KMultiPart::endOfData opening " << tempFileName; 0494 QUrl url(tempFileName); 0495 m_partIsLoading = true; 0496 (void) m_part->openUrl(url); 0497 } 0498 delete m_tempFile; 0499 m_tempFile = nullptr; 0500 } 0501 } 0502 0503 void KMultiPart::slotPartCompleted() 0504 { 0505 if (!m_isHTMLPart) { 0506 Q_ASSERT(m_part); 0507 // Delete temp file used by the part 0508 Q_ASSERT(m_part->url().isLocalFile()); 0509 // qCDebug(KHTML_LOG) << "slotPartCompleted deleting " << m_part->url().toLocalFile(); 0510 (void) unlink(QFile::encodeName(m_part->url().toLocalFile())); 0511 m_partIsLoading = false; 0512 ++m_numberOfFrames; 0513 // Do not emit completed from here. 0514 } 0515 } 0516 0517 bool KMultiPart::closeUrl() 0518 { 0519 m_timer->stop(); 0520 if (m_part) { 0521 return m_part->closeUrl(); 0522 } 0523 return true; 0524 } 0525 0526 void KMultiPart::guiActivateEvent(KParts::GUIActivateEvent *) 0527 { 0528 // Not public! 0529 //if ( m_part ) 0530 // m_part->guiActivateEvent( e ); 0531 } 0532 0533 void KMultiPart::slotJobFinished(KJob *job) 0534 { 0535 if (job->error()) { 0536 // TODO use khtml's error:// scheme 0537 job->uiDelegate()->showErrorMessage(); 0538 emit canceled(job->errorString()); 0539 } else { 0540 /*if ( m_khtml->view()->contentsY() == 0 ) 0541 { 0542 const KParts::OpenUrlArguments args = arguments(); 0543 m_khtml->view()->setContentsPos( args.xOffset(), args.yOffset() ); 0544 }*/ 0545 0546 emit completed(); 0547 0548 //QTimer::singleShot( 0, this, SLOT(updateWindowCaption()) ); 0549 } 0550 m_job = nullptr; 0551 } 0552 0553 void KMultiPart::slotProgressInfo() 0554 { 0555 int time = m_qtime.elapsed(); 0556 if (!time) { 0557 return; 0558 } 0559 if (m_totalNumberOfFrames == m_numberOfFrames + m_numberOfFramesSkipped) { 0560 return; // No change, don't overwrite statusbar messages if any 0561 } 0562 //qCDebug(KHTML_LOG) << m_numberOfFrames << " in " << time << " milliseconds"; 0563 QString str("%1 frames per second, %2 frames skipped per second"); 0564 str = str.arg(1000.0 * (double)m_numberOfFrames / (double)time); 0565 str = str.arg(1000.0 * (double)m_numberOfFramesSkipped / (double)time); 0566 m_totalNumberOfFrames = m_numberOfFrames + m_numberOfFramesSkipped; 0567 //qCDebug(KHTML_LOG) << str; 0568 emit m_extension->infoMessage(str); 0569 } 0570 0571 #if 0 0572 KMultiPartBrowserExtension::KMultiPartBrowserExtension(KMultiPart *parent, const char *name) 0573 : KParts::BrowserExtension(parent, name) 0574 { 0575 m_imgPart = parent; 0576 } 0577 0578 int KMultiPartBrowserExtension::xOffset() 0579 { 0580 return m_imgPart->doc()->view()->contentsX(); 0581 } 0582 0583 int KMultiPartBrowserExtension::yOffset() 0584 { 0585 return m_imgPart->doc()->view()->contentsY(); 0586 } 0587 0588 void KMultiPartBrowserExtension::print() 0589 { 0590 static_cast<KHTMLPartBrowserExtension *>(m_imgPart->doc()->browserExtension())->print(); 0591 } 0592 0593 void KMultiPartBrowserExtension::reparseConfiguration() 0594 { 0595 static_cast<KHTMLPartBrowserExtension *>(m_imgPart->doc()->browserExtension())->reparseConfiguration(); 0596 m_imgPart->doc()->setAutoloadImages(true); 0597 } 0598 #endif 0599 0600 #include "kmultipart.moc" 0601 0602 #include "moc_kmultipart.cpp"