//=============================================================================
//
// File : KviStringConversion.cpp
// Creation date : Thu Oct 20 2000 14:12:21 CEST by Szymon Stefanek
//
// This file is part of the KVIrc IRC client distribution
// Copyright (C) 2000-2010 Szymon Stefanek (pragma at kvirc dot net)
//
// This program 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 2
// of the License, or (at your option) any later version.
//
// This program 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 this program. If not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================
#define _KVI_STRINGCONVERSION_CPP_
#include "KviStringConversion.h"
#include "KviCString.h"
#include "KviMessageTypeSettings.h"
#include "KviPixmap.h"
#include "KviQString.h"
#include <QColor>
#include <QFont>
#include <QRect>
#include <QString>
#include <QStringList>
#include <cstdio>
#include <array>
QString g_szGlobalDir;
QString g_szLocalDir;
namespace KviStringConversion
{
void init(const QString & szGlobalDir, const QString & szLocalDir)
{
g_szGlobalDir = szGlobalDir;
g_szLocalDir = szLocalDir;
}
void encodePath(QString & szBuffer)
{
if(!szBuffer.isEmpty())
{
if(!g_szLocalDir.isEmpty())
{
if(szBuffer.indexOf(g_szLocalDir, 0, Qt::CaseSensitive) == 0)
{
szBuffer.remove(0, g_szLocalDir.length());
szBuffer.prepend("local://");
}
}
if(!g_szGlobalDir.isEmpty())
{
if(szBuffer.indexOf(g_szGlobalDir, 0, Qt::CaseSensitive) == 0)
{
szBuffer.remove(0, g_szGlobalDir.length());
szBuffer.prepend("global://");
}
}
}
}
void decodePath(QString & szBuffer)
{
if(!szBuffer.isEmpty())
{
if(!g_szLocalDir.isEmpty())
{
if(szBuffer.indexOf("local://", 0, Qt::CaseSensitive) == 0)
{
szBuffer.remove(0, 8);
szBuffer.prepend(g_szLocalDir);
}
}
if(!g_szGlobalDir.isEmpty())
{
if(szBuffer.indexOf("global://", 0, Qt::CaseSensitive) == 0)
{
szBuffer.remove(0, 9);
szBuffer.prepend(g_szGlobalDir);
}
}
}
}
void encodePath(QStringList & buffer)
{
for(auto & it : buffer)
encodePath(it);
}
void decodePath(QStringList & buffer)
{
for(auto & it : buffer)
decodePath(it);
}
void toString(const bool bValue, QString & szBuffer)
{
szBuffer = bValue ? '1' : '0';
}
bool fromString(const QString & szValue, bool & bBuffer)
{
if(szValue.isEmpty())
bBuffer = false;
else
bBuffer = !((KviQString::equalCS(szValue, "0")) || (KviQString::equalCI(szValue, "false")));
return true;
}
void toString(const int iValue, QString & szBuffer)
{
szBuffer.setNum(iValue);
}
bool fromString(const QString & szValue, int & iBuffer)
{
bool bOk;
iBuffer = szValue.toInt(&bOk);
return bOk;
}
void toString(const unsigned int uValue, QString & szBuffer)
{
szBuffer.setNum(uValue);
}
bool fromString(const QString & szValue, unsigned int & uBuffer)
{
bool bOk;
uBuffer = szValue.toUInt(&bOk);
return bOk;
}
void toString(const QRect & rValue, QString & szBuffer)
{
szBuffer = QString::asprintf("%d,%d,%d,%d", rValue.x(), rValue.y(), rValue.width(), rValue.height());
}
bool fromString(const QString & szValue, QRect & buffer)
{
QByteArray tmp = szValue.toUtf8();
const char * c = tmp.data();
if(!c)
return false;
int l, t, w, h;
if(sscanf(c, "%d,%d,%d,%d", &l, &t, &w, &h) != 4)
return false;
buffer.setRect(l, t, w, h);
return true;
}
void toString(const QString & szValue, QString & szBuffer)
{
szBuffer = szValue;
}
bool fromString(const QString & szValue, QString & szBuffer)
{
szBuffer = szValue;
return true;
}
void toString(const KviPixmap & pixmap, QString & szBuffer)
{
szBuffer = pixmap.path();
encodePath(szBuffer);
}
bool fromString(const QString & szValue, KviPixmap & buffer)
{
QString szPath(szValue);
decodePath(szPath);
if(szPath.isEmpty())
{
buffer.setNull();
return true;
}
else
{
return buffer.load(szPath);
}
}
void toString(const KviMessageTypeSettings & mValue, QString & szBuffer)
{
szBuffer = QString::asprintf("%d,%u,%u,%d,%d", mValue.m_iPixId, mValue.m_cForeColor, mValue.m_cBackColor, mValue.m_bLogEnabled, mValue.m_iLevel);
}
bool fromString(const QString & szValue, KviMessageTypeSettings & buffer)
{
int iId, iLog, iLevel;
unsigned int uFore, uBack;
QByteArray tmp = szValue.toUtf8();
char * cx = tmp.data();
if(!cx)
return false;
if(sscanf(cx, "%d,%u,%u,%d,%d", &iId, &uFore, &uBack, &iLog, &iLevel) != 5)
return false;
buffer = KviMessageTypeSettings(buffer.m_szType, iId, uFore, uBack, iLog, iLevel);
return true;
}
void toString(const QColor & value, QString & szBuffer)
{
szBuffer = value.name();
}
bool fromString(const QString & szValue, QColor & buffer)
{
#if (QT_VERSION < QT_VERSION_CHECK(6, 4, 0))
buffer.setNamedColor(szValue);
#else
buffer = QColor::fromString(szValue);
#endif
return true;
}
void toString(const QFont & font, QString & szBuffer)
{
QString szFamily(font.family());
QString szOptions;
if(font.bold())
szOptions.append('b');
if(font.italic())
szOptions.append('i');
if(font.underline())
szOptions.append('u');
if(font.strikeOut())
szOptions.append('s');
if(font.fixedPitch())
szOptions.append('f');
szBuffer = QString::asprintf("%s,%d,%d,%d,%s,%s", szFamily.toUtf8().data(), font.pointSize(), font.styleHint(), font.weight(), szOptions.toUtf8().data(), font.styleName().toUtf8().data());
}
/* Helper function to convert Qt < 6.0 font weight to OpenType font weight */
static int fromLegacyWeight(int weight)
{
static constexpr std::array<int, 2> weightMap[] = {
{ 0, QFont::Thin },
{ 12, QFont::ExtraLight },
{ 25, QFont::Light },
{ 50, QFont::Normal },
{ 57, QFont::Medium },
{ 63, QFont::DemiBold },
{ 75, QFont::Bold },
{ 81, QFont::ExtraBold },
{ 87, QFont::Black },
};
int closestDist = INT_MAX;
int result = -1;
for (auto item: weightMap) {
const int dist = qAbs(item[0] - weight);
if (dist < closestDist) {
result = item[1];
closestDist = dist;
} else {
break;
}
}
return result;
}
bool fromString(const QString & szValue, QFont & buffer)
{
KviCString str = szValue;
KviCString family, pointSize, styleHint, weight, options;
str.getToken(family, ',');
str.getToken(pointSize, ',');
str.getToken(styleHint, ',');
str.getToken(weight, ',');
str.getToken(options, ',');
if(!family.isEmpty())
buffer.setFamily(family.ptr());
int i;
bool bOk;
i = pointSize.toInt(&bOk);
if(bOk && (i > 0))
buffer.setPointSize(i);
i = styleHint.toInt(&bOk);
if(bOk && (i >= 0))
buffer.setStyleHint((QFont::StyleHint)i);
i = weight.toInt(&bOk);
if(bOk && (i >= 0)) {
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
buffer.setWeight(i);
#else
/*
* KVIrc <= 5.2.2 used Qt5 font weights (0 = thinner, 99 = bolder)
* Qt6 introduced opentype (css) font weight (100 = thinner, 900 = bolder)
* if the config is using an old weight, convert it
*/
if(i < 100) {
i = KviStringConversion::fromLegacyWeight(i);
}
buffer.setWeight(QFont::Weight(i));
#endif
}
buffer.setBold(options.contains("b"));
buffer.setItalic(options.contains("i"));
buffer.setUnderline(options.contains("u"));
buffer.setStrikeOut(options.contains("s"));
buffer.setFixedPitch(options.contains("f"));
if(!str.isEmpty())
buffer.setStyleName(str.ptr());
return true;
}
void toString(const QStringList & list, QString & szBuffer)
{
szBuffer = list.join(",");
}
bool fromString(const QString & szValue, QStringList & buffer)
{
buffer = szValue.split(",");
return true;
}
}