Files
create/src/Gui/NetworkRetriever.cpp
Markus Reitböck a72a0d6405 Gui: use CMake to generate precompiled headers on all platforms
"Professional CMake" book suggest the following:

"Targets should build successfully with or without compiler support for precompiled headers. It
should be considered an optimization, not a requirement. In particular, do not explicitly include a
precompile header (e.g. stdafx.h) in the source code, let CMake force-include an automatically
generated precompile header on the compiler command line instead. This is more portable across
the major compilers and is likely to be easier to maintain. It will also avoid warnings being
generated from certain code checking tools like iwyu (include what you use)."

Therefore, removed the "#include <PreCompiled.h>" from sources, also
there is no need for the "#ifdef _PreComp_" anymore
2025-09-14 09:47:03 +02:00

558 lines
17 KiB
C++

/***************************************************************************
* Copyright (c) 2004 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
# include <QApplication>
# include <QDir>
# include <QFileInfo>
# include <QMessageBox>
# include <QTimer>
#include <FCConfig.h>
#include <App/Application.h>
#include <Base/Console.h>
#include "NetworkRetriever.h"
#include "Action.h"
#include "BitmapFactory.h"
#include "FileDialog.h"
#include "MainWindow.h"
#include "Dialogs/ui_DlgAuthorization.h"
using namespace Gui;
using namespace Gui::Dialog;
namespace Gui {
struct NetworkRetrieverP
{
// wget options
int tries;
int level;
QString outputFile;
QString user;
QString passwd;
bool timeStamp;
bool img;
bool convert;
bool recurse;
bool folRel;
bool html;
bool nop;
// wget argument
QString startUrl;
QString proxy;
QString dir;
bool fail;
};
} // namespace Gui
/* TRANSLATOR Gui::NetworkRetriever */
NetworkRetriever::NetworkRetriever( QObject * parent )
: QObject( parent )
{
d = new NetworkRetrieverP;
d->tries = 3;
d->level = 1;
d->timeStamp = false;
d->img = false;
d->html = false;
d->convert = true;
d->recurse = false;
d->folRel = false;
d->nop = false;
wget = new QProcess(this);
// if wgets exits emit signal
connect(wget, qOverload<int, QProcess::ExitStatus>(&QProcess::finished),
this, &NetworkRetriever::wgetFinished);
// if application quits kill wget immediately to avoid dangling processes
connect(qApp, &QApplication::lastWindowClosed, wget, &QProcess::kill);
}
NetworkRetriever::~NetworkRetriever()
{
delete wget;
delete d;
}
/**
* This method is connected to QTimer::singleShot() and executed after 5 seconds. If wget then is still running
* we can assume that everything is fine.
* \note This test is necessary since \a wget writes all its output on stderr and we cannot determine surely
* if an error occurred or not.
*
* There is still a problem that is not solved so far. If wget requires the proxy settings and if these
* are not set, wget could take more than 5 seconds without downloading anything.
*/
void NetworkRetriever::testFailure()
{
if ( wget->state() == QProcess::Running )
{
d->fail = false;
QString msg = tr("Download started…");
Base::Console().message("%s\n", msg.toUtf8().constData());
}
}
/**
* Sets the number of retries to \a tries. If \a tries is 0 the number of tries
* is unlimited. The default value of the tries property is set to 3.
*/
void NetworkRetriever::setNumberOfTries( int tries )
{
d->tries = tries;
}
/**
* Sets output file to \a out where documents are written to.
*/
void NetworkRetriever::setOutputFile( const QString& out )
{
d->outputFile = out;
}
/**
* If \a ts is true the timestamping is enabled, otherwise timestamping is
* disabled. If timestamping is enabled files are no more re-retrieved unless
* they are newer than the local files. As default the timestamping property is disabled.
*/
void NetworkRetriever::setEnableTimestamp(bool ts)
{
d->timeStamp = ts;
}
/**
* If you are behind a proxy server then you have to specify your proxy url with \a proxy.
* Moreover, if the proxy requires user authentication then you can specify the username
* with \a user and the password with \a passwd.
*/
void NetworkRetriever::setProxy( const QString& proxy, const QString& user, const QString& passwd )
{
d->proxy = proxy;
d->user = user;
d->passwd = passwd;
}
/**
* If \a recursive is true all referenced files are downloaded recursively.
* As default recursion is disabled. \a level specifies the maximum recursion
* depth. If \a level is 0 the recursion depth is infinite. As default the level
* property is 1.
* \note: Use this with care!
*/
void NetworkRetriever::setEnableRecursive( bool recursive, int level )
{
d->recurse = recursive;
d->level = level;
}
/**
* If \a folRel is true wget follows relative links only. As default
* the follows relative property is false.
*/
void NetworkRetriever::setFollowRelative( bool folRel )
{
d->folRel = folRel;
}
/**
* If \a convert is true all non-relative links are converted to
* relative links. As default the convert property is true.
*/
void NetworkRetriever::setEnableConvert( bool convert )
{
d->convert = convert;
}
/**
* If \a img is true wget tries to get all needed image files
* to display the HTML page. As default this behaviour is disabled..
*/
void NetworkRetriever::setFetchImages( bool img )
{
d->img = img;
}
/**
* Saves all text/html documents with .html extionsion if \a html is true.
* As default the html property is false.
*/
void NetworkRetriever::setEnableHTMLExtension( bool html )
{
d->html = html;
}
/**
* Do not ever ascend to the parent directory when retrieving recursively.
*/
void NetworkRetriever::setNoParent( bool nop )
{
d->nop = nop;
}
/**
* Sets the output directory to \a dir where all downloaded are written into.
*/
void NetworkRetriever::setOutputDirectory( const QString& dir )
{
d->dir = dir;
}
/**
* wget starts to download \a startUrl and all referenced pages.
*/
bool NetworkRetriever::startDownload( const QString& startUrl )
{
if ( !testWget() )
return false;
d->startUrl = startUrl;
// proxy as environment variable
if ( !d->proxy.isEmpty() )
{
QStringList env = wget->environment();
env << QStringLiteral("http_proxy=%1").arg(d->proxy);
env << QStringLiteral("ftp_proxy=%1").arg(d->proxy);
wget->setEnvironment(env);
}
else
{
QStringList env = wget->environment();
env.removeAll(QStringLiteral("http_proxy=%1").arg(d->proxy));
env.removeAll(QStringLiteral("ftp_proxy=%1").arg(d->proxy));
wget->setEnvironment(env);
}
QStringList wgetArguments;
// since the wget option '--directory-prefix' seems not to work as expected
// and QProcess::setWorkingDirectory() fails if the 'doc' directory doesn't
// exist we must check for this and create it if needed.
if ( !d->dir.isEmpty() )
{
QDir dir(d->dir);
if (!dir.exists(d->dir))
{
if (!dir.mkdir(d->dir))
{
Base::Console().error("Directory '%s' could not be created.", (const char*)d->dir.toLatin1());
return true; // please, no error message
}
}
wget->setWorkingDirectory( dir.path() );
}
// user authentication
if ( !d->proxy.isEmpty() )
{
if ( !d->user.isEmpty() )
{
wgetArguments << QStringLiteral("--proxy-user=%1").arg( d->user );
if ( !d->passwd.isEmpty() )
{
wgetArguments << QStringLiteral("--proxy-passwd=%1").arg( d->passwd );
}
}
}
// output file
if ( !d->outputFile.isEmpty() )
wgetArguments << QStringLiteral("--output-document=%1").arg( d->outputFile );
// timestamping enabled -> update newer files only
if ( d->timeStamp )
wgetArguments << QStringLiteral("-N");
// get all needed image files
if ( d->img )
wgetArguments << QStringLiteral("-p");
// follow relative links only
if ( d->folRel )
wgetArguments<< QStringLiteral("-L");
if ( d->recurse )
{
wgetArguments << QStringLiteral("-r");
wgetArguments << QStringLiteral("--level=%1").arg( d->level );
}
if ( d->nop )
wgetArguments << QStringLiteral("-np");
// convert absolute links in to relative
if ( d->convert )
wgetArguments << QStringLiteral("-k");
// number of tries
wgetArguments << QStringLiteral("--tries=%1").arg( d->tries );
// use HTML file extension
if ( d->html )
wgetArguments << QStringLiteral("-E");
// start URL
wgetArguments << startUrl;
#ifdef FC_OS_LINUX
// on Linux it seems that we have to change cwd
QString cwd = QDir::currentPath ();
if ( !d->dir.isEmpty() )
{
QDir::setCurrent(d->dir);
}
wget->start(QStringLiteral("wget"), wgetArguments);
QDir::setCurrent( cwd );
#else
wget->start(QStringLiteral("wget"), wgetArguments);
#endif
return wget->state() == QProcess::Running;
}
/**
* Returns true if wget is still downloading, otherwise returns false.
*/
bool NetworkRetriever::isDownloading() const
{
return wget->state() == QProcess::Running;
}
/**
* Kills wget if it is still running.
*/
void NetworkRetriever::abort()
{
if ( wget->state() == QProcess::Running)
{
QTimer::singleShot( 2000, wget, &QProcess::kill);
}
}
void NetworkRetriever::wgetFinished(int exitCode, QProcess::ExitStatus status)
{
Q_UNUSED(exitCode);
Q_UNUSED(status);
wget->setReadChannel(QProcess::StandardError);
if (wget->canReadLine()) {
QByteArray data = wget->readAll();
Base::Console().warning(data);
}
Q_EMIT wgetExited();
}
/**
* This is a test if wget is in PATH environment or not.
* If the test succeeds true is returned, false otherwise.
*/
bool NetworkRetriever::testWget()
{
QProcess proc;
proc.setProgram(QStringLiteral("wget"));
proc.start();
bool ok = proc.state() == QProcess::Running;
proc.kill();
proc.waitForFinished();
return ok;
}
// --------------------------------------------------------------------
StdCmdDownloadOnlineHelp::StdCmdDownloadOnlineHelp( QObject * parent)
: QObject(parent), Command("Std_DownloadOnlineHelp")
{
sGroup ="Help";
sMenuText = QT_TR_NOOP("Download Online Help");
sToolTipText = QT_TR_NOOP("Downloads %1's online help");
sWhatsThis = "Std_DownloadOnlineHelp";
sStatusTip = sToolTipText;
sPixmap = "help";
wget = new NetworkRetriever( this );
// downloading recursively and depth 5
wget->setEnableRecursive( true, 5 );
wget->setNumberOfTries( 3 );
wget->setEnableHTMLExtension( true );
wget->setEnableConvert( true );
wget->setEnableTimestamp( true );
wget->setFetchImages( true );
wget->setFollowRelative( false );
wget->setNoParent( true );
connect(wget, &NetworkRetriever::wgetExited, this, &StdCmdDownloadOnlineHelp::wgetFinished);
}
StdCmdDownloadOnlineHelp::~StdCmdDownloadOnlineHelp()
{
delete wget;
}
Action * StdCmdDownloadOnlineHelp::createAction()
{
Action *pcAction;
QString exe = QString::fromStdString(App::Application::getExecutableName());
pcAction = new Action(this,getMainWindow());
pcAction->setText(QCoreApplication::translate(
this->className(), getMenuText()));
pcAction->setToolTip(QCoreApplication::translate(
this->className(), getToolTipText()).arg(exe));
pcAction->setStatusTip(QCoreApplication::translate(
this->className(), getStatusTip()).arg(exe));
pcAction->setWhatsThis(QCoreApplication::translate(
this->className(), getWhatsThis()).arg(exe));
pcAction->setIcon(Gui::BitmapFactory().pixmap(getPixmap()));
pcAction->setShortcut(QString::fromLatin1(getAccel()));
return pcAction;
}
void StdCmdDownloadOnlineHelp::languageChange()
{
if (_pcAction) {
QString exe = QString::fromStdString(App::Application::getExecutableName());
_pcAction->setText(QCoreApplication::translate(
this->className(), getMenuText()));
_pcAction->setToolTip(QCoreApplication::translate(
this->className(), getToolTipText()).arg(exe));
_pcAction->setStatusTip(QCoreApplication::translate(
this->className(), getStatusTip()).arg(exe));
_pcAction->setWhatsThis(QCoreApplication::translate(
this->className(), getWhatsThis()).arg(exe));
}
}
void StdCmdDownloadOnlineHelp::activated(int iMsg)
{
Q_UNUSED(iMsg);
if (!wget->isDownloading()) {
ParameterGrp::handle hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp");
hGrp = hGrp->GetGroup("Preferences")->GetGroup("OnlineHelp");
std::string url = hGrp->GetASCII("DownloadURL", "www.freecad.org/wiki/");
std::string prx = hGrp->GetASCII("ProxyText", "");
bool bUseProxy = hGrp->GetBool ("UseProxy", false);
bool bAuthor = hGrp->GetBool ("Authorize", false);
if (bUseProxy) {
QString username;
QString password;
if (bAuthor) {
QDialog dlg(getMainWindow());
dlg.setModal(true);
Ui_DlgAuthorization ui;
ui.setupUi(&dlg);
if (dlg.exec() == QDialog::Accepted) {
username = ui.username->text();
password = ui.password->text();
}
}
wget->setProxy(QString::fromLatin1(prx.c_str()), username, password);
}
int loop=3;
bool canStart = false;
// set output directory
QString path = QString::fromStdString(App::Application::getHomePath());
path += QStringLiteral("/doc/");
ParameterGrp::handle hURLGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/OnlineHelp");
path = QString::fromUtf8(hURLGrp->GetASCII( "DownloadLocation", path.toLatin1() ).c_str());
while (loop > 0) {
loop--;
QFileInfo fi( path);
if (!fi.exists()) {
if (QMessageBox::critical(getMainWindow(), tr("Non-existing directory"),
tr("The directory '%1' does not exist.\n\n"
"Specify an existing directory?").arg(fi.filePath()),
QMessageBox::Yes | QMessageBox::No) !=
QMessageBox::Yes)
{
// exit the command
return;
}
else
{
path = FileDialog::getExistingDirectory();
if ( path.isEmpty() )
return;
}
}
if (!fi.permission( QFile::WriteUser)) {
if (QMessageBox::critical(getMainWindow(), tr("Missing permission"),
tr("You don't have write permission to '%1'\n\n"
"Specify another directory?").arg(fi.filePath()),
QMessageBox::Yes | QMessageBox::No) !=
QMessageBox::Yes)
{
// exit the command
return;
}
else {
path = FileDialog::getExistingDirectory();
if ( path.isEmpty() )
return;
}
}
else {
wget->setOutputDirectory( path );
canStart = true;
break;
}
}
if (canStart) {
bool ok = wget->startDownload(QString::fromLatin1(url.c_str()));
if (!ok)
Base::Console().error("The tool 'wget' could not be found. Check the installation.");
else if ( wget->isDownloading() && _pcAction )
_pcAction->setText(tr("Stop downloading"));
}
}
else // kill the process now
{
wget->abort();
}
}
void StdCmdDownloadOnlineHelp::wgetFinished()
{
if (_pcAction)
_pcAction->setText(QCoreApplication::translate(
this->className(), getMenuText()));
}
#include "moc_NetworkRetriever.cpp"