1 // Implementation of the <property-list> widget.
3 // Copyright (C) 2001 Steve BAKER
4 // Copyright (C) 2001 Jim WILSON
5 // Copyright (C) 2006 Melchior FRANZ
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28 #include <simgear/compiler.h>
32 typedef string stdString; // puObject has a "string" member
34 #include <Main/fg_os.hxx> // fgGetKeyModifiers()
35 #include <Main/fg_props.hxx>
37 #include "property_list.hxx"
40 static int nodeNameCompare(const void *ppNode1, const void *ppNode2)
42 const SGPropertyNode_ptr pNode1 = *(const SGPropertyNode_ptr *)ppNode1;
43 const SGPropertyNode_ptr pNode2 = *(const SGPropertyNode_ptr *)ppNode2;
45 int diff = strcmp(pNode1->getName(), pNode2->getName());
46 return diff ? diff : pNode1->getIndex() - pNode2->getIndex();
50 static string getValueTypeString(const SGPropertyNode *node)
57 SGPropertyNode::Type type = node->getType();
58 if (type == SGPropertyNode::UNSPECIFIED)
59 result = "unspecified";
60 else if (type == SGPropertyNode::NONE)
62 else if (type == SGPropertyNode::BOOL)
64 else if (type == SGPropertyNode::INT)
66 else if (type == SGPropertyNode::LONG)
68 else if (type == SGPropertyNode::FLOAT)
70 else if (type == SGPropertyNode::DOUBLE)
72 else if (type == SGPropertyNode::STRING)
81 PropertyList::PropertyList(int minx, int miny, int maxx, int maxy, SGPropertyNode *start) :
82 puList(minx, miny, maxx, maxy, short(0), 20),
83 GUI_ID(FGCLASS_PROPERTYLIST),
85 _flags(fgGetNode("/sim/gui/dialogs/property-browser/show-flags", true)),
91 _list_box->setUserData(this);
92 _list_box->setCallback(handle_select);
93 _list_box->setValue(0);
98 PropertyList::~PropertyList()
100 // FIXME this seems to cause a crash, which is probably why
101 // commented out in prop_picker.cxx since many years
106 void PropertyList::delete_arrays()
111 for (int i = 0; i < _num_entries; i++)
112 delete[] _entries[i];
114 for (int j = 0; j < _num_children; j++)
115 if (!_children[j]->nChildren())
116 _children[j]->removeChangeListener(this);
125 void PropertyList::handle_select(puObject *list_box)
127 PropertyList *prop_list = (PropertyList *)list_box->getUserData();
128 int selected = list_box->getIntegerValue();
129 bool mod_ctrl = fgGetKeyModifiers() & KEYMOD_CTRL;
131 if (selected >= 0 && selected < prop_list->_num_entries) {
132 const char *src = prop_list->_entries[selected];
134 if (prop_list->dotFiles && (selected < 2)) {
135 if (!strcmp(src, ".")) {
137 prop_list->toggleFlags();
142 } else if (!strcmp(src, "..")) {
143 SGPropertyNode *parent = prop_list->getCurrent()->getParent();
146 for (; parent->getParent(); parent = parent->getParent())
148 prop_list->setCurrent(parent);
154 // we know we're dealing with a regular entry, so convert
155 // it to an index into children[]
156 if (prop_list->dotFiles)
159 SGPropertyNode_ptr child = prop_list->_children[selected];
162 // check if it's a directory
163 if (child->nChildren()) {
164 prop_list->setCurrent(child);
168 // it is a regular property
169 if (child->getType() == SGPropertyNode::BOOL && mod_ctrl) {
170 child->setBoolValue(!child->getBoolValue());
173 prop_list->publish(child);
176 // the user clicked on blank screen
182 void PropertyList::update(bool restore_pos)
188 _num_entries = (int)_curr->nChildren();
190 // instantiate string objects and add [.] and [..] for subdirs
191 if (!_curr->getParent()) {
192 _entries = new char*[_num_entries + 1];
197 _num_entries += 2; // for . and ..
198 _entries = new char*[_num_entries + 1];
200 _entries[0] = new char[2];
201 strcpy(_entries[0], ".");
203 _entries[1] = new char[3];
204 strcpy(_entries[1], "..");
210 _num_children = _curr->nChildren();
211 _children = new SGPropertyNode_ptr[_num_children];
212 for (i = 0; i < _num_children; i++)
213 _children[i] = _curr->getChild(i);
215 qsort(_children, _num_children, sizeof(_children[0]), nodeNameCompare);
217 // Make lists of the children's names, values, etc.
218 for (i = 0; i < _num_children; i++, pi++) {
219 SGPropertyNode *child = _children[i];
221 if (child->nChildren() > 0) {
222 stdString name = stdString(child->getDisplayName(true)) + '/';
223 _entries[pi] = new char[name.size() + 1];
224 strcpy(_entries[pi], name.c_str());
227 _entries[pi] = 0; // ensure it's 0 before setting intial value
228 updateTextForEntry(i);
229 child->addChangeListener(this);
233 _entries[_num_entries] = 0;
235 int top = getTopItem();
242 void PropertyList::updateTextForEntry(int index)
244 assert((index >= 0) && (index < _num_children));
245 SGPropertyNode_ptr node = _children[index];
247 stdString name = node->getDisplayName(true);
248 stdString type = getValueTypeString(node);
249 stdString value = node->getStringValue();
251 stdString line = name + " = '" + value + "' (" + type;
253 if (_flags->getBoolValue()) {
255 if (!node->getAttribute(SGPropertyNode::READ))
257 if (!node->getAttribute(SGPropertyNode::WRITE))
259 if (node->getAttribute(SGPropertyNode::TRACE_READ))
261 if (node->getAttribute(SGPropertyNode::TRACE_WRITE))
263 if (node->getAttribute(SGPropertyNode::ARCHIVE))
265 if (node->getAttribute(SGPropertyNode::USERARCHIVE))
275 if (line.size() >= PUSTRING_MAX)
276 line.resize(PUSTRING_MAX - 1);
281 delete[] _entries[index];
282 _entries[index] = new char[line.size() + 1];
283 strcpy(_entries[index], line.c_str());
287 void PropertyList::valueChanged(SGPropertyNode *nd)
289 for (int i = 0; i < _num_children; i++)
290 if (_children[i] == nd) {
291 updateTextForEntry(i);
297 void PropertyList::setValue(const char *s)
301 p = fgGetNode(s, false);
302 } catch (const stdString& m) {
303 SG_LOG(SG_GENERAL, SG_DEBUG, "property-list: " << m);
310 void PropertyList::setCurrent(SGPropertyNode *p)
312 bool same = (_curr == p);