Multi-thumbnail support in packages.
Allow multiple thumbnails per variant / package, including tagging with types so we can require certain thumbnails in the future.
This commit is contained in:
@@ -35,4 +35,9 @@
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
#define SG_TEST_FAIL(msg) \
|
||||
std::cerr << "failure:" << msg; \
|
||||
exit(1);
|
||||
|
||||
|
||||
#endif // of SG_MISC_TEST_MACROS_HXX
|
||||
|
||||
@@ -150,6 +150,43 @@ int parseTest()
|
||||
COMPARE(p2->qualifiedId(), "org.flightgear.test.catalog1.c172p");
|
||||
COMPARE(p2->description(), "A plane made by Cessna");
|
||||
|
||||
pkg::Package::ThumbnailVec thumbs = p2->thumbnailsForVariant(0);
|
||||
COMPARE(thumbs.size(), 3);
|
||||
|
||||
auto index = std::find_if(thumbs.begin(), thumbs.end(), [](const pkg::Package::Thumbnail& t)
|
||||
{ return (t.type == pkg::Package::Thumbnail::Type::EXTERIOR); });
|
||||
VERIFY(index != thumbs.end());
|
||||
COMPARE(index->path, "thumb-exterior.png");
|
||||
COMPARE(index->url, "http://foo.bar.com/thumb-exterior.png");
|
||||
VERIFY(index->type == pkg::Package::Thumbnail::Type::EXTERIOR);
|
||||
|
||||
index = std::find_if(thumbs.begin(), thumbs.end(), [](const pkg::Package::Thumbnail& t)
|
||||
{ return (t.type == pkg::Package::Thumbnail::Type::PANEL); });
|
||||
VERIFY(index != thumbs.end());
|
||||
COMPARE(index->path, "thumb-panel.png");
|
||||
COMPARE(index->url, "http://foo.bar.com/thumb-panel.png");
|
||||
VERIFY(index->type == pkg::Package::Thumbnail::Type::PANEL);
|
||||
|
||||
// test variants
|
||||
try {
|
||||
p2->indexOfVariant("fofofo");
|
||||
SG_TEST_FAIL("lookup of non-existant variant did not throw");
|
||||
} catch (sg_exception& e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
unsigned int skisVariant = p2->indexOfVariant("c172p-skis");
|
||||
VERIFY(skisVariant > 0);
|
||||
|
||||
pkg::Package::ThumbnailVec thumbs2 = p2->thumbnailsForVariant(skisVariant);
|
||||
COMPARE(thumbs2.size(), 2);
|
||||
|
||||
index = std::find_if(thumbs2.begin(), thumbs2.end(), [](const pkg::Package::Thumbnail& t)
|
||||
{ return (t.type == pkg::Package::Thumbnail::Type::EXTERIOR); });
|
||||
VERIFY(index != thumbs2.end());
|
||||
COMPARE(index->path, "thumb-exterior-skis.png");
|
||||
COMPARE(index->url, "http://foo.bar.com/thumb-exterior-skis.png");
|
||||
VERIFY(index->type == pkg::Package::Thumbnail::Type::EXTERIOR);
|
||||
|
||||
|
||||
// test filtering / searching too
|
||||
@@ -454,7 +491,7 @@ int main(int argc, char* argv[])
|
||||
parseTest();
|
||||
|
||||
testInstallPackage(&cl);
|
||||
|
||||
|
||||
testUninstall(&cl);
|
||||
|
||||
testRemoveCatalog(&cl);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include <simgear/package/Catalog.hxx>
|
||||
@@ -29,7 +29,7 @@
|
||||
#include <simgear/package/Root.hxx>
|
||||
|
||||
namespace simgear {
|
||||
|
||||
|
||||
namespace pkg {
|
||||
|
||||
Package::Package(const SGPropertyNode* aProps, CatalogRef aCatalog) :
|
||||
@@ -103,7 +103,7 @@ bool Package::matches(const SGPropertyNode* aFilter) const
|
||||
else
|
||||
SG_LOG(SG_GENERAL, SG_WARN, "unknown filter term:" << filter_name);
|
||||
} // of filter props iteration
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ InstallRef Package::install()
|
||||
if (ins) {
|
||||
return ins;
|
||||
}
|
||||
|
||||
|
||||
// start a new install
|
||||
ins = new Install(this, pathOnDisk());
|
||||
m_catalog->root()->scheduleToUpdate(ins);
|
||||
@@ -190,10 +190,10 @@ unsigned int Package::revision() const
|
||||
if (!m_props) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return m_props->getIntValue("revision");
|
||||
}
|
||||
|
||||
|
||||
std::string Package::name() const
|
||||
{
|
||||
return m_props->getStringValue("name");
|
||||
@@ -203,7 +203,7 @@ size_t Package::fileSizeBytes() const
|
||||
{
|
||||
return m_props->getIntValue("file-size-bytes");
|
||||
}
|
||||
|
||||
|
||||
std::string Package::description() const
|
||||
{
|
||||
return getLocalisedProp("description");
|
||||
@@ -213,7 +213,7 @@ string_set Package::tags() const
|
||||
{
|
||||
return m_tags;
|
||||
}
|
||||
|
||||
|
||||
SGPropertyNode* Package::properties() const
|
||||
{
|
||||
return m_props.ptr();
|
||||
@@ -225,7 +225,7 @@ string_list Package::thumbnailUrls() const
|
||||
if (!m_props) {
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("thumbnail")) {
|
||||
r.push_back(dl->getStringValue());
|
||||
}
|
||||
@@ -238,20 +238,20 @@ string_list Package::thumbnails() const
|
||||
if (!m_props) {
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("thumbnail-path")) {
|
||||
r.push_back(dl->getStringValue());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
string_list Package::downloadUrls() const
|
||||
{
|
||||
string_list r;
|
||||
if (!m_props) {
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("url")) {
|
||||
r.push_back(dl->getStringValue());
|
||||
}
|
||||
@@ -272,41 +272,41 @@ std::string Package::getLocalisedString(const SGPropertyNode* aRoot, const char*
|
||||
return localeRoot->getStringValue(aName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return aRoot->getStringValue(aName);
|
||||
}
|
||||
|
||||
PackageList Package::dependencies() const
|
||||
{
|
||||
PackageList result;
|
||||
|
||||
|
||||
BOOST_FOREACH(SGPropertyNode* dep, m_props->getChildren("depends")) {
|
||||
std::string depName = dep->getStringValue("id");
|
||||
unsigned int rev = dep->getIntValue("revision", 0);
|
||||
|
||||
|
||||
// prefer local hangar package if possible, in case someone does something
|
||||
// silly with naming. Of course flightgear's aircraft search doesn't know
|
||||
// about hangars, so names still need to be unique.
|
||||
PackageRef depPkg = m_catalog->getPackageById(depName);
|
||||
if (!depPkg) {
|
||||
if (!depPkg) {
|
||||
Root* rt = m_catalog->root();
|
||||
depPkg = rt->getPackageById(depName);
|
||||
if (!depPkg) {
|
||||
throw sg_exception("Couldn't satisfy dependency of " + id() + " : " + depName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (depPkg->revision() < rev) {
|
||||
throw sg_range_exception("Couldn't find suitable revision of " + depName);
|
||||
}
|
||||
|
||||
|
||||
// forbid recursive dependency graphs, we don't need that level
|
||||
// of complexity for aircraft resources
|
||||
assert(depPkg->dependencies() == PackageList());
|
||||
|
||||
|
||||
result.push_back(depPkg);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -338,6 +338,24 @@ std::string Package::nameForVariant(const std::string& vid) const
|
||||
throw sg_exception("Unknow variant +" + vid + " in package " + id());
|
||||
}
|
||||
|
||||
unsigned int Package::indexOfVariant(const std::string& vid) const
|
||||
{
|
||||
if (vid == id()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int result = 1;
|
||||
for (SGPropertyNode* var : m_props->getChildren("variant")) {
|
||||
if (var->getStringValue("id") == vid) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result++;
|
||||
}
|
||||
|
||||
throw sg_exception("Unknow variant " + vid + " in package " + id());
|
||||
}
|
||||
|
||||
std::string Package::nameForVariant(const unsigned int vIndex) const
|
||||
{
|
||||
if (vIndex == 0)
|
||||
@@ -351,6 +369,48 @@ std::string Package::nameForVariant(const unsigned int vIndex) const
|
||||
throw sg_exception("Unknow variant in package " + id());
|
||||
}
|
||||
|
||||
Package::ThumbnailVec Package::thumbnailsForVariant(unsigned int vIndex) const
|
||||
{
|
||||
if (vIndex == 0) {
|
||||
return thumbnailsFromProps(m_props);
|
||||
}
|
||||
|
||||
SGPropertyNode_ptr var = m_props->getChild("variant", vIndex - 1);
|
||||
if (!var) {
|
||||
throw sg_exception("Unknow variant in package " + id());
|
||||
}
|
||||
|
||||
return thumbnailsFromProps(var);
|
||||
}
|
||||
|
||||
Package::Thumbnail::Type thumbnailTypeFromString(const std::string& s)
|
||||
{
|
||||
if (s == "exterior") return Package::Thumbnail::Type::EXTERIOR;
|
||||
if (s == "interior") return Package::Thumbnail::Type::INTERIOR;
|
||||
if (s == "panel") return Package::Thumbnail::Type::PANEL;
|
||||
return Package::Thumbnail::Type::UNKNOWN;
|
||||
}
|
||||
|
||||
Package::Thumbnail::Thumbnail(const std::string& aUrl, const std::string& aPath, Type aType) :
|
||||
url(aUrl),
|
||||
path(aPath),
|
||||
type(aType)
|
||||
{
|
||||
}
|
||||
|
||||
Package::ThumbnailVec Package::thumbnailsFromProps(const SGPropertyNode_ptr& ptr) const
|
||||
{
|
||||
ThumbnailVec result;
|
||||
|
||||
for (auto thumbNode : ptr->getChildren("thumbnail")) {
|
||||
Thumbnail t(thumbNode->getStringValue("url"),
|
||||
thumbNode->getStringValue("path"),
|
||||
thumbnailTypeFromString(thumbNode->getStringValue("type")));
|
||||
result.push_back(t);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // of namespace pkg
|
||||
|
||||
|
||||
@@ -80,7 +80,12 @@ public:
|
||||
* Fully-qualified ID, including our catalog'd ID
|
||||
*/
|
||||
std::string qualifiedVariantId(const unsigned int variantIndex) const;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
unsigned int indexOfVariant(const std::string& vid) const;
|
||||
|
||||
/**
|
||||
* human-readable name - note this is probably not localised,
|
||||
* although this is not ruled out for the future.
|
||||
@@ -133,6 +138,35 @@ public:
|
||||
* thumbnail file paths within the package on disk
|
||||
*/
|
||||
string_list thumbnails() const;
|
||||
|
||||
/**
|
||||
* information about a thumbnail
|
||||
*/
|
||||
struct Thumbnail {
|
||||
enum class Type
|
||||
{
|
||||
UNKNOWN,
|
||||
PANEL,
|
||||
INTERIOR,
|
||||
EXTERIOR
|
||||
|
||||
// NIGHT / GROUND as modifiers? does this add any
|
||||
// actual value for GUIs?
|
||||
};
|
||||
|
||||
Thumbnail(const std::string& url, const std::string& path, Type ty = Type::UNKNOWN);
|
||||
|
||||
std::string url;
|
||||
std::string path;
|
||||
Type type = Type::UNKNOWN;
|
||||
};
|
||||
|
||||
typedef std::vector<Thumbnail> ThumbnailVec;
|
||||
|
||||
/**
|
||||
* retrieve all the thumbnails for a variant
|
||||
*/
|
||||
ThumbnailVec thumbnailsForVariant(unsigned int vIndex) const;
|
||||
|
||||
/**
|
||||
* Packages we depend upon.
|
||||
@@ -159,7 +193,9 @@ private:
|
||||
void updateFromProps(const SGPropertyNode* aProps);
|
||||
|
||||
std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const;
|
||||
|
||||
|
||||
ThumbnailVec thumbnailsFromProps(const SGPropertyNode_ptr& ptr) const;
|
||||
|
||||
SGPropertyNode_ptr m_props;
|
||||
std::string m_id;
|
||||
string_set m_tags;
|
||||
|
||||
@@ -48,6 +48,23 @@
|
||||
<revision>10</revision>
|
||||
</depends>
|
||||
|
||||
<thumbnail>
|
||||
<type>exterior</type>
|
||||
<path>thumb-exterior.png</path>
|
||||
<url>http://foo.bar.com/thumb-exterior.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<thumbnail>
|
||||
<type>panel</type>
|
||||
<path>thumb-panel.png</path>
|
||||
<url>http://foo.bar.com/thumb-panel.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<thumbnail>
|
||||
<path>thumb-something.png</path>
|
||||
<url>http://foo.bar.com/thumb-something.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<variant>
|
||||
<id>c172p-2d-panel</id>
|
||||
<name>C172 with 2d panel only</name>
|
||||
@@ -56,11 +73,35 @@
|
||||
<variant>
|
||||
<id>c172p-floats</id>
|
||||
<name>C172 with floats</name>
|
||||
|
||||
<thumbnail>
|
||||
<type>exterior</type>
|
||||
<path>thumb-exterior-floats.png</path>
|
||||
<url>http://foo.bar.com/thumb-exterior-floats.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<thumbnail>
|
||||
<type>panel</type>
|
||||
<path>thumb-panel.png</path>
|
||||
<url>http://foo.bar.com/thumb-panel.png</url>
|
||||
</thumbnail>
|
||||
</variant>
|
||||
|
||||
<variant>
|
||||
<id>c172p-skis</id>
|
||||
<name>C172 with skis</name>
|
||||
|
||||
<thumbnail>
|
||||
<type>exterior</type>
|
||||
<path>thumb-exterior-skis.png</path>
|
||||
<url>http://foo.bar.com/thumb-exterior-skis.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<thumbnail>
|
||||
<type>panel</type>
|
||||
<path>thumb-panel.png</path>
|
||||
<url>http://foo.bar.com/thumb-panel.png</url>
|
||||
</thumbnail>
|
||||
</variant>
|
||||
|
||||
<md5>ec0e2ffdf98d6a5c05c77445e5447ff5</md5>
|
||||
@@ -99,6 +140,18 @@
|
||||
|
||||
<md5>a94ca5704f305b90767f40617d194ed6</md5>
|
||||
<url>http://localhost:2000/catalogTest1/b737.tar.gz</url>
|
||||
|
||||
<thumbnail>
|
||||
<type>exterior</type>
|
||||
<path>thumb-exterior.png</path>
|
||||
<url>http://foo.bar.com/thumb-exterior.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<thumbnail>
|
||||
<type>panel</type>
|
||||
<path>thumb-panel.png</path>
|
||||
<url>http://foo.bar.com/thumb-panel.png</url>
|
||||
</thumbnail>
|
||||
</package>
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,23 @@
|
||||
<revision>10</revision>
|
||||
</depends>
|
||||
|
||||
<thumbnail>
|
||||
<type>exterior</type>
|
||||
<path>thumb-exterior.png</path>
|
||||
<url>http://foo.bar.com/thumb-exterior.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<thumbnail>
|
||||
<type>panel</type>
|
||||
<path>thumb-panel.png</path>
|
||||
<url>http://foo.bar.com/thumb-panel.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<thumbnail>
|
||||
<path>thumb-something.png</path>
|
||||
<url>http://foo.bar.com/thumb-something.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<variant>
|
||||
<id>c172p-2d-panel</id>
|
||||
<name>C172 with 2d panel only</name>
|
||||
@@ -56,11 +73,35 @@
|
||||
<variant>
|
||||
<id>c172p-floats</id>
|
||||
<name>C172 with floats</name>
|
||||
|
||||
<thumbnail>
|
||||
<type>exterior</type>
|
||||
<path>thumb-exterior-floats.png</path>
|
||||
<url>http://foo.bar.com/thumb-exterior-floats.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<thumbnail>
|
||||
<type>panel</type>
|
||||
<path>thumb-panel.png</path>
|
||||
<url>http://foo.bar.com/thumb-panel.png</url>
|
||||
</thumbnail>
|
||||
</variant>
|
||||
|
||||
<variant>
|
||||
<id>c172p-skis</id>
|
||||
<name>C172 with skis</name>
|
||||
|
||||
<thumbnail>
|
||||
<type>exterior</type>
|
||||
<path>thumb-exterior-skis.png</path>
|
||||
<url>http://foo.bar.com/thumb-exterior-skis.png</url>
|
||||
</thumbnail>
|
||||
|
||||
<thumbnail>
|
||||
<type>panel</type>
|
||||
<path>thumb-panel.png</path>
|
||||
<url>http://foo.bar.com/thumb-panel.png</url>
|
||||
</thumbnail>
|
||||
</variant>
|
||||
|
||||
<md5>ec0e2ffdf98d6a5c05c77445e5447ff5</md5>
|
||||
|
||||
Reference in New Issue
Block a user