Skip to content

Commit f820622

Browse files
committed
Merge remote-tracking branch 'origin/dev'
2 parents 3b25123 + 1da09a6 commit f820622

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2820
-1061
lines changed

README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# OpenModScan
22
OpenModScan is a free and open-source Modbus Master (Client) utility supporting both Modbus-TCP and Modbus-RTU protocols.
33

4-
<img width="1292" height="759" alt="image" src="https://github.com/user-attachments/assets/137433d4-d2fd-484a-bb07-c0e9457f66dc" />
4+
<img width="1292" height="759" alt="image" src="https://github.com/user-attachments/assets/fc839046-f9de-484a-ab8c-1b553635cba8" />
55

6-
<img width="1292" height="759" alt="image" src="https://github.com/user-attachments/assets/3e0ea476-ac6c-4c46-a686-544dddd87825" />
76

7+
<img width="1292" height="760" alt="image" src="https://github.com/user-attachments/assets/f4e6599c-480d-4b26-b0c3-49e5dc8d1f17" />
88

99

1010
## Features
@@ -28,25 +28,27 @@ Registers
2828

2929
## Modbus Logging
3030

31-
<img width="1292" height="759" alt="image" src="https://github.com/user-attachments/assets/de6c8836-8011-43ee-b691-f9a91c6d0679" />
31+
<img width="1292" height="759" alt="image" src="https://github.com/user-attachments/assets/b12b019f-6df6-4c85-b7f3-85e347576c83" />
32+
3233

3334

3435
## Extended Featues
3536
- Modbus Address Scan
3637

