KParts
browserrun.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 * 00003 * Copyright (C) 2002 David Faure <faure@kde.org> 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Library General Public 00006 * License version 2, as published by the Free Software Foundation. 00007 * 00008 * This library is distributed in the hope that it will be useful, 00009 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 * Library General Public License for more details. 00012 * 00013 * You should have received a copy of the GNU Library General Public License 00014 * along with this library; see the file COPYING.LIB. If not, write to 00015 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 * Boston, MA 02110-1301, USA. 00017 */ 00018 00019 #include "browserrun.h" 00020 #include "browserrun_p.h" 00021 00022 #include <kmessagebox.h> 00023 #include <kfiledialog.h> 00024 #include <kio/job.h> 00025 #include <kio/jobuidelegate.h> 00026 #include <kio/scheduler.h> 00027 #include <kio/copyjob.h> 00028 #include <klocale.h> 00029 #include <kshell.h> 00030 #include <kstringhandler.h> 00031 #include <kmimetypetrader.h> 00032 #include <ktemporaryfile.h> 00033 #include <kdebug.h> 00034 #include <kde_file.h> 00035 #include <kstandarddirs.h> 00036 #include <kdatetime.h> 00037 #include "browseropenorsavequestion.h" 00038 #include <kprotocolmanager.h> 00039 00040 using namespace KParts; 00041 00042 class BrowserRun::BrowserRunPrivate 00043 { 00044 public: 00045 bool m_bHideErrorDialog; 00046 bool m_bRemoveReferrer; 00047 bool m_bTrustedSource; 00048 KParts::OpenUrlArguments m_args; 00049 KParts::BrowserArguments m_browserArgs; 00050 00051 KParts::ReadOnlyPart *m_part; // QGuardedPtr? 00052 QPointer<QWidget> m_window; 00053 QString m_mimeType; 00054 QString m_contentDisposition; 00055 }; 00056 00057 BrowserRun::BrowserRun( const KUrl& url, const KParts::OpenUrlArguments& args, 00058 const KParts::BrowserArguments& browserArgs, 00059 KParts::ReadOnlyPart *part, QWidget* window, 00060 bool removeReferrer, bool trustedSource, bool hideErrorDialog ) 00061 : KRun( url, window, 0 /*mode*/, false /*is_local_file known*/, false /* no GUI */ ), 00062 d(new BrowserRunPrivate) 00063 { 00064 d->m_bHideErrorDialog = hideErrorDialog; 00065 d->m_bRemoveReferrer = removeReferrer; 00066 d->m_bTrustedSource = trustedSource; 00067 d->m_args = args; 00068 d->m_browserArgs = browserArgs; 00069 d->m_part = part; 00070 d->m_window = window; 00071 } 00072 00073 BrowserRun::~BrowserRun() 00074 { 00075 delete d; 00076 } 00077 00078 KParts::ReadOnlyPart* BrowserRun::part() const 00079 { 00080 return d->m_part; 00081 } 00082 00083 KUrl BrowserRun::url() const 00084 { 00085 return KRun::url(); 00086 } 00087 00088 void BrowserRun::init() 00089 { 00090 if ( d->m_bHideErrorDialog ) 00091 { 00092 // ### KRun doesn't call a virtual method when it finds out that the URL 00093 // is either malformed, or points to a non-existing local file... 00094 // So we need to reimplement some of the checks, to handle d->m_bHideErrorDialog 00095 if ( !KRun::url().isValid() ) { 00096 redirectToError( KIO::ERR_MALFORMED_URL, KRun::url().url() ); 00097 return; 00098 } 00099 if ( !isLocalFile() && !hasError() && KRun::url().isLocalFile() ) 00100 setIsLocalFile( true ); 00101 00102 if ( isLocalFile() ) { 00103 KDE_struct_stat buff; 00104 if ( KDE::stat( KRun::url().toLocalFile(), &buff ) == -1 ) 00105 { 00106 kDebug(1000) << KRun::url().toLocalFile() << "doesn't exist."; 00107 redirectToError( KIO::ERR_DOES_NOT_EXIST, KRun::url().toLocalFile() ); 00108 return; 00109 } 00110 setMode( buff.st_mode ); // while we're at it, save it for KRun::init() to use it 00111 } 00112 } 00113 KRun::init(); 00114 } 00115 00116 void BrowserRun::scanFile() 00117 { 00118 kDebug(1000) << KRun::url(); 00119 00120 // Let's check for well-known extensions 00121 // Not when there is a query in the URL, in any case. 00122 // Optimization for http/https, findByURL doesn't trust extensions over http. 00123 QString protocol = KRun::url().protocol(); 00124 00125 if (!KProtocolInfo::proxiedBy(protocol).isEmpty()) { 00126 QString dummy; 00127 protocol = KProtocolManager::slaveProtocol(KRun::url(), dummy); 00128 } 00129 00130 if ( KRun::url().query().isEmpty() && !protocol.startsWith(QLatin1String("http"))) 00131 { 00132 KMimeType::Ptr mime = KMimeType::findByUrl( KRun::url() ); 00133 Q_ASSERT( mime ); 00134 if ( !mime->isDefault() || isLocalFile() ) 00135 { 00136 kDebug(1000) << "MIME TYPE is" << mime->name(); 00137 mimeTypeDetermined( mime->name() ); 00138 return; 00139 } 00140 } 00141 00142 QMap<QString, QString>& metaData = d->m_args.metaData(); 00143 if ( d->m_part ) { 00144 const QString proto = d->m_part->url().protocol().toLower(); 00145 00146 if (proto == "https" || proto == "webdavs") { 00147 metaData.insert("main_frame_request", "TRUE" ); 00148 metaData.insert("ssl_was_in_use", "TRUE" ); 00149 // metaData.insert("ssl_activate_warnings", "TRUE" ); 00150 } else if (proto == "http" || proto == "webdav") { 00151 // metaData.insert("ssl_activate_warnings", "TRUE" ); 00152 metaData.insert("ssl_was_in_use", "FALSE" ); 00153 } 00154 00155 // Set the PropagateHttpHeader meta-data if it has not already been set... 00156 if (!metaData.contains("PropagateHttpHeader")) 00157 metaData.insert("PropagateHttpHeader", "TRUE"); 00158 } 00159 00160 KIO::TransferJob *job; 00161 if ( d->m_browserArgs.doPost() && KRun::url().protocol().startsWith(QLatin1String("http"))) { 00162 job = KIO::http_post( KRun::url(), d->m_browserArgs.postData, KIO::HideProgressInfo ); 00163 job->addMetaData( "content-type", d->m_browserArgs.contentType() ); 00164 } else { 00165 job = KIO::get(KRun::url(), 00166 d->m_args.reload() ? KIO::Reload : KIO::NoReload, 00167 KIO::HideProgressInfo); 00168 } 00169 00170 if ( d->m_bRemoveReferrer ) 00171 metaData.remove("referrer"); 00172 00173 job->addMetaData( metaData ); 00174 job->ui()->setWindow( d->m_window ); 00175 connect( job, SIGNAL(result(KJob*)), 00176 this, SLOT(slotBrowserScanFinished(KJob*))); 00177 connect( job, SIGNAL(mimetype(KIO::Job*,QString)), 00178 this, SLOT(slotBrowserMimetype(KIO::Job*,QString))); 00179 setJob( job ); 00180 } 00181 00182 void BrowserRun::slotBrowserScanFinished(KJob *job) 00183 { 00184 kDebug(1000) << job->error(); 00185 if ( job->error() == KIO::ERR_IS_DIRECTORY ) 00186 { 00187 // It is in fact a directory. This happens when HTTP redirects to FTP. 00188 // Due to the "protocol doesn't support listing" code in BrowserRun, we 00189 // assumed it was a file. 00190 kDebug(1000) << "It is in fact a directory!"; 00191 // Update our URL in case of a redirection 00192 KRun::setUrl( static_cast<KIO::TransferJob *>(job)->url() ); 00193 setJob( 0 ); 00194 mimeTypeDetermined( "inode/directory" ); 00195 } 00196 else 00197 { 00198 if ( job->error() ) 00199 handleError( job ); 00200 else 00201 KRun::slotScanFinished(job); 00202 } 00203 } 00204 00205 void BrowserRun::slotBrowserMimetype( KIO::Job *_job, const QString &type ) 00206 { 00207 Q_ASSERT( _job == KRun::job() ); Q_UNUSED(_job) 00208 KIO::TransferJob *job = static_cast<KIO::TransferJob *>(KRun::job()); 00209 // Update our URL in case of a redirection 00210 //kDebug(1000) << "old URL=" << KRun::url(); 00211 //kDebug(1000) << "new URL=" << job->url(); 00212 setUrl( job->url() ); 00213 00214 if (job->isErrorPage()) { 00215 d->m_mimeType = type; 00216 handleError(job); 00217 setJob( 0 ); 00218 } else { 00219 kDebug(1000) << "found" << type << "for" << KRun::url(); 00220 00221 // Suggested filename given by the server (e.g. HTTP content-disposition) 00222 // When set, we should really be saving instead of embedding 00223 const QString suggestedFileName = job->queryMetaData("content-disposition-filename"); 00224 setSuggestedFileName(suggestedFileName); // store it (in KRun) 00225 //kDebug(1000) << "suggestedFileName=" << suggestedFileName; 00226 d->m_contentDisposition = job->queryMetaData("content-disposition-type"); 00227 00228 const QString modificationTime = job->queryMetaData("content-disposition-modification-date"); 00229 if (!modificationTime.isEmpty()) { 00230 d->m_args.metaData().insert(QLatin1String("content-disposition-modification-date"), modificationTime); 00231 } 00232 00233 QMapIterator<QString,QString> it (job->metaData()); 00234 while (it.hasNext()) { 00235 it.next(); 00236 if (it.key().startsWith(QLatin1String("ssl_"), Qt::CaseInsensitive)) 00237 d->m_args.metaData().insert(it.key(), it.value()); 00238 } 00239 00240 // Make a copy to avoid a dead reference 00241 QString _type = type; 00242 job->putOnHold(); 00243 setJob( 0 ); 00244 00245 mimeTypeDetermined( _type ); 00246 } 00247 } 00248 00249 BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable(const QString& mimeType) 00250 { 00251 return handleNonEmbeddable(mimeType, NULL); 00252 } 00253 00254 BrowserRun::NonEmbeddableResult BrowserRun::handleNonEmbeddable(const QString& _mimeType, KService::Ptr* selectedService) 00255 { 00256 QString mimeType( _mimeType ); 00257 Q_ASSERT( !hasFinished() ); // only come here if the mimetype couldn't be embedded 00258 // Support for saving remote files. 00259 if ( mimeType != "inode/directory" && // dirs can't be saved 00260 !KRun::url().isLocalFile() ) 00261 { 00262 if ( isTextExecutable(mimeType) ) 00263 mimeType = QLatin1String("text/plain"); // view, don't execute 00264 // ... -> ask whether to save 00265 BrowserOpenOrSaveQuestion question(d->m_window, KRun::url(), mimeType); 00266 question.setSuggestedFileName(suggestedFileName()); 00267 if (selectedService) 00268 question.setFeatures(BrowserOpenOrSaveQuestion::ServiceSelection); 00269 BrowserOpenOrSaveQuestion::Result res = question.askOpenOrSave(); 00270 if (res == BrowserOpenOrSaveQuestion::Save) { 00271 save( KRun::url(), suggestedFileName() ); 00272 kDebug(1000) << "Save: returning Handled"; 00273 setFinished( true ); 00274 return Handled; 00275 } 00276 else if (res == BrowserOpenOrSaveQuestion::Cancel) { 00277 // saving done or canceled 00278 kDebug(1000) << "Cancel: returning Handled"; 00279 setFinished( true ); 00280 return Handled; 00281 } 00282 else // "Open" chosen (done by KRun::foundMimeType, called when returning NotHandled) 00283 { 00284 // If we were in a POST, we can't just pass a URL to an external application. 00285 // We must save the data to a tempfile first. 00286 if ( d->m_browserArgs.doPost() ) 00287 { 00288 kDebug(1000) << "request comes from a POST, can't pass a URL to another app, need to save"; 00289 d->m_mimeType = mimeType; 00290 QString extension; 00291 QString fileName = suggestedFileName().isEmpty() ? KRun::url().fileName() : suggestedFileName(); 00292 int extensionPos = fileName.lastIndexOf( '.' ); 00293 if ( extensionPos != -1 ) 00294 extension = fileName.mid( extensionPos ); // keep the '.' 00295 KTemporaryFile tempFile; 00296 tempFile.setSuffix(extension); 00297 tempFile.setAutoRemove(false); 00298 tempFile.open(); 00299 KUrl destURL; 00300 destURL.setPath( tempFile.fileName() ); 00301 KIO::Job *job = KIO::file_copy( KRun::url(), destURL, 0600, KIO::Overwrite ); 00302 job->ui()->setWindow(d->m_window); 00303 connect( job, SIGNAL(result(KJob*)), 00304 this, SLOT(slotCopyToTempFileResult(KJob*)) ); 00305 return Delayed; // We'll continue after the job has finished 00306 } 00307 if (selectedService && question.selectedService()) { 00308 *selectedService = question.selectedService(); 00309 // KRun will use this when starting an app 00310 KRun::setPreferredService(question.selectedService()->desktopEntryName()); 00311 } 00312 } 00313 } 00314 00315 // Check if running is allowed 00316 if ( !d->m_bTrustedSource && // ... and untrusted source... 00317 !allowExecution( mimeType, KRun::url() ) ) // ...and the user said no (for executables etc.) 00318 { 00319 setFinished( true ); 00320 return Handled; 00321 } 00322 00323 KIO::Scheduler::publishSlaveOnHold(); // publish any slave on hold so it can be reused. 00324 return NotHandled; 00325 } 00326 00327 //static 00328 bool BrowserRun::allowExecution( const QString &mimeType, const KUrl &url ) 00329 { 00330 if ( !KRun::isExecutable( mimeType ) ) 00331 return true; 00332 00333 if ( !url.isLocalFile() ) // Don't permit to execute remote files 00334 return false; 00335 00336 return ( KMessageBox::warningContinueCancel( 0, 00337 i18n( "Do you really want to execute '%1'?", url.prettyUrl() ), 00338 i18n("Execute File?"), KGuiItem(i18n("Execute")) ) == KMessageBox::Continue ); 00339 } 00340 00341 //static, deprecated 00342 #ifndef KDE_NO_DEPRECATED 00343 BrowserRun::AskSaveResult BrowserRun::askSave( const KUrl & url, KService::Ptr offer, const QString& mimeType, const QString & suggestedFileName ) 00344 { 00345 Q_UNUSED(offer); 00346 BrowserOpenOrSaveQuestion question(0, url, mimeType); 00347 question.setSuggestedFileName(suggestedFileName); 00348 const BrowserOpenOrSaveQuestion::Result result = question.askOpenOrSave(); 00349 return result == BrowserOpenOrSaveQuestion::Save ? Save 00350 : BrowserOpenOrSaveQuestion::Open ? Open 00351 : Cancel; 00352 } 00353 #endif 00354 00355 //static, deprecated 00356 #ifndef KDE_NO_DEPRECATED 00357 BrowserRun::AskSaveResult BrowserRun::askEmbedOrSave( const KUrl & url, const QString& mimeType, const QString & suggestedFileName, int flags ) 00358 { 00359 BrowserOpenOrSaveQuestion question(0, url, mimeType); 00360 question.setSuggestedFileName(suggestedFileName); 00361 const BrowserOpenOrSaveQuestion::Result result = question.askEmbedOrSave(flags); 00362 return result == BrowserOpenOrSaveQuestion::Save ? Save 00363 : BrowserOpenOrSaveQuestion::Embed ? Open 00364 : Cancel; 00365 } 00366 #endif 00367 00368 // Default implementation, overridden in KHTMLRun 00369 void BrowserRun::save( const KUrl & url, const QString & suggestedFileName ) 00370 { 00371 saveUrl(url, suggestedFileName, d->m_window, d->m_args); 00372 } 00373 00374 // static 00375 void BrowserRun::simpleSave( const KUrl & url, const QString & suggestedFileName, 00376 QWidget* window ) 00377 { 00378 saveUrl(url, suggestedFileName, window, KParts::OpenUrlArguments()); 00379 } 00380 00381 void KParts::BrowserRun::saveUrl(const KUrl & url, const QString & suggestedFileName, 00382 QWidget* window, const KParts::OpenUrlArguments& args) 00383 { 00384 // DownloadManager <-> konqueror integration 00385 // find if the integration is enabled 00386 // the empty key means no integration 00387 // only use the downloadmanager for non-local urls 00388 if ( !url.isLocalFile() ) 00389 { 00390 KConfigGroup cfg = KSharedConfig::openConfig("konquerorrc", KConfig::NoGlobals)->group("HTML Settings"); 00391 QString downloadManger = cfg.readPathEntry("DownloadManager", QString()); 00392 if (!downloadManger.isEmpty()) 00393 { 00394 // then find the download manager location 00395 kDebug(1000) << "Using: "<<downloadManger <<" as Download Manager"; 00396 QString cmd=KStandardDirs::findExe(downloadManger); 00397 if (cmd.isEmpty()) 00398 { 00399 QString errMsg=i18n("The Download Manager (%1) could not be found in your $PATH ", downloadManger); 00400 QString errMsgEx= i18n("Try to reinstall it \n\nThe integration with Konqueror will be disabled."); 00401 KMessageBox::detailedSorry(0,errMsg,errMsgEx); 00402 cfg.writePathEntry("DownloadManager",QString()); 00403 cfg.sync (); 00404 } 00405 else 00406 { 00407 // ### suggestedFileName not taken into account. Fix this (and 00408 // the duplicated code) with shiny new KDownload class for 3.2 (pfeiffer) 00409 // Until the shiny new class comes about, send the suggestedFileName 00410 // along with the actual URL to download. (DA) 00411 cmd += ' ' + KShell::quoteArg(url.url()); 00412 if ( !suggestedFileName.isEmpty() ) 00413 cmd += ' ' + KShell::quoteArg(suggestedFileName); 00414 00415 kDebug(1000) << "Calling command" << cmd; 00416 // slave is already on hold (slotBrowserMimetype()) 00417 KIO::Scheduler::publishSlaveOnHold(); 00418 KRun::runCommand(cmd, window); 00419 return; 00420 } 00421 } 00422 } 00423 00424 // no download manager available, let's do it ourself 00425 KFileDialog *dlg = new KFileDialog( QString(), QString() /*all files*/, 00426 window); 00427 dlg->setOperationMode( KFileDialog::Saving ); 00428 dlg->setCaption(i18n("Save As")); 00429 dlg->setConfirmOverwrite(true); 00430 00431 QString name; 00432 if ( !suggestedFileName.isEmpty() ) 00433 name = suggestedFileName; 00434 else 00435 name = url.fileName(KUrl::ObeyTrailingSlash); // can be empty, e.g. in case http://www.kde.org/ 00436 00437 dlg->setSelection(name); 00438 if ( dlg->exec() ) 00439 { 00440 KUrl destURL( dlg->selectedUrl() ); 00441 if ( destURL.isValid() ) 00442 { 00443 saveUrlUsingKIO(url, destURL, window, args.metaData()); 00444 } 00445 } 00446 delete dlg; 00447 } 00448 00449 void BrowserRun::saveUrlUsingKIO(const KUrl & srcUrl, const KUrl& destUrl, 00450 QWidget* window, const QMap<QString, QString> &metaData) 00451 { 00452 KIO::FileCopyJob *job = KIO::file_copy(srcUrl, destUrl, -1, KIO::Overwrite); 00453 00454 const QString modificationTime = metaData[QLatin1String("content-disposition-modification-date")]; 00455 if (!modificationTime.isEmpty()) { 00456 job->setModificationTime(KDateTime::fromString(modificationTime, KDateTime::RFCDate).dateTime()); 00457 } 00458 job->setMetaData(metaData); 00459 job->addMetaData("MaxCacheSize", "0"); // Don't store in http cache. 00460 job->addMetaData("cache", "cache"); // Use entry from cache if available. 00461 job->ui()->setWindow(window); 00462 job->ui()->setAutoErrorHandlingEnabled( true ); 00463 new DownloadJobWatcher(job, metaData); 00464 } 00465 00466 void BrowserRun::slotStatResult( KJob *job ) 00467 { 00468 if ( job->error() ) { 00469 kDebug(1000) << job->errorString(); 00470 handleError( job ); 00471 } else 00472 KRun::slotStatResult( job ); 00473 } 00474 00475 void BrowserRun::handleError( KJob * job ) 00476 { 00477 if ( !job ) { // Shouldn't happen, see docu. 00478 kWarning(1000) << "handleError called with job=0! hideErrorDialog=" << d->m_bHideErrorDialog; 00479 return; 00480 } 00481 00482 KIO::TransferJob *tjob = qobject_cast<KIO::TransferJob *>(job); 00483 if (tjob && tjob->isErrorPage() && !job->error()) { 00484 // The default handling of error pages is to show them like normal pages 00485 // But this is done here in handleError so that KHTMLRun can reimplement it 00486 tjob->putOnHold(); 00487 setJob(0); 00488 if (!d->m_mimeType.isEmpty()) 00489 mimeTypeDetermined(d->m_mimeType); 00490 return; 00491 } 00492 00493 if (d->m_bHideErrorDialog && job->error() != KIO::ERR_NO_CONTENT) 00494 { 00495 redirectToError( job->error(), job->errorText() ); 00496 return; 00497 } 00498 00499 // Reuse code in KRun, to benefit from d->m_showingError etc. 00500 KRun::slotStatResult( job ); 00501 } 00502 00503 // static 00504 KUrl BrowserRun::makeErrorUrl(int error, const QString& errorText, const QString& initialUrl) 00505 { 00506 /* 00507 * The format of the error:/ URL is error:/?query#url, 00508 * where two variables are passed in the query: 00509 * error = int kio error code, errText = QString error text from kio 00510 * The sub-url is the URL that we were trying to open. 00511 */ 00512 KUrl newURL(QString("error:/?error=%1&errText=%2") 00513 .arg( error ) 00514 .arg( QString::fromUtf8( QUrl::toPercentEncoding( errorText ) ) ) ); 00515 00516 QString cleanedOrigUrl = initialUrl; 00517 KUrl runURL = cleanedOrigUrl; 00518 if (runURL.isValid()) { 00519 runURL.setPass( QString() ); // don't put the password in the error URL 00520 cleanedOrigUrl = runURL.url(); 00521 } 00522 00523 newURL.setFragment(cleanedOrigUrl); 00524 return newURL; 00525 00526 // The kde3 approach broke with invalid urls, now that they become empty in qt4. 00527 //KUrl::List lst; 00528 //lst << newURL << runURL; 00529 //return KUrl::join(lst); 00530 } 00531 00532 void BrowserRun::redirectToError( int error, const QString& errorText ) 00533 { 00539 KRun::setUrl(makeErrorUrl(error, errorText, url().url())); 00540 setJob( 0 ); 00541 mimeTypeDetermined( "text/html" ); 00542 } 00543 00544 void BrowserRun::slotCopyToTempFileResult(KJob *job) 00545 { 00546 if ( job->error() ) { 00547 job->uiDelegate()->showErrorMessage(); 00548 } else { 00549 // Same as KRun::foundMimeType but with a different URL 00550 (void) (KRun::runUrl( static_cast<KIO::FileCopyJob *>(job)->destUrl(), d->m_mimeType, d->m_window )); 00551 } 00552 setError( true ); // see above 00553 setFinished( true ); 00554 } 00555 00556 bool BrowserRun::isTextExecutable( const QString &mimeType ) 00557 { 00558 return ( mimeType == "application/x-desktop" || 00559 mimeType == "application/x-shellscript" ); 00560 } 00561 00562 bool BrowserRun::hideErrorDialog() const 00563 { 00564 return d->m_bHideErrorDialog; 00565 } 00566 00567 QString BrowserRun::contentDisposition() const 00568 { 00569 return d->m_contentDisposition; 00570 } 00571 00572 bool BrowserRun::serverSuggestsSave() const 00573 { 00574 // RfC 2183, section 2.8: 00575 // Unrecognized disposition types should be treated as `attachment'. 00576 return !contentDisposition().isEmpty() && (contentDisposition() != "inline"); 00577 } 00578 00579 KParts::OpenUrlArguments& KParts::BrowserRun::arguments() 00580 { 00581 return d->m_args; 00582 } 00583 00584 KParts::BrowserArguments& KParts::BrowserRun::browserArguments() 00585 { 00586 return d->m_browserArgs; 00587 } 00588 00589 #include "browserrun.moc" 00590 #include "browserrun_p.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:36:35 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2019 The KDE developers.
Generated on Mon Jan 21 2019 12:36:35 by doxygen 1.7.5.1 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.