Commit 8748f57a authored by Victor Yacovlev's avatar Victor Yacovlev

Everywhere: Course support in various components

parent 5589884b
......@@ -3,6 +3,7 @@
#include "interfaces/actorinterface.h"
#include "dataformats/ast_algorhitm.h"
#include "debuggerwindow.h"
#include "interfaces/coursesinterface.h"
namespace CoreGUI {
......@@ -294,7 +295,7 @@ void KumirProgram::testingRun()
}
prepareKumirRunner(Shared::GeneratorInterface::LinesOnly);
}
e_state = RegularRun;
e_state = TestingRun;
PluginManager::instance()->switchGlobalState(GS_Running);
setAllActorsAnimationFlag(false);
plugin_bytecodeRun->runTesting();
......@@ -381,7 +382,7 @@ void KumirProgram::stepOut()
void KumirProgram::stop()
{
if (e_state==StepRun || e_state==RegularRun) {
if (e_state==StepRun || e_state==RegularRun || e_state==TestingRun) {
plugin_bytecodeRun->terminate();
}
else if (e_state==FastRun) {
......@@ -407,7 +408,7 @@ void KumirProgram::setAllActorsAnimationFlag(bool animationEnabled)
void KumirProgram::handleRunnerStopped(int rr)
{
const State previousState = e_state;
Shared::RunInterface::StopReason reason = Shared::RunInterface::StopReason (rr);
if (reason==Shared::RunInterface::SR_InputRequest) {
PluginManager::instance()->switchGlobalState(GS_Input);
......@@ -444,8 +445,23 @@ void KumirProgram::handleRunnerStopped(int rr)
if (w_debuggerWindow) w_debuggerWindow->reset();
}
if (e_state==Idle) {
// m_variablesWebObject->reset(0);
typedef Shared::CoursesInterface CI;
CI * courseManager =
ExtensionSystem::PluginManager::instance()->findPlugin<CI>();
typedef Shared::RunInterface RI;
RI * runner =
ExtensionSystem::PluginManager::instance()->findPlugin<RI>();
if (courseManager && previousState == TestingRun) {
if (reason == Shared::RunInterface::SR_UserTerminated) {
courseManager->setTestingResult(CI::UserTerminated, 0);
}
else if (reason == Shared::RunInterface::SR_Done) {
courseManager->setTestingResult(CI::SuccessfullyFinished,
runner->valueStackTopItem().toInt());
}
else if (reason == Shared::RunInterface::SR_Error) {
courseManager->setTestingResult(CI::AbortedOnError, 0);
}
}
}
......
......@@ -65,7 +65,7 @@ private:
void setAllActorsAnimationFlag(bool animationEnabled);
void timerEvent(QTimerEvent *e);
void prepareKumirRunner(Shared::GeneratorInterface::DebugLevel);
enum State { Idle, FastRun, RegularRun, StepRun } e_state;
enum State { Idle, FastRun, RegularRun, StepRun, TestingRun } e_state;
const AST::Data * m_ast;
QString s_endStatus;
QProcess * m_process;
......
......@@ -532,6 +532,7 @@ bool MainWindow::saveCurrentFileTo(const QString &fileName)
int documentId = twe->property("documentId").toInt();
QString error = m_plugin->plugin_editor->saveDocument(documentId, fileName);
if (error.isEmpty()) {
twe->saved = QDateTime::currentDateTime();
m_plugin->plugin_editor->setDocumentChangesSaved(documentId);
return true;
}
......@@ -1376,5 +1377,88 @@ TabWidgetElement * MainWindow::loadFromUrl(const QUrl & url, bool addToRecentFil
return result;
}
TabWidgetElement* MainWindow::loadFromCourseManager(
const GuiInterface::ProgramSourceText &data
)
{
typedef GuiInterface::ProgramSourceText ST;
TabWidgetElement * result = nullptr;
for (int i=0; i<ui->tabWidget->count(); i++) {
TabWidgetElement * courseTab =
qobject_cast<TabWidgetElement*>(ui->tabWidget->widget(i));
if (courseTab && courseTab->isCourseManagerTab()) {
result = courseTab;
break;
}
}
if (data.language == ST::Kumir) {
QWidget * vc = nullptr;
int id = -1;
if (result) {
// Reuse opened course manager tab
id = result->documentId;
vc = result->component;
}
else {
// Create new course manager tab
EditorComponent doc =
m_plugin->plugin_editor->newDocument(
"KumirAnalizer",
QFileInfo(data.url.toLocalFile())
.absoluteDir().absolutePath(),
false
);
vc = doc.widget;
id = doc.id;
QList<QAction*> toolBarActions = doc.toolbarActions;
QList<QMenu*> menus = doc.menus;
result = addCentralComponent(
data.title,
vc,
toolBarActions,
menus,
doc.statusbarWidgets,
Kumir,
true
);
}
m_plugin->plugin_editor->loadDocument(id, data.content);
result->saved = data.saved;
result->changed = data.changed;
result->url = data.url;
vc->setProperty("title", data.title);
vc->setProperty("documentId", id);
vc->setProperty("fromCourseManager", true);
vc->setProperty("realFileName", data.url.toLocalFile());
}
return result;
}
Shared::GuiInterface::ProgramSourceText
MainWindow::courseManagerProgramSource() const
{
typedef GuiInterface::ProgramSourceText ST;
ST result;
result.language = ST::Kumir; // TODO implement for other languages
TabWidgetElement * tab = nullptr;
for (int i=0; i<ui->tabWidget->count(); i++) {
TabWidgetElement * courseTab =
qobject_cast<TabWidgetElement*>(ui->tabWidget->widget(i));
if (courseTab && courseTab->isCourseManagerTab()) {
tab = courseTab;
break;
}
}
if (tab) {
result.saved = tab->saved;
result.changed = tab->changed;
result.url = tab->url;
result.title = tab->title();
int id = tab->documentId;
result.content = m_plugin->plugin_editor->documentContent(id);
}
return result;
}
} // namespace CoreGUI
......@@ -51,6 +51,10 @@ public slots:
void loadRecentFile(const QString & fullPath);
inline void loadFromUrl(const QString &s) { loadFromUrl(QUrl(s), true); }
class TabWidgetElement * loadFromUrl(const QUrl & url, bool addToRecentFiles);
class TabWidgetElement * loadFromCourseManager(
const Shared::GuiInterface::ProgramSourceText &data
);
Shared::GuiInterface::ProgramSourceText courseManagerProgramSource() const;
bool saveCurrentFile();
bool saveCurrentFileAs();
bool saveCurrentFileTo(const QString & fileName);
......
......@@ -22,6 +22,7 @@ Plugin::Plugin() :
kumirProgram_ = 0;
startPage_.widget = 0;
helpViewer_ = 0;
courseManager_ = 0;
}
QString Plugin::InitialTextKey = "InitialText";
......@@ -42,6 +43,12 @@ QString Plugin::initialize(const QStringList & parameters)
qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus");
qRegisterMetaType<QProcess::ProcessError>("QProcess::ProcessError");
qRegisterMetaType<KumFile::Data>("KumirFile.Data");
qRegisterMetaType<Shared::GuiInterface::ProgramSourceText::Language>
("Gui.ProgramSourceText.Language");
qRegisterMetaType<Shared::GuiInterface::ProgramSourceText>
("Gui.ProgramSourceText");
const QStringList BlacklistedThemes = QStringList()
<< "iaorakde" << "iaoraqt" << "iaora";
......@@ -344,6 +351,13 @@ QString Plugin::initialize(const QStringList & parameters)
kumirProgram_->setDebuggerWindow(debugger_);
courseManager_ = ExtensionSystem::PluginManager::instance()
->findPlugin<Shared::CoursesInterface>();
return "";
}
......@@ -469,18 +483,19 @@ Plugin::~Plugin()
void Plugin::setProgramSource(const ProgramSourceText &source)
{
if (mainWindow_) {
mainWindow_->loadFromCourseManager(source);
}
}
GuiInterface::ProgramSourceText Plugin::programSource() const
{
GuiInterface::ProgramSourceText result;
return result;
return mainWindow_->courseManagerProgramSource();
}
void Plugin::startTesting()
{
kumirProgram_->testingRun();
}
} // namespace CoreGUI
......
......@@ -10,6 +10,7 @@
#include "interfaces/actorinterface.h"
#include "interfaces/runinterface.h"
#include "interfaces/guiinterface.h"
#include "interfaces/coursesinterface.h"
#include "widgets/secondarywindow.h"
#include "docbookviewer/docbookview.h"
#include "terminal.h"
......@@ -80,6 +81,7 @@ protected:
class DebuggerWindow * debugger_;
DocBookViewer::DocBookView * helpViewer_;
QSplitter * bottomSplitter_;
Shared::CoursesInterface* courseManager_;
bool sessionsDisableFlag_;
......
......@@ -44,6 +44,7 @@ public:
}
else {
connect(w, SIGNAL(documentCleanChanged(bool)), this, SIGNAL(documentCleanChanged(bool)));
connect(w, SIGNAL(documentCleanChanged(bool)), this, SLOT(setDocumentChangesClean(bool)));
}
QVBoxLayout * l = new QVBoxLayout;
l->setContentsMargins(0,0,0,0);
......@@ -101,7 +102,17 @@ public:
QList<QWidget*> statusbarWidgets;
MainWindow::DocumentType type;
int documentId;
QDateTime saved;
QDateTime changed;
QUrl url;
inline class KumirProgram * kumirProgram() { return m_kumirProgram; }
inline bool isCourseManagerTab() const {
const QVariant prop = component->property("fromCourseManager");
return prop.isValid() && prop.toBool() == true;
}
inline QString title() const {
return component->property("title").toString();
}
signals:
void changeTitle(const QString & txt);
void documentCleanChanged(bool v);
......@@ -110,6 +121,16 @@ protected:
QWidget::focusInEvent(e);
component->setFocus();
}
protected slots:
inline void setDocumentChangesClean(bool clean) {
if (clean) {
changed = saved;
}
else {
changed = QDateTime::currentDateTime();
}
}
private:
class KumirProgram * m_kumirProgram;
};
......
......@@ -196,6 +196,16 @@ QString EditorPlugin::saveDocument(int documentId, const QString &fileName)
return "";
}
KumFile::Data EditorPlugin::documentContent(int documentId) const
{
Q_ASSERT(documentId>=0);
Q_ASSERT(documentId<d->editors.size());
Q_CHECK_PTR(d->editors[documentId].e);
Ed ed = d->editors[documentId];
Editor * editor = ed.e;
return editor->toKumFile();
}
QString EditorPlugin::loadDocument(int documentId, const QString &fileName)
{
Q_ASSERT(documentId>=0);
......@@ -215,6 +225,17 @@ QString EditorPlugin::loadDocument(int documentId, const QString &fileName)
return "";
}
QString EditorPlugin::loadDocument(int documentId, const KumFile::Data & data)
{
Q_ASSERT(documentId>=0);
Q_ASSERT(documentId<d->editors.size());
Q_CHECK_PTR(d->editors[documentId].e);
Ed ed = d->editors[documentId];
Editor * editor = ed.e;
editor->setKumFile(data);
return "";
}
QString EditorPlugin::initialize(const QStringList &arguments)
{
if (arguments.contains("teacher"))
......
......@@ -3,6 +3,7 @@
#include "extensionsystem/kplugin.h"
#include "interfaces/editorinterface.h"
#include "dataformats/kumfile.h"
namespace Editor {
......@@ -26,8 +27,10 @@ public:
QWidget* settingsEditorPage();
bool hasUnsavedChanges(int documentId) const;
void setDocumentChangesSaved(int documentId);
virtual QString loadDocument(int documentId, const QString & fileName);
QString loadDocument(int documentId, const QString & fileName);
QString loadDocument(int documentId, const KumFile::Data &data);
QString saveDocument(int documentId, const QString & fileName);
KumFile::Data documentContent(int documentId) const;
Shared::AnalizerInterface * analizer(int documentId);
quint32 errorsLinesCount(int documentId) const;
void highlightLineGreen(int documentId, int lineNo);
......
......@@ -121,6 +121,11 @@ QMap<QString,QVariant> Plugin::getScalarLocalValues(int frameNo) const
return result;
}
QVariant Plugin::valueStackTopItem() const
{
return pRun_->valueStackTopItem();
}
QMap<QString,QVariant> Plugin::getScalarGlobalValues(const QString & moduleName) const
{
pRun_->lockVMMutex();
......
......@@ -28,6 +28,7 @@ public:
inline QDateTime loadedProgramVersion() const { return loadedVersion_; }
inline bool isGuiRequired() { return false; }
QVariant valueStackTopItem() const;
QMap<QString,QVariant> getScalarLocalValues(int frameNo) const;
QMap<QString,QVariant> getScalarGlobalValues(const QString & moduleName) const;
......
......@@ -462,6 +462,38 @@ bool Run::canStepOut() const
return vm->canStepOut();
}
QVariant Run::valueStackTopItem() const
{
VMMutex_->lock();
AnyValue value;
try {
value = vm->topLevelStackValue();
}
catch (std::string & e) {
qDebug() << e.c_str();
}
VMMutex_->unlock();
QVariant result;
if (value.isValid()) {
if (value.type() == VT_int) {
result = QVariant(value.toInt());
}
else if (value.type() == VT_real) {
result = QVariant(value.toReal());
}
else if (value.type() == VT_bool) {
result = QVariant(value.toBool());
}
else if (value.type() == VT_char) {
result = QVariant(QChar(value.toChar()));
}
else if (value.type() == VT_string) {
result = QVariant(QString::fromStdWString(value.toString()));
}
}
return result;
}
} // namespace KumirCodeRun
......
......@@ -39,6 +39,7 @@ public:
void reset();
void evaluateNextInstruction();
bool canStepOut() const;
QVariant valueStackTopItem() const;
public slots:
void lockVMMutex();
......@@ -184,7 +185,7 @@ protected :
QVariantList funcOptResults_;
QVariant funcResult_;
QString funcError_;
class Mutex * VMMutex_;
mutable class Mutex * VMMutex_;
};
......
......@@ -93,6 +93,20 @@ public:
return result;
}
template <class PluginInterface>
QList<PluginInterface*> findPlugins() {
QList<KPlugin*> plugins = loadedPlugins();
QList<PluginInterface*> result;
for (int i=0; i<plugins.size(); i++) {
KPlugin * plugin = plugins[i];
PluginInterface* implementation =
qobject_cast<PluginInterface*>(plugin);
if (implementation)
result.push_back(implementation);
}
return result;
}
public slots:
/** Show settings for all modules
......
......@@ -2,6 +2,7 @@
#define EDITOR_INTERFACE
#include "interfaces/analizerinterface.h"
#include "dataformats/kumfile.h"
namespace Shared
{
......@@ -26,7 +27,9 @@ public:
virtual bool hasUnsavedChanges(int documentId) const = 0;
virtual void setDocumentChangesSaved(int documentId) = 0;
virtual QString loadDocument(int documentId, const QString & fileName) = 0;
virtual QString loadDocument(int documentId, const KumFile::Data &data) = 0;
virtual QString saveDocument(int documentId, const QString & fileName) = 0;
virtual KumFile::Data documentContent(int documentId) const = 0;
virtual AnalizerInterface * analizer(int documentId) = 0;
virtual quint32 errorsLinesCount(int documentId) const = 0;
virtual void highlightLineGreen(int documentId, int lineNo) = 0;
......
......@@ -21,6 +21,7 @@ public:
QDateTime changed;
KumFile::Data content;
QString title;
QUrl url;
};
public slots:
virtual void setProgramSource(const ProgramSourceText &source) = 0;
......
......@@ -28,6 +28,7 @@ public:
virtual bool hasMoreInstructions() const = 0;
virtual int currentLineNo() const = 0;
virtual QString error() const = 0;
virtual QVariant valueStackTopItem() const = 0;
virtual QMap<QString,QVariant> getScalarLocalValues(int frameNo) const = 0;
virtual QMap<QString,QVariant> getScalarGlobalValues(const QString & moduleName) const = 0;
......
......@@ -67,6 +67,12 @@ public /*methods*/:
inline void setMutex(CriticalSectionLocker * m)
{ stacksMutex_ = m;}
/**
* Returns top-level value stack scalar item or raises an exception
* in case value is not scalar or stack if empty
*/
inline AnyValue topLevelStackValue() const /* throws std::string */;
/** The following two functions are basic to use for actual run:
* while ( vm.hasMoreInstructions() )
* vm.evaluateNextInstruction();
......@@ -204,6 +210,21 @@ private /*instruction methods*/:
/**** IMPLEMENTATION ******/
AnyValue KumirVM::topLevelStackValue() const {
AnyValue result;
if (valuesStack_.size() > 0) {
const Variable & var = valuesStack_.top();
if (var.dimension() > 0) {
throw std::string("Access to non scalar value in values stack");
}
result = var.value();
}
else {
throw std::string("Access to empty values stack");
}
return result;
}
Context & KumirVM::currentContext() {
return contextsStack_.top();
}
......
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