15.1.221. tablet_qt/lib/stringfunc.cpp

/*
    Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CamCOPS.

    CamCOPS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
*/

#include "stringfunc.h"
#include <QVector>


namespace stringfunc {

// ============================================================================
// Basic string formatting
// ============================================================================

QString strnum(const QString& prefix, const int num, const QString& suffix)
{
    return prefix + QString::number(num) + suffix;
}


QStringList strnumlist(const QString& prefix, const QVector<int>& numbers,
                       const QString& suffix)
{
    QStringList strings;
    for (auto num : numbers) {
        strings.append(strnum(prefix, num, suffix));
    }
    return strings;
}


// ============================================================================
// Make sequences of strings
// ============================================================================

QStringList strseq(const QString& prefix, const int first, const int last)
{
    Q_ASSERT(first >= 0 && last >= 0 && first <= last);
    QStringList list;
    for (int i = first; i <= last; ++i) {
        list.append(strnum(prefix, i));
    }
    return list;
}


QStringList strseq(const QString& prefix, const int first, const int last,
                   const QStringList& suffixes)
{
    Q_ASSERT(first >= 0 && last >= 0 && first <= last);
    QStringList list;
    for (int i = first; i <= last; ++i) {
        for (const QString& suffix : suffixes) {
            list.append(strnum(prefix, i, suffix));
        }
    }
    return list;
}


QStringList strseq(const QString& prefix, int first, int last,
                   const QString& suffix)
{
    Q_ASSERT(first >= 0 && last >= 0 && first <= last);
    QStringList list;
    for (int i = first; i <= last; ++i) {
        list.append(strnum(prefix, i, suffix));
    }
    return list;
}


QStringList strseq(const QStringList& prefixes,
                   const int first, const int last)
{
    Q_ASSERT(first >= 0 && last >= 0 && first <= last);
    QStringList list;
    for (const QString& prefix : prefixes) {
        for (int i = first; i <= last; ++i) {
            list.append(strnum(prefix, i));
        }
    }
    return list;
}


QStringList strseq(const QStringList& prefixes,
                   const int first, const int last,
                   const QStringList& suffixes)
{
    Q_ASSERT(first >= 0 && last >= 0 && first <= last);
    QStringList list;
    for (const QString& prefix : prefixes) {
        for (int i = first; i <= last; ++i) {
            for (const QString& suffix : suffixes) {
                list.append(strnum(prefix, i, suffix));
            }
        }
    }
    return list;
}


// ============================================================================
// HTML processing
// ============================================================================

QString bold(const QString& str)
{
    return QString("<b>%1</b>").arg(str);
}


QString bold(const int x)
{
    return QString("<b>%1</b>").arg(x);
}


QString a(const QString& url, const QString& text)
{
    return QString("<a href=\"%1\">%2</a>").arg(url, text);
}


QString a(const QString& url_and_text)
{
    return a(url_and_text, url_and_text);
}


QString joinHtmlLines(const QStringList& lines)
{
    return lines.join("<br>");
}


QString& toHtmlLinebreaks(QString& str, const bool convert_embedded_literals)
{
    str.replace("\n", "<br>");
    if (convert_embedded_literals) {
        str.replace("\\n", "<br>");
    }
    return str;
}


QString standardResult(const QString& name,
                       const QString& value,
                       const QString& separator,
                       const QString& suffix)
{
    return QString("%1%2<b>%3</b>%4").arg(name, separator, value, suffix);
}


QString makeTitle(const QString& part1,
                  const QString& part2,
                  const bool colon)
{
    const QString suffix = colon ? ":" : "";
    if (part2.isEmpty()) {
        return QString("<b>%1%2</b>").arg(part1, suffix);
    } else {
        return QString("<b>%1</b> (%2)%3").arg(part1, part2, suffix);
    }
}


QString makeHint(const QString& part1, const QString& part2)
{
    return QString("%1 (%2)").arg(part1, part2);
}


// ============================================================================
// Other string processing
// ============================================================================

QString& replaceFirst(QString& str, const QString& from, const QString& to)
{
    // Replaces in situ
    return str.replace(str.indexOf(from), from.length(), to);
}


const QString STYLIZED_NEWLINE("↵");  // ⏎


QString stylizeNewlines(const QString& str, const bool stylize)
{
    if (!stylize) {
        return str;
    }
    QString nlstr = str;
    nlstr.replace("\n", STYLIZED_NEWLINE);
    return nlstr;
}


QString abbreviate(const QString& str,
                   const int max_len, const bool stylize_newlines,
                   const QString& suffix)
{
    if (str.length() <= max_len) {
        return stylizeNewlines(str, stylize_newlines);
    }
    const int fragment_len = max_len - suffix.length();
    return stylizeNewlines(str.left(fragment_len) + suffix, stylize_newlines);
}


QString escapeString(const QString& string)
{
    // See also https://doc.qt.io/qt-6.5/qregexp.html#escape
    // Obsolete: Qt::escape()

    // Convert to a C++ literal.
    // There's probably a much more efficient way...
    const QByteArray arr = string.toLatin1();
    const int len = arr.length();
    QString result;
    result.reserve(static_cast<int>(len * 1.1));  // as per QString::toHtmlEscaped
    result.append('"');  // opening quote
    for (int i = 0; i < len; ++i) {
        const char c = arr.at(i);
        if (c < ' ') {
            result.append('\\');
            const int code = c - 1 + 'a';
            result.append(QLatin1Char(code));
        } else {
            result.append(c);
        }
    }
    result.append('"');  // closing quote
    result.squeeze();  // as per QString::toHtmlEscaped
    return result;
}


}  // namespace stringfunc