panda3d/pandatool/src/xfile/xFileDataNodeTemplate.cxx
2004-10-12 19:50:34 +00:00

256 lines
9.1 KiB
C++

// Filename: xFileDataNodeTemplate.cxx
// Created by: drose (03Oct04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "xFileDataNodeTemplate.h"
#include "indent.h"
#include "xFileParseData.h"
#include "xLexerDefs.h"
TypeHandle XFileDataNodeTemplate::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
XFileDataNodeTemplate::
XFileDataNodeTemplate(XFile *x_file, const string &name,
XFileTemplate *xtemplate) :
XFileDataNode(x_file, name, xtemplate)
{
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::is_complex_object
// Access: Public, Virtual
// Description: Returns true if this kind of data object is a complex
// object that can hold nested data elements, false
// otherwise.
////////////////////////////////////////////////////////////////////
bool XFileDataNodeTemplate::
is_complex_object() const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::add_parse_double
// Access: Public
// Description: Adds the indicated list of doubles as a data element
// encountered in the parser. It will later be
// processed by finalize_parse_data().
////////////////////////////////////////////////////////////////////
void XFileDataNodeTemplate::
add_parse_double(PTA_double double_list) {
XFileParseData pdata;
pdata._double_list = double_list;
pdata._parse_flags = XFileParseData::PF_double;
_parse_data_list._list.push_back(pdata);
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::add_parse_int
// Access: Public
// Description: Adds the indicated list of ints as a data element
// encountered in the parser. It will later be
// processed by finalize_parse_data().
////////////////////////////////////////////////////////////////////
void XFileDataNodeTemplate::
add_parse_int(PTA_int int_list) {
XFileParseData pdata;
pdata._int_list = int_list;
pdata._parse_flags = XFileParseData::PF_int;
_parse_data_list._list.push_back(pdata);
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::add_parse_string
// Access: Public
// Description: Adds the indicated string as a data element
// encountered in the parser. It will later be
// processed by finalize_parse_data().
////////////////////////////////////////////////////////////////////
void XFileDataNodeTemplate::
add_parse_string(const string &str) {
XFileParseData pdata;
pdata._string = str;
pdata._parse_flags = XFileParseData::PF_string;
_parse_data_list._list.push_back(pdata);
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::finalize_parse_data
// Access: Public
// Description: Processes all of the data elements added by
// add_parse_*(), checks them for syntactic and semantic
// correctness against the Template definition, and
// stores the appropriate child data elements. Returns
// true on success, false if there is a mismatch.
////////////////////////////////////////////////////////////////////
bool XFileDataNodeTemplate::
finalize_parse_data() {
// Recursively walk through our template definition, while
// simultaneously walking through the list of parse data elements we
// encountered, and re-pack them as actual nested elements.
PrevData prev_data;
size_t index = 0;
size_t sub_index = 0;
if (!_template->repack_data(this, _parse_data_list,
prev_data, index, sub_index)) {
return false;
}
if (index != _parse_data_list._list.size()) {
xyyerror("Too many data elements in structure.");
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::add_element
// Access: Public, Virtual
// Description: Adds the indicated element as a nested data element,
// if this data object type supports it. Returns true
// if added successfully, false if the data object type
// does not support nested data elements.
////////////////////////////////////////////////////////////////////
bool XFileDataNodeTemplate::
add_element(XFileDataObject *element) {
_nested_elements.push_back(element);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::write_text
// Access: Public, Virtual
// Description: Writes a suitable representation of this node to an
// .x file in text mode.
////////////////////////////////////////////////////////////////////
void XFileDataNodeTemplate::
write_text(ostream &out, int indent_level) const {
indent(out, indent_level)
<< _template->get_name();
if (has_name()) {
out << " " << get_name();
}
out << " {\n";
int num_elements = get_num_elements();
for (int i = 0; i < num_elements; i++) {
get_element(i)->write_data(out, indent_level + 2, ";");
}
XFileNode::write_text(out, indent_level + 2);
indent(out, indent_level)
<< "}\n";
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::write_data
// Access: Public, Virtual
// Description: Writes a suitable representation of this node to an
// .x file in text mode.
////////////////////////////////////////////////////////////////////
void XFileDataNodeTemplate::
write_data(ostream &out, int indent_level, const char *separator) const {
if (!_nested_elements.empty()) {
bool indented = false;
for (size_t i = 0; i < _nested_elements.size() - 1; i++) {
XFileDataObject *object = _nested_elements[i];
if (object->is_complex_object()) {
// If we have a "complex" nested object, output it on its own
// line.
if (indented) {
out << "\n";
indented = false;
}
object->write_data(out, indent_level, ";");
} else {
// Otherwise, output them all on the same line.
if (!indented) {
indent(out, indent_level);
indented = true;
}
out << *object << "; ";
}
}
// The last object is the set is different, because it gets
// separator appended to it, and it always gets a newline.
XFileDataObject *object = _nested_elements.back();
if (object->is_complex_object()) {
if (indented) {
out << "\n";
}
string combined_separator = string(";") + string(separator);
object->write_data(out, indent_level, combined_separator.c_str());
} else {
if (!indented) {
indent(out, indent_level);
}
out << *object << ";" << separator << "\n";
}
}
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::get_num_elements
// Access: Protected, Virtual
// Description: Returns the number of nested data elements within the
// object. This may be, e.g. the size of the array, if
// it is an array.
////////////////////////////////////////////////////////////////////
int XFileDataNodeTemplate::
get_num_elements() const {
return _nested_elements.size();
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::get_element
// Access: Protected, Virtual
// Description: Returns the nth nested data element within the
// object.
////////////////////////////////////////////////////////////////////
const XFileDataObject *XFileDataNodeTemplate::
get_element(int n) const {
nassertr(n >= 0 && n < (int)_nested_elements.size(), NULL);
return _nested_elements[n];
}
////////////////////////////////////////////////////////////////////
// Function: XFileDataNodeTemplate::get_element
// Access: Protected, Virtual
// Description: Returns the nested data element within the
// object that has the indicated name.
////////////////////////////////////////////////////////////////////
const XFileDataObject *XFileDataNodeTemplate::
get_element(const string &name) const {
int child_index = _template->find_child_index(name);
if (child_index >= 0) {
return get_element(child_index);
}
return NULL;
}