Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ed7bb8bd69 | ||
|
d827e43a11 |
76
.github/CODE_OF_CONDUCT.md
vendored
@ -1,76 +0,0 @@
|
|||||||
# Contributor Covenant Code of Conduct
|
|
||||||
|
|
||||||
## Our Pledge
|
|
||||||
|
|
||||||
In the interest of fostering an open and welcoming environment, we as
|
|
||||||
contributors and maintainers pledge to making participation in our project and
|
|
||||||
our community a harassment-free experience for everyone, regardless of age, body
|
|
||||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
|
||||||
level of experience, education, socio-economic status, nationality, personal
|
|
||||||
appearance, race, religion, or sexual identity and orientation.
|
|
||||||
|
|
||||||
## Our Standards
|
|
||||||
|
|
||||||
Examples of behavior that contributes to creating a positive environment
|
|
||||||
include:
|
|
||||||
|
|
||||||
* Using welcoming and inclusive language
|
|
||||||
* Being respectful of differing viewpoints and experiences
|
|
||||||
* Gracefully accepting constructive criticism
|
|
||||||
* Focusing on what is best for the community
|
|
||||||
* Showing empathy towards other community members
|
|
||||||
|
|
||||||
Examples of unacceptable behavior by participants include:
|
|
||||||
|
|
||||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
||||||
advances
|
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
||||||
* Public or private harassment
|
|
||||||
* Publishing others' private information, such as a physical or electronic
|
|
||||||
address, without explicit permission
|
|
||||||
* Other conduct which could reasonably be considered inappropriate in a
|
|
||||||
professional setting
|
|
||||||
|
|
||||||
## Our Responsibilities
|
|
||||||
|
|
||||||
Project maintainers are responsible for clarifying the standards of acceptable
|
|
||||||
behavior and are expected to take appropriate and fair corrective action in
|
|
||||||
response to any instances of unacceptable behavior.
|
|
||||||
|
|
||||||
Project maintainers have the right and responsibility to remove, edit, or
|
|
||||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
||||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
||||||
permanently any contributor for other behaviors that they deem inappropriate,
|
|
||||||
threatening, offensive, or harmful.
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
|
|
||||||
This Code of Conduct applies both within project spaces and in public spaces
|
|
||||||
when an individual is representing the project or its community. Examples of
|
|
||||||
representing a project or community include using an official project e-mail
|
|
||||||
address, posting via an official social media account, or acting as an appointed
|
|
||||||
representative at an online or offline event. Representation of a project may be
|
|
||||||
further defined and clarified by project maintainers.
|
|
||||||
|
|
||||||
## Enforcement
|
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
||||||
reported by contacting the project team at support@ostinato.org. All
|
|
||||||
complaints will be reviewed and investigated and will result in a response that
|
|
||||||
is deemed necessary and appropriate to the circumstances. The project team is
|
|
||||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
||||||
Further details of specific enforcement policies may be posted separately.
|
|
||||||
|
|
||||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
||||||
faith may face temporary or permanent repercussions as determined by other
|
|
||||||
members of the project's leadership.
|
|
||||||
|
|
||||||
## Attribution
|
|
||||||
|
|
||||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
||||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
|
||||||
|
|
||||||
[homepage]: https://www.contributor-covenant.org
|
|
||||||
|
|
||||||
For answers to common questions about this code of conduct, see
|
|
||||||
https://www.contributor-covenant.org/faq
|
|
16
.github/CONTRIBUTING.md
vendored
@ -1,16 +0,0 @@
|
|||||||
# Contributing Guidelines
|
|
||||||
Please use a Pull Request to contribute code. Very small fixes (< 10 lines) can provide the diff via an issue instead of a PR.
|
|
||||||
|
|
||||||
In either case, you agree to the below legal terms and you indicate your acceptance by explicitly adding a comment to the issue or PR stating -
|
|
||||||
|
|
||||||
```
|
|
||||||
I have read the contributing guidelines (CONTRIBUTING.md) and I hereby assign the copyrights of these
|
|
||||||
changes to [Srivats P](https://github.com/pstavirs).
|
|
||||||
```
|
|
||||||
|
|
||||||
## Legal
|
|
||||||
By submitting a Pull Request, you disavow any rights or claims to any changes submitted to the Ostinato project and assign the copyright of those changes to [Srivats P](https://github.com/pstavirs).
|
|
||||||
|
|
||||||
If you cannot or do not want to reassign those rights (your employment contract for your employer may not allow this), you should not submit a PR. Open an issue and someone else can do the work.
|
|
||||||
|
|
||||||
This is a legal way of saying "_If you submit a PR to us, that code becomes ours_". 99.9% of the time that's what you intend anyways; we hope it doesn't scare you away from contributing.
|
|
1
.github/FUNDING.yml
vendored
@ -1 +0,0 @@
|
|||||||
github: pstavirs
|
|
14
.travis.yml
@ -1,5 +1,4 @@
|
|||||||
language: cpp
|
language: cpp
|
||||||
osx_image: xcode11.3
|
|
||||||
|
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
@ -14,14 +13,17 @@ matrix:
|
|||||||
- os: osx
|
- os: osx
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
|
|
||||||
before_script:
|
before_install:
|
||||||
- "if [ $TRAVIS_OS_NAME = 'osx' ]; then \
|
- "if [ $TRAVIS_OS_NAME = 'osx' ]; then \
|
||||||
|
brew update && \
|
||||||
|
brew install qt5 && \
|
||||||
|
brew link qt5 --force && \
|
||||||
|
brew install protobuf && \
|
||||||
ls -lR /usr/local/include/google/protobuf; \
|
ls -lR /usr/local/include/google/protobuf; \
|
||||||
which clang++; \
|
which clang++; \
|
||||||
clang++ -E -x c++ - -v < /dev/null; \
|
clang++ -E -x c++ - -v < /dev/null; \
|
||||||
export CPLUS_INCLUDE_PATH=/usr/local/include; \
|
export CPLUS_INCLUDE_PATH=/usr/local/include; \
|
||||||
export LIBRARY_PATH=/usr/local/lib; \
|
export LIBRARY_PATH=/usr/local/lib; \
|
||||||
export PATH=/usr/local/opt/qt/bin:$PATH; \
|
|
||||||
fi"
|
fi"
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
@ -29,16 +31,12 @@ addons:
|
|||||||
packages:
|
packages:
|
||||||
- qtbase5-dev
|
- qtbase5-dev
|
||||||
- qtscript5-dev
|
- qtscript5-dev
|
||||||
- libqt5svg5-dev
|
|
||||||
- libpcap-dev
|
- libpcap-dev
|
||||||
- libprotobuf-dev
|
- libprotobuf-dev
|
||||||
- protobuf-compiler
|
- protobuf-compiler
|
||||||
- libnl-3-dev
|
- libnl-3-dev
|
||||||
- libnl-route-3-dev
|
- libnl-route-3-dev
|
||||||
homebrew:
|
|
||||||
packages:
|
|
||||||
- qt5
|
|
||||||
- protobuf
|
|
||||||
script:
|
script:
|
||||||
- QT_SELECT=qt5 qmake -config debug
|
- QT_SELECT=qt5 qmake -config debug
|
||||||
- make
|
- make
|
||||||
|
18
README.md
@ -1,23 +1,9 @@
|
|||||||
# Ostinato
|
# Ostinato
|
||||||
|
|
||||||
[](https://app.travis-ci.com/pstavirs/ostinato)
|
[](https://travis-ci.org/pstavirs/ostinato)
|
||||||
|
|
||||||
This is the code repository for the Ostinato network packet crafter and traffic generator
|
This is the code repository for the Ostinato network packet crafter and traffic generator
|
||||||
|
|
||||||
Visit https://ostinato.org for demo video and details
|
Visit https://ostinato.org for demo video and details
|
||||||
|
|
||||||
Source License: GPLv3+ (see [COPYING](https://raw.githubusercontent.com/pstavirs/ostinato/master/COPYING))
|
License: GPLv3+ (see [COPYING](https://raw.githubusercontent.com/pstavirs/ostinato/master/COPYING))
|
||||||
|
|
||||||
## Author's note
|
|
||||||
I have been developing and maintaining Ostinato [single-handedly](https://github.com/pstavirs/ostinato/graphs/contributors) for more than 12 years. And during this time I have grudgingly come around to the view that open source cannot survive and thrive without money. Mixing money with open-source is messy, but I don't see a way forward unless we as a community become open to the idea of talking about it and changing our culture so that money is no longer a bad word.
|
|
||||||
|
|
||||||
I sell binary licenses on [ostinato.org](https://ostinato.org/downloads) to try and cover the costs of development. Please consider buying those - they are priced low enough that you can afford it or you could just as easily expense them to your organisation.
|
|
||||||
|
|
||||||
If you build Ostinato from source and find it useful, please sponsor to keep the lights on and sustain the project.
|
|
||||||
|
|
||||||
[](https://github.com/sponsors/pstavirs)
|
|
||||||
|
|
||||||
Read the Ostinato [origin story](https://ostinato.org/about).
|
|
||||||
|
|
||||||
Srivats P<br/>
|
|
||||||
Author, Ostinato
|
|
||||||
|
@ -94,7 +94,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="CopyrightLabel" >
|
<widget class="QLabel" name="CopyrightLabel" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>Copyright (c) 2007-2023 Srivats P.</string>
|
<string>Copyright (c) 2007-2018 Srivats P.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment" >
|
<property name="alignment" >
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
|
@ -136,11 +136,6 @@ QVariant ArpStatusModel::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::DropActions ArpStatusModel::supportedDropActions() const
|
|
||||||
{
|
|
||||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArpStatusModel::setDeviceIndex(Port *port, int deviceIndex)
|
void ArpStatusModel::setDeviceIndex(Port *port, int deviceIndex)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
@ -40,8 +40,6 @@ public:
|
|||||||
int role = Qt::DisplayRole) const;
|
int role = Qt::DisplayRole) const;
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
|
||||||
Qt::DropActions supportedDropActions() const;
|
|
||||||
|
|
||||||
void setDeviceIndex(Port *port, int deviceIndex);
|
void setDeviceIndex(Port *port, int deviceIndex);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -1,221 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2020 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "clipboardhelper.h"
|
|
||||||
|
|
||||||
#include "xtableview.h"
|
|
||||||
|
|
||||||
#include <QAction>
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QClipboard>
|
|
||||||
#include <QIcon>
|
|
||||||
#include <QItemSelection>
|
|
||||||
|
|
||||||
#if 0 // change 0 to 1 for debug
|
|
||||||
#define xDebug(...) qDebug(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define xDebug(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ClipboardHelper::ClipboardHelper(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
actionCut_ = new QAction(tr("&Cut"), this);
|
|
||||||
actionCut_->setObjectName(QStringLiteral("actionCut"));
|
|
||||||
actionCut_->setIcon(QIcon(QString::fromUtf8(":/icons/cut.png")));
|
|
||||||
|
|
||||||
actionCopy_ = new QAction(tr("Cop&y"), this);
|
|
||||||
actionCopy_->setObjectName(QStringLiteral("actionCopy"));
|
|
||||||
actionCopy_->setIcon(QIcon(QString::fromUtf8(":/icons/copy.png")));
|
|
||||||
|
|
||||||
actionPaste_ = new QAction(tr("&Paste"), this);
|
|
||||||
actionPaste_->setObjectName(QStringLiteral("actionPaste"));
|
|
||||||
actionPaste_->setIcon(QIcon(QString::fromUtf8(":/icons/paste.png")));
|
|
||||||
|
|
||||||
connect(actionCut_, SIGNAL(triggered()), SLOT(actionTriggered()));
|
|
||||||
connect(actionCopy_, SIGNAL(triggered()), SLOT(actionTriggered()));
|
|
||||||
connect(actionPaste_, SIGNAL(triggered()), SLOT(actionTriggered()));
|
|
||||||
|
|
||||||
// XXX: failsafe in case updation of cut/copy/status causes issues
|
|
||||||
// Temporary for 1 release - will be removed after that
|
|
||||||
if (qEnvironmentVariableIsSet("X-OSTINATO-CCP-STATUS")) {
|
|
||||||
qWarning("FAILSAFE: Cut-Copy-Paste action status will not be updated");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)),
|
|
||||||
SLOT(updateCutCopyStatus(QWidget*, QWidget*)));
|
|
||||||
|
|
||||||
connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)),
|
|
||||||
SLOT(updatePasteStatus()));
|
|
||||||
connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
|
|
||||||
SLOT(updatePasteStatus()));
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QAction*> ClipboardHelper::actions()
|
|
||||||
{
|
|
||||||
QList<QAction*> actionList({actionCut_, actionCopy_, actionPaste_});
|
|
||||||
return actionList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClipboardHelper::actionTriggered()
|
|
||||||
{
|
|
||||||
QWidget *focusWidget = qApp->focusWidget();
|
|
||||||
|
|
||||||
if (!focusWidget)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// single slot to handle cut/copy/paste - find which action was triggered
|
|
||||||
QString action = sender()->objectName()
|
|
||||||
.remove("action").append("()").toLower();
|
|
||||||
if (focusWidget->metaObject()->indexOfSlot(qPrintable(action)) < 0) {
|
|
||||||
xDebug("%s slot not found for object %s:%s ",
|
|
||||||
qPrintable(action),
|
|
||||||
qPrintable(focusWidget->objectName()),
|
|
||||||
focusWidget->metaObject()->className());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
action.remove("()");
|
|
||||||
QMetaObject::invokeMethod(focusWidget, qPrintable(action),
|
|
||||||
Qt::DirectConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClipboardHelper::updateCutCopyStatus(QWidget *old, QWidget *now)
|
|
||||||
{
|
|
||||||
xDebug("In %s", __FUNCTION__);
|
|
||||||
|
|
||||||
const XTableView *view = dynamic_cast<XTableView*>(old);
|
|
||||||
if (view) {
|
|
||||||
disconnect(view->selectionModel(),
|
|
||||||
SIGNAL(selectionChanged(const QItemSelection&,
|
|
||||||
const QItemSelection&)),
|
|
||||||
this,
|
|
||||||
SLOT(focusWidgetSelectionChanged(const QItemSelection&,
|
|
||||||
const QItemSelection&)));
|
|
||||||
disconnect(view->model(), SIGNAL(modelReset()),
|
|
||||||
this, SLOT(focusWidgetModelReset()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!now) {
|
|
||||||
xDebug("No focus widget to copy from");
|
|
||||||
actionCut_->setEnabled(false);
|
|
||||||
actionCopy_->setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QMetaObject *meta = now->metaObject();
|
|
||||||
if (meta->indexOfSlot("copy()") < 0) {
|
|
||||||
xDebug("Focus Widget (%s) doesn't have a copy slot",
|
|
||||||
qPrintable(now->objectName()));
|
|
||||||
actionCut_->setEnabled(false);
|
|
||||||
actionCopy_->setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
view = dynamic_cast<XTableView*>(now);
|
|
||||||
if (view) {
|
|
||||||
connect(view->selectionModel(),
|
|
||||||
SIGNAL(selectionChanged(const QItemSelection&,
|
|
||||||
const QItemSelection&)),
|
|
||||||
SLOT(focusWidgetSelectionChanged(const QItemSelection&,
|
|
||||||
const QItemSelection&)));
|
|
||||||
connect(view->model(), SIGNAL(modelReset()),
|
|
||||||
this, SLOT(focusWidgetModelReset()));
|
|
||||||
if (!view->hasSelection()) {
|
|
||||||
xDebug("%s doesn't have anything selected to copy",
|
|
||||||
qPrintable(view->objectName()));
|
|
||||||
actionCut_->setEnabled(false);
|
|
||||||
actionCopy_->setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
xDebug("%s model can cut: %d", qPrintable(view->objectName()),
|
|
||||||
view->canCut());
|
|
||||||
actionCut_->setEnabled(view->canCut());
|
|
||||||
}
|
|
||||||
|
|
||||||
xDebug("%s has a selection and copy slot: copy possible",
|
|
||||||
qPrintable(now->objectName()));
|
|
||||||
actionCopy_->setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClipboardHelper::focusWidgetSelectionChanged(
|
|
||||||
const QItemSelection &selected, const QItemSelection &/*deselected*/)
|
|
||||||
{
|
|
||||||
xDebug("In %s", __FUNCTION__);
|
|
||||||
|
|
||||||
// Selection changed in the XTableView that has focus
|
|
||||||
const XTableView *view = dynamic_cast<XTableView*>(qApp->focusWidget());
|
|
||||||
xDebug("canCut:%d empty:%d", view->canCut(), selected.indexes().isEmpty());
|
|
||||||
actionCut_->setEnabled(!selected.indexes().isEmpty()
|
|
||||||
&& view && view->canCut());
|
|
||||||
actionCopy_->setEnabled(!selected.indexes().isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClipboardHelper::updatePasteStatus()
|
|
||||||
{
|
|
||||||
xDebug("In %s", __FUNCTION__);
|
|
||||||
|
|
||||||
QWidget *focusWidget = qApp->focusWidget();
|
|
||||||
if (!focusWidget) {
|
|
||||||
xDebug("No focus widget to paste into");
|
|
||||||
actionPaste_->setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QMimeData *item = QGuiApplication::clipboard()->mimeData();
|
|
||||||
if (!item || item->formats().isEmpty()) {
|
|
||||||
xDebug("Nothing on clipboard to paste");
|
|
||||||
actionPaste_->setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QMetaObject *meta = focusWidget->metaObject();
|
|
||||||
if (meta->indexOfSlot("paste()") < 0) {
|
|
||||||
xDebug("Focus Widget (%s) doesn't have a paste slot",
|
|
||||||
qPrintable(focusWidget->objectName()));
|
|
||||||
actionPaste_->setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const XTableView *view = dynamic_cast<XTableView*>(focusWidget);
|
|
||||||
if (view && !view->canPaste(item)) {
|
|
||||||
xDebug("%s cannot accept this item (%s)",
|
|
||||||
qPrintable(view->objectName()),
|
|
||||||
qPrintable(item->formats().join("|")));
|
|
||||||
actionPaste_->setEnabled(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
xDebug("%s can accept this item (%s): paste possible",
|
|
||||||
qPrintable(focusWidget->objectName()),
|
|
||||||
qPrintable(item->formats().join("|")));
|
|
||||||
actionPaste_->setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClipboardHelper::focusWidgetModelReset()
|
|
||||||
{
|
|
||||||
xDebug("In %s", __FUNCTION__);
|
|
||||||
|
|
||||||
QWidget *focusWidget = qApp->focusWidget();
|
|
||||||
updateCutCopyStatus(focusWidget, focusWidget); // re-eval cut/copy status
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef xDebug
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2020 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _CLIPBOARD_HELPER_H
|
|
||||||
#define _CLIPBOARD_HELPER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QList>
|
|
||||||
|
|
||||||
class QAction;
|
|
||||||
class QItemSelection;
|
|
||||||
|
|
||||||
class ClipboardHelper : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
ClipboardHelper(QObject *parent=nullptr);
|
|
||||||
|
|
||||||
QList<QAction*> actions();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void actionTriggered();
|
|
||||||
void updateCutCopyStatus(QWidget *old, QWidget *now);
|
|
||||||
void focusWidgetSelectionChanged(const QItemSelection &selected,
|
|
||||||
const QItemSelection &deselected);
|
|
||||||
void focusWidgetModelReset();
|
|
||||||
void updatePasteStatus();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QAction *actionCut_{nullptr};
|
|
||||||
QAction *actionCopy_{nullptr};
|
|
||||||
QAction *actionPaste_{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -209,7 +209,7 @@ void DeviceGroupDialog::updateTotalDeviceCount()
|
|||||||
|
|
||||||
void DeviceGroupDialog::updateIp4Gateway()
|
void DeviceGroupDialog::updateIp4Gateway()
|
||||||
{
|
{
|
||||||
quint32 net = ip4Address->value() & (~0UL << (32 - ip4PrefixLength->value()));
|
quint32 net = ip4Address->value() & (~0 << (32 - ip4PrefixLength->value()));
|
||||||
ip4Gateway->setValue(net | 0x01);
|
ip4Gateway->setValue(net | 0x01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,10 +25,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "uint128.h"
|
#include "uint128.h"
|
||||||
|
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QMimeData>
|
|
||||||
|
|
||||||
const QLatin1String kDeviceGroupsMimeType(
|
|
||||||
"application/vnd.ostinato.devicegroups");
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kName,
|
kName,
|
||||||
@ -209,85 +205,6 @@ bool DeviceGroupModel::setData(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList DeviceGroupModel::mimeTypes() const
|
|
||||||
{
|
|
||||||
return QStringList() << kDeviceGroupsMimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMimeData* DeviceGroupModel::mimeData(const QModelIndexList &indexes) const
|
|
||||||
{
|
|
||||||
using ::google::protobuf::uint8;
|
|
||||||
|
|
||||||
if (indexes.isEmpty())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
// indexes may include multiple columns for a row - but we are only
|
|
||||||
// interested in rows 'coz we have a single data for all columns
|
|
||||||
// XXX: use QMap instead of QSet to keep rows in sorted order
|
|
||||||
QMap<int, int> rows;
|
|
||||||
foreach(QModelIndex index, indexes)
|
|
||||||
rows.insert(index.row(), index.row());
|
|
||||||
|
|
||||||
OstProto::DeviceGroupConfigList dgList;
|
|
||||||
dgList.mutable_port_id()->set_id(port_->id());
|
|
||||||
foreach(int row, rows) {
|
|
||||||
OstProto::DeviceGroup *devGrp = dgList.add_device_group();
|
|
||||||
devGrp->CopyFrom(*port_->deviceGroupByIndex(row));
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray data;
|
|
||||||
data.resize(dgList.ByteSize());
|
|
||||||
dgList.SerializeWithCachedSizesToArray((uint8*)data.data());
|
|
||||||
//qDebug("copy %s", dgList.DebugString().c_str());
|
|
||||||
//TODO: copy DebugString as text/plain?
|
|
||||||
|
|
||||||
QMimeData *mimeData = new QMimeData();
|
|
||||||
mimeData->setData(kDeviceGroupsMimeType, data);
|
|
||||||
return mimeData; // XXX: caller is expected to take ownership and free!
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeviceGroupModel::dropMimeData(const QMimeData *data,
|
|
||||||
Qt::DropAction action, int row, int /*column*/,
|
|
||||||
const QModelIndex &parent)
|
|
||||||
{
|
|
||||||
if (!data)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!data->hasFormat(kDeviceGroupsMimeType))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (action != Qt::CopyAction)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
OstProto::DeviceGroupConfigList dgList;
|
|
||||||
QByteArray ba(data->data(kDeviceGroupsMimeType));
|
|
||||||
dgList.ParseFromArray((void*)ba.constData(), ba.size());
|
|
||||||
//qDebug("paste %s", dgList.DebugString().c_str());
|
|
||||||
|
|
||||||
if ((row < 0) || (row > rowCount(parent)))
|
|
||||||
row = rowCount(parent);
|
|
||||||
|
|
||||||
// Delete rows that we are going to overwrite
|
|
||||||
int c = 0, count = dgList.device_group_size();
|
|
||||||
if (row < rowCount(parent))
|
|
||||||
removeRows(row, qMin(rowCount() - row, count));
|
|
||||||
|
|
||||||
beginInsertRows(parent, row, row+count-1);
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
if (port_->newDeviceGroupAt(row+i, &dgList.device_group(i)))
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
endInsertRows();
|
|
||||||
|
|
||||||
if (c != count) {
|
|
||||||
qWarning("failed to copy rows in DeviceGroupModel at row %d; "
|
|
||||||
"requested = %d, actual = %d", row, count, c);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DeviceGroupModel::insertRows(
|
bool DeviceGroupModel::insertRows(
|
||||||
int row,
|
int row,
|
||||||
int count,
|
int count,
|
||||||
|
@ -42,12 +42,6 @@ public:
|
|||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
bool setData(const QModelIndex &index, const QVariant &value,
|
bool setData(const QModelIndex &index, const QVariant &value,
|
||||||
int role = Qt::EditRole);
|
int role = Qt::EditRole);
|
||||||
|
|
||||||
QStringList mimeTypes() const;
|
|
||||||
QMimeData* mimeData(const QModelIndexList &indexes) const;
|
|
||||||
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
|
|
||||||
int row, int column, const QModelIndex &parent);
|
|
||||||
|
|
||||||
bool insertRows (int row, int count,
|
bool insertRows (int row, int count,
|
||||||
const QModelIndex &parent = QModelIndex());
|
const QModelIndex &parent = QModelIndex());
|
||||||
bool removeRows (int row, int count,
|
bool removeRows (int row, int count,
|
||||||
|
@ -242,11 +242,6 @@ QVariant DeviceModel::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::DropActions DeviceModel::supportedDropActions() const
|
|
||||||
{
|
|
||||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceModel::setPort(Port *port)
|
void DeviceModel::setPort(Port *port)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
@ -39,8 +39,6 @@ public:
|
|||||||
int role = Qt::DisplayRole) const;
|
int role = Qt::DisplayRole) const;
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
|
||||||
Qt::DropActions supportedDropActions() const;
|
|
||||||
|
|
||||||
void setPort(Port *port);
|
void setPort(Port *port);
|
||||||
QAbstractItemModel* detailModel(const QModelIndex &index);
|
QAbstractItemModel* detailModel(const QModelIndex &index);
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
#include "deviceswidget.h"
|
#include "deviceswidget.h"
|
||||||
|
|
||||||
#include "clipboardhelper.h"
|
|
||||||
#include "devicegroupdialog.h"
|
#include "devicegroupdialog.h"
|
||||||
#include "port.h"
|
#include "port.h"
|
||||||
#include "portgrouplist.h"
|
#include "portgrouplist.h"
|
||||||
@ -27,8 +26,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
|
||||||
extern ClipboardHelper *clipboardHelper;
|
|
||||||
|
|
||||||
DevicesWidget::DevicesWidget(QWidget *parent)
|
DevicesWidget::DevicesWidget(QWidget *parent)
|
||||||
: QWidget(parent), portGroups_(NULL)
|
: QWidget(parent), portGroups_(NULL)
|
||||||
{
|
{
|
||||||
@ -52,14 +49,6 @@ DevicesWidget::DevicesWidget(QWidget *parent)
|
|||||||
|
|
||||||
// DevicesWidget's actions is an aggegate of all sub-widget's actions
|
// DevicesWidget's actions is an aggegate of all sub-widget's actions
|
||||||
addActions(deviceGroupList->actions());
|
addActions(deviceGroupList->actions());
|
||||||
|
|
||||||
// Add the clipboard actions to the context menu of deviceGroupList
|
|
||||||
// but not to DeviceWidget's actions since they are already available
|
|
||||||
// in the global Edit Menu
|
|
||||||
QAction *sep = new QAction("Clipboard", this);
|
|
||||||
sep->setSeparator(true);
|
|
||||||
deviceGroupList->addAction(sep);
|
|
||||||
deviceGroupList->addActions(clipboardHelper->actions());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DevicesWidget::setPortGroupList(PortGroupList *portGroups)
|
void DevicesWidget::setPortGroupList(PortGroupList *portGroups)
|
||||||
|
@ -158,8 +158,8 @@ To emulate a device, click on Configuration and create a device group</string>
|
|||||||
<property name="whatsThis">
|
<property name="whatsThis">
|
||||||
<string>IP neighbor cache is empty</string>
|
<string>IP neighbor cache is empty</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="selectionBehavior">
|
<property name="selectionMode">
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -262,10 +262,8 @@ void DumpView::paintEvent(QPaintEvent* /*event*/)
|
|||||||
// FIXME(LOW): unable to set the self widget's font in constructor
|
// FIXME(LOW): unable to set the self widget's font in constructor
|
||||||
painter.setFont(QFont("Courier"));
|
painter.setFont(QFont("Courier"));
|
||||||
|
|
||||||
// Qt automatically clears the background before we are called
|
// set a white background
|
||||||
// QWidget::paintEvent doc:
|
painter.fillRect(rect(), QBrush(QColor(Qt::white)));
|
||||||
// When the paint event occurs, the update region has normally
|
|
||||||
// been erased, so you are painting on the widget's background.
|
|
||||||
|
|
||||||
if (model())
|
if (model())
|
||||||
{
|
{
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2021 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "fieldedit.h"
|
|
||||||
|
|
||||||
FieldEdit::FieldEdit(QWidget *parent)
|
|
||||||
: QLineEdit(parent)
|
|
||||||
{
|
|
||||||
setType(kUInt64);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FieldEdit::setType(FieldType type)
|
|
||||||
{
|
|
||||||
// clear existing contents before changing the validator
|
|
||||||
clear();
|
|
||||||
setPlaceholderText("");
|
|
||||||
|
|
||||||
type_ = type;
|
|
||||||
switch (type_) {
|
|
||||||
case kUInt64:
|
|
||||||
setValidator(&uint64Validator_);
|
|
||||||
if (isMaskMode_)
|
|
||||||
setText("0xFFFFFFFFFFFFFFFF");
|
|
||||||
break;
|
|
||||||
case kMacAddress:
|
|
||||||
setValidator(&macValidator_);
|
|
||||||
setPlaceholderText("00:00:00:00:00:00");
|
|
||||||
if (isMaskMode_)
|
|
||||||
setText("FF:FF:FF:FF:FF:FF");
|
|
||||||
break;
|
|
||||||
case kIp4Address:
|
|
||||||
setValidator(&ip4Validator_);
|
|
||||||
setPlaceholderText("0.0.0.0");
|
|
||||||
if (isMaskMode_)
|
|
||||||
setText("255.255.255.255");
|
|
||||||
break;
|
|
||||||
case kIp6Address:
|
|
||||||
setValidator(&ip6Validator_);
|
|
||||||
setPlaceholderText("::");
|
|
||||||
if (isMaskMode_)
|
|
||||||
setText("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setValidator(nullptr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Applicable only if type is kUInt64
|
|
||||||
void FieldEdit::setRange(quint64 min, quint64 max)
|
|
||||||
{
|
|
||||||
uint64Validator_.setRange(min, max);
|
|
||||||
if (type_ == kUInt64) {
|
|
||||||
setPlaceholderText(QString("%1 - %2").arg(min).arg(max));
|
|
||||||
if (isMaskMode_)
|
|
||||||
setText(QString::number(max, 16).toUpper().prepend("0x"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FieldEdit::setMaskMode(bool maskMode)
|
|
||||||
{
|
|
||||||
isMaskMode_ = maskMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString FieldEdit::text() const
|
|
||||||
{
|
|
||||||
QString str = QLineEdit::text();
|
|
||||||
|
|
||||||
switch (type_) {
|
|
||||||
case kMacAddress:
|
|
||||||
str.remove(QRegularExpression("[:-]"));
|
|
||||||
str.prepend("0x");
|
|
||||||
break;
|
|
||||||
case kIp4Address:
|
|
||||||
str = QString::number(QHostAddress(str).toIPv4Address());
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2021 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _FIELD_EDIT_H
|
|
||||||
#define _FIELD_EDIT_H
|
|
||||||
|
|
||||||
#include "ipv4addressvalidator.h"
|
|
||||||
#include "ipv6addressvalidator.h"
|
|
||||||
#include "macaddressvalidator.h"
|
|
||||||
#include "ulonglongvalidator.h"
|
|
||||||
|
|
||||||
#include <QLineEdit>
|
|
||||||
|
|
||||||
class FieldEdit: public QLineEdit
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
enum FieldType {
|
|
||||||
kUInt64,
|
|
||||||
kMacAddress,
|
|
||||||
kIp4Address,
|
|
||||||
kIp6Address
|
|
||||||
};
|
|
||||||
FieldEdit(QWidget *parent = 0);
|
|
||||||
|
|
||||||
void setType(FieldType type);
|
|
||||||
void setRange(quint64 min, quint64 max);
|
|
||||||
|
|
||||||
void setMaskMode(bool maskMode);
|
|
||||||
|
|
||||||
QString text() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
FieldType type_{kUInt64};
|
|
||||||
bool isMaskMode_{false};
|
|
||||||
|
|
||||||
IPv4AddressValidator ip4Validator_;
|
|
||||||
IPv6AddressValidator ip6Validator_;
|
|
||||||
MacAddressValidator macValidator_;
|
|
||||||
ULongLongValidator uint64Validator_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,230 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2021 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "findreplace.h"
|
|
||||||
|
|
||||||
#include "abstractprotocol.h"
|
|
||||||
#include "iputils.h"
|
|
||||||
#include "mandatoryfieldsgroup.h"
|
|
||||||
#include "protocolmanager.h"
|
|
||||||
#include "stream.h"
|
|
||||||
#include "uint128.h"
|
|
||||||
|
|
||||||
#include <QPushButton>
|
|
||||||
|
|
||||||
extern ProtocolManager *OstProtocolManager;
|
|
||||||
|
|
||||||
// TODO: It might be useful for this dialog to support a "preview"
|
|
||||||
// of the replacements
|
|
||||||
|
|
||||||
FindReplaceDialog::FindReplaceDialog(Action *action, QWidget *parent)
|
|
||||||
: QDialog(parent), action_(action)
|
|
||||||
{
|
|
||||||
setupUi(this);
|
|
||||||
|
|
||||||
findMask->setMaskMode(true);
|
|
||||||
replaceMask->setMaskMode(true);
|
|
||||||
|
|
||||||
// Keep things simple and don't use mask(s) (default)
|
|
||||||
useFindMask->setChecked(false);
|
|
||||||
useReplaceMask->setChecked(false);
|
|
||||||
|
|
||||||
// TODO: remove combo protocols - see note in StreamBase::findReplace
|
|
||||||
QStringList protocolList = OstProtocolManager->protocolDatabase();
|
|
||||||
protocolList.sort();
|
|
||||||
protocol->addItems(protocolList);
|
|
||||||
|
|
||||||
// Enable this setting if we have streams selected on input
|
|
||||||
selectedStreamsOnly->setEnabled(action->selectedStreamsOnly);
|
|
||||||
|
|
||||||
// Reset for user input
|
|
||||||
action->selectedStreamsOnly = false;
|
|
||||||
|
|
||||||
QPushButton *ok = buttonBox->button(QDialogButtonBox::Ok);
|
|
||||||
ok->setText(tr("Replace All"));
|
|
||||||
ok->setDisabled(true);
|
|
||||||
|
|
||||||
mandatoryFields_ = new MandatoryFieldsGroup(this);
|
|
||||||
mandatoryFields_->add(protocol);
|
|
||||||
mandatoryFields_->add(field);
|
|
||||||
mandatoryFields_->add(findValue);
|
|
||||||
mandatoryFields_->add(findMask);
|
|
||||||
mandatoryFields_->add(replaceValue);
|
|
||||||
mandatoryFields_->add(replaceMask);
|
|
||||||
mandatoryFields_->setSubmitButton(ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
FindReplaceDialog::~FindReplaceDialog()
|
|
||||||
{
|
|
||||||
delete mandatoryFields_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FindReplaceDialog::on_protocol_currentIndexChanged(const QString &name)
|
|
||||||
{
|
|
||||||
field->clear();
|
|
||||||
fieldAttrib_.clear();
|
|
||||||
|
|
||||||
Stream stream;
|
|
||||||
AbstractProtocol *protocol = OstProtocolManager->createProtocol(
|
|
||||||
name, &stream);
|
|
||||||
int count = protocol->fieldCount();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
// XXX: It might be useful to support meta fields too, later!
|
|
||||||
if (!protocol->fieldFlags(i).testFlag(AbstractProtocol::FrameField))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int bitSize = protocol->fieldData(i, AbstractProtocol::FieldBitSize)
|
|
||||||
.toInt();
|
|
||||||
if (bitSize <= 0) // skip optional fields
|
|
||||||
continue;
|
|
||||||
|
|
||||||
FieldAttrib fieldAttrib;
|
|
||||||
fieldAttrib.index = i; // fieldIndex
|
|
||||||
fieldAttrib.bitSize = bitSize;
|
|
||||||
|
|
||||||
// field and fieldAttrib_ have same count and order of fields
|
|
||||||
fieldAttrib_.append(fieldAttrib);
|
|
||||||
field->addItem(protocol->fieldData(i, AbstractProtocol::FieldName)
|
|
||||||
.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
protocolId_ = protocol->protocolNumber();
|
|
||||||
delete protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FindReplaceDialog::on_field_currentIndexChanged(int index)
|
|
||||||
{
|
|
||||||
if (index < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QString fieldName = field->currentText();
|
|
||||||
FieldAttrib fieldAttrib = fieldAttrib_.at(index);
|
|
||||||
|
|
||||||
// Use heuristics to determine field type
|
|
||||||
if (fieldAttrib.bitSize == 48) {
|
|
||||||
findMask->setType(FieldEdit::kMacAddress);
|
|
||||||
findValue->setType(FieldEdit::kMacAddress);
|
|
||||||
replaceMask->setType(FieldEdit::kMacAddress);
|
|
||||||
replaceValue->setType(FieldEdit::kMacAddress);
|
|
||||||
} else if ((fieldAttrib.bitSize == 32)
|
|
||||||
&& (fieldName.contains(QRegularExpression(
|
|
||||||
"address|source|destination",
|
|
||||||
QRegularExpression::CaseInsensitiveOption)))) {
|
|
||||||
findMask->setType(FieldEdit::kIp4Address);
|
|
||||||
findValue->setType(FieldEdit::kIp4Address);
|
|
||||||
replaceMask->setType(FieldEdit::kIp4Address);
|
|
||||||
replaceValue->setType(FieldEdit::kIp4Address);
|
|
||||||
} else if ((fieldAttrib.bitSize == 128)
|
|
||||||
&& (fieldName.contains(QRegularExpression(
|
|
||||||
"address|source|destination",
|
|
||||||
QRegularExpression::CaseInsensitiveOption)))) {
|
|
||||||
findMask->setType(FieldEdit::kIp6Address);
|
|
||||||
findValue->setType(FieldEdit::kIp6Address);
|
|
||||||
replaceMask->setType(FieldEdit::kIp6Address);
|
|
||||||
replaceValue->setType(FieldEdit::kIp6Address);
|
|
||||||
} else {
|
|
||||||
quint64 max = quint64(~0) >> (64-fieldAttrib.bitSize);
|
|
||||||
qDebug("XXXXXX %s bitSize %d max %llx",
|
|
||||||
qPrintable(field->currentText()),
|
|
||||||
fieldAttrib.bitSize, max);
|
|
||||||
|
|
||||||
findMask->setType(FieldEdit::kUInt64);
|
|
||||||
findMask->setRange(0, max);
|
|
||||||
findValue->setType(FieldEdit::kUInt64);
|
|
||||||
findValue->setRange(0, max);
|
|
||||||
|
|
||||||
replaceMask->setType(FieldEdit::kUInt64);
|
|
||||||
replaceMask->setRange(0, max);
|
|
||||||
replaceValue->setType(FieldEdit::kUInt64);
|
|
||||||
replaceValue->setRange(0, max);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FindReplaceDialog::on_matchAny_toggled(bool checked)
|
|
||||||
{
|
|
||||||
if (checked) {
|
|
||||||
findValueLabel->setHidden(true);
|
|
||||||
findValue->setHidden(true);
|
|
||||||
useFindMask->setHidden(true);
|
|
||||||
findMask->setHidden(true);
|
|
||||||
findMaskHint->setHidden(true);
|
|
||||||
} else {
|
|
||||||
findValueLabel->setVisible(true);
|
|
||||||
findValue->setVisible(true);
|
|
||||||
useFindMask->setVisible(true);
|
|
||||||
if (useFindMask->isChecked()) {
|
|
||||||
findMask->setVisible(true);
|
|
||||||
findMaskHint->setVisible(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FindReplaceDialog::on_buttonBox_accepted()
|
|
||||||
{
|
|
||||||
FieldAttrib fieldAttrib = fieldAttrib_.at(field->currentIndex());
|
|
||||||
action_->protocolField = QString("%1 %2")
|
|
||||||
.arg(protocol->currentText())
|
|
||||||
.arg(field->currentText());
|
|
||||||
action_->protocolNumber = protocolId_;
|
|
||||||
action_->fieldIndex = fieldAttrib.index;
|
|
||||||
action_->fieldBitSize = fieldAttrib.bitSize;
|
|
||||||
|
|
||||||
if (fieldAttrib.bitSize == 128) { // IPv6 address
|
|
||||||
if (matchAny->isChecked()) {
|
|
||||||
action_->findMask.setValue(UInt128(0));
|
|
||||||
action_->findValue.setValue(UInt128(0));
|
|
||||||
} else {
|
|
||||||
action_->findMask.setValue(
|
|
||||||
useFindMask->isChecked() ?
|
|
||||||
ipUtils::ip6StringToUInt128(findMask->text()) :
|
|
||||||
~UInt128(0));
|
|
||||||
action_->findValue.setValue(
|
|
||||||
ipUtils::ip6StringToUInt128(findValue->text()));
|
|
||||||
}
|
|
||||||
|
|
||||||
action_->replaceMask.setValue(
|
|
||||||
useReplaceMask->isChecked() ?
|
|
||||||
ipUtils::ip6StringToUInt128(replaceMask->text()) :
|
|
||||||
~UInt128(0));
|
|
||||||
action_->replaceValue.setValue(
|
|
||||||
ipUtils::ip6StringToUInt128(replaceValue->text()));
|
|
||||||
} else { // everything else
|
|
||||||
if (matchAny->isChecked()) {
|
|
||||||
action_->findMask.setValue(0);
|
|
||||||
action_->findValue.setValue(0);
|
|
||||||
} else {
|
|
||||||
action_->findMask.setValue(
|
|
||||||
useFindMask->isChecked() ?
|
|
||||||
findMask->text().toULongLong(nullptr, 0) :
|
|
||||||
~quint64(0));
|
|
||||||
action_->findValue.setValue(
|
|
||||||
findValue->text().toULongLong(nullptr, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
action_->replaceMask.setValue(
|
|
||||||
useReplaceMask->isChecked() ?
|
|
||||||
replaceMask->text().toULongLong(nullptr, 0) :
|
|
||||||
~quint64(0));
|
|
||||||
action_->replaceValue.setValue(QString::number(
|
|
||||||
replaceValue->text().toULongLong(nullptr, 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
action_->selectedStreamsOnly = selectedStreamsOnly->isChecked();
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2021 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _FIND_REPLACE_H
|
|
||||||
#define _FIND_REPLACE_H
|
|
||||||
|
|
||||||
#include "ui_findreplace.h"
|
|
||||||
|
|
||||||
class MandatoryFieldsGroup;
|
|
||||||
|
|
||||||
class FindReplaceDialog: public QDialog, public Ui::FindReplace
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
struct Action;
|
|
||||||
|
|
||||||
FindReplaceDialog(Action *action, QWidget *parent = 0);
|
|
||||||
~FindReplaceDialog();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void on_protocol_currentIndexChanged(const QString &name);
|
|
||||||
void on_field_currentIndexChanged(int index);
|
|
||||||
void on_matchAny_toggled(bool checked);
|
|
||||||
void on_buttonBox_accepted();
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct FieldAttrib;
|
|
||||||
|
|
||||||
quint32 protocolId_{0};
|
|
||||||
Action *action_{nullptr};
|
|
||||||
QList<FieldAttrib> fieldAttrib_;
|
|
||||||
MandatoryFieldsGroup *mandatoryFields_{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FindReplaceDialog::Action
|
|
||||||
{
|
|
||||||
QString protocolField;
|
|
||||||
quint32 protocolNumber;
|
|
||||||
quint32 fieldIndex;
|
|
||||||
int fieldBitSize;
|
|
||||||
QVariant findValue;
|
|
||||||
QVariant findMask;
|
|
||||||
QVariant replaceValue;
|
|
||||||
QVariant replaceMask;
|
|
||||||
|
|
||||||
bool selectedStreamsOnly; // in-out param
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FindReplaceDialog::FieldAttrib
|
|
||||||
{
|
|
||||||
quint32 index;
|
|
||||||
int bitSize;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,265 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>FindReplace</class>
|
|
||||||
<widget class="QDialog" name="FindReplace">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>361</width>
|
|
||||||
<height>309</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Find & Replace</string>
|
|
||||||
</property>
|
|
||||||
<property name="windowIcon">
|
|
||||||
<iconset resource="ostinato.qrc">
|
|
||||||
<normaloff>:/icons/find.png</normaloff>:/icons/find.png</iconset>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="find">
|
|
||||||
<property name="title">
|
|
||||||
<string>Find</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="protocolLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Protocol</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>protocol</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1" colspan="2">
|
|
||||||
<widget class="QComboBox" name="protocol"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="fieldLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Field</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>field</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1" colspan="2">
|
|
||||||
<widget class="QComboBox" name="field"/>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QLabel" name="findValueLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Value</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1" colspan="2">
|
|
||||||
<widget class="FieldEdit" name="findValue"/>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QCheckBox" name="useFindMask">
|
|
||||||
<property name="text">
|
|
||||||
<string>Mask</string>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="FieldEdit" name="findMask"/>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="2">
|
|
||||||
<widget class="QLabel" name="findMaskHint">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p align="center">Matches a field only if <span style="white-space:nowrap">(FieldValue &amp; FindMask) = FindValue</span></p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="pixmap">
|
|
||||||
<pixmap resource="ostinato.qrc">:/icons/info.png</pixmap>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0" colspan="3">
|
|
||||||
<widget class="QCheckBox" name="matchAny">
|
|
||||||
<property name="text">
|
|
||||||
<string>Match any value</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="replace">
|
|
||||||
<property name="title">
|
|
||||||
<string>Replace with</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1,0">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="replaceValueLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string>Value</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1" colspan="2">
|
|
||||||
<widget class="FieldEdit" name="replaceValue"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QCheckBox" name="useReplaceMask">
|
|
||||||
<property name="text">
|
|
||||||
<string>Mask</string>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="FieldEdit" name="replaceMask"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="2">
|
|
||||||
<widget class="QLabel" name="replaceMaskHint">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p align="center">New field value = <span style="white-space:nowrap">(OldFieldValue &amp; ~ReplaceMask) | (ReplaceValue &amp; ReplaceMask)</span></p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="pixmap">
|
|
||||||
<pixmap resource="ostinato.qrc">:/icons/info.png</pixmap>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="selectedStreamsOnly">
|
|
||||||
<property name="text">
|
|
||||||
<string>Selected Streams Only</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="standardButtons">
|
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>FieldEdit</class>
|
|
||||||
<extends>QLineEdit</extends>
|
|
||||||
<header>fieldedit.h</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources>
|
|
||||||
<include location="ostinato.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections>
|
|
||||||
<connection>
|
|
||||||
<sender>buttonBox</sender>
|
|
||||||
<signal>accepted()</signal>
|
|
||||||
<receiver>FindReplace</receiver>
|
|
||||||
<slot>accept()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>248</x>
|
|
||||||
<y>277</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>157</x>
|
|
||||||
<y>274</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>buttonBox</sender>
|
|
||||||
<signal>rejected()</signal>
|
|
||||||
<receiver>FindReplace</receiver>
|
|
||||||
<slot>reject()</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>316</x>
|
|
||||||
<y>283</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>286</x>
|
|
||||||
<y>274</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>useFindMask</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>findMask</receiver>
|
|
||||||
<slot>setVisible(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>60</x>
|
|
||||||
<y>115</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>76</x>
|
|
||||||
<y>119</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>useReplaceMask</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>replaceMask</receiver>
|
|
||||||
<slot>setVisible(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>56</x>
|
|
||||||
<y>228</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>73</x>
|
|
||||||
<y>227</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>useReplaceMask</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>replaceMaskHint</receiver>
|
|
||||||
<slot>setVisible(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>50</x>
|
|
||||||
<y>230</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>333</x>
|
|
||||||
<y>233</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>useFindMask</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>findMaskHint</receiver>
|
|
||||||
<slot>setVisible(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>46</x>
|
|
||||||
<y>116</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>335</x>
|
|
||||||
<y>122</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
|
@ -31,13 +31,9 @@ class IconOnlyDelegate : public QStyledItemDelegate
|
|||||||
{
|
{
|
||||||
QStyleOptionViewItem opt = option;
|
QStyleOptionViewItem opt = option;
|
||||||
opt.decorationPosition = QStyleOptionViewItem::Top;
|
opt.decorationPosition = QStyleOptionViewItem::Top;
|
||||||
|
opt.features &= ~QStyleOptionViewItem::HasDisplay;
|
||||||
QStyledItemDelegate::paint(painter, opt, index);
|
QStyledItemDelegate::paint(painter, opt, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString displayText(const QVariant&, const QLocale&) const
|
|
||||||
{
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 663 B |
Before Width: | Height: | Size: 648 B |
@ -1,23 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
<svg width="31.44mm" height="31.44mm" version="1.1" viewBox="0 0 31.44 31.44" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
|
||||||
<metadata>
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
|
||||||
<dc:title/>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g transform="translate(-37.525 -210.5)">
|
|
||||||
<circle cx="53.245" cy="226.22" r="15.72" fill="#e96c59" opacity=".8"/>
|
|
||||||
<path d="m53.419 212.28c-2.0736-0.0217-4.1616 0.41684-6.0884 1.3285-4.4585 2.1095-7.4154 6.2656-7.9501 11.175-0.50808 4.6643 1.5269 9.4967 5.2044 12.359 2.066 1.6079 4.6873 2.6928 7.1183 2.9462 2.643 0.2755 5.2282-0.17492 7.6011-1.3243 1.9456-0.94242 3.6302-2.2856 4.9044-3.9102 3.2672-4.1658 3.8994-9.8451 1.6275-14.62-1.0934-2.298-2.6916-4.1431-4.8639-5.6154-2.245-1.5216-4.8872-2.3101-7.5533-2.338zm-0.0276 2.2048c2.2445 0.0235 4.4688 0.68733 6.3588 1.9683 1.8288 1.2395 3.1743 2.7928 4.0948 4.7274 1.9126 4.0198 1.3803 8.8011-1.3702 12.308-1.0727 1.3677-2.4908 2.4985-4.1288 3.2919-1.9976 0.96764-4.1741 1.3468-6.3992 1.1148-2.0466-0.21332-4.2533-1.1267-5.9926-2.4803-3.096-2.4094-4.8092-6.4777-4.3814-10.404 0.45017-4.1327 2.9394-7.6316 6.6928-9.4075 1.6221-0.76747 3.38-1.1367 5.1257-1.1184z" fill="#f9bbab" opacity=".8"/>
|
|
||||||
<g fill="#fff">
|
|
||||||
<rect x="50.933" y="217.52" width="4.6236" height="12.862" opacity=".8"/>
|
|
||||||
<rect transform="scale(1,-1)" x="50.933" y="-234.92" width="4.6236" height="3.5749" opacity=".8"/>
|
|
||||||
<rect x="50.933" y="217.52" width="4.6236" height="12.862" opacity=".8"/>
|
|
||||||
<rect transform="scale(1,-1)" x="50.933" y="-234.92" width="4.6236" height="3.5749" opacity=".8"/>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 659 B |
Before Width: | Height: | Size: 778 B |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 703 B |
@ -1,25 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
<svg width="221.25mm" height="193.24mm" version="1.1" viewBox="0 0 221.25 193.24" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="linearGradient879" x1="193.48" x2="101.09" y1="198.47" y2="254.08" gradientTransform="matrix(1.7412 0 0 1.7412 -267.69 -212.02)" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="#c16602" stop-opacity=".99608" offset="0"/>
|
|
||||||
<stop stop-color="#e8b839" offset="1"/>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<metadata>
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
|
||||||
<dc:title/>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g transform="translate(97.776 -43.224)">
|
|
||||||
<path d="m12.851 49.318 104.53 181.06h-209.07z" fill="#fff" opacity=".8" stroke="url(#linearGradient879)" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".99216" stroke-width="12.188"/>
|
|
||||||
<path d="m12.851 101.1 62.098 107.56h-124.2z" fill="#f5db61" opacity=".8"/>
|
|
||||||
<rect x=".23388" y="113.27" width="25.235" height="54.405" fill="#c28832" opacity=".8"/>
|
|
||||||
<rect transform="scale(1,-1)" x=".23388" y="-196.48" width="25.235" height="14.793" fill="#c28832" opacity=".8"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.5 KiB |
@ -108,11 +108,6 @@ QVariant LogsModel::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::DropActions LogsModel::supportedDropActions() const
|
|
||||||
{
|
|
||||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------- //
|
// --------------------------------------------- //
|
||||||
// Slots
|
// Slots
|
||||||
// --------------------------------------------- //
|
// --------------------------------------------- //
|
||||||
|
@ -44,8 +44,6 @@ public:
|
|||||||
int role = Qt::DisplayRole) const;
|
int role = Qt::DisplayRole) const;
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
Qt::DropActions supportedDropActions() const;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clear();
|
void clear();
|
||||||
void setLogLevel(int level);
|
void setLogLevel(int level);
|
||||||
|
@ -26,7 +26,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QMovie>
|
#include <QMovie>
|
||||||
#include <QPropertyAnimation>
|
|
||||||
|
|
||||||
extern QMainWindow *mainWindow;
|
extern QMainWindow *mainWindow;
|
||||||
|
|
||||||
@ -50,14 +49,6 @@ LogsWindow::LogsWindow(LogsModel *model, QWidget *parent)
|
|||||||
warnAnime_ = new QMovie(":/icons/anime_warn.gif", QByteArray(), this);
|
warnAnime_ = new QMovie(":/icons/anime_warn.gif", QByteArray(), this);
|
||||||
errorAnime_ = new QMovie(":/icons/anime_error.gif", QByteArray(), this);
|
errorAnime_ = new QMovie(":/icons/anime_error.gif", QByteArray(), this);
|
||||||
|
|
||||||
alert_ = new QLabel("ALERT!", this,
|
|
||||||
Qt::FramelessWindowHint|Qt::WindowStaysOnTopHint);
|
|
||||||
alert_->setScaledContents(true);
|
|
||||||
alert_->hide();
|
|
||||||
alertAnime_ = new QPropertyAnimation(alert_, "geometry", this);
|
|
||||||
alertAnime_->setDuration(2000);
|
|
||||||
alertAnime_->setEasingCurve(QEasingCurve::InOutExpo);
|
|
||||||
|
|
||||||
connect(level, SIGNAL(currentIndexChanged(int)),
|
connect(level, SIGNAL(currentIndexChanged(int)),
|
||||||
model, SLOT(setLogLevel(int)));
|
model, SLOT(setLogLevel(int)));
|
||||||
connect(clear, SIGNAL(clicked()), model, SLOT(clear()));
|
connect(clear, SIGNAL(clicked()), model, SLOT(clear()));
|
||||||
@ -84,17 +75,12 @@ LogsWindow::~LogsWindow()
|
|||||||
delete logsModelTest_;
|
delete logsModelTest_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogsWindow::clearCurrentSelection()
|
|
||||||
{
|
|
||||||
logs->selectionModel()->clearCurrentIndex();
|
|
||||||
logs->clearSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogsWindow::when_visibilityChanged(bool visible)
|
void LogsWindow::when_visibilityChanged(bool visible)
|
||||||
{
|
{
|
||||||
if (visible) {
|
if (visible) {
|
||||||
logs->resizeRowsToContents();
|
logs->resizeRowsToContents();
|
||||||
setState(kInfo);
|
state_ = kInfo;
|
||||||
|
notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
isVisible_ = visible;
|
isVisible_ = visible;
|
||||||
@ -104,26 +90,29 @@ void LogsWindow::when_visibilityChanged(bool visible)
|
|||||||
void LogsWindow::when_rowsInserted(const QModelIndex &parent,
|
void LogsWindow::when_rowsInserted(const QModelIndex &parent,
|
||||||
int first, int last)
|
int first, int last)
|
||||||
{
|
{
|
||||||
if (isVisible_)
|
|
||||||
logs->resizeRowsToContents();
|
|
||||||
|
|
||||||
State incrementalState = kInfo;
|
if (isVisible_) {
|
||||||
|
logs->resizeRowsToContents();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_ == kError)
|
||||||
|
return;
|
||||||
|
|
||||||
for (int i = first; i <= last; i++) {
|
for (int i = first; i <= last; i++) {
|
||||||
// FIXME: use a user-role instead, so we don't need to know column and
|
// FIXME: use a user-role instead, so we don't need to know column and
|
||||||
// have to compare strings?
|
// have to compare strings?
|
||||||
QString level = logs->model()->data(logs->model()->index(i, 1, parent))
|
QString level = logs->model()->data(logs->model()->index(i, 1, parent))
|
||||||
.toString();
|
.toString();
|
||||||
if (level == "Error") {
|
if (level == "Error") {
|
||||||
incrementalState = kError;
|
state_ = kError;
|
||||||
break; // Highest level - no need to look further
|
break; // Highest level - no need to look further
|
||||||
}
|
}
|
||||||
else if (level == "Warning") {
|
else if (level == "Warning") {
|
||||||
incrementalState = kWarning;
|
state_ = kWarning;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alert(incrementalState);
|
notify();
|
||||||
if (incrementalState > state())
|
|
||||||
setState(incrementalState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogsWindow::on_autoScroll_toggled(bool checked)
|
void LogsWindow::on_autoScroll_toggled(bool checked)
|
||||||
@ -140,19 +129,6 @@ void LogsWindow::on_autoScroll_toggled(bool checked)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogsWindow::State LogsWindow::state()
|
|
||||||
{
|
|
||||||
return state_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LogsWindow::setState(State state)
|
|
||||||
{
|
|
||||||
if (isVisible_)
|
|
||||||
return;
|
|
||||||
state_ = state;
|
|
||||||
notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
QLabel* LogsWindow::tabIcon()
|
QLabel* LogsWindow::tabIcon()
|
||||||
{
|
{
|
||||||
QList<QTabBar*> tabBars = mainWindow->findChildren<QTabBar*>();
|
QList<QTabBar*> tabBars = mainWindow->findChildren<QTabBar*>();
|
||||||
@ -173,57 +149,6 @@ QLabel* LogsWindow::tabIcon()
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Popup and animate a big icon
|
|
||||||
void LogsWindow::alert(State state)
|
|
||||||
{
|
|
||||||
if (state == kInfo)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// start - center of main window
|
|
||||||
QRect start;
|
|
||||||
QWidget *view = mainWindow;
|
|
||||||
if (!view)
|
|
||||||
return;
|
|
||||||
alert_->setParent(view);
|
|
||||||
alert_->raise();
|
|
||||||
start.setSize(QSize(256, 256).scaled(view->size()/2, Qt::KeepAspectRatio));
|
|
||||||
start.moveCenter(QPoint(view->size().width()/2,
|
|
||||||
view->size().height()/2));
|
|
||||||
// end - center of logs window if visible, tab icon otherwise
|
|
||||||
QPoint c;
|
|
||||||
QLabel *icon = tabIcon();
|
|
||||||
view = isVisible_ ? dynamic_cast<QWidget*>(this) : mainWindow;
|
|
||||||
if (icon && !isVisible_) {
|
|
||||||
c = icon->geometry().center(); // in icon's parent (tabBar) coords
|
|
||||||
c = icon->mapFromParent(c); // in icon's own coords
|
|
||||||
c = icon->mapTo(view, c); // in mainWindow's coords
|
|
||||||
} else {
|
|
||||||
c = view->geometry().center();
|
|
||||||
c = view->mapTo(mainWindow, c); // in mainWindow's coords
|
|
||||||
}
|
|
||||||
|
|
||||||
QRect end;
|
|
||||||
end.moveCenter(c);
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case kError:
|
|
||||||
alert_->setPixmap(QPixmap(":/icons/error.svg"));
|
|
||||||
break;
|
|
||||||
case kWarning:
|
|
||||||
alert_->setPixmap(QPixmap(":/icons/warn.svg"));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Q_UNREACHABLE();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
alertAnime_->setStartValue(start);
|
|
||||||
alertAnime_->setEndValue(end);
|
|
||||||
alert_->show(); // ensure it's visible before starting animation
|
|
||||||
alertAnime_->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Show tab icon
|
|
||||||
void LogsWindow::notify()
|
void LogsWindow::notify()
|
||||||
{
|
{
|
||||||
QString annotation;
|
QString annotation;
|
||||||
@ -233,7 +158,7 @@ void LogsWindow::notify()
|
|||||||
warnAnime_->stop();
|
warnAnime_->stop();
|
||||||
errorAnime_->stop();
|
errorAnime_->stop();
|
||||||
|
|
||||||
switch (state()) {
|
switch (state_) {
|
||||||
case kError:
|
case kError:
|
||||||
anime = errorAnime_;
|
anime = errorAnime_;
|
||||||
annotation = " - Error(s)";
|
annotation = " - Error(s)";
|
||||||
|
@ -26,7 +26,6 @@ class LogsModel;
|
|||||||
class QDockWidget;
|
class QDockWidget;
|
||||||
class QShowEvent;
|
class QShowEvent;
|
||||||
class QMovie;
|
class QMovie;
|
||||||
class QPropertyAnimation;
|
|
||||||
|
|
||||||
class LogsWindow: public QWidget, private Ui::LogsWindow
|
class LogsWindow: public QWidget, private Ui::LogsWindow
|
||||||
{
|
{
|
||||||
@ -35,9 +34,6 @@ public:
|
|||||||
LogsWindow(LogsModel *model, QWidget *parent = 0);
|
LogsWindow(LogsModel *model, QWidget *parent = 0);
|
||||||
~LogsWindow();
|
~LogsWindow();
|
||||||
|
|
||||||
public slots:
|
|
||||||
void clearCurrentSelection();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void when_visibilityChanged(bool visible);
|
void when_visibilityChanged(bool visible);
|
||||||
void when_rowsInserted(const QModelIndex &parent, int first, int last);
|
void when_rowsInserted(const QModelIndex &parent, int first, int last);
|
||||||
@ -47,24 +43,15 @@ private:
|
|||||||
enum State {kInfo, kWarning, kError};
|
enum State {kInfo, kWarning, kError};
|
||||||
|
|
||||||
QLabel* tabIcon();
|
QLabel* tabIcon();
|
||||||
State state();
|
|
||||||
void setState(State state);
|
|
||||||
void alert(State state);
|
|
||||||
void notify();
|
void notify();
|
||||||
|
|
||||||
State state_{kInfo};
|
State state_{kInfo};
|
||||||
QDockWidget *parentDock_;
|
QDockWidget *parentDock_;
|
||||||
QMovie *warnAnime_{nullptr};
|
QMovie *warnAnime_{nullptr};
|
||||||
QMovie *errorAnime_{nullptr};
|
QMovie *errorAnime_{nullptr};
|
||||||
QLabel *alert_{nullptr};
|
|
||||||
QPropertyAnimation *alertAnime_{nullptr};
|
|
||||||
QString windowTitle_;
|
QString windowTitle_;
|
||||||
bool isVisible_{false}; // see XXX below
|
bool isVisible_{false};
|
||||||
QObject *logsModelTest_;
|
QObject *logsModelTest_;
|
||||||
|
|
||||||
// XXX: We cannot use isVisible() instead of isVisible_ since
|
|
||||||
// LogsWindow::isVisible() returns true even when the parent LogsDock
|
|
||||||
// is tabified but not the selected tab
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,7 +24,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "params.h"
|
#include "params.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "thememanager.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
@ -66,8 +65,6 @@ int main(int argc, char* argv[])
|
|||||||
OstProtocolManager = new ProtocolManager();
|
OstProtocolManager = new ProtocolManager();
|
||||||
OstProtocolWidgetFactory = new ProtocolWidgetFactory();
|
OstProtocolWidgetFactory = new ProtocolWidgetFactory();
|
||||||
|
|
||||||
Preferences::initDefaults();
|
|
||||||
|
|
||||||
/* (Portable Mode) If we have a .ini file in the same directory as the
|
/* (Portable Mode) If we have a .ini file in the same directory as the
|
||||||
executable, we use that instead of the platform specific location
|
executable, we use that instead of the platform specific location
|
||||||
and format for the settings */
|
and format for the settings */
|
||||||
@ -77,7 +74,6 @@ int main(int argc, char* argv[])
|
|||||||
appSettings = new QSettings(portableIni, QSettings::IniFormat);
|
appSettings = new QSettings(portableIni, QSettings::IniFormat);
|
||||||
else
|
else
|
||||||
appSettings = new QSettings();
|
appSettings = new QSettings();
|
||||||
qDebug("Settings: %s", qPrintable(appSettings->fileName()));
|
|
||||||
|
|
||||||
OstProtoLib::setExternalApplicationPaths(
|
OstProtoLib::setExternalApplicationPaths(
|
||||||
appSettings->value(kTsharkPathKey, kTsharkPathDefaultValue).toString(),
|
appSettings->value(kTsharkPathKey, kTsharkPathDefaultValue).toString(),
|
||||||
@ -85,8 +81,7 @@ int main(int argc, char* argv[])
|
|||||||
appSettings->value(kDiffPathKey, kDiffPathDefaultValue).toString(),
|
appSettings->value(kDiffPathKey, kDiffPathDefaultValue).toString(),
|
||||||
appSettings->value(kAwkPathKey, kAwkPathDefaultValue).toString());
|
appSettings->value(kAwkPathKey, kAwkPathDefaultValue).toString());
|
||||||
|
|
||||||
ThemeManager::instance()->setTheme(appSettings->value(kThemeKey).toString());
|
Preferences::initDefaults();
|
||||||
|
|
||||||
qsrand(QDateTime::currentDateTime().toTime_t());
|
qsrand(QDateTime::currentDateTime().toTime_t());
|
||||||
|
|
||||||
mainWindow = new MainWindow;
|
mainWindow = new MainWindow;
|
||||||
|
@ -23,8 +23,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "dbgthread.h"
|
#include "dbgthread.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "clipboardhelper.h"
|
|
||||||
#include "fileformatoptions.h"
|
|
||||||
#include "jumpurl.h"
|
#include "jumpurl.h"
|
||||||
#include "logsmodel.h"
|
#include "logsmodel.h"
|
||||||
#include "logswindow.h"
|
#include "logswindow.h"
|
||||||
@ -62,7 +60,6 @@ extern const char* revision;
|
|||||||
|
|
||||||
PortGroupList *pgl;
|
PortGroupList *pgl;
|
||||||
LogsModel *appLogs;
|
LogsModel *appLogs;
|
||||||
ClipboardHelper *clipboardHelper;
|
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent)
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
: QMainWindow (parent)
|
: QMainWindow (parent)
|
||||||
@ -86,14 +83,8 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
localServer_ = new QProcess(this);
|
localServer_ = new QProcess(this);
|
||||||
connect(localServer_, SIGNAL(finished(int, QProcess::ExitStatus)),
|
connect(localServer_, SIGNAL(finished(int, QProcess::ExitStatus)),
|
||||||
SLOT(onLocalServerFinished(int, QProcess::ExitStatus)));
|
SLOT(onLocalServerFinished(int, QProcess::ExitStatus)));
|
||||||
|
|
||||||
#if QT_VERSION >= 0x050600
|
|
||||||
connect(localServer_, SIGNAL(errorOccurred(QProcess::ProcessError)),
|
|
||||||
SLOT(onLocalServerError(QProcess::ProcessError)));
|
|
||||||
#else
|
|
||||||
connect(localServer_, SIGNAL(error(QProcess::ProcessError)),
|
connect(localServer_, SIGNAL(error(QProcess::ProcessError)),
|
||||||
SLOT(onLocalServerError(QProcess::ProcessError)));
|
SLOT(onLocalServerError(QProcess::ProcessError)));
|
||||||
#endif
|
|
||||||
localServer_->setProcessChannelMode(QProcess::ForwardedChannels);
|
localServer_->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||||
localServer_->start(serverApp, QStringList());
|
localServer_->start(serverApp, QStringList());
|
||||||
QTimer::singleShot(5000, this, SLOT(stopLocalServerMonitor()));
|
QTimer::singleShot(5000, this, SLOT(stopLocalServerMonitor()));
|
||||||
@ -103,7 +94,6 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
|
|
||||||
pgl = new PortGroupList;
|
pgl = new PortGroupList;
|
||||||
appLogs = new LogsModel(this);
|
appLogs = new LogsModel(this);
|
||||||
clipboardHelper = new ClipboardHelper(this);
|
|
||||||
|
|
||||||
portsWindow = new PortsWindow(pgl, this);
|
portsWindow = new PortsWindow(pgl, this);
|
||||||
statsWindow = new PortStatsWindow(pgl, this);
|
statsWindow = new PortStatsWindow(pgl, this);
|
||||||
@ -126,11 +116,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
|
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
|
||||||
menuFile->insertActions(menuFile->actions().at(3),
|
menuFile->insertActions(menuFile->actions().at(3), portsWindow->actions());
|
||||||
portsWindow->portActions());
|
|
||||||
menuEdit->addActions(clipboardHelper->actions());
|
|
||||||
menuStreams->addActions(portsWindow->streamActions());
|
|
||||||
menuDevices->addActions(portsWindow->deviceActions());
|
|
||||||
|
|
||||||
statsDock->setWidget(statsWindow);
|
statsDock->setWidget(statsWindow);
|
||||||
addDockWidget(Qt::BottomDockWidgetArea, statsDock);
|
addDockWidget(Qt::BottomDockWidgetArea, statsDock);
|
||||||
@ -143,13 +129,6 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
portsDock->setWidget(portsWindow);
|
portsDock->setWidget(portsWindow);
|
||||||
addDockWidget(Qt::TopDockWidgetArea, portsDock);
|
addDockWidget(Qt::TopDockWidgetArea, portsDock);
|
||||||
|
|
||||||
#if QT_VERSION >= 0x050600
|
|
||||||
// Set top and bottom docks to equal height
|
|
||||||
resizeDocks({portsDock, statsDock}, {height()/2, height()/2}, Qt::Vertical);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
portsWindow->setFocus();
|
|
||||||
|
|
||||||
// Save the default window geometry and layout ...
|
// Save the default window geometry and layout ...
|
||||||
defaultGeometry_ = geometry();
|
defaultGeometry_ = geometry();
|
||||||
defaultLayout_ = saveState(0);
|
defaultLayout_ = saveState(0);
|
||||||
@ -175,7 +154,6 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
this, SLOT(onNewVersion(QString)));
|
this, SLOT(onNewVersion(QString)));
|
||||||
updater->checkForNewVersion();
|
updater->checkForNewVersion();
|
||||||
|
|
||||||
// TODO: If session file specified (and valid?), don't add local drone PG
|
|
||||||
// Add the "Local" Port Group
|
// Add the "Local" Port Group
|
||||||
if (appParams.optLocalDrone()) {
|
if (appParams.optLocalDrone()) {
|
||||||
PortGroup *pg = new PortGroup;
|
PortGroup *pg = new PortGroup;
|
||||||
@ -379,10 +357,6 @@ void MainWindow::on_actionViewRestoreDefaults_triggered()
|
|||||||
statsDock->raise();
|
statsDock->raise();
|
||||||
|
|
||||||
actionViewShowMyReservedPortsOnly->setChecked(false);
|
actionViewShowMyReservedPortsOnly->setChecked(false);
|
||||||
|
|
||||||
portsWindow->clearCurrentSelection();
|
|
||||||
statsWindow->clearCurrentSelection();
|
|
||||||
logsWindow_->clearCurrentSelection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionHelpOnline_triggered()
|
void MainWindow::on_actionHelpOnline_triggered()
|
||||||
@ -420,13 +394,8 @@ void MainWindow::on_actionHelpAbout_triggered()
|
|||||||
void MainWindow::stopLocalServerMonitor()
|
void MainWindow::stopLocalServerMonitor()
|
||||||
{
|
{
|
||||||
// We are only interested in startup errors
|
// We are only interested in startup errors
|
||||||
#if QT_VERSION >= 0x050600
|
|
||||||
disconnect(localServer_, SIGNAL(errorOccurred(QProcess::ProcessError)),
|
|
||||||
this, SLOT(onLocalServerError(QProcess::ProcessError)));
|
|
||||||
#else
|
|
||||||
disconnect(localServer_, SIGNAL(error(QProcess::ProcessError)),
|
disconnect(localServer_, SIGNAL(error(QProcess::ProcessError)),
|
||||||
this, SLOT(onLocalServerError(QProcess::ProcessError)));
|
this, SLOT(onLocalServerError(QProcess::ProcessError)));
|
||||||
#endif
|
|
||||||
disconnect(localServer_, SIGNAL(finished(int, QProcess::ExitStatus)),
|
disconnect(localServer_, SIGNAL(finished(int, QProcess::ExitStatus)),
|
||||||
this, SLOT(onLocalServerFinished(int, QProcess::ExitStatus)));
|
this, SLOT(onLocalServerFinished(int, QProcess::ExitStatus)));
|
||||||
}
|
}
|
||||||
@ -467,8 +436,8 @@ void MainWindow::reportLocalServerError()
|
|||||||
if (localServer_->exitCode() == STATUS_DLL_NOT_FOUND)
|
if (localServer_->exitCode() == STATUS_DLL_NOT_FOUND)
|
||||||
errorStr.append(tr("<p>This is most likely because Packet.dll "
|
errorStr.append(tr("<p>This is most likely because Packet.dll "
|
||||||
"was not found - make sure you have "
|
"was not found - make sure you have "
|
||||||
"<a href='%1'>npcap installed and accessible</a>."
|
"<a href='%1'>WinPcap"
|
||||||
"</p>")
|
"</a> installed.</p>")
|
||||||
.arg(jumpUrl("winpcap")));
|
.arg(jumpUrl("winpcap")));
|
||||||
#endif
|
#endif
|
||||||
msgBox.setText(errorStr);
|
msgBox.setText(errorStr);
|
||||||
@ -548,7 +517,7 @@ bool MainWindow::openSession(QString fileName, QString &error)
|
|||||||
goto _fail;
|
goto _fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((optDialog = FileFormatOptions::openOptionsDialog(fmt)))
|
if ((optDialog = fmt->openOptionsDialog()))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
optDialog->setParent(this, Qt::Dialog);
|
optDialog->setParent(this, Qt::Dialog);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1024</width>
|
<width>1024</width>
|
||||||
<height>700</height>
|
<height>600</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle" >
|
<property name="windowTitle" >
|
||||||
@ -25,33 +25,9 @@
|
|||||||
<addaction name="actionOpenSession" />
|
<addaction name="actionOpenSession" />
|
||||||
<addaction name="actionSaveSession" />
|
<addaction name="actionSaveSession" />
|
||||||
<addaction name="separator" />
|
<addaction name="separator" />
|
||||||
<addaction name="separator" />
|
|
||||||
<addaction name="actionPreferences" />
|
<addaction name="actionPreferences" />
|
||||||
<addaction name="actionFileExit" />
|
<addaction name="actionFileExit" />
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuEdit" >
|
|
||||||
<property name="title" >
|
|
||||||
<string>&Edit</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenu" name="menuView" >
|
|
||||||
<property name="title" >
|
|
||||||
<string>&View</string>
|
|
||||||
</property>
|
|
||||||
<addaction name="actionViewShowMyReservedPortsOnly" />
|
|
||||||
<addaction name="actionViewRestoreDefaults" />
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenu" name="menuStreams" >
|
|
||||||
<property name="title" >
|
|
||||||
<string>&Streams</string>
|
|
||||||
</property>
|
|
||||||
<addaction name="actionTest" />
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenu" name="menuDevices" >
|
|
||||||
<property name="title" >
|
|
||||||
<string>&Devices</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QMenu" name="menuHelp" >
|
<widget class="QMenu" name="menuHelp" >
|
||||||
<property name="title" >
|
<property name="title" >
|
||||||
<string>&Help</string>
|
<string>&Help</string>
|
||||||
@ -64,11 +40,15 @@
|
|||||||
<addaction name="actionHelpAbout" />
|
<addaction name="actionHelpAbout" />
|
||||||
<addaction name="actionAboutQt" />
|
<addaction name="actionAboutQt" />
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuView" >
|
||||||
|
<property name="title" >
|
||||||
|
<string>&View</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionViewShowMyReservedPortsOnly" />
|
||||||
|
<addaction name="actionViewRestoreDefaults" />
|
||||||
|
</widget>
|
||||||
<addaction name="menuFile" />
|
<addaction name="menuFile" />
|
||||||
<addaction name="menuEdit" />
|
|
||||||
<addaction name="menuView" />
|
<addaction name="menuView" />
|
||||||
<addaction name="menuStreams" />
|
|
||||||
<addaction name="menuDevices" />
|
|
||||||
<addaction name="menuHelp" />
|
<addaction name="menuHelp" />
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusbar" />
|
<widget class="QStatusBar" name="statusbar" />
|
||||||
|
@ -1,126 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2021 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mandatoryfieldsgroup.h"
|
|
||||||
|
|
||||||
// No need for QDateEdit, QSpinBox, etc., since these always return values
|
|
||||||
#include <QCheckBox>
|
|
||||||
#include <QComboBox>
|
|
||||||
#include <QLineEdit>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
void MandatoryFieldsGroup::add(QWidget *widget)
|
|
||||||
{
|
|
||||||
if (!widgets_.contains(widget)) {
|
|
||||||
if (widget->inherits("QCheckBox"))
|
|
||||||
connect(qobject_cast<QCheckBox*>(widget),
|
|
||||||
SIGNAL(clicked()),
|
|
||||||
this, SLOT(changed()));
|
|
||||||
else if (widget->inherits("QComboBox"))
|
|
||||||
connect(qobject_cast<QComboBox*>(widget),
|
|
||||||
SIGNAL(highlighted(int)),
|
|
||||||
this, SLOT(changed()));
|
|
||||||
else if (widget->inherits("QLineEdit"))
|
|
||||||
connect(qobject_cast<QLineEdit*>(widget),
|
|
||||||
SIGNAL(textChanged(const QString&)),
|
|
||||||
this, SLOT(changed()));
|
|
||||||
else {
|
|
||||||
qWarning("MandatoryFieldsGroup: unsupported class %s",
|
|
||||||
widget->metaObject()->className());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
widgets_.append(widget);
|
|
||||||
changed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MandatoryFieldsGroup::remove(QWidget *widget)
|
|
||||||
{
|
|
||||||
widgets_.removeAll(widget);
|
|
||||||
|
|
||||||
changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MandatoryFieldsGroup::setSubmitButton(QPushButton *button)
|
|
||||||
{
|
|
||||||
if (submitButton_ && submitButton_ != button)
|
|
||||||
submitButton_->setEnabled(true);
|
|
||||||
submitButton_ = button;
|
|
||||||
|
|
||||||
changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MandatoryFieldsGroup::changed()
|
|
||||||
{
|
|
||||||
if (!submitButton_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool enable = true;
|
|
||||||
for (auto widget : widgets_) {
|
|
||||||
// Invisible mandatory widgets are treated as non-mandatory
|
|
||||||
if (!widget->isVisible())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (widget->inherits("QCheckBox")) {
|
|
||||||
// Makes sense only for tristate checkbox
|
|
||||||
auto checkBox = qobject_cast<const QCheckBox*>(widget);
|
|
||||||
if (checkBox->checkState() == Qt::PartiallyChecked) {
|
|
||||||
enable = false;
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (widget->inherits("QComboBox")) {
|
|
||||||
auto comboBox = qobject_cast<const QComboBox*>(widget);
|
|
||||||
if (comboBox->currentText().isEmpty()) {
|
|
||||||
enable = false;
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (widget->inherits("QLineEdit")) {
|
|
||||||
auto lineEdit = qobject_cast<const QLineEdit*>(widget);
|
|
||||||
if (lineEdit->text().isEmpty()
|
|
||||||
|| !lineEdit->hasAcceptableInput()) {
|
|
||||||
enable = false;
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
submitButton_->setEnabled(enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MandatoryFieldsGroup::clear()
|
|
||||||
{
|
|
||||||
widgets_.clear();
|
|
||||||
|
|
||||||
if (submitButton_) {
|
|
||||||
submitButton_->setEnabled(true);
|
|
||||||
submitButton_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2021 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _MANDATORY_FIELDS_GROUP_H
|
|
||||||
#define _MANDATORY_FIELDS_GROUP_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QList>
|
|
||||||
|
|
||||||
class QPushButton;
|
|
||||||
class QWidget;
|
|
||||||
|
|
||||||
// Adapted from https://doc.qt.io/archives/qq/qq11-mandatoryfields.html
|
|
||||||
// and improved
|
|
||||||
|
|
||||||
class MandatoryFieldsGroup : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
MandatoryFieldsGroup(QObject *parent)
|
|
||||||
: QObject(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(QWidget *widget);
|
|
||||||
void remove(QWidget *widget);
|
|
||||||
void setSubmitButton(QPushButton *button);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void changed();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QList<const QWidget*> widgets_;
|
|
||||||
QPushButton *submitButton_{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -140,11 +140,6 @@ QVariant NdpStatusModel::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::DropActions NdpStatusModel::supportedDropActions() const
|
|
||||||
{
|
|
||||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
|
||||||
}
|
|
||||||
|
|
||||||
void NdpStatusModel::setDeviceIndex(Port *port, int deviceIndex)
|
void NdpStatusModel::setDeviceIndex(Port *port, int deviceIndex)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
@ -40,8 +40,6 @@ public:
|
|||||||
int role = Qt::DisplayRole) const;
|
int role = Qt::DisplayRole) const;
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
|
||||||
Qt::DropActions supportedDropActions() const;
|
|
||||||
|
|
||||||
void setDeviceIndex(Port *port, int deviceIndex);
|
void setDeviceIndex(Port *port, int deviceIndex);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
@ -3,46 +3,47 @@ CONFIG += qt ver_info
|
|||||||
macx: TARGET = Ostinato
|
macx: TARGET = Ostinato
|
||||||
win32:RC_FILE = ostinato.rc
|
win32:RC_FILE = ostinato.rc
|
||||||
macx:ICON = icons/logo.icns
|
macx:ICON = icons/logo.icns
|
||||||
QT += widgets network script xml svg
|
QT += widgets network script xml
|
||||||
INCLUDEPATH += "../rpc/" "../common/"
|
INCLUDEPATH += "../rpc/" "../common/"
|
||||||
|
|
||||||
OBJDIR = .
|
|
||||||
win32 {
|
win32 {
|
||||||
QMAKE_LFLAGS += -static
|
QMAKE_LFLAGS += -static
|
||||||
CONFIG(debug, debug|release) {
|
CONFIG(debug, debug|release) {
|
||||||
OBJDIR = debug
|
LIBS += -L"../common/debug" -lostprotogui -lostproto
|
||||||
|
LIBS += -L"../rpc/debug" -lpbrpc
|
||||||
|
POST_TARGETDEPS += \
|
||||||
|
"../common/debug/libostprotogui.a" \
|
||||||
|
"../common/debug/libostproto.a" \
|
||||||
|
"../rpc/debug/libpbrpc.a"
|
||||||
} else {
|
} else {
|
||||||
OBJDIR = release
|
LIBS += -L"../common/release" -lostprotogui -lostproto
|
||||||
|
LIBS += -L"../rpc/release" -lpbrpc
|
||||||
|
POST_TARGETDEPS += \
|
||||||
|
"../common/release/libostprotogui.a" \
|
||||||
|
"../common/release/libostproto.a" \
|
||||||
|
"../rpc/release/libpbrpc.a"
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
LIBS += -L"../common" -lostprotogui -lostproto
|
||||||
|
LIBS += -L"../rpc" -lpbrpc
|
||||||
|
POST_TARGETDEPS += \
|
||||||
|
"../common/libostprotogui.a" \
|
||||||
|
"../common/libostproto.a" \
|
||||||
|
"../rpc/libpbrpc.a"
|
||||||
}
|
}
|
||||||
LIBS += -L"../common/$$OBJDIR" -lostfile -lostfilegui
|
|
||||||
LIBS += -L"../common/$$OBJDIR" -lostprotogui -lostproto
|
|
||||||
LIBS += -L"../rpc/$$OBJDIR" -lpbrpc
|
|
||||||
POST_TARGETDEPS += \
|
|
||||||
"../common/$$OBJDIR/libostfilegui.a" \
|
|
||||||
"../common/$$OBJDIR/libostfile.a" \
|
|
||||||
"../common/$$OBJDIR/libostprotogui.a" \
|
|
||||||
"../common/$$OBJDIR/libostproto.a" \
|
|
||||||
"../rpc/$$OBJDIR/libpbrpc.a"
|
|
||||||
|
|
||||||
LIBS += -lprotobuf
|
LIBS += -lprotobuf
|
||||||
LIBS += -L"../extra/qhexedit2/$(OBJECTS_DIR)/" -lqhexedit2
|
LIBS += -L"../extra/qhexedit2/$(OBJECTS_DIR)/" -lqhexedit2
|
||||||
RESOURCES += ostinato.qrc
|
RESOURCES += ostinato.qrc
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
arpstatusmodel.h \
|
arpstatusmodel.h \
|
||||||
clipboardhelper.h \
|
|
||||||
devicegroupdialog.h \
|
devicegroupdialog.h \
|
||||||
devicegroupmodel.h \
|
devicegroupmodel.h \
|
||||||
devicemodel.h \
|
devicemodel.h \
|
||||||
deviceswidget.h \
|
deviceswidget.h \
|
||||||
dumpview.h \
|
dumpview.h \
|
||||||
fieldedit.h \
|
|
||||||
hexlineedit.h \
|
hexlineedit.h \
|
||||||
logsmodel.h \
|
logsmodel.h \
|
||||||
logswindow.h \
|
logswindow.h \
|
||||||
findreplace.h \
|
|
||||||
mainwindow.h \
|
mainwindow.h \
|
||||||
mandatoryfieldsgroup.h \
|
|
||||||
ndpstatusmodel.h \
|
ndpstatusmodel.h \
|
||||||
packetmodel.h \
|
packetmodel.h \
|
||||||
port.h \
|
port.h \
|
||||||
@ -55,7 +56,6 @@ HEADERS += \
|
|||||||
portstatsproxymodel.h \
|
portstatsproxymodel.h \
|
||||||
portstatswindow.h \
|
portstatswindow.h \
|
||||||
portswindow.h \
|
portswindow.h \
|
||||||
portwidget.h \
|
|
||||||
preferences.h \
|
preferences.h \
|
||||||
settings.h \
|
settings.h \
|
||||||
streamconfigdialog.h \
|
streamconfigdialog.h \
|
||||||
@ -64,31 +64,25 @@ HEADERS += \
|
|||||||
streamstatsfiltermodel.h \
|
streamstatsfiltermodel.h \
|
||||||
streamstatsmodel.h \
|
streamstatsmodel.h \
|
||||||
streamstatswindow.h \
|
streamstatswindow.h \
|
||||||
streamswidget.h \
|
variablefieldswidget.h
|
||||||
variablefieldswidget.h \
|
|
||||||
xtableview.h
|
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
about.ui \
|
about.ui \
|
||||||
devicegroupdialog.ui \
|
devicegroupdialog.ui \
|
||||||
deviceswidget.ui \
|
deviceswidget.ui \
|
||||||
findreplace.ui \
|
|
||||||
logswindow.ui \
|
logswindow.ui \
|
||||||
mainwindow.ui \
|
mainwindow.ui \
|
||||||
portconfigdialog.ui \
|
portconfigdialog.ui \
|
||||||
portstatsfilter.ui \
|
portstatsfilter.ui \
|
||||||
portstatswindow.ui \
|
portstatswindow.ui \
|
||||||
portswindow.ui \
|
portswindow.ui \
|
||||||
portwidget.ui \
|
|
||||||
preferences.ui \
|
preferences.ui \
|
||||||
streamconfigdialog.ui \
|
streamconfigdialog.ui \
|
||||||
streamstatswindow.ui \
|
streamstatswindow.ui \
|
||||||
streamswidget.ui \
|
|
||||||
variablefieldswidget.ui
|
variablefieldswidget.ui
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
arpstatusmodel.cpp \
|
arpstatusmodel.cpp \
|
||||||
clipboardhelper.cpp \
|
|
||||||
devicegroupdialog.cpp \
|
devicegroupdialog.cpp \
|
||||||
devicegroupmodel.cpp \
|
devicegroupmodel.cpp \
|
||||||
devicemodel.cpp \
|
devicemodel.cpp \
|
||||||
@ -98,11 +92,8 @@ SOURCES += \
|
|||||||
hexlineedit.cpp \
|
hexlineedit.cpp \
|
||||||
logsmodel.cpp \
|
logsmodel.cpp \
|
||||||
logswindow.cpp \
|
logswindow.cpp \
|
||||||
fieldedit.cpp \
|
|
||||||
findreplace.cpp \
|
|
||||||
main.cpp \
|
main.cpp \
|
||||||
mainwindow.cpp \
|
mainwindow.cpp \
|
||||||
mandatoryfieldsgroup.cpp \
|
|
||||||
ndpstatusmodel.cpp \
|
ndpstatusmodel.cpp \
|
||||||
packetmodel.cpp \
|
packetmodel.cpp \
|
||||||
params.cpp \
|
params.cpp \
|
||||||
@ -115,31 +106,18 @@ SOURCES += \
|
|||||||
portstatsfilterdialog.cpp \
|
portstatsfilterdialog.cpp \
|
||||||
portstatswindow.cpp \
|
portstatswindow.cpp \
|
||||||
portswindow.cpp \
|
portswindow.cpp \
|
||||||
portwidget.cpp \
|
|
||||||
preferences.cpp \
|
preferences.cpp \
|
||||||
streamconfigdialog.cpp \
|
streamconfigdialog.cpp \
|
||||||
streamlistdelegate.cpp \
|
streamlistdelegate.cpp \
|
||||||
streammodel.cpp \
|
streammodel.cpp \
|
||||||
streamstatsmodel.cpp \
|
streamstatsmodel.cpp \
|
||||||
streamstatswindow.cpp \
|
streamstatswindow.cpp \
|
||||||
streamswidget.cpp \
|
|
||||||
thememanager.cpp \
|
|
||||||
variablefieldswidget.cpp
|
variablefieldswidget.cpp
|
||||||
|
|
||||||
THEMES += \
|
|
||||||
themes/material-dark.qss \
|
|
||||||
themes/material-dark.rcc \
|
|
||||||
themes/material-light.qss \
|
|
||||||
themes/material-light.rcc \
|
|
||||||
themes/qds-dark.qss \
|
|
||||||
themes/qds-dark.rcc \
|
|
||||||
themes/qds-light.qss \
|
|
||||||
themes/qds-light.rcc \
|
|
||||||
|
|
||||||
QMAKE_DISTCLEAN += object_script.*
|
QMAKE_DISTCLEAN += object_script.*
|
||||||
|
|
||||||
include(../install.pri)
|
include(../install.pri)
|
||||||
include(../shared.pri)
|
|
||||||
include(../version.pri)
|
include(../version.pri)
|
||||||
include(../options.pri)
|
include(../options.pri)
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<RCC>
|
<RCC>
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>icons/find.png</file>
|
|
||||||
<file>icons/info.png</file>
|
|
||||||
<file>icons/about.png</file>
|
<file>icons/about.png</file>
|
||||||
<file>icons/add.png</file>
|
<file>icons/add.png</file>
|
||||||
<file>icons/anime_error.gif</file>
|
<file>icons/anime_error.gif</file>
|
||||||
@ -16,16 +14,13 @@
|
|||||||
<file>icons/bullet_red.png</file>
|
<file>icons/bullet_red.png</file>
|
||||||
<file>icons/bullet_white.png</file>
|
<file>icons/bullet_white.png</file>
|
||||||
<file>icons/bullet_yellow.png</file>
|
<file>icons/bullet_yellow.png</file>
|
||||||
<file>icons/copy.png</file>
|
|
||||||
<file>icons/control_play.png</file>
|
<file>icons/control_play.png</file>
|
||||||
<file>icons/control_stop.png</file>
|
<file>icons/control_stop.png</file>
|
||||||
<file>icons/cut.png</file>
|
|
||||||
<file>icons/delete.png</file>
|
<file>icons/delete.png</file>
|
||||||
<file>icons/devicegroup_add.png</file>
|
<file>icons/devicegroup_add.png</file>
|
||||||
<file>icons/devicegroup_delete.png</file>
|
<file>icons/devicegroup_delete.png</file>
|
||||||
<file>icons/devicegroup_edit.png</file>
|
<file>icons/devicegroup_edit.png</file>
|
||||||
<file>icons/donate.png</file>
|
<file>icons/donate.png</file>
|
||||||
<file>icons/error.svg</file>
|
|
||||||
<file>icons/exit.png</file>
|
<file>icons/exit.png</file>
|
||||||
<file>icons/frag_capture.png</file>
|
<file>icons/frag_capture.png</file>
|
||||||
<file>icons/frag_exclusive.png</file>
|
<file>icons/frag_exclusive.png</file>
|
||||||
@ -40,7 +35,6 @@
|
|||||||
<file>icons/name.png</file>
|
<file>icons/name.png</file>
|
||||||
<file>icons/neighbor_clear.png</file>
|
<file>icons/neighbor_clear.png</file>
|
||||||
<file>icons/neighbor_resolve.png</file>
|
<file>icons/neighbor_resolve.png</file>
|
||||||
<file>icons/paste.png</file>
|
|
||||||
<file>icons/portgroup_add.png</file>
|
<file>icons/portgroup_add.png</file>
|
||||||
<file>icons/portgroup_connect.png</file>
|
<file>icons/portgroup_connect.png</file>
|
||||||
<file>icons/portgroup_delete.png</file>
|
<file>icons/portgroup_delete.png</file>
|
||||||
@ -59,6 +53,5 @@
|
|||||||
<file>icons/stream_edit.png</file>
|
<file>icons/stream_edit.png</file>
|
||||||
<file>icons/stream_stats.png</file>
|
<file>icons/stream_stats.png</file>
|
||||||
<file>icons/transmit_on.png</file>
|
<file>icons/transmit_on.png</file>
|
||||||
<file>icons/warn.svg</file>
|
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@ -243,9 +243,3 @@ QVariant PacketModel::data(const QModelIndex &index, int role) const
|
|||||||
|
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::DropActions PacketModel::supportedDropActions() const
|
|
||||||
{
|
|
||||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -42,7 +42,6 @@ public:
|
|||||||
QModelIndex index (int row, int col, const QModelIndex & parent = QModelIndex() ) const;
|
QModelIndex index (int row, int col, const QModelIndex & parent = QModelIndex() ) const;
|
||||||
QModelIndex parent(const QModelIndex &index) const;
|
QModelIndex parent(const QModelIndex &index) const;
|
||||||
|
|
||||||
Qt::DropActions supportedDropActions() const;
|
|
||||||
private:
|
private:
|
||||||
typedef union _IndexId
|
typedef union _IndexId
|
||||||
{
|
{
|
||||||
|
@ -45,11 +45,11 @@ int Params::parseCommandLine(int argc, char* argv[])
|
|||||||
logsDisabled_ = false;
|
logsDisabled_ = false;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
printf("Ostinato %s rev %s\n", version, revision);
|
qDebug("Ostinato %s rev %s\n", version, revision);
|
||||||
exit(0);
|
exit(0);
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
printf("usage: %s [-cdhv]\n", argv[0]);
|
qDebug("usage: %s [-cdhv]\n", argv[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
n++;
|
n++;
|
||||||
|
@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "port.h"
|
#include "port.h"
|
||||||
|
|
||||||
#include "emulation.h"
|
#include "emulation.h"
|
||||||
#include "fileformatoptions.h"
|
|
||||||
#include "streamfileformat.h"
|
#include "streamfileformat.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@ -29,7 +28,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
#include <google/protobuf/descriptor.h>
|
#include <google/protobuf/descriptor.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
extern QMainWindow *mainWindow;
|
extern QMainWindow *mainWindow;
|
||||||
|
|
||||||
@ -89,10 +87,7 @@ void Port::updatePortConfig(OstProto::Port *port)
|
|||||||
setAlias(QString("if%1").arg(id()));
|
setAlias(QString("if%1").arg(id()));
|
||||||
|
|
||||||
if (recalc)
|
if (recalc)
|
||||||
{
|
|
||||||
recalculateAverageRates();
|
recalculateAverageRates();
|
||||||
emit streamListChanged(mPortGroupId, mPortId); // show/hide 'next' col
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Port::updateStreamOrdinalsFromIndex()
|
void Port::updateStreamOrdinalsFromIndex()
|
||||||
@ -103,7 +98,7 @@ void Port::updateStreamOrdinalsFromIndex()
|
|||||||
|
|
||||||
void Port::reorderStreamsByOrdinals()
|
void Port::reorderStreamsByOrdinals()
|
||||||
{
|
{
|
||||||
std::sort(mStreams.begin(), mStreams.end(), StreamBase::StreamLessThan);
|
qSort(mStreams.begin(), mStreams.end(), StreamBase::StreamLessThan);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Port::setDirty(bool dirty)
|
void Port::setDirty(bool dirty)
|
||||||
@ -192,11 +187,6 @@ void Port::setAveragePacketRate(double packetsPerSec)
|
|||||||
Q_ASSERT(false); // Unreachable!!
|
Q_ASSERT(false); // Unreachable!!
|
||||||
}
|
}
|
||||||
|
|
||||||
// if old avgPps is 0, new rate will be calculated as nan (infinity)
|
|
||||||
// because of divide by 0 (old avgPps) above - fix that
|
|
||||||
if (std::isnan(rate))
|
|
||||||
rate = packetsPerSec;
|
|
||||||
|
|
||||||
qDebug("cur stream pps = %g", s->averagePacketRate());
|
qDebug("cur stream pps = %g", s->averagePacketRate());
|
||||||
|
|
||||||
s->setAveragePacketRate(rate);
|
s->setAveragePacketRate(rate);
|
||||||
@ -271,11 +261,6 @@ void Port::setAverageBitRate(double bitsPerSec)
|
|||||||
Q_ASSERT(false); // Unreachable!!
|
Q_ASSERT(false); // Unreachable!!
|
||||||
}
|
}
|
||||||
|
|
||||||
// if old avgBps is 0, new rate will be calculated as nan (infinity)
|
|
||||||
// because of divide by 0 (old avgBps) above - fix that
|
|
||||||
if (std::isnan(rate))
|
|
||||||
rate = bitsPerSec/((s->frameLenAvg()+kEthOverhead)*8);
|
|
||||||
|
|
||||||
qDebug("cur stream pps = %g", s->averagePacketRate());
|
qDebug("cur stream pps = %g", s->averagePacketRate());
|
||||||
|
|
||||||
s->setAveragePacketRate(rate);
|
s->setAveragePacketRate(rate);
|
||||||
@ -318,12 +303,6 @@ void Port::setAverageBitRate(double bitsPerSec)
|
|||||||
emit portRateChanged(mPortGroupId, mPortId);
|
emit portRateChanged(mPortGroupId, mPortId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Port::setAverageLoadRate(double load)
|
|
||||||
{
|
|
||||||
Q_ASSERT(d.speed() > 0);
|
|
||||||
setAverageBitRate(load*d.speed()*1e6);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Port::newStreamAt(int index, OstProto::Stream const *stream)
|
bool Port::newStreamAt(int index, OstProto::Stream const *stream)
|
||||||
{
|
{
|
||||||
Stream *s = new Stream;
|
Stream *s = new Stream;
|
||||||
@ -516,11 +495,6 @@ bool Port::modifiablePortConfig(OstProto::Port &config) const
|
|||||||
modCfg.set_user_name(config.user_name());
|
modCfg.set_user_name(config.user_name());
|
||||||
change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
if (config.is_tracking_stream_stats() != d.is_tracking_stream_stats()) {
|
|
||||||
modCfg.set_is_tracking_stream_stats(config.is_tracking_stream_stats());
|
|
||||||
change = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (change) {
|
if (change) {
|
||||||
modCfg.mutable_port_id()->set_id(id());
|
modCfg.mutable_port_id()->set_id(id());
|
||||||
@ -605,11 +579,12 @@ bool Port::openStreams(QString fileName, bool append, QString &error)
|
|||||||
goto _fail;
|
goto _fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((optDialog = FileFormatOptions::openOptionsDialog(fmt)))
|
if ((optDialog = fmt->openOptionsDialog()))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
optDialog->setParent(mainWindow, Qt::Dialog);
|
optDialog->setParent(mainWindow, Qt::Dialog);
|
||||||
ret = optDialog->exec();
|
ret = optDialog->exec();
|
||||||
|
optDialog->setParent(0, Qt::Dialog);
|
||||||
if (ret == QDialog::Rejected)
|
if (ret == QDialog::Rejected)
|
||||||
goto _user_opt_cancel;
|
goto _user_opt_cancel;
|
||||||
}
|
}
|
||||||
|
@ -88,15 +88,8 @@ public:
|
|||||||
{ return d.port_id().id(); }
|
{ return d.port_id().id(); }
|
||||||
const QString name() const
|
const QString name() const
|
||||||
{ return QString().fromStdString(d.name()); }
|
{ return QString().fromStdString(d.name()); }
|
||||||
const QString systemDescription() const
|
|
||||||
{ return QString().fromStdString(d.description()); }
|
|
||||||
const QString userDescription() const
|
|
||||||
{ return QString().fromStdString(d.user_description()); }
|
|
||||||
const QString description() const
|
const QString description() const
|
||||||
{
|
{ return QString().fromStdString(d.description()); }
|
||||||
return userDescription().isEmpty() ?
|
|
||||||
systemDescription() : userDescription();
|
|
||||||
}
|
|
||||||
const QString notes() const
|
const QString notes() const
|
||||||
{ return QString().fromStdString(d.notes()); }
|
{ return QString().fromStdString(d.notes()); }
|
||||||
const QString userName() const
|
const QString userName() const
|
||||||
@ -109,10 +102,6 @@ public:
|
|||||||
{ return d.transmit_mode(); }
|
{ return d.transmit_mode(); }
|
||||||
bool trackStreamStats() const
|
bool trackStreamStats() const
|
||||||
{ return d.is_tracking_stream_stats(); }
|
{ return d.is_tracking_stream_stats(); }
|
||||||
double speed() const
|
|
||||||
{ return d.speed(); }
|
|
||||||
double averageLoadRate() const
|
|
||||||
{ return d.speed() ? avgBitsPerSec_/(d.speed()*1e6) : 0; }
|
|
||||||
double averagePacketRate() const
|
double averagePacketRate() const
|
||||||
{ return avgPacketsPerSec_; }
|
{ return avgPacketsPerSec_; }
|
||||||
double averageBitRate() const
|
double averageBitRate() const
|
||||||
@ -194,7 +183,6 @@ public:
|
|||||||
|
|
||||||
void setAveragePacketRate(double packetsPerSec);
|
void setAveragePacketRate(double packetsPerSec);
|
||||||
void setAverageBitRate(double bitsPerSec);
|
void setAverageBitRate(double bitsPerSec);
|
||||||
void setAverageLoadRate(double loadPercent);
|
|
||||||
// FIXME(MED): Bad Hack! port should not need an external trigger to
|
// FIXME(MED): Bad Hack! port should not need an external trigger to
|
||||||
// recalculate - refactor client side domain objects and model objects
|
// recalculate - refactor client side domain objects and model objects
|
||||||
void recalculateAverageRates();
|
void recalculateAverageRates();
|
||||||
|
@ -32,8 +32,6 @@ PortConfigDialog::PortConfigDialog(
|
|||||||
|
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
|
||||||
description->setPlaceholderText(portConfig_.description().c_str());
|
|
||||||
description->setText(portConfig_.user_description().c_str());
|
|
||||||
switch(portConfig_.transmit_mode())
|
switch(portConfig_.transmit_mode())
|
||||||
{
|
{
|
||||||
case OstProto::kSequentialTransmit:
|
case OstProto::kSequentialTransmit:
|
||||||
@ -82,8 +80,6 @@ void PortConfigDialog::accept()
|
|||||||
{
|
{
|
||||||
OstProto::Port pc;
|
OstProto::Port pc;
|
||||||
|
|
||||||
pc.set_user_description(description->text().toStdString());
|
|
||||||
|
|
||||||
if (sequentialStreamsButton->isChecked())
|
if (sequentialStreamsButton->isChecked())
|
||||||
pc.set_transmit_mode(OstProto::kSequentialTransmit);
|
pc.set_transmit_mode(OstProto::kSequentialTransmit);
|
||||||
else if (interleavedStreamsButton->isChecked())
|
else if (interleavedStreamsButton->isChecked())
|
||||||
@ -91,7 +87,6 @@ void PortConfigDialog::accept()
|
|||||||
else
|
else
|
||||||
Q_ASSERT(false); // Unreachable!!!
|
Q_ASSERT(false); // Unreachable!!!
|
||||||
|
|
||||||
pc.set_user_name(portConfig_.user_name());
|
|
||||||
switch (reservedBy_) {
|
switch (reservedBy_) {
|
||||||
case kSelf:
|
case kSelf:
|
||||||
if (!reserveButton->isChecked())
|
if (!reserveButton->isChecked())
|
||||||
@ -113,11 +108,6 @@ void PortConfigDialog::accept()
|
|||||||
pc.set_is_tracking_stream_stats(streamStatsButton->isChecked());
|
pc.set_is_tracking_stream_stats(streamStatsButton->isChecked());
|
||||||
|
|
||||||
// Update fields that have changed, clear the rest
|
// Update fields that have changed, clear the rest
|
||||||
if (pc.user_description() != portConfig_.user_description())
|
|
||||||
portConfig_.set_user_description(pc.user_description());
|
|
||||||
else
|
|
||||||
portConfig_.clear_user_description();
|
|
||||||
|
|
||||||
if (pc.transmit_mode() != portConfig_.transmit_mode())
|
if (pc.transmit_mode() != portConfig_.transmit_mode())
|
||||||
portConfig_.set_transmit_mode(pc.transmit_mode());
|
portConfig_.set_transmit_mode(pc.transmit_mode());
|
||||||
else
|
else
|
||||||
|
@ -1,51 +1,37 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<ui version="4.0" >
|
||||||
<ui version="4.0">
|
|
||||||
<class>PortConfigDialog</class>
|
<class>PortConfigDialog</class>
|
||||||
<widget class="QDialog" name="PortConfigDialog">
|
<widget class="QDialog" name="PortConfigDialog" >
|
||||||
<property name="geometry">
|
<property name="geometry" >
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>248</width>
|
<width>244</width>
|
||||||
<height>292</height>
|
<height>257</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle" >
|
||||||
<string>Port Config</string>
|
<string>Port Config</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout" >
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QGroupBox" name="transmitModeBox" >
|
||||||
<property name="text">
|
<property name="title" >
|
||||||
<string>Description</string>
|
|
||||||
</property>
|
|
||||||
<property name="buddy">
|
|
||||||
<cstring>description</cstring>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="description"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="transmitModeBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>Transmit Mode</string>
|
<string>Transmit Mode</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout" >
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="sequentialStreamsButton">
|
<widget class="QRadioButton" name="sequentialStreamsButton" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>Sequential Streams</string>
|
<string>Sequential Streams</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checked">
|
<property name="checked" >
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="interleavedStreamsButton">
|
<widget class="QRadioButton" name="interleavedStreamsButton" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>Interleaved Streams</string>
|
<string>Interleaved Streams</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -54,21 +40,21 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox" >
|
||||||
<property name="title">
|
<property name="title" >
|
||||||
<string>Reservation</string>
|
<string>Reservation</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout" >
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="reservedBy">
|
<widget class="QLabel" name="reservedBy" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>Reserved by: </string>
|
<string>Reserved by: </string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="reserveButton">
|
<widget class="QCheckBox" name="reserveButton" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>Reserve</string>
|
<string>Reserve</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -77,25 +63,25 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="exclusiveControlButton">
|
<widget class="QCheckBox" name="exclusiveControlButton" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>Exclusive Control</string>
|
<string>Exclusive Control</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="streamStatsButton">
|
<widget class="QCheckBox" name="streamStatsButton" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>Stream Statistics</string>
|
<string>Stream Statistics</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation">
|
<property name="orientation" >
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" >
|
||||||
<size>
|
<size>
|
||||||
<width>226</width>
|
<width>226</width>
|
||||||
<height>71</height>
|
<height>71</height>
|
||||||
@ -104,25 +90,17 @@
|
|||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||||
<property name="orientation">
|
<property name="orientation" >
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="standardButtons">
|
<property name="standardButtons" >
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<tabstops>
|
|
||||||
<tabstop>description</tabstop>
|
|
||||||
<tabstop>sequentialStreamsButton</tabstop>
|
|
||||||
<tabstop>interleavedStreamsButton</tabstop>
|
|
||||||
<tabstop>reserveButton</tabstop>
|
|
||||||
<tabstop>exclusiveControlButton</tabstop>
|
|
||||||
<tabstop>streamStatsButton</tabstop>
|
|
||||||
</tabstops>
|
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
@ -131,11 +109,11 @@
|
|||||||
<receiver>PortConfigDialog</receiver>
|
<receiver>PortConfigDialog</receiver>
|
||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel" >
|
||||||
<x>234</x>
|
<x>234</x>
|
||||||
<y>205</y>
|
<y>205</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel" >
|
||||||
<x>157</x>
|
<x>157</x>
|
||||||
<y>214</y>
|
<y>214</y>
|
||||||
</hint>
|
</hint>
|
||||||
@ -147,11 +125,11 @@
|
|||||||
<receiver>PortConfigDialog</receiver>
|
<receiver>PortConfigDialog</receiver>
|
||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel" >
|
||||||
<x>234</x>
|
<x>234</x>
|
||||||
<y>205</y>
|
<y>205</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel" >
|
||||||
<x>243</x>
|
<x>243</x>
|
||||||
<y>214</y>
|
<y>214</y>
|
||||||
</hint>
|
</hint>
|
||||||
|
@ -206,7 +206,6 @@ void PortGroup::processVersionCompatibility(PbRpcController *controller)
|
|||||||
logError(id(), QString("checkVersion failed: %1")
|
logError(id(), QString("checkVersion failed: %1")
|
||||||
.arg(QString::fromStdString(verCompat->notes())));
|
.arg(QString::fromStdString(verCompat->notes())));
|
||||||
compat = kIncompatible;
|
compat = kIncompatible;
|
||||||
reconnect = false;
|
|
||||||
emit portGroupDataChanged(mPortGroupId);
|
emit portGroupDataChanged(mPortGroupId);
|
||||||
|
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
@ -242,8 +241,7 @@ _error_exit:
|
|||||||
|
|
||||||
void PortGroup::on_rpcChannel_disconnected()
|
void PortGroup::on_rpcChannel_disconnected()
|
||||||
{
|
{
|
||||||
qDebug("disconnected %s:%u",
|
qDebug("disconnected\n");
|
||||||
qPrintable(rpcChannel->serverName()), rpcChannel->serverPort());
|
|
||||||
logError(id(), "PortGroup disconnected");
|
logError(id(), "PortGroup disconnected");
|
||||||
emit portListAboutToBeChanged(mPortGroupId);
|
emit portListAboutToBeChanged(mPortGroupId);
|
||||||
|
|
||||||
@ -254,16 +252,6 @@ void PortGroup::on_rpcChannel_disconnected()
|
|||||||
emit portListChanged(mPortGroupId);
|
emit portListChanged(mPortGroupId);
|
||||||
emit portGroupDataChanged(mPortGroupId);
|
emit portGroupDataChanged(mPortGroupId);
|
||||||
|
|
||||||
// Disconnected during apply? Restore UI.
|
|
||||||
if (applyTimer_.isValid()) {
|
|
||||||
applyTimer_.invalidate();
|
|
||||||
|
|
||||||
emit applyFinished();
|
|
||||||
|
|
||||||
mainWindow->setEnabled(true);
|
|
||||||
QApplication::restoreOverrideCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
isGetStatsPending_ = false;
|
isGetStatsPending_ = false;
|
||||||
|
|
||||||
if (reconnect)
|
if (reconnect)
|
||||||
@ -277,24 +265,11 @@ void PortGroup::on_rpcChannel_disconnected()
|
|||||||
|
|
||||||
void PortGroup::on_rpcChannel_error(QAbstractSocket::SocketError socketError)
|
void PortGroup::on_rpcChannel_error(QAbstractSocket::SocketError socketError)
|
||||||
{
|
{
|
||||||
qDebug("%s: error %d %s:%u", __FUNCTION__, socketError,
|
qDebug("%s: error %d", __FUNCTION__, socketError);
|
||||||
qPrintable(rpcChannel->serverName()), rpcChannel->serverPort());
|
|
||||||
emit portGroupDataChanged(mPortGroupId);
|
emit portGroupDataChanged(mPortGroupId);
|
||||||
|
|
||||||
switch(socketError)
|
if (socketError == QAbstractSocket::RemoteHostClosedError)
|
||||||
{
|
|
||||||
case QAbstractSocket::SslInvalidUserDataError: // actually abort()
|
|
||||||
logWarn(id(), QString("Bad data received from portgroup, "
|
|
||||||
"aborting connection; "
|
|
||||||
"who is listening on %1:%2 "
|
|
||||||
" - is it drone or some other process?")
|
|
||||||
.arg(rpcChannel->serverName())
|
|
||||||
.arg(rpcChannel->serverPort()));
|
|
||||||
reconnect = false;
|
reconnect = false;
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug("%s: state %d", __FUNCTION__, rpcChannel->state());
|
qDebug("%s: state %d", __FUNCTION__, rpcChannel->state());
|
||||||
if ((rpcChannel->state() == QAbstractSocket::UnconnectedState) && reconnect)
|
if ((rpcChannel->state() == QAbstractSocket::UnconnectedState) && reconnect)
|
||||||
@ -826,7 +801,6 @@ void PortGroup::processApplyBuildAck(int portIndex, PbRpcController *controller)
|
|||||||
logInfo(id(), mPorts[portIndex]->id(),
|
logInfo(id(), mPorts[portIndex]->id(),
|
||||||
QString("All port changes applied - in %1s")
|
QString("All port changes applied - in %1s")
|
||||||
.arg(applyTimer_.elapsed()/1e3));
|
.arg(applyTimer_.elapsed()/1e3));
|
||||||
applyTimer_.invalidate();
|
|
||||||
|
|
||||||
if (controller->Failed())
|
if (controller->Failed())
|
||||||
{
|
{
|
||||||
@ -1111,11 +1085,8 @@ void PortGroup::processStreamIdList(int portIndex, PbRpcController *controller)
|
|||||||
// * modify (new) deviceGroups
|
// * modify (new) deviceGroups
|
||||||
// * add (new) stream ids
|
// * add (new) stream ids
|
||||||
// * modify (new) streams
|
// * modify (new) streams
|
||||||
// * resolve neighbors
|
|
||||||
// * build packets
|
|
||||||
// XXX: This assumes getDeviceGroupIdList() was invoked before
|
// XXX: This assumes getDeviceGroupIdList() was invoked before
|
||||||
// getStreamIdList() - if the order changes this code will break!
|
// getStreamIdList() - if the order changes this code will break!
|
||||||
// XXX: See resolve/build notes below
|
|
||||||
|
|
||||||
// XXX: same name as input param, but shouldn't cause any problem
|
// XXX: same name as input param, but shouldn't cause any problem
|
||||||
PbRpcController *controller;
|
PbRpcController *controller;
|
||||||
@ -1156,7 +1127,6 @@ void PortGroup::processStreamIdList(int portIndex, PbRpcController *controller)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add/modify deviceGroups
|
// add/modify deviceGroups
|
||||||
bool resolve = false;
|
|
||||||
if (newPortContent->device_groups_size())
|
if (newPortContent->device_groups_size())
|
||||||
{
|
{
|
||||||
OstProto::DeviceGroupIdList *deviceGroupIdList
|
OstProto::DeviceGroupIdList *deviceGroupIdList
|
||||||
@ -1188,7 +1158,6 @@ void PortGroup::processStreamIdList(int portIndex, PbRpcController *controller)
|
|||||||
deviceGroupConfigList, ack,
|
deviceGroupConfigList, ack,
|
||||||
NewCallback(this, &PortGroup::processModifyDeviceGroupAck,
|
NewCallback(this, &PortGroup::processModifyDeviceGroupAck,
|
||||||
portIndex, controller));
|
portIndex, controller));
|
||||||
resolve = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// add/modify streams
|
// add/modify streams
|
||||||
@ -1219,26 +1188,6 @@ void PortGroup::processStreamIdList(int portIndex, PbRpcController *controller)
|
|||||||
serviceStub->modifyStream(controller, streamConfigList, ack,
|
serviceStub->modifyStream(controller, streamConfigList, ack,
|
||||||
NewCallback(this, &PortGroup::processModifyStreamAck,
|
NewCallback(this, &PortGroup::processModifyStreamAck,
|
||||||
portIndex, controller));
|
portIndex, controller));
|
||||||
resolve = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: Ideally resolve and build should be called after **all**
|
|
||||||
// ports and portgroups are configured. As of now, any resolve
|
|
||||||
// replied to by ports/portgroups configured later in the open
|
|
||||||
// session sequence will fail.
|
|
||||||
// However, to do that, we may need to rethink the open session
|
|
||||||
// implementation - so going with this for now
|
|
||||||
if (resolve)
|
|
||||||
{
|
|
||||||
OstProto::PortIdList *portIdList = new OstProto::PortIdList;
|
|
||||||
portIdList->add_port_id()->set_id(portId);
|
|
||||||
OstProto::Ack *ack = new OstProto::Ack;
|
|
||||||
controller = new PbRpcController(portIdList, ack);
|
|
||||||
serviceStub->resolveDeviceNeighbors(controller, portIdList, ack,
|
|
||||||
NewCallback(this,
|
|
||||||
&PortGroup::processResolveDeviceNeighborsAck,
|
|
||||||
controller));
|
|
||||||
resolve = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// build packets using the new config
|
// build packets using the new config
|
||||||
@ -2052,12 +2001,9 @@ bool PortGroup::getStreamStats(QList<uint> *portList)
|
|||||||
if (portList == NULL)
|
if (portList == NULL)
|
||||||
guidList->mutable_port_id_list()->CopyFrom(*portIdList_);
|
guidList->mutable_port_id_list()->CopyFrom(*portIdList_);
|
||||||
else
|
else
|
||||||
for (int i = 0; i < portList->size(); i++) {
|
for (int i = 0; i < portList->size(); i++)
|
||||||
guidList->mutable_port_id_list()->add_port_id()
|
guidList->mutable_port_id_list()->add_port_id()
|
||||||
->set_id(portList->at(i));
|
->set_id(portList->at(i));
|
||||||
if (mPorts.at(i)->isTransmitting())
|
|
||||||
logWarn(id(), i, "Port is still transmitting - stream stats may be unavailable or incomplete");
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceStub->getStreamStats(controller, guidList, statsList,
|
serviceStub->getStreamStats(controller, guidList, statsList,
|
||||||
NewCallback(this, &PortGroup::processStreamStatsList, controller));
|
NewCallback(this, &PortGroup::processStreamStatsList, controller));
|
||||||
|
@ -68,7 +68,6 @@ bool PortGroupList::isPort(const QModelIndex& index)
|
|||||||
|
|
||||||
PortGroup& PortGroupList::portGroup(const QModelIndex& index)
|
PortGroup& PortGroupList::portGroup(const QModelIndex& index)
|
||||||
{
|
{
|
||||||
Q_ASSERT(index.isValid());
|
|
||||||
Q_ASSERT(mPortGroupListModel.isPortGroup(index));
|
Q_ASSERT(mPortGroupListModel.isPortGroup(index));
|
||||||
|
|
||||||
return *(mPortGroups[index.row()]);
|
return *(mPortGroups[index.row()]);
|
||||||
@ -76,8 +75,6 @@ PortGroup& PortGroupList::portGroup(const QModelIndex& index)
|
|||||||
|
|
||||||
Port& PortGroupList::port(const QModelIndex& index)
|
Port& PortGroupList::port(const QModelIndex& index)
|
||||||
{
|
{
|
||||||
Q_ASSERT(index.isValid());
|
|
||||||
Q_ASSERT(index.parent().isValid());
|
|
||||||
Q_ASSERT(mPortGroupListModel.isPort(index));
|
Q_ASSERT(mPortGroupListModel.isPort(index));
|
||||||
return (*mPortGroups.at(index.parent().row())->mPorts[index.row()]);
|
return (*mPortGroups.at(index.parent().row())->mPorts[index.row()]);
|
||||||
}
|
}
|
||||||
@ -100,9 +97,6 @@ void PortGroupList::addPortGroup(PortGroup &portGroup)
|
|||||||
connect(&portGroup, SIGNAL(portListChanged(quint32)),
|
connect(&portGroup, SIGNAL(portListChanged(quint32)),
|
||||||
&mPortStatsModel, SLOT(when_portListChanged()));
|
&mPortStatsModel, SLOT(when_portListChanged()));
|
||||||
|
|
||||||
connect(&portGroup, SIGNAL(portGroupDataChanged(int, int)),
|
|
||||||
&mPortStatsModel, SLOT(when_portGroupDataChanged(int, int)));
|
|
||||||
|
|
||||||
connect(&portGroup, SIGNAL(statsChanged(quint32)),
|
connect(&portGroup, SIGNAL(statsChanged(quint32)),
|
||||||
&mPortStatsModel, SLOT(when_portGroup_stats_update(quint32)));
|
&mPortStatsModel, SLOT(when_portGroup_stats_update(quint32)));
|
||||||
|
|
||||||
@ -116,10 +110,8 @@ void PortGroupList::addPortGroup(PortGroup &portGroup)
|
|||||||
|
|
||||||
void PortGroupList::removePortGroup(PortGroup &portGroup)
|
void PortGroupList::removePortGroup(PortGroup &portGroup)
|
||||||
{
|
{
|
||||||
// Disconnect before removing from list
|
|
||||||
portGroup.disconnectFromHost();
|
|
||||||
|
|
||||||
mPortGroupListModel.portGroupAboutToBeRemoved(&portGroup);
|
mPortGroupListModel.portGroupAboutToBeRemoved(&portGroup);
|
||||||
|
|
||||||
PortGroup* pg = mPortGroups.takeAt(mPortGroups.indexOf(&portGroup));
|
PortGroup* pg = mPortGroups.takeAt(mPortGroups.indexOf(&portGroup));
|
||||||
qDebug("after takeAt()");
|
qDebug("after takeAt()");
|
||||||
mPortGroupListModel.portGroupRemoved();
|
mPortGroupListModel.portGroupRemoved();
|
||||||
@ -136,12 +128,11 @@ void PortGroupList::removeAllPortGroups()
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
PortGroup *pg = mPortGroups.at(0);
|
PortGroup *pg = mPortGroups.at(0);
|
||||||
pg->disconnectFromHost();
|
|
||||||
mPortGroupListModel.portGroupAboutToBeRemoved(pg);
|
mPortGroupListModel.portGroupAboutToBeRemoved(pg);
|
||||||
mPortGroups.removeFirst();
|
mPortGroups.removeFirst();
|
||||||
delete pg;
|
delete pg;
|
||||||
mPortGroupListModel.portGroupRemoved();
|
|
||||||
} while (!mPortGroups.isEmpty());
|
} while (!mPortGroups.isEmpty());
|
||||||
|
mPortGroupListModel.portGroupRemoved();
|
||||||
|
|
||||||
mPortGroupListModel.when_portListChanged();
|
mPortGroupListModel.when_portListChanged();
|
||||||
mPortStatsModel.when_portListChanged();
|
mPortStatsModel.when_portListChanged();
|
||||||
|
@ -200,11 +200,6 @@ QVariant PortModel::headerData(int /*section*/, Qt::Orientation orientation, int
|
|||||||
return QString("Name");
|
return QString("Name");
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::DropActions PortModel::supportedDropActions() const
|
|
||||||
{
|
|
||||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
|
||||||
}
|
|
||||||
|
|
||||||
QModelIndex PortModel::index (int row, int col,
|
QModelIndex PortModel::index (int row, int col,
|
||||||
const QModelIndex & parent) const
|
const QModelIndex & parent) const
|
||||||
{
|
{
|
||||||
|
@ -45,8 +45,6 @@ public:
|
|||||||
const QModelIndex &parent = QModelIndex()) const;
|
const QModelIndex &parent = QModelIndex()) const;
|
||||||
QModelIndex parent(const QModelIndex &index) const;
|
QModelIndex parent(const QModelIndex &index) const;
|
||||||
|
|
||||||
Qt::DropActions supportedDropActions() const;
|
|
||||||
|
|
||||||
bool isPortGroup(const QModelIndex& index);
|
bool isPortGroup(const QModelIndex& index);
|
||||||
bool isPort(const QModelIndex& index);
|
bool isPort(const QModelIndex& index);
|
||||||
quint32 portGroupId(const QModelIndex& index);
|
quint32 portGroupId(const QModelIndex& index);
|
||||||
|
@ -49,8 +49,7 @@ QList<uint> PortStatsFilterDialog::getItemList(bool* ok,
|
|||||||
{
|
{
|
||||||
QStandardItem *item;
|
QStandardItem *item;
|
||||||
|
|
||||||
item = new QStandardItem(model->headerData(i, orientation)
|
item = new QStandardItem(model->headerData(i, orientation).toString());
|
||||||
.toString().replace('\n', ' '));
|
|
||||||
item->setData(i, kLogicalIndex);
|
item->setData(i, kLogicalIndex);
|
||||||
item->setData(initial.indexOf(i), kVisualIndex);
|
item->setData(initial.indexOf(i), kVisualIndex);
|
||||||
item->setFlags(Qt::ItemIsSelectable
|
item->setFlags(Qt::ItemIsSelectable
|
||||||
@ -88,7 +87,7 @@ void PortStatsFilterDialog::on_tbSelectIn_clicked()
|
|||||||
|
|
||||||
foreach(QModelIndex idx, lvUnselected->selectionModel()->selectedIndexes())
|
foreach(QModelIndex idx, lvUnselected->selectionModel()->selectedIndexes())
|
||||||
rows.append(idx.row());
|
rows.append(idx.row());
|
||||||
std::sort(rows.begin(), rows.end(), qGreater<int>());
|
qSort(rows.begin(), rows.end(), qGreater<int>());
|
||||||
|
|
||||||
QModelIndex idx = lvSelected->selectionModel()->currentIndex();
|
QModelIndex idx = lvSelected->selectionModel()->currentIndex();
|
||||||
int insertAt = idx.isValid() ? idx.row() : mSelected.rowCount();
|
int insertAt = idx.isValid() ? idx.row() : mSelected.rowCount();
|
||||||
@ -106,7 +105,7 @@ void PortStatsFilterDialog::on_tbSelectOut_clicked()
|
|||||||
|
|
||||||
foreach(QModelIndex idx, lvSelected->selectionModel()->selectedIndexes())
|
foreach(QModelIndex idx, lvSelected->selectionModel()->selectedIndexes())
|
||||||
rows.append(idx.row());
|
rows.append(idx.row());
|
||||||
std::sort(rows.begin(), rows.end(), qGreater<int>());
|
qSort(rows.begin(), rows.end(), qGreater<int>());
|
||||||
|
|
||||||
foreach(int row, rows)
|
foreach(int row, rows)
|
||||||
{
|
{
|
||||||
|
@ -20,9 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "portstatsmodel.h"
|
#include "portstatsmodel.h"
|
||||||
#include "portgrouplist.h"
|
#include "portgrouplist.h"
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPalette>
|
|
||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
@ -137,10 +135,7 @@ QVariant PortStatsModel::data(const QModelIndex &index, int role) const
|
|||||||
|
|
||||||
// States
|
// States
|
||||||
case e_COMBO_STATE:
|
case e_COMBO_STATE:
|
||||||
return QString("Link %1%2%3")
|
return QVariant();
|
||||||
.arg(LinkStateName.at(stats.state().link_state()))
|
|
||||||
.arg(stats.state().is_transmit_on() ? ";Tx On" : "")
|
|
||||||
.arg(stats.state().is_capture_on() ? ";Cap On" : "");
|
|
||||||
|
|
||||||
// Statistics
|
// Statistics
|
||||||
case e_STAT_FRAMES_RCVD:
|
case e_STAT_FRAMES_RCVD:
|
||||||
@ -161,13 +156,11 @@ QVariant PortStatsModel::data(const QModelIndex &index, int role) const
|
|||||||
case e_STAT_BYTES_SENT:
|
case e_STAT_BYTES_SENT:
|
||||||
return QString("%L1").arg(quint64(stats.tx_bytes()));
|
return QString("%L1").arg(quint64(stats.tx_bytes()));
|
||||||
|
|
||||||
#if 0
|
|
||||||
case e_STAT_BYTE_SEND_RATE:
|
case e_STAT_BYTE_SEND_RATE:
|
||||||
return QString("%L1").arg(quint64(stats.tx_bps()));
|
return QString("%L1").arg(quint64(stats.tx_bps()));
|
||||||
|
|
||||||
case e_STAT_BYTE_RECV_RATE:
|
case e_STAT_BYTE_RECV_RATE:
|
||||||
return QString("%L1").arg(quint64(stats.rx_bps()));
|
return QString("%L1").arg(quint64(stats.rx_bps()));
|
||||||
#endif
|
|
||||||
|
|
||||||
case e_STAT_BIT_SEND_RATE:
|
case e_STAT_BIT_SEND_RATE:
|
||||||
return QString("%L1").arg(quint64(
|
return QString("%L1").arg(quint64(
|
||||||
@ -277,14 +270,6 @@ QVariant PortStatsModel::headerData(int section, Qt::Orientation orientation, in
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((role == Qt::BackgroundRole) && (orientation == Qt::Vertical)
|
|
||||||
&& qApp->styleSheet().isEmpty())
|
|
||||||
{
|
|
||||||
QPalette palette = QApplication::palette();
|
|
||||||
return section & 0x1 ?
|
|
||||||
palette.alternateBase() : palette.base();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (role != Qt::DisplayRole)
|
if (role != Qt::DisplayRole)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
@ -295,23 +280,16 @@ QVariant PortStatsModel::headerData(int section, Qt::Orientation orientation, in
|
|||||||
|
|
||||||
if (numPorts.isEmpty() || section >= numPorts.last())
|
if (numPorts.isEmpty() || section >= numPorts.last())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
getDomainIndexes(index(0, section), portGroupIdx, portIdx);
|
getDomainIndexes(index(0, section), portGroupIdx, portIdx);
|
||||||
|
|
||||||
PortGroup *portGroup = pgl->mPortGroups.at(portGroupIdx);
|
|
||||||
Port *port = portGroup->mPorts.at(portIdx);
|
|
||||||
|
|
||||||
portName = QString("Port %1-%2")
|
portName = QString("Port %1-%2")
|
||||||
.arg(portGroup->id())
|
.arg(pgl->mPortGroups.at(portGroupIdx)->id())
|
||||||
.arg(port->id());
|
.arg(pgl->mPortGroups.at(portGroupIdx)->mPorts.at(portIdx)->id());
|
||||||
if (portGroupIdx < (uint) pgl->mPortGroups.size()
|
if (portGroupIdx < (uint) pgl->mPortGroups.size()
|
||||||
&& portIdx < (uint) portGroup->mPorts.size())
|
&& portIdx < (uint) pgl->mPortGroups.at(portGroupIdx)->mPorts.size())
|
||||||
{
|
{
|
||||||
if (!port->notes().isEmpty())
|
if (!pgl->mPortGroups.at(portGroupIdx)->mPorts[portIdx]->notes()
|
||||||
|
.isEmpty())
|
||||||
portName += " *";
|
portName += " *";
|
||||||
portName += "\n";
|
|
||||||
portName += port->userDescription().isEmpty() ?
|
|
||||||
port->userAlias() : port->userDescription();
|
|
||||||
}
|
}
|
||||||
return portName;
|
return portName;
|
||||||
}
|
}
|
||||||
@ -319,11 +297,6 @@ QVariant PortStatsModel::headerData(int section, Qt::Orientation orientation, in
|
|||||||
return PortStatName.at(section);
|
return PortStatName.at(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::DropActions PortStatsModel::supportedDropActions() const
|
|
||||||
{
|
|
||||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortStatsModel::portListFromIndex(QModelIndexList indices,
|
void PortStatsModel::portListFromIndex(QModelIndexList indices,
|
||||||
QList<PortGroupAndPortList> &portList)
|
QList<PortGroupAndPortList> &portList)
|
||||||
{
|
{
|
||||||
@ -385,16 +358,6 @@ void PortStatsModel::when_portListChanged()
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortStatsModel::when_portGroupDataChanged(int /*portGroupId*/, int /*portId*/)
|
|
||||||
{
|
|
||||||
if (!columnCount())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Port (user) description may have changed - update column headers
|
|
||||||
// TODO: update only the changed ports, not all
|
|
||||||
emit headerDataChanged(Qt::Horizontal, 0, columnCount()-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: unused? if used, the index calculation row/column needs to be swapped
|
// FIXME: unused? if used, the index calculation row/column needs to be swapped
|
||||||
#if 0
|
#if 0
|
||||||
void PortStatsModel::on_portStatsUpdate(int port, void* /*stats*/)
|
void PortStatsModel::on_portStatsUpdate(int port, void* /*stats*/)
|
||||||
|
@ -26,8 +26,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
class QTimer;
|
class QTimer;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
// Info
|
||||||
|
e_INFO_START = 0,
|
||||||
|
|
||||||
|
e_INFO_USER = e_INFO_START,
|
||||||
|
|
||||||
|
e_INFO_END = e_INFO_USER,
|
||||||
|
|
||||||
// State
|
// State
|
||||||
e_STATE_START = 0,
|
e_STATE_START,
|
||||||
|
|
||||||
e_COMBO_STATE = e_STATE_START,
|
e_COMBO_STATE = e_STATE_START,
|
||||||
|
|
||||||
@ -36,16 +43,14 @@ typedef enum {
|
|||||||
// Statistics
|
// Statistics
|
||||||
e_STATISTICS_START,
|
e_STATISTICS_START,
|
||||||
|
|
||||||
e_STAT_FRAMES_SENT = e_STATISTICS_START,
|
e_STAT_FRAMES_RCVD = e_STATISTICS_START,
|
||||||
e_STAT_FRAMES_RCVD,
|
e_STAT_FRAMES_SENT,
|
||||||
e_STAT_BYTES_SENT,
|
|
||||||
e_STAT_BYTES_RCVD,
|
|
||||||
e_STAT_FRAME_SEND_RATE,
|
e_STAT_FRAME_SEND_RATE,
|
||||||
e_STAT_FRAME_RECV_RATE,
|
e_STAT_FRAME_RECV_RATE,
|
||||||
#if 0
|
e_STAT_BYTES_RCVD,
|
||||||
|
e_STAT_BYTES_SENT,
|
||||||
e_STAT_BYTE_SEND_RATE,
|
e_STAT_BYTE_SEND_RATE,
|
||||||
e_STAT_BYTE_RECV_RATE,
|
e_STAT_BYTE_RECV_RATE,
|
||||||
#endif
|
|
||||||
e_STAT_BIT_SEND_RATE,
|
e_STAT_BIT_SEND_RATE,
|
||||||
e_STAT_BIT_RECV_RATE,
|
e_STAT_BIT_RECV_RATE,
|
||||||
#if 0
|
#if 0
|
||||||
@ -64,34 +69,24 @@ typedef enum {
|
|||||||
|
|
||||||
e_STATISTICS_END = e_STAT_RX_FRAME_ERRORS,
|
e_STATISTICS_END = e_STAT_RX_FRAME_ERRORS,
|
||||||
|
|
||||||
// Info
|
|
||||||
e_INFO_START,
|
|
||||||
|
|
||||||
// XXX: keep hidden rows at end to avoid having to recalculate rows
|
|
||||||
e_INFO_USER = e_INFO_START,
|
|
||||||
|
|
||||||
e_INFO_END = e_INFO_USER,
|
|
||||||
|
|
||||||
|
|
||||||
e_STAT_MAX
|
e_STAT_MAX
|
||||||
} PortStat;
|
} PortStat;
|
||||||
|
|
||||||
static const QStringList PortStatName = (QStringList()
|
static QStringList PortStatName = (QStringList()
|
||||||
|
<< "User"
|
||||||
|
|
||||||
<< "Status"
|
<< "Status"
|
||||||
|
|
||||||
<< "Sent Frames"
|
<< "Frames Received"
|
||||||
<< "Received Frames"
|
<< "Frames Sent"
|
||||||
<< "Sent Bytes"
|
<< "Frame Send Rate (fps)"
|
||||||
<< "Received Bytes"
|
<< "Frame Receive Rate (fps)"
|
||||||
|
<< "Bytes Received"
|
||||||
<< "Send Frame Rate (fps)"
|
<< "Bytes Sent"
|
||||||
<< "Receive Frame Rate (fps)"
|
<< "Byte Send Rate (Bps)"
|
||||||
#if 0
|
<< "Byte Receive Rate (Bps)"
|
||||||
<< "Send Byte Rate (Bps)"
|
<< "Bit Send Rate (bps)"
|
||||||
<< "Receive Byte Rate (Bps)"
|
<< "Bit Receive Rate (bps)"
|
||||||
#endif
|
|
||||||
<< "Send Bit Rate (bps)"
|
|
||||||
<< "Receive Bit Rate (bps)"
|
|
||||||
#if 0
|
#if 0
|
||||||
<< "Frames Received (NIC)"
|
<< "Frames Received (NIC)"
|
||||||
<< "Frames Sent (NIC)"
|
<< "Frames Sent (NIC)"
|
||||||
@ -103,8 +98,6 @@ static const QStringList PortStatName = (QStringList()
|
|||||||
<< "Receive Errors"
|
<< "Receive Errors"
|
||||||
<< "Receive Fifo Errors"
|
<< "Receive Fifo Errors"
|
||||||
<< "Receive Frame Errors"
|
<< "Receive Frame Errors"
|
||||||
|
|
||||||
<< "User"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
static QStringList LinkStateName = (QStringList()
|
static QStringList LinkStateName = (QStringList()
|
||||||
@ -130,8 +123,6 @@ class PortStatsModel : public QAbstractTableModel
|
|||||||
QVariant headerData(int section, Qt::Orientation orientation,
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
int role = Qt::DisplayRole) const;
|
int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
Qt::DropActions supportedDropActions() const;
|
|
||||||
|
|
||||||
class PortGroupAndPortList {
|
class PortGroupAndPortList {
|
||||||
public:
|
public:
|
||||||
uint portGroupId;
|
uint portGroupId;
|
||||||
@ -143,7 +134,6 @@ class PortStatsModel : public QAbstractTableModel
|
|||||||
public slots:
|
public slots:
|
||||||
void when_portListChanged();
|
void when_portListChanged();
|
||||||
//void on_portStatsUpdate(int port, void*stats);
|
//void on_portStatsUpdate(int port, void*stats);
|
||||||
void when_portGroupDataChanged(int portGroupId, int portId);
|
|
||||||
void when_portGroup_stats_update(quint32 portGroupId);
|
void when_portGroup_stats_update(quint32 portGroupId);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -26,17 +26,16 @@ class PortStatsProxyModel : public QSortFilterProxyModel
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
PortStatsProxyModel(int userRow, QObject *parent = 0)
|
PortStatsProxyModel(QObject *parent = 0)
|
||||||
: QSortFilterProxyModel(parent), userRow_(userRow)
|
: QSortFilterProxyModel(parent)
|
||||||
{
|
{
|
||||||
setFilterRegExp(QRegExp(".*"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool filterAcceptsColumn(int sourceColumn,
|
bool filterAcceptsColumn(int sourceColumn,
|
||||||
const QModelIndex &sourceParent) const
|
const QModelIndex &sourceParent) const
|
||||||
{
|
{
|
||||||
QModelIndex index = sourceModel()->index(userRow_, sourceColumn,sourceParent);
|
QModelIndex index = sourceModel()->index(0, sourceColumn, sourceParent);
|
||||||
QString user = sourceModel()->data(index).toString();
|
QString user = sourceModel()->data(index).toString();
|
||||||
|
|
||||||
return filterRegExp().exactMatch(user) ? true : false;
|
return filterRegExp().exactMatch(user) ? true : false;
|
||||||
@ -44,10 +43,9 @@ protected:
|
|||||||
bool filterAcceptsRow(int sourceRow,
|
bool filterAcceptsRow(int sourceRow,
|
||||||
const QModelIndex &/*sourceParent*/) const
|
const QModelIndex &/*sourceParent*/) const
|
||||||
{
|
{
|
||||||
return sourceRow == userRow_ ? false : true;
|
// Hide row 0 - username (needed only by this filter class)
|
||||||
|
return (sourceRow > 0) ? true : false;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
int userRow_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,7 +24,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "portstatsfilterdialog.h"
|
#include "portstatsfilterdialog.h"
|
||||||
#include "portstatsmodel.h"
|
#include "portstatsmodel.h"
|
||||||
#include "portstatsproxymodel.h"
|
#include "portstatsproxymodel.h"
|
||||||
#include "rowborderdelegate.h"
|
|
||||||
#include "streamstatsmodel.h"
|
#include "streamstatsmodel.h"
|
||||||
#include "streamstatswindow.h"
|
#include "streamstatswindow.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
@ -43,8 +42,7 @@ PortStatsWindow::PortStatsWindow(PortGroupList *pgl, QWidget *parent)
|
|||||||
this->pgl = pgl;
|
this->pgl = pgl;
|
||||||
model = pgl->getPortStatsModel();
|
model = pgl->getPortStatsModel();
|
||||||
|
|
||||||
// Hide 'user' row
|
proxyStatsModel = new PortStatsProxyModel(this);
|
||||||
proxyStatsModel = new PortStatsProxyModel(e_INFO_USER, this);
|
|
||||||
if (proxyStatsModel) {
|
if (proxyStatsModel) {
|
||||||
proxyStatsModel->setSourceModel(model);
|
proxyStatsModel->setSourceModel(model);
|
||||||
tvPortStats->setModel(proxyStatsModel);
|
tvPortStats->setModel(proxyStatsModel);
|
||||||
@ -57,17 +55,6 @@ PortStatsWindow::PortStatsWindow(PortGroupList *pgl, QWidget *parent)
|
|||||||
tvPortStats->verticalHeader()->setDefaultSectionSize(
|
tvPortStats->verticalHeader()->setDefaultSectionSize(
|
||||||
tvPortStats->verticalHeader()->minimumSectionSize());
|
tvPortStats->verticalHeader()->minimumSectionSize());
|
||||||
|
|
||||||
// XXX: Set Delegates for port stats view
|
|
||||||
// RowBorderDelegate: Group related stats using a horizontal line
|
|
||||||
// IconOnlyDelegate : For status, show only icons not icons+text
|
|
||||||
tvPortStats->setItemDelegate(
|
|
||||||
new RowBorderDelegate(
|
|
||||||
QSet<int>({
|
|
||||||
e_STAT_FRAMES_SENT,
|
|
||||||
e_STAT_FRAME_SEND_RATE,
|
|
||||||
e_STAT_RX_DROPS}),
|
|
||||||
this));
|
|
||||||
|
|
||||||
statusDelegate = new IconOnlyDelegate(this);
|
statusDelegate = new IconOnlyDelegate(this);
|
||||||
#if 0
|
#if 0
|
||||||
// XXX: Ideally we should use this, but it doesn't work because in
|
// XXX: Ideally we should use this, but it doesn't work because in
|
||||||
@ -81,7 +68,9 @@ PortStatsWindow::PortStatsWindow(PortGroupList *pgl, QWidget *parent)
|
|||||||
statusDelegate);
|
statusDelegate);
|
||||||
#else
|
#else
|
||||||
// ... so we use this hard-coded hack
|
// ... so we use this hard-coded hack
|
||||||
tvPortStats->setItemDelegateForRow(e_COMBO_STATE, statusDelegate);
|
tvPortStats->setItemDelegateForRow(
|
||||||
|
proxyStatsModel ? e_COMBO_STATE-1 : e_COMBO_STATE,
|
||||||
|
statusDelegate);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
connect(tvPortStats->selectionModel(),
|
connect(tvPortStats->selectionModel(),
|
||||||
@ -100,12 +89,6 @@ PortStatsWindow::~PortStatsWindow()
|
|||||||
|
|
||||||
/* ------------- SLOTS (public) -------------- */
|
/* ------------- SLOTS (public) -------------- */
|
||||||
|
|
||||||
void PortStatsWindow::clearCurrentSelection()
|
|
||||||
{
|
|
||||||
tvPortStats->selectionModel()->clearCurrentIndex();
|
|
||||||
tvPortStats->clearSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortStatsWindow::showMyReservedPortsOnly(bool enabled)
|
void PortStatsWindow::showMyReservedPortsOnly(bool enabled)
|
||||||
{
|
{
|
||||||
if (!proxyStatsModel)
|
if (!proxyStatsModel)
|
||||||
@ -306,11 +289,6 @@ void PortStatsWindow::on_tbClearAll_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proxyStatsModel) {
|
|
||||||
for(QModelIndex &index : shownColumns)
|
|
||||||
index = proxyStatsModel->mapToSource(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get ports corresponding to the shown columns
|
// Get ports corresponding to the shown columns
|
||||||
model->portListFromIndex(shownColumns, portList);
|
model->portListFromIndex(shownColumns, portList);
|
||||||
|
|
||||||
@ -342,24 +320,9 @@ void PortStatsWindow::on_tbGetStreamStats_clicked()
|
|||||||
QDockWidget *statsDock = mainWindow->findChild<QDockWidget*>(
|
QDockWidget *statsDock = mainWindow->findChild<QDockWidget*>(
|
||||||
"statsDock");
|
"statsDock");
|
||||||
mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dock);
|
mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dock);
|
||||||
|
|
||||||
// Add stream stats tab to the immediate right of port-stats ...
|
|
||||||
mainWindow->tabifyDockWidget(statsDock, dock);
|
mainWindow->tabifyDockWidget(statsDock, dock);
|
||||||
mainWindow->splitDockWidget(statsDock, dock, Qt::Horizontal);
|
|
||||||
|
|
||||||
// ... make it the currently visible tab ...
|
|
||||||
dock->show();
|
dock->show();
|
||||||
dock->raise();
|
dock->raise();
|
||||||
|
|
||||||
// ... and set tab remove behaviour
|
|
||||||
// XXX: unfortunately, there's no direct way to get the TabBar
|
|
||||||
QList<QTabBar*> tabBars = mainWindow->findChildren<QTabBar*>();
|
|
||||||
foreach(QTabBar* tabBar, tabBars) {
|
|
||||||
if (tabBar->tabText(tabBar->currentIndex())
|
|
||||||
== dock->widget()->windowTitle())
|
|
||||||
tabBar->setSelectionBehaviorOnRemove(
|
|
||||||
QTabBar::SelectPreviousTab);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get stream stats for selected ports, portgroup by portgroup
|
// Get stream stats for selected ports, portgroup by portgroup
|
||||||
|
@ -38,7 +38,6 @@ public:
|
|||||||
~PortStatsWindow();
|
~PortStatsWindow();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clearCurrentSelection();
|
|
||||||
void showMyReservedPortsOnly(bool enabled);
|
void showMyReservedPortsOnly(bool enabled);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -165,7 +165,7 @@
|
|||||||
<string>Stop Capture</string>
|
<string>Stop Capture</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="statusTip">
|
<property name="statusTip">
|
||||||
<string>End capture on selected port(s)</string>
|
<string>End capture on selecteed port(s)</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Stop</string>
|
<string>Stop</string>
|
||||||
@ -279,7 +279,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="XTableView" name="tvPortStats">
|
<widget class="QTableView" name="tvPortStats">
|
||||||
<property name="selectionBehavior">
|
<property name="selectionBehavior">
|
||||||
<enum>QAbstractItemView::SelectColumns</enum>
|
<enum>QAbstractItemView::SelectColumns</enum>
|
||||||
</property>
|
</property>
|
||||||
@ -287,14 +287,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>XTableView</class>
|
|
||||||
<extends>QTableView</extends>
|
|
||||||
<header>xtableview.h</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
|
|
||||||
<resources>
|
<resources>
|
||||||
<include location="ostinato.qrc"/>
|
<include location="ostinato.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -21,17 +21,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
#include "applymsg.h"
|
#include "applymsg.h"
|
||||||
#include "deviceswidget.h"
|
#include "deviceswidget.h"
|
||||||
#include "fileformat.pb.h"
|
|
||||||
#include "portconfigdialog.h"
|
#include "portconfigdialog.h"
|
||||||
#include "portgrouplist.h"
|
|
||||||
#include "portwidget.h"
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "streamswidget.h"
|
#include "streamconfigdialog.h"
|
||||||
|
#include "streamfileformat.h"
|
||||||
|
#include "streamlistdelegate.h"
|
||||||
|
|
||||||
|
#include "fileformat.pb.h"
|
||||||
|
|
||||||
|
#include "xqlocale.h"
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
|
#include <QItemSelectionModel>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QProgressDialog>
|
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
extern QMainWindow *mainWindow;
|
extern QMainWindow *mainWindow;
|
||||||
@ -39,18 +43,26 @@ extern QMainWindow *mainWindow;
|
|||||||
PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
|
PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
|
||||||
: QWidget(parent), proxyPortModel(NULL)
|
: QWidget(parent), proxyPortModel(NULL)
|
||||||
{
|
{
|
||||||
|
QAction *sep;
|
||||||
|
|
||||||
|
delegate = new StreamListDelegate;
|
||||||
proxyPortModel = new QSortFilterProxyModel(this);
|
proxyPortModel = new QSortFilterProxyModel(this);
|
||||||
|
|
||||||
|
//slm = new StreamListModel();
|
||||||
|
//plm = new PortGroupList();
|
||||||
plm = pgl;
|
plm = pgl;
|
||||||
|
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
applyMsg_ = new ApplyMessage();
|
applyMsg_ = new ApplyMessage();
|
||||||
portWidget->setPortGroupList(plm);
|
|
||||||
streamsWidget->setPortGroupList(plm);
|
|
||||||
devicesWidget->setPortGroupList(plm);
|
devicesWidget->setPortGroupList(plm);
|
||||||
|
|
||||||
tvPortList->header()->hide();
|
tvPortList->header()->hide();
|
||||||
|
|
||||||
|
tvStreamList->setItemDelegate(delegate);
|
||||||
|
|
||||||
|
tvStreamList->verticalHeader()->setDefaultSectionSize(
|
||||||
|
tvStreamList->verticalHeader()->minimumSectionSize());
|
||||||
|
|
||||||
// Populate PortList Context Menu Actions
|
// Populate PortList Context Menu Actions
|
||||||
tvPortList->addAction(actionNew_Port_Group);
|
tvPortList->addAction(actionNew_Port_Group);
|
||||||
tvPortList->addAction(actionDelete_Port_Group);
|
tvPortList->addAction(actionDelete_Port_Group);
|
||||||
@ -60,18 +72,33 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
|
|||||||
tvPortList->addAction(actionExclusive_Control);
|
tvPortList->addAction(actionExclusive_Control);
|
||||||
tvPortList->addAction(actionPort_Configuration);
|
tvPortList->addAction(actionPort_Configuration);
|
||||||
|
|
||||||
|
// Populate StreamList Context Menu Actions
|
||||||
|
tvStreamList->addAction(actionNew_Stream);
|
||||||
|
tvStreamList->addAction(actionEdit_Stream);
|
||||||
|
tvStreamList->addAction(actionDuplicate_Stream);
|
||||||
|
tvStreamList->addAction(actionDelete_Stream);
|
||||||
|
|
||||||
|
sep = new QAction(this);
|
||||||
|
sep->setSeparator(true);
|
||||||
|
tvStreamList->addAction(sep);
|
||||||
|
|
||||||
|
tvStreamList->addAction(actionOpen_Streams);
|
||||||
|
tvStreamList->addAction(actionSave_Streams);
|
||||||
|
|
||||||
// PortList, StreamList, DeviceWidget actions combined
|
// PortList, StreamList, DeviceWidget actions combined
|
||||||
// make this window's actions
|
// make this window's actions
|
||||||
addActions(tvPortList->actions());
|
addActions(tvPortList->actions());
|
||||||
QAction *sep = new QAction(this);
|
sep = new QAction(this);
|
||||||
sep->setSeparator(true);
|
sep->setSeparator(true);
|
||||||
addAction(sep);
|
addAction(sep);
|
||||||
addActions(streamsWidget->actions());
|
addActions(tvStreamList->actions());
|
||||||
sep = new QAction(this);
|
sep = new QAction(this);
|
||||||
sep->setSeparator(true);
|
sep->setSeparator(true);
|
||||||
addAction(sep);
|
addAction(sep);
|
||||||
addActions(devicesWidget->actions());
|
addActions(devicesWidget->actions());
|
||||||
|
|
||||||
|
tvStreamList->setModel(plm->getStreamModel());
|
||||||
|
|
||||||
// XXX: It would be ideal if we only needed to do the below to
|
// XXX: It would be ideal if we only needed to do the below to
|
||||||
// get the proxy model to do its magic. However, the QModelIndex
|
// get the proxy model to do its magic. However, the QModelIndex
|
||||||
// used by the source model and the proxy model are different
|
// used by the source model and the proxy model are different
|
||||||
@ -97,33 +124,56 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
|
|||||||
connect(plm->getPortModel(), SIGNAL(modelReset()),
|
connect(plm->getPortModel(), SIGNAL(modelReset()),
|
||||||
SLOT(when_portModel_reset()));
|
SLOT(when_portModel_reset()));
|
||||||
|
|
||||||
connect(actionPort_Configuration, SIGNAL(triggered()),
|
connect( tvPortList->selectionModel(),
|
||||||
SLOT(when_actionPort_Configuration_triggered()));
|
|
||||||
connect(tvPortList, SIGNAL(activated(const QModelIndex&)),
|
|
||||||
SLOT(when_actionPort_Configuration_triggered(const QModelIndex&)));
|
|
||||||
connect(tvPortList->selectionModel(),
|
|
||||||
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
||||||
this, SLOT(when_portView_currentChanged(const QModelIndex&,
|
this, SLOT(when_portView_currentChanged(const QModelIndex&,
|
||||||
const QModelIndex&)));
|
const QModelIndex&)));
|
||||||
|
|
||||||
connect(this,
|
|
||||||
SIGNAL(currentPortChanged(const QModelIndex&, const QModelIndex&)),
|
|
||||||
portWidget,
|
|
||||||
SLOT(setCurrentPortIndex(const QModelIndex&, const QModelIndex&)));
|
|
||||||
connect(this,
|
|
||||||
SIGNAL(currentPortChanged(const QModelIndex&, const QModelIndex&)),
|
|
||||||
streamsWidget, SLOT(setCurrentPortIndex(const QModelIndex&)));
|
|
||||||
connect(this,
|
connect(this,
|
||||||
SIGNAL(currentPortChanged(const QModelIndex&, const QModelIndex&)),
|
SIGNAL(currentPortChanged(const QModelIndex&, const QModelIndex&)),
|
||||||
devicesWidget, SLOT(setCurrentPortIndex(const QModelIndex&)));
|
devicesWidget, SLOT(setCurrentPortIndex(const QModelIndex&)));
|
||||||
|
|
||||||
|
connect(plm->getStreamModel(), SIGNAL(rowsInserted(QModelIndex, int, int)),
|
||||||
|
SLOT(updateStreamViewActions()));
|
||||||
|
connect(plm->getStreamModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)),
|
||||||
|
SLOT(updateStreamViewActions()));
|
||||||
|
|
||||||
|
connect(tvStreamList->selectionModel(),
|
||||||
|
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
||||||
|
SLOT(updateStreamViewActions()));
|
||||||
|
connect(tvStreamList->selectionModel(),
|
||||||
|
SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||||
|
SLOT(updateStreamViewActions()));
|
||||||
|
|
||||||
|
tvStreamList->resizeColumnToContents(StreamModel::StreamIcon);
|
||||||
|
tvStreamList->resizeColumnToContents(StreamModel::StreamStatus);
|
||||||
|
|
||||||
// Initially we don't have any ports/streams/devices
|
// Initially we don't have any ports/streams/devices
|
||||||
// - so send signal triggers
|
// - so send signal triggers
|
||||||
when_portView_currentChanged(QModelIndex(), QModelIndex());
|
when_portView_currentChanged(QModelIndex(), QModelIndex());
|
||||||
|
updateStreamViewActions();
|
||||||
|
|
||||||
|
connect(plm->getStreamModel(),
|
||||||
|
SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||||
|
this, SLOT(streamModelDataChanged()));
|
||||||
|
connect(plm->getStreamModel(),
|
||||||
|
SIGNAL(modelReset()),
|
||||||
|
this, SLOT(streamModelDataChanged()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::streamModelDataChanged()
|
||||||
|
{
|
||||||
|
QModelIndex current = tvPortList->currentIndex();
|
||||||
|
|
||||||
|
if (proxyPortModel)
|
||||||
|
current = proxyPortModel->mapToSource(current);
|
||||||
|
|
||||||
|
if (plm->isPort(current))
|
||||||
|
plm->port(current).recalculateAverageRates();
|
||||||
}
|
}
|
||||||
|
|
||||||
PortsWindow::~PortsWindow()
|
PortsWindow::~PortsWindow()
|
||||||
{
|
{
|
||||||
|
delete delegate;
|
||||||
delete proxyPortModel;
|
delete proxyPortModel;
|
||||||
delete applyMsg_;
|
delete applyMsg_;
|
||||||
}
|
}
|
||||||
@ -238,27 +288,6 @@ bool PortsWindow::saveSession(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QAction*> PortsWindow::portActions()
|
|
||||||
{
|
|
||||||
return tvPortList->actions();
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QAction*> PortsWindow::streamActions()
|
|
||||||
{
|
|
||||||
return streamsWidget->actions();
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QAction*> PortsWindow::deviceActions()
|
|
||||||
{
|
|
||||||
return devicesWidget->actions();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortsWindow::clearCurrentSelection()
|
|
||||||
{
|
|
||||||
tvPortList->selectionModel()->clearCurrentIndex();
|
|
||||||
tvPortList->clearSelection();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortsWindow::showMyReservedPortsOnly(bool enabled)
|
void PortsWindow::showMyReservedPortsOnly(bool enabled)
|
||||||
{
|
{
|
||||||
if (!proxyPortModel)
|
if (!proxyPortModel)
|
||||||
@ -276,6 +305,30 @@ void PortsWindow::showMyReservedPortsOnly(bool enabled)
|
|||||||
proxyPortModel->setFilterRegExp(QRegExp(""));
|
proxyPortModel->setFilterRegExp(QRegExp(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_tvStreamList_activated(const QModelIndex & index)
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
{
|
||||||
|
qDebug("%s: invalid index", __FUNCTION__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug("stream list activated\n");
|
||||||
|
|
||||||
|
Port &curPort = plm->port(proxyPortModel ?
|
||||||
|
proxyPortModel->mapToSource(tvPortList->currentIndex()) :
|
||||||
|
tvPortList->currentIndex());
|
||||||
|
|
||||||
|
QList<Stream*> streams;
|
||||||
|
streams.append(curPort.mutableStreamByIndex(index.row(), false));
|
||||||
|
|
||||||
|
StreamConfigDialog scd(streams, curPort, this);
|
||||||
|
if (scd.exec() == QDialog::Accepted) {
|
||||||
|
curPort.recalculateAverageRates();
|
||||||
|
curPort.setLocalConfigChanged(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PortsWindow::when_portView_currentChanged(const QModelIndex& currentIndex,
|
void PortsWindow::when_portView_currentChanged(const QModelIndex& currentIndex,
|
||||||
const QModelIndex& previousIndex)
|
const QModelIndex& previousIndex)
|
||||||
{
|
{
|
||||||
@ -287,12 +340,16 @@ void PortsWindow::when_portView_currentChanged(const QModelIndex& currentIndex,
|
|||||||
previous = proxyPortModel->mapToSource(previous);
|
previous = proxyPortModel->mapToSource(previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plm->getStreamModel()->setCurrentPortIndex(current);
|
||||||
updatePortViewActions(currentIndex);
|
updatePortViewActions(currentIndex);
|
||||||
|
updateStreamViewActions();
|
||||||
|
|
||||||
qDebug("In %s", __FUNCTION__);
|
qDebug("In %s", __FUNCTION__);
|
||||||
|
|
||||||
if (previous.isValid() && plm->isPort(previous))
|
if (previous.isValid() && plm->isPort(previous))
|
||||||
{
|
{
|
||||||
|
disconnect(&(plm->port(previous)), SIGNAL(portRateChanged(int, int)),
|
||||||
|
this, SLOT(updatePortRates()));
|
||||||
disconnect(&(plm->port(previous)),
|
disconnect(&(plm->port(previous)),
|
||||||
SIGNAL(localConfigChanged(int, int, bool)),
|
SIGNAL(localConfigChanged(int, int, bool)),
|
||||||
this,
|
this,
|
||||||
@ -313,6 +370,9 @@ void PortsWindow::when_portView_currentChanged(const QModelIndex& currentIndex,
|
|||||||
else if (plm->isPort(current))
|
else if (plm->isPort(current))
|
||||||
{
|
{
|
||||||
swDetail->setCurrentIndex(2); // port detail page
|
swDetail->setCurrentIndex(2); // port detail page
|
||||||
|
updatePortRates();
|
||||||
|
connect(&(plm->port(current)), SIGNAL(portRateChanged(int, int)),
|
||||||
|
SLOT(updatePortRates()));
|
||||||
connect(&(plm->port(current)),
|
connect(&(plm->port(current)),
|
||||||
SIGNAL(localConfigChanged(int, int, bool)),
|
SIGNAL(localConfigChanged(int, int, bool)),
|
||||||
SLOT(updateApplyHint(int, int, bool)));
|
SLOT(updateApplyHint(int, int, bool)));
|
||||||
@ -370,6 +430,139 @@ void PortsWindow::when_portModel_reset()
|
|||||||
when_portView_currentChanged(QModelIndex(), tvPortList->currentIndex());
|
when_portView_currentChanged(QModelIndex(), tvPortList->currentIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_startTx_clicked()
|
||||||
|
{
|
||||||
|
QModelIndex current = tvPortList->currentIndex();
|
||||||
|
|
||||||
|
if (proxyPortModel)
|
||||||
|
current = proxyPortModel->mapToSource(current);
|
||||||
|
|
||||||
|
Q_ASSERT(plm->isPort(current));
|
||||||
|
|
||||||
|
QModelIndex curPortGroup = plm->getPortModel()->parent(current);
|
||||||
|
Q_ASSERT(curPortGroup.isValid());
|
||||||
|
Q_ASSERT(plm->isPortGroup(curPortGroup));
|
||||||
|
|
||||||
|
QList<uint> portList({plm->port(current).id()});
|
||||||
|
plm->portGroup(curPortGroup).startTx(&portList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_stopTx_clicked()
|
||||||
|
{
|
||||||
|
QModelIndex current = tvPortList->currentIndex();
|
||||||
|
|
||||||
|
if (proxyPortModel)
|
||||||
|
current = proxyPortModel->mapToSource(current);
|
||||||
|
|
||||||
|
Q_ASSERT(plm->isPort(current));
|
||||||
|
|
||||||
|
QModelIndex curPortGroup = plm->getPortModel()->parent(current);
|
||||||
|
Q_ASSERT(curPortGroup.isValid());
|
||||||
|
Q_ASSERT(plm->isPortGroup(curPortGroup));
|
||||||
|
|
||||||
|
QList<uint> portList({plm->port(current).id()});
|
||||||
|
plm->portGroup(curPortGroup).stopTx(&portList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_averagePacketsPerSec_editingFinished()
|
||||||
|
{
|
||||||
|
QModelIndex current = tvPortList->currentIndex();
|
||||||
|
|
||||||
|
if (proxyPortModel)
|
||||||
|
current = proxyPortModel->mapToSource(current);
|
||||||
|
|
||||||
|
Q_ASSERT(plm->isPort(current));
|
||||||
|
|
||||||
|
bool isOk;
|
||||||
|
double pps = XLocale().toDouble(averagePacketsPerSec->text(), &isOk);
|
||||||
|
|
||||||
|
plm->port(current).setAveragePacketRate(pps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_averageBitsPerSec_editingFinished()
|
||||||
|
{
|
||||||
|
QModelIndex current = tvPortList->currentIndex();
|
||||||
|
|
||||||
|
if (proxyPortModel)
|
||||||
|
current = proxyPortModel->mapToSource(current);
|
||||||
|
|
||||||
|
Q_ASSERT(plm->isPort(current));
|
||||||
|
|
||||||
|
bool isOk;
|
||||||
|
double bps = XLocale().toDouble(averageBitsPerSec->text(), &isOk);
|
||||||
|
|
||||||
|
plm->port(current).setAverageBitRate(bps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::updatePortRates()
|
||||||
|
{
|
||||||
|
QModelIndex current = tvPortList->currentIndex();
|
||||||
|
|
||||||
|
if (proxyPortModel)
|
||||||
|
current = proxyPortModel->mapToSource(current);
|
||||||
|
|
||||||
|
if (!current.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!plm->isPort(current))
|
||||||
|
return;
|
||||||
|
|
||||||
|
averagePacketsPerSec->setText(QString("%L1")
|
||||||
|
.arg(plm->port(current).averagePacketRate(), 0, 'f', 4));
|
||||||
|
averageBitsPerSec->setText(QString("%L1")
|
||||||
|
.arg(plm->port(current).averageBitRate(), 0, 'f', 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::updateStreamViewActions()
|
||||||
|
{
|
||||||
|
QModelIndex current = tvPortList->currentIndex();
|
||||||
|
|
||||||
|
if (proxyPortModel)
|
||||||
|
current = proxyPortModel->mapToSource(current);
|
||||||
|
|
||||||
|
// For some reason hasSelection() returns true even if selection size is 0
|
||||||
|
// so additional check for size introduced
|
||||||
|
if (tvStreamList->selectionModel()->hasSelection() &&
|
||||||
|
(tvStreamList->selectionModel()->selection().size() > 0))
|
||||||
|
{
|
||||||
|
qDebug("Has selection %d",
|
||||||
|
tvStreamList->selectionModel()->selection().size());
|
||||||
|
|
||||||
|
// If more than one non-contiguous ranges selected,
|
||||||
|
// disable "New" and "Edit"
|
||||||
|
if (tvStreamList->selectionModel()->selection().size() > 1)
|
||||||
|
{
|
||||||
|
actionNew_Stream->setDisabled(true);
|
||||||
|
actionEdit_Stream->setDisabled(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
actionNew_Stream->setEnabled(true);
|
||||||
|
actionEdit_Stream->setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicate/Delete are always enabled as long as we have a selection
|
||||||
|
actionDuplicate_Stream->setEnabled(true);
|
||||||
|
actionDelete_Stream->setEnabled(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("No selection");
|
||||||
|
if (plm->isPort(current))
|
||||||
|
actionNew_Stream->setEnabled(true);
|
||||||
|
else
|
||||||
|
actionNew_Stream->setDisabled(true);
|
||||||
|
actionEdit_Stream->setDisabled(true);
|
||||||
|
actionDuplicate_Stream->setDisabled(true);
|
||||||
|
actionDelete_Stream->setDisabled(true);
|
||||||
|
}
|
||||||
|
actionOpen_Streams->setEnabled(plm->isPort(current));
|
||||||
|
actionSave_Streams->setEnabled(tvStreamList->model()->rowCount() > 0);
|
||||||
|
|
||||||
|
startTx->setEnabled(tvStreamList->model()->rowCount() > 0);
|
||||||
|
stopTx->setEnabled(tvStreamList->model()->rowCount() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
void PortsWindow::updateApplyHint(int /*portGroupId*/, int /*portId*/,
|
void PortsWindow::updateApplyHint(int /*portGroupId*/, int /*portId*/,
|
||||||
bool configChanged)
|
bool configChanged)
|
||||||
{
|
{
|
||||||
@ -377,7 +570,7 @@ void PortsWindow::updateApplyHint(int /*portGroupId*/, int /*portId*/,
|
|||||||
applyHint->setText("Configuration has changed - "
|
applyHint->setText("Configuration has changed - "
|
||||||
"<font color='red'><b>click Apply</b></font> "
|
"<font color='red'><b>click Apply</b></font> "
|
||||||
"to activate the changes");
|
"to activate the changes");
|
||||||
else if (plm->getStreamModel()->rowCount() > 0)
|
else if (tvStreamList->model()->rowCount() > 0)
|
||||||
applyHint->setText("Configuration activated - "
|
applyHint->setText("Configuration activated - "
|
||||||
"click <img src=':/icons/control_play'/> "
|
"click <img src=':/icons/control_play'/> "
|
||||||
"to transmit packets");
|
"to transmit packets");
|
||||||
@ -602,11 +795,9 @@ void PortsWindow::on_actionExclusive_Control_triggered(bool checked)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortsWindow::when_actionPort_Configuration_triggered(
|
void PortsWindow::on_actionPort_Configuration_triggered()
|
||||||
const QModelIndex &portIndex)
|
|
||||||
{
|
{
|
||||||
QModelIndex current = portIndex.isValid() ?
|
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||||
portIndex : tvPortList->selectionModel()->currentIndex();
|
|
||||||
|
|
||||||
if (proxyPortModel)
|
if (proxyPortModel)
|
||||||
current = proxyPortModel->mapToSource(current);
|
current = proxyPortModel->mapToSource(current);
|
||||||
@ -621,8 +812,6 @@ void PortsWindow::when_actionPort_Configuration_triggered(
|
|||||||
// TODO: extend Port::protoDataCopyInto() to accept an optional param
|
// TODO: extend Port::protoDataCopyInto() to accept an optional param
|
||||||
// which says copy only modifiable fields
|
// which says copy only modifiable fields
|
||||||
//plm->port(current).protoDataCopyInto(&config);
|
//plm->port(current).protoDataCopyInto(&config);
|
||||||
config.set_description(port.systemDescription().toStdString());
|
|
||||||
config.set_user_description(port.userDescription().toStdString());
|
|
||||||
config.set_transmit_mode(port.transmitMode());
|
config.set_transmit_mode(port.transmitMode());
|
||||||
config.set_is_tracking_stream_stats(port.trackStreamStats());
|
config.set_is_tracking_stream_stats(port.trackStreamStats());
|
||||||
config.set_is_exclusive_control(port.hasExclusiveControl());
|
config.set_is_exclusive_control(port.hasExclusiveControl());
|
||||||
@ -633,3 +822,258 @@ void PortsWindow::when_actionPort_Configuration_triggered(
|
|||||||
if (dialog.exec() == QDialog::Accepted)
|
if (dialog.exec() == QDialog::Accepted)
|
||||||
plm->portGroup(current.parent()).modifyPort(current.row(), config);
|
plm->portGroup(current.parent()).modifyPort(current.row(), config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionNew_Stream_triggered()
|
||||||
|
{
|
||||||
|
qDebug("New Stream Action");
|
||||||
|
|
||||||
|
QItemSelectionModel* selectionModel = tvStreamList->selectionModel();
|
||||||
|
if (selectionModel->selection().size() > 1) {
|
||||||
|
qDebug("%s: Unexpected selection size %d, can't add", __FUNCTION__,
|
||||||
|
selectionModel->selection().size());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case nothing is selected, insert 1 row at the end
|
||||||
|
StreamModel *streamModel = plm->getStreamModel();
|
||||||
|
int row = streamModel->rowCount(), count = 1;
|
||||||
|
|
||||||
|
// In case we have a single range selected; insert as many rows as
|
||||||
|
// in the singe selected range before the top of the selected range
|
||||||
|
if (selectionModel->selection().size() == 1)
|
||||||
|
{
|
||||||
|
row = selectionModel->selection().at(0).top();
|
||||||
|
count = selectionModel->selection().at(0).height();
|
||||||
|
}
|
||||||
|
|
||||||
|
Port &curPort = plm->port(proxyPortModel ?
|
||||||
|
proxyPortModel->mapToSource(tvPortList->currentIndex()) :
|
||||||
|
tvPortList->currentIndex());
|
||||||
|
|
||||||
|
QList<Stream*> streams;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
streams.append(new Stream);
|
||||||
|
|
||||||
|
StreamConfigDialog scd(streams, curPort, this);
|
||||||
|
scd.setWindowTitle(tr("Add Stream"));
|
||||||
|
if (scd.exec() == QDialog::Accepted)
|
||||||
|
streamModel->insert(row, streams);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionEdit_Stream_triggered()
|
||||||
|
{
|
||||||
|
qDebug("Edit Stream Action");
|
||||||
|
|
||||||
|
QItemSelectionModel* streamModel = tvStreamList->selectionModel();
|
||||||
|
if (!streamModel->hasSelection())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Port &curPort = plm->port(proxyPortModel ?
|
||||||
|
proxyPortModel->mapToSource(tvPortList->currentIndex()) :
|
||||||
|
tvPortList->currentIndex());
|
||||||
|
|
||||||
|
QList<Stream*> streams;
|
||||||
|
foreach(QModelIndex index, streamModel->selectedRows())
|
||||||
|
streams.append(curPort.mutableStreamByIndex(index.row(), false));
|
||||||
|
|
||||||
|
StreamConfigDialog scd(streams, curPort, this);
|
||||||
|
if (scd.exec() == QDialog::Accepted) {
|
||||||
|
curPort.recalculateAverageRates();
|
||||||
|
curPort.setLocalConfigChanged(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionDuplicate_Stream_triggered()
|
||||||
|
{
|
||||||
|
QItemSelectionModel* model = tvStreamList->selectionModel();
|
||||||
|
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||||
|
|
||||||
|
qDebug("Duplicate Stream Action");
|
||||||
|
|
||||||
|
if (proxyPortModel)
|
||||||
|
current = proxyPortModel->mapToSource(current);
|
||||||
|
|
||||||
|
if (model->hasSelection())
|
||||||
|
{
|
||||||
|
bool isOk;
|
||||||
|
int count = QInputDialog::getInt(this, "Duplicate Streams",
|
||||||
|
"Count", 1, 1, 9999, 1, &isOk);
|
||||||
|
|
||||||
|
if (!isOk)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QList<int> list;
|
||||||
|
foreach(QModelIndex index, model->selectedRows())
|
||||||
|
list.append(index.row());
|
||||||
|
plm->port(current).duplicateStreams(list, count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
qDebug("No selection");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionDelete_Stream_triggered()
|
||||||
|
{
|
||||||
|
qDebug("Delete Stream Action");
|
||||||
|
|
||||||
|
QModelIndex index;
|
||||||
|
|
||||||
|
if (tvStreamList->selectionModel()->hasSelection())
|
||||||
|
{
|
||||||
|
qDebug("SelectedIndexes %d",
|
||||||
|
tvStreamList->selectionModel()->selectedRows().size());
|
||||||
|
while(tvStreamList->selectionModel()->selectedRows().size())
|
||||||
|
{
|
||||||
|
index = tvStreamList->selectionModel()->selectedRows().at(0);
|
||||||
|
plm->getStreamModel()->removeRows(index.row(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
qDebug("No selection");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionOpen_Streams_triggered()
|
||||||
|
{
|
||||||
|
qDebug("Open Streams Action");
|
||||||
|
|
||||||
|
QStringList fileTypes = StreamFileFormat::supportedFileTypes(
|
||||||
|
StreamFileFormat::kOpenFile);
|
||||||
|
QString fileType;
|
||||||
|
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||||
|
static QString dirName;
|
||||||
|
QString fileName;
|
||||||
|
QString errorStr;
|
||||||
|
bool append = true;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
if (proxyPortModel)
|
||||||
|
current = proxyPortModel->mapToSource(current);
|
||||||
|
|
||||||
|
Q_ASSERT(plm->isPort(current));
|
||||||
|
|
||||||
|
if (fileTypes.size())
|
||||||
|
fileType = fileTypes.at(0);
|
||||||
|
|
||||||
|
fileName = QFileDialog::getOpenFileName(this, tr("Open Streams"),
|
||||||
|
dirName, fileTypes.join(";;"), &fileType);
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
goto _exit;
|
||||||
|
|
||||||
|
if (tvStreamList->model()->rowCount())
|
||||||
|
{
|
||||||
|
QMessageBox msgBox(QMessageBox::Question, qApp->applicationName(),
|
||||||
|
tr("Append to existing streams? Or overwrite?"),
|
||||||
|
QMessageBox::NoButton, this);
|
||||||
|
QPushButton *appendBtn = msgBox.addButton(tr("Append"),
|
||||||
|
QMessageBox::ActionRole);
|
||||||
|
QPushButton *overwriteBtn = msgBox.addButton(tr("Overwrite"),
|
||||||
|
QMessageBox::ActionRole);
|
||||||
|
QPushButton *cancelBtn = msgBox.addButton(QMessageBox::Cancel);
|
||||||
|
|
||||||
|
msgBox.exec();
|
||||||
|
|
||||||
|
if (msgBox.clickedButton() == cancelBtn)
|
||||||
|
goto _exit;
|
||||||
|
else if (msgBox.clickedButton() == appendBtn)
|
||||||
|
append = true;
|
||||||
|
else if (msgBox.clickedButton() == overwriteBtn)
|
||||||
|
append = false;
|
||||||
|
else
|
||||||
|
Q_ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = plm->port(current).openStreams(fileName, append, errorStr);
|
||||||
|
if (!ret || !errorStr.isEmpty())
|
||||||
|
{
|
||||||
|
QMessageBox msgBox(this);
|
||||||
|
QStringList str = errorStr.split("\n\n\n\n");
|
||||||
|
|
||||||
|
msgBox.setIcon(ret ? QMessageBox::Warning : QMessageBox::Critical);
|
||||||
|
msgBox.setWindowTitle(qApp->applicationName());
|
||||||
|
msgBox.setText(str.at(0));
|
||||||
|
if (str.size() > 1)
|
||||||
|
msgBox.setDetailedText(str.at(1));
|
||||||
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
|
|
||||||
|
msgBox.exec();
|
||||||
|
}
|
||||||
|
dirName = QFileInfo(fileName).absolutePath();
|
||||||
|
|
||||||
|
_exit:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionSave_Streams_triggered()
|
||||||
|
{
|
||||||
|
qDebug("Save Streams Action");
|
||||||
|
|
||||||
|
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||||
|
static QString fileName;
|
||||||
|
QStringList fileTypes = StreamFileFormat::supportedFileTypes(
|
||||||
|
StreamFileFormat::kSaveFile);
|
||||||
|
QString fileType;
|
||||||
|
QString errorStr;
|
||||||
|
QFileDialog::Options options;
|
||||||
|
|
||||||
|
if (proxyPortModel)
|
||||||
|
current = proxyPortModel->mapToSource(current);
|
||||||
|
|
||||||
|
// On Mac OS with Native Dialog, getSaveFileName() ignores fileType
|
||||||
|
// which we need
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
options |= QFileDialog::DontUseNativeDialog;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (fileTypes.size())
|
||||||
|
fileType = fileTypes.at(0);
|
||||||
|
|
||||||
|
Q_ASSERT(plm->isPort(current));
|
||||||
|
|
||||||
|
_retry:
|
||||||
|
fileName = QFileDialog::getSaveFileName(this, tr("Save Streams"),
|
||||||
|
fileName, fileTypes.join(";;"), &fileType, options);
|
||||||
|
if (fileName.isEmpty())
|
||||||
|
goto _exit;
|
||||||
|
|
||||||
|
if (QFileInfo(fileName).suffix().isEmpty()) {
|
||||||
|
QString fileExt = fileType.section(QRegExp("[\\*\\)]"), 1, 1);
|
||||||
|
qDebug("Adding extension '%s' to '%s'",
|
||||||
|
qPrintable(fileExt), qPrintable(fileName));
|
||||||
|
fileName.append(fileExt);
|
||||||
|
if (QFileInfo(fileName).exists()) {
|
||||||
|
if (QMessageBox::warning(this, tr("Overwrite File?"),
|
||||||
|
QString("The file \"%1\" already exists.\n\n"
|
||||||
|
"Do you wish to overwrite it?")
|
||||||
|
.arg(QFileInfo(fileName).fileName()),
|
||||||
|
QMessageBox::Yes|QMessageBox::No,
|
||||||
|
QMessageBox::No) != QMessageBox::Yes)
|
||||||
|
goto _retry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileType = fileType.remove(QRegExp("\\(.*\\)")).trimmed();
|
||||||
|
if (!fileType.startsWith("Ostinato")
|
||||||
|
&& !fileType.startsWith("Python"))
|
||||||
|
{
|
||||||
|
if (QMessageBox::warning(this, tr("Ostinato"),
|
||||||
|
QString("You have chosen to save in %1 format. All stream "
|
||||||
|
"attributes may not be saved in this format.\n\n"
|
||||||
|
"It is recommended to save in native Ostinato format.\n\n"
|
||||||
|
"Continue to save in %2 format?").arg(fileType).arg(fileType),
|
||||||
|
QMessageBox::Yes|QMessageBox::No,
|
||||||
|
QMessageBox::No) != QMessageBox::Yes)
|
||||||
|
goto _retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: all or selected?
|
||||||
|
|
||||||
|
if (!plm->port(current).saveStreams(fileName, fileType, errorStr))
|
||||||
|
QMessageBox::critical(this, qApp->applicationName(), errorStr);
|
||||||
|
else if (!errorStr.isEmpty())
|
||||||
|
QMessageBox::warning(this, qApp->applicationName(), errorStr);
|
||||||
|
|
||||||
|
fileName = QFileInfo(fileName).absolutePath();
|
||||||
|
_exit:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,12 +20,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#ifndef _PORTS_WINDOW_H
|
#ifndef _PORTS_WINDOW_H
|
||||||
#define _PORTS_WINDOW_H
|
#define _PORTS_WINDOW_H
|
||||||
|
|
||||||
#include "ui_portswindow.h"
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include "ui_portswindow.h"
|
||||||
|
#include "portgrouplist.h"
|
||||||
|
|
||||||
class ApplyMessage;
|
class ApplyMessage;
|
||||||
class PortGroupList;
|
class QAbstractItemDelegate;
|
||||||
|
|
||||||
class QProgressDialog;
|
class QProgressDialog;
|
||||||
class QSortFilterProxyModel;
|
class QSortFilterProxyModel;
|
||||||
|
|
||||||
@ -37,6 +38,9 @@ class PortsWindow : public QWidget, private Ui::PortsWindow
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
//QAbstractItemModel *slm; // stream list model
|
||||||
|
PortGroupList *plm;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PortsWindow(PortGroupList *pgl, QWidget *parent = 0);
|
PortsWindow(PortGroupList *pgl, QWidget *parent = 0);
|
||||||
~PortsWindow();
|
~PortsWindow();
|
||||||
@ -50,22 +54,30 @@ public:
|
|||||||
QString &error,
|
QString &error,
|
||||||
QProgressDialog *progress = NULL);
|
QProgressDialog *progress = NULL);
|
||||||
|
|
||||||
QList<QAction*> portActions();
|
|
||||||
QList<QAction*> streamActions();
|
|
||||||
QList<QAction*> deviceActions();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void currentPortChanged(const QModelIndex ¤t,
|
void currentPortChanged(const QModelIndex ¤t,
|
||||||
const QModelIndex &previous);
|
const QModelIndex &previous);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString lastNewPortGroup;
|
||||||
|
QAbstractItemDelegate *delegate;
|
||||||
|
QSortFilterProxyModel *proxyPortModel;
|
||||||
|
ApplyMessage *applyMsg_;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clearCurrentSelection();
|
|
||||||
void showMyReservedPortsOnly(bool enabled);
|
void showMyReservedPortsOnly(bool enabled);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void updateApplyHint(int portGroupId, int portId, bool configChanged);
|
void updateApplyHint(int portGroupId, int portId, bool configChanged);
|
||||||
void updatePortViewActions(const QModelIndex& currentIndex);
|
void updatePortViewActions(const QModelIndex& currentIndex);
|
||||||
|
void updateStreamViewActions();
|
||||||
|
|
||||||
|
void on_startTx_clicked();
|
||||||
|
void on_stopTx_clicked();
|
||||||
|
void on_averagePacketsPerSec_editingFinished();
|
||||||
|
void on_averageBitsPerSec_editingFinished();
|
||||||
|
void updatePortRates();
|
||||||
|
void on_tvStreamList_activated(const QModelIndex & index);
|
||||||
void when_portView_currentChanged(const QModelIndex& currentIndex,
|
void when_portView_currentChanged(const QModelIndex& currentIndex,
|
||||||
const QModelIndex& previousIndex);
|
const QModelIndex& previousIndex);
|
||||||
void when_portModel_dataChanged(const QModelIndex& topLeft,
|
void when_portModel_dataChanged(const QModelIndex& topLeft,
|
||||||
@ -80,14 +92,17 @@ private slots:
|
|||||||
void on_actionDisconnect_Port_Group_triggered();
|
void on_actionDisconnect_Port_Group_triggered();
|
||||||
|
|
||||||
void on_actionExclusive_Control_triggered(bool checked);
|
void on_actionExclusive_Control_triggered(bool checked);
|
||||||
void when_actionPort_Configuration_triggered(
|
void on_actionPort_Configuration_triggered();
|
||||||
const QModelIndex &portIndex = QModelIndex());
|
|
||||||
|
|
||||||
private:
|
void on_actionNew_Stream_triggered();
|
||||||
PortGroupList *plm;
|
void on_actionEdit_Stream_triggered();
|
||||||
QString lastNewPortGroup;
|
void on_actionDuplicate_Stream_triggered();
|
||||||
QSortFilterProxyModel *proxyPortModel;
|
void on_actionDelete_Stream_triggered();
|
||||||
ApplyMessage *applyMsg_;
|
|
||||||
|
void on_actionOpen_Streams_triggered();
|
||||||
|
void on_actionSave_Streams_triggered();
|
||||||
|
|
||||||
|
void streamModelDataChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
<widget class="QStackedWidget" name="swDetail">
|
<widget class="QStackedWidget" name="swDetail">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
<horstretch>1</horstretch>
|
<horstretch>2</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
@ -51,7 +51,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><p><b>Welcome to Ostinato!</b></p>
|
<string><p><b>Welcome to Ostinato</b></p>
|
||||||
<p>The port list on the left contains all the ports on which you can transmit packets.</p>
|
<p>The port list on the left contains all the ports on which you can transmit packets.</p>
|
||||||
<p>Ports belong to a port group. Make sure the Port Group has a <img src=":/icons/bullet_green.png"/> next to it, then double click the port group to show or hide the ports in the port group.</p>
|
<p>Ports belong to a port group. Make sure the Port Group has a <img src=":/icons/bullet_green.png"/> next to it, then double click the port group to show or hide the ports in the port group.</p>
|
||||||
<p>To generate packets, you need to create and configure packet streams. A stream is a sequence of one or more packets.</p>
|
<p>To generate packets, you need to create and configure packet streams. A stream is a sequence of one or more packets.</p>
|
||||||
@ -126,16 +126,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="portDetail">
|
<widget class="QWidget" name="portDetail">
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout">
|
||||||
<property name="leftMargin">
|
<property name="margin">
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
@ -147,16 +138,7 @@
|
|||||||
<enum>QFrame::Raised</enum>
|
<enum>QFrame::Raised</enum>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<property name="leftMargin">
|
<property name="margin">
|
||||||
<number>3</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>3</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>3</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>3</number>
|
<number>3</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
@ -213,10 +195,114 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="PortWidget" name="portWidget" native="true"/>
|
<layout class="QHBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="startTx">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Start Transmit</string>
|
||||||
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Start transmit on selected port</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="ostinato.qrc">
|
||||||
|
<normaloff>:/icons/control_play.png</normaloff>:/icons/control_play.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="StreamsWidget" name="streamsWidget" native="true"/>
|
<widget class="QToolButton" name="stopTx">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Stop Transmit</string>
|
||||||
|
</property>
|
||||||
|
<property name="statusTip">
|
||||||
|
<string>Stop transmit on selected port</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="ostinato.qrc">
|
||||||
|
<normaloff>:/icons/control_stop.png</normaloff>:/icons/control_stop.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="radioButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Avg pps</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="averagePacketsPerSec"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="radioButton_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Avg bps</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="averageBitsPerSec">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="XTableView" name="tvStreamList">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>1</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="contextMenuPolicy">
|
||||||
|
<enum>Qt::ActionsContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="whatsThis">
|
||||||
|
<string>This is the stream list for the selected port
|
||||||
|
|
||||||
|
A stream is a sequence of one or more packets
|
||||||
|
|
||||||
|
Right-click to create a stream</string>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="lineWidth">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
@ -274,6 +360,33 @@
|
|||||||
<string>Disconnect Port Group</string>
|
<string>Disconnect Port Group</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionNew_Stream">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="ostinato.qrc">
|
||||||
|
<normaloff>:/icons/stream_add.png</normaloff>:/icons/stream_add.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>New Stream</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDelete_Stream">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="ostinato.qrc">
|
||||||
|
<normaloff>:/icons/stream_delete.png</normaloff>:/icons/stream_delete.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete Stream</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionEdit_Stream">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="ostinato.qrc">
|
||||||
|
<normaloff>:/icons/stream_edit.png</normaloff>:/icons/stream_edit.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit Stream</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
<action name="actionExclusive_Control">
|
<action name="actionExclusive_Control">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@ -282,11 +395,30 @@
|
|||||||
<string>Exclusive Port Control (EXPERIMENTAL)</string>
|
<string>Exclusive Port Control (EXPERIMENTAL)</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionOpen_Streams">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open Streams ...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_Streams">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save Streams ...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
<action name="actionPort_Configuration">
|
<action name="actionPort_Configuration">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Port Configuration ...</string>
|
<string>Port Configuration ...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionDuplicate_Stream">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="ostinato.qrc">
|
||||||
|
<normaloff>:/icons/stream_duplicate.png</normaloff>:/icons/stream_duplicate.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Duplicate Stream</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
@ -301,20 +433,46 @@
|
|||||||
<header>xtreeview.h</header>
|
<header>xtreeview.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>StreamsWidget</class>
|
<class>XTableView</class>
|
||||||
<extends>QWidget</extends>
|
<extends>QTableView</extends>
|
||||||
<header>streamswidget.h</header>
|
<header>xtableview.h</header>
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
|
||||||
<class>PortWidget</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>portwidget.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="ostinato.qrc"/>
|
<include location="ostinato.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
<connections/>
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>radioButton</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>averagePacketsPerSec</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>326</x>
|
||||||
|
<y>80</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>454</x>
|
||||||
|
<y>79</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>radioButton_2</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>averageBitsPerSec</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>523</x>
|
||||||
|
<y>80</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>651</x>
|
||||||
|
<y>88</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -1,186 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2010 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "portwidget.h"
|
|
||||||
|
|
||||||
#include "portgrouplist.h"
|
|
||||||
#include "xqlocale.h"
|
|
||||||
|
|
||||||
#include <cfloat>
|
|
||||||
|
|
||||||
PortWidget::PortWidget(QWidget *parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
|
||||||
setupUi(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortWidget::setPortGroupList(PortGroupList *portGroups)
|
|
||||||
{
|
|
||||||
plm = portGroups;
|
|
||||||
|
|
||||||
connect(plm->getStreamModel(), SIGNAL(rowsInserted(QModelIndex, int, int)),
|
|
||||||
SLOT(updatePortActions()));
|
|
||||||
connect(plm->getStreamModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)),
|
|
||||||
SLOT(updatePortActions()));
|
|
||||||
connect(plm->getStreamModel(), SIGNAL(modelReset()),
|
|
||||||
SLOT(updatePortActions()));
|
|
||||||
|
|
||||||
updatePortActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
PortWidget::~PortWidget()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortWidget::setCurrentPortIndex(const QModelIndex ¤tIndex,
|
|
||||||
const QModelIndex &previousIndex)
|
|
||||||
{
|
|
||||||
if (!plm)
|
|
||||||
return;
|
|
||||||
|
|
||||||
qDebug("In %s", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
// XXX: We assume indices corresponds to sourceModel, not proxyModel
|
|
||||||
// - caller/sender should ensure this
|
|
||||||
|
|
||||||
// Disconnect previous port
|
|
||||||
if (plm->isPort(previousIndex))
|
|
||||||
disconnect(&(plm->port(previousIndex)),
|
|
||||||
SIGNAL(portRateChanged(int, int)),
|
|
||||||
this, SLOT(updatePortRates()));
|
|
||||||
|
|
||||||
if (!plm->isPort(currentIndex)) {
|
|
||||||
currentPortIndex_ = QModelIndex(); // set to invalid
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPortIndex_ = currentIndex;
|
|
||||||
|
|
||||||
// Connect current port
|
|
||||||
connect(&(plm->port(currentPortIndex_)),
|
|
||||||
SIGNAL(portRateChanged(int, int)),
|
|
||||||
this, SLOT(updatePortRates()));
|
|
||||||
|
|
||||||
double speed = plm->port(currentPortIndex_).speed();
|
|
||||||
portSpeed->setText(QString("Max %L1 Mbps").arg(speed));
|
|
||||||
|
|
||||||
rbLoad->setVisible(speed > 0);
|
|
||||||
averageLoadPercent->setVisible(speed > 0);
|
|
||||||
speedSep->setVisible(speed > 0);
|
|
||||||
portSpeed->setVisible(speed > 0);
|
|
||||||
|
|
||||||
updatePortRates();
|
|
||||||
updatePortActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortWidget::on_startTx_clicked()
|
|
||||||
{
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
QModelIndex curPortGroup = plm->getPortModel()->parent(currentPortIndex_);
|
|
||||||
Q_ASSERT(curPortGroup.isValid());
|
|
||||||
Q_ASSERT(plm->isPortGroup(curPortGroup));
|
|
||||||
|
|
||||||
QList<uint> portList({plm->port(currentPortIndex_).id()});
|
|
||||||
plm->portGroup(curPortGroup).startTx(&portList);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortWidget::on_stopTx_clicked()
|
|
||||||
{
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
QModelIndex curPortGroup = plm->getPortModel()->parent(currentPortIndex_);
|
|
||||||
Q_ASSERT(curPortGroup.isValid());
|
|
||||||
Q_ASSERT(plm->isPortGroup(curPortGroup));
|
|
||||||
|
|
||||||
QList<uint> portList({plm->port(currentPortIndex_).id()});
|
|
||||||
plm->portGroup(curPortGroup).stopTx(&portList);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortWidget::on_averageLoadPercent_editingFinished()
|
|
||||||
{
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
plm->port(currentPortIndex_).setAverageLoadRate(
|
|
||||||
averageLoadPercent->value()/100);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortWidget::on_averagePacketsPerSec_editingFinished()
|
|
||||||
{
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
bool isOk;
|
|
||||||
double pps = XLocale().toPacketsPerSecond(averagePacketsPerSec->text(),
|
|
||||||
&isOk);
|
|
||||||
|
|
||||||
if (isOk)
|
|
||||||
plm->port(currentPortIndex_).setAveragePacketRate(pps);
|
|
||||||
else
|
|
||||||
updatePortRates();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortWidget::on_averageBitsPerSec_editingFinished()
|
|
||||||
{
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
bool isOk;
|
|
||||||
double bps = XLocale().toBitsPerSecond(averageBitsPerSec->text(), &isOk);
|
|
||||||
|
|
||||||
if (isOk)
|
|
||||||
plm->port(currentPortIndex_).setAverageBitRate(bps);
|
|
||||||
else
|
|
||||||
updatePortRates();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortWidget::updatePortRates()
|
|
||||||
{
|
|
||||||
if (!currentPortIndex_.isValid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!plm->isPort(currentPortIndex_))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// XXX: pps/bps input widget is a LineEdit and not a SpinBox
|
|
||||||
// because we want users to be able to enter values in various
|
|
||||||
// units e.g. "1.5 Mbps", "1000K", "50" (bps) etc.
|
|
||||||
|
|
||||||
// XXX: It's a considered decision NOT to show frame rate in
|
|
||||||
// higher units of Kpps and Mpps as most users may not be
|
|
||||||
// familiar with those and also we want frame rate to have a
|
|
||||||
// high resolution for input e.g. if user enters 1,488,095.2381
|
|
||||||
// it should NOT be shown as 1.4881 Mpps
|
|
||||||
|
|
||||||
averagePacketsPerSec->setText(QString("%L1 pps")
|
|
||||||
.arg(plm->port(currentPortIndex_).averagePacketRate(), 0, 'f', 4));
|
|
||||||
|
|
||||||
averageBitsPerSec->setText(XLocale().toBitRateString(
|
|
||||||
plm->port(currentPortIndex_).averageBitRate()));
|
|
||||||
|
|
||||||
averageLoadPercent->setValue(
|
|
||||||
plm->port(currentPortIndex_).averageLoadRate()*100);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PortWidget::updatePortActions()
|
|
||||||
{
|
|
||||||
if (!plm->isPort(currentPortIndex_))
|
|
||||||
return;
|
|
||||||
|
|
||||||
startTx->setEnabled(plm->port(currentPortIndex_).numStreams() > 0);
|
|
||||||
stopTx->setEnabled(plm->port(currentPortIndex_).numStreams() > 0);
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2010 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _PORT_WIDGET_H
|
|
||||||
#define _PORT_WIDGET_H
|
|
||||||
|
|
||||||
#include "ui_portwidget.h"
|
|
||||||
#include <QModelIndex>
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
class PortGroupList;
|
|
||||||
|
|
||||||
class PortWidget : public QWidget, private Ui::PortWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
PortWidget(QWidget *parent = 0);
|
|
||||||
~PortWidget();
|
|
||||||
|
|
||||||
void setPortGroupList(PortGroupList *portGroups);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void setCurrentPortIndex(const QModelIndex ¤tIndex,
|
|
||||||
const QModelIndex &previousIndex);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
|
|
||||||
|
|
||||||
void on_startTx_clicked();
|
|
||||||
void on_stopTx_clicked();
|
|
||||||
void on_averageLoadPercent_editingFinished();
|
|
||||||
void on_averagePacketsPerSec_editingFinished();
|
|
||||||
void on_averageBitsPerSec_editingFinished();
|
|
||||||
|
|
||||||
void updatePortActions();
|
|
||||||
void updatePortRates();
|
|
||||||
|
|
||||||
private:
|
|
||||||
PortGroupList *plm{nullptr}; // FIXME: rename to portGroups_?
|
|
||||||
QModelIndex currentPortIndex_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,218 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>PortWidget</class>
|
|
||||||
<widget class="QWidget" name="PortWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>806</width>
|
|
||||||
<height>73</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="startTx">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Start Transmit</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string>Start transmit on selected port</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="ostinato.qrc">
|
|
||||||
<normaloff>:/icons/control_play.png</normaloff>:/icons/control_play.png</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QToolButton" name="stopTx">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Stop Transmit</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string>Stop transmit on selected port</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="ostinato.qrc">
|
|
||||||
<normaloff>:/icons/control_stop.png</normaloff>:/icons/control_stop.png</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer>
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="Line" name="rateSep">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QRadioButton" name="radioButton">
|
|
||||||
<property name="text">
|
|
||||||
<string>Frame Rate</string>
|
|
||||||
</property>
|
|
||||||
<property name="checked">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="averagePacketsPerSec"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QRadioButton" name="radioButton_2">
|
|
||||||
<property name="text">
|
|
||||||
<string>Bit Rate</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLineEdit" name="averageBitsPerSec">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Bit rate on the line including overhead such as Preamble, IPG, FCS etc.</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QRadioButton" name="rbLoad">
|
|
||||||
<property name="text">
|
|
||||||
<string>Load</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QDoubleSpinBox" name="averageLoadPercent">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="buttonSymbols">
|
|
||||||
<enum>QAbstractSpinBox::NoButtons</enum>
|
|
||||||
</property>
|
|
||||||
<property name="suffix">
|
|
||||||
<string>%</string>
|
|
||||||
</property>
|
|
||||||
<property name="decimals">
|
|
||||||
<number>4</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>999.999900000000025</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="Line" name="speedSep">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="portSpeed">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Port Speed</string>
|
|
||||||
</property>
|
|
||||||
<property name="statusTip">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Max speed</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources>
|
|
||||||
<include location="ostinato.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections>
|
|
||||||
<connection>
|
|
||||||
<sender>radioButton</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>averagePacketsPerSec</receiver>
|
|
||||||
<slot>setEnabled(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>450</x>
|
|
||||||
<y>44</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>593</x>
|
|
||||||
<y>45</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>radioButton_2</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>averageBitsPerSec</receiver>
|
|
||||||
<slot>setEnabled(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>661</x>
|
|
||||||
<y>44</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>804</x>
|
|
||||||
<y>45</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
<connection>
|
|
||||||
<sender>rbLoad</sender>
|
|
||||||
<signal>toggled(bool)</signal>
|
|
||||||
<receiver>averageLoadPercent</receiver>
|
|
||||||
<slot>setEnabled(bool)</slot>
|
|
||||||
<hints>
|
|
||||||
<hint type="sourcelabel">
|
|
||||||
<x>281</x>
|
|
||||||
<y>43</y>
|
|
||||||
</hint>
|
|
||||||
<hint type="destinationlabel">
|
|
||||||
<x>308</x>
|
|
||||||
<y>45</y>
|
|
||||||
</hint>
|
|
||||||
</hints>
|
|
||||||
</connection>
|
|
||||||
</connections>
|
|
||||||
</ui>
|
|
@ -21,11 +21,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
#include "../common/ostprotolib.h"
|
#include "../common/ostprotolib.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "thememanager.h"
|
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QXmlStreamReader>
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN32)
|
#if defined(Q_OS_WIN32)
|
||||||
QString kGzipPathDefaultValue;
|
QString kGzipPathDefaultValue;
|
||||||
@ -41,7 +39,6 @@ Preferences::Preferences()
|
|||||||
|
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
|
||||||
// Program paths
|
|
||||||
wiresharkPathEdit->setText(appSettings->value(kWiresharkPathKey,
|
wiresharkPathEdit->setText(appSettings->value(kWiresharkPathKey,
|
||||||
kWiresharkPathDefaultValue).toString());
|
kWiresharkPathDefaultValue).toString());
|
||||||
tsharkPathEdit->setText(appSettings->value(kTsharkPathKey,
|
tsharkPathEdit->setText(appSettings->value(kTsharkPathKey,
|
||||||
@ -53,10 +50,6 @@ Preferences::Preferences()
|
|||||||
awkPathEdit->setText(appSettings->value(kAwkPathKey,
|
awkPathEdit->setText(appSettings->value(kAwkPathKey,
|
||||||
kAwkPathDefaultValue).toString());
|
kAwkPathDefaultValue).toString());
|
||||||
|
|
||||||
// Theme
|
|
||||||
theme->addItems(ThemeManager::instance()->themeList());
|
|
||||||
theme->setCurrentText(appSettings->value(kThemeKey).toString());
|
|
||||||
|
|
||||||
// TODO(only if required): kUserKey
|
// TODO(only if required): kUserKey
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +77,6 @@ void Preferences::initDefaults()
|
|||||||
|
|
||||||
void Preferences::accept()
|
void Preferences::accept()
|
||||||
{
|
{
|
||||||
// Program paths
|
|
||||||
appSettings->setValue(kWiresharkPathKey, wiresharkPathEdit->text());
|
appSettings->setValue(kWiresharkPathKey, wiresharkPathEdit->text());
|
||||||
appSettings->setValue(kTsharkPathKey, tsharkPathEdit->text());
|
appSettings->setValue(kTsharkPathKey, tsharkPathEdit->text());
|
||||||
appSettings->setValue(kGzipPathKey, gzipPathEdit->text());
|
appSettings->setValue(kGzipPathKey, gzipPathEdit->text());
|
||||||
@ -97,9 +89,6 @@ void Preferences::accept()
|
|||||||
appSettings->value(kDiffPathKey, kDiffPathDefaultValue).toString(),
|
appSettings->value(kDiffPathKey, kDiffPathDefaultValue).toString(),
|
||||||
appSettings->value(kAwkPathKey, kAwkPathDefaultValue).toString());
|
appSettings->value(kAwkPathKey, kAwkPathDefaultValue).toString());
|
||||||
|
|
||||||
// Theme
|
|
||||||
ThemeManager::instance()->setTheme(theme->currentText());
|
|
||||||
|
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,31 +98,6 @@ void Preferences::on_wiresharkPathButton_clicked()
|
|||||||
|
|
||||||
path = QFileDialog::getOpenFileName(0, "Locate Wireshark",
|
path = QFileDialog::getOpenFileName(0, "Locate Wireshark",
|
||||||
wiresharkPathEdit->text());
|
wiresharkPathEdit->text());
|
||||||
#ifdef Q_OS_MAC
|
|
||||||
// Find executable inside app bundle using Info.plist
|
|
||||||
if (!path.isEmpty() && path.endsWith(".app")) {
|
|
||||||
QFile plist(path+"/Contents/Info.plist");
|
|
||||||
plist.open(QIODevice::ReadOnly);
|
|
||||||
QXmlStreamReader xml(&plist);
|
|
||||||
|
|
||||||
while (!xml.atEnd()) {
|
|
||||||
xml.readNext();
|
|
||||||
if (xml.isStartElement()
|
|
||||||
&& (xml.name() == "key")
|
|
||||||
&& (xml.readElementText() == "CFBundleExecutable")) {
|
|
||||||
xml.readNext(); // </key>
|
|
||||||
xml.readNext(); // <string>
|
|
||||||
if (xml.isStartElement() && (xml.name() == "string"))
|
|
||||||
path = path+"/Contents/MacOs/"+xml.readElementText();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (xml.hasError())
|
|
||||||
qDebug("%lld:%lld Error reading Info.plist: %s",
|
|
||||||
xml.lineNumber(), xml.columnNumber(),
|
|
||||||
qPrintable(xml.errorString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!path.isEmpty())
|
if (!path.isEmpty())
|
||||||
wiresharkPathEdit->setText(path);
|
wiresharkPathEdit->setText(path);
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<ui version="4.0" >
|
||||||
<ui version="4.0">
|
|
||||||
<class>Preferences</class>
|
<class>Preferences</class>
|
||||||
<widget class="QDialog" name="Preferences">
|
<widget class="QDialog" name="Preferences" >
|
||||||
<property name="geometry">
|
<property name="geometry" >
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
@ -10,149 +9,148 @@
|
|||||||
<height>220</height>
|
<height>220</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle" >
|
||||||
<string>Preferences</string>
|
<string>Preferences</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowIcon">
|
<property name="windowIcon" >
|
||||||
<iconset resource="ostinato.qrc">
|
<iconset resource="ostinato.qrc" >:/icons/preferences.png</iconset>
|
||||||
<normaloff>:/icons/preferences.png</normaloff>:/icons/preferences.png</iconset>
|
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout" >
|
||||||
<item>
|
<item>
|
||||||
<widget class="QFrame" name="frame">
|
<widget class="QFrame" name="frame" >
|
||||||
<property name="frameShape">
|
<property name="frameShape" >
|
||||||
<enum>QFrame::Box</enum>
|
<enum>QFrame::Box</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShadow">
|
<property name="frameShadow" >
|
||||||
<enum>QFrame::Sunken</enum>
|
<enum>QFrame::Sunken</enum>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout">
|
<layout class="QGridLayout" >
|
||||||
<item row="0" column="0">
|
<item row="0" column="0" >
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>'wireshark' Path</string>
|
<string>'wireshark' Path</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy" >
|
||||||
<cstring>wiresharkPathEdit</cstring>
|
<cstring>wiresharkPathEdit</cstring>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1" >
|
||||||
<widget class="QLineEdit" name="wiresharkPathEdit">
|
<widget class="QLineEdit" name="wiresharkPathEdit" >
|
||||||
<property name="enabled">
|
<property name="enabled" >
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="2">
|
<item row="0" column="2" >
|
||||||
<widget class="QToolButton" name="wiresharkPathButton">
|
<widget class="QToolButton" name="wiresharkPathButton" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0" >
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>'tshark' Path</string>
|
<string>'tshark' Path</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy" >
|
||||||
<cstring>tsharkPathEdit</cstring>
|
<cstring>tsharkPathEdit</cstring>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1" >
|
||||||
<widget class="QLineEdit" name="tsharkPathEdit">
|
<widget class="QLineEdit" name="tsharkPathEdit" >
|
||||||
<property name="enabled">
|
<property name="enabled" >
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="2">
|
<item row="1" column="2" >
|
||||||
<widget class="QToolButton" name="tsharkPathButton">
|
<widget class="QToolButton" name="tsharkPathButton" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0" >
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label_5" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>'gzip' Path</string>
|
<string>'gzip' Path</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy" >
|
||||||
<cstring>diffPathEdit</cstring>
|
<cstring>diffPathEdit</cstring>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1" >
|
||||||
<widget class="QLineEdit" name="gzipPathEdit">
|
<widget class="QLineEdit" name="gzipPathEdit" >
|
||||||
<property name="enabled">
|
<property name="enabled" >
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="2">
|
<item row="2" column="2" >
|
||||||
<widget class="QToolButton" name="gzipPathButton">
|
<widget class="QToolButton" name="gzipPathButton" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="0" >
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QLabel" name="label_3" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>'diff' Path</string>
|
<string>'diff' Path</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy" >
|
||||||
<cstring>diffPathEdit</cstring>
|
<cstring>diffPathEdit</cstring>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="3" column="1" >
|
||||||
<widget class="QLineEdit" name="diffPathEdit">
|
<widget class="QLineEdit" name="diffPathEdit" >
|
||||||
<property name="enabled">
|
<property name="enabled" >
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="2">
|
<item row="3" column="2" >
|
||||||
<widget class="QToolButton" name="diffPathButton">
|
<widget class="QToolButton" name="diffPathButton" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="4" column="0" >
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>'awk' Path</string>
|
<string>'awk' Path</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy">
|
<property name="buddy" >
|
||||||
<cstring>awkPathEdit</cstring>
|
<cstring>awkPathEdit</cstring>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="4" column="1" >
|
||||||
<widget class="QLineEdit" name="awkPathEdit">
|
<widget class="QLineEdit" name="awkPathEdit" >
|
||||||
<property name="enabled">
|
<property name="enabled" >
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="2">
|
<item row="4" column="2" >
|
||||||
<widget class="QToolButton" name="awkPathButton">
|
<widget class="QToolButton" name="awkPathButton" >
|
||||||
<property name="text">
|
<property name="text" >
|
||||||
<string>...</string>
|
<string>...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="1">
|
<item row="5" column="1" >
|
||||||
<spacer>
|
<spacer>
|
||||||
<property name="orientation">
|
<property name="orientation" >
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="sizeHint" >
|
||||||
<size>
|
<size>
|
||||||
<width>21</width>
|
<width>21</width>
|
||||||
<height>61</height>
|
<height>61</height>
|
||||||
@ -164,26 +162,12 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||||
<item>
|
<property name="orientation" >
|
||||||
<widget class="QLabel" name="label_6">
|
|
||||||
<property name="text">
|
|
||||||
<string>Theme (Experimental)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="theme"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="standardButtons">
|
<property name="standardButtons" >
|
||||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -203,7 +187,7 @@
|
|||||||
<tabstop>buttonBox</tabstop>
|
<tabstop>buttonBox</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="ostinato.qrc"/>
|
<include location="ostinato.qrc" />
|
||||||
</resources>
|
</resources>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
@ -212,11 +196,11 @@
|
|||||||
<receiver>Preferences</receiver>
|
<receiver>Preferences</receiver>
|
||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel" >
|
||||||
<x>248</x>
|
<x>248</x>
|
||||||
<y>254</y>
|
<y>254</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel" >
|
||||||
<x>157</x>
|
<x>157</x>
|
||||||
<y>274</y>
|
<y>274</y>
|
||||||
</hint>
|
</hint>
|
||||||
@ -228,11 +212,11 @@
|
|||||||
<receiver>Preferences</receiver>
|
<receiver>Preferences</receiver>
|
||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel">
|
<hint type="sourcelabel" >
|
||||||
<x>316</x>
|
<x>316</x>
|
||||||
<y>260</y>
|
<y>260</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel">
|
<hint type="destinationlabel" >
|
||||||
<x>286</x>
|
<x>286</x>
|
||||||
<y>274</y>
|
<y>274</y>
|
||||||
</hint>
|
</hint>
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2023 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _ROW_BORDER_DELEGATE
|
|
||||||
#define _ROW_BORDER_DELEGATE
|
|
||||||
|
|
||||||
#include <QStyledItemDelegate>
|
|
||||||
|
|
||||||
#include <QSet>
|
|
||||||
|
|
||||||
class RowBorderDelegate : public QStyledItemDelegate
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RowBorderDelegate(QSet<int> rows, QObject *parent = nullptr)
|
|
||||||
: QStyledItemDelegate(parent), rows_(rows)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
|
||||||
const QModelIndex &index) const
|
|
||||||
{
|
|
||||||
QStyledItemDelegate::paint(painter, option, index);
|
|
||||||
if (rows_.contains(index.row())) {
|
|
||||||
const QRect rect(option.rect);
|
|
||||||
painter->drawLine(rect.topLeft(), rect.topRight());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QSet<int> rows_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -31,7 +31,7 @@ const QString kWiresharkPathDefaultValue(
|
|||||||
"C:/Program Files/Wireshark/wireshark.exe");
|
"C:/Program Files/Wireshark/wireshark.exe");
|
||||||
#elif defined(Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
const QString kWiresharkPathDefaultValue(
|
const QString kWiresharkPathDefaultValue(
|
||||||
"/Applications/Wireshark.app/Contents/MacOS/Wireshark");
|
"/Applications/Wireshark.app/Contents/Resources/bin/wireshark");
|
||||||
#else
|
#else
|
||||||
const QString kWiresharkPathDefaultValue("/usr/bin/wireshark");
|
const QString kWiresharkPathDefaultValue("/usr/bin/wireshark");
|
||||||
#endif
|
#endif
|
||||||
@ -74,8 +74,6 @@ const QString kAwkPathDefaultValue("/usr/bin/awk");
|
|||||||
const QString kAwkPathDefaultValue("/usr/bin/awk");
|
const QString kAwkPathDefaultValue("/usr/bin/awk");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const QString kThemeKey("Theme");
|
|
||||||
|
|
||||||
const QString kUserKey("User");
|
const QString kUserKey("User");
|
||||||
extern QString kUserDefaultValue;
|
extern QString kUserDefaultValue;
|
||||||
|
|
||||||
|
@ -432,12 +432,6 @@ void StreamConfigDialog::on_cmbPktLenMode_currentIndexChanged(QString mode)
|
|||||||
lePktLenMin->setEnabled(true);
|
lePktLenMin->setEnabled(true);
|
||||||
lePktLenMax->setEnabled(true);
|
lePktLenMax->setEnabled(true);
|
||||||
}
|
}
|
||||||
else if (mode == "IMIX")
|
|
||||||
{
|
|
||||||
lePktLen->setDisabled(true);
|
|
||||||
lePktLenMin->setDisabled(true);
|
|
||||||
lePktLenMax->setDisabled(true);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qWarning("Unhandled/Unknown PktLenMode = %s", qPrintable(mode));
|
qWarning("Unhandled/Unknown PktLenMode = %s", qPrintable(mode));
|
||||||
@ -1171,7 +1165,12 @@ void StreamConfigDialog::on_lePacketsPerSec_textChanged(const QString &text)
|
|||||||
{
|
{
|
||||||
bool isOk;
|
bool isOk;
|
||||||
Stream *pStream = mpStream;
|
Stream *pStream = mpStream;
|
||||||
uint frameLen = pStream->frameLenAvg();
|
uint frameLen;
|
||||||
|
|
||||||
|
if (pStream->lenMode() == Stream::e_fl_fixed)
|
||||||
|
frameLen = pStream->frameLen();
|
||||||
|
else
|
||||||
|
frameLen = (pStream->frameLenMin() + pStream->frameLenMax())/2;
|
||||||
|
|
||||||
if (rbSendPackets->isChecked())
|
if (rbSendPackets->isChecked())
|
||||||
{
|
{
|
||||||
@ -1190,9 +1189,13 @@ void StreamConfigDialog::on_leBurstsPerSec_textChanged(const QString &text)
|
|||||||
bool isOk;
|
bool isOk;
|
||||||
Stream *pStream = mpStream;
|
Stream *pStream = mpStream;
|
||||||
uint burstSize = lePacketsPerBurst->text().toULong(&isOk);
|
uint burstSize = lePacketsPerBurst->text().toULong(&isOk);
|
||||||
uint frameLen = pStream->frameLenAvg();
|
uint frameLen;
|
||||||
|
|
||||||
qDebug("start of %s(%s)", __FUNCTION__, qPrintable(text));
|
qDebug("start of %s(%s)", __FUNCTION__, qPrintable(text));
|
||||||
|
if (pStream->lenMode() == Stream::e_fl_fixed)
|
||||||
|
frameLen = pStream->frameLen();
|
||||||
|
else
|
||||||
|
frameLen = (pStream->frameLenMin() + pStream->frameLenMax())/2;
|
||||||
|
|
||||||
if (rbSendBursts->isChecked())
|
if (rbSendBursts->isChecked())
|
||||||
{
|
{
|
||||||
@ -1212,7 +1215,12 @@ void StreamConfigDialog::on_leBitsPerSec_textEdited(const QString &text)
|
|||||||
bool isOk;
|
bool isOk;
|
||||||
Stream *pStream = mpStream;
|
Stream *pStream = mpStream;
|
||||||
uint burstSize = lePacketsPerBurst->text().toULong(&isOk);
|
uint burstSize = lePacketsPerBurst->text().toULong(&isOk);
|
||||||
uint frameLen = pStream->frameLenAvg();
|
uint frameLen;
|
||||||
|
|
||||||
|
if (pStream->lenMode() == Stream::e_fl_fixed)
|
||||||
|
frameLen = pStream->frameLen();
|
||||||
|
else
|
||||||
|
frameLen = (pStream->frameLenMin() + pStream->frameLenMax())/2;
|
||||||
|
|
||||||
if (rbSendPackets->isChecked())
|
if (rbSendPackets->isChecked())
|
||||||
{
|
{
|
||||||
|
@ -108,11 +108,6 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-colo
|
|||||||
<string>Random</string>
|
<string>Random</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<property name="text">
|
|
||||||
<string>IMIX</string>
|
|
||||||
</property>
|
|
||||||
</item>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
@ -675,19 +670,6 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-colo
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
|
||||||
<spacer name="verticalSpacer">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Vertical</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>20</width>
|
|
||||||
<height>40</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="page_2">
|
<widget class="QWidget" name="page_2">
|
||||||
|
@ -22,10 +22,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "portgrouplist.h"
|
#include "portgrouplist.h"
|
||||||
#include "qicon.h"
|
#include "qicon.h"
|
||||||
|
|
||||||
#include <QMimeData>
|
|
||||||
|
|
||||||
const QLatin1String kStreamsMimeType("application/vnd.ostinato.streams");
|
|
||||||
|
|
||||||
StreamModel::StreamModel(PortGroupList *p, QObject *parent)
|
StreamModel::StreamModel(PortGroupList *p, QObject *parent)
|
||||||
: QAbstractTableModel(parent)
|
: QAbstractTableModel(parent)
|
||||||
{
|
{
|
||||||
@ -227,77 +223,6 @@ QVariant StreamModel::headerData(int section, Qt::Orientation orientation, int r
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList StreamModel::mimeTypes() const
|
|
||||||
{
|
|
||||||
return QStringList() << kStreamsMimeType;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMimeData* StreamModel::mimeData(const QModelIndexList &indexes) const
|
|
||||||
{
|
|
||||||
using ::google::protobuf::uint8;
|
|
||||||
|
|
||||||
if (indexes.isEmpty())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
// indexes may include multiple columns for a row - but we are only
|
|
||||||
// interested in rows 'coz we have a single data for all columns
|
|
||||||
// XXX: use QMap instead of QSet to keep rows in sorted order
|
|
||||||
QMap<int, int> rows;
|
|
||||||
foreach(QModelIndex index, indexes)
|
|
||||||
rows.insert(index.row(), index.row());
|
|
||||||
|
|
||||||
OstProto::StreamConfigList streams;
|
|
||||||
streams.mutable_port_id()->set_id(mCurrentPort->id());
|
|
||||||
foreach(int row, rows) {
|
|
||||||
OstProto::Stream *stream = streams.add_stream();
|
|
||||||
mCurrentPort->streamByIndex(row)->protoDataCopyInto(*stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray data;
|
|
||||||
data.resize(streams.ByteSize());
|
|
||||||
streams.SerializeWithCachedSizesToArray((uint8*)data.data());
|
|
||||||
//qDebug("copy %s", streams.DebugString().c_str());
|
|
||||||
//TODO: copy DebugString as text/plain?
|
|
||||||
|
|
||||||
QMimeData *mimeData = new QMimeData();
|
|
||||||
mimeData->setData(kStreamsMimeType, data);
|
|
||||||
return mimeData; // XXX: caller is expected to take ownership and free!
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StreamModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
|
|
||||||
int row, int /*column*/, const QModelIndex &parent)
|
|
||||||
{
|
|
||||||
if (!data)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!data->hasFormat(kStreamsMimeType))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (action != Qt::CopyAction)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
OstProto::StreamConfigList streamsData;
|
|
||||||
QByteArray ba(data->data(kStreamsMimeType));
|
|
||||||
streamsData.ParseFromArray((void*)ba.constData(), ba.size());
|
|
||||||
//qDebug("paste %s", streamsData.DebugString().c_str());
|
|
||||||
|
|
||||||
QList<Stream*> streams;
|
|
||||||
for (int i = 0; i < streamsData.stream_size(); i++) {
|
|
||||||
Stream *stream = new Stream;
|
|
||||||
stream->protoDataCopyFrom(streamsData.stream(i));
|
|
||||||
streams.append(stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((row < 0) || (row > rowCount(parent)))
|
|
||||||
row = rowCount(parent);
|
|
||||||
|
|
||||||
// Delete rows that we are going to overwrite
|
|
||||||
if (row < rowCount(parent))
|
|
||||||
removeRows(row, qMin(rowCount() - row, streams.size()));
|
|
||||||
|
|
||||||
return insert(row, streams); // callee will free streams after insert
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Inserts streams before the given row
|
* Inserts streams before the given row
|
||||||
*
|
*
|
||||||
@ -361,13 +286,15 @@ void StreamModel::setCurrentPortIndex(const QModelIndex ¤t)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug("change to valid port");
|
qDebug("change to valid port");
|
||||||
|
// Disconnect any existing connection to avoid duplication
|
||||||
|
// Qt 4.6 has Qt::UniqueConnection, but we want to remain compatible
|
||||||
|
// with earlier Qt versions
|
||||||
if (mCurrentPort)
|
if (mCurrentPort)
|
||||||
{
|
{
|
||||||
disconnect(mCurrentPort, SIGNAL(streamListChanged(int, int)),
|
disconnect(mCurrentPort, SIGNAL(streamListChanged(int, int)),
|
||||||
this, SLOT(when_mCurrentPort_streamListChanged(int, int)));
|
this, SLOT(when_mCurrentPort_streamListChanged(int, int)));
|
||||||
}
|
}
|
||||||
quint16 pg = current.internalId() >> 16;
|
quint16 pg = current.internalId() >> 16;
|
||||||
// TODO: make mCurrentPort a smart weak pointer
|
|
||||||
mCurrentPort = pgl->mPortGroups[pgl->indexOfPortGroup(pg)]->mPorts[current.row()];
|
mCurrentPort = pgl->mPortGroups[pgl->indexOfPortGroup(pg)]->mPorts[current.row()];
|
||||||
connect(mCurrentPort, SIGNAL(streamListChanged(int, int)),
|
connect(mCurrentPort, SIGNAL(streamListChanged(int, int)),
|
||||||
this, SLOT(when_mCurrentPort_streamListChanged(int, int)));
|
this, SLOT(when_mCurrentPort_streamListChanged(int, int)));
|
||||||
|
@ -39,19 +39,12 @@ class StreamModel : public QAbstractTableModel
|
|||||||
|
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
|
||||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
bool setData(const QModelIndex &index, const QVariant &value,
|
bool setData(const QModelIndex &index, const QVariant &value,
|
||||||
int role = Qt::EditRole);
|
int role = Qt::EditRole);
|
||||||
QVariant headerData(int section, Qt::Orientation orientation,
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
int role = Qt::DisplayRole) const;
|
int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
QStringList mimeTypes() const;
|
|
||||||
QMimeData* mimeData(const QModelIndexList &indexes) const;
|
|
||||||
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
|
|
||||||
int row, int column, const QModelIndex &parent);
|
|
||||||
|
|
||||||
bool insert(int row, QList<Stream*> &streams);
|
bool insert(int row, QList<Stream*> &streams);
|
||||||
bool insertRows (int row, int count,
|
bool insertRows (int row, int count,
|
||||||
const QModelIndex & parent = QModelIndex());
|
const QModelIndex & parent = QModelIndex());
|
||||||
|
@ -20,12 +20,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "streamstatsmodel.h"
|
#include "streamstatsmodel.h"
|
||||||
|
|
||||||
#include "protocol.pb.h"
|
#include "protocol.pb.h"
|
||||||
#include "xqlocale.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
#include <QFont>
|
|
||||||
#include <QPalette>
|
|
||||||
|
|
||||||
// XXX: Keep the enum in sync with it's string
|
// XXX: Keep the enum in sync with it's string
|
||||||
enum {
|
enum {
|
||||||
@ -46,26 +42,12 @@ enum {
|
|||||||
kAggrTxPkts,
|
kAggrTxPkts,
|
||||||
kAggrRxPkts,
|
kAggrRxPkts,
|
||||||
kAggrPktLoss,
|
kAggrPktLoss,
|
||||||
kTxDuration,
|
|
||||||
kAvgTxFrameRate,
|
|
||||||
kAvgRxFrameRate,
|
|
||||||
kAvgTxBitRate,
|
|
||||||
kAvgRxBitRate,
|
|
||||||
kAvgLatency,
|
|
||||||
kAvgJitter,
|
|
||||||
kMaxAggrStreamStats
|
kMaxAggrStreamStats
|
||||||
};
|
};
|
||||||
static QStringList aggrStatTitles = QStringList()
|
static QStringList aggrStatTitles = QStringList()
|
||||||
<< "Total\nTx Pkts"
|
<< "Total\nTx Pkts"
|
||||||
<< "Total\nRx Pkts"
|
<< "Total\nRx Pkts"
|
||||||
<< "Total\nPkt Loss"
|
<< "Total\nPkt Loss";
|
||||||
<< "Duration\n(secs)"
|
|
||||||
<< "Avg\nTx PktRate"
|
|
||||||
<< "Avg\nRx PktRate"
|
|
||||||
<< "Avg\nTx BitRate"
|
|
||||||
<< "Avg\nRx BitRate"
|
|
||||||
<< "Avg\nLatency"
|
|
||||||
<< "Avg\nJitter";
|
|
||||||
|
|
||||||
static const uint kAggrGuid = 0xffffffff;
|
static const uint kAggrGuid = 0xffffffff;
|
||||||
|
|
||||||
@ -121,35 +103,20 @@ QVariant StreamStatsModel::data(const QModelIndex &index, int role) const
|
|||||||
return Qt::AlignRight;
|
return Qt::AlignRight;
|
||||||
|
|
||||||
int portColumn = index.column() - kMaxAggrStreamStats;
|
int portColumn = index.column() - kMaxAggrStreamStats;
|
||||||
|
if (role == Qt::BackgroundRole) {
|
||||||
// Stylesheets typically don't use or set palette colors, so if
|
if (portColumn < 0)
|
||||||
// using one, don't use palette colors
|
return QBrush(QColor("lavender")); // Aggregate Column
|
||||||
if ((role == Qt::BackgroundRole) && qApp->styleSheet().isEmpty()) {
|
if (index.row() == (guidList_.size() - 1))
|
||||||
QPalette palette = QApplication::palette();
|
return QBrush(QColor("burlywood")); // Aggregate Row
|
||||||
if (index.row() == (guidList_.size() - 1)) // Aggregate Row
|
else if ((portColumn/kMaxStreamStats) & 1)
|
||||||
return palette.dark();
|
return QBrush(QColor("beige")); // Color alternate Ports
|
||||||
if (portColumn < 0) // Aggregate Column
|
|
||||||
return palette.alternateBase();
|
|
||||||
if ((portColumn/kMaxStreamStats) & 1) // Color alternate Ports
|
|
||||||
return palette.alternateBase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Guid guid = guidList_.at(index.row());
|
Guid guid = guidList_.at(index.row());
|
||||||
if ((role == Qt::ForegroundRole && qApp->styleSheet().isEmpty())) {
|
if (role == Qt::ForegroundRole) {
|
||||||
QPalette palette = QApplication::palette();
|
|
||||||
if ((index.column() == kAggrPktLoss)
|
if ((index.column() == kAggrPktLoss)
|
||||||
&& aggrGuidStats_.value(guid).pktLoss)
|
&& aggrGuidStats_.value(guid).pktLoss)
|
||||||
return palette.link();
|
return QBrush(QColor("firebrick"));
|
||||||
if (index.row() == (guidList_.size() - 1)) // Aggregate Row
|
|
||||||
return palette.brightText();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (role == Qt::FontRole ) {
|
|
||||||
if (index.row() == (guidList_.size() - 1)) { // Aggregate Row
|
|
||||||
QFont font;
|
|
||||||
font.setBold(true);
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (role != Qt::DisplayRole)
|
if (role != Qt::DisplayRole)
|
||||||
@ -164,42 +131,6 @@ QVariant StreamStatsModel::data(const QModelIndex &index, int role) const
|
|||||||
return QString("%L1").arg(aggrGuidStats_.value(guid).txPkts);
|
return QString("%L1").arg(aggrGuidStats_.value(guid).txPkts);
|
||||||
case kAggrPktLoss:
|
case kAggrPktLoss:
|
||||||
return QString("%L1").arg(aggrGuidStats_.value(guid).pktLoss);
|
return QString("%L1").arg(aggrGuidStats_.value(guid).pktLoss);
|
||||||
case kTxDuration:
|
|
||||||
return QString("%L1").arg(aggrGuidStats_.value(guid).txDuration);
|
|
||||||
case kAvgTxFrameRate:
|
|
||||||
return aggrGuidStats_.value(guid).txDuration <= 0 ? QString("-") :
|
|
||||||
XLocale().toPktRateString(
|
|
||||||
aggrGuidStats_.value(guid).txPkts
|
|
||||||
/ aggrGuidStats_.value(guid).txDuration);
|
|
||||||
case kAvgRxFrameRate:
|
|
||||||
return aggrGuidStats_.value(guid).txDuration <= 0 ? QString("-") :
|
|
||||||
XLocale().toPktRateString(
|
|
||||||
aggrGuidStats_.value(guid).rxPkts
|
|
||||||
/ aggrGuidStats_.value(guid).txDuration);
|
|
||||||
case kAvgTxBitRate:
|
|
||||||
return aggrGuidStats_.value(guid).txDuration <= 0 ? QString("-") :
|
|
||||||
XLocale().toBitRateString(
|
|
||||||
(aggrGuidStats_.value(guid).txBytes
|
|
||||||
+ 24 * aggrGuidStats_.value(guid).txPkts) * 8
|
|
||||||
/ aggrGuidStats_.value(guid).txDuration);
|
|
||||||
case kAvgRxBitRate:
|
|
||||||
return aggrGuidStats_.value(guid).txDuration <= 0 ? QString("-") :
|
|
||||||
XLocale().toBitRateString(
|
|
||||||
(aggrGuidStats_.value(guid).rxBytes
|
|
||||||
+ 24 * aggrGuidStats_.value(guid).rxPkts) * 8
|
|
||||||
/ aggrGuidStats_.value(guid).txDuration);
|
|
||||||
case kAvgLatency:
|
|
||||||
return aggrGuidStats_.value(guid).latencyCount <= 0
|
|
||||||
|| aggrGuidStats_.value(guid).latencySum <= 0 ? QString("-") :
|
|
||||||
XLocale().toTimeIntervalString(
|
|
||||||
aggrGuidStats_.value(guid).latencySum
|
|
||||||
/ aggrGuidStats_.value(guid).latencyCount);
|
|
||||||
case kAvgJitter:
|
|
||||||
return aggrGuidStats_.value(guid).latencyCount <= 0
|
|
||||||
|| aggrGuidStats_.value(guid).latencySum <= 0 ? QString("-") :
|
|
||||||
XLocale().toTimeIntervalString(
|
|
||||||
aggrGuidStats_.value(guid).jitterSum
|
|
||||||
/ aggrGuidStats_.value(guid).latencyCount);
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
@ -225,11 +156,6 @@ QVariant StreamStatsModel::data(const QModelIndex &index, int role) const
|
|||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::DropActions StreamStatsModel::supportedDropActions() const
|
|
||||||
{
|
|
||||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------- //
|
// --------------------------------------------- //
|
||||||
// Slots
|
// Slots
|
||||||
// --------------------------------------------- //
|
// --------------------------------------------- //
|
||||||
@ -274,8 +200,6 @@ void StreamStatsModel::appendStreamStatsList(
|
|||||||
ss.txPkts = s.tx_pkts();
|
ss.txPkts = s.tx_pkts();
|
||||||
ss.rxBytes = s.rx_bytes();
|
ss.rxBytes = s.rx_bytes();
|
||||||
ss.txBytes = s.tx_bytes();
|
ss.txBytes = s.tx_bytes();
|
||||||
ss.rxLatency = s.latency();
|
|
||||||
ss.rxJitter = s.jitter();
|
|
||||||
|
|
||||||
aggrPort.rxPkts += ss.rxPkts;
|
aggrPort.rxPkts += ss.rxPkts;
|
||||||
aggrPort.txPkts += ss.txPkts;
|
aggrPort.txPkts += ss.txPkts;
|
||||||
@ -285,28 +209,10 @@ void StreamStatsModel::appendStreamStatsList(
|
|||||||
aggrGuid.rxPkts += ss.rxPkts;
|
aggrGuid.rxPkts += ss.rxPkts;
|
||||||
aggrGuid.txPkts += ss.txPkts;
|
aggrGuid.txPkts += ss.txPkts;
|
||||||
aggrGuid.pktLoss += ss.txPkts - ss.rxPkts;
|
aggrGuid.pktLoss += ss.txPkts - ss.rxPkts;
|
||||||
aggrGuid.rxBytes += ss.rxBytes;
|
|
||||||
aggrGuid.txBytes += ss.txBytes;
|
|
||||||
if (s.tx_duration() > aggrGuid.txDuration)
|
|
||||||
aggrGuid.txDuration = s.tx_duration(); // XXX: use largest or avg?
|
|
||||||
if (ss.rxLatency) {
|
|
||||||
aggrGuid.latencySum += ss.rxLatency;
|
|
||||||
aggrGuid.jitterSum += ss.rxJitter;
|
|
||||||
aggrGuid.latencyCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
aggrAggr.rxPkts += ss.rxPkts;
|
aggrAggr.rxPkts += ss.rxPkts;
|
||||||
aggrAggr.txPkts += ss.txPkts;
|
aggrAggr.txPkts += ss.txPkts;
|
||||||
aggrAggr.pktLoss += ss.txPkts - ss.rxPkts;
|
aggrAggr.pktLoss += ss.txPkts - ss.rxPkts;
|
||||||
aggrAggr.rxBytes += ss.rxBytes;
|
|
||||||
aggrAggr.txBytes += ss.txBytes;
|
|
||||||
if (aggrGuid.txDuration > aggrAggr.txDuration)
|
|
||||||
aggrAggr.txDuration = aggrGuid.txDuration;
|
|
||||||
if (ss.rxLatency) {
|
|
||||||
aggrAggr.latencySum += ss.rxLatency;
|
|
||||||
aggrAggr.jitterSum += ss.rxJitter;
|
|
||||||
aggrAggr.latencyCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!portList_.contains(pgp))
|
if (!portList_.contains(pgp))
|
||||||
portList_.append(pgp);
|
portList_.append(pgp);
|
||||||
@ -314,11 +220,9 @@ void StreamStatsModel::appendStreamStatsList(
|
|||||||
guidList_.append(guid);
|
guidList_.append(guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guidList_.size() && !guidList_.contains(kAggrGuid))
|
if (guidList_.size())
|
||||||
guidList_.append(kAggrGuid);
|
guidList_.append(kAggrGuid);
|
||||||
|
|
||||||
std::sort(guidList_.begin(), guidList_.end());
|
|
||||||
|
|
||||||
#if QT_VERSION >= 0x040600
|
#if QT_VERSION >= 0x040600
|
||||||
endResetModel();
|
endResetModel();
|
||||||
#else
|
#else
|
||||||
|
@ -43,8 +43,6 @@ public:
|
|||||||
int role = Qt::DisplayRole) const;
|
int role = Qt::DisplayRole) const;
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
Qt::DropActions supportedDropActions() const;
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clearStats();
|
void clearStats();
|
||||||
void appendStreamStatsList(quint32 portGroupId,
|
void appendStreamStatsList(quint32 portGroupId,
|
||||||
@ -57,19 +55,11 @@ private:
|
|||||||
quint64 txPkts;
|
quint64 txPkts;
|
||||||
quint64 rxBytes;
|
quint64 rxBytes;
|
||||||
quint64 txBytes;
|
quint64 txBytes;
|
||||||
quint64 rxLatency;
|
|
||||||
quint64 rxJitter;
|
|
||||||
};
|
};
|
||||||
struct AggrGuidStats {
|
struct AggrGuidStats {
|
||||||
quint64 rxPkts;
|
quint64 rxPkts;
|
||||||
quint64 txPkts;
|
quint64 txPkts;
|
||||||
quint64 rxBytes;
|
|
||||||
quint64 txBytes;
|
|
||||||
qint64 pktLoss;
|
qint64 pktLoss;
|
||||||
double txDuration;
|
|
||||||
quint64 latencySum;
|
|
||||||
quint64 jitterSum;
|
|
||||||
uint latencyCount;
|
|
||||||
};
|
};
|
||||||
QList<Guid> guidList_;
|
QList<Guid> guidList_;
|
||||||
QList<PortGroupPort> portList_;
|
QList<PortGroupPort> portList_;
|
||||||
|
@ -31,7 +31,7 @@ StreamStatsWindow::StreamStatsWindow(QAbstractItemModel *model, QWidget *parent)
|
|||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
streamStats->addAction(actionShowDetails);
|
streamStats->addAction(actionShowByteCounters);
|
||||||
|
|
||||||
if (id)
|
if (id)
|
||||||
setWindowTitle(windowTitle() + QString("(%1)").arg(id));
|
setWindowTitle(windowTitle() + QString("(%1)").arg(id));
|
||||||
@ -39,17 +39,13 @@ StreamStatsWindow::StreamStatsWindow(QAbstractItemModel *model, QWidget *parent)
|
|||||||
count++;
|
count++;
|
||||||
|
|
||||||
filterModel_ = new StreamStatsFilterModel(this);
|
filterModel_ = new StreamStatsFilterModel(this);
|
||||||
filterModel_->setFilterRegExp(QRegExp(kDefaultFilter_));
|
filterModel_->setFilterRegExp(QRegExp(".*Pkt.*"));
|
||||||
filterModel_->setSourceModel(model);
|
filterModel_->setSourceModel(model);
|
||||||
streamStats->setModel(filterModel_);
|
streamStats->setModel(filterModel_);
|
||||||
|
|
||||||
streamStats->verticalHeader()->setHighlightSections(false);
|
streamStats->verticalHeader()->setHighlightSections(false);
|
||||||
streamStats->verticalHeader()->setDefaultSectionSize(
|
streamStats->verticalHeader()->setDefaultSectionSize(
|
||||||
streamStats->verticalHeader()->minimumSectionSize());
|
streamStats->verticalHeader()->minimumSectionSize());
|
||||||
|
|
||||||
// Fit all columns in window whenever data changes
|
|
||||||
connect(model, &QAbstractItemModel::modelReset,
|
|
||||||
[=]() { streamStats->resizeColumnsToContents(); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamStatsWindow::~StreamStatsWindow()
|
StreamStatsWindow::~StreamStatsWindow()
|
||||||
@ -60,12 +56,10 @@ StreamStatsWindow::~StreamStatsWindow()
|
|||||||
id = 0;
|
id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamStatsWindow::on_actionShowDetails_triggered(bool checked)
|
void StreamStatsWindow::on_actionShowByteCounters_triggered(bool checked)
|
||||||
{
|
{
|
||||||
if (checked)
|
if (checked)
|
||||||
filterModel_->setFilterRegExp(QRegExp(".*"));
|
filterModel_->setFilterRegExp(QRegExp(".*"));
|
||||||
else
|
else
|
||||||
filterModel_->setFilterRegExp(QRegExp(kDefaultFilter_));
|
filterModel_->setFilterRegExp(QRegExp(".*Pkt.*"));
|
||||||
|
|
||||||
streamStats->resizeColumnsToContents();
|
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,9 @@ public:
|
|||||||
~StreamStatsWindow();
|
~StreamStatsWindow();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_actionShowDetails_triggered(bool checked);
|
void on_actionShowByteCounters_triggered(bool checked);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString kDefaultFilter_{"^(?!Port).*"};
|
|
||||||
QSortFilterProxyModel *filterModel_;
|
QSortFilterProxyModel *filterModel_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,9 +19,6 @@
|
|||||||
<property name="contextMenuPolicy">
|
<property name="contextMenuPolicy">
|
||||||
<enum>Qt::ActionsContextMenu</enum>
|
<enum>Qt::ActionsContextMenu</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="selectionBehavior">
|
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
|
||||||
</property>
|
|
||||||
<property name="whatsThis">
|
<property name="whatsThis">
|
||||||
<string>Oops! We don't seem to have any stream statistics for the requested port(s)
|
<string>Oops! We don't seem to have any stream statistics for the requested port(s)
|
||||||
|
|
||||||
@ -30,12 +27,12 @@ Wait a little bit to see if they appear, otherwise verify your stream stats conf
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
<action name="actionShowDetails">
|
<action name="actionShowByteCounters">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Show Details</string>
|
<string>Show Byte Counters</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -1,519 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2010 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "streamswidget.h"
|
|
||||||
|
|
||||||
#include "clipboardhelper.h"
|
|
||||||
#include "findreplace.h"
|
|
||||||
#include "portgrouplist.h"
|
|
||||||
#include "streamconfigdialog.h"
|
|
||||||
#include "streamfileformat.h"
|
|
||||||
#include "streamlistdelegate.h"
|
|
||||||
|
|
||||||
#include <QInputDialog>
|
|
||||||
#include <QItemSelectionModel>
|
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
extern ClipboardHelper *clipboardHelper;
|
|
||||||
|
|
||||||
StreamsWidget::StreamsWidget(QWidget *parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
{
|
|
||||||
setupUi(this);
|
|
||||||
|
|
||||||
delegate = new StreamListDelegate;
|
|
||||||
tvStreamList->setItemDelegate(delegate);
|
|
||||||
|
|
||||||
tvStreamList->verticalHeader()->setDefaultSectionSize(
|
|
||||||
tvStreamList->verticalHeader()->minimumSectionSize());
|
|
||||||
|
|
||||||
// Populate StreamList Context Menu Actions
|
|
||||||
tvStreamList->addAction(actionNew_Stream);
|
|
||||||
tvStreamList->addAction(actionEdit_Stream);
|
|
||||||
tvStreamList->addAction(actionDuplicate_Stream);
|
|
||||||
tvStreamList->addAction(actionDelete_Stream);
|
|
||||||
|
|
||||||
QAction *sep2 = new QAction(this);
|
|
||||||
sep2->setSeparator(true);
|
|
||||||
tvStreamList->addAction(sep2);
|
|
||||||
|
|
||||||
tvStreamList->addAction(actionFind_Replace);
|
|
||||||
|
|
||||||
QAction *sep3 = new QAction(this);
|
|
||||||
sep3->setSeparator(true);
|
|
||||||
tvStreamList->addAction(sep3);
|
|
||||||
|
|
||||||
tvStreamList->addAction(actionOpen_Streams);
|
|
||||||
tvStreamList->addAction(actionSave_Streams);
|
|
||||||
|
|
||||||
// StreamWidget's actions is an aggegate of all sub-widget's actions
|
|
||||||
addActions(tvStreamList->actions());
|
|
||||||
|
|
||||||
// Add the clipboard actions to the context menu of streamList
|
|
||||||
// but not to StreamsWidget's actions since they are already available
|
|
||||||
// in the global Edit Menu
|
|
||||||
QAction *sep4 = new QAction("Clipboard", this);
|
|
||||||
sep4->setSeparator(true);
|
|
||||||
tvStreamList->insertAction(sep2, sep4);
|
|
||||||
tvStreamList->insertActions(sep2, clipboardHelper->actions());
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::setPortGroupList(PortGroupList *portGroups)
|
|
||||||
{
|
|
||||||
plm = portGroups;
|
|
||||||
|
|
||||||
tvStreamList->setModel(plm->getStreamModel());
|
|
||||||
|
|
||||||
connect(plm->getStreamModel(), SIGNAL(rowsInserted(QModelIndex, int, int)),
|
|
||||||
SLOT(updateStreamViewActions()));
|
|
||||||
connect(plm->getStreamModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)),
|
|
||||||
SLOT(updateStreamViewActions()));
|
|
||||||
|
|
||||||
connect(tvStreamList->selectionModel(),
|
|
||||||
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
|
||||||
SLOT(updateStreamViewActions()));
|
|
||||||
connect(tvStreamList->selectionModel(),
|
|
||||||
SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
|
||||||
SLOT(updateStreamViewActions()));
|
|
||||||
|
|
||||||
tvStreamList->resizeColumnToContents(StreamModel::StreamIcon);
|
|
||||||
tvStreamList->resizeColumnToContents(StreamModel::StreamStatus);
|
|
||||||
|
|
||||||
updateStreamViewActions();
|
|
||||||
|
|
||||||
connect(plm->getStreamModel(),
|
|
||||||
SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
|
||||||
this, SLOT(streamModelDataChanged()));
|
|
||||||
connect(plm->getStreamModel(),
|
|
||||||
SIGNAL(modelReset()),
|
|
||||||
this, SLOT(streamModelDataChanged()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::streamModelDataChanged()
|
|
||||||
{
|
|
||||||
if (plm->isPort(currentPortIndex_))
|
|
||||||
plm->port(currentPortIndex_).recalculateAverageRates();
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamsWidget::~StreamsWidget()
|
|
||||||
{
|
|
||||||
delete delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::on_tvStreamList_activated(const QModelIndex & index)
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
{
|
|
||||||
qDebug("%s: invalid index", __FUNCTION__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug("stream list activated\n");
|
|
||||||
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
Port &curPort = plm->port(currentPortIndex_);
|
|
||||||
|
|
||||||
QList<Stream*> streams;
|
|
||||||
streams.append(curPort.mutableStreamByIndex(index.row(), false));
|
|
||||||
|
|
||||||
StreamConfigDialog scd(streams, curPort, this);
|
|
||||||
if (scd.exec() == QDialog::Accepted) {
|
|
||||||
curPort.recalculateAverageRates();
|
|
||||||
curPort.setLocalConfigChanged(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::setCurrentPortIndex(const QModelIndex &portIndex)
|
|
||||||
{
|
|
||||||
if (!plm)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// XXX: We assume portIndex corresponds to sourceModel, not proxyModel;
|
|
||||||
// caller should ensure this
|
|
||||||
|
|
||||||
qDebug("In %s", __PRETTY_FUNCTION__);
|
|
||||||
|
|
||||||
currentPortIndex_ = portIndex;
|
|
||||||
plm->getStreamModel()->setCurrentPortIndex(portIndex);
|
|
||||||
|
|
||||||
updateStreamViewActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::updateStreamViewActions()
|
|
||||||
{
|
|
||||||
// For some reason hasSelection() returns true even if selection size is 0
|
|
||||||
// so additional check for size introduced
|
|
||||||
if (tvStreamList->selectionModel()->hasSelection() &&
|
|
||||||
(tvStreamList->selectionModel()->selection().size() > 0))
|
|
||||||
{
|
|
||||||
qDebug("Has selection %d",
|
|
||||||
tvStreamList->selectionModel()->selection().size());
|
|
||||||
|
|
||||||
// If more than one non-contiguous ranges selected,
|
|
||||||
// disable "New" and "Edit"
|
|
||||||
if (tvStreamList->selectionModel()->selection().size() > 1)
|
|
||||||
{
|
|
||||||
actionNew_Stream->setDisabled(true);
|
|
||||||
actionEdit_Stream->setDisabled(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
actionNew_Stream->setEnabled(true);
|
|
||||||
actionEdit_Stream->setEnabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duplicate/Delete are always enabled as long as we have a selection
|
|
||||||
actionDuplicate_Stream->setEnabled(true);
|
|
||||||
actionDelete_Stream->setEnabled(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qDebug("No selection");
|
|
||||||
if (plm->isPort(currentPortIndex_))
|
|
||||||
actionNew_Stream->setEnabled(true);
|
|
||||||
else
|
|
||||||
actionNew_Stream->setDisabled(true);
|
|
||||||
actionEdit_Stream->setDisabled(true);
|
|
||||||
actionDuplicate_Stream->setDisabled(true);
|
|
||||||
actionDelete_Stream->setDisabled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
actionFind_Replace->setEnabled(tvStreamList->model()->rowCount() > 0);
|
|
||||||
|
|
||||||
actionOpen_Streams->setEnabled(plm->isPort(currentPortIndex_));
|
|
||||||
actionSave_Streams->setEnabled(tvStreamList->model()->rowCount() > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::on_actionNew_Stream_triggered()
|
|
||||||
{
|
|
||||||
qDebug("New Stream Action");
|
|
||||||
|
|
||||||
QItemSelectionModel* selectionModel = tvStreamList->selectionModel();
|
|
||||||
if (selectionModel->selection().size() > 1) {
|
|
||||||
qDebug("%s: Unexpected selection size %d, can't add", __FUNCTION__,
|
|
||||||
selectionModel->selection().size());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In case nothing is selected, insert 1 row at the end
|
|
||||||
StreamModel *streamModel = plm->getStreamModel();
|
|
||||||
int row = streamModel->rowCount(), count = 1;
|
|
||||||
|
|
||||||
// In case we have a single range selected; insert as many rows as
|
|
||||||
// in the singe selected range before the top of the selected range
|
|
||||||
if (selectionModel->selection().size() == 1)
|
|
||||||
{
|
|
||||||
row = selectionModel->selection().at(0).top();
|
|
||||||
count = selectionModel->selection().at(0).height();
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
Port &curPort = plm->port(currentPortIndex_);
|
|
||||||
|
|
||||||
QList<Stream*> streams;
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
streams.append(new Stream);
|
|
||||||
|
|
||||||
StreamConfigDialog scd(streams, curPort, this);
|
|
||||||
scd.setWindowTitle(tr("Add Stream"));
|
|
||||||
if (scd.exec() == QDialog::Accepted)
|
|
||||||
streamModel->insert(row, streams);
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::on_actionEdit_Stream_triggered()
|
|
||||||
{
|
|
||||||
qDebug("Edit Stream Action");
|
|
||||||
|
|
||||||
QItemSelectionModel* streamModel = tvStreamList->selectionModel();
|
|
||||||
if (!streamModel->hasSelection())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
Port &curPort = plm->port(currentPortIndex_);
|
|
||||||
|
|
||||||
QList<Stream*> streams;
|
|
||||||
foreach(QModelIndex index, streamModel->selectedRows())
|
|
||||||
streams.append(curPort.mutableStreamByIndex(index.row(), false));
|
|
||||||
|
|
||||||
StreamConfigDialog scd(streams, curPort, this);
|
|
||||||
if (scd.exec() == QDialog::Accepted) {
|
|
||||||
curPort.recalculateAverageRates();
|
|
||||||
curPort.setLocalConfigChanged(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::on_actionDuplicate_Stream_triggered()
|
|
||||||
{
|
|
||||||
QItemSelectionModel* model = tvStreamList->selectionModel();
|
|
||||||
|
|
||||||
qDebug("Duplicate Stream Action");
|
|
||||||
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
if (model->hasSelection())
|
|
||||||
{
|
|
||||||
bool isOk;
|
|
||||||
int count = QInputDialog::getInt(this, "Duplicate Streams",
|
|
||||||
"Count", 1, 1, 9999, 1, &isOk);
|
|
||||||
|
|
||||||
if (!isOk)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QList<int> list;
|
|
||||||
foreach(QModelIndex index, model->selectedRows())
|
|
||||||
list.append(index.row());
|
|
||||||
plm->port(currentPortIndex_).duplicateStreams(list, count);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
qDebug("No selection");
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::on_actionDelete_Stream_triggered()
|
|
||||||
{
|
|
||||||
qDebug("Delete Stream Action");
|
|
||||||
|
|
||||||
QModelIndex index;
|
|
||||||
|
|
||||||
if (tvStreamList->selectionModel()->hasSelection())
|
|
||||||
{
|
|
||||||
qDebug("SelectedIndexes %d",
|
|
||||||
tvStreamList->selectionModel()->selectedRows().size());
|
|
||||||
while(tvStreamList->selectionModel()->selectedRows().size())
|
|
||||||
{
|
|
||||||
index = tvStreamList->selectionModel()->selectedRows().at(0);
|
|
||||||
plm->getStreamModel()->removeRows(index.row(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
qDebug("No selection");
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::on_actionFind_Replace_triggered()
|
|
||||||
{
|
|
||||||
qDebug("Find & Replace Action");
|
|
||||||
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
QItemSelectionModel* selectionModel = tvStreamList->selectionModel();
|
|
||||||
FindReplaceDialog::Action action;
|
|
||||||
|
|
||||||
action.selectedStreamsOnly = selectionModel->selection().size() > 0 ?
|
|
||||||
true : false;
|
|
||||||
|
|
||||||
FindReplaceDialog findReplace(&action, this);
|
|
||||||
if (findReplace.exec() == QDialog::Accepted) {
|
|
||||||
QProgressDialog progress(this);
|
|
||||||
progress.setLabelText(tr("Replacing %1 ...").arg(action.protocolField));
|
|
||||||
progress.setWindowModality(Qt::WindowModal);
|
|
||||||
int c, fc = 0, sc = 0; // replace counts
|
|
||||||
Port &port = plm->port(currentPortIndex_);
|
|
||||||
if (action.selectedStreamsOnly) {
|
|
||||||
QModelIndexList selected = selectionModel->selectedRows();
|
|
||||||
int count = selected.size();
|
|
||||||
progress.setMaximum(count);
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
QModelIndex index = selected.at(i);
|
|
||||||
Stream *stream = port.mutableStreamByIndex(index.row(), false);
|
|
||||||
c = stream->protocolFieldReplace(action.protocolNumber,
|
|
||||||
action.fieldIndex,
|
|
||||||
action.fieldBitSize,
|
|
||||||
action.findValue,
|
|
||||||
action.findMask,
|
|
||||||
action.replaceValue,
|
|
||||||
action.replaceMask);
|
|
||||||
if (c) {
|
|
||||||
fc += c;
|
|
||||||
sc++;
|
|
||||||
}
|
|
||||||
progress.setValue(i+1);
|
|
||||||
if (progress.wasCanceled())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int count = tvStreamList->model()->rowCount();
|
|
||||||
progress.setMaximum(count);
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
Stream *stream = port.mutableStreamByIndex(i, false);
|
|
||||||
c = stream->protocolFieldReplace(action.protocolNumber,
|
|
||||||
action.fieldIndex,
|
|
||||||
action.fieldBitSize,
|
|
||||||
action.findValue,
|
|
||||||
action.findMask,
|
|
||||||
action.replaceValue,
|
|
||||||
action.replaceMask);
|
|
||||||
if (c) {
|
|
||||||
fc += c;
|
|
||||||
sc++;
|
|
||||||
}
|
|
||||||
progress.setValue(i+1);
|
|
||||||
if (progress.wasCanceled())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fc)
|
|
||||||
port.setLocalConfigChanged(true);
|
|
||||||
|
|
||||||
QMessageBox::information(this, tr("Find & Replace"),
|
|
||||||
tr("%1 fields replaced in %2 streams").arg(fc).arg(sc));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::on_actionOpen_Streams_triggered()
|
|
||||||
{
|
|
||||||
qDebug("Open Streams Action");
|
|
||||||
|
|
||||||
QStringList fileTypes = StreamFileFormat::supportedFileTypes(
|
|
||||||
StreamFileFormat::kOpenFile);
|
|
||||||
QString fileType;
|
|
||||||
static QString dirName;
|
|
||||||
QString fileName;
|
|
||||||
QString errorStr;
|
|
||||||
bool append = true;
|
|
||||||
bool ret;
|
|
||||||
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
if (fileTypes.size())
|
|
||||||
fileType = fileTypes.at(0);
|
|
||||||
|
|
||||||
fileName = QFileDialog::getOpenFileName(this, tr("Open Streams"),
|
|
||||||
dirName, fileTypes.join(";;"), &fileType);
|
|
||||||
if (fileName.isEmpty())
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
if (tvStreamList->model()->rowCount())
|
|
||||||
{
|
|
||||||
QMessageBox msgBox(QMessageBox::Question, qApp->applicationName(),
|
|
||||||
tr("Append to existing streams? Or overwrite?"),
|
|
||||||
QMessageBox::NoButton, this);
|
|
||||||
QPushButton *appendBtn = msgBox.addButton(tr("Append"),
|
|
||||||
QMessageBox::ActionRole);
|
|
||||||
QPushButton *overwriteBtn = msgBox.addButton(tr("Overwrite"),
|
|
||||||
QMessageBox::ActionRole);
|
|
||||||
QPushButton *cancelBtn = msgBox.addButton(QMessageBox::Cancel);
|
|
||||||
|
|
||||||
msgBox.exec();
|
|
||||||
|
|
||||||
if (msgBox.clickedButton() == cancelBtn)
|
|
||||||
goto _exit;
|
|
||||||
else if (msgBox.clickedButton() == appendBtn)
|
|
||||||
append = true;
|
|
||||||
else if (msgBox.clickedButton() == overwriteBtn)
|
|
||||||
append = false;
|
|
||||||
else
|
|
||||||
Q_ASSERT(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = plm->port(currentPortIndex_).openStreams(fileName, append, errorStr);
|
|
||||||
if (!ret || !errorStr.isEmpty())
|
|
||||||
{
|
|
||||||
QMessageBox msgBox(this);
|
|
||||||
QStringList str = errorStr.split("\n\n\n\n");
|
|
||||||
|
|
||||||
msgBox.setIcon(ret ? QMessageBox::Warning : QMessageBox::Critical);
|
|
||||||
msgBox.setWindowTitle(qApp->applicationName());
|
|
||||||
msgBox.setText(str.at(0));
|
|
||||||
if (str.size() > 1)
|
|
||||||
msgBox.setDetailedText(str.at(1));
|
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
|
||||||
|
|
||||||
msgBox.exec();
|
|
||||||
}
|
|
||||||
dirName = QFileInfo(fileName).absolutePath();
|
|
||||||
updateStreamViewActions();
|
|
||||||
|
|
||||||
_exit:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void StreamsWidget::on_actionSave_Streams_triggered()
|
|
||||||
{
|
|
||||||
qDebug("Save Streams Action");
|
|
||||||
|
|
||||||
static QString fileName;
|
|
||||||
QStringList fileTypes = StreamFileFormat::supportedFileTypes(
|
|
||||||
StreamFileFormat::kSaveFile);
|
|
||||||
QString fileType;
|
|
||||||
QString errorStr;
|
|
||||||
QFileDialog::Options options;
|
|
||||||
|
|
||||||
// On Mac OS with Native Dialog, getSaveFileName() ignores fileType
|
|
||||||
// which we need
|
|
||||||
#if defined(Q_OS_MAC)
|
|
||||||
options |= QFileDialog::DontUseNativeDialog;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (fileTypes.size())
|
|
||||||
fileType = fileTypes.at(0);
|
|
||||||
|
|
||||||
Q_ASSERT(plm->isPort(currentPortIndex_));
|
|
||||||
|
|
||||||
_retry:
|
|
||||||
fileName = QFileDialog::getSaveFileName(this, tr("Save Streams"),
|
|
||||||
fileName, fileTypes.join(";;"), &fileType, options);
|
|
||||||
if (fileName.isEmpty())
|
|
||||||
goto _exit;
|
|
||||||
|
|
||||||
if (QFileInfo(fileName).suffix().isEmpty()) {
|
|
||||||
QString fileExt = fileType.section(QRegExp("[\\*\\)]"), 1, 1);
|
|
||||||
qDebug("Adding extension '%s' to '%s'",
|
|
||||||
qPrintable(fileExt), qPrintable(fileName));
|
|
||||||
fileName.append(fileExt);
|
|
||||||
if (QFileInfo(fileName).exists()) {
|
|
||||||
if (QMessageBox::warning(this, tr("Overwrite File?"),
|
|
||||||
QString("The file \"%1\" already exists.\n\n"
|
|
||||||
"Do you wish to overwrite it?")
|
|
||||||
.arg(QFileInfo(fileName).fileName()),
|
|
||||||
QMessageBox::Yes|QMessageBox::No,
|
|
||||||
QMessageBox::No) != QMessageBox::Yes)
|
|
||||||
goto _retry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileType = fileType.remove(QRegExp("\\(.*\\)")).trimmed();
|
|
||||||
if (!fileType.startsWith("Ostinato")
|
|
||||||
&& !fileType.startsWith("Python"))
|
|
||||||
{
|
|
||||||
if (QMessageBox::warning(this, tr("Ostinato"),
|
|
||||||
QString("You have chosen to save in %1 format. All stream "
|
|
||||||
"attributes may not be saved in this format.\n\n"
|
|
||||||
"It is recommended to save in native Ostinato format.\n\n"
|
|
||||||
"Continue to save in %2 format?").arg(fileType).arg(fileType),
|
|
||||||
QMessageBox::Yes|QMessageBox::No,
|
|
||||||
QMessageBox::No) != QMessageBox::Yes)
|
|
||||||
goto _retry;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: all or selected?
|
|
||||||
|
|
||||||
if (!plm->port(currentPortIndex_).saveStreams(fileName, fileType, errorStr))
|
|
||||||
QMessageBox::critical(this, qApp->applicationName(), errorStr);
|
|
||||||
else if (!errorStr.isEmpty())
|
|
||||||
QMessageBox::warning(this, qApp->applicationName(), errorStr);
|
|
||||||
|
|
||||||
fileName = QFileInfo(fileName).absolutePath();
|
|
||||||
_exit:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2010 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _STREAMS_WIDGET_H
|
|
||||||
#define _STREAMS_WIDGET_H
|
|
||||||
|
|
||||||
#include "ui_streamswidget.h"
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
class PortGroupList;
|
|
||||||
class QAbstractItemDelegate;
|
|
||||||
|
|
||||||
class StreamsWidget : public QWidget, private Ui::StreamsWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
StreamsWidget(QWidget *parent = 0);
|
|
||||||
~StreamsWidget();
|
|
||||||
|
|
||||||
void setPortGroupList(PortGroupList *portGroups);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void setCurrentPortIndex(const QModelIndex &portIndex);
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void updateStreamViewActions();
|
|
||||||
|
|
||||||
void on_tvStreamList_activated(const QModelIndex & index);
|
|
||||||
|
|
||||||
void on_actionNew_Stream_triggered();
|
|
||||||
void on_actionEdit_Stream_triggered();
|
|
||||||
void on_actionDuplicate_Stream_triggered();
|
|
||||||
void on_actionDelete_Stream_triggered();
|
|
||||||
|
|
||||||
void on_actionFind_Replace_triggered();
|
|
||||||
|
|
||||||
void on_actionOpen_Streams_triggered();
|
|
||||||
void on_actionSave_Streams_triggered();
|
|
||||||
|
|
||||||
void streamModelDataChanged();
|
|
||||||
|
|
||||||
private:
|
|
||||||
PortGroupList *plm{nullptr}; // FIXME: rename to portGroups_?
|
|
||||||
QModelIndex currentPortIndex_;
|
|
||||||
|
|
||||||
QAbstractItemDelegate *delegate;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,132 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>StreamsWidget</class>
|
|
||||||
<widget class="QWidget" name="StreamsWidget">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>602</width>
|
|
||||||
<height>364</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Form</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>9</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="XTableView" name="tvStreamList">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>1</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="contextMenuPolicy">
|
|
||||||
<enum>Qt::ActionsContextMenu</enum>
|
|
||||||
</property>
|
|
||||||
<property name="whatsThis">
|
|
||||||
<string>This is the stream list for the selected port
|
|
||||||
|
|
||||||
A stream is a sequence of one or more packets
|
|
||||||
|
|
||||||
Right-click to create a stream</string>
|
|
||||||
</property>
|
|
||||||
<property name="frameShape">
|
|
||||||
<enum>QFrame::StyledPanel</enum>
|
|
||||||
</property>
|
|
||||||
<property name="lineWidth">
|
|
||||||
<number>1</number>
|
|
||||||
</property>
|
|
||||||
<property name="selectionMode">
|
|
||||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
|
||||||
</property>
|
|
||||||
<property name="selectionBehavior">
|
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
<action name="actionNew_Stream">
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="ostinato.qrc">
|
|
||||||
<normaloff>:/icons/stream_add.png</normaloff>:/icons/stream_add.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>New Stream</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionDelete_Stream">
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="ostinato.qrc">
|
|
||||||
<normaloff>:/icons/stream_delete.png</normaloff>:/icons/stream_delete.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Delete Stream</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionEdit_Stream">
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="ostinato.qrc">
|
|
||||||
<normaloff>:/icons/stream_edit.png</normaloff>:/icons/stream_edit.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Edit Stream</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionOpen_Streams">
|
|
||||||
<property name="text">
|
|
||||||
<string>Open Streams ...</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionSave_Streams">
|
|
||||||
<property name="text">
|
|
||||||
<string>Save Streams ...</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionDuplicate_Stream">
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="ostinato.qrc">
|
|
||||||
<normaloff>:/icons/stream_duplicate.png</normaloff>:/icons/stream_duplicate.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Duplicate Stream</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionFind_Replace">
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="ostinato.qrc">
|
|
||||||
<normaloff>:/icons/find.png</normaloff>:/icons/find.png</iconset>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Find && Replace</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Find & Replace protocol field values</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
</widget>
|
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>XTableView</class>
|
|
||||||
<extends>QTableView</extends>
|
|
||||||
<header>xtableview.h</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources>
|
|
||||||
<include location="ostinato.qrc"/>
|
|
||||||
</resources>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
@ -1,130 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2021 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "thememanager.h"
|
|
||||||
|
|
||||||
#include "settings.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QDirIterator>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QResource>
|
|
||||||
|
|
||||||
ThemeManager *ThemeManager::instance_{nullptr};
|
|
||||||
|
|
||||||
ThemeManager::ThemeManager()
|
|
||||||
{
|
|
||||||
themeDir_ = QCoreApplication::applicationDirPath() + "/themes/";
|
|
||||||
#if defined(Q_OS_MAC)
|
|
||||||
/*
|
|
||||||
* Executable and Theme directory location inside app bundle -
|
|
||||||
* Ostinato.app/Contents/MacOS/
|
|
||||||
* Ostinato.app/Contents/SharedSupport/themes/
|
|
||||||
*/
|
|
||||||
themeDir_.replace("/MacOS/", "/SharedSupport/");
|
|
||||||
#elif defined(Q_OS_UNIX)
|
|
||||||
/*
|
|
||||||
* Possible (but not comprehensive) locations for Ostinato executable
|
|
||||||
* and theme directory locations
|
|
||||||
*
|
|
||||||
* non-install-dir/
|
|
||||||
* non-install-dir/themes/
|
|
||||||
*
|
|
||||||
* /usr/[local]/bin/
|
|
||||||
* /usr/[local]/share/ostinato-controller/themes/
|
|
||||||
*
|
|
||||||
* /opt/ostinato/bin/
|
|
||||||
* /opt/ostinato/share/themes/
|
|
||||||
*/
|
|
||||||
if (themeDir_.contains(QRegularExpression("^/usr/.*/bin/")))
|
|
||||||
themeDir_.replace("/bin/", "/share/ostinato-controller/");
|
|
||||||
else if (themeDir_.contains(QRegularExpression("^/opt/.*/bin/")))
|
|
||||||
themeDir_.replace("/bin/", "/share/");
|
|
||||||
#endif
|
|
||||||
qDebug("Themes directory: %s", qPrintable(themeDir_));
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList ThemeManager::themeList()
|
|
||||||
{
|
|
||||||
QDir themeDir(themeDir_);
|
|
||||||
|
|
||||||
themeDir.setFilter(QDir::Files);
|
|
||||||
themeDir.setNameFilters(QStringList() << "*.qss");
|
|
||||||
themeDir.setSorting(QDir::Name);
|
|
||||||
|
|
||||||
QStringList themes = themeDir.entryList();
|
|
||||||
for (QString& theme : themes)
|
|
||||||
theme.remove(".qss");
|
|
||||||
themes.prepend("default");
|
|
||||||
|
|
||||||
return themes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ThemeManager::setTheme(QString theme)
|
|
||||||
{
|
|
||||||
// Remove current theme, if we have one
|
|
||||||
QString oldTheme = appSettings->value(kThemeKey).toString();
|
|
||||||
if (!oldTheme.isEmpty()) {
|
|
||||||
// Remove stylesheet first so that there are
|
|
||||||
// no references to resources when unregistering 'em
|
|
||||||
qApp->setStyleSheet("");
|
|
||||||
QString rccFile = themeDir_ + oldTheme + ".rcc";
|
|
||||||
if (QResource::unregisterResource(rccFile)) {
|
|
||||||
qDebug("Unable to unregister theme rccFile %s",
|
|
||||||
qPrintable(rccFile));
|
|
||||||
}
|
|
||||||
appSettings->setValue(kThemeKey, QVariant());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (theme.isEmpty() || (theme == "default"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Apply new theme
|
|
||||||
QFile qssFile(themeDir_ + theme + ".qss");
|
|
||||||
if (!qssFile.open(QFile::ReadOnly)) {
|
|
||||||
qDebug("Unable to open theme qssFile %s",
|
|
||||||
qPrintable(qssFile.fileName()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register theme resource before applying theme style sheet
|
|
||||||
QString rccFile = themeDir_ + theme + ".rcc";
|
|
||||||
if (!QResource::registerResource(rccFile))
|
|
||||||
qDebug("Unable to register theme rccFile %s", qPrintable(rccFile));
|
|
||||||
|
|
||||||
#if 0 // FIXME: debug only
|
|
||||||
QDirIterator it(":", QDirIterator::Subdirectories);
|
|
||||||
while (it.hasNext()) {
|
|
||||||
qDebug() << it.next();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QString styleSheet { qssFile.readAll() };
|
|
||||||
qApp->setStyleSheet(styleSheet);
|
|
||||||
appSettings->setValue(kThemeKey, theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
ThemeManager* ThemeManager::instance()
|
|
||||||
{
|
|
||||||
if (!instance_)
|
|
||||||
instance_ = new ThemeManager();
|
|
||||||
return instance_;
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright (C) 2021 Srivats P.
|
|
||||||
|
|
||||||
This file is part of "Ostinato"
|
|
||||||
|
|
||||||
This 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _THEME_MANAGER_H
|
|
||||||
#define _THEME_MANAGER_H
|
|
||||||
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
class ThemeManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ThemeManager();
|
|
||||||
|
|
||||||
QStringList themeList();
|
|
||||||
void setTheme(QString theme);
|
|
||||||
|
|
||||||
static ThemeManager* instance();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString themeDir_;
|
|
||||||
|
|
||||||
static ThemeManager *instance_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -297,7 +297,7 @@ void VariableFieldsWidget::on_type_currentIndexChanged(int index)
|
|||||||
bitmask->setInputMask("HH");
|
bitmask->setInputMask("HH");
|
||||||
bitmask->setText("FF");
|
bitmask->setText("FF");
|
||||||
valueRange_->setRange(0, 0xFF);
|
valueRange_->setRange(0, 0xFF);
|
||||||
count->setRange(1, 0x100);
|
count->setRange(0, 0xFF);
|
||||||
step->setRange(0, 0xFF);
|
step->setRange(0, 0xFF);
|
||||||
break;
|
break;
|
||||||
case OstProto::VariableField::kCounter16:
|
case OstProto::VariableField::kCounter16:
|
||||||
@ -305,7 +305,7 @@ void VariableFieldsWidget::on_type_currentIndexChanged(int index)
|
|||||||
bitmask->setInputMask("HHHH");
|
bitmask->setInputMask("HHHH");
|
||||||
bitmask->setText("FFFF");
|
bitmask->setText("FFFF");
|
||||||
valueRange_->setRange(0, 0xFFFF);
|
valueRange_->setRange(0, 0xFFFF);
|
||||||
count->setRange(1, 0x10000);
|
count->setRange(0, 0xFFFF);
|
||||||
step->setRange(0, 0xFFFF);
|
step->setRange(0, 0xFFFF);
|
||||||
break;
|
break;
|
||||||
case OstProto::VariableField::kCounter32:
|
case OstProto::VariableField::kCounter32:
|
||||||
@ -313,7 +313,7 @@ void VariableFieldsWidget::on_type_currentIndexChanged(int index)
|
|||||||
bitmask->setInputMask("HHHHHHHH");
|
bitmask->setInputMask("HHHHHHHH");
|
||||||
bitmask->setText("FFFFFFFF");
|
bitmask->setText("FFFFFFFF");
|
||||||
valueRange_->setRange(0, 0xFFFFFFFF);
|
valueRange_->setRange(0, 0xFFFFFFFF);
|
||||||
count->setRange(1, 0x7FFFFFFF); // XXX: QSpinBox max limited to int32
|
count->setRange(0, 0x7FFFFFFF);
|
||||||
step->setRange(0, 0x7FFFFFFF);
|
step->setRange(0, 0x7FFFFFFF);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -376,9 +376,6 @@ void VariableFieldsWidget::loadProtocolFields(
|
|||||||
int byteOfs = bitOfs >> 3;
|
int byteOfs = bitOfs >> 3;
|
||||||
uint bitSize = protocol->fieldData(i, AbstractProtocol::FieldBitSize)
|
uint bitSize = protocol->fieldData(i, AbstractProtocol::FieldBitSize)
|
||||||
.toInt();
|
.toInt();
|
||||||
if (bitSize == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
vm["offset"] = byteOfs;
|
vm["offset"] = byteOfs;
|
||||||
if (bitSize <= 8) {
|
if (bitSize <= 8) {
|
||||||
vm["type"] = int(OstProto::VariableField::kCounter8);
|
vm["type"] = int(OstProto::VariableField::kCounter8);
|
||||||
|