encodingdialog.cpp Example File | Qt Widgets 5.12.8

- Qt 5.12
- Qt Widgets
- Text Codecs Example
- encodingdialog.cpp Example File
- Qt 5.12.8 Reference Documentation

# encodingdialog.cpp Example File

tools/codecs/encodingdialog.cpp

     /****************************************************************************
     **
     ** Copyright (C) 2018 The Qt Company Ltd.
     ** Contact: https://www.qt.io/licensing/
     **
     ** This file is part of the examples of the Qt Toolkit.
     **
     ** $QT_BEGIN_LICENSE:BSD$
     ** Commercial License Usage
     ** Licensees holding valid commercial Qt licenses may use this file in
     ** accordance with the commercial license agreement provided with the
     ** Software or, alternatively, in accordance with the terms contained in
     ** a written agreement between you and The Qt Company. For licensing terms
     ** and conditions see https://www.qt.io/terms-conditions. For further
     ** information use the contact form at https://www.qt.io/contact-us.
     **
     ** BSD License Usage
     ** Alternatively, you may use this file under the terms of the BSD license
     ** as follows:
     **
     ** "Redistribution and use in source and binary forms, with or without
     ** modification, are permitted provided that the following conditions are
     ** met:
     **   * Redistributions of source code must retain the above copyright
     **     notice, this list of conditions and the following disclaimer.
     **   * Redistributions in binary form must reproduce the above copyright
     **     notice, this list of conditions and the following disclaimer in
     **     the documentation and/or other materials provided with the
     **     distribution.
     **   * Neither the name of The Qt Company Ltd nor the names of its
     **     contributors may be used to endorse or promote products derived
     **     from this software without specific prior written permission.
     **
     **
     ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
     **
     ** $QT_END_LICENSE$
     **
     ****************************************************************************/

     #include "encodingdialog.h"

     #if QT_CONFIG(action)
     #  include <QAction>
     #endif
     #include <QDialogButtonBox>
     #include <QFormLayout>
     #include <QLabel>
     #include <QLineEdit>
     #include <QVBoxLayout>

     #if QT_CONFIG(clipboard)
     #  include <QGuiApplication>
     #  include <QClipboard>
     #endif

     #include <QTextStream>

     // Helpers for formatting character sequences

     // Format a special character like '\x0a'
     template <class Int>
     static void formatEscapedNumber(QTextStream &str, Int value, int base,
                                     int width = 0,char prefix = 0)
     {
         str << '\\';
         if (prefix)
             str << prefix;
         const auto oldPadChar = str.padChar();
         const auto oldFieldWidth = str.fieldWidth();
         const auto oldFieldAlignment = str.fieldAlignment();
         const auto oldIntegerBase = str.integerBase();
         str.setPadChar(QLatin1Char('0'));
         str.setFieldWidth(width);
         str.setFieldAlignment(QTextStream::AlignRight);
         str.setIntegerBase(base);
         str << value;
         str.setIntegerBase(oldIntegerBase);
         str.setFieldAlignment(oldFieldAlignment);
         str.setFieldWidth(oldFieldWidth);
         str.setPadChar(oldPadChar);
     }

     template <class Int>
     static bool formatSpecialCharacter(QTextStream &str, Int value)
     {
         bool result = true;
         switch (value) {
         case '\\':
             str << "\\\\";
             break;
         case '\"':
             str << "\\\"";
             break;
         case '\n':
             str << "\\n";
             break;
         default:
             result = false;
             break;
         }
         return result;
     }

     // Format a sequence of characters (QChar, ushort (UTF-16), uint (UTF-32)
     // or just char (Latin1, Utf-8)) with the help of traits specifying
     // how to obtain the code for checking the printable-ness and how to
     // stream out the plain ASCII values.

     template <EncodingDialog::Encoding>
     struct FormattingTraits
     {
     };

     template <>
     struct FormattingTraits<EncodingDialog::Unicode>
     {
         static ushort code(QChar c) { return c.unicode(); }
         static char toAscii(QChar c) { return c.toLatin1(); }
     };

     template <>
     struct FormattingTraits<EncodingDialog::Utf8>
     {
         static ushort code(char c) { return uchar(c); }
         static char toAscii(char c) { return c; }
     };

     template <>
     struct FormattingTraits<EncodingDialog::Utf16>
     {
         static ushort code(ushort c) { return c; }
         static char toAscii(ushort c) { return char(c); }
     };

     template <>
     struct FormattingTraits<EncodingDialog::Utf32>
     {
         static uint code(uint c) { return c; }
         static char toAscii(uint c) { return char(c); }
     };

     template <>
     struct FormattingTraits<EncodingDialog::Latin1>
     {
         static uchar code(char c) { return uchar(c); }
         static char toAscii(char  c) { return c; }
     };

     static bool isHexDigit(char c)
     {
         return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')
             || (c >= 'A' && c <= 'F');
     }

     template <EncodingDialog::Encoding encoding, class Iterator>
     static void formatStringSequence(QTextStream &str, Iterator i1, Iterator i2,
                                      int escapeIntegerBase, int escapeWidth,
                                      char escapePrefix = 0)
     {
         str << '"';
         bool separateHexEscape = false;
         for (; i1 != i2; ++i1) {
             const auto code = FormattingTraits<encoding>::code(*i1);
             if (code >= 0x80) {
                 formatEscapedNumber(str, code, escapeIntegerBase, escapeWidth, escapePrefix);
                 separateHexEscape = escapeIntegerBase == 16 && escapeWidth == 0;
             } else {
                 if (!formatSpecialCharacter(str, code)) {
                     const char c = FormattingTraits<encoding>::toAscii(*i1);
                     // For variable width/hex: Terminate the literal to stop digit parsing
                     // ("\x12" "34...").
                     if (separateHexEscape && isHexDigit(c))
                         str << "\" \"";
                     str << c;
                 }
                 separateHexEscape = false;
             }
         }
         str << '"';
     }

     static QString encodedString(const QString &value, EncodingDialog::Encoding e)
     {
         QString result;
         QTextStream str(&result);
         switch (e) {
         case EncodingDialog::Unicode:
             formatStringSequence<EncodingDialog::Unicode>(str, value.cbegin(), value.cend(),
                                                           16, 4, 'u');
             break;
         case EncodingDialog::Utf8: {
             const QByteArray utf8 = value.toUtf8();
             str << "u8";
             formatStringSequence<EncodingDialog::Utf8>(str, utf8.cbegin(), utf8.cend(),
                                                        8, 3);
         }
             break;
         case EncodingDialog::Utf16: {
             auto utf16 = value.utf16();
             auto utf16End = utf16 + value.size();
             str << 'u';
             formatStringSequence<EncodingDialog::Utf16>(str, utf16, utf16End,
                                                         16, 0, 'x');
         }
             break;
         case EncodingDialog::Utf32: {
             auto utf32 = value.toUcs4();
             str << 'U';
             formatStringSequence<EncodingDialog::Utf32>(str, utf32.cbegin(), utf32.cend(),
                                                         16, 0, 'x');
         }
             break;
         case EncodingDialog::Latin1: {
             const QByteArray latin1 = value.toLatin1();
             formatStringSequence<EncodingDialog::Latin1>(str, latin1.cbegin(), latin1.cend(),
                                                          16, 0, 'x');
         }
             break;
         case EncodingDialog::EncodingCount:
             break;
         }
         return result;
     }

     // Dialog helpers

     static const char *encodingLabels[]
     {
         QT_TRANSLATE_NOOP("EncodingDialog", "Unicode:"),
         QT_TRANSLATE_NOOP("EncodingDialog", "UTF-8:"),
         QT_TRANSLATE_NOOP("EncodingDialog", "UTF-16:"),
         QT_TRANSLATE_NOOP("EncodingDialog", "UTF-32:"),
         QT_TRANSLATE_NOOP("EncodingDialog", "Latin1:")
     };

     static const char *encodingToolTips[]
     {
         QT_TRANSLATE_NOOP("EncodingDialog", "Unicode points for use with any encoding (C++, Python)"),
         QT_TRANSLATE_NOOP("EncodingDialog", "QString::fromUtf8()"),
         QT_TRANSLATE_NOOP("EncodingDialog", "QStringViewLiteral(), wchar_t on Windows"),
         QT_TRANSLATE_NOOP("EncodingDialog", "wchar_t on Unix (Ucs4)"),
         QT_TRANSLATE_NOOP("EncodingDialog", "QLatin1String")
     };

     // A read-only line edit with a tool button to copy the contents
     class DisplayLineEdit : public QLineEdit
     {
         Q_OBJECT
     public:
         explicit DisplayLineEdit(const QIcon &icon, QWidget *parent = nullptr);

     public slots:
         void copyAll();
     };

     DisplayLineEdit::DisplayLineEdit(const QIcon &icon, QWidget *parent) :
         QLineEdit(parent)
     {
         setReadOnly(true);
     #if QT_CONFIG(clipboard) && QT_CONFIG(action)
         auto copyAction = addAction(icon, QLineEdit::TrailingPosition);
         connect(copyAction, &QAction::triggered, this, &DisplayLineEdit::copyAll);
     #endif
     }

     void DisplayLineEdit::copyAll()
     {
     #if QT_CONFIG(clipboard)
         QGuiApplication::clipboard()->setText(text());
     #endif
     }

     static void addFormLayoutRow(QFormLayout *formLayout, const QString &text,
                                  QWidget *w, const QString &toolTip)
     {
         auto label = new QLabel(text);
         label->setToolTip(toolTip);
         w->setToolTip(toolTip);
         label->setBuddy(w);
         formLayout->addRow(label, w);
     }

     EncodingDialog::EncodingDialog(QWidget *parent) :
         QDialog(parent)
     {
         setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
         setWindowTitle(tr("Encodings"));

         auto formLayout = new QFormLayout;
         auto sourceLineEdit = new QLineEdit(this);
         sourceLineEdit->setClearButtonEnabled(true);
         connect(sourceLineEdit, &QLineEdit::textChanged, this, &EncodingDialog::textChanged);

         addFormLayoutRow(formLayout, tr("&Source:"), sourceLineEdit, tr("Enter text"));

         const auto copyIcon = QIcon::fromTheme(QLatin1String("edit-copy"),
                                                QIcon(QLatin1String(":/images/editcopy")));
         for (int i = 0; i < EncodingCount; ++i) {
             m_lineEdits[i] = new DisplayLineEdit(copyIcon, this);
             addFormLayoutRow(formLayout, tr(encodingLabels[i]),
                              m_lineEdits[i], tr(encodingToolTips[i]));
         }

         auto mainLayout = new QVBoxLayout(this);
         mainLayout->addLayout(formLayout);
         auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
         connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
         mainLayout->addWidget(buttonBox);
     }

     void EncodingDialog::textChanged(const QString &t)
     {
         if (t.isEmpty()) {
             for (auto lineEdit : m_lineEdits)
                 lineEdit->clear();
         } else {
              for (int i = 0; i < EncodingCount; ++i)
                  m_lineEdits[i]->setText(encodedString(t, static_cast<Encoding>(i)));
         }
     }

     #include "encodingdialog.moc"