00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
#include "kmultipart.h"
00021
00022
#include <qvbox.h>
00023
#include <kinstance.h>
00024
#include <kmimetype.h>
00025
#include <klocale.h>
00026
#include <kio/job.h>
00027
#include <qfile.h>
00028
#include <ktempfile.h>
00029
#include <kmessagebox.h>
00030
#include <kparts/componentfactory.h>
00031
#include <kparts/genericfactory.h>
00032
#include <khtml_part.h>
00033
#include <unistd.h>
00034
#include <kxmlguifactory.h>
00035
#include <qtimer.h>
00036
00037
typedef KParts::GenericFactory<KMultiPart> KMultiPartFactory;
00038 K_EXPORT_COMPONENT_FACTORY( libkmultipart , KMultiPartFactory )
00039
00040
00041
00042 class KLineParser
00043 {
00044
public:
00045 KLineParser() {
00046 m_lineComplete =
false;
00047 }
00048
void addChar(
char c,
bool storeNewline ) {
00049
if ( !storeNewline && c ==
'\r' )
00050
return;
00051 Q_ASSERT( !m_lineComplete );
00052
if ( storeNewline || c !=
'\n' ) {
00053
int sz = m_currentLine.size();
00054 m_currentLine.resize( sz+1, QGArray::SpeedOptim );
00055 m_currentLine[sz] = c;
00056 }
00057
if ( c ==
'\n' )
00058 m_lineComplete =
true;
00059 }
00060
bool isLineComplete()
const {
00061
return m_lineComplete;
00062 }
00063
QByteArray currentLine()
const {
00064
return m_currentLine;
00065 }
00066
void clearLine() {
00067 Q_ASSERT( m_lineComplete );
00068 reset();
00069 }
00070
void reset() {
00071 m_currentLine.resize( 0, QGArray::SpeedOptim );
00072 m_lineComplete =
false;
00073 }
00074
private:
00075
QByteArray m_currentLine;
00076
bool m_lineComplete;
00077 };
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 KMultiPart::KMultiPart(
QWidget *parentWidget,
const char *widgetName,
00097
QObject *parent,
const char *name,
const QStringList& )
00098 : KParts::ReadOnlyPart( parent,
name )
00099 {
00100 m_filter = 0L;
00101
00102 setInstance( KMultiPartFactory::instance() );
00103
00104
QVBox *box =
new QVBox( parentWidget, widgetName );
00105 setWidget( box );
00106
00107 m_extension =
new KParts::BrowserExtension(
this );
00108
00109
00110
00111 m_part = 0L;
00112 m_job = 0L;
00113 m_lineParser =
new KLineParser;
00114 m_tempFile = 0L;
00115
00116 m_timer =
new QTimer(
this );
00117 connect( m_timer, SIGNAL( timeout() ),
this, SLOT( slotProgressInfo() ) );
00118 }
00119
00120 KMultiPart::~KMultiPart()
00121 {
00122
00123
00124
00125
00126
00127
00128
00129
if ( m_part )
00130
delete static_cast<KParts::ReadOnlyPart *>( m_part );
00131
delete m_job;
00132
delete m_lineParser;
00133
if ( m_tempFile ) {
00134 m_tempFile->
setAutoDelete(
true );
00135
delete m_tempFile;
00136 }
00137
delete m_filter;
00138 m_filter = 0L;
00139 }
00140
00141
00142
void KMultiPart::startHeader()
00143 {
00144 m_bParsingHeader =
true;
00145 m_bGotAnyHeader =
false;
00146 m_gzip =
false;
00147
00148
delete m_filter;
00149 m_filter = 0L;
00150 }
00151
00152
00153
bool KMultiPart::openURL(
const KURL &url )
00154 {
00155
m_url = url;
00156 m_lineParser->reset();
00157 startHeader();
00158
00159
KParts::URLArgs args = m_extension->
urlArgs();
00160
00161
00162
00163
00164
00165 m_job =
KIO::get( url, args.
reload,
false );
00166
00167 emit
started( 0 );
00168
00169 connect( m_job, SIGNAL( result(
KIO::Job * ) ),
00170
this, SLOT(
slotJobFinished(
KIO::Job * ) ) );
00171 connect( m_job, SIGNAL( data(
KIO::Job *,
const QByteArray & ) ),
00172
this, SLOT( slotData(
KIO::Job *,
const QByteArray & ) ) );
00173
00174 m_numberOfFrames = 0;
00175 m_numberOfFramesSkipped = 0;
00176 m_totalNumberOfFrames = 0;
00177 m_qtime.start();
00178 m_timer->start( 1000 );
00179
00180
return true;
00181 }
00182
00183
00184
00185
00186
void KMultiPart::slotData(
KIO::Job *job,
const QByteArray &data )
00187 {
00188
if (m_boundary.isNull())
00189 {
00190
QString tmp = job->
queryMetaData(
"media-boundary");
00191
kdDebug() <<
"Got Boundary from kio-http '" << tmp <<
"'" <<
endl;
00192
if ( !tmp.isEmpty() ) {
00193 m_boundary =
QCString(
"--")+tmp.latin1();
00194 m_boundaryLength = m_boundary.length();
00195 }
00196 }
00197
00198
for ( uint i = 0; i < data.size() ; ++i )
00199 {
00200
00201 m_lineParser->addChar( data[i], !m_bParsingHeader );
00202
if ( m_lineParser->isLineComplete() )
00203 {
00204
QByteArray lineData = m_lineParser->currentLine();
00205
#ifdef DEBUG_PARSING
00206
kdDebug() <<
"lineData.size()=" << lineData.size() <<
endl;
00207
#endif
00208
QCString line( lineData.data(), lineData.size()+1 );
00209
00210
00211
int sz = line.size();
00212
if ( sz > 0 )
00213 line[sz-1] =
'\0';
00214
#ifdef DEBUG_PARSING
00215
kdDebug() <<
"[" << m_bParsingHeader <<
"] line='" << line <<
"'" <<
endl;
00216
#endif
00217
if ( m_bParsingHeader )
00218 {
00219
if ( !line.isEmpty() )
00220 m_bGotAnyHeader =
true;
00221
if ( m_boundary.isNull() )
00222 {
00223
if ( !line.isEmpty() ) {
00224
#ifdef DEBUG_PARSING
00225
kdDebug() <<
"Boundary is " << line <<
endl;
00226
#endif
00227
m_boundary = line;
00228 m_boundaryLength = m_boundary.length();
00229 }
00230 }
00231
else if ( !qstrnicmp( line.data(),
"Content-Encoding:", 17 ) )
00232 {
00233
QString encoding = QString::fromLatin1(line.data()+17).stripWhiteSpace().lower();
00234
if (encoding ==
"gzip" || encoding ==
"x-gzip") {
00235 m_gzip =
true;
00236 }
else {
00237
kdDebug() <<
"FIXME: unhandled encoding type in KMultiPart: " << encoding <<
endl;
00238 }
00239 }
00240
00241
else if ( !qstrnicmp( line.data(),
"Content-Type:", 13 ) )
00242 {
00243 Q_ASSERT( m_nextMimeType.isNull() );
00244 m_nextMimeType = QString::fromLatin1( line.data() + 14 ).stripWhiteSpace();
00245
kdDebug() <<
"m_nextMimeType=" << m_nextMimeType <<
endl;
00246 }
00247
00248
else if ( line.isEmpty() && m_bGotAnyHeader )
00249 {
00250 m_bParsingHeader =
false;
00251
#ifdef DEBUG_PARSING
00252
kdDebug() <<
"end of headers" <<
endl;
00253
#endif
00254
startOfData();
00255 }
00256
00257
else if ( line == m_boundary )
00258 ;
00259
else if ( !line.isEmpty() )
00260
kdDebug() <<
"Ignoring header " << line <<
endl;
00261 }
else {
00262
if ( !qstrncmp( line, m_boundary, m_boundaryLength ) )
00263 {
00264
#ifdef DEBUG_PARSING
00265
kdDebug() <<
"boundary found!" <<
endl;
00266
kdDebug() <<
"after it is " << line.data() + m_boundaryLength <<
endl;
00267
#endif
00268
00269
if ( !qstrncmp( line.data() + m_boundaryLength,
"--", 2 ) )
00270 {
00271
#ifdef DEBUG_PARSING
00272
kdDebug() <<
"Completed!" <<
endl;
00273
#endif
00274
endOfData();
00275 emit
completed();
00276 }
else
00277 {
00278
char nextChar = *(line.data() + m_boundaryLength);
00279
#ifdef DEBUG_PARSING
00280
kdDebug() <<
"KMultiPart::slotData nextChar='" << nextChar <<
"'" <<
endl;
00281
#endif
00282
if ( nextChar ==
'\n' || nextChar ==
'\r' ) {
00283 endOfData();
00284 startHeader();
00285 }
00286
else {
00287
00288 sendData( lineData );
00289 }
00290 }
00291 }
else {
00292
00293 sendData( lineData );
00294 }
00295 }
00296 m_lineParser->clearLine();
00297 }
00298 }
00299 }
00300
00301
void KMultiPart::setPart(
const QString& mimeType )
00302 {
00303
KXMLGUIFactory *guiFactory =
factory();
00304
if ( guiFactory )
00305 guiFactory->
removeClient(
this );
00306
kdDebug() <<
"KMultiPart::setPart " << mimeType <<
endl;
00307
delete m_part;
00308
00309 m_part = KParts::ComponentFactory::createPartInstanceFromQuery<KParts::ReadOnlyPart>
00310 ( m_mimeType, QString::null,
widget(), 0L,
this, 0L );
00311
if ( !m_part ) {
00312
00313
KMessageBox::error(
widget(), i18n(
"No handler found for %1!").arg(m_mimeType) );
00314
return;
00315 }
00316
00317
insertChildClient( m_part );
00318 m_part->widget()->show();
00319
00320 connect( m_part, SIGNAL(
completed() ),
00321
this, SLOT( slotPartCompleted() ) );
00322
00323 m_isHTMLPart = ( mimeType ==
"text/html" );
00324
KParts::BrowserExtension* childExtension =
KParts::BrowserExtension::childObject( m_part );
00325
00326
if ( childExtension )
00327 {
00328
00329
00330
00331
00332 connect( childExtension, SIGNAL( openURLNotify() ),
00333 m_extension, SIGNAL( openURLNotify() ) );
00334
00335 connect( childExtension, SIGNAL( openURLRequestDelayed(
const KURL &,
const KParts::URLArgs & ) ),
00336 m_extension, SIGNAL( openURLRequest(
const KURL &,
const KParts::URLArgs & ) ) );
00337
00338 connect( childExtension, SIGNAL( createNewWindow(
const KURL &,
const KParts::URLArgs & ) ),
00339 m_extension, SIGNAL( createNewWindow(
const KURL &,
const KParts::URLArgs & ) ) );
00340 connect( childExtension, SIGNAL( createNewWindow(
const KURL &,
const KParts::URLArgs &,
const KParts::WindowArgs &,
KParts::ReadOnlyPart *& ) ),
00341 m_extension, SIGNAL( createNewWindow(
const KURL &,
const KParts::URLArgs & ,
const KParts::WindowArgs &,
KParts::ReadOnlyPart *&) ) );
00342
00343
00344 connect( childExtension, SIGNAL( popupMenu(
const QPoint &,
const KFileItemList & ) ),
00345 m_extension, SIGNAL( popupMenu(
const QPoint &,
const KFileItemList & ) ) );
00346 connect( childExtension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KFileItemList & ) ),
00347 m_extension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KFileItemList & ) ) );
00348 connect( childExtension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KFileItemList &,
const KParts::URLArgs &,
KParts::BrowserExtension::PopupFlags ) ),
00349 m_extension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KFileItemList &,
const KParts::URLArgs &,
KParts::BrowserExtension::PopupFlags ) ) );
00350 connect( childExtension, SIGNAL( popupMenu(
const QPoint &,
const KURL &,
const QString &, mode_t ) ),
00351 m_extension, SIGNAL( popupMenu(
const QPoint &,
const KURL &,
const QString &, mode_t ) ) );
00352 connect( childExtension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KURL &,
const QString &, mode_t ) ),
00353 m_extension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KURL &,
const QString &, mode_t ) ) );
00354 connect( childExtension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KURL &,
const KParts::URLArgs &,
KParts::BrowserExtension::PopupFlags, mode_t ) ),
00355 m_extension, SIGNAL( popupMenu(
KXMLGUIClient *,
const QPoint &,
const KURL &,
const KParts::URLArgs &,
KParts::BrowserExtension::PopupFlags, mode_t ) ) );
00356
00357
00358
if ( m_isHTMLPart )
00359 connect( childExtension, SIGNAL( infoMessage(
const QString & ) ),
00360 m_extension, SIGNAL( infoMessage(
const QString & ) ) );
00361
00362
00363 childExtension->
setBrowserInterface( m_extension->
browserInterface() );
00364
00365 connect( childExtension, SIGNAL( enableAction(
const char *,
bool ) ),
00366 m_extension, SIGNAL( enableAction(
const char *,
bool ) ) );
00367 connect( childExtension, SIGNAL( setLocationBarURL(
const QString& ) ),
00368 m_extension, SIGNAL( setLocationBarURL(
const QString& ) ) );
00369 connect( childExtension, SIGNAL( setIconURL(
const KURL& ) ),
00370 m_extension, SIGNAL( setIconURL(
const KURL& ) ) );
00371 connect( childExtension, SIGNAL( loadingProgress(
int ) ),
00372 m_extension, SIGNAL( loadingProgress(
int ) ) );
00373
if ( m_isHTMLPart )
00374 connect( childExtension, SIGNAL( speedProgress(
int ) ),
00375 m_extension, SIGNAL( speedProgress(
int ) ) );
00376 connect( childExtension, SIGNAL( selectionInfo(
const KFileItemList& ) ),
00377 m_extension, SIGNAL( selectionInfo(
const KFileItemList& ) ) );
00378 connect( childExtension, SIGNAL( selectionInfo(
const QString& ) ),
00379 m_extension, SIGNAL( selectionInfo(
const QString& ) ) );
00380 connect( childExtension, SIGNAL( selectionInfo(
const KURL::List& ) ),
00381 m_extension, SIGNAL( selectionInfo(
const KURL::List& ) ) );
00382 connect( childExtension, SIGNAL( mouseOverInfo(
const KFileItem* ) ),
00383 m_extension, SIGNAL( mouseOverInfo(
const KFileItem* ) ) );
00384 connect( childExtension, SIGNAL( moveTopLevelWidget(
int,
int ) ),
00385 m_extension, SIGNAL( moveTopLevelWidget(
int,
int ) ) );
00386 connect( childExtension, SIGNAL( resizeTopLevelWidget(
int,
int ) ),
00387 m_extension, SIGNAL( resizeTopLevelWidget(
int,
int ) ) );
00388 }
00389
00390 m_partIsLoading =
false;
00391
00392
00393
00394
loadPlugins(
this, m_part, m_part->instance() );
00395
00396
if ( guiFactory )
00397 guiFactory->
addClient(
this );
00398 }
00399
00400
void KMultiPart::startOfData()
00401 {
00402
kdDebug() <<
"KMultiPart::startOfData" <<
endl;
00403 Q_ASSERT( !m_nextMimeType.isNull() );
00404
if( m_nextMimeType.isNull() )
00405
return;
00406
00407
if ( m_gzip )
00408 {
00409 m_filter =
new HTTPFilterGZip;
00410 connect( m_filter, SIGNAL( output(
const QByteArray& ) ),
this, SLOT( reallySendData(
const QByteArray& ) ) );
00411 }
00412
00413
if ( m_mimeType != m_nextMimeType )
00414 {
00415
00416 m_mimeType = m_nextMimeType;
00417 setPart( m_mimeType );
00418 }
00419 Q_ASSERT( m_part );
00420
00421
KParts::BrowserExtension* childExtension =
KParts::BrowserExtension::childObject( m_part );
00422
if ( childExtension )
00423 childExtension->
setURLArgs( m_extension->
urlArgs() );
00424
00425 m_nextMimeType = QString::null;
00426
if ( m_tempFile ) {
00427 m_tempFile->
setAutoDelete(
true );
00428
delete m_tempFile;
00429 m_tempFile = 0;
00430 }
00431
if ( m_isHTMLPart )
00432 {
00433
KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00434 htmlPart->
begin(
url() );
00435 }
00436
else
00437 {
00438
00439 m_tempFile =
new KTempFile;
00440 }
00441 }
00442
00443
void KMultiPart::sendData(
const QByteArray& line )
00444 {
00445
if ( m_filter )
00446 {
00447 m_filter->slotInput( line );
00448 }
00449
else
00450 {
00451 reallySendData( line );
00452 }
00453 }
00454
00455
void KMultiPart::reallySendData(
const QByteArray& line )
00456 {
00457
if ( m_isHTMLPart )
00458 {
00459
KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00460 htmlPart->
write( line.data(), line.size() );
00461 }
00462
else if ( m_tempFile )
00463 {
00464 m_tempFile->
file()->writeBlock( line.data(), line.size() );
00465 }
00466 }
00467
00468
void KMultiPart::endOfData()
00469 {
00470 Q_ASSERT( m_part );
00471
if ( m_isHTMLPart )
00472 {
00473
KHTMLPart* htmlPart = static_cast<KHTMLPart *>( static_cast<KParts::ReadOnlyPart *>( m_part ) );
00474 htmlPart->
end();
00475 }
else if ( m_tempFile )
00476 {
00477 m_tempFile->
close();
00478
if ( m_partIsLoading )
00479 {
00480
00481
00482
kdDebug() <<
"KMultiPart::endOfData part isn't ready, skipping frame" <<
endl;
00483 ++m_numberOfFramesSkipped;
00484 m_tempFile->
setAutoDelete(
true );
00485 }
00486
else
00487 {
00488
kdDebug() <<
"KMultiPart::endOfData opening " << m_tempFile->
name() <<
endl;
00489
KURL url;
00490 url.
setPath( m_tempFile->
name() );
00491 m_partIsLoading =
true;
00492 (
void) m_part->openURL( url );
00493 }
00494
delete m_tempFile;
00495 m_tempFile = 0L;
00496 }
00497 }
00498
00499
void KMultiPart::slotPartCompleted()
00500 {
00501
if ( !m_isHTMLPart )
00502 {
00503 Q_ASSERT( m_part );
00504
00505 Q_ASSERT( m_part->url().isLocalFile() );
00506
kdDebug() <<
"slotPartCompleted deleting " << m_part->url().path() <<
endl;
00507 (
void) unlink( QFile::encodeName( m_part->url().path() ) );
00508 m_partIsLoading =
false;
00509 ++m_numberOfFrames;
00510
00511 }
00512 }
00513
00514
bool KMultiPart::closeURL()
00515 {
00516 m_timer->stop();
00517
if ( m_part )
00518
return m_part->closeURL();
00519
return true;
00520 }
00521
00522
void KMultiPart::guiActivateEvent(
KParts::GUIActivateEvent * )
00523 {
00524
00525
00526
00527 }
00528
00529
void KMultiPart::slotJobFinished(
KIO::Job *job )
00530 {
00531
if ( job->
error() )
00532 {
00533
00534 job->
showErrorDialog();
00535 emit
canceled( job->
errorString() );
00536 }
00537
else
00538 {
00539
00540
00541
00542
00543
00544
00545 emit
completed();
00546
00547
00548 }
00549 m_job = 0L;
00550 }
00551
00552
void KMultiPart::slotProgressInfo()
00553 {
00554
int time = m_qtime.elapsed();
00555
if ( !time )
return;
00556
if ( m_totalNumberOfFrames == m_numberOfFrames + m_numberOfFramesSkipped )
00557
return;
00558
00559
QString str(
"%1 frames per second, %2 frames skipped per second" );
00560 str = str.arg( 1000.0 * (
double)m_numberOfFrames / (
double)time );
00561 str = str.arg( 1000.0 * (
double)m_numberOfFramesSkipped / (
double)time );
00562 m_totalNumberOfFrames = m_numberOfFrames + m_numberOfFramesSkipped;
00563
00564 emit m_extension->
infoMessage( str );
00565 }
00566
00567
KAboutData* KMultiPart::createAboutData()
00568 {
00569
KAboutData* aboutData =
new KAboutData(
"kmultipart",
I18N_NOOP(
"KMultiPart"),
00570
"0.1",
00571
I18N_NOOP(
"Embeddable component for multipart/mixed" ),
00572 KAboutData::License_GPL,
00573
"(c) 2001, David Faure <david@mandrakesoft.com>");
00574
return aboutData;
00575 }
00576
00577
#if 0
00578
KMultiPartBrowserExtension::KMultiPartBrowserExtension(
KMultiPart *parent,
const char *name )
00579 : KParts::BrowserExtension( parent,
name )
00580 {
00581 m_imgPart = parent;
00582 }
00583
00584
int KMultiPartBrowserExtension::xOffset()
00585 {
00586
return m_imgPart->doc()->view()->contentsX();
00587 }
00588
00589
int KMultiPartBrowserExtension::yOffset()
00590 {
00591
return m_imgPart->doc()->view()->contentsY();
00592 }
00593
00594
void KMultiPartBrowserExtension::print()
00595 {
00596 static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->print();
00597 }
00598
00599
void KMultiPartBrowserExtension::reparseConfiguration()
00600 {
00601 static_cast<KHTMLPartBrowserExtension *>( m_imgPart->doc()->browserExtension() )->reparseConfiguration();
00602 m_imgPart->doc()->setAutoloadImages(
true );
00603 }
00604
#endif
00605
00606
#include "kmultipart.moc"