- Implemented the "Stop" and "Goto Stream" per stream "nextWhat" options (Goto can only go to first stream for now - not any arbitrary stream)

- StreamListView now has a delegate to display a combobox for "nextWhat" and a checkbox for "status"
- StreamListView now has reasonable default widths for its columns
This commit is contained in:
Srivats P. 2009-03-10 16:48:03 +00:00
parent f13b0915d5
commit 53bcc077da
12 changed files with 342 additions and 47 deletions

View File

@ -20,6 +20,7 @@ HEADERS += \
portstatswindow.h \ portstatswindow.h \
portswindow.h \ portswindow.h \
streamconfigdialog.h \ streamconfigdialog.h \
streamlistdelegate.h \
streammodel.h streammodel.h
FORMS += \ FORMS += \
@ -45,6 +46,7 @@ SOURCES += \
portstatswindow.cpp \ portstatswindow.cpp \
portswindow.cpp \ portswindow.cpp \
streamconfigdialog.cpp \ streamconfigdialog.cpp \
streamlistdelegate.cpp \
streammodel.cpp streammodel.cpp
# Protocol Buffer Sources # Protocol Buffer Sources

View File

@ -1,18 +1,20 @@
#include "portswindow.h" #include "portswindow.h"
#include "streamlistdelegate.h"
#include "streamconfigdialog.h" #include "streamconfigdialog.h"
#include <QInputDialog> #include <QInputDialog>
#include <QItemSelectionModel> #include <QItemSelectionModel>
PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent) PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
{ {
StreamListDelegate *delegate = new StreamListDelegate;
//slm = new StreamListModel(); //slm = new StreamListModel();
//plm = new PortGroupList(); //plm = new PortGroupList();
plm = pgl; plm = pgl;
setupUi(this); setupUi(this);
tvStreamList->horizontalHeader()->resizeSections( tvStreamList->setItemDelegate(delegate);
QHeaderView::ResizeToContents);
tvStreamList->verticalHeader()->setDefaultSectionSize( tvStreamList->verticalHeader()->setDefaultSectionSize(
tvStreamList->verticalHeader()->minimumSectionSize()); tvStreamList->verticalHeader()->minimumSectionSize());
@ -53,6 +55,9 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
plm->getStreamModel(), SLOT(setCurrentPortIndex(const QModelIndex&))); plm->getStreamModel(), SLOT(setCurrentPortIndex(const QModelIndex&)));
#endif #endif
tvStreamList->resizeColumnToContents(StreamModel::StreamIcon);
tvStreamList->resizeColumnToContents(StreamModel::StreamStatus);
// Initially we don't have any ports/streams - so send signal triggers // Initially we don't have any ports/streams - so send signal triggers
when_portView_currentChanged(QModelIndex(), QModelIndex()); when_portView_currentChanged(QModelIndex(), QModelIndex());
when_streamView_currentChanged(QModelIndex(), QModelIndex()); when_streamView_currentChanged(QModelIndex(), QModelIndex());

View File

@ -173,7 +173,8 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex,
pbPrev->setDisabled(true); pbPrev->setDisabled(true);
pbNext->setDisabled(true); pbNext->setDisabled(true);
//! \todo Support Goto Stream Id //! \todo Support Goto Stream Id
rbActionGotoStream->setDisabled(true); leStreamId->setDisabled(true);
disconnect(rbActionGotoStream, SIGNAL(toggled(bool)), leStreamId, SLOT(setEnabled(bool)));
//! \todo Support Continuous Mode //! \todo Support Continuous Mode
rbModeContinuous->setDisabled(true); rbModeContinuous->setDisabled(true);
} }
@ -824,10 +825,11 @@ void StreamConfigDialog::LoadCurrentStream()
leNumPackets->setText(QString().setNum(pStream->numPackets())); leNumPackets->setText(QString().setNum(pStream->numPackets()));
leNumBursts->setText(QString().setNum(pStream->numBursts())); leNumBursts->setText(QString().setNum(pStream->numBursts()));
lePacketsPerBurst->setText(QString().setNum( lePacketsPerBurst->setText(QString().setNum(pStream->burstSize()));
pStream->burstSize()));
lePacketsPerSec->setText(QString().setNum(pStream->packetRate())); lePacketsPerSec->setText(QString().setNum(pStream->packetRate()));
leBurstsPerSec->setText(QString().setNum(pStream->burstRate())); leBurstsPerSec->setText(QString().setNum(pStream->burstRate()));
// TODO(MED): Change this when we support goto to specific stream
leStreamId->setText(QString("0"));
} }
} }

