5ac0166388
This commit adds support for the version of the hwstub library, which requires a lot of changes. It also adds some editing features, such as register access and much better editing of fields using the mouse (double click on a field to be able to resize and move it). Change-Id: I3c4e4cc855cb44911c72bc8127bad841b68efe52
1904 lines
No EOL
64 KiB
C++
1904 lines
No EOL
64 KiB
C++
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2014 by Amaury Pouly
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
#include "regedit.h"
|
|
#include <QFileDialog>
|
|
#include <QDebug>
|
|
#include <QHeaderView>
|
|
#include <QMessageBox>
|
|
#include <QInputDialog>
|
|
#include <QStandardItemModel>
|
|
|
|
/**
|
|
* EmptyEditPanel
|
|
*/
|
|
EmptyEditPanel::EmptyEditPanel(QWidget *parent)
|
|
:QWidget(parent)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* SocEditPanel
|
|
*/
|
|
|
|
namespace
|
|
{
|
|
|
|
template< typename T >
|
|
void my_remove_at(std::vector< T >& v, size_t at)
|
|
{
|
|
v.erase(v.begin() + at);
|
|
}
|
|
|
|
enum
|
|
{
|
|
SocEditPanelDelType = QTableWidgetItem::UserType,
|
|
SocEditPanelAddType,
|
|
};
|
|
|
|
}
|
|
|
|
SocEditPanel::SocEditPanel(const soc_desc::soc_ref_t& ref, QWidget *parent)
|
|
:QWidget(parent), m_ref(ref)
|
|
{
|
|
QLineEdit *name_edit = new QLineEdit(this);
|
|
QLineEdit *title_edit = new QLineEdit(this);
|
|
QLineEdit *isa_edit = new QLineEdit(this);
|
|
QLineEdit *version_edit = new QLineEdit(this);
|
|
|
|
m_authors_list = new QTableWidget(this);
|
|
QGroupBox *authors_group = Misc::EncloseInBox("Authors", m_authors_list);
|
|
|
|
m_desc_edit = new MyTextEditor(this);
|
|
|
|
QGroupBox *desc_group = Misc::EncloseInBox("Description", m_desc_edit);
|
|
|
|
QFormLayout *banner_left_layout = new QFormLayout;
|
|
banner_left_layout->addRow("Name:", name_edit);
|
|
banner_left_layout->addRow("Title:", title_edit);
|
|
banner_left_layout->addRow("Instruction Set:", isa_edit);
|
|
banner_left_layout->addRow("Version:", version_edit);
|
|
|
|
QGroupBox *banner_left_group = new QGroupBox("Information");
|
|
banner_left_group->setLayout(banner_left_layout);
|
|
|
|
QHBoxLayout *banner_layout = new QHBoxLayout;
|
|
banner_layout->addWidget(banner_left_group);
|
|
banner_layout->addWidget(authors_group);
|
|
banner_layout->addStretch(0);
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout;
|
|
layout->addLayout(banner_layout);
|
|
layout->addWidget(desc_group);
|
|
layout->addStretch(1);
|
|
|
|
/* fill data */
|
|
name_edit->setText(QString::fromStdString(ref.get()->name));
|
|
title_edit->setText(QString::fromStdString(ref.get()->title));
|
|
isa_edit->setText(QString::fromStdString(ref.get()->isa));
|
|
version_edit->setText(QString::fromStdString(ref.get()->version));
|
|
m_desc_edit->SetTextHtml(QString::fromStdString(ref.get()->desc));
|
|
|
|
m_authors_list->setColumnCount(2);
|
|
m_authors_list->setHorizontalHeaderItem(0, new QTableWidgetItem(""));
|
|
m_authors_list->setHorizontalHeaderItem(1, new QTableWidgetItem("Name"));
|
|
m_authors_list->horizontalHeader()->setVisible(false);
|
|
m_authors_list->verticalHeader()->setVisible(false);
|
|
m_authors_list->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
std::vector< std::string >& authors = ref.get()->author;
|
|
m_authors_list->setRowCount(authors.size() + 1);
|
|
for(size_t i = 0; i < authors.size(); i++)
|
|
{
|
|
QTableWidgetItem *item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", SocEditPanelDelType);
|
|
item->setToolTip("Remove this author");
|
|
item->setFlags(Qt::ItemIsEnabled);
|
|
m_authors_list->setItem(i, 0, item);
|
|
item = new QTableWidgetItem(QString::fromStdString(authors[i]));
|
|
m_authors_list->setItem(i, 1, item);
|
|
}
|
|
QTableWidgetItem *new_item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListAdd), "", SocEditPanelAddType);
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
m_authors_list->setItem(authors.size(), 0, new_item);
|
|
new_item = new QTableWidgetItem("New author...", QTableWidgetItem::UserType);
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
QFont font = new_item->font();
|
|
font.setItalic(true);
|
|
new_item->setFont(font);
|
|
m_authors_list->setItem(authors.size(), 1, new_item);
|
|
m_authors_list->resizeColumnsToContents();
|
|
m_authors_list->horizontalHeader()->setStretchLastSection(true);
|
|
|
|
connect(name_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnNameEdited(const QString&)));
|
|
connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnTextEdited()));
|
|
connect(title_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnTitleEdited(const QString&)));
|
|
connect(version_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnVersionEdited(const QString&)));
|
|
connect(isa_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnIsaEdited(const QString&)));
|
|
connect(m_authors_list, SIGNAL(itemActivated(QTableWidgetItem *)), this,
|
|
SLOT(OnAuthorActivated(QTableWidgetItem *)));
|
|
connect(m_authors_list, SIGNAL(itemChanged(QTableWidgetItem *)), this,
|
|
SLOT(OnAuthorChanged(QTableWidgetItem *)));
|
|
|
|
setLayout(layout);
|
|
}
|
|
|
|
void SocEditPanel::OnNameEdited(const QString& text)
|
|
{
|
|
m_ref.get()->name = text.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void SocEditPanel::OnTitleEdited(const QString& text)
|
|
{
|
|
m_ref.get()->title = text.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void SocEditPanel::OnVersionEdited(const QString& text)
|
|
{
|
|
m_ref.get()->version = text.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void SocEditPanel::OnIsaEdited(const QString& text)
|
|
{
|
|
m_ref.get()->isa = text.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void SocEditPanel::OnTextEdited()
|
|
{
|
|
m_ref.get()->desc = m_desc_edit->GetTextHtml().toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void SocEditPanel::OnAuthorActivated(QTableWidgetItem *item)
|
|
{
|
|
if(item->type() == SocEditPanelDelType)
|
|
{
|
|
int row = item->row();
|
|
my_remove_at(m_ref.get()->author, row);
|
|
m_authors_list->removeRow(row);
|
|
OnModified();
|
|
}
|
|
else if(item->type() == SocEditPanelAddType)
|
|
{
|
|
int row = m_ref.get()->author.size();
|
|
m_ref.get()->author.push_back("Anonymous");
|
|
m_authors_list->insertRow(row);
|
|
QTableWidgetItem *item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", SocEditPanelDelType);
|
|
item->setToolTip("Remove this author");
|
|
item->setFlags(Qt::ItemIsEnabled);
|
|
m_authors_list->setItem(row, 0, item);
|
|
item = new QTableWidgetItem(QString::fromStdString(m_ref.get()->author.back()));
|
|
m_authors_list->setItem(row, 1, item);
|
|
OnModified();
|
|
}
|
|
}
|
|
|
|
void SocEditPanel::OnAuthorChanged(QTableWidgetItem *item)
|
|
{
|
|
if((size_t)item->row() >= m_ref.get()->author.size())
|
|
return;
|
|
if(item->column() == 1)
|
|
m_ref.get()->author[item->row()] = item->text().toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
/**
|
|
* NodeInstanceEditPanel
|
|
*/
|
|
|
|
namespace
|
|
{
|
|
|
|
template< typename T >
|
|
soc_id_t GetFreshId(const std::vector< T >& list)
|
|
{
|
|
soc_id_t id = 0;
|
|
for(size_t i = 0; i < list.size(); i++)
|
|
id = std::max(id, list[i].id);
|
|
return id + 1;
|
|
}
|
|
|
|
template< typename T >
|
|
int GetIndexById(const std::vector< T >& list, soc_id_t id)
|
|
{
|
|
for(size_t i = 0; i < list.size(); i++)
|
|
if(list[i].id == id)
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
soc_desc::instance_t *GetInstanceById(const soc_desc::node_ref_t& node, soc_id_t id)
|
|
{
|
|
std::vector< soc_desc::instance_t >& inst_list = node.get()->instance;
|
|
for(size_t i = 0; i < inst_list.size(); i++)
|
|
if(inst_list[i].id == id)
|
|
return &inst_list[i];
|
|
return 0;
|
|
}
|
|
|
|
bool RemoveInstanceById(const soc_desc::node_ref_t& node, soc_id_t id)
|
|
{
|
|
std::vector< soc_desc::instance_t >& inst_list = node.get()->instance;
|
|
for(size_t i = 0; i < inst_list.size(); i++)
|
|
if(inst_list[i].id == id)
|
|
{
|
|
my_remove_at(inst_list, i);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
enum
|
|
{
|
|
InstTypeSingle,
|
|
InstTypeRangeStride,
|
|
InstTypeRangeFormula,
|
|
InstTypeRangeList
|
|
};
|
|
|
|
enum
|
|
{
|
|
NodeInstEditPanelDelType = QTableWidgetItem::UserType,
|
|
NodeInstEditPanelAddType
|
|
};
|
|
|
|
}
|
|
|
|
NodeInstanceEditPanel::NodeInstanceEditPanel(const soc_desc::node_ref_t& ref,
|
|
soc_id_t inst_id, QWidget *parent)
|
|
:QWidget(parent), m_ref(ref), m_id(inst_id)
|
|
{
|
|
QLineEdit *name_edit = new QLineEdit(this);
|
|
QLineEdit *title_edit = new QLineEdit(this);
|
|
m_type_combo = new QComboBox(this);
|
|
QLabel *type_label = new QLabel("Type:", this);
|
|
QFont f = type_label->font();
|
|
f.setBold(true);
|
|
type_label->setFont(f);
|
|
|
|
QHBoxLayout *type_layout = new QHBoxLayout;
|
|
type_layout->addWidget(type_label);
|
|
type_layout->addWidget(m_type_combo);
|
|
type_layout->addStretch(0);
|
|
|
|
soc_desc::field_t fake_field;
|
|
fake_field.pos = 0;
|
|
fake_field.width = 32;
|
|
|
|
m_single_group = new QWidget(this);
|
|
QHBoxLayout *sg_layout = new QHBoxLayout;
|
|
sg_layout->addWidget(new QLabel("Address:", m_single_group));
|
|
SocFieldEditor *addr_edit = new SocFieldEditor(fake_field, m_single_group);
|
|
sg_layout->addWidget(addr_edit);
|
|
m_single_group->setLayout(sg_layout);
|
|
|
|
m_range_group = new QWidget(this);
|
|
QGridLayout *rg_layout = new QGridLayout;
|
|
rg_layout->addWidget(new QLabel("First:", m_range_group), 0, 0);
|
|
QSpinBox *first_spin = new QSpinBox(m_range_group);
|
|
rg_layout->addWidget(first_spin, 0, 1);
|
|
rg_layout->addWidget(new QLabel("Count:", m_range_group), 1, 0);
|
|
QSpinBox *count_spin = new QSpinBox(m_range_group);
|
|
rg_layout->addWidget(count_spin, 1, 1);
|
|
m_range_group->setLayout(rg_layout);
|
|
|
|
m_stride_group = new QWidget(m_range_group);
|
|
QGridLayout *rsg_layout = new QGridLayout;
|
|
rsg_layout->addWidget(new QLabel("Base:", m_stride_group), 0, 0);
|
|
SocFieldEditor *base_edit = new SocFieldEditor(fake_field, m_stride_group);
|
|
rsg_layout->addWidget(base_edit, 0, 1);
|
|
rsg_layout->addWidget(new QLabel("Stride:", m_stride_group), 1, 0);
|
|
SocFieldEditor *stride_edit = new SocFieldEditor(fake_field, m_stride_group);
|
|
rsg_layout->addWidget(stride_edit, 1, 1);
|
|
m_stride_group->setLayout(rsg_layout);
|
|
|
|
m_formula_group = new QWidget(m_range_group);
|
|
QGridLayout *fsg_layout = new QGridLayout;
|
|
fsg_layout->addWidget(new QLabel("Variable:", m_formula_group), 0, 0);
|
|
QLineEdit *variable_edit = new QLineEdit(m_formula_group);
|
|
fsg_layout->addWidget(variable_edit, 0, 1);
|
|
fsg_layout->addWidget(new QLabel("Formula:", m_formula_group), 1, 0);
|
|
QLineEdit *formula_edit = new QLineEdit(m_formula_group);
|
|
fsg_layout->addWidget(formula_edit, 1, 1);
|
|
m_formula_group->setLayout(fsg_layout);
|
|
|
|
QTableWidget *addr_list = new QTableWidget(m_range_group);
|
|
m_list_group = addr_list;
|
|
|
|
QHBoxLayout *inst_layout = new QHBoxLayout;
|
|
inst_layout->addWidget(m_single_group);
|
|
inst_layout->addWidget(m_range_group);
|
|
inst_layout->addWidget(m_stride_group);
|
|
inst_layout->addWidget(m_formula_group);
|
|
inst_layout->addWidget(m_list_group);
|
|
inst_layout->addStretch(0);
|
|
|
|
QGroupBox *inst_groupbox = new QGroupBox(this);
|
|
inst_groupbox->setLayout(inst_layout);
|
|
|
|
MyTextEditor *desc_edit = new MyTextEditor(this);
|
|
QVBoxLayout *ii_layout = new QVBoxLayout;
|
|
|
|
QFormLayout *info_layout = new QFormLayout();
|
|
info_layout->addRow("Name", name_edit);
|
|
info_layout->addRow("Title", title_edit);
|
|
|
|
QGroupBox *info_group = Misc::EncloseInBox("Information", info_layout);
|
|
QGroupBox *desc_group = Misc::EncloseInBox("Description", desc_edit);
|
|
QHBoxLayout *name_title_desc_layout = new QHBoxLayout;
|
|
name_title_desc_layout->addWidget(info_group, 1);
|
|
name_title_desc_layout->addWidget(desc_group, 2);
|
|
|
|
ii_layout->addLayout(name_title_desc_layout);
|
|
ii_layout->addLayout(type_layout);
|
|
ii_layout->addWidget(inst_groupbox);
|
|
ii_layout->addStretch(1);
|
|
|
|
m_type_combo->addItem("Single", QVariant(InstTypeSingle));
|
|
m_type_combo->addItem("Range > Stride", QVariant(InstTypeRangeStride));
|
|
m_type_combo->addItem("Range > Formula", QVariant(InstTypeRangeFormula));
|
|
m_type_combo->addItem("Range > List", QVariant(InstTypeRangeList));
|
|
|
|
/* fill info */
|
|
soc_desc::instance_t& inst = GetInstance();
|
|
name_edit->setText(QString::fromStdString(inst.name));
|
|
title_edit->setText(QString::fromStdString(inst.title));
|
|
desc_edit->SetTextHtml(QString::fromStdString(inst.desc));
|
|
addr_edit->setField(inst.addr);
|
|
base_edit->setField(inst.range.base);
|
|
stride_edit->setField(inst.range.stride);
|
|
first_spin->setValue(inst.range.first);
|
|
count_spin->setValue(inst.range.count);
|
|
formula_edit->setText(QString::fromStdString(inst.range.formula));
|
|
variable_edit->setText(QString::fromStdString(inst.range.variable));
|
|
addr_list->setColumnCount(2);
|
|
addr_list->setHorizontalHeaderItem(0, new QTableWidgetItem(""));
|
|
addr_list->setHorizontalHeaderItem(1, new QTableWidgetItem("Address"));
|
|
addr_list->horizontalHeader()->setVisible(false);
|
|
addr_list->verticalHeader()->setVisible(false);
|
|
addr_list->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
std::vector< soc_word_t >& addrs = inst.range.list;
|
|
addr_list->setRowCount(addrs.size() + 1);
|
|
for(size_t i = 0; i < addrs.size(); i++)
|
|
{
|
|
QTableWidgetItem *item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", NodeInstEditPanelDelType);
|
|
item->setToolTip("Remove this address");
|
|
item->setFlags(Qt::ItemIsEnabled);
|
|
addr_list->setItem(i, 0, item);
|
|
item = new QTableWidgetItem();
|
|
item->setData(Qt::EditRole, QVariant::fromValue(addrs[i]));
|
|
addr_list->setItem(i, 1, item);
|
|
}
|
|
QTableWidgetItem *new_item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListAdd), "", NodeInstEditPanelAddType);
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
addr_list->setItem(addrs.size(), 0, new_item);
|
|
new_item = new QTableWidgetItem("New address...", QTableWidgetItem::UserType);
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
QFont font = new_item->font();
|
|
font.setItalic(true);
|
|
new_item->setFont(font);
|
|
addr_list->setItem(addrs.size(), 1, new_item);
|
|
addr_list->resizeColumnsToContents();
|
|
addr_list->horizontalHeader()->setStretchLastSection(true);
|
|
m_table_delegate = new SocFieldItemDelegate(this);
|
|
m_table_delegate->setItemEditorFactory(new QItemEditorFactory);
|
|
m_table_edit_factory = new SocFieldEditorCreator;
|
|
m_table_delegate->itemEditorFactory()->registerEditor(QVariant::UInt, m_table_edit_factory);
|
|
addr_list->setItemDelegate(m_table_delegate);
|
|
|
|
setLayout(ii_layout);
|
|
|
|
connect(name_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnNameEdited(const QString&)));
|
|
connect(desc_edit, SIGNAL(OnTextChanged(const QString&)), this,
|
|
SLOT(OnDescEdited(const QString&)));
|
|
connect(title_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnTitleEdited(const QString&)));
|
|
connect(addr_edit, SIGNAL(editingFinished(uint)), this, SLOT(OnAddrChanged(uint)));
|
|
connect(base_edit, SIGNAL(editingFinished(uint)), this, SLOT(OnBaseChanged(uint)));
|
|
connect(stride_edit, SIGNAL(editingFinished(uint)), this, SLOT(OnStrideChanged(uint)));
|
|
connect(first_spin, SIGNAL(valueChanged(int)), this, SLOT(OnFirstChanged(int)));
|
|
connect(count_spin, SIGNAL(valueChanged(int)), this, SLOT(OnCountChanged(int)));
|
|
connect(formula_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnFormulaChanged(const QString&)));
|
|
connect(variable_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnVariableChanged(const QString&)));
|
|
connect(m_type_combo, SIGNAL(currentIndexChanged(int)),
|
|
this, SLOT(OnTypeChanged(int)));
|
|
connect(addr_list, SIGNAL(itemActivated(QTableWidgetItem *)), this,
|
|
SLOT(OnAddressActivated(QTableWidgetItem *)));
|
|
connect(addr_list, SIGNAL(itemChanged(QTableWidgetItem *)), this,
|
|
SLOT(OnAddressChanged(QTableWidgetItem *)));
|
|
|
|
/* fill info */
|
|
int combo_type;
|
|
if(inst.type == soc_desc::instance_t::RANGE)
|
|
{
|
|
if(inst.range.type == soc_desc::range_t::STRIDE)
|
|
combo_type = InstTypeRangeStride;
|
|
else if(inst.range.type == soc_desc::range_t::FORMULA)
|
|
combo_type = InstTypeRangeFormula;
|
|
else /* LIST */
|
|
combo_type = InstTypeRangeList;
|
|
}
|
|
else
|
|
combo_type = InstTypeSingle;
|
|
m_type_combo->setCurrentIndex(m_type_combo->findData(QVariant(combo_type)));
|
|
UpdateType(combo_type);
|
|
}
|
|
|
|
soc_desc::instance_t& NodeInstanceEditPanel::GetInstance()
|
|
{
|
|
return *GetInstanceById(m_ref, m_id);
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnNameEdited(const QString& text)
|
|
{
|
|
GetInstance().name = text.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnTitleEdited(const QString& text)
|
|
{
|
|
GetInstance().title = text.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnDescEdited(const QString& text)
|
|
{
|
|
GetInstance().desc = text.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnAddrChanged(uint addr)
|
|
{
|
|
GetInstance().addr = addr;
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnBaseChanged(uint base)
|
|
{
|
|
GetInstance().range.base = base;
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnStrideChanged(uint stride)
|
|
{
|
|
GetInstance().range.stride = stride;
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnFirstChanged(int first)
|
|
{
|
|
GetInstance().range.first = first;
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnCountChanged(int count)
|
|
{
|
|
GetInstance().range.count = count;
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnFormulaChanged(const QString& formula)
|
|
{
|
|
GetInstance().range.formula = formula.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnVariableChanged(const QString& variable)
|
|
{
|
|
GetInstance().range.variable = variable.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnAddressActivated(QTableWidgetItem *item)
|
|
{
|
|
QTableWidget *table = item->tableWidget();
|
|
soc_desc::instance_t& inst = GetInstance();
|
|
if(item->type() == NodeInstEditPanelDelType)
|
|
{
|
|
int row = item->row();
|
|
my_remove_at(inst.range.list, row);
|
|
table->removeRow(row);
|
|
OnModified();
|
|
}
|
|
else if(item->type() == NodeInstEditPanelAddType)
|
|
{
|
|
int row = inst.range.list.size();
|
|
soc_word_t new_addr = 0;
|
|
GetInstance().range.list.push_back(new_addr);
|
|
table->insertRow(row);
|
|
QTableWidgetItem *item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", NodeInstEditPanelDelType);
|
|
item->setToolTip("Remove this address");
|
|
item->setFlags(Qt::ItemIsEnabled);
|
|
table->setItem(row, 0, item);
|
|
item = new QTableWidgetItem();
|
|
item->setData(Qt::EditRole, QVariant(new_addr));
|
|
table->setItem(row, 1, item);
|
|
OnModified();
|
|
}
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnAddressChanged(QTableWidgetItem *item)
|
|
{
|
|
soc_desc::instance_t& inst = GetInstance();
|
|
if((size_t)item->row() >= inst.range.list.size())
|
|
return;
|
|
soc_word_t& addr = inst.range.list[item->row()];
|
|
if(item->column() == 1)
|
|
addr = item->data(Qt::EditRole).value< soc_word_t >();
|
|
OnModified();
|
|
}
|
|
|
|
void NodeInstanceEditPanel::UpdateType(int type)
|
|
{
|
|
m_single_group->hide();
|
|
m_range_group->hide();
|
|
m_stride_group->hide();
|
|
m_formula_group->hide();
|
|
m_list_group->hide();
|
|
|
|
switch(type)
|
|
{
|
|
case InstTypeSingle:
|
|
m_single_group->show();
|
|
GetInstance().type = soc_desc::instance_t::SINGLE;
|
|
break;
|
|
case InstTypeRangeStride:
|
|
m_range_group->show();
|
|
m_stride_group->show();
|
|
GetInstance().type = soc_desc::instance_t::RANGE;
|
|
GetInstance().range.type = soc_desc::range_t::STRIDE;
|
|
break;
|
|
case InstTypeRangeFormula:
|
|
m_range_group->show();
|
|
m_formula_group->show();
|
|
GetInstance().type = soc_desc::instance_t::RANGE;
|
|
GetInstance().range.type = soc_desc::range_t::FORMULA;
|
|
break;
|
|
case InstTypeRangeList:
|
|
m_range_group->show();
|
|
m_formula_group->hide();
|
|
m_list_group->show();
|
|
GetInstance().type = soc_desc::instance_t::RANGE;
|
|
GetInstance().range.type = soc_desc::range_t::LIST;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void NodeInstanceEditPanel::OnTypeChanged(int index)
|
|
{
|
|
if(index == -1)
|
|
return;
|
|
UpdateType(m_type_combo->itemData(index).toInt());
|
|
OnModified();
|
|
}
|
|
|
|
soc_id_t NodeInstanceEditPanel::GetId()
|
|
{
|
|
return m_id;
|
|
}
|
|
|
|
/**
|
|
* NodeEditPanel
|
|
*/
|
|
|
|
NodeEditPanel::NodeEditPanel(const soc_desc::node_ref_t& ref, QWidget *parent)
|
|
:QWidget(parent), m_ref(ref)
|
|
{
|
|
/* top layout: name, title then desc */
|
|
QLineEdit *name_edit = new QLineEdit(this);
|
|
name_edit->setText(QString::fromStdString(ref.get()->name));
|
|
|
|
QLineEdit *title_edit = new QLineEdit(this);
|
|
title_edit->setText(QString::fromStdString(ref.get()->title));
|
|
|
|
QFormLayout *info_layout = new QFormLayout();
|
|
info_layout->addRow("Name", name_edit);
|
|
info_layout->addRow("Title", title_edit);
|
|
|
|
QGroupBox *info_group = Misc::EncloseInBox("Information", info_layout);
|
|
|
|
m_desc_edit = new MyTextEditor(this);
|
|
m_desc_edit->SetTextHtml(QString::fromStdString(ref.get()->desc));
|
|
QGroupBox *desc_group = Misc::EncloseInBox("Description", m_desc_edit);
|
|
|
|
QHBoxLayout *name_title_desc_layout = new QHBoxLayout;
|
|
name_title_desc_layout->addWidget(info_group, 1);
|
|
name_title_desc_layout->addWidget(desc_group, 2);
|
|
|
|
/* instance tab */
|
|
m_instances_tab = new YTabWidget(0, this);
|
|
m_instances_tab->setTabOpenable(true);
|
|
std::vector< soc_desc::instance_t >& inst_list = m_ref.get()->instance;
|
|
m_instances_tab->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
|
m_instances_tab->setTabsClosable(true);
|
|
QGroupBox *instance_tab_group = Misc::EncloseInBox("Instances", m_instances_tab);
|
|
for(size_t i = 0; i < inst_list.size(); i++)
|
|
{
|
|
NodeInstanceEditPanel *p = new NodeInstanceEditPanel(m_ref, inst_list[i].id, this);
|
|
connect(p, SIGNAL(OnModified()), this, SLOT(OnInstModified()));
|
|
m_instances_tab->addTab(p, QString::fromStdString(inst_list[i].name));
|
|
}
|
|
|
|
/* boring */
|
|
QVBoxLayout *layout = new QVBoxLayout;
|
|
layout->addLayout(name_title_desc_layout);
|
|
layout->addWidget(instance_tab_group);
|
|
layout->addStretch(1);
|
|
|
|
setLayout(layout);
|
|
|
|
connect(name_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnNameEdited(const QString&)));
|
|
connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnDescEdited()));
|
|
connect(title_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnTitleEdited(const QString&)));
|
|
connect(m_instances_tab, SIGNAL(tabCloseRequested(int)), this,
|
|
SLOT(OnInstRemove(int)));
|
|
connect(m_instances_tab, SIGNAL(tabOpenRequested()), this, SLOT(OnInstCreate()));
|
|
}
|
|
|
|
void NodeEditPanel::OnNameEdited(const QString& text)
|
|
{
|
|
m_ref.get()->name = text.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void NodeEditPanel::OnTitleEdited(const QString& text)
|
|
{
|
|
m_ref.get()->title = text.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void NodeEditPanel::OnDescEdited()
|
|
{
|
|
m_ref.get()->desc = m_desc_edit->GetTextHtml().toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void NodeEditPanel::OnInstRemove(int index)
|
|
{
|
|
NodeInstanceEditPanel *panel =
|
|
dynamic_cast< NodeInstanceEditPanel * >(m_instances_tab->widget(index));
|
|
RemoveInstanceById(m_ref, panel->GetId());
|
|
m_instances_tab->removeTab(index);
|
|
delete panel;
|
|
OnModified();
|
|
}
|
|
|
|
void NodeEditPanel::OnInstModified()
|
|
{
|
|
int index = m_instances_tab->currentIndex();
|
|
NodeInstanceEditPanel *panel =
|
|
dynamic_cast< NodeInstanceEditPanel * >(m_instances_tab->widget(index));
|
|
m_instances_tab->setTabText(index, QString::fromStdString(panel->GetInstance().name));
|
|
OnModified();
|
|
}
|
|
|
|
QString NodeEditPanel::GuessName()
|
|
{
|
|
/* try to find instances named Xddd where X is the node name (case insensitive)
|
|
* and d are digits. */
|
|
int max_nr_digits = -1;
|
|
int max_value = -1;
|
|
QString node_name = QString::fromStdString(m_ref.get()->name);
|
|
std::vector< soc_desc::instance_t >& inst_list = m_ref.get()->instance;
|
|
for(size_t i = 0; i < inst_list.size(); i++)
|
|
{
|
|
QString inst_name = QString::fromStdString(inst_list[i].name);
|
|
/* ignore name if it doesn't start like the node name */
|
|
if(!inst_name.startsWith(node_name, Qt::CaseInsensitive))
|
|
continue;
|
|
/* check if the suffix is a digit */
|
|
QString suffix = inst_name.mid(node_name.size());
|
|
if(suffix.size() == 0)
|
|
{
|
|
max_nr_digits = qMax(max_nr_digits, 0);
|
|
continue;
|
|
}
|
|
bool ok;
|
|
int value = suffix.toUInt(&ok);
|
|
if(!ok)
|
|
continue;
|
|
max_value = qMax(max_value, value);
|
|
max_nr_digits = qMax(max_nr_digits, suffix.size());
|
|
}
|
|
/* if no match, use node name */
|
|
if(max_nr_digits == -1)
|
|
return node_name;
|
|
/* match of size 0, add "1" at the end */
|
|
if(max_nr_digits == 0)
|
|
return node_name + "1";
|
|
/* otherwise, pick next value */
|
|
return QString("%1%2").arg(node_name)
|
|
.arg(max_value + 1, max_nr_digits, 10, QChar('0'));
|
|
}
|
|
|
|
void NodeEditPanel::OnInstCreate()
|
|
{
|
|
std::vector< soc_desc::instance_t >& inst_list = m_ref.get()->instance;
|
|
soc_desc::instance_t inst;
|
|
inst.id = GetFreshId(inst_list);
|
|
inst.name = GuessName().toStdString();
|
|
inst.type = soc_desc::instance_t::SINGLE;
|
|
inst.addr = 0;
|
|
inst.range.type = soc_desc::range_t::STRIDE;
|
|
inst.range.first = 0;
|
|
inst.range.count = 0;
|
|
inst.range.stride = 0;
|
|
inst_list.push_back(inst);
|
|
NodeInstanceEditPanel *p = new NodeInstanceEditPanel(m_ref, inst.id, this);
|
|
connect(p, SIGNAL(OnModified()), this, SLOT(OnInstModified()));
|
|
int idx = m_instances_tab->addTab(p, QString::fromStdString(inst.name));
|
|
m_instances_tab->setCurrentIndex(idx);
|
|
OnModified();
|
|
}
|
|
|
|
/**
|
|
* RegFieldEditPanel
|
|
*/
|
|
|
|
namespace
|
|
{
|
|
|
|
enum
|
|
{
|
|
RegFieldEditPanelDelType = QTableWidgetItem::UserType,
|
|
RegFieldEditPanelAddType,
|
|
};
|
|
|
|
}
|
|
|
|
RegFieldEditPanel::RegFieldEditPanel(const soc_desc::field_ref_t& ref, QWidget *parent)
|
|
:QWidget(parent), m_ref(ref)
|
|
{
|
|
m_name_edit = new QLineEdit(this);
|
|
m_range_edit = new QLineEdit(this);
|
|
m_range_validator = new SocBitRangeValidator(this);
|
|
m_range_validator->setWidth(m_ref.reg().get()->width);
|
|
m_range_edit->setValidator(m_range_validator);
|
|
m_desc_edit = new MyTextEditor(this);
|
|
QHBoxLayout *namepos_layout = new QHBoxLayout;
|
|
namepos_layout->addWidget(new QLabel("Name:"));
|
|
namepos_layout->addWidget(m_name_edit);
|
|
namepos_layout->addWidget(new QLabel("Range:"));
|
|
namepos_layout->addWidget(m_range_edit);
|
|
QVBoxLayout *nameposdesc_layout = new QVBoxLayout;
|
|
nameposdesc_layout->addWidget(Misc::EncloseInBox("Information", namepos_layout));
|
|
nameposdesc_layout->addWidget(Misc::EncloseInBox("Description", m_desc_edit));
|
|
nameposdesc_layout->addStretch(0);
|
|
|
|
m_enum_table = new QTableWidget(this);
|
|
m_enum_table->setColumnCount(4);
|
|
m_enum_table->setHorizontalHeaderItem(0, new QTableWidgetItem(""));
|
|
m_enum_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Name"));
|
|
m_enum_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Value"));
|
|
m_enum_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Description"));
|
|
m_enum_table->verticalHeader()->setVisible(false);
|
|
m_enum_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
m_enum_delegate = new SocFieldItemDelegate(this);
|
|
m_enum_delegate->setItemEditorFactory(new QItemEditorFactory);
|
|
m_enum_editor = new SocFieldEditorCreator;
|
|
m_enum_delegate->itemEditorFactory()->registerEditor(QVariant::UInt, m_enum_editor);
|
|
m_enum_table->setItemDelegate(m_enum_delegate);
|
|
|
|
QHBoxLayout *field_layout = new QHBoxLayout;
|
|
field_layout->addLayout(nameposdesc_layout);
|
|
field_layout->addWidget(Misc::EncloseInBox("Special Values", m_enum_table), 1);
|
|
|
|
setLayout(field_layout);
|
|
|
|
const soc_desc::field_t& field = *m_ref.get();
|
|
m_name_edit->setText(QString::fromStdString(field.name));
|
|
m_range_edit->setText(m_range_validator->generate(
|
|
field.pos + field.width - 1, field.pos));
|
|
m_desc_edit->SetTextHtml(QString::fromStdString(field.desc));
|
|
m_enum_delegate->setWidth(field.width);
|
|
m_enum_editor->setWidth(field.width);
|
|
m_enum_table->setRowCount(field.enum_.size() + 1);
|
|
for(size_t i = 0; i < field.enum_.size(); i++)
|
|
{
|
|
QTableWidgetItem *item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", RegFieldEditPanelDelType);
|
|
item->setToolTip("Remove this enum");
|
|
item->setFlags(Qt::ItemIsEnabled);
|
|
m_enum_table->setItem(i, 0, item);
|
|
item = new QTableWidgetItem(QString::fromStdString(field.enum_[i].name));
|
|
m_enum_table->setItem(i, 1, item);
|
|
item = new QTableWidgetItem();
|
|
item->setData(Qt::EditRole, QVariant(field.enum_[i].value));
|
|
m_enum_table->setItem(i, 2, item);
|
|
item = new QTableWidgetItem(QString::fromStdString(field.enum_[i].desc));
|
|
m_enum_table->setItem(i, 3, item);
|
|
}
|
|
QTableWidgetItem *new_item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListAdd), "", RegFieldEditPanelAddType);
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
m_enum_table->setItem(field.enum_.size(), 0, new_item);
|
|
new_item = new QTableWidgetItem("New field...");
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
QFont font = new_item->font();
|
|
font.setItalic(true);
|
|
new_item->setFont(font);
|
|
m_enum_table->setItem(field.enum_.size(), 1, new_item);
|
|
new_item = new QTableWidgetItem();
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
m_enum_table->setItem(field.enum_.size(), 2, new_item);
|
|
new_item = new QTableWidgetItem();
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
m_enum_table->setItem(field.enum_.size(), 3, new_item);
|
|
m_enum_table->resizeColumnsToContents();
|
|
m_enum_table->horizontalHeader()->setStretchLastSection(true);
|
|
|
|
connect(m_name_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnFieldNameChanged(const QString&)));
|
|
connect(m_range_edit, SIGNAL(textChanged(const QString&)), this,
|
|
SLOT(OnFieldRangeChanged(const QString&)));
|
|
connect(m_desc_edit, SIGNAL(OnTextChanged(const QString&)), this,
|
|
SLOT(OnFieldDescChanged(const QString&)));
|
|
connect(m_enum_table, SIGNAL(itemActivated(QTableWidgetItem *)), this,
|
|
SLOT(OnFieldValueActivated(QTableWidgetItem *)));
|
|
connect(m_enum_table, SIGNAL(itemChanged(QTableWidgetItem *)), this,
|
|
SLOT(OnFieldValueChanged(QTableWidgetItem *)));
|
|
}
|
|
|
|
void RegFieldEditPanel::UpdateWidth()
|
|
{
|
|
m_range_validator->setWidth(m_ref.reg().get()->width);
|
|
}
|
|
|
|
void RegFieldEditPanel::UpdateRange()
|
|
{
|
|
soc_desc::field_t *field = m_ref.get();
|
|
m_range_edit->setText(m_range_validator->generate(
|
|
field->pos + field->width - 1, field->pos));
|
|
}
|
|
|
|
void RegFieldEditPanel::OnFieldValueActivated(QTableWidgetItem *item)
|
|
{
|
|
if(item->type() == RegFieldEditPanelDelType)
|
|
{
|
|
int row = item->row();
|
|
my_remove_at(m_ref.get()->enum_, row);
|
|
m_enum_table->removeRow(row);
|
|
OnModified();
|
|
}
|
|
else if(item->type() == RegFieldEditPanelAddType)
|
|
{
|
|
soc_desc::field_t& field = *m_ref.get();
|
|
int row = field.enum_.size();
|
|
soc_desc::enum_t new_enum;
|
|
new_enum.id = GetFreshId(field.enum_);
|
|
new_enum.name = "UNNAMED";
|
|
new_enum.value = 0;
|
|
field.enum_.push_back(new_enum);
|
|
m_enum_table->insertRow(row);
|
|
QTableWidgetItem *item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", RegFieldEditPanelDelType);
|
|
item->setToolTip("Remove this enum");
|
|
item->setFlags(Qt::ItemIsEnabled);
|
|
m_enum_table->setItem(row, 0, item);
|
|
item = new QTableWidgetItem(QString::fromStdString(new_enum.name));
|
|
m_enum_table->setItem(row, 1, item);
|
|
item = new QTableWidgetItem();
|
|
item->setData(Qt::EditRole, QVariant(new_enum.value));
|
|
m_enum_table->setItem(row, 2, item);
|
|
item = new QTableWidgetItem(QString::fromStdString(new_enum.desc));
|
|
m_enum_table->setItem(row, 3, item);
|
|
OnModified();
|
|
}
|
|
}
|
|
|
|
void RegFieldEditPanel::OnFieldValueChanged(QTableWidgetItem *item)
|
|
{
|
|
soc_desc::field_t& field = *m_ref.get();
|
|
if((size_t)item->row() >= field.enum_.size())
|
|
return;
|
|
soc_desc::enum_t& enum_ = field.enum_[item->row()];
|
|
if(item->column() == 1)
|
|
enum_.name = item->text().toStdString();
|
|
else if(item->column() == 2)
|
|
enum_.value = item->data(Qt::EditRole).value< soc_word_t >();
|
|
else if(item->column() == 3)
|
|
enum_.desc = item->text().toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void RegFieldEditPanel::OnFieldNameChanged(const QString& name)
|
|
{
|
|
m_ref.get()->name = name.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void RegFieldEditPanel::OnFieldRangeChanged(const QString& range)
|
|
{
|
|
soc_desc::field_t *field = m_ref.get();
|
|
int last, first;
|
|
if(m_range_validator->parse(range, last, first) != QValidator::Acceptable)
|
|
return;
|
|
field->pos = first;
|
|
field->width = last - first + 1;
|
|
m_enum_delegate->setWidth(field->width);
|
|
m_enum_editor->setWidth(field->width);
|
|
OnModified();
|
|
}
|
|
|
|
void RegFieldEditPanel::OnFieldDescChanged(const QString& desc)
|
|
{
|
|
m_ref.get()->desc = desc.toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
soc_desc::field_ref_t RegFieldEditPanel::GetField()
|
|
{
|
|
return m_ref;
|
|
}
|
|
|
|
/**
|
|
* RegEditPanel
|
|
*/
|
|
|
|
namespace
|
|
{
|
|
|
|
enum
|
|
{
|
|
RegVariantEditPanelDelType = QTableWidgetItem::UserType,
|
|
RegVariantEditPanelAddType,
|
|
};
|
|
|
|
}
|
|
|
|
RegEditPanel::RegEditPanel(const soc_desc::register_ref_t& ref, QWidget *parent)
|
|
:QWidget(parent), m_ref(ref), m_reg_font(font())
|
|
{
|
|
m_reg_font.setWeight(100);
|
|
m_reg_font.setKerning(false);
|
|
|
|
m_value_model = new RegFieldTableModel(this); // view takes ownership
|
|
m_value_model->SetRegister(*ref.get());
|
|
m_value_model->SetReadOnly(false);
|
|
|
|
m_sexy_display2 = new Unscroll<YRegDisplay>(this);
|
|
m_sexy_display2->setFont(m_reg_font);
|
|
m_sexy_display2->setModel(m_value_model);
|
|
m_sexy_display2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
m_sexy_display2->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
m_sexy_display2->setWidth(m_ref.get()->width);
|
|
|
|
m_view_tab = new QTabWidget(this);
|
|
m_view_tab->setTabPosition(QTabWidget::West);
|
|
|
|
/* field tab */
|
|
m_fields_tab = new YTabWidget(0, this);
|
|
m_fields_tab->setTabOpenable(true);
|
|
std::vector< soc_desc::field_ref_t > field_list = m_ref.fields();
|
|
m_fields_tab->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
|
|
m_fields_tab->setTabsClosable(true);
|
|
m_fields_tab->setElideMode(Qt::ElideRight);
|
|
for(size_t i = 0; i < field_list.size(); i++)
|
|
{
|
|
RegFieldEditPanel *p = new RegFieldEditPanel(field_list[i], this);
|
|
connect(p, SIGNAL(OnModified()), this, SLOT(OnFieldModified()));
|
|
m_fields_tab->addTab(p, QString::fromStdString(field_list[i].get()->name));
|
|
}
|
|
|
|
m_reg_size_group = new QButtonGroup(this);
|
|
QRadioButton *reg_size_32 = new QRadioButton("32-bit");
|
|
QRadioButton *reg_size_16 = new QRadioButton("16-bit");
|
|
QRadioButton *reg_size_8 = new QRadioButton("8-bit");
|
|
m_reg_size_group->addButton(reg_size_32, 32);
|
|
m_reg_size_group->addButton(reg_size_16, 16);
|
|
m_reg_size_group->addButton(reg_size_8, 8);
|
|
if(m_reg_size_group->button(m_ref.get()->width))
|
|
m_reg_size_group->button(m_ref.get()->width)->click();
|
|
QVBoxLayout *width_group_layout = new QVBoxLayout;
|
|
width_group_layout->addWidget(reg_size_32);
|
|
width_group_layout->addWidget(reg_size_16);
|
|
width_group_layout->addWidget(reg_size_8);
|
|
QGroupBox *width_group = new QGroupBox("Width");
|
|
width_group->setLayout(width_group_layout);
|
|
|
|
m_reg_access_group = new QButtonGroup(this);
|
|
QRadioButton *reg_dflt = new QRadioButton("Unspecified");
|
|
QRadioButton *reg_rw = new QRadioButton("Read-Write");
|
|
QRadioButton *reg_ro = new QRadioButton("Read-Only");
|
|
QRadioButton *reg_wo = new QRadioButton("Write-Only");
|
|
m_reg_access_group->addButton(reg_dflt, soc_desc::UNSPECIFIED);
|
|
m_reg_access_group->addButton(reg_rw, soc_desc::READ_WRITE);
|
|
m_reg_access_group->addButton(reg_ro, soc_desc::READ_ONLY);
|
|
m_reg_access_group->addButton(reg_wo, soc_desc::WRITE_ONLY);
|
|
if(m_reg_access_group->button(m_ref.get()->access))
|
|
m_reg_access_group->button(m_ref.get()->access)->click();
|
|
QVBoxLayout *access_group_layout = new QVBoxLayout;
|
|
access_group_layout->addWidget(reg_dflt);
|
|
access_group_layout->addWidget(reg_rw);
|
|
access_group_layout->addWidget(reg_ro);
|
|
access_group_layout->addWidget(reg_wo);
|
|
QGroupBox *access_group = new QGroupBox("Access");
|
|
access_group->setLayout(access_group_layout);
|
|
|
|
QVBoxLayout *width_access_layout = new QVBoxLayout;
|
|
width_access_layout->addWidget(width_group);
|
|
width_access_layout->addWidget(access_group);
|
|
width_access_layout->addStretch(0);
|
|
|
|
m_variant_table = new QTableWidget;
|
|
m_variant_table->setColumnCount(4);
|
|
m_variant_table->setHorizontalHeaderItem(0, new QTableWidgetItem(""));
|
|
m_variant_table->setHorizontalHeaderItem(1, new QTableWidgetItem("Type"));
|
|
m_variant_table->setHorizontalHeaderItem(2, new QTableWidgetItem("Offset"));
|
|
m_variant_table->setHorizontalHeaderItem(3, new QTableWidgetItem("Access"));
|
|
m_variant_table->verticalHeader()->setVisible(false);
|
|
m_variant_table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
m_variant_delegate = new SocFieldItemDelegate(this);
|
|
m_variant_delegate->setItemEditorFactory(new QItemEditorFactory);
|
|
m_variant_delegate->itemEditorFactory()->registerEditor(QVariant::UInt,
|
|
new SocFieldEditorCreator);
|
|
m_variant_table->setItemDelegate(m_variant_delegate);
|
|
m_access_delegate = new SocAccessItemDelegate("Unspecified", this);
|
|
m_access_delegate->setItemEditorFactory(new QItemEditorFactory);
|
|
// FIXME see QTBUG-30392
|
|
m_access_delegate->itemEditorFactory()->registerEditor(
|
|
(QVariant::Type)qMetaTypeId< soc_desc::access_t >(),
|
|
new SocAccessEditorCreator);
|
|
m_variant_table->setItemDelegateForColumn(3, m_access_delegate);
|
|
|
|
std::vector< soc_desc::variant_ref_t > variants = m_ref.variants();
|
|
m_variant_table->setRowCount(variants.size() + 1);
|
|
for(size_t i = 0; i < variants.size(); i++)
|
|
{
|
|
QTableWidgetItem *item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", RegVariantEditPanelDelType);
|
|
item->setToolTip("Remove this variant");
|
|
item->setFlags(Qt::ItemIsEnabled);
|
|
m_variant_table->setItem(i, 0, item);
|
|
item = new QTableWidgetItem(QString::fromStdString(variants[i].get()->type));
|
|
m_variant_table->setItem(i, 1, item);
|
|
item = new QTableWidgetItem();
|
|
item->setData(Qt::EditRole, QVariant(variants[i].get()->offset));
|
|
m_variant_table->setItem(i, 2, item);
|
|
item = new QTableWidgetItem();
|
|
item->setData(Qt::EditRole, QVariant::fromValue(variants[i].get()->access));
|
|
m_variant_table->setItem(i, 3, item);
|
|
}
|
|
QTableWidgetItem *new_item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListAdd), "", RegVariantEditPanelAddType);
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
m_variant_table->setItem(variants.size(), 0, new_item);
|
|
new_item = new QTableWidgetItem("New variant...");
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
QFont font = new_item->font();
|
|
font.setItalic(true);
|
|
new_item->setFont(font);
|
|
m_variant_table->setItem(variants.size(), 1, new_item);
|
|
new_item = new QTableWidgetItem();
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
m_variant_table->setItem(variants.size(), 2, new_item);
|
|
new_item = new QTableWidgetItem();
|
|
new_item->setFlags(Qt::ItemIsEnabled);
|
|
m_variant_table->resizeColumnsToContents();
|
|
m_variant_table->horizontalHeader()->setStretchLastSection(true);
|
|
|
|
m_desc_edit = new MyTextEditor(this);
|
|
m_desc_edit->SetTextHtml(QString::fromStdString(ref.get()->desc));
|
|
|
|
QHBoxLayout *top_info_layout = new QHBoxLayout;
|
|
top_info_layout->addLayout(width_access_layout);
|
|
top_info_layout->addWidget(Misc::EncloseInBox("Variants", m_variant_table));
|
|
top_info_layout->addWidget(Misc::EncloseInBox("Description", m_desc_edit));
|
|
|
|
QWidget *reg_info = new QWidget(this);
|
|
QVBoxLayout *reg_info_layout = new QVBoxLayout;
|
|
reg_info_layout->addLayout(top_info_layout);
|
|
reg_info_layout->addStretch(0);
|
|
reg_info->setLayout(reg_info_layout);
|
|
|
|
m_view_tab->addTab(reg_info, "Information");
|
|
m_view_tab->addTab(m_fields_tab, "Fields");
|
|
|
|
QVBoxLayout *main_layout = new QVBoxLayout;
|
|
main_layout->addWidget(m_sexy_display2, 1);
|
|
main_layout->addWidget(m_view_tab, 2);
|
|
|
|
m_delete_action = new QAction("&Delete", this);
|
|
m_delete_action->setIcon(YIconManager::Get()->GetIcon(YIconManager::ListRemove));
|
|
m_new_action = new QAction("&New field", this);
|
|
m_new_action->setIcon(YIconManager::Get()->GetIcon(YIconManager::ListAdd));
|
|
|
|
setLayout(main_layout);
|
|
|
|
OnRegFieldActivated(QModelIndex());
|
|
UpdateWidthRestrictions();
|
|
|
|
connect(m_sexy_display2, SIGNAL(clicked(const QModelIndex&)), this,
|
|
SLOT(OnRegFieldActivated(const QModelIndex&)));
|
|
connect(m_sexy_display2, SIGNAL(customContextMenuRequested(QPoint)), this,
|
|
SLOT(OnRegDisplayContextMenu(QPoint)));
|
|
connect(m_reg_size_group, SIGNAL(buttonClicked(int)), this, SLOT(OnWidthChanged(int)));
|
|
connect(m_reg_access_group, SIGNAL(buttonClicked(int)), this, SLOT(OnAccessChanged(int)));
|
|
connect(m_delete_action, SIGNAL(triggered()), this, SLOT(OnRegFieldDelete()));
|
|
connect(m_new_action, SIGNAL(triggered()), this, SLOT(OnRegFieldNew()));
|
|
connect(m_variant_table, SIGNAL(itemActivated(QTableWidgetItem *)), this,
|
|
SLOT(OnVariantActivated(QTableWidgetItem *)));
|
|
connect(m_variant_table, SIGNAL(itemChanged(QTableWidgetItem *)), this,
|
|
SLOT(OnVariantValueChanged(QTableWidgetItem *)));
|
|
connect(m_desc_edit, SIGNAL(OnTextChanged()), this, SLOT(OnDescEdited()));
|
|
connect(m_fields_tab, SIGNAL(tabCloseRequested(int)), this, SLOT(OnFieldRemove(int)));
|
|
connect(m_fields_tab, SIGNAL(tabOpenRequested()), this, SLOT(OnFieldCreate()));
|
|
connect(m_value_model, SIGNAL(OnBitrangeModified(int)), this, SLOT(OnBitrangeModified(int)));
|
|
}
|
|
|
|
void RegEditPanel::UpdateWidthRestrictions()
|
|
{
|
|
/* only allow width large enough to fit all fields */
|
|
size_t max_bit = 0;
|
|
std::vector< soc_desc::field_ref_t > field_list = m_ref.fields();
|
|
for(size_t i = 0; i < field_list.size(); i++)
|
|
{
|
|
soc_desc::field_t& f = *field_list[i].get();
|
|
max_bit = std::max(max_bit, f.pos + f.width - 1);
|
|
}
|
|
/* update buttons */
|
|
m_reg_size_group->button(8)->setEnabled(max_bit < 8);
|
|
m_reg_size_group->button(16)->setEnabled(max_bit < 16);
|
|
m_reg_size_group->button(32)->setEnabled(max_bit < 32);
|
|
}
|
|
|
|
int RegEditPanel::IndexById(soc_id_t id)
|
|
{
|
|
for(int i = 0; i < m_fields_tab->count(); i++)
|
|
{
|
|
RegFieldEditPanel *p = dynamic_cast< RegFieldEditPanel * >(m_fields_tab->widget(i));
|
|
if(p->GetField().get()->id == id)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void RegEditPanel::OnWidthChanged(int w)
|
|
{
|
|
m_ref.get()->width = w;
|
|
m_sexy_display2->setWidth(w);
|
|
for(int i = 0; i < m_fields_tab->count(); i++)
|
|
dynamic_cast< RegFieldEditPanel * >(m_fields_tab->widget(i))->UpdateWidth();
|
|
OnModified();
|
|
}
|
|
|
|
void RegEditPanel::OnBitrangeModified(int index)
|
|
{
|
|
soc_desc::register_t reg = m_value_model->GetRegister();
|
|
m_ref.get()->field[index].pos = reg.field[index].pos;
|
|
m_ref.get()->field[index].width = reg.field[index].width;
|
|
for(int i = 0; i < m_fields_tab->count(); i++)
|
|
dynamic_cast< RegFieldEditPanel * >(m_fields_tab->widget(i))->UpdateRange();
|
|
OnModified();
|
|
}
|
|
|
|
void RegEditPanel::OnAccessChanged(int acc)
|
|
{
|
|
m_ref.get()->access = (soc_desc::access_t)acc;
|
|
OnModified();
|
|
}
|
|
|
|
void RegEditPanel::OnDescEdited()
|
|
{
|
|
m_ref.get()->desc = m_desc_edit->GetTextHtml().toStdString();
|
|
OnModified();
|
|
}
|
|
|
|
void RegEditPanel::OnVariantActivated(QTableWidgetItem *item)
|
|
{
|
|
if(item->type() == RegVariantEditPanelDelType)
|
|
{
|
|
int row = item->row();
|
|
my_remove_at(m_ref.get()->variant, row);
|
|
m_variant_table->removeRow(row);
|
|
OnModified();
|
|
}
|
|
else if(item->type() == RegVariantEditPanelAddType)
|
|
{
|
|
int row = m_ref.get()->variant.size();
|
|
soc_desc::variant_t& variant = *m_ref.create_variant().get();
|
|
variant.type = "untyped";
|
|
variant.offset = 0;
|
|
variant.access = soc_desc::UNSPECIFIED;
|
|
m_variant_table->insertRow(row);
|
|
QTableWidgetItem *item = new QTableWidgetItem(
|
|
YIconManager::Get()->GetIcon(YIconManager::ListRemove), "", RegVariantEditPanelDelType);
|
|
item->setToolTip("Remove this variant");
|
|
item->setFlags(Qt::ItemIsEnabled);
|
|
m_variant_table->setItem(row, 0, item);
|
|
item = new QTableWidgetItem(QString::fromStdString(variant.type));
|
|
m_variant_table->setItem(row, 1, item);
|
|
item = new QTableWidgetItem();
|
|
item->setData(Qt::EditRole, QVariant(variant.offset));
|
|
m_variant_table->setItem(row, 2, item);
|
|
item = new QTableWidgetItem();
|
|
item->setData(Qt::EditRole, QVariant::fromValue(variant.access));
|
|
m_variant_table->setItem(row, 3, item);
|
|
OnModified();
|
|
}
|
|
}
|
|
|
|
void RegEditPanel::OnVariantValueChanged(QTableWidgetItem *item)
|
|
{
|
|
soc_desc::register_t& reg = *m_ref.get();
|
|
if((size_t)item->row() >= reg.variant.size())
|
|
return;
|
|
soc_desc::variant_t& var = reg.variant[item->row()];
|
|
if(item->column() == 1)
|
|
var.type = item->text().toStdString();
|
|
else if(item->column() == 2)
|
|
var.offset = item->data(Qt::EditRole).value< soc_word_t >();
|
|
else if(item->column() == 3)
|
|
var.access = item->data(Qt::EditRole).value< soc_desc::access_t >();
|
|
OnModified();
|
|
}
|
|
|
|
void RegEditPanel::OnRegFieldActivated(const QModelIndex& index)
|
|
{
|
|
if(!index.isValid())
|
|
return;
|
|
m_fields_tab->setCurrentIndex(IndexById(m_ref.get()->field[index.row()].id));
|
|
m_view_tab->setCurrentIndex(1);
|
|
}
|
|
|
|
void RegEditPanel::OnFieldModified()
|
|
{
|
|
int idx = m_fields_tab->currentIndex();
|
|
RegFieldEditPanel *p = dynamic_cast< RegFieldEditPanel * >(m_fields_tab->widget(idx));
|
|
m_fields_tab->setTabText(idx, QString::fromStdString(p->GetField().get()->name));
|
|
DoModify();
|
|
}
|
|
|
|
void RegEditPanel::DoModify()
|
|
{
|
|
m_value_model->UpdateRegister(*m_ref.get());
|
|
UpdateWidthRestrictions();
|
|
OnModified();
|
|
}
|
|
|
|
void RegEditPanel::OnRegFieldDelete()
|
|
{
|
|
QModelIndex current = m_sexy_display2->currentIndex();
|
|
if(!current.isValid())
|
|
return;
|
|
QMessageBox msgbox(QMessageBox::Question, "Delete field ?",
|
|
"Are you sure you want to delete this field ?",
|
|
QMessageBox::Yes | QMessageBox::No, this);
|
|
msgbox.setDefaultButton(QMessageBox::No);
|
|
int ret = msgbox.exec();
|
|
if(ret != QMessageBox::Yes)
|
|
return;
|
|
m_fields_tab->removeTab(IndexById(m_ref.get()->field[current.row()].id));
|
|
my_remove_at(m_ref.get()->field, current.row());
|
|
DoModify();
|
|
OnRegFieldActivated(QModelIndex());
|
|
}
|
|
|
|
void RegEditPanel::OnFieldRemove(int index)
|
|
{
|
|
Q_UNUSED(index);
|
|
}
|
|
|
|
int RegEditPanel::FindFreeBit(int preferred)
|
|
{
|
|
int nr_bits = m_ref.get()->width;
|
|
soc_word_t free_mask = (nr_bits == 32) ? 0xffffffff : (1 << nr_bits) - 1;
|
|
soc_desc::register_t& reg = *m_ref.get();
|
|
for(size_t i = 0; i < reg.field.size(); i++)
|
|
free_mask &= ~reg.field[i].bitmask();
|
|
/* any space ? */
|
|
if(free_mask == 0)
|
|
return -1;
|
|
int closest_bit = -1;
|
|
int closest_dist = nr_bits;
|
|
for(int bit = 0; bit < nr_bits; bit++)
|
|
{
|
|
if(!(free_mask & (1 << bit)))
|
|
continue;
|
|
if(abs(bit - preferred) < closest_dist)
|
|
{
|
|
closest_bit = bit;
|
|
closest_dist = abs(bit - preferred);
|
|
}
|
|
}
|
|
return closest_bit;
|
|
}
|
|
|
|
void RegEditPanel::OnRegFieldNew()
|
|
{
|
|
int bit_col = m_sexy_display2->bitColumnAt(m_menu_point);
|
|
/* we need to make sure the created field does not overlap something */
|
|
bit_col = FindFreeBit(bit_col);
|
|
if(bit_col == -1)
|
|
return; /* impossible to find a free position */
|
|
soc_desc::field_ref_t ref = m_ref.create_field();
|
|
soc_desc::field_t& field = *ref.get();
|
|
field.pos = bit_col;
|
|
field.width = 1;
|
|
field.name = "UNNAMED";
|
|
|
|
RegFieldEditPanel *p = new RegFieldEditPanel(ref, this);
|
|
connect(p, SIGNAL(OnModified()), this, SLOT(OnFieldModified()));
|
|
m_fields_tab->addTab(p, QString::fromStdString(field.name));
|
|
|
|
DoModify();
|
|
}
|
|
|
|
void RegEditPanel::OnFieldCreate()
|
|
{
|
|
OnRegFieldNew();
|
|
}
|
|
|
|
void RegEditPanel::OnRegDisplayContextMenu(QPoint point)
|
|
{
|
|
m_menu_point = point;
|
|
QMenu *menu = new QMenu(this);
|
|
QModelIndex item = m_sexy_display2->indexAt(point);
|
|
menu->addAction(m_new_action);
|
|
if(item.isValid())
|
|
menu->addAction(m_delete_action);
|
|
menu->popup(m_sexy_display2->viewport()->mapToGlobal(point));
|
|
}
|
|
|
|
namespace
|
|
{
|
|
|
|
enum
|
|
{
|
|
SocTreeSocType = QTreeWidgetItem::UserType, // SocRefRole -> node_ref_t to root
|
|
SocTreeNodeType, // SocRefRole -> node_ref_t
|
|
SocTreeRegType, // SocRefRole -> register_ref_t
|
|
};
|
|
|
|
enum
|
|
{
|
|
SocRefRole = Qt::UserRole,
|
|
};
|
|
|
|
template<typename T>
|
|
T SocTreeItemVal(QTreeWidgetItem *item)
|
|
{
|
|
return item->data(0, SocRefRole).value<T>();
|
|
}
|
|
|
|
template<typename T>
|
|
QTreeWidgetItem *MakeSocTreeItem(int type, const T& val)
|
|
{
|
|
QTreeWidgetItem *item = new QTreeWidgetItem(type);
|
|
item->setData(0, SocRefRole, QVariant::fromValue(val));
|
|
return item;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* RegEdit
|
|
*/
|
|
RegEdit::RegEdit(Backend *backend, QWidget *parent)
|
|
:QWidget(parent), m_backend(backend)
|
|
{
|
|
QVBoxLayout *m_vert_layout = new QVBoxLayout();
|
|
QLabel *file_static = new QLabel("File:");
|
|
m_file_edit = new QLineEdit(this);
|
|
m_file_edit->setReadOnly(true);
|
|
m_file_open = new QToolButton(this);
|
|
m_file_open->setText("Open");
|
|
m_file_open->setIcon(YIconManager::Get()->GetIcon(YIconManager::DocumentOpen));
|
|
m_file_open->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
|
QMenu *file_open_menu = new QMenu(this);
|
|
QAction *new_act = file_open_menu->addAction(YIconManager::Get()->GetIcon(YIconManager::DocumentNew),
|
|
"New...");
|
|
m_file_open->setPopupMode(QToolButton::MenuButtonPopup);
|
|
m_file_open->setMenu(file_open_menu);
|
|
|
|
m_file_save = new QToolButton(this);
|
|
m_file_save->setText("Save");
|
|
m_file_save->setIcon(YIconManager::Get()->GetIcon(YIconManager::DocumentSave));
|
|
m_file_save->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
|
m_file_save->setPopupMode(QToolButton::MenuButtonPopup);
|
|
QMenu *file_save_menu = new QMenu(this);
|
|
QAction *saveas_act = file_save_menu->addAction(YIconManager::Get()->GetIcon(YIconManager::DocumentSaveAs),
|
|
"Save as...");
|
|
m_file_save->setMenu(file_save_menu);
|
|
|
|
QHBoxLayout *file_group_layout = new QHBoxLayout();
|
|
file_group_layout->addWidget(m_file_open);
|
|
file_group_layout->addWidget(m_file_save);
|
|
file_group_layout->addWidget(file_static);
|
|
file_group_layout->addWidget(m_file_edit);
|
|
|
|
m_splitter = new QSplitter(this);
|
|
m_soc_tree = new QTreeWidget(this);
|
|
m_soc_tree->setColumnCount(1);
|
|
m_soc_tree->setHeaderLabel(QString("Name"));
|
|
m_soc_tree->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
m_delete_action = new QAction("&Delete", this);
|
|
m_delete_action->setIcon(YIconManager::Get()->GetIcon(YIconManager::ListRemove));
|
|
m_new_action = new QAction("&New", this);
|
|
m_new_action->setIcon(YIconManager::Get()->GetIcon(YIconManager::ListAdd));
|
|
m_create_action = new QAction("&Create register", this);
|
|
m_create_action->setIcon(YIconManager::Get()->GetIcon(YIconManager::FolderNew));
|
|
|
|
m_splitter->addWidget(m_soc_tree);
|
|
m_splitter->setStretchFactor(0, 0);
|
|
|
|
m_msg = new MessageWidget(this);
|
|
QWidget *splitter_right = new QWidget(this);
|
|
m_right_panel_layout = new QVBoxLayout;
|
|
m_right_panel_layout->addWidget(m_msg, 0);
|
|
splitter_right->setLayout(m_right_panel_layout);
|
|
m_splitter->addWidget(splitter_right);
|
|
m_splitter->setStretchFactor(1, 2);
|
|
|
|
m_msg_welcome_id = SetMessage(MessageWidget::Information,
|
|
"Open a description file to edit, or create a new file from scratch.");
|
|
m_msg_name_error_id = 0;
|
|
|
|
m_vert_layout->addLayout(file_group_layout);
|
|
m_vert_layout->addWidget(m_splitter, 1);
|
|
|
|
setLayout(m_vert_layout);
|
|
|
|
SetModified(false, false);
|
|
m_right_panel = 0;
|
|
SetPanel(new EmptyEditPanel(this));
|
|
UpdateTabName();
|
|
|
|
connect(m_soc_tree, SIGNAL(customContextMenuRequested(QPoint)), this,
|
|
SLOT(OnSocTreeContextMenu(QPoint)));
|
|
connect(m_delete_action, SIGNAL(triggered()), this, SLOT(OnSocItemDelete()));
|
|
connect(m_new_action, SIGNAL(triggered()), this, SLOT(OnSocItemNew()));
|
|
connect(m_create_action, SIGNAL(triggered()), this, SLOT(OnSocItemCreate()));
|
|
connect(m_file_open, SIGNAL(clicked()), this, SLOT(OnOpen()));
|
|
connect(m_file_save, SIGNAL(clicked()), this, SLOT(OnSave()));
|
|
connect(new_act, SIGNAL(triggered()), this, SLOT(OnNew()));
|
|
connect(saveas_act, SIGNAL(triggered()), this, SLOT(OnSaveAs()));
|
|
connect(m_soc_tree, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
|
|
this, SLOT(OnSocItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
|
|
}
|
|
|
|
QWidget *RegEdit::GetWidget()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
RegEdit::~RegEdit()
|
|
{
|
|
}
|
|
|
|
int RegEdit::SetMessage(MessageWidget::MessageType type, const QString& msg)
|
|
{
|
|
return m_msg->SetMessage(type, msg);
|
|
}
|
|
|
|
void RegEdit::HideMessage(int id)
|
|
{
|
|
m_msg->HideMessage(id);
|
|
}
|
|
|
|
void RegEdit::OnSave()
|
|
{
|
|
SaveSoc();
|
|
}
|
|
|
|
void RegEdit::OnSaveAs()
|
|
{
|
|
SaveSocAs();
|
|
}
|
|
|
|
bool RegEdit::CloseSoc()
|
|
{
|
|
if(!m_modified)
|
|
return true;
|
|
QMessageBox msgbox(QMessageBox::Question, "Save changes ?",
|
|
"The description has been modified. Do you want to save your changes ?",
|
|
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, this);
|
|
msgbox.setDefaultButton(QMessageBox::Cancel);
|
|
int ret = msgbox.exec();
|
|
if(ret == QMessageBox::Discard)
|
|
return true;
|
|
if(ret == QMessageBox::Cancel)
|
|
return false;
|
|
return SaveSoc();
|
|
}
|
|
|
|
bool RegEdit::SaveSoc()
|
|
{
|
|
if(m_file_edit->text().size() == 0)
|
|
return SaveSocAs();
|
|
else
|
|
return SaveSocFile(m_file_edit->text());
|
|
}
|
|
|
|
bool RegEdit::GetFilename(QString& filename, bool save)
|
|
{
|
|
QFileDialog *fd = new QFileDialog(this);
|
|
if(save)
|
|
fd->setAcceptMode(QFileDialog::AcceptSave);
|
|
QStringList filters;
|
|
filters << "Description files (*.xml)";
|
|
filters << "All files (*)";
|
|
fd->setNameFilters(filters);
|
|
fd->setDirectory(Settings::Get()->value("regedit/loaddescdir", QDir::currentPath()).toString());
|
|
if(fd->exec())
|
|
{
|
|
QStringList filenames = fd->selectedFiles();
|
|
filename = filenames[0];
|
|
Settings::Get()->setValue("regedit/loaddescdir", fd->directory().absolutePath());
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
bool RegEdit::SaveSocAs()
|
|
{
|
|
QString filename;
|
|
if(!GetFilename(filename, true))
|
|
return false;
|
|
m_file_edit->setText(filename);
|
|
return SaveSocFile(filename);
|
|
}
|
|
|
|
void RegEdit::OnOpen()
|
|
{
|
|
if(!CloseSoc())
|
|
return;
|
|
QString filename;
|
|
if(!GetFilename(filename, false))
|
|
return;
|
|
LoadSocFile(filename);
|
|
}
|
|
|
|
void RegEdit::OnNew()
|
|
{
|
|
if(!CloseSoc())
|
|
return;
|
|
m_cur_socfile = SocFile();
|
|
m_file_edit->setText("");
|
|
SetModified(false, false);
|
|
UpdateSocFile();
|
|
}
|
|
|
|
bool RegEdit::SaveSocFile(const QString& filename)
|
|
{
|
|
soc_desc::error_context_t ctx;
|
|
soc_desc::normalize(m_cur_socfile.GetSoc());
|
|
if(!soc_desc::produce_xml(filename.toStdString(), m_cur_socfile.GetSoc(), ctx))
|
|
{
|
|
QMessageBox::warning(this, "The description was not saved",
|
|
"There was an error when saving the file");
|
|
return false;
|
|
}
|
|
UpdateSocFile();
|
|
SetModified(false, false);
|
|
return true;
|
|
}
|
|
|
|
void RegEdit::UpdateTabName()
|
|
{
|
|
QFileInfo info(m_cur_socfile.GetFilename());
|
|
if(info.exists())
|
|
SetTabName(info.fileName());
|
|
else
|
|
SetTabName("Register Editor");
|
|
}
|
|
|
|
void RegEdit::LoadSocFile(const QString& filename)
|
|
{
|
|
m_cur_socfile = SocFile(filename);
|
|
if(!m_cur_socfile.IsValid())
|
|
{
|
|
QMessageBox::warning(this, "The description was not loaded",
|
|
"There was an error when loading the file");
|
|
return;
|
|
}
|
|
m_file_edit->setText(filename);
|
|
SetModified(false, false);
|
|
UpdateSocFile();
|
|
UpdateTabName();
|
|
m_msg_welcome_id = SetMessage(MessageWidget::Information,
|
|
"Select items to edit in tree, or right-click on them to see available actions.");
|
|
}
|
|
|
|
void RegEdit::FillNodeTreeItem(QTreeWidgetItem *item)
|
|
{
|
|
soc_desc::node_ref_t node = SocTreeItemVal< soc_desc::node_ref_t >(item);
|
|
soc_desc::register_ref_t reg = node.reg();
|
|
/* put register if there, otherwise offer to create one */
|
|
if(reg.valid() && reg.node() == node)
|
|
{
|
|
QTreeWidgetItem *reg_item = MakeSocTreeItem(SocTreeRegType, reg);
|
|
FixupItem(reg_item);
|
|
item->addChild(reg_item);
|
|
}
|
|
std::vector< soc_desc::node_ref_t > list = node.children();
|
|
for(size_t i = 0; i < list.size(); i++)
|
|
{
|
|
QTreeWidgetItem *node_item = MakeSocTreeItem(SocTreeNodeType, list[i]);
|
|
FixupItem(node_item);
|
|
FillNodeTreeItem(node_item);
|
|
item->addChild(node_item);
|
|
}
|
|
}
|
|
|
|
void RegEdit::FillSocTree()
|
|
{
|
|
soc_desc::soc_ref_t ref = m_cur_socfile.GetSocRef();
|
|
QTreeWidgetItem *root_item = MakeSocTreeItem(SocTreeSocType, ref.root());
|
|
FixupItem(root_item);
|
|
FillNodeTreeItem(root_item);
|
|
m_soc_tree->addTopLevelItem(root_item);
|
|
root_item->setExpanded(true);
|
|
}
|
|
|
|
void RegEdit::MakeItalic(QTreeWidgetItem *item, bool it)
|
|
{
|
|
QFont font = item->font(0);
|
|
font.setItalic(it);
|
|
item->setFont(0, font);
|
|
}
|
|
|
|
QIcon RegEdit::GetIconFromType(int type)
|
|
{
|
|
switch(type)
|
|
{
|
|
case SocTreeSocType: return YIconManager::Get()->GetIcon(YIconManager::Computer);
|
|
case SocTreeNodeType: return YIconManager::Get()->GetIcon(YIconManager::Cpu);
|
|
case SocTreeRegType: return style()->standardIcon(QStyle::SP_ArrowRight);
|
|
default: return QIcon();
|
|
}
|
|
}
|
|
|
|
bool RegEdit::ValidateName(const QString& name)
|
|
{
|
|
if(name.size() == 0)
|
|
return false;
|
|
for(int i = 0; i < name.size(); i++)
|
|
if(!name[i].isLetterOrNumber() && name[i] != QChar('_'))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void RegEdit::FixupItem(QTreeWidgetItem *item)
|
|
{
|
|
UpdateName(item);
|
|
if(!ValidateName(item->text(0)))
|
|
{
|
|
item->setIcon(0, YIconManager::Get()->GetIcon(YIconManager::DialogError));
|
|
if(item->text(0).size() == 0)
|
|
{
|
|
MakeItalic(item, true);
|
|
item->setText(0, "Unnamed");
|
|
}
|
|
m_msg_name_error_id = SetMessage(MessageWidget::Error,
|
|
"The item name is invalid. It must be non-empty and consists only "
|
|
"of alphanumerical or underscore characters");
|
|
}
|
|
else
|
|
{
|
|
HideMessage(m_msg_name_error_id);
|
|
item->setIcon(0, GetIconFromType(item->type()));
|
|
MakeItalic(item, false);
|
|
}
|
|
}
|
|
|
|
void RegEdit::UpdateSocFile()
|
|
{
|
|
m_soc_tree->clear();
|
|
FillSocTree();
|
|
SetPanel(new EmptyEditPanel(this));
|
|
}
|
|
|
|
void RegEdit::SetPanel(QWidget *panel)
|
|
{
|
|
delete m_right_panel;
|
|
m_right_panel = panel;
|
|
connect(m_right_panel, SIGNAL(OnModified()), this,
|
|
SLOT(OnSocModified()));
|
|
m_right_panel_layout->addWidget(m_right_panel, 1);
|
|
}
|
|
|
|
void RegEdit::SetModified(bool add, bool mod)
|
|
{
|
|
m_modified = add ? (m_modified || mod) : mod;
|
|
OnModified(mod);
|
|
}
|
|
|
|
void RegEdit::OnSocItemNew()
|
|
{
|
|
QTreeWidgetItem *current = m_soc_tree->currentItem();
|
|
if(current == 0)
|
|
return;
|
|
soc_desc::node_ref_t node = SocTreeItemVal< soc_desc::node_ref_t >(current);
|
|
node = node.create();
|
|
node.get()->name = "unnamed";
|
|
QTreeWidgetItem *node_item = MakeSocTreeItem(SocTreeNodeType, node);
|
|
FixupItem(node_item);
|
|
current->addChild(node_item);
|
|
m_soc_tree->setCurrentItem(node_item);
|
|
}
|
|
|
|
void RegEdit::OnSocItemCreate()
|
|
{
|
|
QTreeWidgetItem *current = m_soc_tree->currentItem();
|
|
if(current == 0)
|
|
return;
|
|
soc_desc::register_t reg;
|
|
reg.width = 32;
|
|
reg.access = soc_desc::UNSPECIFIED;
|
|
soc_desc::node_ref_t node = SocTreeItemVal< soc_desc::node_ref_t >(current);
|
|
node.get()->register_.push_back(reg);
|
|
QTreeWidgetItem *reg_item = MakeSocTreeItem(SocTreeRegType, node.reg());
|
|
FixupItem(reg_item);
|
|
current->insertChild(0, reg_item);
|
|
m_soc_tree->setCurrentItem(reg_item);
|
|
}
|
|
|
|
void RegEdit::OnSocItemDelete()
|
|
{
|
|
QTreeWidgetItem *current = m_soc_tree->currentItem();
|
|
if(current == 0)
|
|
return;
|
|
QMessageBox msgbox(QMessageBox::Question, "Delete item ?",
|
|
"Are you sure you want to delete this item ?",
|
|
QMessageBox::Yes | QMessageBox::No, this);
|
|
msgbox.setDefaultButton(QMessageBox::No);
|
|
int ret = msgbox.exec();
|
|
if(ret != QMessageBox::Yes)
|
|
return;
|
|
if(current->type() == SocTreeSocType)
|
|
{
|
|
SocTreeItemVal< soc_desc::node_ref_t >(current).remove();
|
|
current->takeChildren();
|
|
OnSocModified();
|
|
}
|
|
else if(current->type() == SocTreeNodeType)
|
|
{
|
|
SocTreeItemVal< soc_desc::node_ref_t >(current).remove();
|
|
current->parent()->removeChild(current);
|
|
OnSocModified();
|
|
}
|
|
else if(current->type() == SocTreeRegType)
|
|
{
|
|
SocTreeItemVal< soc_desc::register_ref_t >(current).remove();
|
|
current->parent()->removeChild(current);
|
|
OnSocModified();
|
|
}
|
|
}
|
|
|
|
void RegEdit::OnSocModified()
|
|
{
|
|
// we might need to update the name in the tree
|
|
FixupItem(m_soc_tree->currentItem());
|
|
SetModified(true, true);
|
|
}
|
|
|
|
void RegEdit::DisplaySoc(const soc_desc::soc_ref_t& ref)
|
|
{
|
|
SetPanel(new SocEditPanel(ref, this));
|
|
}
|
|
|
|
void RegEdit::DisplayNode(const soc_desc::node_ref_t& ref)
|
|
{
|
|
SetPanel(new NodeEditPanel(ref, this));
|
|
}
|
|
|
|
void RegEdit::DisplayReg(const soc_desc::register_ref_t& ref)
|
|
{
|
|
SetPanel(new RegEditPanel(ref, this));
|
|
}
|
|
|
|
void RegEdit::UpdateName(QTreeWidgetItem *current)
|
|
{
|
|
if(current == 0)
|
|
return;
|
|
|
|
if(current->type() == SocTreeSocType)
|
|
{
|
|
current->setText(0, QString::fromStdString(
|
|
SocTreeItemVal< soc_desc::node_ref_t >(current).soc().get()->name));
|
|
}
|
|
else if(current->type() == SocTreeNodeType)
|
|
{
|
|
current->setText(0, QString::fromStdString(
|
|
SocTreeItemVal< soc_desc::node_ref_t >(current).get()->name));
|
|
}
|
|
else if(current->type() == SocTreeRegType)
|
|
{
|
|
current->setText(0, "register");
|
|
}
|
|
}
|
|
|
|
void RegEdit::OnSocTreeContextMenu(QPoint point)
|
|
{
|
|
HideMessage(m_msg_welcome_id);
|
|
QTreeWidgetItem *item = m_soc_tree->itemAt(point);
|
|
if(item == 0)
|
|
return;
|
|
/* customise messages with item */
|
|
m_action_item = item;
|
|
QMenu *menu = new QMenu(this);
|
|
switch(item->type())
|
|
{
|
|
case SocTreeSocType:
|
|
m_new_action->setText("New node...");
|
|
m_delete_action->setText("Delete all nodes...");
|
|
menu->addAction(m_new_action);
|
|
menu->addAction(m_delete_action);
|
|
break;
|
|
case SocTreeNodeType:
|
|
{
|
|
m_new_action->setText("New node...");
|
|
m_delete_action->setText("Delete node...");
|
|
soc_desc::node_ref_t node = SocTreeItemVal< soc_desc::node_ref_t >(item);
|
|
if(node.reg().node() != node)
|
|
menu->addAction(m_create_action);
|
|
menu->addAction(m_new_action);
|
|
menu->addAction(m_delete_action);
|
|
break;
|
|
}
|
|
case SocTreeRegType:
|
|
m_delete_action->setText("Delete register...");
|
|
menu->addAction(m_new_action);
|
|
menu->addAction(m_delete_action);
|
|
break;
|
|
}
|
|
menu->popup(m_soc_tree->viewport()->mapToGlobal(point));
|
|
}
|
|
|
|
void RegEdit::OnSocItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
|
|
{
|
|
Q_UNUSED(previous);
|
|
HideMessage(m_msg_welcome_id);
|
|
if(current == 0)
|
|
return;
|
|
if(current->type() == SocTreeSocType)
|
|
DisplaySoc(SocTreeItemVal< soc_desc::node_ref_t >(current).soc());
|
|
else if(current->type() == SocTreeNodeType)
|
|
DisplayNode(SocTreeItemVal< soc_desc::node_ref_t >(current));
|
|
else if(current->type() == SocTreeRegType)
|
|
DisplayReg(SocTreeItemVal< soc_desc::register_ref_t >(current));
|
|
}
|
|
|
|
bool RegEdit::Quit()
|
|
{
|
|
return CloseSoc();
|
|
} |