/*
* Copyright (C) 2020-2022 Roy Qu (royqh1979@gmail.com)
*
* 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 3 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, see .
*/
#include "qt_utils/utils.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef Q_OS_WIN
#include
#include
#include
#include
#include
#endif
#include "charsetinfo.h"
BaseError::BaseError(const QString &reason):
mReason(reason)
{
}
QString BaseError::reason() const
{
return mReason;
}
IndexOutOfRange::IndexOutOfRange(int Index):
BaseError(QObject::tr("Index %1 out of range").arg(Index))
{
}
FileError::FileError(const QString &reason): BaseError(reason)
{
}
const QByteArray guessTextEncoding(const QByteArray& text){
bool allAscii;
int ii;
int size;
const QByteArray& s=text;
size = s.length();
if ( (size >= 3) && ((unsigned char)s[0]==0xEF) && ((unsigned char)s[1]==0xBB) && ((unsigned char)s[2]==0xBF)) {
return ENCODING_UTF8_BOM;
}
allAscii = true;
ii = 0;
while (ii < size) {
unsigned char ch = s[ii];
if (ch < 0x80 ) {
ii++; // is an ascii char
} else if (ch < 0xC0) { // value between 0x80 and 0xC0 is an invalid UTF-8 char
return ENCODING_SYSTEM_DEFAULT;
} else if (ch < 0xE0) { // should be an 2-byte UTF-8 char
if (ii>=size-1) {
return ENCODING_SYSTEM_DEFAULT;
}
unsigned char ch2=s[ii+1];
if ((ch2 & 0xC0) !=0x80) {
return ENCODING_SYSTEM_DEFAULT;
}
allAscii = false;
ii+=2;
} else if (ch < 0xF0) { // should be an 3-byte UTF-8 char
if (ii>=size-2) {
return ENCODING_SYSTEM_DEFAULT;
}
unsigned char ch2=s[ii+1];
unsigned char ch3=s[ii+2];
if (((ch2 & 0xC0)!=0x80) || ((ch3 & 0xC0)!=0x80)) {
return ENCODING_SYSTEM_DEFAULT;
}
allAscii = false;
ii+=3;
} else { // invalid UTF-8 char
return ENCODING_SYSTEM_DEFAULT;
}
}
if (allAscii)
return ENCODING_ASCII;
return ENCODING_UTF8;
}
bool isTextAllAscii(const QByteArray& text) {
for (char c:text) {
if (c<0 || c>127) {
return false;
}
}
return true;
}
bool isTextAllAscii(const QString& text) {
for (QChar c:text) {
if (c.unicode()>127) {
return false;
}
}
return true;
}
bool isNonPrintableAsciiChar(char ch)
{
return (ch<=32) && (ch>=0);
}
QStringList textToLines(const QString &text)
{
QTextStream stream(&((QString&)text),QIODevice::ReadOnly);
return readStreamToLines(&stream);
}
void textToLines(const QString &text, LineProcessFunc lineFunc)
{
QTextStream stream(&((QString&)text),QIODevice::ReadOnly);
readStreamToLines(&stream,lineFunc);
}
QString linesToText(const QStringList &lines, const QString& lineBreak)
{
return lines.join(lineBreak);
}
QList splitByteArrayToLines(const QByteArray &content)
{
QList lines;
const char* p =content.constData();
const char* end = p+content.length();
const char* lineStart = p;
QByteArray line;
while (p<=end) {
char ch=*p;
switch(ch) {
case '\r':
line = QByteArray(lineStart, p-lineStart);
lines.append(line);
p++;
if (*p=='\n')
p++;
lineStart = p;
break;
case '\n':
line = QByteArray(lineStart, p-lineStart);
lines.append(line);
p++;
lineStart = p;
break;
default:
p++;
}
}
if (lineStart>end) {
lines.append("");
} else {
line = QByteArray(lineStart, end-lineStart+1);
lines.append(line);
}
return lines;
}
QString trimRight(const QString &s)
{
if (s.isEmpty())
return s;
int i = s.length()-1;
// while ((i>=0) && ((s[i] == '\r') || (s[i]=='\n') || (s[i] == '\t') || (s[i]==' '))) {
while ((i>=0) && (s[i]<=32)) {
i--;
};
if (i>=0) {
return s.left(i+1);
} else {
return QString();
}
}
QString trimLeft(const QString &s)
{
if (s.isEmpty())
return s;
int i=0;
// while ((i32)
break;
n++;
}
return n;
}
bool stringIsBlank(const QString &s)
{
for (QChar ch:s) {
if (ch != ' ' && ch != '\t')
return false;
}
return true;
}
QByteArray toByteArray(const QString &s)
{
//return s.toLocal8Bit();
return s.toUtf8();
}
QString fromByteArray(const QByteArray &s)
{
QTextCodec* codec = QTextCodec::codecForName(ENCODING_UTF8);
QTextCodec::ConverterState state;
if (!codec)
return QString(s);
QString tmp = codec->toUnicode(s,s.length(),&state);
if (state.invalidChars>0)
tmp = QString::fromLocal8Bit(s);
return tmp;
}
QStringList readStreamToLines(QTextStream *stream)
{
QStringList list;
QString s;
while (stream->readLineInto(&s)) {
list.append(s);
}
return list;
}
void readStreamToLines(QTextStream *stream,
LineProcessFunc lineFunc)
{
QString s;
while (stream->readLineInto(&s)) {
lineFunc(s);
}
}
QStringList readFileToLines(const QString& fileName, QTextCodec* codec)
{
QFile file(fileName);
if (file.open(QFile::ReadOnly)) {
QTextStream stream(&file);
stream.setCodec(codec);
stream.setAutoDetectUnicode(false);
return readStreamToLines(&stream);
}
return QStringList();
}
void readFileToLines(const QString &fileName, QTextCodec *codec, LineProcessFunc lineFunc)
{
QFile file(fileName);
if (file.open(QFile::ReadOnly)) {
QTextStream stream(&file);
stream.setCodec(codec);
stream.setAutoDetectUnicode(false);
readStreamToLines(&stream, lineFunc);
}
}
static QStringList tryLoadFileByEncoding(QByteArray encodingName, QFile& file, bool* isOk) {
QStringList result;
*isOk=false;
QTextCodec* codec = QTextCodec::codecForName(encodingName);
if (!codec)
return result;
file.reset();
QTextCodec::ConverterState state;
while (true) {
if (file.atEnd()){
break;
}
QByteArray line = file.readLine();
if (line.endsWith("\r\n")) {
line.remove(line.length()-2,2);
} else if (line.endsWith("\r")) {
line.remove(line.length()-1,1);
} else if (line.endsWith("\n")){
line.remove(line.length()-1,1);
}
QString newLine = codec->toUnicode(line.constData(),line.length(),&state);
if (state.invalidChars>0) {
return QStringList();
}
result.append(newLine);
}
*isOk=true;
return result;
}
QStringList readFileToLines(const QString &fileName)
{
QFile file(fileName);
if (file.size()<=0)
return QStringList();
QStringList result;
if (file.open(QFile::ReadOnly)) {
bool ok;
result = tryLoadFileByEncoding("UTF-8",file,&ok);
if (ok) {
return result;
}
QByteArray realEncoding = pCharsetInfoManager->getDefaultSystemEncoding();
result = tryLoadFileByEncoding(realEncoding,file,&ok);
if (ok) {
return result;
}
QList charsets = pCharsetInfoManager->findCharsetByLocale(pCharsetInfoManager->localeName());
if (!charsets.isEmpty()) {
QSet encodingSet;
for (int i=0;iname);
}
encodingSet.remove(realEncoding);
foreach (const QByteArray& encodingName,encodingSet) {
if (encodingName == ENCODING_UTF8)
continue;
result = tryLoadFileByEncoding("UTF-8",file,&ok);
if (ok) {
return result;
}
}
}
}
return result;
}
QByteArray readFileToByteArray(const QString &fileName)
{
QFile file(fileName);
if (file.open(QFile::ReadOnly)) {
return file.readAll();
}
return QByteArray();
}
bool stringToFile(const QString &str, const QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
return false;
QTextStream stream(&file);
stream<= QT_VERSION_CHECK(5,15,0)
<=0 && (path[pos]=='/' || path[pos]==QDir::separator()))
pos--;
return path.mid(0,pos+1);
}
QString changeFileExt(const QString& filename, QString ext)
{
QFileInfo fileInfo(filename);
QString suffix = fileInfo.suffix();
QString name = fileInfo.fileName();
QString path;
if (!ext.isEmpty() && !ext.startsWith(".")) {
ext = "."+ext;
}
if (fileInfo.path() != ".") {
path = includeTrailingPathDelimiter(fileInfo.path());
}
if (suffix.isEmpty()) {
return path+filename+ext;
} else {
return path+fileInfo.completeBaseName()+ext;
}
}
QString extractRelativePath(const QString &base, const QString &dest)
{
if (dest.isEmpty())
return QString();
QFileInfo baseInfo(base);
QDir baseDir;
if (baseInfo.isDir()) {
baseDir = QDir(baseInfo.absoluteFilePath());
} else {
baseDir = baseInfo.absoluteDir();
}
return baseDir.relativeFilePath(dest);
}
QString localizePath(const QString &path)
{
QString result = path;
result.replace("/",QDir::separator());
return result;
}
QString extractFileName(const QString &fileName)
{
QFileInfo fileInfo(fileName);
return fileInfo.fileName();
}
QString extractFileDir(const QString &fileName)
{
return extractFilePath(fileName);
}
QString extractFilePath(const QString &filePath)
{
QFileInfo info(filePath);
return info.path();
}
QString extractAbsoluteFilePath(const QString &filePath)
{
QFileInfo info(filePath);
return info.absoluteFilePath();
}
bool isReadOnly(const QString &filename)
{
return QFile(filename).isWritable();
}
int compareFileModifiedTime(const QString &filename1, const QString &filename2)
{
QFileInfo fileInfo1(filename1);
QFileInfo fileInfo2(filename2);
qint64 time1=fileInfo1.lastModified().toMSecsSinceEpoch();
qint64 time2=fileInfo2.lastModified().toMSecsSinceEpoch();
if (time1 > time2)
return 1;
if (time1 < time2)
return -1;
return 0;
}
void inflateRect(QRect &rect, int delta)
{
inflateRect(rect,delta,delta);
}
void inflateRect(QRect &rect, int dx, int dy)
{
rect.setLeft(rect.left()-dx);
rect.setRight(rect.right()+dx);
rect.setTop(rect.top()-dy);
rect.setBottom(rect.bottom()+dy);
}
static int defaultScreenDPI = -1;
int screenDPI()
{
if (defaultScreenDPI<1) {
defaultScreenDPI = qApp->primaryScreen()->logicalDotsPerInch();
}
return defaultScreenDPI;
}
void setScreenDPI(int dpi)
{
defaultScreenDPI = dpi;
}
float pointToPixel(float point, float dpi)
{
return point * dpi / 72;
}
float pointToPixel(float point)
{
return pointToPixel(point,screenDPI());
}
float pixelToPoint(float pixel)
{
return pixel * 72 / screenDPI();
}
void decodeKey(const int combinedKey, int &key, Qt::KeyboardModifiers &modifiers)
{
modifiers = Qt::NoModifier;
if (combinedKey & Qt::ShiftModifier) {
modifiers|=Qt::ShiftModifier;
}
if (combinedKey & Qt::ControlModifier) {
modifiers|=Qt::ControlModifier;
}
if (combinedKey & Qt::AltModifier) {
modifiers|=Qt::AltModifier;
}
if (combinedKey & Qt::MetaModifier) {
modifiers|=Qt::MetaModifier;
}
if (combinedKey & Qt::KeypadModifier) {
modifiers|= Qt::KeypadModifier;
}
key = combinedKey & ~(Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier | Qt::KeypadModifier);
}
bool isInFolder(const QString &folderpath, const QString &filepath)
{
QDir folder(folderpath);
QFileInfo fileInfo(filepath);
return fileInfo.absoluteFilePath().startsWith(includeTrailingPathDelimiter(folder.absolutePath()));
}
void createFile(const QString &fileName)
{
stringToFile("",fileName);
}
QString cleanPath(const QString &dirPath)
{
return QDir::cleanPath(dirPath);
}
QString generateAbsolutePath(const QString &dirPath, const QString &relativePath)
{
if (relativePath.isEmpty())
return QString();
return QDir::cleanPath(QDir(dirPath).absoluteFilePath(relativePath));
}
QString escapeSpacesInString(const QString &str)
{
QString result=str;
return result.replace(' ',"%20");
}
QStringList extractRelativePaths(const QString &base, const QStringList &destList)
{
QStringList list;
foreach(const QString& dest,destList) {
list.append(extractRelativePath(base,dest));
}
return list;
}
QStringList absolutePaths(const QString &dirPath, const QStringList &relativePaths)
{
QStringList list;
foreach(const QString& path,relativePaths) {
list.append(generateAbsolutePath(dirPath,path));
}
return list;
}
bool isBinaryContent(const QByteArray &text)
{
for (char c:text) {
if (c>=0 && c<' ' && c!='\t' && c!='\n' && c!='\r') {
return true;
}
}
return false;
}
void clearQPlainTextEditFormat(QTextEdit *editor)
{
QTextCursor cursor = editor->textCursor();
cursor.select(QTextCursor::Document);
cursor.setCharFormat(QTextCharFormat());
cursor.clearSelection();
}