forked from len0rd/rockbox
qeditor: on Windows it’s not impossible to create a file with AUX
Change-Id: Ic7ef01328eccbed4afddb0a09d2afbb6c1f6a28f Reviewed-on: http://gerrit.rockbox.org/811 Reviewed-by: Amaury Pouly <amaury.pouly@gmail.com>
This commit is contained in:
parent
7b590a9536
commit
440ff9500b
5 changed files with 5 additions and 5 deletions
800
utils/regtools/qeditor/utils.cpp
Normal file
800
utils/regtools/qeditor/utils.cpp
Normal file
|
@ -0,0 +1,800 @@
|
|||
#include "utils.h"
|
||||
#include <QFontMetrics>
|
||||
#include <QPainter>
|
||||
#include <QTextDocument>
|
||||
#include <QAbstractTextDocumentLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QDebug>
|
||||
#include <QElapsedTimer>
|
||||
#include <QXmlStreamReader>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <QTextBlock>
|
||||
|
||||
/**
|
||||
* SocBitRangeValidator
|
||||
*/
|
||||
SocBitRangeValidator::SocBitRangeValidator(QObject *parent)
|
||||
:QValidator(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void SocBitRangeValidator::fixup(QString& input) const
|
||||
{
|
||||
input = input.trimmed();
|
||||
}
|
||||
|
||||
QValidator::State SocBitRangeValidator::validate(QString& input, int& pos) const
|
||||
{
|
||||
Q_UNUSED(pos);
|
||||
int first, last;
|
||||
State state = parse(input, last, first);
|
||||
return state;
|
||||
}
|
||||
|
||||
QValidator::State SocBitRangeValidator::parse(const QString& input, int& last, int& first) const
|
||||
{
|
||||
// the empty string is always intermediate
|
||||
if(input.size() == 0)
|
||||
return Intermediate;
|
||||
// check if there is ':'
|
||||
int pos = input.indexOf(':');
|
||||
if(pos == -1)
|
||||
pos = input.size();
|
||||
// if field start with ':', the last bit is implicit and is 31
|
||||
if(pos > 0)
|
||||
{
|
||||
// parse last bit and check it's between 0 and 31
|
||||
bool ok = false;
|
||||
last = input.left(pos).toInt(&ok);
|
||||
if(!ok || last < 0 || last >= 32)
|
||||
return Invalid;
|
||||
}
|
||||
else
|
||||
last = 31;
|
||||
// parse first bit
|
||||
if(pos < input.size() - 1)
|
||||
{
|
||||
bool ok = false;
|
||||
first = input.mid(pos + 1).toInt(&ok);
|
||||
if(!ok || first < 0 || first > last)
|
||||
return Invalid;
|
||||
}
|
||||
// if input ends with ':', first bit is implicit and is 0
|
||||
else if(pos == input.size() - 1)
|
||||
first = 0;
|
||||
// if there no ':', first=last
|
||||
else
|
||||
first = last;
|
||||
return Acceptable;
|
||||
}
|
||||
|
||||
/**
|
||||
* SocFieldValidator
|
||||
*/
|
||||
|
||||
SocFieldValidator::SocFieldValidator(QObject *parent)
|
||||
:QValidator(parent)
|
||||
{
|
||||
m_field.first_bit = 0;
|
||||
m_field.last_bit = 31;
|
||||
}
|
||||
|
||||
SocFieldValidator::SocFieldValidator(const soc_reg_field_t& field, QObject *parent)
|
||||
:QValidator(parent), m_field(field)
|
||||
{
|
||||
}
|
||||
|
||||
void SocFieldValidator::fixup(QString& input) const
|
||||
{
|
||||
input = input.trimmed();
|
||||
}
|
||||
|
||||
QValidator::State SocFieldValidator::validate(QString& input, int& pos) const
|
||||
{
|
||||
Q_UNUSED(pos);
|
||||
soc_word_t val;
|
||||
State state = parse(input, val);
|
||||
return state;
|
||||
}
|
||||
|
||||
QValidator::State SocFieldValidator::parse(const QString& input, soc_word_t& val) const
|
||||
{
|
||||
// the empty string is always intermediate
|
||||
if(input.size() == 0)
|
||||
return Intermediate;
|
||||
// first check named values
|
||||
State state = Invalid;
|
||||
foreach(const soc_reg_field_value_t& value, m_field.value)
|
||||
{
|
||||
QString name = QString::fromLocal8Bit(value.name.c_str());
|
||||
// cannot be a substring if too long or empty
|
||||
if(input.size() > name.size())
|
||||
continue;
|
||||
// check equal string
|
||||
if(input == name)
|
||||
{
|
||||
state = Acceptable;
|
||||
val = value.value;
|
||||
break;
|
||||
}
|
||||
// check substring
|
||||
if(name.startsWith(input))
|
||||
state = Intermediate;
|
||||
}
|
||||
// early return for exact match
|
||||
if(state == Acceptable)
|
||||
return state;
|
||||
// do a few special cases for convenience
|
||||
if(input.compare("0x", Qt::CaseInsensitive) == 0 ||
|
||||
input.compare("0b", Qt::CaseInsensitive) == 0)
|
||||
return Intermediate;
|
||||
// try by parsing
|
||||
unsigned basis, pos;
|
||||
if(input.size() >= 2 && input.startsWith("0x", Qt::CaseInsensitive))
|
||||
{
|
||||
basis = 16;
|
||||
pos = 2;
|
||||
}
|
||||
else if(input.size() >= 2 && input.startsWith("0b", Qt::CaseInsensitive))
|
||||
{
|
||||
basis = 2;
|
||||
pos = 2;
|
||||
}
|
||||
else if(input.size() >= 2 && input.startsWith("0"))
|
||||
{
|
||||
basis = 8;
|
||||
pos = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
basis = 10;
|
||||
pos = 0;
|
||||
}
|
||||
bool ok = false;
|
||||
unsigned long v = input.mid(pos).toULong(&ok, basis);
|
||||
// if not ok, return result of name parsing
|
||||
if(!ok)
|
||||
return state;
|
||||
// if ok, check if it fits in the number of bits
|
||||
unsigned nr_bits = m_field.last_bit - m_field.first_bit + 1;
|
||||
unsigned long max = nr_bits == 32 ? 0xffffffff : (1 << nr_bits) - 1;
|
||||
if(v <= max)
|
||||
{
|
||||
val = v;
|
||||
return Acceptable;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* RegLineEdit
|
||||
*/
|
||||
RegLineEdit::RegLineEdit(QWidget *parent)
|
||||
:QWidget(parent)
|
||||
{
|
||||
m_layout = new QHBoxLayout(this);
|
||||
m_button = new QToolButton(this);
|
||||
m_button->setCursor(Qt::ArrowCursor);
|
||||
m_button->setStyleSheet("QToolButton { font-weight: bold; color: white; background: black; }");
|
||||
m_button->setPopupMode(QToolButton::InstantPopup);
|
||||
m_edit = new QLineEdit(this);
|
||||
m_layout->addWidget(m_button);
|
||||
m_layout->addWidget(m_edit);
|
||||
m_menu = new QMenu(this);
|
||||
connect(m_menu->addAction("Write"), SIGNAL(triggered()), this, SLOT(OnWriteAct()));
|
||||
connect(m_menu->addAction("Set"), SIGNAL(triggered()), this, SLOT(OnSetAct()));
|
||||
connect(m_menu->addAction("Clear"), SIGNAL(triggered()), this, SLOT(OnClearAct()));
|
||||
connect(m_menu->addAction("Toggle"), SIGNAL(triggered()), this, SLOT(OnToggleAct()));
|
||||
EnableSCT(false);
|
||||
SetReadOnly(false);
|
||||
ShowMode(true);
|
||||
SetMode(Write);
|
||||
}
|
||||
|
||||
void RegLineEdit::SetReadOnly(bool ro)
|
||||
{
|
||||
m_edit->setReadOnly(ro);
|
||||
m_readonly = ro;
|
||||
ShowMode(!ro);
|
||||
}
|
||||
|
||||
void RegLineEdit::EnableSCT(bool en)
|
||||
{
|
||||
m_has_sct = en;
|
||||
if(!m_has_sct)
|
||||
{
|
||||
m_button->setMenu(0);
|
||||
SetMode(Write);
|
||||
}
|
||||
else
|
||||
m_button->setMenu(m_menu);
|
||||
}
|
||||
|
||||
RegLineEdit::~RegLineEdit()
|
||||
{
|
||||
}
|
||||
|
||||
QLineEdit *RegLineEdit::GetLineEdit()
|
||||
{
|
||||
return m_edit;
|
||||
}
|
||||
|
||||
void RegLineEdit::ShowMode(bool show)
|
||||
{
|
||||
if(show)
|
||||
m_button->show();
|
||||
else
|
||||
m_button->hide();
|
||||
}
|
||||
|
||||
void RegLineEdit::OnWriteAct()
|
||||
{
|
||||
SetMode(Write);
|
||||
}
|
||||
|
||||
void RegLineEdit::OnSetAct()
|
||||
{
|
||||
SetMode(Set);
|
||||
}
|
||||
|
||||
void RegLineEdit::OnClearAct()
|
||||
{
|
||||
SetMode(Clear);
|
||||
}
|
||||
|
||||
void RegLineEdit::OnToggleAct()
|
||||
{
|
||||
SetMode(Toggle);
|
||||
}
|
||||
|
||||
void RegLineEdit::SetMode(EditMode mode)
|
||||
{
|
||||
m_mode = mode;
|
||||
switch(m_mode)
|
||||
{
|
||||
case Write: m_button->setText("WR"); break;
|
||||
case Set: m_button->setText("SET"); break;
|
||||
case Clear: m_button->setText("CLR"); break;
|
||||
case Toggle: m_button->setText("TOG"); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
RegLineEdit::EditMode RegLineEdit::GetMode()
|
||||
{
|
||||
return m_mode;
|
||||
}
|
||||
|
||||
void RegLineEdit::setText(const QString& text)
|
||||
{
|
||||
m_edit->setText(text);
|
||||
}
|
||||
|
||||
QString RegLineEdit::text() const
|
||||
{
|
||||
return m_edit->text();
|
||||
}
|
||||
|
||||
/**
|
||||
* SocFieldItemDelegate
|
||||
*/
|
||||
|
||||
QString SocFieldItemDelegate::displayText(const QVariant& value, const QLocale& locale) const
|
||||
{
|
||||
if(value.type() == QVariant::UInt)
|
||||
return QString("0x%1").arg(value.toUInt(), (m_bitcount + 3) / 4, 16, QChar('0'));
|
||||
else
|
||||
return QStyledItemDelegate::displayText(value, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* SocFieldEditor
|
||||
*/
|
||||
SocFieldEditor::SocFieldEditor(const soc_reg_field_t& field, QWidget *parent)
|
||||
:QLineEdit(parent), m_reg_field(field)
|
||||
{
|
||||
m_validator = new SocFieldValidator(field);
|
||||
setValidator(m_validator);
|
||||
}
|
||||
|
||||
SocFieldEditor::~SocFieldEditor()
|
||||
{
|
||||
delete m_validator;
|
||||
}
|
||||
|
||||
uint SocFieldEditor::field() const
|
||||
{
|
||||
soc_word_t v;
|
||||
/* in case validator fails to parse, return old value */
|
||||
if(m_validator->parse(text(), v) == QValidator::Acceptable)
|
||||
return v;
|
||||
else
|
||||
return m_field;
|
||||
}
|
||||
|
||||
void SocFieldEditor::setField(uint field)
|
||||
{
|
||||
m_field = field;
|
||||
int digits = (m_reg_field.last_bit - m_reg_field.first_bit + 4) / 4;
|
||||
setText(QString("0x%1").arg(field, digits, 16, QChar('0')));
|
||||
}
|
||||
|
||||
/**
|
||||
* SocFieldCachedItemDelegate
|
||||
*/
|
||||
|
||||
QString SocFieldCachedItemDelegate::displayText(const QVariant& value, const QLocale& locale) const
|
||||
{
|
||||
// FIXME see QTBUG-30392
|
||||
if(value.type() == QVariant::UserType && value.userType() == qMetaTypeId< SocFieldCachedValue >())
|
||||
{
|
||||
const SocFieldCachedValue& v = value.value< SocFieldCachedValue >();
|
||||
int bitcount = v.field().last_bit - v.field().first_bit;
|
||||
return QString("0x%1").arg(v.value(), (bitcount + 3) / 4, 16, QChar('0'));
|
||||
}
|
||||
else
|
||||
return QStyledItemDelegate::displayText(value, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* SocFieldCachedEditor
|
||||
*/
|
||||
SocFieldCachedEditor::SocFieldCachedEditor(QWidget *parent)
|
||||
:SocFieldEditor(soc_reg_field_t(), parent)
|
||||
{
|
||||
}
|
||||
|
||||
SocFieldCachedEditor::~SocFieldCachedEditor()
|
||||
{
|
||||
}
|
||||
|
||||
SocFieldCachedValue SocFieldCachedEditor::value() const
|
||||
{
|
||||
return SocFieldCachedValue(m_value.field(), field());
|
||||
}
|
||||
|
||||
void SocFieldCachedEditor::setValue(SocFieldCachedValue val)
|
||||
{
|
||||
m_value = val;
|
||||
SetRegField(m_value.field());
|
||||
setField(m_value.value());
|
||||
}
|
||||
|
||||
/**
|
||||
* SocFieldEditorCreator
|
||||
*/
|
||||
QWidget *SocFieldEditorCreator::createWidget(QWidget *parent) const
|
||||
{
|
||||
return new SocFieldEditor(m_field, parent);
|
||||
}
|
||||
|
||||
QByteArray SocFieldEditorCreator::valuePropertyName() const
|
||||
{
|
||||
return QByteArray("field");
|
||||
}
|
||||
|
||||
/**
|
||||
* SocFieldCachedEditorCreator
|
||||
*/
|
||||
QWidget *SocFieldCachedEditorCreator::createWidget(QWidget *parent) const
|
||||
{
|
||||
return new SocFieldCachedEditor(parent);
|
||||
}
|
||||
|
||||
QByteArray SocFieldCachedEditorCreator::valuePropertyName() const
|
||||
{
|
||||
return QByteArray("value");
|
||||
}
|
||||
|
||||
/**
|
||||
* RegSexyDisplay
|
||||
*/
|
||||
RegSexyDisplay::RegSexyDisplay(const SocRegRef& reg, QWidget *parent)
|
||||
:QWidget(parent), m_reg(reg)
|
||||
{
|
||||
m_size = QSize();
|
||||
}
|
||||
|
||||
int RegSexyDisplay::separatorSize() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int RegSexyDisplay::marginSize() const
|
||||
{
|
||||
return fontMetrics().height() / 3;
|
||||
}
|
||||
|
||||
int RegSexyDisplay::textSep() const
|
||||
{
|
||||
return marginSize() / 2;
|
||||
}
|
||||
|
||||
int RegSexyDisplay::headerHeight() const
|
||||
{
|
||||
return 2 * marginSize() + textSep() + 2 * fontMetrics().height();
|
||||
}
|
||||
|
||||
int RegSexyDisplay::columnWidth() const
|
||||
{
|
||||
return 2 * marginSize() + fontMetrics().height();
|
||||
}
|
||||
|
||||
int RegSexyDisplay::maxContentHeight() const
|
||||
{
|
||||
int max = 0;
|
||||
QFontMetrics metrics = fontMetrics();
|
||||
for(size_t i = 0; i < m_reg.GetReg().field.size(); i++)
|
||||
{
|
||||
QString s = QString::fromStdString(m_reg.GetReg().field[i].name);
|
||||
// add extra spaces arounds
|
||||
s = " " + s + " ";
|
||||
max = qMax(max, metrics.boundingRect(s).width());
|
||||
}
|
||||
return 2 * marginSize() + max;
|
||||
}
|
||||
|
||||
int RegSexyDisplay::gapHeight() const
|
||||
{
|
||||
return marginSize() / 2;
|
||||
}
|
||||
|
||||
QSize RegSexyDisplay::minimumSizeHint() const
|
||||
{
|
||||
/* cache computation because it's expensive */
|
||||
if(m_size.isValid())
|
||||
return m_size;
|
||||
/* width: display 32 columns + 33 vertical separators */
|
||||
m_size.setWidth(32 * columnWidth() + 33 * separatorSize());
|
||||
/* height: one separator + two digits + one separator + margin + separator
|
||||
* + names + separator */
|
||||
m_size.setHeight(4 * separatorSize() + headerHeight() + gapHeight() + maxContentHeight());
|
||||
return m_size;
|
||||
}
|
||||
|
||||
QSize RegSexyDisplay::sizeHint() const
|
||||
{
|
||||
return minimumSizeHint();
|
||||
}
|
||||
|
||||
void RegSexyDisplay::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
// FIXME could be optimised with QStaticText
|
||||
Q_UNUSED(event);
|
||||
int txt_h = fontMetrics().height();
|
||||
int sep_sz = separatorSize();
|
||||
int w = width();
|
||||
int h = height() - 1;
|
||||
int col_w = (w - 33 * sep_sz) / 32;
|
||||
int hdr_h = headerHeight();
|
||||
int gap_h = gapHeight();
|
||||
int tot_w = 33 * sep_sz + 32 * col_w;
|
||||
int margin = marginSize();
|
||||
int txt_sep = textSep();
|
||||
int tot_hdr_sz = 2 * sep_sz + hdr_h;
|
||||
// computer xshift
|
||||
int x_shift = (w - tot_w) / 2;
|
||||
#define ith_col_x(i) (x_shift + (i) * (sep_sz + col_w))
|
||||
|
||||
QPainter painter(this);
|
||||
QBrush back_brush = palette().base();
|
||||
QBrush line_brush = palette().dark();
|
||||
|
||||
// fill interesting zone with base
|
||||
painter.fillRect(x_shift, 0, tot_w, h, back_brush);
|
||||
|
||||
// draw top and bottom lines
|
||||
painter.setPen(QPen(palette().dark(), sep_sz));
|
||||
painter.fillRect(x_shift, 0, tot_w, sep_sz, line_brush);
|
||||
painter.fillRect(x_shift, h - sep_sz, tot_w, sep_sz, line_brush);
|
||||
// draw intemediate lines
|
||||
for(int i = 0; i <= 32; i++)
|
||||
painter.fillRect(ith_col_x(i), 0, sep_sz, 2 * sep_sz + hdr_h, line_brush);
|
||||
// draw bottom header lines
|
||||
painter.fillRect(ith_col_x(0), sep_sz + hdr_h, tot_w, sep_sz, line_brush);
|
||||
painter.fillRect(ith_col_x(0), tot_hdr_sz + gap_h, tot_w, sep_sz, line_brush);
|
||||
// redraw some lines but wider
|
||||
for(int i = 4; i < 32; i += 4)
|
||||
painter.fillRect(ith_col_x(i) - sep_sz, 0, 3 * sep_sz, tot_hdr_sz, line_brush);
|
||||
// draw numbers in the header
|
||||
painter.setPen(palette().brush(QPalette::ButtonText).color());
|
||||
for(int i = 0; i < 32; i++)
|
||||
{
|
||||
QRect r(ith_col_x(i), sep_sz + margin, col_w, txt_h);
|
||||
painter.drawText(r, Qt::AlignCenter, QString("%1").arg((31 - i) / 10));
|
||||
r.translate(0, txt_h + txt_sep);
|
||||
painter.drawText(r, Qt::AlignCenter, QString("%1").arg((31 - i) % 10));
|
||||
}
|
||||
// display content
|
||||
for(size_t i = 0; i < m_reg.GetReg().field.size(); i++)
|
||||
{
|
||||
const soc_reg_field_t& field = m_reg.GetReg().field[i];
|
||||
QRect r(QPoint(ith_col_x(31 - field.last_bit) + sep_sz, tot_hdr_sz),
|
||||
QPoint(ith_col_x(32 - field.first_bit), h - sep_sz));
|
||||
painter.fillRect(r.x() - sep_sz, r.y(), sep_sz, r.height(), line_brush);
|
||||
painter.fillRect(r.right(), r.y(), sep_sz, r.height(), line_brush);
|
||||
r.setY(r.y() + gap_h + sep_sz);
|
||||
// draw rotated text
|
||||
painter.save();
|
||||
painter.translate(r.bottomLeft());
|
||||
painter.rotate(-90);
|
||||
//painter.fillRect(QRect(0, 0, r.height(), r.width()), QBrush(Qt::red));
|
||||
QRect r2(0, 0, r.height(), r.width());
|
||||
painter.drawText(r2, Qt::AlignCenter, QString::fromStdString(field.name));
|
||||
painter.restore();
|
||||
}
|
||||
#undef ith_col_x
|
||||
}
|
||||
|
||||
/**
|
||||
* GrowingTextEdit
|
||||
*/
|
||||
GrowingTextEdit::GrowingTextEdit(QWidget *parent)
|
||||
:QTextEdit(parent)
|
||||
{
|
||||
connect(this, SIGNAL(textChanged()), this, SLOT(TextChanged()));
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
}
|
||||
|
||||
void GrowingTextEdit::TextChanged()
|
||||
{
|
||||
int content_size = document()->documentLayout()->documentSize().height();
|
||||
content_size = qMax(content_size, fontMetrics().height());
|
||||
setFixedHeight(content_size + contentsMargins().top() + contentsMargins().bottom());
|
||||
}
|
||||
|
||||
/**
|
||||
* GrowingTableWidget
|
||||
*/
|
||||
GrowingTableWidget::GrowingTableWidget(QWidget *parent)
|
||||
:QTableWidget(parent)
|
||||
{
|
||||
connect(model(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||
this, SLOT(DataChanged(const QModelIndex&, const QModelIndex&)));
|
||||
}
|
||||
|
||||
void GrowingTableWidget::DataChanged(const QModelIndex& tl, const QModelIndex& br)
|
||||
{
|
||||
Q_UNUSED(tl);
|
||||
Q_UNUSED(br);
|
||||
resizeRowsToContents();
|
||||
resizeColumnsToContents();
|
||||
int h = contentsMargins().top() + contentsMargins().bottom();
|
||||
h += horizontalHeader()->height();
|
||||
for(int i = 0; i < rowCount(); i++)
|
||||
h += rowHeight(i);
|
||||
setMinimumHeight(h);
|
||||
}
|
||||
|
||||
/**
|
||||
* MyTextEditor
|
||||
*/
|
||||
MyTextEditor::MyTextEditor(QWidget *parent)
|
||||
:QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
m_toolbar = new QToolBar(this);
|
||||
m_edit = new QTextEdit(this);
|
||||
layout->addWidget(m_toolbar, 0);
|
||||
layout->addWidget(m_edit, 1);
|
||||
setLayout(layout);
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
|
||||
m_edit->setAcceptRichText(false);
|
||||
m_edit->setAutoFormatting(QTextEdit::AutoAll);
|
||||
|
||||
m_bold_button = new QToolButton(this);
|
||||
m_bold_button->setIcon(QIcon::fromTheme("format-text-bold"));
|
||||
m_bold_button->setText("bold");
|
||||
m_bold_button->setCheckable(true);
|
||||
|
||||
m_italic_button = new QToolButton(this);
|
||||
m_italic_button->setIcon(QIcon::fromTheme("format-text-italic"));
|
||||
m_italic_button->setText("italic");
|
||||
m_italic_button->setCheckable(true);
|
||||
|
||||
m_underline_button = new QToolButton(this);
|
||||
m_underline_button->setIcon(QIcon::fromTheme("format-text-underline"));
|
||||
m_underline_button->setText("underline");
|
||||
m_underline_button->setCheckable(true);
|
||||
|
||||
m_toolbar->addWidget(m_bold_button);
|
||||
m_toolbar->addWidget(m_italic_button);
|
||||
m_toolbar->addWidget(m_underline_button);
|
||||
|
||||
connect(m_bold_button, SIGNAL(toggled(bool)), this, SLOT(OnTextBold(bool)));
|
||||
connect(m_italic_button, SIGNAL(toggled(bool)), this, SLOT(OnTextItalic(bool)));
|
||||
connect(m_underline_button, SIGNAL(toggled(bool)), this, SLOT(OnTextUnderline(bool)));
|
||||
connect(m_edit, SIGNAL(textChanged()), this, SLOT(OnInternalTextChanged()));
|
||||
connect(m_edit, SIGNAL(currentCharFormatChanged(const QTextCharFormat&)),
|
||||
this, SLOT(OnCharFormatChanged(const QTextCharFormat&)));
|
||||
|
||||
SetGrowingMode(false);
|
||||
SetReadOnly(false);
|
||||
}
|
||||
|
||||
void MyTextEditor::SetReadOnly(bool en)
|
||||
{
|
||||
m_read_only = en;
|
||||
if(en)
|
||||
m_toolbar->hide();
|
||||
else
|
||||
m_toolbar->hide();
|
||||
m_edit->setReadOnly(en);
|
||||
}
|
||||
|
||||
void MyTextEditor::SetGrowingMode(bool en)
|
||||
{
|
||||
m_growing_mode = en;
|
||||
if(en)
|
||||
{
|
||||
m_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
m_edit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
OnTextChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
m_edit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
}
|
||||
}
|
||||
|
||||
void MyTextEditor::OnInternalTextChanged()
|
||||
{
|
||||
if(m_growing_mode)
|
||||
{
|
||||
int content_size = m_edit->document()->documentLayout()->documentSize().height();
|
||||
content_size = qMax(content_size, m_edit->fontMetrics().height());
|
||||
m_edit->setMinimumHeight(content_size + m_edit->contentsMargins().top() +
|
||||
m_edit->contentsMargins().bottom());
|
||||
}
|
||||
emit OnTextChanged();
|
||||
}
|
||||
|
||||
void MyTextEditor::OnTextBold(bool checked)
|
||||
{
|
||||
QTextCursor cursor = m_edit->textCursor();
|
||||
QTextCharFormat fmt = cursor.charFormat();
|
||||
fmt.setFontWeight(checked ? QFont::Bold : QFont::Normal);
|
||||
cursor.setCharFormat(fmt);
|
||||
m_edit->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
void MyTextEditor::OnTextItalic(bool checked)
|
||||
{
|
||||
QTextCursor cursor = m_edit->textCursor();
|
||||
QTextCharFormat fmt = cursor.charFormat();
|
||||
fmt.setFontItalic(checked);
|
||||
cursor.setCharFormat(fmt);
|
||||
m_edit->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
void MyTextEditor::OnTextUnderline(bool checked)
|
||||
{
|
||||
QTextCursor cursor = m_edit->textCursor();
|
||||
QTextCharFormat fmt = cursor.charFormat();
|
||||
fmt.setFontUnderline(checked);
|
||||
cursor.setCharFormat(fmt);
|
||||
m_edit->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
void MyTextEditor::OnCharFormatChanged(const QTextCharFormat& fmt)
|
||||
{
|
||||
/* NOTE: changing the button states programmaticaly doesn't trigger
|
||||
* the toggled() signals, otherwise it would result in a loop
|
||||
* between this function and OnText{Bold,Italic,Underline,...} */
|
||||
m_bold_button->setChecked(fmt.fontWeight() > QFont::Normal);
|
||||
m_italic_button->setChecked(fmt.fontItalic());
|
||||
m_underline_button->setChecked(fmt.fontUnderline());
|
||||
}
|
||||
|
||||
void MyTextEditor::SetTextHtml(const QString& text)
|
||||
{
|
||||
m_edit->setHtml(text);
|
||||
}
|
||||
|
||||
QString MyTextEditor::GetTextHtml()
|
||||
{
|
||||
return m_edit->toPlainText();
|
||||
}
|
||||
|
||||
bool MyTextEditor::IsModified()
|
||||
{
|
||||
return m_edit->document()->isModified();
|
||||
}
|
||||
|
||||
/**
|
||||
* MySwitchableTextEditor
|
||||
*/
|
||||
MySwitchableTextEditor::MySwitchableTextEditor(QWidget *parent)
|
||||
:QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
m_edit = new MyTextEditor(this);
|
||||
m_label = new QLabel(this);
|
||||
m_label->setTextFormat(Qt::RichText);
|
||||
m_label->setAlignment(Qt::AlignTop);
|
||||
m_line = new QLineEdit(this);
|
||||
|
||||
layout->addWidget(m_label);
|
||||
layout->addWidget(m_edit);
|
||||
layout->addWidget(m_line);
|
||||
|
||||
setLayout(layout);
|
||||
|
||||
m_editor_mode = false;
|
||||
m_line_mode = false;
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
void MySwitchableTextEditor::SetEditorMode(bool edit)
|
||||
{
|
||||
if(edit == m_editor_mode)
|
||||
return;
|
||||
QString text = GetTextHtml();
|
||||
m_editor_mode = edit;
|
||||
UpdateVisibility();
|
||||
SetTextHtml(text);
|
||||
}
|
||||
|
||||
QString MySwitchableTextEditor::GetTextHtml()
|
||||
{
|
||||
if(m_editor_mode)
|
||||
return m_line_mode ? m_line->text() : m_edit->GetTextHtml();
|
||||
else
|
||||
return m_label->text();
|
||||
}
|
||||
|
||||
void MySwitchableTextEditor::SetTextHtml(const QString& text)
|
||||
{
|
||||
if(m_editor_mode)
|
||||
{
|
||||
if(m_line_mode)
|
||||
m_line->setText(text);
|
||||
else
|
||||
m_edit->SetTextHtml(text);
|
||||
}
|
||||
else
|
||||
m_label->setText(text);
|
||||
}
|
||||
|
||||
MyTextEditor *MySwitchableTextEditor::GetEditor()
|
||||
{
|
||||
return m_edit;
|
||||
}
|
||||
|
||||
void MySwitchableTextEditor::SetLineMode(bool en)
|
||||
{
|
||||
if(m_line_mode == en)
|
||||
return;
|
||||
QString text = GetTextHtml();
|
||||
m_line_mode = en;
|
||||
SetTextHtml(text);
|
||||
UpdateVisibility();
|
||||
}
|
||||
|
||||
QLineEdit *MySwitchableTextEditor::GetLineEdit()
|
||||
{
|
||||
return m_line;
|
||||
}
|
||||
|
||||
void MySwitchableTextEditor::UpdateVisibility()
|
||||
{
|
||||
m_label->setVisible(!m_editor_mode);
|
||||
m_edit->setVisible(m_editor_mode && !m_line_mode);
|
||||
m_line->setVisible(m_editor_mode && m_line_mode);
|
||||
}
|
||||
|
||||
QLabel *MySwitchableTextEditor::GetLabel()
|
||||
{
|
||||
return m_label;
|
||||
}
|
||||
|
||||
bool MySwitchableTextEditor::IsModified()
|
||||
{
|
||||
if(!m_editor_mode)
|
||||
return false;
|
||||
return m_line_mode ? m_line->isModified() : m_edit->IsModified();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue