qsettings 中文键值 注释 支持
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QString>
#include <QVariant>
class QSettings;
class Settings
{
public:
Settings(const QString & fileName);
~Settings();
void setValue ( const QString & key, const QVariant & value );
QVariant value ( const QString & key, const QVariant & defaultValue = QVariant() ) const;
private:
QSettings *d;
};
#endif // SETTINGS_H
#include "settings.h"
#include <QtGui>
QMap<int, QString> comments;
//#define LZM_DEBUG
bool readIniComment(QString fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly))
{
qDebug()<<"readIniComment open"<<fileName<<"failed!: error"<<file.error();
return false;
}
QTextStream inStream(&file);
inStream.setCodec("UTF-8");
QString data;
bool ok = true;
int line=-1;
while (!inStream.atEnd())
{
data = inStream.readLine();
line++;
QString trimmed = data.trimmed();
if(trimmed.isEmpty())
{
continue;
}
else if(trimmed[0]== QChar('#') || trimmed[0]== QChar(';'))
{
comments[line] = data;
#ifdef LZM_DEBUG
qDebug()<<"line"<<line<<"text"<<data;
#endif
}
else
{
continue;
}
}
return ok;
}
bool WriteIniComment(QString fileName)
{
QFile inFile(fileName);
if (!inFile.open(QIODevice::ReadOnly))
{
qDebug()<<"WriteIniComment open"<<fileName<<"failed!";
return false;
}
QString outFileName = fileName+".out";
QFile outfile(outFileName);
if (!outfile.open(QIODevice::WriteOnly))
{
qDebug()<<"open"<<outFileName<<"failed!";
return false;
}
QTextStream inStream(&inFile);
inStream.setCodec("UTF-8");
QTextStream outStream(&outfile);
outStream.setCodec("UTF-8");
QString data;
bool ok = true;
int line=-1;
while (!inStream.atEnd())
{
data = inStream.readLine();
line++;
QString trimmed = data.trimmed();
//add comments
while(comments.contains(line))
{
outStream <<comments[line]<<"\n";
#ifdef LZM_DEBUG
qDebug()<<"line"<<line<<"text"<<comments[line];
#endif
line++;
}
if(trimmed.isEmpty())
{
outStream <<data<<"\n";
continue;
}
else
{
outStream <<data<<"\n";
}
}
inFile.close();
outfile.close();
//
QFile::remove(fileName);
qDebug()<<"remove"<<fileName;
QFile::rename(outFileName, fileName);
qDebug()<<"rename"<<outFileName<<"to"<<fileName;
return ok;
}
QStringList splitArgs(const QString &s, int idx)
{
int l = s.length();
Q_ASSERT(l > 0);
Q_ASSERT(s.at(idx) == QLatin1Char('('));
Q_ASSERT(s.at(l - 1) == QLatin1Char(')'));
QStringList result;
QString item;
for (++idx; idx < l; ++idx) {
QChar c = s.at(idx);
if (c == QLatin1Char(')')) {
Q_ASSERT(idx == l - 1);
result.append(item);
} else if (c == QLatin1Char(' ')) {
result.append(item);
item.clear();
} else {
item.append(c);
}
}
return result;
}
QVariant stringToVariant(const QString &s)
{
if (s.startsWith(QLatin1Char('@'))) {
if (s.endsWith(QLatin1Char(')'))) {
if (s.startsWith(QLatin1String("@ByteArray("))) {
return QVariant(s.toLatin1().mid(11, s.size() - 12));
} else if (s.startsWith(QLatin1String("@Variant("))) {
#ifndef QT_NO_DATASTREAM
QByteArray a(s.toLatin1().mid(9));
QDataStream stream(&a, QIODevice::ReadOnly);
stream.setVersion(QDataStream::Qt_4_0);
QVariant result;
stream >> result;
return result;
#else
Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
#endif
#ifndef QT_NO_GEOM_VARIANT
} else if (s.startsWith(QLatin1String("@Rect("))) {
QStringList args = ::splitArgs(s, 5);
if (args.size() == 4)
return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()));
} else if (s.startsWith(QLatin1String("@Size("))) {
QStringList args = ::splitArgs(s, 5);
if (args.size() == 2)
return QVariant(QSize(args[0].toInt(), args[1].toInt()));
} else if (s.startsWith(QLatin1String("@Point("))) {
QStringList args = ::splitArgs(s, 6);
if (args.size() == 2)
return QVariant(QPoint(args[0].toInt(), args[1].toInt()));
#endif
} else if (s == QLatin1String("@Invalid()")) {
return QVariant();
}
}
if (s.startsWith(QLatin1String("@@")))
return QVariant(s.mid(1));
}
return QVariant(s);
}
bool myReadFunc(QIODevice &device, QSettings::SettingsMap &settingsMap)
{
QString currentSection;
QTextStream stream(&device);
stream.setCodec("UTF-8");
QString data;
bool ok = true;
while (!stream.atEnd())
{
data = stream.readLine();
if (data.trimmed().isEmpty())
{
continue;
}
if (data[0] == QChar('['))
{
QString iniSection;
int inx = data.indexOf(QChar(']'));
if (inx == -1){
ok = false;
iniSection = data.mid(1);
}
else
{
iniSection = data.mid(1, inx - 1);
}
iniSection = iniSection.trimmed();
if (iniSection.compare(QString("general"), Qt::CaseInsensitive) == 0)
{
currentSection.clear();
}
else
{
if (iniSection.compare(QString("%general"), Qt::CaseInsensitive) == 0)
{
currentSection = QString("general");
}
else
{
currentSection = iniSection;
}
currentSection += QChar('/');
}
}
else
{
bool inQuotes = false;
int equalsPos = -1;
QList<int> commaPos;
int i = 0;
while (i < data.size())
{
QChar ch = data.at(i);
if (ch == QChar('='))
{
if (!inQuotes && equalsPos == -1)
{
equalsPos = i;
}
}
else if (ch == QChar('"'))
{
inQuotes = !inQuotes;
}
else if (ch == QChar(','))
{
if (!inQuotes && equalsPos != -1)
{
commaPos.append(i);
}
}
else if (ch == QChar(';') || ch == QChar('#'))
{
if (!inQuotes)
{
data.resize(i);
break;
}
}
else if (ch == QChar('\\'))
{
if (++i < data.size())
{
}
else
{
ok = false;
break;
}
}
i++;
}
if (equalsPos == -1)
{
break;
}
else
{
QString key = data.mid(0, equalsPos).trimmed();
if (key.isEmpty())
{
break;
}
else
{
key = currentSection + key;
}
if (commaPos.isEmpty())
{
//value
QString v = data.mid(equalsPos+1).trimmed();
if (v.startsWith("\"") && v.endsWith("\"") && v.length()>1)
{
v = v.mid(1, v.length()-2);
}
settingsMap[key] = stringToVariant(v);
}
else
{ //value list
commaPos.prepend(equalsPos);
commaPos.append(-1);
QVariantList vals;
for (int i=1; i<commaPos.size(); ++i)
{
QString d = data.mid(commaPos.at(i-1)+1, commaPos.at(i)-commaPos.at(i-1)-1);
QString v = d.trimmed();
if (v.startsWith("\"") && v.endsWith("\"") && v.length()>1)
{
v = v.mid(1, v.length()-2);
}
vals.append(stringToVariant(v) /*stringToVariant(unescapedString(v))*/);
}
settingsMap[key] = vals;
}
}
}
}
return ok;
}
QString variantToString(const QVariant &v)
{
QString result;
switch (v.type()) {
case QVariant::Invalid:
result = QLatin1String("@Invalid()");
break;
case QVariant::ByteArray: {
QByteArray a = v.toByteArray();
result = QLatin1String("@ByteArray(");
result += QString::fromLatin1(a.constData(), a.size());
result += QLatin1Char(')');
break;
}
case QVariant::String:
case QVariant::LongLong:
case QVariant::ULongLong:
case QVariant::Int:
case QVariant::UInt:
case QVariant::Bool:
case QVariant::Double:
case QVariant::KeySequence: {
result = v.toString();
if (result.startsWith(QLatin1Char('@')))
result.prepend(QLatin1Char('@'));
break;
}
#ifndef QT_NO_GEOM_VARIANT
case QVariant::Rect: {
QRect r = qvariant_cast<QRect>(v);
result += QLatin1String("@Rect(");
result += QString::number(r.x());
result += QLatin1Char(' ');
result += QString::number(r.y());
result += QLatin1Char(' ');
result += QString::number(r.width());
result += QLatin1Char(' ');
result += QString::number(r.height());
result += QLatin1Char(')');
break;
}
case QVariant::Size: {
QSize s = qvariant_cast<QSize>(v);
result += QLatin1String("@Size(");
result += QString::number(s.width());
result += QLatin1Char(' ');
result += QString::number(s.height());
result += QLatin1Char(')');
break;
}
case QVariant::Point: {
QPoint p = qvariant_cast<QPoint>(v);
result += QLatin1String("@Point(");
result += QString::number(p.x());
result += QLatin1Char(' ');
result += QString::number(p.y());
result += QLatin1Char(')');
break;
}
#endif // !QT_NO_GEOM_VARIANT
default: {
#ifndef QT_NO_DATASTREAM
QByteArray a;
{
QDataStream s(&a, QIODevice::WriteOnly);
s.setVersion(QDataStream::Qt_4_0);
s << v;
}
result = QLatin1String("@Variant(");
result += QString::fromLatin1(a.constData(), a.size());
result += QLatin1Char(')');
#else
Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
#endif
break;
}
}
return result;
}
bool myWriteFunc(QIODevice &device, const QSettings::SettingsMap &settingsMap)
{
#ifdef Q_OS_WIN
const char * const eol = "\r\n";
#else
const char *eol = "\n";
#endif
bool writeError = false;
QString lastSection;
QMapIterator<QString,QVariant> it(settingsMap);
while(it.hasNext() && !writeError)
{
it.next();
QString key = it.key();
QString section;
qDebug()<<"key: "<<key;
int idx = key.lastIndexOf(QChar('/'));
if (idx == -1)
{
section = QString("[General]");
}
else
{
section = key.left(idx);
key = key.mid(idx+1);
if (section.compare(QString("General"), Qt::CaseInsensitive) == 0)
{
section = QString("[%General]");
}
else
{
section.prepend(QChar('['));
section.append(QChar(']'));
}
}
if (section.compare(lastSection, Qt::CaseInsensitive))
{
if (!lastSection.isEmpty())
{
device.write(eol);
}
lastSection = section;
if (device.write(section.toUtf8() + eol) == -1)
{
writeError = true;
}
}
QByteArray block = key.toUtf8();
block += " = ";
if (it.value().type() == QVariant::StringList)
{
// foreach (QString s, it.value().toStringList())
// {
// block += /*escapedString(s)*/ s;
// block += ", ";
// }
// if (block.endsWith(", "))
// {
// block.chop(2);
// }
qDebug()<< "no support QVariant::StringList";
}
else if (it.value().type() == QVariant::List)
{
// foreach (QVariant v, it.value().toList())
// {
// block += /*escapedString(variantToString(v))*/ v.toString();
// block += ", ";
// }
// if (block.endsWith(", "))
// {
// block.chop(2);
// }
qDebug()<< "no support QVariant::List";
}
else
{
// block += /*escapedString*/(variantToString(it.value()));
// block += it.value().toString();
block += variantToString(it.value());
}
block += eol;
if (device.write(block) == -1)
{
writeError = true;
}
}
return writeError;
}
Settings::Settings(const QString & fileName)
{
readIniComment(fileName);
const QSettings::Format MyIniFormat = QSettings::registerFormat("ini", myReadFunc, myWriteFunc);
d= new QSettings(fileName, MyIniFormat);
d->setIniCodec("UTF-8");
}
Settings::~Settings()
{
if(d)
{
QString fileName = d->fileName();
delete d;
WriteIniComment(fileName);
}
}
void Settings::setValue(const QString &key, const QVariant &value)
{
d->setValue(key, value);
}
QVariant Settings::value(const QString &key, const QVariant &defaultValue) const
{
return d->value(key, defaultValue);
}
qsettings 中文键值 注释 支持的更多相关文章
- KVC - 键值编码
[基本概念] 1.键值编码是一个用于间接访问对象属性的机制,使用该机制不需要调用存取方法和变量实例就可访问对象属性. 2.键值编码方法在OC非正式协议(类目)NSKeyValueCoding中被声明, ...
- CockroachDB学习笔记——[译]CockroachDB中的SQL:映射表中数据到键值存储
CockroachDB学习笔记--[译]CockroachDB中的SQL:映射表中数据到键值存储 原文标题:SQL in CockroachDB: Mapping Table Data to Key- ...
- Mybatis Generator的model生成中文注释,支持oracle和mysql(通过实现CommentGenerator接口的方法来实现)
自己手动实现的前提,对maven项目有基本的了解,在本地成功搭建了maven环境,可以参考我之前的文章:maven环境搭建 项目里新建表时model,mapper以及mapper.xml基本都是用My ...
- JSON创建键值对(key是中文或者数字)方式详解
JSON创建键值对(key是中文或者数字)方式详解 先准备好一个空的json对象 var obj = {}; 1. 最原始的方法 obj.name = 'zhangsan'; //这种方式很简单的添加 ...
- 用字典给Model赋值并支持map键值替换
用字典给Model赋值并支持map键值替换 这个是昨天教程的升级版本,支持键值的map替换. 源码如下: NSObject+Properties.h 与 NSObject+Properties.m / ...
- 【转】kubernetes 中 deployment 支持哪些键值
这个比较全,可以参考 ================= https://www.addops.cn/post/kubernetes-deployment-fileds.html ========== ...
- 将任意一个jQuery对象进行表单序列化,免除了提交请求时大量拼写表单数据的烦恼,支持键值对<name&value>格式和JSON格式。
http://zhengxinlong.iteye.com/blog/848712 将任意一个jQuery对象进行表单序列化,免除了提交请求时大量拼写表单数据的烦恼,支持键值对<name& ...
- OC键值观察KVO
什么是KVO? 什么是KVO?KVO是Key-Value Observing的简称,翻译成中文就是键值观察.这是iOS支持的一种机制,用来做什么呢?我们在开发应用时经常需要进行通信,比如一个model ...
- Java I/O---Properties类(持久化键值对)
1.Properties类简介 Properties类(Java.util.Properties),主要用于读取Java的配置文件,各种语言都有自己所支持的配置文件,配置文件中很多变量是经常改变的,这 ...
随机推荐
- 转:HTTP请求(GET、POST和soap区别)和响应
一直对Http请求和SOAP请求不是太理解,只是知道SOAP是基于Http的,并且增加了很多XML标签,SOAP经常用在WebService中,比如在C#中创建一个WebService,然后在客户端生 ...
- Http Get Post put delete
HTTP POST GET 本质区别详解一 原理区别 一般在浏览器中输入网址访问资源都是通过GET方式:在FORM提交中,可以通过Method指定提交方式为GET或者POST,默认为GET提交 Htt ...
- Android 内核初识(4)属性服务器
简介 Windows平台上有一个叫注册表的东西.注册表可以存储一些类似key/value的键值对.一般而言,系统或某些应用程序会把自己的一些属性存储在注册表中,即使下次系统重启或应用程序重启,它还能够 ...
- Android开发UI之补间动画-Tween Animation
Tween Animation-补间动画 官网链接-http://developer.android.com/reference/android/view/animation/Animation.ht ...
- poj3264Balanced Lineup(RMQ)
http://poj.org/problem?id=3264 RMQ讲解 http://dongxicheng.org/structure/lca-rmq/ j = log2K dp[i][j] = ...
- [hadoop源代码解读] 【SequenceFile】
SequeceFile是Hadoop API提供的一种二进制文件支持.这种二进制文件直接将<key, value>对序列化到文件中.一般对小文件可以使用这种文件合并,即将文件名作为key, ...
- C#中的深拷贝与浅拷贝
1.基本的概念: 首先我们应该了解一下什么叫深拷贝与浅拷贝(Deep Copy and Shallow Copy). a.浅拷贝(Shallow Copy影子克隆):只复制对象的基本类型,对象类型,仍 ...
- Linux Kernel 整数溢出漏洞
漏洞名称: Linux Kernel 整数溢出漏洞 CNNVD编号: CNNVD-201311-062 发布时间: 2013-11-07 更新时间: 2013-11-07 危害等级: 漏洞类型: ...
- Apache ‘mod_pagespeed’模块跨站脚本漏洞
漏洞名称: Apache ‘mod_pagespeed’模块跨站脚本漏洞 CNNVD编号: CNNVD-201310-677 发布时间: 2013-11-05 更新时间: 2013-11-05 危害等 ...
- puppy 制作linux
经过一段时间的使用以后,我们每个人电脑里的Puppy Linux都是独一无二的,我们可以通过简单的方法将自己电脑上的Puppy制作成iso或Live-CD,成为自己玩的“Only You”Puppy ...