1
0
Fork 0

rework directory structure

This commit is contained in:
Kevin Matz 2021-09-06 12:54:28 -04:00
parent 0090fa5706
commit b3ee265745
167 changed files with 1620 additions and 20 deletions

View File

@ -1,7 +1,17 @@
cmake_minimum_required(VERSION 3.20)
set(DEFAULT_BUILD_TYPE "Release")
project(OpenLCP VERSION 0.2.0 LANGUAGES CXX)
add_subdirectory(protocols)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG")
endif()
add_subdirectory(platform)
add_subdirectory(protocol)
add_subdirectory(test)
add_subdirectory(platform/qt)
add_subdirectory(example)
#if (CMAKE_BUILD_TYPE MATCHES "^[Rr]elease")
option(BUILD_DOC "Build documentation" ON)

View File

@ -127,7 +127,8 @@ FILE_PATTERNS = *.cpp \
*.md \
*.py
RECURSIVE = YES
EXCLUDE = @CMAKE_CURRENT_SOURCE_DIR@/platform \
EXCLUDE = @CMAKE_CURRENT_SOURCE_DIR@/example \
@CMAKE_CURRENT_SOURCE_DIR@/platform \
@CMAKE_CURRENT_SOURCE_DIR@/test
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =

1
example/CMakeLists.txt Normal file
View File

@ -0,0 +1 @@
add_subdirectory("sACN Explorer")

View File