View File

@ -1915,6 +1915,9 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff
</item> </item>
<item> <item>
<widget class="QLineEdit" name="leBurstsPerSec" > <widget class="QLineEdit" name="leBurstsPerSec" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="alignment" > <property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>

View File

@ -0,0 +1,175 @@
#include <QComboBox>
#include <QCheckBox>
#include <QApplication>
#include <QMouseEvent>
#include "streammodel.h"
#include "streamlistdelegate.h"
StreamListDelegate::StreamListDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
QWidget *StreamListDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QWidget *editor = NULL;
switch ((StreamModel::StreamFields) index.column())
{
case StreamModel::StreamStatus:
{
editor = new QCheckBox(parent);
goto _handled;
}
case StreamModel::StreamNextWhat:
{
editor = new QComboBox(parent);
static_cast<QComboBox*>(editor)->insertItems(0,
StreamModel::nextWhatOptionList());
goto _handled;
}
case StreamModel::StreamIcon:
case StreamModel::StreamName:
default:
break;
}
editor = QItemDelegate::createEditor(parent, option, index);
_handled:
return editor;
}
void StreamListDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
switch ((StreamModel::StreamFields) index.column())
{
case StreamModel::StreamStatus:
{
QCheckBox *cb = static_cast<QCheckBox*>(editor);
cb->setChecked(
index.model()->data(index, Qt::EditRole).toBool());
goto _handled;
}
case StreamModel::StreamNextWhat:
{
QComboBox *cb = static_cast<QComboBox*>(editor);
cb->setCurrentIndex(
index.model()->data(index, Qt::EditRole).toInt());
goto _handled;
}
case StreamModel::StreamIcon:
case StreamModel::StreamName:
default:
break;
}
QItemDelegate::setEditorData(editor, index);
_handled:
return;
}
void StreamListDelegate::setModelData(QWidget *editor,
QAbstractItemModel *model, const QModelIndex &index) const
{
switch ((StreamModel::StreamFields) index.column())
{
case StreamModel::StreamStatus:
{
QCheckBox *cb = static_cast<QCheckBox*>(editor);
model->setData(index, cb->isChecked(), Qt::EditRole);
goto _handled;
}
case StreamModel::StreamNextWhat:
{
QComboBox *cb = static_cast<QComboBox*>(editor);
model->setData(index, cb->currentIndex(), Qt::EditRole);
goto _handled;
}
case StreamModel::StreamIcon:
case StreamModel::StreamName:
default:
break;
}
QItemDelegate::setModelData(editor, model, index);
_handled:
return;
}
void StreamListDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
switch ((StreamModel::StreamFields) index.column())
{
case StreamModel::StreamStatus:
{
/*
* extra 'coz QItemDelegate does it - otherwise the editor
* placement is incorrect
*/
int extra = 2 * (qApp->style()->pixelMetric(
QStyle::PM_FocusFrameHMargin, 0) + 1);
editor->setGeometry(option.rect.translated(extra, 0));
goto _handled;
}
case StreamModel::StreamIcon:
case StreamModel::StreamName:
case StreamModel::StreamNextWhat:
default:
break;
}
QItemDelegate::updateEditorGeometry(editor, option, index);
_handled:
return;
}
bool StreamListDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option, const QModelIndex &index)
{
/*
* Special Handling so that user can use the "Stream status" checkbox
* without double clicking first. Copied from QItemDelegate::editorEvent()
* and modified suitably
*/
if ((StreamModel::StreamFields)index.column() ==
StreamModel::StreamStatus)
{
// make sure that we have the right event type
if ((event->type() == QEvent::MouseButtonRelease)
|| (event->type() == QEvent::MouseButtonDblClick))
{
QRect checkRect = check(option, option.rect, Qt::Checked);
QRect emptyRect;
doLayout(option, &checkRect, &emptyRect, &emptyRect, false);
if (!checkRect.contains(static_cast<QMouseEvent*>(event)->pos()))
return false;
Qt::CheckState state = (static_cast<Qt::CheckState>(index.data(
Qt::CheckStateRole).toInt()) == Qt::Checked ? Qt::Unchecked : Qt::Checked);
return model->setData(index, state, Qt::CheckStateRole);
}
}
return QItemDelegate::editorEvent(event, model, option, index);
}

