diff --git a/src/preferences.h b/src/preferences.h index 8cdf738cf..52368d45e 100644 --- a/src/preferences.h +++ b/src/preferences.h @@ -990,14 +990,30 @@ public: } #ifdef Q_WS_WIN - static void setPythonPath(QString path) { - QSettings settings("qBittorrent", "qBittorrent"); - settings.setValue(QString::fromUtf8("Preferences/Win32/PythonPath"), path); - } - static QString getPythonPath() { - QSettings settings("qBittorrent", "qBittorrent"); - return settings.value(QString::fromUtf8("Preferences/Win32/PythonPath"), "").toString(); + QSettings reg_python("HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore", QSettings::NativeFormat); + QStringList versions = reg_python.childGroups(); + qDebug("Python versions nb: %d", versions.size()); + versions = versions.filter(QRegExp("2\\..*")); + versions.sort(); + while(!versions.empty()) { + const QString version = versions.takeLast(); + qDebug("Detected possible Python v%s location", qPrintable(version)); + QString path = reg_python.value(version+"/InstallPath/Default", "").toString().replace("/", "\\"); + if(!path.isEmpty() && QDir(path).exists("python.exe")) { + qDebug("Found python.exe at %s", qPrintable(path)); + return path; + } + } + if(QFile::exists("C:/Python26/python.exe")) { + reg_python.setValue("2.6/InstallPath/Default", "C:\\Python26"); + return "C:\\Python26"; + } + if(QFile::exists("C:/Python25/python.exe")) { + reg_python.setValue("2.5/InstallPath/Default", "C:\\Python26"); + return "C:\\Python25"; + } + return QString::null; } static bool neverCheckFileAssoc() { diff --git a/src/searchengine.cpp b/src/searchengine.cpp index 4abc6ef18..42a191830 100644 --- a/src/searchengine.cpp +++ b/src/searchengine.cpp @@ -79,11 +79,10 @@ SearchEngine::SearchEngine(GUI *parent, Bittorrent *BTSession) : QWidget(parent) search_stopped = false; // Creating Search Process #ifdef Q_WS_WIN - checkForPythonExe(); + has_python = addPythonPathToEnv(); #endif searchProcess = new QProcess(this); - QStringList env = QProcess::systemEnvironment(); - searchProcess->setEnvironment(env); + searchProcess->setEnvironment(QProcess::systemEnvironment()); connect(searchProcess, SIGNAL(started()), this, SLOT(searchStarted())); connect(searchProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readSearchOutput())); connect(searchProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(searchFinished(int,QProcess::ExitStatus))); @@ -111,56 +110,63 @@ void SearchEngine::fillCatCombobox() { } #ifdef Q_WS_WIN -void SearchEngine::checkForPythonExe() { - QString python_path = Preferences::getPythonPath(); - if(python_path.isEmpty() || !QFile::exists(python_path+QDir::separator()+"python.exe")) { - // Attempt to detect python in standard location - QStringList filters; - filters << "Python25" << "Python26"; - QStringList python_folders = QDir::root().entryList(filters, QDir::Dirs, QDir::Name); - if(!python_folders.isEmpty()) { - python_path = QDir::root().absoluteFilePath(python_folders.last()); - qDebug("Detected python folder at %s", qPrintable(python_path)); - } else { - filters.clear(); - filters << "Python*"; - python_folders = QDir::root().entryList(filters, QDir::Dirs, QDir::Name); - if(!python_folders.isEmpty()) { - python_path = QDir::root().absoluteFilePath(python_folders.last()); - qDebug("Detected python folder at %s", qPrintable(python_path)); - } else { - qDebug("Failed to detect Python folder"); - } - } - } - if(python_path.isEmpty() || !QFile::exists(python_path+QDir::separator()+"python.exe")) { - QMessageBox::warning(0, tr("Failed to locate the Python interpreter"), tr("The Python interpreter was not found.\nqBittorrent will now ask you to point to its correct location.")); - QString python_exe_path = QFileDialog::getOpenFileName(0, tr("Please point to its location on your hard disk."), - QDir::root().absolutePath(), tr("Python executable (python.exe)")); - if(python_exe_path.isEmpty() || !QFile::exists(python_exe_path)) { - QMessageBox::warning(0, tr("No Python interpreter"), tr("The Python interpreter is missing. qBittorrent search engine will not work.")); - return; - } - qDebug("Python exe path is: %s", qPrintable(python_exe_path)); - QStringList tmp_list = python_exe_path.split(QDir::separator()); - if(tmp_list.size() == 1) - tmp_list = tmp_list.first().split("/"); - tmp_list.removeLast(); - python_path = tmp_list.join(QDir::separator()); - qDebug("New Python path is: %s", qPrintable(python_path)); - // Save python path - Preferences::setPythonPath(python_path); - } +bool SearchEngine::addPythonPathToEnv() { + QString python_path = Preferences::getPythonPath(); + if(!python_path.isEmpty()) { // Add it to PATH envvar QString path_envar = QString::fromLocal8Bit(getenv("PATH")); if(path_envar.isNull()) { - path_envar = ""; + path_envar = ""; } path_envar = python_path+";"+path_envar; qDebug("New PATH envvar is: %s", qPrintable(path_envar)); QString envar = "PATH="+path_envar; putenv(envar.toLocal8Bit().data()); + return true; + } + return false; } + +void SearchEngine::installPython() { + setCursor(QCursor(Qt::WaitCursor)); + // Download python + downloadThread *pydownloader = new downloadThread(this); + connect(pydownloader, SIGNAL(downloadFinished(QString,QString)), this, SLOT(pythonDownloadSuccess(QString,QString))); + connect(pydownloader, SIGNAL(downloadFailure(QString,QString)), this, SLOT(pythonDownloadFailure(QString,QString))); + pydownloader->downloadUrl("http://python.org/ftp/python/2.6.5/python-2.6.5.msi"); +} + +void SearchEngine::pythonDownloadSuccess(QString url, QString file_path) { + setCursor(QCursor(Qt::ArrowCursor)); + Q_UNUSED(url); + QFile::rename(file_path, file_path+".msi"); + QProcess installer; + qDebug("Launching Python installer in passive mode..."); + + installer.start("msiexec.exe /passive /i "+file_path.replace("/", "\\")+".msi"); + // Wait for setup to complete + installer.waitForFinished(); + + qDebug("Installer stdout: %s", installer.readAllStandardOutput().data()); + qDebug("Installer stderr: %s", installer.readAllStandardError().data()); + qDebug("Setup should be complete!"); + // Reload search engine + has_python = addPythonPathToEnv(); + if(has_python) { + supported_engines->update(); + // Launch the search again + on_search_button_clicked(); + } + // Delete temp file + QFile::remove(file_path+".msi"); +} + +void SearchEngine::pythonDownloadFailure(QString url, QString error) { + Q_UNUSED(url); + setCursor(QCursor(Qt::ArrowCursor)); + QMessageBox::warning(this, tr("Download error"), tr("Python setup could not be downloaded, reason: %1.\nPlease install it manually.").arg(error)); +} + #endif QString SearchEngine::selectedCategory() const { @@ -269,6 +275,17 @@ void SearchEngine::searchTextEdited(QString) { // Function called when we click on search button void SearchEngine::on_search_button_clicked(){ +#ifdef Q_WS_WIN + if(!has_python) { + if(QMessageBox::question(this, tr("Missing Python Interpreter"), + tr("Python 2.x is required to use the search engine but it does not seem to be installed.\nDo you want to install it now?"), + QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) { + // Download and Install Python + installPython(); + } + return; + } +#endif if(searchProcess->state() != QProcess::NotRunning){ searchProcess->terminate(); search_stopped = true; @@ -381,6 +398,7 @@ void SearchEngine::downloadTorrent(QString engine_url, QString torrent_url) { parent->downloadFromURLList(urls); } else { QProcess *downloadProcess = new QProcess(this); + downloadProcess->setEnvironment(QProcess::systemEnvironment()); connect(downloadProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(downloadFinished(int,QProcess::ExitStatus))); downloaders << downloadProcess; QStringList params; diff --git a/src/searchengine.h b/src/searchengine.h index 0eafa817e..902b15e7d 100644 --- a/src/searchengine.h +++ b/src/searchengine.h @@ -70,6 +70,9 @@ private: QList > all_tab; // To store all tabs const SearchCategories full_cat_names; GUI *parent; +#ifdef Q_WS_WIN + bool has_python; +#endif public: SearchEngine(GUI *parent, Bittorrent *BTSession); @@ -127,7 +130,10 @@ protected slots: void fillCatCombobox(); void searchTextEdited(QString); #ifdef Q_WS_WIN - void checkForPythonExe(); + bool addPythonPathToEnv(); + void installPython(); + void pythonDownloadSuccess(QString url, QString file_path); + void pythonDownloadFailure(QString url, QString error); #endif };