@ -0,0 +1,60 @@
project(sacnExplorer VERSION 1.1.1 LANGUAGES CXX)
find_package(QT NAMES Qt5 Qt6 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(${PROJECT_NAME} MANUAL_FINALIZATION)
else()
if(ANDROID)
add_library(${PROJECT_NAME} SHARED)
else()
add_executable(${PROJECT_NAME})
endif()
endif()
target_sources(${PROJECT_NAME}
PRIVATE
adduniversedialog.cpp
adduniversedialog.h
adduniversedialog.ui
multiverseitem.h
multiverseitem.cpp
multiversemodel.h
multiversemodel.cpp
main.cpp
multiverseview.cpp
multiverseview.h
multiverseview.ui
sacnexplorer.h
sacnexplorer.cpp
universemodel.cpp
universemodel.h
universeview.h
universeview.cpp
universeview.ui
universeviewdelegate.h
universeviewdelegate.cpp
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
Qt${QT_VERSION_MAJOR}::Widgets
QsACN
)
set_target_properties(${PROJECT_NAME} PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER ${PROJECT_NAME}.company235.com
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(${PROJECT_NAME})
endif()

View File

@ -0,0 +1,25 @@
#include "adduniversedialog.h"
#include "ui_adduniversedialog.h"
AddUniverseDialog::AddUniverseDialog(QWidget *parent, uint16_t universe,
QString title)
: QDialog(parent)
, ui(new Ui::AddUniverseDialog)
{
ui->setupUi(this);
ui->spinBox->setValue(universe);
setWindowTitle(title.isEmpty() ? tr("Add Universe") : title);
connect(this, &QDialog::accepted,
this, &AddUniverseDialog::requestAddition);
}
AddUniverseDialog::~AddUniverseDialog()
{
delete ui;
}
void AddUniverseDialog::requestAddition() {
emit additionRequested(ui->spinBox->value());
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <QDialog>
QT_BEGIN_NAMESPACE
namespace Ui {
class AddUniverseDialog;
}
QT_END_NAMESPACE
class AddUniverseDialog : public QDialog
{
Q_OBJECT
public:
explicit AddUniverseDialog(QWidget *parent = nullptr, uint16_t universe = 1,
QString title = "");
virtual ~AddUniverseDialog();
public slots:
void requestAddition();
signals:
void additionRequested(int universe);
private:
Ui::AddUniverseDialog *ui;
};

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddUniverseDialog</class>
<widget class="QDialog" name="AddUniverseDialog">
<layout class="QVBoxLayout" name="_3">
<item>
<layout class="QFormLayout" name="_2">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Universe</string>
</property>
<property name="buddy">
<cstring>spinBox</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBox">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>63999</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="dialogButtonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>dialogButtonBox</sender>
<signal>accepted()</signal>
<receiver>AddUniverseDialog</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>dialogButtonBox</sender>
<signal>rejected()</signal>
<receiver>AddUniverseDialog</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>

View File

@ -0,0 +1,7 @@
#include "sacnexplorer.h"
int main(int argc, char *argv[])
{
SacnExplorer a(argc, argv);
return a.exec();
}

View File

@ -0,0 +1,205 @@
#include "multiverseitem.h"
#include "multiversemodel.h"
#include <QFont>
#include <QMetaEnum>
#include <QMetaType>
/**
* @brief MultiverseItem::MultiverseItem
* @param universe
* @param parent
*/
MultiverseItem::MultiverseItem(MultiverseItem* parent,
QSacnUniverse *universe,
discoveredUniverse *discovery)
: universe_(universe)
, discovery_(discovery)
, parentItem_(parent)
, override_data_(QVariant())
{
if(parent)
parent->appendChild(this);
}
/**
* @brief MultiverseItem::~MultiverseItem
*/
MultiverseItem::~MultiverseItem()
{
for (const auto & child : childItems_)
delete child;
}
/**
* @brief MultiverseItem::appendChild
* @param item
*/
void MultiverseItem::appendChild(MultiverseItem* item)
{
childItems_.append(item);
}
/**
* @brief MultiverseItem::removeChild
* @param child
*/
void MultiverseItem::removeChild(MultiverseItem* child)
{
for (int i = 0; i < childItems_.size(); ++i)
if (childItems_.at(i) == child)
childItems_.remove(i);
}
/**
* @brief MultiverseItem::setOverrideData
* @param data
*/
void MultiverseItem::setOverrideData(QVariant data)
{
override_data_ = data;
}
/**
* @brief MultiverseItem::child
* @param row
* @return
*/
MultiverseItem* MultiverseItem::child(int row)
{
if (row < 0 || row >= childItems_.size())
return nullptr;
return childItems_.at(row);
}
/**
* @brief MultiverseItem::childCount
* @return
*/
int MultiverseItem::childCount() const
{
return childItems_.count();
}
/**
* @brief MultiverseItem::row
* @return
*/
int MultiverseItem::row() const
{
if (parentItem_)
return parentItem_->childItems_.indexOf(const_cast<MultiverseItem*>(this));
return 0;
}
/**
* @brief MultiverseItem::data
* @param column
* @return
*/
QVariant MultiverseItem::data(int column, int role) const
{
switch (role) {
case Qt::DisplayRole:
{
if (!universe_ && !discovery_)
return column ? QVariant() : override_data_;
if (universe_)
{
switch (static_cast<MultiverseModel::Column>(column))
{
case MultiverseModel::Universe:
return universe_->number();
case MultiverseModel::Priority:
{
auto v = universe_->priority();
if (v > 200)
return QVariant();
return v;
}
case MultiverseModel::Description:
return universe_->description();
default:
return QVariant();
}
}
if (discovery_)
{
switch (static_cast<MultiverseModel::Column>(column))
{
case MultiverseModel::Universe:
return discovery_->universe;
case MultiverseModel::Description:
return QString::fromUtf8(discovery_->description);
default:
return QVariant();
}
}
}
case Qt::FontRole:
if (!universe_ && !discovery_)
{
QFont bold;
bold.setBold(true);
return QVariant(bold);
}
return QVariant();
case Qt::EditRole:
if (universe_)
return QVariant(QVariant::fromValue(universe_));
if (discovery_)
return QVariant(QVariant::fromValue(static_cast<void*>(discovery_)));
return data(column, Qt::DisplayRole);
default:
return QVariant();
}
}
/**
* @brief MultiverseItem::flags
* @param column
* @return
*/
Qt::ItemFlags MultiverseItem::flags(int column, Qt::ItemFlags base) const
{
if (!universe_ && !universe_)
{
if (column)
return Qt::NoItemFlags;
return base & ~Qt::ItemIsSelectable;
}
base |= Qt::ItemIsEditable;
switch (static_cast<MultiverseModel::Column>(column))
{
case MultiverseModel::Universe:
return base;
case MultiverseModel::Priority:
return base;
case MultiverseModel::Description:
return base;
default:
return Qt::NoItemFlags;
}
}
/**
* @brief MultiverseItem::parentItem
* @return
*/
MultiverseItem * MultiverseItem::parentItem()
{
return parentItem_;
}

View File

@ -0,0 +1,44 @@
#pragma once
#include "sacn/extended.h"
#include <QVariant>
#include <QVector>
class QSacnUniverse; // forward declare
using discoveredUniverse = sACN::EXTENDED::DISCOVERY::discoveredUniverse;
/**
* @brief The MultiverseItem class
*/
class MultiverseItem
{
public:
explicit MultiverseItem(MultiverseItem* parentItem = nullptr,
QSacnUniverse * universe = nullptr,
discoveredUniverse * discovery = nullptr);
virtual ~MultiverseItem();
void appendChild(MultiverseItem* child);
void removeChild(MultiverseItem* child);
void setOverrideData(QVariant data);
MultiverseItem * child(int row);
int childCount() const;
QVariant data(int column, int role = Qt::DisplayRole) const;
Qt::ItemFlags flags(int column, Qt::ItemFlags base) const;
int row() const;
MultiverseItem * parentItem();
private:
QVector<MultiverseItem*> childItems_;
QSacnUniverse* universe_;
discoveredUniverse* discovery_;
MultiverseItem* parentItem_;
QVariant override_data_;
};
Q_DECLARE_METATYPE(discoveredUniverse*)

View File

@ -0,0 +1,234 @@
#include "multiverseitem.h"
#include "multiversemodel.h"
#include "uuid/uuid.h"
#include "qsacnnode.h"
#include <QMetaEnum>
/**
* @brief MultiverseModel::MultiverseModel
* @param parent
* @param node
*/
MultiverseModel::MultiverseModel(QObject *parent, QSacnNode *node)
: QAbstractItemModel(parent)
, node_(node)
, rootItem_(new MultiverseItem())
{
QMetaEnum e = QMetaEnum::fromType<MultiverseModel::Catagory>();
for (int k = 0; k < e.keyCount(); k++)
{
auto item = new MultiverseItem(rootItem_);
item->setOverrideData(QString(e.key(k)));
auto idx = MultiverseModel::index(k, 0, QModelIndex());
categoryIndexes.insert(static_cast<MultiverseModel::Catagory>
(e.value(k)), idx);
}
connect(node, &QSacnNode::subscribing,
this, &MultiverseModel::doSubscription);
connect(node, &QSacnNode::creating,
this, &MultiverseModel::doCreation);
}
/**
* @brief MultiverseModel::~MultiverseModel
*/
MultiverseModel::~MultiverseModel()
{
delete rootItem_;
}
/**
* @brief MultiverseModel::root
* @return
*/
MultiverseItem * MultiverseModel::root()
{
return rootItem_;
}
/**
* @brief MultiverseModel::getItem
* @param index
* @return
*/
MultiverseItem * MultiverseModel::getItem(const QModelIndex &index) const
{
if (index.isValid())
{
auto item = static_cast<MultiverseItem*>(index.internalPointer());
if (item)
return item;
}
return rootItem_;
}
/**
* @brief MultiverseModel::headerData
* @param section
* @param orientation
* @param role
* @return
*/
QVariant MultiverseModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
switch (static_cast<Column>(section)) {
case Universe:
return QString(tr("Universe"));
case Priority:
return QString(tr("Priority"));
case Description:
return QString(tr("Description"));
}
}
return QVariant();
}
/**
* @brief MultiverseModel::index
* @param row
* @param column
* @param parent
* @return
*/
QModelIndex MultiverseModel::index(int row, int column,
const QModelIndex &parent) const
{
if (parent.isValid() && parent.column() != 0)
return QModelIndex();
MultiverseItem *parentItem = getItem(parent);
if (!parentItem)
return QModelIndex();
auto childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
return QModelIndex();
}
/**
* @brief MultiverseModel::parent
* @param index
* @return
*/
QModelIndex MultiverseModel::parent(const QModelIndex &index) const
{
if (!checkIndex(index, CheckIndexOption::IndexIsValid |
CheckIndexOption::DoNotUseParent))
return QModelIndex();
auto childItem = getItem(index);
auto parentItem = childItem ? childItem->parentItem() : nullptr;
if (parentItem == rootItem_ || !parentItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
/**
* @brief MultiverseModel::rowCount
* @param parent
* @return
*/
int MultiverseModel::rowCount(const QModelIndex &parent) const
{
auto parentItem = getItem(parent);
return parentItem ? parentItem->childCount() : 0;
}
/**
* @brief MultiverseModel::columnCount
* @param parent
* @return
*/
int MultiverseModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return QMetaEnum::fromType<Column>().keyCount();
}
/**
* @brief MultiverseModel::data
* @param index
* @param role
* @return
*/
QVariant MultiverseModel::data(const QModelIndex &index, int role) const
{
if (!checkIndex(index, CheckIndexOption::IndexIsValid))
return QVariant();
return getItem(index)->data(index.column(), role);
}
/**
* @brief MultiverseModel::flags
* @param index
* @return
*/
Qt::ItemFlags MultiverseModel::flags(const QModelIndex &index) const
{
if (!checkIndex(index, CheckIndexOption::IndexIsValid))
return Qt::NoItemFlags;
auto item = getItem(index);
if (!item)
return Qt::NoItemFlags;
return item->flags(index.column(), QAbstractItemModel::flags(index));
}
/**
* @brief MultiverseModel::insert
* @param universe
* @param parent
* @return
*/
void MultiverseModel::insert(const QModelIndex &parent,
QSacnUniverse *universe,
discoveredUniverse *discovery)
{
auto item = getItem(parent);
beginInsertRows(parent, item->childCount(), item->childCount() + 1);
new MultiverseItem(item, universe, discovery);
endInsertRows();
}
/**
* @brief MultiverseModel::doSubscription
* @param universe
*/
void MultiverseModel::doSubscription(QSacnUniverse* universe)
{
auto parentIndex = categoryIndexes.value(MultiverseModel::Receiver);
insert(parentIndex, universe);
}
/**
* @brief MultiverseModel::doCreation
* @param universe
*/
void MultiverseModel::doCreation(QSacnUniverse* universe)
{
auto parentIndex = categoryIndexes.value(MultiverseModel::Source);
insert(parentIndex, universe);
}

View File

@ -0,0 +1,70 @@
#pragma once
#include <QAbstractItemModel>
#include "qsacnuniverse.h"
#include "multiverseitem.h"
class QSacnNode; // forward declare node class
/**
* @brief The MultiverseModel class
*/
class MultiverseModel
: public QAbstractItemModel
{
Q_OBJECT
public:
/// @brief The Catagory enum
enum Catagory {
Discovery,
Receiver,
Source
};
Q_ENUM(Catagory)
/// @brief The Column enum
enum Column {
Universe,
Priority,
Description
};
Q_ENUM(Column)
explicit MultiverseModel(QObject *parent = nullptr,
QSacnNode *node = nullptr);
virtual ~MultiverseModel();
// Model overrides:
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index,
int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
// non-standard model operations
MultiverseItem * root();
void insert(const QModelIndex &parent,
QSacnUniverse *universe = nullptr,
discoveredUniverse *discovery = nullptr);
QMap<MultiverseModel::Catagory, QModelIndex> categoryIndexes;
public slots:
void doSubscription(QSacnUniverse*);
void doCreation(QSacnUniverse*);
private:
MultiverseItem * getItem(const QModelIndex &index) const;
QSacnNode * node_;
MultiverseItem * rootItem_;
};

View File

@ -0,0 +1,30 @@
#include "multiverseview.h"
#include "multiversemodel.h"
#include "ui_multiverseview.h"
#include "universeviewdelegate.h"
#include <QDebug>
/**
* @brief MultiverseView::MultiverseView
* @param parent
*/
MultiverseView::MultiverseView(QWidget *parent, QSacnNode *node)
: QMainWindow(parent)
, ui(new Ui::MultiverseView)
{
ui->setupUi(this);
ui->multiverseView->setModel(new MultiverseModel(this, node));
ui->multiverseView->setItemDelegate(new UniverseViewDelegate());
ui->multiverseView->expandAll();
}
/**
* @brief MultiverseView::~MultiverseView
*/
MultiverseView::~MultiverseView()
{
delete ui;
}

View File

@ -0,0 +1,47 @@
/*
multiverseview.h
Copyright (c) 2021 Kevin Matz (kevin.matz@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <QMainWindow>
#include "qsacnnode.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MultiverseView;
}
QT_END_NAMESPACE
class MultiverseView
: public QMainWindow
{
Q_OBJECT
public:
explicit MultiverseView(QWidget *parent = nullptr,
QSacnNode* node = nullptr);
virtual ~MultiverseView();
private:
Ui::MultiverseView *ui;
};

View File

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MultiverseView</class>
<widget class="QMainWindow" name="MultiverseView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>391</height>
</rect>
</property>
<property name="windowTitle">
<string>sACN Multiverse</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" name="multiverseView">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="autoExpandDelay">
<number>0</number>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="animated">
<bool>true</bool>
</property>
<attribute name="headerDefaultSectionSize">
<number>120</number>
</attribute>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>25</height>
</rect>
</property>
<widget class="QMenu" name="menuEPI_19">
<property name="title">
<string>EPI 19</string>
</property>
<addaction name="actionUACN"/>
</widget>
<addaction name="menuEPI_19"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="toolBar">
<property name="enabled">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionCreate"/>
<addaction name="actionTerminate"/>
<addaction name="separator"/>
<addaction name="actionSubscribe"/>
<addaction name="actionUnsubscribe"/>
</widget>
<action name="actionSubscribe">
<property name="text">
<string>Subscribe</string>
</property>
<property name="toolTip">
<string>Subscribe to an sACN Universe</string>
</property>
<property name="shortcut">
<string>+</string>
</property>
</action>
<action name="actionUnsubscribe">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Unsubscribe</string>
</property>
<property name="shortcut">
<string>-</string>
</property>
</action>
<action name="actionCreate">
<property name="text">
<string>Create</string>
</property>
<property name="shortcut">
<string>N</string>
</property>
</action>
<action name="actionTerminate">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Terminate</string>
</property>
<property name="toolTip">
<string>Terminate</string>
</property>
<property name="shortcut">
<string>X</string>
</property>
</action>
<action name="actionUACN">
<property name="text">
<string>User Assigned Component Name</string>
</property>
<property name="toolTip">
<string>Set this Component's UACN</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,74 @@
#include "sacnexplorer.h"
#include <QDebug>
#include <QSettings>
SacnExplorer::SacnExplorer(int argc, char *argv[])
: QApplication(argc, argv)
{
setOrganizationName("Company235");
setOrganizationDomain("company235.com");
setApplicationName(tr("sACN Explorer"));
loadSettings();
node_ = new QSacnNode(this, cid_);
qDebug() << "sACN node started with CID" << node_->cid().string().c_str();
node_->assignUserName(applicationName().toStdString());
qDebug() << "Starting sACN discovery.";
node_->discoveryStart();
window = new MultiverseView(nullptr, node_);
window->show();
node_->subscribe(1);
node_->subscribe(2);
node_->subscribe(3);
node_->subscribe(4);
node_->create(1);
node_->sACN::Source::universe(1)->setValue(100, 1);
node_->create(2);
node_->sACN::Source::universe(2)->setValue(100, 2);
node_->create(3);
node_->sACN::Source::universe(3)->setValue(100, 3);
}
SacnExplorer::~SacnExplorer()
{
saveSettings();
delete window;
delete node_;
}
/**
* @brief MultiverseView::loadSettings
*/
void SacnExplorer::loadSettings()
{
QSettings settings;
qDebug() << "Loading application settings from" << settings.fileName();
settings.beginGroup("acn");
cid_ = QUuid(settings.value("cid",
QUuid::createUuid().toString()).toString());
qDebug() << "Persistent CID is" << cid_.toString().toStdString().c_str();
settings.endGroup();
}
/**
* @brief MultiverseView::saveSettings
*/
void SacnExplorer::saveSettings()
{
QSettings settings;
qDebug() << "Saving application settings to" << settings.fileName();
settings.beginGroup("acn");
settings.setValue("cid", cid_.toString());
settings.endGroup();
}

View File

@ -0,0 +1,25 @@
#pragma once
#include "multiverseview.h"
#include "qsacnnode.h"
#include <QApplication>
#include <QUuid>
class SacnExplorer
: public QApplication
{
Q_OBJECT
public:
explicit SacnExplorer(int argc, char *argv[]);
virtual ~SacnExplorer();
private:
void loadSettings();
void saveSettings();
MultiverseView* window;
QSacnNode *node_;
QUuid cid_;
};

View File

@ -0,0 +1,259 @@
#include "universemodel.h"
#include <QBrush>
#include <QFont>
#include <QChar>
#include <QMetaEnum>
/**
* @brief UniverseModel::UniverseModel
* @param parent
*/
UniverseModel::UniverseModel(QObject *parent)
: QAbstractTableModel(parent)
, universe_(nullptr)
, data_mode_(Decimal)
{
}
/**
* @brief UniverseModel::headerData
* @param section
* @param orientation
* @param role
* @return
*/
QVariant UniverseModel::headerData(int section, Qt::Orientation orientation, int role) const
{
switch (role)
{
case Qt::DisplayRole:
switch (orientation)
{
case Qt::Horizontal:
return section + 1;
case Qt::Vertical:
return section * 10;
}
default:
return QVariant();
}
}
/**
* @brief UniverseModel::rowCount
* @param parent
* @return
*/
int UniverseModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return 52;
}
/**
* @brief UniverseModel::columnCount
* @param parent
* @return
*/
int UniverseModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return 10;
}
/**
* @brief UniverseModel::data
* @param index
* @param role
* @return
*/
QVariant UniverseModel::data(const QModelIndex &index, int role) const
{
if (!checkIndex(index, CheckIndexOption::IndexIsValid))
return QVariant();
if (!universe_)
return QVariant();
uint16_t slot = (index.row() * 10) + (index.column() + 1);
switch (role) {
case Qt::DisplayRole:
{
if (slot == 0 || slot > 512)
return QVariant();
switch (data_mode_)
{
case Decimal:
return universe_->slot(slot);
case Hex:
return QString("%1")
.arg(universe_->slot(slot), 2, 16, QChar('0'))
.toUpper();
case Percent:
return QString("%1%").arg((universe_->slot(slot) / 255.0F) * 100,
0, 'f', 0, '0');
}
return QVariant();
}
case Qt::FontRole:
return QFont("monospace");
case Qt::TextAlignmentRole:
return int(Qt::AlignCenter | Qt::AlignVCenter);
case Qt::ForegroundRole:
{
if (slot > universe_->activeSlots() - 1)
return QBrush(Qt::gray);
return QVariant();
}
default:
return QVariant();
}
}
/**
* @brief UniverseModel::setData
* @param index
* @param value
* @param role
* @return
*/
bool UniverseModel::setData(const QModelIndex &index, const QVariant &value,
int role)
{
if (!universe_->isEditable())
return false;
if (data(index, role) == value)
return false;
uint16_t slot = (index.row() * 10) + (index.column() + 1);
uint8_t data;
switch (data_mode_)
{
case Decimal:
{
if (!value.canConvert<uint>())
return false;
uint d = value.toUInt();
if (d > 255)
return false;
data = d;
}
break;
case Hex:
{
if (!value.canConvert<QString>())
return false;
bool ok;
uint d = value.toString().toInt(&ok, 16);
if (!ok || d > 255)
return false;
data = d;
}
break;
case Percent:
{
if (!value.canConvert<double>())
return false;
int d = 255 * (value.toDouble() / 100);
if (d < 0 || d > 255)
return false;
data = d;
}
break;
}
universe_->setValue(slot, data);
emit dataChanged(index, index, QVector<int>() << role);
return true;
}
/**
* @brief UniverseModel::flags
* @param index
* @return
*/
Qt::ItemFlags UniverseModel::flags(const QModelIndex &index) const
{
if (!checkIndex(index, CheckIndexOption::IndexIsValid))
return Qt::NoItemFlags;
if (!universe_)
return Qt::NoItemFlags;
uint16_t slot = (index.row() * 10) + (index.column() + 1);
if (slot == 0 || slot > 512)
return Qt::NoItemFlags;
auto f = QAbstractItemModel::flags(index);
return universe_->isEditable() ? f | Qt::ItemIsEditable : f;
}
/**
* @brief UniverseModel::universeRefreshed
*/
void UniverseModel::universeRefreshed() {
emit dataChanged(index(0,0), index(rowCount(), columnCount()));
emit recievedUpdate(universe_);
}
/**
* @brief UniverseModel::setDataMode
* @param mode
*/
void UniverseModel::setDataMode(const QString mode)
{
auto metaEnum = QMetaEnum::fromType<data_modes>();
data_mode_ = static_cast<data_modes>(metaEnum.keyToValue(mode.toLocal8Bit()));
emit dataChanged(index(0,0), index(rowCount(), columnCount()));
}
/**
* @brief UniverseModel::setUniverse
* @param universe
*/
void UniverseModel::setUniverse(QSacnUniverse *universe)
{
if (universe_)
disconnect(universe_, 0, this, 0);
universe_ = universe;
connect(universe_, &QSacnUniverse::changed,
this, &UniverseModel::universeRefreshed);
}
/**
* @brief UniverseModel::universe
* @return
*/
QSacnUniverse * UniverseModel::universe() const
{
return universe_;
}
/**
* @brief UniverseModel::dataMode
* @return
*/
UniverseModel::data_modes UniverseModel::dataMode()
{
return data_mode_;
}

