Skip to content

Commit 82f9bdc

Browse files
committed
GCoderDocument: improve load
1 parent f8a414a commit 82f9bdc

File tree

5 files changed

+287
-5
lines changed

5 files changed

+287
-5
lines changed

common.pri

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ contains(MODULES, GCodeShared) {
6363
$$shadowed($${PROJECT_ROOT_PATH}/gcodeshared)
6464
LIBS += -L$$shadowed($${PROJECT_ROOT_PATH}/gcodeshared)
6565
LIBS += -lgcodeshared
66+
# QTextCodec in Qt6
67+
greaterThan(QT_MAJOR_VERSION, 5): QT *= core5compat
6668
}
6769

6870
contains(MODULES, GCodeWorkShop) {

gcodeshared/gcodeshared.pro

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ TARGET = gcodeshared
55
CONFIG += staticlib
66

77
QT *= widgets serialport network
8+
# QTextCodec in Qt6
9+
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
810

911
include(../common.pri)
1012

@@ -38,6 +40,7 @@ HEADERS += include/ui/longjobhelper.h \
3840
include/utils/medium.h \
3941
include/utils/configpage.h \
4042
include/utils/configdialog.h \
43+
include/utils/gcode-converter.h \
4144
include/utils/guessfilename.h \
4245
include/utils/splitfile.h \
4346
utils/filepatterns.h
@@ -46,6 +49,7 @@ SOURCES += ui/longjobhelper.cpp \
4649
utils/medium.cpp \
4750
utils/configpage.cpp \
4851
utils/configdialog.cpp \
52+
utils/gcode-converter.cpp \
4953
utils/guessfilename.cpp \
5054
utils/splitfile.cpp
5155

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (C) 2025 Nick Egorrov, nicegorov@yandex.ru
3+
*
4+
* This file is part of GCodeWorkShop.
5+
*
6+
* GCodeWorkShop is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#ifndef UTILS_GCODE_CONVERTER_H
21+
#define UTILS_GCODE_CONVERTER_H
22+
23+
#include <QByteArray> // for QByteArray
24+
25+
class QSettings;
26+
class QString;
27+
28+
29+
namespace GCode {
30+
31+
struct Converter {
32+
Converter();
33+
34+
QString fromRawData(const QByteArray& data) const;
35+
QByteArray toRawData(const QString& text) const;
36+
37+
struct Options {
38+
QByteArray codecName = QByteArray{};
39+
// When loading files, discard "extra" empty lines.
40+
bool dropEmptyLine = true;
41+
// When loading files, discard the upper 128 code points commonly used for national alphabets.
42+
bool dropExtented = false;
43+
// When loading files, discard control characters (0x00-0x1f) other than '\n' and '\r'.
44+
bool dropControll = true;
45+
46+
void load(QSettings* settings);
47+
void save(QSettings* settings);
48+
};
49+
50+
Options options;
51+
52+
static Options defaultOptions();
53+
static void setDefaultOptions(const Options& options);
54+
};
55+
56+
} // namespace GCode
57+
58+
#endif // UTILS_GCODE_CONVERTER_H
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
/*
2+
* Copyright (C) 2025 Nick Egorrov, nicegorov@yandex.ru
3+
*
4+
* This file is part of GCodeWorkShop.
5+
*
6+
* GCodeWorkShop is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include <vector> // for vector
21+
22+
#include <QByteArray> // for QByteArray
23+
#include <QSettings> // for QSettings
24+
#include <QString> // for QString
25+
#include <QVariant> // for QVariant
26+
#include <QTextCodec> // for QTextCodec
27+
28+
#include <utils/gcode-converter.h> // IWYU pragma: associated
29+
30+
31+
namespace GCode {
32+
namespace Private {
33+
34+
// see https://en.wikipedia.org/wiki/Euclidean_algorithm
35+
int greatest_common_divisor(int a, int b)
36+
{
37+
while (a != b) {
38+
if (a > b) {
39+
a -= b;
40+
} else {
41+
b -= a;
42+
}
43+
}
44+
45+
return a;
46+
}
47+
48+
int greatest_common_divisor(const std::vector<int>& values)
49+
{
50+
if (values.empty()) {
51+
return 1;
52+
}
53+
54+
int result = values.front();
55+
56+
for (int a : values) {
57+
result = greatest_common_divisor(a, result);
58+
}
59+
60+
return result;
61+
}
62+
63+
void add_unique(std::vector<int>& values, int v)
64+
{
65+
for (int i : values) {
66+
if (i == v) {
67+
return;
68+
}
69+
}
70+
71+
values.push_back(v);
72+
}
73+
74+
QByteArray filterData(const QByteArray& data,
75+
bool dropEmptyLine,
76+
bool dropExtented,
77+
bool dropControll)
78+
{
79+
int newLineCount = 0;
80+
int mergedLine = 1;
81+
82+
if (dropEmptyLine) {
83+
std::vector<int> values;
84+
newLineCount = 0;
85+
86+
for (char c : data) {
87+
if (c == '\n' || c == '\r') {
88+
++newLineCount;
89+
} else {
90+
if (newLineCount != 0) {
91+
add_unique(values, newLineCount);
92+
newLineCount = 0;
93+
}
94+
}
95+
}
96+
97+
mergedLine = greatest_common_divisor(values);
98+
}
99+
100+
QByteArray handled;
101+
newLineCount = 0;
102+
103+
for (char c : data) {
104+
if (c == '\n' || c == '\r') {
105+
if (++newLineCount > mergedLine) {
106+
newLineCount = 1;
107+
}
108+
109+
if (newLineCount > 1) {
110+
continue;
111+
}
112+
} else if (c < 0) {
113+
newLineCount = 0;
114+
115+
if (dropExtented) {
116+
continue;
117+
}
118+
} else if (c < 0x20) {
119+
newLineCount = 0;
120+
121+
if (dropControll) {
122+
continue;
123+
}
124+
} else {
125+
newLineCount = 0;
126+
}
127+
128+
handled.push_back(c);
129+
}
130+
131+
return handled;
132+
}
133+
134+
QString fromRawData(const QByteArray& data,
135+
bool dropEmptyLine,
136+
bool dropExtented,
137+
bool dropControll,
138+
const QByteArray& codec)
139+
{
140+
const QByteArray& handled = filterData(data,
141+
dropEmptyLine,
142+
dropExtented,
143+
dropControll);
144+
QTextCodec* textCodec = QTextCodec::codecForName(codec);
145+
146+
if (textCodec != nullptr) {
147+
return textCodec->toUnicode(handled);
148+
} else {
149+
return QString::fromLocal8Bit(handled);
150+
}
151+
}
152+
153+
QByteArray toRawData(const QString& text, const QByteArray& codec)
154+
{
155+
QTextCodec* textCodec = QTextCodec::codecForName(codec);
156+
157+
if (textCodec != nullptr) {
158+
return textCodec->fromUnicode(text);
159+
} else {
160+
return text.toLocal8Bit();
161+
}
162+
}
163+
164+
Converter::Options s_defaultOptions{};
165+
166+
} // namespase Private
167+
} // namespase GCode
168+
169+
170+
#define CFG_KEY_CODEC_NAME "CodecName"
171+
#define CFG_KEY_DROP_CONTROLL "DropControll"
172+
#define CFG_KEY_DROP_EMPTY_LINE "DropEmptyLine"
173+
#define CFG_KEY_DROP_EXTENDED "DropExtented"
174+
175+
void GCode::Converter::Options::load(QSettings* settings)
176+
{
177+
codecName = settings->value(CFG_KEY_CODEC_NAME, codecName).toByteArray();
178+
dropControll = settings->value(CFG_KEY_DROP_CONTROLL, dropControll).toBool();
179+
dropEmptyLine = settings->value(CFG_KEY_DROP_EMPTY_LINE, dropEmptyLine).toBool();
180+
dropExtented = settings->value(CFG_KEY_DROP_EXTENDED, dropExtented).toBool();
181+
}
182+
183+
void GCode::Converter::Options::save(QSettings* settings)
184+
{
185+
settings->setValue(CFG_KEY_CODEC_NAME, codecName);
186+
settings->setValue(CFG_KEY_DROP_CONTROLL, dropControll);
187+
settings->setValue(CFG_KEY_DROP_EMPTY_LINE, dropEmptyLine);
188+
settings->setValue(CFG_KEY_DROP_EXTENDED, dropExtented);
189+
}
190+
191+
GCode::Converter::Options GCode::Converter::defaultOptions()
192+
{
193+
return Private::s_defaultOptions;
194+
}
195+
196+
void GCode::Converter::setDefaultOptions(const Options& options)
197+
{
198+
Private::s_defaultOptions = options;
199+
}
200+
201+
GCode::Converter::Converter() :
202+
options{defaultOptions()}
203+
{
204+
}
205+
206+
QString GCode::Converter::fromRawData(const QByteArray& data) const
207+
{
208+
return Private::fromRawData(data,
209+
options.dropEmptyLine,
210+
options.dropExtented,
211+
options.dropControll,
212+
options.codecName);
213+
}
214+
215+
QByteArray GCode::Converter::toRawData(const QString& text) const
216+
{
217+
return Private::toRawData(text, options.codecName);
218+
}

gcodeworkshop/src/gcoderdocument.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class QMenu;
5858
#include <documentstyle.h> // for DocumentStyle, DocumentStyle::Ptr
5959
#include <documentwidgetproperties.h> // for DocumentWidgetProperties, DocumentWidgetProperties::Ptr
6060
#include <gcoderdocument.h> // IWYU pragma: associated
61+
#include <utils/gcode-converter.h> // for Converter
6162
#include <utils/guessfilename.h> // for guessFileNameByComments, guessFileNameByProgNum, FileExt
6263
#include <utils/medium.h> // for Medium
6364
#include <utils/removezeros.h> // for removeZeros
@@ -72,7 +73,6 @@ class QMenu;
7273
#include "highlightmode.h" // for MODE_LINUXCNC, MODE_AUTO, MODE_SINUMERIK_840, MODE_FANUC, MODE_HEIDENHAIN
7374
#include "inlinecalc.h"
7475

75-
7676
GCoderDocument::GCoderDocument() : Document(nullptr)
7777
{
7878
m_highlighter = nullptr;
@@ -86,7 +86,6 @@ GCoderDocument::GCoderDocument() : Document(nullptr)
8686
m_inLineCalc = new InLineCalc(m_textEdit);
8787
connect(m_inLineCalc, SIGNAL(complete(const QString&)), this, SLOT(inLineCalcComplete(const QString&)));
8888

89-
9089
m_textEdit->setWindowIcon(QIcon(":/images/ncfile.png"));
9190
m_textEdit->setContextMenuPolicy(Qt::CustomContextMenu);
9291
connect(m_textEdit, SIGNAL(customContextMenuRequested(const QPoint&)), this,
@@ -207,12 +206,14 @@ bool GCoderDocument::save()
207206

208207
QByteArray GCoderDocument::rawData() const
209208
{
210-
return text(true).toLocal8Bit();
209+
GCode::Converter conv{};
210+
return conv.toRawData(text(true));
211211
}
212212

213213
void GCoderDocument::setRawData(const QByteArray& data)
214214
{
215-
setText(QString::fromLocal8Bit(data));
215+
GCode::Converter conv{};
216+
setText(conv.fromRawData(data));
216217
}
217218

218219
QMenu* GCoderDocument::createStandardContextMenu(const QPoint& pos)
@@ -1363,7 +1364,6 @@ void GCoderDocument::highlightCurrentLine()
13631364
}
13641365
}
13651366

1366-
13671367
if (m_highlightMode == MODE_SINUMERIK_840) {
13681368
cursor = textCursor();
13691369

0 commit comments

Comments
 (0)