--- /dev/null
+// Implementation of the <property-list> widget.
+//
+// Copyright (C) 2001 Steve BAKER
+// Copyright (C) 2001 Jim WILSON
+// Copyright (C) 2006 Melchior FRANZ
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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
+// 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.
+//
+// $Id$
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#include STL_STRING
+SG_USING_STD(string);
+typedef string stdString; // puObject has a "string" member
+
+#include <Main/fg_os.hxx> // fgGetKeyModifiers()
+#include <Main/fg_props.hxx>
+
+#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)
+{
+ string result;
+
+ if (!node)
+ return "unknown";
+
+ SGPropertyNode::Type type = node->getType();
+ if (type == SGPropertyNode::UNSPECIFIED)
+ result = "unspecified";
+ else if (type == SGPropertyNode::NONE)
+ result = "none";
+ else if (type == SGPropertyNode::BOOL)
+ result = "bool";
+ else if (type == SGPropertyNode::INT)
+ result = "int";
+ else if (type == SGPropertyNode::LONG)
+ result = "long";
+ else if (type == SGPropertyNode::FLOAT)
+ result = "float";
+ else if (type == SGPropertyNode::DOUBLE)
+ result = "double";
+ else if (type == SGPropertyNode::STRING)
+ result = "string";
+
+ return result;
+}
+
+
+
+
+PropertyList::PropertyList(int minx, int miny, int maxx, int maxy, SGPropertyNode *start) :
+ puList(minx, miny, maxx, maxy, short(0), 20),
+ _curr(start),
+ _flags(fgGetNode("/sim/gui/dialogs/property-browser/show-flags", true)),
+ _return(0),
+ _entries(0),
+ _num_entries(0)
+
+{
+ _list_box->setUserData(this);
+ _list_box->setCallback(handle_select);
+ _list_box->setValue(0);
+ update();
+}
+
+
+PropertyList::~PropertyList()
+{
+ delete_arrays();
+}
+
+
+void PropertyList::delete_arrays()
+{
+ if (!_entries)
+ return;
+
+ 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;
+ _children = 0;
+}
+
+
+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;
+
+ 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();
+
+ prop_list->update();
+ return;
+
+ } else if (!strcmp(src, "..")) {
+ SGPropertyNode *parent = prop_list->getCurrent()->getParent();
+ if (parent) {
+ if (mod_ctrl)
+ for (; parent->getParent(); parent = parent->getParent())
+ ;
+ prop_list->setCurrent(parent);
+ }
+ return;
+ }
+ }
+
+ // we know we're dealing with a regular entry, so convert
+ // it to an index into children[]
+ if (prop_list->dotFiles)
+ selected -= 2;
+
+ SGPropertyNode_ptr child = prop_list->_children[selected];
+ assert(child);
+
+ // check if it's a directory
+ if (child->nChildren()) {
+ prop_list->setCurrent(child);
+ return;
+ }
+
+ // it is a regular property
+ if (child->getType() == SGPropertyNode::BOOL && mod_ctrl) {
+ child->setBoolValue(!child->getBoolValue());
+ prop_list->update();
+ } else
+ prop_list->publish(child);
+
+ } else {
+ // the user clicked on blank screen
+ prop_list->update();
+ }
+}
+
+
+void PropertyList::update(bool restore_pos)
+{
+ int pi;
+ int i;
+
+ delete_arrays();
+ _num_entries = (int)_curr->nChildren();
+
+ // instantiate string objects and add [.] and [..] for subdirs
+ if (!_curr->getParent()) {
+ _entries = new char*[_num_entries + 1];
+ pi = 0;
+ dotFiles = false;
+
+ } else {
+ _num_entries += 2; // for . and ..
+ _entries = new char*[_num_entries + 1];
+
+ _entries[0] = new char[2];
+ strcpy(_entries[0], ".");
+
+ _entries[1] = new char[3];
+ strcpy(_entries[1], "..");
+
+ pi = 2;
+ dotFiles = true;
+ }
+
+ _num_children = _curr->nChildren();
+ _children = new SGPropertyNode_ptr[_num_children];
+ for (i = 0; i < _num_children; i++)
+ _children[i] = _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);
+ }
+ }
+
+ _entries[_num_entries] = 0;
+
+ int top = getTopItem();
+ newList(_entries);
+ if (restore_pos)
+ setTopItem(top);
+}
+
+
+void PropertyList::updateTextForEntry(int index)
+{
+ assert((index >= 0) && (index < _num_children));
+ SGPropertyNode_ptr node = _children[index];
+
+ 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;
+ }
+
+ line += ')';
+
+ if (line.size() >= PUSTRING_MAX)
+ line.resize(PUSTRING_MAX - 1);
+
+ if (dotFiles)
+ index += 2;
+
+ delete[] _entries[index];
+ _entries[index] = new char[line.size() + 1];
+ strcpy(_entries[index], line.c_str());
+}
+
+
+void PropertyList::valueChanged(SGPropertyNode *nd)
+{
+ for (int i = 0; i < _num_children; i++)
+ if (_children[i] == nd) {
+ updateTextForEntry(i);
+ return;
+ }
+}
+
+
+void PropertyList::setValue(const char *s)
+{
+ SGPropertyNode *p = fgGetNode(s, false);
+ if (p)
+ setCurrent(p);
+}
+
+
--- /dev/null
+// Implementation of the <property-list> widget.
+//
+// Copyright (C) 2001 Steve BAKER
+// Copyright (C) 2001 Jim WILSON
+// Copyright (C) 2006 Melchior FRANZ
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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
+// 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.
+//
+// $Id$
+
+#ifndef _PROPERTY_LIST_HXX
+#define _PROPERTY_LIST_HXX
+
+
+#include <plib/pu.h>
+#include <simgear/props/props.hxx>
+
+#include "puList.hxx"
+
+
+class PropertyList : public puList, public SGPropertyChangeListener {
+public:
+ PropertyList(int minx, int miny, int maxx, int maxy, SGPropertyNode *);
+ ~PropertyList();
+
+ void update (bool restore_slider_pos = false);
+ void setCurrent(SGPropertyNode *p) { _curr = p; update(); publish(p); }
+ SGPropertyNode *getCurrent() const { return _curr; }
+ void publish(SGPropertyNode *p) { _return = p; invokeCallback(); }
+ void toggleFlags() { _flags->setBoolValue(!_flags->getBoolValue()); }
+
+ // overridden plib pui methods
+ virtual char *getStringValue(void) { return (char *)(_return ? _return->getPath(true) : ""); }
+ virtual void setValue(const char *);
+
+ // listener method
+ virtual void valueChanged(SGPropertyNode *node);
+
+private:
+ // update the text string in the puList using the given node and
+ // updating the requested offset. The value of dotFiles is taken
+ // into account before the index is applied, i.e this should be
+ // an index into 'children'
+ void updateTextForEntry(int index);
+ void delete_arrays();
+ static void handle_select(puObject *b);
+
+ SGPropertyNode_ptr _curr;
+ SGPropertyNode_ptr _flags;
+ SGPropertyNode_ptr _return;
+
+ char **_entries;
+ int _num_entries;
+
+ SGPropertyNode_ptr *_children;
+ int _num_children;
+
+ bool dotFiles; // . and .. pseudo-dirs currently shown?
+};
+
+
+#endif // _PROP_PICKER_HXX