File indexing completed on 2024-05-26 05:56:26
0001 /* 0002 This file is part of the Okteta Kasten module, made within the KDE community. 0003 0004 SPDX-FileCopyrightText: 2011, 2022 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 "charsetconversiontool.hpp" 0010 0011 // tool 0012 #include "charsetconversionjob.hpp" 0013 // Okteta Kasten gui 0014 #include <Kasten/Okteta/ByteArrayView> 0015 // Okteta Kasten core 0016 #include <Kasten/Okteta/ByteArrayDocument> 0017 // Okteta core 0018 #include <Okteta/CharCodec> 0019 #include <Okteta/AbstractByteArrayModel> 0020 #include <Okteta/ChangesDescribable> 0021 // KF 0022 #include <KConfigGroup> 0023 #include <KSharedConfig> 0024 #include <KLocalizedString> 0025 // Qt 0026 #include <QApplication> 0027 0028 0029 template <> 0030 inline Kasten::CharsetConversionTool::ConversionDirection KConfigGroup::readEntry(const char *key, 0031 const Kasten::CharsetConversionTool::ConversionDirection &defaultValue) const 0032 { 0033 const QString entry = readEntry(key, QString()); 0034 const Kasten::CharsetConversionTool::ConversionDirection direction = 0035 (entry == QLatin1String("From")) ? Kasten::CharsetConversionTool::ConvertFrom : 0036 (entry == QLatin1String("To")) ? Kasten::CharsetConversionTool::ConvertTo : 0037 /* else */ defaultValue; 0038 return direction; 0039 } 0040 0041 template <> 0042 inline void KConfigGroup::writeEntry(const char *key, 0043 const Kasten::CharsetConversionTool::ConversionDirection &value, 0044 KConfigBase::WriteConfigFlags flags) 0045 { 0046 const QString valueString = 0047 (value == Kasten::CharsetConversionTool::ConvertFrom) ? QLatin1String("From") : QLatin1String("To"); 0048 writeEntry(key, valueString, flags); 0049 } 0050 0051 namespace Kasten { 0052 // helper class for KConfigGroup API 0053 class ByteParameter 0054 { 0055 public: 0056 Okteta::Byte value; 0057 0058 operator Okteta::Byte() const { return value; } 0059 }; 0060 } 0061 0062 template <> 0063 inline Kasten::ByteParameter KConfigGroup::readEntry(const char *key, 0064 const Kasten::ByteParameter &defaultValue) const 0065 { 0066 const int storageValue = readEntry(key, -1); 0067 if ((0 <= storageValue) && (storageValue <= 255)) { 0068 return Kasten::ByteParameter{static_cast<Okteta::Byte>(storageValue)}; 0069 } 0070 return defaultValue; 0071 } 0072 0073 template <> 0074 inline void KConfigGroup::writeEntry(const char *key, 0075 const Kasten::ByteParameter &value, 0076 KConfigBase::WriteConfigFlags flags) 0077 { 0078 writeEntry(key, static_cast<uint>(value.value), flags); 0079 } 0080 0081 0082 namespace Kasten { 0083 0084 CharsetConversionTool::CharsetConversionTool() 0085 { 0086 setObjectName(QStringLiteral("CharsetConversion")); 0087 0088 const KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0089 0090 mOtherCharCodecName = configGroup.readEntry(OtherCharCodecNameConfigKey); 0091 mConversionDirection = configGroup.readEntry(ConversionDirectionConfigKey, DefaultConversionDirection); 0092 mSubstitutingMissingChars = configGroup.readEntry(SubstituteMissingCharsConfigKey, DefaultSubstituteMissingChars); 0093 mSubstituteByte = configGroup.readEntry(SubstituteByteConfigKey, ByteParameter{DefaultSubstituteByte}); 0094 } 0095 0096 CharsetConversionTool::~CharsetConversionTool() = default; 0097 0098 bool CharsetConversionTool::isApplyable() const 0099 { 0100 return (mByteArrayModel && 0101 mByteArrayView && mByteArrayView->hasSelectedData() && 0102 !mOtherCharCodecName.isEmpty() && 0103 mByteArrayView->charCodingName() != mOtherCharCodecName); 0104 } 0105 0106 QString CharsetConversionTool::title() const 0107 { 0108 return i18nc("@title:window of the tool to convert between charsets", 0109 "Charset Conversion"); 0110 } 0111 0112 QString CharsetConversionTool::otherCharCodecName() const 0113 { 0114 return mOtherCharCodecName; 0115 } 0116 0117 CharsetConversionTool::ConversionDirection CharsetConversionTool::conversionDirection() const 0118 { 0119 return mConversionDirection; 0120 } 0121 0122 bool CharsetConversionTool::isSubstitutingMissingChars() const 0123 { 0124 return mSubstitutingMissingChars; 0125 } 0126 0127 Okteta::Byte CharsetConversionTool::substituteByte() const 0128 { 0129 return mSubstituteByte; 0130 } 0131 0132 void CharsetConversionTool::setTargetModel(AbstractModel* model) 0133 { 0134 if (mByteArrayView) { 0135 mByteArrayView->disconnect(this); 0136 } 0137 0138 mByteArrayView = model ? model->findBaseModel<ByteArrayView*>() : nullptr; 0139 0140 ByteArrayDocument* document = 0141 mByteArrayView ? qobject_cast<ByteArrayDocument*>(mByteArrayView->baseModel()) : nullptr; 0142 mByteArrayModel = document ? document->content() : nullptr; 0143 0144 if (mByteArrayView && mByteArrayModel) { 0145 connect(mByteArrayView, &ByteArrayView::charCodecChanged, 0146 this, &CharsetConversionTool::onViewChanged); 0147 connect(mByteArrayView, &ByteArrayView::selectedDataChanged, 0148 this, &CharsetConversionTool::onViewChanged); 0149 } 0150 0151 onViewChanged(); 0152 } 0153 0154 void CharsetConversionTool::setOtherCharCodecName(const QString& codecName) 0155 { 0156 if (codecName == mOtherCharCodecName) { 0157 return; 0158 } 0159 0160 mOtherCharCodecName = codecName; 0161 0162 KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0163 configGroup.writeEntry(OtherCharCodecNameConfigKey, mOtherCharCodecName); 0164 0165 Q_EMIT isApplyableChanged(isApplyable()); 0166 } 0167 0168 void CharsetConversionTool::setConversionDirection(int conversionDirection) 0169 { 0170 if (mConversionDirection == (ConversionDirection)conversionDirection) { 0171 return; 0172 } 0173 0174 mConversionDirection = (ConversionDirection)conversionDirection; 0175 0176 KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0177 configGroup.writeEntry(ConversionDirectionConfigKey, mConversionDirection); 0178 } 0179 0180 void CharsetConversionTool::setSubstitutingMissingChars(bool isSubstitutingMissingChars) 0181 { 0182 if (mSubstitutingMissingChars == isSubstitutingMissingChars) { 0183 return; 0184 } 0185 0186 mSubstitutingMissingChars = isSubstitutingMissingChars; 0187 0188 KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0189 configGroup.writeEntry(SubstituteMissingCharsConfigKey, mSubstitutingMissingChars); 0190 } 0191 0192 void CharsetConversionTool::setSubstituteByte(int byte) 0193 { 0194 if (mSubstituteByte == static_cast<Okteta::Byte>(byte)) { 0195 return; 0196 } 0197 0198 mSubstituteByte = static_cast<Okteta::Byte>(byte); 0199 0200 KConfigGroup configGroup(KSharedConfig::openConfig(), ConfigGroupId); 0201 configGroup.writeEntry(SubstituteByteConfigKey, ByteParameter{mSubstituteByte}); 0202 } 0203 0204 void CharsetConversionTool::convertChars() 0205 { 0206 QApplication::setOverrideCursor(Qt::WaitCursor); 0207 0208 const Okteta::AddressRange convertedSection = mByteArrayView->selection(); 0209 QByteArray conversionResult; 0210 conversionResult.resize(convertedSection.width()); 0211 0212 Okteta::CharCodec* viewCharCodec = 0213 Okteta::CharCodec::createCodec(mByteArrayView->charCodingName()); 0214 Okteta::CharCodec* otherCharCodec = 0215 Okteta::CharCodec::createCodec(mOtherCharCodecName); 0216 const bool convertToOther = (mConversionDirection == ConvertTo); 0217 Okteta::CharCodec* fromCharCodec = convertToOther ? viewCharCodec : otherCharCodec; 0218 Okteta::CharCodec* toCharCodec = convertToOther ? otherCharCodec : viewCharCodec; 0219 auto* charsetConversionJob = 0220 new CharsetConversionJob(reinterpret_cast<Okteta::Byte*>(conversionResult.data()), 0221 mByteArrayModel, convertedSection, 0222 convertToOther ? viewCharCodec : otherCharCodec, 0223 convertToOther ? otherCharCodec : viewCharCodec, 0224 mSubstitutingMissingChars, mSubstituteByte 0225 ); // TODO: report also actually converted bytes 0226 const bool success = charsetConversionJob->exec(); 0227 0228 if (success) { // TODO: if nothing needed to be converted, just report and don't add change 0229 Okteta::ChangesDescribable* changesDescribable = 0230 qobject_cast<Okteta::ChangesDescribable*>(mByteArrayModel); 0231 0232 if (changesDescribable) { 0233 const QString description = 0234 i18nc("Converted from charset 1 to charset 2", 0235 "%1 to %2", fromCharCodec->name(), toCharCodec->name()); 0236 changesDescribable->openGroupedChange(description); 0237 } 0238 mByteArrayModel->replace(convertedSection, conversionResult); 0239 if (changesDescribable) { 0240 changesDescribable->closeGroupedChange(); 0241 } 0242 } 0243 0244 delete viewCharCodec; 0245 delete otherCharCodec; 0246 0247 QApplication::restoreOverrideCursor(); 0248 0249 const QMap<Okteta::Byte, int>& failedPerByteCount = charsetConversionJob->failedPerByteCount(); 0250 const int convertedBytesCount = charsetConversionJob->convertedBytesCount(); 0251 0252 mByteArrayView->setFocus(); 0253 0254 Q_EMIT conversionDone(success, convertedBytesCount, failedPerByteCount); 0255 } 0256 0257 void CharsetConversionTool::onViewChanged() 0258 { 0259 Q_EMIT isApplyableChanged(isApplyable()); 0260 } 0261 0262 } 0263 0264 #include "moc_charsetconversiontool.cpp"