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