- 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 \
portswindow.h \
streamconfigdialog.h \
streamlistdelegate.h \
streammodel.h
FORMS += \
@ -45,6 +46,7 @@ SOURCES += \
portstatswindow.cpp \
portswindow.cpp \
streamconfigdialog.cpp \
streamlistdelegate.cpp \
streammodel.cpp
# Protocol Buffer Sources

View File

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

View File

@ -173,7 +173,8 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex,
pbPrev->setDisabled(true);
pbNext->setDisabled(true);
//! \todo Support Goto Stream Id
rbActionGotoStream->setDisabled(true);
leStreamId->setDisabled(true);
disconnect(rbActionGotoStream, SIGNAL(toggled(bool)), leStreamId, SLOT(setEnabled(bool)));
//! \todo Support Continuous Mode
rbModeContinuous->setDisabled(true);
}
@ -824,10 +825,11 @@ void StreamConfigDialog::LoadCurrentStream()
leNumPackets->setText(QString().setNum(pStream->numPackets()));
leNumBursts->setText(QString().setNum(pStream->numBursts()));
lePacketsPerBurst->setText(QString().setNum(
pStream->burstSize()));
lePacketsPerBurst->setText(QString().setNum(pStream->burstSize()));
lePacketsPerSec->setText(QString().setNum(pStream->packetRate()));
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>
<widget class="QLineEdit" name="leBurstsPerSec" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</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 "portgrouplist.h"
#include "qicon.h"
@ -38,17 +39,19 @@ Qt::ItemFlags StreamModel::flags(const QModelIndex &index) const
flags |= Qt::ItemIsEditable;
break;
case StreamStatus:
#if 0
flags |= Qt::ItemIsUserCheckable | Qt::ItemIsEditable;
#endif
flags |= Qt::ItemIsUserCheckable;
break;
case StreamNextWhat:
flags |= Qt::ItemIsEditable;
break;
default:
//qFatal("Missed case in switch!");
break;
}
return flags;
}
QVariant StreamModel::data(const QModelIndex &index, int role) const
{
// Check for a valid index
@ -72,10 +75,6 @@ QVariant StreamModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DecorationRole)
return QIcon(":/icons/stream_edit.png");
#if 0
else if ((role == Qt::DisplayRole))
return QString("EDIT");
#endif
else
return QVariant();
break;
@ -90,12 +89,7 @@ QVariant StreamModel::data(const QModelIndex &index, int role) const
}
case StreamStatus:
{
if ((role == Qt::DisplayRole) || (role == Qt::EditRole))
return mCurrentPort->streamByIndex(index.row()).isEnabled();
else
return QVariant();
#if 0
if ((role == Qt::CheckStateRole) || (role == Qt::EditRole))
if ((role == Qt::CheckStateRole))
{
if (mCurrentPort->streamByIndex(index.row()).isEnabled())
return Qt::Checked;
@ -104,11 +98,23 @@ QVariant StreamModel::data(const QModelIndex &index, int role) const
}
else
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;
}
default:
qDebug("-------------UNHANDLED STREAM FIELD----------------");
qFatal("-------------UNHANDLED STREAM FIELD----------------");
}
return QVariant();
@ -119,24 +125,35 @@ bool StreamModel::setData(const QModelIndex &index, const QVariant &value, int r
if (mCurrentPort == NULL)
return false;
if (index.isValid() && role == Qt::EditRole)
if (index.isValid())
{
// Edit Supported Fields
switch (index.column())
{
// Edit Supported Fields
case StreamName:
mCurrentPort->streamByIndex(index.row()).setName(value.toString());
emit(dataChanged(index, index));
return true;
break;
case StreamStatus:
mCurrentPort->streamByIndex(index.row()).setIsEnabled(value.toBool());
emit(dataChanged(index, index));
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
case StreamIcon:
return false;
break;
// Unhandled Stream Field
default:
@ -144,6 +161,7 @@ bool StreamModel::setData(const QModelIndex &index, const QVariant &value, int r
break;
}
}
return false;
}
@ -157,13 +175,16 @@ QVariant StreamModel::headerData(int section, Qt::Orientation orientation, int r
switch(section)
{
case StreamIcon:
return QString("Icon");
return QString("");
break;
case StreamName:
return QString("Name");
break;
case StreamStatus:
return QString("Enabled");
return QString("");
break;
case StreamNextWhat:
return QString("Goto");
break;
default:
qDebug("-------------UNHANDLED STREAM FIELD----------------");

View File

@ -1,6 +1,7 @@
#ifndef _STREAM_MODEL_H
#define _STREAM_MODEL_H
#include <QStringList>
#include <QAbstractTableModel>
#include "port.h"
@ -10,14 +11,6 @@ class StreamModel : public QAbstractTableModel
{
Q_OBJECT
enum StreamFields {
StreamIcon = 0,
StreamName,
StreamStatus,
StreamMaxFields
};
Port *mCurrentPort;
PortGroupList *pgl;
@ -43,6 +36,19 @@ class StreamModel : public QAbstractTableModel
{ return &mCurrentPort->mStreams; }
#endif
public:
enum StreamFields {
StreamIcon = 0,
StreamName,
StreamStatus,
StreamNextWhat,
StreamMaxFields
};
static QStringList nextWhatOptionList()
{ return QStringList() << "Stop" << "Next" << "Goto first"; }
public slots:
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
sendQueueList.clear();
returnToQIdx = -1;
pcapExtra.txPkts = 0;
pcapExtra.txBytes = 0;
isSendQueueDirty=true;
@ -581,6 +582,8 @@ void PortInfo::update()
foreach(sendQ, sendQueueList)
pcap_sendqueue_destroy(sendQ.sendQueue);
}
sendQueueList.clear();
returnToQIdx = -1;
// TODO(LOW): calculate sendqueue size
sendQ.sendQueue = pcap_sendqueue_alloc(1*MB);
@ -589,8 +592,11 @@ void PortInfo::update()
// First sort the streams by ordinalValue
qSort(streamList);
pktHdr.ts.tv_sec = 0;
pktHdr.ts.tv_usec = 0;
for (int i = 0; i < streamList.size(); i++)
{
//_restart:
if (streamList[i].d.core().is_enabled())
{
long numPackets, numBursts;
@ -619,8 +625,6 @@ void PortInfo::update()
numBursts, numPackets);
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 k = 0; k < numPackets; k++)
@ -655,6 +659,9 @@ void PortInfo::update()
#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,
(u_char*) pktBuf))
{
@ -664,17 +671,48 @@ void PortInfo::update()
else
sendQ.sendQueueCumLen.append(sendQ.sendQueue->len);
}
}
} // for (numPackets)
pktHdr.ts.tv_usec += ibg;
if (pktHdr.ts.tv_usec > 1000000)
{
pktHdr.ts.tv_sec++;
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
sendQueueList.append(sendQ);
@ -1061,8 +1099,9 @@ void PortInfo::PortTransmitter::run()
m_stop = 0;
ost_pcap_sendqueue_list_transmit(port->devHandleRx, port->sendQueueList,
true, &m_stop, &port->pcapExtra.txPkts, &port->pcapExtra.txBytes,
QThread::usleep);
port->returnToQIdx, true, &m_stop,
&port->pcapExtra.txPkts, &port->pcapExtra.txBytes,
QThread::usleep);
m_stop = 0;
}

View File

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

View File

@ -62,20 +62,32 @@ int pcap_sendqueue_queue (pcap_send_queue *queue,
#endif
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,
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,
p_stop, p_pkts, p_bytes, pf_usleep);
if (*p_stop)
return ret;
// TODO(HI): Timing between subsequent sendQueues
}
if (returnToQIdx >= 0)
{
i = returnToQIdx;
goto _restart;
}
return ret;
}

View File

@ -17,7 +17,7 @@ struct ost_pcap_send_queue
// Common for all OS - *nix or Win32
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,
void (*pf_usleep)(ulong));