Merge pull request #345 from pstavirs/speed
Improve UI/UX of configured traffic rate on a port
This commit is contained in:
commit
90f855ecdf
@ -57,6 +57,7 @@ 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 \
|
||||||
@ -65,6 +66,7 @@ HEADERS += \
|
|||||||
streamstatsfiltermodel.h \
|
streamstatsfiltermodel.h \
|
||||||
streamstatsmodel.h \
|
streamstatsmodel.h \
|
||||||
streamstatswindow.h \
|
streamstatswindow.h \
|
||||||
|
streamswidget.h \
|
||||||
variablefieldswidget.h \
|
variablefieldswidget.h \
|
||||||
xtableview.h
|
xtableview.h
|
||||||
|
|
||||||
@ -78,9 +80,11 @@ FORMS += \
|
|||||||
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 += \
|
||||||
@ -109,12 +113,14 @@ 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 \
|
||||||
variablefieldswidget.cpp
|
variablefieldswidget.cpp
|
||||||
|
|
||||||
|
|
||||||
|
@ -317,6 +317,12 @@ 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;
|
||||||
|
@ -102,6 +102,10 @@ 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
|
||||||
@ -183,6 +187,7 @@ 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();
|
||||||
|
@ -20,51 +20,37 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "portswindow.h"
|
#include "portswindow.h"
|
||||||
|
|
||||||
#include "applymsg.h"
|
#include "applymsg.h"
|
||||||
#include "clipboardhelper.h"
|
|
||||||
#include "deviceswidget.h"
|
#include "deviceswidget.h"
|
||||||
#include "portconfigdialog.h"
|
|
||||||
#include "settings.h"
|
|
||||||
#include "streamconfigdialog.h"
|
|
||||||
#include "streamfileformat.h"
|
|
||||||
#include "streamlistdelegate.h"
|
|
||||||
|
|
||||||
#include "fileformat.pb.h"
|
#include "fileformat.pb.h"
|
||||||
|
#include "portconfigdialog.h"
|
||||||
|
#include "portgrouplist.h"
|
||||||
|
#include "portwidget.h"
|
||||||
|
#include "settings.h"
|
||||||
|
#include "streamswidget.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 ClipboardHelper *clipboardHelper;
|
|
||||||
extern QMainWindow *mainWindow;
|
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);
|
||||||
@ -74,41 +60,18 @@ 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);
|
|
||||||
|
|
||||||
QAction *sep2 = new QAction(this);
|
|
||||||
sep2->setSeparator(true);
|
|
||||||
tvStreamList->addAction(sep2);
|
|
||||||
|
|
||||||
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());
|
||||||
sep = new QAction(this);
|
QAction *sep = new QAction(this);
|
||||||
sep->setSeparator(true);
|
sep->setSeparator(true);
|
||||||
addAction(sep);
|
addAction(sep);
|
||||||
addActions(tvStreamList->actions());
|
addActions(streamsWidget->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());
|
||||||
|
|
||||||
// Add the clipboard actions to the context menu of streamList
|
|
||||||
// but not to PortsWindow's actions since they are already available
|
|
||||||
// in the global Edit Menu
|
|
||||||
sep = new QAction("Clipboard", this);
|
|
||||||
sep->setSeparator(true);
|
|
||||||
tvStreamList->insertAction(sep2, sep);
|
|
||||||
tvStreamList->insertActions(sep2, clipboardHelper->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
|
||||||
@ -138,52 +101,24 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
|
|||||||
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&)));
|
||||||
|
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_;
|
||||||
}
|
}
|
||||||
@ -321,30 +256,6 @@ 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)
|
||||||
{
|
{
|
||||||
@ -356,16 +267,12 @@ 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,
|
||||||
@ -386,9 +293,6 @@ 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)));
|
||||||
@ -446,139 +350,6 @@ 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)
|
||||||
{
|
{
|
||||||
@ -586,7 +357,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 (tvStreamList->model()->rowCount() > 0)
|
else if (plm->getStreamModel()->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");
|
||||||
@ -838,259 +609,3 @@ void PortsWindow::on_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();
|
|
||||||
updateStreamViewActions();
|
|
||||||
|
|
||||||
_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,13 +20,12 @@ 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 <QWidget>
|
|
||||||
#include <QAbstractItemModel>
|
|
||||||
#include "ui_portswindow.h"
|
#include "ui_portswindow.h"
|
||||||
#include "portgrouplist.h"
|
#include <QWidget>
|
||||||
|
|
||||||
class ApplyMessage;
|
class ApplyMessage;
|
||||||
class QAbstractItemDelegate;
|
class PortGroupList;
|
||||||
|
|
||||||
class QProgressDialog;
|
class QProgressDialog;
|
||||||
class QSortFilterProxyModel;
|
class QSortFilterProxyModel;
|
||||||
|
|
||||||
@ -38,9 +37,6 @@ 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();
|
||||||
@ -58,12 +54,6 @@ 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 clearCurrentSelection();
|
||||||
void showMyReservedPortsOnly(bool enabled);
|
void showMyReservedPortsOnly(bool enabled);
|
||||||
@ -71,14 +61,7 @@ public slots:
|
|||||||
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,
|
||||||
@ -95,15 +78,11 @@ private slots:
|
|||||||
void on_actionExclusive_Control_triggered(bool checked);
|
void on_actionExclusive_Control_triggered(bool checked);
|
||||||
void on_actionPort_Configuration_triggered();
|
void on_actionPort_Configuration_triggered();
|
||||||
|
|
||||||
void on_actionNew_Stream_triggered();
|
private:
|
||||||
void on_actionEdit_Stream_triggered();
|
PortGroupList *plm;
|
||||||
void on_actionDuplicate_Stream_triggered();
|
QString lastNewPortGroup;
|
||||||
void on_actionDelete_Stream_triggered();
|
QSortFilterProxyModel *proxyPortModel;
|
||||||
|
ApplyMessage *applyMsg_;
|
||||||
void on_actionOpen_Streams_triggered();
|
|
||||||
void on_actionSave_Streams_triggered();
|
|
||||||
|
|
||||||
void streamModelDataChanged();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -126,7 +126,16 @@
|
|||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="portDetail">
|
<widget class="QWidget" name="portDetail">
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout">
|
||||||
<property name="margin">
|
<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>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
@ -138,7 +147,16 @@
|
|||||||
<enum>QFrame::Raised</enum>
|
<enum>QFrame::Raised</enum>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<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>
|
||||||
@ -195,114 +213,10 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QVBoxLayout">
|
<layout class="QVBoxLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<widget class="PortWidget" name="portWidget" native="true"/>
|
||||||
<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="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>
|
||||||
<item>
|
<item>
|
||||||
<widget class="XTableView" name="tvStreamList">
|
<widget class="StreamsWidget" name="streamsWidget" native="true"/>
|
||||||
<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>
|
||||||
@ -360,33 +274,6 @@ Right-click to create a stream</string>
|
|||||||
<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>
|
||||||
@ -395,30 +282,11 @@ Right-click to create a stream</string>
|
|||||||
<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>
|
||||||
@ -433,46 +301,20 @@ Right-click to create a stream</string>
|
|||||||
<header>xtreeview.h</header>
|
<header>xtreeview.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>XTableView</class>
|
<class>StreamsWidget</class>
|
||||||
<extends>QTableView</extends>
|
<extends>QWidget</extends>
|
||||||
<header>xtableview.h</header>
|
<header>streamswidget.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>
|
||||||
|
182
client/portwidget.cpp
Normal file
182
client/portwidget.cpp
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
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 &portIndex)
|
||||||
|
{
|
||||||
|
if (!plm)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// XXX: We assume portIndex corresponds to sourceModel, not proxyModel
|
||||||
|
if (!plm->isPort(portIndex))
|
||||||
|
return;
|
||||||
|
|
||||||
|
qDebug("In %s", __FUNCTION__);
|
||||||
|
|
||||||
|
// Disconnect previous port
|
||||||
|
if (plm->isPort(currentPortIndex_))
|
||||||
|
disconnect(&(plm->port(currentPortIndex_)),
|
||||||
|
SIGNAL(portRateChanged(int, int)),
|
||||||
|
this, SLOT(updatePortRates()));
|
||||||
|
|
||||||
|
currentPortIndex_ = portIndex;
|
||||||
|
|
||||||
|
// Connect current port
|
||||||
|
if (plm->isPort(currentPortIndex_))
|
||||||
|
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);
|
||||||
|
}
|
60
client/portwidget.h
Normal file
60
client/portwidget.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
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 &portIndex);
|
||||||
|
|
||||||
|
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
|
||||||
|
|
218
client/portwidget.ui
Normal file
218
client/portwidget.ui
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
<?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>
|
430
client/streamswidget.cpp
Normal file
430
client/streamswidget.cpp
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
/*
|
||||||
|
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 "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(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 *sep3 = new QAction("Clipboard", this);
|
||||||
|
sep3->setSeparator(true);
|
||||||
|
tvStreamList->insertAction(sep2, sep3);
|
||||||
|
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");
|
||||||
|
|
||||||
|
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
|
||||||
|
if (!plm->isPort(portIndex))
|
||||||
|
return;
|
||||||
|
|
||||||
|
qDebug("In %s", __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);
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
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_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;
|
||||||
|
}
|
||||||
|
|
65
client/streamswidget.h
Normal file
65
client/streamswidget.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
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_actionOpen_Streams_triggered();
|
||||||
|
void on_actionSave_Streams_triggered();
|
||||||
|
|
||||||
|
void streamModelDataChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PortGroupList *plm{nullptr}; // FIXME: rename to portGroups_?
|
||||||
|
QModelIndex currentPortIndex_;
|
||||||
|
|
||||||
|
QAbstractItemDelegate *delegate;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
120
client/streamswidget.ui
Normal file
120
client/streamswidget.ui
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?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>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>XTableView</class>
|
||||||
|
<extends>QTableView</extends>
|
||||||
|
<header>xtableview.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="ostinato.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -21,14 +21,85 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#define _X_LOCALE_H
|
#define _X_LOCALE_H
|
||||||
|
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
#include <QRegularExpressionMatch>
|
||||||
|
|
||||||
class XLocale: public QLocale
|
class XLocale: public QLocale
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
double toDouble(const QString &s, bool *ok = Q_NULLPTR) const {
|
double toDouble(const QString &s, bool *ok = Q_NULLPTR) const
|
||||||
|
{
|
||||||
QString s2 = s;
|
QString s2 = s;
|
||||||
return QLocale::toDouble(s2.remove(groupSeparator()), ok);
|
return QLocale::toDouble(s2.remove(groupSeparator()), ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double toPacketsPerSecond(const QString &s, bool *ok = Q_NULLPTR) const
|
||||||
|
{
|
||||||
|
QString text = s;
|
||||||
|
double multiplier = 0;
|
||||||
|
QRegularExpression regex("[a-zA-Z/]+$");
|
||||||
|
QRegularExpressionMatch match = regex.match(text);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
QString unit = match.captured(0).toCaseFolded();
|
||||||
|
if ((unit == "mpps") || (unit == "m"))
|
||||||
|
multiplier = 1e6;
|
||||||
|
else if ((unit == "kpps") || (unit == "k"))
|
||||||
|
multiplier = 1e3;
|
||||||
|
else if (unit == "pps")
|
||||||
|
multiplier = 1;
|
||||||
|
|
||||||
|
if (multiplier)
|
||||||
|
text.remove(regex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multiplier == 0)
|
||||||
|
multiplier = 1;
|
||||||
|
|
||||||
|
return toDouble(text, ok) * multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
double toBitsPerSecond(const QString &s, bool *ok = Q_NULLPTR) const
|
||||||
|
{
|
||||||
|
QString text = s;
|
||||||
|
double multiplier = 0;
|
||||||
|
QRegularExpression regex("[a-zA-Z/]+$");
|
||||||
|
QRegularExpressionMatch match = regex.match(text);
|
||||||
|
if (match.hasMatch()) {
|
||||||
|
QString unit = match.captured(0).toCaseFolded();
|
||||||
|
if ((unit == "gbps") || (unit == "gb/s") || (unit == "g"))
|
||||||
|
multiplier = 1e9;
|
||||||
|
else if ((unit == "mbps") || (unit == "mb/s") || (unit == "m"))
|
||||||
|
multiplier = 1e6;
|
||||||
|
else if ((unit == "kbps") || (unit == "kb/s") || (unit == "k"))
|
||||||
|
multiplier = 1e3;
|
||||||
|
else if ((unit == "bps") || (unit == "b/s"))
|
||||||
|
multiplier = 1;
|
||||||
|
|
||||||
|
if (multiplier)
|
||||||
|
text.remove(regex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multiplier == 0)
|
||||||
|
multiplier = 1;
|
||||||
|
|
||||||
|
return toDouble(text, ok) * multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toBitRateString(double bps) const
|
||||||
|
{
|
||||||
|
QString text;
|
||||||
|
|
||||||
|
if (bps >= 1e9)
|
||||||
|
return QObject::tr("%L1 Gbps").arg(bps/1e9, 0, 'f', 4);
|
||||||
|
|
||||||
|
if (bps >= 1e6)
|
||||||
|
return QObject::tr("%L1 Mbps").arg(bps/1e6, 0, 'f', 4);
|
||||||
|
|
||||||
|
if (bps >= 1e3)
|
||||||
|
return QObject::tr("%L1 Kbps").arg(bps/1e3, 0, 'f', 4);
|
||||||
|
|
||||||
|
return QObject::tr("%L1 bps").arg(bps, 0, 'f', 4);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -212,6 +212,9 @@ message Port {
|
|||||||
optional TransmitMode transmit_mode = 7 [default = kSequentialTransmit];
|
optional TransmitMode transmit_mode = 7 [default = kSequentialTransmit];
|
||||||
optional string user_name = 8;
|
optional string user_name = 8;
|
||||||
optional bool is_tracking_stream_stats = 9;
|
optional bool is_tracking_stream_stats = 9;
|
||||||
|
|
||||||
|
optional double speed = 10; // in Mbps
|
||||||
|
optional uint32 mtu = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PortConfigList {
|
message PortConfigList {
|
||||||
|
@ -64,6 +64,11 @@ AbstractPort::~AbstractPort()
|
|||||||
|
|
||||||
void AbstractPort::init()
|
void AbstractPort::init()
|
||||||
{
|
{
|
||||||
|
if (interfaceInfo_) {
|
||||||
|
data_.set_speed(interfaceInfo_->speed);
|
||||||
|
data_.set_mtu(interfaceInfo_->mtu);
|
||||||
|
}
|
||||||
|
|
||||||
if (deviceManager_)
|
if (deviceManager_)
|
||||||
deviceManager_->createHostDevices();
|
deviceManager_->createHostDevices();
|
||||||
}
|
}
|
||||||
|
@ -215,6 +215,10 @@ void BsdPort::populateInterfaceInfo()
|
|||||||
|
|
||||||
interfaceInfo_ = new InterfaceInfo;
|
interfaceInfo_ = new InterfaceInfo;
|
||||||
interfaceInfo_->mac = mac;
|
interfaceInfo_->mac = mac;
|
||||||
|
if (mac) {
|
||||||
|
interfaceInfo_->speed = ((struct if_data*)addr->ifa_data)->ifi_baudrate/1e6;
|
||||||
|
interfaceInfo_->mtu = ((struct if_data*)addr->ifa_data)->ifi_mtu;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Find gateways
|
// Find gateways
|
||||||
|
@ -59,6 +59,7 @@ SOURCES += \
|
|||||||
bsdport.cpp \
|
bsdport.cpp \
|
||||||
linuxhostdevice.cpp \
|
linuxhostdevice.cpp \
|
||||||
linuxport.cpp \
|
linuxport.cpp \
|
||||||
|
linuxutils.cpp \
|
||||||
params.cpp \
|
params.cpp \
|
||||||
winhostdevice.cpp \
|
winhostdevice.cpp \
|
||||||
winpcapport.cpp
|
winpcapport.cpp
|
||||||
|
@ -39,6 +39,9 @@ struct InterfaceInfo
|
|||||||
quint64 mac;
|
quint64 mac;
|
||||||
QList<Ip4Config> ip4;
|
QList<Ip4Config> ip4;
|
||||||
QList<Ip6Config> ip6;
|
QList<Ip6Config> ip6;
|
||||||
|
|
||||||
|
double speed{0}; // in Mbps
|
||||||
|
quint32 mtu{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
|||||||
#include "linuxport.h"
|
#include "linuxport.h"
|
||||||
|
|
||||||
#include "interfaceinfo.h"
|
#include "interfaceinfo.h"
|
||||||
|
#include "linuxutils.h"
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
|
|
||||||
@ -243,10 +244,13 @@ void LinuxPort::populateInterfaceInfo()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interfaceInfo_ = new InterfaceInfo;
|
||||||
|
interfaceInfo_->speed = sysfsAttrib(name(), "speed").toDouble();
|
||||||
|
interfaceInfo_->mtu = rtnl_link_get_mtu(link);
|
||||||
|
|
||||||
int ifIndex = rtnl_link_get_ifindex(link);
|
int ifIndex = rtnl_link_get_ifindex(link);
|
||||||
rtnl_link_put(link);
|
rtnl_link_put(link);
|
||||||
|
|
||||||
interfaceInfo_ = new InterfaceInfo;
|
|
||||||
interfaceInfo_->mac = mac;
|
interfaceInfo_->mac = mac;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
65
server/linuxutils.cpp
Normal file
65
server/linuxutils.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
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 "linuxutils.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
// Reads a text file (size < 4K) and returns content as a string
|
||||||
|
// A terminating \n will be removed
|
||||||
|
// There's no way to distinguish an empty file and error while reading
|
||||||
|
QString readTextFile(QString fileName)
|
||||||
|
{
|
||||||
|
QFile file(fileName);
|
||||||
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
qWarning("Can't read %s", qUtf8Printable(fileName));
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.size() > 4096) {
|
||||||
|
qWarning("Can't read %s - too large (%lld)",
|
||||||
|
qUtf8Printable(fileName), file.size());
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream in(&file);
|
||||||
|
QString text = in.readAll();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (text.endsWith('\n'))
|
||||||
|
text.chop(1);
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads value from /sys/class/net/<device>/<attrib-path>
|
||||||
|
// and returns as string
|
||||||
|
// XXX: reading from sysfs is discouraged
|
||||||
|
QString sysfsAttrib(const char *device, const char *attribPath)
|
||||||
|
{
|
||||||
|
return readTextFile(QString("/sys/class/net/%1/%2")
|
||||||
|
.arg(device).arg(attribPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience overload
|
||||||
|
QString sysfsAttrib(QString device, const char *attribPath)
|
||||||
|
{
|
||||||
|
return sysfsAttrib(qPrintable(device), attribPath);
|
||||||
|
}
|
29
server/linuxutils.h
Normal file
29
server/linuxutils.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
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 _LINUX_UTILS_H
|
||||||
|
#define _LINUX_UTILS_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
QString readTextFile(QString fileName);
|
||||||
|
QString sysfsAttrib(const char *device, const char *attribPath);
|
||||||
|
QString sysfsAttrib(QString device, const char *attribPath);
|
||||||
|
|
||||||
|
#endif
|
@ -74,7 +74,7 @@ PortManager::PortManager()
|
|||||||
{
|
{
|
||||||
AbstractPort *port;
|
AbstractPort *port;
|
||||||
|
|
||||||
qDebug("%d. %s", i, device->name);
|
qDebug("==========\n%d. %s", i, device->name);
|
||||||
if (device->description)
|
if (device->description)
|
||||||
qDebug(" (%s)\n", device->description);
|
qDebug(" (%s)\n", device->description);
|
||||||
|
|
||||||
@ -122,6 +122,8 @@ PortManager::PortManager()
|
|||||||
qPrintable(QHostAddress(ip.address.toArray()).toString()),
|
qPrintable(QHostAddress(ip.address.toArray()).toString()),
|
||||||
ip.prefixLength,
|
ip.prefixLength,
|
||||||
qPrintable(QHostAddress(ip.gateway.toArray()).toString()));
|
qPrintable(QHostAddress(ip.gateway.toArray()).toString()));
|
||||||
|
qDebug("Speed: %g Mbps", intfInfo->speed);
|
||||||
|
qDebug("Mtu: %u", intfInfo->mtu);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!port->setRateAccuracy(txRateAccuracy))
|
if (!port->setRateAccuracy(txRateAccuracy))
|
||||||
|
@ -261,6 +261,11 @@ void WinPcapPort::populateInterfaceInfo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
interfaceInfo_ = new InterfaceInfo;
|
interfaceInfo_ = new InterfaceInfo;
|
||||||
|
|
||||||
|
interfaceInfo_->speed = adapter->TransmitLinkSpeed != quint64(-1) ?
|
||||||
|
adapter->TransmitLinkSpeed/1e6 : 0;
|
||||||
|
interfaceInfo_->mtu = adapter->Mtu;
|
||||||
|
|
||||||
if (adapter->PhysicalAddressLength == 6) {
|
if (adapter->PhysicalAddressLength == 6) {
|
||||||
interfaceInfo_->mac = qFromBigEndian<quint64>(
|
interfaceInfo_->mac = qFromBigEndian<quint64>(
|
||||||
adapter->PhysicalAddress) >> 16;
|
adapter->PhysicalAddress) >> 16;
|
||||||
|
Loading…
Reference in New Issue
Block a user