View File

@ -0,0 +1,29 @@
#ifndef STREAM_LIST_DELEGATE_H
#define STREAM_LIST_DELEGATE_H
#include <QItemDelegate>
#include <QModelIndex>
class StreamListDelegate : public QItemDelegate
{
Q_OBJECT
public:
StreamListDelegate(QObject *parent = 0);
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
void setEditorData(QWidget *editor, const QModelIndex &index) const;
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &index) const;
bool editorEvent(QEvent *event, QAbstractItemModel *model,
const QStyleOptionViewItem &option, const QModelIndex &index);
};
#endif

View File

@ -1,3 +1,4 @@
#include "stream.h"
#include "streammodel.h" #include "streammodel.h"
#include "portgrouplist.h" #include "portgrouplist.h"
#include "qicon.h" #include "qicon.h"
@ -38,17 +39,19 @@ Qt::ItemFlags StreamModel::flags(const QModelIndex &index) const
flags |= Qt::ItemIsEditable; flags |= Qt::ItemIsEditable;
break; break;
case StreamStatus: case StreamStatus:
#if 0 flags |= Qt::ItemIsUserCheckable;
flags |= Qt::ItemIsUserCheckable | Qt::ItemIsEditable; break;
#endif case StreamNextWhat:
flags |= Qt::ItemIsEditable; flags |= Qt::ItemIsEditable;
break; break;
default: default:
//qFatal("Missed case in switch!");
break; break;
} }
return flags; return flags;
} }
QVariant StreamModel::data(const QModelIndex &index, int role) const QVariant StreamModel::data(const QModelIndex &index, int role) const
{ {
// Check for a valid index // Check for a valid index
@ -72,10 +75,6 @@ QVariant StreamModel::data(const QModelIndex &index, int role) const
{ {
if (role == Qt::DecorationRole) if (role == Qt::DecorationRole)
return QIcon(":/icons/stream_edit.png"); return QIcon(":/icons/stream_edit.png");
#if 0
else if ((role == Qt::DisplayRole))
return QString("EDIT");
#endif
else else
return QVariant(); return QVariant();
break; break;
@ -90,12 +89,7 @@ QVariant StreamModel::data(const QModelIndex &index, int role) const
} }
case StreamStatus: case StreamStatus:
{ {
if ((role == Qt::DisplayRole) || (role == Qt::EditRole)) if ((role == Qt::CheckStateRole))
return mCurrentPort->streamByIndex(index.row()).isEnabled();
else
return QVariant();
#if 0
if ((role == Qt::CheckStateRole) || (role == Qt::EditRole))
{ {
if (mCurrentPort->streamByIndex(index.row()).isEnabled()) if (mCurrentPort->streamByIndex(index.row()).isEnabled())
return Qt::Checked; return Qt::Checked;
@ -104,11 +98,23 @@ QVariant StreamModel::data(const QModelIndex &index, int role) const
} }
else else
return QVariant(); return QVariant();
#endif break;
}
case StreamNextWhat:
{
int val = mCurrentPort->streamByIndex(index.row()).nextWhat();
if (role == Qt::DisplayRole)
return nextWhatOptionList().at(val);
else if (role == Qt::EditRole)
return val;
else
return QVariant();
break; break;
} }
default: default:
qDebug("-------------UNHANDLED STREAM FIELD----------------"); qFatal("-------------UNHANDLED STREAM FIELD----------------");
} }
return QVariant(); return QVariant();
@ -119,24 +125,35 @@ bool StreamModel::setData(const QModelIndex &index, const QVariant &value, int r
if (mCurrentPort == NULL) if (mCurrentPort == NULL)
return false; return false;
if (index.isValid() && role == Qt::EditRole) if (index.isValid())
{ {
// Edit Supported Fields
switch (index.column()) switch (index.column())
{ {
// Edit Supported Fields
case StreamName: case StreamName:
mCurrentPort->streamByIndex(index.row()).setName(value.toString()); mCurrentPort->streamByIndex(index.row()).setName(value.toString());
emit(dataChanged(index, index));
return true; return true;
break;
case StreamStatus: case StreamStatus:
mCurrentPort->streamByIndex(index.row()).setIsEnabled(value.toBool()); mCurrentPort->streamByIndex(index.row()).setIsEnabled(value.toBool());
emit(dataChanged(index, index));
return true; return true;
break;
case StreamNextWhat:
if (role == Qt::EditRole)
{
mCurrentPort->streamByIndex(index.row()).setNextWhat(
(Stream::NextWhat)value.toInt());
emit(dataChanged(index, index));
return true;
}
else
return false;
// Edit Not Supported Fields // Edit Not Supported Fields
case StreamIcon: case StreamIcon:
return false; return false;
break;
// Unhandled Stream Field // Unhandled Stream Field
default: default:
@ -144,6 +161,7 @@ bool StreamModel::setData(const QModelIndex &index, const QVariant &value, int r
break; break;
} }
} }
return false; return false;
} }
@ -157,13 +175,16 @@ QVariant StreamModel::headerData(int section, Qt::Orientation orientation, int r
switch(section) switch(section)
{ {
case StreamIcon: case StreamIcon:
return QString("Icon"); return QString("");
break; break;
case StreamName: case StreamName:
return QString("Name"); return QString("Name");
break; break;
case StreamStatus: case StreamStatus:
return QString("Enabled"); return QString("");
break;
case StreamNextWhat:
return QString("Goto");
break; break;
default: default:
qDebug("-------------UNHANDLED STREAM FIELD----------------"); qDebug("-------------UNHANDLED STREAM FIELD----------------");

View File

@ -1,6 +1,7 @@
#ifndef _STREAM_MODEL_H #ifndef _STREAM_MODEL_H
#define _STREAM_MODEL_H #define _STREAM_MODEL_H
#include <QStringList>
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include "port.h" #include "port.h"
@ -10,14 +11,6 @@ class StreamModel : public QAbstractTableModel
{ {
Q_OBJECT Q_OBJECT
enum StreamFields {
StreamIcon = 0,
StreamName,
StreamStatus,
StreamMaxFields
};
Port *mCurrentPort; Port *mCurrentPort;
PortGroupList *pgl; PortGroupList *pgl;
@ -43,6 +36,19 @@ class StreamModel : public QAbstractTableModel
{ return &mCurrentPort->mStreams; } { return &mCurrentPort->mStreams; }
#endif #endif
public:
enum StreamFields {
StreamIcon = 0,
StreamName,
StreamStatus,
StreamNextWhat,
StreamMaxFields
};
static QStringList nextWhatOptionList()
{ return QStringList() << "Stop" << "Next" << "Goto first"; }
public slots: public slots:
void setCurrentPortIndex(const QModelIndex &current); void setCurrentPortIndex(const QModelIndex &current);

View File

@ -559,6 +559,7 @@ PortInfo::PortInfo(uint id, pcap_if_t *dev)
// We'll create sendqueue later when required // We'll create sendqueue later when required
sendQueueList.clear(); sendQueueList.clear();
returnToQIdx = -1;
pcapExtra.txPkts = 0; pcapExtra.txPkts = 0;
pcapExtra.txBytes = 0; pcapExtra.txBytes = 0;
isSendQueueDirty=true; isSendQueueDirty=true;
@ -581,6 +582,8 @@ void PortInfo::update()
foreach(sendQ, sendQueueList) foreach(sendQ, sendQueueList)
pcap_sendqueue_destroy(sendQ.sendQueue); pcap_sendqueue_destroy(sendQ.sendQueue);
} }
sendQueueList.clear();
returnToQIdx = -1;
// TODO(LOW): calculate sendqueue size // TODO(LOW): calculate sendqueue size
sendQ.sendQueue = pcap_sendqueue_alloc(1*MB); sendQ.sendQueue = pcap_sendqueue_alloc(1*MB);
@ -589,8 +592,11 @@ void PortInfo::update()
// First sort the streams by ordinalValue // First sort the streams by ordinalValue
qSort(streamList); qSort(streamList);
pktHdr.ts.tv_sec = 0;
pktHdr.ts.tv_usec = 0;
for (int i = 0; i < streamList.size(); i++) for (int i = 0; i < streamList.size(); i++)
{ {
//_restart:
if (streamList[i].d.core().is_enabled()) if (streamList[i].d.core().is_enabled())
{ {
long numPackets, numBursts; long numPackets, numBursts;
@ -619,8 +625,6 @@ void PortInfo::update()
numBursts, numPackets); numBursts, numPackets);
qDebug("ibg = %ld, ipg = %ld\n", ibg, ipg); qDebug("ibg = %ld, ipg = %ld\n", ibg, ipg);
pktHdr.ts.tv_sec = 0;
pktHdr.ts.tv_usec = 0;
for (int j = 0; j < numBursts; j++) for (int j = 0; j < numBursts; j++)
{ {
for (int k = 0; k < numPackets; k++) for (int k = 0; k < numPackets; k++)
@ -655,6 +659,9 @@ void PortInfo::update()
#endif #endif
} }
qDebug("q(%d, %d, %d) sec = %lu usec = %lu",
i, j, k, pktHdr.ts.tv_sec, pktHdr.ts.tv_usec);
if (-1 == pcap_sendqueue_queue(sendQ.sendQueue, &pktHdr, if (-1 == pcap_sendqueue_queue(sendQ.sendQueue, &pktHdr,
(u_char*) pktBuf)) (u_char*) pktBuf))
{ {
@ -664,17 +671,48 @@ void PortInfo::update()
else else
sendQ.sendQueueCumLen.append(sendQ.sendQueue->len); sendQ.sendQueueCumLen.append(sendQ.sendQueue->len);
} }
} } // for (numPackets)
pktHdr.ts.tv_usec += ibg; pktHdr.ts.tv_usec += ibg;
if (pktHdr.ts.tv_usec > 1000000) if (pktHdr.ts.tv_usec > 1000000)
{ {
pktHdr.ts.tv_sec++; pktHdr.ts.tv_sec++;
pktHdr.ts.tv_usec -= 1000000; pktHdr.ts.tv_usec -= 1000000;
} }
} } // for (numBursts)
}
}
switch(streamList[i].d.control().next())
{
case ::OstProto::StreamControl::e_nw_stop:
goto _stop_no_more_pkts;
case ::OstProto::StreamControl::e_nw_goto_id:
// TODO(MED): define and use
// streamList[i].d.control().goto_stream_id();
// TODO(MED): assumes goto Id is less than current!!!!
// To support goto to any id, do
// if goto_id > curr_id then
// i = goto_id;
// goto restart;
// else
// returnToQIdx = 0;
returnToQIdx=0;
goto _stop_no_more_pkts;
case ::OstProto::StreamControl::e_nw_goto_next:
break;
default:
qFatal("---------- %s: Unhandled case (%d) -----------",
__FUNCTION__, streamList[i].d.control().next() );
break;
}
} // if (stream is enabled)
} // for (numStreams)
_stop_no_more_pkts:
// The last alloc'ed sendQ appended here // The last alloc'ed sendQ appended here
sendQueueList.append(sendQ); sendQueueList.append(sendQ);
@ -1061,8 +1099,9 @@ void PortInfo::PortTransmitter::run()
m_stop = 0; m_stop = 0;
ost_pcap_sendqueue_list_transmit(port->devHandleRx, port->sendQueueList, ost_pcap_sendqueue_list_transmit(port->devHandleRx, port->sendQueueList,
true, &m_stop, &port->pcapExtra.txPkts, &port->pcapExtra.txBytes, port->returnToQIdx, true, &m_stop,
QThread::usleep); &port->pcapExtra.txPkts, &port->pcapExtra.txBytes,
QThread::usleep);
m_stop = 0; m_stop = 0;
} }

