Initial Import
88
client/about.ui
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<ui version="4.0" >
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame" >
|
||||||
|
<property name="frameShape" >
|
||||||
|
<enum>QFrame::Box</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow" >
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label" >
|
||||||
|
<property name="text" >
|
||||||
|
<string><html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:29pt; font-weight:600;">Ostinato</span></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment" >
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons" >
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel" >
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel" >
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel" >
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel" >
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
69
client/hexlineedit.cpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include "hexlineedit.h"
|
||||||
|
#include "qdebug.h"
|
||||||
|
|
||||||
|
QString & uintToHexStr(quint32 num, QString &hexStr, quint8 octets);
|
||||||
|
HexLineEdit::HexLineEdit( QWidget * parent)
|
||||||
|
: QLineEdit(parent)
|
||||||
|
{
|
||||||
|
//QLineEdit::QLineEdit(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HexLineEdit::focusOutEvent( QFocusEvent *e )
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
const QValidator *v = validator();
|
||||||
|
if ( v )
|
||||||
|
{
|
||||||
|
int curpos = cursorPosition();
|
||||||
|
QString str = text();
|
||||||
|
if ( v->validate( str, curpos ) == QValidator::Acceptable )
|
||||||
|
{
|
||||||
|
if ( curpos != cursorPosition() )
|
||||||
|
setCursorPosition( curpos );
|
||||||
|
if ( str != text() )
|
||||||
|
setText( str );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( curpos != cursorPosition() )
|
||||||
|
setCursorPosition( curpos );
|
||||||
|
str = text();
|
||||||
|
v->fixup( str );
|
||||||
|
if ( str != text() )
|
||||||
|
{
|
||||||
|
setText( str );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QLineEdit::focusOutEvent( e );
|
||||||
|
emit focusOut();
|
||||||
|
#else
|
||||||
|
bool isOk;
|
||||||
|
ulong num;
|
||||||
|
QString str;
|
||||||
|
|
||||||
|
qDebug("before = %s\n", text().toAscii().data());
|
||||||
|
num = text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
setText(uintToHexStr(num, str, 4));
|
||||||
|
qDebug("after = %s\n", text().toAscii().data());
|
||||||
|
qDebug("after2 = %s\n", str.toAscii().data());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void HexLineEdit::focusInEvent( QFocusEvent *e )
|
||||||
|
{
|
||||||
|
QLineEdit::focusInEvent( e );
|
||||||
|
emit focusIn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HexLineEdit::keyPressEvent( QKeyEvent *e )
|
||||||
|
{
|
||||||
|
QLineEdit::keyPressEvent( e );
|
||||||
|
if ( e->key() == Key_Enter || e->key() == Key_Return )
|
||||||
|
{
|
||||||
|
setSelection( 0, text().length() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
24
client/hexlineedit.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef _HEXLINEEDIT
|
||||||
|
#define _HEXLINEEDIT
|
||||||
|
|
||||||
|
#include <QLineEdit>
|
||||||
|
|
||||||
|
class HexLineEdit : public QLineEdit
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
// Constructors
|
||||||
|
HexLineEdit ( QWidget * parent);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void focusOutEvent( QFocusEvent *e );
|
||||||
|
//void focusInEvent( QFocusEvent *e );
|
||||||
|
//void keyPressEvent( QKeyEvent *e );
|
||||||
|
|
||||||
|
signals:
|
||||||
|
//void focusIn();
|
||||||
|
void focusOut();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
BIN
client/icons/bullet_error.png
Normal file
After Width: | Height: | Size: 454 B |
BIN
client/icons/bullet_green.png
Normal file
After Width: | Height: | Size: 295 B |
BIN
client/icons/bullet_orange.png
Normal file
After Width: | Height: | Size: 283 B |
BIN
client/icons/bullet_red.png
Normal file
After Width: | Height: | Size: 287 B |
BIN
client/icons/bullet_yellow.png
Normal file
After Width: | Height: | Size: 287 B |
BIN
client/icons/control_play.png
Normal file
After Width: | Height: | Size: 592 B |
BIN
client/icons/control_stop.png
Normal file
After Width: | Height: | Size: 403 B |
BIN
client/icons/gaps.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
client/icons/magnifier.png
Normal file
After Width: | Height: | Size: 615 B |
BIN
client/icons/portgroup_add.png
Normal file
After Width: | Height: | Size: 781 B |
BIN
client/icons/portgroup_connect.png
Normal file
After Width: | Height: | Size: 748 B |
BIN
client/icons/portgroup_delete.png
Normal file
After Width: | Height: | Size: 775 B |
BIN
client/icons/portgroup_disconnect.png
Normal file
After Width: | Height: | Size: 796 B |
BIN
client/icons/sound_mute.png
Normal file
After Width: | Height: | Size: 474 B |
BIN
client/icons/sound_none.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
client/icons/stream_add.png
Normal file
After Width: | Height: | Size: 814 B |
BIN
client/icons/stream_delete.png
Normal file
After Width: | Height: | Size: 847 B |
BIN
client/icons/stream_edit.png
Normal file
After Width: | Height: | Size: 865 B |
11
client/main.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include <QApplication>
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
MainWindow mainWin;
|
||||||
|
|
||||||
|
mainWin.show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
30
client/mainwindow.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <QtGui>
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "portswindow.h"
|
||||||
|
#include "portstatswindow.h"
|
||||||
|
#include "portgrouplist.h"
|
||||||
|
|
||||||
|
PortGroupList *pgl;
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
|
: QMainWindow (parent)
|
||||||
|
{
|
||||||
|
pgl = new PortGroupList;
|
||||||
|
|
||||||
|
PortsWindow *portsWindow = new PortsWindow(pgl, this);
|
||||||
|
PortStatsWindow *statsWindow = new PortStatsWindow(pgl, this);
|
||||||
|
QDockWidget *dock = new QDockWidget(tr("Ports"), this);
|
||||||
|
QDockWidget *dock2 = new QDockWidget(tr("Stats"), this);
|
||||||
|
|
||||||
|
setupUi(this);
|
||||||
|
|
||||||
|
dock->setWidget(portsWindow);
|
||||||
|
addDockWidget(Qt::TopDockWidgetArea, dock);
|
||||||
|
dock2->setWidget(statsWindow);
|
||||||
|
addDockWidget(Qt::BottomDockWidgetArea, dock2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionPreferences_triggered()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
18
client/mainwindow.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _MAIN_WINDOW_H
|
||||||
|
#define _MAIN_WINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow, private Ui::MainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
MainWindow(QWidget *parent = 0);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void on_actionPreferences_triggered();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
159
client/mainwindow.ui
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
<ui version="4.0" >
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget" />
|
||||||
|
<widget class="QMenuBar" name="menubar" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>21</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFile" >
|
||||||
|
<property name="title" >
|
||||||
|
<string>File</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionE_xit" />
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuView" >
|
||||||
|
<property name="title" >
|
||||||
|
<string>View</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionPreferences" />
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuWindow" >
|
||||||
|
<property name="title" >
|
||||||
|
<string>Window</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionMinimize" />
|
||||||
|
<addaction name="actionMaximize_Restore" />
|
||||||
|
<addaction name="actionMinimize_All" />
|
||||||
|
<addaction name="actionMaximize_Restoe_All" />
|
||||||
|
<addaction name="actionArrange_All_Cascade" />
|
||||||
|
<addaction name="actionArrange_All_Tile" />
|
||||||
|
<addaction name="actionDock" />
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenu" name="menuHelp" >
|
||||||
|
<property name="title" >
|
||||||
|
<string>Help</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionAbout" />
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuFile" />
|
||||||
|
<addaction name="menuView" />
|
||||||
|
<addaction name="menuWindow" />
|
||||||
|
<addaction name="menuHelp" />
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar" />
|
||||||
|
<action name="actionOpen_Config" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Open Config</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_Config" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Save Config</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_Config_As" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Save Config As ...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionOpen_Capture" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Open Capture</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_Capture" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Save Capture</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSave_Capture_As" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Save Capture As ...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionE_xit" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>E&xit</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionCopy_Port_Config" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Copy Port Config</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPaste_Port_Config" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Paste Port Config</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPreferences" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Preferences</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionMinimize" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Minimize</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionMaximize_Restore" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Maximize/Restore</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionMinimize_All" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Minimize All</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionMaximize_Restoe_All" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Maximize/Restoe All</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionArrange_All_Cascade" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Arrange All - Cascade</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionArrange_All_Tile" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Arrange All - Tile</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDock" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Dock</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionHelp" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Help</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionAbout" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>About</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
542
client/modeltest.cpp
Normal file
@ -0,0 +1,542 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2007 Trolltech ASA. All rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Concurrent project on Trolltech Labs.
|
||||||
|
**
|
||||||
|
** This file may be used under the terms of the GNU General Public
|
||||||
|
** License version 2.0 as published by the Free Software Foundation
|
||||||
|
** and appearing in the file LICENSE.GPL included in the packaging of
|
||||||
|
** this file. Please review the following information to ensure GNU
|
||||||
|
** General Public Licensing requirements will be met:
|
||||||
|
** http://www.trolltech.com/products/qt/opensource.html
|
||||||
|
**
|
||||||
|
** If you are unsure which license is appropriate for your use, please
|
||||||
|
** review the following information:
|
||||||
|
** http://www.trolltech.com/products/qt/licensing.html or contact the
|
||||||
|
** sales department at sales@trolltech.com.
|
||||||
|
**
|
||||||
|
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||||
|
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <QtGui/QtGui>
|
||||||
|
|
||||||
|
#include "modeltest.h"
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QModelIndex)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Connect to all of the models signals. Whenever anything happens recheck everything.
|
||||||
|
*/
|
||||||
|
ModelTest::ModelTest(QAbstractItemModel *_model, QObject *parent) : QObject(parent), model(_model), fetchingMore(false)
|
||||||
|
{
|
||||||
|
Q_ASSERT(model);
|
||||||
|
|
||||||
|
connect(model, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(columnsInserted(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(columnsRemoved(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
|
||||||
|
this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)),
|
||||||
|
this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(layoutAboutToBeChanged ()), this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(layoutChanged ()), this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(modelReset ()), this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(runAllTests()));
|
||||||
|
connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(runAllTests()));
|
||||||
|
|
||||||
|
// Special checks for inserting/removing
|
||||||
|
connect(model, SIGNAL(layoutAboutToBeChanged()),
|
||||||
|
this, SLOT(layoutAboutToBeChanged()));
|
||||||
|
connect(model, SIGNAL(layoutChanged()),
|
||||||
|
this, SLOT(layoutChanged()));
|
||||||
|
|
||||||
|
connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(rowsAboutToBeInserted(const QModelIndex &, int, int)));
|
||||||
|
connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(rowsAboutToBeRemoved(const QModelIndex &, int, int)));
|
||||||
|
connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(rowsInserted(const QModelIndex &, int, int)));
|
||||||
|
connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
|
||||||
|
this, SLOT(rowsRemoved(const QModelIndex &, int, int)));
|
||||||
|
|
||||||
|
runAllTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelTest::runAllTests()
|
||||||
|
{
|
||||||
|
if (fetchingMore)
|
||||||
|
return;
|
||||||
|
nonDestructiveBasicTest();
|
||||||
|
rowCount();
|
||||||
|
columnCount();
|
||||||
|
hasIndex();
|
||||||
|
index();
|
||||||
|
parent();
|
||||||
|
data();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
nonDestructiveBasicTest tries to call a number of the basic functions (not all)
|
||||||
|
to make sure the model doesn't outright segfault, testing the functions that makes sense.
|
||||||
|
*/
|
||||||
|
void ModelTest::nonDestructiveBasicTest()
|
||||||
|
{
|
||||||
|
Q_ASSERT(model->buddy(QModelIndex()) == QModelIndex());
|
||||||
|
model->canFetchMore(QModelIndex());
|
||||||
|
Q_ASSERT(model->columnCount(QModelIndex()) >= 0);
|
||||||
|
Q_ASSERT(model->data(QModelIndex()) == QVariant());
|
||||||
|
fetchingMore = true;
|
||||||
|
model->fetchMore(QModelIndex());
|
||||||
|
fetchingMore = false;
|
||||||
|
Qt::ItemFlags flags = model->flags(QModelIndex());
|
||||||
|
Q_ASSERT(flags == Qt::ItemIsDropEnabled || flags == 0);
|
||||||
|
model->hasChildren(QModelIndex());
|
||||||
|
model->hasIndex(0, 0);
|
||||||
|
model->headerData(0, Qt::Horizontal);
|
||||||
|
model->index(0, 0);
|
||||||
|
Q_ASSERT(model->index(-1, -1) == QModelIndex());
|
||||||
|
model->itemData(QModelIndex());
|
||||||
|
QVariant cache;
|
||||||
|
model->match(QModelIndex(), -1, cache);
|
||||||
|
model->mimeTypes();
|
||||||
|
Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
|
||||||
|
Q_ASSERT(model->rowCount() >= 0);
|
||||||
|
QVariant variant;
|
||||||
|
model->setData(QModelIndex(), variant, -1);
|
||||||
|
model->setHeaderData(-1, Qt::Horizontal, QVariant());
|
||||||
|
model->setHeaderData(0, Qt::Horizontal, QVariant());
|
||||||
|
model->setHeaderData(999999, Qt::Horizontal, QVariant());
|
||||||
|
QMap<int, QVariant> roles;
|
||||||
|
model->sibling(0, 0, QModelIndex());
|
||||||
|
model->span(QModelIndex());
|
||||||
|
model->supportedDropActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren()
|
||||||
|
|
||||||
|
Models that are dynamically populated are not as fully tested here.
|
||||||
|
*/
|
||||||
|
void ModelTest::rowCount()
|
||||||
|
{
|
||||||
|
// check top row
|
||||||
|
QModelIndex topIndex = model->index(0, 0, QModelIndex());
|
||||||
|
int rows = model->rowCount(topIndex);
|
||||||
|
Q_ASSERT(rows >= 0);
|
||||||
|
if (rows > 0)
|
||||||
|
Q_ASSERT(model->hasChildren(topIndex) == true);
|
||||||
|
|
||||||
|
QModelIndex secondLevelIndex = model->index(0, 0, topIndex);
|
||||||
|
if (secondLevelIndex.isValid()) { // not the top level
|
||||||
|
// check a row count where parent is valid
|
||||||
|
rows = model->rowCount(secondLevelIndex);
|
||||||
|
Q_ASSERT(rows >= 0);
|
||||||
|
if (rows > 0)
|
||||||
|
Q_ASSERT(model->hasChildren(secondLevelIndex) == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The models rowCount() is tested more extensively in checkChildren(),
|
||||||
|
// but this catches the big mistakes
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren()
|
||||||
|
*/
|
||||||
|
void ModelTest::columnCount()
|
||||||
|
{
|
||||||
|
// check top row
|
||||||
|
QModelIndex topIndex = model->index(0, 0, QModelIndex());
|
||||||
|
Q_ASSERT(model->columnCount(topIndex) >= 0);
|
||||||
|
|
||||||
|
// check a column count where parent is valid
|
||||||
|
QModelIndex childIndex = model->index(0, 0, topIndex);
|
||||||
|
if (childIndex.isValid())
|
||||||
|
Q_ASSERT(model->columnCount(childIndex) >= 0);
|
||||||
|
|
||||||
|
// columnCount() is tested more extensively in checkChildren(),
|
||||||
|
// but this catches the big mistakes
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tests model's implementation of QAbstractItemModel::hasIndex()
|
||||||
|
*/
|
||||||
|
void ModelTest::hasIndex()
|
||||||
|
{
|
||||||
|
// Make sure that invalid values returns an invalid index
|
||||||
|
Q_ASSERT(model->hasIndex(-2, -2) == false);
|
||||||
|
Q_ASSERT(model->hasIndex(-2, 0) == false);
|
||||||
|
Q_ASSERT(model->hasIndex(0, -2) == false);
|
||||||
|
|
||||||
|
int rows = model->rowCount();
|
||||||
|
int columns = model->columnCount();
|
||||||
|
|
||||||
|
// check out of bounds
|
||||||
|
Q_ASSERT(model->hasIndex(rows, columns) == false);
|
||||||
|
Q_ASSERT(model->hasIndex(rows + 1, columns + 1) == false);
|
||||||
|
|
||||||
|
if (rows > 0)
|
||||||
|
Q_ASSERT(model->hasIndex(0, 0) == true);
|
||||||
|
|
||||||
|
// hasIndex() is tested more extensively in checkChildren(),
|
||||||
|
// but this catches the big mistakes
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tests model's implementation of QAbstractItemModel::index()
|
||||||
|
*/
|
||||||
|
void ModelTest::index()
|
||||||
|
{
|
||||||
|
// Make sure that invalid values returns an invalid index
|
||||||
|
Q_ASSERT(model->index(-2, -2) == QModelIndex());
|
||||||
|
Q_ASSERT(model->index(-2, 0) == QModelIndex());
|
||||||
|
Q_ASSERT(model->index(0, -2) == QModelIndex());
|
||||||
|
|
||||||
|
int rows = model->rowCount();
|
||||||
|
int columns = model->columnCount();
|
||||||
|
|
||||||
|
if (rows == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Catch off by one errors
|
||||||
|
Q_ASSERT(model->index(rows, columns) == QModelIndex());
|
||||||
|
Q_ASSERT(model->index(0, 0).isValid() == true);
|
||||||
|
|
||||||
|
// Make sure that the same index is *always* returned
|
||||||
|
QModelIndex a = model->index(0, 0);
|
||||||
|
QModelIndex b = model->index(0, 0);
|
||||||
|
Q_ASSERT(a == b);
|
||||||
|
|
||||||
|
// index() is tested more extensively in checkChildren(),
|
||||||
|
// but this catches the big mistakes
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tests model's implementation of QAbstractItemModel::parent()
|
||||||
|
*/
|
||||||
|
void ModelTest::parent()
|
||||||
|
{
|
||||||
|
// Make sure the model wont crash and will return an invalid QModelIndex
|
||||||
|
// when asked for the parent of an invalid index.
|
||||||
|
Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
|
||||||
|
|
||||||
|
if (model->rowCount() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Column 0 | Column 1 |
|
||||||
|
// QModelIndex() | |
|
||||||
|
// \- topIndex | topIndex1 |
|
||||||
|
// \- childIndex | childIndex1 |
|
||||||
|
|
||||||
|
// Common error test #1, make sure that a top level index has a parent
|
||||||
|
// that is a invalid QModelIndex.
|
||||||
|
QModelIndex topIndex = model->index(0, 0, QModelIndex());
|
||||||
|
Q_ASSERT(model->parent(topIndex) == QModelIndex());
|
||||||
|
|
||||||
|
// Common error test #2, make sure that a second level index has a parent
|
||||||
|
// that is the first level index.
|
||||||
|
if (model->rowCount(topIndex) > 0) {
|
||||||
|
QModelIndex childIndex = model->index(0, 0, topIndex);
|
||||||
|
qDebug("topIndex RCI %x %x %llx", topIndex.row(), topIndex.column(), topIndex.internalId());
|
||||||
|
qDebug("topIndex I %llx", topIndex.internalId());
|
||||||
|
qDebug("childIndex RCI %x %x %llx", childIndex.row(), childIndex.column(), childIndex.internalId());
|
||||||
|
Q_ASSERT(model->parent(childIndex) == topIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common error test #3, the second column should NOT have the same children
|
||||||
|
// as the first column in a row.
|
||||||
|
// Usually the second column shouldn't have children.
|
||||||
|
QModelIndex topIndex1 = model->index(0, 1, QModelIndex());
|
||||||
|
if (model->rowCount(topIndex1) > 0) {
|
||||||
|
QModelIndex childIndex = model->index(0, 0, topIndex);
|
||||||
|
QModelIndex childIndex1 = model->index(0, 0, topIndex1);
|
||||||
|
Q_ASSERT(childIndex != childIndex1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Full test, walk n levels deep through the model making sure that all
|
||||||
|
// parent's children correctly specify their parent.
|
||||||
|
checkChildren(QModelIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Called from the parent() test.
|
||||||
|
|
||||||
|
A model that returns an index of parent X should also return X when asking
|
||||||
|
for the parent of the index.
|
||||||
|
|
||||||
|
This recursive function does pretty extensive testing on the whole model in an
|
||||||
|
effort to catch edge cases.
|
||||||
|
|
||||||
|
This function assumes that rowCount(), columnCount() and index() already work.
|
||||||
|
If they have a bug it will point it out, but the above tests should have already
|
||||||
|
found the basic bugs because it is easier to figure out the problem in
|
||||||
|
those tests then this one.
|
||||||
|
*/
|
||||||
|
void ModelTest::checkChildren(const QModelIndex &parent, int currentDepth)
|
||||||
|
{
|
||||||
|
// First just try walking back up the tree.
|
||||||
|
QModelIndex p = parent;
|
||||||
|
while (p.isValid())
|
||||||
|
p = p.parent();
|
||||||
|
|
||||||
|
// For models that are dynamically populated
|
||||||
|
if (model->canFetchMore(parent)) {
|
||||||
|
fetchingMore = true;
|
||||||
|
model->fetchMore(parent);
|
||||||
|
fetchingMore = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rows = model->rowCount(parent);
|
||||||
|
int columns = model->columnCount(parent);
|
||||||
|
|
||||||
|
if (rows > 0)
|
||||||
|
Q_ASSERT(model->hasChildren(parent));
|
||||||
|
|
||||||
|
// Some further testing against rows(), columns(), and hasChildren()
|
||||||
|
Q_ASSERT(rows >= 0);
|
||||||
|
Q_ASSERT(columns >= 0);
|
||||||
|
if (rows > 0)
|
||||||
|
Q_ASSERT(model->hasChildren(parent) == true);
|
||||||
|
|
||||||
|
//qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows
|
||||||
|
// << "columns:" << columns << "parent column:" << parent.column();
|
||||||
|
|
||||||
|
Q_ASSERT(model->hasIndex(rows + 1, 0, parent) == false);
|
||||||
|
for (int r = 0; r < rows; ++r) {
|
||||||
|
if (model->canFetchMore(parent)) {
|
||||||
|
fetchingMore = true;
|
||||||
|
model->fetchMore(parent);
|
||||||
|
fetchingMore = false;
|
||||||
|
}
|
||||||
|
Q_ASSERT(model->hasIndex(r, columns + 1, parent) == false);
|
||||||
|
for (int c = 0; c < columns; ++c) {
|
||||||
|
Q_ASSERT(model->hasIndex(r, c, parent) == true);
|
||||||
|
QModelIndex index = model->index(r, c, parent);
|
||||||
|
// rowCount() and columnCount() said that it existed...
|
||||||
|
Q_ASSERT(index.isValid() == true);
|
||||||
|
|
||||||
|
// index() should always return the same index when called twice in a row
|
||||||
|
QModelIndex modifiedIndex = model->index(r, c, parent);
|
||||||
|
Q_ASSERT(index == modifiedIndex);
|
||||||
|
|
||||||
|
// Make sure we get the same index if we request it twice in a row
|
||||||
|
QModelIndex a = model->index(r, c, parent);
|
||||||
|
QModelIndex b = model->index(r, c, parent);
|
||||||
|
Q_ASSERT(a == b);
|
||||||
|
|
||||||
|
// Some basic checking on the index that is returned
|
||||||
|
Q_ASSERT(index.model() == model);
|
||||||
|
Q_ASSERT(index.row() == r);
|
||||||
|
Q_ASSERT(index.column() == c);
|
||||||
|
// While you can technically return a QVariant usually this is a sign
|
||||||
|
// of an bug in data() Disable if this really is ok in your model.
|
||||||
|
//Q_ASSERT(model->data(index, Qt::DisplayRole).isValid() == true);
|
||||||
|
|
||||||
|
// If the next test fails here is some somewhat useful debug you play with.
|
||||||
|
/*
|
||||||
|
if (model->parent(index) != parent) {
|
||||||
|
qDebug() << r << c << currentDepth << model->data(index).toString()
|
||||||
|
<< model->data(parent).toString();
|
||||||
|
qDebug() << index << parent << model->parent(index);
|
||||||
|
// And a view that you can even use to show the model.
|
||||||
|
//QTreeView view;
|
||||||
|
//view.setModel(model);
|
||||||
|
//view.show();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// Check that we can get back our real parent.
|
||||||
|
QModelIndex p = model->parent(index);
|
||||||
|
//qDebug() << "child:" << index;
|
||||||
|
//qDebug() << p;
|
||||||
|
//qDebug() << parent;
|
||||||
|
Q_ASSERT(model->parent(index) == parent);
|
||||||
|
|
||||||
|
// recursively go down the children
|
||||||
|
if (model->hasChildren(index) && currentDepth < 10 ) {
|
||||||
|
//qDebug() << r << c << "has children" << model->rowCount(index);
|
||||||
|
checkChildren(index, ++currentDepth);
|
||||||
|
}/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/
|
||||||
|
|
||||||
|
// make sure that after testing the children that the index doesn't change.
|
||||||
|
QModelIndex newerIndex = model->index(r, c, parent);
|
||||||
|
Q_ASSERT(index == newerIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Tests model's implementation of QAbstractItemModel::data()
|
||||||
|
*/
|
||||||
|
void ModelTest::data()
|
||||||
|
{
|
||||||
|
// Invalid index should return an invalid qvariant
|
||||||
|
Q_ASSERT(!model->data(QModelIndex()).isValid());
|
||||||
|
|
||||||
|
if (model->rowCount() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// A valid index should have a valid QVariant data
|
||||||
|
Q_ASSERT(model->index(0, 0).isValid());
|
||||||
|
|
||||||
|
// shouldn't be able to set data on an invalid index
|
||||||
|
Q_ASSERT(model->setData(QModelIndex(), QLatin1String("foo"), Qt::DisplayRole) == false);
|
||||||
|
|
||||||
|
// General Purpose roles that should return a QString
|
||||||
|
QVariant variant = model->data(model->index(0, 0), Qt::ToolTipRole);
|
||||||
|
if (variant.isValid()) {
|
||||||
|
Q_ASSERT(qVariantCanConvert<QString>(variant));
|
||||||
|
}
|
||||||
|
variant = model->data(model->index(0, 0), Qt::StatusTipRole);
|
||||||
|
if (variant.isValid()) {
|
||||||
|
Q_ASSERT(qVariantCanConvert<QString>(variant));
|
||||||
|
}
|
||||||
|
variant = model->data(model->index(0, 0), Qt::WhatsThisRole);
|
||||||
|
if (variant.isValid()) {
|
||||||
|
Q_ASSERT(qVariantCanConvert<QString>(variant));
|
||||||
|
}
|
||||||
|
|
||||||
|
// General Purpose roles that should return a QSize
|
||||||
|
variant = model->data(model->index(0, 0), Qt::SizeHintRole);
|
||||||
|
if (variant.isValid()) {
|
||||||
|
Q_ASSERT(qVariantCanConvert<QSize>(variant));
|
||||||
|
}
|
||||||
|
|
||||||
|
// General Purpose roles that should return a QFont
|
||||||
|
QVariant fontVariant = model->data(model->index(0, 0), Qt::FontRole);
|
||||||
|
if (fontVariant.isValid()) {
|
||||||
|
Q_ASSERT(qVariantCanConvert<QFont>(fontVariant));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the alignment is one we know about
|
||||||
|
QVariant textAlignmentVariant = model->data(model->index(0, 0), Qt::TextAlignmentRole);
|
||||||
|
if (textAlignmentVariant.isValid()) {
|
||||||
|
int alignment = textAlignmentVariant.toInt();
|
||||||
|
Q_ASSERT(alignment == Qt::AlignLeft ||
|
||||||
|
alignment == Qt::AlignRight ||
|
||||||
|
alignment == Qt::AlignHCenter ||
|
||||||
|
alignment == Qt::AlignJustify ||
|
||||||
|
alignment == Qt::AlignTop ||
|
||||||
|
alignment == Qt::AlignBottom ||
|
||||||
|
alignment == Qt::AlignVCenter ||
|
||||||
|
alignment == Qt::AlignCenter ||
|
||||||
|
alignment == Qt::AlignAbsolute ||
|
||||||
|
alignment == Qt::AlignLeading ||
|
||||||
|
alignment == Qt::AlignTrailing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// General Purpose roles that should return a QColor
|
||||||
|
QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundColorRole);
|
||||||
|
if (colorVariant.isValid()) {
|
||||||
|
Q_ASSERT(qVariantCanConvert<QColor>(colorVariant));
|
||||||
|
}
|
||||||
|
|
||||||
|
colorVariant = model->data(model->index(0, 0), Qt::TextColorRole);
|
||||||
|
if (colorVariant.isValid()) {
|
||||||
|
Q_ASSERT(qVariantCanConvert<QColor>(colorVariant));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the "check state" is one we know about.
|
||||||
|
QVariant checkStateVariant = model->data(model->index(0, 0), Qt::CheckStateRole);
|
||||||
|
if (checkStateVariant.isValid()) {
|
||||||
|
int state = checkStateVariant.toInt();
|
||||||
|
Q_ASSERT(state == Qt::Unchecked ||
|
||||||
|
state == Qt::PartiallyChecked ||
|
||||||
|
state == Qt::Checked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Store what is about to be inserted to make sure it actually happens
|
||||||
|
|
||||||
|
\sa rowsInserted()
|
||||||
|
*/
|
||||||
|
void ModelTest::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
|
||||||
|
{
|
||||||
|
Q_UNUSED(end);
|
||||||
|
Changing c;
|
||||||
|
c.parent = parent;
|
||||||
|
c.oldSize = model->rowCount(parent);
|
||||||
|
c.last = model->data(model->index(start - 1, 0, parent));
|
||||||
|
c.next = model->data(model->index(start, 0, parent));
|
||||||
|
insert.push(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Confirm that what was said was going to happen actually did
|
||||||
|
|
||||||
|
\sa rowsAboutToBeInserted()
|
||||||
|
*/
|
||||||
|
void ModelTest::rowsInserted(const QModelIndex & parent, int start, int end)
|
||||||
|
{
|
||||||
|
Changing c = insert.pop();
|
||||||
|
Q_ASSERT(c.parent == parent);
|
||||||
|
Q_ASSERT(c.oldSize + (end - start + 1) == model->rowCount(parent));
|
||||||
|
Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
|
||||||
|
/*
|
||||||
|
if (c.next != model->data(model->index(end + 1, 0, c.parent))) {
|
||||||
|
qDebug() << start << end;
|
||||||
|
for (int i=0; i < model->rowCount(); ++i)
|
||||||
|
qDebug() << model->index(i, 0).data().toString();
|
||||||
|
qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
Q_ASSERT(c.next == model->data(model->index(end + 1, 0, c.parent)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelTest::layoutAboutToBeChanged()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < qBound(0, model->rowCount(), 100); ++i)
|
||||||
|
changing.append(QPersistentModelIndex(model->index(i, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelTest::layoutChanged()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < changing.count(); ++i) {
|
||||||
|
QPersistentModelIndex p = changing[i];
|
||||||
|
Q_ASSERT(p == model->index(p.row(), p.column(), p.parent()));
|
||||||
|
}
|
||||||
|
changing.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Store what is about to be inserted to make sure it actually happens
|
||||||
|
|
||||||
|
\sa rowsRemoved()
|
||||||
|
*/
|
||||||
|
void ModelTest::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
|
||||||
|
{
|
||||||
|
Changing c;
|
||||||
|
c.parent = parent;
|
||||||
|
c.oldSize = model->rowCount(parent);
|
||||||
|
c.last = model->data(model->index(start - 1, 0, parent));
|
||||||
|
c.next = model->data(model->index(end + 1, 0, parent));
|
||||||
|
remove.push(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Confirm that what was said was going to happen actually did
|
||||||
|
|
||||||
|
\sa rowsAboutToBeRemoved()
|
||||||
|
*/
|
||||||
|
void ModelTest::rowsRemoved(const QModelIndex & parent, int start, int end)
|
||||||
|
{
|
||||||
|
Changing c = remove.pop();
|
||||||
|
Q_ASSERT(c.parent == parent);
|
||||||
|
Q_ASSERT(c.oldSize - (end - start + 1) == model->rowCount(parent));
|
||||||
|
Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
|
||||||
|
Q_ASSERT(c.next == model->data(model->index(start, 0, c.parent)));
|
||||||
|
}
|
||||||
|
|
76
client/modeltest.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2007 Trolltech ASA. All rights reserved.
|
||||||
|
**
|
||||||
|
** This file is part of the Qt Concurrent project on Trolltech Labs.
|
||||||
|
**
|
||||||
|
** This file may be used under the terms of the GNU General Public
|
||||||
|
** License version 2.0 as published by the Free Software Foundation
|
||||||
|
** and appearing in the file LICENSE.GPL included in the packaging of
|
||||||
|
** this file. Please review the following information to ensure GNU
|
||||||
|
** General Public Licensing requirements will be met:
|
||||||
|
** http://www.trolltech.com/products/qt/opensource.html
|
||||||
|
**
|
||||||
|
** If you are unsure which license is appropriate for your use, please
|
||||||
|
** review the following information:
|
||||||
|
** http://www.trolltech.com/products/qt/licensing.html or contact the
|
||||||
|
** sales department at sales@trolltech.com.
|
||||||
|
**
|
||||||
|
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||||
|
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef MODELTEST_H
|
||||||
|
#define MODELTEST_H
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QtCore/QAbstractItemModel>
|
||||||
|
#include <QtCore/QStack>
|
||||||
|
|
||||||
|
class ModelTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModelTest(QAbstractItemModel *model, QObject *parent = 0);
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void nonDestructiveBasicTest();
|
||||||
|
void rowCount();
|
||||||
|
void columnCount();
|
||||||
|
void hasIndex();
|
||||||
|
void index();
|
||||||
|
void parent();
|
||||||
|
void data();
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
void runAllTests();
|
||||||
|
void layoutAboutToBeChanged();
|
||||||
|
void layoutChanged();
|
||||||
|
void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
|
||||||
|
void rowsInserted(const QModelIndex & parent, int start, int end);
|
||||||
|
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
|
||||||
|
void rowsRemoved(const QModelIndex & parent, int start, int end);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkChildren(const QModelIndex &parent, int currentDepth = 0);
|
||||||
|
|
||||||
|
QAbstractItemModel *model;
|
||||||
|
|
||||||
|
struct Changing
|
||||||
|
{
|
||||||
|
QModelIndex parent;
|
||||||
|
int oldSize;
|
||||||
|
QVariant last;
|
||||||
|
QVariant next;
|
||||||
|
};
|
||||||
|
QStack<Changing> insert;
|
||||||
|
QStack<Changing> remove;
|
||||||
|
|
||||||
|
bool fetchingMore;
|
||||||
|
|
||||||
|
QList<QPersistentModelIndex> changing;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
4
client/modeltest.pri
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
DEPENDPATH += $$PWD
|
||||||
|
SOURCES += $$PWD/modeltest.cpp
|
||||||
|
HEADERS += $$PWD/modeltest.h
|
24
client/mythread.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include "mythread.h"
|
||||||
|
|
||||||
|
void MyThread::run()
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (i=0; i<NumPorts; i++)
|
||||||
|
for (j=0; j<NumStats; j++)
|
||||||
|
stats[i][j] = 0;
|
||||||
|
qDebug("after stats init\n");
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
for (i=0; i<NumPorts; i++)
|
||||||
|
{
|
||||||
|
emit portStatsUpdate(i, (void*) &stats[i]);
|
||||||
|
|
||||||
|
for (j=0; j<NumStats; j++)
|
||||||
|
stats[i][j]+= qrand() & 0xF;
|
||||||
|
|
||||||
|
}
|
||||||
|
sleep(qrand() & 0x3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
23
client/mythread.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef _MY_THREAD_H
|
||||||
|
#define _MY_THREAD_H
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
#define NumPorts 2
|
||||||
|
#define NumStats 8
|
||||||
|
|
||||||
|
class MyThread : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
void run();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void portStatsUpdate(int port, void *stats);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int stats[2][8];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
42
client/ostinato.pro
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += qt debug
|
||||||
|
QT += network
|
||||||
|
RESOURCES += ostinato.qrc
|
||||||
|
HEADERS += \
|
||||||
|
hexlineedit.h \
|
||||||
|
mainwindow.h \
|
||||||
|
mythread.h \
|
||||||
|
port.h \
|
||||||
|
portgroup.h \
|
||||||
|
portgrouplist.h \
|
||||||
|
portmodel.h \
|
||||||
|
portstatsmodel.h \
|
||||||
|
portstatswindow.h \
|
||||||
|
portswindow.h \
|
||||||
|
streamconfigdialog.h \
|
||||||
|
streammodel.h
|
||||||
|
|
||||||
|
FORMS += \
|
||||||
|
mainwindow.ui \
|
||||||
|
portstatswindow.ui \
|
||||||
|
portswindow.ui \
|
||||||
|
streamconfigdialog.ui
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
stream.cpp \
|
||||||
|
hexlineedit.cpp \
|
||||||
|
main.cpp \
|
||||||
|
mainwindow.cpp \
|
||||||
|
mythread.cpp \
|
||||||
|
port.cpp \
|
||||||
|
portgroup.cpp \
|
||||||
|
portgrouplist.cpp \
|
||||||
|
portmodel.cpp \
|
||||||
|
portstatsmodel.cpp \
|
||||||
|
portstatswindow.cpp \
|
||||||
|
portswindow.cpp \
|
||||||
|
streamconfigdialog.cpp \
|
||||||
|
streammodel.cpp
|
||||||
|
|
||||||
|
# TODO(LOW): Test only
|
||||||
|
include(modeltest.pri)
|
21
client/ostinato.qrc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/" >
|
||||||
|
<file>icons/bullet_error.png</file>
|
||||||
|
<file>icons/bullet_green.png</file>
|
||||||
|
<file>icons/bullet_orange.png</file>
|
||||||
|
<file>icons/bullet_red.png</file>
|
||||||
|
<file>icons/bullet_yellow.png</file>
|
||||||
|
<file>icons/control_play.png</file>
|
||||||
|
<file>icons/control_stop.png</file>
|
||||||
|
<file>icons/magnifier.png</file>
|
||||||
|
<file>icons/portgroup_add.png</file>
|
||||||
|
<file>icons/portgroup_connect.png</file>
|
||||||
|
<file>icons/portgroup_delete.png</file>
|
||||||
|
<file>icons/portgroup_disconnect.png</file>
|
||||||
|
<file>icons/sound_mute.png</file>
|
||||||
|
<file>icons/sound_none.png</file>
|
||||||
|
<file>icons/stream_add.png</file>
|
||||||
|
<file>icons/stream_delete.png</file>
|
||||||
|
<file>icons/stream_edit.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
24
client/port.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
Port::Port(quint32 id, quint32 portGroupId)
|
||||||
|
{
|
||||||
|
mPortId = id;
|
||||||
|
mPortGroupId = portGroupId;
|
||||||
|
|
||||||
|
mAdminStatus = AdminDisable;
|
||||||
|
mOperStatus = OperDown;
|
||||||
|
mControlMode = ControlShared;
|
||||||
|
|
||||||
|
// FIXME(HI): TEST only
|
||||||
|
for(int i = 0; i < 10; i++)
|
||||||
|
mPortStats[i] = mPortGroupId*10000+mPortId*100+i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Port::insertDummyStreams()
|
||||||
|
{
|
||||||
|
mStreams.append(*(new Stream));
|
||||||
|
mStreams[0].setName(QString("%1:%2:0").arg(portGroupId()).arg(id()));
|
||||||
|
mStreams.append(*(new Stream));
|
||||||
|
mStreams[1].setName(QString("%1:%2:1").arg(portGroupId()).arg(id()));
|
||||||
|
}
|
||||||
|
|
55
client/port.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef _PORT_H
|
||||||
|
#define _PORT_H
|
||||||
|
|
||||||
|
#include <Qt>
|
||||||
|
#include <QString>
|
||||||
|
#include <QList>
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
class Port {
|
||||||
|
|
||||||
|
friend class StreamModel;
|
||||||
|
friend class PortStatsModel;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum AdminStatus { AdminDisable, AdminEnable };
|
||||||
|
enum OperStatus { OperDown, OperUp };
|
||||||
|
enum ControlMode { ControlShared, ControlExclusive };
|
||||||
|
|
||||||
|
private:
|
||||||
|
quint32 mPortId;
|
||||||
|
quint32 mPortGroupId;
|
||||||
|
QList<Stream> mStreams;
|
||||||
|
QString mName;
|
||||||
|
QString mDescription;
|
||||||
|
QString mUserAlias; // user defined
|
||||||
|
AdminStatus mAdminStatus;
|
||||||
|
OperStatus mOperStatus;
|
||||||
|
ControlMode mControlMode;
|
||||||
|
|
||||||
|
quint32 mPortStats[10]; // FIXME(HI):Hardcoding
|
||||||
|
|
||||||
|
public:
|
||||||
|
// FIXME(HIGH): default args is a hack for QList operations on Port
|
||||||
|
Port(quint32 id = 0xFFFFFFFF, quint32 pgId = 0xFFFFFFFF);
|
||||||
|
|
||||||
|
quint32 id() const { return mPortId; }
|
||||||
|
quint32 portGroupId() const { return mPortGroupId; }
|
||||||
|
const QString& name() const { return mName; }
|
||||||
|
const QString& description() const { return mDescription; }
|
||||||
|
const QString& userAlias() const { return mUserAlias; }
|
||||||
|
|
||||||
|
void setName(QString &name) { mName = name; }
|
||||||
|
void setName(const char* name) { mName = QString(name); }
|
||||||
|
void setDescription(QString &description) { mDescription = description; }
|
||||||
|
void setDescription(const char *description)
|
||||||
|
{ mDescription = QString(description); }
|
||||||
|
|
||||||
|
//void setAdminEnable(AdminStatus status) { mAdminStatus = status; }
|
||||||
|
void setAlias(QString &alias) { mUserAlias = alias; }
|
||||||
|
//void setExclusive(bool flag);
|
||||||
|
// FIXME(HIGH): Only for testing
|
||||||
|
void insertDummyStreams();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
169
client/portgroup.cpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include "portgroup.h"
|
||||||
|
#include "../common/protocol.h"
|
||||||
|
|
||||||
|
quint32 PortGroup::mPortGroupAllocId = 0;
|
||||||
|
|
||||||
|
PortGroup::PortGroup(QHostAddress ip, quint16 port)
|
||||||
|
{
|
||||||
|
// Allocate an id for self
|
||||||
|
mPortGroupId = PortGroup::mPortGroupAllocId++;
|
||||||
|
|
||||||
|
// Init attributes for which we values were passed to us
|
||||||
|
mServerAddress = ip;
|
||||||
|
mServerPort = port;
|
||||||
|
|
||||||
|
// Init remaining attributes with defaults
|
||||||
|
mpSocket = new QTcpSocket(this);
|
||||||
|
|
||||||
|
// TODO: consider using QT's signal-slot autoconnect
|
||||||
|
connect(mpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(on_mpSocket_stateChanged()));
|
||||||
|
connect(mpSocket, SIGNAL(connected()), this, SLOT(when_connected()));
|
||||||
|
connect(mpSocket, SIGNAL(disconnected()), this, SLOT(when_disconnected()));
|
||||||
|
connect(mpSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(when_error(QAbstractSocket::SocketError)));
|
||||||
|
connect(mpSocket, SIGNAL(readyRead()), this, SLOT(when_dataAvail()));
|
||||||
|
}
|
||||||
|
|
||||||
|
PortGroup::~PortGroup()
|
||||||
|
{
|
||||||
|
qDebug("PortGroup Destructor");
|
||||||
|
// Disconnect and free TCP mpSocketet etc.
|
||||||
|
PortGroup::disconnectFromHost();
|
||||||
|
delete mpSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortGroup::connectToHost(QHostAddress ip, quint16 port)
|
||||||
|
{
|
||||||
|
mServerAddress = ip;
|
||||||
|
mServerPort = port;
|
||||||
|
|
||||||
|
PortGroup::connectToHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortGroup::connectToHost()
|
||||||
|
{
|
||||||
|
qDebug("PortGroup::connectToHost()");
|
||||||
|
mpSocket->connectToHost(mServerAddress, mServerPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortGroup::disconnectFromHost()
|
||||||
|
{
|
||||||
|
mpSocket->disconnectFromHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------
|
||||||
|
// Private Methods
|
||||||
|
// --------------------------------------------
|
||||||
|
void PortGroup::ProcessMsg(const char *msg, quint32 size)
|
||||||
|
{
|
||||||
|
tCommHdr *hdr;
|
||||||
|
// TODO: For now, assuming we'll get a complete msg
|
||||||
|
// but need to fix this as this is a TCP stream
|
||||||
|
|
||||||
|
hdr = (tCommHdr*) msg;
|
||||||
|
|
||||||
|
if (hdr->ver != 1) // FIXME:hardcoding
|
||||||
|
{
|
||||||
|
qDebug("Rcvd msg with invalid version %d\n", hdr->ver);
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug("msgType - %x\n", NTOHS(hdr->msgType));
|
||||||
|
switch (NTOHS(hdr->msgType))
|
||||||
|
{
|
||||||
|
case e_MT_CapabilityInfo:
|
||||||
|
ProcessCapabilityInfo(msg+sizeof(tCommHdr),
|
||||||
|
NTOHS(hdr->msgLen)-sizeof(tCommHdr));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
qDebug("Rcvd msg with unrecognized msgType %d\n", NTOHS(hdr->msgType));
|
||||||
|
}
|
||||||
|
|
||||||
|
_exit:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortGroup::ProcessCapabilityInfo(const char *msg, qint32 size)
|
||||||
|
{
|
||||||
|
tTlvPortCapability *cap = (tTlvPortCapability*) msg;
|
||||||
|
Port *p;
|
||||||
|
|
||||||
|
emit portListAboutToBeChanged(mPortGroupId);
|
||||||
|
|
||||||
|
while (size)
|
||||||
|
{
|
||||||
|
qDebug("size = %d, tlvType = %d, tlvLen = %d\n",
|
||||||
|
size, NTOHS(cap->tlvType), NTOHS(cap->tlvLen));
|
||||||
|
if (NTOHS(cap->tlvType) != e_TT_PortCapability)
|
||||||
|
{
|
||||||
|
qDebug("Unrecognized TLV Type %d\n", NTOHS(cap->tlvType));
|
||||||
|
goto _next;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = new Port(NTOHL(cap->port), mPortGroupId);
|
||||||
|
p->setName(cap->name);
|
||||||
|
p->setDescription(cap->desc);
|
||||||
|
p->insertDummyStreams(); // FIXME: only for testing
|
||||||
|
qDebug("before port append\n");
|
||||||
|
mPorts.append(*p);
|
||||||
|
|
||||||
|
_next:
|
||||||
|
size -= NTOHS(cap->tlvLen);
|
||||||
|
cap = (tTlvPortCapability*)((char *)(cap) + NTOHS(cap->tlvLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
emit portListChanged(mPortGroupId);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------
|
||||||
|
// Slots
|
||||||
|
// ------------------------------------------------
|
||||||
|
void PortGroup::on_mpSocket_stateChanged()
|
||||||
|
{
|
||||||
|
qDebug("state changed");
|
||||||
|
emit portGroupDataChanged(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortGroup::when_connected()
|
||||||
|
{
|
||||||
|
qDebug("connected\n");
|
||||||
|
|
||||||
|
emit portGroupDataChanged(this);
|
||||||
|
|
||||||
|
// Ask for Port Capability
|
||||||
|
tCommHdr pkt;
|
||||||
|
pkt.ver = 1;
|
||||||
|
pkt.resv1 = 0;
|
||||||
|
pkt.resv2 = 0;
|
||||||
|
pkt.msgType = HTONS(e_MT_CapabilityReq);
|
||||||
|
pkt.msgLen = HTONS(8);
|
||||||
|
|
||||||
|
mpSocket->write((char*) &pkt, sizeof(pkt));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortGroup::when_disconnected()
|
||||||
|
{
|
||||||
|
qDebug("disconnected\n");
|
||||||
|
emit portListAboutToBeChanged(mPortGroupId);
|
||||||
|
mPorts.clear();
|
||||||
|
emit portListChanged(mPortGroupId);
|
||||||
|
emit portGroupDataChanged(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortGroup::when_error(QAbstractSocket::SocketError socketError)
|
||||||
|
{
|
||||||
|
qDebug("error\n");
|
||||||
|
emit portGroupDataChanged(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortGroup::when_dataAvail()
|
||||||
|
{
|
||||||
|
qDebug("dataAvail\n");
|
||||||
|
|
||||||
|
QByteArray msg = mpSocket->read(1024); // FIXME: hardcoding
|
||||||
|
ProcessMsg(msg.constData(), msg.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
66
client/portgroup.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#ifndef _PORT_GROUP_H
|
||||||
|
#define _PORT_GROUP_H
|
||||||
|
|
||||||
|
#include "port.h"
|
||||||
|
#include <QHostAddress>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
HIGH
|
||||||
|
MED
|
||||||
|
LOW
|
||||||
|
- Allow hostnames in addition to IP Address as "server address"
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DEFAULT_SERVER_PORT 7878
|
||||||
|
|
||||||
|
class PortGroup : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
quint32 mPortGroupId;
|
||||||
|
static quint32 mPortGroupAllocId;
|
||||||
|
QString mUserAlias; // user defined
|
||||||
|
|
||||||
|
QTcpSocket *mpSocket;
|
||||||
|
QHostAddress mServerAddress;
|
||||||
|
quint16 mServerPort;
|
||||||
|
public: // FIXME(HIGH): member access
|
||||||
|
QList<Port> mPorts;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PortGroup(QHostAddress ip = QHostAddress::LocalHost,
|
||||||
|
quint16 port = DEFAULT_SERVER_PORT);
|
||||||
|
~PortGroup();
|
||||||
|
|
||||||
|
void connectToHost();
|
||||||
|
void connectToHost(QHostAddress ip, quint16 port);
|
||||||
|
void disconnectFromHost();
|
||||||
|
|
||||||
|
int numPorts() const { return mPorts.size(); }
|
||||||
|
quint32 id() const { return mPortGroupId; }
|
||||||
|
const QHostAddress& serverAddress() const { return mServerAddress; }
|
||||||
|
quint16 serverPort() const { return mServerPort; }
|
||||||
|
const QString& userAlias() const { return mUserAlias; }
|
||||||
|
QAbstractSocket::SocketState state() const { return mpSocket->state(); }
|
||||||
|
|
||||||
|
void setUserAlias(QString alias) { mUserAlias = alias; };
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void portGroupDataChanged(PortGroup* portGroup);
|
||||||
|
void portListAboutToBeChanged(quint32 portGroupId);
|
||||||
|
void portListChanged(quint32 portGroupId);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_mpSocket_stateChanged();
|
||||||
|
void when_connected();
|
||||||
|
void when_disconnected();
|
||||||
|
void when_error(QAbstractSocket::SocketError socketError);
|
||||||
|
void when_dataAvail();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ProcessCapabilityInfo(const char *msg, qint32 size);
|
||||||
|
void ProcessMsg(const char *msg, quint32 size);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
108
client/portgrouplist.cpp
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#include "portgrouplist.h"
|
||||||
|
|
||||||
|
// TODO(LOW): Remove
|
||||||
|
#include <modeltest.h>
|
||||||
|
|
||||||
|
PortGroupList::PortGroupList()
|
||||||
|
: mPortGroupListModel(this),
|
||||||
|
mStreamListModel(this),
|
||||||
|
mPortStatsModel(this, this)
|
||||||
|
{
|
||||||
|
PortGroup *pg;
|
||||||
|
|
||||||
|
// TODO(LOW): Remove
|
||||||
|
new ModelTest(getStreamModel());
|
||||||
|
new ModelTest(getPortModel());
|
||||||
|
new ModelTest(getPortStatsModel());
|
||||||
|
|
||||||
|
// Add the "Local" Port Group
|
||||||
|
pg = new PortGroup;
|
||||||
|
addPortGroup(*pg);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortGroupList::isPortGroup(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
return mPortGroupListModel.isPortGroup(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortGroupList::isPort(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
return mPortGroupListModel.isPort(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
PortGroup& PortGroupList::portGroup(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if (mPortGroupListModel.isPortGroup(index))
|
||||||
|
{
|
||||||
|
//return *(mPortGroups[mPortGroupListModel.portGroupId(index)]);
|
||||||
|
return *(mPortGroups[index.row()]);
|
||||||
|
}
|
||||||
|
#if 0 // FIXME(MED)
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Port& PortGroupList::port(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if (mPortGroupListModel.isPort(index))
|
||||||
|
{
|
||||||
|
return (mPortGroups.at(index.parent().row())->
|
||||||
|
mPorts[index.row()]);
|
||||||
|
}
|
||||||
|
#if 0 // FIXME(MED)
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortGroupList::addPortGroup(PortGroup &portGroup)
|
||||||
|
{
|
||||||
|
mPortGroupListModel.portGroupAboutToBeAppended();
|
||||||
|
|
||||||
|
connect(&portGroup, SIGNAL(portGroupDataChanged(PortGroup*)),
|
||||||
|
&mPortGroupListModel, SLOT(when_portGroupDataChanged(PortGroup*)));
|
||||||
|
#if 0
|
||||||
|
connect(&portGroup, SIGNAL(portListAboutToBeChanged(quint32)),
|
||||||
|
&mPortGroupListModel, SLOT(triggerLayoutAboutToBeChanged()));
|
||||||
|
connect(&portGroup, SIGNAL(portListChanged(quint32)),
|
||||||
|
&mPortGroupListModel, SLOT(triggerLayoutChanged()));
|
||||||
|
#endif
|
||||||
|
connect(&portGroup, SIGNAL(portListChanged(quint32)),
|
||||||
|
&mPortGroupListModel, SLOT(when_portListChanged()));
|
||||||
|
|
||||||
|
connect(&portGroup, SIGNAL(portListChanged(quint32)),
|
||||||
|
&mPortStatsModel, SLOT(when_portListChanged()));
|
||||||
|
|
||||||
|
mPortGroups.append(&portGroup);
|
||||||
|
portGroup.connectToHost();
|
||||||
|
|
||||||
|
mPortGroupListModel.portGroupAppended();
|
||||||
|
|
||||||
|
mPortStatsModel.when_portListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortGroupList::removePortGroup(PortGroup &portGroup)
|
||||||
|
{
|
||||||
|
mPortGroupListModel.portGroupAboutToBeRemoved(&portGroup);
|
||||||
|
|
||||||
|
PortGroup* pg = mPortGroups.takeAt(mPortGroups.indexOf(&portGroup));
|
||||||
|
qDebug("after takeAt()");
|
||||||
|
mPortGroupListModel.portGroupRemoved();
|
||||||
|
|
||||||
|
delete pg;
|
||||||
|
|
||||||
|
mPortStatsModel.when_portListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
//....................
|
||||||
|
// Private Methods
|
||||||
|
//....................
|
||||||
|
int PortGroupList::indexOfPortGroup(quint32 portGroupId)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < mPortGroups.size(); i++) {
|
||||||
|
if (mPortGroups.value(i)->id() == portGroupId)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
47
client/portgrouplist.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef _PORT_GROUP_LIST_H
|
||||||
|
#define _PORT_GROUP_LIST_H
|
||||||
|
|
||||||
|
#include "portgroup.h"
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QItemSelection>
|
||||||
|
#include "portmodel.h"
|
||||||
|
#include "streammodel.h"
|
||||||
|
#include "portstatsmodel.h"
|
||||||
|
|
||||||
|
class PortModel;
|
||||||
|
class StreamModel;
|
||||||
|
|
||||||
|
class PortGroupList : public QObject {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
friend class PortModel;
|
||||||
|
friend class StreamModel;
|
||||||
|
friend class PortStatsModel;
|
||||||
|
|
||||||
|
QList<PortGroup*> mPortGroups;
|
||||||
|
PortModel mPortGroupListModel;
|
||||||
|
StreamModel mStreamListModel;
|
||||||
|
PortStatsModel mPortStatsModel;
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
public:
|
||||||
|
PortGroupList::PortGroupList();
|
||||||
|
|
||||||
|
PortModel* getPortModel() { return &mPortGroupListModel; }
|
||||||
|
PortStatsModel* getPortStatsModel() { return &mPortStatsModel; }
|
||||||
|
StreamModel* getStreamModel() { return &mStreamListModel; }
|
||||||
|
bool isPortGroup(const QModelIndex& index);
|
||||||
|
bool isPort(const QModelIndex& index);
|
||||||
|
PortGroup& portGroup(const QModelIndex& index);
|
||||||
|
Port& port(const QModelIndex& index);
|
||||||
|
|
||||||
|
void addPortGroup(PortGroup &portGroup);
|
||||||
|
void removePortGroup(PortGroup &portGroup);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int indexOfPortGroup(quint32 portGroupId);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
55
client/portgrouplistmodel.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef _PORT_GROUP_LIST_H
|
||||||
|
#define _PORT_GROUP_LIST_H
|
||||||
|
|
||||||
|
#include "portgroup.h"
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------
|
||||||
|
** NOTE: FILE NOT USED 'COZ MOC DOESN'T SUPPORT NESTED CLASSES
|
||||||
|
*-------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
class PortGroupList;
|
||||||
|
|
||||||
|
class PortGroupList : public QObject {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
class PortListModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
// This is currently a read only model
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
PortGroupList *pgl; // FIXME(HIGH): rename member
|
||||||
|
|
||||||
|
public:
|
||||||
|
PortListModel(PortGroupList *p, QObject *parent = 0);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
QModelIndex index (int row, int col, const QModelIndex & parent = QModelIndex() ) const;
|
||||||
|
QModelIndex parent(const QModelIndex &index) const;
|
||||||
|
|
||||||
|
friend class PortGroupList; // FIXME(MED): Review need for friend
|
||||||
|
};
|
||||||
|
|
||||||
|
friend class PortListModel;
|
||||||
|
|
||||||
|
QList<PortGroup*> mPortGroups;
|
||||||
|
PortListModel mPortGroupListModel;
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
public:
|
||||||
|
PortGroupList::PortGroupList();
|
||||||
|
QAbstractItemModel* getModel();
|
||||||
|
int addPortGroup(PortGroup &portGroup);
|
||||||
|
int removePortGroup(PortGroup &portGroup);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void when_portlist_dataChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
191
client/portlistmodel.cpp
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
#include "portlistmodel.h"
|
||||||
|
|
||||||
|
-----------------------
|
||||||
|
This file is not used
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
PortListModel::PortListModel(QObject *parent)
|
||||||
|
: QAbstractItemModel(parent)
|
||||||
|
{
|
||||||
|
portList = new QList<PortGroup>;
|
||||||
|
|
||||||
|
#if 0 // FIXME: Dummy data only for testing; to be removed
|
||||||
|
PortGroup pg;
|
||||||
|
|
||||||
|
pg.name = "A";
|
||||||
|
pg.isLocal = TRUE;
|
||||||
|
pg.numPorts = 3;
|
||||||
|
pg.port = new Port[pg.numPorts];
|
||||||
|
pg.port[0].portId = 0;
|
||||||
|
pg.port[0].name = "A0";
|
||||||
|
pg.port[0].desc = "a0a0a0a0a0a0";
|
||||||
|
pg.port[1].portId = 1;
|
||||||
|
pg.port[1].name = "A1";
|
||||||
|
pg.port[1].desc = "a1a1a1a1a1a1";
|
||||||
|
pg.port[2].portId = 2;
|
||||||
|
pg.port[2].name = "A2";
|
||||||
|
pg.port[2].desc = "a2a2a2a2a2a2";
|
||||||
|
|
||||||
|
portList->append(pg);
|
||||||
|
|
||||||
|
pg.name = "B";
|
||||||
|
pg.isLocal = FALSE;
|
||||||
|
pg.numPorts = 2;
|
||||||
|
pg.port = new Port[pg.numPorts];
|
||||||
|
pg.port[0].portId = 0;
|
||||||
|
pg.port[0].name = "B0";
|
||||||
|
pg.port[0].desc = "b0b0b0b0b0b0";
|
||||||
|
pg.port[1].portId = 1;
|
||||||
|
pg.port[1].name = "B1";
|
||||||
|
pg.port[1].desc = "b1b1b1b1b1b1";
|
||||||
|
|
||||||
|
portList->append(pg);
|
||||||
|
#endif
|
||||||
|
// Do I need to do anything here?
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortListModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
// qDebug("RowCount Enter\n");
|
||||||
|
if (!parent.isValid())
|
||||||
|
{
|
||||||
|
// Top Level Item
|
||||||
|
// qDebug("RowCount top\n");
|
||||||
|
// qDebug("RowCount Exit: %d\n", portList->size());
|
||||||
|
return portList->size();
|
||||||
|
}
|
||||||
|
// qDebug("RowCount non top %d, %d, %llx\n",
|
||||||
|
// parent.row(), parent.column(), parent.internalId());
|
||||||
|
|
||||||
|
quint16 p = parent.internalId() & 0xFFFF;
|
||||||
|
if (p == 0xFFFF)
|
||||||
|
{
|
||||||
|
// qDebug("RowCount Exit: %d\n", portList->at(parent.row()).numPorts);
|
||||||
|
return portList->at(parent.row()).numPorts;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Leaf Item
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortListModel::columnCount(const QModelIndex &parent ) const
|
||||||
|
{
|
||||||
|
return 1; // FIXME: hardcoding
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags PortListModel::flags(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
return QAbstractItemModel::flags(index); // FIXME: no need for this func
|
||||||
|
}
|
||||||
|
QVariant PortListModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
//qDebug("Enter PortListModel data\n");
|
||||||
|
// Check for a valid index
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
|
||||||
|
// Check role
|
||||||
|
if ((role == Qt::DisplayRole))
|
||||||
|
{
|
||||||
|
#if 0 // Only for debug
|
||||||
|
qDebug("Exit PortListModel data\n");
|
||||||
|
return "Testing"; // FIXME: for dbg only
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QModelIndex parent = index.parent();
|
||||||
|
|
||||||
|
if (!parent.isValid())
|
||||||
|
{
|
||||||
|
// Top Level Item
|
||||||
|
return QString("%1 (%2) [%3]").
|
||||||
|
arg(portList->at(index.row()).name).
|
||||||
|
arg(portList->at(index.row()).isLocal == TRUE? "LOCAL" : "REMOTE").
|
||||||
|
arg(portList->at(index.row()).numPorts);
|
||||||
|
}
|
||||||
|
return QString("%1: %2 (%3)").
|
||||||
|
arg(portList->at(parent.row()).port[index.row()].portId).
|
||||||
|
arg(portList->at(parent.row()).port[index.row()].name).
|
||||||
|
arg(portList->at(parent.row()).port[index.row()].desc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PortListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (role != Qt::DisplayRole)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (orientation == Qt::Horizontal)
|
||||||
|
return QVariant();
|
||||||
|
else
|
||||||
|
return QString("%1").arg(section+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PortListModel::index (int row, int col,
|
||||||
|
const QModelIndex & parent) const
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if (!hasIndex(row, col, parent))
|
||||||
|
return QModelIndex();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//qDebug("index: R=%d, C=%d, PR=%d, PC=%d, PID=%llx\n",
|
||||||
|
// row, col, parent.row(), parent.column(), parent.internalId());
|
||||||
|
|
||||||
|
if (!parent.isValid())
|
||||||
|
{
|
||||||
|
// Top Level Item
|
||||||
|
quint16 pg = row, p = 0xFFFF;
|
||||||
|
quint32 id = (pg << 16) | p;
|
||||||
|
//qDebug("index (top) dbg: PG=%d, P=%d, ID=%x\n", pg, p, id);
|
||||||
|
|
||||||
|
return createIndex(row, col, id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
quint16 pg = parent.row(), p = row;
|
||||||
|
quint32 id = (pg << 16) | p;
|
||||||
|
//qDebug("index (nontop) dbg: PG=%d, P=%d, ID=%x\n", pg, p, id);
|
||||||
|
|
||||||
|
return createIndex(row, col, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PortListModel::parent(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return QModelIndex();
|
||||||
|
|
||||||
|
//qDebug("parent: R=%d, C=%d ID=%llx\n",
|
||||||
|
// index.row(), index.column(), index.internalId());
|
||||||
|
|
||||||
|
quint16 pg = index.internalId() >> 16;
|
||||||
|
quint16 p = index.internalId() & 0x0000FFFF;
|
||||||
|
|
||||||
|
//qDebug("parent dbg: PG=%d, P=%d\n", pg, p);
|
||||||
|
|
||||||
|
if (p == 0xFFFF)
|
||||||
|
{
|
||||||
|
//qDebug("parent ret: NULL\n");
|
||||||
|
// Top Level Item - PG
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 id = (pg << 16) | 0xFFFF;
|
||||||
|
//qDebug("parent ret: R=%d, C=%d, ID=%x\n",
|
||||||
|
// pg, 0, id);
|
||||||
|
|
||||||
|
return createIndex(pg, 0, id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortListModel::doRefresh()
|
||||||
|
{
|
||||||
|
emit layoutChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
37
client/portlistmodel.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef _PORT_LIST_MODEL_H
|
||||||
|
#define _PORT_LIST_MODEL_H
|
||||||
|
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
This file is not used
|
||||||
|
------------------
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QStringList>
|
||||||
|
#include "portgroup.h"
|
||||||
|
|
||||||
|
static QStringList PortListCols = (QStringList()
|
||||||
|
<< "Name"
|
||||||
|
);
|
||||||
|
|
||||||
|
class PortListModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
//PortListModel(QObject *parent = 0) : QAbstractItemModel(parent) {}
|
||||||
|
PortListModel(QObject *parent = 0);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
QModelIndex index (int row, int col, const QModelIndex & parent = QModelIndex() ) const;
|
||||||
|
QModelIndex parent(const QModelIndex &index) const;
|
||||||
|
|
||||||
|
void doRefresh(); // FIXME: temp till model exports functions to insert rows
|
||||||
|
QList<PortGroup> *portList; // FIXME: this shd be private
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
314
client/portmodel.cpp
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
#include "portmodel.h"
|
||||||
|
#include "portgrouplist.h"
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define DBG0(x) qDebug(x)
|
||||||
|
#define DBG1(x, p1) qDebug(x, (p1))
|
||||||
|
#else
|
||||||
|
#define DBG0(x) {}
|
||||||
|
#define DBG1(x, p1) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PortModel::PortModel(PortGroupList *p, QObject *parent)
|
||||||
|
: QAbstractItemModel(parent)
|
||||||
|
{
|
||||||
|
pgl = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
// qDebug("RowCount Enter\n");
|
||||||
|
if (!parent.isValid())
|
||||||
|
{
|
||||||
|
// Top Level Item
|
||||||
|
//qDebug("RowCount (Top) Exit: %d\n", pgl->mPortGroups.size());
|
||||||
|
return pgl->mPortGroups.size();
|
||||||
|
}
|
||||||
|
// qDebug("RowCount non top %d, %d, %llx\n",
|
||||||
|
// parent.row(), parent.column(), parent.internalId());
|
||||||
|
|
||||||
|
quint16 pg = (parent.internalId() >> 16) & 0xFFFF;
|
||||||
|
quint16 p = parent.internalId() & 0xFFFF;
|
||||||
|
if (p == 0xFFFF)
|
||||||
|
{
|
||||||
|
#if 0 // wrong code?
|
||||||
|
int count = 0;
|
||||||
|
foreach(PortGroup *pg, pgl->mPortGroups)
|
||||||
|
{
|
||||||
|
count += pg->numPorts();
|
||||||
|
}
|
||||||
|
//qDebug("RowCount (Mid) Exit: %d\n", count);
|
||||||
|
return count;
|
||||||
|
#endif
|
||||||
|
if (parent.column() == 0)
|
||||||
|
return pgl->mPortGroups.value(pgl->indexOfPortGroup(pg))->numPorts();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Leaf Item
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortModel::columnCount(const QModelIndex &parent ) const
|
||||||
|
{
|
||||||
|
return 1; // FIXME: hardcoding
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags PortModel::flags(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
return QAbstractItemModel::flags(index); // FIXME: no need for this func
|
||||||
|
}
|
||||||
|
QVariant PortModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
|
||||||
|
DBG0("Enter PortModel data\n");
|
||||||
|
|
||||||
|
// Check for a valid index
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
DBG1("PortModel::data(index).row = %d", index.row());
|
||||||
|
DBG1("PortModel::data(index).column = %0d", index.column());
|
||||||
|
DBG1("PortModel::data(index).internalId = %08llx", index.internalId());
|
||||||
|
|
||||||
|
QModelIndex parent = index.parent();
|
||||||
|
|
||||||
|
if (!parent.isValid())
|
||||||
|
{
|
||||||
|
// Top Level Item - PortGroup
|
||||||
|
if ((role == Qt::DisplayRole))
|
||||||
|
{
|
||||||
|
DBG0("Exit PortModel data 1\n");
|
||||||
|
return QString("Port Group %1: %2 [%3:%4] (%5)").
|
||||||
|
arg(pgl->mPortGroups.at(index.row())->id()).
|
||||||
|
arg(pgl->mPortGroups.at(index.row())->userAlias()).
|
||||||
|
arg(pgl->mPortGroups.at(index.row())->serverAddress().toString()).
|
||||||
|
arg(pgl->mPortGroups.at(index.row())->serverPort()).
|
||||||
|
arg(pgl->mPortGroups.value(index.row())->numPorts());
|
||||||
|
}
|
||||||
|
else if ((role == Qt::DecorationRole))
|
||||||
|
{
|
||||||
|
DBG0("Exit PortModel data 2\n");
|
||||||
|
switch(pgl->mPortGroups.at(index.row())->state())
|
||||||
|
{
|
||||||
|
case QAbstractSocket::UnconnectedState:
|
||||||
|
return QIcon(":/icons/bullet_red.png");
|
||||||
|
|
||||||
|
case QAbstractSocket::HostLookupState:
|
||||||
|
return QIcon(":/icons/bullet_yellow.png");
|
||||||
|
|
||||||
|
case QAbstractSocket::ConnectingState:
|
||||||
|
case QAbstractSocket::ClosingState:
|
||||||
|
return QIcon(":/icons/bullet_orange.png");
|
||||||
|
|
||||||
|
case QAbstractSocket::ConnectedState:
|
||||||
|
return QIcon(":/icons/bullet_green.png");
|
||||||
|
|
||||||
|
|
||||||
|
case QAbstractSocket::BoundState:
|
||||||
|
case QAbstractSocket::ListeningState:
|
||||||
|
default:
|
||||||
|
return QIcon(":/icons/bullet_error.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG0("Exit PortModel data 3\n");
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Non Top Level - Port
|
||||||
|
if ((role == Qt::DisplayRole))
|
||||||
|
{
|
||||||
|
DBG0("Exit PortModel data 4\n");
|
||||||
|
if (pgl->mPortGroups.at(parent.row())->numPorts() == 0)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
return QString("Port %1: %2 [%3] (%4)").
|
||||||
|
arg(pgl->mPortGroups.at(
|
||||||
|
parent.row())->mPorts[index.row()].id()).
|
||||||
|
arg(pgl->mPortGroups.at(
|
||||||
|
parent.row())->mPorts[index.row()].name()).
|
||||||
|
arg(QHostAddress("0.0.0.0").toString()). // FIXME(LOW)
|
||||||
|
arg(pgl->mPortGroups.at(
|
||||||
|
parent.row())->mPorts[index.row()].description());
|
||||||
|
}
|
||||||
|
else if ((role == Qt::DecorationRole))
|
||||||
|
{
|
||||||
|
DBG0("Exit PortModel data 5\n");
|
||||||
|
if (pgl->mPortGroups.at(parent.row())->numPorts() == 0)
|
||||||
|
return QVariant();
|
||||||
|
return QIcon(":/icons/bullet_green.png");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG0("Exit PortModel data 6\n");
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PortModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (role != Qt::DisplayRole)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (orientation == Qt::Horizontal)
|
||||||
|
return QVariant();
|
||||||
|
else
|
||||||
|
return QString("Name");
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PortModel::index (int row, int col,
|
||||||
|
const QModelIndex & parent) const
|
||||||
|
{
|
||||||
|
if (!hasIndex(row, col, parent))
|
||||||
|
return QModelIndex();
|
||||||
|
|
||||||
|
//qDebug("index: R=%d, C=%d, PR=%d, PC=%d, PID=%llx\n",
|
||||||
|
// row, col, parent.row(), parent.column(), parent.internalId());
|
||||||
|
|
||||||
|
if (!parent.isValid())
|
||||||
|
{
|
||||||
|
// Top Level Item
|
||||||
|
quint16 pg = pgl->mPortGroups.value(row)->id(), p = 0xFFFF;
|
||||||
|
quint32 id = (pg << 16) | p;
|
||||||
|
//qDebug("index (top) dbg: PG=%d, P=%d, ID=%x\n", pg, p, id);
|
||||||
|
|
||||||
|
return createIndex(row, col, id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
quint16 pg = parent.internalId() >> 16;
|
||||||
|
quint16 p = pgl->mPortGroups.value(parent.row())->mPorts.value(row).id();
|
||||||
|
quint32 id = (pg << 16) | p;
|
||||||
|
//qDebug("index (nontop) dbg: PG=%d, P=%d, ID=%x\n", pg, p, id);
|
||||||
|
|
||||||
|
return createIndex(row, col, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PortModel::parent(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (!index.isValid())
|
||||||
|
return QModelIndex();
|
||||||
|
|
||||||
|
//qDebug("parent: R=%d, C=%d ID=%llx\n",
|
||||||
|
// index.row(), index.column(), index.internalId());
|
||||||
|
|
||||||
|
quint16 pg = index.internalId() >> 16;
|
||||||
|
quint16 p = index.internalId() & 0x0000FFFF;
|
||||||
|
|
||||||
|
//qDebug("parent dbg: PG=%d, P=%d\n", pg, p);
|
||||||
|
|
||||||
|
if (p == 0xFFFF)
|
||||||
|
{
|
||||||
|
//qDebug("parent ret: NULL\n");
|
||||||
|
// Top Level Item - PG
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 id = (pg << 16) | 0xFFFF;
|
||||||
|
//qDebug("parent ret: R=%d, C=%d, ID=%x\n", pg, 0, id);
|
||||||
|
|
||||||
|
return createIndex(pgl->indexOfPortGroup(pg), 0, id);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortModel::isPortGroup(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if ((index.internalId() & 0xFFFF) == 0xFFFF)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PortModel::isPort(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
if ((index.internalId() & 0xFFFF) != 0xFFFF)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 PortModel::portGroupId(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
return (index.internalId()) >> 16 & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
quint32 PortModel::portId(const QModelIndex& index)
|
||||||
|
{
|
||||||
|
return (index.internalId()) & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------
|
||||||
|
// Slots
|
||||||
|
// ----------------------------------------------
|
||||||
|
void PortModel::when_portGroupDataChanged(PortGroup* portGroup)
|
||||||
|
{
|
||||||
|
QModelIndex index;
|
||||||
|
|
||||||
|
if (!pgl->mPortGroups.contains(portGroup))
|
||||||
|
{
|
||||||
|
qDebug("when_portGroupDataChanged(): pg not in list - do nothing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug("when_portGroupDataChanged pgid = %d", portGroup->id());
|
||||||
|
qDebug("when_portGroupDataChanged idx = %d", pgl->mPortGroups.indexOf(portGroup));
|
||||||
|
|
||||||
|
index = createIndex(pgl->mPortGroups.indexOf(portGroup), 0,
|
||||||
|
(portGroup->id() << 16) | 0xFFFF);
|
||||||
|
emit dataChanged(index, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortModel::portGroupAboutToBeAppended()
|
||||||
|
{
|
||||||
|
int row;
|
||||||
|
|
||||||
|
row = pgl->mPortGroups.size();
|
||||||
|
beginInsertRows(QModelIndex(), row, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortModel::portGroupAppended()
|
||||||
|
{
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortModel::portGroupAboutToBeRemoved(PortGroup *portGroup)
|
||||||
|
{
|
||||||
|
int row;
|
||||||
|
|
||||||
|
row = pgl->mPortGroups.indexOf(portGroup);
|
||||||
|
beginRemoveRows(QModelIndex(), row, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortModel::portGroupRemoved()
|
||||||
|
{
|
||||||
|
endRemoveRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void PortModel::triggerLayoutAboutToBeChanged()
|
||||||
|
{
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortModel::triggerLayoutChanged()
|
||||||
|
{
|
||||||
|
emit layoutChanged();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PortModel::when_portListChanged()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
51
client/portmodel.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef _PORT_MODEL_H
|
||||||
|
#define _PORT_MODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
|
class PortGroupList;
|
||||||
|
class PortGroup;
|
||||||
|
|
||||||
|
class PortModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
friend class PortGroupList;
|
||||||
|
|
||||||
|
PortGroupList *pgl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PortModel(PortGroupList *p, QObject *parent = 0);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
QModelIndex index (int row, int col, const QModelIndex & parent = QModelIndex() ) const;
|
||||||
|
QModelIndex parent(const QModelIndex &index) const;
|
||||||
|
|
||||||
|
bool isPortGroup(const QModelIndex& index);
|
||||||
|
bool isPort(const QModelIndex& index);
|
||||||
|
quint32 portGroupId(const QModelIndex& index);
|
||||||
|
quint32 portId(const QModelIndex& index);
|
||||||
|
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void when_portGroupDataChanged(PortGroup *portGroup);
|
||||||
|
|
||||||
|
void portGroupAboutToBeAppended();
|
||||||
|
void portGroupAppended();
|
||||||
|
void portGroupAboutToBeRemoved(PortGroup *portGroup);
|
||||||
|
void portGroupRemoved();
|
||||||
|
|
||||||
|
void when_portListChanged();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void triggerLayoutAboutToBeChanged();
|
||||||
|
void triggerLayoutChanged();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
124
client/portstatsfilter.ui
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
<ui version="4.0" >
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>402</width>
|
||||||
|
<height>275</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QListView" name="lvAllPorts" />
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" >
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="tbFilterIn" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="tbFilterOut" >
|
||||||
|
<property name="text" >
|
||||||
|
<string><</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" >
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListView" name="lvFilteredPorts" />
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons" >
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>lvAllPorts</tabstop>
|
||||||
|
<tabstop>tbFilterIn</tabstop>
|
||||||
|
<tabstop>tbFilterOut</tabstop>
|
||||||
|
<tabstop>lvFilteredPorts</tabstop>
|
||||||
|
<tabstop>buttonBox</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel" >
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel" >
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel" >
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel" >
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
9
client/portstatsfilterdialog.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "portstatsfilterdialog.h"
|
||||||
|
|
||||||
|
PortStatsFilterDialog::PortStatsFilterDialog(AbstractItemModel *allPortsModel,
|
||||||
|
QWidget *parent)
|
||||||
|
{
|
||||||
|
setupUi(this);
|
||||||
|
|
||||||
|
lvAllPorts->setModel(allPortsModel);
|
||||||
|
}
|
19
client/portstatsfilterdialog.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef _PORT_STATS_FILTER_DIALOG_H
|
||||||
|
#define _PORT_STATS_FILTER_DIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include "ui_portstatsfilterdialog.h"
|
||||||
|
#include "portgrouplist.h"
|
||||||
|
|
||||||
|
class PortStatsFilterDialog : public QDialog, public Ui::PortStatsFilterDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PortStatsFilterDialog(AbstractItemModel *allPortsModel,
|
||||||
|
QWidget *parent = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
119
client/portstatsmodel.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#include "portstatsmodel.h"
|
||||||
|
#include "portgrouplist.h"
|
||||||
|
|
||||||
|
PortStatsModel::PortStatsModel(PortGroupList *p, QObject *parent)
|
||||||
|
: QAbstractTableModel(parent)
|
||||||
|
{
|
||||||
|
pgl = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortStatsModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (numPorts.isEmpty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (numPorts.last() == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (int) e_STAT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PortStatsModel::columnCount(const QModelIndex &parent ) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
if (numPorts.isEmpty())
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return numPorts.last();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PortStatsModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
int pgidx, pidx, portNum;
|
||||||
|
|
||||||
|
// Check for a valid index
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
// Check for row/column limits
|
||||||
|
if (index.row() >= e_STAT_MAX)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (numPorts.isEmpty())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (index.column() >= (numPorts.last()))
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
// TODO(LOW): Optimize using binary search: see qLowerBound()
|
||||||
|
portNum = index.column() + 1;
|
||||||
|
for (pgidx = 0; pgidx < numPorts.size(); pgidx++)
|
||||||
|
if (portNum <= numPorts.at(pgidx))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pgidx)
|
||||||
|
{
|
||||||
|
if (numPorts.at(pgidx -1))
|
||||||
|
pidx = (portNum - 1) % numPorts.at(pgidx - 1);
|
||||||
|
else
|
||||||
|
pidx = portNum - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pidx = portNum - 1;
|
||||||
|
|
||||||
|
//qDebug("PSM: %d - %d, %d", index.column(), pgidx, pidx);
|
||||||
|
|
||||||
|
// Check role
|
||||||
|
if (role == Qt::DisplayRole)
|
||||||
|
return pgl->mPortGroups.at(pgidx)->mPorts.at(pidx).mPortStats[index.row()];
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PortStatsModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (role != Qt::DisplayRole)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (orientation == Qt::Horizontal)
|
||||||
|
return QString("Port %1").arg(section);
|
||||||
|
else
|
||||||
|
return PortStatName.at(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Slots
|
||||||
|
//
|
||||||
|
void PortStatsModel::when_portListChanged()
|
||||||
|
{
|
||||||
|
int i, count = 0;
|
||||||
|
|
||||||
|
// recalc numPorts
|
||||||
|
while (numPorts.size())
|
||||||
|
numPorts.removeFirst();
|
||||||
|
|
||||||
|
for (i = 0; i < pgl->mPortGroups.size(); i++)
|
||||||
|
{
|
||||||
|
count += pgl->mPortGroups.at(i)->numPorts();
|
||||||
|
numPorts.append(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortStatsModel::on_portStatsUpdate(int port, void*stats)
|
||||||
|
{
|
||||||
|
// FIXME(MED): update only the changed port not all
|
||||||
|
QModelIndex topLeft = index(port, 0, QModelIndex());
|
||||||
|
QModelIndex bottomRight = index(port, e_STAT_MAX, QModelIndex());
|
||||||
|
|
||||||
|
emit dataChanged(topLeft, bottomRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
59
client/portstatsmodel.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#ifndef _PORT_STATS_MODEL_H
|
||||||
|
#define _PORT_STATS_MODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
e_STAT_FRAMES_RCVD = 0,
|
||||||
|
e_STAT_FRAMES_SENT,
|
||||||
|
e_STAT_FRAME_SEND_RATE,
|
||||||
|
e_STAT_FRAME_RECV_RATE,
|
||||||
|
e_STAT_BYTES_RCVD,
|
||||||
|
e_STAT_BYTES_SENT,
|
||||||
|
e_STAT_BYTE_SEND_RATE,
|
||||||
|
e_STAT_BYTE_RECV_RATE,
|
||||||
|
e_STAT_MAX
|
||||||
|
} PortStat;
|
||||||
|
|
||||||
|
static QStringList PortStatName = (QStringList()
|
||||||
|
<< "Frames Received"
|
||||||
|
<< "Frames Sent"
|
||||||
|
<< "Frame Send Rate (fps)"
|
||||||
|
<< "Frame Receive Rate (fps)"
|
||||||
|
<< "Bytes Received"
|
||||||
|
<< "Bytes Sent"
|
||||||
|
<< "Byte Send Rate (Bps)"
|
||||||
|
<< "Byte Receive Rate (Bps)"
|
||||||
|
);
|
||||||
|
|
||||||
|
class PortGroupList;
|
||||||
|
|
||||||
|
class PortStatsModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
PortGroupList *pgl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PortStatsModel(PortGroupList *p, QObject *parent = 0);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void when_portListChanged();
|
||||||
|
void on_portStatsUpdate(int port, void*stats);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// numPorts stores the num of ports per portgroup
|
||||||
|
// in the same order as the portgroups are index in the pgl
|
||||||
|
// Also it stores them as cumulative totals
|
||||||
|
QList<quint16> numPorts;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
15
client/portstatswindow.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "portstatswindow.h"
|
||||||
|
#include "portstatsmodel.h"
|
||||||
|
|
||||||
|
//PortStatsWindow::PortStatsWindow(QWidget *parent) : QDialog (parent)
|
||||||
|
PortStatsWindow::PortStatsWindow(PortGroupList *pgl, QWidget *parent)
|
||||||
|
{
|
||||||
|
setupUi(this);
|
||||||
|
|
||||||
|
tvPortStats->setModel(pgl->getPortStatsModel());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PortStatsWindow::~PortStatsWindow()
|
||||||
|
{
|
||||||
|
}
|
21
client/portstatswindow.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _PORT_STATS_WINDOW_H
|
||||||
|
#define _PORT_STATS_WINDOW_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include "ui_portstatswindow.h"
|
||||||
|
#include "portgrouplist.h"
|
||||||
|
|
||||||
|
class PortStatsWindow : public QDialog, public Ui::PortStatsWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PortStatsWindow(PortGroupList *pgl, QWidget *parent = 0);
|
||||||
|
~PortStatsWindow();
|
||||||
|
private:
|
||||||
|
QAbstractItemModel *model;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
133
client/portstatswindow.ui
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<ui version="4.0" >
|
||||||
|
<class>PortStatsWindow</class>
|
||||||
|
<widget class="QWidget" name="PortStatsWindow" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>502</width>
|
||||||
|
<height>415</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame" >
|
||||||
|
<property name="frameShape" >
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow" >
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="tbStartTransmit" >
|
||||||
|
<property name="toolTip" >
|
||||||
|
<string>Start Transmit</string>
|
||||||
|
</property>
|
||||||
|
<property name="statusTip" >
|
||||||
|
<string>Stop Transmit</string>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Start Transmit</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/control_play.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="tbStopTransmit" >
|
||||||
|
<property name="toolTip" >
|
||||||
|
<string>Stop Transmit</string>
|
||||||
|
</property>
|
||||||
|
<property name="statusTip" >
|
||||||
|
<string>Stop Transmit</string>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Stop Trasmit</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/control_stop.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="tbClear" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Clear</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="tbClearAll" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Clear All</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="tbStartCapture" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Start Capture</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/sound_none.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="tbStopCapture" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Stop Capture</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/sound_mute.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="tbViewCapture" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>View Capture</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/magnifier.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line" >
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" >
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="tvPortStats" />
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="ostinato.qrc" />
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
320
client/portswindow.cpp
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
#include "portswindow.h"
|
||||||
|
#include "streamlistmodel.h"
|
||||||
|
#include "streamconfigdialog.h"
|
||||||
|
#include <QInputDialog>
|
||||||
|
#include <QItemSelectionModel>
|
||||||
|
|
||||||
|
PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
|
||||||
|
{
|
||||||
|
//slm = new StreamListModel();
|
||||||
|
//plm = new PortGroupList();
|
||||||
|
plm = pgl;
|
||||||
|
|
||||||
|
setupUi(this);
|
||||||
|
|
||||||
|
tvPortList->addAction(actionNew_Port_Group);
|
||||||
|
tvPortList->addAction(actionDelete_Port_Group);
|
||||||
|
tvPortList->addAction(actionConnect_Port_Group);
|
||||||
|
tvPortList->addAction(actionDisconnect_Port_Group);
|
||||||
|
|
||||||
|
tvStreamList->addAction(actionNew_Stream);
|
||||||
|
tvStreamList->addAction(actionDelete_Stream);
|
||||||
|
|
||||||
|
tvStreamList->setModel(plm->getStreamModel());
|
||||||
|
tvPortList->setModel(plm->getPortModel());
|
||||||
|
|
||||||
|
connect( plm->getPortModel(),
|
||||||
|
SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||||
|
this, SLOT(when_portModel_dataChanged(const QModelIndex&,
|
||||||
|
const QModelIndex&)));
|
||||||
|
connect( tvPortList->selectionModel(),
|
||||||
|
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
||||||
|
this, SLOT(when_portView_currentChanged(const QModelIndex&,
|
||||||
|
const QModelIndex&)));
|
||||||
|
connect( tvStreamList->selectionModel(),
|
||||||
|
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
||||||
|
this, SLOT(when_streamView_currentChanged(const QModelIndex&,
|
||||||
|
const QModelIndex&)));
|
||||||
|
connect( tvStreamList->selectionModel(),
|
||||||
|
SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||||
|
this, SLOT(when_streamView_selectionChanged()));
|
||||||
|
connect( tvPortList->selectionModel(),
|
||||||
|
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
||||||
|
plm->getStreamModel(), SLOT(setCurrentPortIndex(const QModelIndex&)));
|
||||||
|
}
|
||||||
|
|
||||||
|
PortsWindow::~PortsWindow()
|
||||||
|
{
|
||||||
|
delete plm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_tvStreamList_activated(const QModelIndex & index)
|
||||||
|
{
|
||||||
|
StreamConfigDialog *scd;
|
||||||
|
|
||||||
|
if (!index.isValid())
|
||||||
|
{
|
||||||
|
qDebug("%s: invalid index", __FUNCTION__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// FIXME(MED): This way of passing params must be changed
|
||||||
|
scd = new StreamConfigDialog(plm->getStreamModel()->currentPortStreamList(),
|
||||||
|
(uint) index.row(), this);
|
||||||
|
qDebug("stream list activated\n");
|
||||||
|
scd->exec(); // TODO: chk retval
|
||||||
|
delete scd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::when_portView_currentChanged(const QModelIndex& current,
|
||||||
|
const QModelIndex& previous)
|
||||||
|
{
|
||||||
|
updatePortViewActions(current);
|
||||||
|
|
||||||
|
if (!current.isValid())
|
||||||
|
{
|
||||||
|
qDebug("setting stacked widget to blank page");
|
||||||
|
swDetail->setCurrentIndex(2); // blank page
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (plm->isPortGroup(current))
|
||||||
|
{
|
||||||
|
swDetail->setCurrentIndex(1); // portGroup detail page
|
||||||
|
}
|
||||||
|
else if (plm->isPort(current))
|
||||||
|
{
|
||||||
|
swDetail->setCurrentIndex(0); // port detail page
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::when_streamView_currentChanged(const QModelIndex& current,
|
||||||
|
const QModelIndex& previous)
|
||||||
|
{
|
||||||
|
qDebug("stream view current changed");
|
||||||
|
updateStreamViewActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::when_streamView_selectionChanged()
|
||||||
|
{
|
||||||
|
qDebug("stream view selection changed");
|
||||||
|
updateStreamViewActions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::when_portModel_dataChanged(const QModelIndex& topLeft,
|
||||||
|
const QModelIndex& bottomRight)
|
||||||
|
{
|
||||||
|
#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))
|
||||||
|
{
|
||||||
|
updatePortViewActions(tvPortList->currentIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void PortsWindow::updateStreamViewActions(const QModelIndex& current)
|
||||||
|
{
|
||||||
|
if (current.isValid())
|
||||||
|
actionDelete_Stream->setEnabled(true);
|
||||||
|
else
|
||||||
|
actionDelete_Stream->setDisabled(true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PortsWindow::updateStreamViewActions()
|
||||||
|
{
|
||||||
|
if (tvStreamList->selectionModel()->hasSelection())
|
||||||
|
{
|
||||||
|
qDebug("Has selection %d",
|
||||||
|
tvStreamList->selectionModel()->selection().size());
|
||||||
|
// If more than one non-contiguous ranges selected, disable "New"
|
||||||
|
if (tvStreamList->selectionModel()->selection().size() > 1)
|
||||||
|
actionNew_Stream->setDisabled(true);
|
||||||
|
else
|
||||||
|
actionNew_Stream->setEnabled(true);
|
||||||
|
|
||||||
|
// Delete is always enabled as long as we have a selection
|
||||||
|
actionDelete_Stream->setEnabled(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("No selection");
|
||||||
|
actionNew_Stream->setEnabled(true);
|
||||||
|
actionDelete_Stream->setDisabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::updatePortViewActions(const QModelIndex& current)
|
||||||
|
{
|
||||||
|
if (!current.isValid())
|
||||||
|
{
|
||||||
|
qDebug("current is now invalid");
|
||||||
|
actionDelete_Port_Group->setDisabled(true);
|
||||||
|
actionConnect_Port_Group->setDisabled(true);
|
||||||
|
actionDisconnect_Port_Group->setDisabled(true);
|
||||||
|
|
||||||
|
goto _EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug("currentChanged %llx", current.internalId());
|
||||||
|
|
||||||
|
if (plm->isPortGroup(current))
|
||||||
|
{
|
||||||
|
actionDelete_Port_Group->setEnabled(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->setEnabled(false);
|
||||||
|
actionConnect_Port_Group->setEnabled(false);
|
||||||
|
actionDisconnect_Port_Group->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
_EXIT:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_pbApply_clicked()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
// 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionNew_Port_Group_triggered()
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
QString text = QInputDialog::getText(this,
|
||||||
|
"Add Port Group", "Port Group Address (IP[:Port])",
|
||||||
|
QLineEdit::Normal, lastNewPortGroup, &ok);
|
||||||
|
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
QStringList addr = text.split(":");
|
||||||
|
if (addr.size() == 1) // Port unspecified
|
||||||
|
addr.append(QString().setNum(DEFAULT_SERVER_PORT));
|
||||||
|
PortGroup *pg = new PortGroup(QHostAddress(addr[0]),addr[1].toUShort());
|
||||||
|
plm->addPortGroup(*pg);
|
||||||
|
lastNewPortGroup = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionDelete_Port_Group_triggered()
|
||||||
|
{
|
||||||
|
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||||
|
|
||||||
|
if (current.isValid())
|
||||||
|
plm->removePortGroup(plm->portGroup(current));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionConnect_Port_Group_triggered()
|
||||||
|
{
|
||||||
|
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||||
|
|
||||||
|
if (current.isValid())
|
||||||
|
plm->portGroup(current).connectToHost();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionDisconnect_Port_Group_triggered()
|
||||||
|
{
|
||||||
|
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||||
|
|
||||||
|
if (current.isValid())
|
||||||
|
plm->portGroup(current).disconnectFromHost();
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
void PortsWindow::on_actionNew_Stream_triggered()
|
||||||
|
{
|
||||||
|
qDebug("New Stream Action");
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
if (tvStreamList->currentIndex().isValid())
|
||||||
|
row = tvStreamList->currentIndex().row();
|
||||||
|
plm->getStreamModel()->insertRows(row, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PortsWindow::on_actionDelete_Stream_triggered()
|
||||||
|
{
|
||||||
|
qDebug("Delete Stream Action");
|
||||||
|
if (tvStreamList->currentIndex().isValid())
|
||||||
|
plm->getStreamModel()->removeRows(tvStreamList->currentIndex().row(), 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PortsWindow::on_actionNew_Stream_triggered()
|
||||||
|
{
|
||||||
|
qDebug("New Stream Action");
|
||||||
|
|
||||||
|
// In case nothing is selected, insert 1 row at the top
|
||||||
|
int row = 0, 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 (tvStreamList->selectionModel()->selection().size() == 1)
|
||||||
|
{
|
||||||
|
row = tvStreamList->selectionModel()->selection().at(0).top();
|
||||||
|
count = tvStreamList->selectionModel()->selection().at(0).height();
|
||||||
|
}
|
||||||
|
|
||||||
|
plm->getStreamModel()->insertRows(row, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
56
client/portswindow.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#ifndef _PORTS_WINDOW_H
|
||||||
|
#define _PORTS_WINDOW_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include "ui_portswindow.h"
|
||||||
|
#include "portgrouplist.h"
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
HIGH
|
||||||
|
MED
|
||||||
|
LOW
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
class PortsWindow : public QWidget, private Ui::PortsWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
//QAbstractItemModel *slm; // stream list model
|
||||||
|
PortGroupList *plm;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PortsWindow(PortGroupList *pgl, QWidget *parent = 0);
|
||||||
|
~PortsWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString lastNewPortGroup;
|
||||||
|
|
||||||
|
void updatePortViewActions(const QModelIndex& current);
|
||||||
|
//void updateStreamViewActions(const QModelIndex& current);
|
||||||
|
void updateStreamViewActions();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_tvStreamList_activated(const QModelIndex & index);
|
||||||
|
void when_portView_currentChanged(const QModelIndex& current,
|
||||||
|
const QModelIndex& previous);
|
||||||
|
void when_streamView_currentChanged(const QModelIndex& current,
|
||||||
|
const QModelIndex& previous);
|
||||||
|
void when_streamView_selectionChanged();
|
||||||
|
void when_portModel_dataChanged(const QModelIndex& topLeft,
|
||||||
|
const QModelIndex& bottomRight);
|
||||||
|
|
||||||
|
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_actionNew_Stream_triggered();
|
||||||
|
void on_actionDelete_Stream_triggered();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
214
client/portswindow.ui
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
<ui version="4.0" >
|
||||||
|
<class>PortsWindow</class>
|
||||||
|
<widget class="QWidget" name="PortsWindow" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>689</width>
|
||||||
|
<height>320</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QSplitter" name="splitter" >
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<widget class="QTreeView" name="tvPortList" >
|
||||||
|
<property name="contextMenuPolicy" >
|
||||||
|
<enum>Qt::ActionsContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode" >
|
||||||
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStackedWidget" name="swDetail" >
|
||||||
|
<property name="currentIndex" >
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="portDetail" >
|
||||||
|
<layout class="QVBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" >
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pbApply" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Apply</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" >
|
||||||
|
<item rowspan="2" row="0" column="0" >
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" >
|
||||||
|
<size>
|
||||||
|
<width>31</width>
|
||||||
|
<height>41</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1" >
|
||||||
|
<widget class="QLabel" name="label" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Capacity</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2" >
|
||||||
|
<widget class="QLineEdit" name="lineEdit_3" />
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3" >
|
||||||
|
<widget class="QLabel" name="label_3" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Aggr fps</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="4" >
|
||||||
|
<widget class="QLineEdit" name="lineEdit" />
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1" >
|
||||||
|
<widget class="QLabel" name="label_2" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>% age</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2" >
|
||||||
|
<widget class="QLineEdit" name="lineEdit_4" />
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3" >
|
||||||
|
<widget class="QLabel" name="label_4" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Aggr bps</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="4" >
|
||||||
|
<widget class="QLineEdit" name="lineEdit_2" />
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="tabWidget" >
|
||||||
|
<property name="currentIndex" >
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tab_3" >
|
||||||
|
<attribute name="title" >
|
||||||
|
<string>Control</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="tvStreamList" >
|
||||||
|
<property name="contextMenuPolicy" >
|
||||||
|
<enum>Qt::ActionsContextMenu</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode" >
|
||||||
|
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior" >
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="portGroupDetail" >
|
||||||
|
<layout class="QHBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_5" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Port Group Detail</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="blankPage" />
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
<action name="actionNew_Port_Group" >
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/portgroup_add.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>New Port Group</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDelete_Port_Group" >
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/portgroup_delete.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Delete Port Group</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionConnect_Port_Group" >
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/portgroup_connect.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Connect Port Group</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDisconnect_Port_Group" >
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/portgroup_disconnect.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Disconnect Port Group</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionNew_Stream" >
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/stream_add.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>New Stream</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionDelete_Stream" >
|
||||||
|
<property name="icon" >
|
||||||
|
<iconset resource="ostinato.qrc" >:/icons/stream_delete.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>Delete Stream</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="ostinato.qrc" />
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
123
client/stream.cpp
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
#include <stream.h>
|
||||||
|
|
||||||
|
Stream::Stream()
|
||||||
|
{
|
||||||
|
// Default constructor
|
||||||
|
InitDefaultMeta();
|
||||||
|
InitDefaultProto();
|
||||||
|
InitDefaultL2();
|
||||||
|
InitDefaultL3();
|
||||||
|
InitDefaultL4();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::InitDefaultMeta()
|
||||||
|
{
|
||||||
|
// TODO(LOW): Use #defines
|
||||||
|
meta.patternMode = e_dp_fixed;
|
||||||
|
meta.pattern = 0x00000000;
|
||||||
|
meta.dataStartOfs = 0; // FIXME(HIGH): this has to calculated
|
||||||
|
meta.lenMode = e_fl_fixed;
|
||||||
|
meta.frameLen = 64;
|
||||||
|
meta.frameLenMin = 64;
|
||||||
|
meta.frameLenMax = 1518;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::InitDefaultProto()
|
||||||
|
{
|
||||||
|
// TODO(LOW): Use #defines
|
||||||
|
proto.ft = e_ft_eth_2;
|
||||||
|
proto.dsap = 0x00;
|
||||||
|
proto.ssap = 0x00;
|
||||||
|
proto.ctl = 0x00;
|
||||||
|
proto.ouiMsb = 0x00;
|
||||||
|
proto.ouiLshw = 0x0000;
|
||||||
|
|
||||||
|
proto.protoMask = PM_L3_PROTO_NONE | PM_L4_PROTO_NONE;
|
||||||
|
proto.etherType = ETH_TYP_IP;
|
||||||
|
proto.ipProto = IP_PROTO_TCP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Stream::InitDefaultL2()
|
||||||
|
{
|
||||||
|
// TODO(LOW): Use #defines
|
||||||
|
l2.eth.dstMacMshw = 0x0000;
|
||||||
|
l2.eth.dstMacLsw = 0x00000001;
|
||||||
|
l2.eth.dstMacMode = e_mm_fixed;
|
||||||
|
l2.eth.dstMacCount = 16;
|
||||||
|
l2.eth.dstMacStep = 1;
|
||||||
|
|
||||||
|
l2.eth.srcMacMshw = 0x0000;
|
||||||
|
l2.eth.srcMacLsw = 0x00000002;
|
||||||
|
l2.eth.srcMacMode = e_mm_fixed;
|
||||||
|
l2.eth.srcMacCount = 16;
|
||||||
|
l2.eth.srcMacStep = 1;
|
||||||
|
|
||||||
|
l2.eth.vlanMask = VM_UNTAGGED;
|
||||||
|
l2.eth.ctpid = 0x8100;
|
||||||
|
l2.eth.cvlanPrio = 0;
|
||||||
|
l2.eth.cvlanCfi = 0;
|
||||||
|
l2.eth.cvlanId = 2;
|
||||||
|
l2.eth.stpid = 0x88a8;
|
||||||
|
l2.eth.svlanPrio = 0;
|
||||||
|
l2.eth.svlanCfi = 0;
|
||||||
|
l2.eth.svlanId = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::InitDefaultL3()
|
||||||
|
{
|
||||||
|
InitDefaultL3Ip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::InitDefaultL3Ip()
|
||||||
|
{
|
||||||
|
l3.ip.ipMask = STREAM_DEF_IP_MASK;
|
||||||
|
l3.ip.ver = STREAM_DEF_L3_IP_VER;
|
||||||
|
l3.ip.hdrLen = STREAM_DEF_L3_IP_HDR_LEN;
|
||||||
|
l3.ip.tos = STREAM_DEF_L3_IP_TOS;
|
||||||
|
l3.ip.totLen = STREAM_DEF_L3_IP_TOT_LEN;
|
||||||
|
l3.ip.id = STREAM_DEF_L3_IP_ID;
|
||||||
|
l3.ip.flags = STREAM_DEF_L3_IP_FLAGS;
|
||||||
|
l3.ip.fragOfs = STREAM_DEF_L3_IP_FRAG_OFS;
|
||||||
|
l3.ip.ttl = STREAM_DEF_L3_IP_TTL;
|
||||||
|
l3.ip.proto = STREAM_DEF_L3_IP_PROTO;
|
||||||
|
l3.ip.cksum = STREAM_DEF_L3_IP_CKSUM;
|
||||||
|
l3.ip.srcIp = STREAM_DEF_L3_IP_SRC_IP;
|
||||||
|
l3.ip.srcIpMode = STREAM_DEF_L3_IP_SRC_IP_MODE;
|
||||||
|
l3.ip.srcIpCount = STREAM_DEF_L3_IP_SRC_IP_COUNT;
|
||||||
|
l3.ip.srcIpMask = STREAM_DEF_L3_IP_SRC_IP_MASK;
|
||||||
|
l3.ip.dstIp = STREAM_DEF_L3_IP_DST_IP;
|
||||||
|
l3.ip.dstIpMode = STREAM_DEF_L3_IP_DST_IP_MODE;
|
||||||
|
l3.ip.dstIpCount = STREAM_DEF_L3_IP_DST_IP_COUNT;
|
||||||
|
l3.ip.dstIpMask = STREAM_DEF_L3_IP_DST_IP_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::InitDefaultL4()
|
||||||
|
{
|
||||||
|
InitDefaultL4Tcp();
|
||||||
|
InitDefaultL4Udp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::InitDefaultL4Tcp()
|
||||||
|
{
|
||||||
|
l4.tcp.tcpMask = STREAM_DEF_L4_TCP_TCP_MASK;
|
||||||
|
l4.tcp.srcPort = STREAM_DEF_L4_TCP_SRC_PORT;
|
||||||
|
l4.tcp.dstPort = STREAM_DEF_L4_TCP_DST_PORT;
|
||||||
|
l4.tcp.seqNum = STREAM_DEF_L4_TCP_SEQ_NUM;
|
||||||
|
l4.tcp.ackNum = STREAM_DEF_L4_TCP_ACK_NUM;
|
||||||
|
l4.tcp.hdrLen = STREAM_DEF_L4_TCP_HDR_LEN;
|
||||||
|
l4.tcp.rsvd = STREAM_DEF_L4_TCP_RSVD;
|
||||||
|
l4.tcp.flags = STREAM_DEF_L4_TCP_FLAGS;
|
||||||
|
l4.tcp.window = STREAM_DEF_L4_TCP_WINDOW;
|
||||||
|
l4.tcp.cksum = STREAM_DEF_L4_TCP_CKSUM;
|
||||||
|
l4.tcp.urgPtr = STREAM_DEF_L4_TCP_URG_PTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stream::InitDefaultL4Udp()
|
||||||
|
{
|
||||||
|
l4.udp.udpMask = STREAM_DEF_L4_UDP_UDP_MASK;
|
||||||
|
l4.udp.srcPort = STREAM_DEF_L4_UDP_SRC_PORT;
|
||||||
|
l4.udp.dstPort = STREAM_DEF_L4_UDP_DST_PORT;
|
||||||
|
l4.udp.totLen = STREAM_DEF_L4_UDP_TOT_LEN;
|
||||||
|
l4.udp.cksum = STREAM_DEF_L4_UDP_CKSUM;
|
||||||
|
}
|
307
client/stream.h
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
#ifndef _STREAM_H
|
||||||
|
#define _STREAM_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class StreamConfigDialog;
|
||||||
|
class StreamModel;
|
||||||
|
|
||||||
|
class Stream {
|
||||||
|
|
||||||
|
friend class StreamConfigDialog;
|
||||||
|
friend class StreamModel;
|
||||||
|
|
||||||
|
enum FrameType {
|
||||||
|
e_ft_none,
|
||||||
|
e_ft_eth_2,
|
||||||
|
e_ft_802_3_raw,
|
||||||
|
e_ft_802_3_llc,
|
||||||
|
e_ft_snap
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DataPatternMode {
|
||||||
|
e_dp_fixed,
|
||||||
|
e_dp_inc,
|
||||||
|
e_dp_dec,
|
||||||
|
e_dp_random
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FrameLengthMode {
|
||||||
|
e_fl_fixed,
|
||||||
|
e_fl_inc,
|
||||||
|
e_fl_dec,
|
||||||
|
e_fl_random
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MacAddrMode {
|
||||||
|
e_mm_fixed,
|
||||||
|
e_mm_inc,
|
||||||
|
e_mm_dec,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum IpAddrMode {
|
||||||
|
e_im_fixed,
|
||||||
|
e_im_inc_host,
|
||||||
|
e_im_dec_host,
|
||||||
|
e_im_random_host
|
||||||
|
};
|
||||||
|
|
||||||
|
// Meta Data
|
||||||
|
struct {
|
||||||
|
// Data Pattern
|
||||||
|
DataPatternMode patternMode;
|
||||||
|
quint32 pattern;
|
||||||
|
quint16 dataStartOfs;
|
||||||
|
|
||||||
|
// Frame Length (includes CRC)
|
||||||
|
FrameLengthMode lenMode;
|
||||||
|
quint16 frameLen;
|
||||||
|
quint16 frameLenMin;
|
||||||
|
quint16 frameLenMax;
|
||||||
|
} meta;
|
||||||
|
|
||||||
|
// Protocols
|
||||||
|
struct {
|
||||||
|
FrameType ft;
|
||||||
|
|
||||||
|
quint8 dsap;
|
||||||
|
quint8 ssap;
|
||||||
|
quint8 ctl;
|
||||||
|
quint8 ouiMsb;
|
||||||
|
quint16 ouiLshw;
|
||||||
|
|
||||||
|
quint16 protoMask;
|
||||||
|
#define PM_L3_PROTO_NONE 0x0001
|
||||||
|
#define PM_L3_PROTO_OTHER 0x0002
|
||||||
|
#define PM_L4_PROTO_NONE 0x0004
|
||||||
|
#define PM_L4_PROTO_OTHER 0x0008
|
||||||
|
|
||||||
|
quint16 etherType;
|
||||||
|
#define ETH_TYP_IP 0x0800
|
||||||
|
#define ETH_TYP_ARP 0x0806
|
||||||
|
|
||||||
|
quint16 ipProto;
|
||||||
|
#define IP_PROTO_ICMP 0x01
|
||||||
|
#define IP_PROTO_IGMP 0x02
|
||||||
|
#define IP_PROTO_TCP 0x06
|
||||||
|
#define IP_PROTO_UDP 0x11
|
||||||
|
} proto;
|
||||||
|
|
||||||
|
// L2
|
||||||
|
struct {
|
||||||
|
// Ethernet
|
||||||
|
struct {
|
||||||
|
// Dst Mac
|
||||||
|
quint16 dstMacMshw;
|
||||||
|
quint32 dstMacLsw;
|
||||||
|
MacAddrMode dstMacMode;
|
||||||
|
quint16 dstMacCount;
|
||||||
|
quint16 dstMacStep;
|
||||||
|
|
||||||
|
// srcMac
|
||||||
|
quint16 srcMacMshw;
|
||||||
|
quint32 srcMacLsw;
|
||||||
|
MacAddrMode srcMacMode;
|
||||||
|
quint16 srcMacCount;
|
||||||
|
quint16 srcMacStep;
|
||||||
|
|
||||||
|
|
||||||
|
quint16 vlanMask;
|
||||||
|
#define VM_UNTAGGED 0x0000
|
||||||
|
#define VM_CVLAN_TAGGED 0x0001
|
||||||
|
#define VM_CVLAN_TPID_OVERRIDE 0x0002
|
||||||
|
#define VM_SVLAN_TAGGED 0x0100
|
||||||
|
#define VM_SVLAN_TPID_OVERRIDE 0x0200
|
||||||
|
|
||||||
|
quint16 ctpid;
|
||||||
|
quint16 cvlanPrio : 3;
|
||||||
|
quint16 cvlanCfi : 1;
|
||||||
|
quint16 cvlanId : 13;
|
||||||
|
quint16 stpid;
|
||||||
|
quint16 svlanPrio : 3;
|
||||||
|
quint16 svlanCfi : 1;
|
||||||
|
quint16 svlanId : 13;
|
||||||
|
} eth;
|
||||||
|
} l2;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
// IP
|
||||||
|
struct {
|
||||||
|
quint8 ipMask;
|
||||||
|
#define IM_OVERRIDE_VERSION 0x01
|
||||||
|
#define IM_OVERRIDE_HDRLEN 0x02
|
||||||
|
#define IM_OVERRIDE_TOTLEN 0x04
|
||||||
|
#define IM_OVERRIDE_CKSUM 0x08
|
||||||
|
#define STREAM_DEF_IP_MASK 0x00
|
||||||
|
|
||||||
|
quint8 ver : 4;
|
||||||
|
#define STREAM_DEF_L3_IP_VER 0x4
|
||||||
|
|
||||||
|
quint8 hdrLen : 4;
|
||||||
|
#define STREAM_DEF_L3_IP_HDR_LEN 0x5
|
||||||
|
|
||||||
|
quint8 tos;
|
||||||
|
#define STREAM_DEF_L3_IP_TOS 0x00
|
||||||
|
|
||||||
|
quint16 totLen;
|
||||||
|
#define STREAM_DEF_L3_IP_TOT_LEN 0x00
|
||||||
|
|
||||||
|
quint16 id;
|
||||||
|
#define STREAM_DEF_L3_IP_ID 0x1234
|
||||||
|
|
||||||
|
quint16 flags : 3;
|
||||||
|
#define IP_FLAG_UNUSED 0x1
|
||||||
|
#define IP_FLAG_DF 0x2
|
||||||
|
#define IP_FLAG_MF 0x4
|
||||||
|
#define STREAM_DEF_L3_IP_FLAGS 0x00
|
||||||
|
|
||||||
|
quint16 fragOfs : 13;
|
||||||
|
#define STREAM_DEF_L3_IP_FRAG_OFS 0x0000
|
||||||
|
|
||||||
|
quint8 ttl;
|
||||||
|
#define STREAM_DEF_L3_IP_TTL 0x7F
|
||||||
|
|
||||||
|
quint8 proto;
|
||||||
|
#define STREAM_DEF_L3_IP_PROTO 0x00
|
||||||
|
|
||||||
|
quint16 cksum;
|
||||||
|
#define STREAM_DEF_L3_IP_CKSUM 0x0000
|
||||||
|
|
||||||
|
// Source IP
|
||||||
|
quint32 srcIp;
|
||||||
|
#define STREAM_DEF_L3_IP_SRC_IP 0x02020202
|
||||||
|
|
||||||
|
IpAddrMode srcIpMode;
|
||||||
|
#define STREAM_DEF_L3_IP_SRC_IP_MODE e_im_fixed
|
||||||
|
|
||||||
|
quint16 srcIpCount;
|
||||||
|
#define STREAM_DEF_L3_IP_SRC_IP_COUNT 16
|
||||||
|
|
||||||
|
quint32 srcIpMask;
|
||||||
|
#define STREAM_DEF_L3_IP_SRC_IP_MASK 0xFFFFFFFF
|
||||||
|
|
||||||
|
// Destination IP
|
||||||
|
quint32 dstIp;
|
||||||
|
#define STREAM_DEF_L3_IP_DST_IP 0x01010101
|
||||||
|
|
||||||
|
IpAddrMode dstIpMode;
|
||||||
|
#define STREAM_DEF_L3_IP_DST_IP_MODE e_im_fixed
|
||||||
|
|
||||||
|
quint16 dstIpCount;
|
||||||
|
#define STREAM_DEF_L3_IP_DST_IP_COUNT 16
|
||||||
|
|
||||||
|
quint32 dstIpMask;
|
||||||
|
#define STREAM_DEF_L3_IP_DST_IP_MASK 0xFFFFFFFF
|
||||||
|
|
||||||
|
// TODO: Options
|
||||||
|
} ip;
|
||||||
|
|
||||||
|
// TODO: ARP
|
||||||
|
struct {
|
||||||
|
} arp;
|
||||||
|
} l3;
|
||||||
|
|
||||||
|
// L4
|
||||||
|
struct {
|
||||||
|
// TCP
|
||||||
|
struct {
|
||||||
|
quint32 tcpMask;
|
||||||
|
#define TM_OVERRIDE_HDRLEN 0x1
|
||||||
|
#define TM_OVERRIDE_CKSUM 0x2
|
||||||
|
#define STREAM_DEF_L4_TCP_TCP_MASK 0x00;
|
||||||
|
|
||||||
|
quint16 srcPort;
|
||||||
|
#define STREAM_DEF_L4_TCP_SRC_PORT 8902;
|
||||||
|
|
||||||
|
quint16 dstPort;
|
||||||
|
#define STREAM_DEF_L4_TCP_DST_PORT 80
|
||||||
|
|
||||||
|
quint32 seqNum;
|
||||||
|
#define STREAM_DEF_L4_TCP_SEQ_NUM 129018
|
||||||
|
|
||||||
|
quint32 ackNum;
|
||||||
|
#define STREAM_DEF_L4_TCP_ACK_NUM 98223
|
||||||
|
|
||||||
|
quint8 hdrLen : 4;
|
||||||
|
#define STREAM_DEF_L4_TCP_HDR_LEN 0x5
|
||||||
|
|
||||||
|
quint8 rsvd : 4;
|
||||||
|
#define STREAM_DEF_L4_TCP_RSVD 0x0
|
||||||
|
|
||||||
|
quint8 flags;
|
||||||
|
#define TCP_FLAG_URG 0x01
|
||||||
|
#define TCP_FLAG_ACK 0x02
|
||||||
|
#define TCP_FLAG_PSH 0x04
|
||||||
|
#define TCP_FLAG_RST 0x08
|
||||||
|
#define TCP_FLAG_SYN 0x10
|
||||||
|
#define TCP_FLAG_FIN 0x20
|
||||||
|
#define STREAM_DEF_L4_TCP_FLAGS 0x00
|
||||||
|
|
||||||
|
|
||||||
|
quint16 window;
|
||||||
|
#define STREAM_DEF_L4_TCP_WINDOW 1024
|
||||||
|
|
||||||
|
quint16 cksum;
|
||||||
|
#define STREAM_DEF_L4_TCP_CKSUM 0x0000
|
||||||
|
|
||||||
|
quint16 urgPtr;
|
||||||
|
#define STREAM_DEF_L4_TCP_URG_PTR 0x0000
|
||||||
|
} tcp;
|
||||||
|
|
||||||
|
// UDP
|
||||||
|
struct {
|
||||||
|
quint32 udpMask;
|
||||||
|
#define UM_OVERRIDE_TOTLEN 0x01
|
||||||
|
#define UM_OVERRIDE_CKSUM 0x02
|
||||||
|
#define STREAM_DEF_L4_UDP_UDP_MASK 0x00
|
||||||
|
|
||||||
|
quint16 srcPort;
|
||||||
|
#define STREAM_DEF_L4_UDP_SRC_PORT 8902
|
||||||
|
|
||||||
|
quint16 dstPort;
|
||||||
|
#define STREAM_DEF_L4_UDP_DST_PORT 80
|
||||||
|
|
||||||
|
quint16 totLen;
|
||||||
|
#define STREAM_DEF_L4_UDP_TOT_LEN 0x0000
|
||||||
|
|
||||||
|
quint16 cksum;
|
||||||
|
#define STREAM_DEF_L4_UDP_CKSUM 0x0000
|
||||||
|
} udp;
|
||||||
|
|
||||||
|
// TODO: ICMP
|
||||||
|
struct {
|
||||||
|
} icmp;
|
||||||
|
|
||||||
|
// TODO: IGMP
|
||||||
|
struct {
|
||||||
|
} igmp;
|
||||||
|
} l4;
|
||||||
|
|
||||||
|
QString mName;
|
||||||
|
bool mIsEnabled;
|
||||||
|
|
||||||
|
// -------------------------------------------------------
|
||||||
|
// Methods
|
||||||
|
// -------------------------------------------------------
|
||||||
|
public:
|
||||||
|
Stream();
|
||||||
|
int enable(bool flag);
|
||||||
|
const QString& name() const { return mName; }
|
||||||
|
bool isEnabled() const { return mIsEnabled; }
|
||||||
|
|
||||||
|
void setName(QString name) { mName = name; }
|
||||||
|
void setEnabled(bool isEnabled) { mIsEnabled = isEnabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitDefaultMeta();
|
||||||
|
void InitDefaultProto();
|
||||||
|
void InitDefaultL2();
|
||||||
|
void InitDefaultL3();
|
||||||
|
void InitDefaultL3Ip();
|
||||||
|
void InitDefaultL4();
|
||||||
|
void InitDefaultL4Tcp();
|
||||||
|
void InitDefaultL4Udp();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
677
client/streamconfigdialog.cpp
Normal file
@ -0,0 +1,677 @@
|
|||||||
|
#include <QHostAddress>
|
||||||
|
#include "streamconfigdialog.h"
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
StreamConfigDialog::StreamConfigDialog(QList<Stream> *streamList,
|
||||||
|
uint streamIndex, QWidget *parent) : QDialog (parent)
|
||||||
|
{
|
||||||
|
setupUi(this);
|
||||||
|
setupUiExtra();
|
||||||
|
|
||||||
|
// FIXME(MED): Assumption that streamlist and streamIndex are valid
|
||||||
|
mpStreamList = streamList;
|
||||||
|
mCurrentStreamIndex = streamIndex;
|
||||||
|
LoadCurrentStream();
|
||||||
|
|
||||||
|
qDebug("stream %p %d/%d loaded",
|
||||||
|
mpStreamList, mCurrentStreamIndex, mpStreamList->size());
|
||||||
|
|
||||||
|
// FIXME(MED): Enable this navigation
|
||||||
|
#if 0
|
||||||
|
pbPrev->setDisabled((currStreamIdx == 0));
|
||||||
|
pbNext->setDisabled((currStreamIdx == 2));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::setupUiExtra()
|
||||||
|
{
|
||||||
|
QRegExp reHex2B("[0-9,a-f,A-F]{1,4}");
|
||||||
|
QRegExp reHex4B("[0-9,a-f,A-F]{1,8}");
|
||||||
|
QRegExp reMac("([0-9,a-f,A-F]{2,2}[:-]){5,5}[0-9,a-f,A-F]{2,2}");
|
||||||
|
|
||||||
|
// Setup default stuff that cannot be done in designer
|
||||||
|
twProto->setTabEnabled(2, FALSE);
|
||||||
|
twProto->setTabEnabled(3, FALSE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Setup Validators
|
||||||
|
*/
|
||||||
|
// Meta Data
|
||||||
|
lePktLen->setValidator(new QIntValidator(MIN_PKT_LEN, MAX_PKT_LEN, this));
|
||||||
|
|
||||||
|
// L2 Ethernet
|
||||||
|
leDstMac->setValidator(new QRegExpValidator(reMac, this));
|
||||||
|
leSrcMac->setValidator(new QRegExpValidator(reMac, this));
|
||||||
|
leDstMacCount->setValidator(new QIntValidator(1, MAX_MAC_ITER_COUNT, this));
|
||||||
|
leSrcMacCount->setValidator(new QIntValidator(1, MAX_MAC_ITER_COUNT, this));
|
||||||
|
leCvlanTpid->setValidator(new QRegExpValidator(reHex2B, this));
|
||||||
|
leSvlanTpid->setValidator(new QRegExpValidator(reHex2B, this));
|
||||||
|
//leEtherType->setValidator(new QRegExpValidator(reHex2B, this));
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Setup Connections
|
||||||
|
*/
|
||||||
|
connect(rbSendPackets, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(update_NumPacketsAndNumBursts()));
|
||||||
|
connect(rbSendBursts, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(update_NumPacketsAndNumBursts()));
|
||||||
|
connect(rbModeFixed, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(update_NumPacketsAndNumBursts()));
|
||||||
|
connect(rbModeContinuous, SIGNAL(toggled(bool)),
|
||||||
|
this, SLOT(update_NumPacketsAndNumBursts()));
|
||||||
|
|
||||||
|
// Show "Packet Config" page by default
|
||||||
|
twTopLevel->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamConfigDialog::~StreamConfigDialog()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_cmbDstMacMode_currentIndexChanged(QString mode)
|
||||||
|
{
|
||||||
|
if (mode == "Fixed")
|
||||||
|
leDstMacCount->setEnabled(FALSE);
|
||||||
|
else
|
||||||
|
leDstMacCount->setEnabled(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_pbPrev_clicked()
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
StoreCurrentStream(currStreamIdx);
|
||||||
|
currStreamIdx--;
|
||||||
|
LoadCurrentStream(currStreamIdx);
|
||||||
|
|
||||||
|
pbPrev->setDisabled((currStreamIdx == 0));
|
||||||
|
pbNext->setDisabled((currStreamIdx == 2));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_pbNext_clicked()
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
StoreCurrentStream(currStreamIdx);
|
||||||
|
currStreamIdx++;
|
||||||
|
LoadCurrentStream(currStreamIdx);
|
||||||
|
|
||||||
|
pbPrev->setDisabled((currStreamIdx == 0));
|
||||||
|
pbNext->setDisabled((currStreamIdx == 2));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_rbFtLlcSnap_toggled(bool checked)
|
||||||
|
{
|
||||||
|
if (checked)
|
||||||
|
{
|
||||||
|
leDsap->setText("AA");
|
||||||
|
leSsap->setText("AA");
|
||||||
|
leControl->setText("03");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_rbL3Ipv4_toggled(bool checked)
|
||||||
|
{
|
||||||
|
if (checked)
|
||||||
|
{
|
||||||
|
swL3Proto->setCurrentIndex(0);
|
||||||
|
twProto->setTabEnabled(2, TRUE);
|
||||||
|
twProto->setTabText(2, "L3 (IPv4)");
|
||||||
|
leType->setText("08 00");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
twProto->setTabEnabled(2, FALSE);
|
||||||
|
twProto->setTabText(2, "L3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_rbL3Arp_toggled(bool checked)
|
||||||
|
{
|
||||||
|
if (checked)
|
||||||
|
{
|
||||||
|
swL3Proto->setCurrentIndex(1);
|
||||||
|
twProto->setTabEnabled(2, TRUE);
|
||||||
|
twProto->setTabText(2, "L3 (ARP)");
|
||||||
|
leType->setText("08 06");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
twProto->setTabEnabled(2, FALSE);
|
||||||
|
twProto->setTabText(2, "L3");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_rbL4Icmp_toggled(bool checked)
|
||||||
|
{
|
||||||
|
QString str;
|
||||||
|
|
||||||
|
if (checked)
|
||||||
|
{
|
||||||
|
swL4Proto->setCurrentIndex(2);
|
||||||
|
twProto->setTabEnabled(3, TRUE);
|
||||||
|
twProto->setTabText(3, "L4 (ICMP)");
|
||||||
|
leIpProto->setText(uintToHexStr(IP_PROTO_ICMP, str, 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
twProto->setTabEnabled(3, FALSE);
|
||||||
|
twProto->setTabText(3, "L4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_rbL4Igmp_toggled(bool checked)
|
||||||
|
{
|
||||||
|
QString str;
|
||||||
|
|
||||||
|
if (checked)
|
||||||
|
{
|
||||||
|
swL4Proto->setCurrentIndex(3);
|
||||||
|
twProto->setTabEnabled(3, TRUE);
|
||||||
|
twProto->setTabText(3, "L4 (IGMP)");
|
||||||
|
leIpProto->setText(uintToHexStr(IP_PROTO_IGMP, str, 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
twProto->setTabEnabled(3, FALSE);
|
||||||
|
twProto->setTabText(3, "L4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_rbL4Tcp_toggled(bool checked)
|
||||||
|
{
|
||||||
|
QString str;
|
||||||
|
|
||||||
|
if (checked)
|
||||||
|
{
|
||||||
|
swL4Proto->setCurrentIndex(0);
|
||||||
|
twProto->setTabEnabled(3, TRUE);
|
||||||
|
twProto->setTabText(3, "L4 (TCP)");
|
||||||
|
leIpProto->setText(uintToHexStr(IP_PROTO_TCP, str, 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
twProto->setTabEnabled(3, FALSE);
|
||||||
|
twProto->setTabText(3, "L4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_rbL4Udp_toggled(bool checked)
|
||||||
|
{
|
||||||
|
QString str;
|
||||||
|
|
||||||
|
if (checked)
|
||||||
|
{
|
||||||
|
swL4Proto->setCurrentIndex(1);
|
||||||
|
twProto->setTabEnabled(3, TRUE);
|
||||||
|
twProto->setTabText(3, "L4 (UDP)");
|
||||||
|
leIpProto->setText(uintToHexStr(IP_PROTO_UDP, str, 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
twProto->setTabEnabled(3, FALSE);
|
||||||
|
twProto->setTabText(3, "L4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::on_rbL4Other_toggled(bool checked)
|
||||||
|
{
|
||||||
|
if (checked)
|
||||||
|
leIpProto->setEnabled(true);
|
||||||
|
else
|
||||||
|
leIpProto->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::update_NumPacketsAndNumBursts()
|
||||||
|
{
|
||||||
|
if (rbSendPackets->isChecked() && rbModeFixed->isChecked())
|
||||||
|
leNumPackets->setEnabled(true);
|
||||||
|
else
|
||||||
|
leNumPackets->setEnabled(false);
|
||||||
|
|
||||||
|
if (rbSendBursts->isChecked() && rbModeFixed->isChecked())
|
||||||
|
leNumBursts->setEnabled(true);
|
||||||
|
else
|
||||||
|
leNumBursts->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString & uintToHexStr(quint32 num, QString &hexStr, quint8 octets)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
QChar zero('0');
|
||||||
|
|
||||||
|
hexStr = "";
|
||||||
|
|
||||||
|
for (i = octets; i > 0; i--)
|
||||||
|
{
|
||||||
|
ushort byte;
|
||||||
|
QString str1 = "%1";
|
||||||
|
QString str;
|
||||||
|
|
||||||
|
byte = num & 0xff;
|
||||||
|
str = str1.arg(byte, 2, 16, zero).append(' ');
|
||||||
|
hexStr.prepend(str);
|
||||||
|
num = num >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hexStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void StreamConfigDialog::on_lePattern_editingFinished()
|
||||||
|
{
|
||||||
|
ulong num = 0;
|
||||||
|
bool isOk;
|
||||||
|
QString str;
|
||||||
|
|
||||||
|
num = lePattern->text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
qDebug("editfinished (%s | %x)\n", lePattern->text().toAscii().data(), num);
|
||||||
|
lePattern->setText(uintToHexStr(num, str, 4));
|
||||||
|
qDebug("editfinished (%s | %x)\n", lePattern->text().toAscii().data(), num);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void StreamConfigDialog::LoadCurrentStream()
|
||||||
|
{
|
||||||
|
Stream *pStream = &((*mpStreamList)[mCurrentStreamIndex]);
|
||||||
|
QString str;
|
||||||
|
|
||||||
|
qDebug("loading pStream %p", pStream);
|
||||||
|
|
||||||
|
// Meta Data
|
||||||
|
{
|
||||||
|
cmbPatternMode->setCurrentIndex(pStream->meta.patternMode);
|
||||||
|
lePattern->setText(uintToHexStr(pStream->meta.pattern, str, 4));
|
||||||
|
|
||||||
|
cmbPktLenMode->setCurrentIndex(pStream->meta.lenMode);
|
||||||
|
lePktLen->setText(str.setNum(pStream->meta.frameLen));
|
||||||
|
lePktLenMin->setText(str.setNum(pStream->meta.frameLenMin));
|
||||||
|
lePktLenMax->setText(str.setNum(pStream->meta.frameLenMax));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protocols
|
||||||
|
{
|
||||||
|
qDebug("ft = %d\n", pStream->proto.ft);
|
||||||
|
switch(pStream->proto.ft)
|
||||||
|
{
|
||||||
|
case Stream::e_ft_none:
|
||||||
|
rbFtNone->setChecked(TRUE);
|
||||||
|
break;
|
||||||
|
case Stream::e_ft_eth_2:
|
||||||
|
rbFtEthernet2->setChecked(TRUE);
|
||||||
|
break;
|
||||||
|
case Stream::e_ft_802_3_raw:
|
||||||
|
rbFt802Dot3Raw->setChecked(TRUE);
|
||||||
|
break;
|
||||||
|
case Stream::e_ft_802_3_llc:
|
||||||
|
rbFt802Dot3Llc->setChecked(TRUE);
|
||||||
|
break;
|
||||||
|
case Stream::e_ft_snap:
|
||||||
|
rbFtLlcSnap->setChecked(TRUE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
leDsap->setText(uintToHexStr(pStream->proto.dsap, str, 1));
|
||||||
|
leSsap->setText(uintToHexStr(pStream->proto.ssap, str, 1));
|
||||||
|
leControl->setText(uintToHexStr(pStream->proto.ctl, str, 1));
|
||||||
|
leOui->setText(uintToHexStr((pStream->proto.ouiMsb << 16 + pStream->proto.ouiLshw), str, 3));
|
||||||
|
|
||||||
|
leType->setText(uintToHexStr(pStream->proto.etherType, str, 2));
|
||||||
|
|
||||||
|
// Check for specific supported protocols first ...
|
||||||
|
if (pStream->proto.etherType == ETH_TYP_IP)
|
||||||
|
rbL3Ipv4->setChecked(TRUE);
|
||||||
|
else if (pStream->proto.etherType == ETH_TYP_ARP)
|
||||||
|
rbL3Arp->setChecked(TRUE);
|
||||||
|
|
||||||
|
// ... then for None/Other
|
||||||
|
rbL3None->setChecked((pStream->proto.protoMask & PM_L3_PROTO_NONE) > 0);
|
||||||
|
rbL3Other->setChecked((pStream->proto.protoMask & PM_L3_PROTO_OTHER) > 0);
|
||||||
|
|
||||||
|
// Check for specific supported protocols first ...
|
||||||
|
if (pStream->proto.ipProto == IP_PROTO_ICMP)
|
||||||
|
rbL4Icmp->setChecked(TRUE);
|
||||||
|
else if (pStream->proto.ipProto == IP_PROTO_IGMP)
|
||||||
|
rbL4Igmp->setChecked(TRUE);
|
||||||
|
else if (pStream->proto.ipProto == IP_PROTO_TCP)
|
||||||
|
rbL4Tcp->setChecked(TRUE);
|
||||||
|
else if (pStream->proto.ipProto == IP_PROTO_UDP)
|
||||||
|
rbL4Udp->setChecked(TRUE);
|
||||||
|
|
||||||
|
// ... then for None/Other
|
||||||
|
rbL4None->setChecked((pStream->proto.protoMask & PM_L4_PROTO_NONE) > 0);
|
||||||
|
rbL4Other->setChecked((pStream->proto.protoMask & PM_L4_PROTO_OTHER) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// L2
|
||||||
|
{
|
||||||
|
// L2 | Ethernet
|
||||||
|
{
|
||||||
|
leDstMac->setText(uintToHexStr(pStream->l2.eth.dstMacMshw, str, 2) +
|
||||||
|
uintToHexStr(pStream->l2.eth.dstMacLsw, str, 4));
|
||||||
|
cmbDstMacMode->setCurrentIndex(pStream->l2.eth.dstMacMode);
|
||||||
|
leDstMacCount->setText(str.setNum(pStream->l2.eth.dstMacCount));
|
||||||
|
leDstMacStep->setText(str.setNum(pStream->l2.eth.dstMacStep));
|
||||||
|
|
||||||
|
leSrcMac->setText(uintToHexStr(pStream->l2.eth.srcMacMshw, str, 2) +
|
||||||
|
uintToHexStr(pStream->l2.eth.srcMacLsw, str, 4));
|
||||||
|
cmbSrcMacMode->setCurrentIndex(pStream->l2.eth.srcMacMode);
|
||||||
|
leSrcMacCount->setText(str.setNum(pStream->l2.eth.srcMacCount));
|
||||||
|
leSrcMacStep->setText(str.setNum(pStream->l2.eth.srcMacStep));
|
||||||
|
|
||||||
|
cmbCvlanPrio->setCurrentIndex(pStream->l2.eth.cvlanPrio);
|
||||||
|
cmbCvlanCfi->setCurrentIndex(pStream->l2.eth.cvlanCfi);
|
||||||
|
leCvlanId->setText(str.setNum(pStream->l2.eth.cvlanId));
|
||||||
|
leCvlanTpid->setText(str.setNum(pStream->l2.eth.ctpid));
|
||||||
|
cbCvlanTpidOverride->setChecked((pStream->l2.eth.vlanMask & VM_CVLAN_TPID_OVERRIDE) > 0);
|
||||||
|
gbCvlan->setChecked((pStream->l2.eth.vlanMask & VM_CVLAN_TAGGED) > 0);
|
||||||
|
|
||||||
|
cmbSvlanPrio->setCurrentIndex(pStream->l2.eth.svlanPrio);
|
||||||
|
cmbSvlanCfi->setCurrentIndex(pStream->l2.eth.svlanCfi);
|
||||||
|
leSvlanId->setText(str.setNum(pStream->l2.eth.svlanId));
|
||||||
|
leSvlanTpid->setText(str.setNum(pStream->l2.eth.stpid));
|
||||||
|
cbSvlanTpidOverride->setChecked((pStream->l2.eth.vlanMask & VM_SVLAN_TPID_OVERRIDE) > 0);
|
||||||
|
gbSvlan->setChecked((pStream->l2.eth.vlanMask & VM_SVLAN_TAGGED) > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// L3
|
||||||
|
{
|
||||||
|
// L3 | IP
|
||||||
|
{
|
||||||
|
leIpVersion->setText(str.setNum(pStream->l3.ip.ver));
|
||||||
|
cbIpVersionOverride->setChecked((pStream->l3.ip.ipMask & IM_OVERRIDE_VERSION) > 0);
|
||||||
|
leIpHdrLen->setText(str.setNum(pStream->l3.ip.hdrLen));
|
||||||
|
cbIpHdrLenOverride->setChecked((pStream->l3.ip.ipMask & IM_OVERRIDE_HDRLEN) > 0);
|
||||||
|
|
||||||
|
leIpTos->setText(uintToHexStr(pStream->l3.ip.tos, str, 1));
|
||||||
|
|
||||||
|
leIpLength->setText(str.setNum(pStream->l3.ip.totLen));
|
||||||
|
cbIpLengthOverride->setChecked((pStream->l3.ip.ipMask & IM_OVERRIDE_TOTLEN) > 0);
|
||||||
|
|
||||||
|
leIpId->setText(uintToHexStr(pStream->l3.ip.id, str, 2));
|
||||||
|
leIpFragOfs->setText(str.setNum(pStream->l3.ip.fragOfs));
|
||||||
|
cbIpFlagsDf->setChecked((pStream->l3.ip.flags & IP_FLAG_DF) > 0);
|
||||||
|
cbIpFlagsMf->setChecked((pStream->l3.ip.flags & IP_FLAG_MF) > 0);
|
||||||
|
|
||||||
|
leIpTtl->setText(str.setNum(pStream->l3.ip.ttl));
|
||||||
|
leIpProto->setText(uintToHexStr(pStream->l3.ip.proto, str, 1));
|
||||||
|
|
||||||
|
leIpCksum->setText(uintToHexStr(pStream->l3.ip.cksum, str, 2));
|
||||||
|
cbIpCksumOverride->setChecked((pStream->l3.ip.ipMask & IM_OVERRIDE_CKSUM) > 0);
|
||||||
|
|
||||||
|
leIpSrcAddr->setText(QHostAddress(pStream->l3.ip.srcIp).toString());
|
||||||
|
cmbIpSrcAddrMode->setCurrentIndex(pStream->l3.ip.srcIpMode);
|
||||||
|
leIpSrcAddrCount->setText(str.setNum(pStream->l3.ip.srcIpCount));
|
||||||
|
leIpSrcAddrMask->setText(QHostAddress(pStream->l3.ip.srcIpMask).toString());
|
||||||
|
|
||||||
|
leIpDstAddr->setText(QHostAddress(pStream->l3.ip.dstIp).toString());
|
||||||
|
cmbIpDstAddrMode->setCurrentIndex(pStream->l3.ip.dstIpMode);
|
||||||
|
leIpDstAddrCount->setText(str.setNum(pStream->l3.ip.dstIpCount));
|
||||||
|
leIpDstAddrMask->setText(QHostAddress(pStream->l3.ip.dstIpMask).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// L3 | ARP
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// L4
|
||||||
|
{
|
||||||
|
// L4 | TCP
|
||||||
|
{
|
||||||
|
leTcpSrcPort->setText(str.setNum(pStream->l4.tcp.srcPort));
|
||||||
|
leTcpDstPort->setText(str.setNum(pStream->l4.tcp.dstPort));
|
||||||
|
|
||||||
|
leTcpSeqNum->setText(str.setNum(pStream->l4.tcp.seqNum));
|
||||||
|
leTcpAckNum->setText(str.setNum(pStream->l4.tcp.ackNum));
|
||||||
|
|
||||||
|
leTcpHdrLen->setText(str.setNum(pStream->l4.tcp.hdrLen));
|
||||||
|
cbTcpHdrLenOverride->setChecked((pStream->l4.tcp.tcpMask & TM_OVERRIDE_HDRLEN) > 0);
|
||||||
|
|
||||||
|
leTcpWindow->setText(str.setNum(pStream->l4.tcp.window));
|
||||||
|
|
||||||
|
leTcpCksum->setText(str.setNum(pStream->l4.tcp.cksum));
|
||||||
|
cbTcpCksumOverride->setChecked((pStream->l4.tcp.tcpMask & TM_OVERRIDE_CKSUM) > 0);
|
||||||
|
|
||||||
|
leTcpUrgentPointer->setText(str.setNum(pStream->l4.tcp.urgPtr));
|
||||||
|
|
||||||
|
cbTcpFlagsUrg->setChecked((pStream->l4.tcp.flags & TCP_FLAG_URG) > 0);
|
||||||
|
cbTcpFlagsAck->setChecked((pStream->l4.tcp.flags & TCP_FLAG_ACK) > 0);
|
||||||
|
cbTcpFlagsPsh->setChecked((pStream->l4.tcp.flags & TCP_FLAG_PSH) > 0);
|
||||||
|
cbTcpFlagsRst->setChecked((pStream->l4.tcp.flags & TCP_FLAG_RST) > 0);
|
||||||
|
cbTcpFlagsSyn->setChecked((pStream->l4.tcp.flags & TCP_FLAG_SYN) > 0);
|
||||||
|
cbTcpFlagsFin->setChecked((pStream->l4.tcp.flags & TCP_FLAG_FIN) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// L4 | UDP
|
||||||
|
{
|
||||||
|
leUdpSrcPort->setText(str.setNum(pStream->l4.udp.srcPort));
|
||||||
|
leUdpDstPort->setText(str.setNum(pStream->l4.udp.dstPort));
|
||||||
|
|
||||||
|
leUdpLength->setText(str.setNum(pStream->l4.udp.totLen));
|
||||||
|
cbUdpLengthOverride->setChecked((pStream->l4.udp.udpMask & UM_OVERRIDE_TOTLEN) > 0);
|
||||||
|
|
||||||
|
leUdpCksum->setText(str.setNum(pStream->l4.udp.cksum));
|
||||||
|
cbUdpCksumOverride->setChecked((pStream->l4.udp.udpMask & UM_OVERRIDE_CKSUM) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// L4 | ICMP
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// L4 | IGMP
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamConfigDialog::StoreCurrentStream()
|
||||||
|
{
|
||||||
|
Stream *pStream = &(*mpStreamList)[mCurrentStreamIndex];
|
||||||
|
QString str;
|
||||||
|
bool isOk;
|
||||||
|
|
||||||
|
qDebug("storing pStream %p", pStream);
|
||||||
|
|
||||||
|
// Meta Data
|
||||||
|
pStream->meta.patternMode = (Stream::DataPatternMode) cmbPatternMode->currentIndex();
|
||||||
|
pStream->meta.pattern = lePattern->text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
|
||||||
|
pStream->meta.lenMode = (Stream::FrameLengthMode) cmbPktLenMode->currentIndex();
|
||||||
|
pStream->meta.frameLen = lePktLen->text().toULong(&isOk);
|
||||||
|
pStream->meta.frameLenMin = lePktLenMin->text().toULong(&isOk);
|
||||||
|
pStream->meta.frameLenMax = lePktLenMax->text().toULong(&isOk);
|
||||||
|
|
||||||
|
// Protocols
|
||||||
|
{
|
||||||
|
if (rbFtNone->isChecked())
|
||||||
|
pStream->proto.ft = Stream::e_ft_none;
|
||||||
|
else if (rbFtEthernet2->isChecked())
|
||||||
|
pStream->proto.ft = Stream::e_ft_eth_2;
|
||||||
|
else if (rbFt802Dot3Raw->isChecked())
|
||||||
|
pStream->proto.ft = Stream::e_ft_802_3_raw;
|
||||||
|
else if (rbFt802Dot3Llc->isChecked())
|
||||||
|
pStream->proto.ft = Stream::e_ft_802_3_llc;
|
||||||
|
else if (rbFtLlcSnap->isChecked())
|
||||||
|
pStream->proto.ft = Stream::e_ft_snap;
|
||||||
|
|
||||||
|
qDebug("store ft = %d\n", pStream->proto.ft);
|
||||||
|
|
||||||
|
pStream->proto.dsap = leDsap->text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
pStream->proto.ssap = leSsap->text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
pStream->proto.ctl = leControl->text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
pStream->proto.ouiMsb = leOui->text().remove(QChar(' ')).toULong(&isOk, 16) >> 16;
|
||||||
|
pStream->proto.ouiLshw = 0x0000FFFF & leOui->text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
pStream->proto.etherType = leType->text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
|
||||||
|
pStream->proto.ipProto = leIpProto->text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
|
||||||
|
// Just check for None/Other - no need to do anything for specific supported protocols
|
||||||
|
pStream->proto.protoMask = 0;
|
||||||
|
if (rbL3None->isChecked())
|
||||||
|
pStream->proto.protoMask |= PM_L3_PROTO_NONE;
|
||||||
|
else if (rbL3Other->isChecked())
|
||||||
|
pStream->proto.protoMask |= PM_L3_PROTO_OTHER;
|
||||||
|
|
||||||
|
if (rbL4None->isChecked())
|
||||||
|
pStream->proto.protoMask |= PM_L4_PROTO_NONE;
|
||||||
|
else if (rbL4Other->isChecked())
|
||||||
|
pStream->proto.protoMask |= PM_L4_PROTO_OTHER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// L2
|
||||||
|
{
|
||||||
|
// L2 | Ethernet
|
||||||
|
{
|
||||||
|
pStream->l2.eth.dstMacMshw = leDstMac->text().remove(QChar(' ')).left(4).toULong(&isOk, 16);
|
||||||
|
pStream->l2.eth.dstMacLsw = leDstMac->text().remove(QChar(' ')).right(8).toULong(&isOk, 16);
|
||||||
|
pStream->l2.eth.dstMacMode = (Stream::MacAddrMode) cmbDstMacMode->currentIndex();
|
||||||
|
pStream->l2.eth.dstMacCount = leDstMacCount->text().toULong(&isOk);
|
||||||
|
pStream->l2.eth.dstMacStep = leDstMacStep->text().toULong(&isOk);
|
||||||
|
|
||||||
|
pStream->l2.eth.srcMacMshw = leSrcMac->text().remove(QChar(' ')).left(4).toULong(&isOk, 16);
|
||||||
|
pStream->l2.eth.srcMacLsw = leSrcMac->text().remove(QChar(' ')).right(8).toULong(&isOk, 16);
|
||||||
|
pStream->l2.eth.srcMacMode = (Stream::MacAddrMode) cmbSrcMacMode->currentIndex();
|
||||||
|
pStream->l2.eth.srcMacCount = leSrcMacCount->text().toULong(&isOk);
|
||||||
|
pStream->l2.eth.srcMacStep = leSrcMacStep->text().toULong(&isOk);
|
||||||
|
|
||||||
|
pStream->l2.eth.vlanMask = 0;
|
||||||
|
|
||||||
|
pStream->l2.eth.cvlanPrio = cmbCvlanPrio->currentIndex();
|
||||||
|
pStream->l2.eth.cvlanCfi = cmbCvlanCfi->currentIndex();
|
||||||
|
pStream->l2.eth.cvlanId = leCvlanId->text().toULong(&isOk);
|
||||||
|
pStream->l2.eth.ctpid = leCvlanTpid->text().remove(QChar(' ')).toULong(&isOk);
|
||||||
|
if (cbCvlanTpidOverride->isChecked())
|
||||||
|
pStream->l2.eth.vlanMask |= VM_CVLAN_TPID_OVERRIDE;
|
||||||
|
if (gbCvlan->isChecked())
|
||||||
|
pStream->l2.eth.vlanMask |= VM_CVLAN_TAGGED;
|
||||||
|
|
||||||
|
pStream->l2.eth.svlanPrio = cmbSvlanPrio->currentIndex();
|
||||||
|
pStream->l2.eth.svlanCfi = cmbSvlanCfi->currentIndex();
|
||||||
|
pStream->l2.eth.svlanId = leSvlanId->text().toULong(&isOk);
|
||||||
|
pStream->l2.eth.stpid = leSvlanTpid->text().remove(QChar(' ')).toULong(&isOk);
|
||||||
|
if (cbSvlanTpidOverride->isChecked())
|
||||||
|
pStream->l2.eth.vlanMask |= VM_SVLAN_TPID_OVERRIDE;
|
||||||
|
if (gbSvlan->isChecked())
|
||||||
|
pStream->l2.eth.vlanMask |= VM_SVLAN_TAGGED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// L3
|
||||||
|
{
|
||||||
|
// L3 | IP
|
||||||
|
{
|
||||||
|
pStream->l3.ip.ipMask = 0;
|
||||||
|
|
||||||
|
pStream->l3.ip.ver = leIpVersion->text().toULong(&isOk);
|
||||||
|
if (cbIpVersionOverride->isChecked())
|
||||||
|
pStream->l3.ip.ipMask |= IM_OVERRIDE_VERSION;
|
||||||
|
pStream->l3.ip.hdrLen = leIpHdrLen->text().toULong(&isOk);
|
||||||
|
if (cbIpHdrLenOverride->isChecked())
|
||||||
|
pStream->l3.ip.ipMask |= IM_OVERRIDE_HDRLEN;
|
||||||
|
|
||||||
|
pStream->l3.ip.tos = leIpTos->text().toULong(&isOk, 16);
|
||||||
|
|
||||||
|
pStream->l3.ip.totLen = leIpLength->text().toULong(&isOk);
|
||||||
|
if (cbIpLengthOverride->isChecked())
|
||||||
|
pStream->l3.ip.ipMask |= IM_OVERRIDE_TOTLEN;
|
||||||
|
|
||||||
|
pStream->l3.ip.id = leIpId->text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
pStream->l3.ip.fragOfs = leIpFragOfs->text().toULong(&isOk);
|
||||||
|
if (cbIpFlagsDf->isChecked()) pStream->l3.ip.ipMask |= IP_FLAG_DF;
|
||||||
|
if (cbIpFlagsMf->isChecked()) pStream->l3.ip.ipMask |= IP_FLAG_MF;
|
||||||
|
|
||||||
|
pStream->l3.ip.ttl = leIpTtl->text().toULong(&isOk);
|
||||||
|
pStream->l3.ip.proto = leIpProto->text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||||
|
|
||||||
|
pStream->l3.ip.cksum = leIpCksum->text().remove(QChar(' ')).toULong(&isOk);
|
||||||
|
if (cbIpCksumOverride->isChecked())
|
||||||
|
pStream->l3.ip.ipMask |= IM_OVERRIDE_CKSUM;
|
||||||
|
|
||||||
|
pStream->l3.ip.srcIp = QHostAddress(leIpSrcAddr->text()).toIPv4Address();
|
||||||
|
pStream->l3.ip.srcIpMode = (Stream::IpAddrMode) cmbIpSrcAddrMode->currentIndex();
|
||||||
|
pStream->l3.ip.srcIpCount = leIpSrcAddrCount->text().toULong(&isOk);
|
||||||
|
pStream->l3.ip.srcIpMask = QHostAddress(leIpSrcAddrMask->text()).toIPv4Address();
|
||||||
|
|
||||||
|
pStream->l3.ip.dstIp = QHostAddress(leIpDstAddr->text()).toIPv4Address();
|
||||||
|
pStream->l3.ip.dstIpMode = (Stream::IpAddrMode) cmbIpDstAddrMode->currentIndex();
|
||||||
|
pStream->l3.ip.dstIpCount = leIpDstAddrCount->text().toULong(&isOk);
|
||||||
|
pStream->l3.ip.dstIpMask = QHostAddress(leIpDstAddrMask->text()).toIPv4Address();
|
||||||
|
}
|
||||||
|
|
||||||
|
// L3 | ARP
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// L4
|
||||||
|
{
|
||||||
|
// L4 | TCP
|
||||||
|
{
|
||||||
|
pStream->l4.tcp.tcpMask = 0;
|
||||||
|
|
||||||
|
pStream->l4.tcp.srcPort = leTcpSrcPort->text().toULong(&isOk);
|
||||||
|
pStream->l4.tcp.dstPort = leTcpDstPort->text().toULong(&isOk);
|
||||||
|
|
||||||
|
pStream->l4.tcp.seqNum = leTcpSeqNum->text().toULong(&isOk);
|
||||||
|
pStream->l4.tcp.ackNum = leTcpAckNum->text().toULong(&isOk);
|
||||||
|
|
||||||
|
pStream->l4.tcp.hdrLen = leTcpHdrLen->text().toULong(&isOk);
|
||||||
|
if (cbTcpHdrLenOverride->isChecked())
|
||||||
|
pStream->l4.tcp.tcpMask |= TM_OVERRIDE_HDRLEN;
|
||||||
|
|
||||||
|
pStream->l4.tcp.window = leTcpWindow->text().toULong(&isOk);
|
||||||
|
|
||||||
|
pStream->l4.tcp.cksum = leTcpCksum->text().remove(QChar(' ')).toULong(&isOk);
|
||||||
|
if (cbTcpCksumOverride->isChecked())
|
||||||
|
pStream->l4.tcp.tcpMask |= TM_OVERRIDE_CKSUM;
|
||||||
|
|
||||||
|
pStream->l4.tcp.urgPtr = leTcpUrgentPointer->text().toULong(&isOk);
|
||||||
|
|
||||||
|
pStream->l4.tcp.flags = 0;
|
||||||
|
if (cbTcpFlagsUrg->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_URG;
|
||||||
|
if (cbTcpFlagsAck->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_ACK;
|
||||||
|
if (cbTcpFlagsPsh->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_PSH;
|
||||||
|
if (cbTcpFlagsRst->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_RST;
|
||||||
|
if (cbTcpFlagsSyn->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_SYN;
|
||||||
|
if (cbTcpFlagsFin->isChecked()) pStream->l4.tcp.flags |= TCP_FLAG_FIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// L4 | UDP
|
||||||
|
{
|
||||||
|
pStream->l4.udp.udpMask = 0;
|
||||||
|
|
||||||
|
pStream->l4.udp.srcPort = leUdpSrcPort->text().toULong(&isOk);
|
||||||
|
pStream->l4.udp.dstPort = leUdpDstPort->text().toULong(&isOk);
|
||||||
|
|
||||||
|
pStream->l4.udp.totLen = leUdpLength->text().toULong(&isOk);
|
||||||
|
if (cbUdpLengthOverride->isChecked()) pStream->l4.udp.udpMask |= UM_OVERRIDE_TOTLEN;
|
||||||
|
|
||||||
|
pStream->l4.udp.cksum = leUdpCksum->text().remove(QChar(' ')).toULong(&isOk);
|
||||||
|
if (cbUdpCksumOverride->isChecked()) pStream->l4.udp.udpMask |= UM_OVERRIDE_CKSUM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// L4 | ICMP
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
// L4 | IGMP
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void StreamConfigDialog::on_pbOk_clicked()
|
||||||
|
{
|
||||||
|
// Store dialog contents into stream
|
||||||
|
StoreCurrentStream();
|
||||||
|
qDebug("stream stored");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Junk Line for introducing a compiler error
|
||||||
|
|
58
client/streamconfigdialog.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef _STREAM_CONFIG_DIALOG_H
|
||||||
|
#define _STREAM_CONFIG_DIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include "ui_streamconfigdialog.h"
|
||||||
|
#include <stream.h>
|
||||||
|
|
||||||
|
#define MAX_MAC_ITER_COUNT 256
|
||||||
|
#define MIN_PKT_LEN 64
|
||||||
|
#define MAX_PKT_LEN 1522
|
||||||
|
|
||||||
|
/*
|
||||||
|
** TODO
|
||||||
|
** - Improve HexStr handling
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
|
||||||
|
class StreamConfigDialog : public QDialog, public Ui::StreamConfigDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
StreamConfigDialog(QList<Stream> *streamList, uint streamIndex,
|
||||||
|
QWidget *parent = 0);
|
||||||
|
~StreamConfigDialog();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<Stream> *mpStreamList;
|
||||||
|
uint mCurrentStreamIndex;
|
||||||
|
|
||||||
|
void setupUiExtra();
|
||||||
|
void LoadCurrentStream();
|
||||||
|
void StoreCurrentStream();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_cmbDstMacMode_currentIndexChanged(QString mode);
|
||||||
|
void on_pbPrev_clicked();
|
||||||
|
void on_pbNext_clicked();
|
||||||
|
|
||||||
|
void on_rbFtLlcSnap_toggled(bool checked);
|
||||||
|
|
||||||
|
void on_rbL3Ipv4_toggled(bool checked);
|
||||||
|
void on_rbL3Arp_toggled(bool checked);
|
||||||
|
|
||||||
|
void on_rbL4Icmp_toggled(bool checked);
|
||||||
|
void on_rbL4Igmp_toggled(bool checked);
|
||||||
|
void on_rbL4Tcp_toggled(bool checked);
|
||||||
|
void on_rbL4Udp_toggled(bool checked);
|
||||||
|
void on_rbL4Other_toggled(bool checked);
|
||||||
|
|
||||||
|
void update_NumPacketsAndNumBursts();
|
||||||
|
|
||||||
|
void on_pbOk_clicked();
|
||||||
|
};
|
||||||
|
|
||||||
|
QString & uintToHexStr(quint32 num, QString &hexStr, quint8 octets);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
3224
client/streamconfigdialog.ui
Normal file
119
client/streamlistmodel.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#include "streamlistmodel.h"
|
||||||
|
|
||||||
|
StreamListModel::StreamListModel(QObject *parent)
|
||||||
|
: QAbstractTableModel(parent)
|
||||||
|
{
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
// Enable all streams by default
|
||||||
|
for (i=0; i<MAX_ROWS; i++)
|
||||||
|
{
|
||||||
|
streamList[i].isEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int StreamListModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return MAX_ROWS; // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
int StreamListModel::columnCount(const QModelIndex &parent ) const
|
||||||
|
{
|
||||||
|
return MAX_COLS; // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags StreamListModel::flags(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
|
||||||
|
|
||||||
|
if (index.column() == 0)
|
||||||
|
;
|
||||||
|
else if (index.column() == 1)
|
||||||
|
flags |= Qt::ItemIsEditable;
|
||||||
|
else if (index.column() == 2)
|
||||||
|
flags |= Qt::ItemIsUserCheckable | Qt::ItemIsEditable;
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
QVariant StreamListModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
// Check for a valid index
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
// Check for row/column limits
|
||||||
|
if (index.row() >= MAX_ROWS)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (index.column() >= MAX_COLS)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
// Check role
|
||||||
|
if (index.column() == 0) // Icon
|
||||||
|
{
|
||||||
|
if ((role == Qt::DisplayRole))
|
||||||
|
return QString("EDIT");
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
else if (index.column() == 1) // Name
|
||||||
|
{
|
||||||
|
if ((role == Qt::DisplayRole) || (role == Qt::EditRole))
|
||||||
|
return streamList[index.row()].streamName;
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
else if (index.column() == 2) // Enabled?
|
||||||
|
{
|
||||||
|
//if ((role == Qt::CheckStateRole) || (role == Qt::EditRole))
|
||||||
|
// return streamList[index.row()].isEnabled ? Qt::Checked : Qt::Unchecked;
|
||||||
|
if ((role == Qt::DisplayRole) || (role == Qt::EditRole))
|
||||||
|
return streamList[index.row()].isEnabled;
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StreamListModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||||
|
{
|
||||||
|
if (index.isValid() && role == Qt::EditRole)
|
||||||
|
{
|
||||||
|
if (index.column() == 1) // Name
|
||||||
|
streamList[index.row()].streamName = value.toString();
|
||||||
|
else if (index.column() == 2) // Enabled?
|
||||||
|
streamList[index.row()].isEnabled = value.toBool();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant StreamListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (role != Qt::DisplayRole)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (orientation == Qt::Horizontal)
|
||||||
|
return StreamListCols.at(section);
|
||||||
|
else
|
||||||
|
return QString("%1").arg(section+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// QModelIndex StreamListModel::index (int portNum, PortStat stat, const QModelIndex & parent = QModelIndex() ) const
|
||||||
|
|
||||||
|
void StreamListModel::on_portStatsUpdate(int port, void*stats)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
QModelIndex topLeft = index(port, 0, QModelIndex());
|
||||||
|
QModelIndex bottomRight = index(port, e_STAT_MAX, QModelIndex());
|
||||||
|
|
||||||
|
for (i = 0; i < e_STAT_MAX; i++)
|
||||||
|
dummyStats[port][i] = ((int *)stats)[i];
|
||||||
|
|
||||||
|
emit dataChanged(topLeft, bottomRight);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
46
client/streamlistmodel.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef _STREAM_LIST_MODEL_H
|
||||||
|
#define _STREAM_LIST_MODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
static QStringList StreamListCols = (QStringList()
|
||||||
|
<< "Icon"
|
||||||
|
<< "Name"
|
||||||
|
<< "Enable"
|
||||||
|
);
|
||||||
|
|
||||||
|
#define MAX_ROWS 5
|
||||||
|
#define MAX_COLS 3
|
||||||
|
|
||||||
|
class StreamListModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
//StreamListModel(QObject *parent = 0) : QAbstractTableModel(parent) {}
|
||||||
|
StreamListModel(QObject *parent = 0);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
// QModelIndex index (int portNum, PortStat stat, const QModelIndex & parent = QModelIndex() ) const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
// void on_portStatsUpdate(int port, void*stats);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// FIXME: temp
|
||||||
|
//#define NUM_PORTS 2
|
||||||
|
// int dummyStats[NUM_PORTS][e_STAT_MAX];
|
||||||
|
struct {
|
||||||
|
QString streamName;
|
||||||
|
bool isEnabled;
|
||||||
|
} streamList[MAX_ROWS];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
218
client/streammodel.cpp
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
#include "streammodel.h"
|
||||||
|
#include "portgrouplist.h"
|
||||||
|
#include "qicon.h"
|
||||||
|
|
||||||
|
StreamModel::StreamModel(PortGroupList *p, QObject *parent)
|
||||||
|
: QAbstractTableModel(parent)
|
||||||
|
{
|
||||||
|
pgl = p;
|
||||||
|
mCurrentPort = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int StreamModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
if (parent.isValid())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (mCurrentPort)
|
||||||
|
return mCurrentPort->mStreams.size();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int StreamModel::columnCount(const QModelIndex &parent ) const
|
||||||
|
{
|
||||||
|
return (int) StreamMaxFields;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags StreamModel::flags(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
|
||||||
|
|
||||||
|
|
||||||
|
switch (index.column())
|
||||||
|
{
|
||||||
|
case StreamIcon:
|
||||||
|
break;
|
||||||
|
case StreamName:
|
||||||
|
flags |= Qt::ItemIsEditable;
|
||||||
|
break;
|
||||||
|
case StreamStatus:
|
||||||
|
flags |= Qt::ItemIsUserCheckable | Qt::ItemIsEditable;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
QVariant StreamModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
// Check for a valid index
|
||||||
|
if (!index.isValid())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
// Check for row/column limits
|
||||||
|
if (index.row() >= mCurrentPort->mStreams.size())
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (index.column() >= StreamMaxFields)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (mCurrentPort == NULL)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
// Return data based on field and role
|
||||||
|
switch(index.column())
|
||||||
|
{
|
||||||
|
case StreamIcon:
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
case StreamName:
|
||||||
|
{
|
||||||
|
if ((role == Qt::DisplayRole) || (role == Qt::EditRole))
|
||||||
|
return mCurrentPort->mStreams[index.row()].name();
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StreamStatus:
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if ((role == Qt::DisplayRole) || (role == Qt::EditRole))
|
||||||
|
return streamList[index.row()].isEnabled;
|
||||||
|
if ((role == Qt::DisplayRole) || (role == Qt::CheckStateRole) ||
|
||||||
|
#endif
|
||||||
|
if ((role == Qt::CheckStateRole) || (role == Qt::EditRole))
|
||||||
|
{
|
||||||
|
if (mCurrentPort->mStreams[index.row()].isEnabled())
|
||||||
|
return Qt::Checked;
|
||||||
|
else
|
||||||
|
return Qt::Unchecked;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return QVariant();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
qDebug("-------------UNHANDLED STREAM FIELD----------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StreamModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||||
|
{
|
||||||
|
if (mCurrentPort == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (index.isValid() && role == Qt::EditRole)
|
||||||
|
{
|
||||||
|
// Edit Supported Fields
|
||||||
|
switch (index.column())
|
||||||
|
{
|
||||||
|
case StreamName:
|
||||||
|
mCurrentPort->mStreams[index.row()].setName(value.toString());
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case StreamStatus:
|
||||||
|
mCurrentPort->mStreams[index.row()].setEnabled(value.toBool());
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Edit Not Supported Fields
|
||||||
|
case StreamIcon:
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Unhandled Stream Field
|
||||||
|
default:
|
||||||
|
qDebug("-------------UNHANDLED STREAM FIELD----------------");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant StreamModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
if (role != Qt::DisplayRole)
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
if (orientation == Qt::Horizontal)
|
||||||
|
{
|
||||||
|
switch(section)
|
||||||
|
{
|
||||||
|
case StreamIcon:
|
||||||
|
return QString("Icon");
|
||||||
|
break;
|
||||||
|
case StreamName:
|
||||||
|
return QString("Name");
|
||||||
|
break;
|
||||||
|
case StreamStatus:
|
||||||
|
return QString("Enabled");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
qDebug("-------------UNHANDLED STREAM FIELD----------------");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return QString("%1").arg(section+1);
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StreamModel::insertRows(int row, int count, const QModelIndex &parent)
|
||||||
|
{
|
||||||
|
qDebug("insertRows() row = %d", row);
|
||||||
|
qDebug("insertRows() count = %d", count);
|
||||||
|
beginInsertRows(QModelIndex(), row, row+count-1);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
mCurrentPort->mStreams.insert(row, Stream());
|
||||||
|
endInsertRows();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StreamModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||||
|
{
|
||||||
|
qDebug("removeRows() row = %d", row);
|
||||||
|
qDebug("removeRows() count = %d", count);
|
||||||
|
beginRemoveRows(QModelIndex(), row, row+count-1);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
// FIXME(HIGH): do we need to free the removed stream?
|
||||||
|
mCurrentPort->mStreams.removeAt(row);
|
||||||
|
}
|
||||||
|
endRemoveRows();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------- SLOTS ------------------------
|
||||||
|
|
||||||
|
void StreamModel::setCurrentPortIndex(const QModelIndex ¤t)
|
||||||
|
{
|
||||||
|
if (!current.isValid() || !pgl->isPort(current))
|
||||||
|
{
|
||||||
|
qDebug("current is either invalid or not a port");
|
||||||
|
mCurrentPort = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qDebug("change to valid port");
|
||||||
|
quint16 pg = current.internalId() >> 16;
|
||||||
|
mCurrentPort = &pgl->mPortGroups[pgl->indexOfPortGroup(pg)]->mPorts[current.row()];
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
}
|
49
client/streammodel.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef _STREAM_MODEL_H
|
||||||
|
#define _STREAM_MODEL_H
|
||||||
|
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
#include "port.h"
|
||||||
|
|
||||||
|
class PortGroupList;
|
||||||
|
|
||||||
|
class StreamModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
enum StreamFields {
|
||||||
|
StreamIcon = 0,
|
||||||
|
StreamName,
|
||||||
|
StreamStatus,
|
||||||
|
|
||||||
|
StreamMaxFields
|
||||||
|
};
|
||||||
|
|
||||||
|
Port *mCurrentPort;
|
||||||
|
PortGroupList *pgl;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StreamModel(PortGroupList *p, QObject *parent = 0);
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
|
bool setData(const QModelIndex &index, const QVariant &value,
|
||||||
|
int role = Qt::EditRole);
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role = Qt::DisplayRole) const;
|
||||||
|
bool insertRows (int row, int count,
|
||||||
|
const QModelIndex & parent = QModelIndex());
|
||||||
|
bool removeRows (int row, int count,
|
||||||
|
const QModelIndex & parent = QModelIndex());
|
||||||
|
|
||||||
|
// FIXME(HIGH): This *is* like a kludge
|
||||||
|
QList<Stream>* currentPortStreamList()
|
||||||
|
{ return &mCurrentPort->mStreams; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setCurrentPortIndex(const QModelIndex ¤t);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
53
common/protocol.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef _PROTOCOL_H
|
||||||
|
#define _PROTOCOL_H
|
||||||
|
|
||||||
|
#define UINT8 unsigned char
|
||||||
|
#define UINT16 unsigned short
|
||||||
|
#define UINT32 unsigned int
|
||||||
|
|
||||||
|
#define BYTESWAP4(x) \
|
||||||
|
(((x & 0xFF000000) >> 24) | \
|
||||||
|
((x & 0x00FF0000) >> 8) | \
|
||||||
|
((x & 0x0000FF00) << 8) | \
|
||||||
|
((x & 0x000000FF) << 24))
|
||||||
|
|
||||||
|
#define BYTESWAP2(x) \
|
||||||
|
(((x & 0xFF00) >> 8) | \
|
||||||
|
((x & 0x00FF) << 8))
|
||||||
|
|
||||||
|
// TODO: portability
|
||||||
|
#define HTONL(x) BYTESWAP4(x)
|
||||||
|
#define NTOHL(x) BYTESWAP4(x)
|
||||||
|
#define HTONS(x) BYTESWAP2(x)
|
||||||
|
#define NTOHS(x) BYTESWAP2(x)
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT8 ver;
|
||||||
|
UINT8 resv1;
|
||||||
|
UINT16 resv2;
|
||||||
|
UINT16 msgType;
|
||||||
|
UINT16 msgLen;
|
||||||
|
} tCommHdr;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
e_MT_CapabilityReq=1,
|
||||||
|
e_MT_CapabilityInfo
|
||||||
|
} eMsgType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
e_TT_PortCapability
|
||||||
|
} eTlvType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UINT16 tlvType;
|
||||||
|
UINT16 tlvLen;
|
||||||
|
UINT32 port;
|
||||||
|
UINT32 speed;
|
||||||
|
#define TLV_MAX_PORT_NAME 64
|
||||||
|
#define TLV_MAX_PORT_DESC 64
|
||||||
|
char name[TLV_MAX_PORT_NAME];
|
||||||
|
char desc[TLV_MAX_PORT_DESC];
|
||||||
|
} tTlvPortCapability;
|
||||||
|
|
||||||
|
#endif
|
12
server/abstracthost.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef _ABSTRACT_HOST
|
||||||
|
#define _ABSTRACT_HOST
|
||||||
|
|
||||||
|
class AbstractHost
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void Log(const char* str) = 0;
|
||||||
|
virtual int SendMsg(const void* msg, int size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
85
server/drone.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#include "drone.h"
|
||||||
|
|
||||||
|
extern int myport; // FIXME(HIGH)
|
||||||
|
|
||||||
|
Drone::Drone(QDialog *parent)
|
||||||
|
: QDialog(parent)
|
||||||
|
{
|
||||||
|
ui.setupUi(this);
|
||||||
|
serverPortNum = DRONE_PORT;
|
||||||
|
clientSock = NULL;
|
||||||
|
|
||||||
|
if (myport)
|
||||||
|
serverPortNum = myport;
|
||||||
|
|
||||||
|
rxtx = new RxTx(this);
|
||||||
|
|
||||||
|
server = new QTcpServer(this);
|
||||||
|
connect(server, SIGNAL(newConnection()), this, SLOT(when_newConnection()));
|
||||||
|
//if (!server->listen(QHostAddress("10.0.0.1"), serverPortNum))
|
||||||
|
if (!server->listen(QHostAddress::Any, serverPortNum))
|
||||||
|
LogInt(tr("Unable to start the server: %1").arg(server->errorString()));
|
||||||
|
else
|
||||||
|
LogInt(tr("The server is running on %1:%2").arg(server->serverAddress().toString()).arg(server->serverPort()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Drone::Log(const char* str)
|
||||||
|
{
|
||||||
|
ui.teLog->append(QString(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
int Drone::SendMsg(const void* msg, int size)
|
||||||
|
{
|
||||||
|
qDebug("Inside SendMsg\n");
|
||||||
|
clientSock->write((char*) msg, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Drone::LogInt(const QString &str)
|
||||||
|
{
|
||||||
|
ui.teLog->append(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Drone::when_newConnection()
|
||||||
|
{
|
||||||
|
if (clientSock)
|
||||||
|
{
|
||||||
|
QTcpSocket *sock;
|
||||||
|
|
||||||
|
LogInt(tr("already connected, no new connections will be accepted\n"));
|
||||||
|
sock = server->nextPendingConnection();
|
||||||
|
// TODO: Send reason msg to client
|
||||||
|
sock->disconnectFromHost();
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
clientSock = server->nextPendingConnection();
|
||||||
|
LogInt(tr("accepting new connection from %1:%2").arg(clientSock->peerAddress().toString()).arg(clientSock->peerPort()));
|
||||||
|
connect(clientSock, SIGNAL(readyRead()),
|
||||||
|
this, SLOT(when_dataAvail()));
|
||||||
|
connect(clientSock, SIGNAL(disconnected()),
|
||||||
|
this, SLOT(when_disconnected()));
|
||||||
|
connect(clientSock, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||||
|
this, SLOT(when_error(QAbstractSocket::SocketError)));
|
||||||
|
|
||||||
|
|
||||||
|
_exit:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Drone::when_disconnected()
|
||||||
|
{
|
||||||
|
LogInt(tr("closing connection from %1:%2").arg(clientSock->peerAddress().toString()).arg(clientSock->peerPort()));
|
||||||
|
clientSock->deleteLater();
|
||||||
|
clientSock = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Drone::when_dataAvail()
|
||||||
|
{
|
||||||
|
QByteArray msg = clientSock->read(1024); // FIXME: hardcoding
|
||||||
|
LogInt(QString(msg.toHex()));
|
||||||
|
rxtx->ProcessMsg(msg.constData(), msg.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Drone::when_error(QAbstractSocket::SocketError socketError)
|
||||||
|
{
|
||||||
|
LogInt(clientSock->errorString());
|
||||||
|
}
|
36
server/drone.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef _DRONE_H
|
||||||
|
#define _DRONE_H
|
||||||
|
|
||||||
|
#include <QTcpServer>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include "ui_drone.h"
|
||||||
|
#include "abstracthost.h"
|
||||||
|
#include "rxtx.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Drone : public QDialog, AbstractHost
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
Drone(QDialog *parent = 0);
|
||||||
|
void Log(const char *msg);
|
||||||
|
int SendMsg(const void* msg, int msgLen);
|
||||||
|
|
||||||
|
Ui::Drone ui;
|
||||||
|
private:
|
||||||
|
RxTx *rxtx;
|
||||||
|
QTcpServer *server;
|
||||||
|
QTcpSocket *clientSock;
|
||||||
|
#define DRONE_PORT 7878
|
||||||
|
quint16 serverPortNum;
|
||||||
|
// Ui::Drone ui;
|
||||||
|
void LogInt(const QString &msg);
|
||||||
|
private slots:
|
||||||
|
void when_newConnection();
|
||||||
|
void when_disconnected();
|
||||||
|
void when_dataAvail();
|
||||||
|
void when_error(QAbstractSocket::SocketError socketError);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
9
server/drone.pro
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += qt
|
||||||
|
QT += network
|
||||||
|
DEFINES += HAVE_REMOTE
|
||||||
|
INCLUDEPATH += "C:\DevelLibs\WpdPack\Include"
|
||||||
|
LIBS += -L"C:\DevelLibs\WpdPack\Lib" -lwpcap
|
||||||
|
HEADERS += drone.h
|
||||||
|
FORMS += drone.ui
|
||||||
|
SOURCES += drone_main.cpp drone.cpp rxtx.cpp
|
126
server/drone.ui
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<ui version="4.0" >
|
||||||
|
<class>Drone</class>
|
||||||
|
<widget class="QDialog" name="Drone" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>Drone</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="twDisplay" >
|
||||||
|
<property name="currentIndex" >
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tabStatus" >
|
||||||
|
<attribute name="title" >
|
||||||
|
<string>Status</string>
|
||||||
|
</attribute>
|
||||||
|
<widget class="QLabel" name="label" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>160</x>
|
||||||
|
<y>100</y>
|
||||||
|
<width>46</width>
|
||||||
|
<height>14</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text" >
|
||||||
|
<string>TODO</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tabLog" >
|
||||||
|
<attribute name="title" >
|
||||||
|
<string>Log</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QHBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="teLog" >
|
||||||
|
<property name="readOnly" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<property name="acceptRichText" >
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" >
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pbClearLog" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Clear Log</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer>
|
||||||
|
<property name="orientation" >
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" >
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Exit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>pushButton</sender>
|
||||||
|
<signal>clicked(bool)</signal>
|
||||||
|
<receiver>Drone</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel" >
|
||||||
|
<x>341</x>
|
||||||
|
<y>279</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel" >
|
||||||
|
<x>226</x>
|
||||||
|
<y>268</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>pbClearLog</sender>
|
||||||
|
<signal>clicked()</signal>
|
||||||
|
<receiver>teLog</receiver>
|
||||||
|
<slot>clear()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel" >
|
||||||
|
<x>52</x>
|
||||||
|
<y>278</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel" >
|
||||||
|
<x>100</x>
|
||||||
|
<y>185</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
22
server/drone_main.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "drone.h"
|
||||||
|
|
||||||
|
Drone *drone;
|
||||||
|
|
||||||
|
//void FindDevList(void);
|
||||||
|
|
||||||
|
int myport;
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
// FIXME(HIGH)
|
||||||
|
if (argc > 1)
|
||||||
|
myport = atoi(argv[1]);
|
||||||
|
|
||||||
|
drone = new Drone;
|
||||||
|
//FindDevList();
|
||||||
|
drone->show();
|
||||||
|
return app.exec();
|
||||||
|
}
|
||||||
|
|
147
server/rxtx.cpp
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
#include "rxtx.h"
|
||||||
|
#include "../common/protocol.h"
|
||||||
|
#include "qtglobal" // FIXME: needed only for qdebug
|
||||||
|
|
||||||
|
//#define LOG(...) drone->ui.teLOG->append(QString().sprintf( __VA_ARGS__))
|
||||||
|
//#define LOG(...) drone->LOG(QString().sprintf( __VA_ARGS__))
|
||||||
|
#define LOG(...) {sprintf(logStr, __VA_ARGS__); host->Log(logStr);}
|
||||||
|
|
||||||
|
|
||||||
|
RxTx::RxTx(AbstractHost *host)
|
||||||
|
{
|
||||||
|
pcap_if_t *d;
|
||||||
|
int i=0;
|
||||||
|
char errbuf[PCAP_ERRBUF_SIZE];
|
||||||
|
|
||||||
|
// Init Data
|
||||||
|
RxTx::host = host;
|
||||||
|
numPorts = 0;
|
||||||
|
alldevs = NULL;
|
||||||
|
|
||||||
|
LOG("Retrieving the device list from the local machine\n");
|
||||||
|
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
|
||||||
|
{
|
||||||
|
LOG("Error in pcap_findalldevs_ex: %s\n", errbuf);
|
||||||
|
goto _fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count number of local ports */
|
||||||
|
for(d = alldevs; d != NULL; d = d->next)
|
||||||
|
numPorts++;
|
||||||
|
|
||||||
|
portInfo = new PortInfo[numPorts];
|
||||||
|
|
||||||
|
/* Print the list */
|
||||||
|
for(i=0, d=alldevs; d!=NULL; i++, d=d->next)
|
||||||
|
{
|
||||||
|
portInfo[i].portId = i;
|
||||||
|
portInfo[i].dev = d;
|
||||||
|
#if 1
|
||||||
|
LOG("%d. %s", i, d->name);
|
||||||
|
if (d->description)
|
||||||
|
{
|
||||||
|
LOG(" (%s)\n", d->description);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG(" (No description available)\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
LOG("\nNo interfaces found! Make sure WinPcap is installed.\n");
|
||||||
|
goto _fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fail:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
RxTx::LOG(char* fmt, ...)
|
||||||
|
{
|
||||||
|
sprintf(logStr, fmt, _VA_ARGS_);
|
||||||
|
host->LOG(logStr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RxTx::~RxTx()
|
||||||
|
{
|
||||||
|
pcap_freealldevs(alldevs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RxTx::ProcessMsg(const char* msg, int len)
|
||||||
|
{
|
||||||
|
tCommHdr *hdr;
|
||||||
|
// TODO: For now, assuming we'll get a complete msg
|
||||||
|
// but need to fix this as this is a TCP stream
|
||||||
|
|
||||||
|
hdr = (tCommHdr*) msg;
|
||||||
|
|
||||||
|
if (hdr->ver != 1) // FIXME:hardcoding
|
||||||
|
{
|
||||||
|
LOG("Rcvd msg with invalid version %d\n", hdr->ver);
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug("msgType - %x: %x\n", hdr->msgType, NTOHS(hdr->msgType));
|
||||||
|
switch (NTOHS(hdr->msgType))
|
||||||
|
{
|
||||||
|
case e_MT_CapabilityReq:
|
||||||
|
SendCapabilityInfo();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG("Rcvd msg with unrecognized msgType %d\n", NTOHS(hdr->msgType));
|
||||||
|
}
|
||||||
|
|
||||||
|
_exit:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RxTx::SendCapabilityInfo(void)
|
||||||
|
{
|
||||||
|
unsigned char *msg, *p;
|
||||||
|
unsigned int i, msgLen;
|
||||||
|
|
||||||
|
p = msg = (unsigned char*) pktBuff;
|
||||||
|
((tCommHdr*)(p))->ver = 1;
|
||||||
|
((tCommHdr*)(p))->msgType = HTONS(e_MT_CapabilityInfo);
|
||||||
|
p += sizeof(tCommHdr);
|
||||||
|
|
||||||
|
for (i = 0; i < numPorts; i++)
|
||||||
|
{
|
||||||
|
// TLV: Port Capability
|
||||||
|
((tTlvPortCapability*)(p))->tlvType = HTONS(e_TT_PortCapability);
|
||||||
|
((tTlvPortCapability*)(p))->tlvLen = HTONS(sizeof(tTlvPortCapability));
|
||||||
|
((tTlvPortCapability*)(p))->port = HTONL(portInfo[i].portId);
|
||||||
|
((tTlvPortCapability*)(p))->speed = 0; // TODO
|
||||||
|
#if 0
|
||||||
|
strncpy(((tTlvPortCapability*)(p))->name,
|
||||||
|
portInfo[i].dev->name, TLV_MAX_PORT_NAME);
|
||||||
|
((tTlvPortCapability*)(p))->name[TLV_MAX_PORT_NAME-1] = 0;
|
||||||
|
#else
|
||||||
|
strcpy(((tTlvPortCapability*)(p))->name, "eth");
|
||||||
|
//strcat(((tTlvPortCapability*)(p))->name, itoa(portInfo[i].portId, NULL, 10));
|
||||||
|
itoa(portInfo[i].portId, &(((tTlvPortCapability*)(p))->name[3]), 10);
|
||||||
|
#endif
|
||||||
|
strncpy(((tTlvPortCapability*)(p))->desc,
|
||||||
|
portInfo[i].dev->description, TLV_MAX_PORT_DESC);
|
||||||
|
((tTlvPortCapability*)(p))->desc[TLV_MAX_PORT_DESC -1] = 0;
|
||||||
|
p += sizeof(tTlvPortCapability);
|
||||||
|
}
|
||||||
|
msgLen = (p - msg);
|
||||||
|
((tCommHdr*)(msg))->msgLen = HTONS(msgLen);
|
||||||
|
|
||||||
|
logStr[0] = 0;
|
||||||
|
for (i = 0; i < msgLen >> 2; i++)
|
||||||
|
{
|
||||||
|
char word[10];
|
||||||
|
|
||||||
|
sprintf(word, "%08X ", HTONL(((unsigned int *)(msg))[i]));
|
||||||
|
strcat(logStr, word);
|
||||||
|
}
|
||||||
|
host->Log("Sending msg\n");
|
||||||
|
host->Log(logStr);
|
||||||
|
host->SendMsg(pktBuff, msgLen);
|
||||||
|
}
|
35
server/rxtx.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef _RXTX_H
|
||||||
|
#define _RXTX_H
|
||||||
|
|
||||||
|
#include "pcap.h"
|
||||||
|
#include "abstracthost.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int portId;
|
||||||
|
pcap_if_t *dev;
|
||||||
|
} PortInfo;
|
||||||
|
|
||||||
|
class RxTx
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RxTx(AbstractHost* host);
|
||||||
|
~RxTx();
|
||||||
|
void ProcessMsg(const char* msg, int len);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AbstractHost *host;
|
||||||
|
char logStr[1024];
|
||||||
|
|
||||||
|
#define MAX_PKT_SIZE 1024
|
||||||
|
unsigned char pktBuff[MAX_PKT_SIZE];
|
||||||
|
unsigned numPorts;
|
||||||
|
PortInfo *portInfo;
|
||||||
|
pcap_if_t *alldevs;
|
||||||
|
|
||||||
|
//void Log(char *fmt, ...);
|
||||||
|
void SendCapabilityInfo(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|