Extract streamsWidget code out of portsWindow

All functionality seems to be working, so hopefully no regressions!

It does appear to me that portWidget can be extracted out of
streamsWidget
This commit is contained in:
Srivats P 2021-11-05 15:27:37 +05:30
parent 214c774fc6
commit 0a825a0aa3
6 changed files with 123 additions and 1260 deletions

View File

@ -65,6 +65,7 @@ HEADERS += \
streamstatsfiltermodel.h \ streamstatsfiltermodel.h \
streamstatsmodel.h \ streamstatsmodel.h \
streamstatswindow.h \ streamstatswindow.h \
streamswidget.h \
variablefieldswidget.h \ variablefieldswidget.h \
xtableview.h xtableview.h
@ -116,6 +117,7 @@ SOURCES += \
streammodel.cpp \ streammodel.cpp \
streamstatsmodel.cpp \ streamstatsmodel.cpp \
streamstatswindow.cpp \ streamstatswindow.cpp \
streamswidget.cpp \
variablefieldswidget.cpp variablefieldswidget.cpp

View File

@ -20,52 +20,35 @@ 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 "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;
Ui::PortsWindow::setupUi(this); setupUi(this);
Ui::StreamsWidget::setupUi(streamsWidget);
applyMsg_ = new ApplyMessage(); applyMsg_ = new ApplyMessage();
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);
@ -75,41 +58,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
@ -139,52 +99,20 @@ 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&)),
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_;
} }
@ -322,30 +250,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)
{ {
@ -357,16 +261,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,
@ -387,9 +287,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)));
@ -447,139 +344,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)
{ {
@ -587,7 +351,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");
@ -839,259 +603,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;
}

View File

@ -20,14 +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 "ui_streamswidget.h" #include <QWidget>
#include "portgrouplist.h"
class ApplyMessage; class ApplyMessage;
class QAbstractItemDelegate; class PortGroupList;
class QProgressDialog; class QProgressDialog;
class QSortFilterProxyModel; class QSortFilterProxyModel;
@ -35,13 +33,10 @@ namespace OstProto {
class SessionContent; class SessionContent;
} }
class PortsWindow : public QWidget, private Ui::PortsWindow, private Ui::StreamsWidget 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();
@ -59,12 +54,6 @@ signals:
void currentPortChanged(const QModelIndex &current, void currentPortChanged(const QModelIndex &current,
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);
@ -72,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,
@ -96,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

View File

@ -213,7 +213,7 @@
</attribute> </attribute>
<layout class="QVBoxLayout"> <layout class="QVBoxLayout">
<item> <item>
<widget class="QWidget" name="streamsWidget" native="true"/> <widget class="StreamsWidget" name="streamsWidget" native="true"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -297,6 +297,12 @@
<extends>QTreeView</extends> <extends>QTreeView</extends>
<header>xtreeview.h</header> <header>xtreeview.h</header>
</customwidget> </customwidget>
<customwidget>
<class>StreamsWidget</class>
<extends>QWidget</extends>
<header>streamswidget.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="ostinato.qrc"/> <include location="ostinato.qrc"/>

View File

@ -17,64 +17,32 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/> along with this program. If not, see <http://www.gnu.org/licenses/>
*/ */
#include "portswindow.h" #include "streamswidget.h"
#include "applymsg.h"
#include "clipboardhelper.h" #include "clipboardhelper.h"
#include "deviceswidget.h" #include "portgrouplist.h"
#include "portconfigdialog.h"
#include "settings.h"
#include "streamconfigdialog.h" #include "streamconfigdialog.h"
#include "streamfileformat.h" #include "streamfileformat.h"
#include "streamlistdelegate.h" #include "streamlistdelegate.h"
#include "fileformat.pb.h"
#include "xqlocale.h" #include "xqlocale.h"
#include <QFileInfo>
#include <QInputDialog> #include <QInputDialog>
#include <QItemSelectionModel> #include <QItemSelectionModel>
#include <QMainWindow>
#include <QMessageBox> #include <QMessageBox>
#include <QSortFilterProxyModel>
extern ClipboardHelper *clipboardHelper; extern ClipboardHelper *clipboardHelper;
extern QMainWindow *mainWindow;
PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent) StreamsWidget::StreamsWidget(QWidget *parent)
: QWidget(parent), proxyPortModel(NULL) : QWidget(parent)
{ {
QAction *sep; setupUi(this);
delegate = new StreamListDelegate; delegate = new StreamListDelegate;
proxyPortModel = new QSortFilterProxyModel(this);
//slm = new StreamListModel();
//plm = new PortGroupList();
plm = pgl;
Ui::PortsWindow::setupUi(this);
Ui::StreamsWidget::setupUi(streamsWidget);
applyMsg_ = new ApplyMessage();
devicesWidget->setPortGroupList(plm);
tvPortList->header()->hide();
tvStreamList->setItemDelegate(delegate); tvStreamList->setItemDelegate(delegate);
tvStreamList->verticalHeader()->setDefaultSectionSize( tvStreamList->verticalHeader()->setDefaultSectionSize(
tvStreamList->verticalHeader()->minimumSectionSize()); tvStreamList->verticalHeader()->minimumSectionSize());
// Populate PortList Context Menu Actions
tvPortList->addAction(actionNew_Port_Group);
tvPortList->addAction(actionDelete_Port_Group);
tvPortList->addAction(actionConnect_Port_Group);
tvPortList->addAction(actionDisconnect_Port_Group);
tvPortList->addAction(actionExclusive_Control);
tvPortList->addAction(actionPort_Configuration);
// Populate StreamList Context Menu Actions // Populate StreamList Context Menu Actions
tvStreamList->addAction(actionNew_Stream); tvStreamList->addAction(actionNew_Stream);
tvStreamList->addAction(actionEdit_Stream); tvStreamList->addAction(actionEdit_Stream);
@ -88,61 +56,24 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
tvStreamList->addAction(actionOpen_Streams); tvStreamList->addAction(actionOpen_Streams);
tvStreamList->addAction(actionSave_Streams); tvStreamList->addAction(actionSave_Streams);
// PortList, StreamList, DeviceWidget actions combined // StreamWidget's actions is an aggegate of all sub-widget's actions
// make this window's actions
addActions(tvPortList->actions());
sep = new QAction(this);
sep->setSeparator(true);
addAction(sep);
addActions(tvStreamList->actions()); addActions(tvStreamList->actions());
sep = new QAction(this);
sep->setSeparator(true);
addAction(sep);
addActions(devicesWidget->actions());
// Add the clipboard actions to the context menu of streamList // Add the clipboard actions to the context menu of streamList
// but not to PortsWindow's actions since they are already available // but not to StreamsWidget's actions since they are already available
// in the global Edit Menu // in the global Edit Menu
sep = new QAction("Clipboard", this); QAction *sep3 = new QAction("Clipboard", this);
sep->setSeparator(true); sep3->setSeparator(true);
tvStreamList->insertAction(sep2, sep); tvStreamList->insertAction(sep2, sep3);
tvStreamList->insertActions(sep2, clipboardHelper->actions()); tvStreamList->insertActions(sep2, clipboardHelper->actions());
}
void StreamsWidget::setPortGroupList(PortGroupList *portGroups)
{
plm = portGroups;
tvStreamList->setModel(plm->getStreamModel()); tvStreamList->setModel(plm->getStreamModel());
// 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
// used by the source model and the proxy model are different
// i.e. the row, column, internalId/internalPtr used by both
// will be different. Since our domain objects - PortGroupList,
// PortGroup, Port etc. use these attributes, we need to map the
// proxy's index to the source's index before invoking any domain
// object methods
// TODO: research if we can skip the mapping when the domain
// objects' design is reviewed
if (proxyPortModel) {
proxyPortModel->setSourceModel(plm->getPortModel());
tvPortList->setModel(proxyPortModel);
}
else
tvPortList->setModel(plm->getPortModel());
connect( plm->getPortModel(),
SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
this, SLOT(when_portModel_dataChanged(const QModelIndex&,
const QModelIndex&)));
connect(plm->getPortModel(), SIGNAL(modelReset()),
SLOT(when_portModel_reset()));
connect( tvPortList->selectionModel(),
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
this, SLOT(when_portView_currentChanged(const QModelIndex&,
const QModelIndex&)));
connect(this,
SIGNAL(currentPortChanged(const QModelIndex&, const QModelIndex&)),
devicesWidget, SLOT(setCurrentPortIndex(const QModelIndex&)));
connect(plm->getStreamModel(), SIGNAL(rowsInserted(QModelIndex, int, int)), connect(plm->getStreamModel(), SIGNAL(rowsInserted(QModelIndex, int, int)),
SLOT(updateStreamViewActions())); SLOT(updateStreamViewActions()));
connect(plm->getStreamModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)), connect(plm->getStreamModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)),
@ -158,9 +89,6 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
tvStreamList->resizeColumnToContents(StreamModel::StreamIcon); tvStreamList->resizeColumnToContents(StreamModel::StreamIcon);
tvStreamList->resizeColumnToContents(StreamModel::StreamStatus); tvStreamList->resizeColumnToContents(StreamModel::StreamStatus);
// Initially we don't have any ports/streams/devices
// - so send signal triggers
when_portView_currentChanged(QModelIndex(), QModelIndex());
updateStreamViewActions(); updateStreamViewActions();
connect(plm->getStreamModel(), connect(plm->getStreamModel(),
@ -171,158 +99,18 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
this, SLOT(streamModelDataChanged())); this, SLOT(streamModelDataChanged()));
} }
void PortsWindow::streamModelDataChanged() void StreamsWidget::streamModelDataChanged()
{ {
QModelIndex current = tvPortList->currentIndex(); if (plm->isPort(currentPortIndex_))
plm->port(currentPortIndex_).recalculateAverageRates();
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
if (plm->isPort(current))
plm->port(current).recalculateAverageRates();
} }
PortsWindow::~PortsWindow() StreamsWidget::~StreamsWidget()
{ {
delete delegate; delete delegate;
delete proxyPortModel;
delete applyMsg_;
} }
int PortsWindow::portGroupCount() void StreamsWidget::on_tvStreamList_activated(const QModelIndex & index)
{
return plm->numPortGroups();
}
int PortsWindow::reservedPortCount()
{
int count = 0;
int n = portGroupCount();
for (int i = 0; i < n; i++)
count += plm->portGroupByIndex(i).numReservedPorts();
return count;
}
//! Always return true
bool PortsWindow::openSession(
const OstProto::SessionContent *session,
QString & /*error*/)
{
QProgressDialog progress("Opening Session", NULL,
0, session->port_groups_size(), mainWindow);
progress.show();
progress.setEnabled(true); // since parent (mainWindow) is disabled
plm->removeAllPortGroups();
for (int i = 0; i < session->port_groups_size(); i++) {
const OstProto::PortGroupContent &pgc = session->port_groups(i);
PortGroup *pg = new PortGroup(QString::fromStdString(
pgc.server_name()),
quint16(pgc.server_port()));
pg->setConfigAtConnect(&pgc);
plm->addPortGroup(*pg);
progress.setValue(i+1);
}
return true;
}
/*!
* Prepare content to be saved for a session
*
* If port reservation is in use, saves only 'my' reserved ports
*
* Returns false, if user cancels op; true, otherwise
*/
bool PortsWindow::saveSession(
OstProto::SessionContent *session, // OUT param
QString & /*error*/,
QProgressDialog *progress)
{
int n = portGroupCount();
QString myself;
if (progress) {
progress->setLabelText("Preparing Ports and PortGroups ...");
progress->setRange(0, n);
}
if (reservedPortCount())
myself = appSettings->value(kUserKey, kUserDefaultValue).toString();
for (int i = 0; i < n; i++)
{
PortGroup &pg = plm->portGroupByIndex(i);
OstProto::PortGroupContent *pgc = session->add_port_groups();
pgc->set_server_name(pg.serverName().toStdString());
pgc->set_server_port(pg.serverPort());
for (int j = 0; j < pg.numPorts(); j++)
{
if (myself != pg.mPorts.at(j)->userName())
continue;
OstProto::PortContent *pc = pgc->add_ports();
OstProto::Port *p = pc->mutable_port_config();
// XXX: We save the entire OstProto::Port even though some
// fields may be ephemeral; while opening we use only relevant
// fields
pg.mPorts.at(j)->protoDataCopyInto(p);
for (int k = 0; k < pg.mPorts.at(j)->numStreams(); k++)
{
OstProto::Stream *s = pc->add_streams();
pg.mPorts.at(j)->streamByIndex(k)->protoDataCopyInto(*s);
}
for (int k = 0; k < pg.mPorts.at(j)->numDeviceGroups(); k++)
{
OstProto::DeviceGroup *dg = pc->add_device_groups();
dg->CopyFrom(*(pg.mPorts.at(j)->deviceGroupByIndex(k)));
}
}
if (progress) {
if (progress->wasCanceled())
return false;
progress->setValue(i);
}
if (i % 2 == 0)
qApp->processEvents();
}
return true;
}
void PortsWindow::clearCurrentSelection()
{
tvPortList->selectionModel()->clearCurrentIndex();
tvPortList->clearSelection();
}
void PortsWindow::showMyReservedPortsOnly(bool enabled)
{
if (!proxyPortModel)
return;
if (enabled) {
QString rx = "Port Group|\\["
+ QRegExp::escape(appSettings->value(kUserKey,
kUserDefaultValue).toString())
+ "\\]";
qDebug("%s: regexp: <%s>", __FUNCTION__, qPrintable(rx));
proxyPortModel->setFilterRegExp(QRegExp(rx));
}
else
proxyPortModel->setFilterRegExp(QRegExp(""));
}
void PortsWindow::on_tvStreamList_activated(const QModelIndex & index)
{ {
if (!index.isValid()) if (!index.isValid())
{ {
@ -332,9 +120,7 @@ void PortsWindow::on_tvStreamList_activated(const QModelIndex & index)
qDebug("stream list activated\n"); qDebug("stream list activated\n");
Port &curPort = plm->port(proxyPortModel ? Port &curPort = plm->port(currentPortIndex_);
proxyPortModel->mapToSource(tvPortList->currentIndex()) :
tvPortList->currentIndex());
QList<Stream*> streams; QList<Stream*> streams;
streams.append(curPort.mutableStreamByIndex(index.row(), false)); streams.append(curPort.mutableStreamByIndex(index.row(), false));
@ -346,197 +132,95 @@ void PortsWindow::on_tvStreamList_activated(const QModelIndex & index)
} }
} }
void PortsWindow::when_portView_currentChanged(const QModelIndex& currentIndex, void StreamsWidget::setCurrentPortIndex(const QModelIndex &portIndex)
const QModelIndex& previousIndex)
{ {
QModelIndex current = currentIndex; if (!plm)
QModelIndex previous = previousIndex; return;
if (proxyPortModel) { // XXX: We assume portIndex corresponds to sourceModel, not proxyModel
current = proxyPortModel->mapToSource(current); if (!plm->isPort(portIndex))
previous = proxyPortModel->mapToSource(previous); return;
}
plm->getStreamModel()->setCurrentPortIndex(current);
updatePortViewActions(currentIndex);
updateStreamViewActions();
qDebug("In %s", __FUNCTION__); qDebug("In %s", __FUNCTION__);
if (previous.isValid() && plm->isPort(previous)) // Disconnect previous port
{ if (plm->isPort(currentPortIndex_))
disconnect(&(plm->port(previous)), SIGNAL(portRateChanged(int, int)), disconnect(&(plm->port(currentPortIndex_)),
SIGNAL(portRateChanged(int, int)),
this, SLOT(updatePortRates())); this, SLOT(updatePortRates()));
disconnect(&(plm->port(previous)),
SIGNAL(localConfigChanged(int, int, bool)),
this,
SLOT(updateApplyHint(int, int, bool)));
}
if (!current.isValid()) currentPortIndex_ = portIndex;
{ plm->getStreamModel()->setCurrentPortIndex(portIndex);
qDebug("setting stacked widget to welcome page");
swDetail->setCurrentIndex(0); // welcome page // Connect current port
} if (plm->isPort(currentPortIndex_))
else connect(&(plm->port(currentPortIndex_)),
{ SIGNAL(portRateChanged(int, int)),
if (plm->isPortGroup(current)) this, SLOT(updatePortRates()));
{
swDetail->setCurrentIndex(1); // portGroup detail page
}
else if (plm->isPort(current))
{
swDetail->setCurrentIndex(2); // port detail page
updatePortRates(); updatePortRates();
connect(&(plm->port(current)), SIGNAL(portRateChanged(int, int)), updateStreamViewActions();
SLOT(updatePortRates()));
connect(&(plm->port(current)),
SIGNAL(localConfigChanged(int, int, bool)),
SLOT(updateApplyHint(int, int, bool)));
if (plm->port(current).isDirty())
updateApplyHint(plm->port(current).portGroupId(),
plm->port(current).id(), true);
else if (plm->port(current).numStreams())
applyHint->setText("Click <img src=':/icons/control_play'/> "
"to transmit packets");
else
applyHint->setText("");
}
}
emit currentPortChanged(current, previous);
} }
void PortsWindow::when_portModel_dataChanged(const QModelIndex& topLeft, void StreamsWidget::on_startTx_clicked()
const QModelIndex& bottomRight)
{ {
qDebug("In %s %d:(%d, %d) - %d:(%d, %d)", __FUNCTION__, Q_ASSERT(plm->isPort(currentPortIndex_));
topLeft.parent().isValid(), topLeft.row(), topLeft.column(),
bottomRight.parent().isValid(), bottomRight.row(), bottomRight.column());
if (!topLeft.isValid() || !bottomRight.isValid()) QModelIndex curPortGroup = plm->getPortModel()->parent(currentPortIndex_);
return;
if (topLeft.parent() != bottomRight.parent())
return;
// If a port has changed, expand the port group
if (topLeft.parent().isValid())
tvPortList->expand(proxyPortModel ?
proxyPortModel->mapFromSource(topLeft.parent()) :
topLeft.parent());
#if 0 // not sure why the >= <= operators are not overloaded in QModelIndex
if ((tvPortList->currentIndex() >= topLeft) &&
(tvPortList->currentIndex() <= bottomRight))
#endif
if (((topLeft < tvPortList->currentIndex()) ||
(topLeft == tvPortList->currentIndex())) &&
(((tvPortList->currentIndex() < bottomRight)) ||
(tvPortList->currentIndex() == bottomRight)))
{
// Update UI to reflect potential change in exclusive mode,
// transmit mode et al
when_portView_currentChanged(tvPortList->currentIndex(),
tvPortList->currentIndex());
}
}
void PortsWindow::when_portModel_reset()
{
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(curPortGroup.isValid());
Q_ASSERT(plm->isPortGroup(curPortGroup)); Q_ASSERT(plm->isPortGroup(curPortGroup));
QList<uint> portList({plm->port(current).id()}); QList<uint> portList({plm->port(currentPortIndex_).id()});
plm->portGroup(curPortGroup).startTx(&portList); plm->portGroup(curPortGroup).startTx(&portList);
} }
void PortsWindow::on_stopTx_clicked() void StreamsWidget::on_stopTx_clicked()
{ {
QModelIndex current = tvPortList->currentIndex(); Q_ASSERT(plm->isPort(currentPortIndex_));
if (proxyPortModel) QModelIndex curPortGroup = plm->getPortModel()->parent(currentPortIndex_);
current = proxyPortModel->mapToSource(current);
Q_ASSERT(plm->isPort(current));
QModelIndex curPortGroup = plm->getPortModel()->parent(current);
Q_ASSERT(curPortGroup.isValid()); Q_ASSERT(curPortGroup.isValid());
Q_ASSERT(plm->isPortGroup(curPortGroup)); Q_ASSERT(plm->isPortGroup(curPortGroup));
QList<uint> portList({plm->port(current).id()}); QList<uint> portList({plm->port(currentPortIndex_).id()});
plm->portGroup(curPortGroup).stopTx(&portList); plm->portGroup(curPortGroup).stopTx(&portList);
} }
void PortsWindow::on_averagePacketsPerSec_editingFinished() void StreamsWidget::on_averagePacketsPerSec_editingFinished()
{ {
QModelIndex current = tvPortList->currentIndex(); Q_ASSERT(plm->isPort(currentPortIndex_));
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
Q_ASSERT(plm->isPort(current));
bool isOk; bool isOk;
double pps = XLocale().toDouble(averagePacketsPerSec->text(), &isOk); double pps = XLocale().toDouble(averagePacketsPerSec->text(), &isOk);
plm->port(current).setAveragePacketRate(pps); plm->port(currentPortIndex_).setAveragePacketRate(pps);
} }
void PortsWindow::on_averageBitsPerSec_editingFinished() void StreamsWidget::on_averageBitsPerSec_editingFinished()
{ {
QModelIndex current = tvPortList->currentIndex(); Q_ASSERT(plm->isPort(currentPortIndex_));
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
Q_ASSERT(plm->isPort(current));
bool isOk; bool isOk;
double bps = XLocale().toDouble(averageBitsPerSec->text(), &isOk); double bps = XLocale().toDouble(averageBitsPerSec->text(), &isOk);
plm->port(current).setAverageBitRate(bps); plm->port(currentPortIndex_).setAverageBitRate(bps);
} }
void PortsWindow::updatePortRates() void StreamsWidget::updatePortRates()
{ {
QModelIndex current = tvPortList->currentIndex(); if (!currentPortIndex_.isValid())
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
if (!current.isValid())
return; return;
if (!plm->isPort(current)) if (!plm->isPort(currentPortIndex_))
return; return;
averagePacketsPerSec->setText(QString("%L1") averagePacketsPerSec->setText(QString("%L1")
.arg(plm->port(current).averagePacketRate(), 0, 'f', 4)); .arg(plm->port(currentPortIndex_).averagePacketRate(), 0, 'f', 4));
averageBitsPerSec->setText(QString("%L1") averageBitsPerSec->setText(QString("%L1")
.arg(plm->port(current).averageBitRate(), 0, 'f', 0)); .arg(plm->port(currentPortIndex_).averageBitRate(), 0, 'f', 0));
} }
void PortsWindow::updateStreamViewActions() void StreamsWidget::updateStreamViewActions()
{ {
QModelIndex current = tvPortList->currentIndex();
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
// For some reason hasSelection() returns true even if selection size is 0 // For some reason hasSelection() returns true even if selection size is 0
// so additional check for size introduced // so additional check for size introduced
if (tvStreamList->selectionModel()->hasSelection() && if (tvStreamList->selectionModel()->hasSelection() &&
@ -565,7 +249,7 @@ void PortsWindow::updateStreamViewActions()
else else
{ {
qDebug("No selection"); qDebug("No selection");
if (plm->isPort(current)) if (plm->isPort(currentPortIndex_))
actionNew_Stream->setEnabled(true); actionNew_Stream->setEnabled(true);
else else
actionNew_Stream->setDisabled(true); actionNew_Stream->setDisabled(true);
@ -573,274 +257,14 @@ void PortsWindow::updateStreamViewActions()
actionDuplicate_Stream->setDisabled(true); actionDuplicate_Stream->setDisabled(true);
actionDelete_Stream->setDisabled(true); actionDelete_Stream->setDisabled(true);
} }
actionOpen_Streams->setEnabled(plm->isPort(current)); actionOpen_Streams->setEnabled(plm->isPort(currentPortIndex_));
actionSave_Streams->setEnabled(tvStreamList->model()->rowCount() > 0); actionSave_Streams->setEnabled(tvStreamList->model()->rowCount() > 0);
startTx->setEnabled(tvStreamList->model()->rowCount() > 0); startTx->setEnabled(tvStreamList->model()->rowCount() > 0);
stopTx->setEnabled(tvStreamList->model()->rowCount() > 0); stopTx->setEnabled(tvStreamList->model()->rowCount() > 0);
} }
void PortsWindow::updateApplyHint(int /*portGroupId*/, int /*portId*/, void StreamsWidget::on_actionNew_Stream_triggered()
bool configChanged)
{
if (configChanged)
applyHint->setText("Configuration has changed - "
"<font color='red'><b>click Apply</b></font> "
"to activate the changes");
else if (tvStreamList->model()->rowCount() > 0)
applyHint->setText("Configuration activated - "
"click <img src=':/icons/control_play'/> "
"to transmit packets");
else
applyHint->setText("Configuration activated");
}
void PortsWindow::updatePortViewActions(const QModelIndex& currentIndex)
{
QModelIndex current = currentIndex;
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
if (!current.isValid())
{
qDebug("current is now invalid");
actionDelete_Port_Group->setDisabled(true);
actionConnect_Port_Group->setDisabled(true);
actionDisconnect_Port_Group->setDisabled(true);
actionExclusive_Control->setDisabled(true);
actionPort_Configuration->setDisabled(true);
goto _EXIT;
}
qDebug("currentChanged %p", (void*)current.internalId());
if (plm->isPortGroup(current))
{
actionDelete_Port_Group->setEnabled(true);
actionExclusive_Control->setDisabled(true);
actionPort_Configuration->setDisabled(true);
switch(plm->portGroup(current).state())
{
case QAbstractSocket::UnconnectedState:
case QAbstractSocket::ClosingState:
qDebug("state = unconnected|closing");
actionConnect_Port_Group->setEnabled(true);
actionDisconnect_Port_Group->setDisabled(true);
break;
case QAbstractSocket::HostLookupState:
case QAbstractSocket::ConnectingState:
case QAbstractSocket::ConnectedState:
qDebug("state = lookup|connecting|connected");
actionConnect_Port_Group->setDisabled(true);
actionDisconnect_Port_Group->setEnabled(true);
break;
case QAbstractSocket::BoundState:
case QAbstractSocket::ListeningState:
default:
// FIXME(LOW): indicate error
qDebug("unexpected state");
break;
}
}
else if (plm->isPort(current))
{
actionDelete_Port_Group->setDisabled(true);
actionConnect_Port_Group->setDisabled(true);
actionDisconnect_Port_Group->setDisabled(true);
actionExclusive_Control->setEnabled(true);
if (plm->port(current).hasExclusiveControl())
actionExclusive_Control->setChecked(true);
else
actionExclusive_Control->setChecked(false);
actionPort_Configuration->setEnabled(true);
}
_EXIT:
return;
}
void PortsWindow::on_pbApply_clicked()
{
QModelIndex curPort;
QModelIndex curPortGroup;
curPort = tvPortList->selectionModel()->currentIndex();
if (proxyPortModel)
curPort = proxyPortModel->mapToSource(curPort);
if (!curPort.isValid())
{
qDebug("%s: curPort is invalid", __FUNCTION__);
goto _exit;
}
if (!plm->isPort(curPort))
{
qDebug("%s: curPort is not a port", __FUNCTION__);
goto _exit;
}
if (plm->port(curPort).getStats().state().is_transmit_on())
{
QMessageBox::information(0, "Configuration Change",
"Please stop transmit on the port before applying any changes");
goto _exit;
}
curPortGroup = plm->getPortModel()->parent(curPort);
if (!curPortGroup.isValid())
{
qDebug("%s: curPortGroup is invalid", __FUNCTION__);
goto _exit;
}
if (!plm->isPortGroup(curPortGroup))
{
qDebug("%s: curPortGroup is not a portGroup", __FUNCTION__);
goto _exit;
}
disconnect(applyMsg_);
connect(&(plm->portGroup(curPortGroup)), SIGNAL(applyFinished()),
applyMsg_, SLOT(hide()));
applyMsg_->show();
// FIXME(HI): shd this be a signal?
//portGroup.when_configApply(port);
// FIXME(MED): mixing port id and index!!!
plm->portGroup(curPortGroup).when_configApply(plm->port(curPort).id());
_exit:
return;
#if 0
// TODO (LOW): This block is for testing only
QModelIndex current = tvPortList->selectionModel()->currentIndex();
if (current.isValid())
qDebug("current = %llx", current.internalId());
else
qDebug("current is invalid");
#endif
}
void PortsWindow::on_actionNew_Port_Group_triggered()
{
bool ok;
QString text = QInputDialog::getText(this,
"Add Port Group", "Port Group Address (HostName[:Port])",
QLineEdit::Normal, lastNewPortGroup, &ok);
if (ok)
{
QStringList addr = text.split(":");
quint16 port = DEFAULT_SERVER_PORT;
if (addr.size() > 2) { // IPv6 Address
// IPv6 addresses with port number SHOULD be specified as
// [2001:db8::1]:80 (RFC5952 Sec6) to avoid ambiguity due to ':'
addr = text.split("]:");
if (addr.size() > 1)
port = addr[1].toUShort();
}
else if (addr.size() == 2) // Hostname/IPv4 + Port specified
port = addr[1].toUShort();
// Play nice and remove square brackets irrespective of addr type
addr[0].remove(QChar('['));
addr[0].remove(QChar(']'));
PortGroup *pg = new PortGroup(addr[0], port);
plm->addPortGroup(*pg);
lastNewPortGroup = text;
}
}
void PortsWindow::on_actionDelete_Port_Group_triggered()
{
QModelIndex current = tvPortList->selectionModel()->currentIndex();
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
if (current.isValid())
plm->removePortGroup(plm->portGroup(current));
}
void PortsWindow::on_actionConnect_Port_Group_triggered()
{
QModelIndex current = tvPortList->selectionModel()->currentIndex();
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
if (current.isValid())
plm->portGroup(current).connectToHost();
}
void PortsWindow::on_actionDisconnect_Port_Group_triggered()
{
QModelIndex current = tvPortList->selectionModel()->currentIndex();
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
if (current.isValid())
plm->portGroup(current).disconnectFromHost();
}
void PortsWindow::on_actionExclusive_Control_triggered(bool checked)
{
QModelIndex current = tvPortList->selectionModel()->currentIndex();
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
if (plm->isPort(current))
{
OstProto::Port config;
config.set_is_exclusive_control(checked);
plm->portGroup(current.parent()).modifyPort(current.row(), config);
}
}
void PortsWindow::on_actionPort_Configuration_triggered()
{
QModelIndex current = tvPortList->selectionModel()->currentIndex();
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
if (!plm->isPort(current))
return;
Port &port = plm->port(current);
OstProto::Port config;
// XXX: we don't call Port::protoDataCopyInto() to get config b'coz
// we want only the modifiable fields populated to send to Drone
// TODO: extend Port::protoDataCopyInto() to accept an optional param
// which says copy only modifiable fields
//plm->port(current).protoDataCopyInto(&config);
config.set_transmit_mode(port.transmitMode());
config.set_is_tracking_stream_stats(port.trackStreamStats());
config.set_is_exclusive_control(port.hasExclusiveControl());
config.set_user_name(port.userName().toStdString());
PortConfigDialog dialog(config, port.getStats().state(), this);
if (dialog.exec() == QDialog::Accepted)
plm->portGroup(current.parent()).modifyPort(current.row(), config);
}
void PortsWindow::on_actionNew_Stream_triggered()
{ {
qDebug("New Stream Action"); qDebug("New Stream Action");
@ -863,9 +287,7 @@ void PortsWindow::on_actionNew_Stream_triggered()
count = selectionModel->selection().at(0).height(); count = selectionModel->selection().at(0).height();
} }
Port &curPort = plm->port(proxyPortModel ? Port &curPort = plm->port(currentPortIndex_);
proxyPortModel->mapToSource(tvPortList->currentIndex()) :
tvPortList->currentIndex());
QList<Stream*> streams; QList<Stream*> streams;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
@ -877,7 +299,7 @@ void PortsWindow::on_actionNew_Stream_triggered()
streamModel->insert(row, streams); streamModel->insert(row, streams);
} }
void PortsWindow::on_actionEdit_Stream_triggered() void StreamsWidget::on_actionEdit_Stream_triggered()
{ {
qDebug("Edit Stream Action"); qDebug("Edit Stream Action");
@ -885,9 +307,7 @@ void PortsWindow::on_actionEdit_Stream_triggered()
if (!streamModel->hasSelection()) if (!streamModel->hasSelection())
return; return;
Port &curPort = plm->port(proxyPortModel ? Port &curPort = plm->port(currentPortIndex_);
proxyPortModel->mapToSource(tvPortList->currentIndex()) :
tvPortList->currentIndex());
QList<Stream*> streams; QList<Stream*> streams;
foreach(QModelIndex index, streamModel->selectedRows()) foreach(QModelIndex index, streamModel->selectedRows())
@ -900,16 +320,12 @@ void PortsWindow::on_actionEdit_Stream_triggered()
} }
} }
void PortsWindow::on_actionDuplicate_Stream_triggered() void StreamsWidget::on_actionDuplicate_Stream_triggered()
{ {
QItemSelectionModel* model = tvStreamList->selectionModel(); QItemSelectionModel* model = tvStreamList->selectionModel();
QModelIndex current = tvPortList->selectionModel()->currentIndex();
qDebug("Duplicate Stream Action"); qDebug("Duplicate Stream Action");
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
if (model->hasSelection()) if (model->hasSelection())
{ {
bool isOk; bool isOk;
@ -922,13 +338,13 @@ void PortsWindow::on_actionDuplicate_Stream_triggered()
QList<int> list; QList<int> list;
foreach(QModelIndex index, model->selectedRows()) foreach(QModelIndex index, model->selectedRows())
list.append(index.row()); list.append(index.row());
plm->port(current).duplicateStreams(list, count); plm->port(currentPortIndex_).duplicateStreams(list, count);
} }
else else
qDebug("No selection"); qDebug("No selection");
} }
void PortsWindow::on_actionDelete_Stream_triggered() void StreamsWidget::on_actionDelete_Stream_triggered()
{ {
qDebug("Delete Stream Action"); qDebug("Delete Stream Action");
@ -948,24 +364,20 @@ void PortsWindow::on_actionDelete_Stream_triggered()
qDebug("No selection"); qDebug("No selection");
} }
void PortsWindow::on_actionOpen_Streams_triggered() void StreamsWidget::on_actionOpen_Streams_triggered()
{ {
qDebug("Open Streams Action"); qDebug("Open Streams Action");
QStringList fileTypes = StreamFileFormat::supportedFileTypes( QStringList fileTypes = StreamFileFormat::supportedFileTypes(
StreamFileFormat::kOpenFile); StreamFileFormat::kOpenFile);
QString fileType; QString fileType;
QModelIndex current = tvPortList->selectionModel()->currentIndex();
static QString dirName; static QString dirName;
QString fileName; QString fileName;
QString errorStr; QString errorStr;
bool append = true; bool append = true;
bool ret; bool ret;
if (proxyPortModel) Q_ASSERT(plm->isPort(currentPortIndex_));
current = proxyPortModel->mapToSource(current);
Q_ASSERT(plm->isPort(current));
if (fileTypes.size()) if (fileTypes.size())
fileType = fileTypes.at(0); fileType = fileTypes.at(0);
@ -998,7 +410,7 @@ void PortsWindow::on_actionOpen_Streams_triggered()
Q_ASSERT(false); Q_ASSERT(false);
} }
ret = plm->port(current).openStreams(fileName, append, errorStr); ret = plm->port(currentPortIndex_).openStreams(fileName, append, errorStr);
if (!ret || !errorStr.isEmpty()) if (!ret || !errorStr.isEmpty())
{ {
QMessageBox msgBox(this); QMessageBox msgBox(this);
@ -1014,16 +426,16 @@ void PortsWindow::on_actionOpen_Streams_triggered()
msgBox.exec(); msgBox.exec();
} }
dirName = QFileInfo(fileName).absolutePath(); dirName = QFileInfo(fileName).absolutePath();
updateStreamViewActions();
_exit: _exit:
return; return;
} }
void PortsWindow::on_actionSave_Streams_triggered() void StreamsWidget::on_actionSave_Streams_triggered()
{ {
qDebug("Save Streams Action"); qDebug("Save Streams Action");
QModelIndex current = tvPortList->selectionModel()->currentIndex();
static QString fileName; static QString fileName;
QStringList fileTypes = StreamFileFormat::supportedFileTypes( QStringList fileTypes = StreamFileFormat::supportedFileTypes(
StreamFileFormat::kSaveFile); StreamFileFormat::kSaveFile);
@ -1031,9 +443,6 @@ void PortsWindow::on_actionSave_Streams_triggered()
QString errorStr; QString errorStr;
QFileDialog::Options options; QFileDialog::Options options;
if (proxyPortModel)
current = proxyPortModel->mapToSource(current);
// On Mac OS with Native Dialog, getSaveFileName() ignores fileType // On Mac OS with Native Dialog, getSaveFileName() ignores fileType
// which we need // which we need
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
@ -1043,7 +452,7 @@ void PortsWindow::on_actionSave_Streams_triggered()
if (fileTypes.size()) if (fileTypes.size())
fileType = fileTypes.at(0); fileType = fileTypes.at(0);
Q_ASSERT(plm->isPort(current)); Q_ASSERT(plm->isPort(currentPortIndex_));
_retry: _retry:
fileName = QFileDialog::getSaveFileName(this, tr("Save Streams"), fileName = QFileDialog::getSaveFileName(this, tr("Save Streams"),
@ -1083,7 +492,7 @@ _retry:
// TODO: all or selected? // TODO: all or selected?
if (!plm->port(current).saveStreams(fileName, fileType, errorStr)) if (!plm->port(currentPortIndex_).saveStreams(fileName, fileType, errorStr))
QMessageBox::critical(this, qApp->applicationName(), errorStr); QMessageBox::critical(this, qApp->applicationName(), errorStr);
else if (!errorStr.isEmpty()) else if (!errorStr.isEmpty())
QMessageBox::warning(this, qApp->applicationName(), errorStr); QMessageBox::warning(this, qApp->applicationName(), errorStr);

View File

@ -17,61 +17,30 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/> along with this program. If not, see <http://www.gnu.org/licenses/>
*/ */
#ifndef _PORTS_WINDOW_H #ifndef _STREAMS_WIDGET_H
#define _PORTS_WINDOW_H #define _STREAMS_WIDGET_H
#include <QWidget>
#include <QAbstractItemModel>
#include "ui_portswindow.h"
#include "ui_streamswidget.h" #include "ui_streamswidget.h"
#include "portgrouplist.h" #include <QWidget>
//#include <QAbstractItemModel>
class ApplyMessage; class PortGroupList;
class QAbstractItemDelegate; class QAbstractItemDelegate;
class QProgressDialog;
class QSortFilterProxyModel;
namespace OstProto { class StreamsWidget : public QWidget, private Ui::StreamsWidget
class SessionContent;
}
class PortsWindow : public QWidget, private Ui::PortsWindow, private Ui::StreamsWidget
{ {
Q_OBJECT Q_OBJECT
//QAbstractItemModel *slm; // stream list model
PortGroupList *plm;
public: public:
PortsWindow(PortGroupList *pgl, QWidget *parent = 0); StreamsWidget(QWidget *parent = 0);
~PortsWindow(); ~StreamsWidget();
int portGroupCount(); void setPortGroupList(PortGroupList *portGroups);
int reservedPortCount();
bool openSession(const OstProto::SessionContent *session,
QString &error);
bool saveSession(OstProto::SessionContent *session,
QString &error,
QProgressDialog *progress = NULL);
signals:
void currentPortChanged(const QModelIndex &current,
const QModelIndex &previous);
private:
QString lastNewPortGroup;
QAbstractItemDelegate *delegate;
QSortFilterProxyModel *proxyPortModel;
ApplyMessage *applyMsg_;
public slots: public slots:
void clearCurrentSelection(); void setCurrentPortIndex(const QModelIndex &portIndex);
void showMyReservedPortsOnly(bool enabled);
private slots: private slots:
void updateApplyHint(int portGroupId, int portId, bool configChanged);
void updatePortViewActions(const QModelIndex& currentIndex);
void updateStreamViewActions(); void updateStreamViewActions();
void on_startTx_clicked(); void on_startTx_clicked();
@ -80,21 +49,6 @@ private slots:
void on_averageBitsPerSec_editingFinished(); void on_averageBitsPerSec_editingFinished();
void updatePortRates(); void updatePortRates();
void on_tvStreamList_activated(const QModelIndex & index); void on_tvStreamList_activated(const QModelIndex & index);
void when_portView_currentChanged(const QModelIndex& currentIndex,
const QModelIndex& previousIndex);
void when_portModel_dataChanged(const QModelIndex& topLeft,
const QModelIndex& bottomRight);
void when_portModel_reset();
void on_pbApply_clicked();
void on_actionNew_Port_Group_triggered();
void on_actionDelete_Port_Group_triggered();
void on_actionConnect_Port_Group_triggered();
void on_actionDisconnect_Port_Group_triggered();
void on_actionExclusive_Control_triggered(bool checked);
void on_actionPort_Configuration_triggered();
void on_actionNew_Stream_triggered(); void on_actionNew_Stream_triggered();
void on_actionEdit_Stream_triggered(); void on_actionEdit_Stream_triggered();
@ -105,6 +59,12 @@ private slots:
void on_actionSave_Streams_triggered(); void on_actionSave_Streams_triggered();
void streamModelDataChanged(); void streamModelDataChanged();
private:
PortGroupList *plm{nullptr}; // FIXME: rename to portGroups_?
QModelIndex currentPortIndex_;
QAbstractItemDelegate *delegate;
}; };
#endif #endif