mirror of
https://github.com/OPM/ResInsight.git
synced 2024-12-29 10:21:54 -06:00
449 lines
16 KiB
C++
449 lines
16 KiB
C++
//##################################################################################################
|
|
//
|
|
// 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 <<http://www.gnu.org/licenses/gpl.html>>
|
|
// for more details.
|
|
//
|
|
//##################################################################################################
|
|
|
|
#pragma once
|
|
#include <QVariant>
|
|
#include <QList>
|
|
#include <QStringList>
|
|
#include <QXmlStreamReader>
|
|
#include <QXmlStreamWriter>
|
|
#include <QTextStream>
|
|
|
|
#include "cafPdmUiItem.h"
|
|
#include "cafPdmObjectFactory.h"
|
|
|
|
namespace caf
|
|
{
|
|
|
|
// Forward declarations
|
|
template <typename T> class PdmField;
|
|
template <typename T> class PdmPointer;
|
|
template <typename T> 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 <typename T>
|
|
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<T>();
|
|
}
|
|
|
|
/// Methods to get a list of options for a field, specialized for AppEnum
|
|
static QList<PdmOptionItemInfo> valueOptions( bool* useOptionsOnly, const T& )
|
|
{
|
|
return QList<PdmOptionItemInfo>();
|
|
}
|
|
|
|
/// Methods to retrieve the possible PdmObject pointed to by a field
|
|
static void childObjects(const PdmField<T>& , std::vector<PdmObject*>* )
|
|
{ }
|
|
/*
|
|
static void writeFieldData(PdmField<T> & field, QXmlStreamWriter& xmlStream)
|
|
{
|
|
QString dataString;
|
|
QTextStream data(&dataString, QIODevice::WriteOnly);
|
|
data << field.v();
|
|
xmlStream.writeCharacters(dataString);
|
|
}
|
|
|
|
static void readFieldData(PdmField<DataType> & 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<T> >
|
|
//==================================================================================================
|
|
|
|
template <typename T>
|
|
class PdmFieldTypeSpecialization < std::list<T> >
|
|
{
|
|
public:
|
|
/// Convert the field value into a QVariant
|
|
static QVariant convert(const std::list<T>& value)
|
|
{
|
|
QList<QVariant> returnList;
|
|
typename std::list<T>::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<T>& value)
|
|
{
|
|
if (variantValue.canConvert< QList<QVariant> >())
|
|
{
|
|
value.clear();
|
|
QList<QVariant> lst = variantValue.toList();
|
|
int i;
|
|
for (i = 0; i < lst.size(); ++i)
|
|
{
|
|
value.push_back(lst[i].value<T>());
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Methods to get a list of options for a field, specialized for AppEnum
|
|
static QList<PdmOptionItemInfo> valueOptions( bool* useOptionsOnly, const std::list<T>& )
|
|
{
|
|
return QList<PdmOptionItemInfo>();
|
|
}
|
|
|
|
/// Methods to retrieve the possible PdmObject pointed to by a field
|
|
static void childObjects(const PdmField< std::list<T> >& , std::vector<PdmObject*>* )
|
|
{ }
|
|
|
|
};
|
|
|
|
//==================================================================================================
|
|
/// Partial specialization for PdmField< std::list< PdmPointer<T> > >
|
|
//==================================================================================================
|
|
|
|
template <typename T>
|
|
class PdmFieldTypeSpecialization < std::list<PdmPointer<T> > >
|
|
{
|
|
public:
|
|
/// Convert the field value into a QVariant
|
|
static QVariant convert(const std::list<PdmPointer<T> >& )
|
|
{
|
|
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<PdmPointer<T> >& )
|
|
{ }
|
|
|
|
/// Methods to get a list of options for a field, specialized for AppEnum
|
|
static QList<PdmOptionItemInfo> valueOptions( bool* useOptionsOnly, const std::list<PdmPointer<T> >& )
|
|
{
|
|
return QList<PdmOptionItemInfo>();
|
|
}
|
|
|
|
/// Methods to retrieve the possible PdmObject pointed to by a field
|
|
static void childObjects(const PdmField<std::list<PdmPointer<T> > >& field, std::vector<PdmObject*>* objects)
|
|
{
|
|
if (!objects) return;
|
|
|
|
typename std::list<PdmPointer<T> >::const_iterator it;
|
|
for (it = field.v().begin() ; it != field.v().end(); ++it)
|
|
{
|
|
objects->push_back(*it);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
//==================================================================================================
|
|
/// Partial specialization for PdmField< std::vector<T> >
|
|
//==================================================================================================
|
|
|
|
template <typename T>
|
|
class PdmFieldTypeSpecialization < std::vector<T> >
|
|
{
|
|
public:
|
|
/// Convert the field value into a QVariant
|
|
static QVariant convert(const std::vector<T>& value)
|
|
{
|
|
QList<QVariant> returnList;
|
|
typename std::vector<T>::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<T>& value)
|
|
{
|
|
if (variantValue.canConvert< QList<QVariant> >())
|
|
{
|
|
value.clear();
|
|
QList<QVariant> lst = variantValue.toList();
|
|
int i;
|
|
for (i = 0; i < lst.size(); ++i)
|
|
{
|
|
value.push_back(lst[i].value<T>());
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Methods to get a list of options for a field, specialized for AppEnum
|
|
static QList<PdmOptionItemInfo> valueOptions( bool* useOptionsOnly, const std::vector<T>& )
|
|
{
|
|
return QList<PdmOptionItemInfo>();
|
|
}
|
|
|
|
/// Methods to retrieve the possible PdmObject pointed to by a field
|
|
static void childObjects(const PdmField< std::vector<T> > & field, std::vector<PdmObject*>* objects)
|
|
{ }
|
|
|
|
};
|
|
|
|
//==================================================================================================
|
|
/// Partial specialization for PdmField< caf::AppEnum<T> >
|
|
//==================================================================================================
|
|
|
|
template <typename T>
|
|
class PdmFieldTypeSpecialization < caf::AppEnum<T> >
|
|
{
|
|
public:
|
|
/// Convert the field value into a QVariant
|
|
static QVariant convert(const caf::AppEnum<T>& value)
|
|
{
|
|
return QVariant(static_cast<unsigned int>(caf::AppEnum<T>::index(value)));
|
|
}
|
|
|
|
/// Set the field value from a QVariant
|
|
static void setFromVariant(const QVariant& variantValue, caf::AppEnum<T>& value)
|
|
{
|
|
value.setFromIndex(variantValue.toInt());
|
|
}
|
|
|
|
/// Methods to get a list of options for a field, specialized for AppEnum
|
|
static QList<PdmOptionItemInfo> valueOptions( bool* useOptionsOnly, const caf::AppEnum<T>& )
|
|
{
|
|
if (useOptionsOnly) *useOptionsOnly = true;
|
|
|
|
QStringList optionTexts = caf::AppEnum<T>::uiTexts();
|
|
QList<PdmOptionItemInfo> optionList;
|
|
int i;
|
|
for (i = 0; i < optionTexts.size(); ++i)
|
|
{
|
|
optionList.push_back(PdmOptionItemInfo(optionTexts[i]));
|
|
}
|
|
|
|
return optionList;
|
|
}
|
|
|
|
/// Methods to retrieve the possible PdmObject pointed to by a field
|
|
static void childObjects(const PdmField< caf::AppEnum<T> >& field, std::vector<PdmObject*>* 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 <typename T>
|
|
struct PdmFieldWriter
|
|
{
|
|
static void writeFieldData(PdmField<T> & field, QXmlStreamWriter& xmlStream)
|
|
{
|
|
QString dataString;
|
|
QTextStream data(&dataString, QIODevice::WriteOnly);
|
|
data << field.v();
|
|
xmlStream.writeCharacters(dataString);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct PdmFieldReader
|
|
{
|
|
static void readFieldData(PdmField<T> & 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<typename DataType >
|
|
void PdmFieldReader<DataType>::readFieldData(PdmField<DataType> & 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<QString>::readFieldData(PdmField<QString> & field, QXmlStreamReader& xmlStream);
|
|
|
|
//==================================================================================================
|
|
/// Read and write method specializations for containers of pointers
|
|
/// std::list is the main one
|
|
//==================================================================================================
|
|
|
|
template <typename T>
|
|
struct PdmFieldWriter<std::list< PdmPointer<T> > >
|
|
{
|
|
static void writeFieldData(PdmField<std::list< PdmPointer<T> > > & field, QXmlStreamWriter& xmlStream)
|
|
{
|
|
typename std::list< PdmPointer<T> >::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 <typename T>
|
|
struct PdmFieldReader<std::list< PdmPointer<T> > >
|
|
{
|
|
static void readFieldData(PdmField<std::list< PdmPointer<T> > > & 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<T *> (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 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 >
|
|
void operator << (QTextStream& str, const std::vector<T>& sobj)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < sobj.size(); ++i)
|
|
{
|
|
str << sobj[i] << " ";
|
|
}
|
|
}
|
|
|
|
template < typename T >
|
|
void operator >> (QTextStream& str, std::vector<T>& sobj)
|
|
{
|
|
while (str.status() == QTextStream::Ok )
|
|
{
|
|
T d;
|
|
str >> d;
|
|
if (str.status() == QTextStream::Ok ) sobj.push_back(d);
|
|
}
|
|
}
|
|
|
|
//==================================================================================================
|
|
/// QTextStream Stream operator overloading for bool`s
|
|
/// Prints bool`s as "True"/"False", and reads them too
|
|
//==================================================================================================
|
|
|
|
void operator >> (QTextStream& str, bool& value);
|
|
void operator << (QTextStream& str, const bool& value);
|
|
|