]> git.mxchange.org Git - flightgear.git/blob - src/GUI/property_list.cxx
Compile
[flightgear.git] / src / GUI / property_list.cxx
1 // Implementation of the <property-list> widget.
2 //
3 // Copyright (C) 2001  Steve BAKER
4 // Copyright (C) 2001  Jim WILSON
5 // Copyright (C) 2006  Melchior FRANZ
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #include <simgear/compiler.h>
29
30 #include STL_STRING
31 SG_USING_STD(string);
32 typedef string stdString;      // puObject has a "string" member
33
34 #include <Main/fg_os.hxx>      // fgGetKeyModifiers()
35 #include <Main/fg_props.hxx>
36
37 #include "property_list.hxx"
38
39
40 static string getValueTypeString(const SGPropertyNode *node)
41 {
42     string result;
43
44     if (!node)
45         return "unknown";
46
47     SGPropertyNode::Type type = node->getType();
48     if (type == SGPropertyNode::UNSPECIFIED)
49         result = "unspecified";
50     else if (type == SGPropertyNode::NONE)
51         result = "none";
52     else if (type == SGPropertyNode::BOOL)
53         result = "bool";
54     else if (type == SGPropertyNode::INT)
55         result = "int";
56     else if (type == SGPropertyNode::LONG)
57         result = "long";
58     else if (type == SGPropertyNode::FLOAT)
59         result = "float";
60     else if (type == SGPropertyNode::DOUBLE)
61         result = "double";
62     else if (type == SGPropertyNode::STRING)
63         result = "string";
64
65     return result;
66 }
67
68
69
70
71 PropertyList::PropertyList(int minx, int miny, int maxx, int maxy, SGPropertyNode *start) :
72     puList(minx, miny, maxx, maxy, short(0), 20),
73     GUI_ID(FGCLASS_PROPERTYLIST),
74     _curr(start),
75     _flags(fgGetNode("/sim/gui/dialogs/property-browser/show-flags", true)),
76     _return(0),
77     _entries(0),
78     _num_entries(0)
79
80 {
81     _list_box->setUserData(this);
82     _list_box->setCallback(handle_select);
83     _list_box->setValue(0);
84     update();
85 }
86
87
88 PropertyList::~PropertyList()
89 {
90     delete_arrays();
91 }
92
93
94 void PropertyList::delete_arrays()
95 {
96     if (!_entries)
97         return;
98
99     for (int i = 0; i < _num_entries; i++)
100         delete[] _entries[i];
101
102     delete[] _entries;
103     delete[] _children;
104     _entries = 0;
105     _children = 0;
106 }
107
108
109 void PropertyList::handle_select(puObject *list_box)
110 {
111     PropertyList *prop_list = (PropertyList *)list_box->getUserData();
112     int selected = list_box->getIntegerValue();
113     bool mod_ctrl = fgGetKeyModifiers() & KEYMOD_CTRL;
114
115     if (selected >= 0 && selected < prop_list->_num_entries) {
116         const char *src = prop_list->_entries[selected];
117
118         if (prop_list->dotFiles && (selected < 2)) {
119             if (!strcmp(src, ".")) {
120                 if (mod_ctrl)
121                     prop_list->toggleFlags();
122
123                 prop_list->update();
124                 return;
125
126             } else if (!strcmp(src, "..")) {
127                 SGPropertyNode *parent = prop_list->getCurrent()->getParent();
128                 if (parent) {
129                     if (mod_ctrl)
130                         for (; parent->getParent(); parent = parent->getParent())
131                             ;
132                     prop_list->setCurrent(parent);
133                 }
134                 return;
135             }
136         }
137
138         // we know we're dealing with a regular entry, so convert
139         // it to an index into children[]
140         if (prop_list->dotFiles)
141             selected -= 2;
142
143         SGPropertyNode_ptr child = prop_list->_children[selected].node;
144         assert(child);
145
146         // check if it's a directory
147         if (child->nChildren()) {
148             prop_list->setCurrent(child);
149             return;
150         }
151
152         // it is a regular property
153         if (child->getType() == SGPropertyNode::BOOL && mod_ctrl) {
154             child->setBoolValue(!child->getBoolValue());
155             prop_list->update(true);
156         } else
157             prop_list->publish(child);
158
159     } else {
160         // the user clicked on blank screen
161         prop_list->update(true);
162     }
163 }
164
165
166 void PropertyList::update(bool restore_pos)
167 {
168     int pi;
169
170     delete_arrays();
171     _num_entries = (int)_curr->nChildren();
172
173     // instantiate string objects and add [.] and [..] for subdirs
174     if (!_curr->getParent()) {
175         _entries = new char*[_num_entries + 1];
176         pi = 0;
177         dotFiles = false;
178
179     } else {
180         _num_entries += 2;    // for . and ..
181         _entries = new char*[_num_entries + 1];
182
183         _entries[0] = new char[2];
184         strcpy(_entries[0], ".");
185
186         _entries[1] = new char[3];
187         strcpy(_entries[1], "..");
188
189         pi = 2;
190         dotFiles = true;
191     }
192
193     int i;
194     _num_children = _curr->nChildren();
195     _children = new NodeData[_num_children];
196     for (i = 0; i < _num_children; i++)
197         _children[i].node = _curr->getChild(i);
198
199     qsort(_children, _num_children, sizeof(_children[0]), nodeNameCompare);
200
201     // Make lists of the children's names, values, etc.
202     for (i = 0; i < _num_children; i++, pi++) {
203         SGPropertyNode *child = _children[i].node;
204
205         if (child->nChildren() > 0) {
206             stdString name = stdString(child->getDisplayName(true)) + '/';
207             _entries[pi] = new char[name.size() + 1];
208             strcpy(_entries[pi], name.c_str());
209
210         } else {
211             _entries[pi] = 0;       // ensure it's 0 before setting intial value
212             updateTextForEntry(i);
213             _children[i].setListener(this);
214         }
215     }
216
217     _entries[_num_entries] = 0;
218
219     int top = getTopItem();
220     newList(_entries);
221     if (restore_pos)
222         setTopItem(top);
223 }
224
225
226 void PropertyList::updateTextForEntry(int index)
227 {
228     assert((index >= 0) && (index < _num_children));
229     SGPropertyNode_ptr node = _children[index].node;
230
231     stdString name = node->getDisplayName(true);
232     stdString type = getValueTypeString(node);
233     stdString value = node->getStringValue();
234
235     stdString line = name + " = '" + value + "' (" + type;
236
237     if (_flags->getBoolValue()) {
238         stdString ext;
239         if (!node->getAttribute(SGPropertyNode::READ))
240             ext += 'r';
241         if (!node->getAttribute(SGPropertyNode::WRITE))
242             ext += 'w';
243         if (node->getAttribute(SGPropertyNode::TRACE_READ))
244             ext += 'R';
245         if (node->getAttribute(SGPropertyNode::TRACE_WRITE))
246             ext += 'W';
247         if (node->getAttribute(SGPropertyNode::ARCHIVE))
248             ext += 'A';
249         if (node->getAttribute(SGPropertyNode::USERARCHIVE))
250             ext += 'U';
251         if (node->isTied())
252             ext += 'T';
253         if (ext.size())
254             line += ", " + ext;
255     }
256
257     line += ')';
258
259     if (line.size() >= PUSTRING_MAX)
260         line.resize(PUSTRING_MAX - 1);
261
262     if (dotFiles)
263         index += 2;
264
265     delete[] _entries[index];
266     _entries[index] = new char[line.size() + 1];
267     strcpy(_entries[index], line.c_str());
268 }
269
270
271 void PropertyList::valueChanged(SGPropertyNode *nd)
272 {
273     for (int i = 0; i < _num_children; i++)
274         if (_children[i].node == nd) {
275             updateTextForEntry(i);
276             return;
277         }
278 }
279
280
281 int PropertyList::nodeNameCompare(const void *ppNode1, const void *ppNode2)
282 {
283     const SGPropertyNode_ptr pNode1 = (*(const NodeData *)ppNode1).node;
284     const SGPropertyNode_ptr pNode2 = (*(const NodeData *)ppNode2).node;
285
286     int diff = strcmp(pNode1->getName(), pNode2->getName());
287     return diff ? diff : pNode1->getIndex() - pNode2->getIndex();
288 }
289
290
291 void PropertyList::setValue(const char *s)
292 {
293     try {
294         SGPropertyNode *p = fgGetNode(s, false);
295         if (p)
296             setCurrent(p);
297         else
298             throw stdString("node doesn't exist");
299     } catch (const stdString& m) {
300         SG_LOG(SG_GENERAL, SG_DEBUG, "property-list node `" << s << "': " << m);
301     }
302 }
303
304
305 void PropertyList::setCurrent(SGPropertyNode *p)
306 {
307     bool same = (_curr == p);
308     _return = _curr = p;
309     update(same);
310     if (!same)
311         publish(p);
312 }
313