]> SALOME platform Git repositories - modules/hydro.git/commitdiff
Salome HOME
Initial version
authoradmin <salome-admin@opencascade.com>
Tue, 16 Jul 2013 05:23:57 +0000 (05:23 +0000)
committeradmin <salome-admin@opencascade.com>
Tue, 16 Jul 2013 05:23:57 +0000 (05:23 +0000)
src/HYDROData/HYDROData_Document.cxx [new file with mode: 0644]
src/HYDROData/HYDROData_Document.h [new file with mode: 0644]
src/HYDROData/HYDROData_Image.h [new file with mode: 0644]
src/HYDROData/HYDROData_Iterator.cxx [new file with mode: 0644]
src/HYDROData/HYDROData_Object.h [new file with mode: 0644]
src/HYDROData/test_HYDROData_Document.cxx [new file with mode: 0644]
src/HYDROData/test_HYDROData_Image.cxx [new file with mode: 0644]
src/HYDROData/test_HYDROData_Main.cxx [new file with mode: 0644]

diff --git a/src/HYDROData/HYDROData_Document.cxx b/src/HYDROData/HYDROData_Document.cxx
new file mode 100644 (file)
index 0000000..3960c4a
--- /dev/null
@@ -0,0 +1,214 @@
+#include <HYDROData_Document.h>
+#include <HYDROData_Application.h>
+#include <HYDROData_Iterator.h>
+
+#include <TDataStd_Integer.hxx>
+
+IMPLEMENT_STANDARD_HANDLE(HYDROData_Document,MMgt_TShared)
+IMPLEMENT_STANDARD_RTTIEXT(HYDROData_Document,MMgt_TShared)
+
+static const int UNDO_LIMIT = 10; // number of possible undo operations in the module
+
+static const int TAG_PROPS = 1; // general properties tag
+static const int TAG_PROPS_NEW_ID = 1; // general properties: tag for storage of the new object ID
+static const int TAG_OBJECTS = 2; // tag of the objects sub-tree
+static const int TAG_HISTORY = 3; // tag of the history sub-tree (Root for History)
+
+using namespace std;
+
+Handle(HYDROData_Document) HYDROData_Document::Document(const int theStudyID)
+{
+  Handle(HYDROData_Document) aResult = 
+    HYDROData_Application::GetApplication()->GetDocument(theStudyID);
+  if (aResult.IsNull()) {
+    aResult = new HYDROData_Document();
+    HYDROData_Application::GetApplication()->AddDocument(theStudyID, aResult);
+  }
+  return aResult;
+}
+
+bool HYDROData_Document::HasDocument(const int theStudyID)
+{
+  Handle(HYDROData_Document) aResult = 
+    HYDROData_Application::GetApplication()->GetDocument(theStudyID);
+  return !aResult.IsNull();
+}
+
+Data_DocError HYDROData_Document::Load(const char* theFileName, const int theStudyID)
+{
+  Handle(TDocStd_Document) aResult;
+  TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
+  PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
+  try
+  {
+    aStatus = HYDROData_Application::GetApplication()->Open (aPath, aResult);
+  }
+  catch (Standard_Failure)
+  {}
+  if (!aResult.IsNull()) {
+    aResult->SetUndoLimit(UNDO_LIMIT);
+    HYDROData_Application::GetApplication()->AddDocument(theStudyID, new HYDROData_Document(aResult));
+  }
+  // recognize error
+  Data_DocError anError;
+  switch(aStatus) {
+  case PCDM_RS_OK:
+    anError = DocError_OK;
+    break;
+  case PCDM_RS_NoDriver:
+  case PCDM_RS_UnknownFileDriver:
+  case PCDM_RS_NoSchema:
+  case PCDM_RS_DriverFailure:
+  case PCDM_RS_WrongResource:
+    anError = DocError_ResourcesProblem;
+    break;
+  case PCDM_RS_OpenError:
+  case PCDM_RS_NoDocument:
+  case PCDM_RS_WrongStreamMode:
+  case PCDM_RS_PermissionDenied:
+    anError = DocError_CanNotOpen;
+    break;
+  case PCDM_RS_NoVersion:
+    anError = DocError_InvalidVersion;
+    break;
+  case PCDM_RS_ExtensionFailure:
+  case PCDM_RS_FormatFailure:
+  case PCDM_RS_TypeFailure:
+  case PCDM_RS_TypeNotFoundInSchema:
+  case PCDM_RS_UnrecognizedFileFormat:
+    anError = DocError_InvalidFormat;
+    break;
+  case PCDM_RS_MakeFailure:
+  default:
+    anError = DocError_UnknownProblem;
+    break;
+  }
+  return anError;
+}
+
+Data_DocError HYDROData_Document::Save(const char* theFileName)
+{
+  TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
+  PCDM_StoreStatus aStatus;
+  try {
+    aStatus = HYDROData_Application::GetApplication()->SaveAs (myDoc, aPath);
+  }
+  catch (Standard_Failure) {}
+  myTransactionsAfterSave = 0;
+  Standard::Purge(); // Release free memory
+
+  // recognize error
+  Data_DocError anError;
+  switch(aStatus) {
+  case PCDM_SS_OK:
+    anError = DocError_OK;
+    break;
+  case PCDM_SS_DriverFailure:
+    anError = DocError_ResourcesProblem;
+    break;
+  case PCDM_SS_WriteFailure:
+  case PCDM_SS_DiskWritingFailure:
+  case PCDM_SS_UserRightsFailure:
+    anError = DocError_CanNotOpen;
+    break;
+  default:
+    anError = DocError_UnknownProblem;
+    break;
+  }
+  return anError;
+}
+
+void HYDROData_Document::Close()
+{
+  myDoc->Close();
+  HYDROData_Application::GetApplication()->RemoveDocument(this);
+}
+
+void HYDROData_Document::StartOperation()
+{
+  myDoc->NewCommand();
+}
+
+void HYDROData_Document::CommitOperation()
+{
+  myDoc->CommitCommand();
+  myTransactionsAfterSave++;
+}
+
+void HYDROData_Document::AbortOperation()
+{
+  myDoc->AbortCommand();
+}
+
+bool HYDROData_Document::IsOperation()
+{
+  return myDoc->HasOpenCommand() != 0;
+}
+
+bool HYDROData_Document::IsModified()
+{
+  return myTransactionsAfterSave != 0;
+}
+
+bool HYDROData_Document::CanUndo()
+{
+  return myDoc->GetAvailableUndos() > 0;
+}
+
+void HYDROData_Document::Undo()
+{
+  myDoc->Undo();
+  myTransactionsAfterSave--;
+}
+
+bool HYDROData_Document::CanRedo()
+{
+  return myDoc->GetAvailableRedos() > 0;
+}
+
+void HYDROData_Document::Redo()
+{
+  myDoc->Redo();
+  myTransactionsAfterSave++;
+}
+
+Handle_HYDROData_Object HYDROData_Document::CreateObject(const ObjectKind theKind)
+{
+  return HYDROData_Iterator::CreateObject(this, theKind);
+}
+
+HYDROData_Document::HYDROData_Document()
+{
+  HYDROData_Application::GetApplication()->NewDocument("BinOcaf", myDoc);
+  myDoc->SetUndoLimit(UNDO_LIMIT);
+  NewID(); // needed to have at least one attribute in initial document to avoid errors
+  myTransactionsAfterSave = 0;
+}
+
+HYDROData_Document::HYDROData_Document(const Handle(TDocStd_Document)& theDoc)
+{
+  myDoc = theDoc;
+  myTransactionsAfterSave = 0;
+}
+
+HYDROData_Document::~HYDROData_Document()
+{
+}
+
+int HYDROData_Document::NewID()
+{
+  TDF_Label anIDLab = myDoc->Main().FindChild(TAG_PROPS).
+    FindChild(TAG_PROPS_NEW_ID);
+  Handle(TDataStd_Integer) anInt;
+  if (!anIDLab.FindAttribute(TDataStd_Integer::GetID(), anInt)) {
+    anInt = TDataStd_Integer::Set(anIDLab, 0);
+  }
+  // just increment value and return
+  anInt->Set(anInt->Get() + 1);
+  return anInt->Get();
+}
+
+TDF_Label HYDROData_Document::LabelOfObjects()
+{
+  return myDoc->Main().FindChild(TAG_OBJECTS);
+}
diff --git a/src/HYDROData/HYDROData_Document.h b/src/HYDROData/HYDROData_Document.h
new file mode 100644 (file)
index 0000000..00a9072
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef HYDROData_Document_HeaderFile
+#define HYDROData_Document_HeaderFile
+
+#include <HYDROData.h>
+#include <HYDROData_Object.h>
+
+#include <TDocStd_Document.hxx>
+
+/**
+ * Errors that could appear on document open/save actions.
+ * If there is no error, it is "OK".
+ */
+enum Data_DocError {
+  DocError_OK = 0, ///< success
+  DocError_ResourcesProblem, ///< resources files are invalid or not found
+  DocError_CanNotOpen, ///< can not open file for reading or writing
+  DocError_InvalidVersion, ///< version of document is different than expected
+  DocError_InvalidFormat, ///< format of the document is bad
+  DocError_UnknownProblem ///< problem has unknown nature
+};
+
+DEFINE_STANDARD_HANDLE(HYDROData_Document, MMgt_TShared)
+
+/**\class HYDROData_Document
+ *
+ * \brief Document for internal data structure of any object storage. Corresponds to the SALOME study.
+ *
+ * Document contains all data of the Study specific to this module.
+ * Also it provides acces to this data: open/save, transactions management etc.
+ * to provide access to all stored data.
+ */
+
+class HYDROData_Document : public MMgt_TShared
+{
+public:
+
+  DEFINE_STANDARD_RTTI(HYDROData_Document);
+
+  //! Returns the existing document or creates new if it is not exist
+  HYDRODATA_EXPORT static Handle(HYDROData_Document) Document(const int theStudyID);
+
+  //! Returns true if data model contains document for this study
+  HYDRODATA_EXPORT static bool HasDocument(const int theStudyID);
+
+  //! Loads the OCAF document from the file.
+  //! \param theFileName full name of the file to load
+  //! \param theStudyID identifier of the SALOME study to associate with loaded file
+  //! \returns error status (OK in case of success)
+  HYDRODATA_EXPORT static Data_DocError Load(const char* theFileName, const int theStudyID);
+
+  //! Saves the OCAF document to the file.
+  //! \param theFileName full name of the file to store
+  //! \returns error status (OK in case of success)
+  HYDRODATA_EXPORT Data_DocError Save(const char* theFileName);
+
+  //! Removes document data
+  HYDRODATA_EXPORT void Close();
+
+  //! Starts a new operation (opens a tansaction)
+  HYDRODATA_EXPORT void StartOperation();
+  //! Finishes the previously started operation (closes the transaction)
+  HYDRODATA_EXPORT void CommitOperation();
+  //! Aborts the operation 
+  HYDRODATA_EXPORT void AbortOperation();
+  //! Returns true if operation has been started, but not yet finished or aborted
+  HYDRODATA_EXPORT bool IsOperation();
+  //! Returns true if document was modified (since creation/opening)
+  HYDRODATA_EXPORT bool IsModified();
+
+  //! Returns True if there are available Undos
+  HYDRODATA_EXPORT bool CanUndo();
+  //! Undoes last operation
+  HYDRODATA_EXPORT void Undo();
+  //! Returns True if there are available Redos
+  HYDRODATA_EXPORT bool CanRedo();
+  //! Redoes last operation
+  HYDRODATA_EXPORT void Redo();
+
+  //! Creates and locates in the document a new object
+  //! \param theKind kind of the created object, can not be UNKNOWN
+  //! \returns the created object
+  HYDRODATA_EXPORT Handle_HYDROData_Object CreateObject(const ObjectKind theKind);
+
+protected:
+
+  friend class HYDROData_Iterator;
+  friend class test_HYDROData_Document;
+
+  //! Creates new document: private because "Document" method must be used instead of direct creation.
+  HYDROData_Document();
+  //! Creates new document by existing OCAF structure
+  HYDROData_Document(const Handle(TDocStd_Document)& theDoc);
+  //! Deletes all high-level data, managed this document
+  ~HYDROData_Document();
+
+  //! Returns the new identifier of the new object (may be used for correct ordering of objects)
+  HYDRODATA_EXPORT int NewID();
+
+  //! Returns the label where the objects are located (used by Iterator)
+  TDF_Label LabelOfObjects();
+
+private:
+  Handle(TDocStd_Document) myDoc; ///< OCAF document instance corresponding for keeping all persistent data
+  int myTransactionsAfterSave; ///< number of transactions after the last "save" call, used for "IsModified" method
+};
+
+#endif
diff --git a/src/HYDROData/HYDROData_Image.h b/src/HYDROData/HYDROData_Image.h
new file mode 100644 (file)
index 0000000..38e48c1
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef HYDROData_Image_HeaderFile
+#define HYDROData_Image_HeaderFile
+
+#include <HYDROData_Object.h>
+
+#include <QImage>
+#include <QTransform>
+
+DEFINE_STANDARD_HANDLE(HYDROData_Image, HYDROData_Object)
+
+/**\class HYDROData_Image
+ * \brief Class that stores/retreives information about the image.
+ *
+ * Keeps image as binary array, transformation and other properties
+ * of image with correspondent API for forkind wit hthese properties.
+ */
+class HYDROData_Image : public HYDROData_Object
+{
+public:
+  DEFINE_STANDARD_RTTI(HYDROData_Image);
+
+  /**
+   * Returns the kind of this object. Must be redefined in all objects of known type.
+   */
+  HYDRODATA_EXPORT virtual const ObjectKind GetKind() const {return KIND_IMAGE;}
+
+  /**
+   * Stores the image
+   * \param theImage new image
+   */
+  HYDRODATA_EXPORT void SetImage(const QImage& theImage);
+
+  /**
+   * Returns the kept image
+   */
+  HYDRODATA_EXPORT QImage Image();
+
+  /**
+   * Stores the image transformation
+   * \param theTrsf new transformation
+   */
+  HYDRODATA_EXPORT void SetTrsf(const QTransform& theTrsf);
+
+  /**
+   * Returns the kept transformation, or "identity" if not yet stored
+   */
+  HYDRODATA_EXPORT QTransform Trsf();
+
+  /**
+   * Appends reference to other image.
+   * \param theReferenced the image referenced by this
+   */
+  HYDRODATA_EXPORT void AppendReference(Handle(HYDROData_Image) theReferenced);
+
+  /**
+   * Returns the number of referenced images
+   * \return zero if there is no references
+   */
+  HYDRODATA_EXPORT int NbReferences();
+
+  /**
+   * Returns reference by index.
+   * \param theIndex number of reference [0; NbReference)
+   * \returns the referenced image, or Null if index is invalid
+   */
+  HYDRODATA_EXPORT Handle(HYDROData_Image) Reference(const int theIndex) const;
+
+  /**
+   * Updates reference by index. If index is one-bigger than \a NbReferences, 
+   * this method appends it to the end (NbReferences is incremented).
+   * \param theIndex number of reference [0; NbReference]
+   * \param theReferenced the image referenced by this
+   */
+  HYDRODATA_EXPORT void ChangeReference(
+    const int theIndex, Handle(HYDROData_Image) theReferenced);
+
+  /**
+   * Removes reference by index
+   * \param theIndex number of reference [0; NbReference)
+   */
+  HYDRODATA_EXPORT void RemoveReference(const int theIndex);
+
+  /**
+   * Removes all references.
+   */
+  HYDRODATA_EXPORT void ClearReferences();
+
+protected:
+
+  friend class HYDROData_Iterator;
+
+  /**
+   * Creates new object in the internal data structure. Use higher level objects 
+   * to create objects with real content.
+   */
+  HYDROData_Image();
+
+  /**
+   * Destructs properties of the object and object itself, removes it from the document.
+   */
+  ~HYDROData_Image();
+
+};
+
+#endif
diff --git a/src/HYDROData/HYDROData_Iterator.cxx b/src/HYDROData/HYDROData_Iterator.cxx
new file mode 100644 (file)
index 0000000..534cbd1
--- /dev/null
@@ -0,0 +1,61 @@
+#include <HYDROData_Iterator.h>
+
+#include <HYDROData_Image.h>
+
+#include <TDataStd_Name.hxx>
+#include <NCollection_DataMap.hxx>
+
+//! Returns label by root objects kind and the kind of the object
+static TDF_Label GetLabelByKind(TDF_Label theRoot, ObjectKind theKind)
+{
+  if (theKind == KIND_UNKNOWN) return theRoot;
+  return theRoot.FindChild(theKind);
+}
+
+HYDROData_Iterator::HYDROData_Iterator(Handle(HYDROData_Document) theDoc, ObjectKind theKind)
+  : myIter(GetLabelByKind(theDoc->LabelOfObjects(), theKind), 
+           TDataStd_Name::GetID(), theKind == KIND_UNKNOWN) // iterate all sub-objects for unknown kind
+{
+}
+
+void HYDROData_Iterator::Next()
+{
+  myIter.Next();
+  // omit the properties iteration in case of UNKNOWN kind filtering
+  while(myIter.More() && myIter.Value()->Label().Depth() != 4) 
+    myIter.Next();
+}
+
+bool HYDROData_Iterator::More() const
+{
+  return myIter.More();
+}
+
+Handle(HYDROData_Object) HYDROData_Iterator::Current()
+{
+  return Object(myIter.Value()->Label());
+}
+
+Handle_HYDROData_Object HYDROData_Iterator::CreateObject(
+  Handle(HYDROData_Document) theDoc, ObjectKind theKind)
+{
+  TDF_Label aNewLab = GetLabelByKind(theDoc->LabelOfObjects(), theKind).
+    FindChild(theDoc->NewID());
+  // object exists if there is name attribute
+  TDataStd_Name::Set(aNewLab, TCollection_ExtendedString(""));
+  return Object(aNewLab);
+}
+
+Handle_HYDROData_Object HYDROData_Iterator::Object(const TDF_Label theLabel)
+{
+  ObjectKind aKind = theLabel.Father().Tag();
+  Handle(HYDROData_Object) aResult;
+  switch(aKind) {
+  case KIND_IMAGE:
+    aResult = new HYDROData_Image();
+    break;
+  }
+  if (!aResult.IsNull())
+    aResult->SetLabel(theLabel);
+  return aResult;
+}
diff --git a/src/HYDROData/HYDROData_Object.h b/src/HYDROData/HYDROData_Object.h
new file mode 100644 (file)
index 0000000..852c067
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef HYDROData_Object_HeaderFile
+#define HYDROData_Object_HeaderFile
+
+#include <HYDROData.h>
+
+#include <TDF_Label.hxx>
+#include <QString>
+
+///! Kind of an object in a document
+typedef int ObjectKind;
+///! Unrecognized object
+const ObjectKind KIND_UNKNOWN = 0;
+const ObjectKind KIND_IMAGE = 1;
+
+DEFINE_STANDARD_HANDLE(HYDROData_Object, MMgt_TShared)
+
+/**\class HYDROData_Object
+ * \brief Generic class of any object in the data model.
+ *
+ * Interface for getting access to the object that belong to the data model.
+ * Managed by Document. Provides access to the common properties: 
+ * kind of an object, name.
+ */
+class HYDROData_Object : public MMgt_TShared
+{
+public:
+  DEFINE_STANDARD_RTTI(HYDROData_Object);
+
+  /**
+   * Returns the kind of this object. Must be redefined in all objects of known type.
+   */
+  HYDRODATA_EXPORT virtual const ObjectKind GetKind() const {return KIND_UNKNOWN;}
+
+  /**
+   * Returns the name of this object.
+   */
+  HYDRODATA_EXPORT QString GetName() const;
+
+  /**
+   * Updates the name of this object.
+   */
+  HYDRODATA_EXPORT void SetName(const QString& theName);
+
+  /**
+   * Checks is object exists in the data structure.
+   * \returns true is object is not exists in the data model
+   */
+  HYDRODATA_EXPORT bool IsRemoved() const;
+
+  /**
+   * Removes object from the data structure.
+   */
+  HYDRODATA_EXPORT void Remove();
+
+  /**
+   * Returns unique integer identifier of the object (may be used for ordering of objects)
+   */
+  HYDRODATA_EXPORT inline int ID() const {return myLab.Tag();}
+
+  /**
+   * Copies all properties of this to the destinated object.
+   * Objects must be the same type.
+   * \param theDestination initialized object (from any document) - target of copying
+   */
+  HYDRODATA_EXPORT void CopyTo(Handle_HYDROData_Object theDestination) const;
+
+protected:
+
+  friend class HYDROData_Iterator;
+
+  /**
+   * Creates new object in the internal data structure. Use higher level objects 
+   * to create objects with real content.
+   */
+  HYDRODATA_EXPORT HYDROData_Object();
+
+  /**
+   * Destructs properties of the object and object itself, removes it from the document.
+   */
+  virtual HYDRODATA_EXPORT ~HYDROData_Object();
+
+  /**
+   * Put the object to the label of the document.
+   * \param theLabel new label of the object
+   */
+  HYDRODATA_EXPORT virtual void SetLabel(TDF_Label theLabel);
+
+  /**
+   * Returns the label of this object.
+   */
+  TDF_Label& Label() {return myLab;}
+
+protected:
+  /// Array of pointers to the properties of this object; index in this array is returned by \a AddProperty.
+  TDF_Label myLab; ///< label of this object
+};
+
+///! Is Equal for HYDROData_Object mapping
+HYDRODATA_EXPORT bool IsEqual(const Handle_HYDROData_Object& theObj1, const Handle_HYDROData_Object& theObj2);
+
+#endif
diff --git a/src/HYDROData/test_HYDROData_Document.cxx b/src/HYDROData/test_HYDROData_Document.cxx
new file mode 100644 (file)
index 0000000..9ec1221
--- /dev/null
@@ -0,0 +1,90 @@
+#include<test_HYDROData_Document.h>
+
+#include <HYDROData_Document.h>
+#include <QFile>
+
+void test_HYDROData_Document::testSaveOpen()
+{
+  // temporarly created file name (in the current directory)
+  const char* aTestFile = "TestDoc.cbf";
+  // save
+  Handle(HYDROData_Document) aDoc = HYDROData_Document::Document(1);
+  CPPUNIT_ASSERT(!aDoc.IsNull());
+  // keep some saved information to check after retreive
+  aDoc->NewID();
+  int anID = aDoc->NewID();
+  Data_DocError aStatus = aDoc->Save(aTestFile);
+  CPPUNIT_ASSERT(aStatus == DocError_OK);
+  aDoc->Close();
+  CPPUNIT_ASSERT(!HYDROData_Document::HasDocument(1));
+
+  // open
+  aStatus = HYDROData_Document::Load(aTestFile, 2);
+  CPPUNIT_ASSERT(aStatus == DocError_OK);
+  CPPUNIT_ASSERT(HYDROData_Document::HasDocument(2));
+  aDoc = HYDROData_Document::Document(2);
+  CPPUNIT_ASSERT(!aDoc.IsNull());
+  // check that retreived correctly
+  CPPUNIT_ASSERT(aDoc->NewID() == anID + 1);
+
+  // remove the created file using Qt functionality
+  QFile aFile(aTestFile);
+  aFile.remove();
+
+  aDoc->Close();
+}
+
+void test_HYDROData_Document::testOperations()
+{
+  Handle(HYDROData_Document) aDoc = HYDROData_Document::Document(1);
+  CPPUNIT_ASSERT(!aDoc.IsNull());
+  CPPUNIT_ASSERT(!aDoc->IsOperation());
+  CPPUNIT_ASSERT(!aDoc->IsModified());
+  // commit operation
+  aDoc->StartOperation();
+  CPPUNIT_ASSERT(aDoc->IsOperation());
+  int anID = aDoc->NewID();
+  aDoc->CommitOperation();
+  CPPUNIT_ASSERT(!aDoc->IsOperation());
+  CPPUNIT_ASSERT(aDoc->IsModified());
+  // abort operation
+  aDoc->StartOperation();
+  CPPUNIT_ASSERT(aDoc->IsOperation());
+  int anIDAborted = aDoc->NewID();
+  aDoc->AbortOperation();
+  CPPUNIT_ASSERT(!aDoc->IsOperation());
+  CPPUNIT_ASSERT(aDoc->IsModified());
+
+  CPPUNIT_ASSERT(anID + 1 == aDoc->NewID());
+
+  aDoc->Close();
+}
+
+void test_HYDROData_Document::testUndoRedo()
+{
+  Handle(HYDROData_Document) aDoc = HYDROData_Document::Document(1);
+  CPPUNIT_ASSERT(!aDoc.IsNull());
+  CPPUNIT_ASSERT(!aDoc->CanUndo());
+  CPPUNIT_ASSERT(!aDoc->CanRedo());
+  // commit operation
+  aDoc->StartOperation();
+  CPPUNIT_ASSERT(aDoc->IsOperation());
+  int anID = aDoc->NewID();
+  aDoc->CommitOperation();
+  CPPUNIT_ASSERT(aDoc->CanUndo());
+  CPPUNIT_ASSERT(!aDoc->CanRedo());
+  CPPUNIT_ASSERT(aDoc->IsModified());
+  // undo
+  aDoc->Undo();
+  CPPUNIT_ASSERT(!aDoc->CanUndo());
+  CPPUNIT_ASSERT(aDoc->CanRedo());
+  CPPUNIT_ASSERT(anID == aDoc->NewID());
+  CPPUNIT_ASSERT(!aDoc->IsModified());
+  // redo
+  aDoc->Redo();
+  CPPUNIT_ASSERT(aDoc->CanUndo());
+  CPPUNIT_ASSERT(!aDoc->CanRedo());
+  CPPUNIT_ASSERT(aDoc->IsModified());
+
+  aDoc->Close();
+}
diff --git a/src/HYDROData/test_HYDROData_Image.cxx b/src/HYDROData/test_HYDROData_Image.cxx
new file mode 100644 (file)
index 0000000..8e5d8ad
--- /dev/null
@@ -0,0 +1,151 @@
+#include<test_HYDROData_Image.h>
+
+#include <HYDROData_Document.h>
+#include <HYDROData_Image.h>
+#include <QPainter>
+
+static QImage TestImage() {
+  QImage aPic(50, 40, QImage::Format_RGB32);
+  QPainter aPainter(&aPic);
+  aPainter.drawEllipse(6, 7, 38, 30);
+  aPainter.drawLine(0, 40, 10, 0);
+  aPainter.drawLine(10, 0, 25, 35);
+  aPainter.drawLine(25, 35, 40, 0);
+  aPainter.drawLine(40, 0, 50, 40);
+  return aPic;
+}
+
+void test_HYDROData_Image::testQImage()
+{
+  Handle(HYDROData_Document) aDoc = HYDROData_Document::Document(1);
+
+  Handle(HYDROData_Image) anImage = 
+    Handle(HYDROData_Image)::DownCast(aDoc->CreateObject(KIND_IMAGE));
+  // empty image
+  QImage anEmpty = anImage->Image();
+  CPPUNIT_ASSERT(anEmpty.isNull());
+
+  // prepare Qt Image for testing
+  QImage aPic(TestImage());
+  anImage->SetImage(aPic);
+  QImage aRestored = anImage->Image();
+
+  CPPUNIT_ASSERT(!aRestored.isNull());
+  //aRestored.save("pic2.bmp");
+  CPPUNIT_ASSERT(aPic == aRestored);
+
+  aDoc->Close();
+}
+
+void test_HYDROData_Image::testTrsf()
+{
+  Handle(HYDROData_Document) aDoc = HYDROData_Document::Document(1);
+
+  Handle(HYDROData_Image) anImage = 
+    Handle(HYDROData_Image)::DownCast(aDoc->CreateObject(KIND_IMAGE));
+  // empty trsf
+  QTransform anEmpty = anImage->Trsf();
+  CPPUNIT_ASSERT(anEmpty.isIdentity());
+
+  // prepare Qt transformation for testing
+  QTransform aTrsf;
+  aTrsf.translate(50, 50);
+  aTrsf.rotate(45);
+  aTrsf.scale(0.5, 1.0);
+
+  anImage->SetTrsf(aTrsf);
+  QTransform aRestored = anImage->Trsf();
+
+  CPPUNIT_ASSERT(!aRestored.isIdentity());
+  CPPUNIT_ASSERT(aTrsf == aRestored);
+
+  aDoc->Close();
+}
+
+void test_HYDROData_Image::testReferences()
+{
+  Handle(HYDROData_Document) aDoc = HYDROData_Document::Document(1);
+
+  Handle(HYDROData_Image) anImage1 = 
+    Handle(HYDROData_Image)::DownCast(aDoc->CreateObject(KIND_IMAGE));
+  Handle(HYDROData_Image) anImage2 = 
+    Handle(HYDROData_Image)::DownCast(aDoc->CreateObject(KIND_IMAGE));
+  Handle(HYDROData_Image) anImage3 = 
+    Handle(HYDROData_Image)::DownCast(aDoc->CreateObject(KIND_IMAGE));
+
+  CPPUNIT_ASSERT(anImage1->ID() != anImage2->ID());
+  CPPUNIT_ASSERT(anImage2->ID() != anImage3->ID());
+
+  // check initially there is no references
+  CPPUNIT_ASSERT_EQUAL(anImage3->NbReferences(), 0);
+
+  // append reference
+  anImage3->AppendReference(anImage1);
+  CPPUNIT_ASSERT_EQUAL(anImage3->NbReferences(), 1);
+  CPPUNIT_ASSERT(IsEqual(anImage3->Reference(0), anImage1));
+
+  // change reference
+  anImage3->ChangeReference(0, anImage2);
+  CPPUNIT_ASSERT_EQUAL(anImage3->NbReferences(), 1);
+  CPPUNIT_ASSERT(IsEqual(anImage3->Reference(0), anImage2));
+
+  // append one more reference
+  anImage3->AppendReference(anImage1);
+  CPPUNIT_ASSERT_EQUAL(anImage3->NbReferences(), 2);
+  CPPUNIT_ASSERT(IsEqual(anImage3->Reference(0), anImage2));
+  CPPUNIT_ASSERT(IsEqual(anImage3->Reference(1), anImage1));
+
+  // remove reference
+  anImage3->RemoveReference(0);
+  CPPUNIT_ASSERT_EQUAL(anImage3->NbReferences(), 1);
+  CPPUNIT_ASSERT(IsEqual(anImage3->Reference(0), anImage1));
+
+  // remove reference
+  anImage3->RemoveReference(0);
+  CPPUNIT_ASSERT_EQUAL(anImage3->NbReferences(), 0);
+
+  // append two references once again and remove all references
+  anImage3->ChangeReference(0, anImage1);
+  anImage3->ChangeReference(1, anImage2);
+  CPPUNIT_ASSERT_EQUAL(anImage3->NbReferences(), 2);
+  CPPUNIT_ASSERT(IsEqual(anImage3->Reference(0), anImage1));
+  CPPUNIT_ASSERT(IsEqual(anImage3->Reference(1), anImage2));
+  anImage3->ClearReferences();
+  CPPUNIT_ASSERT_EQUAL(anImage3->NbReferences(), 0);
+
+  aDoc->Close();
+}
+
+void test_HYDROData_Image::testCopy()
+{
+  Handle(HYDROData_Document) aDoc = HYDROData_Document::Document(1);
+
+  Handle(HYDROData_Image) anImage1 = 
+    Handle(HYDROData_Image)::DownCast(aDoc->CreateObject(KIND_IMAGE));
+  // fill image 1
+  anImage1->SetImage(TestImage());
+
+  QTransform aTrsf;
+  aTrsf.translate(50, 50);
+  aTrsf.rotate(45);
+  aTrsf.scale(0.5, 1.0);
+  anImage1->SetTrsf(aTrsf);
+
+  Handle(HYDROData_Image) anImage2 = 
+    Handle(HYDROData_Image)::DownCast(aDoc->CreateObject(KIND_IMAGE));
+
+  anImage1->AppendReference(anImage2);
+
+  // copy image to the new one
+  Handle(HYDROData_Image) anImage3 = 
+    Handle(HYDROData_Image)::DownCast(aDoc->CreateObject(KIND_IMAGE));
+  anImage1->CopyTo(anImage3);
+
+  // check all fields are correctly copied
+  CPPUNIT_ASSERT(anImage1->Image() == anImage3->Image());
+  CPPUNIT_ASSERT(anImage1->Trsf() == anImage3->Trsf());
+  CPPUNIT_ASSERT_EQUAL(anImage3->NbReferences(), 1);
+  CPPUNIT_ASSERT(IsEqual(anImage3->Reference(0), anImage2));
+
+  aDoc->Close();
+}
diff --git a/src/HYDROData/test_HYDROData_Main.cxx b/src/HYDROData/test_HYDROData_Main.cxx
new file mode 100644 (file)
index 0000000..6797154
--- /dev/null
@@ -0,0 +1,50 @@
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/CompilerOutputter.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/TestRunner.h>
+#include <cppunit/TextTestProgressListener.h>
+#include <stdexcept>
+
+int 
+  main( int argc, char* argv[] )
+{
+  std::string testPath = (argc > 1) ? std::string(argv[1]) : "";
+
+  // Create the event manager and test controller
+  CppUnit::TestResult controller;
+
+  // Add a listener that colllects test result
+  CppUnit::TestResultCollector result;
+  controller.addListener( &result );        
+
+  // Add a listener that print dots as test run.
+  CppUnit::TextTestProgressListener progress;
+  controller.addListener( &progress );      
+
+  CppUnit::TestFactoryRegistry& registry = 
+    CppUnit::TestFactoryRegistry::getRegistry();
+  // Add the top suite to the test runner
+  CppUnit::TestRunner runner;
+  runner.addTest( registry.makeTest() );   
+  try
+  {
+    std::cout << "Running "  <<  testPath;
+    runner.run( controller, testPath );
+
+    std::cerr << std::endl;
+
+    // Print test in a compiler compatible format.
+    CppUnit::CompilerOutputter outputter( &result, std::cerr );
+    outputter.write();                      
+  }
+  catch ( std::invalid_argument &e )  // Test path not resolved
+  {
+    std::cerr  <<  std::endl  
+      <<  "ERROR: "  <<  e.what()
+      << std::endl;
+    return 0;
+  }
+
+  return result.wasSuccessful() ? 0 : 1;
+}