View File

@ -133,6 +133,7 @@ class PortInfo
pcap_t *devHandleRx; pcap_t *devHandleRx;
pcap_t *devHandleTx; pcap_t *devHandleTx;
QList<ost_pcap_send_queue> sendQueueList; QList<ost_pcap_send_queue> sendQueueList;
int returnToQIdx; // FIXME(MED): combine with sendQList
bool isSendQueueDirty; bool isSendQueueDirty;
PcapExtra pcapExtra; PcapExtra pcapExtra;
PortMonitorRx monitorRx; PortMonitorRx monitorRx;

View File

@ -62,20 +62,32 @@ int pcap_sendqueue_queue (pcap_send_queue *queue,
#endif #endif
u_int ost_pcap_sendqueue_list_transmit(pcap_t *p, u_int ost_pcap_sendqueue_list_transmit(pcap_t *p,
QList<ost_pcap_send_queue> sendQueueList, int sync, QList<ost_pcap_send_queue> sendQueueList, int returnToQIdx, int sync,
int *p_stop, quint64* p_pkts, quint64* p_bytes, int *p_stop, quint64* p_pkts, quint64* p_bytes,
void (*pf_usleep)(ulong)) void (*pf_usleep)(ulong))
{ {
uint ret = 0; uint i, ret = 0;
ost_pcap_send_queue sq;
foreach(ost_pcap_send_queue sq, sendQueueList) for(i = 0; i < sendQueueList.size(); i++)
{ {
_restart:
sq = sendQueueList.at(i);
ret += ost_pcap_sendqueue_transmit(p, sq.sendQueue, sync, ret += ost_pcap_sendqueue_transmit(p, sq.sendQueue, sync,
p_stop, p_pkts, p_bytes, pf_usleep); p_stop, p_pkts, p_bytes, pf_usleep);
if (*p_stop)
return ret;
// TODO(HI): Timing between subsequent sendQueues // TODO(HI): Timing between subsequent sendQueues
} }
if (returnToQIdx >= 0)
{
i = returnToQIdx;
goto _restart;
}
return ret; return ret;
} }

View File

@ -17,7 +17,7 @@ struct ost_pcap_send_queue
// Common for all OS - *nix or Win32 // Common for all OS - *nix or Win32
u_int ost_pcap_sendqueue_list_transmit(pcap_t *p, u_int ost_pcap_sendqueue_list_transmit(pcap_t *p,
QList<ost_pcap_send_queue> sendQueueList, int sync, QList<ost_pcap_send_queue> sendQueueList, int returnToQIdx, int sync,
int *p_stop, quint64* p_pkts, quint64* p_bytes, int *p_stop, quint64* p_pkts, quint64* p_bytes,
void (*pf_usleep)(ulong)); void (*pf_usleep)(ulong));