2020-03-08 17:49:15 +07:00
|
|
|
#include "substitutionstable.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "languagecodes.h"
|
2020-03-19 01:21:17 +07:00
|
|
|
#include "tesseract.h"
|
2020-03-08 17:49:15 +07:00
|
|
|
|
|
|
|
#include <QComboBox>
|
|
|
|
#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());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
SubstitutionsTable::SubstitutionsTable(QWidget *parent)
|
|
|
|
: QTableWidget(parent)
|
2020-03-19 01:21:17 +07:00
|
|
|
, languagesModel_(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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SubstitutionsTable::setSubstitutions(const Substitutions &substitutions)
|
|
|
|
{
|
2020-03-19 01:21:17 +07:00
|
|
|
setRowCount(0);
|
|
|
|
|
|
|
|
updateModel(substitutions);
|
|
|
|
|
2020-03-08 17:49:15 +07:00
|
|
|
for (const auto &i : substitutions) addRow(i.first, i.second);
|
2020-03-19 01:21:17 +07:00
|
|
|
|
2020-03-08 17:49:15 +07:00
|
|
|
addRow(); // for editing
|
|
|
|
resizeColumnsToContents();
|
|
|
|
}
|
|
|
|
|
2020-03-19 01:21:17 +07:00
|
|
|
void SubstitutionsTable::setTessdataPath(const QString &tessdataPath)
|
|
|
|
{
|
|
|
|
tessdataPath_ = tessdataPath;
|
|
|
|
if (rowCount() == 0) // must be at least 1 if inited
|
|
|
|
return;
|
|
|
|
setSubstitutions(substitutions());
|
|
|
|
}
|
|
|
|
|
|
|
|
void SubstitutionsTable::updateModel(const Substitutions &substitutions)
|
|
|
|
{
|
|
|
|
auto strings = Tesseract::availableLanguageNames(tessdataPath_);
|
|
|
|
|
|
|
|
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));
|
2020-03-19 01:21:17 +07:00
|
|
|
|
|
|
|
if (!strings.contains(name))
|
|
|
|
strings.append(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::sort(strings.begin(), strings.end());
|
|
|
|
languagesModel_->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);
|
|
|
|
SOFT_ASSERT(!pair.first.isEmpty(), continue);
|
|
|
|
if (pair.second.source.isEmpty())
|
|
|
|
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);
|
|
|
|
combo->setModel(languagesModel_);
|
|
|
|
|
|
|
|
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-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;
|
|
|
|
}
|
|
|
|
}
|