diff --git a/src/IndentHandler.cpp b/src/IndentHandler.cpp index a11ea24..5e74706 100644 --- a/src/IndentHandler.cpp +++ b/src/IndentHandler.cpp @@ -21,6 +21,7 @@ #include "IndentHandler.h" #include +#include #include "MainWindow.h" #include "SettingsPaths.h" @@ -41,11 +42,11 @@ #include #include #include +#include #include #include #include #include -//--- #include //--- #include //--- #include //--- #include @@ -468,11 +469,11 @@ TQString IndentHandler::generateShellScript(const TQString &configFilename) //--- //--- // Set the directory where the indenter will be executed for the process' environment as PWD. //--- TQStringList env = indentProcess.environment(); -//--- env << "PWD=" + TQFileInfo(m_tempDirectoryStr).absoluteFilePath(); +//--- env << "PWD=" + TQFileInfo(m_tempDirectoryStr).absFilePath(); //--- indentProcess.setEnvironment(env); //--- //--- // Set the directory for the indenter execution -//--- indentProcess.setWorkingDirectory(TQFileInfo(m_tempDirectoryStr).absoluteFilePath()); +//--- indentProcess.setWorkingDirectory(TQFileInfo(m_tempDirectoryStr).absFilePath()); //--- //--- tqDebug() << __LINE__ << " " << __FUNCTION__ << ": Will call the indenter in the directory " << //--- indentProcess.workingDirectory() << " using this commandline call: " << @@ -921,6 +922,14 @@ void IndentHandler::resetToDefaultValues() } } +/* + \brief Feedback when the inderter process has finished + */ +void IndentHandler::indenterProcessFinished() +{ + m_indenterProcessFinished = true; +} + /* \brief Opens and parses the indenter ini file that is declared by \a iniFilePath. */ @@ -1368,162 +1377,225 @@ TQString IndentHandler::getIndenterCfgFile() */ bool IndentHandler::createIndenterCallString() { -//--- TQProcess indentProcess; -//--- -//--- if (m_indenterFileName.isEmpty()) -//--- { -//--- return false; -//--- } -//--- -//--- // First try to call the indenter inside of the data dir, using some suffix -//--- // ------------------------------------------------------------------------ -//--- -//--- // Set the directory for the indenter execution -//--- indentProcess.setWorkingDirectory(TQFileInfo(m_indenterDirectoryStr).absoluteFilePath()); -//--- -//--- foreach(TQString suffix, TQStringList() << "" << ".exe" << ".bat" << ".com" << ".sh") -//--- { -//--- m_indenterExecutableSuffix = suffix; -//--- m_indenterExecutableCallString = TQFileInfo(m_indenterDirectoryStr).absoluteFilePath() + "/" + -//--- m_indenterFileName; -//--- m_indenterExecutableCallString += suffix; -//--- -//--- // Only try to call the indenter, if the file exists. -//--- if (TQFile::exists(m_indenterExecutableCallString)) -//--- { -//--- // Only try to call the indenter directly if it is no php file -//--- if (TQFileInfo(m_indenterExecutableCallString).suffix().toLower() != "php") -//--- { -//--- indentProcess.start( -//--- "\"" + m_indenterExecutableCallString + +"\" " + m_indenterShowHelpParameter); -//--- if (indentProcess.waitForFinished(2000)) -//--- { -//--- m_indenterExecutableCallString = "\"" + m_indenterExecutableCallString + "\""; -//--- return true; -//--- } -//--- else if (indentProcess.error() == TQProcess::Timedout) -//--- { -//--- m_indenterExecutableCallString = "\"" + m_indenterExecutableCallString + "\""; -//--- return true; -//--- } -//--- } -//--- -//--- // Test for needed interpreters -//--- // ---------------------------- -//--- // If the file could not be executed, try to find a shebang at its start or test if its a php -//--- // file. -//--- TQString interpreterName = ""; -//--- TQFile indenterExecutable(m_indenterExecutableCallString); -//--- -//--- // If indenter executable file has .php as suffix, use php as default interpreter -//--- if (TQFileInfo(m_indenterExecutableCallString).suffix().toLower() == "php") -//--- { -//--- interpreterName = "php -f"; -//--- } -//--- // Else try to open the file and read the shebang. -//--- else if (indenterExecutable.open(TQFile::ReadOnly)) -//--- { -//--- // Read the first line of the file. -//--- TQTextStream indenterExecutableContent(&indenterExecutable); -//--- TQString firstLineOfIndenterExe = indenterExecutableContent.readLine(75); -//--- indenterExecutable.close(); -//--- -//--- // If the initial shebang is found, read the named intepreter. e.g. perl -//--- if (firstLineOfIndenterExe.startsWith("#!")) -//--- { -//--- // Get the rightmost word. by splitting the string into only full words. -//--- interpreterName = firstLineOfIndenterExe.split("/").last(); -//--- } -//--- } -//--- -//--- // Try to call the interpreter, if it exists. -//--- if (!interpreterName.isEmpty()) -//--- { -//--- m_indenterExecutableCallString = interpreterName + " \"" + m_indenterExecutableCallString + -//--- "\""; -//--- indentProcess.start(interpreterName + " -h"); -//--- if (indentProcess.waitForFinished(2000)) -//--- { -//--- return true; -//--- } -//--- else if (indentProcess.error() == TQProcess::Timedout) -//--- { -//--- return true; -//--- } -//--- // now we know an interpreter is needed but it could not be called, so inform the user. -//--- else -//--- { -//--- m_errorMessageDialog->showMessage(tr("Interpreter needed"), tr( -//--- "To use the selected indenter the program \"%1\" needs to be available in the global environment. You should add an entry to your path settings.").arg( -//--- interpreterName)); -//--- return true; -//--- } -//--- } -//--- } -//--- } -//--- -//--- // If unsuccessful try if the indenter executable is a JavaScript file -//--- // ------------------------------------------------------------------- -//--- m_indenterExecutableSuffix = ".js"; -//--- m_indenterExecutableCallString = TQFileInfo(m_indenterDirectoryStr).absoluteFilePath() + "/" + -//--- m_indenterFileName; -//--- m_indenterExecutableCallString += m_indenterExecutableSuffix; -//--- if (TQFile::exists(m_indenterExecutableCallString)) -//--- { -//--- return true; -//--- } -//--- -//--- // If unsuccessful try to call the indenter global, using some suffix -//--- // ------------------------------------------------------------------ -//--- foreach(TQString suffix, TQStringList() << "" << ".exe" << ".bat" << ".com" << ".sh") -//--- { -//--- m_indenterExecutableSuffix = suffix; -//--- m_indenterExecutableCallString = m_indenterFileName + suffix; -//--- indentProcess.start(m_indenterExecutableCallString + " " + m_indenterShowHelpParameter); -//--- if (indentProcess.waitForFinished(2000)) -//--- { -//--- return true; -//--- } -//--- else if (indentProcess.error() == TQProcess::Timedout) -//--- { -//--- return true; -//--- } -//--- } -//--- -//--- // If even globally calling the indenter fails, try calling .com and .exe via wine -//--- // ------------------------------------------------------------------------------- -//--- m_indenterExecutableCallString = "\"" + TQFileInfo(m_indenterDirectoryStr).absoluteFilePath() + "/" + -//--- m_indenterFileName; -//--- -//--- foreach(TQString suffix, TQStringList() << ".exe" << ".com") -//--- { -//--- m_indenterExecutableSuffix = suffix; -//--- if (TQFile::exists(m_indenterDirectoryStr + "/" + m_indenterFileName + suffix)) -//--- { -//--- TQProcess wineTestProcess; -//--- wineTestProcess.start("wine --version"); -//--- // if the process of wine was not callable assume that wine is not installed -//--- if (!wineTestProcess.waitForFinished(2000)) -//--- { -//--- m_errorMessageDialog->showMessage(tr("wine not installed"), tr( -//--- "There exists only a win32 executable of the indenter and wine does not seem to be installed. Please install wine to be able to run the indenter.")); -//--- m_indenterExecutableCallString = ""; -//--- return false; -//--- } -//--- else -//--- { -//--- m_indenterExecutableCallString = "\"" + -//--- TQFileInfo(m_indenterDirectoryStr).absoluteFilePath() + "/"; -//--- m_indenterExecutableCallString += m_indenterFileName + suffix + "\""; -//--- m_indenterExecutableCallString = "wine " + m_indenterExecutableCallString; -//--- -//--- return true; -//--- } -//--- } -//--- } -//--- -//--- m_indenterExecutableCallString = ""; -//--- m_indenterExecutableSuffix = ""; + TQProcess indentProcess(this); + TQObject::connect(&indentProcess, SIGNAL(processExited()), this, SLOT(indenterProcessFinished())); + + if (m_indenterFileName.isEmpty()) + { + return false; + } + + // First try to call the indenter inside of the data dir, using some suffix + // ------------------------------------------------------------------------ + + // Set the directory for the indenter execution + indentProcess.setWorkingDirectory(TQFileInfo(m_indenterDirectoryStr).absFilePath()); + + TQStringList extentionList; + extentionList << "" << ".exe" << ".bat" << ".com" << ".sh"; + for (const TQString &suffix : extentionList) + { + m_indenterExecutableSuffix = suffix; + m_indenterExecutableCallString = TQFileInfo(m_indenterDirectoryStr).absFilePath() + "/" + + m_indenterFileName; + m_indenterExecutableCallString += suffix; + + // Only try to call the indenter, if the file exists. + if (TQFile::exists(m_indenterExecutableCallString)) + { + // Only try to call the indenter directly if it is no php file + if (TQFileInfo(m_indenterExecutableCallString).extension(false).lower() != "php") + { + indentProcess.clearArguments(); + indentProcess.addArgument(m_indenterExecutableCallString); + indentProcess.addArgument(m_indenterShowHelpParameter); + m_indenterProcessFinished = false; + indentProcess.start(); + int counter = 20; // roughtly 2s at 100ms interval + while (!m_indenterProcessFinished && counter > 0) + { + usleep(100 * 1000); + tqApp->processEvents(); + --counter; + } + if (indentProcess.normalExit()) + { + m_indenterExecutableCallString = "\"" + m_indenterExecutableCallString + "\""; + return true; + } + else + { + if (indentProcess.isRunning()) + { + indentProcess.kill(); + } + } + } + + // Test for needed interpreters + // ---------------------------- + // If the file could not be executed, try to find a shebang at its start or test if its a php + // file. + TQString interpreterName = ""; + TQFile indenterExecutable(m_indenterExecutableCallString); + + // If indenter executable file has .php as suffix, use php as default interpreter + if (TQFileInfo(m_indenterExecutableCallString).extension(false).lower() == "php") + { + interpreterName = "php -f"; + } + // Else try to open the file and read the shebang. + else if (indenterExecutable.open(IO_ReadOnly)) + { + // Read the first line of the file. + TQTextStream indenterExecutableContent(&indenterExecutable); + TQString firstLineOfIndenterExe = indenterExecutableContent.readLine(); + indenterExecutable.close(); + + // If the initial shebang is found, read the named intepreter. e.g. perl + if (firstLineOfIndenterExe.startsWith("#!")) + { + // Get the rightmost word. by splitting the string into only full words. + TQStringList indenterFirstLineStrings = TQStringList::split("/", firstLineOfIndenterExe); + interpreterName = indenterFirstLineStrings.last(); + } + } + + // Try to call the interpreter, if it exists. + if (!interpreterName.isEmpty()) + { + m_indenterExecutableCallString = interpreterName + " \"" + + m_indenterExecutableCallString + "\""; + indentProcess.clearArguments(); + indentProcess.addArgument(interpreterName); + indentProcess.addArgument("-h"); + m_indenterProcessFinished = false; + indentProcess.start(); + int counter = 20; // roughtly 2s at 100ms interval + while (!m_indenterProcessFinished && counter > 0) + { + usleep(100 * 1000); + tqApp->processEvents(); + --counter; + } + if (indentProcess.normalExit()) + { + return true; + } + // now we know an interpreter is needed but it could not be called, so inform the user. + else + { + if (indentProcess.isRunning()) + { + indentProcess.kill(); + } + m_errorMessageDialog->showMessage(tr("Interpreter needed"), + tr("To use the selected indenter the program \"%1\" needs to be available in the global environment. " + "You should add an entry to your path settings.").arg(interpreterName)); + return true; + } + } + } + } + + // If unsuccessful try if the indenter executable is a JavaScript file + // ------------------------------------------------------------------- + m_indenterExecutableSuffix = ".js"; + m_indenterExecutableCallString = TQFileInfo(m_indenterDirectoryStr).absFilePath() + "/" + + m_indenterFileName; + m_indenterExecutableCallString += m_indenterExecutableSuffix; + if (TQFile::exists(m_indenterExecutableCallString)) + { + return true; + } + + // If unsuccessful try to call the indenter global, using some suffix + // ------------------------------------------------------------------ + extentionList.clear(); + extentionList << "" << ".exe" << ".bat" << ".com" << ".sh"; + for (const TQString &suffix : extentionList) + { + m_indenterExecutableSuffix = suffix; + m_indenterExecutableCallString = m_indenterFileName + suffix; + indentProcess.clearArguments(); + indentProcess.addArgument(m_indenterExecutableCallString); + indentProcess.addArgument(m_indenterShowHelpParameter); + m_indenterProcessFinished = false; + indentProcess.start(); + int counter = 20; // roughtly 2s at 100ms interval + while (!m_indenterProcessFinished && counter > 0) + { + usleep(100 * 1000); + tqApp->processEvents(); + --counter; + } + if (indentProcess.normalExit()) + { + return true; + } + else + { + if (indentProcess.isRunning()) + { + indentProcess.kill(); + } + } + } + + // If even globally calling the indenter fails, try calling .com and .exe via wine + // ------------------------------------------------------------------------------- + m_indenterExecutableCallString = "\"" + TQFileInfo(m_indenterDirectoryStr).absFilePath() + "/" + + m_indenterFileName; + + extentionList.clear(); + extentionList << ".exe" << ".com"; + for (const TQString &suffix : extentionList) + { + m_indenterExecutableSuffix = suffix; + if (TQFile::exists(m_indenterDirectoryStr + "/" + m_indenterFileName + suffix)) + { + indentProcess.clearArguments(); + indentProcess.addArgument("wine"); + indentProcess.addArgument("--version"); + m_indenterProcessFinished = false; + indentProcess.start(); + int counter = 20; // roughtly 2s at 100ms interval + while (!m_indenterProcessFinished && counter > 0) + { + usleep(100 * 1000); + tqApp->processEvents(); + --counter; + } + // if the process of wine was not callable assume that wine is not installed + if (indentProcess.normalExit()) + { + m_errorMessageDialog->showMessage(tr("wine not installed"), tr( + "There exists only a win32 executable of the indenter and wine does not seem to be installed. Please install wine to be able to run the indenter.")); + m_indenterExecutableCallString = ""; + return false; + } + else + { + if (indentProcess.isRunning()) + { + indentProcess.kill(); + } + m_indenterExecutableCallString = "\"" + + TQFileInfo(m_indenterDirectoryStr).absFilePath() + "/"; + m_indenterExecutableCallString += m_indenterFileName + suffix + "\""; + m_indenterExecutableCallString = "wine " + m_indenterExecutableCallString; + + return true; + } + } + } + + m_indenterExecutableCallString = ""; + m_indenterExecutableSuffix = ""; + if (indentProcess.isRunning()) + { + indentProcess.kill(); + } return false; } diff --git a/src/IndentHandler.h b/src/IndentHandler.h index 9677f6a..0d51a0a 100644 --- a/src/IndentHandler.h +++ b/src/IndentHandler.h @@ -65,7 +65,7 @@ class IndentHandler : public TQWidget ///-- protected: ///-- bool event(TQEvent *event); ///-- void wheelEvent(TQWheelEvent *event); -///-- + private slots: void setIndenter(int indenterID); void showIndenterManual() const; @@ -74,6 +74,7 @@ class IndentHandler : public TQWidget void createIndenterCallShellScript(); void resetIndenterParameter(); void handleChangedIndenterSettings(); + void indenterProcessFinished(); private: ///-- TQString callExecutableIndenter(TQString sourceCode, TQString inputFileExtension); @@ -166,7 +167,7 @@ class IndentHandler : public TQWidget UiGuiErrorMessage *m_errorMessageDialog; TQString m_indenterExecutableCallString; TQString m_indenterExecutableSuffix; -///-- + bool m_indenterProcessFinished; ///-- //TODO: This function should go into a string helper/tool class/file. ///-- TQString encodeToHTML(const TQString &text);