View File

@ -0,0 +1,48 @@
#pragma once
#include <QAbstractTableModel>
#include "qsacnuniverse.h"
class UniverseModel
: public QAbstractTableModel
{
Q_OBJECT
public:
/// @brief The data_modes enum
enum data_modes {
Decimal,
Hex,
Percent
};
Q_ENUM(data_modes)
explicit UniverseModel(QObject *parent = nullptr);
// Model overrides:
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index,
int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
// Data source:
void setUniverse(QSacnUniverse *universe);
QSacnUniverse * universe() const;
data_modes dataMode();
signals:
void recievedUpdate(const QSacnUniverse*);
public slots:
void universeRefreshed();
void setDataMode(const QString mode);
private:
QSacnUniverse * universe_;
data_modes data_mode_;
};

View File

@ -0,0 +1,98 @@
#include "universeview.h"
#include "ui_universeview.h"
#include <QComboBox>
#include <QLabel>
#include <QMetaEnum>
/**
* @brief UniverseView::UniverseView
* @param parent
*/
UniverseView::UniverseView(QWidget *parent, QSacnUniverse *universe)
: QMainWindow(parent)
, ui(new Ui::UniverseView())
{
ui->setupUi(this);
auto model = new UniverseModel(this);
ui->tableView->setModel(model);
model->setUniverse(universe);
// update the status bar whenever the universe refreshes
connect(model, &UniverseModel::recievedUpdate,
this, &UniverseView::updateStatus);
// add data format combobox to toolbar
auto formatLabel = new QLabel(this);
formatLabel->setText(tr("Data Format") + ": ");
ui->toolBar->addWidget(formatLabel);
auto dataModes = new QComboBox(this);
const QMetaEnum types = QMetaEnum::fromType<UniverseModel::data_modes>();
for (int i=0; i < types.keyCount(); ++i)
dataModes->addItem(types.key(i));
connect(dataModes, &QComboBox::currentTextChanged,
model, &UniverseModel::setDataMode);
ui->toolBar->addWidget(dataModes);
ui->toolBar->addSeparator();
// add priority picker to the toolbar
auto priorityLabel = new QLabel(this);
priorityLabel->setText(tr("Priority") + ": ");
ui->toolBar->addWidget(priorityLabel);
prioritySpinBox = new QSpinBox(this);
prioritySpinBox->setMinimum(0);
prioritySpinBox->setValue(100);
prioritySpinBox->setMaximum(200);
prioritySpinBox->setEnabled(false);
ui->toolBar->addWidget(prioritySpinBox);
ui->toolBar->addSeparator();
updateStatus(universe);
if (universe->isEditable())
{
prioritySpinBox->setValue(universe->priority());
prioritySpinBox->setEnabled(true);
connect(prioritySpinBox, &QSpinBox::valueChanged,
universe, &QSacnUniverse::setPriority);
}
}
/**
* @brief UniverseView::~UniverseView
*/
UniverseView::~UniverseView()
{
delete ui;
}
/**
* @brief UniverseView::updateStatusBar
* @param universe
*/
void UniverseView::updateStatus(const QSacnUniverse * universe)
{
// window title
QString titlestring = QString("%1 " + tr("Universe") + " %2 - \"%3\"").arg(
universe->isEditable() ? tr("Editing") : tr("Viewing"),
QString::number(universe->number()),
universe->description());
this->setWindowTitle(titlestring);
if (!universe->isEditable())
{
// status bar
ui->statusbar->clearMessage();
QString message = QString("%1 " + tr("Hz")).arg(
QString::number(universe->rxRate()));
ui->statusbar->showMessage(message, 2500);
// priority spinbox
prioritySpinBox->setValue(universe->priority());
}
}

View File

@ -0,0 +1,31 @@
#pragma once
#include <QMainWindow>
#include <QSpinBox>
#include "multiversemodel.h"
#include "universemodel.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class UniverseView;
}
QT_END_NAMESPACE
class UniverseView
: public QMainWindow
{
Q_OBJECT
public:
explicit UniverseView(QWidget *parent = nullptr,
QSacnUniverse* universe = nullptr);
virtual ~UniverseView();
public slots:
void updateStatus(const QSacnUniverse*);
private:
Ui::UniverseView *ui;
QSpinBox *prioritySpinBox;
};

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>UniverseView</class>
<widget class="QMainWindow" name="UniverseView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>800</height>
</rect>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTableView" name="tableView">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>60</number>
</attribute>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar"/>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="toolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,32 @@
#include "adduniversedialog.h"
#include "qsacnuniverse.h"
#include "sacn/extended.h"
#include "universeview.h"
#include "universeviewdelegate.h"
QWidget * UniverseViewDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QVariant data = index.data(Qt::EditRole);
if (data.metaType().id() == qMetaTypeId<QSacnUniverse*>())
{
auto univ = data.value<QSacnUniverse*>();
auto universeView = new UniverseView(parent, univ);
universeView->show();
return new QWidget(parent);
}
if (index.data().canConvert<sACN::EXTENDED::DISCOVERY::discoveredUniverse*>())
{
auto disc = data.value<sACN::EXTENDED::DISCOVERY::discoveredUniverse*>();
auto subscribe = new AddUniverseDialog(parent, disc->universe,
tr("Subscribe to Universe"));
return subscribe;
}
return QStyledItemDelegate::createEditor(parent, option, index);
}

View File

@ -0,0 +1,14 @@
#pragma once
#include <QStyledItemDelegate>
class UniverseViewDelegate
: public QStyledItemDelegate
{
Q_OBJECT
public:
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const override;
};

1
platform/CMakeLists.txt Normal file
View File

@ -0,0 +1 @@
add_subdirectory(qt)

View File

@ -2,14 +2,8 @@ project(QsACN VERSION 0.1 LANGUAGES CXX)
cmake_minimum_required(VERSION 3.20)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG")
endif()
find_package(QT NAMES Qt6 Qt5 COMPONENTS Network Gui REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network Gui REQUIRED)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Network REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network REQUIRED)
add_library(${PROJECT_NAME} SHARED)
@ -18,15 +12,16 @@ target_sources(${PROJECT_NAME}
qsacnnode.h
qsacnuniverse.h
PRIVATE
qsacn_global.h
qsacnnode.cpp
qsacnuniverse.cpp
qsacn_global.h
)
target_link_libraries(${PROJECT_NAME} PUBLIC
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Gui
OpenLCP)
target_link_libraries(${PROJECT_NAME}
PUBLIC
Qt${QT_VERSION_MAJOR}::Network
LCP
)
target_compile_definitions(${PROJECT_NAME} PUBLIC ${PROJECT_NAME}_LIBRARY)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@ -1,7 +1,5 @@
project(OpenLCP VERSION 0.2.0 LANGUAGES CXX)
set(DEFAULT_BUILD_TYPE "Release")
cmake_minimum_required(VERSION 3.20)
project(LCP VERSION 0.2.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

Some files were not shown because too many files have changed in this diff Show More