ScreenTranslator/src/substitutionstable.cpp

210 lines
5.6 KiB
C++
Raw Normal View History

2020-03-08 17:49:15 +07:00
#include "substitutionstable.h"
#include "debug.h"
#include "languagecodes.h"
#include <QComboBox>
#include <QLineEdit>
2020-03-08 17:49:15 +07:00
#include <QPainter>
#include <QStringListModel>
#include <QStyledItemDelegate>
namespace
{
class SubstitutionDelegate : public QStyledItemDelegate
{
public:
explicit SubstitutionDelegate(QObject *parent = nullptr)
: QStyledItemDelegate(parent)
{
}
void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override
{
painter->drawText(option.rect, Qt::AlignCenter, index.data().toString());
}
QWidget *createEditor(QWidget *parent,
const QStyleOptionViewItem & /*option*/,
const QModelIndex & /*index*/) const override
{
return new QLineEdit(parent);
}
void setEditorData(QWidget *editor, const QModelIndex &index) const override
{
auto casted = qobject_cast<QLineEdit *>(editor);
SOFT_ASSERT(casted, return );
auto text = index.data(Qt::EditRole).toString();
text.replace('\\', "\\\\");
text.replace('\n', "\\n");
casted->setText(text);
}
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const override
{
auto casted = qobject_cast<QLineEdit *>(editor);
SOFT_ASSERT(casted, return );
auto text = casted->text();
if (!text.isEmpty()) {
const QMap<QString, QString> replacements{
{"\\\\", "\\"},
{"\\n", "\n"},
};
for (auto i = 0, end = text.size() - 1; i < end; ++i) {
const auto pair = text.mid(i, 2);
const auto replaced = replacements.value(pair);
if (replaced.isEmpty())
continue;
text.replace(i, 2, replaced);
--end;
}
}
model->setData(index, text);
}
}; // namespace
2020-03-08 17:49:15 +07:00
} // namespace
SubstitutionsTable::SubstitutionsTable(QWidget *parent)
: QTableWidget(parent)
2020-03-28 18:26:05 +07:00
, substitutionLanguages_(new QStringListModel(this))
2020-03-08 17:49:15 +07:00
{
setItemDelegate(new SubstitutionDelegate(this));
setColumnCount(int(Column::Count));
setHorizontalHeaderLabels({tr("Language"), tr("Source"), tr("Changed")});
connect(this, &SubstitutionsTable::itemChanged, //
this, &SubstitutionsTable::handleItemChange);
}
2020-03-28 18:26:05 +07:00
void SubstitutionsTable::setSourceLanguageModel(QStringListModel *model)
{
sourceLanguages_ = model;
connect(model, &QStringListModel::modelReset, //
this, [this] {
if (rowCount() > 0) // must be at least 1 if inited
setSubstitutions(substitutions());
});
}
2020-03-08 17:49:15 +07:00
void SubstitutionsTable::setSubstitutions(const Substitutions &substitutions)
{
setRowCount(0);
updateModel(substitutions);
2020-03-08 17:49:15 +07:00
for (const auto &i : substitutions) addRow(i.first, i.second);
2020-03-08 17:49:15 +07:00
addRow(); // for editing
resizeColumnsToContents();
}
void SubstitutionsTable::updateModel(const Substitutions &substitutions)
{
2020-03-28 18:26:05 +07:00
auto strings = sourceLanguages_->stringList();
if (!substitutions.empty()) {
for (const auto &i : substitutions) {
2020-03-25 01:38:05 +07:00
const auto name =
LanguageCodes::name(LanguageCodes::idForTesseract(i.first));
if (!strings.contains(name))
strings.append(name);
}
}
const auto any = LanguageCodes::name(LanguageCodes::anyLanguageId());
if (!strings.contains(any))
strings.append(any);
std::sort(strings.begin(), strings.end());
2020-03-28 18:26:05 +07:00
substitutionLanguages_->setStringList(strings);
}
2020-03-08 17:49:15 +07:00
Substitutions SubstitutionsTable::substitutions() const
{
Substitutions result;
for (auto row = 0, end = rowCount(); row < end; ++row) {
const auto pair = at(row);
2020-03-31 23:43:28 +07:00
if (pair.first.isEmpty() || pair.second.source.isEmpty())
2020-03-08 17:49:15 +07:00
continue;
result.emplace(pair.first, pair.second);
}
return result;
}
void SubstitutionsTable::addRow(const LanguageId &language,
const Substitution &substutution)
{
QSignalBlocker blocker(this);
auto row = rowCount();
insertRow(row);
auto combo = new QComboBox(this);
2020-03-28 18:26:05 +07:00
combo->setModel(substitutionLanguages_);
2020-03-08 17:49:15 +07:00
using E = Column;
if (!language.isEmpty()) {
2020-03-25 01:38:05 +07:00
combo->setCurrentText(LanguageCodes::name(language));
2020-03-08 17:49:15 +07:00
} else if (rowCount() > 1) {
const auto previousRow = rowCount() - 2;
auto previousCombo =
static_cast<QComboBox *>(cellWidget(previousRow, int(E::Language)));
SOFT_ASSERT(previousCombo, return );
combo->setCurrentText(previousCombo->currentText());
}
setCellWidget(row, int(E::Language), combo);
setItem(row, int(E::Source), new QTableWidgetItem(substutution.source));
setItem(row, int(E::Target), new QTableWidgetItem(substutution.target));
}
std::pair<LanguageId, Substitution> SubstitutionsTable::at(int row) const
{
SOFT_ASSERT(row >= 0 && row < rowCount(), return {});
using E = Column;
auto combo = static_cast<QComboBox *>(cellWidget(row, int(E::Language)));
SOFT_ASSERT(combo, return {});
2020-03-31 23:43:28 +07:00
if (combo->currentText().isEmpty())
return {};
2020-03-25 01:38:05 +07:00
const auto langId = LanguageCodes::idForName(combo->currentText());
SOFT_ASSERT(!langId.isEmpty(), return {});
2020-03-08 17:49:15 +07:00
Substitution sub;
auto sourceItem = item(row, int(E::Source));
SOFT_ASSERT(sourceItem, return {});
sub.source = sourceItem->text();
auto targetItem = item(row, int(E::Target));
SOFT_ASSERT(targetItem, return {});
sub.target = targetItem->text();
2020-03-25 01:38:05 +07:00
return std::make_pair(langId, sub);
2020-03-08 17:49:15 +07:00
}
void SubstitutionsTable::handleItemChange(QTableWidgetItem *item)
{
if (item->column() != int(Column::Source))
return;
const auto lastRow = rowCount() - 1;
if (!item->text().isEmpty() && item->row() == lastRow) {
addRow();
return;
}
if (item->text().isEmpty() && item->row() != lastRow) {
removeRow(item->row());
return;
}
}