37-
![image](https://github.com/user-attachments/assets/798ed74a-c5fc-413f-a173-e223c9c7d3f3)
38+
![image](https://github.com/user-attachments/assets/798ed74a-c5fc-413f-a173-e223c9c7d3f3)
3839

3940
- Modbus Scanner (supports both Modbus RTU and Modbus TCP scanning)
4041

4142
![image](https://github.com/user-attachments/assets/17d5f43d-c341-455d-a9b8-67db50a35699)
4243

4344
- Modbus Message Parser
4445

45-
![image](https://github.com/sanny32/OpenModScan/assets/13627951/4f05f38e-d739-4c49-8bc3-f12e7b74d8ab)
46+
<img width="674" height="463" alt="image" src="https://github.com/user-attachments/assets/9d7a53ef-dda2-4d7f-bfb0-c3337e2ca40b" />
4647

4748
- Modbus User Message
48-
49-
![image](https://github.com/sanny32/OpenModScan/assets/13627951/1aba6329-873c-4ff2-8db8-939245a50722)
49+
50+
<img width="529" height="722" alt="image" src="https://github.com/user-attachments/assets/1aa3aadb-1462-4989-afa9-0ad131d5faa7" />
51+
5052

5153
## Building
5254
Building is available via cmake (with installed Qt version 5.15 and above) or Qt Creator. Supports both OS Microsoft Windows and Linux.

omodscan/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
cmake_minimum_required(VERSION 3.25)
22

33
project(omodscan
4-
VERSION 1.10.0
4+
VERSION 1.11.0
55
DESCRIPTION "An Open Source Modbus Master (Client) Utility"
66
LANGUAGES CXX)
77

@@ -151,6 +151,7 @@ set(HEADERS
151151
dialogs/dialogwriteholdingregisterbits.h
152152
displaydefinition.h
153153
enums.h
154+
fontutils.h
154155
formatutils.h
155156
formmodsca.h
156157
htmldelegate.h

omodscan/controls/bytelisttextedit.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <QRegularExpressionValidator>
22
#include <QMimeData>
3+
#include "fontutils.h"
34
#include "formatutils.h"
45
#include "bytelisttextedit.h"
56

@@ -31,6 +32,7 @@ ByteListTextEdit::ByteListTextEdit(QWidget* parent)
3132
,_validator(nullptr)
3233
{
3334
setInputMode(DecMode);
35+
setFont(defaultMonospaceFont());
3436
connect(this, &QPlainTextEdit::textChanged, this, &ByteListTextEdit::on_textChanged);
3537
}
3638

@@ -45,6 +47,7 @@ ByteListTextEdit::ByteListTextEdit(InputMode mode, QWidget *parent)
4547
,_validator(nullptr)
4648
{
4749
setInputMode(mode);
50+
setFont(defaultMonospaceFont());
4851
connect(this, &QPlainTextEdit::textChanged, this, &ByteListTextEdit::on_textChanged);
4952
}
5053

omodscan/controls/functioncodecombobox.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,14 @@ QModbusPdu::FunctionCode FunctionCodeComboBox::currentFunctionCode() const
3535
///
3636
void FunctionCodeComboBox::setCurrentFunctionCode(QModbusPdu::FunctionCode funcCode)
3737
{
38-
_currentFunc = funcCode;
38+
if(funcCode != _currentFunc)
39+
{
40+
_currentFunc = funcCode;
3941

40-
const auto idx = findData(funcCode);
41-
if(idx != -1) setCurrentIndex(idx);
42-
else setCurrentText(formatFuncCode(funcCode));
42+
const auto idx = findData(funcCode);
43+
if(idx != -1) setCurrentIndex(idx);
44+
else setCurrentText(formatFuncCode(funcCode));
45+
}
4346
}
4447

4548
///
@@ -162,10 +165,11 @@ void FunctionCodeComboBox::on_currentIndexChanged(int index)
162165
///
163166
void FunctionCodeComboBox::on_currentTextChanged(const QString& text)
164167
{
168+
QModbusPdu::FunctionCode funcCode;
165169
const auto idx = findData(text, Qt::DisplayRole);
166170
if(idx != -1)
167171
{
168-
_currentFunc = itemData(idx).value<QModbusPdu::FunctionCode>();
172+
funcCode = itemData(idx).value<QModbusPdu::FunctionCode>();
169173
}
170174
else
171175
{
@@ -183,7 +187,12 @@ void FunctionCodeComboBox::on_currentTextChanged(const QString& text)
183187
break;
184188
}
185189

186-
_currentFunc = ok ? (QModbusPdu::FunctionCode)func : QModbusPdu::Invalid;
190+
funcCode = ok ? (QModbusPdu::FunctionCode)func : QModbusPdu::Invalid;
191+
}
192+
193+
if(funcCode != _currentFunc) {
194+
_currentFunc = funcCode;
195+
emit functionCodeChanged(_currentFunc);
187196
}
188197
}
189198

omodscan/controls/modbuslogwidget.cpp

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1+
#include <QMenu>
12
#include <QEvent>
3+
#include <QStyle>
4+
#include <QClipboard>
5+
#include <QTextDocument>
6+
#include <QApplication>
7+
#include "fontutils.h"
28
#include "htmldelegate.h"
39
#include "modbuslogwidget.h"
410

@@ -45,9 +51,15 @@ QVariant ModbusLogModel::data(const QModelIndex& index, int role) const
4551
switch(role)
4652
{
4753
case Qt::DisplayRole:
48-
return QString("<b>%1</b> %2 %3").arg(item->timestamp().toString(Qt::ISODateWithMs),
49-
(item->isRequest()? "&larr;" : "&rarr;"),
50-
item->toString(_parentWidget->dataDisplayMode()));
54+
return QString(R"(
55+
<span style="color:#444444">%1</span>
56+
<b style="color:%2">%3</b>
57+
<span>%4</span>
58+
)")
59+
.arg(item->timestamp().toString(Qt::ISODateWithMs),
60+
item->isRequest() ? "#0066cc" : "#009933",
61+
item->isRequest() ? "[Tx] ←" : "[Rx] →",
62+
item->toString(_parentWidget->dataDisplayMode()));
5163

5264
case Qt::UserRole:
5365
return QVariant::fromValue(item);
@@ -76,7 +88,9 @@ void ModbusLogModel::append(QSharedPointer<const ModbusMessage> data)
7688

7789
while(rowCount() >= _rowLimit)
7890
{
91+
beginRemoveRows(QModelIndex(), 0, 0);
7992
_items.removeFirst();
93+
endRemoveRows();
8094
}
8195

8296
beginInsertRows(QModelIndex(), rowCount(), rowCount());
@@ -118,13 +132,51 @@ ModbusLogWidget::ModbusLogWidget(QWidget* parent)
118132
: QListView(parent)
119133
, _autoscroll(false)
120134
{
135+
setFocusPolicy(Qt::StrongFocus);
136+
setFont(defaultMonospaceFont());
137+
setContextMenuPolicy(Qt::CustomContextMenu);
121138
setItemDelegate(new HtmlDelegate(this));
122139
setModel(new ModbusLogModel(this));
123140

141+
QIcon copyIcon = QIcon::fromTheme("edit-copy");
142+
if (copyIcon.isNull()) {
143+
copyIcon = style()->standardIcon(QStyle::SP_FileIcon);
144+
}
145+
146+
_copyAct = new QAction(copyIcon, tr("Copy Text"), this);
147+
_copyAct->setShortcut(QKeySequence::Copy);
148+
_copyAct->setShortcutContext(Qt::WidgetShortcut);
149+
_copyAct->setShortcutVisibleInContextMenu(true);
150+
addAction(_copyAct);
151+
152+
connect(_copyAct, &QAction::triggered, this, [this]() {
153+
QModelIndex index = currentIndex();
154+
if (index.isValid()) {
155+
QTextDocument doc;
156+
doc.setHtml(index.data(Qt::DisplayRole).toString());
157+
QApplication::clipboard()->setText(doc.toPlainText());
158+
}
159+
});
160+
161+
_copyBytesAct = new QAction(tr("Copy Bytes"), this);
162+
_copyBytesAct->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_C));
163+
_copyBytesAct->setShortcutContext(Qt::WidgetShortcut);
164+
_copyBytesAct->setShortcutVisibleInContextMenu(true);
165+
addAction(_copyBytesAct);
166+
167+
connect(_copyBytesAct, &QAction::triggered, this, [this]() {
168+
QModelIndex index = currentIndex();
169+
if (index.isValid()) {
170+
auto msg = index.data(Qt::UserRole).value<QSharedPointer<const ModbusMessage>>();
171+
if (msg) QApplication::clipboard()->setText(msg->toString(dataDisplayMode()));
172+
}
173+
});
174+
175+
connect(this, &QWidget::customContextMenuRequested,
176+
this, &ModbusLogWidget::on_customContextMenuRequested);
124177
connect(model(), &ModbusLogModel::rowsInserted,
125178
this, [&]{
126179
if(_autoscroll) scrollToBottom();
127-
setCurrentIndex(QModelIndex());
128180
});
129181
}
130182

@@ -137,6 +189,8 @@ void ModbusLogWidget::changeEvent(QEvent* event)
137189
if (event->type() == QEvent::LanguageChange)
138190
{
139191
update();
192+
_copyAct->setText(tr("Copy Text"));
193+
_copyBytesAct->setText(tr("Copy Bytes"));
140194
}
141195
QListView::changeEvent(event);
142196
}
@@ -267,3 +321,36 @@ void ModbusLogWidget::setAutoscroll(bool on)
267321
{
268322
_autoscroll = on;
269323
}
324+
325+
///
326+
/// \brief ModbusLogWidget::backgroundColor
327+
/// \return
328+
///
329+
QColor ModbusLogWidget::backgroundColor() const
330+
{
331+
return palette().color(QPalette::Base);
332+
}
333+
334+
///
335+
/// \brief ModbusLogWidget::setBackGroundColor
336+
/// \param clr
337+
///
338+
void ModbusLogWidget::setBackGroundColor(const QColor& clr)
339+
{
340+
auto pal = palette();
341+
pal.setColor(QPalette::Base, clr);
342+
pal.setColor(QPalette::Window, clr);
343+
setPalette(pal);
344+
}
345+
346+
///
347+
/// \brief ModbusLogWidget::on_customContextMenuRequested
348+
/// \param pos
349+
///
350+
void ModbusLogWidget::on_customContextMenuRequested(const QPoint &pos)
351+
{
352+
QMenu menu(this);
353+
menu.addAction(_copyAct);
354+
menu.addAction(_copyBytesAct);
355+
menu.exec(viewport()->mapToGlobal(pos));
356+
}

omodscan/controls/modbuslogwidget.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,19 @@ class ModbusLogWidget : public QListView
6565
bool autoscroll() const;
6666
void setAutoscroll(bool on);
6767

68+
QColor backgroundColor() const;
69+
void setBackGroundColor(const QColor& clr);
70+
6871
protected:
6972
void changeEvent(QEvent* event) override;
7073

74+
private slots:
75+
void on_customContextMenuRequested(const QPoint &pos);
76+
7177
private:
7278
bool _autoscroll;
79+
QAction* _copyAct;
80+
QAction* _copyBytesAct;
7381
DataDisplayMode _dataDisplayMode;
7482
};
7583

0 commit comments

Comments
 (0)