X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FGUI%2Fproperty_list.cxx;h=5bcb46a3542cbca9a729460102433b3fd0cfbfae;hb=da02c09ec08cc357926ce6f06b3c6fc5925986d8;hp=a1f59624ee6094d11f6e31ad4182e3c7c7594acf;hpb=3610680095a229d8dec3b2b7dd4557633af8744a;p=flightgear.git diff --git a/src/GUI/property_list.cxx b/src/GUI/property_list.cxx index a1f59624e..5bcb46a35 100644 --- a/src/GUI/property_list.cxx +++ b/src/GUI/property_list.cxx @@ -27,8 +27,13 @@ #include -#include STL_STRING -SG_USING_STD(string); +#include +#include +#include +#include +using std::string; +using std::cout; + typedef string stdString; // puObject has a "string" member #include
// fgGetKeyModifiers() @@ -37,54 +42,127 @@ typedef string stdString; // puObject has a "string" member #include "property_list.hxx" -static int nodeNameCompare(const void *ppNode1, const void *ppNode2) -{ - const SGPropertyNode_ptr pNode1 = *(const SGPropertyNode_ptr *)ppNode1; - const SGPropertyNode_ptr pNode2 = *(const SGPropertyNode_ptr *)ppNode2; - - int diff = strcmp(pNode1->getName(), pNode2->getName()); - return diff ? diff : pNode1->getIndex() - pNode2->getIndex(); -} - - static string getValueTypeString(const SGPropertyNode *node) { + using namespace simgear; string result; - if (!node) - return "unknown"; - - SGPropertyNode::Type type = node->getType(); - if (type == SGPropertyNode::UNSPECIFIED) + props::Type type = node->getType(); + if (type == props::UNSPECIFIED) result = "unspecified"; - else if (type == SGPropertyNode::NONE) + else if (type == props::NONE) result = "none"; - else if (type == SGPropertyNode::BOOL) + else if (type == props::BOOL) result = "bool"; - else if (type == SGPropertyNode::INT) + else if (type == props::INT) result = "int"; - else if (type == SGPropertyNode::LONG) + else if (type == props::LONG) result = "long"; - else if (type == SGPropertyNode::FLOAT) + else if (type == props::FLOAT) result = "float"; - else if (type == SGPropertyNode::DOUBLE) + else if (type == props::DOUBLE) result = "double"; - else if (type == SGPropertyNode::STRING) + else if (type == props::STRING) result = "string"; + else if (type == props::VEC3D) + result = "vec3d"; + else if (type == props::VEC4D) + result = "vec4d"; return result; } +static void dumpProperties(const SGPropertyNode *node) +{ + using namespace simgear; + cout << node->getPath() << '/' << endl; + for (int i = 0; i < node->nChildren(); i++) { + const SGPropertyNode *c = node->getChild(i); + props::Type type = c->getType(); + if (type == props::ALIAS || c->nChildren()) + continue; + + int index = c->getIndex(); + cout << std::setw(11) << getValueTypeString(c) << " " << c->getName(); + if (index > 0) + cout << '[' << index << ']'; + cout << " = "; + + switch (c->getType()) { + case props::DOUBLE: + case props::FLOAT: + case props::VEC3D: + case props::VEC4D: + { + streamsize precision = cout.precision(15); + c->printOn(cout); + cout.precision(precision); + } + break; + case props::LONG: + case props::INT: + case props::BOOL: + c->printOn(cout); + break; + case props::STRING: + cout << '"' << c->getStringValue() << '"'; + break; + case props::NONE: + break; + default: + cout << '\'' << c->getStringValue() << '\''; + } + cout << endl; + } + cout << endl; +} + + +static void sanitize(stdString& s) +{ + stdString r = s; + s = ""; + for (unsigned i = 0; i < r.size(); i++) { + if (r[i] == '\a') + s += "\\a"; + else if (r[i] == '\b') + s += "\\b"; + else if (r[i] == '\t') + s += "\\t"; + else if (r[i] == '\n') + s += "\\n"; + else if (r[i] == '\v') + s += "\\v"; + else if (r[i] == '\f') + s += "\\f"; + else if (r[i] == '\r') + s += "\\r"; + else if (r[i] == '\'') + s += "\'"; + else if (r[i] == '\\') + s += "\\"; + else if (isprint(r[i])) + s += r[i]; + else { + const char *hex = "0123456789abcdef"; + int c = r[i] & 255; + s += stdString("\\x") + hex[c / 16] + hex[c % 16]; + } + } +} + + PropertyList::PropertyList(int minx, int miny, int maxx, int maxy, SGPropertyNode *start) : - puList(minx, miny, maxx, maxy, short(0), 20), + puaList(minx, miny, maxx, maxy, short(0), 20), + GUI_ID(FGCLASS_PROPERTYLIST), _curr(start), - _flags(fgGetNode("/sim/gui/dialogs/property-browser/show-flags", true)), _return(0), _entries(0), - _num_entries(0) + _num_entries(0), + _verbose(false) { _list_box->setUserData(this); @@ -108,11 +186,6 @@ void PropertyList::delete_arrays() for (int i = 0; i < _num_entries; i++) delete[] _entries[i]; - for (int j = 0; j < _num_children; j++) { - if (!_children[j]->nChildren()) - _children[j]->removeChangeListener(this); - } - delete[] _entries; delete[] _children; _entries = 0; @@ -124,15 +197,20 @@ void PropertyList::handle_select(puObject *list_box) { PropertyList *prop_list = (PropertyList *)list_box->getUserData(); int selected = list_box->getIntegerValue(); - bool mod_ctrl = fgGetKeyModifiers() & KEYMOD_CTRL; + int mod_ctrl = fgGetKeyModifiers() & KEYMOD_CTRL; + int mod_shift = fgGetKeyModifiers() & KEYMOD_SHIFT; if (selected >= 0 && selected < prop_list->_num_entries) { const char *src = prop_list->_entries[selected]; - if (prop_list->dotFiles && (selected < 2)) { - if (!strcmp(src, ".")) { - if (mod_ctrl) - prop_list->toggleFlags(); + if (prop_list->_dot_files && (selected < 2)) { + if (src[0] == '.' && (src[1] == '\0' || src[1] == ' ')) { + if (mod_ctrl && mod_shift) + prop_list->_curr->fireValueChanged(); + else if (mod_ctrl) + prop_list->toggleVerbosity(); + else if (mod_shift) + dumpProperties(prop_list->_curr); prop_list->update(); return; @@ -151,28 +229,28 @@ void PropertyList::handle_select(puObject *list_box) // we know we're dealing with a regular entry, so convert // it to an index into children[] - if (prop_list->dotFiles) + if (prop_list->_dot_files) selected -= 2; - SGPropertyNode_ptr child = prop_list->_children[selected]; - assert(child); + SGPropertyNode_ptr child = prop_list->_children[selected].node; // check if it's a directory if (child->nChildren()) { + prop_list->setTopItem(0); prop_list->setCurrent(child); return; } // it is a regular property - if (child->getType() == SGPropertyNode::BOOL && mod_ctrl) { + if (child->getType() == simgear::props::BOOL && mod_ctrl) { child->setBoolValue(!child->getBoolValue()); - prop_list->update(); + prop_list->update(true); } else prop_list->publish(child); } else { // the user clicked on blank screen - prop_list->update(); + prop_list->update(true); } } @@ -180,7 +258,6 @@ void PropertyList::handle_select(puObject *list_box) void PropertyList::update(bool restore_pos) { int pi; - int i; delete_arrays(); _num_entries = (int)_curr->nChildren(); @@ -189,43 +266,36 @@ void PropertyList::update(bool restore_pos) if (!_curr->getParent()) { _entries = new char*[_num_entries + 1]; pi = 0; - dotFiles = false; + _dot_files = false; } else { _num_entries += 2; // for . and .. _entries = new char*[_num_entries + 1]; - _entries[0] = new char[2]; - strcpy(_entries[0], "."); + _entries[0] = new char[16]; + strcpy(_entries[0], _verbose ? ". [verbose]" : "."); _entries[1] = new char[3]; strcpy(_entries[1], ".."); pi = 2; - dotFiles = true; + _dot_files = true; } + int i; _num_children = _curr->nChildren(); - _children = new SGPropertyNode_ptr[_num_children]; + _children = new NodeData[_num_children]; for (i = 0; i < _num_children; i++) - _children[i] = _curr->getChild(i); + _children[i].node = _curr->getChild(i); qsort(_children, _num_children, sizeof(_children[0]), nodeNameCompare); // Make lists of the children's names, values, etc. for (i = 0; i < _num_children; i++, pi++) { - SGPropertyNode *child = _children[i]; - - if (child->nChildren() > 0) { - stdString name = stdString(child->getDisplayName(true)) + '/'; - _entries[pi] = new char[name.size() + 1]; - strcpy(_entries[pi], name.c_str()); - - } else { - _entries[pi] = 0; // ensure it's 0 before setting intial value - updateTextForEntry(i); - child->addChangeListener(this); - } + _children[i].text = &_entries[pi]; + _entries[pi] = 0; // make it deletable + updateTextForEntry(_children[i]); + _children[i].setListener(this); } _entries[_num_entries] = 0; @@ -237,66 +307,107 @@ void PropertyList::update(bool restore_pos) } -void PropertyList::updateTextForEntry(int index) +void PropertyList::updateTextForEntry(NodeData& data) { - assert((index >= 0) && (index < _num_children)); - SGPropertyNode_ptr node = _children[index]; - + using namespace simgear; + SGPropertyNode *node = data.node; stdString name = node->getDisplayName(true); stdString type = getValueTypeString(node); stdString value = node->getStringValue(); - stdString line = name + " = '" + value + "' (" + type; - - if (_flags->getBoolValue()) { - stdString ext; - if (!node->getAttribute(SGPropertyNode::READ)) - ext += 'r'; - if (!node->getAttribute(SGPropertyNode::WRITE)) - ext += 'w'; - if (node->getAttribute(SGPropertyNode::TRACE_READ)) - ext += 'R'; - if (node->getAttribute(SGPropertyNode::TRACE_WRITE)) - ext += 'W'; - if (node->getAttribute(SGPropertyNode::ARCHIVE)) - ext += 'A'; - if (node->getAttribute(SGPropertyNode::USERARCHIVE)) - ext += 'U'; - if (node->isTied()) - ext += 'T'; - if (ext.size()) - line += ", " + ext; + std::ostringstream line; + line << name; + + int children = node->nChildren(); + if (children) + line << '/'; + + if (!children || (_verbose && node->hasValue())) { + if (node->getType() == props::STRING + || node->getType() == props::UNSPECIFIED) + sanitize(value); + + line << " = '" << value << "' (" << type; + + if (_verbose) { + stdString ext; + if (!node->getAttribute(SGPropertyNode::READ)) + ext += 'r'; + if (!node->getAttribute(SGPropertyNode::WRITE)) + ext += 'w'; + if (node->getAttribute(SGPropertyNode::TRACE_READ)) + ext += 'R'; + if (node->getAttribute(SGPropertyNode::TRACE_WRITE)) + ext += 'W'; + if (node->getAttribute(SGPropertyNode::ARCHIVE)) + ext += 'A'; + if (node->getAttribute(SGPropertyNode::USERARCHIVE)) + ext += 'U'; + if (node->isTied()) + ext += 'T'; + + if (!ext.empty()) + line << ", " << ext; + + int num = node->nListeners(); + if (data.listener) + num--; + if (num) + line << ", L" << num; + } + line << ')'; } - line += ')'; - - if (line.size() >= PUSTRING_MAX) - line.resize(PUSTRING_MAX - 1); + stdString out = line.str(); + if (out.size() >= PUSTRING_MAX) + out.resize(PUSTRING_MAX - 1); - if (dotFiles) - index += 2; - - delete[] _entries[index]; - _entries[index] = new char[line.size() + 1]; - strcpy(_entries[index], line.c_str()); + delete[] *data.text; + *data.text = new char[out.size() + 1]; + strcpy(*data.text, out.c_str()); } void PropertyList::valueChanged(SGPropertyNode *nd) { for (int i = 0; i < _num_children; i++) - if (_children[i] == nd) { - updateTextForEntry(i); + if (_children[i].node == nd) { + updateTextForEntry(_children[i]); return; } } +int PropertyList::nodeNameCompare(const void *p1, const void *p2) +{ + const SGPropertyNode *n1 = (*(const NodeData *)p1).node; + const SGPropertyNode *n2 = (*(const NodeData *)p2).node; + + int diff = strcmp(n1->getName(), n2->getName()); + return diff ? diff : n1->getIndex() - n2->getIndex(); +} + + void PropertyList::setValue(const char *s) { - SGPropertyNode *p = fgGetNode(s, false); - if (p) - setCurrent(p); + try { + SGPropertyNode *p = fgGetNode(s, false); + if (p) + setCurrent(p); + else + throw stdString("node doesn't exist"); + } catch (const stdString& m) { + SG_LOG(SG_GENERAL, SG_DEBUG, "property-list node '" << s << "': " << m); + } } +void PropertyList::setCurrent(SGPropertyNode *p) +{ + bool same = (_curr == p); + _return = _curr = p; + update(same); + if (!same) + publish(p); +} +