//################################################################################################## // // Custom Visualization Core library // Copyright (C) 2011-2012 Ceetron AS // // This library 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 3 of the License, or // (at your option) any later version. // // This library 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 at <> // for more details. // //################################################################################################## #pragma once #include #include #include #include #include #include #include "cafPdmUiItem.h" #include "cafPdmObjectFactory.h" namespace caf { // Forward declarations template class PdmField; template class PdmPointer; template class AppEnum; //================================================================================================== /// A proxy class that implements the Gui interface of fields /// /// This class collects methods that need specialization when introducing a new type in a PdmField. /// Having those methods in a separate class makes it possible to "partially specialize" the methods /// for container classes etc. since partial specialization of template functions is not C++ as of yet. /// /// When introducing a new type in a PdmField, you might need to implement a (partial)specialization /// of this class. //================================================================================================== template class PdmFieldTypeSpecialization { public: /// Convert the field value into a QVariant static QVariant convert(const T& value) { return QVariant(value); } /// Set the field value from a QVariant static void setFromVariant(const QVariant& variantValue, T& value) { value = variantValue.value(); } /// Methods to get a list of options for a field, specialized for AppEnum static QList valueOptions( bool* useOptionsOnly, const T& ) { return QList(); } /// Methods to retrieve the possible PdmObject pointed to by a field static void childObjects(const PdmField& , std::vector* ) { } /* static void writeFieldData(PdmField & field, QXmlStreamWriter& xmlStream) { QString dataString; QTextStream data(&dataString, QIODevice::WriteOnly); data << field.v(); xmlStream.writeCharacters(dataString); } static void readFieldData(PdmField & field, QXmlStreamReader& xmlStream) { PdmFieldHandle::skipComments(xmlStream); if (!xmlStream.isCharacters()) return; QString dataString = xmlStream.text().toString(); QTextStream data(&dataString, QIODevice::ReadOnly); data >> field.v(); // Make stream point to end of element QXmlStreamReader::TokenType type; type = xmlStream.readNext(); PdmFieldHandle::skipCharactersAndComments(xmlStream); } */ }; //================================================================================================== /// Partial specialization for PdmField< std::list > //================================================================================================== template class PdmFieldTypeSpecialization < std::list > { public: /// Convert the field value into a QVariant static QVariant convert(const std::list& value) { QList returnList; typename std::list::const_iterator it; for (it = value.begin(); it != value.end() ; ++it) { returnList.push_back(QVariant(*it)); } return returnList; } /// Set the field value from a QVariant static void setFromVariant(const QVariant& variantValue, std::list& value) { if (variantValue.canConvert< QList >()) { value.clear(); QList lst = variantValue.toList(); int i; for (i = 0; i < lst.size(); ++i) { value.push_back(lst[i].value()); } } } /// Methods to get a list of options for a field, specialized for AppEnum static QList valueOptions( bool* useOptionsOnly, const std::list& ) { return QList(); } /// Methods to retrieve the possible PdmObject pointed to by a field static void childObjects(const PdmField< std::list >& , std::vector* ) { } }; //================================================================================================== /// Partial specialization for PdmField< std::list< PdmPointer > > //================================================================================================== template class PdmFieldTypeSpecialization < std::list > > { public: /// Convert the field value into a QVariant static QVariant convert(const std::list >& ) { return QVariant(); // Do nothing. The members are "children" } /// Set the field value from a QVariant // Overloaded to do nothing because this is supposed to be handled as children static void setFromVariant(const QVariant& , std::list >& ) { } /// Methods to get a list of options for a field, specialized for AppEnum static QList valueOptions( bool* useOptionsOnly, const std::list >& ) { return QList(); } /// Methods to retrieve the possible PdmObject pointed to by a field static void childObjects(const PdmField > >& field, std::vector* objects) { if (!objects) return; typename std::list >::const_iterator it; for (it = field.v().begin() ; it != field.v().end(); ++it) { objects->push_back(*it); } } }; //================================================================================================== /// Partial specialization for PdmField< std::vector > //================================================================================================== template class PdmFieldTypeSpecialization < std::vector > { public: /// Convert the field value into a QVariant static QVariant convert(const std::vector& value) { QList returnList; typename std::vector::const_iterator it; for (it = value.begin(); it != value.end() ; ++it) { returnList.push_back(QVariant(*it)); } return returnList; } /// Set the field value from a QVariant static void setFromVariant(const QVariant& variantValue, std::vector& value) { if (variantValue.canConvert< QList >()) { value.clear(); QList lst = variantValue.toList(); int i; for (i = 0; i < lst.size(); ++i) { value.push_back(lst[i].value()); } } } /// Methods to get a list of options for a field, specialized for AppEnum static QList valueOptions( bool* useOptionsOnly, const std::vector& ) { return QList(); } /// Methods to retrieve the possible PdmObject pointed to by a field static void childObjects(const PdmField< std::vector > & field, std::vector* objects) { } }; //================================================================================================== /// Partial specialization for PdmField< caf::AppEnum > //================================================================================================== template class PdmFieldTypeSpecialization < caf::AppEnum > { public: /// Convert the field value into a QVariant static QVariant convert(const caf::AppEnum& value) { return QVariant(static_cast(caf::AppEnum::index(value))); } /// Set the field value from a QVariant static void setFromVariant(const QVariant& variantValue, caf::AppEnum& value) { value.setFromIndex(variantValue.toInt()); } /// Methods to get a list of options for a field, specialized for AppEnum static QList valueOptions( bool* useOptionsOnly, const caf::AppEnum& ) { if (useOptionsOnly) *useOptionsOnly = true; QStringList optionTexts = caf::AppEnum::uiTexts(); QList optionList; int i; for (i = 0; i < optionTexts.size(); ++i) { optionList.push_back(PdmOptionItemInfo(optionTexts[i], static_cast(i))); } return optionList; } /// Methods to retrieve the possible PdmObject pointed to by a field static void childObjects(const PdmField< caf::AppEnum >& field, std::vector* objects) { } }; class PdmFieldIOHelper { public: // Utility functions for reading from QXmlStreamReader static void skipCharactersAndComments(QXmlStreamReader& xmlStream); static void skipComments(QXmlStreamReader& xmlStream); }; //-------------------------------------------------------------------------------------------------- /// Generic write method for fields. Will work as long as DataType supports the stream operator /// towards a QTextStream. Some special datatype should not specialize this method unless it is /// impossible/awkward to implement the stream operator /// Implemented in a proxy class to allow partial specialization //-------------------------------------------------------------------------------------------------- template struct PdmFieldWriter { static void writeFieldData(PdmField & field, QXmlStreamWriter& xmlStream) { QString dataString; QTextStream data(&dataString, QIODevice::WriteOnly); data << field.v(); xmlStream.writeCharacters(dataString); } }; template struct PdmFieldReader { static void readFieldData(PdmField & field, QXmlStreamReader& xmlStream); }; //-------------------------------------------------------------------------------------------------- /// Generic read method for fields. Will work as long as DataType supports the stream operator /// towards a QTextStream. Some special datatype should not specialize this method unless it is /// impossible/awkward to implement the stream operator //-------------------------------------------------------------------------------------------------- template void PdmFieldReader::readFieldData(PdmField & field, QXmlStreamReader& xmlStream) { PdmFieldIOHelper::skipComments(xmlStream); if (!xmlStream.isCharacters()) return; QString dataString = xmlStream.text().toString(); QTextStream data(&dataString, QIODevice::ReadOnly); data >> field.v(); // Make stream point to end of element QXmlStreamReader::TokenType type; type = xmlStream.readNext(); PdmFieldIOHelper::skipCharactersAndComments(xmlStream); } //-------------------------------------------------------------------------------------------------- /// Specialized read function for QStrings, because the >> operator only can read word by word //-------------------------------------------------------------------------------------------------- template<> void PdmFieldReader::readFieldData(PdmField & field, QXmlStreamReader& xmlStream); //================================================================================================== /// Read and write method specializations for containers of pointers /// std::list is the main one //================================================================================================== template struct PdmFieldWriter > > { static void writeFieldData(PdmField > > & field, QXmlStreamWriter& xmlStream) { typename std::list< PdmPointer >::iterator it; for (it = field.v().begin(); it != field.v().end(); ++it) { if (*it == NULL) continue; QString className = (*it)->classKeyword(); xmlStream.writeStartElement("", className); (*it)->writeFields(xmlStream); xmlStream.writeEndElement(); } } }; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- template struct PdmFieldReader > > { static void readFieldData(PdmField > > & field, QXmlStreamReader& xmlStream) { T * currentObject = NULL; PdmFieldIOHelper::skipCharactersAndComments(xmlStream); while (xmlStream.isStartElement()) { QString className = xmlStream.name().toString(); PdmObject * obj = PdmObjectFactory::instance()->create(className); if (obj == NULL) { // Warning: Unknown className read // Skip to corresponding end element xmlStream.skipCurrentElement(); PdmFieldIOHelper::skipCharactersAndComments(xmlStream); continue; } currentObject = dynamic_cast (obj); if (currentObject == NULL) { // Warning: Inconsistency in factory !! Assert ? // Skip to corresponding end element xmlStream.skipCurrentElement(); PdmFieldIOHelper::skipCharactersAndComments(xmlStream); continue; } currentObject->readFields(xmlStream); field.v().push_back(currentObject); // Skip comments and for some reason: Characters. The last bit should not be correct, // but Qt reports a character token between EndElement and StartElement QXmlStreamReader::TokenType type; type = xmlStream.readNext(); PdmFieldIOHelper::skipCharactersAndComments(xmlStream); } } }; } // End of namespace caf //================================================================================================== /// QTextStream Stream operator overloading for bool`s /// Prints bool`s as "True"/"False", and reads them too //================================================================================================== QTextStream& operator >> (QTextStream& str, bool& value); QTextStream& operator << (QTextStream& str, const bool& value); //================================================================================================== /// QTextStream Stream operator overloading for QDateTimes`s /// //================================================================================================== //class QDateTime; QTextStream& operator >> (QTextStream& str, QDateTime& value); QTextStream& operator << (QTextStream& str, const QDateTime& value); //================================================================================================== /// QTextStream Stream operator overloading for std::vector of things. /// Makes automated IO of PdmField< std::vector< Whatever > possible as long as /// the type will print as one single word //================================================================================================== template < typename T > QTextStream& operator << (QTextStream& str, const std::vector& sobj) { size_t i; for (i = 0; i < sobj.size(); ++i) { str << sobj[i] << " "; } return str; } template < typename T > QTextStream& operator >> (QTextStream& str, std::vector& sobj) { while (str.status() == QTextStream::Ok ) { T d; str >> d; if (str.status() == QTextStream::Ok ) sobj.push_back(d); } return str; }