File indexing completed on 2024-06-16 05:24:49

0001 /*
0002     This file is part of the Okteta Kasten module, made within the KDE community.
0003 
0004     SPDX-FileCopyrightText: 2011 Friedrich W. H. Kossebau <kossebau@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "charsetconversionview.hpp"
0010 
0011 // tool
0012 #include "charsetconversiontool.hpp"
0013 // Okteta Kasten gui
0014 #include <Kasten/Okteta/ByteArrayComboBox>
0015 // Okteta core
0016 #include <Okteta/CharCodec>
0017 // KF
0018 #include <KMessageBox>
0019 #include <KComboBox>
0020 #include <KLocalizedString>
0021 // Qt
0022 #include <QToolBar>
0023 #include <QPushButton>
0024 #include <QFormLayout>
0025 #include <QVBoxLayout>
0026 #include <QCheckBox>
0027 #include <QGroupBox>
0028 #include <QAction>
0029 #include <QIcon>
0030 
0031 namespace Kasten {
0032 
0033 CharsetConversionView::CharsetConversionView(CharsetConversionTool* tool, QWidget* parent)
0034     : QWidget(parent)
0035     , mTool(tool)
0036 {
0037     auto* baseLayout = new QVBoxLayout(this);
0038     baseLayout->setContentsMargins(0, 0, 0, 0);
0039     baseLayout->setSpacing(0);
0040 
0041     // source/target charset
0042     auto* directionCharsetToolBar = new QToolBar(this);
0043 
0044     mDirectionComboBox = new KComboBox(this);
0045     const QStringList directionList {
0046         i18nc("@item:inmenu Is converted _from_ charset (selected in combobox next to this)",
0047               "From"),
0048         i18nc("@item:inmenu Is converted _to_ charset (selected in combobox next to this)",
0049               "To"),
0050     };
0051     mDirectionComboBox->addItems(directionList);
0052     mDirectionComboBox->setCurrentIndex(mTool->conversionDirection());
0053 
0054     const QString directionToolTip =
0055         i18nc("@info:tooltip",
0056               "The direction the bytes are converted, to or from the selected charset.");
0057     mDirectionComboBox->setToolTip(directionToolTip);
0058     const QString directionWhatsThis =
0059         i18nc("@info:whatsthis",
0060               "Select the direction the bytes are converted, to or from the selected charset.");
0061     mDirectionComboBox->setWhatsThis(directionWhatsThis);
0062     connect(mDirectionComboBox, qOverload<int>(&KComboBox::activated),
0063             mTool, &CharsetConversionTool::setConversionDirection);
0064 
0065     directionCharsetToolBar->addWidget(mDirectionComboBox);
0066 
0067     mOtherCharSetComboBox = new KComboBox(this);
0068     const QStringList charCodecNames = Okteta::CharCodec::codecNames();
0069     const int indexOfCurrentCharCodec = charCodecNames.indexOf(mTool->otherCharCodecName());
0070     mOtherCharSetComboBox->addItems(charCodecNames);
0071     mOtherCharSetComboBox->setCurrentIndex(indexOfCurrentCharCodec);
0072     mOtherCharSetComboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
0073 
0074     const QString targetCharsetToolTip =
0075         i18nc("@info:tooltip",
0076               "The charset the bytes are converted to.");
0077     mOtherCharSetComboBox->setToolTip(targetCharsetToolTip);
0078     const QString targetCharsetWhatsThis =
0079         i18nc("@info:whatsthis",
0080               "Select the charset the bytes are converted to.");
0081     mOtherCharSetComboBox->setWhatsThis(targetCharsetWhatsThis);
0082 
0083     connect(mOtherCharSetComboBox, &KComboBox::textActivated,
0084             mTool, &CharsetConversionTool::setOtherCharCodecName);
0085 
0086     directionCharsetToolBar->addWidget(mOtherCharSetComboBox);
0087     baseLayout->addWidget(directionCharsetToolBar);
0088 
0089     // settings
0090     auto* settingsBox = new QGroupBox(i18nc("@title:group", "Parameters"), this);
0091 
0092     auto* settingsLayout = new QFormLayout();
0093 
0094     const QString substituteMissingCharLabelText =
0095         i18nc("@option:check substitute bytes whose char is not part of the target charset",
0096               "Substitute missing:");
0097     mSubstituteMissingCharCheckBox = new QCheckBox(this);
0098     mSubstituteMissingCharCheckBox->setChecked(mTool->isSubstitutingMissingChars());
0099     const QString substituteMissingCharToolTip =
0100         i18nc("@info:tooltip",
0101               "Selects if bytes should be substituted with a default byte "
0102               "if its char in the source charset is not part of the target charset.");
0103     const QString substituteMissingCharWhatsThis =
0104         i18nc("@info:whatsthis",
0105               "Set to true if bytes should be substituted with a default byte "
0106               "if its char in the source charset is not part of the target charset.");
0107     mSubstituteMissingCharCheckBox->setToolTip(substituteMissingCharToolTip);
0108     mSubstituteMissingCharCheckBox->setWhatsThis(substituteMissingCharWhatsThis);
0109     connect(mSubstituteMissingCharCheckBox, &QCheckBox::toggled,
0110             mTool, &CharsetConversionTool::setSubstitutingMissingChars);
0111     settingsLayout->addRow(substituteMissingCharLabelText, mSubstituteMissingCharCheckBox);
0112     // TODO: control what happens on conflicts or unmatched chars in the target set
0113     // option to try only if no conflicts or unmatched chars are hit
0114     // choosing substitute for unmatched and resolve conflicts (general/case-by-case)
0115     // TODO: extra button to request check if all chars are matched, shows state
0116     // TODO: option to switch view to target charset, once done, if "to" other charset
0117 
0118     // default byte
0119     const QString substituteByteLabelText =
0120         i18nc("@label:textbox byte to use for chars which are not part of the target charset",
0121               "Substitute byte:");
0122     mSubstituteByteEdit = new Okteta::ByteArrayComboBox(this);
0123     mSubstituteByteEdit->setMinLength(1);
0124     mSubstituteByteEdit->setMaxLength(1);
0125     const QString substituteByteToolTip =
0126         i18nc("@info:tooltip",
0127               "The byte to use for chars which are not part of the target charset.");
0128     const QString substituteByteWhatsThis =
0129         i18nc("@info:whatsthis",
0130               "Define the byte to use for chars which are not part of the target charset.");
0131     mSubstituteByteEdit->setToolTip(substituteByteToolTip);
0132     mSubstituteByteEdit->setWhatsThis(substituteByteWhatsThis);
0133 //     mSubstituteByteEdit->setEnabled( mTool->isSubstitutingMissingChars() );
0134     mSubstituteByteEdit->setEnabled(false);   // TODO: fix char entering and enable again
0135     connect(mSubstituteByteEdit, &Okteta::ByteArrayComboBox::byteArrayChanged,
0136             this, &CharsetConversionView::onDefaultByteEditChanged);
0137 //     connect( mSubstituteMissingCharCheckBox, SIGNAL(toggled(bool)),
0138 //              mSubstituteByteEdit, SLOT(setEnabled(bool)) );
0139     mSubstituteByteEdit->setByteArray(QByteArray(1, mTool->substituteByte()));
0140     settingsLayout->addRow(substituteByteLabelText, mSubstituteByteEdit);
0141 
0142     settingsBox->setLayout(settingsLayout);
0143 
0144     baseLayout->addWidget(settingsBox);
0145 
0146     // action
0147     auto* actionToolBar = new QToolBar(this);
0148     actionToolBar->setToolButtonStyle(Qt::ToolButtonFollowStyle);
0149 
0150     auto* stretcher = new QWidget(this);
0151     stretcher->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
0152     actionToolBar->addWidget(stretcher);
0153 
0154     mConvertAction =
0155         actionToolBar->addAction(QIcon::fromTheme(QStringLiteral("run-build")),
0156                                  i18n("Con&vert"),
0157                                  this, &CharsetConversionView::onConvertButtonClicked);
0158     mConvertAction->setToolTip(i18nc("@info:tooltip",
0159                        "Converts the bytes in the selected range."));
0160     mConvertAction->setWhatsThis(xi18nc("@info:whatsthis",
0161                         "If you press the <interface>Convert</interface> button, "
0162                         "all bytes in the selected range "
0163                         "will be replaced by bytes which represent the same character "
0164                         "in the selected target charset."));
0165     baseLayout->addWidget(actionToolBar);
0166     baseLayout->addStretch();
0167 
0168     connect(mTool, &CharsetConversionTool::isApplyableChanged,
0169             this, &CharsetConversionView::onApplyableChanged);
0170     connect(mTool, &CharsetConversionTool::conversionDone,
0171             this, &CharsetConversionView::onConversionDone);
0172 }
0173 
0174 CharsetConversionView::~CharsetConversionView() = default;
0175 
0176 void CharsetConversionView::onApplyableChanged(bool isApplyable)
0177 {
0178     mConvertAction->setEnabled(isApplyable);
0179 }
0180 
0181 void CharsetConversionView::onDefaultByteEditChanged(const QByteArray& byteArray)
0182 {
0183     Q_UNUSED(byteArray);
0184 }
0185 
0186 void CharsetConversionView::onConvertButtonClicked()
0187 {
0188     mTool->convertChars();
0189 }
0190 
0191 void CharsetConversionView::onConversionDone(bool success, int convertedBytesCount,
0192                                              const QMap<Okteta::Byte, int>& failedPerByteCount)
0193 {
0194 
0195     const QString messageBoxTitle = mTool->title();
0196 
0197     if (success) {
0198         QString conversionReport = (convertedBytesCount == 0) ?
0199                                    i18nc("@info", "No bytes converted.") :
0200                                    i18ncp("@info", "1 byte converted.", "%1 bytes converted.", convertedBytesCount);
0201         if (mTool->isSubstitutingMissingChars()) {
0202             int totalFailedByteCount = 0;
0203             for (int failedByteCount : failedPerByteCount) {
0204                 totalFailedByteCount += failedByteCount;
0205             }
0206 
0207             // TODO: show table with failed bytes and their number.
0208             conversionReport += QLatin1String("<br />");
0209             conversionReport += (totalFailedByteCount == 0) ?
0210                                 i18nc("@info", "No bytes substituted.") :
0211                                 i18ncp("@info", "1 byte substituted.", "%1 bytes substituted.", totalFailedByteCount);
0212         }
0213         KMessageBox::information(/*mParentWidget*/ nullptr,
0214                                  conversionReport,
0215                                  messageBoxTitle);
0216     } else {
0217         // TODO: show/goto byte which on which conversion fails
0218         KMessageBox::error(/*mParentWidget*/ nullptr,
0219                            i18nc("@info",
0220                                  "Conversion cancelled because of chars which are not "
0221                                  "in the target charset."),
0222                            messageBoxTitle);
0223 
0224     }
0225 }
0226 
0227 }
0228 
0229 #include "moc_charsetconversionview.cpp"