Commit df223bcb authored by Victor Yacovlev's avatar Victor Yacovlev

Everywhere: working MVC implementation of variables debugger view

parent 9724ad00
......@@ -19,7 +19,7 @@ endif(MSVC)
if(NOT MSVC)
set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(CMAKE_CXX_FLAGS "-Werror -Wreturn-type ${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "-Werror -Wreturn-type -O0 ${CMAKE_CXX_FLAGS}")
endif()
endif()
......
......@@ -16,6 +16,7 @@ set(SOURCES
aboutdialog.cpp
debuggerwindow.cpp
statusbar.cpp
debuggerview.cpp
)
set(EXTRA_LIBS
......@@ -42,6 +43,7 @@ set(MOC_HEADERS
tabwidgetelement.h
debuggerwindow.h
statusbar.h
debuggerview.h
)
set(FORMS
......
#include "debuggerview.h"
namespace CoreGUI {
DebuggerView::DebuggerView(Shared::RunInterface * runner, QWidget *parent)
: QTreeView(parent)
, runner_(runner)
, debuggerEnabled_(false)
{
setHeaderHidden(true);
}
void DebuggerView::setDebuggerEnabled(bool enabled)
{
debuggerEnabled_ = enabled;
if (enabled && runner_ && runner_->debuggerVariablesViewModel()) {
QAbstractItemModel * newModel = runner_->debuggerVariablesViewModel();
if (model() != newModel) {
setModel(runner_->debuggerVariablesViewModel());
connect(model(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(handleRowsInserted(QModelIndex,int,int)));
for (int column = 0; column < model()->columnCount(); ++column)
resizeColumnToContents(column);
handleRowsInserted(QModelIndex(),
model()->rowCount() - 1,
model()->rowCount() - 1);
}
}
else {
if (model()) {
disconnect(model(), SIGNAL(rowsInserted(QModelIndex,int,int)),
this, SLOT(handleRowsInserted(QModelIndex,int,int)));
}
setModel(0);
}
}
void DebuggerView::paintEvent(QPaintEvent *event)
{
if (debuggerEnabled_ && model()) {
QTreeView::paintEvent(event);
}
else {
static const QString message =
tr("Current values available only while running program in step-by-step mode");
event->accept();
QPainter p(viewport());
QStyleOptionFrame opt;
opt.initFrom(viewport());
opt.rect = viewport()->rect();
opt.palette.setCurrentColorGroup(QPalette::Disabled);
style()->drawPrimitive(QStyle::PE_Frame, &opt, &p, viewport());
QTextOption textOpt;
textOpt.setAlignment(Qt::AlignCenter);
textOpt.setWrapMode(QTextOption::WordWrap);
p.setPen(QPen(opt.palette.buttonText().color()));
p.drawText(viewport()->rect().adjusted(5,5,-10,-10),
message,
textOpt
);
}
}
void DebuggerView::handleRowsInserted(const QModelIndex &index, int start, int end)
{
if (!index.isValid() && start == end) { // top level context
const QModelIndex elementIndex = model()->index(start, 0, index);
if (elementIndex.isValid()) {
setExpanded(elementIndex, true);
}
}
}
void DebuggerView::handleRowsRemoved(const QModelIndex &index, int start, int end)
{
}
} // namespace CoreGUI
#ifndef COREGUI_DEBUGGERVIEW_H
#define COREGUI_DEBUGGERVIEW_H
#include "interfaces/runinterface.h"
#include <QTreeView>
namespace CoreGUI {
class DebuggerView : public QTreeView
{
Q_OBJECT
public:
explicit DebuggerView(Shared::RunInterface * runner, QWidget *parent = 0);
signals:
public slots:
void setDebuggerEnabled(bool enabled);
private slots:
void handleRowsInserted(const QModelIndex & index, int start, int end);
void handleRowsRemoved(const QModelIndex & index, int start, int end);
private /*methods*/:
void paintEvent(QPaintEvent *event);
private /*fields*/:
Shared::RunInterface * runner_;
bool debuggerEnabled_;
};
} // namespace CoreGUI
#endif // COREGUI_DEBUGGERVIEW_H
......@@ -34,7 +34,6 @@ public:
inline void setDocumentId(int id) { if (e_state==Idle) documentId_ = id; }
inline int documentId() const { return documentId_; }
inline void setMainWidget(QWidget * w) { w_mainWidget = w; }
inline void setDebuggerWindow(class DebuggerWindow * w) { w_debuggerWindow = w; }
void setTerminal(Term * t, QDockWidget * w);
void setBytecodeRun(KPlugin * run);
......
......@@ -2,7 +2,7 @@
#include "mainwindow.h"
#include "extensionsystem/pluginmanager.h"
#include "widgets/secondarywindow.h"
#include "debuggerwindow.h"
#include "debuggerview.h"
#include "ui_mainwindow.h"
#include "statusbar.h"
#ifdef Q_OS_MACX
......@@ -363,7 +363,7 @@ QString Plugin::initialize(const QStringList & parameters)
debuggerPlace_->setVisible(false);
debugger_ = new DebuggerWindow(plugin_kumirCodeRun);
debugger_ = new DebuggerView(plugin_kumirCodeRun);
Widgets::SecondaryWindow * debuggerWindow = new Widgets::SecondaryWindow(
debugger_,
debuggerPlace_,
......@@ -385,57 +385,56 @@ QString Plugin::initialize(const QStringList & parameters)
connect(debuggerWindow->toggleViewAction(), SIGNAL(toggled(bool)),
mainWindow_->ui->actionVariables, SLOT(setChecked(bool)));
connect(kumirRunner, SIGNAL(debuggerReset()),
debugger_, SLOT(reset()));
connect(kumirRunner, SIGNAL(debuggerPopContext()),
debugger_, SLOT(popContext()));
connect(kumirRunner,
SIGNAL(debuggerPushContext(QString,QStringList,QStringList,QList<int>)),
debugger_,
SLOT(pushContext(QString,QStringList,QStringList,QList<int>)));
connect(kumirRunner,
SIGNAL(debuggerUpdateLocalVariable(QString,QString)),
debugger_,
SLOT(updateLocalVariable(QString,QString)));
connect(kumirRunner,
SIGNAL(debuggerUpdateGlobalVariable(QString,QString,QString)),
debugger_,
SLOT(updateGlobalVariable(QString,QString,QString)));
connect(kumirRunner,
SIGNAL(debuggerUpdateLocalTableBounds(QString,QList<int>)),
debugger_,
SLOT(updateLocalTableBounds(QString,QList<int>)));
connect(kumirRunner,
SIGNAL(debuggerUpdateGlobalTableBounds(QString,QString,QList<int>)),
debugger_,
SLOT(updateGlobalTableBounds(QString,QString,QList<int>)));
connect(kumirRunner,
SIGNAL(debuggerSetLocalReference(QString,QString,QList<int>,int,QString)),
debugger_,
SLOT(setLocalReference(QString,QString,QList<int>,int,QString)));
connect(kumirRunner,
SIGNAL(debuggerForceUpdateValues()),
debugger_,
SLOT(updateAllValues()));
connect(kumirRunner,
SIGNAL(debuggerUpdateLocalTableValue(QString,QList<int>)),
debugger_,
SLOT(updateLocalTableValue(QString,QList<int>)));
connect(kumirRunner,
SIGNAL(debuggerUpdateGlobalTableValue(QString,QString,QList<int>)),
debugger_,
SLOT(updateGlobalTableValue(QString,QString,QList<int>)));
connect(kumirRunner,
SIGNAL(debuggerSetGlobals(QString,QStringList,QStringList,QList<int>)),
debugger_,
SLOT(setGlobals(QString,QStringList,QStringList,QList<int>))
);
// connect(kumirRunner, SIGNAL(debuggerReset()),
// debugger_, SLOT(reset()));
// connect(kumirRunner, SIGNAL(debuggerPopContext()),
// debugger_, SLOT(popContext()));
// connect(kumirRunner,
// SIGNAL(debuggerPushContext(QString,QStringList,QStringList,QList<int>)),
// debugger_,
// SLOT(pushContext(QString,QStringList,QStringList,QList<int>)));
// connect(kumirRunner,
// SIGNAL(debuggerUpdateLocalVariable(QString,QString)),
// debugger_,
// SLOT(updateLocalVariable(QString,QString)));
// connect(kumirRunner,
// SIGNAL(debuggerUpdateGlobalVariable(QString,QString,QString)),
// debugger_,
// SLOT(updateGlobalVariable(QString,QString,QString)));
// connect(kumirRunner,
// SIGNAL(debuggerUpdateLocalTableBounds(QString,QList<int>)),
// debugger_,
// SLOT(updateLocalTableBounds(QString,QList<int>)));
// connect(kumirRunner,
// SIGNAL(debuggerUpdateGlobalTableBounds(QString,QString,QList<int>)),
// debugger_,
// SLOT(updateGlobalTableBounds(QString,QString,QList<int>)));
// connect(kumirRunner,
// SIGNAL(debuggerSetLocalReference(QString,QString,QList<int>,int,QString)),
// debugger_,
// SLOT(setLocalReference(QString,QString,QList<int>,int,QString)));
// connect(kumirRunner,
// SIGNAL(debuggerForceUpdateValues()),
// debugger_,
// SLOT(updateAllValues()));
// connect(kumirRunner,
// SIGNAL(debuggerUpdateLocalTableValue(QString,QList<int>)),
// debugger_,
// SLOT(updateLocalTableValue(QString,QList<int>)));
// connect(kumirRunner,
// SIGNAL(debuggerUpdateGlobalTableValue(QString,QString,QList<int>)),
// debugger_,
// SLOT(updateGlobalTableValue(QString,QString,QList<int>)));
// connect(kumirRunner,
// SIGNAL(debuggerSetGlobals(QString,QStringList,QStringList,QList<int>)),
// debugger_,
// SLOT(setGlobals(QString,QStringList,QStringList,QList<int>))
// );
connect(kumirProgram_, SIGNAL(activateDocumentTab(int)),
mainWindow_, SLOT(activateDocumentTab(int)));
kumirProgram_->setDebuggerWindow(debugger_);
......@@ -562,6 +561,7 @@ void Plugin::changeGlobalState(ExtensionSystem::GlobalState old, ExtensionSystem
mainWindow_->setFocusOnCentralWidget();
mainWindow_->unlockActions();
debugger_->reset();
debugger_->setDebuggerEnabled(false);
}
else if (state==ExtensionSystem::GS_Observe) {
// m_kumirStateLabel->setText(tr("Observe"));
......@@ -577,6 +577,7 @@ void Plugin::changeGlobalState(ExtensionSystem::GlobalState old, ExtensionSystem
else if (state==ExtensionSystem::GS_Pause) {
// m_kumirStateLabel->setText(tr("Pause"));
mainWindow_->lockActions();
debugger_->setDebuggerEnabled(true);
}
else if (state==ExtensionSystem::GS_Input) {
// m_kumirStateLabel->setText(tr("Pause"));
......
......@@ -85,7 +85,7 @@ protected:
Term * m_terminal;
QMap<QString,QObject*> m_browserObjects;
KumirProgram * kumirProgram_;
class DebuggerWindow * debugger_;
class DebuggerView * debugger_;
DocBookViewer::DocBookView * helpViewer_;
QSplitter * bottomSplitter_;
Shared::CoursesInterface* courseManager_;
......
......@@ -11,6 +11,7 @@ set(SOURCES
commonrun.cpp
util.cpp
guirun.cpp
kumvariablesmodel.cpp
)
set(HEADERS
......@@ -22,6 +23,7 @@ set(MOC_HEADERS
run.h
commonrun.h
guirun.h
kumvariablesmodel.h
)
qt4_wrap_cpp(MOC_SOURCES ${MOC_HEADERS})
......
#include "kumvariablesmodel.h"
#include <QFont>
#include <QPalette>
#include <QApplication>
namespace KumirCodeRun {
static const int MAXIMUM_SHOWN_TABLE_ITEMS_COUNT = 255;
KumVariablesModel::KumVariablesModel(
VM::KumirVM * vm,
VM::CriticalSectionLocker * mutex,
QObject *parent)
: QAbstractItemModel(parent)
, vm_(vm)
, mutex_(mutex)
{
}
void KumVariablesModel::clear()
{
beginResetModel();
parents_.clear();
cache_.clear();
endResetModel();
}
QModelIndex KumVariablesModel::index(int row, int column, const QModelIndex &parent) const
{
if (!parent.isValid() && column > 0) {
return QModelIndex();
}
QModelIndex result;
if (!parent.isValid()) {
result = topLevelIndex(row);
}
else {
KumVariableItem * parentItem =
static_cast<KumVariableItem*>(parent.internalPointer());
if (parentItem->itemType() == KumVariableItem::GlobalsTable ||
parentItem->itemType() == KumVariableItem::LocalsTable)
{
result = valueIndex(row, column, parentItem->table());
}
else if (parentItem->itemType() == KumVariableItem::Variable ||
parentItem->itemType() == KumVariableItem::ArrayItem)
{
if (parentItem->variable()->dimension() > 0) {
result = arrayIndex(row, column, parentItem->variable(), parentItem->arrayIndeces());
}
}
}
return result;
}
QModelIndex KumVariablesModel::topLevelIndex(int row) const
{
mutex_->lock();
TableOfVariables * globalsTable = vm_->getMainModuleGlobals();
bool hasGlobals = globalsTable && globalsTable->size() > 0;
mutex_->unlock();
int globalsOffset = hasGlobals? -1 : 0;
KumVariableItem * result = nullptr;
if (hasGlobals && row == 0) {
for (int i=0; i<cache_.size(); i++) {
KumVariableItem * item = cache_[i];
if (item->itemType() == KumVariableItem::GlobalsTable) {
result = item;
break;
}
}
if (result == nullptr) {
mutex_->lock();
result = new KumVariableItem(vm_->getMainModuleGlobals(), row);
mutex_->unlock();
cache_.push_back(result);
}
}
else {
size_t stackIndex = size_t(row + globalsOffset);
mutex_->lock();
size_t stackSize = vm_->functionCallStackSize();
mutex_->unlock();
if (stackIndex < stackSize) {
mutex_->lock();
std::pair< std::wstring, TableOfVariables * > stackItem =
vm_->getLocalsAndName(stackIndex);
mutex_->unlock();
for (int i=0; i<cache_.size(); i++) {
KumVariableItem * item = cache_[i];
if (item->table() == stackItem.second) {
result = item;
break;
}
}
if (result == nullptr) {
const QString algorithmName =
QString::fromStdWString(stackItem.first);
result = new KumVariableItem(stackItem.second, row, algorithmName);
cache_.push_back(result);
}
}
}
return createIndex(row, 0, result);
}
QModelIndex KumVariablesModel::valueIndex(int row, int column, TableOfVariables *table) const
{
size_t indexInTable = size_t(row);
mutex_->lock();
size_t tableSize = table->size();
mutex_->unlock();
if (indexInTable >= tableSize) {
return QModelIndex();
}
mutex_->lock();
const VM::Variable * var = & table->at(indexInTable);
mutex_->unlock();
KumVariableItem * result = nullptr;
for (int i=0; i<cache_.size(); i++) {
KumVariableItem * item = cache_[i];
if (item->itemType() == KumVariableItem::Variable &&
item->variable() == var)
{
result = item;
break;
}
}
if (result == nullptr) {
result = new KumVariableItem(var, row, table);
cache_.push_back(result);
}
QModelIndex resultIndex;
if (modelIndeces_.contains(result)) {
resultIndex = modelIndeces_[result];
}
else {
resultIndex = createIndex(row, column, result);
modelIndeces_[result] = resultIndex;
}
return resultIndex;
}
QModelIndex KumVariablesModel::arrayIndex(
int row, int column,
const VM::Variable * variable,
const QVector<int> &prevIndeces
) const
{
QVector<int> newIndeces(prevIndeces.size() + 1);
qMemCopy(newIndeces.data(), prevIndeces.constData(), prevIndeces.size() * sizeof(int));
int bounds[7];
mutex_->lock();
variable->getEffectiveBounds(bounds);
mutex_->unlock();
int newIndex = row + bounds[2 * prevIndeces.size()];
newIndeces.last() = newIndex;
KumVariableItem * result = nullptr;
for (int i=0; i<cache_.size(); i++) {
KumVariableItem * item = cache_[i];
if (item->itemType() == KumVariableItem::ArrayItem &&
item->variable() == variable &&
item->arrayIndeces() == newIndeces)
{
result = item;
break;
}
}
if (result == nullptr) {
result = new KumVariableItem(variable, row, newIndeces);
cache_.push_back(result);
}
QModelIndex resultIndex;
if (modelIndeces_.contains(result)) {
resultIndex = modelIndeces_[result];
}
else {
resultIndex = createIndex(row, column, result);
modelIndeces_[result] = resultIndex;
}
return resultIndex;
}
QModelIndex KumVariablesModel::parent(const QModelIndex &child) const
{
if (!child.isValid()) {
return QModelIndex();
}
KumVariableItem * item =
static_cast<KumVariableItem*>(child.internalPointer());
if (item == nullptr) {
return QModelIndex();
}
if (item->itemType() == KumVariableItem::GlobalsTable ||
item->itemType() == KumVariableItem::LocalsTable)
{
return QModelIndex();
}
KumVariableItem * result = nullptr;
if (item->itemType() == KumVariableItem::Variable) {
for (int i=0; i<cache_.size(); i++) {
KumVariableItem * it = cache_[i];
if (it->itemType() == KumVariableItem::GlobalsTable ||
it->itemType() == KumVariableItem::LocalsTable)
{
if (it->table() == item->table()) {
result = it;
break;
}
}
}
}
else if (item->itemType() == KumVariableItem::ArrayItem) {
QVector<int> indeces = item->arrayIndeces();
indeces.pop_back();
if (indeces.isEmpty()) {
for (int i=0; i<cache_.size(); i++) {
KumVariableItem * it = cache_[i];
if (it->itemType() == KumVariableItem::Variable
&& it->variable() == item->variable())
{
result = it;
break;
}
}
}
else {
for (int i=0; i<cache_.size(); i++) {
KumVariableItem * it = cache_[i];
if (it->itemType() == KumVariableItem::ArrayItem
&& it->variable() == item->variable()
&& it->arrayIndeces() == indeces
)
{
result = it;
break;
}
}
}
}
return createIndex(result->numberInTable(), 0, result);
}
int KumVariablesModel::rowCount(const QModelIndex &parent) const
{
if (!parent.isValid()) {
// top level item
mutex_->lock();
int topLevelItemsCount = vm_->functionCallStackSize();
TableOfVariables * globalsTable = vm_->getMainModuleGlobals();
if (globalsTable && globalsTable->size() > 0)
topLevelItemsCount ++;
mutex_->unlock();
return topLevelItemsCount;
}
KumVariableItem * item =
static_cast<KumVariableItem*>(parent.internalPointer());
if (item->itemType() == KumVariableItem::GlobalsTable ||
item->itemType() == KumVariableItem::LocalsTable)
{
mutex_->lock();
size_t size = item->table()->size();
mutex_->unlock();
return size;
}
else if (item->itemType() == KumVariableItem::Variable && item->hasValue()) {
quint8 dim = item->variable()->dimension();
if (dim > 0) {
mutex_->lock();
int bounds[7];
item->variable()->getEffectiveBounds(bounds);
mutex_->unlock();
return bounds[1] - bounds[0] + 1;
}
}