void PythonUploader::showSettingsUI(QWidget *parent)
{
    connect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
    pythonContext.addObject("parentWidget_", parent);
    pythonContext.evalScript(shortname + "_u.showSettingsUI(parentWidget_)");
    if(hadPythonErr)
    {
        PythonQt::self()->handleError();
        WARNING(tr("Failed to call showSettingsUI() in ") + this->className);
        QMessageBox::critical(NULL, tr("Script error in plugin '") + shortname + "'", tr("Failed to call ") + this->className + ".showSettingsUI()" + "\n" + lastPythonErr);
        lastPythonErr.clear();
        hadPythonErr = false;
    }
    disconnect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
}
bool PythonUploader::isConfigured()
{
    connect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
    QVariant result = pythonContext.call(shortname + "_u.isConfigured");
    if(hadPythonErr)
    {
        PythonQt::self()->handleError();
        WARNING("Failed to call isConfigured() in " + this->className);
        QMessageBox::critical(NULL, "Script error in plugin '" + shortname + "'", "Failed to call " + this->className + ".isConfigured()" + "\n" + lastPythonErr);
        lastPythonErr.clear();
        hadPythonErr = false;
        disconnect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
        return false;
    }
    disconnect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
    return result.toBool();
}
QString PythonUploader::getFilename()
{
    connect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
    QVariant result = pythonContext.call(shortname + "_u.getFilename");
    if(hadPythonErr)
    {
        PythonQt::self()->handleError();
        WARNING(tr("Failed to call getFilename() in ") + this->className);
        QMessageBox::critical(NULL, tr("Script error in plugin '") + shortname + "'", tr("Failed to call ") + this->className + ".getFilename()" + "\n" + lastPythonErr);
        lastPythonErr.clear();
        hadPythonErr = false;
        disconnect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
        return QString();
    }
    disconnect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
    this->filename = result.toString();
    return filename;
}
PythonUploader::PythonUploader(QString name, QString shortname, QString className, QString iconFilename, QObject *parent) :
    Uploader(parent)
{
    this->workingDir = PluginManager::pluginPath() + shortname;
    this->shortname = shortname;
    this->name = name;
    this->className = className;
    this->filename = QString();
    QFile iconFile(workingDir + QDir::separator() + iconFilename);
    if(iconFile.exists())
    {
        this->icon = QIcon(iconFile.fileName());
    }
    QFile mainScriptFile(workingDir + QDir::separator() + "main.py");
    if(!mainScriptFile.exists())
    {
        QMessageBox::critical(0, "Error", "Failed to load plugin \"" + shortname + "\". Script file \"main.py\" does not exist.");
        return;
    }
    if (!mainScriptFile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
      QMessageBox::critical(0, "Error", "Failed to load plugin \"" + shortname + "\". File main.py exists, but is not readable.");
      return;
    }
    hadPythonErr = false;
    connect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
    PythonQt::self()->addSysPath(workingDir + QDir::separator() + "modules");
    moduleObj = PythonQt::self()->createModuleFromScript(shortname + "_uploader");
    moduleObj.addVariable("workingDir", workingDir);
    moduleObj.evalScript(QString(mainScriptFile.readAll()));
    if(hadPythonErr)
    {
        PythonQt::self()->handleError();
        WARNING("Error while parsing script file " + mainScriptFile.fileName());
        QMessageBox::critical(NULL, "Script error in plugin '" + shortname + "'", "Error in file: " + mainScriptFile.fileName() + "\n" + lastPythonErr);
        lastPythonErr.clear();
        hadPythonErr = false;
    }
    pythonContext = PythonQt::self()->getMainModule();
    pythonContext.evalScript("from " + shortname + "_uploader import " + className);
    pythonContext.evalScript(shortname + "_u = " + className + "()");
    disconnect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
}
void PythonUploader::showSettingsUI(QWidget *parent)
{
    connect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
    moduleObj.addObject("parentWidget", parent);
#ifdef Q_OS_WIN
    pythonContext.evalScript(shortname + "_u.showSettingsUI()");
#else
    pythonContext.call(shortname + "_u.showSettingsUI");
#endif
    if(hadPythonErr)
    {
        PythonQt::self()->handleError();
        WARNING("Failed to call showSettingsUI() in " + this->className);
        QMessageBox::critical(NULL, "Script error in plugin '" + shortname + "'", "Failed to call " + this->className + ".showSettingsUI()" + "\n" + lastPythonErr);
        lastPythonErr.clear();
        hadPythonErr = false;
    }
    disconnect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
}
void PythonUploader::upload(const QImage &screenshot, QString name)
{
    connect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
    QVariantList args;
    args << screenshot;
    args << name;
    QVariant result = pythonContext.call(shortname + "_u.upload", args);
    if(hadPythonErr)
    {
        PythonQt::self()->handleError();
        WARNING("Failed to call upload() in " + this->className);
        emit uploadingError("Failed to call " + this->className + ".upload()" + "\n" + lastPythonErr);
        lastPythonErr.clear();
        hadPythonErr = false;
        disconnect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
        return;
    }
    bool success = result.toBool();
    if(success)
    {
        QString url = moduleObj.getVariable("ScreenCloud.clipboardUrl").toString();
        emit uploadingFinished(url);
    }else
    {
        QString errorString = moduleObj.getVariable("ScreenCloud.uploadingError").toString();
        if(errorString.isEmpty())
        {
            errorString = tr("Unknown error");
        }
        emit uploadingError(errorString);
    }
    //Clean up
    disconnect(PythonQt::self(), SIGNAL(pythonStdErr(QString)), this, SLOT(pythonError(QString)));
    moduleObj.evalScript("ScreenCloud.clipboardUrl = None");
    moduleObj.evalScript("ScreenCloud.uploadingError = None");
    emit finished();
}
//-----------------------------------------------------------------------------
void ctkAbstractPythonManager::initPythonQt(int flags)
{
  Q_D(ctkAbstractPythonManager);

  PythonQt::init(flags);

  // Python maps SIGINT (control-c) to its own handler.  We will remap it
  // to the default so that control-c works.
  #ifdef SIGINT
  signal(SIGINT, SIG_DFL);
  #endif

  PythonQtObjectPtr _mainContext = PythonQt::self()->getMainModule();

  this->connect(PythonQt::self(), SIGNAL(pythonStdOut(QString)),
                SLOT(printStdout(QString)));
  this->connect(PythonQt::self(), SIGNAL(pythonStdErr(QString)),
                SLOT(printStderr(QString)));

  PythonQt_init_QtBindings();

  QStringList initCode;

  // Update 'sys.path'
  initCode << "import sys";
  foreach (const QString& path, this->pythonPaths())
    {
    initCode << QString("sys.path.append('%1')").arg(QDir::fromNativeSeparators(path));
    }

  _mainContext.evalScript(initCode.join("\n"));

  this->preInitialization();
  if (d->InitFunction)
    {
    (*d->InitFunction)();
    }
  emit this->pythonPreInitialized();

  this->executeInitializationScripts();
  emit this->pythonInitialized();
}