Commit 86679168 authored by Nikita Sirgienko's avatar Nikita Sirgienko

[Octave] Refactor graphic catching to GraphicPackage

parent 88d05e69
Pipeline #25340 passed with stage
in 23 minutes and 31 seconds
......@@ -51,3 +51,5 @@ if(BUILD_TESTING)
endif(BUILD_TESTING)
install(FILES cantor_octave.knsrc DESTINATION ${KDE_INSTALL_CONFDIR} )
install(FILES graphic_packages.xml DESTINATION ${KDE_INSTALL_DATADIR}/cantor/octave)
<GraphicPackages>
<GraphicPackage>
<Id>octave_universal</Id>
<Name>Octave</Name>
<TestPresenceCommand>
if (length(available_graphics_toolkits()) > 0)
printf("%d", 1);
else
printf("%d", 0);
endif
</TestPresenceCommand>
<EnableCommand>
set (0, "defaultfigurevisible","off");
</EnableCommand>
<DisableCommand>
set (0, "defaultfigurevisible","on");
</DisableCommand>
<ToFileCommandTemplate>
__cantor_plot_filename__ ='%1%2.%3';
try
print(strcat('-d', '%3'), __cantor_plot_filename__, '-tight');
catch
try
print(strcat('-d', '%3'), __cantor_plot_filename__);
end_try_catch
end_try_catch
clear __cantor_plot_filename__
</ToFileCommandTemplate>
</GraphicPackage>
</GraphicPackages>
\ No newline at end of file
......@@ -48,9 +48,11 @@ QString OctaveBackend::version() const
Cantor::Backend::Capabilities OctaveBackend::capabilities() const
{
Cantor::Backend::Capabilities cap =
SyntaxHighlighting|
Completion |
SyntaxHelp;
SyntaxHighlighting |
Completion |
SyntaxHelp |
IntegratedPlots;
if (OctaveSettings::self()->variableManagement())
cap |= VariableManagement;
return cap;
......
......@@ -71,10 +71,6 @@ OctaveExpression::OctaveExpression(Cantor::Session* session, bool internal): Exp
OctaveExpression::~OctaveExpression()
{
if(m_tempFile) {
delete m_tempFile;
m_tempFile = nullptr;
}
}
void OctaveExpression::interrupt()
......@@ -86,47 +82,11 @@ void OctaveExpression::interrupt()
void OctaveExpression::evaluate()
{
if(m_tempFile) {
delete m_tempFile;
m_tempFile = nullptr;
}
qDebug() << "evaluate";
QString cmd = command();
QStringList cmdWords = cmd.split(QRegularExpression(QStringLiteral("\\b")), QString::SkipEmptyParts);
if (static_cast<OctaveSession*>(session())->isIntegratedPlotsEnabled() && !cmdWords.contains(QLatin1String("help")) && !cmdWords.contains(QLatin1String("completion_matches")))
{
for (const QString& plotCmd : plotCommands)
{
if (cmdWords.contains(plotCmd))
{
qDebug() << "Executing a plot command";
/*
#ifdef WITH_EPS
QLatin1String ext(".eps");
#else
QLatin1String ext(".png");
#endif
*/
m_tempFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/cantor_octave-XXXXXX.")+plotExtensions[OctaveSettings::inlinePlotFormat()]);
m_tempFile->open();
qDebug() << "plot temp file" << m_tempFile->fileName();
QFileSystemWatcher* watcher = fileWatcher();
if (!watcher->files().isEmpty())
watcher->removePaths(watcher->files());
watcher->addPath(m_tempFile->fileName());
connect(watcher, &QFileSystemWatcher::fileChanged, this, &OctaveExpression::imageChanged, Qt::UniqueConnection);
m_plotPending = true;
break;
}
}
}
m_plotFilename.clear();
m_finished = false;
m_plotPending = false;
session()->enqueueExpression(this);
}
......@@ -134,11 +94,42 @@ QString OctaveExpression::internalCommand()
{
QString cmd = command();
if (m_plotPending)
OctaveSession* octaveSession = static_cast<OctaveSession*>(session());
if (octaveSession->isIntegratedPlotsEnabled() && !isInternal())
{
if (!cmd.endsWith(QLatin1Char(';')) && !cmd.endsWith(QLatin1Char(',')))
cmd += QLatin1Char(',');
cmd += printCommandTemplate.arg(QFileInfo(m_tempFile->fileName()).suffix()).arg(m_tempFile->fileName());
QStringList cmdWords = cmd.split(QRegularExpression(QStringLiteral("\\b")), QString::SkipEmptyParts);
if (!cmdWords.contains(QLatin1String("help")) && !cmdWords.contains(QLatin1String("completion_matches")))
{
for (const QString& plotCmd : plotCommands)
if (cmdWords.contains(plotCmd))
{
Q_ASSERT(session()->enabledGraphicPackages().size() == 1);
const Cantor::GraphicPackage& package = session()->enabledGraphicPackages().first();
Q_ASSERT(package.id() == QLatin1String("octave_universal"));
if (package.isHavePlotCommand())
{
m_plotFilename = octaveSession->plotFilePrefixPath() + QString::number(id()) + QLatin1String(".") + plotExtensions[OctaveSettings::inlinePlotFormat()];
if (!cmd.endsWith(QLatin1Char(';')) && !cmd.endsWith(QLatin1Char(',')))
cmd += QLatin1Char(',');
cmd.append(package.savePlotCommand(octaveSession->plotFilePrefixPath(), id(), plotExtensions[OctaveSettings::inlinePlotFormat()]));
QFileSystemWatcher* watcher = fileWatcher();
if (!watcher->files().isEmpty())
watcher->removePaths(watcher->files());
// Add path works only with existed paths, so create the file
QFile file(m_plotFilename);
file.open(QFile::WriteOnly);
file.close();
watcher->addPath(m_plotFilename);
m_plotPending = true;
connect(watcher, &QFileSystemWatcher::fileChanged, this, &OctaveExpression::imageChanged, Qt::UniqueConnection);
}
break;
}
}
}
// We need remove all comments here, because below we merge all strings to one long string
......@@ -214,12 +205,12 @@ void OctaveExpression::parseError(const QString& error)
void OctaveExpression::imageChanged()
{
if(m_tempFile->size() <= 0)
if(QFile(m_plotFilename).size() <= 0)
return;
const QUrl& url = QUrl::fromLocalFile(m_tempFile->fileName());
const QUrl& url = QUrl::fromLocalFile(m_plotFilename);
Cantor::Result* newResult;
if (m_tempFile->fileName().endsWith(QLatin1String(".eps")))
if (m_plotFilename.endsWith(QLatin1String(".eps")))
newResult = new Cantor::EpsResult(url);
else
newResult = new Cantor::ImageResult(url);
......@@ -231,13 +222,12 @@ void OctaveExpression::imageChanged()
replaceResult(i, newResult);
found = true;
}
if (!found)
addResult(newResult);
m_plotPending = false;
if (m_finished && status() != Expression::Done)
{
if (m_finished && status() == Expression::Computing)
setStatus(Done);
}
}
......@@ -50,7 +50,7 @@ private:
QString m_resultString;
bool m_finished = false;
bool m_plotPending = false;
QTemporaryFile* m_tempFile = nullptr;
QString m_plotFilename;
};
#endif // OCTAVEEXPRESSION_H
......@@ -17,6 +17,7 @@
Boston, MA 02110-1301, USA.
*/
#include <random>
#include "octavesession.h"
#include "octaveexpression.h"
#include "octavecompletionobject.h"
......@@ -52,7 +53,8 @@ m_prompt(QStringLiteral("CANTOR_OCTAVE_BACKEND_PROMPT:([0-9]+)> ")),
m_subprompt(QStringLiteral("CANTOR_OCTAVE_BACKEND_SUBPROMPT:([0-9]+)> ")),
m_previousPromptNumber(1),
m_syntaxError(false),
m_isIntegratedPlotsEnabled(false)
m_isIntegratedPlotsEnabled(false),
m_isIntegratedPlotsSettingsEnabled(false)
{
setVariableModel(new OctaveVariableModel(this));
}
......@@ -75,44 +77,6 @@ void OctaveSession::login()
emit loginStarted();
bool isIntegratedPlots = OctaveSettings::integratePlots();
QString tmpWritableErrorReason;
if (isIntegratedPlots)
{
QString filename = QDir::tempPath() + QLatin1String("/cantor_octave_plot_integration_test.txt");
QFile::remove(filename); // Remove previous file, if precents
int test_number = rand() % 1000;
QStringList args;
args << QLatin1String("--no-init-file");
args << QLatin1String("--no-gui");
args << QLatin1String("--eval");
args << QString::fromLatin1("file_id = fopen('%1', 'w'); fdisp(file_id, %2); fclose(file_id);").arg(filename).arg(test_number);
QString errorMsg;
isIntegratedPlots = Cantor::Backend::testProgramWritable(
OctaveSettings::path().toLocalFile(),
args,
filename,
QString::number(test_number),
&errorMsg
);
// If we in this branch, then isIntegratedPlots was true, but if it false now, then it means, that the writabl test is failed
if (isIntegratedPlots == false)
{
KMessageBox::error(nullptr,
i18n("Plot integration test failed.")+
QLatin1String("\n\n")+
errorMsg+
QLatin1String("\n\n")+
i18n("The integration of plots will be disabled."),
i18n("Cantor")
);
}
}
m_isIntegratedPlotsEnabled = isIntegratedPlots;
m_process = new KProcess ( this );
QStringList args;
args << QLatin1String("--silent");
......@@ -139,20 +103,6 @@ void OctaveSession::login()
args << QLatin1String("--eval");
args << QLatin1String("suppress_verbose_help_message(1);");
if (isIntegratedPlots)
{
// Do not show the popup when plotting, rather only print to a file
args << QLatin1String("--eval");
args << QLatin1String("set (0, \"defaultfigurevisible\",\"off\");");
args << QLatin1String("--eval");
args << QLatin1String("if strcmp(graphics_toolkit(), \"fltk\") graphics_toolkit(\"gnuplot\") endif;");
}
else
{
args << QLatin1String("--eval");
args << QLatin1String("set (0, \"defaultfigurevisible\",\"on\");");
}
m_process->setProgram ( OctaveSettings::path().toLocalFile(), args );
qDebug() << "starting " << m_process->program();
m_process->setOutputChannelMode ( KProcess::SeparateChannels );
......@@ -163,6 +113,17 @@ void OctaveSession::login()
connect ( m_process, SIGNAL (readyReadStandardError()), SLOT (readError()) );
connect ( m_process, SIGNAL (error(QProcess::ProcessError)), SLOT (processError()) );
std::random_device rd;
std::mt19937 mt(rd());
std::uniform_int_distribution<int> rand_dist(0, 999999999);
m_plotFilePrefixPath =
QDir::tempPath()
+ QLatin1String("/cantor_octave_")
+ QString::number(m_process->pid())
+ QLatin1String("_")
+ QString::number(rand_dist(mt))
+ QLatin1String("_");
if(!OctaveSettings::self()->autorunScripts().isEmpty()){
QString autorunScripts = OctaveSettings::self()->autorunScripts().join(QLatin1String("\n"));
......@@ -198,10 +159,25 @@ void OctaveSession::logout()
m_process->deleteLater();
m_process = nullptr;
if (!m_plotFilePrefixPath.isEmpty())
{
int i = 0;
const QString& extension = OctaveExpression::plotExtensions[OctaveSettings::inlinePlotFormat()];
QString filename = m_plotFilePrefixPath + QString::number(i) + QLatin1String(".") + extension;
while (QFile::exists(filename))
{
QFile::remove(filename);
i++;
filename = m_plotFilePrefixPath + QString::number(i) + QLatin1String(".") + extension;
}
}
expressionQueue().clear();
m_output.clear();
m_previousPromptNumber = 1;
m_isIntegratedPlotsEnabled = false;
m_isIntegratedPlotsSettingsEnabled = false;
Session::logout();
......@@ -247,6 +223,9 @@ void OctaveSession::processError()
Cantor::Expression* OctaveSession::evaluateExpression ( const QString& command, Cantor::Expression::FinishingBehavior finishingBehavior, bool internal )
{
if (!internal)
updateGraphicPackagesFromSettings();
qDebug() << "evaluating: " << command;
OctaveExpression* expression = new OctaveExpression ( this, internal);
expression->setCommand ( command );
......@@ -387,3 +366,67 @@ bool OctaveSession::isIntegratedPlotsEnabled() const
{
return m_isIntegratedPlotsEnabled;
}
QString OctaveSession::plotFilePrefixPath() const
{
return m_plotFilePrefixPath;
}
void OctaveSession::updateGraphicPackagesFromSettings()
{
if (m_isIntegratedPlotsSettingsEnabled == OctaveSettings::integratePlots())
return;
if (m_isIntegratedPlotsEnabled && OctaveSettings::integratePlots() == false)
{
updateEnabledGraphicPackages(QList<Cantor::GraphicPackage>());
m_isIntegratedPlotsEnabled = false;
m_isIntegratedPlotsSettingsEnabled = OctaveSettings::integratePlots();
return;
}
else if (!m_isIntegratedPlotsEnabled && OctaveSettings::integratePlots() == true)
{
bool isIntegratedPlots = OctaveSettings::integratePlots();
if (isIntegratedPlots)
{
QString filename = QDir::tempPath() + QLatin1String("/cantor_octave_plot_integration_test.txt");
QFile::remove(filename); // Remove previous file, if precents
int test_number = rand() % 1000;
QStringList args;
args << QLatin1String("--no-init-file");
args << QLatin1String("--no-gui");
args << QLatin1String("--eval");
args << QString::fromLatin1("file_id = fopen('%1', 'w'); fdisp(file_id, %2); fclose(file_id);").arg(filename).arg(test_number);
QString errorMsg;
isIntegratedPlots = Cantor::Backend::testProgramWritable(
OctaveSettings::path().toLocalFile(),
args,
filename,
QString::number(test_number),
&errorMsg
);
// If we in this branch, then isIntegratedPlots was true, but if it false now, then it means, that the writable test is failed
if (isIntegratedPlots == false)
{
KMessageBox::error(nullptr,
i18n("Plot integration test failed.")+
QLatin1String("\n\n")+
errorMsg+
QLatin1String("\n\n")+
i18n("The integration of plots will be disabled."),
i18n("Cantor")
);
}
}
m_isIntegratedPlotsEnabled = isIntegratedPlots;
m_isIntegratedPlotsSettingsEnabled = OctaveSettings::integratePlots();
if (m_isIntegratedPlotsEnabled)
updateEnabledGraphicPackages(backend()->availableGraphicPackages());
else
updateEnabledGraphicPackages(QList<Cantor::GraphicPackage>());
}
}
......@@ -51,6 +51,7 @@ class OctaveSession : public Cantor::Session
void runFirstExpression() override;
bool isIntegratedPlotsEnabled() const;
QString plotFilePrefixPath() const;
private:
const static QRegularExpression PROMPT_UNCHANGEABLE_COMMAND;
......@@ -65,12 +66,15 @@ class OctaveSession : public Cantor::Session
bool m_syntaxError;
QString m_output;
QString m_plotFilePrefixPath;
bool m_isIntegratedPlotsEnabled; // Better move it in worksheet, like isCompletion, etc.
bool m_isIntegratedPlotsSettingsEnabled;
private:
void readFromOctave(QByteArray data);
bool isDoNothingCommand(const QString& command);
bool isSpecialOctaveCommand(const QString& command);
void updateGraphicPackagesFromSettings();
private Q_SLOTS:
void readOutput();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment