This commit is contained in:
gallaert
2018-08-29 21:01:36 +01:00
18 changed files with 290 additions and 57 deletions
+2 -5
View File
@@ -202,11 +202,8 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
message(STATUS "BOOST_INCLUDEDIR is ${BOOST_INCLUDEDIR}") message(STATUS "BOOST_INCLUDEDIR is ${BOOST_INCLUDEDIR}")
endif() endif()
if (NOT USE_AEONWAVE) set (OPENAL_INCLUDE_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/include)
set (OPENAL_INCLUDE_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/include) set (OPENAL_LIBRARY_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib)
set (OPENAL_LIBRARY_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib)
message(STATUS "OPENAL_INCLUDE_DIR is ${OPENAL_INCLUDE_DIR}")
endif()
endif (MSVC AND MSVC_3RDPARTY_ROOT) endif (MSVC AND MSVC_3RDPARTY_ROOT)
if(APPLE) if(APPLE)
+17 -8
View File
@@ -97,17 +97,26 @@ namespace canvas
|| (!geo_node->isDirty() && !_projection_dirty) ) || (!geo_node->isDirty() && !_projection_dirty) )
continue; continue;
GeoCoord lat = parseGeoCoord(geo_node->getLat()); double latD = -9999.0, lonD = -9999.0;
if( lat.type != GeoCoord::LATITUDE ) if (geo_node->isDirty()) {
continue; GeoCoord lat = parseGeoCoord(geo_node->getLat());
if( lat.type != GeoCoord::LATITUDE )
continue;
GeoCoord lon = parseGeoCoord(geo_node->getLon()); GeoCoord lon = parseGeoCoord(geo_node->getLon());
if( lon.type != GeoCoord::LONGITUDE ) if( lon.type != GeoCoord::LONGITUDE )
continue; continue;
Projection::ScreenPosition pos = // save the parsed values so we can re-use them if only projection
_projection->worldToScreen(lat.value, lon.value); // is changed (very common case for moving vehicle)
latD = lat.value;
lonD = lon.value;
geo_node->setCachedLatLon(std::make_pair(latD, lonD));
} else {
std::tie(latD, lonD) = geo_node->getCachedLatLon();
}
Projection::ScreenPosition pos = _projection->worldToScreen(latD, lonD);
geo_node->setScreenPos(pos.x, pos.y); geo_node->setScreenPos(pos.x, pos.y);
// geo_node->print(); // geo_node->print();
+3 -3
View File
@@ -863,6 +863,9 @@ namespace canvas
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void Path::childChanged(SGPropertyNode* child) void Path::childChanged(SGPropertyNode* child)
{ {
if( child->getParent() != _node )
return;
const std::string& name = child->getNameString(); const std::string& name = child->getNameString();
const std::string &prName = child->getParent()->getNameString(); const std::string &prName = child->getParent()->getNameString();
@@ -892,9 +895,6 @@ namespace canvas
return; return;
} }
if( child->getParent() != _node )
return;
if( name == "cmd" ) if( name == "cmd" )
_attributes_dirty |= CMDS; _attributes_dirty |= CMDS;
else if( name == "coord" ) else if( name == "coord" )
+25 -5
View File
@@ -67,6 +67,7 @@ namespace canvas
{ {
_node_lat = node; _node_lat = node;
_status &= ~LAT_MISSING; _status &= ~LAT_MISSING;
_xNode.reset();
if( node == _node_lon ) if( node == _node_lon )
{ {
@@ -79,6 +80,7 @@ namespace canvas
{ {
_node_lon = node; _node_lon = node;
_status &= ~LON_MISSING; _status &= ~LON_MISSING;
_yNode.reset();
if( node == _node_lat ) if( node == _node_lat )
{ {
@@ -97,19 +99,34 @@ namespace canvas
return _node_lon ? _node_lon->getStringValue() : ""; return _node_lon ? _node_lon->getStringValue() : "";
} }
void setCachedLatLon(const std::pair<double, double>& latLon)
{ _cachedLatLon = latLon; }
std::pair<double, double> getCachedLatLon()
{ return _cachedLatLon; }
void setTargetName(const std::string& name) void setTargetName(const std::string& name)
{ {
_target_name = name; _target_name = name;
_xNode.reset();
_yNode.reset();
} }
void setScreenPos(float x, float y) void setScreenPos(float x, float y)
{ {
assert( isComplete() ); assert( isComplete() );
SGPropertyNode *parent = _node_lat->getParent(); if (!_xNode) {
parent->getChild(_target_name, _node_lat->getIndex(), true) SGPropertyNode *parent = _node_lat->getParent();
->setDoubleValue(x); _xNode = parent->getChild(_target_name, _node_lat->getIndex(), true);
parent->getChild(_target_name, _node_lon->getIndex(), true) }
->setDoubleValue(y);
if (!_yNode) {
SGPropertyNode *parent = _node_lat->getParent();
_yNode = parent->getChild(_target_name, _node_lon->getIndex(), true);
}
_xNode->setDoubleValue(x);
_yNode->setDoubleValue(y);
} }
void print() void print()
@@ -125,6 +142,9 @@ namespace canvas
SGPropertyNode *_node_lat, SGPropertyNode *_node_lat,
*_node_lon; *_node_lon;
std::string _target_name; std::string _target_name;
SGPropertyNode_ptr _xNode,
_yNode;
std::pair<double, double> _cachedLatLon;
}; };
+1 -1
View File
@@ -1,7 +1,7 @@
include (SimGearComponent) include (SimGearComponent)
set(HEADERS debug_types.h logstream.hxx BufferedLogCallback.hxx) set(HEADERS debug_types.h logstream.hxx BufferedLogCallback.hxx OsgIoCapture.hxx)
set(SOURCES logstream.cxx BufferedLogCallback.cxx) set(SOURCES logstream.cxx BufferedLogCallback.cxx)
simgear_component(debug debug "${SOURCES}" "${HEADERS}") simgear_component(debug debug "${SOURCES}" "${HEADERS}")
+45
View File
@@ -0,0 +1,45 @@
#include <cstring>
#include <osg/Notify>
using namespace osg;
/**
* merge OSG output into our logging system, so it gets recorded to file,
* and so we can display a GUI console with renderer issues, especially
* shader compilation warnings and errors.
*/
class NotifyLogger : public osg::NotifyHandler
{
public:
// note this callback will be invoked by OSG from multiple threads.
// fortunately our Simgear logging implementation already handles
// that internally, so we simply pass the message on.
virtual void notify(osg::NotifySeverity severity, const char* message) {
// Detect whether a osg::Reference derived object is deleted with a non-zero
// reference count. In this case trigger a segfault to get a stack trace.
if (strstr(message, "the final reference count was")) {
// as this is going to segfault ignore the translation of severity and always output the message.
SG_LOG(SG_GL, SG_ALERT, message);
int* trigger_segfault = 0;
*trigger_segfault = 0;
return;
}
SG_LOG(SG_GL, translateSeverity(severity), message);
}
private:
sgDebugPriority translateSeverity(osg::NotifySeverity severity) {
switch (severity) {
case osg::ALWAYS:
case osg::FATAL: return SG_ALERT;
case osg::WARN: return SG_WARN;
case osg::NOTICE:
case osg::INFO: return SG_INFO;
case osg::DEBUG_FP:
case osg::DEBUG_INFO: return SG_DEBUG;
default: return SG_ALERT;
}
}
};
+2 -1
View File
@@ -34,7 +34,8 @@ typedef enum {
SG_GUI = 0x00800000, SG_GUI = 0x00800000,
SG_TERRASYNC = 0x01000000, SG_TERRASYNC = 0x01000000,
SG_PARTICLES = 0x02000000, SG_PARTICLES = 0x02000000,
SG_UNDEFD = 0x04000000, // For range checking SG_HEADLESS = 0x04000000,
SG_UNDEFD = 0x08000000, // For range checking
SG_ALL = 0xFFFFFFFF SG_ALL = 0xFFFFFFFF
} sgDebugClass; } sgDebugClass;
+1
View File
@@ -100,6 +100,7 @@ const char* LogCallback::debugClassToString(sgDebugClass c)
case SG_GUI: return "gui"; case SG_GUI: return "gui";
case SG_TERRASYNC: return "terrasync"; case SG_TERRASYNC: return "terrasync";
case SG_PARTICLES: return "particles"; case SG_PARTICLES: return "particles";
case SG_HEADLESS: return "headless";
default: return "unknown"; default: return "unknown";
} }
} }
+7 -4
View File
@@ -1006,11 +1006,11 @@ HTTPRepository::failure() const
SGPath cachePath = basePath; SGPath cachePath = basePath;
cachePath.append(".hashes"); cachePath.append(".hashes");
sg_ofstream stream(cachePath, std::ios::out | std::ios::trunc); sg_ofstream stream(cachePath, std::ios::out | std::ios::trunc | std::ios::binary);
HashCache::const_iterator it; HashCache::const_iterator it;
for (it = hashes.begin(); it != hashes.end(); ++it) { for (it = hashes.begin(); it != hashes.end(); ++it) {
stream << it->filePath << ":" << it->modTime << ":" stream << it->filePath << "*" << it->modTime << "*"
<< it->lengthBytes << ":" << it->hashHex << "\n"; << it->lengthBytes << "*" << it->hashHex << "\n";
} }
stream.close(); stream.close();
hashCacheDirty = false; hashCacheDirty = false;
@@ -1034,7 +1034,7 @@ HTTPRepository::failure() const
if( line.empty() || line[0] == '#' ) if( line.empty() || line[0] == '#' )
continue; continue;
string_list tokens = simgear::strutils::split( line, ":" ); string_list tokens = simgear::strutils::split(line, "*");
if( tokens.size() < 4 ) { if( tokens.size() < 4 ) {
SG_LOG(SG_TERRASYNC, SG_WARN, "invalid entry in '" << cachePath << "': '" << line << "' (ignoring line)"); SG_LOG(SG_TERRASYNC, SG_WARN, "invalid entry in '" << cachePath << "': '" << line << "' (ignoring line)");
continue; continue;
@@ -1056,6 +1056,9 @@ HTTPRepository::failure() const
entry.lengthBytes = strtol(sizeData.c_str(), NULL, 10); entry.lengthBytes = strtol(sizeData.c_str(), NULL, 10);
hashes.push_back(entry); hashes.push_back(entry);
} }
SG_LOG(SG_TERRASYNC, SG_INFO, "restored hashes:" << hashes.size());
} }
class DirectoryWithPath class DirectoryWithPath
+35
View File
@@ -1379,6 +1379,35 @@ std::string formatLatLonValueAsString(double deg, LatLonFormat format,
case LatLonFormat::DECIMAL_DEGREES_SYMBOL: case LatLonFormat::DECIMAL_DEGREES_SYMBOL:
::snprintf(buf, sizeof(buf), "%3.6f%s%c", deg, degSym, c); ::snprintf(buf, sizeof(buf), "%3.6f%s%c", deg, degSym, c);
break; break;
case LatLonFormat::ICAO_ROUTE_DEGREES:
{
min = (deg - int(deg)) * 60.0;
if (min >= 59.9995) {
min -= 60.0;
deg += 1.0;
}
if (static_cast<int>(min) == 0) {
// 7-digit mode
if (c == 'N' || c == 'S') {
snprintf(buf, sizeof(buf), "%02d%c", int(deg), c);
} else {
snprintf(buf, sizeof(buf), "%03d%c", int(deg), c);
}
} else {
// 11-digit mode
if (c == 'N' || c == 'S') {
snprintf(buf, sizeof(buf), "%02d%02d%c", int(deg), int(min), c);
} else {
snprintf(buf, sizeof(buf), "%03d%02d%c", int(deg), int(min), c);
}
}
break;
}
default:
break;
} }
return std::string(buf); return std::string(buf);
@@ -1390,6 +1419,12 @@ std::string formatGeodAsString(const SGGeod& geod, LatLonFormat format,
const char ns = (geod.getLatitudeDeg() > 0.0) ? 'N' : 'S'; const char ns = (geod.getLatitudeDeg() > 0.0) ? 'N' : 'S';
const char ew = (geod.getLongitudeDeg() > 0.0) ? 'E' : 'W'; const char ew = (geod.getLongitudeDeg() > 0.0) ? 'E' : 'W';
// no comma seperator
if (format == LatLonFormat::ICAO_ROUTE_DEGREES) {
return formatLatLonValueAsString(geod.getLatitudeDeg(), format, ns, degreeSymbol) +
formatLatLonValueAsString(geod.getLongitudeDeg(), format, ew, degreeSymbol);
}
return formatLatLonValueAsString(geod.getLatitudeDeg(), format, ns, degreeSymbol) + "," return formatLatLonValueAsString(geod.getLatitudeDeg(), format, ns, degreeSymbol) + ","
+ formatLatLonValueAsString(geod.getLongitudeDeg(), format, ew, degreeSymbol); + formatLatLonValueAsString(geod.getLongitudeDeg(), format, ew, degreeSymbol);
} }
+2 -1
View File
@@ -396,7 +396,8 @@ namespace simgear {
ZERO_PAD_DEGREES_MINUTES, ZERO_PAD_DEGREES_MINUTES,
ZERO_PAD_DEGREES_MINUTES_SECONDS, ZERO_PAD_DEGREES_MINUTES_SECONDS,
TRINITY_HOUSE, ///< dd* mm'.mmm X, ddd* mm'.mmm X (Trinity House Navigation standard). TRINITY_HOUSE, ///< dd* mm'.mmm X, ddd* mm'.mmm X (Trinity House Navigation standard).
DECIMAL_DEGREES_SYMBOL ///< 88.4*N,4.54*W DECIMAL_DEGREES_SYMBOL, ///< 88.4*N,4.54*W
ICAO_ROUTE_DEGREES, ///< 52N045W or 5212N04512W - precision auto-selected
}; };
enum class DegreeSymbol enum class DegreeSymbol
+10
View File
@@ -685,6 +685,14 @@ void test_formatGeod()
SG_CHECK_EQUAL(strutils::formatGeodAsString(a, strutils::LatLonFormat::DEGREES_MINUTES_SECONDS), SG_CHECK_EQUAL(strutils::formatGeodAsString(a, strutils::LatLonFormat::DEGREES_MINUTES_SECONDS),
"55*27'00.0\"N,3*27'36.0\"W"); "55*27'00.0\"N,3*27'36.0\"W");
SG_CHECK_EQUAL(strutils::formatGeodAsString(a, strutils::LatLonFormat::ICAO_ROUTE_DEGREES),
"5527N00327W");
SGGeod shortA = SGGeod::fromDeg(106, -34);
SG_CHECK_EQUAL(strutils::formatGeodAsString(shortA, strutils::LatLonFormat::ICAO_ROUTE_DEGREES),
"34S106E");
const auto s = strutils::formatGeodAsString(a, const auto s = strutils::formatGeodAsString(a,
strutils::LatLonFormat::ZERO_PAD_DEGREES_MINUTES, strutils::LatLonFormat::ZERO_PAD_DEGREES_MINUTES,
strutils::DegreeSymbol::LATIN1_DEGREE); strutils::DegreeSymbol::LATIN1_DEGREE);
@@ -696,6 +704,8 @@ void test_formatGeod()
strutils::LatLonFormat::DECIMAL_DEGREES_SYMBOL, strutils::LatLonFormat::DECIMAL_DEGREES_SYMBOL,
strutils::DegreeSymbol::UTF8_DEGREE); strutils::DegreeSymbol::UTF8_DEGREE);
SG_CHECK_EQUAL(s2, "6.156800\xC2\xB0S,106.827800\xC2\xB0" "E"); SG_CHECK_EQUAL(s2, "6.156800\xC2\xB0S,106.827800\xC2\xB0" "E");
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
+3 -3
View File
@@ -45,8 +45,7 @@ class Install::PackageArchiveDownloader : public HTTP::Request
public: public:
PackageArchiveDownloader(InstallRef aOwner) : PackageArchiveDownloader(InstallRef aOwner) :
HTTP::Request("" /* dummy URL */), HTTP::Request("" /* dummy URL */),
m_owner(aOwner), m_owner(aOwner)
m_downloaded(0)
{ {
m_urls = m_owner->package()->downloadUrls(); m_urls = m_owner->package()->downloadUrls();
if (m_urls.empty()) { if (m_urls.empty()) {
@@ -115,6 +114,7 @@ protected:
{ {
const uint8_t* ubytes = (uint8_t*) s; const uint8_t* ubytes = (uint8_t*) s;
SG_MD5Update(&m_md5, ubytes, n); SG_MD5Update(&m_md5, ubytes, n);
m_downloaded += n;
m_owner->installProgress(m_downloaded, responseLength()); m_owner->installProgress(m_downloaded, responseLength());
m_extractor->extractBytes(ubytes, n); m_extractor->extractBytes(ubytes, n);
} }
@@ -221,7 +221,7 @@ private:
string_list m_urls; string_list m_urls;
SG_MD5_CTX m_md5; SG_MD5_CTX m_md5;
SGPath m_extractPath; SGPath m_extractPath;
size_t m_downloaded; size_t m_downloaded = 0;
std::unique_ptr<ArchiveExtractor> m_extractor; std::unique_ptr<ArchiveExtractor> m_extractor;
}; };
+1 -1
View File
@@ -751,7 +751,7 @@ typedef SGSharedPtr<const SGPropertyNode> SGConstPropertyNode_ptr;
namespace simgear namespace simgear
{ {
typedef std::vector<SGPropertyNode_ptr> PropertyList; using PropertyList = std::vector<SGPropertyNode_ptr>;
} }
/** /**
+23
View File
@@ -1,3 +1,20 @@
// Copyright (C) 2018 James Turner - <james@flightgear>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
/** \file /** \file
* *
* Forward declarations for properties (and related structures) * Forward declarations for properties (and related structures)
@@ -7,12 +24,18 @@
#define SG_PROPS_FWD_HXX #define SG_PROPS_FWD_HXX
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
#include <vector>
class SGPropertyNode; class SGPropertyNode;
typedef SGSharedPtr<SGPropertyNode> SGPropertyNode_ptr; typedef SGSharedPtr<SGPropertyNode> SGPropertyNode_ptr;
typedef SGSharedPtr<const SGPropertyNode> SGConstPropertyNode_ptr; typedef SGSharedPtr<const SGPropertyNode> SGConstPropertyNode_ptr;
namespace simgear
{
using PropertyList = std::vector<SGPropertyNode_ptr>;
}
class SGCondition; class SGCondition;
#endif // of SG_PROPS_FWD_HXX #endif // of SG_PROPS_FWD_HXX
+31 -17
View File
@@ -440,6 +440,8 @@ SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
if (name.empty()) { if (name.empty()) {
SG_LOG(SG_GENERAL, SG_DEV_WARN, "adding subsystem to group without a name"); SG_LOG(SG_GENERAL, SG_DEV_WARN, "adding subsystem to group without a name");
// TODO, make this an exception in the future // TODO, make this an exception in the future
} else if (subsystem->name().empty()) {
subsystem->set_name(name);
} else if (name != subsystem->name()) { } else if (name != subsystem->name()) {
SG_LOG(SG_GENERAL, SG_DEV_WARN, "adding subsystem to group with name '" << name SG_LOG(SG_GENERAL, SG_DEV_WARN, "adding subsystem to group with name '" << name
<< "', but name() returns '" << subsystem->name() << "'"); << "', but name() returns '" << subsystem->name() << "'");
@@ -453,14 +455,25 @@ SGSubsystemGroup::set_subsystem (const string &name, SGSubsystem * subsystem,
subsystem->set_group(this); subsystem->set_group(this);
notifyDidChange(subsystem, State::ADD); notifyDidChange(subsystem, State::ADD);
if (_state != State::INVALID) { if (_state != State::INVALID && (_state <= State::POSTINIT)) {
SG_LOG(SG_GENERAL, SG_DEV_WARN, "TODO: implement SGSubsystemGroup transition when adding after init");
// transition to the correct state // transition to the correct state
// bind if (_state >= State::BIND) {
notifyWillChange(subsystem, State::BIND);
subsystem->bind();
notifyDidChange(subsystem, State::BIND);
}
// init if (_state >= State::INIT) {
notifyWillChange(subsystem, State::INIT);
subsystem->init();
notifyDidChange(subsystem, State::INIT);
}
// post-init if (_state == State::POSTINIT) {
notifyWillChange(subsystem, State::POSTINIT);
subsystem->postinit();
notifyDidChange(subsystem, State::POSTINIT);
}
} }
} }
@@ -502,11 +515,17 @@ SGSubsystemGroup::remove_subsystem(const string &name)
if (_state != State::INVALID) { if (_state != State::INVALID) {
// transition out correctly // transition out correctly
SG_LOG(SG_GENERAL, SG_DEV_WARN, "TODO: implement SGSubsystemGroup transition when removing before shutdown"); if ((_state >= State::INIT) && (_state < State::SHUTDOWN)) {
notifyWillChange(sub, State::SHUTDOWN);
sub->shutdown();
notifyDidChange(sub, State::SHUTDOWN);
}
// shutdown if ((_state >= State::BIND) && (_state < State::UNBIND)) {
notifyWillChange(sub, State::UNBIND);
// unbind sub->unbind();
notifyDidChange(sub, State::UNBIND);
}
} }
notifyWillChange(sub, State::REMOVE); notifyWillChange(sub, State::REMOVE);
@@ -1150,10 +1169,9 @@ namespace {
group, group,
minTime); minTime);
if (arg->getBoolValue("do-bind-init", false)) { // we no longer check for the do-bind-init flag here, since set_subsystem
sub->bind(); // tracks the group state and will transition the added subsystem
sub->init(); // automatically
}
return true; return true;
} }
@@ -1169,10 +1187,6 @@ namespace {
return false; return false;
} }
// is it safe to always call these? let's assume so!
instance->shutdown();
instance->unbind();
// unplug from the manager (this also deletes the instance!) // unplug from the manager (this also deletes the instance!)
manager->remove(name.c_str()); manager->remove(name.c_str());
return true; return true;
+5 -1
View File
@@ -301,6 +301,10 @@ public:
/// get the parent group of this subsystem /// get the parent group of this subsystem
SGSubsystemGroup* get_group() const; SGSubsystemGroup* get_group() const;
// ordering here is exceptionally important, due to
// liveness of ranges. If you're extending this consider
// carefully where the new state lies and position it correctly.
// Also extend the tests to ensure you handle all cases.
enum class State { enum class State {
INVALID = -1, INVALID = -1,
ADD = 0, ADD = 0,
@@ -310,8 +314,8 @@ public:
REINIT, REINIT,
SUSPEND, SUSPEND,
RESUME, RESUME,
UNBIND,
SHUTDOWN, SHUTDOWN,
UNBIND,
REMOVE REMOVE
}; };
+70
View File
@@ -439,6 +439,75 @@ void testPropertyRoot()
SG_CHECK_EQUAL(props->getIntValue("anothersub/bar"), 172); SG_CHECK_EQUAL(props->getIntValue("anothersub/bar"), 172);
} }
void testAddRemoveAfterInit()
{
SGSharedPtr<SGSubsystemMgr> manager = new SGSubsystemMgr;
auto d = new RecorderDelegate;
manager->addDelegate(d);
auto group = manager->add<InstrumentGroup>();
SG_VERIFY(group);
auto radio1 = manager->createInstance<FakeRadioSub>("nav1");
group->set_subsystem(radio1);
auto com1 = manager->createInstance<FakeRadioSub>("com1");
group->set_subsystem(com1);
auto com2 = manager->createInstance<FakeRadioSub>("com2");
group->set_subsystem(com2);
manager->bind();
manager->init();
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-init"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-bind"));
auto radio2 = manager->createInstance<FakeRadioSub>("nav2");
group->set_subsystem(radio2);
SG_VERIFY(d->hasEvent("fake-radio.nav2-will-init"));
SG_VERIFY(d->hasEvent("fake-radio.nav2-did-init"));
SG_VERIFY(d->hasEvent("fake-radio.nav2-did-bind"));
bool ok = manager->remove("fake-radio.nav1");
SG_VERIFY(ok);
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-shutdown"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-shutdown"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-unbind"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-unbind"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-will-remove"));
SG_VERIFY(d->hasEvent("fake-radio.nav1-did-remove"));
manager->shutdown();
SG_VERIFY(d->hasEvent("fake-radio.nav2-will-shutdown"));
SG_VERIFY(d->hasEvent("fake-radio.nav2-did-shutdown"));
SG_VERIFY(d->hasEvent("fake-radio.com1-will-shutdown"));
SG_VERIFY(d->hasEvent("fake-radio.com1-did-shutdown"));
d->events.clear();
ok = manager->remove("fake-radio.com1");
SG_VERIFY(d->hasEvent("fake-radio.com1-will-remove"));
SG_VERIFY(d->hasEvent("fake-radio.com1-did-remove"));
SG_VERIFY(d->hasEvent("fake-radio.com1-will-unbind"));
SG_VERIFY(d->hasEvent("fake-radio.com1-did-unbind"));
SG_VERIFY(!d->hasEvent("fake-radio.com1-will-shutdown"));
SG_VERIFY(!d->hasEvent("fake-radio.com1-did-shutdown"));
manager->unbind();
SG_VERIFY(d->hasEvent("fake-radio.com2-will-unbind"));
SG_VERIFY(d->hasEvent("fake-radio.com2-did-unbind"));
d->events.clear();
manager->remove("fake-radio.com2");
SG_VERIFY(!d->hasEvent("fake-radio.com2-will-unbind"));
SG_VERIFY(!d->hasEvent("fake-radio.com2-did-unbind"));
SG_VERIFY(d->hasEvent("fake-radio.com2-will-remove"));
SG_VERIFY(d->hasEvent("fake-radio.com2-did-remove"));
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@@ -450,6 +519,7 @@ int main(int argc, char* argv[])
testIncrementalInit(); testIncrementalInit();
testSuspendResume(); testSuspendResume();
testPropertyRoot(); testPropertyRoot();
testAddRemoveAfterInit();
cout << __FILE__ << ": All tests passed" << endl; cout << __FILE__ << ": All tests passed" << endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;