File indexing completed on 2024-12-22 04:40:07

0001 #include "encodingdetectdialog.h"
0002 #include "ui_encodingdetectdialog.h"
0003 
0004 #include <QPushButton>
0005 #include <QScrollBar>
0006 #include <QTextCodec>
0007 #include <QTextStream>
0008 
0009 #include <KCharsets>
0010 
0011 using namespace SubtitleComposer;
0012 
0013 #define INVALID_PARENT_ROW quintptr(-1)
0014 
0015 namespace SubtitleComposer {
0016 class TreeModel : public QAbstractItemModel
0017 {
0018     Q_OBJECT
0019     friend class EncodingDetectDialog;
0020 
0021 public:
0022     explicit TreeModel(QObject *parent = nullptr);
0023     ~TreeModel();
0024 
0025     QVariant data(const QModelIndex &index, int role) const override;
0026     Qt::ItemFlags flags(const QModelIndex &index) const override;
0027     QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
0028     QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
0029     QModelIndex parent(const QModelIndex &index) const override;
0030     int rowCount(const QModelIndex &parent = QModelIndex()) const override;
0031     int columnCount(const QModelIndex &parent = QModelIndex()) const override { Q_UNUSED(parent); return 1; }
0032     const QString & encoding(const QModelIndex &index) const;
0033 
0034 private:
0035     void setupModelData();
0036 
0037     QList<QStringList> m_encodings;
0038     QStringList m_detectedName;
0039     QStringList m_detected;
0040 };
0041 }
0042 
0043 EncodingDetectDialog::EncodingDetectDialog(const QByteArray &text, QWidget *parent)
0044     : QDialog(parent),
0045       ui(new Ui::EncodingDetectDialog),
0046       m_text(text)
0047 {
0048     ui->setupUi(this);
0049     TreeModel *model = new TreeModel(this);
0050     ui->encoding->setModel(model);
0051 
0052     ui->buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true);
0053     connect(ui->encoding->selectionModel(), &QItemSelectionModel::selectionChanged, this, [&, model](const QItemSelection &sel, const QItemSelection &){
0054         const bool hasSelection = !sel.isEmpty() && !sel.first().isEmpty();
0055         ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(hasSelection);
0056 
0057         if(hasSelection) {
0058             const QModelIndex first = sel.first().indexes().first();
0059             m_selectedEncoding = model->encoding(first);
0060             QTextCodec *codec = QTextCodec::codecForName(m_selectedEncoding.toUtf8());
0061             const int val = ui->preview->verticalScrollBar()->value();
0062             ui->preview->setPlainText(codec->toUnicode(m_text));
0063             ui->preview->verticalScrollBar()->setValue(val);
0064         } else {
0065             ui->preview->clear();
0066             m_selectedEncoding.clear();
0067         }
0068     });
0069 }
0070 
0071 EncodingDetectDialog::~EncodingDetectDialog()
0072 {
0073     delete ui;
0074 }
0075 
0076 void
0077 EncodingDetectDialog::addEncoding(const QString &name, int confidence)
0078 {
0079     TreeModel *model = reinterpret_cast<TreeModel *>(ui->encoding->model());
0080     model->m_detectedName.append(name);
0081     model->m_detected.append(i18nc("Text encoding detected with n% confidence.", "%1 (%2% confidence)",
0082         name.toUpper(), confidence));
0083 
0084     if(ui->encoding->selectionModel()->selection().isEmpty()) {
0085         const QModelIndex &detected = model->index(0, 0);
0086         ui->encoding->expand(detected);
0087         const QModelIndex &selected = model->index(0, 0, detected);
0088         ui->encoding->selectionModel()->select(selected, QItemSelectionModel::ClearAndSelect);
0089     }
0090 }
0091 
0092 /// Tree Model
0093 TreeModel::TreeModel(QObject *parent)
0094     : QAbstractItemModel(parent)
0095 {
0096     m_encodings = KCharsets::charsets()->encodingsByScript();
0097     for(QStringList &encList : m_encodings) {
0098         bool first = true;
0099         for(QString &enc: encList) {
0100             if(first)
0101                 first = false;
0102             else
0103                 enc = enc.toUpper();
0104         }
0105     }
0106 }
0107 
0108 TreeModel::~TreeModel() {}
0109 
0110 const QString &
0111 TreeModel::encoding(const QModelIndex &index) const
0112 {
0113     int p = index.parent().row();
0114     const QStringList &parentList = p == 0 ? m_detectedName : m_encodings.at(p - 1);
0115     return parentList.at(p == 0 ? index.row() : index.row() + 1);
0116 }
0117 
0118 Qt::ItemFlags
0119 TreeModel::flags(const QModelIndex &index) const
0120 {
0121     if(!index.isValid())
0122         return Qt::NoItemFlags;
0123     if(index.internalId() != INVALID_PARENT_ROW)
0124         return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
0125     return Qt::ItemIsEnabled;
0126 }
0127 
0128 QVariant
0129 TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
0130 {
0131     if(orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0)
0132         return QStringLiteral("Encoding");
0133 
0134     return QVariant();
0135 }
0136 
0137 QModelIndex
0138 TreeModel::index(int row, int column, const QModelIndex &parent) const
0139 {
0140     Q_ASSERT(column == 0);
0141 
0142     if(!parent.isValid()) {
0143         if(row <= m_encodings.size())
0144             return createIndex(row, 0, INVALID_PARENT_ROW);
0145         return QModelIndex();
0146     }
0147 
0148     Q_ASSERT(parent.internalId() == INVALID_PARENT_ROW);
0149 
0150     if(row < rowCount(parent))
0151         return createIndex(row, 0, parent.row());
0152 
0153     return QModelIndex();
0154 }
0155 
0156 QModelIndex
0157 TreeModel::parent(const QModelIndex &index) const
0158 {
0159     if(!index.isValid())
0160         return QModelIndex();
0161 
0162     if(index.internalId() == INVALID_PARENT_ROW)
0163         return QModelIndex();
0164 
0165     return createIndex(index.internalId(), 0, INVALID_PARENT_ROW);
0166 }
0167 
0168 int
0169 TreeModel::rowCount(const QModelIndex &parent) const
0170 {
0171     if(parent.column() > 0)
0172         return 0;
0173 
0174     if(!parent.isValid())
0175         return m_encodings.size() + 1;
0176 
0177     if(parent.internalId() != INVALID_PARENT_ROW)
0178         return 0;
0179 
0180     return parent.row() == 0 ? m_detected.size() : m_encodings.at(parent.row() - 1).size() - 1;
0181 }
0182 
0183 QVariant
0184 TreeModel::data(const QModelIndex &index, int role) const
0185 {
0186     if(!index.isValid() || role != Qt::DisplayRole)
0187         return QVariant();
0188 
0189     const QModelIndex &parentIndex = index.parent();
0190     if(!parentIndex.isValid())
0191         return index.row() == 0 ? i18n("Detected") : m_encodings.at(index.row() - 1).at(0);
0192 
0193     const QStringList &parentList = parentIndex.row() == 0 ? m_detected : m_encodings.at(parentIndex.row() - 1);
0194     return parentList.at(parentIndex.row() == 0 ? index.row() : index.row() + 1);
0195 }
0196 
0197 #include "encodingdetectdialog.moc"