pgLab/pglablib/util.cpp

357 lines
8.5 KiB
C++
Raw Normal View History

#include "util.h"
#include "CsvWriter.h"
#include <QApplication>
#include <QTextStream>
#include <QClipboard>
2017-02-05 08:23:06 +01:00
#include <sstream>
#include <stdexcept>
// Supported range from microseconds to seconds
// min:sec to hours::min::sec
QString msfloatToHumanReadableString(float ms)
{
QString unit;
float val;
int deci = 2;
if (ms < 1.0f) {
val = ms * 1000.f;
//result = QString::asprintf("%0.3f", ms * 1000.0f);
unit = u8"μs";
}
else if (ms >= 1000.0) {
val = ms / 1000.0f;
unit = "s";
if (val >= 60.0) {
int secs = val;
int min = secs / 60.0;
secs -= min * 60;
if (min >= 60) {
int hour = min / 60;
min -= hour * 60;
return QString::asprintf("%d:%02d:%02d", hour, min, secs);
}
else {
return QString::asprintf("%02d:%02d", min, secs);
}
}
}
else {
val = ms;
unit = "ms";
}
// if (val >= 1000.f) {
// deci = 0;
// }
// else
if (val >= 100.f) {
deci = 0;
}
else if (val >= 10.f) {
deci = 1;
}
QString result = QString::asprintf("%0.*f", deci, val);
return result + unit;
}
2017-02-05 13:35:41 +01:00
void exportTable(const QTableView *view, QTextStream &out)
{
auto model = view->model();
if (model) {
CsvWriter csv(&out);
csv.setSeperator('\t');
csv.setQuote('"');
auto cols = model->columnCount();
auto rows = model->rowCount();
for (auto row = 0; row < rows; ++row) {
2017-02-05 13:35:41 +01:00
for (int col = 0; col < cols; ++col) {
auto idx = model->index(row, col);
auto display_text = idx.data(Qt::DisplayRole).toString();
csv.writeField(display_text);
}
csv.nextRow();
}
out.flush();
}
}
void copySelectionToClipboard(const QTableView *view)
{
//QAbstractItemModel * model = resultModel; //view->model();
QItemSelectionModel * selection = view->selectionModel();
QModelIndexList selectedIndexes = selection->selectedIndexes();
if (selectedIndexes.count() > 0) {
QString clipboard_string;
QTextStream out(&clipboard_string, QIODevice::WriteOnly);
CsvWriter csv(&out);
csv.setSeperator('\t');
csv.setQuote('"');
int previous_row = selectedIndexes[0].row();
// for (int i = 0; i < selectedIndexes.count(); ++i) {
// QModelIndex current = selectedIndexes[i];
for (auto current : selectedIndexes) {
if (current.row() > previous_row) {
csv.nextRow();
previous_row = current.row();
}
QString display_text = current.data(Qt::DisplayRole).toString();
csv.writeField(display_text);
}
out.flush();
QApplication::clipboard()->setText(clipboard_string);
}
}
2017-02-05 08:23:06 +01:00
QString ConvertToMultiLineCString(const QString &in)
{
// We need to atleast escape " and \ and also any multi byte utf8 char
2017-02-05 08:23:06 +01:00
QString out;
out.append('"');
QByteArray ba = in.toUtf8();
for (auto c : ba) {
if (c == '\\') {
out.append("\\\\");
}
else if (c == '"') {
out.append("\\\"");
}
else if (uchar(c) > 127) {
out.append(QString("\\x%1").arg(uchar(c), 2, 16, QChar('0')));
}
else if (c == '\n') {
// at end of line we add a space and a new line in the string then we put in the end quote go to the next line and put the open quote
out.append(" \\n\"\n\"");
}
else {
out.append(c);
}
}
out.append('"');
return out;
}
QString ConvertToMultiLineRawCppString(const QString &in)
{
const QString delim = "__SQL__";
QString out;
out.append("R\"" + delim + "(\n");
out.append(in.trimmed());
out.append("\n)" + delim + "\"");
return out;
}
QString ConvertLangToSqlString(const QString &in)
{
// Assume mostly C++ for now but allow some other things like
// - single quotes (php)
// - concattenation operators . (php) and + (java)
// Allow cpp prefixes L u8 u U
// Parser flow, we start in whitespace state and search for prefix|opening quote
// parse string and process escapes
// if escape is \r strip it if \n go to new line
// until we reach matching end quote
// skip whitespace and + or .
QString output;
enum {
WHITESPACE,
PREFIX,
IN_STRING,
END,
ERROR
} state = WHITESPACE;
int index = 0;
QChar quote = '\0';
while (state != ERROR && state != END && index < in.length()) {
if (state == WHITESPACE) {
// skip all whitespace untill we encounter something else
// we also skip concatenation operators. Note this code is not trying to validate
// for correct syntax so it will quite happily accept many incorrect constructs
// that doesn't matter however as we are just trying to strip everything which is not SQL.
while (index < in.length() && (in[index].isSpace() || in[index] == '+' || in[index] == '.')) ++index;
if (index == in.length()) {
state == END;
break;
}
// Assume quotes can vary
if (in[index] == '\'' || in[index] == '\"') {
quote = in[index];
++index;
state = IN_STRING;
}
else {
state = PREFIX;
}
}
else if (state == PREFIX) {
auto c = in[index];
if (c == 'L' || c == 'U') {
// C++ prefix expect C++ double quote
if (in.length() > index+ 1 && in[index+1] == '"') {
index += 2;
state = IN_STRING;
}
else {
state = ERROR;
break;
}
}
if (c == 'u') {
// C++ prefix expect C++ double quote
if (in.length() > index+ 2 && in[index+1] == '8' && in[index+2] == '"') {
index += 3;
state = IN_STRING;
}
else if (in.length() > index+ 1 && in[index+1] == '"') {
index += 2;
state = IN_STRING;
}
else {
state = ERROR;
break;
}
}
else {
state = ERROR;
break;
}
}
else if (state == IN_STRING) {
// scan contents of string and process any escapes encountered
bool escape = false;
while (state != ERROR && index < in.length()) {
QChar c = in[index];
if (escape) {
if (c == 'a') output += '\x07';
else if (c == 'a') output += '\x07';
else if (c == 'b') output += '\x08';
else if (c == 'f') output += '\x0c';
else if (c == 'n') output += '\n';
else if (c == 'r') ;
else if (c == 'v') ;
else if (c >= '0' && c <= '7') {
// process octal escape
if (in.length() > index + 2) {
char buf[4];
buf[0] = c.toLatin1();
buf[1] = in[++index].toLatin1();
buf[2] = in[++index].toLatin1();
buf[3] = 0;
long int v = strtol(buf, nullptr, 8);
if (v < 0x80) {
output += static_cast<QChar>(static_cast<char>(v));
}
else {
state = ERROR;
break;
}
}
else {
state = ERROR;
break;
}
}
else if (c == 'x') {
// hex byte
if (in.length() > index + 2) {
char buf[3];
buf[0] = in[++index].toLatin1();
buf[1] = in[++index].toLatin1();
buf[2] = 0;
long int v = strtol(buf, nullptr, 16);
output += static_cast<QChar>(static_cast<char>(v));
}
else {
state = ERROR;
break;
}
}
else if (c == 'u') {
// 4 digit hax unicode codepoint
// hex byte
if (in.length() > index + 4) {
char buf[5];
buf[0] = in[++index].toLatin1();
buf[1] = in[++index].toLatin1();
buf[2] = in[++index].toLatin1();
buf[3] = in[++index].toLatin1();
buf[4] = 0;
long int v = strtol(buf, nullptr, 16);
output += static_cast<QChar>(static_cast<ushort>(v));
}
else {
state = ERROR;
break;
}
}
else if (c == 'U') {
// 8 digit hax unicode codepoint
if (in.length() > index + 8) {
char buf[9];
buf[0] = in[++index].toLatin1();
buf[1] = in[++index].toLatin1();
buf[2] = in[++index].toLatin1();
buf[3] = in[++index].toLatin1();
buf[4] = in[++index].toLatin1();
buf[5] = in[++index].toLatin1();
buf[6] = in[++index].toLatin1();
buf[7] = in[++index].toLatin1();
buf[8] = 0;
uint v = static_cast<uint>(strtol(buf, nullptr, 16));
if (QChar::requiresSurrogates(v)) {
output += QChar(QChar::highSurrogate(v));
output += QChar(QChar::lowSurrogate(v));
}
}
else {
state = ERROR;
break;
}
}
else {
output += c;
}
escape = false;
}
else {
if (c == quote) {
state = WHITESPACE;
++index;
break;
}
// Is there any language where string literals do not have to be terminated before the end of the line
// Not considering string literals that explicitly allow for multiline strings as these are often raw strings
// and can be copy pasted normally.
else if (c == '\n') {
state = WHITESPACE;
++index;
break;
}
else if (c == '\\') {
escape = true;
}
else {
output += c;
}
}
++index;
}
}
}
return output;
}